]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Mario/bulldozer
authorMario <mario@smbclan.net>
Fri, 13 Nov 2015 14:29:42 +0000 (00:29 +1000)
committerMario <mario@smbclan.net>
Fri, 13 Nov 2015 14:29:42 +0000 (00:29 +1000)
586 files changed:
check-translations.sh
languages.txt
qcsrc/client/announcer.qc
qcsrc/client/announcer.qh
qcsrc/client/commands/cl_cmd.qc
qcsrc/client/controlpoint.qc [deleted file]
qcsrc/client/controlpoint.qh [deleted file]
qcsrc/client/csqcmodel_hooks.qc
qcsrc/client/damage.qc [deleted file]
qcsrc/client/damage.qh [deleted file]
qcsrc/client/defs.qh
qcsrc/client/effects.qc [deleted file]
qcsrc/client/effects.qh [deleted file]
qcsrc/client/generator.qc [deleted file]
qcsrc/client/generator.qh [deleted file]
qcsrc/client/gibs.qc [deleted file]
qcsrc/client/gibs.qh [deleted file]
qcsrc/client/hook.qc
qcsrc/client/hook.qh
qcsrc/client/hud.qc [deleted file]
qcsrc/client/hud.qh [deleted file]
qcsrc/client/hud/all.inc [new file with mode: 0644]
qcsrc/client/hud/all.qc [new file with mode: 0644]
qcsrc/client/hud/all.qh [new file with mode: 0644]
qcsrc/client/hud/hud.qc [new file with mode: 0644]
qcsrc/client/hud/hud.qh [new file with mode: 0644]
qcsrc/client/hud/hud_config.qc [new file with mode: 0644]
qcsrc/client/hud/hud_config.qh [new file with mode: 0644]
qcsrc/client/hud/panel/ammo.qc [new file with mode: 0644]
qcsrc/client/hud/panel/centerprint.qc [new file with mode: 0644]
qcsrc/client/hud/panel/chat.qc [new file with mode: 0644]
qcsrc/client/hud/panel/engineinfo.qc [new file with mode: 0644]
qcsrc/client/hud/panel/healtharmor.qc [new file with mode: 0644]
qcsrc/client/hud/panel/infomessages.qc [new file with mode: 0644]
qcsrc/client/hud/panel/minigame.qc [new file with mode: 0644]
qcsrc/client/hud/panel/modicons.qc [new file with mode: 0644]
qcsrc/client/hud/panel/notify.qc [new file with mode: 0644]
qcsrc/client/hud/panel/physics.qc [new file with mode: 0644]
qcsrc/client/hud/panel/powerups.qc [new file with mode: 0644]
qcsrc/client/hud/panel/pressedkeys.qc [new file with mode: 0644]
qcsrc/client/hud/panel/quickmenu.qc [new file with mode: 0644]
qcsrc/client/hud/panel/racetimer.qc [new file with mode: 0644]
qcsrc/client/hud/panel/radar.qc [new file with mode: 0644]
qcsrc/client/hud/panel/score.qc [new file with mode: 0644]
qcsrc/client/hud/panel/timer.qc [new file with mode: 0644]
qcsrc/client/hud/panel/vote.qc [new file with mode: 0644]
qcsrc/client/hud/panel/weapons.qc [new file with mode: 0644]
qcsrc/client/hud_config.qc [deleted file]
qcsrc/client/hud_config.qh [deleted file]
qcsrc/client/laser.qc [deleted file]
qcsrc/client/laser.qh [deleted file]
qcsrc/client/main.qc
qcsrc/client/main.qh
qcsrc/client/mapvoting.qc
qcsrc/client/mapvoting.qh
qcsrc/client/miscfunctions.qc
qcsrc/client/miscfunctions.qh
qcsrc/client/modeleffects.qc [deleted file]
qcsrc/client/modeleffects.qh [deleted file]
qcsrc/client/mutators/events.qh
qcsrc/client/particles.qc [deleted file]
qcsrc/client/particles.qh [deleted file]
qcsrc/client/progs.inc
qcsrc/client/quickmenu.qc
qcsrc/client/rubble.qc [deleted file]
qcsrc/client/rubble.qh [deleted file]
qcsrc/client/scoreboard.qc
qcsrc/client/scoreboard.qh
qcsrc/client/shownames.qc
qcsrc/client/t_items.qc
qcsrc/client/teamradar.qc
qcsrc/client/teamradar.qh
qcsrc/client/tuba.qc
qcsrc/client/tuba.qh
qcsrc/client/view.qc
qcsrc/client/wall.qc
qcsrc/client/wall.qh
qcsrc/client/weapons/projectile.qc
qcsrc/client/weapons/projectile.qh
qcsrc/common/buffs/all.inc [deleted file]
qcsrc/common/buffs/all.qc [deleted file]
qcsrc/common/buffs/all.qh [deleted file]
qcsrc/common/command/all.qh
qcsrc/common/command/generic.qc
qcsrc/common/command/generic.qh
qcsrc/common/constants.qh
qcsrc/common/csqcmodel_settings.qh
qcsrc/common/deathtypes/all.qc
qcsrc/common/deathtypes/all.qh
qcsrc/common/debug.qh [new file with mode: 0644]
qcsrc/common/effects/all.inc
qcsrc/common/effects/all.qc
qcsrc/common/effects/all.qh
qcsrc/common/effects/effect.qh
qcsrc/common/effects/effectinfo.qc
qcsrc/common/effects/qc/all.inc [new file with mode: 0644]
qcsrc/common/effects/qc/all.qc [new file with mode: 0644]
qcsrc/common/effects/qc/all.qh [new file with mode: 0644]
qcsrc/common/effects/qc/casings.qc [new file with mode: 0644]
qcsrc/common/effects/qc/damageeffects.qc [new file with mode: 0644]
qcsrc/common/effects/qc/gibs.qc [new file with mode: 0644]
qcsrc/common/effects/qc/lightningarc.qc [new file with mode: 0644]
qcsrc/common/effects/qc/modeleffects.qc [new file with mode: 0644]
qcsrc/common/effects/qc/rubble.qh [new file with mode: 0644]
qcsrc/common/gamemodes/all.inc
qcsrc/common/gamemodes/gamemode/nexball/module.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/nexball/nexball.qc
qcsrc/common/gamemodes/gamemode/nexball/nexball.qh
qcsrc/common/gamemodes/gamemode/nexball/weapon.qc
qcsrc/common/gamemodes/gamemode/onslaught/cl_controlpoint.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/cl_controlpoint.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/cl_generator.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/cl_generator.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/module.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/onslaught.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/sv_controlpoint.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/sv_controlpoint.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/sv_generator.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/onslaught/sv_generator.qh [new file with mode: 0644]
qcsrc/common/items/all.qh
qcsrc/common/items/inventory.qh
qcsrc/common/items/item/armor.qc
qcsrc/common/items/item/armor.qh
qcsrc/common/items/item/health.qc
qcsrc/common/items/item/health.qh
qcsrc/common/items/item/pickup.qc
qcsrc/common/items/item/pickup.qh
qcsrc/common/items/item/powerup.qc
qcsrc/common/items/item/powerup.qh
qcsrc/common/mapinfo.qc
qcsrc/common/mapinfo.qh
qcsrc/common/minigames/cl_minigames.qc
qcsrc/common/minigames/cl_minigames.qh
qcsrc/common/minigames/minigame/nmm.qc
qcsrc/common/minigames/minigame/ttt.qc
qcsrc/common/minigames/minigames.qc
qcsrc/common/minigames/sv_minigames.qc
qcsrc/common/minigames/sv_minigames.qh
qcsrc/common/models/all.inc
qcsrc/common/models/all.qh
qcsrc/common/monsters/all.qc
qcsrc/common/monsters/all.qh
qcsrc/common/monsters/monster.qh
qcsrc/common/monsters/monster/mage.qc
qcsrc/common/monsters/monster/shambler.qc
qcsrc/common/monsters/monster/spider.qc
qcsrc/common/monsters/monster/wyvern.qc
qcsrc/common/monsters/monster/zombie.qc
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/movetypes/movetypes.qh
qcsrc/common/mutators/all.inc
qcsrc/common/mutators/base.qh
qcsrc/common/mutators/events.qh
qcsrc/common/mutators/mutator/bloodloss/bloodloss.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/bloodloss/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/breakablehook/breakablehook.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/breakablehook/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/buffs/all.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/buffs/all.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/buffs/all.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/buffs/buffs.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/buffs/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/campcheck/campcheck.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/campcheck/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/casings.qc [deleted file]
qcsrc/common/mutators/mutator/cloaked/cloaked.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/cloaked/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/damagetext.qc [deleted file]
qcsrc/common/mutators/mutator/damagetext/damagetext.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/damagetext/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/dodging/dodging.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/dodging/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/hook/hook.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/hook/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/instagib/instagib.qc
qcsrc/common/mutators/mutator/instagib/items.qc
qcsrc/common/mutators/mutator/instagib/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/invincibleproj/invincibleproj.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/invincibleproj/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/itemstime.qc
qcsrc/common/mutators/mutator/melee_only/melee_only.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/melee_only/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/midair/midair.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/midair/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/multijump/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/multijump/multijump.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/nades/effects.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/nades/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/nades/nades.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/nades/nades.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/nades/nades.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/nades/net.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/new_toys/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/new_toys/new_toys.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/nix/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/nix/nix.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/hmg.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/overkill.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/rpc.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/physical_items/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/physical_items/physical_items.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/pinata/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/pinata/pinata.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/random_gravity/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/random_gravity/random_gravity.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/rocketflying/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/rocketflying/rocketflying.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/rocketminsta/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/rocketminsta/rocketminsta.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/running_guns/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/running_guns/running_guns.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/sandbox/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/sandbox/sandbox.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/spawn_near_teammate/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/spawn_near_teammate/spawn_near_teammate.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/superspec/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/superspec/superspec.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/touchexplode/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/touchexplode/touchexplode.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/vampire/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/vampire/vampire.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/vampirehook/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/vampirehook/vampirehook.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/waypoints/all.inc
qcsrc/common/mutators/mutator/waypoints/all.qh
qcsrc/common/mutators/mutator/waypoints/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc
qcsrc/common/mutators/mutator/weaponarena_random/module.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/weaponarena_random/weaponarena_random.qc [new file with mode: 0644]
qcsrc/common/nades/all.inc [deleted file]
qcsrc/common/nades/all.qc [deleted file]
qcsrc/common/nades/all.qh [deleted file]
qcsrc/common/net_notice.qc
qcsrc/common/notifications.qc
qcsrc/common/notifications.qh
qcsrc/common/physics.qc
qcsrc/common/physics.qh
qcsrc/common/playerstats.qc
qcsrc/common/playerstats.qh
qcsrc/common/sounds/all.inc
qcsrc/common/sounds/all.qc [new file with mode: 0644]
qcsrc/common/sounds/all.qh
qcsrc/common/sounds/sound.qh
qcsrc/common/stats.qh
qcsrc/common/triggers/func/bobbing.qc
qcsrc/common/triggers/func/breakable.qc
qcsrc/common/triggers/func/conveyor.qc
qcsrc/common/triggers/func/conveyor.qh [deleted file]
qcsrc/common/triggers/func/door.qc
qcsrc/common/triggers/func/door.qh
qcsrc/common/triggers/func/door_secret.qc
qcsrc/common/triggers/func/fourier.qc
qcsrc/common/triggers/func/include.qh
qcsrc/common/triggers/func/ladder.qc
qcsrc/common/triggers/func/ladder.qh
qcsrc/common/triggers/func/pendulum.qc
qcsrc/common/triggers/func/plat.qc
qcsrc/common/triggers/func/plat.qh [deleted file]
qcsrc/common/triggers/func/pointparticles.qc
qcsrc/common/triggers/func/pointparticles.qh [deleted file]
qcsrc/common/triggers/func/rainsnow.qc
qcsrc/common/triggers/func/rainsnow.qh [deleted file]
qcsrc/common/triggers/func/train.qc
qcsrc/common/triggers/func/train.qh
qcsrc/common/triggers/func/vectormamamam.qc
qcsrc/common/triggers/include.qh
qcsrc/common/triggers/misc/corner.qc
qcsrc/common/triggers/misc/corner.qh [deleted file]
qcsrc/common/triggers/misc/include.qc
qcsrc/common/triggers/misc/include.qh [deleted file]
qcsrc/common/triggers/misc/laser.qc
qcsrc/common/triggers/misc/laser.qh [deleted file]
qcsrc/common/triggers/subs.qc
qcsrc/common/triggers/target/music.qc
qcsrc/common/triggers/target/music.qh
qcsrc/common/triggers/teleporters.qc
qcsrc/common/triggers/teleporters.qh
qcsrc/common/triggers/trigger/impulse.qc
qcsrc/common/triggers/trigger/impulse.qh
qcsrc/common/triggers/trigger/jumppads.qc
qcsrc/common/triggers/trigger/jumppads.qh
qcsrc/common/triggers/trigger/keylock.qc
qcsrc/common/triggers/trigger/keylock.qh
qcsrc/common/triggers/trigger/multi.qc
qcsrc/common/triggers/trigger/swamp.qc
qcsrc/common/triggers/trigger/swamp.qh
qcsrc/common/triggers/trigger/teleport.qc
qcsrc/common/triggers/trigger/viewloc.qc
qcsrc/common/triggers/trigger/viewloc.qh
qcsrc/common/triggers/triggers.qc
qcsrc/common/turrets/all.qc
qcsrc/common/turrets/all.qh
qcsrc/common/turrets/cl_turrets.qc
qcsrc/common/turrets/cl_turrets.qh [deleted file]
qcsrc/common/turrets/config.qc
qcsrc/common/turrets/config.qh
qcsrc/common/turrets/sv_turrets.qc
qcsrc/common/turrets/turret.qh
qcsrc/common/turrets/turret/ewheel_weapon.qc
qcsrc/common/turrets/turret/flac_weapon.qc
qcsrc/common/turrets/turret/fusionreactor.qc
qcsrc/common/turrets/turret/hellion_weapon.qc
qcsrc/common/turrets/turret/hk_weapon.qc
qcsrc/common/turrets/turret/machinegun_weapon.qc
qcsrc/common/turrets/turret/mlrs_weapon.qc
qcsrc/common/turrets/turret/phaser_weapon.qc
qcsrc/common/turrets/turret/plasma.qc
qcsrc/common/turrets/turret/plasma_dual.qc
qcsrc/common/turrets/turret/plasma_weapon.qc
qcsrc/common/turrets/turret/tesla.qc
qcsrc/common/turrets/turret/tesla_weapon.qc
qcsrc/common/turrets/turret/walker.qc
qcsrc/common/turrets/turret/walker_weapon.qc
qcsrc/common/turrets/util.qc
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/common/vehicles/all.qc
qcsrc/common/vehicles/all.qh
qcsrc/common/vehicles/cl_vehicles.qc
qcsrc/common/vehicles/cl_vehicles.qh
qcsrc/common/vehicles/sv_vehicles.qc
qcsrc/common/vehicles/vehicle/bumblebee.qc
qcsrc/common/vehicles/vehicle/bumblebee.qh
qcsrc/common/vehicles/vehicle/bumblebee_weapons.qc
qcsrc/common/vehicles/vehicle/racer.qc
qcsrc/common/vehicles/vehicle/racer_weapon.qc
qcsrc/common/vehicles/vehicle/raptor.qc
qcsrc/common/vehicles/vehicle/raptor_weapons.qc
qcsrc/common/vehicles/vehicle/spiderbot.qc
qcsrc/common/vehicles/vehicle/spiderbot_weapons.qc
qcsrc/common/weapons/all.inc
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/all.qh
qcsrc/common/weapons/config.qc
qcsrc/common/weapons/config.qh
qcsrc/common/weapons/weapon.qh
qcsrc/common/weapons/weapon/arc.qc
qcsrc/common/weapons/weapon/blaster.qc
qcsrc/common/weapons/weapon/crylink.qc
qcsrc/common/weapons/weapon/devastator.qc
qcsrc/common/weapons/weapon/electro.qc
qcsrc/common/weapons/weapon/fireball.qc
qcsrc/common/weapons/weapon/hagar.qc
qcsrc/common/weapons/weapon/hlac.qc
qcsrc/common/weapons/weapon/hmg.qc [deleted file]
qcsrc/common/weapons/weapon/hook.qc
qcsrc/common/weapons/weapon/machinegun.qc
qcsrc/common/weapons/weapon/minelayer.qc
qcsrc/common/weapons/weapon/mortar.qc
qcsrc/common/weapons/weapon/porto.qc
qcsrc/common/weapons/weapon/rifle.qc
qcsrc/common/weapons/weapon/rpc.qc [deleted file]
qcsrc/common/weapons/weapon/seeker.qc
qcsrc/common/weapons/weapon/shockwave.qc
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/common/weapons/weapon/tuba.qc
qcsrc/common/weapons/weapon/vaporizer.qc
qcsrc/common/weapons/weapon/vortex.qc
qcsrc/dpdefs/csprogsdefs.qh
qcsrc/dpdefs/dpextensions.qh
qcsrc/dpdefs/progsdefs.qh
qcsrc/lib/_all.inc
qcsrc/lib/accumulate.qh
qcsrc/lib/bits.qh
qcsrc/lib/bool.qh
qcsrc/lib/color.qh
qcsrc/lib/compiler.qh
qcsrc/lib/counting.qh
qcsrc/lib/csqcmodel/cl_model.qc
qcsrc/lib/csqcmodel/cl_model.qh
qcsrc/lib/csqcmodel/cl_player.qc
qcsrc/lib/csqcmodel/common.qh
qcsrc/lib/csqcmodel/sv_model.qc
qcsrc/lib/cvar.qh
qcsrc/lib/defer.qh
qcsrc/lib/draw.qh
qcsrc/lib/file.qh
qcsrc/lib/functional.qh
qcsrc/lib/i18n.qh
qcsrc/lib/int.qh
qcsrc/lib/iter.qh
qcsrc/lib/lazy.qh
qcsrc/lib/linkedlist.qh
qcsrc/lib/log.qh
qcsrc/lib/map.qc [new file with mode: 0644]
qcsrc/lib/math.qh
qcsrc/lib/misc.qh
qcsrc/lib/net.qh
qcsrc/lib/nil.qh
qcsrc/lib/noise.qc
qcsrc/lib/oo.qh
qcsrc/lib/p2mathlib.qc
qcsrc/lib/p2mathlib.qh
qcsrc/lib/player.qh
qcsrc/lib/progname.qh
qcsrc/lib/random.qc
qcsrc/lib/random.qh
qcsrc/lib/registry.qh
qcsrc/lib/registry_net.qh [new file with mode: 0644]
qcsrc/lib/replicate.qh
qcsrc/lib/self.qh
qcsrc/lib/sort.qh
qcsrc/lib/sortlist.qc
qcsrc/lib/sortlist.qh
qcsrc/lib/spawnfunc.qh
qcsrc/lib/static.qh
qcsrc/lib/stats.qh [new file with mode: 0644]
qcsrc/lib/string.qh
qcsrc/lib/struct.qh
qcsrc/lib/test.qc
qcsrc/lib/test.qh
qcsrc/lib/urllib.qc
qcsrc/lib/urllib.qh
qcsrc/lib/vector.qh
qcsrc/lib/warpzone/client.qc
qcsrc/lib/warpzone/client.qh
qcsrc/lib/warpzone/common.qc
qcsrc/lib/warpzone/mathlib.qc
qcsrc/lib/warpzone/mathlib.qh
qcsrc/lib/warpzone/server.qc
qcsrc/lib/warpzone/server.qh
qcsrc/menu/anim/animation.qc
qcsrc/menu/anim/animhost.qc
qcsrc/menu/anim/easing.qc
qcsrc/menu/anim/keyframe.qc
qcsrc/menu/classes.qc [new file with mode: 0644]
qcsrc/menu/command/menu_cmd.qc
qcsrc/menu/draw.qc
qcsrc/menu/draw.qh
qcsrc/menu/gamesettings.qh
qcsrc/menu/item.qc
qcsrc/menu/item/borderimage.qc
qcsrc/menu/item/button.qc
qcsrc/menu/item/checkbox.qc
qcsrc/menu/item/container.qc
qcsrc/menu/item/dialog.qc
qcsrc/menu/item/image.qc
qcsrc/menu/item/inputbox.qc
qcsrc/menu/item/inputcontainer.qc
qcsrc/menu/item/label.qc
qcsrc/menu/item/listbox.qc
qcsrc/menu/item/modalcontroller.qc
qcsrc/menu/item/nexposee.qc
qcsrc/menu/item/radiobutton.qc
qcsrc/menu/item/slider.qc
qcsrc/menu/item/tab.qc
qcsrc/menu/item/textslider.qc
qcsrc/menu/menu.qc
qcsrc/menu/menu.qh
qcsrc/menu/mutators/events.qh [new file with mode: 0644]
qcsrc/menu/oo/classes.qc [deleted file]
qcsrc/menu/progs.inc
qcsrc/menu/sys-post.qh [deleted file]
qcsrc/menu/sys-pre.qh [deleted file]
qcsrc/menu/xonotic/crosshairpicker.qc
qcsrc/menu/xonotic/datasource.qc
qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc
qcsrc/menu/xonotic/dialog_settings_game.qc
qcsrc/menu/xonotic/gametypelist.qc
qcsrc/menu/xonotic/languagelist.qc
qcsrc/menu/xonotic/serverlist.qc
qcsrc/menu/xonotic/util.qc
qcsrc/menu/xonotic/util.qh
qcsrc/menu/xonotic/weaponslist.qc
qcsrc/server/_all.qh
qcsrc/server/autocvars.qh
qcsrc/server/bot/aim.qc
qcsrc/server/bot/bot.qc
qcsrc/server/bot/bot.qh
qcsrc/server/bot/havocbot/havocbot.qc
qcsrc/server/bot/scripting.qc
qcsrc/server/bot/waypoints.qc
qcsrc/server/cheats.qc
qcsrc/server/cl_client.qc
qcsrc/server/cl_impulse.qc
qcsrc/server/cl_impulse.qh
qcsrc/server/cl_player.qc
qcsrc/server/cl_player.qh
qcsrc/server/command/banning.qc
qcsrc/server/command/banning.qh
qcsrc/server/command/cmd.qc
qcsrc/server/command/common.qc
qcsrc/server/command/common.qh
qcsrc/server/command/getreplies.qc
qcsrc/server/command/getreplies.qh
qcsrc/server/command/radarmap.qc
qcsrc/server/command/sv_cmd.qc
qcsrc/server/command/sv_cmd.qh
qcsrc/server/command/vote.qc
qcsrc/server/command/vote.qh
qcsrc/server/constants.qh
qcsrc/server/controlpoint.qc [deleted file]
qcsrc/server/controlpoint.qh [deleted file]
qcsrc/server/csqceffects.qc [deleted file]
qcsrc/server/csqceffects.qh [deleted file]
qcsrc/server/defs.qh
qcsrc/server/ent_cs.qc
qcsrc/server/g_damage.qc
qcsrc/server/g_hook.qc
qcsrc/server/g_models.qc
qcsrc/server/g_subs.qc
qcsrc/server/g_subs.qh
qcsrc/server/g_violence.qc [deleted file]
qcsrc/server/g_violence.qh [deleted file]
qcsrc/server/g_world.qc
qcsrc/server/generator.qc [deleted file]
qcsrc/server/generator.qh [deleted file]
qcsrc/server/ipban.qc
qcsrc/server/item_key.qc
qcsrc/server/mapvoting.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/miscfunctions.qh
qcsrc/server/mutators/all.inc
qcsrc/server/mutators/all.qc
qcsrc/server/mutators/events.qh
qcsrc/server/mutators/mutator/gamemode_ca.qc
qcsrc/server/mutators/mutator/gamemode_ctf.qc
qcsrc/server/mutators/mutator/gamemode_cts.qc
qcsrc/server/mutators/mutator/gamemode_deathmatch.qc
qcsrc/server/mutators/mutator/gamemode_domination.qc
qcsrc/server/mutators/mutator/gamemode_freezetag.qc
qcsrc/server/mutators/mutator/gamemode_invasion.qc
qcsrc/server/mutators/mutator/gamemode_keepaway.qc
qcsrc/server/mutators/mutator/gamemode_keyhunt.qc
qcsrc/server/mutators/mutator/gamemode_lms.qc
qcsrc/server/mutators/mutator/gamemode_onslaught.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_race.qc
qcsrc/server/mutators/mutator/gamemode_tdm.qc
qcsrc/server/mutators/mutator/mutator_bloodloss.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_breakablehook.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_buffs.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_campcheck.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_dodging.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_hook.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_invincibleproj.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_melee_only.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_midair.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_multijump.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_nades.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_new_toys.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_nix.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_overkill.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_physical_items.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_pinata.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_random_gravity.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_rocketflying.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_rocketminsta.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_spawn_near_teammate.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_superspec.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_touchexplode.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_vampire.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_vampirehook.qc [deleted file]
qcsrc/server/mutators/mutator/mutator_weaponarena_random.qc [deleted file]
qcsrc/server/mutators/mutator/sandbox.qc [deleted file]
qcsrc/server/pathlib/main.qc
qcsrc/server/portals.qc
qcsrc/server/progs.inc
qcsrc/server/race.qc
qcsrc/server/round_handler.qc
qcsrc/server/scores.qc
qcsrc/server/scores_rules.qc
qcsrc/server/spawnpoints.qc
qcsrc/server/steerlib.qc
qcsrc/server/sv_main.qc
qcsrc/server/t_items.qc
qcsrc/server/t_items.qh
qcsrc/server/t_quake3.qc
qcsrc/server/teamplay.qc
qcsrc/server/teamplay.qh
qcsrc/server/weapons/accuracy.qc
qcsrc/server/weapons/accuracy.qh
qcsrc/server/weapons/common.qc
qcsrc/server/weapons/csqcprojectile.qc
qcsrc/server/weapons/selection.qc
qcsrc/server/weapons/selection.qh
qcsrc/server/weapons/spawning.qc
qcsrc/server/weapons/spawning.qh
qcsrc/server/weapons/throwing.qc
qcsrc/server/weapons/tracing.qc
qcsrc/server/weapons/tracing.qh
qcsrc/server/weapons/weaponsystem.qc
qcsrc/server/weapons/weaponsystem.qh
qcsrc/uncrustify.cfg
qcsrc/uncrustify.sh
quickmenu_example.txt [new file with mode: 0644]

index facee4a7bc8fc4d49fe5d2f2089ed56d4c227037..a7406532d8d61829e952a19d91ccc5ccb0e28494 100755 (executable)
@@ -36,7 +36,8 @@ fi
 
 if [ x"$mode" = x"txt" ]; then
        {
-               echo "en English \"English\""
+               item=`grep "^en " languages.txt`
+               echo "$item"
                for X in common.*.po; do
                        [ -f "$X" ] || continue
                        if [ -n "$language" ]; then
@@ -67,9 +68,9 @@ if [ x"$mode" = x"txt" ]; then
                                if [ "$p" -lt 50 ]; then
                                        continue
                                fi
-                               item="$l $l \"$l (0%)\""
+                               item="$l $l \"$l\" 0%"
                        fi
-                       printf "%s\n" "$item" | sed -e "s/([0-9][0-9]*%)/($p%)/"
+                       printf "%s\n" "$item" | sed -e "s/[0-9][0-9]*%/$p%/"
                done
        } | tr '"' '\t' | sort -k3 | tr '\t' '"'
 fi
index a43c6cff46fa58a65421361b1356a0ded506dc95..9f0d1743b14bdfc98382aee4fdf9d7c5bfbeced8 100644 (file)
@@ -1,19 +1,19 @@
-ast Asturian "Asturianu (60%)"
-de German "Deutsch (90%)"
-de_CH German "Deutsch (Schweiz) (90%)"
-en_AU en_AU "en_AU (77%)"
-en English "English"
-es Spanish "Español (68%)"
-fr French "Français (98%)"
-it Italian "Italiano (97%)"
-hu Hungarian "Magyar (50%)"
-nl Dutch "Nederlands (45%)"
-pl Polish "Polski (60%)"
-pt Portuguese "Português (42%)"
-ro Romanian "Romana (90%)"
-fi Finnish "Suomi (35%)"
-el Greek "Ελληνική (25%)"
-be Belarusian "Беларуская (65%)"
-bg Bulgarian "Български (65%)"
-ru Russian "Русский (93%)"
-uk Ukrainian "Українська (60%)"
+ast   Asturian "Asturianu" 60%
+de    German "Deutsch" 90%
+de_CH German "Deutsch (Schweiz)" 90%
+en    English "English"
+en_AU English "English (Australia)" 77%
+es    Spanish "Español" 68%
+fr    French "Français" 98%
+it    Italian "Italiano" 97%
+hu    Hungarian "Magyar" 50%
+nl    Dutch "Nederlands" 45%
+pl    Polish "Polski" 60%
+pt    Portuguese "Português" 42%
+ro    Romanian "Romana" 90%
+fi    Finnish "Suomi" 35%
+el    Greek "Ελληνική" 25%
+be    Belarusian "Беларуская" 65%
+bg    Bulgarian "Български" 65%
+ru    Russian "Русский" 93%
+uk    Ukrainian "Українська" 60%
\ No newline at end of file
index e20557fa741300f05bb7dfd5027a7832f5b70638..fa8f2b0055b51395ed0248ae4129cc1e741d55fa 100644 (file)
@@ -1,14 +1,24 @@
 #include "announcer.qh"
 
+#include "mutators/events.qh"
+
 #include "../common/notifications.qh"
 #include "../common/stats.qh"
 
 bool announcer_1min;
 bool announcer_5min;
+string AnnouncerOption()
+{
+       string ret = autocvar_cl_announcer;
+       MUTATOR_CALLHOOK(AnnouncerOption, ret);
+       ret = ret_string;
+       return ret;
+}
+
 void Announcer_Countdown()
 {
        SELFPARAM();
-       float starttime = getstatf(STAT_GAMESTARTTIME);
+       float starttime = STAT(GAMESTARTTIME);
        float roundstarttime = getstatf(STAT_ROUNDSTARTTIME);
        if(roundstarttime == -1)
        {
@@ -59,7 +69,7 @@ void Announcer_Countdown()
  float previous_game_starttime;
 void Announcer_Gamestart()
 {
-       float startTime = getstatf(STAT_GAMESTARTTIME);
+       float startTime = STAT(GAMESTARTTIME);
        float roundstarttime = getstatf(STAT_ROUNDSTARTTIME);
        if(roundstarttime > startTime)
                startTime = roundstarttime;
@@ -68,19 +78,18 @@ void Announcer_Gamestart()
        {
                if(time < startTime)
                {
-                       entity e = find(world, classname, "announcer_countdown");
-                       if (!e)
+                       static entity announcer_countdown;
+                       if (!announcer_countdown)
                        {
-                               e = spawn();
-                               e.classname = "announcer_countdown";
-                               e.think = Announcer_Countdown;
+                               announcer_countdown = new(announcer_countdown);
+                               announcer_countdown.think = Announcer_Countdown;
                        }
 
                        if(time + 5.0 < startTime) // if connecting to server while restart was active don't always play prepareforbattle
-                       if(time > e.nextthink) // don't play it again if countdown was already going
+                       if(time > announcer_countdown.nextthink) // don't play it again if countdown was already going
                                Local_Notification(MSG_ANNCE, ANNCE_PREPARE);
 
-                       e.nextthink = startTime - floor(startTime - time); //synchronize nextthink to startTime
+                       announcer_countdown.nextthink = startTime - floor(startTime - time); //synchronize nextthink to startTime
                }
        }
 
@@ -92,12 +101,12 @@ void Announcer_Gamestart()
 void Announcer_Time()
 {
        float timelimit = getstatf(STAT_TIMELIMIT);
-       float timeleft = max(0, timelimit * 60 + getstatf(STAT_GAMESTARTTIME) - time);
+       float timeleft = max(0, timelimit * 60 + STAT(GAMESTARTTIME) - time);
        float warmup_timeleft = 0;
 
        if(warmup_stage)
                if(autocvar_g_warmup_limit > 0)
-                       warmup_timeleft = max(0, autocvar_g_warmup_limit + getstatf(STAT_GAMESTARTTIME) - time);
+                       warmup_timeleft = max(0, autocvar_g_warmup_limit + STAT(GAMESTARTTIME) - time);
 
        // 5 minute check
        if(autocvar_cl_announcer_maptime >= 2)
index 64be1433af70bd80d6c0450a8b497c98a0a34205..314c6602d8dd8871051557bcd3a2b52593b0635f 100644 (file)
@@ -3,4 +3,6 @@
 
 void Announcer();
 
+string AnnouncerOption();
+
 #endif
index bed70f57fcb2eb6370d084be5719eb2d2d67068f..63e0c56126f7394c8ffd8eacbab9a9d194a229c6 100644 (file)
@@ -8,8 +8,7 @@
 
 #include "../autocvars.qh"
 #include "../defs.qh"
-#include "../hud.qh"
-#include "../hud_config.qh"
+#include "../hud/all.qh"
 #include "../main.qh"
 #include "../mapvoting.qh"
 #include "../miscfunctions.qh"
@@ -22,7 +21,7 @@
 
 void DrawDebugModel(entity this)
 {
-       if(time - floor(time) > 0.5)
+       if (time - floor(time) > 0.5)
        {
                PolyDrawModel(self);
                self.drawmask = 0;
@@ -45,7 +44,7 @@ void LocalCommand_blurtest(int request)
        // Anyway, to enable it, just compile the client with -DBLURTEST and then you can use the command.
 
        #ifdef BLURTEST
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -66,7 +65,7 @@ void LocalCommand_blurtest(int request)
                }
        }
        #else
-       if(request)
+       if (request)
        {
                LOG_INFO("Blurtest is not enabled on this client.\n");
                return;
@@ -76,7 +75,7 @@ void LocalCommand_blurtest(int request)
 
 void LocalCommand_boxparticles(int request, int argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -87,7 +86,7 @@ void LocalCommand_boxparticles(int request, int argc)
                                {
                                        int index = stoi(argv(2));
                                        entity own;
-                                       if(index <= 0)
+                                       if (index <= 0)
                                                own = entitybyindex(-index);
                                        else
                                                own = findfloat(world, entnum, index);
@@ -104,7 +103,9 @@ void LocalCommand_boxparticles(int request, int argc)
                }
 
                default:
+               {
                        LOG_INFO("Incorrect parameters for ^2boxparticles^7\n");
+               }
                case CMD_REQUEST_USAGE:
                {
                        LOG_INFO("\nUsage:^3 lv_cmd boxparticles effectname own org_from org_to, dir_from, dir_to, countmultiplier, flags\n");
@@ -127,14 +128,14 @@ void LocalCommand_boxparticles(int request, int argc)
 
 void LocalCommand_create_scrshot_ent(int request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        string filename = strcat(MapInfo_Map_bspname, "_scrshot_ent.txt");
                        int fh = fopen(filename, FILE_WRITE);
 
-                       if(fh >= 0)
+                       if (fh >= 0)
                        {
                                fputs(fh, "{\n");
                                fputs(fh, strcat("\"classname\" \"info_autoscreenshot\"\n"));
@@ -165,20 +166,18 @@ void LocalCommand_create_scrshot_ent(int request)
 
 void LocalCommand_debugmodel(int request, int argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        string modelname = argv(1);
-                       entity debugmodel_entity;
 
-                       debugmodel_entity = spawn();
+                       entity debugmodel_entity = new(debugmodel);
                        precache_model(modelname);
                        _setmodel(debugmodel_entity, modelname);
                        setorigin(debugmodel_entity, view_origin);
                        debugmodel_entity.angles = view_angles;
                        debugmodel_entity.draw = DrawDebugModel;
-                       debugmodel_entity.classname = "debugmodel";
 
                        return;
                }
@@ -195,14 +194,14 @@ void LocalCommand_debugmodel(int request, int argc)
 
 void LocalCommand_handlevote(int request, int argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        int vote_selection;
                        string vote_string;
 
-                       if(InterpretBoolean(argv(1)))
+                       if (InterpretBoolean(argv(1)))
                        {
                                vote_selection = 2;
                                vote_string = "yes";
@@ -213,9 +212,9 @@ void LocalCommand_handlevote(int request, int argc)
                                vote_string = "no";
                        }
 
-                       if(vote_selection)
+                       if (vote_selection)
                        {
-                               if(uid2name_dialog) // handled by "uid2name" option
+                               if (uid2name_dialog)  // handled by "uid2name" option
                                {
                                        vote_active = 0;
                                        vote_prev = 0;
@@ -230,7 +229,9 @@ void LocalCommand_handlevote(int request, int argc)
                }
 
                default:
+               {
                        LOG_INFO("Incorrect parameters for ^2handlevote^7\n");
+               }
                case CMD_REQUEST_USAGE:
                {
                        LOG_INFO("\nUsage:^3 cl_cmd handlevote vote\n");
@@ -252,11 +253,11 @@ void HUD_Radar_Show_Maximized(bool doshow, bool clickable);
 
 void LocalCommand_hud(int request, int argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       switch(argv(1))
+                       switch (argv(1))
                        {
                                case "configure":
                                {
@@ -266,16 +267,23 @@ void LocalCommand_hud(int request, int argc)
 
                                case "quickmenu":
                                {
-                                       if(QuickMenu_IsOpened())
+                                       if (argv(2) == "help")
+                                       {
+                                               LOG_INFO(" quickmenu [[default | file | \"\"] submenu]\n");
+                                               LOG_INFO("Called without options (or with \"\") loads either the default quickmenu or a quickmenu file if hud_panel_quickmenu_file is set to a valid filename.\n");
+                                               LOG_INFO("A submenu name can be given to open the quickmenu directly in a submenu; it requires to specify 'default', 'file' or '\"\"' option.\n");
+                                               return;
+                                       }
+                                       if (QuickMenu_IsOpened())
                                                QuickMenu_Close();
                                        else
-                                               QuickMenu_Open(argv(2), argv(3)); // mode, submenu
+                                               QuickMenu_Open(argv(2), argv(3));  // mode, submenu
                                        return;
                                }
 
                                case "minigame":
                                {
-                                       if(HUD_MinigameMenu_IsOpened())
+                                       if (HUD_MinigameMenu_IsOpened())
                                                HUD_MinigameMenu_Close();
                                        else
                                                HUD_MinigameMenu_Open();
@@ -284,14 +292,14 @@ void LocalCommand_hud(int request, int argc)
 
                                case "save":
                                {
-                                       if(argv(2))
+                                       if (argv(2))
                                        {
                                                HUD_Panel_ExportCfg(argv(2));
                                                return;
                                        }
                                        else
                                        {
-                                               break; // go to usage, we're missing the paramater needed here.
+                                               break;  // go to usage, we're missing the paramater needed here.
                                        }
                                }
 
@@ -309,23 +317,25 @@ void LocalCommand_hud(int request, int argc)
 
                                case "radar":
                                {
-                                       if(argv(2))
-                                               HUD_Radar_Show_Maximized(InterpretBoolean(argv(2)),0);
+                                       if (argv(2))
+                                               HUD_Radar_Show_Maximized(InterpretBoolean(argv(2)), 0);
                                        else
-                                               HUD_Radar_Show_Maximized(!hud_panel_radar_maximized,0);
+                                               HUD_Radar_Show_Maximized(!hud_panel_radar_maximized, 0);
                                        return;
                                }
 
                                case "clickradar":
                                {
-                                       HUD_Radar_Show_Maximized(!hud_panel_radar_mouse,1);
+                                       HUD_Radar_Show_Maximized(!hud_panel_radar_mouse, 1);
                                        return;
                                }
                        }
                }
 
                default:
+               {
                        LOG_INFO("Incorrect parameters for ^2hud^7\n");
+               }
                case CMD_REQUEST_USAGE:
                {
                        LOG_INFO("\nUsage:^3 cl_cmd hud action [configname | radartoggle | layout]\n");
@@ -333,10 +343,7 @@ void LocalCommand_hud(int request, int argc)
                        LOG_INFO("  'configname' is the name to save to for \"save\" action,\n");
                        LOG_INFO("  'radartoggle' is to control hud_panel_radar_maximized for \"radar\" action,\n");
                        LOG_INFO("  and 'layout' is how to organize the scoreboard columns for the set action.\n");
-                       LOG_INFO("  quickmenu [[default | file | \"\"] submenu]\n");
-                       LOG_INFO("    Called without options (or with "") loads either the default quickmenu or a quickmenu file if hud_panel_quickmenu_file is set to a valid filename.\n");
-                       LOG_INFO("    Submenu option allows to open quickmenu directly in a submenu, it requires to specify 'default', 'file' or '\"\"' option.\n");
-                       LOG_INFO("  Full list of commands here: \"configure, minigame, save, scoreboard_columns_help, scoreboard_columns_set, radar.\"\n");
+                       LOG_INFO("  Full list of commands here: \"configure, quickmenu, minigame, save, scoreboard_columns_help, scoreboard_columns_set, radar.\"\n");
                        return;
                }
        }
@@ -344,11 +351,11 @@ void LocalCommand_hud(int request, int argc)
 
 void LocalCommand_localprint(int request, int argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1))
+                       if (argv(1))
                        {
                                centerprint_hud(argv(1));
                                return;
@@ -356,7 +363,9 @@ void LocalCommand_localprint(int request, int argc)
                }
 
                default:
+               {
                        LOG_INFO("Incorrect parameters for ^2localprint^7\n");
+               }
                case CMD_REQUEST_USAGE:
                {
                        LOG_INFO("\nUsage:^3 cl_cmd localprint \"message\"\n");
@@ -368,11 +377,11 @@ void LocalCommand_localprint(int request, int argc)
 
 void LocalCommand_mv_download(int request, int argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1))
+                       if (argv(1))
                        {
                                Cmd_MapVote_MapDownload(argc);
                                return;
@@ -380,7 +389,9 @@ void LocalCommand_mv_download(int request, int argc)
                }
 
                default:
+               {
                        LOG_INFO("Incorrect parameters for ^2mv_download^7\n");
+               }
                case CMD_REQUEST_USAGE:
                {
                        LOG_INFO("\nUsage:^3 cl_cmd mv_download mapid\n");
@@ -392,20 +403,22 @@ void LocalCommand_mv_download(int request, int argc)
 
 void LocalCommand_find(int request, int argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        entity client;
 
-                       for(client = world; (client = find(client, classname, argv(1))); )
+                       for (client = world; (client = find(client, classname, argv(1))); )
                                LOG_INFO(etos(client), "\n");
 
                        return;
                }
 
                default:
+               {
                        LOG_INFO("Incorrect parameters for ^2find^7\n");
+               }
                case CMD_REQUEST_USAGE:
                {
                        LOG_INFO("\nUsage:^3 cl_cmd find classname\n");
@@ -417,19 +430,19 @@ void LocalCommand_find(int request, int argc)
 
 void LocalCommand_sendcvar(int request, int argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1))
+                       if (argv(1))
                        {
                                // W_FixWeaponOrder will trash argv, so save what we need.
                                string thiscvar = strzone(argv(1));
                                string s = cvar_string(thiscvar);
 
-                               if(thiscvar == "cl_weaponpriority")
+                               if (thiscvar == "cl_weaponpriority")
                                        s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 1);
-                               else if(substring(thiscvar, 0, 17) == "cl_weaponpriority" && strlen(thiscvar) == 18)
+                               else if (substring(thiscvar, 0, 17) == "cl_weaponpriority" && strlen(thiscvar) == 18)
                                        s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 0);
 
                                localcmd("cmd sentcvar ", thiscvar, " \"", s, "\"\n");
@@ -439,7 +452,9 @@ void LocalCommand_sendcvar(int request, int argc)
                }
 
                default:
+               {
                        LOG_INFO("Incorrect parameters for ^2sendcvar^7\n");
+               }
                case CMD_REQUEST_USAGE:
                {
                        LOG_INFO("\nUsage:^3 cl_cmd sendcvar <cvar>\n");
@@ -453,22 +468,22 @@ void LocalCommand_sendcvar(int request, int argc)
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
 void LocalCommand_(int request)
 {
-       switch(request)
-       {
-               case CMD_REQUEST_COMMAND:
-               {
-
-                       return;
-               }
-
-               default:
-               case CMD_REQUEST_USAGE:
-               {
-                       print("\nUsage:^3 cl_cmd \n");
-                       print("  No arguments required.\n");
-                       return;
-               }
-       }
+    switch(request)
+    {
+        case CMD_REQUEST_COMMAND:
+        {
+
+            return;
+        }
+
+        default:
+        case CMD_REQUEST_USAGE:
+        {
+            print("\nUsage:^3 cl_cmd \n");
+            print("  No arguments required.\n");
+            return;
+        }
+    }
 }
 */
 
@@ -478,7 +493,7 @@ void LocalCommand_(int request)
 // ==================================
 
 // Normally do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define CLIENT_COMMANDS(request,arguments) \
+#define CLIENT_COMMANDS(request, arguments) \
        CLIENT_COMMAND("blurtest", LocalCommand_blurtest(request), "Feature for testing blur postprocessing") \
        CLIENT_COMMAND("boxparticles", LocalCommand_boxparticles(request, arguments), "Spawn particles manually") \
        CLIENT_COMMAND("create_scrshot_ent", LocalCommand_create_scrshot_ent(request), "Create an entity at this location for automatic screenshots") \
@@ -493,19 +508,17 @@ void LocalCommand_(int request)
 
 void LocalCommand_macro_help()
 {
-       #define CLIENT_COMMAND(name,function,description) \
-               { if(strtolower(description) != "") { LOG_INFO("  ^2", name, "^7: ", description, "\n"); } }
+       #define CLIENT_COMMAND(name, function, description) \
+               { if (strtolower(description) != "") { LOG_INFO("  ^2", name, "^7: ", description, "\n"); } }
 
        CLIENT_COMMANDS(0, 0);
        #undef CLIENT_COMMAND
-
-       return;
 }
 
 bool LocalCommand_macro_command(int argc)
 {
-       #define CLIENT_COMMAND(name,function,description) \
-               { if(name == strtolower(argv(0))) { function; return true; } }
+       #define CLIENT_COMMAND(name, function, description) \
+               { if (name == strtolower(argv(0))) { function; return true; } }
 
        CLIENT_COMMANDS(CMD_REQUEST_COMMAND, argc);
        #undef CLIENT_COMMAND
@@ -515,8 +528,8 @@ bool LocalCommand_macro_command(int argc)
 
 bool LocalCommand_macro_usage(int argc)
 {
-       #define CLIENT_COMMAND(name,function,description) \
-               { if(name == strtolower(argv(1))) { function; return true; } }
+       #define CLIENT_COMMAND(name, function, description) \
+               { if (name == strtolower(argv(1))) { function; return true; } }
 
        CLIENT_COMMANDS(CMD_REQUEST_USAGE, argc);
        #undef CLIENT_COMMAND
@@ -526,13 +539,11 @@ bool LocalCommand_macro_usage(int argc)
 
 void LocalCommand_macro_write_aliases(int fh)
 {
-       #define CLIENT_COMMAND(name,function,description) \
-               { if(strtolower(description) != "") { CMD_Write_Alias("qc_cmd_cl", name, description); } }
+       #define CLIENT_COMMAND(name, function, description) \
+               { if (strtolower(description) != "") { CMD_Write_Alias("qc_cmd_cl", name, description); } }
 
        CLIENT_COMMANDS(0, 0);
        #undef CLIENT_COMMAND
-
-       return;
 }
 
 
@@ -552,7 +563,7 @@ void GameCommand(string command)
        string s = strtolower(argv(0));
        if (s == "help")
        {
-               if(argc == 1)
+               if (argc == 1)
                {
                        LOG_INFO("\nClient console commands:\n");
                        LocalCommand_macro_help();
@@ -565,25 +576,23 @@ void GameCommand(string command)
 
                        return;
                }
-               else if(GenericCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
+               else if (GenericCommand_macro_usage(argc))  // Instead of trying to call a command, we're going to see detailed information about it
                {
                        return;
                }
-               else if(LocalCommand_macro_usage(argc)) // now try for normal commands too
+               else if (LocalCommand_macro_usage(argc))  // now try for normal commands too
                {
                        return;
                }
        }
        // continue as usual and scan for normal commands
-       if (GenericCommand(command)// handled by common/command/generic.qc
-       || LocalCommand_macro_command(argc) // handled by one of the above LocalCommand_* functions
-       || MUTATOR_CALLHOOK(CSQC_ConsoleCommand, s, argc, command) // handled by a mutator
-       ) return;
+       if (GenericCommand(command)                                    // handled by common/command/generic.qc
+           || LocalCommand_macro_command(argc)                        // handled by one of the above LocalCommand_* functions
+           || MUTATOR_CALLHOOK(CSQC_ConsoleCommand, s, argc, command) // handled by a mutator
+          ) return;
 
        // nothing above caught the command, must be invalid
        LOG_INFO(((command != "") ? strcat("Unknown client command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try cl_cmd help.\n");
-
-       return;
 }
 
 
@@ -622,7 +631,7 @@ void GameCommand(string command)
 void ConsoleCommand_macro_init()
 {
        // first init normal commands
-       #define CONSOLE_COMMAND(name,execution) \
+       #define CONSOLE_COMMAND(name, execution) \
                { registercommand(name); }
 
        CONSOLE_COMMANDS_NORMAL();
@@ -630,22 +639,22 @@ void ConsoleCommand_macro_init()
 
        // then init movement commands
        #ifndef CAMERATEST
-       if(isdemo())
+       if (isdemo())
        {
        #endif
-               #define CONSOLE_COMMAND(name,execution) \
-                       { registercommand(name); }
+       #define CONSOLE_COMMAND(name, execution) \
+               registercommand(name);
 
-               CONSOLE_COMMANDS_MOVEMENT();
+       CONSOLE_COMMANDS_MOVEMENT();
                #undef CONSOLE_COMMAND
        #ifndef CAMERATEST
-       }
+}
        #endif
 }
 
 bool ConsoleCommand_macro_normal(string s, int argc)
 {
-       #define CONSOLE_COMMAND(name,execution) \
+       #define CONSOLE_COMMAND(name, execution) \
                { if (name == s) { { execution } return true; } }
 
        CONSOLE_COMMANDS_NORMAL();
@@ -656,9 +665,9 @@ bool ConsoleCommand_macro_normal(string s, int argc)
 
 bool ConsoleCommand_macro_movement(string s, int argc)
 {
-       if(camera_active)
+       if (camera_active)
        {
-               #define CONSOLE_COMMAND(name,execution) \
+               #define CONSOLE_COMMAND(name, execution) \
                        { if (name == s) { { execution } return true; } }
 
                CONSOLE_COMMANDS_MOVEMENT();
@@ -679,7 +688,7 @@ bool CSQC_ConsoleCommand(string command)
        int argc = tokenize_console(command);
        string s = strtolower(argv(0));
        // Return value should be true if CSQC handled the command, otherwise return false to have the engine handle it.
-       return (ConsoleCommand_macro_normal(s, argc)
-       || ConsoleCommand_macro_movement(s, argc)
-       );
+       return ConsoleCommand_macro_normal(s, argc)
+              || ConsoleCommand_macro_movement(s, argc)
+       ;
 }
diff --git a/qcsrc/client/controlpoint.qc b/qcsrc/client/controlpoint.qc
deleted file mode 100644 (file)
index 575bce5..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-#include "controlpoint.qh"
-
-#include "teamradar.qh"
-#include "../common/movetypes/movetypes.qh"
-
-.vector colormod;
-.float alpha;
-.int count;
-.float pain_finished;
-
-.bool iscaptured;
-
-.vector cp_origin, cp_bob_origin;
-.float cp_bob_spd;
-
-.vector cp_bob_dmg;
-
-.vector punchangle;
-
-.float max_health;
-
-.entity icon_realmodel;
-
-void cpicon_draw(entity this)
-{
-       if(time < this.move_time) { return; }
-
-       if(this.cp_bob_dmg_z > 0)
-               this.cp_bob_dmg_z = this.cp_bob_dmg_z - 3 * frametime;
-       else
-               this.cp_bob_dmg_z = 0;
-       this.cp_bob_origin_z = 4 * PI * (1 - cos(this.cp_bob_spd));
-       this.cp_bob_spd = this.cp_bob_spd + 1.875 * frametime;
-       this.colormod = '1 1 1' * (2 - bound(0, (this.pain_finished - time) / 10, 1));
-
-       if(!this.iscaptured) this.alpha = this.health / this.max_health;
-
-       if(this.iscaptured)
-       {
-               if (this.punchangle_x > 0)
-               {
-                       this.punchangle_x = this.punchangle_x - 60 * frametime;
-                       if (this.punchangle_x < 0)
-                               this.punchangle_x = 0;
-               }
-               else if (this.punchangle_x < 0)
-               {
-                       this.punchangle_x = this.punchangle_x + 60 * frametime;
-                       if (this.punchangle_x > 0)
-                               this.punchangle_x = 0;
-               }
-
-               if (this.punchangle_y > 0)
-               {
-                       this.punchangle_y = this.punchangle_y - 60 * frametime;
-                       if (this.punchangle_y < 0)
-                               this.punchangle_y = 0;
-               }
-               else if (this.punchangle_y < 0)
-               {
-                       this.punchangle_y = this.punchangle_y + 60 * frametime;
-                       if (this.punchangle_y > 0)
-                               this.punchangle_y = 0;
-               }
-
-               if (this.punchangle_z > 0)
-               {
-                       this.punchangle_z = this.punchangle_z - 60 * frametime;
-                       if (this.punchangle_z < 0)
-                               this.punchangle_z = 0;
-               }
-               else if (this.punchangle_z < 0)
-               {
-                       this.punchangle_z = this.punchangle_z + 60 * frametime;
-                       if (this.punchangle_z > 0)
-                               this.punchangle_z = 0;
-               }
-
-               this.angles_x = this.punchangle_x;
-               this.angles_y = this.punchangle_y + this.move_angles_y;
-               this.angles_z = this.punchangle_z;
-               this.move_angles_y = this.move_angles_y + 45 * frametime;
-       }
-
-       setorigin(this, this.cp_origin + this.cp_bob_origin + this.cp_bob_dmg);
-}
-
-void cpicon_damage(entity this, float hp)
-{
-       if(!this.iscaptured) { return; }
-
-       if(hp < this.max_health * 0.25)
-               setmodel(this, MDL_ONS_CP3);
-       else if(hp < this.max_health * 0.50)
-               setmodel(this, MDL_ONS_CP2);
-       else if(hp < this.max_health * 0.75)
-               setmodel(this, MDL_ONS_CP1);
-       else if(hp <= this.max_health || hp >= this.max_health)
-               setmodel(this, MDL_ONS_CP);
-
-       this.punchangle = (2 * randomvec() - '1 1 1') * 45;
-
-       this.cp_bob_dmg_z = (2 * random() - 1) * 15;
-       this.pain_finished = time + 1;
-       this.colormod = '2 2 2';
-
-       setsize(this, CPICON_MIN, CPICON_MAX);
-}
-
-void cpicon_construct(entity this)
-{
-       this.netname = "Control Point Icon";
-
-       setmodel(this, MDL_ONS_CP);
-       setsize(this, CPICON_MIN, CPICON_MAX);
-
-       if(this.icon_realmodel == world)
-       {
-               this.icon_realmodel = spawn();
-               setmodel(this.icon_realmodel, MDL_Null);
-               setorigin(this.icon_realmodel, this.origin);
-               setsize(this.icon_realmodel, CPICON_MIN, CPICON_MAX);
-               this.icon_realmodel.movetype = MOVETYPE_NOCLIP;
-               this.icon_realmodel.solid = SOLID_NOT;
-               this.icon_realmodel.move_origin = this.icon_realmodel.origin;
-       }
-
-       if(this.iscaptured) { this.icon_realmodel.solid = SOLID_BBOX; }
-
-       this.move_movetype      = MOVETYPE_NOCLIP;
-       this.solid                      = SOLID_NOT;
-       this.movetype           = MOVETYPE_NOCLIP;
-       this.move_origin        = this.origin;
-       this.move_time          = time;
-       this.drawmask           = MASK_NORMAL;
-       this.alpha                      = 1;
-       this.draw                       = cpicon_draw;
-       this.cp_origin          = this.origin;
-       this.cp_bob_origin      = '0 0 0.1';
-       this.cp_bob_spd         = 0;
-}
-
-.vector glowmod;
-void cpicon_changeteam(entity this)
-{
-       if(this.team)
-       {
-               this.glowmod = Team_ColorRGB(this.team - 1);
-               this.teamradar_color = Team_ColorRGB(this.team - 1);
-               this.colormap = 1024 + (this.team - 1) * 17;
-       }
-       else
-       {
-               this.colormap = 1024;
-               this.glowmod = '1 1 0';
-               this.teamradar_color = '1 1 0';
-       }
-}
-
-void ent_cpicon(entity this)
-{
-       int sf = ReadByte();
-
-       if(sf & CPSF_SETUP)
-       {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
-               setorigin(this, this.origin);
-
-               this.health = ReadByte();
-               this.max_health = ReadByte();
-               this.count = ReadByte();
-               this.team = ReadByte();
-               this.iscaptured = ReadByte();
-
-               if(!this.count)
-                       this.count = (this.health - this.max_health) * frametime;
-
-               cpicon_changeteam(this);
-               cpicon_construct(this);
-       }
-
-       if(sf & CPSF_STATUS)
-       {
-               int _tmp = ReadByte();
-               if(_tmp != this.team)
-               {
-                       this.team = _tmp;
-                       cpicon_changeteam(this);
-               }
-
-               _tmp = ReadByte();
-
-               if(_tmp != this.health)
-                       cpicon_damage(this, _tmp);
-
-               this.health = _tmp;
-       }
-}
diff --git a/qcsrc/client/controlpoint.qh b/qcsrc/client/controlpoint.qh
deleted file mode 100644 (file)
index 5f2e89b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef CLIENT_CONTROLPOINT_H
-#define CLIENT_CONTROLPOINT_H
-
-const vector CPICON_MIN = '-32 -32 -9';
-const vector CPICON_MAX = '32 32 25';
-
-const int CPSF_STATUS = 4;
-const int CPSF_SETUP = 8;
-
-void ent_cpicon(entity this);
-
-#endif
index e2e0e9341ac4a0e5741a085cd69d821e7f7111a9..7eb672ba5f54d7f0045525d40442398fc6cc419e 100644 (file)
@@ -19,7 +19,7 @@ void CSQCModel_Hook_PreDraw(bool isplayer);
 .int lodmodelindex0;
 .int lodmodelindex1;
 .int lodmodelindex2;
-void CSQCPlayer_LOD_Apply(void)
+void CSQCPlayer_LOD_Apply()
 {SELFPARAM();
        // LOD model loading
        if(self.lodmodelindex0 != self.modelindex)
@@ -108,14 +108,14 @@ int forceplayermodels_goodmodelindex;
 .vector glowmod;
 .vector old_glowmod;
 
-void CSQCPlayer_ModelAppearance_PreUpdate(void)
+void CSQCPlayer_ModelAppearance_PreUpdate()
 {SELFPARAM();
        self.model = self.forceplayermodels_savemodel;
        self.modelindex = self.forceplayermodels_savemodelindex;
        self.skin = self.forceplayermodels_saveskin;
        self.colormap = self.forceplayermodels_savecolormap;
 }
-void CSQCPlayer_ModelAppearance_PostUpdate(void)
+void CSQCPlayer_ModelAppearance_PostUpdate()
 {SELFPARAM();
        self.forceplayermodels_savemodel = self.model;
        self.forceplayermodels_savemodelindex = self.modelindex;
@@ -136,8 +136,7 @@ void CSQCPlayer_ModelAppearance_Apply(bool islocalplayer)
        // which one is ALWAYS good?
        if (!forceplayermodels_goodmodel)
        {
-               entity e;
-               e = spawn();
+               entity e = spawn();
                precache_model(cvar_defstring("_cl_playermodel"));
                _setmodel(e, cvar_defstring("_cl_playermodel"));
                forceplayermodels_goodmodel = e.model;
@@ -168,8 +167,7 @@ void CSQCPlayer_ModelAppearance_Apply(bool islocalplayer)
                forceplayermodels_attempted = 1;
 
                // only if this failed, find it out on our own
-               entity e;
-               e = spawn();
+               entity e = spawn();
                _setmodel(e, autocvar__cl_playermodel); // this is harmless, see below
                forceplayermodels_modelisgoodmodel = fexists(e.model);
                forceplayermodels_model = e.model;
@@ -180,8 +178,7 @@ void CSQCPlayer_ModelAppearance_Apply(bool islocalplayer)
 
        if(autocvar_cl_forcemyplayermodel != "" && autocvar_cl_forcemyplayermodel != forceplayermodels_mymodel)
        {
-               entity e;
-               e = spawn();
+               entity e = spawn();
                _setmodel(e, autocvar_cl_forcemyplayermodel); // this is harmless, see below
                forceplayermodels_myisgoodmodel = fexists(e.model);
                forceplayermodels_mymodel = e.model;
@@ -313,7 +310,7 @@ void CSQCPlayer_ModelAppearance_Apply(bool islocalplayer)
 .int csqcmodel_framecount;
 
 #define IS_DEAD_FRAME(f) ((f) == 0 || (f) == 1)
-void CSQCPlayer_FallbackFrame_PreUpdate(void)
+void CSQCPlayer_FallbackFrame_PreUpdate()
 {SELFPARAM();
        self.frame = self.csqcmodel_saveframe;
        self.frame2 = self.csqcmodel_saveframe2;
@@ -372,7 +369,7 @@ int CSQCPlayer_FallbackFrame(int f)
        LOG_INFOF("Frame %d missing in model %s, and we have no fallback - FAIL!\n", f, self.model);
        return f;
 }
-void CSQCPlayer_FallbackFrame_Apply(void)
+void CSQCPlayer_FallbackFrame_Apply()
 {SELFPARAM();
        self.frame = CSQCPlayer_FallbackFrame(self.frame);
        self.frame2 = CSQCPlayer_FallbackFrame(self.frame2);
@@ -386,7 +383,7 @@ void CSQCPlayer_FallbackFrame_Apply(void)
 .entity tag_entity;
 .int tag_entity_lastmodelindex;
 .int tag_index;
-void CSQCModel_AutoTagIndex_Apply(void)
+void CSQCModel_AutoTagIndex_Apply()
 {SELFPARAM();
        if(self.tag_entity && wasfreed(self.tag_entity))
                self.tag_entity = world;
@@ -481,14 +478,14 @@ const int MF_TRACER3 = BIT(7); // purple trail
 .int csqcmodel_effects;
 .int csqcmodel_modelflags;
 .int csqcmodel_traileffect;
-void CSQCModel_Effects_PreUpdate(void)
+void CSQCModel_Effects_PreUpdate()
 {SELFPARAM();
        self.effects = self.csqcmodel_effects;
        self.modelflags = self.csqcmodel_modelflags;
        self.traileffect = self.csqcmodel_traileffect;
 }
-void Reset_ArcBeam(void);
-void CSQCModel_Effects_PostUpdate(void)
+void Reset_ArcBeam();
+void CSQCModel_Effects_PostUpdate()
 {SELFPARAM();
        if (self == csqcplayer) {
                if (self.csqcmodel_teleported) {
@@ -504,7 +501,7 @@ void CSQCModel_Effects_PostUpdate(void)
                Projectile_ResetTrail(self, self.origin);
 }
 .int snd_looping;
-void CSQCModel_Effects_Apply(void)
+void CSQCModel_Effects_Apply()
 {SELFPARAM();
        int eff = self.csqcmodel_effects & ~CSQCMODEL_EF_RESPAWNGHOST;
        int tref = self.csqcmodel_traileffect;
@@ -532,9 +529,9 @@ void CSQCModel_Effects_Apply(void)
        if(eff & EF_FULLBRIGHT)
                self.renderflags |= RF_FULLBRIGHT;
        if(eff & EF_FLAME)
-               pointparticles(particleeffectnum(EFFECT_EF_FLAME), self.origin, '0 0 0', bound(0, frametime, 0.1));
+               pointparticles(EFFECT_EF_FLAME, self.origin, '0 0 0', bound(0, frametime, 0.1));
        if(eff & EF_STARDUST)
-               pointparticles(particleeffectnum(EFFECT_EF_STARDUST), self.origin, '0 0 0', bound(0, frametime, 0.1));
+               pointparticles(EFFECT_EF_STARDUST, self.origin, '0 0 0', bound(0, frametime, 0.1));
        if(eff & EF_NOSHADOW)
                self.renderflags |= RF_NOSHADOW;
        if(eff & EF_NODEPTHTEST)
diff --git a/qcsrc/client/damage.qc b/qcsrc/client/damage.qc
deleted file mode 100644 (file)
index 34890e0..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-#include "damage.qh"
-
-#include "gibs.qh"
-#include "../common/deathtypes/all.qh"
-#include "../common/movetypes/movetypes.qh"
-#include "../common/vehicles/all.qh"
-#include "../common/weapons/all.qh"
-
-.entity tag_entity;
-
-.float cnt;
-.int state;
-.bool isplayermodel;
-
-void DamageEffect_Think()
-{SELFPARAM();
-       // if particle distribution is enabled, slow ticrate by total number of damages
-       if(autocvar_cl_damageeffect_distribute)
-               self.nextthink = time + autocvar_cl_damageeffect_ticrate * self.owner.total_damages;
-       else
-               self.nextthink = time + autocvar_cl_damageeffect_ticrate;
-
-       if(time >= self.cnt || !self.owner || !self.owner.modelindex || !self.owner.drawmask)
-       {
-               // time is up or the player got gibbed / disconnected
-               self.owner.total_damages = max(0, self.owner.total_damages - 1);
-               remove(self);
-               return;
-       }
-       if(self.state && !self.owner.csqcmodel_isdead)
-       {
-               // if the player was dead but is now alive, it means he respawned
-               // if so, clear his damage effects, or damages from his dead body will be copied back
-               self.owner.total_damages = max(0, self.owner.total_damages - 1);
-               remove(self);
-               return;
-       }
-       self.state = self.owner.csqcmodel_isdead;
-       if(self.owner.isplayermodel && (self.owner.entnum == player_localentnum) && !autocvar_chase_active)
-               return; // if we aren't using a third person camera, hide our own effects
-
-       // now generate the particles
-       vector org;
-       org = gettaginfo(self, 0); // origin at attached location
-       pointparticles(self.team, org, '0 0 0', 1);
-}
-
-void DamageEffect(vector hitorg, float thedamage, int type, int specnum)
-{SELFPARAM();
-       // particle effects for players and objects damaged by weapons (eg: flames coming out of victims shot with rockets)
-
-       int nearestbone = 0;
-       float life;
-       string specstr, effectname;
-       entity e;
-
-       if(!autocvar_cl_damageeffect || autocvar_cl_gentle || autocvar_cl_gentle_damage)
-               return;
-       if(!self || !self.modelindex || !self.drawmask)
-               return;
-
-       // if this is a rigged mesh, the effect will show on the bone where damage was dealt
-       // we do this by choosing the skeletal bone closest to the impact, and attaching our entity to it
-       // if there's no skeleton, object origin will automatically be selected
-       FOR_EACH_TAG(self)
-       {
-               if(!tagnum)
-                       continue; // skip empty bones
-               // blacklist bones positioned outside the mesh, or the effect will be floating
-               // TODO: Do we have to do it this way? Why do these bones exist at all?
-               if(gettaginfo_name == "master" || gettaginfo_name == "knee_L" || gettaginfo_name == "knee_R" || gettaginfo_name == "leg_L" || gettaginfo_name == "leg_R")
-                       continue; // player model bone blacklist
-
-               // now choose the bone closest to impact origin
-               if(nearestbone == 0 || vlen(hitorg - gettaginfo(self, tagnum)) <= vlen(hitorg - gettaginfo(self, nearestbone)))
-                       nearestbone = tagnum;
-       }
-       gettaginfo(self, nearestbone); // set gettaginfo_name
-
-       // return if we reached our damage effect limit or damages are disabled
-       // TODO: When the limit is reached, it would be better if the oldest damage was removed instead of not adding a new one
-       if(nearestbone)
-       {
-               if(self.total_damages >= autocvar_cl_damageeffect_bones)
-                       return; // allow multiple damages on skeletal models
-       }
-       else
-       {
-               if(autocvar_cl_damageeffect < 2 || self.total_damages)
-                       return; // allow a single damage on non-skeletal models
-       }
-
-       life = bound(autocvar_cl_damageeffect_lifetime_min, thedamage * autocvar_cl_damageeffect_lifetime, autocvar_cl_damageeffect_lifetime_max);
-
-       effectname = DEATH_WEAPONOF(type).netname;
-
-       if(substring(effectname, strlen(effectname) - 5, 5) == "BLOOD")
-       {
-               if(self.isplayermodel)
-               {
-                       specstr = species_prefix(specnum);
-                       specstr = substring(specstr, 0, strlen(specstr) - 1);
-                       effectname = strreplace("BLOOD", specstr, effectname);
-               }
-               else { return; } // objects don't bleed
-       }
-
-       e = spawn();
-       setmodel(e, MDL_Null); // necessary to attach and read origin
-       setattachment(e, self, gettaginfo_name); // attach to the given bone
-       e.classname = "damage";
-       e.owner = self;
-       e.cnt = time + life;
-       e.team = _particleeffectnum(effectname);
-       e.think = DamageEffect_Think;
-       e.nextthink = time;
-       self.total_damages += 1;
-}
-
-void Ent_DamageInfo(float isNew)
-{SELFPARAM();
-       float thedamage, rad, edge, thisdmg;
-       bool hitplayer = false;
-       int species, forcemul;
-       vector force, thisforce;
-
-       w_deathtype = ReadShort();
-       w_issilent = (w_deathtype & 0x8000);
-       w_deathtype = (w_deathtype & 0x7FFF);
-
-       w_org.x = ReadCoord();
-       w_org.y = ReadCoord();
-       w_org.z = ReadCoord();
-
-       thedamage = ReadByte();
-       rad = ReadByte();
-       edge = ReadByte();
-       force = decompressShortVector(ReadShort());
-       species = ReadByte();
-
-       if (!isNew)
-               return;
-
-       if(rad < 0)
-       {
-               rad = -rad;
-               forcemul = -1;
-       }
-       else
-               forcemul = 1;
-
-       for(entity e = findradius(w_org, rad + MAX_DAMAGEEXTRARADIUS); e; e = e.chain)
-       {
-               setself(e);
-               // attached ents suck
-               if(self.tag_entity)
-                       continue;
-
-               vector nearest = NearestPointOnBox(self, w_org);
-               if(rad)
-               {
-                       thisdmg = ((vlen (nearest - w_org) - bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
-                       if(thisdmg >= 1)
-                               continue;
-                       if(thisdmg < 0)
-                               thisdmg = 0;
-                       if(thedamage)
-                       {
-                               thisdmg = thedamage + (edge - thedamage) * thisdmg;
-                               thisforce = forcemul * vlen(force) * (thisdmg / thedamage) * normalize(self.origin - w_org);
-                       }
-                       else
-                       {
-                               thisdmg = 0;
-                               thisforce = forcemul * vlen(force) * normalize(self.origin - w_org);
-                       }
-               }
-               else
-               {
-                       if(vlen(nearest - w_org) > bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS))
-                               continue;
-
-                       thisdmg = thedamage;
-                       thisforce = forcemul * force;
-               }
-
-               if(self.damageforcescale)
-                       if(vlen(thisforce))
-                       {
-                               self.move_velocity = self.move_velocity + damage_explosion_calcpush(self.damageforcescale * thisforce, self.move_velocity, autocvar_g_balance_damagepush_speedfactor);
-                               self.move_flags &= ~FL_ONGROUND;
-                       }
-
-               if(w_issilent)
-                       self.silent = 1;
-
-               if(self.event_damage)
-                       self.event_damage(thisdmg, w_deathtype, w_org, thisforce);
-
-               DamageEffect(w_org, thisdmg, w_deathtype, species);
-
-               if(self.isplayermodel)
-                       hitplayer = true; // this impact damaged a player
-       }
-       setself(this);
-
-       if(DEATH_ISVEHICLE(w_deathtype))
-       {
-               traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
-               if(trace_plane_normal != '0 0 0')
-                       w_backoff = trace_plane_normal;
-               else
-                       w_backoff = -1 * normalize(w_org - (w_org + normalize(force) * 16));
-
-               setorigin(self, w_org + w_backoff * 2); // for sound() calls
-
-               switch(DEATH_ENT(w_deathtype))
-               {
-                       case DEATH_VH_CRUSH:
-                               break;
-
-                       // spiderbot
-                       case DEATH_VH_SPID_MINIGUN:
-                               sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
-                               pointparticles(particleeffectnum(EFFECT_SPIDERBOT_MINIGUN_IMPACT), self.origin, w_backoff * 1000, 1);
-                               break;
-                       case DEATH_VH_SPID_ROCKET:
-                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-                               pointparticles(particleeffectnum(EFFECT_SPIDERBOT_ROCKET_EXPLODE), self.origin, w_backoff * 1000, 1);
-                               break;
-                       case DEATH_VH_SPID_DEATH:
-                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
-                               pointparticles(particleeffectnum(EFFECT_EXPLOSION_BIG), self.origin, w_backoff * 1000, 1);
-                               break;
-
-                       case DEATH_VH_WAKI_GUN:
-                               sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_NORM);
-                               pointparticles(particleeffectnum(EFFECT_RACER_IMPACT), self.origin, w_backoff * 1000, 1);
-                               break;
-                       case DEATH_VH_WAKI_ROCKET:
-                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-                               pointparticles(particleeffectnum(EFFECT_RACER_ROCKET_EXPLODE), self.origin, w_backoff * 1000, 1);
-                               break;
-                       case DEATH_VH_WAKI_DEATH:
-                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
-                               pointparticles(particleeffectnum(EFFECT_EXPLOSION_BIG), self.origin, w_backoff * 1000, 1);
-                               break;
-
-                       case DEATH_VH_RAPT_CANNON:
-                               sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_NORM);
-                               pointparticles(particleeffectnum(EFFECT_RAPTOR_CANNON_IMPACT), self.origin, w_backoff * 1000, 1);
-                               break;
-                       case DEATH_VH_RAPT_FRAGMENT:
-                               float i;
-                               vector ang, vel;
-                               for(i = 1; i < 4; ++i)
-                               {
-                                       vel = normalize(w_org - (w_org + normalize(force) * 16)) + randomvec() * 128;
-                                       ang = vectoangles(vel);
-                                       RaptorCBShellfragToss(w_org, vel, ang + '0 0 1' * (120 * i));
-                               }
-                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-                               pointparticles(particleeffectnum(EFFECT_RAPTOR_BOMB_SPREAD), self.origin, w_backoff * 1000, 1);
-                               break;
-                       case DEATH_VH_RAPT_BOMB:
-                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-                               pointparticles(particleeffectnum(EFFECT_RAPTOR_BOMB_IMPACT), self.origin, w_backoff * 1000, 1);
-                               break;
-                       case DEATH_VH_RAPT_DEATH:
-                               sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_MIN);
-                               pointparticles(particleeffectnum(EFFECT_EXPLOSION_BIG), self.origin, w_backoff * 1000, 1);
-                               break;
-                       case DEATH_VH_BUMB_GUN:
-                               sound(self, CH_SHOTS, SND_FIREBALL_IMPACT2, VOL_BASE, ATTEN_NORM);
-                               pointparticles(particleeffectnum(EFFECT_BIGPLASMA_IMPACT), self.origin, w_backoff * 1000, 1);
-                               break;
-               }
-       }
-
-
-       if(DEATH_ISTURRET(w_deathtype))
-       {
-               traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
-               if(trace_plane_normal != '0 0 0')
-                       w_backoff = trace_plane_normal;
-               else
-                       w_backoff = -1 * normalize(w_org - (w_org + normalize(force) * 16));
-
-               setorigin(self, w_org + w_backoff * 2); // for sound() calls
-
-               switch(DEATH_ENT(w_deathtype))
-               {
-                        case DEATH_TURRET_EWHEEL:
-                               sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_MIN);
-                               pointparticles(particleeffectnum(EFFECT_BLASTER_IMPACT), self.origin, w_backoff * 1000, 1);
-                               break;
-
-                        case DEATH_TURRET_FLAC:
-                               pointparticles(particleeffectnum(EFFECT_HAGAR_EXPLODE), w_org, '0 0 0', 1);
-                               sound(self, CH_SHOTS, SND_HAGEXP_RANDOM(), VOL_BASE, ATTEN_NORM);
-                               break;
-
-                        case DEATH_TURRET_MLRS:
-                        case DEATH_TURRET_HK:
-                        case DEATH_TURRET_WALK_ROCKET:
-                        case DEATH_TURRET_HELLION:
-                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
-                               pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), self.origin, w_backoff * 1000, 1);
-                               break;
-
-                        case DEATH_TURRET_MACHINEGUN:
-                        case DEATH_TURRET_WALK_GUN:
-                               sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
-                               pointparticles(particleeffectnum(EFFECT_MACHINEGUN_IMPACT), self.origin, w_backoff * 1000, 1);
-                               break;
-
-                        case DEATH_TURRET_PLASMA:
-                               sound(self, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_MIN);
-                               pointparticles(particleeffectnum(EFFECT_ELECTRO_IMPACT), self.origin, w_backoff * 1000, 1);
-                               break;
-
-                        case DEATH_TURRET_WALK_MELEE:
-                               sound(self, CH_SHOTS, SND_RIC1, VOL_BASE, ATTEN_MIN);
-                               pointparticles(particleeffectnum(EFFECT_TE_SPARK), self.origin, w_backoff * 1000, 1);
-                               break;
-
-                        case DEATH_TURRET_PHASER:
-                               break;
-
-                        case DEATH_TURRET_TESLA:
-                               te_smallflash(self.origin);
-                               break;
-
-               }
-       }
-
-       // TODO spawn particle effects and sounds based on w_deathtype
-       if(!DEATH_ISSPECIAL(w_deathtype))
-       if(!hitplayer || rad) // don't show ground impacts for hitscan weapons if a player was hit
-       {
-               Weapon hitwep = DEATH_WEAPONOF(w_deathtype);
-               w_random = prandom();
-
-               traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
-               if(trace_fraction < 1 && hitwep != WEP_VORTEX && hitwep != WEP_VAPORIZER)
-                       w_backoff = trace_plane_normal;
-               else
-                       w_backoff = -1 * normalize(force);
-               setorigin(self, w_org + w_backoff * 2); // for sound() calls
-
-               if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)) {
-                       hitwep.wr_impacteffect(hitwep);
-               }
-       }
-}
diff --git a/qcsrc/client/damage.qh b/qcsrc/client/damage.qh
deleted file mode 100644 (file)
index 3f11b9a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef CLIENT_DAMAGE_H
-#define CLIENT_DAMAGE_H
-
-.float total_damages; // number of effects which currently are attached to a player
-
-void Ent_DamageInfo(float isNew);
-
-#endif
index 6325a8ab3c6651481938e9999f23ecc5f63aae5c..98f25cc9037772d9d3a158407109af1fb63e7fe1 100644 (file)
@@ -23,8 +23,8 @@ float         dmg_take;
 #endif
 
 // Basic variables
-.float enttype; // entity type sent from server
-.int   sv_entnum; // entity number sent from server
+.int enttype; // entity type sent from server
+.int sv_entnum; // entity number sent from server
 .int team;
 .int team_size;
 
diff --git a/qcsrc/client/effects.qc b/qcsrc/client/effects.qc
deleted file mode 100644 (file)
index 21fa1ce..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-#include "effects.qh"
-
-/*
-.vector fx_start;
-.vector fx_end;
-.float  fx_with;
-.string fx_texture;
-.float  fx_lifetime;
-
-void b_draw()
-{
-    //Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, 0, time * 3, '1 1 1', 0.7, DRAWFLAG_ADDITIVE, view_origin);
-    Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, (self.fx_with/256), 0, '1 1 1', 1, DRAWFLAG_ADDITIVE, view_origin);
-
-}
-void b_make(vector s,vector e, string t,float l,float z)
-{
-    entity b;
-    b = spawn();
-    b.fx_texture = t;
-    b.fx_start = s;
-    b.fx_end = e;
-    b.fx_with = z;
-    b.think = SUB_Remove;
-    b.nextthink = time + l;
-       b.draw = b_draw;
-
-       //b.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
-}
-*/
-
-void cl_effects_lightningarc(vector from, vector to,float seglength,float drifts,float drifte,float branchfactor,float branchfactor_add)
-{
-    vector direction,dirnew, pos, pos_l;
-    float length, steps, steplength, i,drift;
-
-    length     = vlen(from - to);
-    if(length < 1)
-        return;
-
-    // Use at most 16 te_lightning1 segments, as these eat up beam list segments.
-    // TODO: Change this to R_BeginPolygon code, then we no longer have this limit.
-    steps      = min(16, floor(length / seglength));
-    if(steps < 1)
-    {
-        te_lightning1(world,from,to);
-        return;
-    }
-
-    steplength = length / steps;
-    direction  = normalize(to - from);
-    pos_l = from;
-    if(length > seglength)
-    {
-        for(i = 1; i < steps; i += 1)
-        {
-            drift = drifts * (1 - (i / steps)) + drifte * (i / steps);
-            dirnew = normalize(direction * (1 - drift) + randomvec() * drift);
-            pos = pos_l +  dirnew * steplength;
-            te_lightning1(world,pos_l,pos);
-            // WTF endless recursion if branchfactor is 1.0 (possibly due to adding branchfactor_add). FIXME
-            // if(random() < branchfactor)
-            //     cl_effects_lightningarc(pos, pos + (dirnew * length * 0.25),seglength,drifts,drifte,min(branchfactor + branchfactor_add,1),branchfactor_add);
-
-            pos_l = pos;
-        }
-        te_lightning1(world,pos_l,to);
-
-    }
-    else
-        te_lightning1(world,from,to);
-
-}
-
-void Net_ReadLightningarc()
-{
-       vector from, to;
-
-    from.x = ReadCoord(); from.y = ReadCoord(); from.z = ReadCoord();
-    to.x = ReadCoord(); to.y = ReadCoord(); to.z = ReadCoord();
-
-    if(autocvar_cl_effects_lightningarc_simple)
-    {
-        te_lightning1(world,from,to);
-    }
-    else
-    {
-        float seglength, drifts, drifte, branchfactor, branchfactor_add;
-
-        seglength        = autocvar_cl_effects_lightningarc_segmentlength;
-        drifts           = autocvar_cl_effects_lightningarc_drift_start;
-        drifte           = autocvar_cl_effects_lightningarc_drift_end;
-        branchfactor     = autocvar_cl_effects_lightningarc_branchfactor_start;
-        branchfactor_add = autocvar_cl_effects_lightningarc_branchfactor_add;
-
-        cl_effects_lightningarc(from,to,seglength,drifts,drifte,branchfactor,branchfactor_add);
-    }
-
-}
-void Net_ReadArc() { Net_ReadLightningarc(); }
diff --git a/qcsrc/client/effects.qh b/qcsrc/client/effects.qh
deleted file mode 100644 (file)
index 2d93f41..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef CLIENT_EFFECTS_H
-#define CLIENT_EFFECTS_H
-
-void Net_ReadArc();
-
-#endif
diff --git a/qcsrc/client/generator.qc b/qcsrc/client/generator.qc
deleted file mode 100644 (file)
index d7114d1..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-#include "generator.qh"
-
-#include "teamradar.qh"
-#include "../common/movetypes/movetypes.qh"
-
-.float alpha;
-.float scale;
-.int count;
-.float max_health;
-
-void ons_generator_ray_draw(entity this)
-{
-       if(time < self.move_time)
-               return;
-
-       self.move_time = time + 0.05;
-
-       if(self.count > 10)
-       {
-               remove(self);
-               return;
-       }
-
-       if(self.count > 5)
-               self.alpha -= 0.1;
-       else
-               self.alpha += 0.1;
-
-       self.scale += 0.2;
-       self.count +=1;
-}
-
-void ons_generator_ray_spawn(vector org)
-{
-       entity e;
-       e = spawn();
-       e.classname = "ons_ray";
-       setmodel(e, MDL_ONS_RAY);
-       setorigin(e, org);
-       e.angles = randomvec() * 360;
-       e.move_origin = org;
-       e.movetype = MOVETYPE_NONE;
-       e.alpha = 0;
-       e.scale = random() * 5 + 8;
-       e.move_time = time + 0.05;
-       e.drawmask = MASK_NORMAL;
-       e.draw = ons_generator_ray_draw;
-}
-
-void generator_draw(entity this)
-{
-       if(time < self.move_time)
-               return;
-
-       if(self.health > 0)
-       {
-               // damaged fx (less probable the more damaged is the generator)
-               if(random() < 0.9 - self.health / self.max_health)
-               if(random() < 0.01)
-               {
-                       pointparticles(particleeffectnum(EFFECT_ELECTRO_BALLEXPLODE), self.origin + randompos('-50 -50 -20', '50 50 50'), '0 0 0', 1);
-                       sound(self, CH_TRIGGER, SND_ONS_ELECTRICITY_EXPLODE, VOL_BASE, ATTEN_NORM);
-               }
-               else
-                       pointparticles(particleeffectnum(EFFECT_ONS_GENERATOR_DAMAGED), self.origin + randompos('-60 -60 -20', '60 60 60'), '0 0 0', 1);
-
-               self.move_time = time + 0.1;
-
-               return;
-       }
-
-       if(self.count <= 0)
-               return;
-
-       vector org;
-       int i;
-
-       // White shockwave
-       if(self.count==40||self.count==20)
-       {
-               sound(self, CH_TRIGGER, SND_ONS_SHOCKWAVE, VOL_BASE, ATTEN_NORM);
-               pointparticles(particleeffectnum(EFFECT_ELECTRO_COMBO), self.origin, '0 0 0', 6);
-       }
-
-       // rays
-       if(random() > 0.25)
-       {
-               ons_generator_ray_spawn(self.origin);
-       }
-
-       // Spawn fire balls
-       for(i=0;i < 10;++i)
-       {
-               org = self.origin + randompos('-30 -30 -30' * i + '0 0 -20', '30 30 30' * i + '0 0 20');
-               pointparticles(particleeffectnum(EFFECT_ONS_GENERATOR_GIB), org, '0 0 0', 1);
-       }
-
-       // Short explosion sound + small explosion
-       if(random() < 0.25)
-       {
-               te_explosion(self.origin);
-               sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
-       }
-
-       // Particles
-       org = self.origin + randompos(self.mins + '8 8 8', self.maxs + '-8 -8 -8');
-       pointparticles(particleeffectnum(EFFECT_ONS_GENERATOR_EXPLODE), org, '0 0 0', 1);
-
-       // Final explosion
-       if(self.count==1)
-       {
-               org = self.origin;
-               te_explosion(org);
-               pointparticles(particleeffectnum(EFFECT_ONS_GENERATOR_EXPLODE2), org, '0 0 0', 1);
-               sound(self, CH_TRIGGER, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-       }
-
-       self.move_time = time + 0.05;
-
-       self.count -= 1;
-}
-
-void generator_damage(float hp)
-{SELFPARAM();
-       if(hp <= 0)
-               setmodel(self, MDL_ONS_GEN_DEAD);
-       else if(hp < self.max_health * 0.10)
-               setmodel(self, MDL_ONS_GEN9);
-       else if(hp < self.max_health * 0.20)
-               setmodel(self, MDL_ONS_GEN8);
-       else if(hp < self.max_health * 0.30)
-               setmodel(self, MDL_ONS_GEN7);
-       else if(hp < self.max_health * 0.40)
-               setmodel(self, MDL_ONS_GEN6);
-       else if(hp < self.max_health * 0.50)
-               setmodel(self, MDL_ONS_GEN5);
-       else if(hp < self.max_health * 0.60)
-               setmodel(self, MDL_ONS_GEN4);
-       else if(hp < self.max_health * 0.70)
-               setmodel(self, MDL_ONS_GEN3);
-       else if(hp < self.max_health * 0.80)
-               setmodel(self, MDL_ONS_GEN2);
-       else if(hp < self.max_health * 0.90)
-               setmodel(self, MDL_ONS_GEN1);
-       else if(hp <= self.max_health || hp >= self.max_health)
-               setmodel(self, MDL_ONS_GEN);
-
-       setsize(self, GENERATOR_MIN, GENERATOR_MAX);
-}
-
-void generator_construct()
-{SELFPARAM();
-       self.netname = "Generator";
-       self.classname = "onslaught_generator";
-
-       setorigin(self, self.origin);
-       setmodel(self, MDL_ONS_GEN);
-       setsize(self, GENERATOR_MIN, GENERATOR_MAX);
-
-       self.move_movetype      = MOVETYPE_NOCLIP;
-       self.solid                      = SOLID_BBOX;
-       self.movetype           = MOVETYPE_NOCLIP;
-       self.move_origin        = self.origin;
-       self.move_time          = time;
-       self.drawmask           = MASK_NORMAL;
-       self.alpha                      = 1;
-       self.draw                       = generator_draw;
-}
-
-.vector glowmod;
-void generator_changeteam()
-{SELFPARAM();
-       if(self.team)
-       {
-               self.glowmod = Team_ColorRGB(self.team - 1);
-               self.teamradar_color = Team_ColorRGB(self.team - 1);
-               self.colormap = 1024 + (self.team - 1) * 17;
-       }
-       else
-       {
-               self.colormap = 1024;
-               self.glowmod = '1 1 0';
-               self.teamradar_color = '1 1 0';
-       }
-}
-
-void ent_generator()
-{SELFPARAM();
-       int sf = ReadByte();
-
-       if(sf & GSF_SETUP)
-       {
-               self.origin_x = ReadCoord();
-               self.origin_y = ReadCoord();
-               self.origin_z = ReadCoord();
-               setorigin(self, self.origin);
-
-               self.health = ReadByte();
-               self.max_health = ReadByte();
-               self.count = ReadByte();
-               self.team = ReadByte();
-
-               if(!self.count)
-                       self.count = 40;
-
-               generator_changeteam();
-               generator_construct();
-       }
-
-       if(sf & GSF_STATUS)
-       {
-               int _tmp;
-               _tmp = ReadByte();
-               if(_tmp != self.team)
-               {
-                       self.team = _tmp;
-                       generator_changeteam();
-               }
-
-               _tmp = ReadByte();
-
-               if(_tmp != self.health)
-                       generator_damage(_tmp);
-
-               self.health = _tmp;
-       }
-}
diff --git a/qcsrc/client/generator.qh b/qcsrc/client/generator.qh
deleted file mode 100644 (file)
index c60aff4..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef CLIENT_GENERATOR_H
-#define CLIENT_GENERATOR_H
-const vector GENERATOR_MIN = '-52 -52 -14';
-const vector GENERATOR_MAX = '52 52 75';
-
-const int GSF_STATUS = 4;
-const int GSF_SETUP = 8;
-
-void ent_generator();
-#endif
diff --git a/qcsrc/client/gibs.qc b/qcsrc/client/gibs.qc
deleted file mode 100644 (file)
index 4afa5eb..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-#include "gibs.qh"
-
-#include "rubble.qh"
-#include "../common/movetypes/movetypes.qh"
-
-.float scale;
-.float alpha;
-.float cnt;
-.float gravity;
-
-void Gib_Delete()
-{SELFPARAM();
-       remove(self);
-}
-
-string species_prefix(int specnum)
-{
-       switch(specnum)
-       {
-               case SPECIES_HUMAN:       return "";
-               case SPECIES_ALIEN:       return "alien_";
-               case SPECIES_ROBOT_SHINY: return "robot_";
-               case SPECIES_ROBOT_RUSTY: return "robot_"; // use the same effects, only different gibs
-               case SPECIES_ROBOT_SOLID: return "robot_"; // use the same effects, only different gibs
-               case SPECIES_ANIMAL:      return "animal_";
-               case SPECIES_RESERVED:    return "reserved_";
-               default:         return "";
-       }
-}
-
-void Gib_setmodel(entity gib, string mdlname, int specnum)
-{
-       switch(specnum)
-       {
-               case SPECIES_ROBOT_RUSTY:
-               case SPECIES_ROBOT_SHINY:
-               case SPECIES_ROBOT_SOLID:
-                       if(specnum != SPECIES_ROBOT_SOLID || mdlname == "models/gibs/chunk.mdl")
-                       {
-                               if(mdlname == "models/gibs/bloodyskull.md3")
-                                       setmodel(gib, MDL_GIB_ROBO);
-                               else
-                                       setmodel(gib, MDL_GIB_ROBO_RANDOM());
-                               if(specnum == SPECIES_ROBOT_SHINY)
-                               {
-                                       gib.skin = 1;
-                                       gib.colormod = '2 2 2';
-                               }
-                               gib.scale = 1;
-                               break;
-                       }
-               default:
-                       _setmodel(gib, mdlname);
-                       gib.skin = specnum;
-                       break;
-       }
-}
-
-void new_te_bloodshower (int ef, vector org, float explosionspeed, int howmany)
-{
-       float i, pmod;
-       pmod = autocvar_cl_particles_quality;
-       for (i = 0; i < 50 * pmod; ++i)
-               pointparticles(ef, org, randomvec() * explosionspeed, howmany / 50);
-}
-
-void SUB_RemoveOnNoImpact()
-{
-       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
-               Gib_Delete();
-}
-
-void Gib_Touch()
-{SELFPARAM();
-       // TODO maybe bounce of walls, make more gibs, etc.
-
-       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
-       {
-               Gib_Delete();
-               return;
-       }
-
-       if(!self.silent)
-               sound(self, CH_PAIN, SND_GIB_SPLAT_RANDOM(), VOL_BASE, ATTEN_NORM);
-       pointparticles(_particleeffectnum(strcat(species_prefix(self.cnt), "blood")), self.origin + '0 0 1', '0 0 30', 10);
-
-       Gib_Delete();
-}
-
-void Gib_Draw(entity this)
-{
-       vector oldorg;
-       oldorg = self.origin;
-
-       Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
-       if(wasfreed(self))
-               return;
-
-       if(self.touch == Gib_Touch) // don't do this for the "chunk" thingie...
-               // TODO somehow make it spray in a direction dependent on self.angles
-               trailparticles(self, _particleeffectnum(strcat(species_prefix(self.cnt), EFFECT_TR_SLIGHTBLOOD.eent_eff_name)), oldorg, self.origin);
-       else
-               trailparticles(self, _particleeffectnum(strcat(species_prefix(self.cnt), EFFECT_TR_BLOOD.eent_eff_name)), oldorg, self.origin);
-
-       self.renderflags = 0;
-
-       // make gibs die faster at low view quality
-       // if view_quality is 0.5, we want to have them die twice as fast
-       self.nextthink -= frametime * (1 / bound(0.01, view_quality, 1.00) - 1);
-
-       self.alpha = bound(0, self.nextthink - time, 1);
-
-       if(self.alpha < ALPHA_MIN_VISIBLE)
-       {
-               self.drawmask = 0;
-               Gib_Delete();
-       }
-}
-
-void TossGib (string mdlname, vector safeorg, vector org, vector vconst, vector vrand, int specnum, bool destroyontouch, bool issilent)
-{
-       entity gib;
-
-       // TODO remove some gibs according to cl_nogibs
-       gib = RubbleNew("gib");
-       gib.classname = "gib";
-       gib.move_movetype = MOVETYPE_BOUNCE;
-       gib.gravity = 1;
-       gib.solid = SOLID_CORPSE;
-       gib.cnt = specnum;
-       gib.silent = issilent;
-       Gib_setmodel(gib, mdlname, specnum);
-
-       setsize (gib, '-8 -8 -8', '8 8 8');
-
-       gib.draw = Gib_Draw;
-       if(destroyontouch)
-               gib.move_touch = Gib_Touch;
-       else
-               gib.move_touch = SUB_RemoveOnNoImpact;
-
-       // don't spawn gibs inside solid - just don't
-       if(org != safeorg)
-       {
-               tracebox(safeorg, gib.mins, gib.maxs, org, MOVE_NOMONSTERS, gib);
-               org = trace_endpos;
-       }
-
-       gib.move_origin = org;
-       setorigin(gib, org);
-       gib.move_velocity = vconst * autocvar_cl_gibs_velocity_scale + vrand * autocvar_cl_gibs_velocity_random + '0 0 1' * autocvar_cl_gibs_velocity_up;
-       gib.move_avelocity = prandomvec() * vlen(gib.move_velocity) * autocvar_cl_gibs_avelocity_scale;
-       gib.move_time = time;
-       gib.damageforcescale = autocvar_cl_gibs_damageforcescale;
-
-       gib.nextthink = time + autocvar_cl_gibs_lifetime * (1 + prandom() * 0.15);
-       gib.drawmask = MASK_NORMAL;
-
-       RubbleLimit("gib", autocvar_cl_gibs_maxcount, Gib_Delete);
-}
-
-void Ent_GibSplash(bool isNew)
-{SELFPARAM();
-       int amount, type, specnum;
-       vector org, vel;
-       string specstr;
-       bool issilent;
-       string gentle_prefix = "morphed_";
-
-       float randomvalue;
-       int c;
-
-       type = ReadByte(); // gibbage type
-       amount = ReadByte() / 16.0; // gibbage amount
-       org.x = ReadShort() * 4 + 2;
-       org.y = ReadShort() * 4 + 2;
-       org.z = ReadShort() * 4 + 2;
-       vel = decompressShortVector(ReadShort());
-
-       float cl_gentle_gibs = autocvar_cl_gentle_gibs;
-       if(cl_gentle_gibs || autocvar_cl_gentle)
-               type |= 0x80; // set gentle bit
-
-       if(type & 0x80)
-       {
-               if(cl_gentle_gibs == 2)
-                       gentle_prefix = "";
-               else if(cl_gentle_gibs == 3)
-                       gentle_prefix = "happy_";
-       }
-       else if(autocvar_cl_particlegibs)
-       {
-               type |= 0x80;
-               gentle_prefix = "particlegibs_";
-       }
-
-       if (!(cl_gentle_gibs || autocvar_cl_gentle))
-               amount *= 1 - autocvar_cl_nogibs;
-
-       if(autocvar_ekg)
-               amount *= 5;
-
-       if(amount <= 0 || !isNew)
-               return;
-
-       setorigin(self, org); // for the sounds
-
-       specnum = (type & 0x78) / 8; // blood/gibmodel type: using four bits (0..7, bit indexes 3,4,5)
-       issilent = (type & 0x40);
-       type = type & 0x87; // remove the species bits: bit 7 = gentle, bit 0,1,2 = kind of gib
-       specstr = species_prefix(specnum);
-
-       switch(type)
-       {
-               case 0x01:
-                       if(!issilent)
-                               sound (self, CH_PAIN, SND_GIB, VOL_BASE, ATTEN_NORM);
-
-                       if(prandom() < amount)
-                               TossGib ("models/gibs/eye.md3", org, org, vel, prandomvec() * 150, specnum, 0, issilent);
-                       new_te_bloodshower(_particleeffectnum(strcat(specstr, "bloodshower")), org, 1200, amount);
-                       if(prandom() < amount)
-                               TossGib ("models/gibs/bloodyskull.md3", org, org + 16 * prandomvec(), vel, prandomvec() * 100, specnum, 0, issilent);
-
-                       for(c = 0; c < amount; ++c)
-                       {
-                               randomvalue = amount - c;
-
-                               if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
-                               if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
-                               if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/chest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
-                               if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/smallchest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
-                               if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/leg1.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
-                               if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/leg2.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
-
-                               // these splat on impact
-                               if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
-                               if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
-                               if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
-                               if(prandom() < randomvalue)
-                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
-                       }
-                       break;
-               case 0x02:
-                       pointparticles(_particleeffectnum(strcat(specstr, "blood")), org, vel, amount * 16);
-                       break;
-               case 0x03:
-                       if(prandom() < amount)
-                               TossGib ("models/gibs/chunk.mdl", org, org, vel, prandomvec() * (prandom() * 30 + 20), specnum, 1, issilent); // TODO maybe adjust to more randomization?
-                       break;
-               case 0x81:
-                       pointparticles(_particleeffectnum(strcat(gentle_prefix, "damage_dissolve")), org, vel, amount);
-                       break;
-               case 0x82:
-                       pointparticles(_particleeffectnum(strcat(gentle_prefix, "damage_hit")), org, vel, amount * 16);
-                       break;
-               case 0x83:
-                       // no gibs in gentle mode, sorry
-                       break;
-       }
-}
diff --git a/qcsrc/client/gibs.qh b/qcsrc/client/gibs.qh
deleted file mode 100644 (file)
index eb63aa1..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef CLIENT_GIBS_H
-#define CLIENT_GIBS_H
-
-.vector colormod;
-
-.bool silent;
-
-void Gib_Delete();
-
-string species_prefix(int specnum);
-
-void Gib_setmodel(entity gib, string mdlname, int specnum);
-
-void new_te_bloodshower (int ef, vector org, float explosionspeed, int howmany);
-
-void SUB_RemoveOnNoImpact();
-
-void Gib_Touch();
-
-void Gib_Draw(entity this);
-
-void TossGib (string mdlname, vector safeorg, vector org, vector vconst, vector vrand, int specnum, bool destroyontouch, bool issilent);
-
-void Ent_GibSplash(bool isNew);
-
-#endif
index 5b8d09312049202197e379e5cb616b504fb8892b..cee2a0cd83a1d6e64c8a9eb2b68807bc1bbf3c88 100644 (file)
@@ -4,7 +4,7 @@
 #include "../lib/warpzone/common.qh"
 
 entityclass(Hook);
-class(Hook) .float HookType; // ENT_CLIENT_*
+class(Hook) .entity HookType; // ENT_CLIENT_*
 class(Hook) .vector origin;
 class(Hook) .vector velocity;
 class(Hook) .float HookSilent;
@@ -48,10 +48,10 @@ void Draw_GrapplingHook(entity this)
        switch(self.HookType)
        {
                default:
-               case ENT_CLIENT_HOOK:
+               case NET_ENT_CLIENT_HOOK:
                        vs = hook_shotorigin[s];
                        break;
-               case ENT_CLIENT_ARC_BEAM:
+               case NET_ENT_CLIENT_ARC_BEAM:
                        vs = lightning_shotorigin[s];
                        break;
        }
@@ -61,11 +61,11 @@ void Draw_GrapplingHook(entity this)
                switch(self.HookType)
                {
                        default:
-                       case ENT_CLIENT_HOOK:
+                       case NET_ENT_CLIENT_HOOK:
                                a = view_origin + view_forward * vs.x + view_right * -vs.y + view_up * vs.z;
                                b = self.origin;
                                break;
-                       case ENT_CLIENT_ARC_BEAM:
+                       case NET_ENT_CLIENT_ARC_BEAM:
                                if(self.HookRange)
                                        b = view_origin + view_forward * self.HookRange;
                                else
@@ -81,11 +81,11 @@ void Draw_GrapplingHook(entity this)
                switch(self.HookType)
                {
                        default:
-                       case ENT_CLIENT_HOOK:
+                       case NET_ENT_CLIENT_HOOK:
                                a = self.velocity;
                                b = self.origin;
                                break;
-                       case ENT_CLIENT_ARC_BEAM:
+                       case NET_ENT_CLIENT_ARC_BEAM:
                                a = self.origin;
                                b = self.velocity;
                                break;
@@ -97,7 +97,7 @@ void Draw_GrapplingHook(entity this)
        switch(self.HookType)
        {
                default:
-               case ENT_CLIENT_HOOK:
+               case NET_ENT_CLIENT_HOOK:
                        intensity = 1;
                        offset = 0;
                        switch(t)
@@ -109,7 +109,7 @@ void Draw_GrapplingHook(entity this)
                                default: tex = "particles/hook_white"; rgb = getcsqcplayercolor(self.sv_entnum); break;
                        }
                        break;
-               case ENT_CLIENT_ARC_BEAM: // todo
+               case NET_ENT_CLIENT_ARC_BEAM: // todo
                        intensity = bound(0.2, 1 + Noise_Pink(self, frametime) * 1 + Noise_Burst(self, frametime, 0.03) * 0.3, 2);
                        offset = Noise_Brown(self, frametime) * 10;
                        tex = "particles/lgbeam";
@@ -121,7 +121,7 @@ void Draw_GrapplingHook(entity this)
        Draw_GrapplingHook_trace_callback_rnd = offset;
        Draw_GrapplingHook_trace_callback_rgb = rgb;
        Draw_GrapplingHook_trace_callback_a = intensity;
-       WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, ((self.HookType == ENT_CLIENT_HOOK) ? MOVE_NOTHING : MOVE_NORMAL), world, world, Draw_GrapplingHook_trace_callback);
+       WarpZone_TraceBox_ThroughZone(a, '0 0 0', '0 0 0', b, ((self.HookType == NET_ENT_CLIENT_HOOK) ? MOVE_NOTHING : MOVE_NORMAL), world, world, Draw_GrapplingHook_trace_callback);
        Draw_GrapplingHook_trace_callback_tex = string_null;
 
        atrans = WarpZone_TransformOrigin(WarpZone_trace_transform, a);
@@ -129,7 +129,7 @@ void Draw_GrapplingHook(entity this)
        switch(self.HookType)
        {
                default:
-               case ENT_CLIENT_HOOK:
+               case NET_ENT_CLIENT_HOOK:
                        if(vlen(trace_endpos - atrans) > 0.5)
                        {
                                setorigin(self, trace_endpos); // hook endpoint!
@@ -141,7 +141,7 @@ void Draw_GrapplingHook(entity this)
                                self.drawmask = 0;
                        }
                        break;
-               case ENT_CLIENT_ARC_BEAM:
+               case NET_ENT_CLIENT_ARC_BEAM:
                        setorigin(self, a); // beam origin!
                        break;
        }
@@ -149,10 +149,10 @@ void Draw_GrapplingHook(entity this)
        switch(self.HookType)
        {
                default:
-               case ENT_CLIENT_HOOK:
+               case NET_ENT_CLIENT_HOOK:
                        break;
-               case ENT_CLIENT_ARC_BEAM:
-                       pointparticles(particleeffectnum(EFFECT_ARC_LIGHTNING2), trace_endpos, normalize(atrans - trace_endpos), frametime * intensity); // todo: new effect
+               case NET_ENT_CLIENT_ARC_BEAM:
+                       pointparticles(EFFECT_ARC_LIGHTNING2, trace_endpos, normalize(atrans - trace_endpos), frametime * intensity); // todo: new effect
                        break;
        }
 }
@@ -162,9 +162,9 @@ void Remove_GrapplingHook()
        sound (self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
 }
 
-void Ent_ReadHook(float bIsNew, float type)
-{SELFPARAM();
-       self.HookType = type;
+NET_HANDLE(ENT_CLIENT_HOOK, bool bIsNew)
+{
+       self.HookType = NET_ENT_CLIENT_HOOK;
 
        int sf = ReadByte();
 
@@ -181,10 +181,10 @@ void Ent_ReadHook(float bIsNew, float type)
                switch(self.HookType)
                {
                        default:
-                       case ENT_CLIENT_HOOK:
+                       case NET_ENT_CLIENT_HOOK:
                                self.HookRange = 0;
                                break;
-                       case ENT_CLIENT_ARC_BEAM:
+                       case NET_ENT_CLIENT_ARC_BEAM:
                                self.HookRange = ReadCoord();
                                break;
                }
@@ -213,18 +213,19 @@ void Ent_ReadHook(float bIsNew, float type)
                switch(self.HookType)
                {
                        default:
-                       case ENT_CLIENT_HOOK:
+                       case NET_ENT_CLIENT_HOOK:
                                // for the model
                                setmodel(self, MDL_HOOK);
                                self.drawmask = MASK_NORMAL;
                                break;
-                       case ENT_CLIENT_ARC_BEAM:
+                       case NET_ENT_CLIENT_ARC_BEAM:
                                sound (self, CH_SHOTS_SINGLE, SND_LGBEAM_FLY, VOL_BASE, ATTEN_NORM);
                                break;
                }
        }
 
        self.teleport_time = time + 10;
+       return true;
 }
 
 // TODO: hook: temporarily transform self.origin for drawing the model along warpzones!
index 9e6ee548cfab5ae0a97a169b213c9596d497ff85..36624255f94e5ad16458c58b9b78cd43f2a2a8f4 100644 (file)
@@ -3,6 +3,4 @@
 
 void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg);
 
-void Ent_ReadHook(float bIsNew, float type);
-
 #endif
diff --git a/qcsrc/client/hud.qc b/qcsrc/client/hud.qc
deleted file mode 100644 (file)
index a00a9c3..0000000
+++ /dev/null
@@ -1,4855 +0,0 @@
-#include "hud.qh"
-
-#include "hud_config.qh"
-#include "mapvoting.qh"
-#include "scoreboard.qh"
-#include "teamradar.qh"
-#include "t_items.qh"
-#include "../common/buffs/all.qh"
-#include "../common/deathtypes/all.qh"
-#include "../common/items/all.qc"
-#include "../common/mapinfo.qh"
-#include "../common/mutators/mutator/waypoints/all.qh"
-#include "../common/nades/all.qh"
-#include "../common/stats.qh"
-#include "../lib/csqcmodel/cl_player.qh"
-// TODO: remove
-#include "../server/mutators/mutator/gamemode_ctf.qc"
-
-
-/*
-==================
-Misc HUD functions
-==================
-*/
-
-vector HUD_Get_Num_Color (float x, float maxvalue)
-{
-       float blinkingamt;
-       vector color;
-       if(x >= maxvalue) {
-               color.x = sin(2*M_PI*time);
-               color.y = 1;
-               color.z = sin(2*M_PI*time);
-       }
-       else if(x > maxvalue * 0.75) {
-               color.x = 0.4 - (x-150)*0.02 * 0.4; //red value between 0.4 -> 0
-               color.y = 0.9 + (x-150)*0.02 * 0.1; // green value between 0.9 -> 1
-               color.z = 0;
-       }
-       else if(x > maxvalue * 0.5) {
-               color.x = 1 - (x-100)*0.02 * 0.6; //red value between 1 -> 0.4
-               color.y = 1 - (x-100)*0.02 * 0.1; // green value between 1 -> 0.9
-               color.z = 1 - (x-100)*0.02; // blue value between 1 -> 0
-       }
-       else if(x > maxvalue * 0.25) {
-               color.x = 1;
-               color.y = 1;
-               color.z = 0.2 + (x-50)*0.02 * 0.8; // blue value between 0.2 -> 1
-       }
-       else if(x > maxvalue * 0.1) {
-               color.x = 1;
-               color.y = (x-20)*90/27/100; // green value between 0 -> 1
-               color.z = (x-20)*90/27/100 * 0.2; // blue value between 0 -> 0.2
-       }
-       else {
-               color.x = 1;
-               color.y = 0;
-               color.z = 0;
-       }
-
-       blinkingamt = (1 - x/maxvalue/0.25);
-       if(blinkingamt > 0)
-       {
-               color.x = color.x - color.x * blinkingamt * sin(2*M_PI*time);
-               color.y = color.y - color.y * blinkingamt * sin(2*M_PI*time);
-               color.z = color.z - color.z * blinkingamt * sin(2*M_PI*time);
-       }
-       return color;
-}
-
-float HUD_GetRowCount(int item_count, vector size, float item_aspect)
-{
-       float aspect = size_y / size_x;
-       return bound(1, floor((sqrt(4 * item_aspect * aspect * item_count + aspect * aspect) + aspect + 0.5) / 2), item_count);
-}
-
-vector HUD_GetTableSize_BestItemAR(int item_count, vector psize, float item_aspect)
-{
-       float columns, rows;
-       float ratio, best_ratio = 0;
-       float best_columns = 1, best_rows = 1;
-       bool vertical = (psize.x / psize.y >= item_aspect);
-       if(vertical)
-       {
-               psize = eX * psize.y + eY * psize.x;
-               item_aspect = 1 / item_aspect;
-       }
-
-       rows = ceil(sqrt(item_count));
-       columns = ceil(item_count/rows);
-       while(columns >= 1)
-       {
-               ratio = (psize.x/columns) / (psize.y/rows);
-               if(ratio > item_aspect)
-                       ratio = item_aspect * item_aspect / ratio;
-
-               if(ratio <= best_ratio)
-                       break; // ratio starts decreasing by now, skip next configurations
-
-               best_columns = columns;
-               best_rows = rows;
-               best_ratio = ratio;
-
-               if(columns == 1)
-                       break;
-
-               --columns;
-               rows = ceil(item_count/columns);
-       }
-
-       if(vertical)
-               return eX * best_rows + eY * best_columns;
-       else
-               return eX * best_columns + eY * best_rows;
-}
-
-// return the string of the onscreen race timer
-string MakeRaceString(int cp, float mytime, float theirtime, float lapdelta, string theirname)
-{
-       string col;
-       string timestr;
-       string cpname;
-       string lapstr;
-       lapstr = "";
-
-       if(theirtime == 0) // goal hit
-       {
-               if(mytime > 0)
-               {
-                       timestr = strcat("+", ftos_decimals(+mytime, TIME_DECIMALS));
-                       col = "^1";
-               }
-               else if(mytime == 0)
-               {
-                       timestr = "+0.0";
-                       col = "^3";
-               }
-               else
-               {
-                       timestr = strcat("-", ftos_decimals(-mytime, TIME_DECIMALS));
-                       col = "^2";
-               }
-
-               if(lapdelta > 0)
-               {
-                       lapstr = sprintf(_(" (-%dL)"), lapdelta);
-                       col = "^2";
-               }
-               else if(lapdelta < 0)
-               {
-                       lapstr = sprintf(_(" (+%dL)"), -lapdelta);
-                       col = "^1";
-               }
-       }
-       else if(theirtime > 0) // anticipation
-       {
-               if(mytime >= theirtime)
-                       timestr = strcat("+", ftos_decimals(mytime - theirtime, TIME_DECIMALS));
-               else
-                       timestr = TIME_ENCODED_TOSTRING(TIME_ENCODE(theirtime));
-               col = "^3";
-       }
-       else
-       {
-               col = "^7";
-               timestr = "";
-       }
-
-       if(cp == 254)
-               cpname = _("Start line");
-       else if(cp == 255)
-               cpname = _("Finish line");
-       else if(cp)
-               cpname = sprintf(_("Intermediate %d"), cp);
-       else
-               cpname = _("Finish line");
-
-       if(theirtime < 0)
-               return strcat(col, cpname);
-       else if(theirname == "")
-               return strcat(col, sprintf("%s (%s)", cpname, timestr));
-       else
-               return strcat(col, sprintf("%s (%s %s)", cpname, timestr, strcat(theirname, col, lapstr)));
-}
-
-// Check if the given name already exist in race rankings? In that case, where? (otherwise return 0)
-int race_CheckName(string net_name)
-{
-       int i;
-       for (i=RANKINGS_CNT-1;i>=0;--i)
-               if(grecordholder[i] == net_name)
-                       return i+1;
-       return 0;
-}
-
-/*
-==================
-HUD panels
-==================
-*/
-
-//basically the same code of draw_ButtonPicture and draw_VertButtonPicture for the menu
-void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag)
-{
-       if(!length_ratio || !theAlpha)
-               return;
-       if(length_ratio > 1)
-               length_ratio = 1;
-       if (baralign == 3)
-       {
-               if(length_ratio < -1)
-                       length_ratio = -1;
-       }
-       else if(length_ratio < 0)
-               return;
-
-       vector square;
-       vector width, height;
-       if(vertical) {
-               pic = strcat(hud_skin_path, "/", pic, "_vertical");
-               if(precache_pic(pic) == "") {
-                       pic = "gfx/hud/default/progressbar_vertical";
-               }
-
-        if (baralign == 1) // bottom align
-                       theOrigin.y += (1 - length_ratio) * theSize.y;
-        else if (baralign == 2) // center align
-            theOrigin.y += 0.5 * (1 - length_ratio) * theSize.y;
-        else if (baralign == 3) // center align, positive values down, negative up
-               {
-                       theSize.y *= 0.5;
-                       if (length_ratio > 0)
-                               theOrigin.y += theSize.y;
-                       else
-                       {
-                               theOrigin.y += (1 + length_ratio) * theSize.y;
-                               length_ratio = -length_ratio;
-                       }
-               }
-               theSize.y *= length_ratio;
-
-               vector bH;
-               width = eX * theSize.x;
-               height = eY * theSize.y;
-               if(theSize.y <= theSize.x * 2)
-               {
-                       // button not high enough
-                       // draw just upper and lower part then
-                       square = eY * theSize.y * 0.5;
-                       bH = eY * (0.25 * theSize.y / (theSize.x * 2));
-                       drawsubpic(theOrigin,          square + width, pic, '0 0 0', eX + bH, theColor, theAlpha, drawflag);
-                       drawsubpic(theOrigin + square, square + width, pic, eY - bH, eX + bH, theColor, theAlpha, drawflag);
-               }
-               else
-               {
-                       square = eY * theSize.x;
-                       drawsubpic(theOrigin,                   width   +     square, pic, '0 0    0', '1 0.25 0', theColor, theAlpha, drawflag);
-                       drawsubpic(theOrigin +          square, theSize - 2 * square, pic, '0 0.25 0', '1 0.5  0', theColor, theAlpha, drawflag);
-                       drawsubpic(theOrigin + height - square, width   +     square, pic, '0 0.75 0', '1 0.25 0', theColor, theAlpha, drawflag);
-               }
-       } else {
-               pic = strcat(hud_skin_path, "/", pic);
-               if(precache_pic(pic) == "") {
-                       pic = "gfx/hud/default/progressbar";
-               }
-
-               if (baralign == 1) // right align
-                       theOrigin.x += (1 - length_ratio) * theSize.x;
-        else if (baralign == 2) // center align
-            theOrigin.x += 0.5 * (1 - length_ratio) * theSize.x;
-        else if (baralign == 3) // center align, positive values on the right, negative on the left
-               {
-                       theSize.x *= 0.5;
-                       if (length_ratio > 0)
-                               theOrigin.x += theSize.x;
-                       else
-                       {
-                               theOrigin.x += (1 + length_ratio) * theSize.x;
-                               length_ratio = -length_ratio;
-                       }
-               }
-               theSize.x *= length_ratio;
-
-               vector bW;
-               width = eX * theSize.x;
-               height = eY * theSize.y;
-               if(theSize.x <= theSize.y * 2)
-               {
-                       // button not wide enough
-                       // draw just left and right part then
-                       square = eX * theSize.x * 0.5;
-                       bW = eX * (0.25 * theSize.x / (theSize.y * 2));
-                       drawsubpic(theOrigin,          square + height, pic, '0 0 0', eY + bW, theColor, theAlpha, drawflag);
-                       drawsubpic(theOrigin + square, square + height, pic, eX - bW, eY + bW, theColor, theAlpha, drawflag);
-               }
-               else
-               {
-                       square = eX * theSize.y;
-                       drawsubpic(theOrigin,                  height  +     square, pic, '0    0 0', '0.25 1 0', theColor, theAlpha, drawflag);
-                       drawsubpic(theOrigin +         square, theSize - 2 * square, pic, '0.25 0 0', '0.5  1 0', theColor, theAlpha, drawflag);
-                       drawsubpic(theOrigin + width - square, height  +     square, pic, '0.75 0 0', '0.25 1 0', theColor, theAlpha, drawflag);
-               }
-       }
-}
-
-void HUD_Panel_DrawHighlight(vector pos, vector mySize, vector color, float theAlpha, int drawflag)
-{
-       if(!theAlpha)
-               return;
-
-       string pic;
-       pic = strcat(hud_skin_path, "/num_leading");
-       if(precache_pic(pic) == "") {
-               pic = "gfx/hud/default/num_leading";
-       }
-
-       drawsubpic(pos, eX * min(mySize.x * 0.5, mySize.y) + eY * mySize.y, pic, '0 0 0', '0.25 1 0', color, theAlpha, drawflag);
-       if(mySize.x/mySize.y > 2)
-               drawsubpic(pos + eX * mySize.y, eX * (mySize.x - 2 * mySize.y) + eY * mySize.y, pic, '0.25 0 0', '0.5 1 0', color, theAlpha, drawflag);
-       drawsubpic(pos + eX * mySize.x - eX * min(mySize.x * 0.5, mySize.y), eX * min(mySize.x * 0.5, mySize.y) + eY * mySize.y, pic, '0.75 0 0', '0.25 1 0', color, theAlpha, drawflag);
-}
-
-// Weapon icons (#0)
-//
-entity weaponorder[Weapons_MAX];
-void weaponorder_swap(int i, int j, entity pass)
-{
-       entity h = weaponorder[i];
-       weaponorder[i] = weaponorder[j];
-       weaponorder[j] = h;
-}
-
-string weaponorder_cmp_str;
-int weaponorder_cmp(int i, int j, entity pass)
-{
-       int ai, aj;
-       ai = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[i].weapon), 0);
-       aj = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[j].weapon), 0);
-       return aj - ai; // the string is in REVERSE order (higher prio at the right is what we want, but higher prio first is the string)
-}
-
-void HUD_Weapons(void)
-{SELFPARAM();
-       // declarations
-       WepSet weapons_stat = WepSet_GetFromStat();
-       int i;
-       float f, a;
-       float screen_ar;
-       vector center = '0 0 0';
-       int weapon_count, weapon_id;
-       int row, column, rows = 0, columns = 0;
-       bool vertical_order = true;
-       float aspect = autocvar_hud_panel_weapons_aspect;
-
-       float timeout = autocvar_hud_panel_weapons_timeout;
-       float timein_effect_length = autocvar_hud_panel_weapons_timeout_speed_in; //? 0.375 : 0);
-       float timeout_effect_length = autocvar_hud_panel_weapons_timeout_speed_out; //? 0.75 : 0);
-
-       vector barsize = '0 0 0', baroffset = '0 0 0';
-       vector ammo_color = '1 0 1';
-       float ammo_alpha = 1;
-
-       float when = max(1, autocvar_hud_panel_weapons_complainbubble_time);
-       float fadetime = max(0, autocvar_hud_panel_weapons_complainbubble_fadetime);
-
-       vector weapon_pos, weapon_size = '0 0 0';
-       vector color;
-
-       // check to see if we want to continue
-       if(hud != HUD_NORMAL) return;
-
-       if(!autocvar__hud_configure)
-       {
-               if((!autocvar_hud_panel_weapons) || (spectatee_status == -1))
-                       return;
-               if(timeout && time >= weapontime + timeout + timeout_effect_length)
-               if(autocvar_hud_panel_weapons_timeout_effect == 3 || (autocvar_hud_panel_weapons_timeout_effect == 1 && !(autocvar_hud_panel_weapons_timeout_fadebgmin + autocvar_hud_panel_weapons_timeout_fadefgmin)))
-               {
-                       weaponprevtime = time;
-                       return;
-               }
-       }
-
-       // update generic hud functions
-       HUD_Panel_UpdateCvars();
-
-       // figure out weapon order (how the weapons are sorted) // TODO make this configurable
-       if(weaponorder_bypriority != autocvar_cl_weaponpriority || !weaponorder[0])
-       {
-               int weapon_cnt;
-               if(weaponorder_bypriority)
-                       strunzone(weaponorder_bypriority);
-               if(weaponorder_byimpulse)
-                       strunzone(weaponorder_byimpulse);
-
-               weaponorder_bypriority = strzone(autocvar_cl_weaponpriority);
-               weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(W_FixWeaponOrder_ForceComplete(W_NumberWeaponOrder(weaponorder_bypriority))));
-               weaponorder_cmp_str = strcat(" ", weaponorder_byimpulse, " ");
-
-               weapon_cnt = 0;
-               for(i = WEP_FIRST; i <= WEP_LAST; ++i)
-               {
-                       setself(get_weaponinfo(i));
-                       if(self.impulse >= 0)
-                       {
-                               weaponorder[weapon_cnt] = self;
-                               ++weapon_cnt;
-                       }
-               }
-               for(i = weapon_cnt; i < Weapons_MAX; ++i)
-                       weaponorder[i] = world;
-               heapsort(weapon_cnt, weaponorder_swap, weaponorder_cmp, world);
-
-               weaponorder_cmp_str = string_null;
-       }
-
-       if(!autocvar_hud_panel_weapons_complainbubble || autocvar__hud_configure || time - complain_weapon_time >= when + fadetime)
-               complain_weapon = 0;
-
-       if(autocvar__hud_configure)
-       {
-               if(!weapons_stat)
-                       for(i = WEP_FIRST; i <= WEP_LAST; i += floor((WEP_LAST-WEP_FIRST)/5))
-                               weapons_stat |= WepSet_FromWeapon(i);
-
-               #if 0
-               /// debug code
-               if(cvar("wep_add"))
-               {
-                       weapons_stat = '0 0 0';
-                       float countw = 1 + floor((floor(time * cvar("wep_add"))) % (Weapons_COUNT - 1));
-                       for(i = WEP_FIRST; i <= countw; ++i)
-                               weapons_stat |= WepSet_FromWeapon(i);
-               }
-               #endif
-       }
-
-       // determine which weapons are going to be shown
-       if (autocvar_hud_panel_weapons_onlyowned)
-       {
-               if(autocvar__hud_configure)
-               {
-                       if(menu_enabled != 2)
-                               HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
-               }
-
-               // do we own this weapon?
-               weapon_count = 0;
-               for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
-                       if((weapons_stat & WepSet_FromWeapon(weaponorder[i].weapon)) || (weaponorder[i].weapon == complain_weapon))
-                               ++weapon_count;
-
-
-               // might as well commit suicide now, no reason to live ;)
-               if (weapon_count == 0)
-                       return;
-
-               vector old_panel_size = panel_size;
-               vector padded_panel_size = panel_size - '2 2 0' * panel_bg_padding;
-
-               // get the all-weapons layout
-               int nHidden = 0;
-               WepSet weapons_stat = WepSet_GetFromStat();
-               for (int i = WEP_FIRST; i <= WEP_LAST; ++i) {
-                       WepSet weapons_wep = WepSet_FromWeapon(i);
-                       if (weapons_stat & weapons_wep) continue;
-                       Weapon w = get_weaponinfo(i);
-                       if (w.spawnflags & WEP_FLAG_MUTATORBLOCKED) nHidden += 1;
-               }
-               vector table_size = HUD_GetTableSize_BestItemAR((Weapons_COUNT - 1) - nHidden, padded_panel_size, aspect);
-               columns = table_size.x;
-               rows = table_size.y;
-               weapon_size.x = padded_panel_size.x / columns;
-               weapon_size.y = padded_panel_size.y / rows;
-
-               // NOTE: although weapons should aways look the same even if onlyowned is enabled,
-               // we enlarge them a bit when possible to better match the desired aspect ratio
-               if(padded_panel_size.x / padded_panel_size.y < aspect)
-               {
-                       // maximum number of rows that allows to display items with the desired aspect ratio
-                       int max_rows = floor(padded_panel_size.y / (weapon_size.x / aspect));
-                       columns = min(columns, ceil(weapon_count / max_rows));
-                       rows = ceil(weapon_count / columns);
-                       weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
-                       weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
-                       vertical_order = false;
-               }
-               else
-               {
-                       int max_columns = floor(padded_panel_size.x / (weapon_size.y * aspect));
-                       rows = min(rows, ceil(weapon_count / max_columns));
-                       columns = ceil(weapon_count / rows);
-                       weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
-                       weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
-                       vertical_order = true;
-               }
-
-               // reduce size of the panel
-               panel_size.x = columns * weapon_size.x;
-               panel_size.y = rows * weapon_size.y;
-               panel_size += '2 2 0' * panel_bg_padding;
-
-               // center the resized panel, or snap it to the screen edge when close enough
-               if(panel_pos.x > vid_conwidth * 0.001)
-               {
-                       if(panel_pos.x + old_panel_size.x > vid_conwidth * 0.999)
-                               panel_pos.x += old_panel_size.x - panel_size.x;
-                       else
-                               panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
-               }
-               else if(old_panel_size.x > vid_conwidth * 0.999)
-                       panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
-
-               if(panel_pos.y > vid_conheight * 0.001)
-               {
-                       if(panel_pos.y + old_panel_size.y > vid_conheight * 0.999)
-                               panel_pos.y += old_panel_size.y - panel_size.y;
-                       else
-                               panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
-               }
-               else if(old_panel_size.y > vid_conheight * 0.999)
-                       panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
-       }
-       else
-               weapon_count = (Weapons_COUNT - 1);
-
-       // animation for fading in/out the panel respectively when not in use
-       if(!autocvar__hud_configure)
-       {
-               if (timeout && time >= weapontime + timeout) // apply timeout effect if needed
-               {
-                       f = bound(0, (time - (weapontime + timeout)) / timeout_effect_length, 1);
-
-                       // fade the panel alpha
-                       if(autocvar_hud_panel_weapons_timeout_effect == 1)
-                       {
-                               panel_bg_alpha *= (autocvar_hud_panel_weapons_timeout_fadebgmin * f + (1 - f));
-                               panel_fg_alpha *= (autocvar_hud_panel_weapons_timeout_fadefgmin * f + (1 - f));
-                       }
-                       else if(autocvar_hud_panel_weapons_timeout_effect == 3)
-                       {
-                               panel_bg_alpha *= (1 - f);
-                               panel_fg_alpha *= (1 - f);
-                       }
-
-                       // move the panel off the screen
-                       if (autocvar_hud_panel_weapons_timeout_effect == 2 || autocvar_hud_panel_weapons_timeout_effect == 3)
-                       {
-                               f *= f; // for a cooler movement
-                               center.x = panel_pos.x + panel_size.x/2;
-                               center.y = panel_pos.y + panel_size.y/2;
-                               screen_ar = vid_conwidth/vid_conheight;
-                               if (center.x/center.y < screen_ar) //bottom left
-                               {
-                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
-                                               panel_pos.y += f * (vid_conheight - panel_pos.y);
-                                       else //left
-                                               panel_pos.x -= f * (panel_pos.x + panel_size.x);
-                               }
-                               else //top right
-                               {
-                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //right
-                                               panel_pos.x += f * (vid_conwidth - panel_pos.x);
-                                       else //top
-                                               panel_pos.y -= f * (panel_pos.y + panel_size.y);
-                               }
-                               if(f == 1)
-                                       center.x = -1; // mark the panel as off screen
-                       }
-                       weaponprevtime = time - (1 - f) * timein_effect_length;
-               }
-               else if (timeout && time < weaponprevtime + timein_effect_length) // apply timein effect if needed
-               {
-                       f = bound(0, (time - weaponprevtime) / timein_effect_length, 1);
-
-                       // fade the panel alpha
-                       if(autocvar_hud_panel_weapons_timeout_effect == 1)
-                       {
-                               panel_bg_alpha *= (autocvar_hud_panel_weapons_timeout_fadebgmin * (1 - f) + f);
-                               panel_fg_alpha *= (autocvar_hud_panel_weapons_timeout_fadefgmin * (1 - f) + f);
-                       }
-                       else if(autocvar_hud_panel_weapons_timeout_effect == 3)
-                       {
-                               panel_bg_alpha *= (f);
-                               panel_fg_alpha *= (f);
-                       }
-
-                       // move the panel back on screen
-                       if (autocvar_hud_panel_weapons_timeout_effect == 2 || autocvar_hud_panel_weapons_timeout_effect == 3)
-                       {
-                               f *= f; // for a cooler movement
-                               f = 1 - f;
-                               center.x = panel_pos.x + panel_size.x/2;
-                               center.y = panel_pos.y + panel_size.y/2;
-                               screen_ar = vid_conwidth/vid_conheight;
-                               if (center.x/center.y < screen_ar) //bottom left
-                               {
-                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
-                                               panel_pos.y += f * (vid_conheight - panel_pos.y);
-                                       else //left
-                                               panel_pos.x -= f * (panel_pos.x + panel_size.x);
-                               }
-                               else //top right
-                               {
-                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //right
-                                               panel_pos.x += f * (vid_conwidth - panel_pos.x);
-                                       else //top
-                                               panel_pos.y -= f * (panel_pos.y + panel_size.y);
-                               }
-                       }
-               }
-       }
-
-       // draw the background, then change the virtual size of it to better fit other items inside
-       HUD_Panel_DrawBg(1);
-
-       if(center.x == -1)
-               return;
-
-       if(panel_bg_padding)
-       {
-               panel_pos += '1 1 0' * panel_bg_padding;
-               panel_size -= '2 2 0' * panel_bg_padding;
-       }
-
-       // after the sizing and animations are done, update the other values
-
-       if(!rows) // if rows is > 0 onlyowned code has already updated these vars
-       {
-               vector table_size = HUD_GetTableSize_BestItemAR((Weapons_COUNT - 1), panel_size, aspect);
-               columns = table_size.x;
-               rows = table_size.y;
-               weapon_size.x = panel_size.x / columns;
-               weapon_size.y = panel_size.y / rows;
-               vertical_order = (panel_size.x / panel_size.y >= aspect);
-       }
-
-       // calculate position/size for visual bar displaying ammount of ammo status
-       if (autocvar_hud_panel_weapons_ammo)
-       {
-               ammo_color = stov(autocvar_hud_panel_weapons_ammo_color);
-               ammo_alpha = panel_fg_alpha * autocvar_hud_panel_weapons_ammo_alpha;
-
-               if(weapon_size.x/weapon_size.y > aspect)
-               {
-                       barsize.x = aspect * weapon_size.y;
-                       barsize.y = weapon_size.y;
-                       baroffset.x = (weapon_size.x - barsize.x) / 2;
-               }
-               else
-               {
-                       barsize.y = 1/aspect * weapon_size.x;
-                       barsize.x = weapon_size.x;
-                       baroffset.y = (weapon_size.y - barsize.y) / 2;
-               }
-       }
-       if(autocvar_hud_panel_weapons_accuracy)
-               Accuracy_LoadColors();
-
-       // draw items
-       row = column = 0;
-       vector label_size = '1 1 0' * min(weapon_size.x, weapon_size.y) * bound(0, autocvar_hud_panel_weapons_label_scale, 1);
-       vector noncurrent_pos = '0 0 0';
-       vector noncurrent_size = weapon_size * bound(0, autocvar_hud_panel_weapons_noncurrent_scale, 1);
-       float noncurrent_alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_weapons_noncurrent_alpha, 1);
-       bool isCurrent;
-
-       for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
-       {
-               // retrieve information about the current weapon to be drawn
-               setself(weaponorder[i]);
-               weapon_id = self.impulse;
-               isCurrent = (self.weapon == switchweapon);
-
-               // skip if this weapon doesn't exist
-               if(!self || weapon_id < 0) { continue; }
-
-               // skip this weapon if we don't own it (and onlyowned is enabled)-- or if weapons_complainbubble is showing for this weapon
-               if(autocvar_hud_panel_weapons_onlyowned)
-               if (!((weapons_stat & WepSet_FromWeapon(self.weapon)) || (self.weapon == complain_weapon)))
-                       continue;
-
-               // figure out the drawing position of weapon
-               weapon_pos = (panel_pos + eX * column * weapon_size.x + eY * row * weapon_size.y);
-               noncurrent_pos.x = weapon_pos.x + (weapon_size.x - noncurrent_size.x) / 2;
-               noncurrent_pos.y = weapon_pos.y + (weapon_size.y - noncurrent_size.y) / 2;
-
-               // draw background behind currently selected weapon
-               if(isCurrent)
-                       drawpic_aspect_skin(weapon_pos, "weapon_current_bg", weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-
-               // draw the weapon accuracy
-               if(autocvar_hud_panel_weapons_accuracy)
-               {
-                       float panel_weapon_accuracy = weapon_accuracy[self.weapon-WEP_FIRST];
-                       if(panel_weapon_accuracy >= 0)
-                       {
-                               color = Accuracy_GetColor(panel_weapon_accuracy);
-                               drawpic_aspect_skin(weapon_pos, "weapon_accuracy", weapon_size, color, panel_fg_alpha, DRAWFLAG_NORMAL);
-                       }
-               }
-
-               // drawing all the weapon items
-               if(weapons_stat & WepSet_FromWeapon(self.weapon))
-               {
-                       // draw the weapon image
-                       if(isCurrent)
-                               drawpic_aspect_skin(weapon_pos, self.model2, weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                       else
-                               drawpic_aspect_skin(noncurrent_pos, self.model2, noncurrent_size, '1 1 1', noncurrent_alpha, DRAWFLAG_NORMAL);
-
-                       // draw weapon label string
-                       switch(autocvar_hud_panel_weapons_label)
-                       {
-                               case 1: // weapon number
-                                       drawstring(weapon_pos, ftos(weapon_id), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                                       break;
-
-                               case 2: // bind
-                                       drawstring(weapon_pos, getcommandkey(ftos(weapon_id), strcat("weapon_group_", ftos(weapon_id))), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                                       break;
-
-                               case 3: // weapon name
-                                       drawstring(weapon_pos, strtolower(self.message), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                                       break;
-
-                               default: // nothing
-                                       break;
-                       }
-
-                       // draw ammo status bar
-                       if(autocvar_hud_panel_weapons_ammo && (self.ammo_field != ammo_none))
-                       {
-                               float ammo_full;
-                               a = getstati(GetAmmoStat(self.ammo_field)); // how much ammo do we have?
-
-                               if(a > 0)
-                               {
-                                       switch(self.ammo_field)
-                                       {
-                                               case ammo_shells:  ammo_full = autocvar_hud_panel_weapons_ammo_full_shells;  break;
-                                               case ammo_nails:   ammo_full = autocvar_hud_panel_weapons_ammo_full_nails;   break;
-                                               case ammo_rockets: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
-                                               case ammo_cells:   ammo_full = autocvar_hud_panel_weapons_ammo_full_cells;   break;
-                                               case ammo_plasma:  ammo_full = autocvar_hud_panel_weapons_ammo_full_plasma;  break;
-                                               case ammo_fuel:    ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel;    break;
-                                               default: ammo_full = 60;
-                                       }
-
-                                       drawsetcliparea(
-                                               weapon_pos.x + baroffset.x,
-                                               weapon_pos.y + baroffset.y,
-                                               barsize.x * bound(0, a/ammo_full, 1),
-                                               barsize.y
-                                       );
-
-                                       drawpic_aspect_skin(
-                                               weapon_pos,
-                                               "weapon_ammo",
-                                               weapon_size,
-                                               ammo_color,
-                                               ammo_alpha,
-                                               DRAWFLAG_NORMAL
-                                       );
-
-                                       drawresetcliparea();
-                               }
-                       }
-               }
-               else // draw a "ghost weapon icon" if you don't have the weapon
-               {
-                       drawpic_aspect_skin(noncurrent_pos, self.model2, noncurrent_size, '0.2 0.2 0.2', panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
-               }
-
-               // draw the complain message
-               if(self.weapon == complain_weapon)
-               {
-                       if(fadetime)
-                               a = ((complain_weapon_time + when > time) ? 1 : bound(0, (complain_weapon_time + when + fadetime - time) / fadetime, 1));
-                       else
-                               a = ((complain_weapon_time + when > time) ? 1 : 0);
-
-                       string s;
-                       if(complain_weapon_type == 0) {
-                               s = _("Out of ammo");
-                               color = stov(autocvar_hud_panel_weapons_complainbubble_color_outofammo);
-                       }
-                       else if(complain_weapon_type == 1) {
-                               s = _("Don't have");
-                               color = stov(autocvar_hud_panel_weapons_complainbubble_color_donthave);
-                       }
-                       else {
-                               s = _("Unavailable");
-                               color = stov(autocvar_hud_panel_weapons_complainbubble_color_unavailable);
-                       }
-                       float padding = autocvar_hud_panel_weapons_complainbubble_padding;
-                       drawpic_aspect_skin(weapon_pos + '1 1 0' * padding, "weapon_complainbubble", weapon_size - '2 2 0' * padding, color, a * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       drawstring_aspect(weapon_pos + '1 1 0' * padding, s, weapon_size - '2 2 0' * padding, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               }
-
-               #if 0
-               /// debug code
-               if(!autocvar_hud_panel_weapons_onlyowned)
-               {
-                       drawfill(weapon_pos + '1 1 0', weapon_size - '2 2 0', '1 1 1', panel_fg_alpha * 0.2, DRAWFLAG_NORMAL);
-                       drawstring(weapon_pos, ftos(i + 1), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
-               #endif
-
-               // continue with new position for the next weapon
-               if(vertical_order)
-               {
-                       ++column;
-                       if(column >= columns)
-                       {
-                               column = 0;
-                               ++row;
-                       }
-               }
-               else
-               {
-                       ++row;
-                       if(row >= rows)
-                       {
-                               row = 0;
-                               ++column;
-                       }
-               }
-       }
-}
-
-// Ammo (#1)
-void DrawNadeProgressBar(vector myPos, vector mySize, float progress, vector color)
-{
-       HUD_Panel_DrawProgressBar(
-               myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x,
-               mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x,
-               autocvar_hud_panel_ammo_progressbar_name,
-               progress, 0, 0, color,
-               autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-}
-
-void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time)
-{
-       float bonusNades    = getstatf(STAT_NADE_BONUS);
-       float bonusProgress = getstatf(STAT_NADE_BONUS_SCORE);
-       float bonusType     = getstati(STAT_NADE_BONUS_TYPE);
-       vector nadeColor    = Nades[bonusType].m_color;
-       string nadeIcon     = Nades[bonusType].m_icon;
-
-       vector iconPos, textPos;
-
-       if(autocvar_hud_panel_ammo_iconalign)
-       {
-               iconPos = myPos + eX * 2 * mySize.y;
-               textPos = myPos;
-       }
-       else
-       {
-               iconPos = myPos;
-               textPos = myPos + eX * mySize.y;
-       }
-
-       if(bonusNades > 0 || bonusProgress > 0)
-       {
-               DrawNadeProgressBar(myPos, mySize, bonusProgress, nadeColor);
-
-               if(autocvar_hud_panel_ammo_text)
-                       drawstring_aspect(textPos, ftos(bonusNades), eX * (2/3) * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-
-               if(draw_expanding)
-                       drawpic_aspect_skin_expanding(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, expand_time);
-
-               drawpic_aspect_skin(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       }
-}
-
-void DrawAmmoItem(vector myPos, vector mySize, .int ammoType, bool isCurrent, bool isInfinite)
-{
-       if(ammoType == ammo_none)
-               return;
-
-       // Initialize variables
-
-       int ammo;
-       if(autocvar__hud_configure)
-       {
-               isCurrent = (ammoType == ammo_rockets); // Rockets always current
-               ammo = 60;
-       }
-       else
-               ammo = getstati(GetAmmoStat(ammoType));
-
-       if(!isCurrent)
-       {
-               float scale = bound(0, autocvar_hud_panel_ammo_noncurrent_scale, 1);
-               myPos = myPos + (mySize - mySize * scale) * 0.5;
-               mySize = mySize * scale;
-       }
-
-       vector iconPos, textPos;
-       if(autocvar_hud_panel_ammo_iconalign)
-       {
-               iconPos = myPos + eX * 2 * mySize.y;
-               textPos = myPos;
-       }
-       else
-       {
-               iconPos = myPos;
-               textPos = myPos + eX * mySize.y;
-       }
-
-       bool isShadowed = (ammo <= 0 && !isCurrent && !isInfinite);
-
-       vector iconColor = isShadowed ? '0 0 0' : '1 1 1';
-       vector textColor;
-       if(isInfinite)
-               textColor = '0.2 0.95 0';
-       else if(isShadowed)
-               textColor = '0 0 0';
-       else if(ammo < 10)
-               textColor = '0.8 0.04 0';
-       else
-               textColor = '1 1 1';
-
-       float alpha;
-       if(isCurrent)
-               alpha = panel_fg_alpha;
-       else if(isShadowed)
-               alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_ammo_noncurrent_alpha, 1) * 0.5;
-       else
-               alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_ammo_noncurrent_alpha, 1);
-
-       string text = isInfinite ? "\xE2\x88\x9E" : ftos(ammo); // Use infinity symbol (U+221E)
-
-       // Draw item
-
-       if(isCurrent)
-               drawpic_aspect_skin(myPos, "ammo_current_bg", mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-
-       if(ammo > 0 && autocvar_hud_panel_ammo_progressbar)
-               HUD_Panel_DrawProgressBar(myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x, mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x, autocvar_hud_panel_ammo_progressbar_name, ammo/autocvar_hud_panel_ammo_maxammo, 0, 0, textColor, autocvar_hud_progressbar_alpha * alpha, DRAWFLAG_NORMAL);
-
-       if(autocvar_hud_panel_ammo_text)
-               drawstring_aspect(textPos, text, eX * (2/3) * mySize.x + eY * mySize.y, textColor, alpha, DRAWFLAG_NORMAL);
-
-       drawpic_aspect_skin(iconPos, GetAmmoPicture(ammoType), '1 1 0' * mySize.y, iconColor, alpha, DRAWFLAG_NORMAL);
-}
-
-int nade_prevstatus;
-int nade_prevframe;
-float nade_statuschange_time;
-void HUD_Ammo(void)
-{
-       if(hud != HUD_NORMAL) return;
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_ammo) return;
-               if(spectatee_status == -1) return;
-       }
-
-       HUD_Panel_UpdateCvars();
-
-       draw_beginBoldFont();
-
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
-       HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
-       }
-
-       int rows = 0, columns, row, column;
-       float nade_cnt = getstatf(STAT_NADE_BONUS), nade_score = getstatf(STAT_NADE_BONUS_SCORE);
-       bool draw_nades = (nade_cnt > 0 || nade_score > 0);
-       float nade_statuschange_elapsedtime;
-       int total_ammo_count;
-
-       vector ammo_size;
-       if (autocvar_hud_panel_ammo_onlycurrent)
-               total_ammo_count = 1;
-       else
-               total_ammo_count = AMMO_COUNT;
-
-       if(draw_nades)
-       {
-               ++total_ammo_count;
-               if (nade_cnt != nade_prevframe)
-               {
-                       nade_statuschange_time = time;
-                       nade_prevstatus = nade_prevframe;
-                       nade_prevframe = nade_cnt;
-               }
-       }
-       else
-               nade_prevstatus = nade_prevframe = nade_statuschange_time = 0;
-
-       rows = HUD_GetRowCount(total_ammo_count, mySize, 3);
-       columns = ceil((total_ammo_count)/rows);
-       ammo_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
-
-       vector offset = '0 0 0'; // fteqcc sucks
-       float newSize;
-       if(ammo_size.x/ammo_size.y > 3)
-       {
-               newSize = 3 * ammo_size.y;
-               offset.x = ammo_size.x - newSize;
-               pos.x += offset.x/2;
-               ammo_size.x = newSize;
-       }
-       else
-       {
-               newSize = 1/3 * ammo_size.x;
-               offset.y = ammo_size.y - newSize;
-               pos.y += offset.y/2;
-               ammo_size.y = newSize;
-       }
-
-       int i;
-       bool infinite_ammo = (getstati(STAT_ITEMS, 0, 24) & IT_UNLIMITED_WEAPON_AMMO);
-       row = column = 0;
-       if(autocvar_hud_panel_ammo_onlycurrent)
-       {
-               if(autocvar__hud_configure)
-               {
-                       DrawAmmoItem(pos, ammo_size, ammo_rockets, true, false);
-               }
-               else
-               {
-                       DrawAmmoItem(
-                               pos,
-                               ammo_size,
-                               (get_weaponinfo(switchweapon)).ammo_field,
-                               true,
-                               infinite_ammo
-                       );
-               }
-
-               ++row;
-               if(row >= rows)
-               {
-                       row = 0;
-                       column = column + 1;
-               }
-       }
-       else
-       {
-               .int ammotype;
-               row = column = 0;
-               for(i = 0; i < AMMO_COUNT; ++i)
-               {
-                       ammotype = GetAmmoFieldFromNum(i);
-                       DrawAmmoItem(
-                               pos + eX * column * (ammo_size.x + offset.x) + eY * row * (ammo_size.y + offset.y),
-                               ammo_size,
-                               ammotype,
-                               ((get_weaponinfo(switchweapon)).ammo_field == ammotype),
-                               infinite_ammo
-                       );
-
-                       ++row;
-                       if(row >= rows)
-                       {
-                               row = 0;
-                               column = column + 1;
-                       }
-               }
-       }
-
-       if (draw_nades)
-       {
-               nade_statuschange_elapsedtime = time - nade_statuschange_time;
-
-               float f = bound(0, nade_statuschange_elapsedtime*2, 1);
-
-               DrawAmmoNades(pos + eX * column * (ammo_size.x + offset.x) + eY * row * (ammo_size.y + offset.y), ammo_size, nade_prevstatus < nade_cnt && nade_cnt != 0 && f < 1, f);
-       }
-
-       draw_endBoldFont();
-}
-
-void DrawNumIcon_expanding(vector myPos, vector mySize, float x, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha, float fadelerp)
-{
-       vector newPos = '0 0 0', newSize = '0 0 0';
-       vector picpos, numpos;
-
-       if (vertical)
-       {
-               if(mySize.y/mySize.x > 2)
-               {
-                       newSize.y = 2 * mySize.x;
-                       newSize.x = mySize.x;
-
-                       newPos.y = myPos.y + (mySize.y - newSize.y) / 2;
-                       newPos.x = myPos.x;
-               }
-               else
-               {
-                       newSize.x = 1/2 * mySize.y;
-                       newSize.y = mySize.y;
-
-                       newPos.x = myPos.x + (mySize.x - newSize.x) / 2;
-                       newPos.y = myPos.y;
-               }
-
-               if(icon_right_align)
-               {
-                       numpos = newPos;
-                       picpos = newPos + eY * newSize.x;
-               }
-               else
-               {
-                       picpos = newPos;
-                       numpos = newPos + eY * newSize.x;
-               }
-
-               newSize.y /= 2;
-               drawpic_aspect_skin(picpos, icon, newSize, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
-               // make number smaller than icon, it looks better
-               // reduce only y to draw numbers with different number of digits with the same y size
-               numpos.y += newSize.y * ((1 - 0.7) / 2);
-               newSize.y *= 0.7;
-               drawstring_aspect(numpos, ftos(x), newSize, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
-               return;
-       }
-
-       if(mySize.x/mySize.y > 3)
-       {
-               newSize.x = 3 * mySize.y;
-               newSize.y = mySize.y;
-
-               newPos.x = myPos.x + (mySize.x - newSize.x) / 2;
-               newPos.y = myPos.y;
-       }
-       else
-       {
-               newSize.y = 1/3 * mySize.x;
-               newSize.x = mySize.x;
-
-               newPos.y = myPos.y + (mySize.y - newSize.y) / 2;
-               newPos.x = myPos.x;
-       }
-
-       if(icon_right_align) // right align
-       {
-               numpos = newPos;
-               picpos = newPos + eX * 2 * newSize.y;
-       }
-       else // left align
-       {
-               numpos = newPos + eX * newSize.y;
-               picpos = newPos;
-       }
-
-       // NOTE: newSize_x is always equal to 3 * mySize_y so we can use
-       // '2 1 0' * newSize_y instead of eX * (2/3) * newSize_x + eY * newSize_y
-       drawstring_aspect_expanding(numpos, ftos(x), '2 1 0' * newSize.y, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
-       drawpic_aspect_skin_expanding(picpos, icon, '1 1 0' * newSize.y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
-}
-
-void DrawNumIcon(vector myPos, vector mySize, float x, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha)
-{
-       DrawNumIcon_expanding(myPos, mySize, x, icon, vertical, icon_right_align, color, theAlpha, 0);
-}
-
-// Powerups (#2)
-//
-
-// Powerup item fields (reusing existing fields)
-.string message;  // Human readable name
-.string netname;  // Icon name
-.vector colormod; // Color
-.float count;     // Time left
-.float lifetime;  // Maximum time
-
-entity powerupItems;
-int powerupItemsCount;
-
-void resetPowerupItems()
-{
-       entity item;
-       for(item = powerupItems; item; item = item.chain)
-               item.count = 0;
-
-       powerupItemsCount = 0;
-}
-
-void addPowerupItem(string name, string icon, vector color, float currentTime, float lifeTime)
-{
-       if(!powerupItems)
-               powerupItems = spawn();
-
-       entity item;
-       for(item = powerupItems; item.count; item = item.chain)
-               if(!item.chain)
-                       item.chain = spawn();
-
-       item.message  = name;
-       item.netname  = icon;
-       item.colormod = color;
-       item.count    = currentTime;
-       item.lifetime = lifeTime;
-
-       ++powerupItemsCount;
-}
-
-int getPowerupItemAlign(int align, int column, int row, int columns, int rows, bool isVertical)
-{
-       if(align < 2)
-               return align;
-
-       bool isTop    =  isVertical && rows > 1 && row == 0;
-       bool isBottom =  isVertical && rows > 1 && row == rows-1;
-       bool isLeft   = !isVertical && columns > 1 && column == 0;
-       bool isRight  = !isVertical && columns > 1 && column == columns-1;
-
-       if(isTop    || isLeft)  return (align == 2) ? 1 : 0;
-       if(isBottom || isRight) return (align == 2) ? 0 : 1;
-
-       return 2;
-}
-
-void HUD_Powerups()
-{
-       int allItems = getstati(STAT_ITEMS, 0, 24);
-       int allBuffs = getstati(STAT_BUFFS, 0, 24);
-       int strengthTime, shieldTime, superTime;
-
-       // Initialize items
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_powerups) return;
-               if(spectatee_status == -1) return;
-               if(getstati(STAT_HEALTH) <= 0) return;
-               if(!(allItems & (ITEM_Strength.m_itemid | ITEM_Shield.m_itemid | IT_SUPERWEAPON)) && !allBuffs) return;
-
-               strengthTime = bound(0, getstatf(STAT_STRENGTH_FINISHED) - time, 99);
-               shieldTime = bound(0, getstatf(STAT_INVINCIBLE_FINISHED) - time, 99);
-               superTime = bound(0, getstatf(STAT_SUPERWEAPONS_FINISHED) - time, 99);
-
-               if(allItems & IT_UNLIMITED_SUPERWEAPONS)
-                       superTime = 99;
-
-               // Prevent stuff to show up on mismatch that will be fixed next frame
-               if(!(allItems & IT_SUPERWEAPON))
-                       superTime = 0;
-       }
-       else
-       {
-               strengthTime = 15;
-               shieldTime = 27;
-               superTime = 13;
-               allBuffs = 0;
-       }
-
-       // Add items to linked list
-       resetPowerupItems();
-
-       if(strengthTime)
-               addPowerupItem("Strength", "strength", autocvar_hud_progressbar_strength_color, strengthTime, 30);
-       if(shieldTime)
-               addPowerupItem("Shield", "shield", autocvar_hud_progressbar_shield_color, shieldTime, 30);
-       if(superTime)
-               addPowerupItem("Superweapons", "superweapons", autocvar_hud_progressbar_superweapons_color, superTime, 30);
-
-       FOREACH(Buffs, it.m_itemid & allBuffs, LAMBDA(
-               addPowerupItem(it.m_prettyName, strcat("buff_", it.m_name), it.m_color, bound(0, getstatf(STAT_BUFF_TIME) - time, 99), 60);
-       ));
-
-       if(!powerupItemsCount)
-               return;
-
-       // Draw panel background
-       HUD_Panel_UpdateCvars();
-       HUD_Panel_DrawBg(1);
-
-       // Set drawing area
-       vector pos = panel_pos;
-       vector size = panel_size;
-       bool isVertical = size.y > size.x;
-
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               size -= '2 2 0' * panel_bg_padding;
-       }
-
-       // Find best partitioning of the drawing area
-       const float DESIRED_ASPECT = 6;
-       float aspect = 0, a;
-       int columns = 0, c;
-       int rows = 0, r;
-       int i = 1;
-
-       do
-       {
-               c = floor(powerupItemsCount / i);
-               r = ceil(powerupItemsCount / c);
-               a = isVertical ? (size.y/r) / (size.x/c) : (size.x/c) / (size.y/r);
-
-               if(i == 1 || fabs(DESIRED_ASPECT - a) < fabs(DESIRED_ASPECT - aspect))
-               {
-                       aspect = a;
-                       columns = c;
-                       rows = r;
-               }
-       }
-       while(++i <= powerupItemsCount);
-
-       // Prevent single items from getting too wide
-       if(powerupItemsCount == 1 && aspect > DESIRED_ASPECT)
-       {
-               if(isVertical)
-               {
-                       size.y *= 0.5;
-                       pos.y += size.y * 0.5;
-               }
-               else
-               {
-                       size.x *= 0.5;
-                       pos.x += size.x * 0.5;
-               }
-       }
-
-       // Draw items from linked list
-       vector itemPos = pos;
-       vector itemSize = eX * (size.x / columns) + eY * (size.y / rows);
-       vector textColor = '1 1 1';
-
-       int fullSeconds = 0;
-       int align = 0;
-       int column = 0;
-       int row = 0;
-
-       draw_beginBoldFont();
-       for(entity item = powerupItems; item.count; item = item.chain)
-       {
-               itemPos = eX * (pos.x + column * itemSize.x) + eY * (pos.y + row * itemSize.y);
-
-               // Draw progressbar
-               if(autocvar_hud_panel_powerups_progressbar)
-               {
-                       align = getPowerupItemAlign(autocvar_hud_panel_powerups_baralign, column, row, columns, rows, isVertical);
-                       HUD_Panel_DrawProgressBar(itemPos, itemSize, "progressbar", item.count / item.lifetime, isVertical, align, item.colormod, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
-
-               // Draw icon and text
-               if(autocvar_hud_panel_powerups_text)
-               {
-                       align = getPowerupItemAlign(autocvar_hud_panel_powerups_iconalign, column, row, columns, rows, isVertical);
-                       fullSeconds = ceil(item.count);
-                       textColor = '0.6 0.6 0.6' + (item.colormod * 0.4);
-
-                       if(item.count > 1)
-                               DrawNumIcon(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha);
-                       if(item.count <= 5)
-                               DrawNumIcon_expanding(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha, bound(0, (fullSeconds - item.count) / 0.5, 1));
-               }
-
-               // Determine next section
-               if(isVertical)
-               {
-                       if(++column >= columns)
-                       {
-                               column = 0;
-                               ++row;
-                       }
-               }
-               else
-               {
-                       if(++row >= rows)
-                       {
-                               row = 0;
-                               ++column;
-                       }
-               }
-       }
-       draw_endBoldFont();
-}
-
-// Health/armor (#3)
-//
-
-
-void HUD_HealthArmor(void)
-{
-       int armor, health, fuel;
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_healtharmor) return;
-               if(hud != HUD_NORMAL) return;
-               if(spectatee_status == -1) return;
-
-               health = getstati(STAT_HEALTH);
-               if(health <= 0)
-               {
-                       prev_health = -1;
-                       return;
-               }
-               armor = getstati(STAT_ARMOR);
-
-               // code to check for spectatee_status changes is in Ent_ClientData()
-               // prev_p_health and prev_health can be set to -1 there
-
-               if (prev_p_health == -1)
-               {
-                       // no effect
-                       health_beforedamage = 0;
-                       armor_beforedamage = 0;
-                       health_damagetime = 0;
-                       armor_damagetime = 0;
-                       prev_health = health;
-                       prev_armor = armor;
-                       old_p_health = health;
-                       old_p_armor = armor;
-                       prev_p_health = health;
-                       prev_p_armor = armor;
-               }
-               else if (prev_health == -1)
-               {
-                       //start the load effect
-                       health_damagetime = 0;
-                       armor_damagetime = 0;
-                       prev_health = 0;
-                       prev_armor = 0;
-               }
-               fuel = getstati(STAT_FUEL);
-       }
-       else
-       {
-               health = 150;
-               armor = 75;
-               fuel = 20;
-       }
-
-       HUD_Panel_UpdateCvars();
-
-       draw_beginBoldFont();
-
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
-       HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
-       }
-
-       int baralign = autocvar_hud_panel_healtharmor_baralign;
-       int iconalign = autocvar_hud_panel_healtharmor_iconalign;
-
-    int maxhealth = autocvar_hud_panel_healtharmor_maxhealth;
-    int maxarmor = autocvar_hud_panel_healtharmor_maxarmor;
-       if(autocvar_hud_panel_healtharmor == 2) // combined health and armor display
-       {
-               vector v;
-               v = healtharmor_maxdamage(health, armor, armorblockpercent, DEATH_WEAPON.m_id);
-
-               float x;
-               x = floor(v.x + 1);
-
-        float maxtotal = maxhealth + maxarmor;
-               string biggercount;
-               if(v.z) // NOT fully armored
-               {
-                       biggercount = "health";
-                       if(autocvar_hud_panel_healtharmor_progressbar)
-                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_health, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       if(armor)
-            if(autocvar_hud_panel_healtharmor_text)
-                               drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "armor", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha * armor / health, DRAWFLAG_NORMAL);
-               }
-               else
-               {
-                       biggercount = "armor";
-                       if(autocvar_hud_panel_healtharmor_progressbar)
-                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       if(health)
-            if(autocvar_hud_panel_healtharmor_text)
-                               drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "health", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
-        if(autocvar_hud_panel_healtharmor_text)
-                       DrawNumIcon(pos, mySize, x, biggercount, 0, iconalign, HUD_Get_Num_Color(x, maxtotal), 1);
-
-               if(fuel)
-                       HUD_Panel_DrawProgressBar(pos, eX * mySize.x + eY * 0.2 * mySize.y, "progressbar", fuel/100, 0, (baralign == 1 || baralign == 3), autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
-       }
-       else
-       {
-               float panel_ar = mySize.x/mySize.y;
-               bool is_vertical = (panel_ar < 1);
-               vector health_offset = '0 0 0', armor_offset = '0 0 0';
-               if (panel_ar >= 4 || (panel_ar >= 1/4 && panel_ar < 1))
-               {
-                       mySize.x *= 0.5;
-                       if (autocvar_hud_panel_healtharmor_flip)
-                               health_offset.x = mySize.x;
-                       else
-                               armor_offset.x = mySize.x;
-               }
-               else
-               {
-                       mySize.y *= 0.5;
-                       if (autocvar_hud_panel_healtharmor_flip)
-                               health_offset.y = mySize.y;
-                       else
-                               armor_offset.y = mySize.y;
-               }
-
-               bool health_baralign, armor_baralign, fuel_baralign;
-               bool health_iconalign, armor_iconalign;
-               if (autocvar_hud_panel_healtharmor_flip)
-               {
-                       armor_baralign = (autocvar_hud_panel_healtharmor_baralign == 2 || autocvar_hud_panel_healtharmor_baralign == 1);
-                       health_baralign = (autocvar_hud_panel_healtharmor_baralign == 3 || autocvar_hud_panel_healtharmor_baralign == 1);
-                       fuel_baralign = health_baralign;
-                       armor_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 2 || autocvar_hud_panel_healtharmor_iconalign == 1);
-                       health_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 3 || autocvar_hud_panel_healtharmor_iconalign == 1);
-               }
-               else
-               {
-                       health_baralign = (autocvar_hud_panel_healtharmor_baralign == 2 || autocvar_hud_panel_healtharmor_baralign == 1);
-                       armor_baralign = (autocvar_hud_panel_healtharmor_baralign == 3 || autocvar_hud_panel_healtharmor_baralign == 1);
-                       fuel_baralign = armor_baralign;
-                       health_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 2 || autocvar_hud_panel_healtharmor_iconalign == 1);
-                       armor_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 3 || autocvar_hud_panel_healtharmor_iconalign == 1);
-               }
-
-               //if(health)
-               {
-                       if(autocvar_hud_panel_healtharmor_progressbar)
-                       {
-                               float p_health, pain_health_alpha;
-                               p_health = health;
-                               pain_health_alpha = 1;
-                               if (autocvar_hud_panel_healtharmor_progressbar_gfx)
-                               {
-                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_smooth > 0)
-                                       {
-                                               if (fabs(prev_health - health) >= autocvar_hud_panel_healtharmor_progressbar_gfx_smooth)
-                                               {
-                                                       if (time - old_p_healthtime < 1)
-                                                               old_p_health = prev_p_health;
-                                                       else
-                                                               old_p_health = prev_health;
-                                                       old_p_healthtime = time;
-                                               }
-                                               if (time - old_p_healthtime < 1)
-                                               {
-                                                       p_health += (old_p_health - health) * (1 - (time - old_p_healthtime));
-                                                       prev_p_health = p_health;
-                                               }
-                                       }
-                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0)
-                                       {
-                                               if (prev_health - health >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
-                                               {
-                                                       if (time - health_damagetime >= 1)
-                                                               health_beforedamage = prev_health;
-                                                       health_damagetime = time;
-                                               }
-                                               if (time - health_damagetime < 1)
-                                               {
-                                                       float health_damagealpha = 1 - (time - health_damagetime)*(time - health_damagetime);
-                                                       HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, health_beforedamage/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * health_damagealpha, DRAWFLAG_NORMAL);
-                                               }
-                                       }
-                                       prev_health = health;
-
-                                       if (health <= autocvar_hud_panel_healtharmor_progressbar_gfx_lowhealth)
-                                       {
-                                               float BLINK_FACTOR = 0.15;
-                                               float BLINK_BASE = 0.85;
-                                               float BLINK_FREQ = 9;
-                                               pain_health_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
-                                       }
-                               }
-                               HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, p_health/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * pain_health_alpha, DRAWFLAG_NORMAL);
-                       }
-                       if(autocvar_hud_panel_healtharmor_text)
-                               DrawNumIcon(pos + health_offset, mySize, health, "health", is_vertical, health_iconalign, HUD_Get_Num_Color(health, maxhealth), 1);
-               }
-
-               if(armor)
-               {
-                       if(autocvar_hud_panel_healtharmor_progressbar)
-                       {
-                               float p_armor;
-                               p_armor = armor;
-                               if (autocvar_hud_panel_healtharmor_progressbar_gfx)
-                               {
-                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_smooth > 0)
-                                       {
-                                               if (fabs(prev_armor - armor) >= autocvar_hud_panel_healtharmor_progressbar_gfx_smooth)
-                                               {
-                                                       if (time - old_p_armortime < 1)
-                                                               old_p_armor = prev_p_armor;
-                                                       else
-                                                               old_p_armor = prev_armor;
-                                                       old_p_armortime = time;
-                                               }
-                                               if (time - old_p_armortime < 1)
-                                               {
-                                                       p_armor += (old_p_armor - armor) * (1 - (time - old_p_armortime));
-                                                       prev_p_armor = p_armor;
-                                               }
-                                       }
-                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0)
-                                       {
-                                               if (prev_armor - armor >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
-                                               {
-                                                       if (time - armor_damagetime >= 1)
-                                                               armor_beforedamage = prev_armor;
-                                                       armor_damagetime = time;
-                                               }
-                                               if (time - armor_damagetime < 1)
-                                               {
-                                                       float armor_damagealpha = 1 - (time - armor_damagetime)*(time - armor_damagetime);
-                                                       HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, armor_beforedamage/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * armor_damagealpha, DRAWFLAG_NORMAL);
-                                               }
-                                       }
-                                       prev_armor = armor;
-                               }
-                               HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, p_armor/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       }
-                       if(autocvar_hud_panel_healtharmor_text)
-                               DrawNumIcon(pos + armor_offset, mySize, armor, "armor", is_vertical, armor_iconalign, HUD_Get_Num_Color(armor, maxarmor), 1);
-               }
-
-               if(fuel)
-               {
-                       if (is_vertical)
-                               mySize.x *= 0.2 / 2; //if vertical always halve x to not cover too much numbers with 3 digits
-                       else
-                               mySize.y *= 0.2;
-                       if (panel_ar >= 4)
-                               mySize.x *= 2; //restore full panel size
-                       else if (panel_ar < 1/4)
-                               mySize.y *= 2; //restore full panel size
-                       HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", fuel/100, is_vertical, fuel_baralign, autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
-               }
-       }
-
-       draw_endBoldFont();
-}
-
-// Notification area (#4)
-//
-
-void HUD_Notify_Push(string icon, string attacker, string victim)
-{
-       if (icon == "")
-               return;
-
-       ++notify_count;
-       --notify_index;
-
-       if (notify_index == -1)
-               notify_index = NOTIFY_MAX_ENTRIES-1;
-
-       // Free old strings
-       if (notify_attackers[notify_index])
-               strunzone(notify_attackers[notify_index]);
-
-       if (notify_victims[notify_index])
-               strunzone(notify_victims[notify_index]);
-
-       if (notify_icons[notify_index])
-               strunzone(notify_icons[notify_index]);
-
-       // Allocate new strings
-       if (victim != "")
-       {
-               notify_attackers[notify_index] = strzone(attacker);
-               notify_victims[notify_index] = strzone(victim);
-       }
-       else
-       {
-               // In case of a notification without a victim, the attacker
-               // is displayed on the victim's side. Instead of special
-               // treatment later on, we can simply switch them here.
-               notify_attackers[notify_index] = string_null;
-               notify_victims[notify_index] = strzone(attacker);
-       }
-
-       notify_icons[notify_index] = strzone(icon);
-       notify_times[notify_index] = time;
-}
-
-void HUD_Notify(void)
-{
-       if (!autocvar__hud_configure)
-               if (!autocvar_hud_panel_notify)
-                       return;
-
-       HUD_Panel_UpdateCvars();
-       HUD_Panel_DrawBg(1);
-
-       if (!autocvar__hud_configure)
-               if (notify_count == 0)
-                       return;
-
-       vector pos, size;
-       pos  = panel_pos;
-       size = panel_size;
-
-       if (panel_bg_padding)
-       {
-               pos  += '1 1 0' * panel_bg_padding;
-               size -= '2 2 0' * panel_bg_padding;
-       }
-
-       float fade_start = max(0, autocvar_hud_panel_notify_time);
-       float fade_time = max(0, autocvar_hud_panel_notify_fadetime);
-       float icon_aspect = max(1, autocvar_hud_panel_notify_icon_aspect);
-
-       int entry_count = bound(1, floor(NOTIFY_MAX_ENTRIES * size.y / size.x), NOTIFY_MAX_ENTRIES);
-       float entry_height = size.y / entry_count;
-
-       float panel_width_half = size.x * 0.5;
-       float icon_width_half = entry_height * icon_aspect / 2;
-       float name_maxwidth = panel_width_half - icon_width_half - size.x * NOTIFY_ICON_MARGIN;
-
-       vector font_size = '0.5 0.5 0' * entry_height * autocvar_hud_panel_notify_fontsize;
-       vector icon_size = (eX * icon_aspect + eY) * entry_height;
-       vector icon_left = eX * (panel_width_half - icon_width_half);
-       vector attacker_right = eX * name_maxwidth;
-       vector victim_left = eX * (size.x - name_maxwidth);
-
-       vector attacker_pos, victim_pos, icon_pos;
-       string attacker, victim, icon;
-       int i, j, count, step, limit;
-       float alpha;
-
-       if (autocvar_hud_panel_notify_flip)
-       {
-               // Order items from the top down
-               i = 0;
-               step = +1;
-               limit = entry_count;
-       }
-       else
-       {
-               // Order items from the bottom up
-               i = entry_count - 1;
-               step = -1;
-               limit = -1;
-       }
-
-       for (j = notify_index, count = 0; i != limit; i += step, ++j, ++count)
-       {
-               if(autocvar__hud_configure)
-               {
-                       attacker = sprintf(_("Player %d"), count + 1);
-                       victim = sprintf(_("Player %d"), count + 2);
-                       icon = get_weaponinfo(min(WEP_FIRST + count * 2, WEP_LAST)).model2;
-                       alpha = bound(0, 1.2 - count / entry_count, 1);
-               }
-               else
-               {
-                       if (j == NOTIFY_MAX_ENTRIES)
-                               j = 0;
-
-                       if (notify_times[j] + fade_start > time)
-                               alpha = 1;
-                       else if (fade_time != 0)
-                       {
-                               alpha = bound(0, (notify_times[j] + fade_start + fade_time - time) / fade_time, 1);
-                               if (alpha == 0)
-                                       break;
-                       }
-                       else
-                               break;
-
-                       attacker = notify_attackers[j];
-                       victim = notify_victims[j];
-                       icon = notify_icons[j];
-               }
-
-               if (icon != "" && victim != "")
-               {
-                       vector name_top = eY * (i * entry_height + 0.5 * (entry_height - font_size.y));
-
-                       icon_pos = pos + icon_left + eY * i * entry_height;
-                       drawpic_aspect_skin(icon_pos, icon, icon_size, '1 1 1', panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
-
-                       victim = textShortenToWidth(victim, name_maxwidth, font_size, stringwidth_colors);
-                       victim_pos = pos + victim_left + name_top;
-                       drawcolorcodedstring(victim_pos, victim, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
-
-                       if (attacker != "")
-                       {
-                               attacker = textShortenToWidth(attacker, name_maxwidth, font_size, stringwidth_colors);
-                               attacker_pos = pos + attacker_right - eX * stringwidth(attacker, true, font_size) + name_top;
-                               drawcolorcodedstring(attacker_pos, attacker, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
-                       }
-               }
-       }
-
-       notify_count = count;
-}
-
-void HUD_Timer(void)
-{
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_timer) return;
-       }
-
-       HUD_Panel_UpdateCvars();
-
-       draw_beginBoldFont();
-
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
-       HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
-       }
-
-       string timer;
-       float timelimit, elapsedTime, timeleft, minutesLeft;
-
-       timelimit = getstatf(STAT_TIMELIMIT);
-
-       timeleft = max(0, timelimit * 60 + getstatf(STAT_GAMESTARTTIME) - time);
-       timeleft = ceil(timeleft);
-
-       minutesLeft = floor(timeleft / 60);
-
-       vector timer_color;
-       if(minutesLeft >= 5 || warmup_stage || timelimit == 0) //don't use red or yellow in warmup or when there is no timelimit
-               timer_color = '1 1 1'; //white
-       else if(minutesLeft >= 1)
-               timer_color = '1 1 0'; //yellow
-       else
-               timer_color = '1 0 0'; //red
-
-       if (autocvar_hud_panel_timer_increment || timelimit == 0 || warmup_stage) {
-               if (time < getstatf(STAT_GAMESTARTTIME)) {
-                       //while restart is still active, show 00:00
-                       timer = seconds_tostring(0);
-               } else {
-                       elapsedTime = floor(time - getstatf(STAT_GAMESTARTTIME)); //127
-                       timer = seconds_tostring(elapsedTime);
-               }
-       } else {
-               timer = seconds_tostring(timeleft);
-       }
-
-       drawstring_aspect(pos, timer, mySize, timer_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-
-       draw_endBoldFont();
-}
-
-// Radar (#6)
-//
-
-float HUD_Radar_Clickable()
-{
-       return hud_panel_radar_mouse && !hud_panel_radar_temp_hidden;
-}
-
-void HUD_Radar_Show_Maximized(bool doshow,float clickable)
-{
-       hud_panel_radar_maximized = doshow;
-       hud_panel_radar_temp_hidden = 0;
-
-       if ( doshow )
-       {
-               if (clickable)
-               {
-                       if(autocvar_hud_cursormode)
-                               setcursormode(1);
-                       hud_panel_radar_mouse = 1;
-               }
-       }
-       else if ( hud_panel_radar_mouse )
-       {
-               hud_panel_radar_mouse = 0;
-               mouseClicked = 0;
-               if(autocvar_hud_cursormode)
-               if(!mv_active)
-                       setcursormode(0);
-       }
-}
-void HUD_Radar_Hide_Maximized()
-{
-       HUD_Radar_Show_Maximized(false,false);
-}
-
-
-float HUD_Radar_InputEvent(float bInputType, float nPrimary, float nSecondary)
-{
-       if(!hud_panel_radar_maximized || !hud_panel_radar_mouse ||
-               autocvar__hud_configure || mv_active)
-               return false;
-
-       if(bInputType == 3)
-       {
-               mousepos_x = nPrimary;
-               mousepos_y = nSecondary;
-               return true;
-       }
-
-       if(nPrimary == K_MOUSE1)
-       {
-               if(bInputType == 0) // key pressed
-                       mouseClicked |= S_MOUSE1;
-               else if(bInputType == 1) // key released
-                       mouseClicked -= (mouseClicked & S_MOUSE1);
-       }
-       else if(nPrimary == K_MOUSE2)
-       {
-               if(bInputType == 0) // key pressed
-                       mouseClicked |= S_MOUSE2;
-               else if(bInputType == 1) // key released
-                       mouseClicked -= (mouseClicked & S_MOUSE2);
-       }
-       else if ( nPrimary == K_ESCAPE && bInputType == 0 )
-       {
-               HUD_Radar_Hide_Maximized();
-       }
-       else
-       {
-               // allow console/use binds to work without hiding the map
-               string con_keys;
-               float keys;
-               float i;
-               con_keys = strcat(findkeysforcommand("toggleconsole", 0)," ",findkeysforcommand("+use", 0)) ;
-               keys = tokenize(con_keys); // findkeysforcommand returns data for this
-               for (i = 0; i < keys; ++i)
-               {
-                       if(nPrimary == stof(argv(i)))
-                               return false;
-               }
-
-               if ( getstati(STAT_HEALTH) <= 0 )
-               {
-                       // Show scoreboard
-                       if ( bInputType < 2 )
-                       {
-                               con_keys = findkeysforcommand("+showscores", 0);
-                               keys = tokenize(con_keys);
-                               for (i = 0; i < keys; ++i)
-                               {
-                                       if ( nPrimary == stof(argv(i)) )
-                                       {
-                                               hud_panel_radar_temp_hidden = bInputType == 0;
-                                               return false;
-                                       }
-                               }
-                       }
-               }
-               else if ( bInputType == 0 )
-                       HUD_Radar_Hide_Maximized();
-
-               return false;
-       }
-
-       return true;
-}
-
-void HUD_Radar_Mouse()
-{
-       if ( !hud_panel_radar_mouse ) return;
-       if(mv_active) return;
-
-       if ( intermission )
-       {
-               HUD_Radar_Hide_Maximized();
-               return;
-       }
-
-       if(mouseClicked & S_MOUSE2)
-       {
-               HUD_Radar_Hide_Maximized();
-               return;
-       }
-
-       if(!autocvar_hud_cursormode)
-       {
-               mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
-
-               mousepos_x = bound(0, mousepos_x, vid_conwidth);
-               mousepos_y = bound(0, mousepos_y, vid_conheight);
-       }
-
-       HUD_Panel_UpdateCvars();
-
-
-       panel_size = autocvar_hud_panel_radar_maximized_size;
-       panel_size_x = bound(0.2, panel_size_x, 1) * vid_conwidth;
-       panel_size_y = bound(0.2, panel_size_y, 1) * vid_conheight;
-       panel_pos_x = (vid_conwidth - panel_size_x) / 2;
-       panel_pos_y = (vid_conheight - panel_size_y) / 2;
-
-       if(mouseClicked & S_MOUSE1)
-       {
-               // click outside
-               if ( mousepos_x < panel_pos_x || mousepos_x > panel_pos_x + panel_size_x ||
-                        mousepos_y < panel_pos_y || mousepos_y > panel_pos_y + panel_size_y )
-               {
-                       HUD_Radar_Hide_Maximized();
-                       return;
-               }
-               vector pos = teamradar_texcoord_to_3dcoord(teamradar_2dcoord_to_texcoord(mousepos),view_origin_z);
-               localcmd(sprintf("cmd ons_spawn %f %f %f",pos_x,pos_y,pos_z));
-
-               HUD_Radar_Hide_Maximized();
-               return;
-       }
-
-
-       const vector cursor_size = '32 32 0';
-       drawpic(mousepos-'8 4 0', strcat("gfx/menu/", autocvar_menu_skin, "/cursor.tga"), cursor_size, '1 1 1', 0.8, DRAWFLAG_NORMAL);
-}
-
-void HUD_Radar(void)
-{
-       if (!autocvar__hud_configure)
-       {
-               if (hud_panel_radar_maximized)
-               {
-                       if (!hud_draw_maximized) return;
-               }
-               else
-               {
-                       if (autocvar_hud_panel_radar == 0) return;
-                       if (autocvar_hud_panel_radar != 2 && !teamplay) return;
-                       if(radar_panel_modified)
-                       {
-                               panel.update_time = time; // forces reload of panel attributes
-                               radar_panel_modified = false;
-                       }
-               }
-       }
-
-       if ( hud_panel_radar_temp_hidden )
-               return;
-
-       HUD_Panel_UpdateCvars();
-
-       float f = 0;
-
-       if (hud_panel_radar_maximized && !autocvar__hud_configure)
-       {
-               panel_size = autocvar_hud_panel_radar_maximized_size;
-               panel_size.x = bound(0.2, panel_size.x, 1) * vid_conwidth;
-               panel_size.y = bound(0.2, panel_size.y, 1) * vid_conheight;
-               panel_pos.x = (vid_conwidth - panel_size.x) / 2;
-               panel_pos.y = (vid_conheight - panel_size.y) / 2;
-
-               string panel_bg;
-               panel_bg = strcat(hud_skin_path, "/border_default"); // always use the default border when maximized
-               if(precache_pic(panel_bg) == "")
-                       panel_bg = "gfx/hud/default/border_default"; // fallback
-               if(!radar_panel_modified && panel_bg != panel.current_panel_bg)
-                       radar_panel_modified = true;
-               if(panel.current_panel_bg)
-                       strunzone(panel.current_panel_bg);
-               panel.current_panel_bg = strzone(panel_bg);
-
-               switch(hud_panel_radar_maximized_zoommode)
-               {
-                       default:
-                       case 0:
-                               f = current_zoomfraction;
-                               break;
-                       case 1:
-                               f = 1 - current_zoomfraction;
-                               break;
-                       case 2:
-                               f = 0;
-                               break;
-                       case 3:
-                               f = 1;
-                               break;
-               }
-
-               switch(hud_panel_radar_maximized_rotation)
-               {
-                       case 0:
-                               teamradar_angle = view_angles.y - 90;
-                               break;
-                       default:
-                               teamradar_angle = 90 * hud_panel_radar_maximized_rotation;
-                               break;
-               }
-       }
-       if (!hud_panel_radar_maximized && !autocvar__hud_configure)
-       {
-               switch(hud_panel_radar_zoommode)
-               {
-                       default:
-                       case 0:
-                               f = current_zoomfraction;
-                               break;
-                       case 1:
-                               f = 1 - current_zoomfraction;
-                               break;
-                       case 2:
-                               f = 0;
-                               break;
-                       case 3:
-                               f = 1;
-                               break;
-               }
-
-               switch(hud_panel_radar_rotation)
-               {
-                       case 0:
-                               teamradar_angle = view_angles.y - 90;
-                               break;
-                       default:
-                               teamradar_angle = 90 * hud_panel_radar_rotation;
-                               break;
-               }
-       }
-
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
-       HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
-       }
-
-       int color2;
-       entity tm;
-       float scale2d, normalsize, bigsize;
-
-       teamradar_origin2d = pos + 0.5 * mySize;
-       teamradar_size2d = mySize;
-
-       if(minimapname == "")
-               return;
-
-       teamradar_loadcvars();
-
-       scale2d = vlen_maxnorm2d(mi_picmax - mi_picmin);
-       teamradar_size2d = mySize;
-
-       teamradar_extraclip_mins = teamradar_extraclip_maxs = '0 0 0'; // we always center
-
-       // pixels per world qu to match the teamradar_size2d_x range in the longest dimension
-       if((hud_panel_radar_rotation == 0 && !hud_panel_radar_maximized) || (hud_panel_radar_maximized_rotation == 0 && hud_panel_radar_maximized))
-       {
-               // max-min distance must fit the radar in any rotation
-               bigsize = vlen_minnorm2d(teamradar_size2d) * scale2d / (1.05 * vlen2d(mi_scale));
-       }
-       else
-       {
-               vector c0, c1, c2, c3, span;
-               c0 = rotate(mi_min, teamradar_angle * DEG2RAD);
-               c1 = rotate(mi_max, teamradar_angle * DEG2RAD);
-               c2 = rotate('1 0 0' * mi_min.x + '0 1 0' * mi_max.y, teamradar_angle * DEG2RAD);
-               c3 = rotate('1 0 0' * mi_max.x + '0 1 0' * mi_min.y, teamradar_angle * DEG2RAD);
-               span = '0 0 0';
-               span.x = max(c0_x, c1_x, c2_x, c3_x) - min(c0_x, c1_x, c2_x, c3_x);
-               span.y = max(c0_y, c1_y, c2_y, c3_y) - min(c0_y, c1_y, c2_y, c3_y);
-
-               // max-min distance must fit the radar in x=x, y=y
-               bigsize = min(
-                       teamradar_size2d.x * scale2d / (1.05 * span.x),
-                       teamradar_size2d.y * scale2d / (1.05 * span.y)
-               );
-       }
-
-       normalsize = vlen_maxnorm2d(teamradar_size2d) * scale2d / hud_panel_radar_scale;
-       if(bigsize > normalsize)
-               normalsize = bigsize;
-
-       teamradar_size =
-                 f * bigsize
-               + (1 - f) * normalsize;
-       teamradar_origin3d_in_texcoord = teamradar_3dcoord_to_texcoord(
-                 f * mi_center
-               + (1 - f) * view_origin);
-
-       drawsetcliparea(
-               pos.x,
-               pos.y,
-               mySize.x,
-               mySize.y
-       );
-
-       draw_teamradar_background(hud_panel_radar_foreground_alpha);
-
-       for(tm = world; (tm = find(tm, classname, "radarlink")); )
-               draw_teamradar_link(tm.origin, tm.velocity, tm.team);
-
-       vector coord;
-       vector brightcolor;
-       for(tm = world; (tm = findflags(tm, teamradar_icon, 0xFFFFFF)); )
-       {
-               if ( hud_panel_radar_mouse )
-               if ( tm.health > 0 )
-               if ( tm.team == myteam+1 )
-               {
-                       coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(tm.origin));
-                       if ( vlen(mousepos-coord) < 8 )
-                       {
-                               brightcolor_x = min(1,tm.teamradar_color_x*1.5);
-                               brightcolor_y = min(1,tm.teamradar_color_y*1.5);
-                               brightcolor_z = min(1,tm.teamradar_color_z*1.5);
-                               drawpic(coord - '8 8 0', "gfx/teamradar_icon_glow", '16 16 0', brightcolor, panel_fg_alpha, 0);
-                       }
-               }
-               entity icon = RadarIcons[tm.teamradar_icon];
-               draw_teamradar_icon(tm.origin, icon, tm, spritelookupcolor(tm, icon.netname, tm.teamradar_color), panel_fg_alpha);
-       }
-       for(tm = world; (tm = find(tm, classname, "entcs_receiver")); )
-       {
-               color2 = GetPlayerColor(tm.sv_entnum);
-               //if(color == NUM_SPECTATOR || color == color2)
-                       draw_teamradar_player(tm.origin, tm.angles, Team_ColorRGB(color2));
-       }
-       draw_teamradar_player(view_origin, view_angles, '1 1 1');
-
-       drawresetcliparea();
-
-       if ( hud_panel_radar_mouse )
-       {
-               string message = "Click to select teleport destination";
-
-               if ( getstati(STAT_HEALTH) <= 0 )
-               {
-                       message = "Click to select spawn location";
-               }
-
-               drawcolorcodedstring(pos + '0.5 0 0' * (mySize_x - stringwidth(message, true, hud_fontsize)) - '0 1 0' * hud_fontsize_y * 2,
-                                                        message, hud_fontsize, hud_panel_radar_foreground_alpha, DRAWFLAG_NORMAL);
-
-               hud_panel_radar_bottom = pos_y + mySize_y + hud_fontsize_y;
-       }
-}
-
-// Score (#7)
-//
-void HUD_UpdatePlayerTeams();
-void HUD_Score_Rankings(vector pos, vector mySize, entity me)
-{
-       float score;
-       entity tm = world, pl;
-       int SCOREPANEL_MAX_ENTRIES = 6;
-       float SCOREPANEL_ASPECTRATIO = 2;
-       int entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize.y/mySize.x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
-       vector fontsize = '1 1 0' * (mySize.y/entries);
-
-       vector rgb, score_color;
-       rgb = '1 1 1';
-       score_color = '1 1 1';
-
-       float name_size = mySize.x*0.75;
-       float spacing_size = mySize.x*0.04;
-       const float highlight_alpha = 0.2;
-       int i = 0, first_pl = 0;
-       bool me_printed = false;
-       string s;
-       if (autocvar__hud_configure)
-       {
-               float players_per_team = 0;
-               if (team_count)
-               {
-                       // show team scores in the first line
-                       float score_size = mySize.x / team_count;
-                       players_per_team = max(2, ceil((entries - 1) / team_count));
-                       for(i=0; i<team_count; ++i) {
-                               if (i == floor((entries - 2) / players_per_team) || (entries == 1 && i == 0))
-                                       HUD_Panel_DrawHighlight(pos + eX * score_size * i, eX * score_size + eY * fontsize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring_aspect(pos + eX * score_size * i, ftos(175 - 23*i), eX * score_size + eY * fontsize.y, Team_ColorRGB(ColorByTeam(i)) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
-                       }
-                       first_pl = 1;
-                       pos.y += fontsize.y;
-               }
-               score = 10 + SCOREPANEL_MAX_ENTRIES * 3;
-               for (i=first_pl; i<entries; ++i)
-               {
-                       //simulate my score is lower than all displayed players,
-                       //so that I don't appear at all showing pure rankings.
-                       //This is to better show the difference between the 2 ranking views
-                       if (i == entries-1 && autocvar_hud_panel_score_rankings == 1)
-                       {
-                               rgb = '1 1 0';
-                               drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                               s = GetPlayerName(player_localnum);
-                               score = 7;
-                       }
-                       else
-                       {
-                               s = sprintf(_("Player %d"), i + 1 - first_pl);
-                               score -= 3;
-                       }
-
-                       if (team_count)
-                               score_color = Team_ColorRGB(ColorByTeam(floor((i - first_pl) / players_per_team))) * 0.8;
-                       s = textShortenToWidth(s, name_size, fontsize, stringwidth_colors);
-                       drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
-                       drawstring(pos + eX * (name_size + spacing_size), ftos(score), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-                       pos.y += fontsize.y;
-               }
-               return;
-       }
-
-       if (!scoreboard_fade_alpha) // the scoreboard too calls HUD_UpdatePlayerTeams
-               HUD_UpdatePlayerTeams();
-       if (team_count)
-       {
-               // show team scores in the first line
-               float score_size = mySize.x / team_count;
-               for(tm = teams.sort_next; tm; tm = tm.sort_next) {
-                       if(tm.team == NUM_SPECTATOR)
-                               continue;
-                       if (tm.team == myteam)
-                               drawfill(pos + eX * score_size * i, eX * score_size + eY * fontsize.y, '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores[ts_primary])), eX * score_size + eY * fontsize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
-                       ++i;
-               }
-               first_pl = 1;
-               pos.y += fontsize.y;
-               tm = teams.sort_next;
-       }
-       i = first_pl;
-
-       do
-       for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
-       {
-               if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
-                       continue;
-
-               if (i == entries-1 && !me_printed && pl != me)
-               if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
-               {
-                       for (pl = me.sort_next; pl; pl = pl.sort_next)
-                               if (pl.team != NUM_SPECTATOR)
-                                       break;
-
-                       if (pl)
-                               rgb = '1 1 0'; //not last but not among the leading players: yellow
-                       else
-                               rgb = '1 0 0'; //last: red
-                       pl = me;
-               }
-
-               if (pl == me)
-               {
-                       if (i == first_pl)
-                               rgb = '0 1 0'; //first: green
-                       me_printed = true;
-                       drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
-               if (team_count)
-                       score_color = Team_ColorRGB(pl.team) * 0.8;
-               s = textShortenToWidth(GetPlayerName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
-               drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores[ps_primary])), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-               pos.y += fontsize.y;
-               ++i;
-       }
-       while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
-}
-
-void HUD_Score(void)
-{
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_score) return;
-               if(spectatee_status == -1 && (gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
-       }
-
-       HUD_Panel_UpdateCvars();
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
-       HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
-       }
-
-       float score, distribution = 0;
-       string sign;
-       vector distribution_color;
-       entity tm, pl, me;
-
-       me = playerslots[current_player];
-
-       if((scores_flags[ps_primary] & SFL_TIME) && !teamplay) { // race/cts record display on HUD
-               string timer, distrtimer;
-
-               pl = players.sort_next;
-               if(pl == me)
-                       pl = pl.sort_next;
-               if(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)
-                       if(pl.scores[ps_primary] == 0)
-                               pl = world;
-
-               score = me.(scores[ps_primary]);
-               timer = TIME_ENCODED_TOSTRING(score);
-
-               draw_beginBoldFont();
-               if (pl && ((!(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)) || score)) {
-                       // distribution display
-                       distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
-
-                       distrtimer = ftos_decimals(fabs(distribution/pow(10, TIME_DECIMALS)), TIME_DECIMALS);
-
-                       if (distribution <= 0) {
-                               distribution_color = '0 1 0';
-                               sign = "-";
-                       }
-                       else {
-                               distribution_color = '1 0 0';
-                               sign = "+";
-                       }
-                       drawstring_aspect(pos + eX * 0.75 * mySize.x, strcat(sign, distrtimer), eX * 0.25 * mySize.x + eY * (1/3) * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
-               // race record display
-               if (distribution <= 0)
-                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(pos, timer, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               draw_endBoldFont();
-       } else if (!teamplay) { // non-teamgames
-               if ((spectatee_status == -1 && !autocvar__hud_configure) || autocvar_hud_panel_score_rankings)
-               {
-                       HUD_Score_Rankings(pos, mySize, me);
-                       return;
-               }
-               // me vector := [team/connected frags id]
-               pl = players.sort_next;
-               if(pl == me)
-                       pl = pl.sort_next;
-
-               if(autocvar__hud_configure)
-                       distribution = 42;
-               else if(pl)
-                       distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
-               else
-                       distribution = 0;
-
-               score = me.(scores[ps_primary]);
-               if(autocvar__hud_configure)
-                       score = 123;
-
-               if(distribution >= 5)
-                       distribution_color = eY;
-               else if(distribution >= 0)
-                       distribution_color = '1 1 1';
-               else if(distribution >= -5)
-                       distribution_color = '1 1 0';
-               else
-                       distribution_color = eX;
-
-               string distribution_str;
-               distribution_str = ftos(distribution);
-               draw_beginBoldFont();
-               if (distribution >= 0)
-               {
-                       if (distribution > 0)
-                               distribution_str = strcat("+", distribution_str);
-                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
-               drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(pos + eX * 0.75 * mySize.x, distribution_str, eX * 0.25 * mySize.x + eY * (1/3) * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-               draw_endBoldFont();
-       } else { // teamgames
-               float row, column, rows = 0, columns = 0;
-               vector offset = '0 0 0';
-               vector score_pos, score_size; //for scores other than myteam
-               if(autocvar_hud_panel_score_rankings)
-               {
-                       HUD_Score_Rankings(pos, mySize, me);
-                       return;
-               }
-               if(spectatee_status == -1)
-               {
-                       rows = HUD_GetRowCount(team_count, mySize, 3);
-                       columns = ceil(team_count/rows);
-                       score_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
-
-                       float newSize;
-                       if(score_size.x/score_size.y > 3)
-                       {
-                               newSize = 3 * score_size.y;
-                               offset.x = score_size.x - newSize;
-                               pos.x += offset.x/2;
-                               score_size.x = newSize;
-                       }
-                       else
-                       {
-                               newSize = 1/3 * score_size.x;
-                               offset.y = score_size.y - newSize;
-                               pos.y += offset.y/2;
-                               score_size.y = newSize;
-                       }
-               }
-               else
-                       score_size = eX * mySize.x*(1/4) + eY * mySize.y*(1/3);
-
-               float max_fragcount;
-               max_fragcount = -99;
-               draw_beginBoldFont();
-               row = column = 0;
-               for(tm = teams.sort_next; tm; tm = tm.sort_next) {
-                       if(tm.team == NUM_SPECTATOR)
-                               continue;
-                       score = tm.(teamscores[ts_primary]);
-                       if(autocvar__hud_configure)
-                               score = 123;
-
-                       if (score > max_fragcount)
-                               max_fragcount = score;
-
-                       if (spectatee_status == -1)
-                       {
-                               score_pos = pos + eX * column * (score_size.x + offset.x) + eY * row * (score_size.y + offset.y);
-                               if (max_fragcount == score)
-                                       HUD_Panel_DrawHighlight(score_pos, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring_aspect(score_pos, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
-                               ++row;
-                               if(row >= rows)
-                               {
-                                       row = 0;
-                                       ++column;
-                               }
-                       }
-                       else if(tm.team == myteam) {
-                               if (max_fragcount == score)
-                                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
-                       } else {
-                               if (max_fragcount == score)
-                                       HUD_Panel_DrawHighlight(pos + eX * 0.75 * mySize.x + eY * (1/3) * rows * mySize.y, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring_aspect(pos + eX * 0.75 * mySize.x + eY * (1/3) * rows * mySize.y, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
-                               ++rows;
-                       }
-               }
-               draw_endBoldFont();
-       }
-}
-
-// Race timer (#8)
-//
-void HUD_RaceTimer (void)
-{
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_racetimer) return;
-               if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
-               if(spectatee_status == -1) return;
-       }
-
-       HUD_Panel_UpdateCvars();
-
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
-       HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
-       }
-
-       // always force 4:1 aspect
-       vector newSize = '0 0 0';
-       if(mySize.x/mySize.y > 4)
-       {
-               newSize.x = 4 * mySize.y;
-               newSize.y = mySize.y;
-
-               pos.x = pos.x + (mySize.x - newSize.x) / 2;
-       }
-       else
-       {
-               newSize.y = 1/4 * mySize.x;
-               newSize.x = mySize.x;
-
-               pos.y = pos.y + (mySize.y - newSize.y) / 2;
-       }
-       mySize = newSize;
-
-       float a, t;
-       string s, forcetime;
-
-       if(autocvar__hud_configure)
-       {
-               s = "0:13:37";
-               draw_beginBoldFont();
-               drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.60 0.60 0' * mySize.y), s, '0.60 0.60 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               draw_endBoldFont();
-               s = _("^1Intermediate 1 (+15.42)");
-               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.20 * mySize.y) + eY * 0.60 * mySize.y, s, '1 1 0' * 0.20 * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
-               s = sprintf(_("^1PENALTY: %.1f (%s)"), 2, "missing a checkpoint");
-               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.20 * mySize.y) + eY * 0.80 * mySize.y, s, '1 1 0' * 0.20 * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
-       }
-       else if(race_checkpointtime)
-       {
-               a = bound(0, 2 - (time - race_checkpointtime), 1);
-               s = "";
-               forcetime = "";
-               if(a > 0) // just hit a checkpoint?
-               {
-                       if(race_checkpoint != 254)
-                       {
-                               if(race_time && race_previousbesttime)
-                                       s = MakeRaceString(race_checkpoint, TIME_DECODE(race_time) - TIME_DECODE(race_previousbesttime), 0, 0, race_previousbestname);
-                               else
-                                       s = MakeRaceString(race_checkpoint, 0, -1, 0, race_previousbestname);
-                               if(race_time)
-                                       forcetime = TIME_ENCODED_TOSTRING(race_time);
-                       }
-               }
-               else
-               {
-                       if(race_laptime && race_nextbesttime && race_nextcheckpoint != 254)
-                       {
-                               a = bound(0, 2 - ((race_laptime + TIME_DECODE(race_nextbesttime)) - (time + TIME_DECODE(race_penaltyaccumulator))), 1);
-                               if(a > 0) // next one?
-                               {
-                                       s = MakeRaceString(race_nextcheckpoint, (time + TIME_DECODE(race_penaltyaccumulator)) - race_laptime, TIME_DECODE(race_nextbesttime), 0, race_nextbestname);
-                               }
-                       }
-               }
-
-               if(s != "" && a > 0)
-               {
-                       drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               }
-
-               if(race_penaltytime)
-               {
-                       a = bound(0, 2 - (time - race_penaltyeventtime), 1);
-                       if(a > 0)
-                       {
-                               s = sprintf(_("^1PENALTY: %.1f (%s)"), race_penaltytime * 0.1, race_penaltyreason);
-                               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.8 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                       }
-               }
-
-               draw_beginBoldFont();
-
-               if(forcetime != "")
-               {
-                       a = bound(0, (time - race_checkpointtime) / 0.5, 1);
-                       drawstring_expanding(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(forcetime, false, '1 1 0' * 0.6 * mySize.y), forcetime, '1 1 0' * 0.6 * mySize.y, '1 1 1', panel_fg_alpha, 0, a);
-               }
-               else
-                       a = 1;
-
-               if(race_laptime && race_checkpoint != 255)
-               {
-                       s = TIME_ENCODED_TOSTRING(TIME_ENCODE(time + TIME_DECODE(race_penaltyaccumulator) - race_laptime));
-                       drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.6 0.6 0' * mySize.y), s, '0.6 0.6 0' * mySize.y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               }
-
-               draw_endBoldFont();
-       }
-       else
-       {
-               if(race_mycheckpointtime)
-               {
-                       a = bound(0, 2 - (time - race_mycheckpointtime), 1);
-                       s = MakeRaceString(race_mycheckpoint, TIME_DECODE(race_mycheckpointdelta), -(race_mycheckpointenemy == ""), race_mycheckpointlapsdelta, race_mycheckpointenemy);
-                       drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               }
-               if(race_othercheckpointtime && race_othercheckpointenemy != "")
-               {
-                       a = bound(0, 2 - (time - race_othercheckpointtime), 1);
-                       s = MakeRaceString(race_othercheckpoint, -TIME_DECODE(race_othercheckpointdelta), -(race_othercheckpointenemy == ""), race_othercheckpointlapsdelta, race_othercheckpointenemy);
-                       drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               }
-
-               if(race_penaltytime && !race_penaltyaccumulator)
-               {
-                       t = race_penaltytime * 0.1 + race_penaltyeventtime;
-                       a = bound(0, (1 + t - time), 1);
-                       if(a > 0)
-                       {
-                               if(time < t)
-                                       s = sprintf(_("^1PENALTY: %.1f (%s)"), (t - time) * 0.1, race_penaltyreason);
-                               else
-                                       s = sprintf(_("^2PENALTY: %.1f (%s)"), 0, race_penaltyreason);
-                               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                       }
-               }
-       }
-}
-
-// Vote window (#9)
-//
-
-void HUD_Vote(void)
-{
-       if(autocvar_cl_allow_uid2name == -1 && (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
-       {
-               vote_active = 1;
-               if (autocvar__hud_configure)
-               {
-                       vote_yescount = 0;
-                       vote_nocount = 0;
-                       LOG_INFO(_("^1You must answer before entering hud configure mode\n"));
-                       cvar_set("_hud_configure", "0");
-               }
-               if(vote_called_vote)
-                       strunzone(vote_called_vote);
-               vote_called_vote = strzone(_("^2Name ^7instead of \"^1Anonymous player^7\" in stats"));
-               uid2name_dialog = 1;
-       }
-
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_vote) return;
-
-               panel_fg_alpha = autocvar_hud_panel_fg_alpha;
-               panel_bg_alpha_str = autocvar_hud_panel_vote_bg_alpha;
-
-               if(panel_bg_alpha_str == "") {
-                       panel_bg_alpha_str = ftos(autocvar_hud_panel_bg_alpha);
-               }
-               panel_bg_alpha = stof(panel_bg_alpha_str);
-       }
-       else
-       {
-               vote_yescount = 3;
-               vote_nocount = 2;
-               vote_needed = 4;
-       }
-
-       string s;
-       float a;
-       if(vote_active != vote_prev) {
-               vote_change = time;
-               vote_prev = vote_active;
-       }
-
-       if(vote_active || autocvar__hud_configure)
-               vote_alpha = bound(0, (time - vote_change) * 2, 1);
-       else
-               vote_alpha = bound(0, 1 - (time - vote_change) * 2, 1);
-
-       if(!vote_alpha)
-               return;
-
-       HUD_Panel_UpdateCvars();
-
-       if(uid2name_dialog)
-       {
-               panel_pos = eX * 0.3 * vid_conwidth + eY * 0.1 * vid_conheight;
-               panel_size = eX * 0.4 * vid_conwidth + eY * 0.3 * vid_conheight;
-       }
-
-    // these must be below above block
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
-       a = vote_alpha * (vote_highlighted ? autocvar_hud_panel_vote_alreadyvoted_alpha : 1);
-       HUD_Panel_DrawBg(a);
-       a = panel_fg_alpha * a;
-
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
-       }
-
-       // always force 3:1 aspect
-       vector newSize = '0 0 0';
-       if(mySize.x/mySize.y > 3)
-       {
-               newSize.x = 3 * mySize.y;
-               newSize.y = mySize.y;
-
-               pos.x = pos.x + (mySize.x - newSize.x) / 2;
-       }
-       else
-       {
-               newSize.y = 1/3 * mySize.x;
-               newSize.x = mySize.x;
-
-               pos.y = pos.y + (mySize.y - newSize.y) / 2;
-       }
-       mySize = newSize;
-
-       s = _("A vote has been called for:");
-       if(uid2name_dialog)
-               s = _("Allow servers to store and display your name?");
-       drawstring_aspect(pos, s, eX * mySize.x + eY * (2/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
-       s = textShortenToWidth(vote_called_vote, mySize.x, '1 1 0' * mySize.y * (1/8), stringwidth_colors);
-       if(autocvar__hud_configure)
-               s = _("^1Configure the HUD");
-       drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize.y, s, eX * mySize.x + eY * (1.75/8) * mySize.y, a, DRAWFLAG_NORMAL);
-
-       // print the yes/no counts
-    s = sprintf(_("Yes (%s): %d"), getcommandkey("vyes", "vyes"), vote_yescount);
-       drawstring_aspect(pos + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '0 1 0', a, DRAWFLAG_NORMAL);
-    s = sprintf(_("No (%s): %d"), getcommandkey("vno", "vno"), vote_nocount);
-       drawstring_aspect(pos + eX * 0.5 * mySize.x + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '1 0 0', a, DRAWFLAG_NORMAL);
-
-       // draw the progress bar backgrounds
-       drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_back", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
-
-       // draw the highlights
-       if(vote_highlighted == 1) {
-               drawsetcliparea(pos.x, pos.y, mySize.x * 0.5, mySize.y);
-               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
-       }
-       else if(vote_highlighted == -1) {
-               drawsetcliparea(pos.x + 0.5 * mySize.x, pos.y, mySize.x * 0.5, mySize.y);
-               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
-       }
-
-       // draw the progress bars
-       if(vote_yescount && vote_needed)
-       {
-               drawsetcliparea(pos.x, pos.y, mySize.x * 0.5 * (vote_yescount/vote_needed), mySize.y);
-               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
-       }
-
-       if(vote_nocount && vote_needed)
-       {
-               drawsetcliparea(pos.x + mySize.x - mySize.x * 0.5 * (vote_nocount/vote_needed), pos.y, mySize.x * 0.5, mySize.y);
-               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
-       }
-
-       drawresetcliparea();
-}
-
-// Mod icons panel (#10)
-//
-
-bool mod_active; // is there any active mod icon?
-
-void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
-{
-       int stat = -1;
-       string pic = "";
-       vector color = '0 0 0';
-       switch(i)
-       {
-               case 0:
-                       stat = getstati(STAT_REDALIVE);
-                       pic = "player_red.tga";
-                       color = '1 0 0';
-                       break;
-               case 1:
-                       stat = getstati(STAT_BLUEALIVE);
-                       pic = "player_blue.tga";
-                       color = '0 0 1';
-                       break;
-               case 2:
-                       stat = getstati(STAT_YELLOWALIVE);
-                       pic = "player_yellow.tga";
-                       color = '1 1 0';
-                       break;
-               default:
-               case 3:
-                       stat = getstati(STAT_PINKALIVE);
-                       pic = "player_pink.tga";
-                       color = '1 0 1';
-                       break;
-       }
-
-       if(mySize.x/mySize.y > aspect_ratio)
-       {
-               i = aspect_ratio * mySize.y;
-               myPos.x = myPos.x + (mySize.x - i) / 2;
-               mySize.x = i;
-       }
-       else
-       {
-               i = 1/aspect_ratio * mySize.x;
-               myPos.y = myPos.y + (mySize.y - i) / 2;
-               mySize.y = i;
-       }
-
-       if(layout)
-       {
-               drawpic_aspect_skin(myPos, pic, eX * 0.7 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(myPos + eX * 0.7 * mySize.x, ftos(stat), eX * 0.3 * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
-       }
-       else
-               drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
-}
-
-// Clan Arena and Freeze Tag HUD modicons
-void HUD_Mod_CA(vector myPos, vector mySize)
-{
-       mod_active = 1; // required in each mod function that always shows something
-
-       int layout;
-       if(gametype == MAPINFO_TYPE_CA)
-               layout = autocvar_hud_panel_modicons_ca_layout;
-       else //if(gametype == MAPINFO_TYPE_FREEZETAG)
-               layout = autocvar_hud_panel_modicons_freezetag_layout;
-       int rows, columns;
-       float aspect_ratio;
-       aspect_ratio = (layout) ? 2 : 1;
-       rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
-       columns = ceil(team_count/rows);
-
-       int i;
-       float row = 0, column = 0;
-       vector pos, itemSize;
-       itemSize = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
-       for(i=0; i<team_count; ++i)
-       {
-               pos = myPos + eX * column * itemSize.x + eY * row * itemSize.y;
-
-               DrawCAItem(pos, itemSize, aspect_ratio, layout, i);
-
-               ++row;
-               if(row >= rows)
-               {
-                       row = 0;
-                       ++column;
-               }
-       }
-}
-
-// CTF HUD modicon section
-int redflag_prevframe, blueflag_prevframe, yellowflag_prevframe, pinkflag_prevframe, neutralflag_prevframe; // status during previous frame
-int redflag_prevstatus, blueflag_prevstatus, yellowflag_prevstatus, pinkflag_prevstatus, neutralflag_prevstatus; // last remembered status
-float redflag_statuschange_time, blueflag_statuschange_time, yellowflag_statuschange_time, pinkflag_statuschange_time, neutralflag_statuschange_time; // time when the status changed
-
-void HUD_Mod_CTF_Reset(void)
-{
-       redflag_prevstatus = blueflag_prevstatus = yellowflag_prevstatus = pinkflag_prevstatus = neutralflag_prevstatus = 0;
-       redflag_prevframe = blueflag_prevframe = yellowflag_prevframe = pinkflag_prevframe = neutralflag_prevframe = 0;
-       redflag_statuschange_time = blueflag_statuschange_time = yellowflag_statuschange_time = pinkflag_statuschange_time = neutralflag_statuschange_time = 0;
-}
-
-void HUD_Mod_CTF(vector pos, vector mySize)
-{
-       vector redflag_pos, blueflag_pos, yellowflag_pos, pinkflag_pos, neutralflag_pos;
-       vector flag_size;
-       float f; // every function should have that
-
-       int redflag, blueflag, yellowflag, pinkflag, neutralflag; // current status
-       float redflag_statuschange_elapsedtime, blueflag_statuschange_elapsedtime, yellowflag_statuschange_elapsedtime, pinkflag_statuschange_elapsedtime, neutralflag_statuschange_elapsedtime; // time since the status changed
-       bool ctf_oneflag; // one-flag CTF mode enabled/disabled
-       int stat_items = getstati(STAT_CTF_FLAGSTATUS, 0, 24);
-       float fs, fs2, fs3, size1, size2;
-       vector e1, e2;
-
-       redflag = (stat_items/CTF_RED_FLAG_TAKEN) & 3;
-       blueflag = (stat_items/CTF_BLUE_FLAG_TAKEN) & 3;
-       yellowflag = (stat_items/CTF_YELLOW_FLAG_TAKEN) & 3;
-       pinkflag = (stat_items/CTF_PINK_FLAG_TAKEN) & 3;
-       neutralflag = (stat_items/CTF_NEUTRAL_FLAG_TAKEN) & 3;
-
-       ctf_oneflag = (stat_items & CTF_FLAG_NEUTRAL);
-
-       mod_active = (redflag || blueflag || yellowflag || pinkflag || neutralflag);
-
-       if (autocvar__hud_configure) {
-               redflag = 1;
-               blueflag = 2;
-               if (team_count >= 3)
-                       yellowflag = 2;
-               if (team_count >= 4)
-                       pinkflag = 3;
-               ctf_oneflag = neutralflag = 0; // disable neutral flag in hud editor?
-       }
-
-       // when status CHANGES, set old status into prevstatus and current status into status
-       #define X(team) do {                                                                                                                    \
-               if (team##flag != team##flag_prevframe) {                                                                       \
-               team##flag_statuschange_time = time;                                                                    \
-               team##flag_prevstatus = team##flag_prevframe;                                                   \
-               team##flag_prevframe = team##flag;                                                                              \
-       }                                                                                                                                                       \
-       team##flag_statuschange_elapsedtime = time - team##flag_statuschange_time;      \
-    } while (0)
-       X(red);
-       X(blue);
-       X(yellow);
-       X(pink);
-       X(neutral);
-       #undef X
-
-       const float BLINK_FACTOR = 0.15;
-       const float BLINK_BASE = 0.85;
-       // note:
-       //   RMS = sqrt(BLINK_BASE^2 + 0.5 * BLINK_FACTOR^2)
-       // thus
-       //   BLINK_BASE = sqrt(RMS^2 - 0.5 * BLINK_FACTOR^2)
-       // ensure RMS == 1
-       const float BLINK_FREQ = 5; // circle frequency, = 2*pi*frequency in hertz
-
-       #define X(team, cond) \
-       string team##_icon, team##_icon_prevstatus; \
-       int team##_alpha, team##_alpha_prevstatus; \
-       team##_alpha = team##_alpha_prevstatus = 1; \
-       do { \
-               switch (team##flag) { \
-                       case 1: team##_icon = "flag_" #team "_taken"; break; \
-                       case 2: team##_icon = "flag_" #team "_lost"; break; \
-                       case 3: team##_icon = "flag_" #team "_carrying"; team##_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
-                       default: \
-                               if ((stat_items & CTF_SHIELDED) && (cond)) { \
-                                       team##_icon = "flag_" #team "_shielded"; \
-                               } else { \
-                                       team##_icon = string_null; \
-                               } \
-                               break; \
-               } \
-               switch (team##flag_prevstatus) { \
-                       case 1: team##_icon_prevstatus = "flag_" #team "_taken"; break; \
-                       case 2: team##_icon_prevstatus = "flag_" #team "_lost"; break; \
-                       case 3: team##_icon_prevstatus = "flag_" #team "_carrying"; team##_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
-                       default: \
-                               if (team##flag == 3) { \
-                                       team##_icon_prevstatus = "flag_" #team "_carrying"; /* make it more visible */\
-                               } else if((stat_items & CTF_SHIELDED) && (cond)) { \
-                                       team##_icon_prevstatus = "flag_" #team "_shielded"; \
-                               } else { \
-                                       team##_icon_prevstatus = string_null; \
-                               } \
-                               break; \
-               } \
-       } while (0)
-       X(red, myteam != NUM_TEAM_1);
-       X(blue, myteam != NUM_TEAM_2);
-       X(yellow, myteam != NUM_TEAM_3);
-       X(pink, myteam != NUM_TEAM_4);
-       X(neutral, true);
-       #undef X
-
-       if (ctf_oneflag) {
-               // hacky, but these aren't needed
-               red_icon = red_icon_prevstatus = blue_icon = blue_icon_prevstatus = yellow_icon = yellow_icon_prevstatus = pink_icon = pink_icon_prevstatus = string_null;
-               fs = fs2 = fs3 = 1;
-       } else switch (team_count) {
-               default:
-               case 2: fs = 0.5; fs2 = 0.5; fs3 = 0.5; break;
-               case 3: fs = 1; fs2 = 0.35; fs3 = 0.35; break;
-               case 4: fs = 0.75; fs2 = 0.25; fs3 = 0.5; break;
-       }
-
-       if (mySize_x > mySize_y) {
-               size1 = mySize_x;
-               size2 = mySize_y;
-               e1 = eX;
-               e2 = eY;
-       } else {
-               size1 = mySize_y;
-               size2 = mySize_x;
-               e1 = eY;
-               e2 = eX;
-       }
-
-       switch (myteam) {
-               default:
-               case NUM_TEAM_1: {
-                       redflag_pos = pos;
-                       blueflag_pos = pos + eX * fs2 * size1;
-                       yellowflag_pos = pos - eX * fs2 * size1;
-                       pinkflag_pos = pos + eX * fs3 * size1;
-                       break;
-               }
-               case NUM_TEAM_2: {
-                       redflag_pos = pos + eX * fs2 * size1;
-                       blueflag_pos = pos;
-                       yellowflag_pos = pos - eX * fs2 * size1;
-                       pinkflag_pos = pos + eX * fs3 * size1;
-                       break;
-               }
-               case NUM_TEAM_3: {
-                       redflag_pos = pos + eX * fs3 * size1;
-                       blueflag_pos = pos - eX * fs2 * size1;
-                       yellowflag_pos = pos;
-                       pinkflag_pos = pos + eX * fs2 * size1;
-                       break;
-               }
-               case NUM_TEAM_4: {
-                       redflag_pos = pos - eX * fs2 * size1;
-                       blueflag_pos = pos + eX * fs3 * size1;
-                       yellowflag_pos = pos + eX * fs2 * size1;
-                       pinkflag_pos = pos;
-                       break;
-               }
-       }
-       neutralflag_pos = pos;
-       flag_size = e1 * fs * size1 + e2 * size2;
-
-       #define X(team) do { \
-               f = bound(0, team##flag_statuschange_elapsedtime * 2, 1); \
-               if (team##_icon_prevstatus && f < 1) \
-                       drawpic_aspect_skin_expanding(team##flag_pos, team##_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * team##_alpha_prevstatus, DRAWFLAG_NORMAL, f); \
-               if (team##_icon) \
-                       drawpic_aspect_skin(team##flag_pos, team##_icon, flag_size, '1 1 1', panel_fg_alpha * team##_alpha * f, DRAWFLAG_NORMAL); \
-       } while (0)
-       X(red);
-       X(blue);
-       X(yellow);
-       X(pink);
-       X(neutral);
-       #undef X
-}
-
-// Keyhunt HUD modicon section
-vector KH_SLOTS[4];
-
-void HUD_Mod_KH(vector pos, vector mySize)
-{
-       mod_active = 1; // keyhunt should never hide the mod icons panel
-
-       // Read current state
-
-       int state = getstati(STAT_KH_KEYS);
-       int i, key_state;
-       int all_keys, team1_keys, team2_keys, team3_keys, team4_keys, dropped_keys, carrying_keys;
-       all_keys = team1_keys = team2_keys = team3_keys = team4_keys = dropped_keys = carrying_keys = 0;
-
-       for(i = 0; i < 4; ++i)
-       {
-               key_state = (bitshift(state, i * -5) & 31) - 1;
-
-               if(key_state == -1)
-                       continue;
-
-               if(key_state == 30)
-               {
-                       ++carrying_keys;
-                       key_state = myteam;
-               }
-
-               switch(key_state)
-               {
-                       case NUM_TEAM_1: ++team1_keys; break;
-                       case NUM_TEAM_2: ++team2_keys; break;
-                       case NUM_TEAM_3: ++team3_keys; break;
-                       case NUM_TEAM_4: ++team4_keys; break;
-                       case 29: ++dropped_keys; break;
-               }
-
-               ++all_keys;
-       }
-
-       // Calculate slot measurements
-
-       vector slot_size;
-
-       if(all_keys == 4 && mySize.x * 0.5 < mySize.y && mySize.y * 0.5 < mySize.x)
-       {
-               // Quadratic arrangement
-               slot_size = eX * mySize.x * 0.5 + eY * mySize.y * 0.5;
-               KH_SLOTS[0] = pos;
-               KH_SLOTS[1] = pos + eX * slot_size.x;
-               KH_SLOTS[2] = pos + eY * slot_size.y;
-               KH_SLOTS[3] = pos + eX * slot_size.x + eY * slot_size.y;
-       }
-       else
-       {
-               if(mySize.x > mySize.y)
-               {
-                       // Horizontal arrangement
-                       slot_size = eX * mySize.x / all_keys + eY * mySize.y;
-                       for(i = 0; i < all_keys; ++i)
-                               KH_SLOTS[i] = pos + eX * slot_size.x * i;
-               }
-               else
-               {
-                       // Vertical arrangement
-                       slot_size = eX * mySize.x + eY * mySize.y / all_keys;
-                       for(i = 0; i < all_keys; ++i)
-                               KH_SLOTS[i] = pos + eY * slot_size.y * i;
-               }
-       }
-
-       // Make icons blink in case of RUN HERE
-
-       float blink = 0.6 + sin(2*M_PI*time) / 2.5; // Oscillate between 0.2 and 1
-       float alpha;
-       alpha = 1;
-
-       if(carrying_keys)
-               switch(myteam)
-               {
-                       case NUM_TEAM_1: if(team1_keys == all_keys) alpha = blink; break;
-                       case NUM_TEAM_2: if(team2_keys == all_keys) alpha = blink; break;
-                       case NUM_TEAM_3: if(team3_keys == all_keys) alpha = blink; break;
-                       case NUM_TEAM_4: if(team4_keys == all_keys) alpha = blink; break;
-               }
-
-       // Draw icons
-
-       i = 0;
-
-       while(team1_keys--)
-               if(myteam == NUM_TEAM_1 && carrying_keys)
-               {
-                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-                       --carrying_keys;
-               }
-               else
-                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
-       while(team2_keys--)
-               if(myteam == NUM_TEAM_2 && carrying_keys)
-               {
-                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-                       --carrying_keys;
-               }
-               else
-                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
-       while(team3_keys--)
-               if(myteam == NUM_TEAM_3 && carrying_keys)
-               {
-                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-                       --carrying_keys;
-               }
-               else
-                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
-       while(team4_keys--)
-               if(myteam == NUM_TEAM_4 && carrying_keys)
-               {
-                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-                       --carrying_keys;
-               }
-               else
-                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
-       while(dropped_keys--)
-               drawpic_aspect_skin(KH_SLOTS[i++], "kh_dropped", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-}
-
-// Keepaway HUD mod icon
-int kaball_prevstatus; // last remembered status
-float kaball_statuschange_time; // time when the status changed
-
-// we don't need to reset for keepaway since it immediately
-// autocorrects prevstatus as to if the player has the ball or not
-
-void HUD_Mod_Keepaway(vector pos, vector mySize)
-{
-       mod_active = 1; // keepaway should always show the mod HUD
-
-       float BLINK_FACTOR = 0.15;
-       float BLINK_BASE = 0.85;
-       float BLINK_FREQ = 5;
-       float kaball_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
-
-       int stat_items = getstati(STAT_ITEMS, 0, 24);
-       int kaball = (stat_items/IT_KEY1) & 1;
-
-       if(kaball != kaball_prevstatus)
-       {
-               kaball_statuschange_time = time;
-               kaball_prevstatus = kaball;
-       }
-
-       vector kaball_pos, kaball_size;
-
-       if(mySize.x > mySize.y) {
-               kaball_pos = pos + eX * 0.25 * mySize.x;
-               kaball_size = eX * 0.5 * mySize.x + eY * mySize.y;
-       } else {
-               kaball_pos = pos + eY * 0.25 * mySize.y;
-               kaball_size = eY * 0.5 * mySize.y + eX * mySize.x;
-       }
-
-       float kaball_statuschange_elapsedtime = time - kaball_statuschange_time;
-       float f = bound(0, kaball_statuschange_elapsedtime*2, 1);
-
-       if(kaball_prevstatus && f < 1)
-               drawpic_aspect_skin_expanding(kaball_pos, "keepawayball_carrying", kaball_size, '1 1 1', panel_fg_alpha * kaball_alpha, DRAWFLAG_NORMAL, f);
-
-       if(kaball)
-               drawpic_aspect_skin(pos, "keepawayball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha * kaball_alpha * f, DRAWFLAG_NORMAL);
-}
-
-
-// Nexball HUD mod icon
-void HUD_Mod_NexBall(vector pos, vector mySize)
-{
-       float nb_pb_starttime, dt, p;
-       int stat_items;
-
-       stat_items = getstati(STAT_ITEMS, 0, 24);
-       nb_pb_starttime = getstatf(STAT_NB_METERSTART);
-
-       if (stat_items & IT_KEY1)
-               mod_active = 1;
-       else
-               mod_active = 0;
-
-       //Manage the progress bar if any
-       if (nb_pb_starttime > 0)
-       {
-               dt = (time - nb_pb_starttime) % nb_pb_period;
-               // one period of positive triangle
-               p = 2 * dt / nb_pb_period;
-               if (p > 1)
-                       p = 2 - p;
-
-               HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, (mySize.x <= mySize.y), 0, autocvar_hud_progressbar_nexball_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-       }
-
-       if (stat_items & IT_KEY1)
-               drawpic_aspect_skin(pos, "nexball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-}
-
-// Race/CTS HUD mod icons
-float crecordtime_prev; // last remembered crecordtime
-float crecordtime_change_time; // time when crecordtime last changed
-float srecordtime_prev; // last remembered srecordtime
-float srecordtime_change_time; // time when srecordtime last changed
-
-float race_status_time;
-int race_status_prev;
-string race_status_name_prev;
-void HUD_Mod_Race(vector pos, vector mySize)
-{
-       mod_active = 1; // race should never hide the mod icons panel
-       entity me;
-       me = playerslots[player_localnum];
-       float t, score;
-       float f; // yet another function has this
-       score = me.(scores[ps_primary]);
-
-       if(!(scores_flags[ps_primary] & SFL_TIME) || teamplay) // race/cts record display on HUD
-               return; // no records in the actual race
-
-       // clientside personal record
-       string rr;
-       if(gametype == MAPINFO_TYPE_CTS)
-               rr = CTS_RECORD;
-       else
-               rr = RACE_RECORD;
-       t = stof(db_get(ClientProgsDB, strcat(shortmapname, rr, "time")));
-
-       if(score && (score < t || !t)) {
-               db_put(ClientProgsDB, strcat(shortmapname, rr, "time"), ftos(score));
-               if(autocvar_cl_autodemo_delete_keeprecords)
-               {
-                       f = autocvar_cl_autodemo_delete;
-                       f &= ~1;
-                       cvar_set("cl_autodemo_delete", ftos(f)); // don't delete demo with new record!
-               }
-       }
-
-       if(t != crecordtime_prev) {
-               crecordtime_prev = t;
-               crecordtime_change_time = time;
-       }
-
-       vector textPos, medalPos;
-       float squareSize;
-       if(mySize.x > mySize.y) {
-               // text on left side
-               squareSize = min(mySize.y, mySize.x/2);
-               textPos = pos + eX * 0.5 * max(0, mySize.x/2 - squareSize) + eY * 0.5 * (mySize.y - squareSize);
-               medalPos = pos + eX * 0.5 * max(0, mySize.x/2 - squareSize) + eX * 0.5 * mySize.x + eY * 0.5 * (mySize.y - squareSize);
-       } else {
-               // text on top
-               squareSize = min(mySize.x, mySize.y/2);
-               textPos = pos + eY * 0.5 * max(0, mySize.y/2 - squareSize) + eX * 0.5 * (mySize.x - squareSize);
-               medalPos = pos + eY * 0.5 * max(0, mySize.y/2 - squareSize) + eY * 0.5 * mySize.y + eX * 0.5 * (mySize.x - squareSize);
-       }
-
-       f = time - crecordtime_change_time;
-
-       if (f > 1) {
-               drawstring_aspect(textPos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(textPos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       } else {
-               drawstring_aspect(textPos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(textPos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect_expanding(pos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
-               drawstring_aspect_expanding(pos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
-       }
-
-       // server record
-       t = race_server_record;
-       if(t != srecordtime_prev) {
-               srecordtime_prev = t;
-               srecordtime_change_time = time;
-       }
-       f = time - srecordtime_change_time;
-
-       if (f > 1) {
-               drawstring_aspect(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       } else {
-               drawstring_aspect(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect_expanding(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
-               drawstring_aspect_expanding(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
-       }
-
-       if (race_status != race_status_prev || race_status_name != race_status_name_prev) {
-               race_status_time = time + 5;
-               race_status_prev = race_status;
-               if (race_status_name_prev)
-                       strunzone(race_status_name_prev);
-               race_status_name_prev = strzone(race_status_name);
-       }
-
-       // race "awards"
-       float a;
-       a = bound(0, race_status_time - time, 1);
-
-       string s;
-       s = textShortenToWidth(race_status_name, squareSize, '1 1 0' * 0.1 * squareSize, stringwidth_colors);
-
-       float rank;
-       if(race_status > 0)
-               rank = race_CheckName(race_status_name);
-       else
-               rank = 0;
-       string rankname;
-       rankname = count_ordinal(rank);
-
-       vector namepos;
-       namepos = medalPos + '0 0.8 0' * squareSize;
-       vector rankpos;
-       rankpos = medalPos + '0 0.15 0' * squareSize;
-
-       if(race_status == 0)
-               drawpic_aspect_skin(medalPos, "race_newfail", '1 1 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-       else if(race_status == 1) {
-               drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newtime", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-       } else if(race_status == 2) {
-               if(race_status_name == GetPlayerName(player_localnum) || !race_myrank || race_myrank < rank)
-                       drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankgreen", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               else
-                       drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankyellow", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-       } else if(race_status == 3) {
-               drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrecordserver", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-               drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-       }
-
-       if (race_status_time - time <= 0) {
-               race_status_prev = -1;
-               race_status = -1;
-               if(race_status_name)
-                       strunzone(race_status_name);
-               race_status_name = string_null;
-               if(race_status_name_prev)
-                       strunzone(race_status_name_prev);
-               race_status_name_prev = string_null;
-       }
-}
-
-void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
-{
-       float stat = -1;
-       string pic = "";
-       vector color = '0 0 0';
-       switch(i)
-       {
-               case 0:
-                       stat = getstatf(STAT_DOM_PPS_RED);
-                       pic = "dom_icon_red";
-                       color = '1 0 0';
-                       break;
-               case 1:
-                       stat = getstatf(STAT_DOM_PPS_BLUE);
-                       pic = "dom_icon_blue";
-                       color = '0 0 1';
-                       break;
-               case 2:
-                       stat = getstatf(STAT_DOM_PPS_YELLOW);
-                       pic = "dom_icon_yellow";
-                       color = '1 1 0';
-                       break;
-               default:
-               case 3:
-                       stat = getstatf(STAT_DOM_PPS_PINK);
-                       pic = "dom_icon_pink";
-                       color = '1 0 1';
-                       break;
-       }
-       float pps_ratio = stat / getstatf(STAT_DOM_TOTAL_PPS);
-
-       if(mySize.x/mySize.y > aspect_ratio)
-       {
-               i = aspect_ratio * mySize.y;
-               myPos.x = myPos.x + (mySize.x - i) / 2;
-               mySize.x = i;
-       }
-       else
-       {
-               i = 1/aspect_ratio * mySize.x;
-               myPos.y = myPos.y + (mySize.y - i) / 2;
-               mySize.y = i;
-       }
-
-       if (layout) // show text too
-       {
-               //draw the text
-               color *= 0.5 + pps_ratio * (1 - 0.5); // half saturated color at min, full saturated at max
-               if (layout == 2) // average pps
-                       drawstring_aspect(myPos + eX * mySize.y, ftos_decimals(stat, 2), eX * (2/3) * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
-               else // percentage of average pps
-                       drawstring_aspect(myPos + eX * mySize.y, strcat( ftos(floor(pps_ratio*100 + 0.5)), "%" ), eX * (2/3) * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
-       }
-
-       //draw the icon
-       drawpic_aspect_skin(myPos, pic, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       if (stat > 0)
-       {
-               drawsetcliparea(myPos.x, myPos.y + mySize.y * (1 - pps_ratio), mySize.y, mySize.y * pps_ratio);
-               drawpic_aspect_skin(myPos, strcat(pic, "-highlighted"), '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawresetcliparea();
-       }
-}
-
-void HUD_Mod_Dom(vector myPos, vector mySize)
-{
-       mod_active = 1; // required in each mod function that always shows something
-
-       int layout = autocvar_hud_panel_modicons_dom_layout;
-       int rows, columns;
-       float aspect_ratio;
-       aspect_ratio = (layout) ? 3 : 1;
-       rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
-       columns = ceil(team_count/rows);
-
-       int i;
-       float row = 0, column = 0;
-       vector pos, itemSize;
-       itemSize = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
-       for(i=0; i<team_count; ++i)
-       {
-               pos = myPos + eX * column * itemSize.x + eY * row * itemSize.y;
-
-               DrawDomItem(pos, itemSize, aspect_ratio, layout, i);
-
-               ++row;
-               if(row >= rows)
-               {
-                       row = 0;
-                       ++column;
-               }
-       }
-}
-
-void HUD_ModIcons_SetFunc()
-{
-       switch(gametype)
-       {
-               case MAPINFO_TYPE_KEYHUNT:              HUD_ModIcons_GameType = HUD_Mod_KH; break;
-               case MAPINFO_TYPE_CTF:                  HUD_ModIcons_GameType = HUD_Mod_CTF; break;
-               case MAPINFO_TYPE_NEXBALL:              HUD_ModIcons_GameType = HUD_Mod_NexBall; break;
-               case MAPINFO_TYPE_CTS:
-               case MAPINFO_TYPE_RACE:         HUD_ModIcons_GameType = HUD_Mod_Race; break;
-               case MAPINFO_TYPE_CA:
-               case MAPINFO_TYPE_FREEZETAG:    HUD_ModIcons_GameType = HUD_Mod_CA; break;
-               case MAPINFO_TYPE_DOMINATION:   HUD_ModIcons_GameType = HUD_Mod_Dom; break;
-               case MAPINFO_TYPE_KEEPAWAY:     HUD_ModIcons_GameType = HUD_Mod_Keepaway; break;
-       }
-}
-
-int mod_prev; // previous state of mod_active to check for a change
-float mod_alpha;
-float mod_change; // "time" when mod_active changed
-
-void HUD_ModIcons(void)
-{
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_modicons) return;
-               if(!HUD_ModIcons_GameType) return;
-       }
-
-       HUD_Panel_UpdateCvars();
-
-       draw_beginBoldFont();
-
-       if(mod_active != mod_prev) {
-               mod_change = time;
-               mod_prev = mod_active;
-       }
-
-       if(mod_active || autocvar__hud_configure)
-               mod_alpha = bound(0, (time - mod_change) * 2, 1);
-       else
-               mod_alpha = bound(0, 1 - (time - mod_change) * 2, 1);
-
-       if(mod_alpha)
-               HUD_Panel_DrawBg(mod_alpha);
-
-       if(panel_bg_padding)
-       {
-               panel_pos += '1 1 0' * panel_bg_padding;
-               panel_size -= '2 2 0' * panel_bg_padding;
-       }
-
-       if(autocvar__hud_configure)
-               HUD_Mod_CTF(panel_pos, panel_size);
-       else
-               HUD_ModIcons_GameType(panel_pos, panel_size);
-
-       draw_endBoldFont();
-}
-
-// Draw pressed keys (#11)
-//
-void HUD_PressedKeys(void)
-{
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_pressedkeys) return;
-               if(spectatee_status <= 0 && autocvar_hud_panel_pressedkeys < 2) return;
-       }
-
-       HUD_Panel_UpdateCvars();
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
-       HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
-       }
-
-       // force custom aspect
-       float aspect = autocvar_hud_panel_pressedkeys_aspect;
-       if(aspect)
-       {
-               vector newSize = '0 0 0';
-               if(mySize.x/mySize.y > aspect)
-               {
-                       newSize.x = aspect * mySize.y;
-                       newSize.y = mySize.y;
-
-                       pos.x = pos.x + (mySize.x - newSize.x) / 2;
-               }
-               else
-               {
-                       newSize.y = 1/aspect * mySize.x;
-                       newSize.x = mySize.x;
-
-                       pos.y = pos.y + (mySize.y - newSize.y) / 2;
-               }
-               mySize = newSize;
-       }
-
-       vector keysize;
-       keysize = eX * mySize.x * (1/3.0) + eY * mySize.y * (1/(3.0 - !autocvar_hud_panel_pressedkeys_attack));
-       float pressedkeys;
-       pressedkeys = getstatf(STAT_PRESSED_KEYS);
-
-       if(autocvar_hud_panel_pressedkeys_attack)
-       {
-               drawpic_aspect_skin(pos + eX * keysize.x * 0.5, ((pressedkeys & KEY_ATCK) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawpic_aspect_skin(pos + eX * keysize.x * 1.5, ((pressedkeys & KEY_ATCK2) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               pos.y += keysize.y;
-       }
-
-       drawpic_aspect_skin(pos, ((pressedkeys & KEY_CROUCH) ? "key_crouch_inv.tga" : "key_crouch.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       drawpic_aspect_skin(pos + eX * keysize.x, ((pressedkeys & KEY_FORWARD) ? "key_forward_inv.tga" : "key_forward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       drawpic_aspect_skin(pos + eX * keysize.x * 2, ((pressedkeys & KEY_JUMP) ? "key_jump_inv.tga" : "key_jump.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       pos.y += keysize.y;
-       drawpic_aspect_skin(pos, ((pressedkeys & KEY_LEFT) ? "key_left_inv.tga" : "key_left.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       drawpic_aspect_skin(pos + eX * keysize.x, ((pressedkeys & KEY_BACKWARD) ? "key_backward_inv.tga" : "key_backward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       drawpic_aspect_skin(pos + eX * keysize.x * 2, ((pressedkeys & KEY_RIGHT) ? "key_right_inv.tga" : "key_right.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-}
-
-// Handle chat as a panel (#12)
-//
-void HUD_Chat(void)
-{
-       if(!autocvar__hud_configure)
-       {
-               if (!autocvar_hud_panel_chat)
-               {
-                       if (!autocvar_con_chatrect)
-                               cvar_set("con_chatrect", "0");
-                       return;
-               }
-               if(autocvar__con_chat_maximized)
-               {
-                       if(!hud_draw_maximized) return;
-               }
-               else if(chat_panel_modified)
-               {
-                       panel.update_time = time; // forces reload of panel attributes
-                       chat_panel_modified = false;
-               }
-       }
-
-       HUD_Panel_UpdateCvars();
-
-       if(intermission == 2)
-       {
-               // reserve some more space to the mapvote panel
-               // by resizing and moving chat panel to the bottom
-               panel_size.y = min(panel_size.y, vid_conheight * 0.2);
-               panel_pos.y = vid_conheight - panel_size.y - panel_bg_border * 2;
-               chat_posy = panel_pos.y;
-               chat_sizey = panel_size.y;
-       }
-       if(autocvar__con_chat_maximized && !autocvar__hud_configure) // draw at full screen height if maximized
-       {
-               panel_pos.y = panel_bg_border;
-               panel_size.y = vid_conheight - panel_bg_border * 2;
-               if(panel.current_panel_bg == "0") // force a border when maximized
-               {
-                       string panel_bg;
-                       panel_bg = strcat(hud_skin_path, "/border_default");
-                       if(precache_pic(panel_bg) == "")
-                               panel_bg = "gfx/hud/default/border_default";
-                       if(panel.current_panel_bg)
-                               strunzone(panel.current_panel_bg);
-                       panel.current_panel_bg = strzone(panel_bg);
-                       chat_panel_modified = true;
-               }
-               panel_bg_alpha = max(0.75, panel_bg_alpha); // force an theAlpha of at least 0.75
-       }
-
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
-       HUD_Panel_DrawBg(1);
-
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
-       }
-
-       if (!autocvar_con_chatrect)
-               cvar_set("con_chatrect", "1");
-
-       cvar_set("con_chatrect_x", ftos(pos.x/vid_conwidth));
-       cvar_set("con_chatrect_y", ftos(pos.y/vid_conheight));
-
-       cvar_set("con_chatwidth", ftos(mySize.x/vid_conwidth));
-       cvar_set("con_chat", ftos(floor(mySize.y/autocvar_con_chatsize - 0.5)));
-
-       if(autocvar__hud_configure)
-       {
-               vector chatsize;
-               chatsize = '1 1 0' * autocvar_con_chatsize;
-               cvar_set("con_chatrect_x", "9001"); // over 9000, we'll fake it instead for more control over theAlpha and such
-               float i, a;
-               for(i = 0; i < autocvar_con_chat; ++i)
-               {
-                       if(i == autocvar_con_chat - 1)
-                               a = panel_fg_alpha;
-                       else
-                               a = panel_fg_alpha * floor(((i + 1) * 7 + autocvar_con_chattime)/45);
-                       drawcolorcodedstring(pos, textShortenToWidth(_("^3Player^7: This is the chat area."), mySize.x, chatsize, stringwidth_colors), chatsize, a, DRAWFLAG_NORMAL);
-                       pos.y += chatsize.y;
-               }
-       }
-}
-
-// Engine info panel (#13)
-//
-float prevfps;
-float prevfps_time;
-int framecounter;
-
-float frametimeavg;
-float frametimeavg1; // 1 frame ago
-float frametimeavg2; // 2 frames ago
-void HUD_EngineInfo(void)
-{
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_engineinfo) return;
-       }
-
-       HUD_Panel_UpdateCvars();
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
-       HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
-       }
-
-       float currentTime = gettime(GETTIME_REALTIME);
-       if(cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage"))
-       {
-               float currentframetime = currentTime - prevfps_time;
-               frametimeavg = (frametimeavg + frametimeavg1 + frametimeavg2 + currentframetime)/4; // average three frametimes into framecounter for slightly more stable fps readings :P
-               frametimeavg2 = frametimeavg1;
-               frametimeavg1 = frametimeavg;
-
-               float weight;
-               weight = cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_new_weight");
-               if(currentframetime > 0.0001) // filter out insane values which sometimes seem to occur and throw off the average? If you are getting 10,000 fps or more, then you don't need a framerate counter.
-               {
-                       if(fabs(prevfps - (1/frametimeavg)) > prevfps * cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_instantupdate_change_threshold")) // if there was a big jump in fps, just force prevfps at current (1/currentframetime) to make big updates instant
-                               prevfps = (1/currentframetime);
-                       prevfps = (1 - weight) * prevfps + weight * (1/frametimeavg); // framecounter just used so there's no need for a new variable, think of it as "frametime average"
-               }
-               prevfps_time = currentTime;
-       }
-       else
-       {
-               framecounter += 1;
-               if(currentTime - prevfps_time > autocvar_hud_panel_engineinfo_framecounter_time)
-               {
-                       prevfps = framecounter/(currentTime - prevfps_time);
-                       framecounter = 0;
-                       prevfps_time = currentTime;
-               }
-       }
-
-       vector color;
-       color = HUD_Get_Num_Color (prevfps, 100);
-       drawstring_aspect(pos, sprintf(_("FPS: %.*f"), autocvar_hud_panel_engineinfo_framecounter_decimals, prevfps), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
-}
-
-// Info messages panel (#14)
-//
-#define drawInfoMessage(s) do {                                                                                                                                                                                \
-       if(autocvar_hud_panel_infomessages_flip)                                                                                                                                                \
-               o.x = pos.x + mySize.x - stringwidth(s, true, fontsize);                                                                                                        \
-       drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL);                                                                                                               \
-       o.y += fontsize.y;                                                                                                                                                                                              \
-} while(0)
-void HUD_InfoMessages(void)
-{
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_infomessages) return;
-       }
-
-       HUD_Panel_UpdateCvars();
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
-       HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
-       {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
-       }
-
-       // always force 5:1 aspect
-       vector newSize = '0 0 0';
-       if(mySize.x/mySize.y > 5)
-       {
-               newSize.x = 5 * mySize.y;
-               newSize.y = mySize.y;
-
-               pos.x = pos.x + (mySize.x - newSize.x) / 2;
-       }
-       else
-       {
-               newSize.y = 1/5 * mySize.x;
-               newSize.x = mySize.x;
-
-               pos.y = pos.y + (mySize.y - newSize.y) / 2;
-       }
-
-       mySize = newSize;
-       entity tm;
-       vector o;
-       o = pos;
-
-       vector fontsize;
-       fontsize = '0.20 0.20 0' * mySize.y;
-
-       float a;
-       a = panel_fg_alpha;
-
-       string s;
-       if(!autocvar__hud_configure)
-       {
-               if(spectatee_status && !intermission)
-               {
-                       a = 1;
-                       if(spectatee_status == -1)
-                               s = _("^1Observing");
-                       else
-                               s = sprintf(_("^1Spectating: ^7%s"), GetPlayerName(current_player));
-                       drawInfoMessage(s);
-
-                       if(spectatee_status == -1)
-                               s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey("primary fire", "+fire"));
-                       else
-                               s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
-                       drawInfoMessage(s);
-
-                       if(spectatee_status == -1)
-                               s = sprintf(_("^1Use ^3%s^1 or ^3%s^1 to change the speed"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
-                       else
-                               s = sprintf(_("^1Press ^3%s^1 to observe"), getcommandkey("secondary fire", "+fire2"));
-                       drawInfoMessage(s);
-
-                       s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey("server info", "+show_info"));
-                       drawInfoMessage(s);
-
-                       if(gametype == MAPINFO_TYPE_LMS)
-                       {
-                               entity sk;
-                               sk = playerslots[player_localnum];
-                               if(sk.(scores[ps_primary]) >= 666)
-                                       s = _("^1Match has already begun");
-                               else if(sk.(scores[ps_primary]) > 0)
-                                       s = _("^1You have no more lives left");
-                               else
-                                       s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
-                       }
-                       else
-                               s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
-                       drawInfoMessage(s);
-
-                       //show restart countdown:
-                       if (time < getstatf(STAT_GAMESTARTTIME)) {
-                               float countdown;
-                               //we need to ceil, otherwise the countdown would be off by .5 when using round()
-                               countdown = ceil(getstatf(STAT_GAMESTARTTIME) - time);
-                               s = sprintf(_("^1Game starts in ^3%d^1 seconds"), countdown);
-                               drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL);
-                               o.y += fontsize.y;
-                       }
-               }
-               if(warmup_stage && !intermission)
-               {
-                       s = _("^2Currently in ^1warmup^2 stage!");
-                       drawInfoMessage(s);
-               }
-
-               string blinkcolor;
-               if(time % 1 >= 0.5)
-                       blinkcolor = "^1";
-               else
-                       blinkcolor = "^3";
-
-               if(ready_waiting && !intermission && !spectatee_status)
-               {
-                       if(ready_waiting_for_me)
-                       {
-                               if(warmup_stage)
-                                       s = sprintf(_("%sPress ^3%s%s to end warmup"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
-                               else
-                                       s = sprintf(_("%sPress ^3%s%s once you are ready"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
-                       }
-                       else
-                       {
-                               if(warmup_stage)
-                                       s = _("^2Waiting for others to ready up to end warmup...");
-                               else
-                                       s = _("^2Waiting for others to ready up...");
-                       }
-                       drawInfoMessage(s);
-               }
-               else if(warmup_stage && !intermission && !spectatee_status)
-               {
-                       s = sprintf(_("^2Press ^3%s^2 to end warmup"), getcommandkey("ready", "ready"));
-                       drawInfoMessage(s);
-               }
-
-               if(teamplay && !intermission && !spectatee_status && gametype != MAPINFO_TYPE_CA && teamnagger)
-               {
-                       float ts_min = 0, ts_max = 0;
-                       tm = teams.sort_next;
-                       if (tm)
-                       {
-                               for (; tm.sort_next; tm = tm.sort_next)
-                               {
-                                       if(!tm.team_size || tm.team == NUM_SPECTATOR)
-                                               continue;
-                                       if(!ts_min) ts_min = tm.team_size;
-                                       else ts_min = min(ts_min, tm.team_size);
-                                       if(!ts_max) ts_max = tm.team_size;
-                                       else ts_max = max(ts_max, tm.team_size);
-                               }
-                               if ((ts_max - ts_min) > 1)
-                               {
-                                       s = strcat(blinkcolor, _("Teamnumbers are unbalanced!"));
-                                       tm = GetTeam(myteam, false);
-                                       if (tm)
-                                       if (tm.team != NUM_SPECTATOR)
-                                       if (tm.team_size == ts_max)
-                                               s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey("team menu", "menu_showteamselect"), blinkcolor));
-                                       drawInfoMessage(s);
-                               }
-                       }
-               }
-       }
-       else
-       {
-               s = _("^7Press ^3ESC ^7to show HUD options.");
-               drawInfoMessage(s);
-               s = _("^3Doubleclick ^7a panel for panel-specific options.");
-               drawInfoMessage(s);
-               s = _("^3CTRL ^7to disable collision testing, ^3SHIFT ^7and");
-               drawInfoMessage(s);
-               s = _("^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments.");
-               drawInfoMessage(s);
-       }
-}
-
-// Physics panel (#15)
-//
-vector acc_prevspeed;
-float acc_prevtime, acc_avg, top_speed, top_speed_time;
-float physics_update_time, discrete_speed, discrete_acceleration;
-void HUD_Physics(void)
-{
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_physics) return;
-               if(spectatee_status == -1 && (autocvar_hud_panel_physics == 1 || autocvar_hud_panel_physics == 3)) return;
-               if(autocvar_hud_panel_physics == 3 && !(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
-       }
-
-       HUD_Panel_UpdateCvars();
-
-       draw_beginBoldFont();
-
-       HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
-       {
-               panel_pos += '1 1 0' * panel_bg_padding;
-               panel_size -= '2 2 0' * panel_bg_padding;
-       }
-
-       float acceleration_progressbar_scale = 0;
-       if(autocvar_hud_panel_physics_progressbar && autocvar_hud_panel_physics_acceleration_progressbar_scale > 1)
-               acceleration_progressbar_scale = autocvar_hud_panel_physics_acceleration_progressbar_scale;
-
-       float text_scale;
-       if (autocvar_hud_panel_physics_text_scale <= 0)
-               text_scale = 1;
-       else
-               text_scale = min(autocvar_hud_panel_physics_text_scale, 1);
-
-       //compute speed
-       float speed, conversion_factor;
-       string unit;
-
-       switch(autocvar_hud_panel_physics_speed_unit)
-       {
-               default:
-               case 1:
-                       unit = _(" qu/s");
-                       conversion_factor = 1.0;
-                       break;
-               case 2:
-                       unit = _(" m/s");
-                       conversion_factor = 0.0254;
-                       break;
-               case 3:
-                       unit = _(" km/h");
-                       conversion_factor = 0.0254 * 3.6;
-                       break;
-               case 4:
-                       unit = _(" mph");
-                       conversion_factor = 0.0254 * 3.6 * 0.6213711922;
-                       break;
-               case 5:
-                       unit = _(" knots");
-                       conversion_factor = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
-                       break;
-       }
-
-       vector vel = (csqcplayer ? csqcplayer.velocity : pmove_vel);
-
-       float max_speed = floor( autocvar_hud_panel_physics_speed_max * conversion_factor + 0.5 );
-       if (autocvar__hud_configure)
-               speed = floor( max_speed * 0.65 + 0.5 );
-       else if(autocvar_hud_panel_physics_speed_vertical)
-               speed = floor( vlen(vel) * conversion_factor + 0.5 );
-       else
-               speed = floor( vlen(vel - vel.z * '0 0 1') * conversion_factor + 0.5 );
-
-       //compute acceleration
-       float acceleration, f;
-       if (autocvar__hud_configure)
-               acceleration = autocvar_hud_panel_physics_acceleration_max * 0.3;
-       else
-       {
-               // 1 m/s = 0.0254 qu/s; 1 g = 9.80665 m/s^2
-               f = time - acc_prevtime;
-               if(autocvar_hud_panel_physics_acceleration_vertical)
-                       acceleration = (vlen(vel) - vlen(acc_prevspeed));
-               else
-                       acceleration = (vlen(vel - '0 0 1' * vel.z) - vlen(acc_prevspeed - '0 0 1' * acc_prevspeed.z));
-
-               acceleration = acceleration * (1 / max(0.0001, f)) * (0.0254 / 9.80665);
-
-               acc_prevspeed = vel;
-               acc_prevtime = time;
-
-               if(autocvar_hud_panel_physics_acceleration_movingaverage)
-               {
-                       f = bound(0, f * 10, 1);
-                       acc_avg = acc_avg * (1 - f) + acceleration * f;
-                       acceleration = acc_avg;
-               }
-       }
-
-       int acc_decimals = 2;
-       if(time > physics_update_time)
-       {
-               // workaround for ftos_decimals returning a negative 0
-               if(discrete_acceleration > -1 / pow(10, acc_decimals) && discrete_acceleration < 0)
-                       discrete_acceleration = 0;
-               discrete_acceleration = acceleration;
-               discrete_speed = speed;
-               physics_update_time += autocvar_hud_panel_physics_update_interval;
-       }
-
-       //compute layout
-       float panel_ar = panel_size.x/panel_size.y;
-       vector speed_offset = '0 0 0', acceleration_offset = '0 0 0';
-       if (panel_ar >= 5 && !acceleration_progressbar_scale)
-       {
-               panel_size.x *= 0.5;
-               if (autocvar_hud_panel_physics_flip)
-                       speed_offset.x = panel_size.x;
-               else
-                       acceleration_offset.x = panel_size.x;
-       }
-       else
-       {
-               panel_size.y *= 0.5;
-               if (autocvar_hud_panel_physics_flip)
-                       speed_offset.y = panel_size.y;
-               else
-                       acceleration_offset.y = panel_size.y;
-       }
-       int speed_baralign, acceleration_baralign;
-       if (autocvar_hud_panel_physics_baralign == 1)
-               acceleration_baralign = speed_baralign = 1;
-    else if(autocvar_hud_panel_physics_baralign == 4)
-               acceleration_baralign = speed_baralign = 2;
-       else if (autocvar_hud_panel_physics_flip)
-       {
-               acceleration_baralign = (autocvar_hud_panel_physics_baralign == 2);
-               speed_baralign = (autocvar_hud_panel_physics_baralign == 3);
-       }
-       else
-       {
-               speed_baralign = (autocvar_hud_panel_physics_baralign == 2);
-               acceleration_baralign = (autocvar_hud_panel_physics_baralign == 3);
-       }
-       if (autocvar_hud_panel_physics_acceleration_progressbar_mode == 0)
-               acceleration_baralign = 3; //override hud_panel_physics_baralign value for acceleration
-
-       //draw speed
-       if(speed)
-       if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
-               HUD_Panel_DrawProgressBar(panel_pos + speed_offset, panel_size, "progressbar", speed/max_speed, 0, speed_baralign, autocvar_hud_progressbar_speed_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-       vector tmp_offset = '0 0 0', tmp_size = '0 0 0';
-       if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
-       {
-               tmp_size.x = panel_size.x * 0.75;
-               tmp_size.y = panel_size.y * text_scale;
-               if (speed_baralign)
-                       tmp_offset.x = panel_size.x - tmp_size.x;
-               //else
-                       //tmp_offset_x = 0;
-               tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
-               drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(discrete_speed), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-
-               //draw speed unit
-               if (speed_baralign)
-                       tmp_offset.x = 0;
-               else
-                       tmp_offset.x = tmp_size.x;
-               if (autocvar_hud_panel_physics_speed_unit_show)
-               {
-                       //tmp_offset_y = 0;
-                       tmp_size.x = panel_size.x * (1 - 0.75);
-                       tmp_size.y = panel_size.y * 0.4 * text_scale;
-                       tmp_offset.y = (panel_size.y * 0.4 - tmp_size.y) / 2;
-                       drawstring_aspect(panel_pos + speed_offset + tmp_offset, unit, tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
-       }
-
-       //compute and draw top speed
-       if (autocvar_hud_panel_physics_topspeed)
-       if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
-       {
-               if (autocvar__hud_configure)
-               {
-                       top_speed = floor( max_speed * 0.75 + 0.5 );
-                       f = 1;
-               }
-               else
-               {
-                       if (speed >= top_speed)
-                       {
-                               top_speed = speed;
-                               top_speed_time = time;
-                       }
-                       if (top_speed != 0)
-                       {
-                               f = max(1, autocvar_hud_panel_physics_topspeed_time);
-                               // divide by f to make it start from 1
-                               f = cos( ((time - top_speed_time) / f) * PI/2 );
-                       }
-            else //hide top speed 0, it would be stupid
-                               f = 0;
-               }
-               if (f > 0)
-               {
-                       //top speed progressbar peak
-                       if(speed < top_speed)
-                       if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
-                       {
-                               float peak_offsetX;
-                               vector peak_size = '0 0 0';
-                               if (speed_baralign == 0)
-                                       peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x;
-                else if (speed_baralign == 1)
-                                       peak_offsetX = (1 - min(top_speed, max_speed)/max_speed) * panel_size.x;
-                else // if (speed_baralign == 2)
-                    peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x * 0.5;
-                               peak_size.x = floor(panel_size.x * 0.01 + 1.5);
-                peak_size.y = panel_size.y;
-                if (speed_baralign == 2) // draw two peaks, on both sides
-                {
-                    drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x + peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                    drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x - peak_offsetX + peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                }
-                else
-                    drawfill(panel_pos + speed_offset + eX * (peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       }
-
-                       //top speed
-                       tmp_offset.y = panel_size.y * 0.4;
-                       tmp_size.x = panel_size.x * (1 - 0.75);
-                       tmp_size.y = (panel_size.y - tmp_offset.y) * text_scale;
-                       tmp_offset.y += (panel_size.y - tmp_offset.y - tmp_size.y) / 2;
-                       drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(top_speed), tmp_size, '1 0 0', f * panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
-               else
-                       top_speed = 0;
-       }
-
-       //draw acceleration
-       if(acceleration)
-       if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 3)
-       {
-               vector progressbar_color;
-               if(acceleration < 0)
-                       progressbar_color = autocvar_hud_progressbar_acceleration_neg_color;
-               else
-                       progressbar_color = autocvar_hud_progressbar_acceleration_color;
-
-               f = acceleration/autocvar_hud_panel_physics_acceleration_max;
-               if (autocvar_hud_panel_physics_acceleration_progressbar_nonlinear)
-                       f = (f >= 0 ? sqrt(f) : -sqrt(-f));
-
-               if (acceleration_progressbar_scale) // allow progressbar to go out of panel bounds
-               {
-                       tmp_size = acceleration_progressbar_scale * panel_size.x * eX + panel_size.y * eY;
-
-                       if (acceleration_baralign == 1)
-                               tmp_offset.x = panel_size.x - tmp_size.x;
-                       else if (acceleration_baralign == 2 || acceleration_baralign == 3)
-                               tmp_offset.x = (panel_size.x - tmp_size.x) / 2;
-                       else
-                               tmp_offset.x = 0;
-                       tmp_offset.y = 0;
-               }
-               else
-               {
-                       tmp_size = panel_size;
-                       tmp_offset = '0 0 0';
-               }
-
-               HUD_Panel_DrawProgressBar(panel_pos + acceleration_offset + tmp_offset, tmp_size, "accelbar", f, 0, acceleration_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-       }
-
-       if(autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 3)
-       {
-               tmp_size.x = panel_size.x;
-               tmp_size.y = panel_size.y * text_scale;
-               tmp_offset.x = 0;
-               tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
-
-               drawstring_aspect(panel_pos + acceleration_offset + tmp_offset, strcat(ftos_decimals(discrete_acceleration, acc_decimals), "g"), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       }
-
-       draw_endBoldFont();
-}
-
-// CenterPrint (#16)
-//
-const int CENTERPRINT_MAX_MSGS = 10;
-const int CENTERPRINT_MAX_ENTRIES = 50;
-const float CENTERPRINT_SPACING = 0.7;
-int cpm_index;
-string centerprint_messages[CENTERPRINT_MAX_MSGS];
-int centerprint_msgID[CENTERPRINT_MAX_MSGS];
-float centerprint_time[CENTERPRINT_MAX_MSGS];
-float centerprint_expire_time[CENTERPRINT_MAX_MSGS];
-int centerprint_countdown_num[CENTERPRINT_MAX_MSGS];
-bool centerprint_showing;
-
-void centerprint_generic(int new_id, string strMessage, float duration, int countdown_num)
-{
-       //printf("centerprint_generic(%d, '%s^7', %d, %d);\n", new_id, strMessage, duration, countdown_num);
-       int i, j;
-
-       if(strMessage == "" && new_id == 0)
-               return;
-
-       // strip trailing newlines
-       j = strlen(strMessage) - 1;
-       while(substring(strMessage, j, 1) == "\n" && j >= 0)
-               --j;
-       if (j < strlen(strMessage) - 1)
-               strMessage = substring(strMessage, 0, j + 1);
-
-       if(strMessage == "" && new_id == 0)
-               return;
-
-       // strip leading newlines
-       j = 0;
-       while(substring(strMessage, j, 1) == "\n" && j < strlen(strMessage))
-               ++j;
-       if (j > 0)
-               strMessage = substring(strMessage, j, strlen(strMessage) - j);
-
-       if(strMessage == "" && new_id == 0)
-               return;
-
-       if (!centerprint_showing)
-               centerprint_showing = true;
-
-       for (i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
-       {
-               if (j == CENTERPRINT_MAX_MSGS)
-                       j = 0;
-               if (new_id && new_id == centerprint_msgID[j])
-               {
-                       if (strMessage == "" && centerprint_messages[j] != "" && centerprint_countdown_num[j] == 0)
-                       {
-                               // fade out the current msg (duration and countdown_num are ignored)
-                               centerprint_time[j] = min(5, autocvar_hud_panel_centerprint_fade_out);
-                               if (centerprint_expire_time[j] > time + min(5, autocvar_hud_panel_centerprint_fade_out) || centerprint_expire_time[j] < time)
-                                       centerprint_expire_time[j] = time + min(5, autocvar_hud_panel_centerprint_fade_out);
-                               return;
-                       }
-                       break; // found a msg with the same id, at position j
-               }
-       }
-
-       if (i == CENTERPRINT_MAX_MSGS)
-       {
-               // a msg with the same id was not found, add the msg at the next position
-               --cpm_index;
-               if (cpm_index == -1)
-                       cpm_index = CENTERPRINT_MAX_MSGS - 1;
-               j = cpm_index;
-       }
-       if(centerprint_messages[j])
-               strunzone(centerprint_messages[j]);
-       centerprint_messages[j] = strzone(strMessage);
-       centerprint_msgID[j] = new_id;
-       if (duration < 0)
-       {
-               centerprint_time[j] = -1;
-               centerprint_expire_time[j] = time;
-       }
-       else
-       {
-               if(duration == 0)
-                       duration = max(1, autocvar_hud_panel_centerprint_time);
-               centerprint_time[j] = duration;
-               centerprint_expire_time[j] = time + duration;
-       }
-       centerprint_countdown_num[j] = countdown_num;
-}
-
-void centerprint_hud(string strMessage)
-{
-       centerprint_generic(0, strMessage, autocvar_hud_panel_centerprint_time, 0);
-}
-
-void reset_centerprint_messages(void)
-{
-       int i;
-       for (i=0; i<CENTERPRINT_MAX_MSGS; ++i)
-       {
-               centerprint_expire_time[i] = 0;
-               centerprint_time[i] = 1;
-               centerprint_msgID[i] = 0;
-               if(centerprint_messages[i])
-                       strunzone(centerprint_messages[i]);
-               centerprint_messages[i] = string_null;
-       }
-}
-float hud_configure_cp_generation_time;
-void HUD_CenterPrint (void)
-{
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_centerprint) return;
-
-               if(hud_configure_prev)
-                       reset_centerprint_messages();
-       }
-       else
-       {
-               if(!hud_configure_prev)
-                       reset_centerprint_messages();
-               if (time > hud_configure_cp_generation_time)
-               {
-                       if(highlightedPanel == HUD_PANEL(CENTERPRINT))
-                       {
-                               float r;
-                               r = random();
-                               if (r > 0.8)
-                                       centerprint_generic(floor(r*1000), strcat(sprintf("^3Countdown message at time %s", seconds_tostring(time)), ", seconds left: ^COUNT"), 1, 10);
-                               else if (r > 0.55)
-                                       centerprint_generic(0, sprintf("^1Multiline message at time %s that\n^1lasts longer than normal", seconds_tostring(time)), 20, 0);
-                               else
-                                       centerprint_hud(sprintf("Message at time %s", seconds_tostring(time)));
-                               hud_configure_cp_generation_time = time + 1 + random()*4;
-                       }
-                       else
-                       {
-                               centerprint_generic(0, sprintf("Centerprint message", seconds_tostring(time)), 10, 0);
-                               hud_configure_cp_generation_time = time + 10 - random()*3;
-                       }
-               }
-       }
-
-       // this panel fades only when the menu does
-       float hud_fade_alpha_save = 0;
-       if(scoreboard_fade_alpha)
-       {
-               hud_fade_alpha_save = hud_fade_alpha;
-               hud_fade_alpha = 1 - autocvar__menu_alpha;
-       }
-       HUD_Panel_UpdateCvars();
-
-       if ( HUD_Radar_Clickable() )
-       {
-               if (hud_panel_radar_bottom >= 0.96 * vid_conheight)
-                       return;
-
-               panel_pos = eY * hud_panel_radar_bottom + eX * 0.5 * (vid_conwidth - panel_size_x);
-               panel_size_y = min(panel_size_y, vid_conheight - hud_panel_radar_bottom);
-       }
-       else if(scoreboard_fade_alpha)
-       {
-               hud_fade_alpha = hud_fade_alpha_save;
-
-               // move the panel below the scoreboard
-               if (scoreboard_bottom >= 0.96 * vid_conheight)
-                       return;
-               vector target_pos;
-
-               target_pos = eY * scoreboard_bottom + eX * 0.5 * (vid_conwidth - panel_size.x);
-
-               if(target_pos.y > panel_pos.y)
-               {
-                       panel_pos = panel_pos + (target_pos - panel_pos) * sqrt(scoreboard_fade_alpha);
-                       panel_size.y = min(panel_size.y, vid_conheight - scoreboard_bottom);
-               }
-       }
-
-       HUD_Panel_DrawBg(1);
-
-       if (!centerprint_showing)
-               return;
-
-       if(panel_bg_padding)
-       {
-               panel_pos += '1 1 0' * panel_bg_padding;
-               panel_size -= '2 2 0' * panel_bg_padding;
-       }
-
-       int entries;
-       float height;
-       vector fontsize;
-       // entries = bound(1, floor(CENTERPRINT_MAX_ENTRIES * 4 * panel_size_y/panel_size_x), CENTERPRINT_MAX_ENTRIES);
-       // height = panel_size_y/entries;
-       // fontsize = '1 1 0' * height;
-       height = vid_conheight/50 * autocvar_hud_panel_centerprint_fontscale;
-       fontsize = '1 1 0' * height;
-       entries = bound(1, floor(panel_size.y/height), CENTERPRINT_MAX_ENTRIES);
-
-       int i, j, k, n, g;
-       float a, sz, align, current_msg_posY = 0, msg_size;
-       vector pos;
-       string ts;
-       bool all_messages_expired = true;
-
-       pos = panel_pos;
-       if (autocvar_hud_panel_centerprint_flip)
-               pos.y += panel_size.y;
-       align = bound(0, autocvar_hud_panel_centerprint_align, 1);
-       for (g=0, i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
-       {
-               if (j == CENTERPRINT_MAX_MSGS)
-                       j = 0;
-               if (centerprint_expire_time[j] <= time)
-               {
-                       if (centerprint_countdown_num[j] && centerprint_time[j] > 0)
-                       {
-                               centerprint_countdown_num[j] = centerprint_countdown_num[j] - 1;
-                               if (centerprint_countdown_num[j] == 0)
-                                       continue;
-                               centerprint_expire_time[j] = centerprint_expire_time[j] + centerprint_time[j];
-                       }
-                       else if(centerprint_time[j] != -1)
-                               continue;
-               }
-
-               all_messages_expired = false;
-
-               // fade the centerprint_hud in/out
-               if(centerprint_time[j] < 0)  // Expired but forced. Expire time is the fade-in time.
-                       a = (time - centerprint_expire_time[j]) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
-               else if(centerprint_expire_time[j] - autocvar_hud_panel_centerprint_fade_out > time)  // Regularily printed. Not fading out yet.
-                       a = (time - (centerprint_expire_time[j] - centerprint_time[j])) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
-               else // Expiring soon, so fade it out.
-                       a = (centerprint_expire_time[j] - time) / max(0.0001, autocvar_hud_panel_centerprint_fade_out);
-
-               // while counting down show it anyway in order to hold the current message position
-               if (a <= 0.5/255.0 && centerprint_countdown_num[j] == 0)  // Guaranteed invisible - don't show.
-                       continue;
-               if (a > 1)
-                       a = 1;
-
-               // set the size from fading in/out before subsequent fading
-               sz = autocvar_hud_panel_centerprint_fade_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_minfontsize);
-
-               // also fade it based on positioning
-               if(autocvar_hud_panel_centerprint_fade_subsequent)
-               {
-                       a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1); // pass one: all messages after the first have half theAlpha
-                       a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1); // pass two: after that, gradually lower theAlpha even more for each message
-               }
-               a *= panel_fg_alpha;
-
-               // finally set the size based on the new theAlpha from subsequent fading
-               sz = sz * (autocvar_hud_panel_centerprint_fade_subsequent_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_subsequent_minfontsize));
-               drawfontscale = sz * '1 1 0';
-
-               if (centerprint_countdown_num[j])
-                       n = tokenizebyseparator(strreplace("^COUNT", count_seconds(centerprint_countdown_num[j]), centerprint_messages[j]), "\n");
-               else
-                       n = tokenizebyseparator(centerprint_messages[j], "\n");
-
-               if (autocvar_hud_panel_centerprint_flip)
-               {
-                       // check if the message can be entirely shown
-                       for(k = 0; k < n; ++k)
-                       {
-                               getWrappedLine_remaining = argv(k);
-                               while(getWrappedLine_remaining)
-                               {
-                                       ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
-                                       if (ts != "")
-                                               pos.y -= fontsize.y;
-                                       else
-                                               pos.y -= fontsize.y * CENTERPRINT_SPACING/2;
-                               }
-                       }
-                       current_msg_posY = pos.y; // save starting pos (first line) of the current message
-               }
-
-               msg_size = pos.y;
-               for(k = 0; k < n; ++k)
-               {
-                       getWrappedLine_remaining = argv(k);
-                       while(getWrappedLine_remaining)
-                       {
-                               ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
-                               if (ts != "")
-                               {
-                                       if (align)
-                                               pos.x = panel_pos.x + (panel_size.x - stringwidth(ts, true, fontsize)) * align;
-                                       if (a > 0.5/255.0)  // Otherwise guaranteed invisible - don't show. This is checked a second time after some multiplications with other factors were done so temporary changes of these cannot cause flicker.
-                                               drawcolorcodedstring(pos + eY * 0.5 * (1 - sz) * fontsize.y, ts, fontsize, a, DRAWFLAG_NORMAL);
-                                       pos.y += fontsize.y;
-                               }
-                               else
-                                       pos.y += fontsize.y * CENTERPRINT_SPACING/2;
-                       }
-               }
-
-               ++g; // move next position number up
-
-               msg_size = pos.y - msg_size;
-               if (autocvar_hud_panel_centerprint_flip)
-               {
-                       pos.y = current_msg_posY - CENTERPRINT_SPACING * fontsize.y;
-                       if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
-                               pos.y += (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
-
-                       if (pos.y < panel_pos.y) // check if the next message can be shown
-                       {
-                               drawfontscale = '1 1 0';
-                               return;
-                       }
-               }
-               else
-               {
-                       pos.y += CENTERPRINT_SPACING * fontsize.y;
-                       if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
-                               pos.y -= (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
-
-                       if(pos.y > panel_pos.y + panel_size.y - fontsize.y) // check if the next message can be shown
-                       {
-                               drawfontscale = '1 1 0';
-                               return;
-                       }
-               }
-       }
-       drawfontscale = '1 1 0';
-       if (all_messages_expired)
-       {
-               centerprint_showing = false;
-               reset_centerprint_messages();
-       }
-}
-
-
-// Minigame
-//
-#include "../common/minigames/cl_minigames_hud.qc"
-
-
-// QuickMenu (#23)
-//
-#include "quickmenu.qc"
-
-
-/*
-==================
-Main HUD system
-==================
-*/
-
-void HUD_Vehicle()
-{
-       if(autocvar__hud_configure) return;
-       if(intermission == 2) return;
-
-       if(hud == HUD_BUMBLEBEE_GUN)
-               CSQC_BUMBLE_GUN_HUD();
-       else {
-               Vehicle info = get_vehicleinfo(hud);
-               info.vr_hud(info);
-       }
-}
-
-bool HUD_Panel_CheckFlags(int showflags)
-{
-       if ( HUD_Minigame_Showpanels() )
-               return showflags & PANEL_SHOW_MINIGAME;
-       if(intermission == 2)
-               return showflags & PANEL_SHOW_MAPVOTE;
-       return showflags & PANEL_SHOW_MAINGAME;
-}
-
-void HUD_Panel_Draw(entity panent)
-{
-       panel = panent;
-       if(autocvar__hud_configure)
-       {
-               if(panel.panel_configflags & PANEL_CONFIG_MAIN)
-                       panel.panel_draw();
-       }
-       else if(HUD_Panel_CheckFlags(panel.panel_showflags))
-               panel.panel_draw();
-}
-
-void HUD_Reset(void)
-{
-       // reset gametype specific icons
-       if(gametype == MAPINFO_TYPE_CTF)
-               HUD_Mod_CTF_Reset();
-}
-
-void HUD_Main(void)
-{
-       int i;
-       // global hud theAlpha fade
-       if(menu_enabled == 1)
-               hud_fade_alpha = 1;
-       else
-               hud_fade_alpha = (1 - autocvar__menu_alpha);
-
-       if(scoreboard_fade_alpha)
-               hud_fade_alpha = (1 - scoreboard_fade_alpha);
-
-       HUD_Configure_Frame();
-
-       // panels that we want to be active together with the scoreboard
-       // they must fade only when the menu does
-       if(scoreboard_fade_alpha == 1)
-       {
-               HUD_Panel_Draw(HUD_PANEL(CENTERPRINT));
-               return;
-       }
-
-       if(!autocvar__hud_configure && !hud_fade_alpha)
-       {
-               hud_fade_alpha = 1;
-               HUD_Panel_Draw(HUD_PANEL(VOTE));
-               hud_fade_alpha = 0;
-               return;
-       }
-
-       // Drawing stuff
-       if (hud_skin_prev != autocvar_hud_skin)
-       {
-               if (hud_skin_path)
-                       strunzone(hud_skin_path);
-               hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin));
-               if (hud_skin_prev)
-                       strunzone(hud_skin_prev);
-               hud_skin_prev = strzone(autocvar_hud_skin);
-       }
-
-       // draw the dock
-       if(autocvar_hud_dock != "" && autocvar_hud_dock != "0")
-       {
-               int f;
-               vector color;
-               float hud_dock_color_team = autocvar_hud_dock_color_team;
-               if((teamplay) && hud_dock_color_team) {
-                       if(autocvar__hud_configure && myteam == NUM_SPECTATOR)
-                               color = '1 0 0' * hud_dock_color_team;
-                       else
-                               color = myteamcolors * hud_dock_color_team;
-               }
-               else if(autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && hud_dock_color_team) {
-                       color = '1 0 0' * hud_dock_color_team;
-               }
-               else
-               {
-                       string hud_dock_color = autocvar_hud_dock_color;
-                       if(hud_dock_color == "shirt") {
-                               f = stof(getplayerkeyvalue(current_player, "colors"));
-                               color = colormapPaletteColor(floor(f / 16), 0);
-                       }
-                       else if(hud_dock_color == "pants") {
-                               f = stof(getplayerkeyvalue(current_player, "colors"));
-                               color = colormapPaletteColor(f % 16, 1);
-                       }
-                       else
-                               color = stov(hud_dock_color);
-               }
-
-               string pic;
-               pic = strcat(hud_skin_path, "/", autocvar_hud_dock);
-               if(precache_pic(pic) == "") {
-                       pic = strcat(hud_skin_path, "/dock_medium");
-                       if(precache_pic(pic) == "") {
-                               pic = "gfx/hud/default/dock_medium";
-                       }
-               }
-               drawpic('0 0 0', pic, eX * vid_conwidth + eY * vid_conheight, color, autocvar_hud_dock_alpha * hud_fade_alpha, DRAWFLAG_NORMAL); // no aspect ratio forcing on dock...
-       }
-
-       // cache the panel order into the panel_order array
-       if(autocvar__hud_panelorder != hud_panelorder_prev) {
-               for(i = 0; i < hud_panels_COUNT; ++i)
-                       panel_order[i] = -1;
-               string s = "";
-               int p_num;
-               bool warning = false;
-               int argc = tokenize_console(autocvar__hud_panelorder);
-               if (argc > hud_panels_COUNT)
-                       warning = true;
-               //first detect wrong/missing panel numbers
-               for(i = 0; i < hud_panels_COUNT; ++i) {
-                       p_num = stoi(argv(i));
-                       if (p_num >= 0 && p_num < hud_panels_COUNT) { //correct panel number?
-                               if (panel_order[p_num] == -1) //found for the first time?
-                                       s = strcat(s, ftos(p_num), " ");
-                               panel_order[p_num] = 1; //mark as found
-                       }
-                       else
-                               warning = true;
-               }
-               for(i = 0; i < hud_panels_COUNT; ++i) {
-                       if (panel_order[i] == -1) {
-                               warning = true;
-                               s = strcat(s, ftos(i), " "); //add missing panel number
-                       }
-               }
-               if (warning)
-                       LOG_TRACE("Automatically fixed wrong/missing panel numbers in _hud_panelorder\n");
-
-               cvar_set("_hud_panelorder", s);
-               if(hud_panelorder_prev)
-                       strunzone(hud_panelorder_prev);
-               hud_panelorder_prev = strzone(s);
-
-               //now properly set panel_order
-               tokenize_console(s);
-               for(i = 0; i < hud_panels_COUNT; ++i) {
-                       panel_order[i] = stof(argv(i));
-               }
-       }
-
-       hud_draw_maximized = 0;
-       // draw panels in the order specified by panel_order array
-       for(i = hud_panels_COUNT - 1; i >= 0; --i)
-               HUD_Panel_Draw(hud_panels[panel_order[i]]);
-
-       HUD_Vehicle();
-
-       hud_draw_maximized = 1; // panels that may be maximized must check this var
-       // draw maximized panels on top
-       if(hud_panel_radar_maximized)
-               HUD_Panel_Draw(HUD_PANEL(RADAR));
-       if(autocvar__con_chat_maximized)
-               HUD_Panel_Draw(HUD_PANEL(CHAT));
-       if(hud_panel_quickmenu)
-               HUD_Panel_Draw(HUD_PANEL(QUICKMENU));
-
-       if (scoreboard_active || intermission == 2)
-               HUD_Reset();
-
-       HUD_Configure_PostDraw();
-
-       hud_configure_prev = autocvar__hud_configure;
-}
diff --git a/qcsrc/client/hud.qh b/qcsrc/client/hud.qh
deleted file mode 100644 (file)
index ba9cb17..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-#ifndef CLIENT_HUD_H
-#define CLIENT_HUD_H
-
-#include "../common/weapons/all.qh"
-
-bool HUD_Radar_Clickable();
-void HUD_Radar_Mouse();
-
-REGISTRY(hud_panels, 24)
-REGISTER_REGISTRY(Registerhud_panels)
-
-#define REGISTER_HUD_PANEL(id, draw_func, name, configflags, showflags) \
-       void draw_func(); \
-       REGISTER(Registerhud_panels, HUD_PANEL, hud_panels, id, m_id, new(hud_panel)) { \
-               this.panel_id = this.m_id; \
-               this.panel_draw = draw_func; \
-               this.panel_name = #name; \
-               this.panel_configflags = configflags; \
-               this.panel_showflags = showflags; \
-       }
-
-#define HUD_PANEL(NAME) HUD_PANEL_##NAME
-
-// draw the background/borders
-#define HUD_Panel_DrawBg(theAlpha) do {                                                                                                                                                                \
-       if(panel.current_panel_bg != "0" && panel.current_panel_bg != "")                                                                                               \
-               draw_BorderPicture(panel_pos - '1 1 0' * panel_bg_border, panel.current_panel_bg, panel_size + '1 1 0' * 2 * panel_bg_border, panel_bg_color, panel_bg_alpha * theAlpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER));\
-} while(0)
-
-int panel_order[hud_panels_MAX];
-string hud_panelorder_prev;
-
-bool hud_draw_maximized;
-bool hud_panel_radar_maximized;
-bool hud_panel_radar_mouse;
-float hud_panel_radar_bottom;
-bool hud_panel_radar_temp_hidden;
-bool chat_panel_modified;
-bool radar_panel_modified;
-
-float HUD_Radar_InputEvent(float bInputType, float nPrimary, float nSecondary);
-void HUD_Radar_Hide_Maximized();
-
-void HUD_Reset (void);
-void HUD_Main (void);
-
-int vote_yescount;
-int vote_nocount;
-int vote_needed;
-int vote_highlighted; // currently selected vote
-
-int vote_active; // is there an active vote?
-int vote_prev; // previous state of vote_active to check for a change
-float vote_alpha;
-float vote_change; // "time" when vote_active changed
-
-float hud_panel_quickmenu;
-
-vector mousepos;
-vector panel_click_distance; // mouse cursor distance from the top left corner of the panel (saved only upon a click)
-vector panel_click_resizeorigin; // coordinates for opposite point when resizing
-float resizeCorner; // 1 = topleft, 2 = topright, 3 = bottomleft, 4 = bottomright
-entity highlightedPanel;
-float highlightedAction; // 0 = nothing, 1 = move, 2 = resize
-
-const float BORDER_MULTIPLIER = 0.25;
-float scoreboard_bottom;
-int weapon_accuracy[Weapons_MAX];
-
-int complain_weapon;
-string complain_weapon_name;
-float complain_weapon_type;
-float complain_weapon_time;
-
-int ps_primary, ps_secondary;
-int ts_primary, ts_secondary;
-
-int last_switchweapon;
-int last_activeweapon;
-float weapontime;
-float weaponprevtime;
-
-float teamnagger;
-
-float hud_configure_checkcollisions;
-float hud_configure_prev;
-vector hud_configure_gridSize;
-vector hud_configure_realGridSize;
-
-int hudShiftState;
-const int S_SHIFT = 1;
-const int S_CTRL = 2;
-const int S_ALT = 4;
-
-float menu_enabled; // 1 showing the entire HUD, 2 showing only the clicked panel
-
-float hud_fade_alpha;
-
-string hud_skin_path;
-string hud_skin_prev;
-
-vector myteamcolors;
-
-entity highlightedPanel_backup;
-vector panel_pos_backup;
-vector panel_size_backup;
-
-vector panel_size_copied;
-
-entity panel;
-entityclass(HUDPanel);
-class(HUDPanel) .string panel_name;
-class(HUDPanel) .int panel_id;
-class(HUDPanel) .vector current_panel_pos;
-class(HUDPanel) .vector current_panel_size;
-class(HUDPanel) .string current_panel_bg;
-class(HUDPanel) .float current_panel_bg_alpha;
-class(HUDPanel) .float current_panel_bg_border;
-class(HUDPanel) .vector current_panel_bg_color;
-class(HUDPanel) .float current_panel_bg_color_team;
-class(HUDPanel) .float current_panel_bg_padding;
-class(HUDPanel) .float current_panel_fg_alpha;
-class(HUDPanel) .float update_time;
-float panel_enabled;
-vector panel_pos;
-vector panel_size;
-string panel_bg_str; // "_str" vars contain the raw value of the cvar, non-"_str" contains what hud.qc code should use
-vector panel_bg_color;
-string panel_bg_color_str;
-float panel_bg_color_team;
-string panel_bg_color_team_str;
-float panel_fg_alpha;
-float panel_bg_alpha;
-string panel_bg_alpha_str;
-float panel_bg_border;
-string panel_bg_border_str;
-float panel_bg_padding;
-string panel_bg_padding_str;
-
-class(HUDPanel) .void() panel_draw;
-
-// chat panel can be reduced / moved while the mapvote is active
-// let know the mapvote panel about chat pos and size
-float chat_posy;
-float chat_sizey;
-
-float current_player;
-
-float stringwidth_colors(string s, vector theSize);
-float stringwidth_nocolors(string s, vector theSize);
-float GetPlayerColorForce(int i);
-int GetPlayerColor(int i);
-string GetPlayerName(int i);
-void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag);
-
-.int panel_showflags;
-const int PANEL_SHOW_NEVER    = 0x00;
-const int PANEL_SHOW_MAINGAME = 0x01;
-const int PANEL_SHOW_MINIGAME = 0x02;
-const int PANEL_SHOW_MAPVOTE  = 0x04;
-const int PANEL_SHOW_ALWAYS   = 0xff;
-bool HUD_Panel_CheckFlags(int showflags);
-
-.int panel_configflags;
-const int PANEL_CONFIG_NO    = 0x00;
-const int PANEL_CONFIG_MAIN  = 0x01;
-
-
-// prev_* vars contain the health/armor at the previous FRAME
-// set to -1 when player is dead or was not playing
-int prev_health, prev_armor;
-float health_damagetime, armor_damagetime;
-int health_beforedamage, armor_beforedamage;
-// old_p_* vars keep track of previous values when smoothing value changes of the progressbar
-int old_p_health, old_p_armor;
-float old_p_healthtime, old_p_armortime;
-// prev_p_* vars contain the health/armor progressbar value at the previous FRAME
-// set to -1 to forcedly stop effects when we switch spectated player (e.g. from playerX: 70h to playerY: 50h)
-int prev_p_health, prev_p_armor;
-
-void HUD_ItemsTime();
-
-REGISTER_HUD_PANEL(WEAPONS,         HUD_Weapons,        weapons,        PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(AMMO,            HUD_Ammo,           ammo,           PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(POWERUPS,        HUD_Powerups,       powerups,       PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(HEALTHARMOR,     HUD_HealthArmor,    healtharmor,    PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(NOTIFY,          HUD_Notify,         notify,         PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
-REGISTER_HUD_PANEL(TIMER,           HUD_Timer,          timer,          PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
-REGISTER_HUD_PANEL(RADAR,           HUD_Radar,          radar,          PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(SCORE,           HUD_Score,          score,          PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
-REGISTER_HUD_PANEL(RACETIMER,       HUD_RaceTimer,      racetimer,      PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(VOTE,            HUD_Vote,           vote,           PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS  )
-REGISTER_HUD_PANEL(MODICONS,        HUD_ModIcons,       modicons,       PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(PRESSEDKEYS,     HUD_PressedKeys,    pressedkeys,    PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(CHAT,            HUD_Chat,           chat,           PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS  )
-REGISTER_HUD_PANEL(ENGINEINFO,      HUD_EngineInfo,     engineinfo,     PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS  )
-REGISTER_HUD_PANEL(INFOMESSAGES,    HUD_InfoMessages,   infomessages,   PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(PHYSICS,         HUD_Physics,        physics,        PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(CENTERPRINT,     HUD_CenterPrint,    centerprint,    PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(MINIGAME_BOARD,  HUD_MinigameBoard,  minigameboard,  PANEL_CONFIG_NO  , PANEL_SHOW_MINIGAME)
-REGISTER_HUD_PANEL(MINIGAME_STATUS, HUD_MinigameStatus, minigamestatus, PANEL_CONFIG_NO  , PANEL_SHOW_MINIGAME)
-REGISTER_HUD_PANEL(MINIGAME_HELP,   HUD_MinigameHelp,   minigamehelp,   PANEL_CONFIG_NO  , PANEL_SHOW_MINIGAME)
-REGISTER_HUD_PANEL(MINIGAME_MENU,   HUD_MinigameMenu,   minigamemenu,   PANEL_CONFIG_NO  , PANEL_SHOW_ALWAYS  )
-REGISTER_HUD_PANEL(MAPVOTE,         MapVote_Draw,       mapvote,        PANEL_CONFIG_NO  , PANEL_SHOW_MAPVOTE )
-REGISTER_HUD_PANEL(ITEMSTIME,       HUD_ItemsTime,      itemstime,      PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-REGISTER_HUD_PANEL(QUICKMENU,       HUD_QuickMenu,      quickmenu,      PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
-// always add new panels to the end of list
-
-// Because calling lots of functions in QC apparently cuts fps in half on many machines:
-// ----------------------
-// MACRO HELL STARTS HERE
-// ----------------------
-// Little help for the poor people who have to make sense of this: Start from the bottom ;)
-
-// Get value for panel.current_panel_bg: if "" fetch default, else use panel_bg_str
-// comment on last line of macro: // we probably want to see a background in config mode at all times...
-#define HUD_Panel_GetBg() do {                                                                                      \
-       string panel_bg;                                                                                                \
-       if (!autocvar__hud_configure && panel_bg_str == "0") {                                                          \
-               panel_bg = "0";                                                                                             \
-       } else {                                                                                                        \
-               if (panel_bg_str == "") {                                                                                   \
-                       panel_bg_str = autocvar_hud_panel_bg;                                                                   \
-               }                                                                                                           \
-               if (panel_bg_str == "0" && !autocvar__hud_configure) {                                                      \
-                       panel_bg = "0";                                                                                         \
-               } else {                                                                                                    \
-                       if (panel_bg_str == "0" && autocvar__hud_configure)                                                     \
-                               panel_bg_alpha_str = "0";                                                                           \
-                       panel_bg = strcat(hud_skin_path, "/", panel_bg_str);                                                    \
-                       if (precache_pic(panel_bg) == "") {                                                                     \
-                               panel_bg = strcat(hud_skin_path, "/", "border_default");                                            \
-                               if (precache_pic(panel_bg) == "") {                                                                 \
-                                       panel_bg = strcat("gfx/hud/default/", "border_default");                                        \
-                               }                                                                                                   \
-                       }                                                                                                       \
-               }                                                                                                           \
-       }                                                                                                               \
-       if (panel.current_panel_bg)                                                                                     \
-               strunzone(panel.current_panel_bg);                                                                          \
-       panel.current_panel_bg = strzone(panel_bg);                                                                     \
-} while(0)
-
-// Get value for panel_bg_color: if "" fetch default, else use panel_bg_color. Convert pants, shirt or teamcolor into a vector.
-#define HUD_Panel_GetColor() do {                                                                                   \
-       if ((teamplay) && panel_bg_color_team) {                                                                        \
-               if (autocvar__hud_configure && myteam == NUM_SPECTATOR)                                                     \
-                       panel_bg_color = '1 0 0' * panel_bg_color_team;                                                         \
-               else                                                                                                        \
-                       panel_bg_color = myteamcolors * panel_bg_color_team;                                                    \
-       } else if (autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && panel_bg_color_team) {          \
-               panel_bg_color = '1 0 0' * panel_bg_color_team;                                                             \
-       } else {                                                                                                        \
-               if (panel_bg_color_str == "") {                                                                             \
-                       panel_bg_color = autocvar_hud_panel_bg_color;                                                           \
-               } else {                                                                                                    \
-                       if (panel_bg_color_str == "shirt") {                                                                    \
-                               panel_bg_color = colormapPaletteColor(floor(stof(getplayerkeyvalue(current_player, "colors")) / 16), 0); \
-                       } else if (panel_bg_color_str == "pants") {                                                             \
-                               panel_bg_color = colormapPaletteColor(stof(getplayerkeyvalue(current_player, "colors")) % 16, 1); \
-                       } else {                                                                                                \
-                               panel_bg_color = stov(panel_bg_color_str);                                                          \
-                       }                                                                                                       \
-               }                                                                                                           \
-       }                                                                                                               \
-} while(0)
-
-// Get value for panel_bg_color_team: if "" fetch default, else use panel_bg_color_team_str
-#define HUD_Panel_GetColorTeam() do {                                                                               \
-       if (panel_bg_color_team_str == "") {                                                                            \
-               panel_bg_color_team = autocvar_hud_panel_bg_color_team;                                                     \
-       } else {                                                                                                        \
-               panel_bg_color_team = stof(panel_bg_color_team_str);                                                        \
-       }                                                                                                               \
-} while(0)
-
-// Get value for panel_bg_alpha: if "" fetch default, else use panel_bg_alpha. Also do various menu dialog fadeout/in checks, and minalpha checks
-// comment on line 3 of macro: // do not set a minalpha cap when showing the config dialog for this panel
-#define HUD_Panel_GetBgAlpha() do {                                                                                 \
-       if (panel_bg_alpha_str == "") {                                                                                 \
-               panel_bg_alpha_str = ftos(autocvar_hud_panel_bg_alpha);                                                     \
-       }                                                                                                               \
-       panel_bg_alpha = stof(panel_bg_alpha_str);                                                                      \
-       if (autocvar__hud_configure) {                                                                                  \
-               if (!panel_enabled)                                                                                         \
-                       panel_bg_alpha = 0.25;                                                                                  \
-               else if (menu_enabled == 2 && panel == highlightedPanel)                                                    \
-                       panel_bg_alpha = (1 - autocvar__menu_alpha) * max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha) + autocvar__menu_alpha * panel_bg_alpha;\
-               else                                                                                                        \
-                       panel_bg_alpha = max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha);                                \
-       }                                                                                                               \
-} while(0)
-
-// Get value for panel_fg_alpha. Also do various minalpha checks
-// comment on line 2 of macro: // ALWAYS show disabled panels at 0.25 alpha when in config mode
-#define HUD_Panel_GetFgAlpha() do {                                                                                 \
-       panel_fg_alpha = autocvar_hud_panel_fg_alpha;                                                                   \
-       if (autocvar__hud_configure && !panel_enabled)                                                                  \
-               panel_fg_alpha = 0.25;                                                                                      \
-} while(0)
-
-// Get border. See comments above, it's similar.
-#define HUD_Panel_GetBorder() do {                                                                                  \
-       if (panel_bg_border_str == "") {                                                                                \
-               panel_bg_border = autocvar_hud_panel_bg_border;                                                             \
-       } else {                                                                                                        \
-               panel_bg_border = stof(panel_bg_border_str);                                                                \
-       }                                                                                                               \
-} while(0)
-
-// Get padding. See comments above, it's similar.
-// last line is a port of the old function, basically always make sure the panel contents are at least 5 pixels tall/wide, to disallow extreme padding values
-#define HUD_Panel_GetPadding() do {                                                                                 \
-       if (panel_bg_padding_str == "") {                                                                               \
-               panel_bg_padding = autocvar_hud_panel_bg_padding;                                                           \
-       } else {                                                                                                        \
-               panel_bg_padding = stof(panel_bg_padding_str);                                                              \
-       }                                                                                                               \
-       panel_bg_padding = min(min(panel_size.x, panel_size.y)/2 - 5, panel_bg_padding);                                \
-} while(0)
-
-// return smoothly faded pos and size of given panel when a dialog is active
-// don't center too wide panels, it doesn't work with different resolutions
-#define HUD_Panel_UpdatePosSize_ForMenu() do { \
-       vector menu_enable_size = panel_size; \
-       float max_panel_width = 0.52 * vid_conwidth; \
-       if(panel_size.x > max_panel_width) \
-       { \
-               menu_enable_size.x = max_panel_width; \
-               menu_enable_size.y = panel_size.y * (menu_enable_size.x / panel_size.x); \
-       } \
-       vector menu_enable_pos = eX * (panel_bg_border + 0.5 * max_panel_width) + eY * 0.5 * vid_conheight - 0.5 * menu_enable_size; \
-       panel_pos = (1 - autocvar__menu_alpha) * panel_pos + (autocvar__menu_alpha) * menu_enable_pos; \
-       panel_size = (1 - autocvar__menu_alpha) * panel_size + (autocvar__menu_alpha) * menu_enable_size; \
-} while(0)
-
-// Scale the pos and size vectors to absolute coordinates
-#define HUD_Panel_ScalePosSize() do {                                                                               \
-       panel_pos.x *= vid_conwidth;  panel_pos.y *= vid_conheight;                                                     \
-       panel_size.x *= vid_conwidth; panel_size.y *= vid_conheight;                                                    \
-} while(0)
-
-// NOTE: in hud_configure mode cvars must be reloaded every frame
-#define HUD_Panel_UpdateCvars() do {                                                                                \
-       if (panel.update_time <= time) {                                                                                \
-               if (autocvar__hud_configure) panel_enabled = cvar(strcat("hud_panel_", panel.panel_name));                  \
-               panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos")));                              \
-               panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size")));                            \
-               HUD_Panel_ScalePosSize();                                                                                   \
-               panel_bg_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg"));                                  \
-               panel_bg_color_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color"));                      \
-               panel_bg_color_team_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color_team"));            \
-               panel_bg_alpha_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_alpha"));                      \
-               panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border"));                    \
-               panel_bg_padding_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_padding"));                  \
-               HUD_Panel_GetBg();                                                                                          \
-               if (panel.current_panel_bg != "0") {                                                                        \
-                       HUD_Panel_GetColorTeam();                                                                               \
-                       HUD_Panel_GetColor();                                                                                   \
-                       HUD_Panel_GetBgAlpha();                                                                                 \
-                       HUD_Panel_GetBorder();                                                                                  \
-               }                                                                                                           \
-               HUD_Panel_GetFgAlpha();                                                                                     \
-               HUD_Panel_GetPadding();                                                                                     \
-               panel.current_panel_bg_alpha = panel_bg_alpha;                                                              \
-               panel.current_panel_fg_alpha = panel_fg_alpha;                                                              \
-               if (menu_enabled == 2 && panel == highlightedPanel) {                                                       \
-                       HUD_Panel_UpdatePosSize_ForMenu();                                                                      \
-               } else {                                                                                                    \
-                       panel_bg_alpha *= hud_fade_alpha;                                                                       \
-                       panel_fg_alpha *= hud_fade_alpha;                                                                       \
-               }                                                                                                           \
-               panel.current_panel_pos = panel_pos;                                                                        \
-               panel.current_panel_size = panel_size;                                                                      \
-               panel.current_panel_bg_border = panel_bg_border;                                                            \
-               panel.current_panel_bg_color = panel_bg_color;                                                              \
-               panel.current_panel_bg_color_team = panel_bg_color_team;                                                    \
-               panel.current_panel_bg_padding = panel_bg_padding;                                                          \
-               panel.update_time = (autocvar__hud_configure) ? time : time + autocvar_hud_panel_update_interval;           \
-       } else {                                                                                                        \
-               panel_pos = panel.current_panel_pos;                                                                        \
-               panel_size = panel.current_panel_size;                                                                      \
-               panel_bg_alpha = panel.current_panel_bg_alpha * hud_fade_alpha;                                             \
-               panel_bg_border = panel.current_panel_bg_border;                                                            \
-               panel_bg_color = panel.current_panel_bg_color;                                                              \
-               panel_bg_color_team = panel.current_panel_bg_color_team;                                                    \
-               panel_bg_padding = panel.current_panel_bg_padding;                                                          \
-               panel_fg_alpha = panel.current_panel_fg_alpha * hud_fade_alpha;                                             \
-       }                                                                                                               \
-} while(0)
-
-#define HUD_Panel_UpdatePosSize() do {                                                                              \
-       panel_enabled = cvar(strcat("hud_panel_", panel.panel_name));                                                   \
-       panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos")));                                  \
-       panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size")));                                \
-       HUD_Panel_ScalePosSize();                                                                                       \
-       if (menu_enabled == 2 && panel == highlightedPanel) {                                                           \
-               HUD_Panel_UpdatePosSize_ForMenu();                                                                          \
-       }                                                                                                               \
-       panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border"));                        \
-       HUD_Panel_GetBorder();                                                                                          \
-} while(0)
-
-const int NOTIFY_MAX_ENTRIES = 10;
-const float NOTIFY_ICON_MARGIN = 0.02;
-
-int notify_index;
-int notify_count;
-float notify_times[NOTIFY_MAX_ENTRIES];
-string notify_attackers[NOTIFY_MAX_ENTRIES];
-string notify_victims[NOTIFY_MAX_ENTRIES];
-string notify_icons[NOTIFY_MAX_ENTRIES];
-
-void HUD_Notify_Push(string icon, string attacker, string victim);
-
-var void HUD_ModIcons_GameType(vector pos, vector size);
-void HUD_ModIcons_SetFunc();
-#endif
diff --git a/qcsrc/client/hud/all.inc b/qcsrc/client/hud/all.inc
new file mode 100644 (file)
index 0000000..aa36eec
--- /dev/null
@@ -0,0 +1,21 @@
+#include "panel/weapons.qc"
+#include "panel/ammo.qc"
+#include "panel/powerups.qc"
+#include "panel/healtharmor.qc"
+#include "panel/notify.qc"
+#include "panel/timer.qc"
+#include "panel/radar.qc"
+#include "panel/score.qc"
+#include "panel/racetimer.qc"
+#include "panel/vote.qc"
+#include "panel/modicons.qc"
+#include "panel/pressedkeys.qc"
+#include "panel/chat.qc"
+#include "panel/engineinfo.qc"
+#include "panel/infomessages.qc"
+#include "panel/physics.qc"
+#include "panel/centerprint.qc"
+#include "panel/minigame.qc"
+// #include "panel/mapvote.qc"
+// #include "panel/itemstime.qc"
+#include "panel/quickmenu.qc"
diff --git a/qcsrc/client/hud/all.qc b/qcsrc/client/hud/all.qc
new file mode 100644 (file)
index 0000000..680b023
--- /dev/null
@@ -0,0 +1,2 @@
+#include "hud.qc"
+#include "hud_config.qc"
diff --git a/qcsrc/client/hud/all.qh b/qcsrc/client/hud/all.qh
new file mode 100644 (file)
index 0000000..4f8cee5
--- /dev/null
@@ -0,0 +1,2 @@
+#include "hud.qh"
+#include "hud_config.qh"
diff --git a/qcsrc/client/hud/hud.qc b/qcsrc/client/hud/hud.qc
new file mode 100644 (file)
index 0000000..75e6782
--- /dev/null
@@ -0,0 +1,600 @@
+#include "hud.qh"
+
+#include "hud_config.qh"
+#include "mapvoting.qh"
+#include "scoreboard.qh"
+#include "teamradar.qh"
+#include "t_items.qh"
+#include "../common/deathtypes/all.qh"
+#include "../common/items/all.qc"
+#include "../common/mapinfo.qh"
+#include "../common/mutators/mutator/waypoints/all.qh"
+#include "../common/stats.qh"
+#include "../lib/csqcmodel/cl_player.qh"
+// TODO: remove
+#include "../server/mutators/mutator/gamemode_ctf.qc"
+
+
+/*
+==================
+Misc HUD functions
+==================
+*/
+
+vector HUD_Get_Num_Color (float x, float maxvalue)
+{
+       float blinkingamt;
+       vector color;
+       if(x >= maxvalue) {
+               color.x = sin(2*M_PI*time);
+               color.y = 1;
+               color.z = sin(2*M_PI*time);
+       }
+       else if(x > maxvalue * 0.75) {
+               color.x = 0.4 - (x-150)*0.02 * 0.4; //red value between 0.4 -> 0
+               color.y = 0.9 + (x-150)*0.02 * 0.1; // green value between 0.9 -> 1
+               color.z = 0;
+       }
+       else if(x > maxvalue * 0.5) {
+               color.x = 1 - (x-100)*0.02 * 0.6; //red value between 1 -> 0.4
+               color.y = 1 - (x-100)*0.02 * 0.1; // green value between 1 -> 0.9
+               color.z = 1 - (x-100)*0.02; // blue value between 1 -> 0
+       }
+       else if(x > maxvalue * 0.25) {
+               color.x = 1;
+               color.y = 1;
+               color.z = 0.2 + (x-50)*0.02 * 0.8; // blue value between 0.2 -> 1
+       }
+       else if(x > maxvalue * 0.1) {
+               color.x = 1;
+               color.y = (x-20)*90/27/100; // green value between 0 -> 1
+               color.z = (x-20)*90/27/100 * 0.2; // blue value between 0 -> 0.2
+       }
+       else {
+               color.x = 1;
+               color.y = 0;
+               color.z = 0;
+       }
+
+       blinkingamt = (1 - x/maxvalue/0.25);
+       if(blinkingamt > 0)
+       {
+               color.x = color.x - color.x * blinkingamt * sin(2*M_PI*time);
+               color.y = color.y - color.y * blinkingamt * sin(2*M_PI*time);
+               color.z = color.z - color.z * blinkingamt * sin(2*M_PI*time);
+       }
+       return color;
+}
+
+float HUD_GetRowCount(int item_count, vector size, float item_aspect)
+{
+       float aspect = size_y / size_x;
+       return bound(1, floor((sqrt(4 * item_aspect * aspect * item_count + aspect * aspect) + aspect + 0.5) / 2), item_count);
+}
+
+vector HUD_GetTableSize_BestItemAR(int item_count, vector psize, float item_aspect)
+{
+       float columns, rows;
+       float ratio, best_ratio = 0;
+       float best_columns = 1, best_rows = 1;
+       bool vertical = (psize.x / psize.y >= item_aspect);
+       if(vertical)
+       {
+               psize = eX * psize.y + eY * psize.x;
+               item_aspect = 1 / item_aspect;
+       }
+
+       rows = ceil(sqrt(item_count));
+       columns = ceil(item_count/rows);
+       while(columns >= 1)
+       {
+               ratio = (psize.x/columns) / (psize.y/rows);
+               if(ratio > item_aspect)
+                       ratio = item_aspect * item_aspect / ratio;
+
+               if(ratio <= best_ratio)
+                       break; // ratio starts decreasing by now, skip next configurations
+
+               best_columns = columns;
+               best_rows = rows;
+               best_ratio = ratio;
+
+               if(columns == 1)
+                       break;
+
+               --columns;
+               rows = ceil(item_count/columns);
+       }
+
+       if(vertical)
+               return eX * best_rows + eY * best_columns;
+       else
+               return eX * best_columns + eY * best_rows;
+}
+
+// return the string of the onscreen race timer
+string MakeRaceString(int cp, float mytime, float theirtime, float lapdelta, string theirname)
+{
+       string col;
+       string timestr;
+       string cpname;
+       string lapstr;
+       lapstr = "";
+
+       if(theirtime == 0) // goal hit
+       {
+               if(mytime > 0)
+               {
+                       timestr = strcat("+", ftos_decimals(+mytime, TIME_DECIMALS));
+                       col = "^1";
+               }
+               else if(mytime == 0)
+               {
+                       timestr = "+0.0";
+                       col = "^3";
+               }
+               else
+               {
+                       timestr = strcat("-", ftos_decimals(-mytime, TIME_DECIMALS));
+                       col = "^2";
+               }
+
+               if(lapdelta > 0)
+               {
+                       lapstr = sprintf(_(" (-%dL)"), lapdelta);
+                       col = "^2";
+               }
+               else if(lapdelta < 0)
+               {
+                       lapstr = sprintf(_(" (+%dL)"), -lapdelta);
+                       col = "^1";
+               }
+       }
+       else if(theirtime > 0) // anticipation
+       {
+               if(mytime >= theirtime)
+                       timestr = strcat("+", ftos_decimals(mytime - theirtime, TIME_DECIMALS));
+               else
+                       timestr = TIME_ENCODED_TOSTRING(TIME_ENCODE(theirtime));
+               col = "^3";
+       }
+       else
+       {
+               col = "^7";
+               timestr = "";
+       }
+
+       if(cp == 254)
+               cpname = _("Start line");
+       else if(cp == 255)
+               cpname = _("Finish line");
+       else if(cp)
+               cpname = sprintf(_("Intermediate %d"), cp);
+       else
+               cpname = _("Finish line");
+
+       if(theirtime < 0)
+               return strcat(col, cpname);
+       else if(theirname == "")
+               return strcat(col, sprintf("%s (%s)", cpname, timestr));
+       else
+               return strcat(col, sprintf("%s (%s %s)", cpname, timestr, strcat(theirname, col, lapstr)));
+}
+
+// Check if the given name already exist in race rankings? In that case, where? (otherwise return 0)
+int race_CheckName(string net_name)
+{
+       int i;
+       for (i=RANKINGS_CNT-1;i>=0;--i)
+               if(grecordholder[i] == net_name)
+                       return i+1;
+       return 0;
+}
+
+/*
+==================
+HUD panels
+==================
+*/
+
+//basically the same code of draw_ButtonPicture and draw_VertButtonPicture for the menu
+void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag)
+{
+       if(!length_ratio || !theAlpha)
+               return;
+       if(length_ratio > 1)
+               length_ratio = 1;
+       if (baralign == 3)
+       {
+               if(length_ratio < -1)
+                       length_ratio = -1;
+       }
+       else if(length_ratio < 0)
+               return;
+
+       vector square;
+       vector width, height;
+       if(vertical) {
+               pic = strcat(hud_skin_path, "/", pic, "_vertical");
+               if(precache_pic(pic) == "") {
+                       pic = "gfx/hud/default/progressbar_vertical";
+               }
+
+        if (baralign == 1) // bottom align
+                       theOrigin.y += (1 - length_ratio) * theSize.y;
+        else if (baralign == 2) // center align
+            theOrigin.y += 0.5 * (1 - length_ratio) * theSize.y;
+        else if (baralign == 3) // center align, positive values down, negative up
+               {
+                       theSize.y *= 0.5;
+                       if (length_ratio > 0)
+                               theOrigin.y += theSize.y;
+                       else
+                       {
+                               theOrigin.y += (1 + length_ratio) * theSize.y;
+                               length_ratio = -length_ratio;
+                       }
+               }
+               theSize.y *= length_ratio;
+
+               vector bH;
+               width = eX * theSize.x;
+               height = eY * theSize.y;
+               if(theSize.y <= theSize.x * 2)
+               {
+                       // button not high enough
+                       // draw just upper and lower part then
+                       square = eY * theSize.y * 0.5;
+                       bH = eY * (0.25 * theSize.y / (theSize.x * 2));
+                       drawsubpic(theOrigin,          square + width, pic, '0 0 0', eX + bH, theColor, theAlpha, drawflag);
+                       drawsubpic(theOrigin + square, square + width, pic, eY - bH, eX + bH, theColor, theAlpha, drawflag);
+               }
+               else
+               {
+                       square = eY * theSize.x;
+                       drawsubpic(theOrigin,                   width   +     square, pic, '0 0    0', '1 0.25 0', theColor, theAlpha, drawflag);
+                       drawsubpic(theOrigin +          square, theSize - 2 * square, pic, '0 0.25 0', '1 0.5  0', theColor, theAlpha, drawflag);
+                       drawsubpic(theOrigin + height - square, width   +     square, pic, '0 0.75 0', '1 0.25 0', theColor, theAlpha, drawflag);
+               }
+       } else {
+               pic = strcat(hud_skin_path, "/", pic);
+               if(precache_pic(pic) == "") {
+                       pic = "gfx/hud/default/progressbar";
+               }
+
+               if (baralign == 1) // right align
+                       theOrigin.x += (1 - length_ratio) * theSize.x;
+        else if (baralign == 2) // center align
+            theOrigin.x += 0.5 * (1 - length_ratio) * theSize.x;
+        else if (baralign == 3) // center align, positive values on the right, negative on the left
+               {
+                       theSize.x *= 0.5;
+                       if (length_ratio > 0)
+                               theOrigin.x += theSize.x;
+                       else
+                       {
+                               theOrigin.x += (1 + length_ratio) * theSize.x;
+                               length_ratio = -length_ratio;
+                       }
+               }
+               theSize.x *= length_ratio;
+
+               vector bW;
+               width = eX * theSize.x;
+               height = eY * theSize.y;
+               if(theSize.x <= theSize.y * 2)
+               {
+                       // button not wide enough
+                       // draw just left and right part then
+                       square = eX * theSize.x * 0.5;
+                       bW = eX * (0.25 * theSize.x / (theSize.y * 2));
+                       drawsubpic(theOrigin,          square + height, pic, '0 0 0', eY + bW, theColor, theAlpha, drawflag);
+                       drawsubpic(theOrigin + square, square + height, pic, eX - bW, eY + bW, theColor, theAlpha, drawflag);
+               }
+               else
+               {
+                       square = eX * theSize.y;
+                       drawsubpic(theOrigin,                  height  +     square, pic, '0    0 0', '0.25 1 0', theColor, theAlpha, drawflag);
+                       drawsubpic(theOrigin +         square, theSize - 2 * square, pic, '0.25 0 0', '0.5  1 0', theColor, theAlpha, drawflag);
+                       drawsubpic(theOrigin + width - square, height  +     square, pic, '0.75 0 0', '0.25 1 0', theColor, theAlpha, drawflag);
+               }
+       }
+}
+
+void HUD_Panel_DrawHighlight(vector pos, vector mySize, vector color, float theAlpha, int drawflag)
+{
+       if(!theAlpha)
+               return;
+
+       string pic;
+       pic = strcat(hud_skin_path, "/num_leading");
+       if(precache_pic(pic) == "") {
+               pic = "gfx/hud/default/num_leading";
+       }
+
+       drawsubpic(pos, eX * min(mySize.x * 0.5, mySize.y) + eY * mySize.y, pic, '0 0 0', '0.25 1 0', color, theAlpha, drawflag);
+       if(mySize.x/mySize.y > 2)
+               drawsubpic(pos + eX * mySize.y, eX * (mySize.x - 2 * mySize.y) + eY * mySize.y, pic, '0.25 0 0', '0.5 1 0', color, theAlpha, drawflag);
+       drawsubpic(pos + eX * mySize.x - eX * min(mySize.x * 0.5, mySize.y), eX * min(mySize.x * 0.5, mySize.y) + eY * mySize.y, pic, '0.75 0 0', '0.25 1 0', color, theAlpha, drawflag);
+}
+
+void DrawNumIcon_expanding(vector myPos, vector mySize, float x, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha, float fadelerp)
+{
+       vector newPos = '0 0 0', newSize = '0 0 0';
+       vector picpos, numpos;
+
+       if (vertical)
+       {
+               if(mySize.y/mySize.x > 2)
+               {
+                       newSize.y = 2 * mySize.x;
+                       newSize.x = mySize.x;
+
+                       newPos.y = myPos.y + (mySize.y - newSize.y) / 2;
+                       newPos.x = myPos.x;
+               }
+               else
+               {
+                       newSize.x = 1/2 * mySize.y;
+                       newSize.y = mySize.y;
+
+                       newPos.x = myPos.x + (mySize.x - newSize.x) / 2;
+                       newPos.y = myPos.y;
+               }
+
+               if(icon_right_align)
+               {
+                       numpos = newPos;
+                       picpos = newPos + eY * newSize.x;
+               }
+               else
+               {
+                       picpos = newPos;
+                       numpos = newPos + eY * newSize.x;
+               }
+
+               newSize.y /= 2;
+               drawpic_aspect_skin(picpos, icon, newSize, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+               // make number smaller than icon, it looks better
+               // reduce only y to draw numbers with different number of digits with the same y size
+               numpos.y += newSize.y * ((1 - 0.7) / 2);
+               newSize.y *= 0.7;
+               drawstring_aspect(numpos, ftos(x), newSize, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+               return;
+       }
+
+       if(mySize.x/mySize.y > 3)
+       {
+               newSize.x = 3 * mySize.y;
+               newSize.y = mySize.y;
+
+               newPos.x = myPos.x + (mySize.x - newSize.x) / 2;
+               newPos.y = myPos.y;
+       }
+       else
+       {
+               newSize.y = 1/3 * mySize.x;
+               newSize.x = mySize.x;
+
+               newPos.y = myPos.y + (mySize.y - newSize.y) / 2;
+               newPos.x = myPos.x;
+       }
+
+       if(icon_right_align) // right align
+       {
+               numpos = newPos;
+               picpos = newPos + eX * 2 * newSize.y;
+       }
+       else // left align
+       {
+               numpos = newPos + eX * newSize.y;
+               picpos = newPos;
+       }
+
+       // NOTE: newSize_x is always equal to 3 * mySize_y so we can use
+       // '2 1 0' * newSize_y instead of eX * (2/3) * newSize_x + eY * newSize_y
+       drawstring_aspect_expanding(numpos, ftos(x), '2 1 0' * newSize.y, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
+       drawpic_aspect_skin_expanding(picpos, icon, '1 1 0' * newSize.y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
+}
+
+void DrawNumIcon(vector myPos, vector mySize, float x, string icon, bool vertical, bool icon_right_align, vector color, float theAlpha)
+{
+       DrawNumIcon_expanding(myPos, mySize, x, icon, vertical, icon_right_align, color, theAlpha, 0);
+}
+
+#include "all.inc"
+
+/*
+==================
+Main HUD system
+==================
+*/
+
+void HUD_Vehicle()
+{
+       if(autocvar__hud_configure) return;
+       if(intermission == 2) return;
+
+       if(hud == HUD_BUMBLEBEE_GUN)
+               CSQC_BUMBLE_GUN_HUD();
+       else {
+               Vehicle info = get_vehicleinfo(hud);
+               info.vr_hud(info);
+       }
+}
+
+bool HUD_Panel_CheckFlags(int showflags)
+{
+       if ( HUD_Minigame_Showpanels() )
+               return showflags & PANEL_SHOW_MINIGAME;
+       if(intermission == 2)
+               return showflags & PANEL_SHOW_MAPVOTE;
+       return showflags & PANEL_SHOW_MAINGAME;
+}
+
+void HUD_Panel_Draw(entity panent)
+{
+       panel = panent;
+       if(autocvar__hud_configure)
+       {
+               if(panel.panel_configflags & PANEL_CONFIG_MAIN)
+                       panel.panel_draw();
+       }
+       else if(HUD_Panel_CheckFlags(panel.panel_showflags))
+               panel.panel_draw();
+}
+
+void HUD_Reset()
+{
+       // reset gametype specific icons
+       if(gametype == MAPINFO_TYPE_CTF)
+               HUD_Mod_CTF_Reset();
+}
+
+void HUD_Main()
+{
+       int i;
+       // global hud theAlpha fade
+       if(menu_enabled == 1)
+               hud_fade_alpha = 1;
+       else
+               hud_fade_alpha = (1 - autocvar__menu_alpha);
+
+       if(scoreboard_fade_alpha)
+               hud_fade_alpha = (1 - scoreboard_fade_alpha);
+
+       HUD_Configure_Frame();
+
+       // panels that we want to be active together with the scoreboard
+       // they must fade only when the menu does
+       if(scoreboard_fade_alpha == 1)
+       {
+               HUD_Panel_Draw(HUD_PANEL(CENTERPRINT));
+               return;
+       }
+
+       if(!autocvar__hud_configure && !hud_fade_alpha)
+       {
+               hud_fade_alpha = 1;
+               HUD_Panel_Draw(HUD_PANEL(VOTE));
+               hud_fade_alpha = 0;
+               return;
+       }
+
+       // Drawing stuff
+       if (hud_skin_prev != autocvar_hud_skin)
+       {
+               if (hud_skin_path)
+                       strunzone(hud_skin_path);
+               hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin));
+               if (hud_skin_prev)
+                       strunzone(hud_skin_prev);
+               hud_skin_prev = strzone(autocvar_hud_skin);
+       }
+
+       // draw the dock
+       if(autocvar_hud_dock != "" && autocvar_hud_dock != "0")
+       {
+               int f;
+               vector color;
+               float hud_dock_color_team = autocvar_hud_dock_color_team;
+               if((teamplay) && hud_dock_color_team) {
+                       if(autocvar__hud_configure && myteam == NUM_SPECTATOR)
+                               color = '1 0 0' * hud_dock_color_team;
+                       else
+                               color = myteamcolors * hud_dock_color_team;
+               }
+               else if(autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && hud_dock_color_team) {
+                       color = '1 0 0' * hud_dock_color_team;
+               }
+               else
+               {
+                       string hud_dock_color = autocvar_hud_dock_color;
+                       if(hud_dock_color == "shirt") {
+                               f = stof(getplayerkeyvalue(current_player, "colors"));
+                               color = colormapPaletteColor(floor(f / 16), 0);
+                       }
+                       else if(hud_dock_color == "pants") {
+                               f = stof(getplayerkeyvalue(current_player, "colors"));
+                               color = colormapPaletteColor(f % 16, 1);
+                       }
+                       else
+                               color = stov(hud_dock_color);
+               }
+
+               string pic;
+               pic = strcat(hud_skin_path, "/", autocvar_hud_dock);
+               if(precache_pic(pic) == "") {
+                       pic = strcat(hud_skin_path, "/dock_medium");
+                       if(precache_pic(pic) == "") {
+                               pic = "gfx/hud/default/dock_medium";
+                       }
+               }
+               drawpic('0 0 0', pic, eX * vid_conwidth + eY * vid_conheight, color, autocvar_hud_dock_alpha * hud_fade_alpha, DRAWFLAG_NORMAL); // no aspect ratio forcing on dock...
+       }
+
+       // cache the panel order into the panel_order array
+       if(autocvar__hud_panelorder != hud_panelorder_prev) {
+               for(i = 0; i < hud_panels_COUNT; ++i)
+                       panel_order[i] = -1;
+               string s = "";
+               int p_num;
+               bool warning = false;
+               int argc = tokenize_console(autocvar__hud_panelorder);
+               if (argc > hud_panels_COUNT)
+                       warning = true;
+               //first detect wrong/missing panel numbers
+               for(i = 0; i < hud_panels_COUNT; ++i) {
+                       p_num = stoi(argv(i));
+                       if (p_num >= 0 && p_num < hud_panels_COUNT) { //correct panel number?
+                               if (panel_order[p_num] == -1) //found for the first time?
+                                       s = strcat(s, ftos(p_num), " ");
+                               panel_order[p_num] = 1; //mark as found
+                       }
+                       else
+                               warning = true;
+               }
+               for(i = 0; i < hud_panels_COUNT; ++i) {
+                       if (panel_order[i] == -1) {
+                               warning = true;
+                               s = strcat(s, ftos(i), " "); //add missing panel number
+                       }
+               }
+               if (warning)
+                       LOG_TRACE("Automatically fixed wrong/missing panel numbers in _hud_panelorder\n");
+
+               cvar_set("_hud_panelorder", s);
+               if(hud_panelorder_prev)
+                       strunzone(hud_panelorder_prev);
+               hud_panelorder_prev = strzone(s);
+
+               //now properly set panel_order
+               tokenize_console(s);
+               for(i = 0; i < hud_panels_COUNT; ++i) {
+                       panel_order[i] = stof(argv(i));
+               }
+       }
+
+       hud_draw_maximized = 0;
+       // draw panels in the order specified by panel_order array
+       for(i = hud_panels_COUNT - 1; i >= 0; --i)
+               HUD_Panel_Draw(hud_panels_from(panel_order[i]));
+
+       HUD_Vehicle();
+
+       hud_draw_maximized = 1; // panels that may be maximized must check this var
+       // draw maximized panels on top
+       if(hud_panel_radar_maximized)
+               HUD_Panel_Draw(HUD_PANEL(RADAR));
+       if(autocvar__con_chat_maximized)
+               HUD_Panel_Draw(HUD_PANEL(CHAT));
+       if(hud_panel_quickmenu)
+               HUD_Panel_Draw(HUD_PANEL(QUICKMENU));
+
+       if (scoreboard_active || intermission == 2)
+               HUD_Reset();
+
+       HUD_Configure_PostDraw();
+
+       hud_configure_prev = autocvar__hud_configure;
+}
diff --git a/qcsrc/client/hud/hud.qh b/qcsrc/client/hud/hud.qh
new file mode 100644 (file)
index 0000000..7762d16
--- /dev/null
@@ -0,0 +1,420 @@
+#ifndef CLIENT_HUD_H
+#define CLIENT_HUD_H
+
+#include "../common/weapons/all.qh"
+
+bool HUD_Radar_Clickable();
+void HUD_Radar_Mouse();
+
+REGISTRY(hud_panels, BITS(6))
+#define hud_panels_from(i) _hud_panels_from(i, NULL)
+REGISTER_REGISTRY(hud_panels)
+
+#define REGISTER_HUD_PANEL(id, draw_func, name, configflags, showflags) \
+       void draw_func(); \
+       REGISTER(hud_panels, HUD_PANEL, id, m_id, new(hud_panel)) { \
+               make_pure(this); \
+               this.panel_id = this.m_id; \
+               this.panel_draw = draw_func; \
+               this.panel_name = #name; \
+               this.panel_configflags = configflags; \
+               this.panel_showflags = showflags; \
+       }
+
+#define HUD_PANEL(NAME) HUD_PANEL_##NAME
+
+// draw the background/borders
+#define HUD_Panel_DrawBg(theAlpha) do {                                                                                                                                                                \
+       if(panel.current_panel_bg != "0" && panel.current_panel_bg != "")                                                                                               \
+               draw_BorderPicture(panel_pos - '1 1 0' * panel_bg_border, panel.current_panel_bg, panel_size + '1 1 0' * 2 * panel_bg_border, panel_bg_color, panel_bg_alpha * theAlpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER));\
+} while(0)
+
+int panel_order[hud_panels_MAX];
+string hud_panelorder_prev;
+
+bool hud_draw_maximized;
+bool hud_panel_radar_maximized;
+bool hud_panel_radar_mouse;
+float hud_panel_radar_bottom;
+bool hud_panel_radar_temp_hidden;
+bool chat_panel_modified;
+bool radar_panel_modified;
+
+float HUD_Radar_InputEvent(float bInputType, float nPrimary, float nSecondary);
+void HUD_Radar_Hide_Maximized();
+
+void HUD_Reset ();
+void HUD_Main ();
+
+int vote_yescount;
+int vote_nocount;
+int vote_needed;
+int vote_highlighted; // currently selected vote
+
+int vote_active; // is there an active vote?
+int vote_prev; // previous state of vote_active to check for a change
+float vote_alpha;
+float vote_change; // "time" when vote_active changed
+
+float hud_panel_quickmenu;
+
+vector mousepos;
+vector panel_click_distance; // mouse cursor distance from the top left corner of the panel (saved only upon a click)
+vector panel_click_resizeorigin; // coordinates for opposite point when resizing
+float resizeCorner; // 1 = topleft, 2 = topright, 3 = bottomleft, 4 = bottomright
+entity highlightedPanel;
+float highlightedAction; // 0 = nothing, 1 = move, 2 = resize
+
+const float BORDER_MULTIPLIER = 0.25;
+float scoreboard_bottom;
+int weapon_accuracy[Weapons_MAX];
+
+int complain_weapon;
+string complain_weapon_name;
+float complain_weapon_type;
+float complain_weapon_time;
+
+int ps_primary, ps_secondary;
+int ts_primary, ts_secondary;
+
+int last_switchweapon;
+int last_activeweapon;
+float weapontime;
+float weaponprevtime;
+
+float teamnagger;
+
+float hud_configure_checkcollisions;
+float hud_configure_prev;
+vector hud_configure_gridSize;
+vector hud_configure_realGridSize;
+
+int hudShiftState;
+const int S_SHIFT = 1;
+const int S_CTRL = 2;
+const int S_ALT = 4;
+
+float menu_enabled; // 1 showing the entire HUD, 2 showing only the clicked panel
+
+float hud_fade_alpha;
+
+string hud_skin_path;
+string hud_skin_prev;
+
+vector myteamcolors;
+
+entity highlightedPanel_backup;
+vector panel_pos_backup;
+vector panel_size_backup;
+
+vector panel_size_copied;
+
+entity panel;
+entityclass(HUDPanel);
+class(HUDPanel) .string panel_name;
+class(HUDPanel) .int panel_id;
+class(HUDPanel) .vector current_panel_pos;
+class(HUDPanel) .vector current_panel_size;
+class(HUDPanel) .string current_panel_bg;
+class(HUDPanel) .float current_panel_bg_alpha;
+class(HUDPanel) .float current_panel_bg_border;
+class(HUDPanel) .vector current_panel_bg_color;
+class(HUDPanel) .float current_panel_bg_color_team;
+class(HUDPanel) .float current_panel_bg_padding;
+class(HUDPanel) .float current_panel_fg_alpha;
+class(HUDPanel) .float update_time;
+float panel_enabled;
+vector panel_pos;
+vector panel_size;
+string panel_bg_str; // "_str" vars contain the raw value of the cvar, non-"_str" contains what hud.qc code should use
+vector panel_bg_color;
+string panel_bg_color_str;
+float panel_bg_color_team;
+string panel_bg_color_team_str;
+float panel_fg_alpha;
+float panel_bg_alpha;
+string panel_bg_alpha_str;
+float panel_bg_border;
+string panel_bg_border_str;
+float panel_bg_padding;
+string panel_bg_padding_str;
+
+class(HUDPanel) .void() panel_draw;
+
+// chat panel can be reduced / moved while the mapvote is active
+// let know the mapvote panel about chat pos and size
+float chat_posy;
+float chat_sizey;
+
+float current_player;
+
+float stringwidth_colors(string s, vector theSize);
+float stringwidth_nocolors(string s, vector theSize);
+float GetPlayerColorForce(int i);
+int GetPlayerColor(int i);
+string GetPlayerName(int i);
+void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag);
+
+.int panel_showflags;
+const int PANEL_SHOW_NEVER    = 0x00;
+const int PANEL_SHOW_MAINGAME = 0x01;
+const int PANEL_SHOW_MINIGAME = 0x02;
+const int PANEL_SHOW_MAPVOTE  = 0x04;
+const int PANEL_SHOW_ALWAYS   = 0xff;
+bool HUD_Panel_CheckFlags(int showflags);
+
+.int panel_configflags;
+const int PANEL_CONFIG_NO    = 0x00;
+const int PANEL_CONFIG_MAIN  = 0x01;
+
+
+// prev_* vars contain the health/armor at the previous FRAME
+// set to -1 when player is dead or was not playing
+int prev_health, prev_armor;
+float health_damagetime, armor_damagetime;
+int health_beforedamage, armor_beforedamage;
+// old_p_* vars keep track of previous values when smoothing value changes of the progressbar
+int old_p_health, old_p_armor;
+float old_p_healthtime, old_p_armortime;
+// prev_p_* vars contain the health/armor progressbar value at the previous FRAME
+// set to -1 to forcedly stop effects when we switch spectated player (e.g. from playerX: 70h to playerY: 50h)
+int prev_p_health, prev_p_armor;
+
+void HUD_ItemsTime();
+
+REGISTER_HUD_PANEL(WEAPONS,         HUD_Weapons,        weapons,        PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(AMMO,            HUD_Ammo,           ammo,           PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(POWERUPS,        HUD_Powerups,       powerups,       PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(HEALTHARMOR,     HUD_HealthArmor,    healtharmor,    PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(NOTIFY,          HUD_Notify,         notify,         PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
+REGISTER_HUD_PANEL(TIMER,           HUD_Timer,          timer,          PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
+REGISTER_HUD_PANEL(RADAR,           HUD_Radar,          radar,          PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(SCORE,           HUD_Score,          score,          PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS & ~PANEL_SHOW_MAPVOTE)
+REGISTER_HUD_PANEL(RACETIMER,       HUD_RaceTimer,      racetimer,      PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(VOTE,            HUD_Vote,           vote,           PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS  )
+REGISTER_HUD_PANEL(MODICONS,        HUD_ModIcons,       modicons,       PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(PRESSEDKEYS,     HUD_PressedKeys,    pressedkeys,    PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(CHAT,            HUD_Chat,           chat,           PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS  )
+REGISTER_HUD_PANEL(ENGINEINFO,      HUD_EngineInfo,     engineinfo,     PANEL_CONFIG_MAIN, PANEL_SHOW_ALWAYS  )
+REGISTER_HUD_PANEL(INFOMESSAGES,    HUD_InfoMessages,   infomessages,   PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(PHYSICS,         HUD_Physics,        physics,        PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(CENTERPRINT,     HUD_CenterPrint,    centerprint,    PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(MINIGAME_BOARD,  HUD_MinigameBoard,  minigameboard,  PANEL_CONFIG_NO  , PANEL_SHOW_MINIGAME)
+REGISTER_HUD_PANEL(MINIGAME_STATUS, HUD_MinigameStatus, minigamestatus, PANEL_CONFIG_NO  , PANEL_SHOW_MINIGAME)
+REGISTER_HUD_PANEL(MINIGAME_HELP,   HUD_MinigameHelp,   minigamehelp,   PANEL_CONFIG_NO  , PANEL_SHOW_MINIGAME)
+REGISTER_HUD_PANEL(MINIGAME_MENU,   HUD_MinigameMenu,   minigamemenu,   PANEL_CONFIG_NO  , PANEL_SHOW_ALWAYS  )
+REGISTER_HUD_PANEL(MAPVOTE,         MapVote_Draw,       mapvote,        PANEL_CONFIG_NO  , PANEL_SHOW_MAPVOTE )
+REGISTER_HUD_PANEL(ITEMSTIME,       HUD_ItemsTime,      itemstime,      PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(QUICKMENU,       HUD_QuickMenu,      quickmenu,      PANEL_CONFIG_MAIN, PANEL_SHOW_MAINGAME)
+// always add new panels to the end of list
+
+// Because calling lots of functions in QC apparently cuts fps in half on many machines:
+// ----------------------
+// MACRO HELL STARTS HERE
+// ----------------------
+// Little help for the poor people who have to make sense of this: Start from the bottom ;)
+
+// Get value for panel.current_panel_bg: if "" fetch default, else use panel_bg_str
+// comment on last line of macro: // we probably want to see a background in config mode at all times...
+#define HUD_Panel_GetBg() do {                                                                                      \
+       string panel_bg;                                                                                                \
+       if (!autocvar__hud_configure && panel_bg_str == "0") {                                                          \
+               panel_bg = "0";                                                                                             \
+       } else {                                                                                                        \
+               if (panel_bg_str == "") {                                                                                   \
+                       panel_bg_str = autocvar_hud_panel_bg;                                                                   \
+               }                                                                                                           \
+               if (panel_bg_str == "0" && !autocvar__hud_configure) {                                                      \
+                       panel_bg = "0";                                                                                         \
+               } else {                                                                                                    \
+                       if (panel_bg_str == "0" && autocvar__hud_configure)                                                     \
+                               panel_bg_alpha_str = "0";                                                                           \
+                       panel_bg = strcat(hud_skin_path, "/", panel_bg_str);                                                    \
+                       if (precache_pic(panel_bg) == "") {                                                                     \
+                               panel_bg = strcat(hud_skin_path, "/", "border_default");                                            \
+                               if (precache_pic(panel_bg) == "") {                                                                 \
+                                       panel_bg = strcat("gfx/hud/default/", "border_default");                                        \
+                               }                                                                                                   \
+                       }                                                                                                       \
+               }                                                                                                           \
+       }                                                                                                               \
+       if (panel.current_panel_bg)                                                                                     \
+               strunzone(panel.current_panel_bg);                                                                          \
+       panel.current_panel_bg = strzone(panel_bg);                                                                     \
+} while(0)
+
+// Get value for panel_bg_color: if "" fetch default, else use panel_bg_color. Convert pants, shirt or teamcolor into a vector.
+#define HUD_Panel_GetColor() do {                                                                                   \
+       if ((teamplay) && panel_bg_color_team) {                                                                        \
+               if (autocvar__hud_configure && myteam == NUM_SPECTATOR)                                                     \
+                       panel_bg_color = '1 0 0' * panel_bg_color_team;                                                         \
+               else                                                                                                        \
+                       panel_bg_color = myteamcolors * panel_bg_color_team;                                                    \
+       } else if (autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && panel_bg_color_team) {          \
+               panel_bg_color = '1 0 0' * panel_bg_color_team;                                                             \
+       } else {                                                                                                        \
+               if (panel_bg_color_str == "") {                                                                             \
+                       panel_bg_color = autocvar_hud_panel_bg_color;                                                           \
+               } else {                                                                                                    \
+                       if (panel_bg_color_str == "shirt") {                                                                    \
+                               panel_bg_color = colormapPaletteColor(floor(stof(getplayerkeyvalue(current_player, "colors")) / 16), 0); \
+                       } else if (panel_bg_color_str == "pants") {                                                             \
+                               panel_bg_color = colormapPaletteColor(stof(getplayerkeyvalue(current_player, "colors")) % 16, 1); \
+                       } else {                                                                                                \
+                               panel_bg_color = stov(panel_bg_color_str);                                                          \
+                       }                                                                                                       \
+               }                                                                                                           \
+       }                                                                                                               \
+} while(0)
+
+// Get value for panel_bg_color_team: if "" fetch default, else use panel_bg_color_team_str
+#define HUD_Panel_GetColorTeam() do {                                                                               \
+       if (panel_bg_color_team_str == "") {                                                                            \
+               panel_bg_color_team = autocvar_hud_panel_bg_color_team;                                                     \
+       } else {                                                                                                        \
+               panel_bg_color_team = stof(panel_bg_color_team_str);                                                        \
+       }                                                                                                               \
+} while(0)
+
+// Get value for panel_bg_alpha: if "" fetch default, else use panel_bg_alpha. Also do various menu dialog fadeout/in checks, and minalpha checks
+// comment on line 3 of macro: // do not set a minalpha cap when showing the config dialog for this panel
+#define HUD_Panel_GetBgAlpha() do {                                                                                 \
+       if (panel_bg_alpha_str == "") {                                                                                 \
+               panel_bg_alpha_str = ftos(autocvar_hud_panel_bg_alpha);                                                     \
+       }                                                                                                               \
+       panel_bg_alpha = stof(panel_bg_alpha_str);                                                                      \
+       if (autocvar__hud_configure) {                                                                                  \
+               if (!panel_enabled)                                                                                         \
+                       panel_bg_alpha = 0.25;                                                                                  \
+               else if (menu_enabled == 2 && panel == highlightedPanel)                                                    \
+                       panel_bg_alpha = (1 - autocvar__menu_alpha) * max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha) + autocvar__menu_alpha * panel_bg_alpha;\
+               else                                                                                                        \
+                       panel_bg_alpha = max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha);                                \
+       }                                                                                                               \
+} while(0)
+
+// Get value for panel_fg_alpha. Also do various minalpha checks
+// comment on line 2 of macro: // ALWAYS show disabled panels at 0.25 alpha when in config mode
+#define HUD_Panel_GetFgAlpha() do {                                                                                 \
+       panel_fg_alpha = autocvar_hud_panel_fg_alpha;                                                                   \
+       if (autocvar__hud_configure && !panel_enabled)                                                                  \
+               panel_fg_alpha = 0.25;                                                                                      \
+} while(0)
+
+// Get border. See comments above, it's similar.
+#define HUD_Panel_GetBorder() do {                                                                                  \
+       if (panel_bg_border_str == "") {                                                                                \
+               panel_bg_border = autocvar_hud_panel_bg_border;                                                             \
+       } else {                                                                                                        \
+               panel_bg_border = stof(panel_bg_border_str);                                                                \
+       }                                                                                                               \
+} while(0)
+
+// Get padding. See comments above, it's similar.
+// last line is a port of the old function, basically always make sure the panel contents are at least 5 pixels tall/wide, to disallow extreme padding values
+#define HUD_Panel_GetPadding() do {                                                                                 \
+       if (panel_bg_padding_str == "") {                                                                               \
+               panel_bg_padding = autocvar_hud_panel_bg_padding;                                                           \
+       } else {                                                                                                        \
+               panel_bg_padding = stof(panel_bg_padding_str);                                                              \
+       }                                                                                                               \
+       panel_bg_padding = min(min(panel_size.x, panel_size.y)/2 - 5, panel_bg_padding);                                \
+} while(0)
+
+// return smoothly faded pos and size of given panel when a dialog is active
+// don't center too wide panels, it doesn't work with different resolutions
+#define HUD_Panel_UpdatePosSize_ForMenu() do { \
+       vector menu_enable_size = panel_size; \
+       float max_panel_width = 0.52 * vid_conwidth; \
+       if(panel_size.x > max_panel_width) \
+       { \
+               menu_enable_size.x = max_panel_width; \
+               menu_enable_size.y = panel_size.y * (menu_enable_size.x / panel_size.x); \
+       } \
+       vector menu_enable_pos = eX * (panel_bg_border + 0.5 * max_panel_width) + eY * 0.5 * vid_conheight - 0.5 * menu_enable_size; \
+       panel_pos = (1 - autocvar__menu_alpha) * panel_pos + (autocvar__menu_alpha) * menu_enable_pos; \
+       panel_size = (1 - autocvar__menu_alpha) * panel_size + (autocvar__menu_alpha) * menu_enable_size; \
+} while(0)
+
+// Scale the pos and size vectors to absolute coordinates
+#define HUD_Panel_ScalePosSize() do {                                                                               \
+       panel_pos.x *= vid_conwidth;  panel_pos.y *= vid_conheight;                                                     \
+       panel_size.x *= vid_conwidth; panel_size.y *= vid_conheight;                                                    \
+} while(0)
+
+// NOTE: in hud_configure mode cvars must be reloaded every frame
+#define HUD_Panel_UpdateCvars() do {                                                                                \
+       if (panel.update_time <= time) {                                                                                \
+               if (autocvar__hud_configure) panel_enabled = cvar(strcat("hud_panel_", panel.panel_name));                  \
+               panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos")));                              \
+               panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size")));                            \
+               HUD_Panel_ScalePosSize();                                                                                   \
+               panel_bg_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg"));                                  \
+               panel_bg_color_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color"));                      \
+               panel_bg_color_team_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_color_team"));            \
+               panel_bg_alpha_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_alpha"));                      \
+               panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border"));                    \
+               panel_bg_padding_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_padding"));                  \
+               HUD_Panel_GetBg();                                                                                          \
+               if (panel.current_panel_bg != "0") {                                                                        \
+                       HUD_Panel_GetColorTeam();                                                                               \
+                       HUD_Panel_GetColor();                                                                                   \
+                       HUD_Panel_GetBgAlpha();                                                                                 \
+                       HUD_Panel_GetBorder();                                                                                  \
+               }                                                                                                           \
+               HUD_Panel_GetFgAlpha();                                                                                     \
+               HUD_Panel_GetPadding();                                                                                     \
+               panel.current_panel_bg_alpha = panel_bg_alpha;                                                              \
+               panel.current_panel_fg_alpha = panel_fg_alpha;                                                              \
+               if (menu_enabled == 2 && panel == highlightedPanel) {                                                       \
+                       HUD_Panel_UpdatePosSize_ForMenu();                                                                      \
+               } else {                                                                                                    \
+                       panel_bg_alpha *= hud_fade_alpha;                                                                       \
+                       panel_fg_alpha *= hud_fade_alpha;                                                                       \
+               }                                                                                                           \
+               panel.current_panel_pos = panel_pos;                                                                        \
+               panel.current_panel_size = panel_size;                                                                      \
+               panel.current_panel_bg_border = panel_bg_border;                                                            \
+               panel.current_panel_bg_color = panel_bg_color;                                                              \
+               panel.current_panel_bg_color_team = panel_bg_color_team;                                                    \
+               panel.current_panel_bg_padding = panel_bg_padding;                                                          \
+               panel.update_time = (autocvar__hud_configure) ? time : time + autocvar_hud_panel_update_interval;           \
+       } else {                                                                                                        \
+               panel_pos = panel.current_panel_pos;                                                                        \
+               panel_size = panel.current_panel_size;                                                                      \
+               panel_bg_alpha = panel.current_panel_bg_alpha * hud_fade_alpha;                                             \
+               panel_bg_border = panel.current_panel_bg_border;                                                            \
+               panel_bg_color = panel.current_panel_bg_color;                                                              \
+               panel_bg_color_team = panel.current_panel_bg_color_team;                                                    \
+               panel_bg_padding = panel.current_panel_bg_padding;                                                          \
+               panel_fg_alpha = panel.current_panel_fg_alpha * hud_fade_alpha;                                             \
+       }                                                                                                               \
+} while(0)
+
+#define HUD_Panel_UpdatePosSize() do {                                                                              \
+       panel_enabled = cvar(strcat("hud_panel_", panel.panel_name));                                                   \
+       panel_pos = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_pos")));                                  \
+       panel_size = stov(cvar_string(strcat("hud_panel_", panel.panel_name, "_size")));                                \
+       HUD_Panel_ScalePosSize();                                                                                       \
+       if (menu_enabled == 2 && panel == highlightedPanel) {                                                           \
+               HUD_Panel_UpdatePosSize_ForMenu();                                                                          \
+       }                                                                                                               \
+       panel_bg_border_str = cvar_string(strcat("hud_panel_", panel.panel_name, "_bg_border"));                        \
+       HUD_Panel_GetBorder();                                                                                          \
+} while(0)
+
+const int NOTIFY_MAX_ENTRIES = 10;
+const float NOTIFY_ICON_MARGIN = 0.02;
+
+int notify_index;
+int notify_count;
+float notify_times[NOTIFY_MAX_ENTRIES];
+string notify_attackers[NOTIFY_MAX_ENTRIES];
+string notify_victims[NOTIFY_MAX_ENTRIES];
+string notify_icons[NOTIFY_MAX_ENTRIES];
+
+void HUD_Notify_Push(string icon, string attacker, string victim);
+
+var void HUD_ModIcons_GameType(vector pos, vector size);
+void HUD_ModIcons_SetFunc();
+#endif
diff --git a/qcsrc/client/hud/hud_config.qc b/qcsrc/client/hud/hud_config.qc
new file mode 100644 (file)
index 0000000..6b05078
--- /dev/null
@@ -0,0 +1,1297 @@
+#include "hud_config.qh"
+
+#include "hud.qh"
+
+#define HUD_Write(s) fputs(fh, s)
+// q: quoted, n: not quoted
+#define HUD_Write_Cvar_n(cvar) HUD_Write(strcat("seta ", cvar, " ", cvar_string(cvar), "\n"))
+#define HUD_Write_Cvar_q(cvar) HUD_Write(strcat("seta ", cvar, " \"", cvar_string(cvar), "\"\n"))
+#define HUD_Write_PanelCvar_n(cvar_suf) HUD_Write_Cvar_n(strcat("hud_panel_", panel.panel_name, cvar_suf))
+#define HUD_Write_PanelCvar_q(cvar_suf) HUD_Write_Cvar_q(strcat("hud_panel_", panel.panel_name, cvar_suf))
+// Save the config
+void HUD_Panel_ExportCfg(string cfgname)
+{
+       float fh;
+       string filename = strcat("hud_", autocvar_hud_skin, "_", cfgname, ".cfg");
+       fh = fopen(filename, FILE_WRITE);
+       if(fh >= 0)
+       {
+               HUD_Write_Cvar_q("hud_skin");
+               HUD_Write_Cvar_q("hud_panel_bg");
+               HUD_Write_Cvar_q("hud_panel_bg_color");
+               HUD_Write_Cvar_q("hud_panel_bg_color_team");
+               HUD_Write_Cvar_q("hud_panel_bg_alpha");
+               HUD_Write_Cvar_q("hud_panel_bg_border");
+               HUD_Write_Cvar_q("hud_panel_bg_padding");
+               HUD_Write_Cvar_q("hud_panel_fg_alpha");
+               HUD_Write("\n");
+
+               HUD_Write_Cvar_q("hud_dock");
+               HUD_Write_Cvar_q("hud_dock_color");
+               HUD_Write_Cvar_q("hud_dock_color_team");
+               HUD_Write_Cvar_q("hud_dock_alpha");
+               HUD_Write("\n");
+
+               HUD_Write_Cvar_q("hud_progressbar_alpha");
+               HUD_Write_Cvar_q("hud_progressbar_strength_color");
+               HUD_Write_Cvar_q("hud_progressbar_shield_color");
+               HUD_Write_Cvar_q("hud_progressbar_health_color");
+               HUD_Write_Cvar_q("hud_progressbar_armor_color");
+               HUD_Write_Cvar_q("hud_progressbar_fuel_color");
+               HUD_Write_Cvar_q("hud_progressbar_nexball_color");
+               HUD_Write_Cvar_q("hud_progressbar_speed_color");
+               HUD_Write_Cvar_q("hud_progressbar_acceleration_color");
+               HUD_Write_Cvar_q("hud_progressbar_acceleration_neg_color");
+               HUD_Write("\n");
+
+               HUD_Write_Cvar_q("_hud_panelorder");
+               HUD_Write("\n");
+
+               HUD_Write_Cvar_q("hud_configure_grid");
+               HUD_Write_Cvar_q("hud_configure_grid_xsize");
+               HUD_Write_Cvar_q("hud_configure_grid_ysize");
+               HUD_Write("\n");
+
+               // common cvars for all panels
+               for (int i = 0; i < hud_panels_COUNT; ++i)
+               {
+                       panel = hud_panels_from(i);
+
+                       HUD_Write_PanelCvar_n("");
+                       HUD_Write_PanelCvar_q("_pos");
+                       HUD_Write_PanelCvar_q("_size");
+                       HUD_Write_PanelCvar_q("_bg");
+                       HUD_Write_PanelCvar_q("_bg_color");
+                       HUD_Write_PanelCvar_q("_bg_color_team");
+                       HUD_Write_PanelCvar_q("_bg_alpha");
+                       HUD_Write_PanelCvar_q("_bg_border");
+                       HUD_Write_PanelCvar_q("_bg_padding");
+                       switch(panel) {
+                               case HUD_PANEL_WEAPONS:
+                                       HUD_Write_PanelCvar_q("_accuracy");
+                                       HUD_Write_PanelCvar_q("_label");
+                                       HUD_Write_PanelCvar_q("_label_scale");
+                                       HUD_Write_PanelCvar_q("_complainbubble");
+                                       HUD_Write_PanelCvar_q("_complainbubble_padding");
+                                       HUD_Write_PanelCvar_q("_complainbubble_time");
+                                       HUD_Write_PanelCvar_q("_complainbubble_fadetime");
+                                       HUD_Write_PanelCvar_q("_complainbubble_color_outofammo");
+                                       HUD_Write_PanelCvar_q("_complainbubble_color_donthave");
+                                       HUD_Write_PanelCvar_q("_complainbubble_color_unavailable");
+                                       HUD_Write_PanelCvar_q("_ammo");
+                                       HUD_Write_PanelCvar_q("_ammo_color");
+                                       HUD_Write_PanelCvar_q("_ammo_alpha");
+                                       HUD_Write_PanelCvar_q("_aspect");
+                                       HUD_Write_PanelCvar_q("_timeout");
+                                       HUD_Write_PanelCvar_q("_timeout_effect");
+                                       HUD_Write_PanelCvar_q("_timeout_fadebgmin");
+                                       HUD_Write_PanelCvar_q("_timeout_fadefgmin");
+                                       HUD_Write_PanelCvar_q("_timeout_speed_in");
+                                       HUD_Write_PanelCvar_q("_timeout_speed_out");
+                                       HUD_Write_PanelCvar_q("_onlyowned");
+                                       HUD_Write_PanelCvar_q("_noncurrent_alpha");
+                                       HUD_Write_PanelCvar_q("_noncurrent_scale");
+                                       break;
+                               case HUD_PANEL_AMMO:
+                                       HUD_Write_PanelCvar_q("_onlycurrent");
+                                       HUD_Write_PanelCvar_q("_noncurrent_alpha");
+                                       HUD_Write_PanelCvar_q("_noncurrent_scale");
+                                       HUD_Write_PanelCvar_q("_iconalign");
+                                       HUD_Write_PanelCvar_q("_progressbar");
+                                       HUD_Write_PanelCvar_q("_progressbar_name");
+                                       HUD_Write_PanelCvar_q("_progressbar_xoffset");
+                                       HUD_Write_PanelCvar_q("_text");
+                                       break;
+                               case HUD_PANEL_POWERUPS:
+                                       HUD_Write_PanelCvar_q("_iconalign");
+                                       HUD_Write_PanelCvar_q("_baralign");
+                                       HUD_Write_PanelCvar_q("_progressbar");
+                                       HUD_Write_PanelCvar_q("_text");
+                                       break;
+                               case HUD_PANEL_HEALTHARMOR:
+                                       HUD_Write_PanelCvar_q("_flip");
+                                       HUD_Write_PanelCvar_q("_iconalign");
+                                       HUD_Write_PanelCvar_q("_baralign");
+                                       HUD_Write_PanelCvar_q("_progressbar");
+                                       HUD_Write_PanelCvar_q("_progressbar_health");
+                                       HUD_Write_PanelCvar_q("_progressbar_armor");
+                                       HUD_Write_PanelCvar_q("_progressbar_gfx");
+                                       HUD_Write_PanelCvar_q("_progressbar_gfx_smooth");
+                                       HUD_Write_PanelCvar_q("_text");
+                                       break;
+                               case HUD_PANEL_NOTIFY:
+                                       HUD_Write_PanelCvar_q("_flip");
+                                       HUD_Write_PanelCvar_q("_fontsize");
+                                       HUD_Write_PanelCvar_q("_time");
+                                       HUD_Write_PanelCvar_q("_fadetime");
+                                       HUD_Write_PanelCvar_q("_icon_aspect");
+                                       break;
+                               case HUD_PANEL_TIMER:
+                                       HUD_Write_PanelCvar_q("_increment");
+                                       break;
+                               case HUD_PANEL_RADAR:
+                                       HUD_Write_PanelCvar_q("_foreground_alpha");
+                                       HUD_Write_PanelCvar_q("_rotation");
+                                       HUD_Write_PanelCvar_q("_zoommode");
+                                       HUD_Write_PanelCvar_q("_scale");
+                                       HUD_Write_PanelCvar_q("_maximized_scale");
+                                       HUD_Write_PanelCvar_q("_maximized_size");
+                                       HUD_Write_PanelCvar_q("_maximized_rotation");
+                                       HUD_Write_PanelCvar_q("_maximized_zoommode");
+                                       break;
+                               case HUD_PANEL_SCORE:
+                                       HUD_Write_PanelCvar_q("_rankings");
+                                       break;
+                               case HUD_PANEL_VOTE:
+                                       HUD_Write_PanelCvar_q("_alreadyvoted_alpha");
+                                       break;
+                               case HUD_PANEL_MODICONS:
+                                       HUD_Write_PanelCvar_q("_ca_layout");
+                                       HUD_Write_PanelCvar_q("_dom_layout");
+                                       HUD_Write_PanelCvar_q("_freezetag_layout");
+                                       break;
+                               case HUD_PANEL_PRESSEDKEYS:
+                                       HUD_Write_PanelCvar_q("_aspect");
+                                       HUD_Write_PanelCvar_q("_attack");
+                                       break;
+                               case HUD_PANEL_ENGINEINFO:
+                                       HUD_Write_PanelCvar_q("_framecounter_time");
+                                       HUD_Write_PanelCvar_q("_framecounter_decimals");
+                                       break;
+                               case HUD_PANEL_INFOMESSAGES:
+                                       HUD_Write_PanelCvar_q("_flip");
+                                       break;
+                               case HUD_PANEL_PHYSICS:
+                                       HUD_Write_PanelCvar_q("_speed_unit");
+                                       HUD_Write_PanelCvar_q("_speed_unit_show");
+                                       HUD_Write_PanelCvar_q("_speed_max");
+                                       HUD_Write_PanelCvar_q("_speed_vertical");
+                                       HUD_Write_PanelCvar_q("_topspeed");
+                                       HUD_Write_PanelCvar_q("_topspeed_time");
+                                       HUD_Write_PanelCvar_q("_acceleration_max");
+                                       HUD_Write_PanelCvar_q("_acceleration_vertical");
+                                       HUD_Write_PanelCvar_q("_flip");
+                                       HUD_Write_PanelCvar_q("_baralign");
+                                       HUD_Write_PanelCvar_q("_progressbar");
+                                       HUD_Write_PanelCvar_q("_progressbar_acceleration_mode");
+                                       HUD_Write_PanelCvar_q("_progressbar_acceleration_scale");
+                                       HUD_Write_PanelCvar_q("_progressbar_acceleration_nonlinear");
+                                       HUD_Write_PanelCvar_q("_text");
+                                       HUD_Write_PanelCvar_q("_text_scale");
+                                       break;
+                               case HUD_PANEL_CENTERPRINT:
+                                       HUD_Write_PanelCvar_q("_align");
+                                       HUD_Write_PanelCvar_q("_flip");
+                                       HUD_Write_PanelCvar_q("_fontscale");
+                                       HUD_Write_PanelCvar_q("_time");
+                                       HUD_Write_PanelCvar_q("_fade_in");
+                                       HUD_Write_PanelCvar_q("_fade_out");
+                                       HUD_Write_PanelCvar_q("_fade_subsequent");
+                                       HUD_Write_PanelCvar_q("_fade_subsequent_passone");
+                                       HUD_Write_PanelCvar_q("_fade_subsequent_passone_minalpha");
+                                       HUD_Write_PanelCvar_q("_fade_subsequent_passtwo");
+                                       HUD_Write_PanelCvar_q("_fade_subsequent_passtwo_minalpha");
+                                       HUD_Write_PanelCvar_q("_fade_subsequent_minfontsize");
+                                       HUD_Write_PanelCvar_q("_fade_minfontsize");
+                                       break;
+                               case HUD_PANEL_ITEMSTIME:
+                                       HUD_Write_PanelCvar_q("_iconalign");
+                                       HUD_Write_PanelCvar_q("_progressbar");
+                                       HUD_Write_PanelCvar_q("_progressbar_name");
+                                       HUD_Write_PanelCvar_q("_progressbar_reduced");
+                                       HUD_Write_PanelCvar_q("_text");
+                                       HUD_Write_PanelCvar_q("_ratio");
+                                       HUD_Write_PanelCvar_q("_dynamicsize");
+                               case HUD_PANEL_QUICKMENU:
+                                       HUD_Write_PanelCvar_q("_align");
+                                       break;
+                       }
+                       HUD_Write("\n");
+               }
+               HUD_Write("menu_sync\n"); // force the menu to reread the cvars, so that the dialogs are updated
+
+               LOG_INFOF(_("^2Successfully exported to %s! (Note: It's saved in data/data/)\n"), filename);
+               fclose(fh);
+       }
+       else
+               LOG_INFOF(_("^1Couldn't write to %s\n"), filename);
+}
+
+void HUD_Configure_Exit_Force()
+{
+       if (menu_enabled)
+       {
+               menu_enabled = 0;
+               localcmd("togglemenu\n");
+       }
+       cvar_set("_hud_configure", "0");
+}
+
+// check if move will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
+vector HUD_Panel_CheckMove(vector myPos, vector mySize)
+{
+       vector myCenter, targCenter;
+       vector myTarget = myPos;
+       int i;
+       for (i = 0; i < hud_panels_COUNT; ++i) {
+               panel = hud_panels_from(i);
+               if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
+               if(panel == highlightedPanel) continue;
+               HUD_Panel_UpdatePosSize();
+               if(!panel_enabled) continue;
+
+               panel_pos -= '1 1 0' * panel_bg_border;
+               panel_size += '2 2 0' * panel_bg_border;
+
+               if(myPos.y + mySize.y < panel_pos.y)
+                       continue;
+               if(myPos.y > panel_pos.y + panel_size.y)
+                       continue;
+
+               if(myPos.x + mySize.x < panel_pos.x)
+                       continue;
+               if(myPos.x > panel_pos.x + panel_size.x)
+                       continue;
+
+               // OK, there IS a collision.
+
+               myCenter.x = myPos.x + 0.5 * mySize.x;
+               myCenter.y = myPos.y + 0.5 * mySize.y;
+
+               targCenter.x = panel_pos.x + 0.5 * panel_size.x;
+               targCenter.y = panel_pos.y + 0.5 * panel_size.y;
+
+               if(myCenter.x < targCenter.x && myCenter.y < targCenter.y) // top left (of the target panel)
+               {
+                       if(myPos.x + mySize.x - panel_pos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
+                               myTarget.x = panel_pos.x - mySize.x;
+                       else // push it upwards
+                               myTarget.y = panel_pos.y - mySize.y;
+               }
+               else if(myCenter.x > targCenter.x && myCenter.y < targCenter.y) // top right
+               {
+                       if(panel_pos.x + panel_size.x - myPos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
+                               myTarget.x = panel_pos.x + panel_size.x;
+                       else // push it upwards
+                               myTarget.y = panel_pos.y - mySize.y;
+               }
+               else if(myCenter.x < targCenter.x && myCenter.y > targCenter.y) // bottom left
+               {
+                       if(myPos.x + mySize.x - panel_pos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
+                               myTarget.x = panel_pos.x - mySize.x;
+                       else // push it downwards
+                               myTarget.y = panel_pos.y + panel_size.y;
+               }
+               else if(myCenter.x > targCenter.x && myCenter.y > targCenter.y) // bottom right
+               {
+                       if(panel_pos.x + panel_size.x - myPos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
+                               myTarget.x = panel_pos.x + panel_size.x;
+                       else // push it downwards
+                               myTarget.y = panel_pos.y + panel_size.y;
+               }
+               //if(cvar("hud_configure_checkcollisions_debug"))
+                       //drawfill(panel_pos, panel_size, '1 1 0', .3, DRAWFLAG_NORMAL);
+       }
+
+       return myTarget;
+}
+
+void HUD_Panel_SetPos(vector pos)
+{
+       panel = highlightedPanel;
+       HUD_Panel_UpdatePosSize();
+       vector mySize;
+       mySize = panel_size;
+
+       //if(cvar("hud_configure_checkcollisions_debug"))
+               //drawfill(pos, mySize, '1 1 1', .2, DRAWFLAG_NORMAL);
+
+       if(autocvar_hud_configure_grid)
+       {
+               pos.x = floor((pos.x/vid_conwidth)/hud_configure_gridSize.x + 0.5) * hud_configure_realGridSize.x;
+               pos.y = floor((pos.y/vid_conheight)/hud_configure_gridSize.y + 0.5) * hud_configure_realGridSize.y;
+       }
+
+       if(hud_configure_checkcollisions)
+               pos = HUD_Panel_CheckMove(pos, mySize);
+
+       pos.x = bound(0, pos.x, vid_conwidth - mySize.x);
+       pos.y = bound(0, pos.y, vid_conheight - mySize.y);
+
+       string s;
+       s = strcat(ftos(pos.x/vid_conwidth), " ", ftos(pos.y/vid_conheight));
+
+       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
+}
+
+// check if resize will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
+vector HUD_Panel_CheckResize(vector mySize, vector resizeorigin) {
+       vector targEndPos;
+       vector dist;
+       float ratio = mySize.x/mySize.y;
+       int i;
+       for (i = 0; i < hud_panels_COUNT; ++i) {
+               panel = hud_panels_from(i);
+               if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
+               if(panel == highlightedPanel) continue;
+               HUD_Panel_UpdatePosSize();
+               if(!panel_enabled) continue;
+
+               panel_pos -= '1 1 0' * panel_bg_border;
+               panel_size += '2 2 0' * panel_bg_border;
+
+               targEndPos = panel_pos + panel_size;
+
+               // resizeorigin is WITHIN target panel, just abort any collision testing against that particular panel to produce expected behaviour!
+               if(resizeorigin.x > panel_pos.x && resizeorigin.x < targEndPos.x && resizeorigin.y > panel_pos.y && resizeorigin.y < targEndPos.y)
+                       continue;
+
+               if (resizeCorner == 1)
+               {
+                       // check if this panel is on our way
+                       if (resizeorigin.x <= panel_pos.x)
+                               continue;
+                       if (resizeorigin.y <= panel_pos.y)
+                               continue;
+                       if (targEndPos.x <= resizeorigin.x - mySize.x)
+                               continue;
+                       if (targEndPos.y <= resizeorigin.y - mySize.y)
+                               continue;
+
+                       // there is a collision:
+                       // detect which side of the panel we are facing is actually limiting the resizing
+                       // (which side the resize direction finds for first) and reduce the size up to there
+                       //
+                       // dist is the distance between resizeorigin and the "analogous" point of the panel
+                       // in this case between resizeorigin (bottom-right point) and the bottom-right point of the panel
+                       dist.x = resizeorigin.x - targEndPos.x;
+                       dist.y = resizeorigin.y - targEndPos.y;
+                       if (dist.y <= 0 || dist.x / dist.y > ratio)
+                               mySize.x = min(mySize.x, dist.x);
+                       else
+                               mySize.y = min(mySize.y, dist.y);
+               }
+               else if (resizeCorner == 2)
+               {
+                       if (resizeorigin.x >= targEndPos.x)
+                               continue;
+                       if (resizeorigin.y <= panel_pos.y)
+                               continue;
+                       if (panel_pos.x >= resizeorigin.x + mySize.x)
+                               continue;
+                       if (targEndPos.y <= resizeorigin.y - mySize.y)
+                               continue;
+
+                       dist.x = panel_pos.x - resizeorigin.x;
+                       dist.y = resizeorigin.y - targEndPos.y;
+                       if (dist.y <= 0 || dist.x / dist.y > ratio)
+                               mySize.x = min(mySize.x, dist.x);
+                       else
+                               mySize.y = min(mySize.y, dist.y);
+               }
+               else if (resizeCorner == 3)
+               {
+                       if (resizeorigin.x <= panel_pos.x)
+                               continue;
+                       if (resizeorigin.y >= targEndPos.y)
+                               continue;
+                       if (targEndPos.x <= resizeorigin.x - mySize.x)
+                               continue;
+                       if (panel_pos.y >= resizeorigin.y + mySize.y)
+                               continue;
+
+                       dist.x = resizeorigin.x - targEndPos.x;
+                       dist.y = panel_pos.y - resizeorigin.y;
+                       if (dist.y <= 0 || dist.x / dist.y > ratio)
+                               mySize.x = min(mySize.x, dist.x);
+                       else
+                               mySize.y = min(mySize.y, dist.y);
+               }
+               else if (resizeCorner == 4)
+               {
+                       if (resizeorigin.x >= targEndPos.x)
+                               continue;
+                       if (resizeorigin.y >= targEndPos.y)
+                               continue;
+                       if (panel_pos.x >= resizeorigin.x + mySize.x)
+                               continue;
+                       if (panel_pos.y >= resizeorigin.y + mySize.y)
+                               continue;
+
+                       dist.x = panel_pos.x - resizeorigin.x;
+                       dist.y = panel_pos.y - resizeorigin.y;
+                       if (dist.y <= 0 || dist.x / dist.y > ratio)
+                               mySize.x = min(mySize.x, dist.x);
+                       else
+                               mySize.y = min(mySize.y, dist.y);
+               }
+               //if(cvar("hud_configure_checkcollisions_debug"))
+                       //drawfill(panel_pos, panel_size, '1 1 0', .3, DRAWFLAG_NORMAL);
+       }
+
+       return mySize;
+}
+
+void HUD_Panel_SetPosSize(vector mySize)
+{
+       panel = highlightedPanel;
+       HUD_Panel_UpdatePosSize();
+       vector resizeorigin = panel_click_resizeorigin;
+       vector myPos;
+
+       // minimum panel size cap
+       mySize.x = max(0.025 * vid_conwidth, mySize.x);
+       mySize.y = max(0.025 * vid_conheight, mySize.y);
+
+       if(highlightedPanel == HUD_PANEL(CHAT)) // some panels have their own restrictions, like the chat panel (which actually only moves the engine chat print around). Looks bad if it's too small.
+       {
+               mySize.x = max(17 * autocvar_con_chatsize, mySize.x);
+               mySize.y = max(2 * autocvar_con_chatsize + 2 * panel_bg_padding, mySize.y);
+       }
+
+       // collision testing|
+       // -----------------+
+
+       // we need to know pos at this stage, but it might still change later if we hit a screen edge/other panel (?)
+       if(resizeCorner == 1) {
+               myPos.x = resizeorigin.x - mySize.x;
+               myPos.y = resizeorigin.y - mySize.y;
+       } else if(resizeCorner == 2) {
+               myPos.x = resizeorigin.x;
+               myPos.y = resizeorigin.y - mySize.y;
+       } else if(resizeCorner == 3) {
+               myPos.x = resizeorigin.x - mySize.x;
+               myPos.y = resizeorigin.y;
+       } else { // resizeCorner == 4
+               myPos.x = resizeorigin.x;
+               myPos.y = resizeorigin.y;
+       }
+
+       // left/top screen edges
+       if(myPos.x < 0)
+               mySize.x = mySize.x + myPos.x;
+       if(myPos.y < 0)
+               mySize.y = mySize.y + myPos.y;
+
+       // bottom/right screen edges
+       if(myPos.x + mySize.x > vid_conwidth)
+               mySize.x = vid_conwidth - myPos.x;
+       if(myPos.y + mySize.y > vid_conheight)
+               mySize.y = vid_conheight - myPos.y;
+
+       //if(cvar("hud_configure_checkcollisions_debug"))
+               //drawfill(myPos, mySize, '1 1 1', .2, DRAWFLAG_NORMAL);
+
+       // before checkresize, otherwise panel can be snapped partially inside another panel or panel aspect ratio can be broken
+       if(autocvar_hud_configure_grid)
+       {
+               mySize.x = floor((mySize.x/vid_conwidth)/hud_configure_gridSize.x + 0.5) * hud_configure_realGridSize.x;
+               mySize.y = floor((mySize.y/vid_conheight)/hud_configure_gridSize.y + 0.5) * hud_configure_realGridSize.y;
+       }
+
+       if(hud_configure_checkcollisions)
+               mySize = HUD_Panel_CheckResize(mySize, resizeorigin);
+
+       // minimum panel size cap, do this once more so we NEVER EVER EVER have a panel smaller than this, JUST IN CASE above code still makes the panel eg negative (impossible to resize back without changing cvars manually then)
+       mySize.x = max(0.025 * vid_conwidth, mySize.x);
+       mySize.y = max(0.025 * vid_conheight, mySize.y);
+
+       // do another pos check, as size might have changed by now
+       if(resizeCorner == 1) {
+               myPos.x = resizeorigin.x - mySize.x;
+               myPos.y = resizeorigin.y - mySize.y;
+       } else if(resizeCorner == 2) {
+               myPos.x = resizeorigin.x;
+               myPos.y = resizeorigin.y - mySize.y;
+       } else if(resizeCorner == 3) {
+               myPos.x = resizeorigin.x - mySize.x;
+               myPos.y = resizeorigin.y;
+       } else { // resizeCorner == 4
+               myPos.x = resizeorigin.x;
+               myPos.y = resizeorigin.y;
+       }
+
+       //if(cvar("hud_configure_checkcollisions_debug"))
+               //drawfill(myPos, mySize, '0 1 0', .3, DRAWFLAG_NORMAL);
+
+       string s;
+       s = strcat(ftos(mySize.x/vid_conwidth), " ", ftos(mySize.y/vid_conheight));
+       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
+
+       s = strcat(ftos(myPos.x/vid_conwidth), " ", ftos(myPos.y/vid_conheight));
+       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
+}
+
+float pressed_key_time;
+vector highlightedPanel_initial_pos, highlightedPanel_initial_size;
+void HUD_Panel_Arrow_Action(float nPrimary)
+{
+       if(!highlightedPanel)
+               return;
+
+       hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
+
+       float step;
+       if(autocvar_hud_configure_grid)
+       {
+               if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
+               {
+                       if (hudShiftState & S_SHIFT)
+                               step = hud_configure_realGridSize.y;
+                       else
+                               step = 2 * hud_configure_realGridSize.y;
+               }
+               else
+               {
+                       if (hudShiftState & S_SHIFT)
+                               step = hud_configure_realGridSize.x;
+                       else
+                               step = 2 * hud_configure_realGridSize.x;
+               }
+       }
+       else
+       {
+               if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
+                       step = vid_conheight;
+               else
+                       step = vid_conwidth;
+               if (hudShiftState & S_SHIFT)
+                       step = (step / 256); // more precision
+               else
+                       step = (step / 64) * (1 + 2 * (time - pressed_key_time));
+       }
+
+       panel = highlightedPanel;
+       HUD_Panel_UpdatePosSize();
+
+       highlightedPanel_initial_pos = panel_pos;
+       highlightedPanel_initial_size = panel_size;
+
+       if (hudShiftState & S_ALT) // resize
+       {
+               if(nPrimary == K_UPARROW)
+                       resizeCorner = 1;
+               else if(nPrimary == K_RIGHTARROW)
+                       resizeCorner = 2;
+               else if(nPrimary == K_LEFTARROW)
+                       resizeCorner = 3;
+               else // if(nPrimary == K_DOWNARROW)
+                       resizeCorner = 4;
+
+               // ctrl+arrow reduces the size, instead of increasing it
+               // Note that ctrl disables collisions check too, but it's fine
+               // since we don't collide with anything reducing the size
+               if (hudShiftState & S_CTRL) {
+                       step = -step;
+                       resizeCorner = 5 - resizeCorner;
+               }
+
+               vector mySize;
+               mySize = panel_size;
+               panel_click_resizeorigin = panel_pos;
+               if(resizeCorner == 1) {
+                       panel_click_resizeorigin += mySize;
+                       mySize.y += step;
+               } else if(resizeCorner == 2) {
+                       panel_click_resizeorigin.y += mySize.y;
+                       mySize.x += step;
+               } else if(resizeCorner == 3) {
+                       panel_click_resizeorigin.x += mySize.x;
+                       mySize.x += step;
+               } else { // resizeCorner == 4
+                       mySize.y += step;
+               }
+               HUD_Panel_SetPosSize(mySize);
+       }
+       else // move
+       {
+               vector pos;
+               pos = panel_pos;
+               if(nPrimary == K_UPARROW)
+                       pos.y -= step;
+               else if(nPrimary == K_DOWNARROW)
+                       pos.y += step;
+               else if(nPrimary == K_LEFTARROW)
+                       pos.x -= step;
+               else // if(nPrimary == K_RIGHTARROW)
+                       pos.x += step;
+
+               HUD_Panel_SetPos(pos);
+       }
+
+       panel = highlightedPanel;
+       HUD_Panel_UpdatePosSize();
+
+       if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
+       {
+               // backup!
+               panel_pos_backup = highlightedPanel_initial_pos;
+               panel_size_backup = highlightedPanel_initial_size;
+               highlightedPanel_backup = highlightedPanel;
+       }
+}
+
+void HUD_Panel_EnableMenu();
+entity tab_panels[hud_panels_MAX];
+entity tab_panel;
+vector tab_panel_pos;
+float tab_backward;
+void HUD_Panel_FirstInDrawQ(float id);
+void reset_tab_panels()
+{
+       int i;
+       for(i = 0; i < hud_panels_COUNT; ++i)
+               tab_panels[i] = world;
+}
+float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
+{
+       string s;
+
+       if(bInputType == 2)
+               return false;
+
+       if(!autocvar__hud_configure)
+               return false;
+
+       if(bInputType == 3)
+       {
+               mousepos.x = nPrimary;
+               mousepos.y = nSecondary;
+               return true;
+       }
+
+       // block any input while a menu dialog is fading
+       // don't block mousepos read as it leads to cursor jumps in the interaction with the menu
+       if(autocvar__menu_alpha)
+       {
+               hudShiftState = 0;
+               mouseClicked = 0;
+               return true;
+       }
+
+       // allow console bind to work
+       string con_keys;
+       float keys;
+       con_keys = findkeysforcommand("toggleconsole", 0);
+       keys = tokenize(con_keys); // findkeysforcommand returns data for this
+
+       bool hit_con_bind = false;
+       int i;
+       for (i = 0; i < keys; ++i)
+       {
+               if(nPrimary == stof(argv(i)))
+                       hit_con_bind = true;
+       }
+
+       if(bInputType == 0) {
+               if(nPrimary == K_ALT) hudShiftState |= S_ALT;
+               if(nPrimary == K_CTRL) hudShiftState |= S_CTRL;
+               if(nPrimary == K_SHIFT) hudShiftState |= S_SHIFT;
+       }
+       else if(bInputType == 1) {
+               if(nPrimary == K_ALT) hudShiftState -= (hudShiftState & S_ALT);
+               if(nPrimary == K_CTRL) hudShiftState -= (hudShiftState & S_CTRL);
+               if(nPrimary == K_SHIFT) hudShiftState -= (hudShiftState & S_SHIFT);
+       }
+
+       if(nPrimary == K_CTRL)
+       {
+               if (bInputType == 1) //ctrl has been released
+               {
+                       if (tab_panel)
+                       {
+                               //switch to selected panel
+                               highlightedPanel = tab_panel;
+                               highlightedAction = 0;
+                               HUD_Panel_FirstInDrawQ(highlightedPanel.panel_id);
+                       }
+                       tab_panel = world;
+                       reset_tab_panels();
+               }
+       }
+
+       if(nPrimary == K_MOUSE1)
+       {
+               if(bInputType == 0) // key pressed
+                       mouseClicked |= S_MOUSE1;
+               else if(bInputType == 1) // key released
+                       mouseClicked -= (mouseClicked & S_MOUSE1);
+       }
+       else if(nPrimary == K_MOUSE2)
+       {
+               if(bInputType == 0) // key pressed
+                       mouseClicked |= S_MOUSE2;
+               else if(bInputType == 1) // key released
+                       mouseClicked -= (mouseClicked & S_MOUSE2);
+       }
+       else if(nPrimary == K_ESCAPE)
+       {
+               if (bInputType == 1)
+                       return true;
+               menu_enabled = 1;
+               localcmd("menu_showhudexit\n");
+       }
+       else if(nPrimary == K_BACKSPACE && hudShiftState & S_CTRL)
+       {
+               if (bInputType == 1)
+                       return true;
+               if (!menu_enabled)
+                       cvar_set("_hud_configure", "0");
+       }
+       else if(nPrimary == K_TAB && hudShiftState & S_CTRL) // switch panel
+       {
+               if (bInputType == 1 || mouseClicked)
+                       return true;
+
+               // FIXME minor bug: if a panel is highlighted, has the same pos_x and
+               // lays in the same level of another panel then the next consecutive
+               // CTRL TAB presses will reselect once more the highlighted panel
+
+               entity starting_panel;
+               entity old_tab_panel = tab_panel;
+               if (!tab_panel) //first press of TAB
+               {
+                       if (highlightedPanel)
+                       {
+                               panel = highlightedPanel;
+                               HUD_Panel_UpdatePosSize();
+                       }
+                       else
+                               panel_pos = '0 0 0';
+                       starting_panel = highlightedPanel;
+                       tab_panel_pos = panel_pos; //to compute level
+               }
+               else
+               {
+                       if ( ((!tab_backward) && (hudShiftState & S_SHIFT)) || (tab_backward && !(hudShiftState & S_SHIFT)) ) //tab direction changed?
+                               reset_tab_panels();
+                       starting_panel = tab_panel;
+               }
+               tab_backward = (hudShiftState & S_SHIFT);
+
+               float k, level = 0, start_posX;
+               vector candidate_pos = '0 0 0';
+               const float LEVELS_NUM = 4;
+               float level_height = vid_conheight / LEVELS_NUM;
+:find_tab_panel
+               level = floor(tab_panel_pos.y / level_height) * level_height; //starting level
+               candidate_pos.x = (!tab_backward) ? vid_conwidth : 0;
+               start_posX = tab_panel_pos.x;
+               tab_panel = world;
+               k=0;
+               while(++k)
+               {
+                       for(i = 0; i < hud_panels_COUNT; ++i)
+                       {
+                               panel = hud_panels_from(i);
+                               if(!(panel.panel_configflags & PANEL_CONFIG_MAIN))
+                                       continue;
+                               if (panel == tab_panels[i] || panel == starting_panel)
+                                       continue;
+                               HUD_Panel_UpdatePosSize();
+                               if (panel_pos.y >= level && (panel_pos.y - level) < level_height)
+                               if (  ( !tab_backward && panel_pos.x >= start_posX && (panel_pos.x < candidate_pos.x || (panel_pos.x == candidate_pos.x && panel_pos.y <= candidate_pos.y)) )
+                                       || ( tab_backward && panel_pos.x <= start_posX && (panel_pos.x > candidate_pos.x || (panel_pos.x == candidate_pos.x && panel_pos.y >= candidate_pos.y)) )  )
+                               {
+                                       tab_panel = panel;
+                                       tab_panel_pos = candidate_pos = panel_pos;
+                               }
+                       }
+                       if (tab_panel)
+                               break;
+                       if (k == LEVELS_NUM) //tab_panel not found
+                       {
+                               reset_tab_panels();
+                               if (!old_tab_panel)
+                               {
+                                       tab_panel = world;
+                                       return true;
+                               }
+                               starting_panel = old_tab_panel;
+                               old_tab_panel = world;
+                               goto find_tab_panel; //u must find tab_panel!
+                       }
+                       if (!tab_backward)
+                       {
+                               level = (level + level_height) % vid_conheight;
+                               start_posX = 0;
+                               candidate_pos.x = vid_conwidth;
+                       }
+                       else
+                       {
+                               level = (level - level_height) % vid_conheight;
+                               start_posX = vid_conwidth;
+                               candidate_pos.x = 0;
+                       }
+               }
+
+               tab_panels[tab_panel.panel_id] = tab_panel;
+       }
+       else if(nPrimary == K_SPACE && hudShiftState & S_CTRL) // enable/disable highlighted panel or dock
+       {
+               if (bInputType == 1 || mouseClicked)
+                       return true;
+
+               if (highlightedPanel)
+                       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name), ftos(!cvar(strcat("hud_panel_", highlightedPanel.panel_name))));
+               else
+                       cvar_set(strcat("hud_dock"), (autocvar_hud_dock == "") ? "dock" : "");
+       }
+       else if(nPrimary == 'c' && hudShiftState & S_CTRL) // copy highlighted panel size
+       {
+               if (bInputType == 1 || mouseClicked)
+                       return true;
+
+               if (highlightedPanel)
+               {
+                       panel = highlightedPanel;
+                       HUD_Panel_UpdatePosSize();
+                       panel_size_copied = panel_size;
+               }
+       }
+       else if(nPrimary == 'v' && hudShiftState & S_CTRL) // past copied size on the highlighted panel
+       {
+               if (bInputType == 1 || mouseClicked)
+                       return true;
+
+               if (panel_size_copied == '0 0 0' || !highlightedPanel)
+                       return true;
+
+               panel = highlightedPanel;
+               HUD_Panel_UpdatePosSize();
+
+               // reduce size if it'd go beyond screen boundaries
+               vector tmp_size = panel_size_copied;
+               if (panel_pos.x + panel_size_copied.x > vid_conwidth)
+                       tmp_size.x = vid_conwidth - panel_pos.x;
+               if (panel_pos.y + panel_size_copied.y > vid_conheight)
+                       tmp_size.y = vid_conheight - panel_pos.y;
+
+               if (panel_size == tmp_size)
+                       return true;
+
+               // backup first!
+               panel_pos_backup = panel_pos;
+               panel_size_backup = panel_size;
+               highlightedPanel_backup = highlightedPanel;
+
+               s = strcat(ftos(tmp_size.x/vid_conwidth), " ", ftos(tmp_size.y/vid_conheight));
+               cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
+       }
+       else if(nPrimary == 'z' && hudShiftState & S_CTRL) // undo last action
+       {
+               if (bInputType == 1 || mouseClicked)
+                       return true;
+               //restore previous values
+               if (highlightedPanel_backup)
+               {
+                       s = strcat(ftos(panel_pos_backup.x/vid_conwidth), " ", ftos(panel_pos_backup.y/vid_conheight));
+                       cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_pos"), s);
+                       s = strcat(ftos(panel_size_backup.x/vid_conwidth), " ", ftos(panel_size_backup.y/vid_conheight));
+                       cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_size"), s);
+                       highlightedPanel_backup = world;
+               }
+       }
+       else if(nPrimary == 's' && hudShiftState & S_CTRL) // save config
+       {
+               if (bInputType == 1 || mouseClicked)
+                       return true;
+               localcmd("hud save myconfig\n");
+       }
+       else if(nPrimary == K_UPARROW || nPrimary == K_DOWNARROW || nPrimary == K_LEFTARROW || nPrimary == K_RIGHTARROW)
+       {
+               if (bInputType == 1)
+               {
+                       pressed_key_time = 0;
+                       return true;
+               }
+               else if (pressed_key_time == 0)
+                       pressed_key_time = time;
+
+               if (!mouseClicked)
+                       HUD_Panel_Arrow_Action(nPrimary); //move or resize panel
+       }
+       else if(nPrimary == K_ENTER || nPrimary == K_SPACE || nPrimary == K_KP_ENTER)
+       {
+               if (bInputType == 1)
+                       return true;
+               if (highlightedPanel)
+                       HUD_Panel_EnableMenu();
+       }
+       else if(hit_con_bind || nPrimary == K_PAUSE)
+               return false;
+
+       return true;
+}
+
+float HUD_Panel_Check_Mouse_Pos(float allow_move)
+{
+       int i, j = 0;
+       while(j < hud_panels_COUNT)
+       {
+               i = panel_order[j];
+               j += 1;
+
+               panel = hud_panels_from(i);
+               if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
+               HUD_Panel_UpdatePosSize();
+
+               float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
+
+               // move
+               if(allow_move && mousepos.x > panel_pos.x && mousepos.y > panel_pos.y && mousepos.x < panel_pos.x + panel_size.x && mousepos.y < panel_pos.y + panel_size.y)
+               {
+                       return 1;
+               }
+               // resize from topleft border
+               else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
+               {
+                       return 2;
+               }
+               // resize from topright border
+               else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
+               {
+                       return 3;
+               }
+               // resize from bottomleft border
+               else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + panel_size.y + border)
+               {
+                       return 3;
+               }
+               // resize from bottomright border
+               else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + panel_size.y + border)
+               {
+                       return 2;
+               }
+       }
+       return 0;
+}
+
+// move a panel to the beginning of the panel order array (which means it gets drawn last, on top of everything else)
+void HUD_Panel_FirstInDrawQ(float id)
+{
+       int i;
+       int place = -1;
+       // find out where in the array our current id is, save into place
+       for(i = 0; i < hud_panels_COUNT; ++i)
+       {
+               if(panel_order[i] == id)
+               {
+                       place = i;
+                       break;
+               }
+       }
+       // place last if we didn't find a place for it yet (probably new panel, or screwed up cvar)
+       if(place == -1)
+               place = hud_panels_COUNT - 1;
+
+       // move all ids up by one step in the array until "place"
+       for(i = place; i > 0; --i)
+       {
+               panel_order[i] = panel_order[i-1];
+       }
+       // now save the new top id
+       panel_order[0] = id;
+
+       // let's save them into the cvar by some strcat trickery
+       string s = "";
+       for(i = 0; i < hud_panels_COUNT; ++i)
+       {
+               s = strcat(s, ftos(panel_order[i]), " ");
+       }
+       cvar_set("_hud_panelorder", s);
+       if(hud_panelorder_prev)
+               strunzone(hud_panelorder_prev);
+       hud_panelorder_prev = strzone(autocvar__hud_panelorder); // prevent HUD_Main from doing useless update, we already updated here
+}
+
+void HUD_Panel_Highlight(float allow_move)
+{
+       int i, j = 0;
+
+       while(j < hud_panels_COUNT)
+       {
+               i = panel_order[j];
+               j += 1;
+
+               panel = hud_panels_from(i);
+               if(!(panel.panel_configflags & PANEL_CONFIG_MAIN))
+                       continue;
+               HUD_Panel_UpdatePosSize();
+
+               float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
+
+               // move
+               if(allow_move && mousepos.x > panel_pos.x && mousepos.y > panel_pos.y && mousepos.x < panel_pos.x + panel_size.x && mousepos.y < panel_pos.y + panel_size.y)
+               {
+                       highlightedPanel = hud_panels_from(i);
+                       HUD_Panel_FirstInDrawQ(i);
+                       highlightedAction = 1;
+                       panel_click_distance = mousepos - panel_pos;
+                       return;
+               }
+               // resize from topleft border
+               else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
+               {
+                       highlightedPanel = hud_panels_from(i);
+                       HUD_Panel_FirstInDrawQ(i);
+                       highlightedAction = 2;
+                       resizeCorner = 1;
+                       panel_click_distance = mousepos - panel_pos;
+                       panel_click_resizeorigin = panel_pos + panel_size;
+                       return;
+               }
+               // resize from topright border
+               else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
+               {
+                       highlightedPanel = hud_panels_from(i);
+                       HUD_Panel_FirstInDrawQ(i);
+                       highlightedAction = 2;
+                       resizeCorner = 2;
+                       panel_click_distance.x = panel_size.x - mousepos.x + panel_pos.x;
+                       panel_click_distance.y = mousepos.y - panel_pos.y;
+                       panel_click_resizeorigin = panel_pos + eY * panel_size.y;
+                       return;
+               }
+               // resize from bottomleft border
+               else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + panel_size.y + border)
+               {
+                       highlightedPanel = hud_panels_from(i);
+                       HUD_Panel_FirstInDrawQ(i);
+                       highlightedAction = 2;
+                       resizeCorner = 3;
+                       panel_click_distance.x = mousepos.x - panel_pos.x;
+                       panel_click_distance.y = panel_size.y - mousepos.y + panel_pos.y;
+                       panel_click_resizeorigin = panel_pos + eX * panel_size.x;
+                       return;
+               }
+               // resize from bottomright border
+               else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + panel_size.y + border)
+               {
+                       highlightedPanel = hud_panels_from(i);
+                       HUD_Panel_FirstInDrawQ(i);
+                       highlightedAction = 2;
+                       resizeCorner = 4;
+                       panel_click_distance = panel_size - mousepos + panel_pos;
+                       panel_click_resizeorigin = panel_pos;
+                       return;
+               }
+       }
+       highlightedPanel = world;
+       highlightedAction = 0;
+}
+
+void HUD_Panel_EnableMenu()
+{
+       menu_enabled = 2;
+       localcmd("menu_showhudoptions ", highlightedPanel.panel_name, "\n");
+}
+float mouse_over_panel;
+void HUD_Panel_Mouse()
+{
+       if(autocvar__menu_alpha == 1)
+               return;
+
+       if (!autocvar_hud_cursormode)
+       {
+               mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
+
+               mousepos.x = bound(0, mousepos.x, vid_conwidth);
+               mousepos.y = bound(0, mousepos.y, vid_conheight);
+       }
+
+       if(mouseClicked)
+       {
+               if(prevMouseClicked == 0)
+               {
+                       if (tab_panel)
+                       {
+                               //stop ctrl-tab selection
+                               tab_panel = world;
+                               reset_tab_panels();
+                       }
+                       HUD_Panel_Highlight(mouseClicked & S_MOUSE1); // sets highlightedPanel, highlightedAction, panel_click_distance, panel_click_resizeorigin
+                                                                       // and calls HUD_Panel_UpdatePosSize() for the highlighted panel
+                       if (highlightedPanel)
+                       {
+                               highlightedPanel_initial_pos = panel_pos;
+                               highlightedPanel_initial_size = panel_size;
+                       }
+                       // doubleclick check
+                       if ((mouseClicked & S_MOUSE1) && time - prevMouseClickedTime < 0.4 && highlightedPanel && prevMouseClickedPos == mousepos)
+                       {
+                               mouseClicked = 0; // to prevent spam, I guess.
+                               HUD_Panel_EnableMenu();
+                       }
+                       else
+                       {
+                               if (mouseClicked & S_MOUSE1)
+                               {
+                                       prevMouseClickedTime = time;
+                                       prevMouseClickedPos = mousepos;
+                               }
+                               mouse_over_panel = HUD_Panel_Check_Mouse_Pos(mouseClicked & S_MOUSE1);
+                       }
+               }
+               else
+               {
+                       panel = highlightedPanel;
+                       HUD_Panel_UpdatePosSize();
+               }
+
+               if (highlightedPanel)
+               {
+                       drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
+                       if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
+                       {
+                               hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
+                               // backup!
+                               panel_pos_backup = highlightedPanel_initial_pos;
+                               panel_size_backup = highlightedPanel_initial_size;
+                               highlightedPanel_backup = highlightedPanel;
+                       }
+                       else
+                               // in case the clicked panel is inside another panel and we aren't
+                               // moving it, avoid the immediate "fix" of its position/size
+                               // (often unwanted and hateful) by disabling collisions check
+                               hud_configure_checkcollisions = false;
+               }
+
+               if(highlightedAction == 1)
+                       HUD_Panel_SetPos(mousepos - panel_click_distance);
+               else if(highlightedAction == 2)
+               {
+                       vector mySize = '0 0 0';
+                       if(resizeCorner == 1) {
+                               mySize.x = panel_click_resizeorigin.x - (mousepos.x - panel_click_distance.x);
+                               mySize.y = panel_click_resizeorigin.y - (mousepos.y - panel_click_distance.y);
+                       } else if(resizeCorner == 2) {
+                               mySize.x = mousepos.x + panel_click_distance.x - panel_click_resizeorigin.x;
+                               mySize.y = panel_click_distance.y + panel_click_resizeorigin.y - mousepos.y;
+                       } else if(resizeCorner == 3) {
+                               mySize.x = panel_click_resizeorigin.x + panel_click_distance.x - mousepos.x;
+                               mySize.y = mousepos.y + panel_click_distance.y - panel_click_resizeorigin.y;
+                       } else { // resizeCorner == 4
+                               mySize.x = mousepos.x - (panel_click_resizeorigin.x - panel_click_distance.x);
+                               mySize.y = mousepos.y - (panel_click_resizeorigin.y - panel_click_distance.y);
+                       }
+                       HUD_Panel_SetPosSize(mySize);
+               }
+       }
+       else
+       {
+               if(prevMouseClicked)
+                       highlightedAction = 0;
+               if(menu_enabled == 2)
+                       mouse_over_panel = 0;
+               else
+                       mouse_over_panel = HUD_Panel_Check_Mouse_Pos(true);
+               if (mouse_over_panel && !tab_panel)
+                       drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
+       }
+       // draw cursor after performing move/resize to have the panel pos/size updated before mouse_over_panel
+       const vector cursorsize = '32 32 0';
+       float cursor_alpha = 1 - autocvar__menu_alpha;
+
+       if(!mouse_over_panel)
+               drawpic(mousepos, strcat("gfx/menu/", autocvar_menu_skin, "/cursor.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
+       else if(mouse_over_panel == 1)
+               drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_move.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
+       else if(mouse_over_panel == 2)
+               drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_resize.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
+       else
+               drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_resize2.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
+
+       prevMouseClicked = mouseClicked;
+}
+void HUD_Configure_DrawGrid()
+{
+       float i;
+       if(autocvar_hud_configure_grid && autocvar_hud_configure_grid_alpha)
+       {
+               hud_configure_gridSize.x = bound(0.005, cvar("hud_configure_grid_xsize"), 0.2);
+               hud_configure_gridSize.y = bound(0.005, cvar("hud_configure_grid_ysize"), 0.2);
+               hud_configure_realGridSize.x = hud_configure_gridSize.x * vid_conwidth;
+               hud_configure_realGridSize.y = hud_configure_gridSize.y * vid_conheight;
+               vector s;
+               // x-axis
+               s = eX + eY * vid_conheight;
+               for(i = 1; i < 1/hud_configure_gridSize.x; ++i)
+                       drawfill(eX * i * hud_configure_realGridSize.x, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
+               // y-axis
+               s = eY + eX * vid_conwidth;
+               for(i = 1; i < 1/hud_configure_gridSize.y; ++i)
+                       drawfill(eY * i * hud_configure_realGridSize.y, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
+       }
+}
+
+float _menu_alpha_prev;
+void HUD_Configure_Frame()
+{
+       int i;
+       if(autocvar__hud_configure)
+       {
+               if(isdemo() || intermission == 2)
+               {
+                       HUD_Configure_Exit_Force();
+                       return;
+               }
+
+               if(!hud_configure_prev)
+               {
+                       if(autocvar_hud_cursormode)
+                               setcursormode(1);
+                       hudShiftState = 0;
+                       for(i = hud_panels_COUNT - 1; i >= 0; --i)
+                               hud_panels_from(panel_order[i]).update_time = time;
+               }
+
+               // NOTE this check is necessary because _menu_alpha isn't updated the frame the menu gets enabled
+               if(autocvar__menu_alpha != _menu_alpha_prev)
+               {
+                       if(autocvar__menu_alpha == 0)
+                               menu_enabled = 0;
+                       _menu_alpha_prev = autocvar__menu_alpha;
+               }
+
+               HUD_Configure_DrawGrid();
+       }
+       else if(hud_configure_prev)
+       {
+               if(menu_enabled)
+                       menu_enabled = 0;
+               if(autocvar_hud_cursormode)
+                       setcursormode(0);
+       }
+}
+
+const float hlBorderSize = 2;
+const string hlBorder = "gfx/hud/default/border_highlighted";
+const string hlBorder2 = "gfx/hud/default/border_highlighted2";
+void HUD_Panel_HlBorder(float myBorder, vector color, float theAlpha)
+{
+       drawfill(panel_pos - '1 1 0' * myBorder, panel_size + '2 2 0' * myBorder, '0 0.5 1', .5 * theAlpha, DRAWFLAG_NORMAL);
+       drawpic_tiled(panel_pos - '1 1 0' * myBorder, hlBorder, '8 1 0' * hlBorderSize, eX * (panel_size.x + 2 * myBorder) + eY * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
+       drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * (panel_size.y + 2 * myBorder - hlBorderSize), hlBorder, '8 1 0' * hlBorderSize, eX * (panel_size.x + 2 * myBorder) + eY * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
+       drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * hlBorderSize, hlBorder2, '1 8 0' * hlBorderSize, eY * (panel_size.y + 2 * myBorder - 2 * hlBorderSize) + eX * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
+       drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * hlBorderSize + eX * (panel_size.x + 2 * myBorder - hlBorderSize), hlBorder2, '1 8 0' * hlBorderSize, eY * (panel_size.y + 2 * myBorder - 2 * hlBorderSize) + eX * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
+}
+
+void HUD_Configure_PostDraw()
+{
+       if(autocvar__hud_configure)
+       {
+               if(tab_panel)
+               {
+                       panel = tab_panel;
+                       HUD_Panel_UpdatePosSize();
+                       drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .2, DRAWFLAG_NORMAL);
+               }
+               if(highlightedPanel)
+               {
+                       panel = highlightedPanel;
+                       HUD_Panel_UpdatePosSize();
+                       HUD_Panel_HlBorder(panel_bg_border * hlBorderSize, '0 0.5 1', 0.4 * (1 - autocvar__menu_alpha));
+               }
+       }
+}
diff --git a/qcsrc/client/hud/hud_config.qh b/qcsrc/client/hud/hud_config.qh
new file mode 100644 (file)
index 0000000..0579228
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef CLIENT_HUD_CONFIG_H
+#define CLIENT_HUD_CONFIG_H
+
+const int S_MOUSE1 = 1;
+const int S_MOUSE2 = 2;
+const int S_MOUSE3 = 4;
+int mouseClicked;
+int prevMouseClicked; // previous state
+float prevMouseClickedTime; // time during previous left mouse click, to check for doubleclicks
+vector prevMouseClickedPos; // pos during previous left mouse click, to check for doubleclicks
+
+void HUD_Panel_ExportCfg(string cfgname);
+
+void HUD_Panel_Mouse();
+
+void HUD_Configure_Frame();
+
+void HUD_Configure_PostDraw();
+
+float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary);
+
+#endif
diff --git a/qcsrc/client/hud/panel/ammo.qc b/qcsrc/client/hud/panel/ammo.qc
new file mode 100644 (file)
index 0000000..236a585
--- /dev/null
@@ -0,0 +1,222 @@
+// Ammo (#1)
+
+void DrawNadeProgressBar(vector myPos, vector mySize, float progress, vector color)
+{
+       HUD_Panel_DrawProgressBar(
+               myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x,
+               mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x,
+               autocvar_hud_panel_ammo_progressbar_name,
+               progress, 0, 0, color,
+               autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time); // TODO: mutator
+
+void DrawAmmoItem(vector myPos, vector mySize, .int ammoType, bool isCurrent, bool isInfinite)
+{
+       if(ammoType == ammo_none)
+               return;
+
+       // Initialize variables
+
+       int ammo;
+       if(autocvar__hud_configure)
+       {
+               isCurrent = (ammoType == ammo_rockets); // Rockets always current
+               ammo = 60;
+       }
+       else
+               ammo = getstati(GetAmmoStat(ammoType));
+
+       if(!isCurrent)
+       {
+               float scale = bound(0, autocvar_hud_panel_ammo_noncurrent_scale, 1);
+               myPos = myPos + (mySize - mySize * scale) * 0.5;
+               mySize = mySize * scale;
+       }
+
+       vector iconPos, textPos;
+       if(autocvar_hud_panel_ammo_iconalign)
+       {
+               iconPos = myPos + eX * 2 * mySize.y;
+               textPos = myPos;
+       }
+       else
+       {
+               iconPos = myPos;
+               textPos = myPos + eX * mySize.y;
+       }
+
+       bool isShadowed = (ammo <= 0 && !isCurrent && !isInfinite);
+
+       vector iconColor = isShadowed ? '0 0 0' : '1 1 1';
+       vector textColor;
+       if(isInfinite)
+               textColor = '0.2 0.95 0';
+       else if(isShadowed)
+               textColor = '0 0 0';
+       else if(ammo < 10)
+               textColor = '0.8 0.04 0';
+       else
+               textColor = '1 1 1';
+
+       float alpha;
+       if(isCurrent)
+               alpha = panel_fg_alpha;
+       else if(isShadowed)
+               alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_ammo_noncurrent_alpha, 1) * 0.5;
+       else
+               alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_ammo_noncurrent_alpha, 1);
+
+       string text = isInfinite ? "\xE2\x88\x9E" : ftos(ammo); // Use infinity symbol (U+221E)
+
+       // Draw item
+
+       if(isCurrent)
+               drawpic_aspect_skin(myPos, "ammo_current_bg", mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+       if(ammo > 0 && autocvar_hud_panel_ammo_progressbar)
+               HUD_Panel_DrawProgressBar(myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x, mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x, autocvar_hud_panel_ammo_progressbar_name, ammo/autocvar_hud_panel_ammo_maxammo, 0, 0, textColor, autocvar_hud_progressbar_alpha * alpha, DRAWFLAG_NORMAL);
+
+       if(autocvar_hud_panel_ammo_text)
+               drawstring_aspect(textPos, text, eX * (2/3) * mySize.x + eY * mySize.y, textColor, alpha, DRAWFLAG_NORMAL);
+
+       drawpic_aspect_skin(iconPos, GetAmmoPicture(ammoType), '1 1 0' * mySize.y, iconColor, alpha, DRAWFLAG_NORMAL);
+}
+
+int nade_prevstatus;
+int nade_prevframe;
+float nade_statuschange_time;
+
+void HUD_Ammo()
+{
+       if(hud != HUD_NORMAL) return;
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_ammo) return;
+               if(spectatee_status == -1) return;
+       }
+
+       HUD_Panel_UpdateCvars();
+
+       draw_beginBoldFont();
+
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+
+       int rows = 0, columns, row, column;
+       float nade_cnt = getstatf(STAT_NADE_BONUS), nade_score = getstatf(STAT_NADE_BONUS_SCORE);
+       bool draw_nades = (nade_cnt > 0 || nade_score > 0);
+       float nade_statuschange_elapsedtime;
+       int total_ammo_count;
+
+       vector ammo_size;
+       if (autocvar_hud_panel_ammo_onlycurrent)
+               total_ammo_count = 1;
+       else
+               total_ammo_count = AMMO_COUNT;
+
+       if(draw_nades)
+       {
+               ++total_ammo_count;
+               if (nade_cnt != nade_prevframe)
+               {
+                       nade_statuschange_time = time;
+                       nade_prevstatus = nade_prevframe;
+                       nade_prevframe = nade_cnt;
+               }
+       }
+       else
+               nade_prevstatus = nade_prevframe = nade_statuschange_time = 0;
+
+       rows = HUD_GetRowCount(total_ammo_count, mySize, 3);
+       columns = ceil((total_ammo_count)/rows);
+       ammo_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
+
+       vector offset = '0 0 0'; // fteqcc sucks
+       float newSize;
+       if(ammo_size.x/ammo_size.y > 3)
+       {
+               newSize = 3 * ammo_size.y;
+               offset.x = ammo_size.x - newSize;
+               pos.x += offset.x/2;
+               ammo_size.x = newSize;
+       }
+       else
+       {
+               newSize = 1/3 * ammo_size.x;
+               offset.y = ammo_size.y - newSize;
+               pos.y += offset.y/2;
+               ammo_size.y = newSize;
+       }
+
+       int i;
+       bool infinite_ammo = (getstati(STAT_ITEMS, 0, 24) & IT_UNLIMITED_WEAPON_AMMO);
+       row = column = 0;
+       if(autocvar_hud_panel_ammo_onlycurrent)
+       {
+               if(autocvar__hud_configure)
+               {
+                       DrawAmmoItem(pos, ammo_size, ammo_rockets, true, false);
+               }
+               else
+               {
+                       DrawAmmoItem(
+                               pos,
+                               ammo_size,
+                               (get_weaponinfo(switchweapon)).ammo_field,
+                               true,
+                               infinite_ammo
+                       );
+               }
+
+               ++row;
+               if(row >= rows)
+               {
+                       row = 0;
+                       column = column + 1;
+               }
+       }
+       else
+       {
+               .int ammotype;
+               row = column = 0;
+               for(i = 0; i < AMMO_COUNT; ++i)
+               {
+                       ammotype = GetAmmoFieldFromNum(i);
+                       DrawAmmoItem(
+                               pos + eX * column * (ammo_size.x + offset.x) + eY * row * (ammo_size.y + offset.y),
+                               ammo_size,
+                               ammotype,
+                               ((get_weaponinfo(switchweapon)).ammo_field == ammotype),
+                               infinite_ammo
+                       );
+
+                       ++row;
+                       if(row >= rows)
+                       {
+                               row = 0;
+                               column = column + 1;
+                       }
+               }
+       }
+
+       if (draw_nades)
+       {
+               nade_statuschange_elapsedtime = time - nade_statuschange_time;
+
+               float f = bound(0, nade_statuschange_elapsedtime*2, 1);
+
+               DrawAmmoNades(pos + eX * column * (ammo_size.x + offset.x) + eY * row * (ammo_size.y + offset.y), ammo_size, nade_prevstatus < nade_cnt && nade_cnt != 0 && f < 1, f);
+       }
+
+       draw_endBoldFont();
+}
diff --git a/qcsrc/client/hud/panel/centerprint.qc b/qcsrc/client/hud/panel/centerprint.qc
new file mode 100644 (file)
index 0000000..3169d92
--- /dev/null
@@ -0,0 +1,335 @@
+// CenterPrint (#16)
+
+const int CENTERPRINT_MAX_MSGS = 10;
+const int CENTERPRINT_MAX_ENTRIES = 50;
+const float CENTERPRINT_SPACING = 0.7;
+int cpm_index;
+string centerprint_messages[CENTERPRINT_MAX_MSGS];
+int centerprint_msgID[CENTERPRINT_MAX_MSGS];
+float centerprint_time[CENTERPRINT_MAX_MSGS];
+float centerprint_expire_time[CENTERPRINT_MAX_MSGS];
+int centerprint_countdown_num[CENTERPRINT_MAX_MSGS];
+bool centerprint_showing;
+
+void centerprint_generic(int new_id, string strMessage, float duration, int countdown_num)
+{
+       //printf("centerprint_generic(%d, '%s^7', %d, %d);\n", new_id, strMessage, duration, countdown_num);
+       int i, j;
+
+       if(strMessage == "" && new_id == 0)
+               return;
+
+       // strip trailing newlines
+       j = strlen(strMessage) - 1;
+       while(substring(strMessage, j, 1) == "\n" && j >= 0)
+               --j;
+       if (j < strlen(strMessage) - 1)
+               strMessage = substring(strMessage, 0, j + 1);
+
+       if(strMessage == "" && new_id == 0)
+               return;
+
+       // strip leading newlines
+       j = 0;
+       while(substring(strMessage, j, 1) == "\n" && j < strlen(strMessage))
+               ++j;
+       if (j > 0)
+               strMessage = substring(strMessage, j, strlen(strMessage) - j);
+
+       if(strMessage == "" && new_id == 0)
+               return;
+
+       if (!centerprint_showing)
+               centerprint_showing = true;
+
+       for (i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
+       {
+               if (j == CENTERPRINT_MAX_MSGS)
+                       j = 0;
+               if (new_id && new_id == centerprint_msgID[j])
+               {
+                       if (strMessage == "" && centerprint_messages[j] != "" && centerprint_countdown_num[j] == 0)
+                       {
+                               // fade out the current msg (duration and countdown_num are ignored)
+                               centerprint_time[j] = min(5, autocvar_hud_panel_centerprint_fade_out);
+                               if (centerprint_expire_time[j] > time + min(5, autocvar_hud_panel_centerprint_fade_out) || centerprint_expire_time[j] < time)
+                                       centerprint_expire_time[j] = time + min(5, autocvar_hud_panel_centerprint_fade_out);
+                               return;
+                       }
+                       break; // found a msg with the same id, at position j
+               }
+       }
+
+       if (i == CENTERPRINT_MAX_MSGS)
+       {
+               // a msg with the same id was not found, add the msg at the next position
+               --cpm_index;
+               if (cpm_index == -1)
+                       cpm_index = CENTERPRINT_MAX_MSGS - 1;
+               j = cpm_index;
+       }
+       if(centerprint_messages[j])
+               strunzone(centerprint_messages[j]);
+       centerprint_messages[j] = strzone(strMessage);
+       centerprint_msgID[j] = new_id;
+       if (duration < 0)
+       {
+               centerprint_time[j] = -1;
+               centerprint_expire_time[j] = time;
+       }
+       else
+       {
+               if(duration == 0)
+                       duration = max(1, autocvar_hud_panel_centerprint_time);
+               centerprint_time[j] = duration;
+               centerprint_expire_time[j] = time + duration;
+       }
+       centerprint_countdown_num[j] = countdown_num;
+}
+
+void centerprint_hud(string strMessage)
+{
+       centerprint_generic(0, strMessage, autocvar_hud_panel_centerprint_time, 0);
+}
+
+void reset_centerprint_messages()
+{
+       int i;
+       for (i=0; i<CENTERPRINT_MAX_MSGS; ++i)
+       {
+               centerprint_expire_time[i] = 0;
+               centerprint_time[i] = 1;
+               centerprint_msgID[i] = 0;
+               if(centerprint_messages[i])
+                       strunzone(centerprint_messages[i]);
+               centerprint_messages[i] = string_null;
+       }
+}
+float hud_configure_cp_generation_time;
+void HUD_CenterPrint ()
+{
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_centerprint) return;
+
+               if(hud_configure_prev)
+                       reset_centerprint_messages();
+       }
+       else
+       {
+               if(!hud_configure_prev)
+                       reset_centerprint_messages();
+               if (time > hud_configure_cp_generation_time)
+               {
+                       if(highlightedPanel == HUD_PANEL(CENTERPRINT))
+                       {
+                               float r;
+                               r = random();
+                               if (r > 0.8)
+                                       centerprint_generic(floor(r*1000), strcat(sprintf("^3Countdown message at time %s", seconds_tostring(time)), ", seconds left: ^COUNT"), 1, 10);
+                               else if (r > 0.55)
+                                       centerprint_generic(0, sprintf("^1Multiline message at time %s that\n^1lasts longer than normal", seconds_tostring(time)), 20, 0);
+                               else
+                                       centerprint_hud(sprintf("Message at time %s", seconds_tostring(time)));
+                               hud_configure_cp_generation_time = time + 1 + random()*4;
+                       }
+                       else
+                       {
+                               centerprint_generic(0, sprintf("Centerprint message", seconds_tostring(time)), 10, 0);
+                               hud_configure_cp_generation_time = time + 10 - random()*3;
+                       }
+               }
+       }
+
+       // this panel fades only when the menu does
+       float hud_fade_alpha_save = 0;
+       if(scoreboard_fade_alpha)
+       {
+               hud_fade_alpha_save = hud_fade_alpha;
+               hud_fade_alpha = 1 - autocvar__menu_alpha;
+       }
+       HUD_Panel_UpdateCvars();
+
+       if ( HUD_Radar_Clickable() )
+       {
+               if (hud_panel_radar_bottom >= 0.96 * vid_conheight)
+                       return;
+
+               panel_pos = eY * hud_panel_radar_bottom + eX * 0.5 * (vid_conwidth - panel_size_x);
+               panel_size_y = min(panel_size_y, vid_conheight - hud_panel_radar_bottom);
+       }
+       else if(scoreboard_fade_alpha)
+       {
+               hud_fade_alpha = hud_fade_alpha_save;
+
+               // move the panel below the scoreboard
+               if (scoreboard_bottom >= 0.96 * vid_conheight)
+                       return;
+               vector target_pos;
+
+               target_pos = eY * scoreboard_bottom + eX * 0.5 * (vid_conwidth - panel_size.x);
+
+               if(target_pos.y > panel_pos.y)
+               {
+                       panel_pos = panel_pos + (target_pos - panel_pos) * sqrt(scoreboard_fade_alpha);
+                       panel_size.y = min(panel_size.y, vid_conheight - scoreboard_bottom);
+               }
+       }
+
+       HUD_Panel_DrawBg(1);
+
+       if (!centerprint_showing)
+               return;
+
+       if(panel_bg_padding)
+       {
+               panel_pos += '1 1 0' * panel_bg_padding;
+               panel_size -= '2 2 0' * panel_bg_padding;
+       }
+
+       int entries;
+       float height;
+       vector fontsize;
+       // entries = bound(1, floor(CENTERPRINT_MAX_ENTRIES * 4 * panel_size_y/panel_size_x), CENTERPRINT_MAX_ENTRIES);
+       // height = panel_size_y/entries;
+       // fontsize = '1 1 0' * height;
+       height = vid_conheight/50 * autocvar_hud_panel_centerprint_fontscale;
+       fontsize = '1 1 0' * height;
+       entries = bound(1, floor(panel_size.y/height), CENTERPRINT_MAX_ENTRIES);
+
+       int i, j, k, n, g;
+       float a, sz, align, current_msg_posY = 0, msg_size;
+       vector pos;
+       string ts;
+       bool all_messages_expired = true;
+
+       pos = panel_pos;
+       if (autocvar_hud_panel_centerprint_flip)
+               pos.y += panel_size.y;
+       align = bound(0, autocvar_hud_panel_centerprint_align, 1);
+       for (g=0, i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
+       {
+               if (j == CENTERPRINT_MAX_MSGS)
+                       j = 0;
+               if (centerprint_expire_time[j] <= time)
+               {
+                       if (centerprint_countdown_num[j] && centerprint_time[j] > 0)
+                       {
+                               centerprint_countdown_num[j] = centerprint_countdown_num[j] - 1;
+                               if (centerprint_countdown_num[j] == 0)
+                                       continue;
+                               centerprint_expire_time[j] = centerprint_expire_time[j] + centerprint_time[j];
+                       }
+                       else if(centerprint_time[j] != -1)
+                               continue;
+               }
+
+               all_messages_expired = false;
+
+               // fade the centerprint_hud in/out
+               if(centerprint_time[j] < 0)  // Expired but forced. Expire time is the fade-in time.
+                       a = (time - centerprint_expire_time[j]) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
+               else if(centerprint_expire_time[j] - autocvar_hud_panel_centerprint_fade_out > time)  // Regularily printed. Not fading out yet.
+                       a = (time - (centerprint_expire_time[j] - centerprint_time[j])) / max(0.0001, autocvar_hud_panel_centerprint_fade_in);
+               else // Expiring soon, so fade it out.
+                       a = (centerprint_expire_time[j] - time) / max(0.0001, autocvar_hud_panel_centerprint_fade_out);
+
+               // while counting down show it anyway in order to hold the current message position
+               if (a <= 0.5/255.0 && centerprint_countdown_num[j] == 0)  // Guaranteed invisible - don't show.
+                       continue;
+               if (a > 1)
+                       a = 1;
+
+               // set the size from fading in/out before subsequent fading
+               sz = autocvar_hud_panel_centerprint_fade_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_minfontsize);
+
+               // also fade it based on positioning
+               if(autocvar_hud_panel_centerprint_fade_subsequent)
+               {
+                       a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1); // pass one: all messages after the first have half theAlpha
+                       a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1); // pass two: after that, gradually lower theAlpha even more for each message
+               }
+               a *= panel_fg_alpha;
+
+               // finally set the size based on the new theAlpha from subsequent fading
+               sz = sz * (autocvar_hud_panel_centerprint_fade_subsequent_minfontsize + a * (1 - autocvar_hud_panel_centerprint_fade_subsequent_minfontsize));
+               drawfontscale = sz * '1 1 0';
+
+               if (centerprint_countdown_num[j])
+                       n = tokenizebyseparator(strreplace("^COUNT", count_seconds(centerprint_countdown_num[j]), centerprint_messages[j]), "\n");
+               else
+                       n = tokenizebyseparator(centerprint_messages[j], "\n");
+
+               if (autocvar_hud_panel_centerprint_flip)
+               {
+                       // check if the message can be entirely shown
+                       for(k = 0; k < n; ++k)
+                       {
+                               getWrappedLine_remaining = argv(k);
+                               while(getWrappedLine_remaining)
+                               {
+                                       ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
+                                       if (ts != "")
+                                               pos.y -= fontsize.y;
+                                       else
+                                               pos.y -= fontsize.y * CENTERPRINT_SPACING/2;
+                               }
+                       }
+                       current_msg_posY = pos.y; // save starting pos (first line) of the current message
+               }
+
+               msg_size = pos.y;
+               for(k = 0; k < n; ++k)
+               {
+                       getWrappedLine_remaining = argv(k);
+                       while(getWrappedLine_remaining)
+                       {
+                               ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
+                               if (ts != "")
+                               {
+                                       if (align)
+                                               pos.x = panel_pos.x + (panel_size.x - stringwidth(ts, true, fontsize)) * align;
+                                       if (a > 0.5/255.0)  // Otherwise guaranteed invisible - don't show. This is checked a second time after some multiplications with other factors were done so temporary changes of these cannot cause flicker.
+                                               drawcolorcodedstring(pos + eY * 0.5 * (1 - sz) * fontsize.y, ts, fontsize, a, DRAWFLAG_NORMAL);
+                                       pos.y += fontsize.y;
+                               }
+                               else
+                                       pos.y += fontsize.y * CENTERPRINT_SPACING/2;
+                       }
+               }
+
+               ++g; // move next position number up
+
+               msg_size = pos.y - msg_size;
+               if (autocvar_hud_panel_centerprint_flip)
+               {
+                       pos.y = current_msg_posY - CENTERPRINT_SPACING * fontsize.y;
+                       if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
+                               pos.y += (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
+
+                       if (pos.y < panel_pos.y) // check if the next message can be shown
+                       {
+                               drawfontscale = '1 1 0';
+                               return;
+                       }
+               }
+               else
+               {
+                       pos.y += CENTERPRINT_SPACING * fontsize.y;
+                       if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
+                               pos.y -= (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
+
+                       if(pos.y > panel_pos.y + panel_size.y - fontsize.y) // check if the next message can be shown
+                       {
+                               drawfontscale = '1 1 0';
+                               return;
+                       }
+               }
+       }
+       drawfontscale = '1 1 0';
+       if (all_messages_expired)
+       {
+               centerprint_showing = false;
+               reset_centerprint_messages();
+       }
+}
diff --git a/qcsrc/client/hud/panel/chat.qc b/qcsrc/client/hud/panel/chat.qc
new file mode 100644 (file)
index 0000000..02df4ed
--- /dev/null
@@ -0,0 +1,89 @@
+/** Handle chat as a panel (#12) */
+void HUD_Chat()
+{
+       if(!autocvar__hud_configure)
+       {
+               if (!autocvar_hud_panel_chat)
+               {
+                       if (!autocvar_con_chatrect)
+                               cvar_set("con_chatrect", "0");
+                       return;
+               }
+               if(autocvar__con_chat_maximized)
+               {
+                       if(!hud_draw_maximized) return;
+               }
+               else if(chat_panel_modified)
+               {
+                       panel.update_time = time; // forces reload of panel attributes
+                       chat_panel_modified = false;
+               }
+       }
+
+       HUD_Panel_UpdateCvars();
+
+       if(intermission == 2)
+       {
+               // reserve some more space to the mapvote panel
+               // by resizing and moving chat panel to the bottom
+               panel_size.y = min(panel_size.y, vid_conheight * 0.2);
+               panel_pos.y = vid_conheight - panel_size.y - panel_bg_border * 2;
+               chat_posy = panel_pos.y;
+               chat_sizey = panel_size.y;
+       }
+       if(autocvar__con_chat_maximized && !autocvar__hud_configure) // draw at full screen height if maximized
+       {
+               panel_pos.y = panel_bg_border;
+               panel_size.y = vid_conheight - panel_bg_border * 2;
+               if(panel.current_panel_bg == "0") // force a border when maximized
+               {
+                       string panel_bg;
+                       panel_bg = strcat(hud_skin_path, "/border_default");
+                       if(precache_pic(panel_bg) == "")
+                               panel_bg = "gfx/hud/default/border_default";
+                       if(panel.current_panel_bg)
+                               strunzone(panel.current_panel_bg);
+                       panel.current_panel_bg = strzone(panel_bg);
+                       chat_panel_modified = true;
+               }
+               panel_bg_alpha = max(0.75, panel_bg_alpha); // force an theAlpha of at least 0.75
+       }
+
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+
+       HUD_Panel_DrawBg(1);
+
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+
+       if (!autocvar_con_chatrect)
+               cvar_set("con_chatrect", "1");
+
+       cvar_set("con_chatrect_x", ftos(pos.x/vid_conwidth));
+       cvar_set("con_chatrect_y", ftos(pos.y/vid_conheight));
+
+       cvar_set("con_chatwidth", ftos(mySize.x/vid_conwidth));
+       cvar_set("con_chat", ftos(floor(mySize.y/autocvar_con_chatsize - 0.5)));
+
+       if(autocvar__hud_configure)
+       {
+               vector chatsize;
+               chatsize = '1 1 0' * autocvar_con_chatsize;
+               cvar_set("con_chatrect_x", "9001"); // over 9000, we'll fake it instead for more control over theAlpha and such
+               float i, a;
+               for(i = 0; i < autocvar_con_chat; ++i)
+               {
+                       if(i == autocvar_con_chat - 1)
+                               a = panel_fg_alpha;
+                       else
+                               a = panel_fg_alpha * floor(((i + 1) * 7 + autocvar_con_chattime)/45);
+                       drawcolorcodedstring(pos, textShortenToWidth(_("^3Player^7: This is the chat area."), mySize.x, chatsize, stringwidth_colors), chatsize, a, DRAWFLAG_NORMAL);
+                       pos.y += chatsize.y;
+               }
+       }
+}
diff --git a/qcsrc/client/hud/panel/engineinfo.qc b/qcsrc/client/hud/panel/engineinfo.qc
new file mode 100644 (file)
index 0000000..01e7ae3
--- /dev/null
@@ -0,0 +1,61 @@
+// Engine info panel (#13)
+
+float prevfps;
+float prevfps_time;
+int framecounter;
+
+float frametimeavg;
+float frametimeavg1; // 1 frame ago
+float frametimeavg2; // 2 frames ago
+void HUD_EngineInfo()
+{
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_engineinfo) return;
+       }
+
+       HUD_Panel_UpdateCvars();
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+
+       float currentTime = gettime(GETTIME_REALTIME);
+       if(cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage"))
+       {
+               float currentframetime = currentTime - prevfps_time;
+               frametimeavg = (frametimeavg + frametimeavg1 + frametimeavg2 + currentframetime)/4; // average three frametimes into framecounter for slightly more stable fps readings :P
+               frametimeavg2 = frametimeavg1;
+               frametimeavg1 = frametimeavg;
+
+               float weight;
+               weight = cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_new_weight");
+               if(currentframetime > 0.0001) // filter out insane values which sometimes seem to occur and throw off the average? If you are getting 10,000 fps or more, then you don't need a framerate counter.
+               {
+                       if(fabs(prevfps - (1/frametimeavg)) > prevfps * cvar("hud_panel_engineinfo_framecounter_exponentialmovingaverage_instantupdate_change_threshold")) // if there was a big jump in fps, just force prevfps at current (1/currentframetime) to make big updates instant
+                               prevfps = (1/currentframetime);
+                       prevfps = (1 - weight) * prevfps + weight * (1/frametimeavg); // framecounter just used so there's no need for a new variable, think of it as "frametime average"
+               }
+               prevfps_time = currentTime;
+       }
+       else
+       {
+               framecounter += 1;
+               if(currentTime - prevfps_time > autocvar_hud_panel_engineinfo_framecounter_time)
+               {
+                       prevfps = framecounter/(currentTime - prevfps_time);
+                       framecounter = 0;
+                       prevfps_time = currentTime;
+               }
+       }
+
+       vector color;
+       color = HUD_Get_Num_Color (prevfps, 100);
+       drawstring_aspect(pos, sprintf(_("FPS: %.*f"), autocvar_hud_panel_engineinfo_framecounter_decimals, prevfps), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+}
diff --git a/qcsrc/client/hud/panel/healtharmor.qc b/qcsrc/client/hud/panel/healtharmor.qc
new file mode 100644 (file)
index 0000000..8304329
--- /dev/null
@@ -0,0 +1,264 @@
+/** Health/armor (#3) */
+void HUD_HealthArmor()
+{
+       int armor, health, fuel;
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_healtharmor) return;
+               if(hud != HUD_NORMAL) return;
+               if(spectatee_status == -1) return;
+
+               health = getstati(STAT_HEALTH);
+               if(health <= 0)
+               {
+                       prev_health = -1;
+                       return;
+               }
+               armor = getstati(STAT_ARMOR);
+
+               // code to check for spectatee_status changes is in Ent_ClientData()
+               // prev_p_health and prev_health can be set to -1 there
+
+               if (prev_p_health == -1)
+               {
+                       // no effect
+                       health_beforedamage = 0;
+                       armor_beforedamage = 0;
+                       health_damagetime = 0;
+                       armor_damagetime = 0;
+                       prev_health = health;
+                       prev_armor = armor;
+                       old_p_health = health;
+                       old_p_armor = armor;
+                       prev_p_health = health;
+                       prev_p_armor = armor;
+               }
+               else if (prev_health == -1)
+               {
+                       //start the load effect
+                       health_damagetime = 0;
+                       armor_damagetime = 0;
+                       prev_health = 0;
+                       prev_armor = 0;
+               }
+               fuel = getstati(STAT_FUEL);
+       }
+       else
+       {
+               health = 150;
+               armor = 75;
+               fuel = 20;
+       }
+
+       HUD_Panel_UpdateCvars();
+
+       draw_beginBoldFont();
+
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+
+       int baralign = autocvar_hud_panel_healtharmor_baralign;
+       int iconalign = autocvar_hud_panel_healtharmor_iconalign;
+
+    int maxhealth = autocvar_hud_panel_healtharmor_maxhealth;
+    int maxarmor = autocvar_hud_panel_healtharmor_maxarmor;
+       if(autocvar_hud_panel_healtharmor == 2) // combined health and armor display
+       {
+               vector v;
+               v = healtharmor_maxdamage(health, armor, armorblockpercent, DEATH_WEAPON.m_id);
+
+               float x;
+               x = floor(v.x + 1);
+
+        float maxtotal = maxhealth + maxarmor;
+               string biggercount;
+               if(v.z) // NOT fully armored
+               {
+                       biggercount = "health";
+                       if(autocvar_hud_panel_healtharmor_progressbar)
+                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_health, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       if(armor)
+            if(autocvar_hud_panel_healtharmor_text)
+                               drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "armor", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha * armor / health, DRAWFLAG_NORMAL);
+               }
+               else
+               {
+                       biggercount = "armor";
+                       if(autocvar_hud_panel_healtharmor_progressbar)
+                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       if(health)
+            if(autocvar_hud_panel_healtharmor_text)
+                               drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "health", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
+        if(autocvar_hud_panel_healtharmor_text)
+                       DrawNumIcon(pos, mySize, x, biggercount, 0, iconalign, HUD_Get_Num_Color(x, maxtotal), 1);
+
+               if(fuel)
+                       HUD_Panel_DrawProgressBar(pos, eX * mySize.x + eY * 0.2 * mySize.y, "progressbar", fuel/100, 0, (baralign == 1 || baralign == 3), autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
+       }
+       else
+       {
+               float panel_ar = mySize.x/mySize.y;
+               bool is_vertical = (panel_ar < 1);
+               vector health_offset = '0 0 0', armor_offset = '0 0 0';
+               if (panel_ar >= 4 || (panel_ar >= 1/4 && panel_ar < 1))
+               {
+                       mySize.x *= 0.5;
+                       if (autocvar_hud_panel_healtharmor_flip)
+                               health_offset.x = mySize.x;
+                       else
+                               armor_offset.x = mySize.x;
+               }
+               else
+               {
+                       mySize.y *= 0.5;
+                       if (autocvar_hud_panel_healtharmor_flip)
+                               health_offset.y = mySize.y;
+                       else
+                               armor_offset.y = mySize.y;
+               }
+
+               bool health_baralign, armor_baralign, fuel_baralign;
+               bool health_iconalign, armor_iconalign;
+               if (autocvar_hud_panel_healtharmor_flip)
+               {
+                       armor_baralign = (autocvar_hud_panel_healtharmor_baralign == 2 || autocvar_hud_panel_healtharmor_baralign == 1);
+                       health_baralign = (autocvar_hud_panel_healtharmor_baralign == 3 || autocvar_hud_panel_healtharmor_baralign == 1);
+                       fuel_baralign = health_baralign;
+                       armor_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 2 || autocvar_hud_panel_healtharmor_iconalign == 1);
+                       health_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 3 || autocvar_hud_panel_healtharmor_iconalign == 1);
+               }
+               else
+               {
+                       health_baralign = (autocvar_hud_panel_healtharmor_baralign == 2 || autocvar_hud_panel_healtharmor_baralign == 1);
+                       armor_baralign = (autocvar_hud_panel_healtharmor_baralign == 3 || autocvar_hud_panel_healtharmor_baralign == 1);
+                       fuel_baralign = armor_baralign;
+                       health_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 2 || autocvar_hud_panel_healtharmor_iconalign == 1);
+                       armor_iconalign = (autocvar_hud_panel_healtharmor_iconalign == 3 || autocvar_hud_panel_healtharmor_iconalign == 1);
+               }
+
+               //if(health)
+               {
+                       if(autocvar_hud_panel_healtharmor_progressbar)
+                       {
+                               float p_health, pain_health_alpha;
+                               p_health = health;
+                               pain_health_alpha = 1;
+                               if (autocvar_hud_panel_healtharmor_progressbar_gfx)
+                               {
+                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_smooth > 0)
+                                       {
+                                               if (fabs(prev_health - health) >= autocvar_hud_panel_healtharmor_progressbar_gfx_smooth)
+                                               {
+                                                       if (time - old_p_healthtime < 1)
+                                                               old_p_health = prev_p_health;
+                                                       else
+                                                               old_p_health = prev_health;
+                                                       old_p_healthtime = time;
+                                               }
+                                               if (time - old_p_healthtime < 1)
+                                               {
+                                                       p_health += (old_p_health - health) * (1 - (time - old_p_healthtime));
+                                                       prev_p_health = p_health;
+                                               }
+                                       }
+                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0)
+                                       {
+                                               if (prev_health - health >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
+                                               {
+                                                       if (time - health_damagetime >= 1)
+                                                               health_beforedamage = prev_health;
+                                                       health_damagetime = time;
+                                               }
+                                               if (time - health_damagetime < 1)
+                                               {
+                                                       float health_damagealpha = 1 - (time - health_damagetime)*(time - health_damagetime);
+                                                       HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, health_beforedamage/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * health_damagealpha, DRAWFLAG_NORMAL);
+                                               }
+                                       }
+                                       prev_health = health;
+
+                                       if (health <= autocvar_hud_panel_healtharmor_progressbar_gfx_lowhealth)
+                                       {
+                                               float BLINK_FACTOR = 0.15;
+                                               float BLINK_BASE = 0.85;
+                                               float BLINK_FREQ = 9;
+                                               pain_health_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
+                                       }
+                               }
+                               HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, p_health/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * pain_health_alpha, DRAWFLAG_NORMAL);
+                       }
+                       if(autocvar_hud_panel_healtharmor_text)
+                               DrawNumIcon(pos + health_offset, mySize, health, "health", is_vertical, health_iconalign, HUD_Get_Num_Color(health, maxhealth), 1);
+               }
+
+               if(armor)
+               {
+                       if(autocvar_hud_panel_healtharmor_progressbar)
+                       {
+                               float p_armor;
+                               p_armor = armor;
+                               if (autocvar_hud_panel_healtharmor_progressbar_gfx)
+                               {
+                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_smooth > 0)
+                                       {
+                                               if (fabs(prev_armor - armor) >= autocvar_hud_panel_healtharmor_progressbar_gfx_smooth)
+                                               {
+                                                       if (time - old_p_armortime < 1)
+                                                               old_p_armor = prev_p_armor;
+                                                       else
+                                                               old_p_armor = prev_armor;
+                                                       old_p_armortime = time;
+                                               }
+                                               if (time - old_p_armortime < 1)
+                                               {
+                                                       p_armor += (old_p_armor - armor) * (1 - (time - old_p_armortime));
+                                                       prev_p_armor = p_armor;
+                                               }
+                                       }
+                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0)
+                                       {
+                                               if (prev_armor - armor >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
+                                               {
+                                                       if (time - armor_damagetime >= 1)
+                                                               armor_beforedamage = prev_armor;
+                                                       armor_damagetime = time;
+                                               }
+                                               if (time - armor_damagetime < 1)
+                                               {
+                                                       float armor_damagealpha = 1 - (time - armor_damagetime)*(time - armor_damagetime);
+                                                       HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, armor_beforedamage/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * armor_damagealpha, DRAWFLAG_NORMAL);
+                                               }
+                                       }
+                                       prev_armor = armor;
+                               }
+                               HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, p_armor/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       }
+                       if(autocvar_hud_panel_healtharmor_text)
+                               DrawNumIcon(pos + armor_offset, mySize, armor, "armor", is_vertical, armor_iconalign, HUD_Get_Num_Color(armor, maxarmor), 1);
+               }
+
+               if(fuel)
+               {
+                       if (is_vertical)
+                               mySize.x *= 0.2 / 2; //if vertical always halve x to not cover too much numbers with 3 digits
+                       else
+                               mySize.y *= 0.2;
+                       if (panel_ar >= 4)
+                               mySize.x *= 2; //restore full panel size
+                       else if (panel_ar < 1/4)
+                               mySize.y *= 2; //restore full panel size
+                       HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", fuel/100, is_vertical, fuel_baralign, autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
+               }
+       }
+
+       draw_endBoldFont();
+}
diff --git a/qcsrc/client/hud/panel/infomessages.qc b/qcsrc/client/hud/panel/infomessages.qc
new file mode 100644 (file)
index 0000000..2bcad64
--- /dev/null
@@ -0,0 +1,183 @@
+// Info messages panel (#14)
+
+#define drawInfoMessage(s) do {                                                                                                                                                                                \
+       if(autocvar_hud_panel_infomessages_flip)                                                                                                                                                \
+               o.x = pos.x + mySize.x - stringwidth(s, true, fontsize);                                                                                                        \
+       drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL);                                                                                                               \
+       o.y += fontsize.y;                                                                                                                                                                                              \
+} while(0)
+void HUD_InfoMessages()
+{
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_infomessages) return;
+       }
+
+       HUD_Panel_UpdateCvars();
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+
+       // always force 5:1 aspect
+       vector newSize = '0 0 0';
+       if(mySize.x/mySize.y > 5)
+       {
+               newSize.x = 5 * mySize.y;
+               newSize.y = mySize.y;
+
+               pos.x = pos.x + (mySize.x - newSize.x) / 2;
+       }
+       else
+       {
+               newSize.y = 1/5 * mySize.x;
+               newSize.x = mySize.x;
+
+               pos.y = pos.y + (mySize.y - newSize.y) / 2;
+       }
+
+       mySize = newSize;
+       entity tm;
+       vector o;
+       o = pos;
+
+       vector fontsize;
+       fontsize = '0.20 0.20 0' * mySize.y;
+
+       float a;
+       a = panel_fg_alpha;
+
+       string s;
+       if(!autocvar__hud_configure)
+       {
+               if(spectatee_status && !intermission)
+               {
+                       a = 1;
+                       if(spectatee_status == -1)
+                               s = _("^1Observing");
+                       else
+                               s = sprintf(_("^1Spectating: ^7%s"), GetPlayerName(current_player));
+                       drawInfoMessage(s);
+
+                       if(spectatee_status == -1)
+                               s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey("primary fire", "+fire"));
+                       else
+                               s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
+                       drawInfoMessage(s);
+
+                       if(spectatee_status == -1)
+                               s = sprintf(_("^1Use ^3%s^1 or ^3%s^1 to change the speed"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
+                       else
+                               s = sprintf(_("^1Press ^3%s^1 to observe"), getcommandkey("secondary fire", "+fire2"));
+                       drawInfoMessage(s);
+
+                       s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey("server info", "+show_info"));
+                       drawInfoMessage(s);
+
+                       if(gametype == MAPINFO_TYPE_LMS)
+                       {
+                               entity sk;
+                               sk = playerslots[player_localnum];
+                               if(sk.(scores[ps_primary]) >= 666)
+                                       s = _("^1Match has already begun");
+                               else if(sk.(scores[ps_primary]) > 0)
+                                       s = _("^1You have no more lives left");
+                               else
+                                       s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
+                       }
+                       else
+                               s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
+                       drawInfoMessage(s);
+
+                       //show restart countdown:
+                       if (time < STAT(GAMESTARTTIME)) {
+                               float countdown;
+                               //we need to ceil, otherwise the countdown would be off by .5 when using round()
+                               countdown = ceil(STAT(GAMESTARTTIME) - time);
+                               s = sprintf(_("^1Game starts in ^3%d^1 seconds"), countdown);
+                               drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL);
+                               o.y += fontsize.y;
+                       }
+               }
+               if(warmup_stage && !intermission)
+               {
+                       s = _("^2Currently in ^1warmup^2 stage!");
+                       drawInfoMessage(s);
+               }
+
+               string blinkcolor;
+               if(time % 1 >= 0.5)
+                       blinkcolor = "^1";
+               else
+                       blinkcolor = "^3";
+
+               if(ready_waiting && !intermission && !spectatee_status)
+               {
+                       if(ready_waiting_for_me)
+                       {
+                               if(warmup_stage)
+                                       s = sprintf(_("%sPress ^3%s%s to end warmup"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
+                               else
+                                       s = sprintf(_("%sPress ^3%s%s once you are ready"), blinkcolor, getcommandkey("ready", "ready"), blinkcolor);
+                       }
+                       else
+                       {
+                               if(warmup_stage)
+                                       s = _("^2Waiting for others to ready up to end warmup...");
+                               else
+                                       s = _("^2Waiting for others to ready up...");
+                       }
+                       drawInfoMessage(s);
+               }
+               else if(warmup_stage && !intermission && !spectatee_status)
+               {
+                       s = sprintf(_("^2Press ^3%s^2 to end warmup"), getcommandkey("ready", "ready"));
+                       drawInfoMessage(s);
+               }
+
+               if(teamplay && !intermission && !spectatee_status && gametype != MAPINFO_TYPE_CA && teamnagger)
+               {
+                       float ts_min = 0, ts_max = 0;
+                       tm = teams.sort_next;
+                       if (tm)
+                       {
+                               for (; tm.sort_next; tm = tm.sort_next)
+                               {
+                                       if(!tm.team_size || tm.team == NUM_SPECTATOR)
+                                               continue;
+                                       if(!ts_min) ts_min = tm.team_size;
+                                       else ts_min = min(ts_min, tm.team_size);
+                                       if(!ts_max) ts_max = tm.team_size;
+                                       else ts_max = max(ts_max, tm.team_size);
+                               }
+                               if ((ts_max - ts_min) > 1)
+                               {
+                                       s = strcat(blinkcolor, _("Teamnumbers are unbalanced!"));
+                                       tm = GetTeam(myteam, false);
+                                       if (tm)
+                                       if (tm.team != NUM_SPECTATOR)
+                                       if (tm.team_size == ts_max)
+                                               s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey("team menu", "menu_showteamselect"), blinkcolor));
+                                       drawInfoMessage(s);
+                               }
+                       }
+               }
+       }
+       else
+       {
+               s = _("^7Press ^3ESC ^7to show HUD options.");
+               drawInfoMessage(s);
+               s = _("^3Doubleclick ^7a panel for panel-specific options.");
+               drawInfoMessage(s);
+               s = _("^3CTRL ^7to disable collision testing, ^3SHIFT ^7and");
+               drawInfoMessage(s);
+               s = _("^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments.");
+               drawInfoMessage(s);
+       }
+}
diff --git a/qcsrc/client/hud/panel/minigame.qc b/qcsrc/client/hud/panel/minigame.qc
new file mode 100644 (file)
index 0000000..dbacddb
--- /dev/null
@@ -0,0 +1,3 @@
+// Minigame
+
+#include "../../../common/minigames/cl_minigames_hud.qc"
diff --git a/qcsrc/client/hud/panel/modicons.qc b/qcsrc/client/hud/panel/modicons.qc
new file mode 100644 (file)
index 0000000..a8cb7c2
--- /dev/null
@@ -0,0 +1,776 @@
+// Mod icons panel (#10)
+
+bool mod_active; // is there any active mod icon?
+
+void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
+{
+       int stat = -1;
+       string pic = "";
+       vector color = '0 0 0';
+       switch(i)
+       {
+               case 0:
+                       stat = getstati(STAT_REDALIVE);
+                       pic = "player_red.tga";
+                       color = '1 0 0';
+                       break;
+               case 1:
+                       stat = getstati(STAT_BLUEALIVE);
+                       pic = "player_blue.tga";
+                       color = '0 0 1';
+                       break;
+               case 2:
+                       stat = getstati(STAT_YELLOWALIVE);
+                       pic = "player_yellow.tga";
+                       color = '1 1 0';
+                       break;
+               default:
+               case 3:
+                       stat = getstati(STAT_PINKALIVE);
+                       pic = "player_pink.tga";
+                       color = '1 0 1';
+                       break;
+       }
+
+       if(mySize.x/mySize.y > aspect_ratio)
+       {
+               i = aspect_ratio * mySize.y;
+               myPos.x = myPos.x + (mySize.x - i) / 2;
+               mySize.x = i;
+       }
+       else
+       {
+               i = 1/aspect_ratio * mySize.x;
+               myPos.y = myPos.y + (mySize.y - i) / 2;
+               mySize.y = i;
+       }
+
+       if(layout)
+       {
+               drawpic_aspect_skin(myPos, pic, eX * 0.7 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(myPos + eX * 0.7 * mySize.x, ftos(stat), eX * 0.3 * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+       else
+               drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+// Clan Arena and Freeze Tag HUD modicons
+void HUD_Mod_CA(vector myPos, vector mySize)
+{
+       mod_active = 1; // required in each mod function that always shows something
+
+       int layout;
+       if(gametype == MAPINFO_TYPE_CA)
+               layout = autocvar_hud_panel_modicons_ca_layout;
+       else //if(gametype == MAPINFO_TYPE_FREEZETAG)
+               layout = autocvar_hud_panel_modicons_freezetag_layout;
+       int rows, columns;
+       float aspect_ratio;
+       aspect_ratio = (layout) ? 2 : 1;
+       rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
+       columns = ceil(team_count/rows);
+
+       int i;
+       float row = 0, column = 0;
+       vector pos, itemSize;
+       itemSize = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
+       for(i=0; i<team_count; ++i)
+       {
+               pos = myPos + eX * column * itemSize.x + eY * row * itemSize.y;
+
+               DrawCAItem(pos, itemSize, aspect_ratio, layout, i);
+
+               ++row;
+               if(row >= rows)
+               {
+                       row = 0;
+                       ++column;
+               }
+       }
+}
+
+// CTF HUD modicon section
+int redflag_prevframe, blueflag_prevframe, yellowflag_prevframe, pinkflag_prevframe, neutralflag_prevframe; // status during previous frame
+int redflag_prevstatus, blueflag_prevstatus, yellowflag_prevstatus, pinkflag_prevstatus, neutralflag_prevstatus; // last remembered status
+float redflag_statuschange_time, blueflag_statuschange_time, yellowflag_statuschange_time, pinkflag_statuschange_time, neutralflag_statuschange_time; // time when the status changed
+
+void HUD_Mod_CTF_Reset()
+{
+       redflag_prevstatus = blueflag_prevstatus = yellowflag_prevstatus = pinkflag_prevstatus = neutralflag_prevstatus = 0;
+       redflag_prevframe = blueflag_prevframe = yellowflag_prevframe = pinkflag_prevframe = neutralflag_prevframe = 0;
+       redflag_statuschange_time = blueflag_statuschange_time = yellowflag_statuschange_time = pinkflag_statuschange_time = neutralflag_statuschange_time = 0;
+}
+
+void HUD_Mod_CTF(vector pos, vector mySize)
+{
+       vector redflag_pos, blueflag_pos, yellowflag_pos, pinkflag_pos, neutralflag_pos;
+       vector flag_size;
+       float f; // every function should have that
+
+       int redflag, blueflag, yellowflag, pinkflag, neutralflag; // current status
+       float redflag_statuschange_elapsedtime, blueflag_statuschange_elapsedtime, yellowflag_statuschange_elapsedtime, pinkflag_statuschange_elapsedtime, neutralflag_statuschange_elapsedtime; // time since the status changed
+       bool ctf_oneflag; // one-flag CTF mode enabled/disabled
+       int stat_items = getstati(STAT_CTF_FLAGSTATUS, 0, 24);
+       float fs, fs2, fs3, size1, size2;
+       vector e1, e2;
+
+       redflag = (stat_items/CTF_RED_FLAG_TAKEN) & 3;
+       blueflag = (stat_items/CTF_BLUE_FLAG_TAKEN) & 3;
+       yellowflag = (stat_items/CTF_YELLOW_FLAG_TAKEN) & 3;
+       pinkflag = (stat_items/CTF_PINK_FLAG_TAKEN) & 3;
+       neutralflag = (stat_items/CTF_NEUTRAL_FLAG_TAKEN) & 3;
+
+       ctf_oneflag = (stat_items & CTF_FLAG_NEUTRAL);
+
+       mod_active = (redflag || blueflag || yellowflag || pinkflag || neutralflag);
+
+       if (autocvar__hud_configure) {
+               redflag = 1;
+               blueflag = 2;
+               if (team_count >= 3)
+                       yellowflag = 2;
+               if (team_count >= 4)
+                       pinkflag = 3;
+               ctf_oneflag = neutralflag = 0; // disable neutral flag in hud editor?
+       }
+
+       // when status CHANGES, set old status into prevstatus and current status into status
+       #define X(team) do {                                                                                                                    \
+               if (team##flag != team##flag_prevframe) {                                                                       \
+               team##flag_statuschange_time = time;                                                                    \
+               team##flag_prevstatus = team##flag_prevframe;                                                   \
+               team##flag_prevframe = team##flag;                                                                              \
+       }                                                                                                                                                       \
+       team##flag_statuschange_elapsedtime = time - team##flag_statuschange_time;      \
+    } while (0)
+       X(red);
+       X(blue);
+       X(yellow);
+       X(pink);
+       X(neutral);
+       #undef X
+
+       const float BLINK_FACTOR = 0.15;
+       const float BLINK_BASE = 0.85;
+       // note:
+       //   RMS = sqrt(BLINK_BASE^2 + 0.5 * BLINK_FACTOR^2)
+       // thus
+       //   BLINK_BASE = sqrt(RMS^2 - 0.5 * BLINK_FACTOR^2)
+       // ensure RMS == 1
+       const float BLINK_FREQ = 5; // circle frequency, = 2*pi*frequency in hertz
+
+       #define X(team, cond) \
+       string team##_icon, team##_icon_prevstatus; \
+       int team##_alpha, team##_alpha_prevstatus; \
+       team##_alpha = team##_alpha_prevstatus = 1; \
+       do { \
+               switch (team##flag) { \
+                       case 1: team##_icon = "flag_" #team "_taken"; break; \
+                       case 2: team##_icon = "flag_" #team "_lost"; break; \
+                       case 3: team##_icon = "flag_" #team "_carrying"; team##_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
+                       default: \
+                               if ((stat_items & CTF_SHIELDED) && (cond)) { \
+                                       team##_icon = "flag_" #team "_shielded"; \
+                               } else { \
+                                       team##_icon = string_null; \
+                               } \
+                               break; \
+               } \
+               switch (team##flag_prevstatus) { \
+                       case 1: team##_icon_prevstatus = "flag_" #team "_taken"; break; \
+                       case 2: team##_icon_prevstatus = "flag_" #team "_lost"; break; \
+                       case 3: team##_icon_prevstatus = "flag_" #team "_carrying"; team##_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
+                       default: \
+                               if (team##flag == 3) { \
+                                       team##_icon_prevstatus = "flag_" #team "_carrying"; /* make it more visible */\
+                               } else if((stat_items & CTF_SHIELDED) && (cond)) { \
+                                       team##_icon_prevstatus = "flag_" #team "_shielded"; \
+                               } else { \
+                                       team##_icon_prevstatus = string_null; \
+                               } \
+                               break; \
+               } \
+       } while (0)
+       X(red, myteam != NUM_TEAM_1);
+       X(blue, myteam != NUM_TEAM_2);
+       X(yellow, myteam != NUM_TEAM_3);
+       X(pink, myteam != NUM_TEAM_4);
+       X(neutral, true);
+       #undef X
+
+       if (ctf_oneflag) {
+               // hacky, but these aren't needed
+               red_icon = red_icon_prevstatus = blue_icon = blue_icon_prevstatus = yellow_icon = yellow_icon_prevstatus = pink_icon = pink_icon_prevstatus = string_null;
+               fs = fs2 = fs3 = 1;
+       } else switch (team_count) {
+               default:
+               case 2: fs = 0.5; fs2 = 0.5; fs3 = 0.5; break;
+               case 3: fs = 1; fs2 = 0.35; fs3 = 0.35; break;
+               case 4: fs = 0.75; fs2 = 0.25; fs3 = 0.5; break;
+       }
+
+       if (mySize_x > mySize_y) {
+               size1 = mySize_x;
+               size2 = mySize_y;
+               e1 = eX;
+               e2 = eY;
+       } else {
+               size1 = mySize_y;
+               size2 = mySize_x;
+               e1 = eY;
+               e2 = eX;
+       }
+
+       switch (myteam) {
+               default:
+               case NUM_TEAM_1: {
+                       redflag_pos = pos;
+                       blueflag_pos = pos + eX * fs2 * size1;
+                       yellowflag_pos = pos - eX * fs2 * size1;
+                       pinkflag_pos = pos + eX * fs3 * size1;
+                       break;
+               }
+               case NUM_TEAM_2: {
+                       redflag_pos = pos + eX * fs2 * size1;
+                       blueflag_pos = pos;
+                       yellowflag_pos = pos - eX * fs2 * size1;
+                       pinkflag_pos = pos + eX * fs3 * size1;
+                       break;
+               }
+               case NUM_TEAM_3: {
+                       redflag_pos = pos + eX * fs3 * size1;
+                       blueflag_pos = pos - eX * fs2 * size1;
+                       yellowflag_pos = pos;
+                       pinkflag_pos = pos + eX * fs2 * size1;
+                       break;
+               }
+               case NUM_TEAM_4: {
+                       redflag_pos = pos - eX * fs2 * size1;
+                       blueflag_pos = pos + eX * fs3 * size1;
+                       yellowflag_pos = pos + eX * fs2 * size1;
+                       pinkflag_pos = pos;
+                       break;
+               }
+       }
+       neutralflag_pos = pos;
+       flag_size = e1 * fs * size1 + e2 * size2;
+
+       #define X(team) do { \
+               f = bound(0, team##flag_statuschange_elapsedtime * 2, 1); \
+               if (team##_icon_prevstatus && f < 1) \
+                       drawpic_aspect_skin_expanding(team##flag_pos, team##_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * team##_alpha_prevstatus, DRAWFLAG_NORMAL, f); \
+               if (team##_icon) \
+                       drawpic_aspect_skin(team##flag_pos, team##_icon, flag_size, '1 1 1', panel_fg_alpha * team##_alpha * f, DRAWFLAG_NORMAL); \
+       } while (0)
+       X(red);
+       X(blue);
+       X(yellow);
+       X(pink);
+       X(neutral);
+       #undef X
+}
+
+// Keyhunt HUD modicon section
+vector KH_SLOTS[4];
+
+void HUD_Mod_KH(vector pos, vector mySize)
+{
+       mod_active = 1; // keyhunt should never hide the mod icons panel
+
+       // Read current state
+
+       int state = STAT(KH_KEYS);
+       int i, key_state;
+       int all_keys, team1_keys, team2_keys, team3_keys, team4_keys, dropped_keys, carrying_keys;
+       all_keys = team1_keys = team2_keys = team3_keys = team4_keys = dropped_keys = carrying_keys = 0;
+
+       for(i = 0; i < 4; ++i)
+       {
+               key_state = (bitshift(state, i * -5) & 31) - 1;
+
+               if(key_state == -1)
+                       continue;
+
+               if(key_state == 30)
+               {
+                       ++carrying_keys;
+                       key_state = myteam;
+               }
+
+               switch(key_state)
+               {
+                       case NUM_TEAM_1: ++team1_keys; break;
+                       case NUM_TEAM_2: ++team2_keys; break;
+                       case NUM_TEAM_3: ++team3_keys; break;
+                       case NUM_TEAM_4: ++team4_keys; break;
+                       case 29: ++dropped_keys; break;
+               }
+
+               ++all_keys;
+       }
+
+       // Calculate slot measurements
+
+       vector slot_size;
+
+       if(all_keys == 4 && mySize.x * 0.5 < mySize.y && mySize.y * 0.5 < mySize.x)
+       {
+               // Quadratic arrangement
+               slot_size = eX * mySize.x * 0.5 + eY * mySize.y * 0.5;
+               KH_SLOTS[0] = pos;
+               KH_SLOTS[1] = pos + eX * slot_size.x;
+               KH_SLOTS[2] = pos + eY * slot_size.y;
+               KH_SLOTS[3] = pos + eX * slot_size.x + eY * slot_size.y;
+       }
+       else
+       {
+               if(mySize.x > mySize.y)
+               {
+                       // Horizontal arrangement
+                       slot_size = eX * mySize.x / all_keys + eY * mySize.y;
+                       for(i = 0; i < all_keys; ++i)
+                               KH_SLOTS[i] = pos + eX * slot_size.x * i;
+               }
+               else
+               {
+                       // Vertical arrangement
+                       slot_size = eX * mySize.x + eY * mySize.y / all_keys;
+                       for(i = 0; i < all_keys; ++i)
+                               KH_SLOTS[i] = pos + eY * slot_size.y * i;
+               }
+       }
+
+       // Make icons blink in case of RUN HERE
+
+       float blink = 0.6 + sin(2*M_PI*time) / 2.5; // Oscillate between 0.2 and 1
+       float alpha;
+       alpha = 1;
+
+       if(carrying_keys)
+               switch(myteam)
+               {
+                       case NUM_TEAM_1: if(team1_keys == all_keys) alpha = blink; break;
+                       case NUM_TEAM_2: if(team2_keys == all_keys) alpha = blink; break;
+                       case NUM_TEAM_3: if(team3_keys == all_keys) alpha = blink; break;
+                       case NUM_TEAM_4: if(team4_keys == all_keys) alpha = blink; break;
+               }
+
+       // Draw icons
+
+       i = 0;
+
+       while(team1_keys--)
+               if(myteam == NUM_TEAM_1 && carrying_keys)
+               {
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+                       --carrying_keys;
+               }
+               else
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+       while(team2_keys--)
+               if(myteam == NUM_TEAM_2 && carrying_keys)
+               {
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+                       --carrying_keys;
+               }
+               else
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+       while(team3_keys--)
+               if(myteam == NUM_TEAM_3 && carrying_keys)
+               {
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+                       --carrying_keys;
+               }
+               else
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+       while(team4_keys--)
+               if(myteam == NUM_TEAM_4 && carrying_keys)
+               {
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+                       --carrying_keys;
+               }
+               else
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+       while(dropped_keys--)
+               drawpic_aspect_skin(KH_SLOTS[i++], "kh_dropped", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+}
+
+// Keepaway HUD mod icon
+int kaball_prevstatus; // last remembered status
+float kaball_statuschange_time; // time when the status changed
+
+// we don't need to reset for keepaway since it immediately
+// autocorrects prevstatus as to if the player has the ball or not
+
+void HUD_Mod_Keepaway(vector pos, vector mySize)
+{
+       mod_active = 1; // keepaway should always show the mod HUD
+
+       float BLINK_FACTOR = 0.15;
+       float BLINK_BASE = 0.85;
+       float BLINK_FREQ = 5;
+       float kaball_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
+
+       int stat_items = getstati(STAT_ITEMS, 0, 24);
+       int kaball = (stat_items/IT_KEY1) & 1;
+
+       if(kaball != kaball_prevstatus)
+       {
+               kaball_statuschange_time = time;
+               kaball_prevstatus = kaball;
+       }
+
+       vector kaball_pos, kaball_size;
+
+       if(mySize.x > mySize.y) {
+               kaball_pos = pos + eX * 0.25 * mySize.x;
+               kaball_size = eX * 0.5 * mySize.x + eY * mySize.y;
+       } else {
+               kaball_pos = pos + eY * 0.25 * mySize.y;
+               kaball_size = eY * 0.5 * mySize.y + eX * mySize.x;
+       }
+
+       float kaball_statuschange_elapsedtime = time - kaball_statuschange_time;
+       float f = bound(0, kaball_statuschange_elapsedtime*2, 1);
+
+       if(kaball_prevstatus && f < 1)
+               drawpic_aspect_skin_expanding(kaball_pos, "keepawayball_carrying", kaball_size, '1 1 1', panel_fg_alpha * kaball_alpha, DRAWFLAG_NORMAL, f);
+
+       if(kaball)
+               drawpic_aspect_skin(pos, "keepawayball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha * kaball_alpha * f, DRAWFLAG_NORMAL);
+}
+
+
+// Nexball HUD mod icon
+void HUD_Mod_NexBall(vector pos, vector mySize)
+{
+       float nb_pb_starttime, dt, p;
+       int stat_items;
+
+       stat_items = getstati(STAT_ITEMS, 0, 24);
+       nb_pb_starttime = getstatf(STAT_NB_METERSTART);
+
+       if (stat_items & IT_KEY1)
+               mod_active = 1;
+       else
+               mod_active = 0;
+
+       //Manage the progress bar if any
+       if (nb_pb_starttime > 0)
+       {
+               dt = (time - nb_pb_starttime) % nb_pb_period;
+               // one period of positive triangle
+               p = 2 * dt / nb_pb_period;
+               if (p > 1)
+                       p = 2 - p;
+
+               HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, (mySize.x <= mySize.y), 0, autocvar_hud_progressbar_nexball_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+
+       if (stat_items & IT_KEY1)
+               drawpic_aspect_skin(pos, "nexball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+// Race/CTS HUD mod icons
+float crecordtime_prev; // last remembered crecordtime
+float crecordtime_change_time; // time when crecordtime last changed
+float srecordtime_prev; // last remembered srecordtime
+float srecordtime_change_time; // time when srecordtime last changed
+
+float race_status_time;
+int race_status_prev;
+string race_status_name_prev;
+void HUD_Mod_Race(vector pos, vector mySize)
+{
+       mod_active = 1; // race should never hide the mod icons panel
+       entity me;
+       me = playerslots[player_localnum];
+       float t, score;
+       float f; // yet another function has this
+       score = me.(scores[ps_primary]);
+
+       if(!(scores_flags[ps_primary] & SFL_TIME) || teamplay) // race/cts record display on HUD
+               return; // no records in the actual race
+
+       // clientside personal record
+       string rr;
+       if(gametype == MAPINFO_TYPE_CTS)
+               rr = CTS_RECORD;
+       else
+               rr = RACE_RECORD;
+       t = stof(db_get(ClientProgsDB, strcat(shortmapname, rr, "time")));
+
+       if(score && (score < t || !t)) {
+               db_put(ClientProgsDB, strcat(shortmapname, rr, "time"), ftos(score));
+               if(autocvar_cl_autodemo_delete_keeprecords)
+               {
+                       f = autocvar_cl_autodemo_delete;
+                       f &= ~1;
+                       cvar_set("cl_autodemo_delete", ftos(f)); // don't delete demo with new record!
+               }
+       }
+
+       if(t != crecordtime_prev) {
+               crecordtime_prev = t;
+               crecordtime_change_time = time;
+       }
+
+       vector textPos, medalPos;
+       float squareSize;
+       if(mySize.x > mySize.y) {
+               // text on left side
+               squareSize = min(mySize.y, mySize.x/2);
+               textPos = pos + eX * 0.5 * max(0, mySize.x/2 - squareSize) + eY * 0.5 * (mySize.y - squareSize);
+               medalPos = pos + eX * 0.5 * max(0, mySize.x/2 - squareSize) + eX * 0.5 * mySize.x + eY * 0.5 * (mySize.y - squareSize);
+       } else {
+               // text on top
+               squareSize = min(mySize.x, mySize.y/2);
+               textPos = pos + eY * 0.5 * max(0, mySize.y/2 - squareSize) + eX * 0.5 * (mySize.x - squareSize);
+               medalPos = pos + eY * 0.5 * max(0, mySize.y/2 - squareSize) + eY * 0.5 * mySize.y + eX * 0.5 * (mySize.x - squareSize);
+       }
+
+       f = time - crecordtime_change_time;
+
+       if (f > 1) {
+               drawstring_aspect(textPos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(textPos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       } else {
+               drawstring_aspect(textPos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(textPos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect_expanding(pos, _("Personal best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
+               drawstring_aspect_expanding(pos + eY * 0.25 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
+       }
+
+       // server record
+       t = race_server_record;
+       if(t != srecordtime_prev) {
+               srecordtime_prev = t;
+               srecordtime_change_time = time;
+       }
+       f = time - srecordtime_change_time;
+
+       if (f > 1) {
+               drawstring_aspect(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       } else {
+               drawstring_aspect(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect_expanding(textPos + eY * 0.5 * squareSize, _("Server best"), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
+               drawstring_aspect_expanding(textPos + eY * 0.75 * squareSize, TIME_ENCODED_TOSTRING(t), eX * squareSize + eY * 0.25 * squareSize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, f);
+       }
+
+       if (race_status != race_status_prev || race_status_name != race_status_name_prev) {
+               race_status_time = time + 5;
+               race_status_prev = race_status;
+               if (race_status_name_prev)
+                       strunzone(race_status_name_prev);
+               race_status_name_prev = strzone(race_status_name);
+       }
+
+       // race "awards"
+       float a;
+       a = bound(0, race_status_time - time, 1);
+
+       string s;
+       s = textShortenToWidth(race_status_name, squareSize, '1 1 0' * 0.1 * squareSize, stringwidth_colors);
+
+       float rank;
+       if(race_status > 0)
+               rank = race_CheckName(race_status_name);
+       else
+               rank = 0;
+       string rankname;
+       rankname = count_ordinal(rank);
+
+       vector namepos;
+       namepos = medalPos + '0 0.8 0' * squareSize;
+       vector rankpos;
+       rankpos = medalPos + '0 0.15 0' * squareSize;
+
+       if(race_status == 0)
+               drawpic_aspect_skin(medalPos, "race_newfail", '1 1 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+       else if(race_status == 1) {
+               drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newtime", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+       } else if(race_status == 2) {
+               if(race_status_name == GetPlayerName(player_localnum) || !race_myrank || race_myrank < rank)
+                       drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankgreen", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               else
+                       drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrankyellow", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+       } else if(race_status == 3) {
+               drawpic_aspect_skin(medalPos + '0.1 0 0' * squareSize, "race_newrecordserver", '1 1 0' * 0.8 * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               drawcolorcodedstring_aspect(namepos, s, '1 0.2 0' * squareSize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               drawstring_aspect(rankpos, rankname, '1 0.15 0' * squareSize, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+       }
+
+       if (race_status_time - time <= 0) {
+               race_status_prev = -1;
+               race_status = -1;
+               if(race_status_name)
+                       strunzone(race_status_name);
+               race_status_name = string_null;
+               if(race_status_name_prev)
+                       strunzone(race_status_name_prev);
+               race_status_name_prev = string_null;
+       }
+}
+
+void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
+{
+       float stat = -1;
+       string pic = "";
+       vector color = '0 0 0';
+       switch(i)
+       {
+               case 0:
+                       stat = getstatf(STAT_DOM_PPS_RED);
+                       pic = "dom_icon_red";
+                       color = '1 0 0';
+                       break;
+               case 1:
+                       stat = getstatf(STAT_DOM_PPS_BLUE);
+                       pic = "dom_icon_blue";
+                       color = '0 0 1';
+                       break;
+               case 2:
+                       stat = getstatf(STAT_DOM_PPS_YELLOW);
+                       pic = "dom_icon_yellow";
+                       color = '1 1 0';
+                       break;
+               default:
+               case 3:
+                       stat = getstatf(STAT_DOM_PPS_PINK);
+                       pic = "dom_icon_pink";
+                       color = '1 0 1';
+                       break;
+       }
+       float pps_ratio = stat / getstatf(STAT_DOM_TOTAL_PPS);
+
+       if(mySize.x/mySize.y > aspect_ratio)
+       {
+               i = aspect_ratio * mySize.y;
+               myPos.x = myPos.x + (mySize.x - i) / 2;
+               mySize.x = i;
+       }
+       else
+       {
+               i = 1/aspect_ratio * mySize.x;
+               myPos.y = myPos.y + (mySize.y - i) / 2;
+               mySize.y = i;
+       }
+
+       if (layout) // show text too
+       {
+               //draw the text
+               color *= 0.5 + pps_ratio * (1 - 0.5); // half saturated color at min, full saturated at max
+               if (layout == 2) // average pps
+                       drawstring_aspect(myPos + eX * mySize.y, ftos_decimals(stat, 2), eX * (2/3) * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+               else // percentage of average pps
+                       drawstring_aspect(myPos + eX * mySize.y, strcat( ftos(floor(pps_ratio*100 + 0.5)), "%" ), eX * (2/3) * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+
+       //draw the icon
+       drawpic_aspect_skin(myPos, pic, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       if (stat > 0)
+       {
+               drawsetcliparea(myPos.x, myPos.y + mySize.y * (1 - pps_ratio), mySize.y, mySize.y * pps_ratio);
+               drawpic_aspect_skin(myPos, strcat(pic, "-highlighted"), '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawresetcliparea();
+       }
+}
+
+void HUD_Mod_Dom(vector myPos, vector mySize)
+{
+       mod_active = 1; // required in each mod function that always shows something
+
+       int layout = autocvar_hud_panel_modicons_dom_layout;
+       int rows, columns;
+       float aspect_ratio;
+       aspect_ratio = (layout) ? 3 : 1;
+       rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
+       columns = ceil(team_count/rows);
+
+       int i;
+       float row = 0, column = 0;
+       vector pos, itemSize;
+       itemSize = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
+       for(i=0; i<team_count; ++i)
+       {
+               pos = myPos + eX * column * itemSize.x + eY * row * itemSize.y;
+
+               DrawDomItem(pos, itemSize, aspect_ratio, layout, i);
+
+               ++row;
+               if(row >= rows)
+               {
+                       row = 0;
+                       ++column;
+               }
+       }
+}
+
+void HUD_ModIcons_SetFunc()
+{
+       switch(gametype)
+       {
+               case MAPINFO_TYPE_KEYHUNT:              HUD_ModIcons_GameType = HUD_Mod_KH; break;
+               case MAPINFO_TYPE_CTF:                  HUD_ModIcons_GameType = HUD_Mod_CTF; break;
+               case MAPINFO_TYPE_NEXBALL:              HUD_ModIcons_GameType = HUD_Mod_NexBall; break;
+               case MAPINFO_TYPE_CTS:
+               case MAPINFO_TYPE_RACE:         HUD_ModIcons_GameType = HUD_Mod_Race; break;
+               case MAPINFO_TYPE_CA:
+               case MAPINFO_TYPE_FREEZETAG:    HUD_ModIcons_GameType = HUD_Mod_CA; break;
+               case MAPINFO_TYPE_DOMINATION:   HUD_ModIcons_GameType = HUD_Mod_Dom; break;
+               case MAPINFO_TYPE_KEEPAWAY:     HUD_ModIcons_GameType = HUD_Mod_Keepaway; break;
+       }
+}
+
+int mod_prev; // previous state of mod_active to check for a change
+float mod_alpha;
+float mod_change; // "time" when mod_active changed
+
+void HUD_ModIcons()
+{
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_modicons) return;
+               if(!HUD_ModIcons_GameType) return;
+       }
+
+       HUD_Panel_UpdateCvars();
+
+       draw_beginBoldFont();
+
+       if(mod_active != mod_prev) {
+               mod_change = time;
+               mod_prev = mod_active;
+       }
+
+       if(mod_active || autocvar__hud_configure)
+               mod_alpha = bound(0, (time - mod_change) * 2, 1);
+       else
+               mod_alpha = bound(0, 1 - (time - mod_change) * 2, 1);
+
+       if(mod_alpha)
+               HUD_Panel_DrawBg(mod_alpha);
+
+       if(panel_bg_padding)
+       {
+               panel_pos += '1 1 0' * panel_bg_padding;
+               panel_size -= '2 2 0' * panel_bg_padding;
+       }
+
+       if(autocvar__hud_configure)
+               HUD_Mod_CTF(panel_pos, panel_size);
+       else
+               HUD_ModIcons_GameType(panel_pos, panel_size);
+
+       draw_endBoldFont();
+}
diff --git a/qcsrc/client/hud/panel/notify.qc b/qcsrc/client/hud/panel/notify.qc
new file mode 100644 (file)
index 0000000..821c993
--- /dev/null
@@ -0,0 +1,154 @@
+// Notification area (#4)
+
+void HUD_Notify_Push(string icon, string attacker, string victim)
+{
+       if (icon == "")
+               return;
+
+       ++notify_count;
+       --notify_index;
+
+       if (notify_index == -1)
+               notify_index = NOTIFY_MAX_ENTRIES-1;
+
+       // Free old strings
+       if (notify_attackers[notify_index])
+               strunzone(notify_attackers[notify_index]);
+
+       if (notify_victims[notify_index])
+               strunzone(notify_victims[notify_index]);
+
+       if (notify_icons[notify_index])
+               strunzone(notify_icons[notify_index]);
+
+       // Allocate new strings
+       if (victim != "")
+       {
+               notify_attackers[notify_index] = strzone(attacker);
+               notify_victims[notify_index] = strzone(victim);
+       }
+       else
+       {
+               // In case of a notification without a victim, the attacker
+               // is displayed on the victim's side. Instead of special
+               // treatment later on, we can simply switch them here.
+               notify_attackers[notify_index] = string_null;
+               notify_victims[notify_index] = strzone(attacker);
+       }
+
+       notify_icons[notify_index] = strzone(icon);
+       notify_times[notify_index] = time;
+}
+
+void HUD_Notify()
+{
+       if (!autocvar__hud_configure)
+               if (!autocvar_hud_panel_notify)
+                       return;
+
+       HUD_Panel_UpdateCvars();
+       HUD_Panel_DrawBg(1);
+
+       if (!autocvar__hud_configure)
+               if (notify_count == 0)
+                       return;
+
+       vector pos, size;
+       pos  = panel_pos;
+       size = panel_size;
+
+       if (panel_bg_padding)
+       {
+               pos  += '1 1 0' * panel_bg_padding;
+               size -= '2 2 0' * panel_bg_padding;
+       }
+
+       float fade_start = max(0, autocvar_hud_panel_notify_time);
+       float fade_time = max(0, autocvar_hud_panel_notify_fadetime);
+       float icon_aspect = max(1, autocvar_hud_panel_notify_icon_aspect);
+
+       int entry_count = bound(1, floor(NOTIFY_MAX_ENTRIES * size.y / size.x), NOTIFY_MAX_ENTRIES);
+       float entry_height = size.y / entry_count;
+
+       float panel_width_half = size.x * 0.5;
+       float icon_width_half = entry_height * icon_aspect / 2;
+       float name_maxwidth = panel_width_half - icon_width_half - size.x * NOTIFY_ICON_MARGIN;
+
+       vector font_size = '0.5 0.5 0' * entry_height * autocvar_hud_panel_notify_fontsize;
+       vector icon_size = (eX * icon_aspect + eY) * entry_height;
+       vector icon_left = eX * (panel_width_half - icon_width_half);
+       vector attacker_right = eX * name_maxwidth;
+       vector victim_left = eX * (size.x - name_maxwidth);
+
+       vector attacker_pos, victim_pos, icon_pos;
+       string attacker, victim, icon;
+       int i, j, count, step, limit;
+       float alpha;
+
+       if (autocvar_hud_panel_notify_flip)
+       {
+               // Order items from the top down
+               i = 0;
+               step = +1;
+               limit = entry_count;
+       }
+       else
+       {
+               // Order items from the bottom up
+               i = entry_count - 1;
+               step = -1;
+               limit = -1;
+       }
+
+       for (j = notify_index, count = 0; i != limit; i += step, ++j, ++count)
+       {
+               if(autocvar__hud_configure)
+               {
+                       attacker = sprintf(_("Player %d"), count + 1);
+                       victim = sprintf(_("Player %d"), count + 2);
+                       icon = get_weaponinfo(min(WEP_FIRST + count * 2, WEP_LAST)).model2;
+                       alpha = bound(0, 1.2 - count / entry_count, 1);
+               }
+               else
+               {
+                       if (j == NOTIFY_MAX_ENTRIES)
+                               j = 0;
+
+                       if (notify_times[j] + fade_start > time)
+                               alpha = 1;
+                       else if (fade_time != 0)
+                       {
+                               alpha = bound(0, (notify_times[j] + fade_start + fade_time - time) / fade_time, 1);
+                               if (alpha == 0)
+                                       break;
+                       }
+                       else
+                               break;
+
+                       attacker = notify_attackers[j];
+                       victim = notify_victims[j];
+                       icon = notify_icons[j];
+               }
+
+               if (icon != "" && victim != "")
+               {
+                       vector name_top = eY * (i * entry_height + 0.5 * (entry_height - font_size.y));
+
+                       icon_pos = pos + icon_left + eY * i * entry_height;
+                       drawpic_aspect_skin(icon_pos, icon, icon_size, '1 1 1', panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+
+                       victim = textShortenToWidth(victim, name_maxwidth, font_size, stringwidth_colors);
+                       victim_pos = pos + victim_left + name_top;
+                       drawcolorcodedstring(victim_pos, victim, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+
+                       if (attacker != "")
+                       {
+                               attacker = textShortenToWidth(attacker, name_maxwidth, font_size, stringwidth_colors);
+                               attacker_pos = pos + attacker_right - eX * stringwidth(attacker, true, font_size) + name_top;
+                               drawcolorcodedstring(attacker_pos, attacker, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+                       }
+               }
+       }
+
+       notify_count = count;
+}
diff --git a/qcsrc/client/hud/panel/physics.qc b/qcsrc/client/hud/panel/physics.qc
new file mode 100644 (file)
index 0000000..e59b5e7
--- /dev/null
@@ -0,0 +1,287 @@
+// Physics panel (#15)
+
+vector acc_prevspeed;
+float acc_prevtime, acc_avg, top_speed, top_speed_time;
+float physics_update_time, discrete_speed, discrete_acceleration;
+void HUD_Physics()
+{
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_physics) return;
+               if(spectatee_status == -1 && (autocvar_hud_panel_physics == 1 || autocvar_hud_panel_physics == 3)) return;
+               if(autocvar_hud_panel_physics == 3 && !(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
+       }
+
+       HUD_Panel_UpdateCvars();
+
+       draw_beginBoldFont();
+
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
+       {
+               panel_pos += '1 1 0' * panel_bg_padding;
+               panel_size -= '2 2 0' * panel_bg_padding;
+       }
+
+       float acceleration_progressbar_scale = 0;
+       if(autocvar_hud_panel_physics_progressbar && autocvar_hud_panel_physics_acceleration_progressbar_scale > 1)
+               acceleration_progressbar_scale = autocvar_hud_panel_physics_acceleration_progressbar_scale;
+
+       float text_scale;
+       if (autocvar_hud_panel_physics_text_scale <= 0)
+               text_scale = 1;
+       else
+               text_scale = min(autocvar_hud_panel_physics_text_scale, 1);
+
+       //compute speed
+       float speed, conversion_factor;
+       string unit;
+
+       switch(autocvar_hud_panel_physics_speed_unit)
+       {
+               default:
+               case 1:
+                       unit = _(" qu/s");
+                       conversion_factor = 1.0;
+                       break;
+               case 2:
+                       unit = _(" m/s");
+                       conversion_factor = 0.0254;
+                       break;
+               case 3:
+                       unit = _(" km/h");
+                       conversion_factor = 0.0254 * 3.6;
+                       break;
+               case 4:
+                       unit = _(" mph");
+                       conversion_factor = 0.0254 * 3.6 * 0.6213711922;
+                       break;
+               case 5:
+                       unit = _(" knots");
+                       conversion_factor = 0.0254 * 1.943844492; // 1 m/s = 1.943844492 knots, because 1 knot = 1.852 km/h
+                       break;
+       }
+
+       vector vel = (csqcplayer ? csqcplayer.velocity : pmove_vel);
+
+       float max_speed = floor( autocvar_hud_panel_physics_speed_max * conversion_factor + 0.5 );
+       if (autocvar__hud_configure)
+               speed = floor( max_speed * 0.65 + 0.5 );
+       else if(autocvar_hud_panel_physics_speed_vertical)
+               speed = floor( vlen(vel) * conversion_factor + 0.5 );
+       else
+               speed = floor( vlen(vel - vel.z * '0 0 1') * conversion_factor + 0.5 );
+
+       //compute acceleration
+       float acceleration, f;
+       if (autocvar__hud_configure)
+               acceleration = autocvar_hud_panel_physics_acceleration_max * 0.3;
+       else
+       {
+               // 1 m/s = 0.0254 qu/s; 1 g = 9.80665 m/s^2
+               f = time - acc_prevtime;
+               if(autocvar_hud_panel_physics_acceleration_vertical)
+                       acceleration = (vlen(vel) - vlen(acc_prevspeed));
+               else
+                       acceleration = (vlen(vel - '0 0 1' * vel.z) - vlen(acc_prevspeed - '0 0 1' * acc_prevspeed.z));
+
+               acceleration = acceleration * (1 / max(0.0001, f)) * (0.0254 / 9.80665);
+
+               acc_prevspeed = vel;
+               acc_prevtime = time;
+
+               if(autocvar_hud_panel_physics_acceleration_movingaverage)
+               {
+                       f = bound(0, f * 10, 1);
+                       acc_avg = acc_avg * (1 - f) + acceleration * f;
+                       acceleration = acc_avg;
+               }
+       }
+
+       int acc_decimals = 2;
+       if(time > physics_update_time)
+       {
+               // workaround for ftos_decimals returning a negative 0
+               if(discrete_acceleration > -1 / pow(10, acc_decimals) && discrete_acceleration < 0)
+                       discrete_acceleration = 0;
+               discrete_acceleration = acceleration;
+               discrete_speed = speed;
+               physics_update_time += autocvar_hud_panel_physics_update_interval;
+       }
+
+       //compute layout
+       float panel_ar = panel_size.x/panel_size.y;
+       vector speed_offset = '0 0 0', acceleration_offset = '0 0 0';
+       if (panel_ar >= 5 && !acceleration_progressbar_scale)
+       {
+               panel_size.x *= 0.5;
+               if (autocvar_hud_panel_physics_flip)
+                       speed_offset.x = panel_size.x;
+               else
+                       acceleration_offset.x = panel_size.x;
+       }
+       else
+       {
+               panel_size.y *= 0.5;
+               if (autocvar_hud_panel_physics_flip)
+                       speed_offset.y = panel_size.y;
+               else
+                       acceleration_offset.y = panel_size.y;
+       }
+       int speed_baralign, acceleration_baralign;
+       if (autocvar_hud_panel_physics_baralign == 1)
+               acceleration_baralign = speed_baralign = 1;
+    else if(autocvar_hud_panel_physics_baralign == 4)
+               acceleration_baralign = speed_baralign = 2;
+       else if (autocvar_hud_panel_physics_flip)
+       {
+               acceleration_baralign = (autocvar_hud_panel_physics_baralign == 2);
+               speed_baralign = (autocvar_hud_panel_physics_baralign == 3);
+       }
+       else
+       {
+               speed_baralign = (autocvar_hud_panel_physics_baralign == 2);
+               acceleration_baralign = (autocvar_hud_panel_physics_baralign == 3);
+       }
+       if (autocvar_hud_panel_physics_acceleration_progressbar_mode == 0)
+               acceleration_baralign = 3; //override hud_panel_physics_baralign value for acceleration
+
+       //draw speed
+       if(speed)
+       if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
+               HUD_Panel_DrawProgressBar(panel_pos + speed_offset, panel_size, "progressbar", speed/max_speed, 0, speed_baralign, autocvar_hud_progressbar_speed_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+       vector tmp_offset = '0 0 0', tmp_size = '0 0 0';
+       if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
+       {
+               tmp_size.x = panel_size.x * 0.75;
+               tmp_size.y = panel_size.y * text_scale;
+               if (speed_baralign)
+                       tmp_offset.x = panel_size.x - tmp_size.x;
+               //else
+                       //tmp_offset_x = 0;
+               tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
+               drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(discrete_speed), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+               //draw speed unit
+               if (speed_baralign)
+                       tmp_offset.x = 0;
+               else
+                       tmp_offset.x = tmp_size.x;
+               if (autocvar_hud_panel_physics_speed_unit_show)
+               {
+                       //tmp_offset_y = 0;
+                       tmp_size.x = panel_size.x * (1 - 0.75);
+                       tmp_size.y = panel_size.y * 0.4 * text_scale;
+                       tmp_offset.y = (panel_size.y * 0.4 - tmp_size.y) / 2;
+                       drawstring_aspect(panel_pos + speed_offset + tmp_offset, unit, tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
+       }
+
+       //compute and draw top speed
+       if (autocvar_hud_panel_physics_topspeed)
+       if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
+       {
+               if (autocvar__hud_configure)
+               {
+                       top_speed = floor( max_speed * 0.75 + 0.5 );
+                       f = 1;
+               }
+               else
+               {
+                       if (speed >= top_speed)
+                       {
+                               top_speed = speed;
+                               top_speed_time = time;
+                       }
+                       if (top_speed != 0)
+                       {
+                               f = max(1, autocvar_hud_panel_physics_topspeed_time);
+                               // divide by f to make it start from 1
+                               f = cos( ((time - top_speed_time) / f) * PI/2 );
+                       }
+            else //hide top speed 0, it would be stupid
+                               f = 0;
+               }
+               if (f > 0)
+               {
+                       //top speed progressbar peak
+                       if(speed < top_speed)
+                       if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
+                       {
+                               float peak_offsetX;
+                               vector peak_size = '0 0 0';
+                               if (speed_baralign == 0)
+                                       peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x;
+                else if (speed_baralign == 1)
+                                       peak_offsetX = (1 - min(top_speed, max_speed)/max_speed) * panel_size.x;
+                else // if (speed_baralign == 2)
+                    peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x * 0.5;
+                               peak_size.x = floor(panel_size.x * 0.01 + 1.5);
+                peak_size.y = panel_size.y;
+                if (speed_baralign == 2) // draw two peaks, on both sides
+                {
+                    drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x + peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                    drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x - peak_offsetX + peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                }
+                else
+                    drawfill(panel_pos + speed_offset + eX * (peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       }
+
+                       //top speed
+                       tmp_offset.y = panel_size.y * 0.4;
+                       tmp_size.x = panel_size.x * (1 - 0.75);
+                       tmp_size.y = (panel_size.y - tmp_offset.y) * text_scale;
+                       tmp_offset.y += (panel_size.y - tmp_offset.y - tmp_size.y) / 2;
+                       drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(top_speed), tmp_size, '1 0 0', f * panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
+               else
+                       top_speed = 0;
+       }
+
+       //draw acceleration
+       if(acceleration)
+       if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 3)
+       {
+               vector progressbar_color;
+               if(acceleration < 0)
+                       progressbar_color = autocvar_hud_progressbar_acceleration_neg_color;
+               else
+                       progressbar_color = autocvar_hud_progressbar_acceleration_color;
+
+               f = acceleration/autocvar_hud_panel_physics_acceleration_max;
+               if (autocvar_hud_panel_physics_acceleration_progressbar_nonlinear)
+                       f = (f >= 0 ? sqrt(f) : -sqrt(-f));
+
+               if (acceleration_progressbar_scale) // allow progressbar to go out of panel bounds
+               {
+                       tmp_size = acceleration_progressbar_scale * panel_size.x * eX + panel_size.y * eY;
+
+                       if (acceleration_baralign == 1)
+                               tmp_offset.x = panel_size.x - tmp_size.x;
+                       else if (acceleration_baralign == 2 || acceleration_baralign == 3)
+                               tmp_offset.x = (panel_size.x - tmp_size.x) / 2;
+                       else
+                               tmp_offset.x = 0;
+                       tmp_offset.y = 0;
+               }
+               else
+               {
+                       tmp_size = panel_size;
+                       tmp_offset = '0 0 0';
+               }
+
+               HUD_Panel_DrawProgressBar(panel_pos + acceleration_offset + tmp_offset, tmp_size, "accelbar", f, 0, acceleration_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+
+       if(autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 3)
+       {
+               tmp_size.x = panel_size.x;
+               tmp_size.y = panel_size.y * text_scale;
+               tmp_offset.x = 0;
+               tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
+
+               drawstring_aspect(panel_pos + acceleration_offset + tmp_offset, strcat(ftos_decimals(discrete_acceleration, acc_decimals), "g"), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+
+       draw_endBoldFont();
+}
diff --git a/qcsrc/client/hud/panel/powerups.qc b/qcsrc/client/hud/panel/powerups.qc
new file mode 100644 (file)
index 0000000..10446d6
--- /dev/null
@@ -0,0 +1,211 @@
+// Powerups (#2)
+
+// Powerup item fields (reusing existing fields)
+.string message;  // Human readable name
+.string netname;  // Icon name
+.vector colormod; // Color
+.float count;     // Time left
+.float lifetime;  // Maximum time
+
+entity powerupItems;
+int powerupItemsCount;
+
+void resetPowerupItems()
+{
+       entity item;
+       for(item = powerupItems; item; item = item.chain)
+               item.count = 0;
+
+       powerupItemsCount = 0;
+}
+
+void addPowerupItem(string name, string icon, vector color, float currentTime, float lifeTime)
+{
+       if(!powerupItems)
+               powerupItems = spawn();
+
+       entity item;
+       for(item = powerupItems; item.count; item = item.chain)
+               if(!item.chain)
+                       item.chain = spawn();
+
+       item.message  = name;
+       item.netname  = icon;
+       item.colormod = color;
+       item.count    = currentTime;
+       item.lifetime = lifeTime;
+
+       ++powerupItemsCount;
+}
+
+int getPowerupItemAlign(int align, int column, int row, int columns, int rows, bool isVertical)
+{
+       if(align < 2)
+               return align;
+
+       bool isTop    =  isVertical && rows > 1 && row == 0;
+       bool isBottom =  isVertical && rows > 1 && row == rows-1;
+       bool isLeft   = !isVertical && columns > 1 && column == 0;
+       bool isRight  = !isVertical && columns > 1 && column == columns-1;
+
+       if(isTop    || isLeft)  return (align == 2) ? 1 : 0;
+       if(isBottom || isRight) return (align == 2) ? 0 : 1;
+
+       return 2;
+}
+
+void HUD_Powerups()
+{
+       int allItems = getstati(STAT_ITEMS, 0, 24);
+       int allBuffs = getstati(STAT_BUFFS, 0, 24);
+       int strengthTime, shieldTime, superTime;
+
+       // Initialize items
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_powerups) return;
+               if(spectatee_status == -1) return;
+               if(getstati(STAT_HEALTH) <= 0) return;
+               if(!(allItems & (ITEM_Strength.m_itemid | ITEM_Shield.m_itemid | IT_SUPERWEAPON)) && !allBuffs) return;
+
+               strengthTime = bound(0, STAT(STRENGTH_FINISHED) - time, 99);
+               shieldTime = bound(0, STAT(INVINCIBLE_FINISHED) - time, 99);
+               superTime = bound(0, getstatf(STAT_SUPERWEAPONS_FINISHED) - time, 99);
+
+               if(allItems & IT_UNLIMITED_SUPERWEAPONS)
+                       superTime = 99;
+
+               // Prevent stuff to show up on mismatch that will be fixed next frame
+               if(!(allItems & IT_SUPERWEAPON))
+                       superTime = 0;
+       }
+       else
+       {
+               strengthTime = 15;
+               shieldTime = 27;
+               superTime = 13;
+               allBuffs = 0;
+       }
+
+       // Add items to linked list
+       resetPowerupItems();
+
+       if(strengthTime)
+               addPowerupItem("Strength", "strength", autocvar_hud_progressbar_strength_color, strengthTime, 30);
+       if(shieldTime)
+               addPowerupItem("Shield", "shield", autocvar_hud_progressbar_shield_color, shieldTime, 30);
+       if(superTime)
+               addPowerupItem("Superweapons", "superweapons", autocvar_hud_progressbar_superweapons_color, superTime, 30);
+
+       MUTATOR_CALLHOOK(HUD_Powerups_add);
+
+       if(!powerupItemsCount)
+               return;
+
+       // Draw panel background
+       HUD_Panel_UpdateCvars();
+       HUD_Panel_DrawBg(1);
+
+       // Set drawing area
+       vector pos = panel_pos;
+       vector size = panel_size;
+       bool isVertical = size.y > size.x;
+
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               size -= '2 2 0' * panel_bg_padding;
+       }
+
+       // Find best partitioning of the drawing area
+       const float DESIRED_ASPECT = 6;
+       float aspect = 0, a;
+       int columns = 0, c;
+       int rows = 0, r;
+       int i = 1;
+
+       do
+       {
+               c = floor(powerupItemsCount / i);
+               r = ceil(powerupItemsCount / c);
+               a = isVertical ? (size.y/r) / (size.x/c) : (size.x/c) / (size.y/r);
+
+               if(i == 1 || fabs(DESIRED_ASPECT - a) < fabs(DESIRED_ASPECT - aspect))
+               {
+                       aspect = a;
+                       columns = c;
+                       rows = r;
+               }
+       }
+       while(++i <= powerupItemsCount);
+
+       // Prevent single items from getting too wide
+       if(powerupItemsCount == 1 && aspect > DESIRED_ASPECT)
+       {
+               if(isVertical)
+               {
+                       size.y *= 0.5;
+                       pos.y += size.y * 0.5;
+               }
+               else
+               {
+                       size.x *= 0.5;
+                       pos.x += size.x * 0.5;
+               }
+       }
+
+       // Draw items from linked list
+       vector itemPos = pos;
+       vector itemSize = eX * (size.x / columns) + eY * (size.y / rows);
+       vector textColor = '1 1 1';
+
+       int fullSeconds = 0;
+       int align = 0;
+       int column = 0;
+       int row = 0;
+
+       draw_beginBoldFont();
+       for(entity item = powerupItems; item.count; item = item.chain)
+       {
+               itemPos = eX * (pos.x + column * itemSize.x) + eY * (pos.y + row * itemSize.y);
+
+               // Draw progressbar
+               if(autocvar_hud_panel_powerups_progressbar)
+               {
+                       align = getPowerupItemAlign(autocvar_hud_panel_powerups_baralign, column, row, columns, rows, isVertical);
+                       HUD_Panel_DrawProgressBar(itemPos, itemSize, "progressbar", item.count / item.lifetime, isVertical, align, item.colormod, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
+
+               // Draw icon and text
+               if(autocvar_hud_panel_powerups_text)
+               {
+                       align = getPowerupItemAlign(autocvar_hud_panel_powerups_iconalign, column, row, columns, rows, isVertical);
+                       fullSeconds = ceil(item.count);
+                       textColor = '0.6 0.6 0.6' + (item.colormod * 0.4);
+
+                       if(item.count > 1)
+                               DrawNumIcon(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha);
+                       if(item.count <= 5)
+                               DrawNumIcon_expanding(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha, bound(0, (fullSeconds - item.count) / 0.5, 1));
+               }
+
+               // Determine next section
+               if(isVertical)
+               {
+                       if(++column >= columns)
+                       {
+                               column = 0;
+                               ++row;
+                       }
+               }
+               else
+               {
+                       if(++row >= rows)
+                       {
+                               row = 0;
+                               ++column;
+                       }
+               }
+       }
+       draw_endBoldFont();
+}
diff --git a/qcsrc/client/hud/panel/pressedkeys.qc b/qcsrc/client/hud/panel/pressedkeys.qc
new file mode 100644 (file)
index 0000000..94cc328
--- /dev/null
@@ -0,0 +1,63 @@
+/** Draw pressed keys (#11) */
+void HUD_PressedKeys()
+{
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_pressedkeys) return;
+               if(spectatee_status <= 0 && autocvar_hud_panel_pressedkeys < 2) return;
+       }
+
+       HUD_Panel_UpdateCvars();
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+
+       // force custom aspect
+       float aspect = autocvar_hud_panel_pressedkeys_aspect;
+       if(aspect)
+       {
+               vector newSize = '0 0 0';
+               if(mySize.x/mySize.y > aspect)
+               {
+                       newSize.x = aspect * mySize.y;
+                       newSize.y = mySize.y;
+
+                       pos.x = pos.x + (mySize.x - newSize.x) / 2;
+               }
+               else
+               {
+                       newSize.y = 1/aspect * mySize.x;
+                       newSize.x = mySize.x;
+
+                       pos.y = pos.y + (mySize.y - newSize.y) / 2;
+               }
+               mySize = newSize;
+       }
+
+       vector keysize;
+       keysize = eX * mySize.x * (1/3.0) + eY * mySize.y * (1/(3.0 - !autocvar_hud_panel_pressedkeys_attack));
+       float pressedkeys;
+       pressedkeys = getstatf(STAT_PRESSED_KEYS);
+
+       if(autocvar_hud_panel_pressedkeys_attack)
+       {
+               drawpic_aspect_skin(pos + eX * keysize.x * 0.5, ((pressedkeys & KEY_ATCK) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(pos + eX * keysize.x * 1.5, ((pressedkeys & KEY_ATCK2) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               pos.y += keysize.y;
+       }
+
+       drawpic_aspect_skin(pos, ((pressedkeys & KEY_CROUCH) ? "key_crouch_inv.tga" : "key_crouch.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawpic_aspect_skin(pos + eX * keysize.x, ((pressedkeys & KEY_FORWARD) ? "key_forward_inv.tga" : "key_forward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawpic_aspect_skin(pos + eX * keysize.x * 2, ((pressedkeys & KEY_JUMP) ? "key_jump_inv.tga" : "key_jump.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       pos.y += keysize.y;
+       drawpic_aspect_skin(pos, ((pressedkeys & KEY_LEFT) ? "key_left_inv.tga" : "key_left.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawpic_aspect_skin(pos + eX * keysize.x, ((pressedkeys & KEY_BACKWARD) ? "key_backward_inv.tga" : "key_backward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawpic_aspect_skin(pos + eX * keysize.x * 2, ((pressedkeys & KEY_RIGHT) ? "key_right_inv.tga" : "key_right.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+}
diff --git a/qcsrc/client/hud/panel/quickmenu.qc b/qcsrc/client/hud/panel/quickmenu.qc
new file mode 100644 (file)
index 0000000..128d54a
--- /dev/null
@@ -0,0 +1,3 @@
+// QuickMenu (#23)
+
+#include "../../quickmenu.qc"
diff --git a/qcsrc/client/hud/panel/racetimer.qc b/qcsrc/client/hud/panel/racetimer.qc
new file mode 100644 (file)
index 0000000..1fa216b
--- /dev/null
@@ -0,0 +1,147 @@
+/** Race timer (#8) */
+void HUD_RaceTimer ()
+{
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_racetimer) return;
+               if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
+               if(spectatee_status == -1) return;
+       }
+
+       HUD_Panel_UpdateCvars();
+
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+
+       // always force 4:1 aspect
+       vector newSize = '0 0 0';
+       if(mySize.x/mySize.y > 4)
+       {
+               newSize.x = 4 * mySize.y;
+               newSize.y = mySize.y;
+
+               pos.x = pos.x + (mySize.x - newSize.x) / 2;
+       }
+       else
+       {
+               newSize.y = 1/4 * mySize.x;
+               newSize.x = mySize.x;
+
+               pos.y = pos.y + (mySize.y - newSize.y) / 2;
+       }
+       mySize = newSize;
+
+       float a, t;
+       string s, forcetime;
+
+       if(autocvar__hud_configure)
+       {
+               s = "0:13:37";
+               draw_beginBoldFont();
+               drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.60 0.60 0' * mySize.y), s, '0.60 0.60 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               draw_endBoldFont();
+               s = _("^1Intermediate 1 (+15.42)");
+               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.20 * mySize.y) + eY * 0.60 * mySize.y, s, '1 1 0' * 0.20 * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
+               s = sprintf(_("^1PENALTY: %.1f (%s)"), 2, "missing a checkpoint");
+               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.20 * mySize.y) + eY * 0.80 * mySize.y, s, '1 1 0' * 0.20 * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+       else if(race_checkpointtime)
+       {
+               a = bound(0, 2 - (time - race_checkpointtime), 1);
+               s = "";
+               forcetime = "";
+               if(a > 0) // just hit a checkpoint?
+               {
+                       if(race_checkpoint != 254)
+                       {
+                               if(race_time && race_previousbesttime)
+                                       s = MakeRaceString(race_checkpoint, TIME_DECODE(race_time) - TIME_DECODE(race_previousbesttime), 0, 0, race_previousbestname);
+                               else
+                                       s = MakeRaceString(race_checkpoint, 0, -1, 0, race_previousbestname);
+                               if(race_time)
+                                       forcetime = TIME_ENCODED_TOSTRING(race_time);
+                       }
+               }
+               else
+               {
+                       if(race_laptime && race_nextbesttime && race_nextcheckpoint != 254)
+                       {
+                               a = bound(0, 2 - ((race_laptime + TIME_DECODE(race_nextbesttime)) - (time + TIME_DECODE(race_penaltyaccumulator))), 1);
+                               if(a > 0) // next one?
+                               {
+                                       s = MakeRaceString(race_nextcheckpoint, (time + TIME_DECODE(race_penaltyaccumulator)) - race_laptime, TIME_DECODE(race_nextbesttime), 0, race_nextbestname);
+                               }
+                       }
+               }
+
+               if(s != "" && a > 0)
+               {
+                       drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               }
+
+               if(race_penaltytime)
+               {
+                       a = bound(0, 2 - (time - race_penaltyeventtime), 1);
+                       if(a > 0)
+                       {
+                               s = sprintf(_("^1PENALTY: %.1f (%s)"), race_penaltytime * 0.1, race_penaltyreason);
+                               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.8 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                       }
+               }
+
+               draw_beginBoldFont();
+
+               if(forcetime != "")
+               {
+                       a = bound(0, (time - race_checkpointtime) / 0.5, 1);
+                       drawstring_expanding(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(forcetime, false, '1 1 0' * 0.6 * mySize.y), forcetime, '1 1 0' * 0.6 * mySize.y, '1 1 1', panel_fg_alpha, 0, a);
+               }
+               else
+                       a = 1;
+
+               if(race_laptime && race_checkpoint != 255)
+               {
+                       s = TIME_ENCODED_TOSTRING(TIME_ENCODE(time + TIME_DECODE(race_penaltyaccumulator) - race_laptime));
+                       drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.6 0.6 0' * mySize.y), s, '0.6 0.6 0' * mySize.y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               }
+
+               draw_endBoldFont();
+       }
+       else
+       {
+               if(race_mycheckpointtime)
+               {
+                       a = bound(0, 2 - (time - race_mycheckpointtime), 1);
+                       s = MakeRaceString(race_mycheckpoint, TIME_DECODE(race_mycheckpointdelta), -(race_mycheckpointenemy == ""), race_mycheckpointlapsdelta, race_mycheckpointenemy);
+                       drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               }
+               if(race_othercheckpointtime && race_othercheckpointenemy != "")
+               {
+                       a = bound(0, 2 - (time - race_othercheckpointtime), 1);
+                       s = MakeRaceString(race_othercheckpoint, -TIME_DECODE(race_othercheckpointdelta), -(race_othercheckpointenemy == ""), race_othercheckpointlapsdelta, race_othercheckpointenemy);
+                       drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               }
+
+               if(race_penaltytime && !race_penaltyaccumulator)
+               {
+                       t = race_penaltytime * 0.1 + race_penaltyeventtime;
+                       a = bound(0, (1 + t - time), 1);
+                       if(a > 0)
+                       {
+                               if(time < t)
+                                       s = sprintf(_("^1PENALTY: %.1f (%s)"), (t - time) * 0.1, race_penaltyreason);
+                               else
+                                       s = sprintf(_("^2PENALTY: %.1f (%s)"), 0, race_penaltyreason);
+                               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                       }
+               }
+       }
+}
diff --git a/qcsrc/client/hud/panel/radar.qc b/qcsrc/client/hud/panel/radar.qc
new file mode 100644 (file)
index 0000000..ad3e79c
--- /dev/null
@@ -0,0 +1,384 @@
+// Radar (#6)
+
+float HUD_Radar_Clickable()
+{
+       return hud_panel_radar_mouse && !hud_panel_radar_temp_hidden;
+}
+
+void HUD_Radar_Show_Maximized(bool doshow,float clickable)
+{
+       hud_panel_radar_maximized = doshow;
+       hud_panel_radar_temp_hidden = 0;
+
+       if ( doshow )
+       {
+               if (clickable)
+               {
+                       if(autocvar_hud_cursormode)
+                               setcursormode(1);
+                       hud_panel_radar_mouse = 1;
+               }
+       }
+       else if ( hud_panel_radar_mouse )
+       {
+               hud_panel_radar_mouse = 0;
+               mouseClicked = 0;
+               if(autocvar_hud_cursormode)
+               if(!mv_active)
+                       setcursormode(0);
+       }
+}
+void HUD_Radar_Hide_Maximized()
+{
+       HUD_Radar_Show_Maximized(false,false);
+}
+
+
+float HUD_Radar_InputEvent(float bInputType, float nPrimary, float nSecondary)
+{
+       if(!hud_panel_radar_maximized || !hud_panel_radar_mouse ||
+               autocvar__hud_configure || mv_active)
+               return false;
+
+       if(bInputType == 3)
+       {
+               mousepos_x = nPrimary;
+               mousepos_y = nSecondary;
+               return true;
+       }
+
+       if(nPrimary == K_MOUSE1)
+       {
+               if(bInputType == 0) // key pressed
+                       mouseClicked |= S_MOUSE1;
+               else if(bInputType == 1) // key released
+                       mouseClicked -= (mouseClicked & S_MOUSE1);
+       }
+       else if(nPrimary == K_MOUSE2)
+       {
+               if(bInputType == 0) // key pressed
+                       mouseClicked |= S_MOUSE2;
+               else if(bInputType == 1) // key released
+                       mouseClicked -= (mouseClicked & S_MOUSE2);
+       }
+       else if ( nPrimary == K_ESCAPE && bInputType == 0 )
+       {
+               HUD_Radar_Hide_Maximized();
+       }
+       else
+       {
+               // allow console/use binds to work without hiding the map
+               string con_keys;
+               float keys;
+               float i;
+               con_keys = strcat(findkeysforcommand("toggleconsole", 0)," ",findkeysforcommand("+use", 0)) ;
+               keys = tokenize(con_keys); // findkeysforcommand returns data for this
+               for (i = 0; i < keys; ++i)
+               {
+                       if(nPrimary == stof(argv(i)))
+                               return false;
+               }
+
+               if ( getstati(STAT_HEALTH) <= 0 )
+               {
+                       // Show scoreboard
+                       if ( bInputType < 2 )
+                       {
+                               con_keys = findkeysforcommand("+showscores", 0);
+                               keys = tokenize(con_keys);
+                               for (i = 0; i < keys; ++i)
+                               {
+                                       if ( nPrimary == stof(argv(i)) )
+                                       {
+                                               hud_panel_radar_temp_hidden = bInputType == 0;
+                                               return false;
+                                       }
+                               }
+                       }
+               }
+               else if ( bInputType == 0 )
+                       HUD_Radar_Hide_Maximized();
+
+               return false;
+       }
+
+       return true;
+}
+
+void HUD_Radar_Mouse()
+{
+       if ( !hud_panel_radar_mouse ) return;
+       if(mv_active) return;
+
+       if ( intermission )
+       {
+               HUD_Radar_Hide_Maximized();
+               return;
+       }
+
+       if(mouseClicked & S_MOUSE2)
+       {
+               HUD_Radar_Hide_Maximized();
+               return;
+       }
+
+       if(!autocvar_hud_cursormode)
+       {
+               mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
+
+               mousepos_x = bound(0, mousepos_x, vid_conwidth);
+               mousepos_y = bound(0, mousepos_y, vid_conheight);
+       }
+
+       HUD_Panel_UpdateCvars();
+
+
+       panel_size = autocvar_hud_panel_radar_maximized_size;
+       panel_size_x = bound(0.2, panel_size_x, 1) * vid_conwidth;
+       panel_size_y = bound(0.2, panel_size_y, 1) * vid_conheight;
+       panel_pos_x = (vid_conwidth - panel_size_x) / 2;
+       panel_pos_y = (vid_conheight - panel_size_y) / 2;
+
+       if(mouseClicked & S_MOUSE1)
+       {
+               // click outside
+               if ( mousepos_x < panel_pos_x || mousepos_x > panel_pos_x + panel_size_x ||
+                        mousepos_y < panel_pos_y || mousepos_y > panel_pos_y + panel_size_y )
+               {
+                       HUD_Radar_Hide_Maximized();
+                       return;
+               }
+               vector pos = teamradar_texcoord_to_3dcoord(teamradar_2dcoord_to_texcoord(mousepos),view_origin_z);
+               localcmd(sprintf("cmd ons_spawn %f %f %f",pos_x,pos_y,pos_z));
+
+               HUD_Radar_Hide_Maximized();
+               return;
+       }
+
+
+       const vector cursor_size = '32 32 0';
+       drawpic(mousepos-'8 4 0', strcat("gfx/menu/", autocvar_menu_skin, "/cursor.tga"), cursor_size, '1 1 1', 0.8, DRAWFLAG_NORMAL);
+}
+
+void HUD_Radar()
+{
+       if (!autocvar__hud_configure)
+       {
+               if (hud_panel_radar_maximized)
+               {
+                       if (!hud_draw_maximized) return;
+               }
+               else
+               {
+                       if (autocvar_hud_panel_radar == 0) return;
+                       if (autocvar_hud_panel_radar != 2 && !teamplay) return;
+                       if(radar_panel_modified)
+                       {
+                               panel.update_time = time; // forces reload of panel attributes
+                               radar_panel_modified = false;
+                       }
+               }
+       }
+
+       if ( hud_panel_radar_temp_hidden )
+               return;
+
+       HUD_Panel_UpdateCvars();
+
+       float f = 0;
+
+       if (hud_panel_radar_maximized && !autocvar__hud_configure)
+       {
+               panel_size = autocvar_hud_panel_radar_maximized_size;
+               panel_size.x = bound(0.2, panel_size.x, 1) * vid_conwidth;
+               panel_size.y = bound(0.2, panel_size.y, 1) * vid_conheight;
+               panel_pos.x = (vid_conwidth - panel_size.x) / 2;
+               panel_pos.y = (vid_conheight - panel_size.y) / 2;
+
+               string panel_bg;
+               panel_bg = strcat(hud_skin_path, "/border_default"); // always use the default border when maximized
+               if(precache_pic(panel_bg) == "")
+                       panel_bg = "gfx/hud/default/border_default"; // fallback
+               if(!radar_panel_modified && panel_bg != panel.current_panel_bg)
+                       radar_panel_modified = true;
+               if(panel.current_panel_bg)
+                       strunzone(panel.current_panel_bg);
+               panel.current_panel_bg = strzone(panel_bg);
+
+               switch(hud_panel_radar_maximized_zoommode)
+               {
+                       default:
+                       case 0:
+                               f = current_zoomfraction;
+                               break;
+                       case 1:
+                               f = 1 - current_zoomfraction;
+                               break;
+                       case 2:
+                               f = 0;
+                               break;
+                       case 3:
+                               f = 1;
+                               break;
+               }
+
+               switch(hud_panel_radar_maximized_rotation)
+               {
+                       case 0:
+                               teamradar_angle = view_angles.y - 90;
+                               break;
+                       default:
+                               teamradar_angle = 90 * hud_panel_radar_maximized_rotation;
+                               break;
+               }
+       }
+       if (!hud_panel_radar_maximized && !autocvar__hud_configure)
+       {
+               switch(hud_panel_radar_zoommode)
+               {
+                       default:
+                       case 0:
+                               f = current_zoomfraction;
+                               break;
+                       case 1:
+                               f = 1 - current_zoomfraction;
+                               break;
+                       case 2:
+                               f = 0;
+                               break;
+                       case 3:
+                               f = 1;
+                               break;
+               }
+
+               switch(hud_panel_radar_rotation)
+               {
+                       case 0:
+                               teamradar_angle = view_angles.y - 90;
+                               break;
+                       default:
+                               teamradar_angle = 90 * hud_panel_radar_rotation;
+                               break;
+               }
+       }
+
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+
+       int color2;
+       entity tm;
+       float scale2d, normalsize, bigsize;
+
+       teamradar_origin2d = pos + 0.5 * mySize;
+       teamradar_size2d = mySize;
+
+       if(minimapname == "")
+               return;
+
+       teamradar_loadcvars();
+
+       scale2d = vlen_maxnorm2d(mi_picmax - mi_picmin);
+       teamradar_size2d = mySize;
+
+       teamradar_extraclip_mins = teamradar_extraclip_maxs = '0 0 0'; // we always center
+
+       // pixels per world qu to match the teamradar_size2d_x range in the longest dimension
+       if((hud_panel_radar_rotation == 0 && !hud_panel_radar_maximized) || (hud_panel_radar_maximized_rotation == 0 && hud_panel_radar_maximized))
+       {
+               // max-min distance must fit the radar in any rotation
+               bigsize = vlen_minnorm2d(teamradar_size2d) * scale2d / (1.05 * vlen2d(mi_scale));
+       }
+       else
+       {
+               vector c0, c1, c2, c3, span;
+               c0 = rotate(mi_min, teamradar_angle * DEG2RAD);
+               c1 = rotate(mi_max, teamradar_angle * DEG2RAD);
+               c2 = rotate('1 0 0' * mi_min.x + '0 1 0' * mi_max.y, teamradar_angle * DEG2RAD);
+               c3 = rotate('1 0 0' * mi_max.x + '0 1 0' * mi_min.y, teamradar_angle * DEG2RAD);
+               span = '0 0 0';
+               span.x = max(c0_x, c1_x, c2_x, c3_x) - min(c0_x, c1_x, c2_x, c3_x);
+               span.y = max(c0_y, c1_y, c2_y, c3_y) - min(c0_y, c1_y, c2_y, c3_y);
+
+               // max-min distance must fit the radar in x=x, y=y
+               bigsize = min(
+                       teamradar_size2d.x * scale2d / (1.05 * span.x),
+                       teamradar_size2d.y * scale2d / (1.05 * span.y)
+               );
+       }
+
+       normalsize = vlen_maxnorm2d(teamradar_size2d) * scale2d / hud_panel_radar_scale;
+       if(bigsize > normalsize)
+               normalsize = bigsize;
+
+       teamradar_size =
+                 f * bigsize
+               + (1 - f) * normalsize;
+       teamradar_origin3d_in_texcoord = teamradar_3dcoord_to_texcoord(
+                 f * mi_center
+               + (1 - f) * view_origin);
+
+       drawsetcliparea(
+               pos.x,
+               pos.y,
+               mySize.x,
+               mySize.y
+       );
+
+       draw_teamradar_background(hud_panel_radar_foreground_alpha);
+
+       for(tm = world; (tm = find(tm, classname, "radarlink")); )
+               draw_teamradar_link(tm.origin, tm.velocity, tm.team);
+
+       vector coord;
+       vector brightcolor;
+       for(tm = world; (tm = findflags(tm, teamradar_icon, 0xFFFFFF)); )
+       {
+               if ( hud_panel_radar_mouse )
+               if ( tm.health > 0 )
+               if ( tm.team == myteam+1 )
+               {
+                       coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(tm.origin));
+                       if ( vlen(mousepos-coord) < 8 )
+                       {
+                               brightcolor_x = min(1,tm.teamradar_color_x*1.5);
+                               brightcolor_y = min(1,tm.teamradar_color_y*1.5);
+                               brightcolor_z = min(1,tm.teamradar_color_z*1.5);
+                               drawpic(coord - '8 8 0', "gfx/teamradar_icon_glow", '16 16 0', brightcolor, panel_fg_alpha, 0);
+                       }
+               }
+               entity icon = RadarIcons_from(tm.teamradar_icon);
+               draw_teamradar_icon(tm.origin, icon, tm, spritelookupcolor(tm, icon.netname, tm.teamradar_color), panel_fg_alpha);
+       }
+       for(tm = world; (tm = find(tm, classname, "entcs_receiver")); )
+       {
+               color2 = GetPlayerColor(tm.sv_entnum);
+               //if(color == NUM_SPECTATOR || color == color2)
+                       draw_teamradar_player(tm.origin, tm.angles, Team_ColorRGB(color2));
+       }
+       draw_teamradar_player(view_origin, view_angles, '1 1 1');
+
+       drawresetcliparea();
+
+       if ( hud_panel_radar_mouse )
+       {
+               string message = "Click to select teleport destination";
+
+               if ( getstati(STAT_HEALTH) <= 0 )
+               {
+                       message = "Click to select spawn location";
+               }
+
+               drawcolorcodedstring(pos + '0.5 0 0' * (mySize_x - stringwidth(message, true, hud_fontsize)) - '0 1 0' * hud_fontsize_y * 2,
+                                                        message, hud_fontsize, hud_panel_radar_foreground_alpha, DRAWFLAG_NORMAL);
+
+               hud_panel_radar_bottom = pos_y + mySize_y + hud_fontsize_y;
+       }
+}
diff --git a/qcsrc/client/hud/panel/score.qc b/qcsrc/client/hud/panel/score.qc
new file mode 100644 (file)
index 0000000..dd3000c
--- /dev/null
@@ -0,0 +1,305 @@
+// Score (#7)
+
+void HUD_UpdatePlayerTeams();
+void HUD_Score_Rankings(vector pos, vector mySize, entity me)
+{
+       float score;
+       entity tm = world, pl;
+       int SCOREPANEL_MAX_ENTRIES = 6;
+       float SCOREPANEL_ASPECTRATIO = 2;
+       int entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize.y/mySize.x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
+       vector fontsize = '1 1 0' * (mySize.y/entries);
+
+       vector rgb, score_color;
+       rgb = '1 1 1';
+       score_color = '1 1 1';
+
+       float name_size = mySize.x*0.75;
+       float spacing_size = mySize.x*0.04;
+       const float highlight_alpha = 0.2;
+       int i = 0, first_pl = 0;
+       bool me_printed = false;
+       string s;
+       if (autocvar__hud_configure)
+       {
+               float players_per_team = 0;
+               if (team_count)
+               {
+                       // show team scores in the first line
+                       float score_size = mySize.x / team_count;
+                       players_per_team = max(2, ceil((entries - 1) / team_count));
+                       for(i=0; i<team_count; ++i) {
+                               if (i == floor((entries - 2) / players_per_team) || (entries == 1 && i == 0))
+                                       HUD_Panel_DrawHighlight(pos + eX * score_size * i, eX * score_size + eY * fontsize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring_aspect(pos + eX * score_size * i, ftos(175 - 23*i), eX * score_size + eY * fontsize.y, Team_ColorRGB(ColorByTeam(i)) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       }
+                       first_pl = 1;
+                       pos.y += fontsize.y;
+               }
+               score = 10 + SCOREPANEL_MAX_ENTRIES * 3;
+               for (i=first_pl; i<entries; ++i)
+               {
+                       //simulate my score is lower than all displayed players,
+                       //so that I don't appear at all showing pure rankings.
+                       //This is to better show the difference between the 2 ranking views
+                       if (i == entries-1 && autocvar_hud_panel_score_rankings == 1)
+                       {
+                               rgb = '1 1 0';
+                               drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                               s = GetPlayerName(player_localnum);
+                               score = 7;
+                       }
+                       else
+                       {
+                               s = sprintf(_("Player %d"), i + 1 - first_pl);
+                               score -= 3;
+                       }
+
+                       if (team_count)
+                               score_color = Team_ColorRGB(ColorByTeam(floor((i - first_pl) / players_per_team))) * 0.8;
+                       s = textShortenToWidth(s, name_size, fontsize, stringwidth_colors);
+                       drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring(pos + eX * (name_size + spacing_size), ftos(score), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       pos.y += fontsize.y;
+               }
+               return;
+       }
+
+       if (!scoreboard_fade_alpha) // the scoreboard too calls HUD_UpdatePlayerTeams
+               HUD_UpdatePlayerTeams();
+       if (team_count)
+       {
+               // show team scores in the first line
+               float score_size = mySize.x / team_count;
+               for(tm = teams.sort_next; tm; tm = tm.sort_next) {
+                       if(tm.team == NUM_SPECTATOR)
+                               continue;
+                       if (tm.team == myteam)
+                               drawfill(pos + eX * score_size * i, eX * score_size + eY * fontsize.y, '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores[ts_primary])), eX * score_size + eY * fontsize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       ++i;
+               }
+               first_pl = 1;
+               pos.y += fontsize.y;
+               tm = teams.sort_next;
+       }
+       i = first_pl;
+
+       do
+       for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
+       {
+               if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
+                       continue;
+
+               if (i == entries-1 && !me_printed && pl != me)
+               if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
+               {
+                       for (pl = me.sort_next; pl; pl = pl.sort_next)
+                               if (pl.team != NUM_SPECTATOR)
+                                       break;
+
+                       if (pl)
+                               rgb = '1 1 0'; //not last but not among the leading players: yellow
+                       else
+                               rgb = '1 0 0'; //last: red
+                       pl = me;
+               }
+
+               if (pl == me)
+               {
+                       if (i == first_pl)
+                               rgb = '0 1 0'; //first: green
+                       me_printed = true;
+                       drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
+               if (team_count)
+                       score_color = Team_ColorRGB(pl.team) * 0.8;
+               s = textShortenToWidth(GetPlayerName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
+               drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores[ps_primary])), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+               pos.y += fontsize.y;
+               ++i;
+       }
+       while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
+}
+
+void HUD_Score()
+{
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_score) return;
+               if(spectatee_status == -1 && (gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
+       }
+
+       HUD_Panel_UpdateCvars();
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+
+       float score, distribution = 0;
+       string sign;
+       vector distribution_color;
+       entity tm, pl, me;
+
+       me = playerslots[current_player];
+
+       if((scores_flags[ps_primary] & SFL_TIME) && !teamplay) { // race/cts record display on HUD
+               string timer, distrtimer;
+
+               pl = players.sort_next;
+               if(pl == me)
+                       pl = pl.sort_next;
+               if(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)
+                       if(pl.scores[ps_primary] == 0)
+                               pl = world;
+
+               score = me.(scores[ps_primary]);
+               timer = TIME_ENCODED_TOSTRING(score);
+
+               draw_beginBoldFont();
+               if (pl && ((!(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)) || score)) {
+                       // distribution display
+                       distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
+
+                       distrtimer = ftos_decimals(fabs(distribution/pow(10, TIME_DECIMALS)), TIME_DECIMALS);
+
+                       if (distribution <= 0) {
+                               distribution_color = '0 1 0';
+                               sign = "-";
+                       }
+                       else {
+                               distribution_color = '1 0 0';
+                               sign = "+";
+                       }
+                       drawstring_aspect(pos + eX * 0.75 * mySize.x, strcat(sign, distrtimer), eX * 0.25 * mySize.x + eY * (1/3) * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
+               // race record display
+               if (distribution <= 0)
+                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(pos, timer, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               draw_endBoldFont();
+       } else if (!teamplay) { // non-teamgames
+               if ((spectatee_status == -1 && !autocvar__hud_configure) || autocvar_hud_panel_score_rankings)
+               {
+                       HUD_Score_Rankings(pos, mySize, me);
+                       return;
+               }
+               // me vector := [team/connected frags id]
+               pl = players.sort_next;
+               if(pl == me)
+                       pl = pl.sort_next;
+
+               if(autocvar__hud_configure)
+                       distribution = 42;
+               else if(pl)
+                       distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
+               else
+                       distribution = 0;
+
+               score = me.(scores[ps_primary]);
+               if(autocvar__hud_configure)
+                       score = 123;
+
+               if(distribution >= 5)
+                       distribution_color = eY;
+               else if(distribution >= 0)
+                       distribution_color = '1 1 1';
+               else if(distribution >= -5)
+                       distribution_color = '1 1 0';
+               else
+                       distribution_color = eX;
+
+               string distribution_str;
+               distribution_str = ftos(distribution);
+               draw_beginBoldFont();
+               if (distribution >= 0)
+               {
+                       if (distribution > 0)
+                               distribution_str = strcat("+", distribution_str);
+                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
+               drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(pos + eX * 0.75 * mySize.x, distribution_str, eX * 0.25 * mySize.x + eY * (1/3) * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+               draw_endBoldFont();
+       } else { // teamgames
+               float row, column, rows = 0, columns = 0;
+               vector offset = '0 0 0';
+               vector score_pos, score_size; //for scores other than myteam
+               if(autocvar_hud_panel_score_rankings)
+               {
+                       HUD_Score_Rankings(pos, mySize, me);
+                       return;
+               }
+               if(spectatee_status == -1)
+               {
+                       rows = HUD_GetRowCount(team_count, mySize, 3);
+                       columns = ceil(team_count/rows);
+                       score_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
+
+                       float newSize;
+                       if(score_size.x/score_size.y > 3)
+                       {
+                               newSize = 3 * score_size.y;
+                               offset.x = score_size.x - newSize;
+                               pos.x += offset.x/2;
+                               score_size.x = newSize;
+                       }
+                       else
+                       {
+                               newSize = 1/3 * score_size.x;
+                               offset.y = score_size.y - newSize;
+                               pos.y += offset.y/2;
+                               score_size.y = newSize;
+                       }
+               }
+               else
+                       score_size = eX * mySize.x*(1/4) + eY * mySize.y*(1/3);
+
+               float max_fragcount;
+               max_fragcount = -99;
+               draw_beginBoldFont();
+               row = column = 0;
+               for(tm = teams.sort_next; tm; tm = tm.sort_next) {
+                       if(tm.team == NUM_SPECTATOR)
+                               continue;
+                       score = tm.(teamscores[ts_primary]);
+                       if(autocvar__hud_configure)
+                               score = 123;
+
+                       if (score > max_fragcount)
+                               max_fragcount = score;
+
+                       if (spectatee_status == -1)
+                       {
+                               score_pos = pos + eX * column * (score_size.x + offset.x) + eY * row * (score_size.y + offset.y);
+                               if (max_fragcount == score)
+                                       HUD_Panel_DrawHighlight(score_pos, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring_aspect(score_pos, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                               ++row;
+                               if(row >= rows)
+                               {
+                                       row = 0;
+                                       ++column;
+                               }
+                       }
+                       else if(tm.team == myteam) {
+                               if (max_fragcount == score)
+                                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       } else {
+                               if (max_fragcount == score)
+                                       HUD_Panel_DrawHighlight(pos + eX * 0.75 * mySize.x + eY * (1/3) * rows * mySize.y, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring_aspect(pos + eX * 0.75 * mySize.x + eY * (1/3) * rows * mySize.y, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                               ++rows;
+                       }
+               }
+               draw_endBoldFont();
+       }
+}
diff --git a/qcsrc/client/hud/panel/timer.qc b/qcsrc/client/hud/panel/timer.qc
new file mode 100644 (file)
index 0000000..f709b41
--- /dev/null
@@ -0,0 +1,56 @@
+void HUD_Timer()
+{
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_timer) return;
+       }
+
+       HUD_Panel_UpdateCvars();
+
+       draw_beginBoldFont();
+
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+
+       string timer;
+       float timelimit, elapsedTime, timeleft, minutesLeft;
+
+       timelimit = getstatf(STAT_TIMELIMIT);
+
+       timeleft = max(0, timelimit * 60 + STAT(GAMESTARTTIME) - time);
+       timeleft = ceil(timeleft);
+
+       minutesLeft = floor(timeleft / 60);
+
+       vector timer_color;
+       if(minutesLeft >= 5 || warmup_stage || timelimit == 0) //don't use red or yellow in warmup or when there is no timelimit
+               timer_color = '1 1 1'; //white
+       else if(minutesLeft >= 1)
+               timer_color = '1 1 0'; //yellow
+       else
+               timer_color = '1 0 0'; //red
+
+       if (autocvar_hud_panel_timer_increment || timelimit == 0 || warmup_stage) {
+               if (time < STAT(GAMESTARTTIME)) {
+                       //while restart is still active, show 00:00
+                       timer = seconds_tostring(0);
+               } else {
+                       elapsedTime = floor(time - STAT(GAMESTARTTIME)); //127
+                       timer = seconds_tostring(elapsedTime);
+               }
+       } else {
+               timer = seconds_tostring(timeleft);
+       }
+
+       drawstring_aspect(pos, timer, mySize, timer_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+
+       draw_endBoldFont();
+}
diff --git a/qcsrc/client/hud/panel/vote.qc b/qcsrc/client/hud/panel/vote.qc
new file mode 100644 (file)
index 0000000..5f286b2
--- /dev/null
@@ -0,0 +1,137 @@
+/** Vote window (#9) */
+void HUD_Vote()
+{
+       if(autocvar_cl_allow_uid2name == -1 && (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
+       {
+               vote_active = 1;
+               if (autocvar__hud_configure)
+               {
+                       vote_yescount = 0;
+                       vote_nocount = 0;
+                       LOG_INFO(_("^1You must answer before entering hud configure mode\n"));
+                       cvar_set("_hud_configure", "0");
+               }
+               if(vote_called_vote)
+                       strunzone(vote_called_vote);
+               vote_called_vote = strzone(_("^2Name ^7instead of \"^1Anonymous player^7\" in stats"));
+               uid2name_dialog = 1;
+       }
+
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_vote) return;
+
+               panel_fg_alpha = autocvar_hud_panel_fg_alpha;
+               panel_bg_alpha_str = autocvar_hud_panel_vote_bg_alpha;
+
+               if(panel_bg_alpha_str == "") {
+                       panel_bg_alpha_str = ftos(autocvar_hud_panel_bg_alpha);
+               }
+               panel_bg_alpha = stof(panel_bg_alpha_str);
+       }
+       else
+       {
+               vote_yescount = 3;
+               vote_nocount = 2;
+               vote_needed = 4;
+       }
+
+       string s;
+       float a;
+       if(vote_active != vote_prev) {
+               vote_change = time;
+               vote_prev = vote_active;
+       }
+
+       if(vote_active || autocvar__hud_configure)
+               vote_alpha = bound(0, (time - vote_change) * 2, 1);
+       else
+               vote_alpha = bound(0, 1 - (time - vote_change) * 2, 1);
+
+       if(!vote_alpha)
+               return;
+
+       HUD_Panel_UpdateCvars();
+
+       if(uid2name_dialog)
+       {
+               panel_pos = eX * 0.3 * vid_conwidth + eY * 0.1 * vid_conheight;
+               panel_size = eX * 0.4 * vid_conwidth + eY * 0.3 * vid_conheight;
+       }
+
+    // these must be below above block
+       vector pos, mySize;
+       pos = panel_pos;
+       mySize = panel_size;
+
+       a = vote_alpha * (vote_highlighted ? autocvar_hud_panel_vote_alreadyvoted_alpha : 1);
+       HUD_Panel_DrawBg(a);
+       a = panel_fg_alpha * a;
+
+       if(panel_bg_padding)
+       {
+               pos += '1 1 0' * panel_bg_padding;
+               mySize -= '2 2 0' * panel_bg_padding;
+       }
+
+       // always force 3:1 aspect
+       vector newSize = '0 0 0';
+       if(mySize.x/mySize.y > 3)
+       {
+               newSize.x = 3 * mySize.y;
+               newSize.y = mySize.y;
+
+               pos.x = pos.x + (mySize.x - newSize.x) / 2;
+       }
+       else
+       {
+               newSize.y = 1/3 * mySize.x;
+               newSize.x = mySize.x;
+
+               pos.y = pos.y + (mySize.y - newSize.y) / 2;
+       }
+       mySize = newSize;
+
+       s = _("A vote has been called for:");
+       if(uid2name_dialog)
+               s = _("Allow servers to store and display your name?");
+       drawstring_aspect(pos, s, eX * mySize.x + eY * (2/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+       s = textShortenToWidth(vote_called_vote, mySize.x, '1 1 0' * mySize.y * (1/8), stringwidth_colors);
+       if(autocvar__hud_configure)
+               s = _("^1Configure the HUD");
+       drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize.y, s, eX * mySize.x + eY * (1.75/8) * mySize.y, a, DRAWFLAG_NORMAL);
+
+       // print the yes/no counts
+    s = sprintf(_("Yes (%s): %d"), getcommandkey("vyes", "vyes"), vote_yescount);
+       drawstring_aspect(pos + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '0 1 0', a, DRAWFLAG_NORMAL);
+    s = sprintf(_("No (%s): %d"), getcommandkey("vno", "vno"), vote_nocount);
+       drawstring_aspect(pos + eX * 0.5 * mySize.x + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '1 0 0', a, DRAWFLAG_NORMAL);
+
+       // draw the progress bar backgrounds
+       drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_back", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+
+       // draw the highlights
+       if(vote_highlighted == 1) {
+               drawsetcliparea(pos.x, pos.y, mySize.x * 0.5, mySize.y);
+               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+       }
+       else if(vote_highlighted == -1) {
+               drawsetcliparea(pos.x + 0.5 * mySize.x, pos.y, mySize.x * 0.5, mySize.y);
+               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+       }
+
+       // draw the progress bars
+       if(vote_yescount && vote_needed)
+       {
+               drawsetcliparea(pos.x, pos.y, mySize.x * 0.5 * (vote_yescount/vote_needed), mySize.y);
+               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+       }
+
+       if(vote_nocount && vote_needed)
+       {
+               drawsetcliparea(pos.x + mySize.x - mySize.x * 0.5 * (vote_nocount/vote_needed), pos.y, mySize.x * 0.5, mySize.y);
+               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+       }
+
+       drawresetcliparea();
+}
diff --git a/qcsrc/client/hud/panel/weapons.qc b/qcsrc/client/hud/panel/weapons.qc
new file mode 100644 (file)
index 0000000..4d1d722
--- /dev/null
@@ -0,0 +1,509 @@
+// Weapon icons (#0)
+
+entity weaponorder[Weapons_MAX];
+void weaponorder_swap(int i, int j, entity pass)
+{
+       entity h = weaponorder[i];
+       weaponorder[i] = weaponorder[j];
+       weaponorder[j] = h;
+}
+
+string weaponorder_cmp_str;
+int weaponorder_cmp(int i, int j, entity pass)
+{
+       int ai, aj;
+       ai = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[i].weapon), 0);
+       aj = strstrofs(weaponorder_cmp_str, sprintf(" %d ", weaponorder[j].weapon), 0);
+       return aj - ai; // the string is in REVERSE order (higher prio at the right is what we want, but higher prio first is the string)
+}
+
+void HUD_Weapons()
+{
+       SELFPARAM();
+       // declarations
+       WepSet weapons_stat = WepSet_GetFromStat();
+       int i;
+       float f, a;
+       float screen_ar;
+       vector center = '0 0 0';
+       int weapon_count, weapon_id;
+       int row, column, rows = 0, columns = 0;
+       bool vertical_order = true;
+       float aspect = autocvar_hud_panel_weapons_aspect;
+
+       float timeout = autocvar_hud_panel_weapons_timeout;
+       float timein_effect_length = autocvar_hud_panel_weapons_timeout_speed_in; //? 0.375 : 0);
+       float timeout_effect_length = autocvar_hud_panel_weapons_timeout_speed_out; //? 0.75 : 0);
+
+       vector barsize = '0 0 0', baroffset = '0 0 0';
+       vector ammo_color = '1 0 1';
+       float ammo_alpha = 1;
+
+       float when = max(1, autocvar_hud_panel_weapons_complainbubble_time);
+       float fadetime = max(0, autocvar_hud_panel_weapons_complainbubble_fadetime);
+
+       vector weapon_pos, weapon_size = '0 0 0';
+       vector color;
+
+       // check to see if we want to continue
+       if(hud != HUD_NORMAL) return;
+
+       if(!autocvar__hud_configure)
+       {
+               if((!autocvar_hud_panel_weapons) || (spectatee_status == -1))
+                       return;
+               if(timeout && time >= weapontime + timeout + timeout_effect_length)
+               if(autocvar_hud_panel_weapons_timeout_effect == 3 || (autocvar_hud_panel_weapons_timeout_effect == 1 && !(autocvar_hud_panel_weapons_timeout_fadebgmin + autocvar_hud_panel_weapons_timeout_fadefgmin)))
+               {
+                       weaponprevtime = time;
+                       return;
+               }
+       }
+
+       // update generic hud functions
+       HUD_Panel_UpdateCvars();
+
+       // figure out weapon order (how the weapons are sorted) // TODO make this configurable
+       if(weaponorder_bypriority != autocvar_cl_weaponpriority || !weaponorder[0])
+       {
+               int weapon_cnt;
+               if(weaponorder_bypriority)
+                       strunzone(weaponorder_bypriority);
+               if(weaponorder_byimpulse)
+                       strunzone(weaponorder_byimpulse);
+
+               weaponorder_bypriority = strzone(autocvar_cl_weaponpriority);
+               weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(W_FixWeaponOrder_ForceComplete(W_NumberWeaponOrder(weaponorder_bypriority))));
+               weaponorder_cmp_str = strcat(" ", weaponorder_byimpulse, " ");
+
+               weapon_cnt = 0;
+               for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+               {
+                       setself(get_weaponinfo(i));
+                       if(self.impulse >= 0)
+                       {
+                               weaponorder[weapon_cnt] = self;
+                               ++weapon_cnt;
+                       }
+               }
+               for(i = weapon_cnt; i < Weapons_MAX; ++i)
+                       weaponorder[i] = world;
+               heapsort(weapon_cnt, weaponorder_swap, weaponorder_cmp, world);
+
+               weaponorder_cmp_str = string_null;
+       }
+
+       if(!autocvar_hud_panel_weapons_complainbubble || autocvar__hud_configure || time - complain_weapon_time >= when + fadetime)
+               complain_weapon = 0;
+
+       if(autocvar__hud_configure)
+       {
+               if(!weapons_stat)
+                       for(i = WEP_FIRST; i <= WEP_LAST; i += floor((WEP_LAST-WEP_FIRST)/5))
+                               weapons_stat |= WepSet_FromWeapon(i);
+
+               #if 0
+               /// debug code
+               if(cvar("wep_add"))
+               {
+                       weapons_stat = '0 0 0';
+                       float countw = 1 + floor((floor(time * cvar("wep_add"))) % (Weapons_COUNT - 1));
+                       for(i = WEP_FIRST; i <= countw; ++i)
+                               weapons_stat |= WepSet_FromWeapon(i);
+               }
+               #endif
+       }
+
+       // determine which weapons are going to be shown
+       if (autocvar_hud_panel_weapons_onlyowned)
+       {
+               if(autocvar__hud_configure)
+               {
+                       if(menu_enabled != 2)
+                               HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
+               }
+
+               // do we own this weapon?
+               weapon_count = 0;
+               for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
+                       if((weapons_stat & WepSet_FromWeapon(weaponorder[i].weapon)) || (weaponorder[i].weapon == complain_weapon))
+                               ++weapon_count;
+
+
+               // might as well commit suicide now, no reason to live ;)
+               if (weapon_count == 0)
+                       return;
+
+               vector old_panel_size = panel_size;
+               vector padded_panel_size = panel_size - '2 2 0' * panel_bg_padding;
+
+               // get the all-weapons layout
+               int nHidden = 0;
+               WepSet weapons_stat = WepSet_GetFromStat();
+               for (int i = WEP_FIRST; i <= WEP_LAST; ++i) {
+                       WepSet weapons_wep = WepSet_FromWeapon(i);
+                       if (weapons_stat & weapons_wep) continue;
+                       Weapon w = get_weaponinfo(i);
+                       if (w.spawnflags & WEP_FLAG_MUTATORBLOCKED) nHidden += 1;
+               }
+               vector table_size = HUD_GetTableSize_BestItemAR((Weapons_COUNT - 1) - nHidden, padded_panel_size, aspect);
+               columns = table_size.x;
+               rows = table_size.y;
+               weapon_size.x = padded_panel_size.x / columns;
+               weapon_size.y = padded_panel_size.y / rows;
+
+               // NOTE: although weapons should aways look the same even if onlyowned is enabled,
+               // we enlarge them a bit when possible to better match the desired aspect ratio
+               if(padded_panel_size.x / padded_panel_size.y < aspect)
+               {
+                       // maximum number of rows that allows to display items with the desired aspect ratio
+                       int max_rows = floor(padded_panel_size.y / (weapon_size.x / aspect));
+                       columns = min(columns, ceil(weapon_count / max_rows));
+                       rows = ceil(weapon_count / columns);
+                       weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
+                       weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
+                       vertical_order = false;
+               }
+               else
+               {
+                       int max_columns = floor(padded_panel_size.x / (weapon_size.y * aspect));
+                       rows = min(rows, ceil(weapon_count / max_columns));
+                       columns = ceil(weapon_count / rows);
+                       weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
+                       weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
+                       vertical_order = true;
+               }
+
+               // reduce size of the panel
+               panel_size.x = columns * weapon_size.x;
+               panel_size.y = rows * weapon_size.y;
+               panel_size += '2 2 0' * panel_bg_padding;
+
+               // center the resized panel, or snap it to the screen edge when close enough
+               if(panel_pos.x > vid_conwidth * 0.001)
+               {
+                       if(panel_pos.x + old_panel_size.x > vid_conwidth * 0.999)
+                               panel_pos.x += old_panel_size.x - panel_size.x;
+                       else
+                               panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
+               }
+               else if(old_panel_size.x > vid_conwidth * 0.999)
+                       panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
+
+               if(panel_pos.y > vid_conheight * 0.001)
+               {
+                       if(panel_pos.y + old_panel_size.y > vid_conheight * 0.999)
+                               panel_pos.y += old_panel_size.y - panel_size.y;
+                       else
+                               panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
+               }
+               else if(old_panel_size.y > vid_conheight * 0.999)
+                       panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
+       }
+       else
+               weapon_count = (Weapons_COUNT - 1);
+
+       // animation for fading in/out the panel respectively when not in use
+       if(!autocvar__hud_configure)
+       {
+               if (timeout && time >= weapontime + timeout) // apply timeout effect if needed
+               {
+                       f = bound(0, (time - (weapontime + timeout)) / timeout_effect_length, 1);
+
+                       // fade the panel alpha
+                       if(autocvar_hud_panel_weapons_timeout_effect == 1)
+                       {
+                               panel_bg_alpha *= (autocvar_hud_panel_weapons_timeout_fadebgmin * f + (1 - f));
+                               panel_fg_alpha *= (autocvar_hud_panel_weapons_timeout_fadefgmin * f + (1 - f));
+                       }
+                       else if(autocvar_hud_panel_weapons_timeout_effect == 3)
+                       {
+                               panel_bg_alpha *= (1 - f);
+                               panel_fg_alpha *= (1 - f);
+                       }
+
+                       // move the panel off the screen
+                       if (autocvar_hud_panel_weapons_timeout_effect == 2 || autocvar_hud_panel_weapons_timeout_effect == 3)
+                       {
+                               f *= f; // for a cooler movement
+                               center.x = panel_pos.x + panel_size.x/2;
+                               center.y = panel_pos.y + panel_size.y/2;
+                               screen_ar = vid_conwidth/vid_conheight;
+                               if (center.x/center.y < screen_ar) //bottom left
+                               {
+                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
+                                               panel_pos.y += f * (vid_conheight - panel_pos.y);
+                                       else //left
+                                               panel_pos.x -= f * (panel_pos.x + panel_size.x);
+                               }
+                               else //top right
+                               {
+                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //right
+                                               panel_pos.x += f * (vid_conwidth - panel_pos.x);
+                                       else //top
+                                               panel_pos.y -= f * (panel_pos.y + panel_size.y);
+                               }
+                               if(f == 1)
+                                       center.x = -1; // mark the panel as off screen
+                       }
+                       weaponprevtime = time - (1 - f) * timein_effect_length;
+               }
+               else if (timeout && time < weaponprevtime + timein_effect_length) // apply timein effect if needed
+               {
+                       f = bound(0, (time - weaponprevtime) / timein_effect_length, 1);
+
+                       // fade the panel alpha
+                       if(autocvar_hud_panel_weapons_timeout_effect == 1)
+                       {
+                               panel_bg_alpha *= (autocvar_hud_panel_weapons_timeout_fadebgmin * (1 - f) + f);
+                               panel_fg_alpha *= (autocvar_hud_panel_weapons_timeout_fadefgmin * (1 - f) + f);
+                       }
+                       else if(autocvar_hud_panel_weapons_timeout_effect == 3)
+                       {
+                               panel_bg_alpha *= (f);
+                               panel_fg_alpha *= (f);
+                       }
+
+                       // move the panel back on screen
+                       if (autocvar_hud_panel_weapons_timeout_effect == 2 || autocvar_hud_panel_weapons_timeout_effect == 3)
+                       {
+                               f *= f; // for a cooler movement
+                               f = 1 - f;
+                               center.x = panel_pos.x + panel_size.x/2;
+                               center.y = panel_pos.y + panel_size.y/2;
+                               screen_ar = vid_conwidth/vid_conheight;
+                               if (center.x/center.y < screen_ar) //bottom left
+                               {
+                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
+                                               panel_pos.y += f * (vid_conheight - panel_pos.y);
+                                       else //left
+                                               panel_pos.x -= f * (panel_pos.x + panel_size.x);
+                               }
+                               else //top right
+                               {
+                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //right
+                                               panel_pos.x += f * (vid_conwidth - panel_pos.x);
+                                       else //top
+                                               panel_pos.y -= f * (panel_pos.y + panel_size.y);
+                               }
+                       }
+               }
+       }
+
+       // draw the background, then change the virtual size of it to better fit other items inside
+       HUD_Panel_DrawBg(1);
+
+       if(center.x == -1)
+               return;
+
+       if(panel_bg_padding)
+       {
+               panel_pos += '1 1 0' * panel_bg_padding;
+               panel_size -= '2 2 0' * panel_bg_padding;
+       }
+
+       // after the sizing and animations are done, update the other values
+
+       if(!rows) // if rows is > 0 onlyowned code has already updated these vars
+       {
+               vector table_size = HUD_GetTableSize_BestItemAR((Weapons_COUNT - 1), panel_size, aspect);
+               columns = table_size.x;
+               rows = table_size.y;
+               weapon_size.x = panel_size.x / columns;
+               weapon_size.y = panel_size.y / rows;
+               vertical_order = (panel_size.x / panel_size.y >= aspect);
+       }
+
+       // calculate position/size for visual bar displaying ammount of ammo status
+       if (autocvar_hud_panel_weapons_ammo)
+       {
+               ammo_color = stov(autocvar_hud_panel_weapons_ammo_color);
+               ammo_alpha = panel_fg_alpha * autocvar_hud_panel_weapons_ammo_alpha;
+
+               if(weapon_size.x/weapon_size.y > aspect)
+               {
+                       barsize.x = aspect * weapon_size.y;
+                       barsize.y = weapon_size.y;
+                       baroffset.x = (weapon_size.x - barsize.x) / 2;
+               }
+               else
+               {
+                       barsize.y = 1/aspect * weapon_size.x;
+                       barsize.x = weapon_size.x;
+                       baroffset.y = (weapon_size.y - barsize.y) / 2;
+               }
+       }
+       if(autocvar_hud_panel_weapons_accuracy)
+               Accuracy_LoadColors();
+
+       // draw items
+       row = column = 0;
+       vector label_size = '1 1 0' * min(weapon_size.x, weapon_size.y) * bound(0, autocvar_hud_panel_weapons_label_scale, 1);
+       vector noncurrent_pos = '0 0 0';
+       vector noncurrent_size = weapon_size * bound(0, autocvar_hud_panel_weapons_noncurrent_scale, 1);
+       float noncurrent_alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_weapons_noncurrent_alpha, 1);
+       bool isCurrent;
+
+       for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
+       {
+               // retrieve information about the current weapon to be drawn
+               setself(weaponorder[i]);
+               weapon_id = self.impulse;
+               isCurrent = (self.weapon == switchweapon);
+
+               // skip if this weapon doesn't exist
+               if(!self || weapon_id < 0) { continue; }
+
+               // skip this weapon if we don't own it (and onlyowned is enabled)-- or if weapons_complainbubble is showing for this weapon
+               if(autocvar_hud_panel_weapons_onlyowned)
+               if (!((weapons_stat & WepSet_FromWeapon(self.weapon)) || (self.weapon == complain_weapon)))
+                       continue;
+
+               // figure out the drawing position of weapon
+               weapon_pos = (panel_pos + eX * column * weapon_size.x + eY * row * weapon_size.y);
+               noncurrent_pos.x = weapon_pos.x + (weapon_size.x - noncurrent_size.x) / 2;
+               noncurrent_pos.y = weapon_pos.y + (weapon_size.y - noncurrent_size.y) / 2;
+
+               // draw background behind currently selected weapon
+               if(isCurrent)
+                       drawpic_aspect_skin(weapon_pos, "weapon_current_bg", weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+               // draw the weapon accuracy
+               if(autocvar_hud_panel_weapons_accuracy)
+               {
+                       float panel_weapon_accuracy = weapon_accuracy[self.weapon-WEP_FIRST];
+                       if(panel_weapon_accuracy >= 0)
+                       {
+                               color = Accuracy_GetColor(panel_weapon_accuracy);
+                               drawpic_aspect_skin(weapon_pos, "weapon_accuracy", weapon_size, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       }
+               }
+
+               // drawing all the weapon items
+               if(weapons_stat & WepSet_FromWeapon(self.weapon))
+               {
+                       // draw the weapon image
+                       if(isCurrent)
+                               drawpic_aspect_skin(weapon_pos, self.model2, weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                       else
+                               drawpic_aspect_skin(noncurrent_pos, self.model2, noncurrent_size, '1 1 1', noncurrent_alpha, DRAWFLAG_NORMAL);
+
+                       // draw weapon label string
+                       switch(autocvar_hud_panel_weapons_label)
+                       {
+                               case 1: // weapon number
+                                       drawstring(weapon_pos, ftos(weapon_id), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                                       break;
+
+                               case 2: // bind
+                                       drawstring(weapon_pos, getcommandkey(ftos(weapon_id), strcat("weapon_group_", ftos(weapon_id))), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                                       break;
+
+                               case 3: // weapon name
+                                       drawstring(weapon_pos, strtolower(self.m_name), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                                       break;
+
+                               default: // nothing
+                                       break;
+                       }
+
+                       // draw ammo status bar
+                       if(autocvar_hud_panel_weapons_ammo && (self.ammo_field != ammo_none))
+                       {
+                               float ammo_full;
+                               a = getstati(GetAmmoStat(self.ammo_field)); // how much ammo do we have?
+
+                               if(a > 0)
+                               {
+                                       switch(self.ammo_field)
+                                       {
+                                               case ammo_shells:  ammo_full = autocvar_hud_panel_weapons_ammo_full_shells;  break;
+                                               case ammo_nails:   ammo_full = autocvar_hud_panel_weapons_ammo_full_nails;   break;
+                                               case ammo_rockets: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
+                                               case ammo_cells:   ammo_full = autocvar_hud_panel_weapons_ammo_full_cells;   break;
+                                               case ammo_plasma:  ammo_full = autocvar_hud_panel_weapons_ammo_full_plasma;  break;
+                                               case ammo_fuel:    ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel;    break;
+                                               default: ammo_full = 60;
+                                       }
+
+                                       drawsetcliparea(
+                                               weapon_pos.x + baroffset.x,
+                                               weapon_pos.y + baroffset.y,
+                                               barsize.x * bound(0, a/ammo_full, 1),
+                                               barsize.y
+                                       );
+
+                                       drawpic_aspect_skin(
+                                               weapon_pos,
+                                               "weapon_ammo",
+                                               weapon_size,
+                                               ammo_color,
+                                               ammo_alpha,
+                                               DRAWFLAG_NORMAL
+                                       );
+
+                                       drawresetcliparea();
+                               }
+                       }
+               }
+               else // draw a "ghost weapon icon" if you don't have the weapon
+               {
+                       drawpic_aspect_skin(noncurrent_pos, self.model2, noncurrent_size, '0.2 0.2 0.2', panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
+               }
+
+               // draw the complain message
+               if(self.weapon == complain_weapon)
+               {
+                       if(fadetime)
+                               a = ((complain_weapon_time + when > time) ? 1 : bound(0, (complain_weapon_time + when + fadetime - time) / fadetime, 1));
+                       else
+                               a = ((complain_weapon_time + when > time) ? 1 : 0);
+
+                       string s;
+                       if(complain_weapon_type == 0) {
+                               s = _("Out of ammo");
+                               color = stov(autocvar_hud_panel_weapons_complainbubble_color_outofammo);
+                       }
+                       else if(complain_weapon_type == 1) {
+                               s = _("Don't have");
+                               color = stov(autocvar_hud_panel_weapons_complainbubble_color_donthave);
+                       }
+                       else {
+                               s = _("Unavailable");
+                               color = stov(autocvar_hud_panel_weapons_complainbubble_color_unavailable);
+                       }
+                       float padding = autocvar_hud_panel_weapons_complainbubble_padding;
+                       drawpic_aspect_skin(weapon_pos + '1 1 0' * padding, "weapon_complainbubble", weapon_size - '2 2 0' * padding, color, a * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring_aspect(weapon_pos + '1 1 0' * padding, s, weapon_size - '2 2 0' * padding, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+               }
+
+               #if 0
+               /// debug code
+               if(!autocvar_hud_panel_weapons_onlyowned)
+               {
+                       drawfill(weapon_pos + '1 1 0', weapon_size - '2 2 0', '1 1 1', panel_fg_alpha * 0.2, DRAWFLAG_NORMAL);
+                       drawstring(weapon_pos, ftos(i + 1), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
+               #endif
+
+               // continue with new position for the next weapon
+               if(vertical_order)
+               {
+                       ++column;
+                       if(column >= columns)
+                       {
+                               column = 0;
+                               ++row;
+                       }
+               }
+               else
+               {
+                       ++row;
+                       if(row >= rows)
+                       {
+                               row = 0;
+                               ++column;
+                       }
+               }
+       }
+}
diff --git a/qcsrc/client/hud_config.qc b/qcsrc/client/hud_config.qc
deleted file mode 100644 (file)
index 48b3c82..0000000
+++ /dev/null
@@ -1,1297 +0,0 @@
-#include "hud_config.qh"
-
-#include "hud.qh"
-
-#define HUD_Write(s) fputs(fh, s)
-// q: quoted, n: not quoted
-#define HUD_Write_Cvar_n(cvar) HUD_Write(strcat("seta ", cvar, " ", cvar_string(cvar), "\n"))
-#define HUD_Write_Cvar_q(cvar) HUD_Write(strcat("seta ", cvar, " \"", cvar_string(cvar), "\"\n"))
-#define HUD_Write_PanelCvar_n(cvar_suf) HUD_Write_Cvar_n(strcat("hud_panel_", panel.panel_name, cvar_suf))
-#define HUD_Write_PanelCvar_q(cvar_suf) HUD_Write_Cvar_q(strcat("hud_panel_", panel.panel_name, cvar_suf))
-// Save the config
-void HUD_Panel_ExportCfg(string cfgname)
-{
-       float fh;
-       string filename = strcat("hud_", autocvar_hud_skin, "_", cfgname, ".cfg");
-       fh = fopen(filename, FILE_WRITE);
-       if(fh >= 0)
-       {
-               HUD_Write_Cvar_q("hud_skin");
-               HUD_Write_Cvar_q("hud_panel_bg");
-               HUD_Write_Cvar_q("hud_panel_bg_color");
-               HUD_Write_Cvar_q("hud_panel_bg_color_team");
-               HUD_Write_Cvar_q("hud_panel_bg_alpha");
-               HUD_Write_Cvar_q("hud_panel_bg_border");
-               HUD_Write_Cvar_q("hud_panel_bg_padding");
-               HUD_Write_Cvar_q("hud_panel_fg_alpha");
-               HUD_Write("\n");
-
-               HUD_Write_Cvar_q("hud_dock");
-               HUD_Write_Cvar_q("hud_dock_color");
-               HUD_Write_Cvar_q("hud_dock_color_team");
-               HUD_Write_Cvar_q("hud_dock_alpha");
-               HUD_Write("\n");
-
-               HUD_Write_Cvar_q("hud_progressbar_alpha");
-               HUD_Write_Cvar_q("hud_progressbar_strength_color");
-               HUD_Write_Cvar_q("hud_progressbar_shield_color");
-               HUD_Write_Cvar_q("hud_progressbar_health_color");
-               HUD_Write_Cvar_q("hud_progressbar_armor_color");
-               HUD_Write_Cvar_q("hud_progressbar_fuel_color");
-               HUD_Write_Cvar_q("hud_progressbar_nexball_color");
-               HUD_Write_Cvar_q("hud_progressbar_speed_color");
-               HUD_Write_Cvar_q("hud_progressbar_acceleration_color");
-               HUD_Write_Cvar_q("hud_progressbar_acceleration_neg_color");
-               HUD_Write("\n");
-
-               HUD_Write_Cvar_q("_hud_panelorder");
-               HUD_Write("\n");
-
-               HUD_Write_Cvar_q("hud_configure_grid");
-               HUD_Write_Cvar_q("hud_configure_grid_xsize");
-               HUD_Write_Cvar_q("hud_configure_grid_ysize");
-               HUD_Write("\n");
-
-               // common cvars for all panels
-               for (int i = 0; i < hud_panels_COUNT; ++i)
-               {
-                       panel = hud_panels[i];
-
-                       HUD_Write_PanelCvar_n("");
-                       HUD_Write_PanelCvar_q("_pos");
-                       HUD_Write_PanelCvar_q("_size");
-                       HUD_Write_PanelCvar_q("_bg");
-                       HUD_Write_PanelCvar_q("_bg_color");
-                       HUD_Write_PanelCvar_q("_bg_color_team");
-                       HUD_Write_PanelCvar_q("_bg_alpha");
-                       HUD_Write_PanelCvar_q("_bg_border");
-                       HUD_Write_PanelCvar_q("_bg_padding");
-                       switch(panel) {
-                               case HUD_PANEL_WEAPONS:
-                                       HUD_Write_PanelCvar_q("_accuracy");
-                                       HUD_Write_PanelCvar_q("_label");
-                                       HUD_Write_PanelCvar_q("_label_scale");
-                                       HUD_Write_PanelCvar_q("_complainbubble");
-                                       HUD_Write_PanelCvar_q("_complainbubble_padding");
-                                       HUD_Write_PanelCvar_q("_complainbubble_time");
-                                       HUD_Write_PanelCvar_q("_complainbubble_fadetime");
-                                       HUD_Write_PanelCvar_q("_complainbubble_color_outofammo");
-                                       HUD_Write_PanelCvar_q("_complainbubble_color_donthave");
-                                       HUD_Write_PanelCvar_q("_complainbubble_color_unavailable");
-                                       HUD_Write_PanelCvar_q("_ammo");
-                                       HUD_Write_PanelCvar_q("_ammo_color");
-                                       HUD_Write_PanelCvar_q("_ammo_alpha");
-                                       HUD_Write_PanelCvar_q("_aspect");
-                                       HUD_Write_PanelCvar_q("_timeout");
-                                       HUD_Write_PanelCvar_q("_timeout_effect");
-                                       HUD_Write_PanelCvar_q("_timeout_fadebgmin");
-                                       HUD_Write_PanelCvar_q("_timeout_fadefgmin");
-                                       HUD_Write_PanelCvar_q("_timeout_speed_in");
-                                       HUD_Write_PanelCvar_q("_timeout_speed_out");
-                                       HUD_Write_PanelCvar_q("_onlyowned");
-                                       HUD_Write_PanelCvar_q("_noncurrent_alpha");
-                                       HUD_Write_PanelCvar_q("_noncurrent_scale");
-                                       break;
-                               case HUD_PANEL_AMMO:
-                                       HUD_Write_PanelCvar_q("_onlycurrent");
-                                       HUD_Write_PanelCvar_q("_noncurrent_alpha");
-                                       HUD_Write_PanelCvar_q("_noncurrent_scale");
-                                       HUD_Write_PanelCvar_q("_iconalign");
-                                       HUD_Write_PanelCvar_q("_progressbar");
-                                       HUD_Write_PanelCvar_q("_progressbar_name");
-                                       HUD_Write_PanelCvar_q("_progressbar_xoffset");
-                                       HUD_Write_PanelCvar_q("_text");
-                                       break;
-                               case HUD_PANEL_POWERUPS:
-                                       HUD_Write_PanelCvar_q("_iconalign");
-                                       HUD_Write_PanelCvar_q("_baralign");
-                                       HUD_Write_PanelCvar_q("_progressbar");
-                                       HUD_Write_PanelCvar_q("_text");
-                                       break;
-                               case HUD_PANEL_HEALTHARMOR:
-                                       HUD_Write_PanelCvar_q("_flip");
-                                       HUD_Write_PanelCvar_q("_iconalign");
-                                       HUD_Write_PanelCvar_q("_baralign");
-                                       HUD_Write_PanelCvar_q("_progressbar");
-                                       HUD_Write_PanelCvar_q("_progressbar_health");
-                                       HUD_Write_PanelCvar_q("_progressbar_armor");
-                                       HUD_Write_PanelCvar_q("_progressbar_gfx");
-                                       HUD_Write_PanelCvar_q("_progressbar_gfx_smooth");
-                                       HUD_Write_PanelCvar_q("_text");
-                                       break;
-                               case HUD_PANEL_NOTIFY:
-                                       HUD_Write_PanelCvar_q("_flip");
-                                       HUD_Write_PanelCvar_q("_fontsize");
-                                       HUD_Write_PanelCvar_q("_time");
-                                       HUD_Write_PanelCvar_q("_fadetime");
-                                       HUD_Write_PanelCvar_q("_icon_aspect");
-                                       break;
-                               case HUD_PANEL_TIMER:
-                                       HUD_Write_PanelCvar_q("_increment");
-                                       break;
-                               case HUD_PANEL_RADAR:
-                                       HUD_Write_PanelCvar_q("_foreground_alpha");
-                                       HUD_Write_PanelCvar_q("_rotation");
-                                       HUD_Write_PanelCvar_q("_zoommode");
-                                       HUD_Write_PanelCvar_q("_scale");
-                                       HUD_Write_PanelCvar_q("_maximized_scale");
-                                       HUD_Write_PanelCvar_q("_maximized_size");
-                                       HUD_Write_PanelCvar_q("_maximized_rotation");
-                                       HUD_Write_PanelCvar_q("_maximized_zoommode");
-                                       break;
-                               case HUD_PANEL_SCORE:
-                                       HUD_Write_PanelCvar_q("_rankings");
-                                       break;
-                               case HUD_PANEL_VOTE:
-                                       HUD_Write_PanelCvar_q("_alreadyvoted_alpha");
-                                       break;
-                               case HUD_PANEL_MODICONS:
-                                       HUD_Write_PanelCvar_q("_ca_layout");
-                                       HUD_Write_PanelCvar_q("_dom_layout");
-                                       HUD_Write_PanelCvar_q("_freezetag_layout");
-                                       break;
-                               case HUD_PANEL_PRESSEDKEYS:
-                                       HUD_Write_PanelCvar_q("_aspect");
-                                       HUD_Write_PanelCvar_q("_attack");
-                                       break;
-                               case HUD_PANEL_ENGINEINFO:
-                                       HUD_Write_PanelCvar_q("_framecounter_time");
-                                       HUD_Write_PanelCvar_q("_framecounter_decimals");
-                                       break;
-                               case HUD_PANEL_INFOMESSAGES:
-                                       HUD_Write_PanelCvar_q("_flip");
-                                       break;
-                               case HUD_PANEL_PHYSICS:
-                                       HUD_Write_PanelCvar_q("_speed_unit");
-                                       HUD_Write_PanelCvar_q("_speed_unit_show");
-                                       HUD_Write_PanelCvar_q("_speed_max");
-                                       HUD_Write_PanelCvar_q("_speed_vertical");
-                                       HUD_Write_PanelCvar_q("_topspeed");
-                                       HUD_Write_PanelCvar_q("_topspeed_time");
-                                       HUD_Write_PanelCvar_q("_acceleration_max");
-                                       HUD_Write_PanelCvar_q("_acceleration_vertical");
-                                       HUD_Write_PanelCvar_q("_flip");
-                                       HUD_Write_PanelCvar_q("_baralign");
-                                       HUD_Write_PanelCvar_q("_progressbar");
-                                       HUD_Write_PanelCvar_q("_progressbar_acceleration_mode");
-                                       HUD_Write_PanelCvar_q("_progressbar_acceleration_scale");
-                                       HUD_Write_PanelCvar_q("_progressbar_acceleration_nonlinear");
-                                       HUD_Write_PanelCvar_q("_text");
-                                       HUD_Write_PanelCvar_q("_text_scale");
-                                       break;
-                               case HUD_PANEL_CENTERPRINT:
-                                       HUD_Write_PanelCvar_q("_align");
-                                       HUD_Write_PanelCvar_q("_flip");
-                                       HUD_Write_PanelCvar_q("_fontscale");
-                                       HUD_Write_PanelCvar_q("_time");
-                                       HUD_Write_PanelCvar_q("_fade_in");
-                                       HUD_Write_PanelCvar_q("_fade_out");
-                                       HUD_Write_PanelCvar_q("_fade_subsequent");
-                                       HUD_Write_PanelCvar_q("_fade_subsequent_passone");
-                                       HUD_Write_PanelCvar_q("_fade_subsequent_passone_minalpha");
-                                       HUD_Write_PanelCvar_q("_fade_subsequent_passtwo");
-                                       HUD_Write_PanelCvar_q("_fade_subsequent_passtwo_minalpha");
-                                       HUD_Write_PanelCvar_q("_fade_subsequent_minfontsize");
-                                       HUD_Write_PanelCvar_q("_fade_minfontsize");
-                                       break;
-                               case HUD_PANEL_ITEMSTIME:
-                                       HUD_Write_PanelCvar_q("_iconalign");
-                                       HUD_Write_PanelCvar_q("_progressbar");
-                                       HUD_Write_PanelCvar_q("_progressbar_name");
-                                       HUD_Write_PanelCvar_q("_progressbar_reduced");
-                                       HUD_Write_PanelCvar_q("_text");
-                                       HUD_Write_PanelCvar_q("_ratio");
-                                       HUD_Write_PanelCvar_q("_dynamicsize");
-                               case HUD_PANEL_QUICKMENU:
-                                       HUD_Write_PanelCvar_q("_align");
-                                       break;
-                       }
-                       HUD_Write("\n");
-               }
-               HUD_Write("menu_sync\n"); // force the menu to reread the cvars, so that the dialogs are updated
-
-               LOG_INFOF(_("^2Successfully exported to %s! (Note: It's saved in data/data/)\n"), filename);
-               fclose(fh);
-       }
-       else
-               LOG_INFOF(_("^1Couldn't write to %s\n"), filename);
-}
-
-void HUD_Configure_Exit_Force()
-{
-       if (menu_enabled)
-       {
-               menu_enabled = 0;
-               localcmd("togglemenu\n");
-       }
-       cvar_set("_hud_configure", "0");
-}
-
-// check if move will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
-vector HUD_Panel_CheckMove(vector myPos, vector mySize)
-{
-       vector myCenter, targCenter;
-       vector myTarget = myPos;
-       int i;
-       for (i = 0; i < hud_panels_COUNT; ++i) {
-               panel = hud_panels[i];
-               if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
-               if(panel == highlightedPanel) continue;
-               HUD_Panel_UpdatePosSize();
-               if(!panel_enabled) continue;
-
-               panel_pos -= '1 1 0' * panel_bg_border;
-               panel_size += '2 2 0' * panel_bg_border;
-
-               if(myPos.y + mySize.y < panel_pos.y)
-                       continue;
-               if(myPos.y > panel_pos.y + panel_size.y)
-                       continue;
-
-               if(myPos.x + mySize.x < panel_pos.x)
-                       continue;
-               if(myPos.x > panel_pos.x + panel_size.x)
-                       continue;
-
-               // OK, there IS a collision.
-
-               myCenter.x = myPos.x + 0.5 * mySize.x;
-               myCenter.y = myPos.y + 0.5 * mySize.y;
-
-               targCenter.x = panel_pos.x + 0.5 * panel_size.x;
-               targCenter.y = panel_pos.y + 0.5 * panel_size.y;
-
-               if(myCenter.x < targCenter.x && myCenter.y < targCenter.y) // top left (of the target panel)
-               {
-                       if(myPos.x + mySize.x - panel_pos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
-                               myTarget.x = panel_pos.x - mySize.x;
-                       else // push it upwards
-                               myTarget.y = panel_pos.y - mySize.y;
-               }
-               else if(myCenter.x > targCenter.x && myCenter.y < targCenter.y) // top right
-               {
-                       if(panel_pos.x + panel_size.x - myPos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
-                               myTarget.x = panel_pos.x + panel_size.x;
-                       else // push it upwards
-                               myTarget.y = panel_pos.y - mySize.y;
-               }
-               else if(myCenter.x < targCenter.x && myCenter.y > targCenter.y) // bottom left
-               {
-                       if(myPos.x + mySize.x - panel_pos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
-                               myTarget.x = panel_pos.x - mySize.x;
-                       else // push it downwards
-                               myTarget.y = panel_pos.y + panel_size.y;
-               }
-               else if(myCenter.x > targCenter.x && myCenter.y > targCenter.y) // bottom right
-               {
-                       if(panel_pos.x + panel_size.x - myPos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
-                               myTarget.x = panel_pos.x + panel_size.x;
-                       else // push it downwards
-                               myTarget.y = panel_pos.y + panel_size.y;
-               }
-               //if(cvar("hud_configure_checkcollisions_debug"))
-                       //drawfill(panel_pos, panel_size, '1 1 0', .3, DRAWFLAG_NORMAL);
-       }
-
-       return myTarget;
-}
-
-void HUD_Panel_SetPos(vector pos)
-{
-       panel = highlightedPanel;
-       HUD_Panel_UpdatePosSize();
-       vector mySize;
-       mySize = panel_size;
-
-       //if(cvar("hud_configure_checkcollisions_debug"))
-               //drawfill(pos, mySize, '1 1 1', .2, DRAWFLAG_NORMAL);
-
-       if(autocvar_hud_configure_grid)
-       {
-               pos.x = floor((pos.x/vid_conwidth)/hud_configure_gridSize.x + 0.5) * hud_configure_realGridSize.x;
-               pos.y = floor((pos.y/vid_conheight)/hud_configure_gridSize.y + 0.5) * hud_configure_realGridSize.y;
-       }
-
-       if(hud_configure_checkcollisions)
-               pos = HUD_Panel_CheckMove(pos, mySize);
-
-       pos.x = bound(0, pos.x, vid_conwidth - mySize.x);
-       pos.y = bound(0, pos.y, vid_conheight - mySize.y);
-
-       string s;
-       s = strcat(ftos(pos.x/vid_conwidth), " ", ftos(pos.y/vid_conheight));
-
-       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
-}
-
-// check if resize will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
-vector HUD_Panel_CheckResize(vector mySize, vector resizeorigin) {
-       vector targEndPos;
-       vector dist;
-       float ratio = mySize.x/mySize.y;
-       int i;
-       for (i = 0; i < hud_panels_COUNT; ++i) {
-               panel = hud_panels[i];
-               if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
-               if(panel == highlightedPanel) continue;
-               HUD_Panel_UpdatePosSize();
-               if(!panel_enabled) continue;
-
-               panel_pos -= '1 1 0' * panel_bg_border;
-               panel_size += '2 2 0' * panel_bg_border;
-
-               targEndPos = panel_pos + panel_size;
-
-               // resizeorigin is WITHIN target panel, just abort any collision testing against that particular panel to produce expected behaviour!
-               if(resizeorigin.x > panel_pos.x && resizeorigin.x < targEndPos.x && resizeorigin.y > panel_pos.y && resizeorigin.y < targEndPos.y)
-                       continue;
-
-               if (resizeCorner == 1)
-               {
-                       // check if this panel is on our way
-                       if (resizeorigin.x <= panel_pos.x)
-                               continue;
-                       if (resizeorigin.y <= panel_pos.y)
-                               continue;
-                       if (targEndPos.x <= resizeorigin.x - mySize.x)
-                               continue;
-                       if (targEndPos.y <= resizeorigin.y - mySize.y)
-                               continue;
-
-                       // there is a collision:
-                       // detect which side of the panel we are facing is actually limiting the resizing
-                       // (which side the resize direction finds for first) and reduce the size up to there
-                       //
-                       // dist is the distance between resizeorigin and the "analogous" point of the panel
-                       // in this case between resizeorigin (bottom-right point) and the bottom-right point of the panel
-                       dist.x = resizeorigin.x - targEndPos.x;
-                       dist.y = resizeorigin.y - targEndPos.y;
-                       if (dist.y <= 0 || dist.x / dist.y > ratio)
-                               mySize.x = min(mySize.x, dist.x);
-                       else
-                               mySize.y = min(mySize.y, dist.y);
-               }
-               else if (resizeCorner == 2)
-               {
-                       if (resizeorigin.x >= targEndPos.x)
-                               continue;
-                       if (resizeorigin.y <= panel_pos.y)
-                               continue;
-                       if (panel_pos.x >= resizeorigin.x + mySize.x)
-                               continue;
-                       if (targEndPos.y <= resizeorigin.y - mySize.y)
-                               continue;
-
-                       dist.x = panel_pos.x - resizeorigin.x;
-                       dist.y = resizeorigin.y - targEndPos.y;
-                       if (dist.y <= 0 || dist.x / dist.y > ratio)
-                               mySize.x = min(mySize.x, dist.x);
-                       else
-                               mySize.y = min(mySize.y, dist.y);
-               }
-               else if (resizeCorner == 3)
-               {
-                       if (resizeorigin.x <= panel_pos.x)
-                               continue;
-                       if (resizeorigin.y >= targEndPos.y)
-                               continue;
-                       if (targEndPos.x <= resizeorigin.x - mySize.x)
-                               continue;
-                       if (panel_pos.y >= resizeorigin.y + mySize.y)
-                               continue;
-
-                       dist.x = resizeorigin.x - targEndPos.x;
-                       dist.y = panel_pos.y - resizeorigin.y;
-                       if (dist.y <= 0 || dist.x / dist.y > ratio)
-                               mySize.x = min(mySize.x, dist.x);
-                       else
-                               mySize.y = min(mySize.y, dist.y);
-               }
-               else if (resizeCorner == 4)
-               {
-                       if (resizeorigin.x >= targEndPos.x)
-                               continue;
-                       if (resizeorigin.y >= targEndPos.y)
-                               continue;
-                       if (panel_pos.x >= resizeorigin.x + mySize.x)
-                               continue;
-                       if (panel_pos.y >= resizeorigin.y + mySize.y)
-                               continue;
-
-                       dist.x = panel_pos.x - resizeorigin.x;
-                       dist.y = panel_pos.y - resizeorigin.y;
-                       if (dist.y <= 0 || dist.x / dist.y > ratio)
-                               mySize.x = min(mySize.x, dist.x);
-                       else
-                               mySize.y = min(mySize.y, dist.y);
-               }
-               //if(cvar("hud_configure_checkcollisions_debug"))
-                       //drawfill(panel_pos, panel_size, '1 1 0', .3, DRAWFLAG_NORMAL);
-       }
-
-       return mySize;
-}
-
-void HUD_Panel_SetPosSize(vector mySize)
-{
-       panel = highlightedPanel;
-       HUD_Panel_UpdatePosSize();
-       vector resizeorigin = panel_click_resizeorigin;
-       vector myPos;
-
-       // minimum panel size cap
-       mySize.x = max(0.025 * vid_conwidth, mySize.x);
-       mySize.y = max(0.025 * vid_conheight, mySize.y);
-
-       if(highlightedPanel == HUD_PANEL(CHAT)) // some panels have their own restrictions, like the chat panel (which actually only moves the engine chat print around). Looks bad if it's too small.
-       {
-               mySize.x = max(17 * autocvar_con_chatsize, mySize.x);
-               mySize.y = max(2 * autocvar_con_chatsize + 2 * panel_bg_padding, mySize.y);
-       }
-
-       // collision testing|
-       // -----------------+
-
-       // we need to know pos at this stage, but it might still change later if we hit a screen edge/other panel (?)
-       if(resizeCorner == 1) {
-               myPos.x = resizeorigin.x - mySize.x;
-               myPos.y = resizeorigin.y - mySize.y;
-       } else if(resizeCorner == 2) {
-               myPos.x = resizeorigin.x;
-               myPos.y = resizeorigin.y - mySize.y;
-       } else if(resizeCorner == 3) {
-               myPos.x = resizeorigin.x - mySize.x;
-               myPos.y = resizeorigin.y;
-       } else { // resizeCorner == 4
-               myPos.x = resizeorigin.x;
-               myPos.y = resizeorigin.y;
-       }
-
-       // left/top screen edges
-       if(myPos.x < 0)
-               mySize.x = mySize.x + myPos.x;
-       if(myPos.y < 0)
-               mySize.y = mySize.y + myPos.y;
-
-       // bottom/right screen edges
-       if(myPos.x + mySize.x > vid_conwidth)
-               mySize.x = vid_conwidth - myPos.x;
-       if(myPos.y + mySize.y > vid_conheight)
-               mySize.y = vid_conheight - myPos.y;
-
-       //if(cvar("hud_configure_checkcollisions_debug"))
-               //drawfill(myPos, mySize, '1 1 1', .2, DRAWFLAG_NORMAL);
-
-       // before checkresize, otherwise panel can be snapped partially inside another panel or panel aspect ratio can be broken
-       if(autocvar_hud_configure_grid)
-       {
-               mySize.x = floor((mySize.x/vid_conwidth)/hud_configure_gridSize.x + 0.5) * hud_configure_realGridSize.x;
-               mySize.y = floor((mySize.y/vid_conheight)/hud_configure_gridSize.y + 0.5) * hud_configure_realGridSize.y;
-       }
-
-       if(hud_configure_checkcollisions)
-               mySize = HUD_Panel_CheckResize(mySize, resizeorigin);
-
-       // minimum panel size cap, do this once more so we NEVER EVER EVER have a panel smaller than this, JUST IN CASE above code still makes the panel eg negative (impossible to resize back without changing cvars manually then)
-       mySize.x = max(0.025 * vid_conwidth, mySize.x);
-       mySize.y = max(0.025 * vid_conheight, mySize.y);
-
-       // do another pos check, as size might have changed by now
-       if(resizeCorner == 1) {
-               myPos.x = resizeorigin.x - mySize.x;
-               myPos.y = resizeorigin.y - mySize.y;
-       } else if(resizeCorner == 2) {
-               myPos.x = resizeorigin.x;
-               myPos.y = resizeorigin.y - mySize.y;
-       } else if(resizeCorner == 3) {
-               myPos.x = resizeorigin.x - mySize.x;
-               myPos.y = resizeorigin.y;
-       } else { // resizeCorner == 4
-               myPos.x = resizeorigin.x;
-               myPos.y = resizeorigin.y;
-       }
-
-       //if(cvar("hud_configure_checkcollisions_debug"))
-               //drawfill(myPos, mySize, '0 1 0', .3, DRAWFLAG_NORMAL);
-
-       string s;
-       s = strcat(ftos(mySize.x/vid_conwidth), " ", ftos(mySize.y/vid_conheight));
-       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
-
-       s = strcat(ftos(myPos.x/vid_conwidth), " ", ftos(myPos.y/vid_conheight));
-       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
-}
-
-float pressed_key_time;
-vector highlightedPanel_initial_pos, highlightedPanel_initial_size;
-void HUD_Panel_Arrow_Action(float nPrimary)
-{
-       if(!highlightedPanel)
-               return;
-
-       hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
-
-       float step;
-       if(autocvar_hud_configure_grid)
-       {
-               if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
-               {
-                       if (hudShiftState & S_SHIFT)
-                               step = hud_configure_realGridSize.y;
-                       else
-                               step = 2 * hud_configure_realGridSize.y;
-               }
-               else
-               {
-                       if (hudShiftState & S_SHIFT)
-                               step = hud_configure_realGridSize.x;
-                       else
-                               step = 2 * hud_configure_realGridSize.x;
-               }
-       }
-       else
-       {
-               if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
-                       step = vid_conheight;
-               else
-                       step = vid_conwidth;
-               if (hudShiftState & S_SHIFT)
-                       step = (step / 256); // more precision
-               else
-                       step = (step / 64) * (1 + 2 * (time - pressed_key_time));
-       }
-
-       panel = highlightedPanel;
-       HUD_Panel_UpdatePosSize();
-
-       highlightedPanel_initial_pos = panel_pos;
-       highlightedPanel_initial_size = panel_size;
-
-       if (hudShiftState & S_ALT) // resize
-       {
-               if(nPrimary == K_UPARROW)
-                       resizeCorner = 1;
-               else if(nPrimary == K_RIGHTARROW)
-                       resizeCorner = 2;
-               else if(nPrimary == K_LEFTARROW)
-                       resizeCorner = 3;
-               else // if(nPrimary == K_DOWNARROW)
-                       resizeCorner = 4;
-
-               // ctrl+arrow reduces the size, instead of increasing it
-               // Note that ctrl disables collisions check too, but it's fine
-               // since we don't collide with anything reducing the size
-               if (hudShiftState & S_CTRL) {
-                       step = -step;
-                       resizeCorner = 5 - resizeCorner;
-               }
-
-               vector mySize;
-               mySize = panel_size;
-               panel_click_resizeorigin = panel_pos;
-               if(resizeCorner == 1) {
-                       panel_click_resizeorigin += mySize;
-                       mySize.y += step;
-               } else if(resizeCorner == 2) {
-                       panel_click_resizeorigin.y += mySize.y;
-                       mySize.x += step;
-               } else if(resizeCorner == 3) {
-                       panel_click_resizeorigin.x += mySize.x;
-                       mySize.x += step;
-               } else { // resizeCorner == 4
-                       mySize.y += step;
-               }
-               HUD_Panel_SetPosSize(mySize);
-       }
-       else // move
-       {
-               vector pos;
-               pos = panel_pos;
-               if(nPrimary == K_UPARROW)
-                       pos.y -= step;
-               else if(nPrimary == K_DOWNARROW)
-                       pos.y += step;
-               else if(nPrimary == K_LEFTARROW)
-                       pos.x -= step;
-               else // if(nPrimary == K_RIGHTARROW)
-                       pos.x += step;
-
-               HUD_Panel_SetPos(pos);
-       }
-
-       panel = highlightedPanel;
-       HUD_Panel_UpdatePosSize();
-
-       if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
-       {
-               // backup!
-               panel_pos_backup = highlightedPanel_initial_pos;
-               panel_size_backup = highlightedPanel_initial_size;
-               highlightedPanel_backup = highlightedPanel;
-       }
-}
-
-void HUD_Panel_EnableMenu();
-entity tab_panels[hud_panels_MAX];
-entity tab_panel;
-vector tab_panel_pos;
-float tab_backward;
-void HUD_Panel_FirstInDrawQ(float id);
-void reset_tab_panels()
-{
-       int i;
-       for(i = 0; i < hud_panels_COUNT; ++i)
-               tab_panels[i] = world;
-}
-float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
-{
-       string s;
-
-       if(bInputType == 2)
-               return false;
-
-       if(!autocvar__hud_configure)
-               return false;
-
-       if(bInputType == 3)
-       {
-               mousepos.x = nPrimary;
-               mousepos.y = nSecondary;
-               return true;
-       }
-
-       // block any input while a menu dialog is fading
-       // don't block mousepos read as it leads to cursor jumps in the interaction with the menu
-       if(autocvar__menu_alpha)
-       {
-               hudShiftState = 0;
-               mouseClicked = 0;
-               return true;
-       }
-
-       // allow console bind to work
-       string con_keys;
-       float keys;
-       con_keys = findkeysforcommand("toggleconsole", 0);
-       keys = tokenize(con_keys); // findkeysforcommand returns data for this
-
-       bool hit_con_bind = false;
-       int i;
-       for (i = 0; i < keys; ++i)
-       {
-               if(nPrimary == stof(argv(i)))
-                       hit_con_bind = true;
-       }
-
-       if(bInputType == 0) {
-               if(nPrimary == K_ALT) hudShiftState |= S_ALT;
-               if(nPrimary == K_CTRL) hudShiftState |= S_CTRL;
-               if(nPrimary == K_SHIFT) hudShiftState |= S_SHIFT;
-       }
-       else if(bInputType == 1) {
-               if(nPrimary == K_ALT) hudShiftState -= (hudShiftState & S_ALT);
-               if(nPrimary == K_CTRL) hudShiftState -= (hudShiftState & S_CTRL);
-               if(nPrimary == K_SHIFT) hudShiftState -= (hudShiftState & S_SHIFT);
-       }
-
-       if(nPrimary == K_CTRL)
-       {
-               if (bInputType == 1) //ctrl has been released
-               {
-                       if (tab_panel)
-                       {
-                               //switch to selected panel
-                               highlightedPanel = tab_panel;
-                               highlightedAction = 0;
-                               HUD_Panel_FirstInDrawQ(highlightedPanel.panel_id);
-                       }
-                       tab_panel = world;
-                       reset_tab_panels();
-               }
-       }
-
-       if(nPrimary == K_MOUSE1)
-       {
-               if(bInputType == 0) // key pressed
-                       mouseClicked |= S_MOUSE1;
-               else if(bInputType == 1) // key released
-                       mouseClicked -= (mouseClicked & S_MOUSE1);
-       }
-       else if(nPrimary == K_MOUSE2)
-       {
-               if(bInputType == 0) // key pressed
-                       mouseClicked |= S_MOUSE2;
-               else if(bInputType == 1) // key released
-                       mouseClicked -= (mouseClicked & S_MOUSE2);
-       }
-       else if(nPrimary == K_ESCAPE)
-       {
-               if (bInputType == 1)
-                       return true;
-               menu_enabled = 1;
-               localcmd("menu_showhudexit\n");
-       }
-       else if(nPrimary == K_BACKSPACE && hudShiftState & S_CTRL)
-       {
-               if (bInputType == 1)
-                       return true;
-               if (!menu_enabled)
-                       cvar_set("_hud_configure", "0");
-       }
-       else if(nPrimary == K_TAB && hudShiftState & S_CTRL) // switch panel
-       {
-               if (bInputType == 1 || mouseClicked)
-                       return true;
-
-               // FIXME minor bug: if a panel is highlighted, has the same pos_x and
-               // lays in the same level of another panel then the next consecutive
-               // CTRL TAB presses will reselect once more the highlighted panel
-
-               entity starting_panel;
-               entity old_tab_panel = tab_panel;
-               if (!tab_panel) //first press of TAB
-               {
-                       if (highlightedPanel)
-                       {
-                               panel = highlightedPanel;
-                               HUD_Panel_UpdatePosSize();
-                       }
-                       else
-                               panel_pos = '0 0 0';
-                       starting_panel = highlightedPanel;
-                       tab_panel_pos = panel_pos; //to compute level
-               }
-               else
-               {
-                       if ( ((!tab_backward) && (hudShiftState & S_SHIFT)) || (tab_backward && !(hudShiftState & S_SHIFT)) ) //tab direction changed?
-                               reset_tab_panels();
-                       starting_panel = tab_panel;
-               }
-               tab_backward = (hudShiftState & S_SHIFT);
-
-               float k, level = 0, start_posX;
-               vector candidate_pos = '0 0 0';
-               const float LEVELS_NUM = 4;
-               float level_height = vid_conheight / LEVELS_NUM;
-:find_tab_panel
-               level = floor(tab_panel_pos.y / level_height) * level_height; //starting level
-               candidate_pos.x = (!tab_backward) ? vid_conwidth : 0;
-               start_posX = tab_panel_pos.x;
-               tab_panel = world;
-               k=0;
-               while(++k)
-               {
-                       for(i = 0; i < hud_panels_COUNT; ++i)
-                       {
-                               panel = hud_panels[i];
-                               if(!(panel.panel_configflags & PANEL_CONFIG_MAIN))
-                                       continue;
-                               if (panel == tab_panels[i] || panel == starting_panel)
-                                       continue;
-                               HUD_Panel_UpdatePosSize();
-                               if (panel_pos.y >= level && (panel_pos.y - level) < level_height)
-                               if (  ( !tab_backward && panel_pos.x >= start_posX && (panel_pos.x < candidate_pos.x || (panel_pos.x == candidate_pos.x && panel_pos.y <= candidate_pos.y)) )
-                                       || ( tab_backward && panel_pos.x <= start_posX && (panel_pos.x > candidate_pos.x || (panel_pos.x == candidate_pos.x && panel_pos.y >= candidate_pos.y)) )  )
-                               {
-                                       tab_panel = panel;
-                                       tab_panel_pos = candidate_pos = panel_pos;
-                               }
-                       }
-                       if (tab_panel)
-                               break;
-                       if (k == LEVELS_NUM) //tab_panel not found
-                       {
-                               reset_tab_panels();
-                               if (!old_tab_panel)
-                               {
-                                       tab_panel = world;
-                                       return true;
-                               }
-                               starting_panel = old_tab_panel;
-                               old_tab_panel = world;
-                               goto find_tab_panel; //u must find tab_panel!
-                       }
-                       if (!tab_backward)
-                       {
-                               level = (level + level_height) % vid_conheight;
-                               start_posX = 0;
-                               candidate_pos.x = vid_conwidth;
-                       }
-                       else
-                       {
-                               level = (level - level_height) % vid_conheight;
-                               start_posX = vid_conwidth;
-                               candidate_pos.x = 0;
-                       }
-               }
-
-               tab_panels[tab_panel.panel_id] = tab_panel;
-       }
-       else if(nPrimary == K_SPACE && hudShiftState & S_CTRL) // enable/disable highlighted panel or dock
-       {
-               if (bInputType == 1 || mouseClicked)
-                       return true;
-
-               if (highlightedPanel)
-                       cvar_set(strcat("hud_panel_", highlightedPanel.panel_name), ftos(!cvar(strcat("hud_panel_", highlightedPanel.panel_name))));
-               else
-                       cvar_set(strcat("hud_dock"), (autocvar_hud_dock == "") ? "dock" : "");
-       }
-       else if(nPrimary == 'c' && hudShiftState & S_CTRL) // copy highlighted panel size
-       {
-               if (bInputType == 1 || mouseClicked)
-                       return true;
-
-               if (highlightedPanel)
-               {
-                       panel = highlightedPanel;
-                       HUD_Panel_UpdatePosSize();
-                       panel_size_copied = panel_size;
-               }
-       }
-       else if(nPrimary == 'v' && hudShiftState & S_CTRL) // past copied size on the highlighted panel
-       {
-               if (bInputType == 1 || mouseClicked)
-                       return true;
-
-               if (panel_size_copied == '0 0 0' || !highlightedPanel)
-                       return true;
-
-               panel = highlightedPanel;
-               HUD_Panel_UpdatePosSize();
-
-               // reduce size if it'd go beyond screen boundaries
-               vector tmp_size = panel_size_copied;
-               if (panel_pos.x + panel_size_copied.x > vid_conwidth)
-                       tmp_size.x = vid_conwidth - panel_pos.x;
-               if (panel_pos.y + panel_size_copied.y > vid_conheight)
-                       tmp_size.y = vid_conheight - panel_pos.y;
-
-               if (panel_size == tmp_size)
-                       return true;
-
-               // backup first!
-               panel_pos_backup = panel_pos;
-               panel_size_backup = panel_size;
-               highlightedPanel_backup = highlightedPanel;
-
-               s = strcat(ftos(tmp_size.x/vid_conwidth), " ", ftos(tmp_size.y/vid_conheight));
-               cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
-       }
-       else if(nPrimary == 'z' && hudShiftState & S_CTRL) // undo last action
-       {
-               if (bInputType == 1 || mouseClicked)
-                       return true;
-               //restore previous values
-               if (highlightedPanel_backup)
-               {
-                       s = strcat(ftos(panel_pos_backup.x/vid_conwidth), " ", ftos(panel_pos_backup.y/vid_conheight));
-                       cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_pos"), s);
-                       s = strcat(ftos(panel_size_backup.x/vid_conwidth), " ", ftos(panel_size_backup.y/vid_conheight));
-                       cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_size"), s);
-                       highlightedPanel_backup = world;
-               }
-       }
-       else if(nPrimary == 's' && hudShiftState & S_CTRL) // save config
-       {
-               if (bInputType == 1 || mouseClicked)
-                       return true;
-               localcmd("hud save myconfig\n");
-       }
-       else if(nPrimary == K_UPARROW || nPrimary == K_DOWNARROW || nPrimary == K_LEFTARROW || nPrimary == K_RIGHTARROW)
-       {
-               if (bInputType == 1)
-               {
-                       pressed_key_time = 0;
-                       return true;
-               }
-               else if (pressed_key_time == 0)
-                       pressed_key_time = time;
-
-               if (!mouseClicked)
-                       HUD_Panel_Arrow_Action(nPrimary); //move or resize panel
-       }
-       else if(nPrimary == K_ENTER || nPrimary == K_SPACE || nPrimary == K_KP_ENTER)
-       {
-               if (bInputType == 1)
-                       return true;
-               if (highlightedPanel)
-                       HUD_Panel_EnableMenu();
-       }
-       else if(hit_con_bind || nPrimary == K_PAUSE)
-               return false;
-
-       return true;
-}
-
-float HUD_Panel_Check_Mouse_Pos(float allow_move)
-{
-       int i, j = 0;
-       while(j < hud_panels_COUNT)
-       {
-               i = panel_order[j];
-               j += 1;
-
-               panel = hud_panels[i];
-               if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
-               HUD_Panel_UpdatePosSize();
-
-               float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
-
-               // move
-               if(allow_move && mousepos.x > panel_pos.x && mousepos.y > panel_pos.y && mousepos.x < panel_pos.x + panel_size.x && mousepos.y < panel_pos.y + panel_size.y)
-               {
-                       return 1;
-               }
-               // resize from topleft border
-               else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
-               {
-                       return 2;
-               }
-               // resize from topright border
-               else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
-               {
-                       return 3;
-               }
-               // resize from bottomleft border
-               else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + panel_size.y + border)
-               {
-                       return 3;
-               }
-               // resize from bottomright border
-               else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + panel_size.y + border)
-               {
-                       return 2;
-               }
-       }
-       return 0;
-}
-
-// move a panel to the beginning of the panel order array (which means it gets drawn last, on top of everything else)
-void HUD_Panel_FirstInDrawQ(float id)
-{
-       int i;
-       int place = -1;
-       // find out where in the array our current id is, save into place
-       for(i = 0; i < hud_panels_COUNT; ++i)
-       {
-               if(panel_order[i] == id)
-               {
-                       place = i;
-                       break;
-               }
-       }
-       // place last if we didn't find a place for it yet (probably new panel, or screwed up cvar)
-       if(place == -1)
-               place = hud_panels_COUNT - 1;
-
-       // move all ids up by one step in the array until "place"
-       for(i = place; i > 0; --i)
-       {
-               panel_order[i] = panel_order[i-1];
-       }
-       // now save the new top id
-       panel_order[0] = id;
-
-       // let's save them into the cvar by some strcat trickery
-       string s = "";
-       for(i = 0; i < hud_panels_COUNT; ++i)
-       {
-               s = strcat(s, ftos(panel_order[i]), " ");
-       }
-       cvar_set("_hud_panelorder", s);
-       if(hud_panelorder_prev)
-               strunzone(hud_panelorder_prev);
-       hud_panelorder_prev = strzone(autocvar__hud_panelorder); // prevent HUD_Main from doing useless update, we already updated here
-}
-
-void HUD_Panel_Highlight(float allow_move)
-{
-       int i, j = 0;
-
-       while(j < hud_panels_COUNT)
-       {
-               i = panel_order[j];
-               j += 1;
-
-               panel = hud_panels[i];
-               if(!(panel.panel_configflags & PANEL_CONFIG_MAIN))
-                       continue;
-               HUD_Panel_UpdatePosSize();
-
-               float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
-
-               // move
-               if(allow_move && mousepos.x > panel_pos.x && mousepos.y > panel_pos.y && mousepos.x < panel_pos.x + panel_size.x && mousepos.y < panel_pos.y + panel_size.y)
-               {
-                       highlightedPanel = hud_panels[i];
-                       HUD_Panel_FirstInDrawQ(i);
-                       highlightedAction = 1;
-                       panel_click_distance = mousepos - panel_pos;
-                       return;
-               }
-               // resize from topleft border
-               else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
-               {
-                       highlightedPanel = hud_panels[i];
-                       HUD_Panel_FirstInDrawQ(i);
-                       highlightedAction = 2;
-                       resizeCorner = 1;
-                       panel_click_distance = mousepos - panel_pos;
-                       panel_click_resizeorigin = panel_pos + panel_size;
-                       return;
-               }
-               // resize from topright border
-               else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
-               {
-                       highlightedPanel = hud_panels[i];
-                       HUD_Panel_FirstInDrawQ(i);
-                       highlightedAction = 2;
-                       resizeCorner = 2;
-                       panel_click_distance.x = panel_size.x - mousepos.x + panel_pos.x;
-                       panel_click_distance.y = mousepos.y - panel_pos.y;
-                       panel_click_resizeorigin = panel_pos + eY * panel_size.y;
-                       return;
-               }
-               // resize from bottomleft border
-               else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + panel_size.y + border)
-               {
-                       highlightedPanel = hud_panels[i];
-                       HUD_Panel_FirstInDrawQ(i);
-                       highlightedAction = 2;
-                       resizeCorner = 3;
-                       panel_click_distance.x = mousepos.x - panel_pos.x;
-                       panel_click_distance.y = panel_size.y - mousepos.y + panel_pos.y;
-                       panel_click_resizeorigin = panel_pos + eX * panel_size.x;
-                       return;
-               }
-               // resize from bottomright border
-               else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + panel_size.y + border)
-               {
-                       highlightedPanel = hud_panels[i];
-                       HUD_Panel_FirstInDrawQ(i);
-                       highlightedAction = 2;
-                       resizeCorner = 4;
-                       panel_click_distance = panel_size - mousepos + panel_pos;
-                       panel_click_resizeorigin = panel_pos;
-                       return;
-               }
-       }
-       highlightedPanel = world;
-       highlightedAction = 0;
-}
-
-void HUD_Panel_EnableMenu()
-{
-       menu_enabled = 2;
-       localcmd("menu_showhudoptions ", highlightedPanel.panel_name, "\n");
-}
-float mouse_over_panel;
-void HUD_Panel_Mouse()
-{
-       if(autocvar__menu_alpha == 1)
-               return;
-
-       if (!autocvar_hud_cursormode)
-       {
-               mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
-
-               mousepos.x = bound(0, mousepos.x, vid_conwidth);
-               mousepos.y = bound(0, mousepos.y, vid_conheight);
-       }
-
-       if(mouseClicked)
-       {
-               if(prevMouseClicked == 0)
-               {
-                       if (tab_panel)
-                       {
-                               //stop ctrl-tab selection
-                               tab_panel = world;
-                               reset_tab_panels();
-                       }
-                       HUD_Panel_Highlight(mouseClicked & S_MOUSE1); // sets highlightedPanel, highlightedAction, panel_click_distance, panel_click_resizeorigin
-                                                                       // and calls HUD_Panel_UpdatePosSize() for the highlighted panel
-                       if (highlightedPanel)
-                       {
-                               highlightedPanel_initial_pos = panel_pos;
-                               highlightedPanel_initial_size = panel_size;
-                       }
-                       // doubleclick check
-                       if ((mouseClicked & S_MOUSE1) && time - prevMouseClickedTime < 0.4 && highlightedPanel && prevMouseClickedPos == mousepos)
-                       {
-                               mouseClicked = 0; // to prevent spam, I guess.
-                               HUD_Panel_EnableMenu();
-                       }
-                       else
-                       {
-                               if (mouseClicked & S_MOUSE1)
-                               {
-                                       prevMouseClickedTime = time;
-                                       prevMouseClickedPos = mousepos;
-                               }
-                               mouse_over_panel = HUD_Panel_Check_Mouse_Pos(mouseClicked & S_MOUSE1);
-                       }
-               }
-               else
-               {
-                       panel = highlightedPanel;
-                       HUD_Panel_UpdatePosSize();
-               }
-
-               if (highlightedPanel)
-               {
-                       drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
-                       if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
-                       {
-                               hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
-                               // backup!
-                               panel_pos_backup = highlightedPanel_initial_pos;
-                               panel_size_backup = highlightedPanel_initial_size;
-                               highlightedPanel_backup = highlightedPanel;
-                       }
-                       else
-                               // in case the clicked panel is inside another panel and we aren't
-                               // moving it, avoid the immediate "fix" of its position/size
-                               // (often unwanted and hateful) by disabling collisions check
-                               hud_configure_checkcollisions = false;
-               }
-
-               if(highlightedAction == 1)
-                       HUD_Panel_SetPos(mousepos - panel_click_distance);
-               else if(highlightedAction == 2)
-               {
-                       vector mySize = '0 0 0';
-                       if(resizeCorner == 1) {
-                               mySize.x = panel_click_resizeorigin.x - (mousepos.x - panel_click_distance.x);
-                               mySize.y = panel_click_resizeorigin.y - (mousepos.y - panel_click_distance.y);
-                       } else if(resizeCorner == 2) {
-                               mySize.x = mousepos.x + panel_click_distance.x - panel_click_resizeorigin.x;
-                               mySize.y = panel_click_distance.y + panel_click_resizeorigin.y - mousepos.y;
-                       } else if(resizeCorner == 3) {
-                               mySize.x = panel_click_resizeorigin.x + panel_click_distance.x - mousepos.x;
-                               mySize.y = mousepos.y + panel_click_distance.y - panel_click_resizeorigin.y;
-                       } else { // resizeCorner == 4
-                               mySize.x = mousepos.x - (panel_click_resizeorigin.x - panel_click_distance.x);
-                               mySize.y = mousepos.y - (panel_click_resizeorigin.y - panel_click_distance.y);
-                       }
-                       HUD_Panel_SetPosSize(mySize);
-               }
-       }
-       else
-       {
-               if(prevMouseClicked)
-                       highlightedAction = 0;
-               if(menu_enabled == 2)
-                       mouse_over_panel = 0;
-               else
-                       mouse_over_panel = HUD_Panel_Check_Mouse_Pos(true);
-               if (mouse_over_panel && !tab_panel)
-                       drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
-       }
-       // draw cursor after performing move/resize to have the panel pos/size updated before mouse_over_panel
-       const vector cursorsize = '32 32 0';
-       float cursor_alpha = 1 - autocvar__menu_alpha;
-
-       if(!mouse_over_panel)
-               drawpic(mousepos, strcat("gfx/menu/", autocvar_menu_skin, "/cursor.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
-       else if(mouse_over_panel == 1)
-               drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_move.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
-       else if(mouse_over_panel == 2)
-               drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_resize.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
-       else
-               drawpic(mousepos - cursorsize * 0.5, strcat("gfx/menu/", autocvar_menu_skin, "/cursor_resize2.tga"), cursorsize, '1 1 1', cursor_alpha, DRAWFLAG_NORMAL);
-
-       prevMouseClicked = mouseClicked;
-}
-void HUD_Configure_DrawGrid()
-{
-       float i;
-       if(autocvar_hud_configure_grid && autocvar_hud_configure_grid_alpha)
-       {
-               hud_configure_gridSize.x = bound(0.005, cvar("hud_configure_grid_xsize"), 0.2);
-               hud_configure_gridSize.y = bound(0.005, cvar("hud_configure_grid_ysize"), 0.2);
-               hud_configure_realGridSize.x = hud_configure_gridSize.x * vid_conwidth;
-               hud_configure_realGridSize.y = hud_configure_gridSize.y * vid_conheight;
-               vector s;
-               // x-axis
-               s = eX + eY * vid_conheight;
-               for(i = 1; i < 1/hud_configure_gridSize.x; ++i)
-                       drawfill(eX * i * hud_configure_realGridSize.x, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
-               // y-axis
-               s = eY + eX * vid_conwidth;
-               for(i = 1; i < 1/hud_configure_gridSize.y; ++i)
-                       drawfill(eY * i * hud_configure_realGridSize.y, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
-       }
-}
-
-float _menu_alpha_prev;
-void HUD_Configure_Frame()
-{
-       int i;
-       if(autocvar__hud_configure)
-       {
-               if(isdemo() || intermission == 2)
-               {
-                       HUD_Configure_Exit_Force();
-                       return;
-               }
-
-               if(!hud_configure_prev)
-               {
-                       if(autocvar_hud_cursormode)
-                               setcursormode(1);
-                       hudShiftState = 0;
-                       for(i = hud_panels_COUNT - 1; i >= 0; --i)
-                               hud_panels[panel_order[i]].update_time = time;
-               }
-
-               // NOTE this check is necessary because _menu_alpha isn't updated the frame the menu gets enabled
-               if(autocvar__menu_alpha != _menu_alpha_prev)
-               {
-                       if(autocvar__menu_alpha == 0)
-                               menu_enabled = 0;
-                       _menu_alpha_prev = autocvar__menu_alpha;
-               }
-
-               HUD_Configure_DrawGrid();
-       }
-       else if(hud_configure_prev)
-       {
-               if(menu_enabled)
-                       menu_enabled = 0;
-               if(autocvar_hud_cursormode)
-                       setcursormode(0);
-       }
-}
-
-const float hlBorderSize = 2;
-const string hlBorder = "gfx/hud/default/border_highlighted";
-const string hlBorder2 = "gfx/hud/default/border_highlighted2";
-void HUD_Panel_HlBorder(float myBorder, vector color, float theAlpha)
-{
-       drawfill(panel_pos - '1 1 0' * myBorder, panel_size + '2 2 0' * myBorder, '0 0.5 1', .5 * theAlpha, DRAWFLAG_NORMAL);
-       drawpic_tiled(panel_pos - '1 1 0' * myBorder, hlBorder, '8 1 0' * hlBorderSize, eX * (panel_size.x + 2 * myBorder) + eY * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
-       drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * (panel_size.y + 2 * myBorder - hlBorderSize), hlBorder, '8 1 0' * hlBorderSize, eX * (panel_size.x + 2 * myBorder) + eY * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
-       drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * hlBorderSize, hlBorder2, '1 8 0' * hlBorderSize, eY * (panel_size.y + 2 * myBorder - 2 * hlBorderSize) + eX * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
-       drawpic_tiled(panel_pos - '1 1 0' * myBorder + eY * hlBorderSize + eX * (panel_size.x + 2 * myBorder - hlBorderSize), hlBorder2, '1 8 0' * hlBorderSize, eY * (panel_size.y + 2 * myBorder - 2 * hlBorderSize) + eX * hlBorderSize, color, theAlpha, DRAWFLAG_NORMAL);
-}
-
-void HUD_Configure_PostDraw()
-{
-       if(autocvar__hud_configure)
-       {
-               if(tab_panel)
-               {
-                       panel = tab_panel;
-                       HUD_Panel_UpdatePosSize();
-                       drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .2, DRAWFLAG_NORMAL);
-               }
-               if(highlightedPanel)
-               {
-                       panel = highlightedPanel;
-                       HUD_Panel_UpdatePosSize();
-                       HUD_Panel_HlBorder(panel_bg_border * hlBorderSize, '0 0.5 1', 0.4 * (1 - autocvar__menu_alpha));
-               }
-       }
-}
diff --git a/qcsrc/client/hud_config.qh b/qcsrc/client/hud_config.qh
deleted file mode 100644 (file)
index 0579228..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef CLIENT_HUD_CONFIG_H
-#define CLIENT_HUD_CONFIG_H
-
-const int S_MOUSE1 = 1;
-const int S_MOUSE2 = 2;
-const int S_MOUSE3 = 4;
-int mouseClicked;
-int prevMouseClicked; // previous state
-float prevMouseClickedTime; // time during previous left mouse click, to check for doubleclicks
-vector prevMouseClickedPos; // pos during previous left mouse click, to check for doubleclicks
-
-void HUD_Panel_ExportCfg(string cfgname);
-
-void HUD_Panel_Mouse();
-
-void HUD_Configure_Frame();
-
-void HUD_Configure_PostDraw();
-
-float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary);
-
-#endif
diff --git a/qcsrc/client/laser.qc b/qcsrc/client/laser.qc
deleted file mode 100644 (file)
index 1c63a0d..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-#include "laser.qh"
-
-#include "../lib/csqcmodel/interpolate.qh"
-
-// a laser goes from origin in direction angles
-// it has color 'colormod'
-// and stops when something is in the way
-entityclass(Laser);
-class(Laser) .int cnt; // end effect
-class(Laser) .vector colormod;
-class(Laser) .int state; // on-off
-class(Laser) .int count; // flags for the laser
-class(Laser) .vector velocity;
-class(Laser) .float alpha;
-class(Laser) .float scale; // scaling factor of the thickness
-class(Laser) .float modelscale; // scaling factor of the dlight
-
-void Draw_Laser(entity this)
-{
-       if(!self.state)
-               return;
-       InterpolateOrigin_Do();
-       if(self.count & 0x80)
-       {
-               if(self.count & 0x10)
-               {
-                       trace_endpos = self.velocity;
-                       trace_dphitq3surfaceflags = 0;
-               }
-               else
-                       traceline(self.origin, self.velocity, 0, self);
-       }
-       else
-       {
-               if(self.count & 0x10)
-               {
-                       makevectors(self.angles);
-                       trace_endpos = self.origin + v_forward * 1048576;
-                       trace_dphitq3surfaceflags = Q3SURFACEFLAG_SKY;
-               }
-               else
-               {
-                       makevectors(self.angles);
-                       traceline(self.origin, self.origin + v_forward * 32768, 0, self);
-                       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
-                               trace_endpos = self.origin + v_forward * 1048576;
-               }
-       }
-       if(self.scale != 0)
-       {
-               if(self.alpha)
-               {
-                       Draw_CylindricLine(self.origin, trace_endpos, self.scale, "particles/laserbeam", 0, time * 3, self.colormod, self.alpha, DRAWFLAG_NORMAL, view_origin);
-               }
-               else
-               {
-                       Draw_CylindricLine(self.origin, trace_endpos, self.scale, "particles/laserbeam", 0, time * 3, self.colormod, 0.5, DRAWFLAG_ADDITIVE, view_origin);
-               }
-       }
-       if (!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
-       {
-               if(self.cnt >= 0)
-                       pointparticles(self.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
-               if(self.colormod != '0 0 0' && self.modelscale != 0)
-                       adddynamiclight(trace_endpos + trace_plane_normal * 1, self.modelscale, self.colormod * 5);
-       }
-}
-
-void Ent_Laser()
-{
-       InterpolateOrigin_Undo();
-
-       // 30 bytes, or 13 bytes for just moving
-       int f = ReadByte();
-       self.count = (f & 0xF0);
-
-       if(self.count & 0x80)
-               self.iflags = IFLAG_VELOCITY | IFLAG_ORIGIN;
-       else
-               self.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
-
-       if(f & 1)
-       {
-               self.origin_x = ReadCoord();
-               self.origin_y = ReadCoord();
-               self.origin_z = ReadCoord();
-               setorigin(self, self.origin);
-       }
-       if(f & 8)
-       {
-               self.colormod_x = ReadByte() / 255.0;
-               self.colormod_y = ReadByte() / 255.0;
-               self.colormod_z = ReadByte() / 255.0;
-               if(f & 0x40)
-                       self.alpha = ReadByte() / 255.0;
-               else
-                       self.alpha = 0;
-               self.scale = 2;
-               self.modelscale = 50;
-               if(f & 0x20)
-               {
-                       self.scale *= ReadByte() / 16.0; // beam radius
-                       self.modelscale *= ReadByte() / 16.0; // dlight radius
-               }
-               if((f & 0x80) || !(f & 0x10))
-                       self.cnt = ReadShort() - 1; // effect number
-               else
-                       self.cnt = 0;
-       }
-       if(f & 2)
-       {
-               if(f & 0x80)
-               {
-                       self.velocity_x = ReadCoord();
-                       self.velocity_y = ReadCoord();
-                       self.velocity_z = ReadCoord();
-               }
-               else
-               {
-                       self.angles_x = ReadAngle();
-                       self.angles_y = ReadAngle();
-               }
-       }
-       if(f & 4)
-               self.state = ReadByte();
-       InterpolateOrigin_Note();
-       self.draw = Draw_Laser;
-}
diff --git a/qcsrc/client/laser.qh b/qcsrc/client/laser.qh
deleted file mode 100644 (file)
index 32c6cd8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef CLIENT_LASER_H
-#define CLIENT_LASER_H
-
-void Ent_Laser();
-
-#endif
index d43c0bbbef658585503674777cefd73204bcfc8f..1d543af2607457e97cf3fa85338116f72a5ce864 100644 (file)
@@ -1,18 +1,10 @@
 #include "main.qh"
 
-#include "controlpoint.qh"
-#include "damage.qh"
-#include "effects.qh"
-#include "generator.qh"
-#include "gibs.qh"
+#include "../common/effects/qc/all.qh"
 #include "hook.qh"
-#include "hud.qh"
-#include "hud_config.qh"
-#include "laser.qh"
+#include "hud/all.qh"
 #include "mapvoting.qh"
-#include "modeleffects.qh"
 #include "mutators/events.qh"
-#include "particles.qh"
 #include "quickmenu.qh"
 #include "scoreboard.qh"
 #include "shownames.qh"
@@ -27,7 +19,6 @@
 #include "../common/minigames/cl_minigames_hud.qh"
 #include "../common/net_notice.qh"
 #include "../common/triggers/include.qh"
-#include "../common/turrets/cl_turrets.qh"
 #include "../common/vehicles/all.qh"
 #include "../lib/csqcmodel/cl_model.qh"
 #include "../lib/csqcmodel/interpolate.qh"
 // BEGIN REQUIRED CSQC FUNCTIONS
 //include "main.qh"
 
-entity clearentity_ent;
-void clearentity(entity e)
-{
-       if (!clearentity_ent)
-       {
-               clearentity_ent = spawn();
-               clearentity_ent.classname = "clearentity";
-       }
-       int n = e.entnum;
-       copyentity(clearentity_ent, e);
-       e.entnum = n;
-}
-
 #define DP_CSQC_ENTITY_REMOVE_IS_B0RKED
-void menu_show_error()
-{
-       drawstring('0 200 0', _("ERROR - MENU IS VISIBLE BUT NO MENU WAS DEFINED!"), '8 8 0', '1 0 0', 1, 0);
-}
 
 // CSQC_Init : Called every time the CSQC code is initialized (essentially at map load)
 // Useful for precaching things
 
-void menu_sub_null()
-{
-}
-
-void draw_null(entity this) { }
-
-string forcefog;
 void ConsoleCommand_macro_init();
-void CSQC_Init(void)
+void CSQC_Init()
 {
        prvm_language = strzone(cvar_string("prvm_language"));
 
 #ifdef WATERMARK
-       LOG_TRACEF("^4CSQC Build information: ^1%s\n", WATERMARK);
+       LOG_INFOF("^4CSQC Build information: ^1%s\n", WATERMARK);
 #endif
 
-       int i;
-
        binddb = db_create();
        tempdb = db_create();
        ClientProgsDB = db_load("client.db");
        compressShortVector_init();
 
        draw_endBoldFont();
-       menu_visible = false;
-       menu_show = menu_show_error;
-       menu_action = func_null;
 
-       for(i = 0; i < 255; ++i)
-               if(getplayerkeyvalue(i, "viewentity") == "")
-                       break;
-       maxclients = i;
+       {
+               int i = 0;
+               for ( ; i < 255; ++i)
+                       if (getplayerkeyvalue(i, "viewentity") == "")
+                               break;
+               maxclients = i;
+       }
 
        //registercommand("hud_configure");
        //registercommand("hud_save");
@@ -114,7 +79,7 @@ void CSQC_Init(void)
        gametype = 0;
 
        // hud_fields uses strunzone on the titles!
-       for(i = 0; i < MAX_HUD_FIELDS; ++i)
+       for(int i = 0; i < MAX_HUD_FIELDS; ++i)
                hud_title[i] = strzone("(null)");
 
        Cmd_HUD_SetFields(0);
@@ -131,44 +96,42 @@ void CSQC_Init(void)
        // needs to be done so early because of the constants they create
        static_init();
        static_init_late();
+       static_init_precache();
 
        // precaches
 
-       Projectile_Precache();
-       Tuba_Precache();
-
        if(autocvar_cl_reticle)
        {
                precache_pic("gfx/reticle_normal");
                // weapon reticles are precached in weapon files
        }
 
-       get_mi_min_max_texcoords(1); // try the CLEVER way first
-       minimapname = strcat("gfx/", mi_shortname, "_radar.tga");
-       shortmapname = mi_shortname;
-
-       if(precache_pic(minimapname) == "")
        {
-               // but maybe we have a non-clever minimap
-               minimapname = strcat("gfx/", mi_shortname, "_mini.tga");
-               if(precache_pic(minimapname) == "")
-                       minimapname = ""; // FAIL
-               else
-                       get_mi_min_max_texcoords(0); // load new texcoords
-       }
+               get_mi_min_max_texcoords(1); // try the CLEVER way first
+               minimapname = strcat("gfx/", mi_shortname, "_radar.tga");
+               shortmapname = mi_shortname;
 
-       mi_center = (mi_min + mi_max) * 0.5;
-       mi_scale = mi_max - mi_min;
-       minimapname = strzone(minimapname);
+               if (precache_pic(minimapname) == "")
+               {
+                       // but maybe we have a non-clever minimap
+                       minimapname = strcat("gfx/", mi_shortname, "_mini.tga");
+                       if (precache_pic(minimapname) == "")
+                               minimapname = ""; // FAIL
+                       else
+                               get_mi_min_max_texcoords(0); // load new texcoords
+               }
 
-       WarpZone_Init();
+               mi_center = (mi_min + mi_max) * 0.5;
+               mi_scale = mi_max - mi_min;
+               minimapname = strzone(minimapname);
+       }
 
        hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin));
        draw_currentSkin = strzone(strcat("gfx/menu/", cvar_string("menu_skin")));
 }
 
 // CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc)
-void Shutdown(void)
+void Shutdown()
 {
        WarpZone_Shutdown();
 
@@ -274,7 +237,8 @@ float SetTeam(entity o, int Team)
 }
 
 void Playerchecker_Think()
-{SELFPARAM();
+{
+       SELFPARAM();
     int i;
        entity e;
        for(i = 0; i < maxclients; ++i)
@@ -297,7 +261,10 @@ void Playerchecker_Think()
                        {
                                // player connected
                                if (!e)
-                                       playerslots[i] = e = spawn();
+                               {
+                                       playerslots[i] = e = new(playerslot);
+                                       make_pure(e);
+                               }
                                e.sv_entnum = i;
                                e.ping = 0;
                                e.ping_packetloss = 0;
@@ -309,15 +276,15 @@ void Playerchecker_Think()
                        }
                }
        }
-       self.nextthink = time + 0.2;
+       this.nextthink = time + 0.2;
 }
 
 void Porto_Init();
 void TrueAim_Init();
-void PostInit(void)
+void PostInit()
 {
-       entity playerchecker;
-       playerchecker = spawn();
+       entity playerchecker = new(playerchecker);
+       make_pure(playerchecker);
        playerchecker.think = Playerchecker_Think;
        playerchecker.nextthink = time + 0.2;
 
@@ -336,16 +303,13 @@ void PostInit(void)
 // In the case of mouse input after a setcursormode(1) call, nPrimary is xpos, nSecondary is ypos.
 float CSQC_InputEvent(float bInputType, float nPrimary, float nSecondary)
 {
-       float bSkipKey;
-       bSkipKey = false;
-
        if (HUD_Panel_InputEvent(bInputType, nPrimary, nSecondary))
                return true;
 
        if (QuickMenu_InputEvent(bInputType, nPrimary, nSecondary))
                return true;
 
-       if ( HUD_Radar_InputEvent(bInputType, nPrimary, nSecondary) )
+       if (HUD_Radar_InputEvent(bInputType, nPrimary, nSecondary))
                return true;
 
        if (MapVote_InputEvent(bInputType, nPrimary, nSecondary))
@@ -354,11 +318,7 @@ float CSQC_InputEvent(float bInputType, float nPrimary, float nSecondary)
        if (HUD_Minigame_InputEvent(bInputType, nPrimary, nSecondary))
                return true;
 
-       if(menu_visible && menu_action)
-               if(menu_action(bInputType, nPrimary, nSecondary))
-                       return true;
-
-       return bSkipKey;
+       return false;
 }
 
 // END REQUIRED CSQC FUNCTIONS
@@ -368,37 +328,42 @@ float CSQC_InputEvent(float bInputType, float nPrimary, float nSecondary)
 // BEGIN OPTIONAL CSQC FUNCTIONS
 
 void Ent_RemoveEntCS()
-{SELFPARAM();
-       entcs_receiver[self.sv_entnum] = NULL;
+{
+       SELFPARAM();
+       entcs_receiver[this.sv_entnum] = NULL;
 }
-void Ent_ReadEntCS()
-{SELFPARAM();
+
+NET_HANDLE(ENT_CLIENT_ENTCS, bool isnew)
+{
+       make_pure(this);
+       this.classname = "entcs_receiver";
        InterpolateOrigin_Undo();
-       self.classname = "entcs_receiver";
        int sf = ReadByte();
 
        if(sf & BIT(0))
-               self.sv_entnum = ReadByte();
+               this.sv_entnum = ReadByte();
        if (sf & BIT(1))
        {
-               self.origin_x = ReadShort();
-               self.origin_y = ReadShort();
-               self.origin_z = ReadShort();
-               setorigin(self, self.origin);
+               this.origin_x = ReadShort();
+               this.origin_y = ReadShort();
+               this.origin_z = ReadShort();
+               setorigin(this, this.origin);
        }
        if (sf & BIT(2))
        {
-               self.angles_y = ReadByte() * 360.0 / 256;
-               self.angles_x = self.angles_z = 0;
+               this.angles_y = ReadByte() * 360.0 / 256;
+               this.angles_x = this.angles_z = 0;
        }
        if (sf & BIT(3))
-               self.healthvalue = ReadByte() * 10;
+               this.healthvalue = ReadByte() * 10;
        if (sf & BIT(4))
-               self.armorvalue = ReadByte() * 10;
+               this.armorvalue = ReadByte() * 10;
 
-       entcs_receiver[self.sv_entnum] = self;
-       self.entremove = Ent_RemoveEntCS;
-       self.iflags |= IFLAG_ORIGIN;
+       return = true;
+
+       entcs_receiver[this.sv_entnum] = this;
+       this.entremove = Ent_RemoveEntCS;
+       this.iflags |= IFLAG_ORIGIN;
 
        InterpolateOrigin_Note();
 }
@@ -406,44 +371,49 @@ void Ent_ReadEntCS()
 void Ent_Remove();
 
 void Ent_RemovePlayerScore()
-{SELFPARAM();
-       if(self.owner) {
-               SetTeam(self.owner, -1);
-               self.owner.gotscores = 0;
+{
+       SELFPARAM();
+       if(this.owner) {
+               SetTeam(this.owner, -1);
+               this.owner.gotscores = 0;
                for(int i = 0; i < MAX_SCORE; ++i) {
-                       self.owner.(scores[i]) = 0; // clear all scores
+                       this.owner.(scores[i]) = 0; // clear all scores
                }
        }
 }
 
-void Ent_ReadPlayerScore()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_SCORES, bool isnew)
+{
+       make_pure(this);
        int i, n;
        bool isNew;
        entity o;
 
        // damnit -.- don't want to go change every single .sv_entnum in hud.qc AGAIN
        // (no I've never heard of M-x replace-string, sed, or anything like that)
-       isNew = !self.owner; // workaround for DP bug
+       isNew = !this.owner; // workaround for DP bug
        n = ReadByte()-1;
 
 #ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED
-       if(!isNew && n != self.sv_entnum)
+       if(!isNew && n != this.sv_entnum)
        {
                //print("A CSQC entity changed its owner!\n");
-               LOG_INFOF("A CSQC entity changed its owner! (edict: %d, classname: %s)\n", num_for_edict(self), self.classname);
+               LOG_INFOF("A CSQC entity changed its owner! (edict: %d, classname: %s)\n", num_for_edict(this), this.classname);
                isNew = true;
                Ent_Remove();
-               self.enttype = ENT_CLIENT_SCORES;
        }
 #endif
 
-       self.sv_entnum = n;
+       this.sv_entnum = n;
 
-       if (!(playerslots[self.sv_entnum]))
-               playerslots[self.sv_entnum] = spawn();
-       o = self.owner = playerslots[self.sv_entnum];
-       o.sv_entnum = self.sv_entnum;
+       o = playerslots[this.sv_entnum];
+       if (!o)
+       {
+               o = playerslots[this.sv_entnum] = new(playerslot);
+               make_pure(o);
+       }
+       this.owner = o;
+       o.sv_entnum = this.sv_entnum;
        o.gotscores = 1;
 
        //if (!o.sort_prev)
@@ -468,19 +438,22 @@ void Ent_ReadPlayerScore()
                                o.(scores[i]) = ReadChar();
                }
 
+       return = true;
+
        if(o.sort_prev)
                HUD_UpdatePlayerPos(o); // if not registered, we cannot do this yet!
 
-       self.entremove = Ent_RemovePlayerScore;
+       this.entremove = Ent_RemovePlayerScore;
 }
 
-void Ent_ReadTeamScore()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TEAMSCORES, bool isnew)
+{
+       make_pure(this);
        int i;
        entity o;
 
-       self.team = ReadByte();
-       o = self.owner = GetTeam(self.team, true); // these team numbers can always be trusted
+       this.team = ReadByte();
+       o = this.owner = GetTeam(this.team, true); // these team numbers can always be trusted
 
     int sf, lf;
 #if MAX_TEAMSCORE <= 8
@@ -500,11 +473,14 @@ void Ent_ReadTeamScore()
                                o.(teamscores[i]) = ReadChar();
                }
 
+       return = true;
+
        HUD_UpdateTeamPos(o);
 }
 
-void Ent_ClientData()
+NET_HANDLE(ENT_CLIENT_CLIENTDATA, bool isnew)
 {
+       make_pure(this);
        float newspectatee_status;
 
     int f = ReadByte();
@@ -532,6 +508,8 @@ void Ent_ClientData()
        else
                angles_held_status = 0;
 
+       return = true;
+
        if(newspectatee_status != spectatee_status)
        {
                // clear race stuff
@@ -552,8 +530,9 @@ void Ent_ClientData()
        // we could get rid of spectatee_status, and derive it from player_localentnum and player_localnum
 }
 
-void Ent_Nagger()
+NET_HANDLE(ENT_CLIENT_NAGGER, bool isnew)
 {
+       make_pure(this);
     int i, j, b, f;
 
     int nags = ReadByte(); // NAGS NAGS NAGS NAGS NAGS NAGS NADZ NAGS NAGS NAGS
@@ -600,6 +579,8 @@ void Ent_Nagger()
                }
        }
 
+       return = true;
+
        ready_waiting = (nags & BIT(0));
        ready_waiting_for_me = (nags & BIT(1));
        vote_waiting = (nags & BIT(2));
@@ -607,8 +588,9 @@ void Ent_Nagger()
        warmup_stage = (nags & BIT(4));
 }
 
-void Ent_EliminatedPlayers()
+NET_HANDLE(ENT_CLIENT_ELIMINATEDPLAYERS, bool isnew)
 {
+       make_pure(this);
     int i, j, b, f;
 
     int sf = ReadByte();
@@ -626,53 +608,51 @@ void Ent_EliminatedPlayers()
                                                playerslots[j].eliminated = 0;
                }
        }
+       return true;
 }
 
-void Ent_RandomSeed()
+NET_HANDLE(ENT_CLIENT_RANDOMSEED, bool isnew)
 {
-       float s;
+       make_pure(this);
        prandom_debug();
-       s = ReadShort();
+       float s = ReadShort();
        psrandom(s);
+       return true;
 }
 
-void Ent_ReadAccuracy(void)
+NET_HANDLE(ENT_CLIENT_ACCURACY, bool isnew)
 {
-    int f, w;
+       make_pure(this);
     int sf = ReadInt24_t();
-       if(sf == 0)
-       {
-               for(w = 0; w <= WEP_LAST - WEP_FIRST; ++w)
+       if (sf == 0) {
+               for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w)
                        weapon_accuracy[w] = -1;
-               return;
+               return true;
        }
 
-       for(w = 0, f = 1; w <= WEP_LAST - WEP_FIRST; ++w)
-       {
-               if(sf & f)
-               {
+       int f = 1;
+       for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w) {
+               if (sf & f) {
             int b = ReadByte();
-                       if(b == 0)
+                       if (b == 0)
                                weapon_accuracy[w] = -1;
-                       else if(b == 255)
+                       else if (b == 255)
                                weapon_accuracy[w] = 1.0; // no better error handling yet, sorry
                        else
                                weapon_accuracy[w] = (b - 1.0) / 100.0;
                }
-               if(f == 0x800000)
-                       f = 1;
-               else
-                       f *= 2;
+               f = (f == 0x800000) ? 1 : f * 2;
        }
+       return true;
 }
 
 void Spawn_Draw(entity this)
 {
-       pointparticles(this.cnt, this.origin + '0 0 28', '0 0 2', bound(0, frametime, 0.1));
+       __pointparticles(this.cnt, this.origin + '0 0 28', '0 0 2', bound(0, frametime, 0.1));
 }
 
-void Ent_ReadSpawnPoint(float is_new) // entity for spawnpoint
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_SPAWNPOINT, bool is_new)
+{
        float teamnum = (ReadByte() - 1);
        vector spn_origin;
        spn_origin.x = ReadShort();
@@ -681,19 +661,19 @@ void Ent_ReadSpawnPoint(float is_new) // entity for spawnpoint
 
        //if(is_new)
        //{
-               self.origin = spn_origin;
-               setsize(self, PL_MIN_CONST, PL_MAX_CONST);
+               this.origin = spn_origin;
+               setsize(this, PL_MIN_CONST, PL_MAX_CONST);
                //droptofloor();
 
                /*if(autocvar_cl_spawn_point_model) // needs a model first
                {
-                       self.mdl = "models/spawnpoint.md3";
-                       self.colormod = Team_ColorRGB(teamnum);
-                       precache_model(self.mdl);
-                       setmodel(self, self.mdl);
-                       self.drawmask = MASK_NORMAL;
-                       //self.movetype = MOVETYPE_NOCLIP;
-                       //self.draw = Spawn_Draw;
+                       this.mdl = "models/spawnpoint.md3";
+                       this.colormod = Team_ColorRGB(teamnum);
+                       precache_model(this.mdl);
+                       setmodel(this, this.mdl);
+                       this.drawmask = MASK_NORMAL;
+                       //this.movetype = MOVETYPE_NOCLIP;
+                       //this.draw = Spawn_Draw;
                }*/
                if(autocvar_cl_spawn_point_particles)
                {
@@ -701,24 +681,25 @@ void Ent_ReadSpawnPoint(float is_new) // entity for spawnpoint
                        {
                                switch(teamnum)
                                {
-                                       case NUM_TEAM_1: self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_RED); break;
-                                       case NUM_TEAM_2: self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_BLUE); break;
-                                       case NUM_TEAM_3: self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_YELLOW); break;
-                                       case NUM_TEAM_4: self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_PINK); break;
-                                       default: self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_NEUTRAL); break;
+                                       case NUM_TEAM_1: this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_RED); break;
+                                       case NUM_TEAM_2: this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_BLUE); break;
+                                       case NUM_TEAM_3: this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_YELLOW); break;
+                                       case NUM_TEAM_4: this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_PINK); break;
+                                       default: this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_NEUTRAL); break;
                                }
                        }
-                       else { self.cnt = particleeffectnum(EFFECT_SPAWNPOINT_NEUTRAL); }
+                       else { this.cnt = particleeffectnum(EFFECT_SPAWNPOINT_NEUTRAL); }
 
-                       self.draw = Spawn_Draw;
+                       this.draw = Spawn_Draw;
                }
        //}
 
-       //printf("Ent_ReadSpawnPoint(is_new = %d); origin = %s, team = %d, effect = %d\n", is_new, vtos(self.origin), teamnum, self.cnt);
+       //printf("Ent_ReadSpawnPoint(is_new = %d); origin = %s, team = %d, effect = %d\n", is_new, vtos(this.origin), teamnum, this.cnt);
+       return true;
 }
 
-void Ent_ReadSpawnEvent(float is_new)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_SPAWNEVENT, bool is_new)
+{
        // If entnum is 0, ONLY do the local spawn actions
        // this way the server can disable the sending of
        // spawn origin or such to clients if wanted.
@@ -726,9 +707,9 @@ void Ent_ReadSpawnEvent(float is_new)
 
        if(entnum)
        {
-               self.origin_x = ReadShort();
-               self.origin_y = ReadShort();
-               self.origin_z = ReadShort();
+               this.origin_x = ReadShort();
+               this.origin_y = ReadShort();
+               this.origin_z = ReadShort();
 
                if(is_new)
                {
@@ -738,19 +719,20 @@ void Ent_ReadSpawnEvent(float is_new)
                        {
                                switch(teamnum)
                                {
-                                       case NUM_TEAM_1: pointparticles(particleeffectnum(EFFECT_SPAWN_RED), self.origin, '0 0 0', 1); break;
-                                       case NUM_TEAM_2: pointparticles(particleeffectnum(EFFECT_SPAWN_BLUE), self.origin, '0 0 0', 1); break;
-                                       case NUM_TEAM_3: pointparticles(particleeffectnum(EFFECT_SPAWN_YELLOW), self.origin, '0 0 0', 1); break;
-                                       case NUM_TEAM_4: pointparticles(particleeffectnum(EFFECT_SPAWN_PINK), self.origin, '0 0 0', 1); break;
-                                       default: pointparticles(particleeffectnum(EFFECT_SPAWN_NEUTRAL), self.origin, '0 0 0', 1); break;
+                                       case NUM_TEAM_1: pointparticles(EFFECT_SPAWN_RED, this.origin, '0 0 0', 1); break;
+                                       case NUM_TEAM_2: pointparticles(EFFECT_SPAWN_BLUE, this.origin, '0 0 0', 1); break;
+                                       case NUM_TEAM_3: pointparticles(EFFECT_SPAWN_YELLOW, this.origin, '0 0 0', 1); break;
+                                       case NUM_TEAM_4: pointparticles(EFFECT_SPAWN_PINK, this.origin, '0 0 0', 1); break;
+                                       default: pointparticles(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1); break;
                                }
                        }
                        if(autocvar_cl_spawn_event_sound)
                        {
-                               sound(self, CH_TRIGGER, SND_SPAWN, VOL_BASE, ATTEN_NORM);
+                               sound(this, CH_TRIGGER, SND_SPAWN, VOL_BASE, ATTEN_NORM);
                        }
                }
        }
+       return = true;
 
        // local spawn actions
        if(is_new && (!entnum || (entnum == player_localentnum)))
@@ -765,21 +747,18 @@ void Ent_ReadSpawnEvent(float is_new)
                }
        }
        HUD_Radar_Hide_Maximized();
-       //printf("Ent_ReadSpawnEvent(is_new = %d); origin = %s, entnum = %d, localentnum = %d\n", is_new, vtos(self.origin), entnum, player_localentnum);
+       //printf("Ent_ReadSpawnEvent(is_new = %d); origin = %s, entnum = %d, localentnum = %d\n", is_new, vtos(this.origin), entnum, player_localentnum);
 }
 
 // CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured.
 // The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS.
-void Ent_RadarLink();
-void Ent_Init();
-void Ent_ScoresInfo();
-void CSQC_Ent_Update(float bIsNewEntity)
-{SELFPARAM();
+void CSQC_Ent_Update(bool isnew)
+{
+       SELFPARAM();
+       this.sourceLocLine = __LINE__;
+       this.sourceLocFile = __FILE__;
        int t = ReadByte();
 
-       if(autocvar_developer_csqcentities)
-               LOG_INFOF("CSQC_Ent_Update(%d) with self=%i self.entnum=%d self.enttype=%d t=%d\n", bIsNewEntity, self, self.entnum, self.enttype, t);
-
        // set up the "time" global for received entities to be correct for interpolation purposes
        float savetime = time;
        if(servertime)
@@ -794,143 +773,79 @@ void CSQC_Ent_Update(float bIsNewEntity)
        }
 
 #ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED
-       if(self.enttype)
+       if (this.enttype)
        {
-               if(t != self.enttype || bIsNewEntity)
+               if (t != this.enttype || isnew)
                {
-                       LOG_INFOF("A CSQC entity changed its type! (edict: %d, server: %d, type: %d -> %d)\n", num_for_edict(self), self.entnum, self.enttype, t);
+                       LOG_INFOF("A CSQC entity changed its type! (edict: %d, server: %d, type: %d -> %d)\n", num_for_edict(this), this.entnum, this.enttype, t);
                        Ent_Remove();
-                       clearentity(self);
-                       bIsNewEntity = 1;
+                       clearentity(this);
+                       isnew = true;
                }
        }
        else
        {
-               if(!bIsNewEntity)
+               if (!isnew)
                {
-                       LOG_INFOF("A CSQC entity appeared out of nowhere! (edict: %d, server: %d, type: %d)\n", num_for_edict(self), self.entnum, t);
-                       bIsNewEntity = 1;
+                       LOG_INFOF("A CSQC entity appeared out of nowhere! (edict: %d, server: %d, type: %d)\n", num_for_edict(this), this.entnum, t);
+                       isnew = true;
                }
        }
 #endif
-       self.enttype = t;
+       this.enttype = t;
        bool done = false;
        FOREACH(LinkedEntities, it.m_id == t, LAMBDA(
-               it.m_read(self, bIsNewEntity);
-               done = true;
+               if (isnew) this.classname = it.netname;
+               if (autocvar_developer_csqcentities)
+            LOG_INFOF("CSQC_Ent_Update(%d) at %f with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)\n", isnew, savetime, this, this.entnum, this.enttype, this.classname, t);
+               done = it.m_read(this, isnew);
                break;
        ));
+       time = savetime;
        if (!done)
-       switch(t)
        {
-               case ENT_CLIENT_MUTATOR: {
-                       int mutID = ReadMutator();
-                       if (!MUTATOR_CALLHOOK(CSQC_Ent_Update, mutID, bIsNewEntity))
-                       error(sprintf("Unknown mutator type in CSQC_Ent_Update (mutID: %d, edict: %d, classname: %s)\n", mutID, num_for_edict(self), self.classname));
-                       break;
-               }
-               case ENT_CLIENT_ENTCS: Ent_ReadEntCS(); break;
-               case ENT_CLIENT_SCORES: Ent_ReadPlayerScore(); break;
-               case ENT_CLIENT_TEAMSCORES: Ent_ReadTeamScore(); break;
-               case ENT_CLIENT_POINTPARTICLES: Ent_PointParticles(); break;
-               case ENT_CLIENT_RAINSNOW: Ent_RainOrSnow(); break;
-               case ENT_CLIENT_LASER: Ent_Laser(); break;
-               case ENT_CLIENT_NAGGER: Ent_Nagger(); break;
-               case ENT_CLIENT_ELIMINATEDPLAYERS: Ent_EliminatedPlayers(); break;
-               case ENT_CLIENT_RADARLINK: Ent_RadarLink(); break;
-               case ENT_CLIENT_PROJECTILE: Ent_Projectile(); break;
-               case ENT_CLIENT_GIBSPLASH: Ent_GibSplash(bIsNewEntity); break;
-               case ENT_CLIENT_DAMAGEINFO: Ent_DamageInfo(bIsNewEntity); break;
-               case ENT_CLIENT_INIT: Ent_Init(); break;
-               case ENT_CLIENT_SCORES_INFO: Ent_ScoresInfo(); break;
-               case ENT_CLIENT_MAPVOTE: Ent_MapVote(); break;
-               case ENT_CLIENT_CLIENTDATA: Ent_ClientData(); break;
-               case ENT_CLIENT_RANDOMSEED: Ent_RandomSeed(); break;
-               case ENT_CLIENT_WALL: Ent_Wall(); break;
-               case ENT_CLIENT_MODELEFFECT: Ent_ModelEffect(bIsNewEntity); break;
-               case ENT_CLIENT_TUBANOTE: Ent_TubaNote(bIsNewEntity); break;
-               case ENT_CLIENT_WARPZONE: WarpZone_Read(bIsNewEntity); break;
-               case ENT_CLIENT_WARPZONE_CAMERA: WarpZone_Camera_Read(bIsNewEntity); break;
-               case ENT_CLIENT_WARPZONE_TELEPORTED: WarpZone_Teleported_Read(bIsNewEntity); break;
-               case ENT_CLIENT_TRIGGER_MUSIC: Ent_ReadTriggerMusic(); break;
-               case ENT_CLIENT_HOOK: Ent_ReadHook(bIsNewEntity, ENT_CLIENT_HOOK); break;
-               case ENT_CLIENT_INVENTORY: Inventory_Read(self); break;
-               case ENT_CLIENT_ARC_BEAM: Ent_ReadArcBeam(bIsNewEntity); break;
-               case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break;
-               case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break;
-               case ENT_CLIENT_TURRET: ent_turret(); break;
-               case ENT_CLIENT_GENERATOR: ent_generator(); break;
-               case ENT_CLIENT_CONTROLPOINT_ICON: ent_cpicon(this); break;
-               case ENT_CLIENT_MODEL: CSQCModel_Read(bIsNewEntity); break;
-               case ENT_CLIENT_ITEM: ItemRead(bIsNewEntity); break;
-               case ENT_CLIENT_BUMBLE_RAYGUN: bumble_raygun_read(bIsNewEntity); break;
-               case ENT_CLIENT_SPAWNPOINT: Ent_ReadSpawnPoint(bIsNewEntity); break;
-               case ENT_CLIENT_SPAWNEVENT: Ent_ReadSpawnEvent(bIsNewEntity); break;
-               case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break;
-               case ENT_CLIENT_MINIGAME: ent_read_minigame(); break;
-               case ENT_CLIENT_VIEWLOC: ent_viewloc(); break;
-               case ENT_CLIENT_VIEWLOC_TRIGGER: ent_viewloc_trigger(); break;
-               case ENT_CLIENT_LADDER: ent_func_ladder(); break;
-               case ENT_CLIENT_TRIGGER_PUSH: ent_trigger_push(); break;
-               case ENT_CLIENT_TARGET_PUSH: ent_target_push(); break;
-               case ENT_CLIENT_CONVEYOR: ent_conveyor(); break;
-               case ENT_CLIENT_DOOR: ent_door(); break;
-               case ENT_CLIENT_PLAT: ent_plat(); break;
-               case ENT_CLIENT_SWAMP: ent_swamp(); break;
-               case ENT_CLIENT_CORNER: ent_corner(); break;
-               case ENT_CLIENT_KEYLOCK: ent_keylock(); break;
-               case ENT_CLIENT_TRAIN: ent_train(); break;
-               case ENT_CLIENT_TRIGGER_IMPULSE: ent_trigger_impulse(); break;
-               case ENT_CLIENT_EFFECT: Read_Effect(bIsNewEntity); break;
-
-               default:
-                       //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype));
-                       error(sprintf("Unknown entity type in CSQC_Ent_Update (enttype: %d, edict: %d, classname: %s)\n", self.enttype, num_for_edict(self), self.classname));
-                       break;
+               LOG_FATALF("CSQC_Ent_Update(%d) at %f with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)\n", isnew, savetime, this, this.entnum, this.enttype, this.classname, t);
        }
-
-       time = savetime;
 }
+
 // Destructor, but does NOT deallocate the entity by calling remove(). Also
 // used when an entity changes its type. For an entity that someone interacts
 // with others, make sure it can no longer do so.
 void Ent_Remove()
-{SELFPARAM();
-       if(self.entremove)
-               self.entremove();
+{
+       SELFPARAM();
+       if(this.entremove) this.entremove();
 
-       if(self.skeletonindex)
+       if(this.skeletonindex)
        {
-               skel_delete(self.skeletonindex);
-               self.skeletonindex = 0;
+               skel_delete(this.skeletonindex);
+               this.skeletonindex = 0;
        }
 
-       if(self.snd_looping > 0)
+       if(this.snd_looping > 0)
        {
-               sound(self, self.snd_looping, SND_Null, VOL_BASE, autocvar_g_jetpack_attenuation);
-               self.snd_looping = 0;
+               sound(this, this.snd_looping, SND_Null, VOL_BASE, autocvar_g_jetpack_attenuation);
+               this.snd_looping = 0;
        }
 
-       self.enttype = 0;
-       self.classname = "";
-       self.draw = draw_null;
-       self.entremove = menu_sub_null;
+       this.enttype = 0;
+       this.classname = "";
+       this.draw = func_null;
+       this.entremove = func_null;
        // TODO possibly set more stuff to defaults
 }
-// CSQC_Ent_Remove : Called when the server requests a SSQC / CSQC entity to be removed.  Essentially call remove(self) as well.
+// CSQC_Ent_Remove : Called when the server requests a SSQC / CSQC entity to be removed.  Essentially call remove(this) as well.
 void CSQC_Ent_Remove()
-{SELFPARAM();
-       if(autocvar_developer_csqcentities)
-               LOG_INFOF("CSQC_Ent_Remove() with self=%i self.entnum=%d self.enttype=%d\n", self, self.entnum, self.enttype);
-
-       if(wasfreed(self))
+{
+       SELFPARAM();
+       if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Ent_Remove() with this=%i {.entnum=%d, .enttype=%d}\n", this, this.entnum, this.enttype);
+       if (wasfreed(this))
        {
-               LOG_INFO("WARNING: CSQC_Ent_Remove called for already removed entity. Packet loss?\n");
+               LOG_WARNING("CSQC_Ent_Remove called for already removed entity. Packet loss?\n");
                return;
        }
-       if(self.enttype)
-               Ent_Remove();
-       remove(self);
+       if (this.enttype) Ent_Remove();
+       remove(this);
 }
 
 void Gamemode_Init()
@@ -945,70 +860,79 @@ void Gamemode_Init()
 // CSQC_Parse_StuffCmd : Provides the stuffcmd string in the first parameter that the server provided.  To execute standard behavior, simply execute localcmd with the string.
 void CSQC_Parse_StuffCmd(string strMessage)
 {
-       if(autocvar_developer_csqcentities)
-               LOG_INFOF("CSQC_Parse_StuffCmd(\"%s\")\n", strMessage);
-
+       if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Parse_StuffCmd(\"%s\")\n", strMessage);
        localcmd(strMessage);
 }
 // CSQC_Parse_Print : Provides the print string in the first parameter that the server provided.  To execute standard behavior, simply execute print with the string.
 void CSQC_Parse_Print(string strMessage)
 {
-       if(autocvar_developer_csqcentities)
-               LOG_INFOF("CSQC_Parse_Print(\"%s\")\n", strMessage);
-
+       if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Parse_Print(\"%s\")\n", strMessage);
        print(ColorTranslateRGB(strMessage));
 }
 
 // CSQC_Parse_CenterPrint : Provides the centerprint_hud string in the first parameter that the server provided.
 void CSQC_Parse_CenterPrint(string strMessage)
 {
-       if(autocvar_developer_csqcentities)
-               LOG_INFOF("CSQC_Parse_CenterPrint(\"%s\")\n", strMessage);
-
+       if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Parse_CenterPrint(\"%s\")\n", strMessage);
        centerprint_hud(strMessage);
 }
 
-string notranslate_fogcmd1 = "\nfog ";
-string notranslate_fogcmd2 = "\nr_fog_exp2 0\nr_drawfog 1\n";
-void Fog_Force()
+// CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer.
+// You must ALWAYS first acquire the temporary ID, which is sent as a byte.
+// Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event.
+bool CSQC_Parse_TempEntity()
 {
-       // TODO somehow thwart prvm_globalset client ...
+       // Acquire TE ID
+       int nTEID = ReadByte();
+
+       FOREACH(TempEntities, it.m_id == nTEID, LAMBDA(
+               if (autocvar_developer_csqcentities)
+                       LOG_INFOF("CSQC_Parse_TempEntity() nTEID=%s (%d)\n", it.netname, nTEID);
+               return it.m_read(NULL, true);
+       ));
 
-       if(autocvar_cl_orthoview && autocvar_cl_orthoview_nofog)
-               { localcmd("\nr_drawfog 0\n"); }
-       else if(forcefog != "")
-               { localcmd(strcat(notranslate_fogcmd1, forcefog, notranslate_fogcmd2)); }
+       if (autocvar_developer_csqcentities)
+               LOG_INFOF("CSQC_Parse_TempEntity() with nTEID=%d\n", nTEID);
+
+       // No special logic for this temporary entity; return 0 so the engine can handle it
+       return false;
+}
+
+/** TODO somehow thwart prvm_globalset client ... */
+string forcefog;
+void Fog_Force()
+{
+       if (autocvar_cl_orthoview && autocvar_cl_orthoview_nofog)
+               localcmd("\nr_drawfog 0\n");
+       else if (forcefog != "")
+               localcmd(sprintf("\nfog %s\nr_fog_exp2 0\nr_drawfog 1\n", forcefog));
 }
 
 void Gamemode_Init();
-void Ent_ScoresInfo()
-{SELFPARAM();
-    int i;
-       self.classname = "ent_client_scores_info";
+NET_HANDLE(ENT_CLIENT_SCORES_INFO, bool isnew)
+{
+       make_pure(this);
        gametype = ReadInt24_t();
        HUD_ModIcons_SetFunc();
-       for(i = 0; i < MAX_SCORE; ++i)
+       for (int i = 0; i < MAX_SCORE; ++i)
        {
-               if(scores_label[i])
-                       strunzone(scores_label[i]);
+               if (scores_label[i]) strunzone(scores_label[i]);
                scores_label[i] = strzone(ReadString());
                scores_flags[i] = ReadByte();
        }
-       for(i = 0; i < MAX_TEAMSCORE; ++i)
+       for (int i = 0; i < MAX_TEAMSCORE; ++i)
        {
-               if(teamscores_label[i])
-                       strunzone(teamscores_label[i]);
+               if (teamscores_label[i]) strunzone(teamscores_label[i]);
                teamscores_label[i] = strzone(ReadString());
                teamscores_flags[i] = ReadByte();
        }
+       return = true;
        HUD_InitScores();
        Gamemode_Init();
 }
 
-void Ent_Init()
-{SELFPARAM();
-       self.classname = "ent_client_init";
-
+NET_HANDLE(ENT_CLIENT_INIT, bool isnew)
+{
        nb_pb_period = ReadByte() / 32; //Accuracy of 1/32th
 
        hook_shotorigin[0] = decompressShotOrigin(ReadInt24_t());
@@ -1020,8 +944,7 @@ void Ent_Init()
        arc_shotorigin[2] = decompressShotOrigin(ReadInt24_t());
        arc_shotorigin[3] = decompressShotOrigin(ReadInt24_t());
 
-       if(forcefog)
-               strunzone(forcefog);
+       if (forcefog) strunzone(forcefog);
        forcefog = strzone(ReadString());
 
        armorblockpercent = ReadByte() / 255.0;
@@ -1042,18 +965,18 @@ void Ent_Init()
 
        g_trueaim_minrange = ReadCoord();
        g_balance_porto_secondary = ReadByte();
+       return = true;
+
+       MUTATOR_CALLHOOK(Ent_Init);
 
-       if(!postinit)
-               PostInit();
+       if (!postinit) PostInit();
 }
 
-void Net_ReadRace()
+NET_HANDLE(TE_CSQC_RACE, bool isNew)
 {
-       float b;
+       int b = ReadByte();
 
-       b = ReadByte();
-
-       switch(b)
+       switch (b)
        {
                case RACE_NET_CHECKPOINT_HIT_QUALIFYING:
                        race_checkpoint = ReadByte();
@@ -1201,36 +1124,36 @@ void Net_ReadRace()
                                strunzone(race_status_name);
                        race_status_name = strzone(ReadString());
        }
+       return true;
 }
 
-void Net_TeamNagger()
+NET_HANDLE(TE_CSQC_TEAMNAGGER, bool isNew)
 {
        teamnagger = 1;
+       return true;
 }
 
-void Net_ReadPingPLReport()
+NET_HANDLE(TE_CSQC_PINGPLREPORT, bool isNew)
 {
-       int e, pi, pl, ml;
-       e = ReadByte();
-       pi = ReadShort();
-       pl = ReadByte();
-       ml = ReadByte();
-       if (!(playerslots[e]))
-               return;
-       playerslots[e].ping = pi;
-       playerslots[e].ping_packetloss = pl / 255.0;
-       playerslots[e].ping_movementloss = ml / 255.0;
+       int i = ReadByte();
+       int pi = ReadShort();
+       int pl = ReadByte();
+       int ml = ReadByte();
+       return = true;
+       entity e = playerslots[i];
+       if (!e) return;
+       e.ping = pi;
+       e.ping_packetloss = pl / 255.0;
+       e.ping_movementloss = ml / 255.0;
 }
 
-void Net_WeaponComplain()
+NET_HANDLE(TE_CSQC_WEAPONCOMPLAIN, bool isNew)
 {
        complain_weapon = ReadByte();
-
-       if(complain_weapon_name)
-               strunzone(complain_weapon_name);
+       if (complain_weapon_name) strunzone(complain_weapon_name);
        complain_weapon_name = strzone(WEP_NAME(complain_weapon));
-
        complain_weapon_type = ReadByte();
+       return = true;
 
        complain_weapon_time = time;
        weapontime = time; // ping the weapon panel
@@ -1243,66 +1166,6 @@ void Net_WeaponComplain()
        }
 }
 
-// CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer.
-// You must ALWAYS first acquire the temporary ID, which is sent as a byte.
-// Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event.
-bool CSQC_Parse_TempEntity()
-{
-       // Acquire TE ID
-       int nTEID = ReadByte();
-
-       if (autocvar_developer_csqcentities)
-               LOG_INFOF("CSQC_Parse_TempEntity() with nTEID=%d\n", nTEID);
-
-       FOREACH(TempEntities, it.m_id == nTEID, LAMBDA(
-               it.m_read(NULL, true);
-               return true;
-       ));
-       switch (nTEID)
-       {
-               case TE_CSQC_MUTATOR:
-                       int mutID = ReadMutator();
-                       if (MUTATOR_CALLHOOK(CSQC_Parse_TempEntity, mutID))
-                       return true;
-               case TE_CSQC_TARGET_MUSIC:
-                       Net_TargetMusic();
-                       return true;
-               case TE_CSQC_PICTURE:
-                       Net_MapVote_Picture();
-                       return true;
-               case TE_CSQC_RACE:
-                       Net_ReadRace();
-                       return true;
-               case TE_CSQC_VORTEXBEAMPARTICLE:
-                       Net_ReadVortexBeamParticle();
-                       return true;
-               case TE_CSQC_TEAMNAGGER:
-                       Net_TeamNagger();
-                       return true;
-               case TE_CSQC_ARC:
-                       Net_ReadArc();
-                       return true;
-               case TE_CSQC_PINGPLREPORT:
-                       Net_ReadPingPLReport();
-                       return true;
-               case TE_CSQC_WEAPONCOMPLAIN:
-                       Net_WeaponComplain();
-                       return true;
-               case TE_CSQC_VEHICLESETUP:
-                       Net_VehicleSetup();
-                       return true;
-               case TE_CSQC_SVNOTICE:
-                       cl_notice_read();
-                       return true;
-               case TE_CSQC_SHOCKWAVEPARTICLE:
-                       Net_ReadShockwaveParticle();
-                       return true;
-               default:
-                       // No special logic for this temporary entity; return 0 so the engine can handle it
-                       return false;
-       }
-}
-
 string getcommandkey(string text, string command)
 {
        string keys;
index acd0bcb1ef3651f2c0f7798ae756fcc6e36dd88a..48f7621879e63ace51b83a5904b4db03aebfdede 100644 (file)
@@ -13,13 +13,6 @@ const float DATABUF_PING = 0;
 
 #define DATABUF_NEXT (5*maxclients)
 
-void() menu_show_error;
-void() menu_sub_null;
-
-float menu_visible;
-var void() menu_show;
-var float(float bInputType, float nPrimary, float nSecondary) menu_action;
-
 // --------------------------------------------------------------------------
 // Onslaught
 
@@ -93,7 +86,7 @@ entity teamslots[17];    // 17 teams (including "spectator team")
 
 .void(entity) draw;
 .void(entity) draw2d;
-.void(void) entremove;
+.void() entremove;
 float drawframetime;
 vector view_origin, view_forward, view_right, view_up;
 
@@ -103,7 +96,7 @@ float button_attack2;
 
 int activeweapon;
 int switchingweapon;
-int switchweapon;
+#define switchweapon STAT(SWITCHWEAPON)
 float current_viewzoom;
 float zoomin_effect;
 float warmup_stage;
index 21bb421a960d3a0a4b8738b32ad9bc6d1ba0df26..a134357aaad4b0eedae07e1c79d4191248031fc1 100644 (file)
@@ -1,6 +1,6 @@
 #include "mapvoting.qh"
 
-#include "hud.qh"
+#include "hud/all.qh"
 #include "scoreboard.qh"
 
 #include "../common/mapinfo.qh"
@@ -851,9 +851,11 @@ void MapVote_UpdateVotes()
        mv_ownvote = ReadByte()-1;
 }
 
-void Ent_MapVote()
+NET_HANDLE(ENT_CLIENT_MAPVOTE, bool isnew)
 {
+       make_pure(self);
        int sf = ReadByte();
+       return = true;
 
        if(sf & 1)
                MapVote_Init();
@@ -865,6 +867,12 @@ void Ent_MapVote()
                MapVote_UpdateVotes();
 }
 
+NET_HANDLE(TE_CSQC_PICTURE, bool isNew)
+{
+       Net_MapVote_Picture();
+       return true;
+}
+
 void Net_MapVote_Picture()
 {
        int type = ReadByte();
index c1c27ad5b13640cf39fa69e4be6e19c427bbe98b..1c84419482c264b841ab336bf6dd351a88cb6b47 100644 (file)
@@ -8,8 +8,6 @@ void Cmd_MapVote_MapDownload(float argc);
 
 float MapVote_InputEvent(float bInputType, float nPrimary, float nSecondary);
 
-void Ent_MapVote();
-
 void Net_MapVote_Picture();
 
 float mv_active;
index 7983e740f1a0862d90a958fa2b64f214653249ef..ab4cb1f15673c6c952872e83e22f2048c3b15237 100644 (file)
@@ -1,6 +1,6 @@
 #include "miscfunctions.qh"
 
-#include "hud.qh"
+#include "hud/all.qh"
 
 #include "../common/command/generic.qh"
 
@@ -123,7 +123,8 @@ entity GetTeam(int Team, bool add)
                return teamslots[num];
        if (!add)
                return world;
-       entity tm = spawn();
+       entity tm = new(team);
+       make_pure(tm);
        tm.team = Team;
        teamslots[num] = tm;
        RegisterTeam(tm);
@@ -155,15 +156,6 @@ float PreviewExists(string name)
        return false;
 }
 
-vector rotate(vector v, float a)
-{
-       vector w = '0 0 0';
-       // FTEQCC SUCKS AGAIN
-       w.x =      v.x * cos(a) + v.y * sin(a);
-       w.y = -1 * v.x * sin(a) + v.y * cos(a);
-       return w;
-}
-
 // decolorizes and team colors the player name when needed
 string playername(string thename, float teamid)
 {
@@ -198,10 +190,6 @@ vector project_3d_to_2d(vector vec)
        return vec;
 }
 
-void dummyfunction(float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8)
-{
-}
-
 float expandingbox_sizefactor_from_fadelerp(float fadelerp)
 {
        return 1.2 / (1.2 - fadelerp);
@@ -286,7 +274,6 @@ void drawstring_expanding(vector position, string text, vector theScale, vector
        sz = expandingbox_sizefactor_from_fadelerp(fadelerp);
 
        drawfontscale = sz * '1 1 0';
-       dummyfunction(0, 0, 0, 0, 0, 0, 0, 0);
        drawstring(position + expandingbox_resize_centered_box_offset(sz, theScale, stringwidth(text, false, theScale * (sz / drawfontscale.x)) / (theScale.x * sz)), text, theScale * (sz / drawfontscale.x), rgb, theAlpha * (1 - fadelerp), flag);
        // width parameter:
        //    (scale_x * sz / drawfontscale_x) * drawfontscale_x * SIZE1 / (scale_x * sz)
@@ -306,7 +293,6 @@ void drawcolorcodedstring_expanding(vector position, string text, vector theScal
        sz = expandingbox_sizefactor_from_fadelerp(fadelerp);
 
        drawfontscale = sz * '1 1 0';
-       dummyfunction(0, 0, 0, 0, 0, 0, 0, 0);
        drawcolorcodedstring(position + expandingbox_resize_centered_box_offset(sz, theScale, stringwidth(text, true, theScale * (sz / drawfontscale.x)) / (theScale.x * sz)), text, theScale * (sz / drawfontscale.x), theAlpha * (1 - fadelerp), flag);
        drawfontscale = '1 1 0';
 }
@@ -547,6 +533,7 @@ float getplayerisdead(float pl)
        return false;
 }
 
+/** engine callback */
 void URI_Get_Callback(int id, float status, string data)
 {
        if(url_URI_Get_Callback(id, status, data))
@@ -568,16 +555,6 @@ void URI_Get_Callback(int id, float status, string data)
        }
 }
 
-void draw_beginBoldFont()
-{
-       drawfont = FONT_USER+2;
-}
-
-void draw_endBoldFont()
-{
-       drawfont = FONT_USER+1;
-}
-
 void Accuracy_LoadLevels()
 {
        if(autocvar_accuracy_color_levels != acc_color_levels)
index b223d88b9ee1408f755ad627acf9c6aeff6558a6..60048d0497bdd65279c9ec7f1e57c0551031bab2 100644 (file)
@@ -44,7 +44,8 @@ float cvar_or(string cv, float v);
 
 vector project_3d_to_2d(vector vec);
 
-void dummyfunction(float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8);
+#define draw_beginBoldFont()    do { drawfont = FONT_USER + 2; } while (0)
+#define draw_endBoldFont()      do { drawfont = FONT_USER + 1; } while (0)
 
 float expandingbox_sizefactor_from_fadelerp(float fadelerp);
 
@@ -151,13 +152,6 @@ vector getcsqcplayercolor(float pl);
 
 float getplayerisdead(float pl);
 
-void URI_Get_Callback(int id, float status, string data);
-
-void draw_beginBoldFont();
-
-void draw_endBoldFont();
-
-
 const int MAX_ACCURACY_LEVELS = 10;
 float acc_lev[MAX_ACCURACY_LEVELS];
 vector acc_col[MAX_ACCURACY_LEVELS];
diff --git a/qcsrc/client/modeleffects.qc b/qcsrc/client/modeleffects.qc
deleted file mode 100644 (file)
index d870d81..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-#include "modeleffects.qh"
-
-.float cnt;
-.float scale;
-.float alpha;
-
-void ModelEffect_Draw(entity this)
-{
-       self.angles = self.angles + frametime * self.avelocity;
-       setorigin(self, self.origin + frametime * self.velocity);
-       self.scale = self.scale1 + (self.scale2 - self.scale1) * (time - self.teleport_time) / (self.lifetime + self.fadetime - self.teleport_time);
-       self.alpha = self.cnt * bound(0, 1 - (time - self.lifetime) / self.fadetime, 1);
-       if(self.alpha < ALPHA_MIN_VISIBLE)
-       {
-               remove(self);
-               return;
-       }
-       self.drawmask = MASK_NORMAL;
-       if(self.scale <= 0)
-       {
-               self.drawmask = 0;
-               return;
-       }
-}
-
-void Ent_ModelEffect(bool isNew)
-{SELFPARAM();
-       self.classname = "modeleffect_spawner";
-
-       int f = ReadByte();
-
-       entity e = spawn();
-       e.classname = "modeleffect";
-       e.model = "from network";
-       e.modelindex = ReadShort();
-       e.skin = ReadByte();
-       e.frame = ReadByte();
-       e.frame1time = time;
-       e.origin_x = ReadCoord();
-       e.origin_y = ReadCoord();
-       e.origin_z = ReadCoord();
-       setorigin(e, e.origin);
-       if(f & 1)
-       {
-               e.velocity_x = ReadCoord();
-               e.velocity_y = ReadCoord();
-               e.velocity_z = ReadCoord();
-       }
-       if(f & 2)
-       {
-               e.angles_x = ReadAngle();
-               e.angles_y = ReadAngle();
-               e.angles_z = ReadAngle();
-       }
-       if(f & 4)
-       {
-               e.avelocity_x = ReadAngle();
-               e.avelocity_y = ReadAngle();
-               e.avelocity_z = ReadAngle();
-       }
-       e.scale1 = ReadShort() / 256.0;
-       e.scale2 = ReadShort() / 256.0;
-       e.lifetime = time + ReadByte() * 0.01;
-       e.fadetime = ReadByte() * 0.01;
-       e.teleport_time = time;
-       e.cnt = ReadByte() / 255.0; // actually alpha
-
-       e.draw = ModelEffect_Draw;
-
-       if(!isNew)
-               remove(e); // yes, this IS stupid, but I don't need to duplicate all the read* stuff then
-}
diff --git a/qcsrc/client/modeleffects.qh b/qcsrc/client/modeleffects.qh
deleted file mode 100644 (file)
index 32641f3..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef CLIENT_MODELEFFECTS_H
-#define CLIENT_MODELEFFECTS_H
-
-entityclass(ModelEffect);
-class(ModelEffect) .float frame1time;
-class(ModelEffect) .float lifetime, fadetime;
-class(ModelEffect) .float teleport_time;
-class(ModelEffect) .float scale1, scale2;
-
-void ModelEffect_Draw(entity this);
-
-void Ent_ModelEffect(bool isNew);
-#endif
index a79e0b4712eef8ade9c5573967e5833a61629128..baaba14aef2a0f6d5607f688f1d79192486f4d0c 100644 (file)
@@ -29,49 +29,25 @@ string cmd_string;
  * }
  */
 #define EV_CSQC_ConsoleCommand(i, o) \
-    /** command name */ i(string, cmd_name) \
-    /** also, argv() can be used */ i(int, cmd_argc) \
-    /** whole command, use only if you really have to */ i(string, cmd_string) \
-    /**/
+       /** command name */ i(string, cmd_name) \
+       /** also, argv() can be used */ i(int, cmd_argc) \
+       /** whole command, use only if you really have to */ i(string, cmd_string) \
+       /**/
 MUTATOR_HOOKABLE(CSQC_ConsoleCommand, EV_CSQC_ConsoleCommand);
 
 /* Called when the crosshair is being updated */
 MUTATOR_HOOKABLE(UpdateCrosshair, EV_NO_ARGS);
 
-/**
- * Called when a temp entity is parsed
- * NOTE: hooks MUST start with:
- *     if (MUTATOR_RETURNVALUE) return;
- *     if (!ReadMutatorEquals(mutator_argv_int_0, name_of_mutator)) return;
- *     return = true;
- */
-#define EV_CSQC_Parse_TempEntity(i, o) \
-    /** mutator id */ i(int, mutator_argv_int_0) \
-    /**/
-MUTATOR_HOOKABLE(CSQC_Parse_TempEntity, EV_CSQC_Parse_TempEntity);
-
-/**
- * Called when a shared entity is updated
- *     if (MUTATOR_RETURNVALUE) return;
- *     if (!ReadMutatorEquals(mutator_argv_int_0, name_of_mutator)) return;
- *     return = true;
- */
-#define EV_CSQC_Ent_Update(i, o) \
-    /** mutator id */ i(int, mutator_argv_int_0) \
-    /** bIsNewEntity */ i(bool, mutator_argv_bool_0) \
-    /**/
-MUTATOR_HOOKABLE(CSQC_Ent_Update, EV_CSQC_Ent_Update);
-
 /** Called when a projectile is linked with CSQC */
 #define EV_Ent_Projectile(i, o) \
-    /** entity id */ i(entity, __self) \
-    /**/
+       /** entity id */ i(entity, __self) \
+       /**/
 MUTATOR_HOOKABLE(Ent_Projectile, EV_Ent_Projectile);
 
 /** Called when a projectile's properties are being modified */
 #define EV_EditProjectile(i, o) \
-    /** entity id */ i(entity, __self) \
-    /**/
+       /** entity id */ i(entity, __self) \
+       /**/
 MUTATOR_HOOKABLE(EditProjectile, EV_EditProjectile);
 
 /* Called when projectiles are precached */
@@ -79,26 +55,26 @@ MUTATOR_HOOKABLE(PrecacheProjectiles, EV_NO_ARGS);
 
 /** Called when updating the attached tags index */
 #define EV_TagIndex_Update(i, o) \
-    /** entity id */ i(entity, __self) \
-    /**/
+       /** entity id */ i(entity, __self) \
+       /**/
 MUTATOR_HOOKABLE(TagIndex_Update, EV_TagIndex_Update);
 
 /** Called when setting the attached tags */
 #define EV_TagIndex_Apply(i, o) \
-    /** entity id */ i(entity, __self) \
-    /**/
+       /** entity id */ i(entity, __self) \
+       /**/
 MUTATOR_HOOKABLE(TagIndex_Apply, EV_TagIndex_Apply);
 
 /** Called when setting up skeleton bones */
 #define EV_Skeleton_CheckBones(i, o) \
-    /** entity id */ i(entity, __self) \
-    /**/
+       /** entity id */ i(entity, __self) \
+       /**/
 MUTATOR_HOOKABLE(Skeleton_CheckBones, EV_Skeleton_CheckBones);
 
 /** Called when setting up bones from the loaded model */
 #define EV_Skeleton_CheckModel(i, o) \
-    /** entity id */ i(entity, __self) \
-    /**/
+       /** entity id */ i(entity, __self) \
+       /**/
 MUTATOR_HOOKABLE(Skeleton_CheckModel, EV_Skeleton_CheckModel);
 
 /** Called when clearing the global parameters for a model */
@@ -106,27 +82,59 @@ MUTATOR_HOOKABLE(ClearModelParams, EV_NO_ARGS);
 
 /** Called when getting the global parameters for a model */
 #define EV_GetModelParams(i, o) \
-    /** entity id */ i(string, checkmodel_input) \
-    /** entity id */ i(string, checkmodel_command) \
-    /**/
+       /** entity id */ i(string, checkmodel_input) \
+       /** entity id */ i(string, checkmodel_command) \
+       /**/
 string checkmodel_input, checkmodel_command;
 MUTATOR_HOOKABLE(GetModelParams, EV_GetModelParams);
 
 /** called when a player presses the jump key */
 #define EV_PlayerJump(i, o) \
-    /**/ i(float, player_multijump) \
-    /**/ i(float, player_jumpheight) \
-    /**/ o(float, player_multijump) \
-    /**/ o(float, player_jumpheight) \
-    /**/
+       /**/ i(float, player_multijump) \
+       /**/ i(float, player_jumpheight) \
+       /**/ o(float, player_multijump) \
+       /**/ o(float, player_jumpheight) \
+       /**/
 float player_multijump;
 float player_jumpheight;
 MUTATOR_HOOKABLE(PlayerJump, EV_PlayerJump);
 
 /** Called checking if 3rd person mode should be forced on */
 #define EV_WantEventchase(i, o) \
-    /** entity id */ i(entity, __self) \
-    /**/
+       /** entity id */ i(entity, __self) \
+       /**/
 MUTATOR_HOOKABLE(WantEventchase, EV_WantEventchase);
 
+#define EV_AnnouncerOption(i, o) \
+       /**/ i(string, ret_string) \
+       /**/ o(string, ret_string) \
+       /**/
+MUTATOR_HOOKABLE(AnnouncerOption, EV_AnnouncerOption);
+
+MUTATOR_HOOKABLE(Ent_Init, EV_NO_ARGS);
+
+#define EV_HUD_Draw_overlay(i, o) \
+       /**/ o(vector, MUTATOR_ARGV_0_vector) \
+       /**/ o(float, MUTATOR_ARGV_0_float) \
+       /**/
+MUTATOR_HOOKABLE(HUD_Draw_overlay, EV_HUD_Draw_overlay);
+
+MUTATOR_HOOKABLE(HUD_Powerups_add, EV_NO_ARGS);
+
+/** Return true to not draw any vortex beam */
+#define EV_Particles_VortexBeam(i, o) \
+       /**/ i(vector, vbeam_shotorg) \
+       /**/ i(vector, vbeam_endpos) \
+       /**/
+vector vbeam_shotorg;
+vector vbeam_endpos;
+MUTATOR_HOOKABLE(Particles_VortexBeam, EV_Particles_VortexBeam);
+
+/** Return true to not draw any impact effect */
+#define EV_Weapon_ImpactEffect(i, o) \
+       /**/ i(entity, w_hitwep) \
+       /**/
+entity w_hitwep;
+MUTATOR_HOOKABLE(Weapon_ImpactEffect, EV_Weapon_ImpactEffect);
+
 #endif
diff --git a/qcsrc/client/particles.qc b/qcsrc/client/particles.qc
deleted file mode 100644 (file)
index 0c7f7a3..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#include "particles.qh"
-
-#include "../common/stats.qh"
-
-#include "../lib/warpzone/common.qh"
-
-void Net_ReadVortexBeamParticle()
-{
-       vector shotorg, endpos;
-       float charge;
-       shotorg.x = ReadCoord(); shotorg.y = ReadCoord(); shotorg.z = ReadCoord();
-       endpos.x = ReadCoord(); endpos.y = ReadCoord(); endpos.z = ReadCoord();
-       charge = ReadByte() / 255.0;
-
-       pointparticles(particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH), shotorg, normalize(endpos - shotorg) * 1000, 1);
-
-       //draw either the old v2.3 beam or the new beam
-       charge = sqrt(charge); // divide evenly among trail spacing and alpha
-       particles_alphamin = particles_alphamax = particles_fade = charge;
-
-       if (autocvar_cl_particles_oldvortexbeam && (getstati(STAT_ALLOW_OLDVORTEXBEAM) || isdemo()))
-               WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM_OLD), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
-       else
-               WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
-}
diff --git a/qcsrc/client/particles.qh b/qcsrc/client/particles.qh
deleted file mode 100644 (file)
index 3735641..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef CLIENT_PARTICLES_H
-#define CLIENT_PARTICLES_H
-.int dphitcontentsmask;
-
-entityclass(PointParticles);
-class(PointParticles) .int cnt; // effect number
-class(PointParticles) .vector velocity; // particle velocity
-class(PointParticles) .float waterlevel; // direction jitter
-class(PointParticles) .int count; // count multiplier
-class(PointParticles) .int impulse; // density
-class(PointParticles) .string noise; // sound
-class(PointParticles) .float atten;
-class(PointParticles) .float volume;
-class(PointParticles) .float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
-class(PointParticles) .vector movedir; // trace direction
-
-void Draw_PointParticles(entity this);
-
-void Ent_PointParticles_Remove();
-
-void Ent_PointParticles();
-
-class(PointParticles) .float glow_color; // palette index
-
-void Net_ReadVortexBeamParticle();
-#endif
index 5c110e2b8986547e93e16b0e3bc1ba96b4cf24ce..1e939b77035169aa0fd727d954155c9a4ccb1d45 100644 (file)
@@ -1,25 +1,18 @@
 #include "../lib/_all.inc"
 #include "_all.qh"
 
+#include "../common/effects/qc/all.qc"
+
 #include "announcer.qc"
 #include "bgmscript.qc"
-#include "controlpoint.qc"
 #include "csqcmodel_hooks.qc"
-#include "damage.qc"
-#include "effects.qc"
-#include "generator.qc"
-#include "gibs.qc"
 #include "hook.qc"
-#include "hud.qc"
-#include "hud_config.qc"
+#include "hud/all.qc"
 #include "main.qc"
 #include "mapvoting.qc"
 #include "miscfunctions.qc"
-#include "modeleffects.qc"
 #include "movelib.qc"
-#include "particles.qc"
 #include "player_skeleton.qc"
-#include "rubble.qc"
 #include "scoreboard.qc"
 #include "shownames.qc"
 #include "teamradar.qc"
 #include "../common/minigames/minigames.qc"
 #include "../common/minigames/cl_minigames.qc"
 
-#include "../common/buffs/all.qc"
 #include "../common/deathtypes/all.qc"
 #include "../common/effects/all.qc"
 #include "../common/gamemodes/all.qc"
 #include "../common/items/all.qc"
 #include "../common/monsters/all.qc"
 #include "../common/mutators/all.qc"
-#include "../common/nades/all.qc"
 #include "../common/turrets/all.qc"
 #include "../common/vehicles/all.qc"
 #include "../common/weapons/all.qc"
 #include "../lib/csqcmodel/cl_player.qc"
 #include "../lib/csqcmodel/interpolate.qc"
 
-// TODO: move to common
-#include "../server/mutators/mutator/mutator_multijump.qc"
-#define IMPLEMENTATION
-#include "../server/mutators/mutator/mutator_multijump.qc"
-#undef IMPLEMENTATION
-
 #include "../lib/warpzone/anglestransform.qc"
 #include "../lib/warpzone/client.qc"
 #include "../lib/warpzone/common.qc"
index 1f7be0c500ca33663a11463d1e96233982b048ed..a4fdfea382f170bfb1f69bb3583a7883901c7c56 100644 (file)
@@ -1,7 +1,6 @@
 #include "quickmenu.qh"
 
-#include "hud.qh"
-#include "hud_config.qh"
+#include "hud/all.qh"
 #include "mapvoting.qh"
 
 // QUICKMENU_MAXLINES must be <= 10
@@ -75,12 +74,12 @@ bool QuickMenu_Open(string mode, string submenu)
        if(mode == "file")
        {
                if(autocvar_hud_panel_quickmenu_file == "" || autocvar_hud_panel_quickmenu_file == "0")
-                       printf("No file name is set in hud_panel_quickmenu_file, loading default quickmenu\n");
+                       LOG_INFO("No file name is set in hud_panel_quickmenu_file, loading default quickmenu\n");
                else
                {
                        fh = fopen(autocvar_hud_panel_quickmenu_file, FILE_READ);
                        if(fh < 0)
-                               printf("Couldn't open file \"%s\", loading default quickmenu\n", autocvar_hud_panel_quickmenu_file);
+                               LOG_INFOF("Couldn't open file \"%s\", loading default quickmenu\n", autocvar_hud_panel_quickmenu_file);
                }
                if(fh < 0)
                        mode = "default";
@@ -152,7 +151,7 @@ bool QuickMenu_Open(string mode, string submenu)
        }
        else
        {
-               printf("Unrecognized mode %s\n", mode);
+               LOG_WARNINGF("Unrecognized mode %s\n", mode);
                return false;
        }
 
@@ -286,7 +285,7 @@ bool QuickMenu_Page_Load(string target_submenu, int new_page)
                        // printf("^1 skipping %s\n", s);
                }
                if(QuickMenu_Buffer_Index == QuickMenu_Buffer_Size)
-                       printf("Couldn't find submenu \"%s\"\n", z_submenu);
+                       LOG_WARNINGF("Couldn't find submenu \"%s\"\n", z_submenu);
        }
 
        // only the last page can contain up to QUICKMENU_MAXLINES entries
@@ -574,7 +573,7 @@ void HUD_Quickmenu_DrawEntry(vector pos, string desc, string option, vector font
                drawcolorcodedstring(pos, entry, fontsize, panel_fg_alpha, DRAWFLAG_ADDITIVE);
 }
 
-void HUD_QuickMenu(void)
+void HUD_QuickMenu()
 {
        if(!autocvar__hud_configure)
        {
@@ -859,9 +858,9 @@ void QuickMenu_Default(string target_submenu)
 
        if(target_submenu != "" && !target_submenu_found)
        {
-               printf("Couldn't find submenu \"%s\"\n", target_submenu);
+               LOG_WARNINGF("Couldn't find submenu \"%s\"\n", target_submenu);
                if(prvm_language != "en")
-                       printf("^3Warning: submenu must be in English\n", target_submenu);
+                       LOG_WARNINGF("^3Warning: submenu must be in English\n", target_submenu);
                QuickMenu_Buffer_Size = 0;
        }
 }
diff --git a/qcsrc/client/rubble.qc b/qcsrc/client/rubble.qc
deleted file mode 100644 (file)
index 5af2e23..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#include "rubble.qh"
-
-// LordHavoc: rewrote this file, it was really bad code
-
-void RubbleLimit(string cname, float limit, void() deleteproc)
-{SELFPARAM();
-       entity e;
-       entity oldest;
-       float c;
-       float oldesttime;
-
-       // remove rubble of the same type if it's at the limit
-       // remove multiple rubble if the limit has been decreased
-       while(1)
-       {
-               e = findchain(classname,cname);
-               if (e == world)
-                       break;
-               // walk the list and count the entities, find the oldest
-               // initialize our search with the first entity
-               c = 1;
-               oldest = e;
-               oldesttime = e.creationtime;
-               e = e.chain;
-               // compare to all other matching entities
-               while (e)
-               {
-                       c = c + 1;
-                       if (oldesttime > e.creationtime)
-                       {
-                               oldesttime = e.creationtime;
-                               oldest = e;
-                       }
-                       e = e.chain;
-               }
-
-               // stop if there are less than the limit already
-               if (c <= limit)
-                       break;
-
-               // delete this oldest one and search again
-               WITH(entity, self, oldest, deleteproc());
-       }
-}
-
-entity RubbleNew(string cname)
-{
-       entity e;
-       // spawn a new entity and return it
-       e = spawn();
-       e.classname = cname;
-       e.creationtime = time;
-       return e;
-}
diff --git a/qcsrc/client/rubble.qh b/qcsrc/client/rubble.qh
deleted file mode 100644 (file)
index 9441168..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef CLIENT_RUBBLE_H
-#define CLIENT_RUBBLE_H
-entityclass(Rubble);
-class(Rubble) .float creationtime;
-void RubbleLimit(string cname, float limit, void() deleteproc);
-entity RubbleNew(string cname);
-#endif
index adbac93c8fed9fd56b28bf2ffb2e25d5baba951b..681183594f2efdc550a08c0147698e1b6cadb871 100644 (file)
@@ -1,7 +1,7 @@
 #include "scoreboard.qh"
 
 #include "quickmenu.qh"
-#include "hud.qh"
+#include "hud/all.qh"
 
 #include "../common/constants.qh"
 #include "../common/mapinfo.qh"
@@ -33,6 +33,8 @@ string TranslateScoresLabel(string l)
                case "captime": return CTX(_("SCO^captime"));
                case "deaths": return CTX(_("SCO^deaths"));
                case "destroyed": return CTX(_("SCO^destroyed"));
+               case "dmg": return CTX(_("SCO^dmg"));
+               case "dmgtaken": return CTX(_("SCO^dmgtaken"));
                case "drops": return CTX(_("SCO^drops"));
                case "faults": return CTX(_("SCO^faults"));
                case "fckills": return CTX(_("SCO^fckills"));
@@ -260,6 +262,8 @@ void Cmd_HUD_Help()
        LOG_INFO(_("^3suicides^7                 Number of suicides\n"));
        LOG_INFO(_("^3frags^7                    kills - suicides\n"));
        LOG_INFO(_("^3kd^7                       The kill-death ratio\n"));
+       LOG_INFO(_("^3dmg^7                      The total damage done\n"));
+       LOG_INFO(_("^3dmgtaken^7                 The total damage taken\n"));
        LOG_INFO(_("^3sum^7                      frags - deaths\n"));
        LOG_INFO(_("^3caps^7                     How often a flag (CTF) or a key (KeyHunt) was captured\n"));
        LOG_INFO(_("^3pickups^7                  How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\n"));
@@ -300,6 +304,7 @@ void Cmd_HUD_Help()
 #define HUD_DefaultColumnLayout() \
 "ping pl name | " \
 "-teams,rc,lms/kills +ft,tdm/kills -teams,lms/deaths +ft,tdm/deaths -teams,lms,rc,ka/suicides +ft,tdm/suicides -rc,dm,tdm,ka,ft/frags " /* tdm already has this in "score" */ \
+"dmg dmgtaken " \
 "+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns +ons/caps +ons/takes " \
 "+lms/lives +lms/rank " \
 "+kh/caps +kh/pushes +kh/destroyed " \
@@ -394,6 +399,8 @@ void Cmd_HUD_SetFields(float argc)
                        case "sum": case "diff": case "k-d": hud_field[hud_num_fields] = SP_SUM; break;
                        case "name": case "nick": hud_field[hud_num_fields] = SP_NAME; have_name = true; break;
                        case "|": hud_field[hud_num_fields] = SP_SEPARATOR; have_separator = true; break;
+                       case "dmg": hud_field[hud_num_fields] = SP_DMG; break;
+                       case "dmgtaken": hud_field[hud_num_fields] = SP_DMGTAKEN; break;
                        default:
                        {
                                for(j = 0; j < MAX_SCORE; ++j)
@@ -598,6 +605,20 @@ string HUD_GetField(entity pl, int field)
                        }
                        return ftos(f);
 
+               case SP_DMG:
+                       num = pl.(scores[SP_DMG]);
+                       denom = 1000;
+                       
+                       str = sprintf("%.1f k", num/denom);
+                       return str;
+                       
+               case SP_DMGTAKEN:
+                       num = pl.(scores[SP_DMGTAKEN]);
+                       denom = 1000;
+                       
+                       str = sprintf("%.1f k", num/denom);
+                       return str; 
+               
                default:
                        tmp = pl.(scores[field]);
                        f = scores_flags[field];
@@ -974,35 +995,28 @@ float HUD_WouldDrawScoreboard() {
 
 float average_accuracy;
 vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
-{SELFPARAM();
+{
+       SELFPARAM();
        WepSet weapons_stat = WepSet_GetFromStat();
        WepSet weapons_inmap = WepSet_GetFromStat_InMap();
        float initial_posx = pos.x;
-       int i;
-       float weapon_stats;
        int disownedcnt = 0;
-       for(i = WEP_FIRST; i <= WEP_LAST; ++i)
-       {
+       for (int i = WEP_FIRST; i <= WEP_LAST; ++i) {
                setself(get_weaponinfo(i));
-               if(!self.weapon)
-                       continue;
+               if (!self.weapon) continue;
 
-               weapon_stats = weapon_accuracy[i-WEP_FIRST];
+               int weapon_stats = weapon_accuracy[i - WEP_FIRST];
 
-               if(weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
+               if (weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
                        ++disownedcnt;
        }
 
        int weapon_cnt = (Weapons_COUNT - 1) - disownedcnt;
+       if (weapon_cnt <= 0) return pos;
 
-       if(weapon_cnt <= 0)
-               return pos;
-
-       int rows;
-       if(autocvar_scoreboard_accuracy_doublerows && weapon_cnt >= floor((Weapons_COUNT - 1) * 0.5))
+       int rows = 1;
+       if (autocvar_scoreboard_accuracy_doublerows && weapon_cnt >= floor((Weapons_COUNT - 1) * 0.5))
                rows = 2;
-       else
-               rows = 1;
        int columnns = ceil(weapon_cnt / rows);
 
        float height = 40;
@@ -1023,24 +1037,24 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
        drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
 
        // column highlighting
-       for(i = 0; i < columnns; ++i)
+       for (int i = 0; i < columnns; ++i)
        {
-               if(!(i % 2))
+               if ((i % 2) == 0)
                        drawfill(pos + '1 0 0' * weapon_width * rows * i, '0 1 0' * height * rows + '1 0 0' * weapon_width * rows, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
        }
 
        // row highlighting
-       for(i = 0; i < rows; ++i)
+       for (int i = 0; i < rows; ++i)
        {
                drawfill(pos + '0 1 0' * weapon_height + '0 1 0' * height * i, '1 0 0' * sbwidth + '0 1 0' * fontsize, '1 1 1', scoreboard_highlight_alpha, DRAWFLAG_NORMAL);
        }
 
        average_accuracy = 0;
        int weapons_with_stats = 0;
-       if(rows == 2)
+       if (rows == 2)
                pos.x += weapon_width / 2;
 
-       if(autocvar_scoreboard_accuracy_nocolors)
+       if (autocvar_scoreboard_accuracy_nocolors)
                rgb = '1 1 1';
        else
                Accuracy_LoadColors();
@@ -1048,19 +1062,17 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
        float oldposx = pos.x;
        vector tmpos = pos;
 
-       int column;
-       for(i = WEP_FIRST, column = 0; i <= WEP_LAST; ++i)
-       {
+       int column = 0;
+       for (int i = WEP_FIRST; i <= WEP_LAST; ++i) {
                setself(get_weaponinfo(i));
-               if (!self.weapon)
-                       continue;
-               weapon_stats = weapon_accuracy[i-WEP_FIRST];
+               if (!self.weapon) continue;
+               int weapon_stats = weapon_accuracy[i - WEP_FIRST];
 
-               if(weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
+               if (weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
                        continue;
 
                float weapon_alpha;
-               if(weapon_stats >= 0)
+               if (weapon_stats >= 0)
                        weapon_alpha = scoreboard_alpha_fg;
                else
                        weapon_alpha = 0.2 * scoreboard_alpha_fg;
@@ -1068,7 +1080,7 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
                // weapon icon
                drawpic_aspect_skin(tmpos, self.model2, '1 0 0' * weapon_width + '0 1 0' * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
                // the accuracy
-               if(weapon_stats >= 0) {
+               if (weapon_stats >= 0) {
                        weapons_with_stats += 1;
                        average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
 
@@ -1085,7 +1097,7 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
                }
                tmpos.x += weapon_width * rows;
                pos.x += weapon_width * rows;
-               if(rows == 2 && column == columnns - 1) {
+               if (rows == 2 && column == columnns - 1) {
                        tmpos.x = oldposx;
                        tmpos.y += height;
                        pos.y += height;
@@ -1093,7 +1105,7 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
                ++column;
        }
 
-       if(weapons_with_stats)
+       if (weapons_with_stats)
                average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
 
        pos.y += height;
@@ -1349,7 +1361,7 @@ void HUD_DrawScoreboard()
                }
                pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
        }
-       else if(autocvar_scoreboard_accuracy && spectatee_status == 0 && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL) {
+       else if (autocvar_scoreboard_accuracy && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL) {
                if(teamplay)
                        pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size);
                else
index 5b5f812a0ab448e43d058313894e926b45eb4e02..4e43cb65fd303ab7a1f1f6beb8e0b34d7ecfaac4 100644 (file)
@@ -11,5 +11,5 @@ void HUD_DrawScoreboard();
 void HUD_InitScores();
 void HUD_UpdatePlayerPos(entity pl);
 void HUD_UpdateTeamPos(entity Team);
-float HUD_WouldDrawScoreboard(void);
+float HUD_WouldDrawScoreboard();
 #endif
index 80a15ad38b49d064c9557a5e994e20afe078991e..300521545354cad1a34efbca961a6193b8e8c9a5 100644 (file)
@@ -1,6 +1,6 @@
 #include "shownames.qh"
 
-#include "hud.qh"
+#include "hud/all.qh"
 
 #include "../common/constants.qh"
 #include "../common/mapinfo.qh"
@@ -202,8 +202,7 @@ void Draw_ShowNames_All()
                e = shownames_ent[i];
                if(!e)
                {
-                       e = spawn();
-                       e.classname = "shownames_tag";
+                       e = new(shownames_tag);
                        e.sv_entnum = i+1;
                        shownames_ent[i] = e;
                }
index f4096b87a6a8fabed875b52faf37a62ca3e2edfc..b0e1315f69bf3d9abc33c5b9be58f4556e6363db 100644 (file)
@@ -1,5 +1,4 @@
 
-#include "../common/buffs/all.qh"
 #include "../common/movetypes/movetypes.qh"
 #include "../common/weapons/all.qh"
 #include "../lib/csqcmodel/cl_model.qh"
index c866a1b73e4eb1ef6d95a975531b3bab646c5926..af43dae0373f125aa37d7856b65667dbb4880281 100644 (file)
@@ -1,6 +1,6 @@
 #include "teamradar.qh"
 
-#include "hud.qh"
+#include "hud/all.qh"
 
 #include "../common/mutators/mutator/waypoints/all.qh"
 
@@ -58,12 +58,6 @@ vector teamradar_texcoord_to_3dcoord(vector in,float z)
        return out;
 }
 
-vector yinvert(vector v)
-{
-       v.y = 1 - v.y;
-       return v;
-}
-
 void draw_teamradar_background(float fg)
 {
        float fga;
@@ -200,8 +194,8 @@ void teamradar_loadcvars()
 
 // radar links
 
-void Ent_RadarLink()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_RADARLINK, bool isnew)
+{
        int sendflags = ReadByte();
 
        InterpolateOrigin_Undo();
@@ -229,5 +223,7 @@ void Ent_RadarLink()
                self.team = ReadByte();
        }
 
+       return = true;
+
        InterpolateOrigin_Note();
 }
index b882f39fbdafa7e14e4a5c5c4de18cb57a2f0c23..ca7ec87b59f14e58deab8b41a291556e00379fcd 100644 (file)
@@ -35,8 +35,6 @@ vector teamradar_texcoord_to_2dcoord(vector in);
 
 vector teamradar_texcoord_to_3dcoord(vector in,float z);
 
-vector yinvert(vector v);
-
 void draw_teamradar_background(float fg);
 
 void draw_teamradar_player(vector coord3d, vector pangles, vector rgb);
@@ -47,8 +45,4 @@ void draw_teamradar_link(vector start, vector end, int colors);
 
 void teamradar_loadcvars();
 
-// radar links
-
-void Ent_RadarLink();
-
 #endif
index ed2964936a3bd3942ba90cf1af2921c5d5197fcd..8f8fc4db5f2573213b2222b06f6df9b4a59f68dc 100644 (file)
@@ -3,7 +3,7 @@
 #include "../common/constants.qh"
 
 
-#define TUBA_STARTNOTE(i, n) W_Sound(strcat("tuba", (i ? ftos(i) : ""), "_loopnote", ftos(n)))
+#define TUBA_STARTNOTE(i, n) _Sound_fixpath(W_Sound(strcat("tuba", (i ? ftos(i) : ""), "_loopnote", ftos(n))))
 
 const int TUBA_MIN = -18;
 const int TUBA_MAX = 27;
@@ -103,8 +103,8 @@ void Ent_TubaNote_StopSound()
        self.enemy = world;
 }
 
-void Ent_TubaNote(bool isNew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TUBANOTE, bool isNew)
+{
        bool upd = false;
        int f = ReadByte();
        if (f & 1) {
@@ -118,11 +118,9 @@ void Ent_TubaNote(bool isNew)
                                Ent_TubaNote_StopSound();
                        }
                } else {
-                       self.enemy = spawn();
-                       self.enemy.classname = "tuba_note";
+                       self.enemy = new(tuba_note);
                        if (Tuba_PitchStep) {
-                               self.enemy.enemy = spawn();
-                               self.enemy.enemy.classname = "tuba_note_2";
+                               self.enemy.enemy = new(tuba_note_2);
                        }
                        isNew = true;
                }
@@ -154,9 +152,10 @@ void Ent_TubaNote(bool isNew)
        if (upd) {
                Ent_TubaNote_UpdateSound();
        }
+       return true;
 }
 
-void Tuba_Precache()
+PRECACHE(Tuba)
 {
        Tuba_PitchStep = autocvar_g_balance_tuba_pitchstep;
        if (Tuba_PitchStep) {
index e936dcd6ec61885fa2ad2748f23048375cfa5d1b..0a310c359ab3d342c1e27014a5f565085d414b66 100644 (file)
@@ -1,7 +1,5 @@
 #ifndef CLIENT_TUBA_H
 #define CLIENT_TUBA_H
-void Ent_TubaNote(bool isNew);
-void Tuba_Precache();
 
 entityclass(Tuba);
 
index c7144372a304b45bdee0cbbcc4036b5681015523..699e2d8ade41b81b6da5922980f2aa4449849009 100644 (file)
@@ -1,8 +1,7 @@
 
 #include "announcer.qh"
 #include "hook.qh"
-#include "hud.qh"
-#include "hud_config.qh"
+#include "hud/all.qh"
 #include "mapvoting.qh"
 #include "scoreboard.qh"
 #include "shownames.qh"
@@ -11,9 +10,9 @@
 #include "mutators/events.qh"
 
 #include "../common/constants.qh"
+#include "../common/debug.qh"
 #include "../common/mapinfo.qh"
 #include "../common/gamemodes/all.qh"
-#include "../common/nades/all.qh"
 #include "../common/stats.qh"
 #include "../common/triggers/target/music.qh"
 #include "../common/teams.qh"
@@ -110,8 +109,8 @@ void Porto_Draw(entity this)
 
 void Porto_Init()
 {
-       porto = spawn();
-       porto.classname = "porto";
+       porto = new(porto);
+       make_pure(porto);
        porto.draw = Porto_Draw;
        porto.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
 }
@@ -278,11 +277,11 @@ const float SHOTTYPE_HITENEMY = 4;
 
 void TrueAim_Init()
 {
-       trueaim = spawn();
-       trueaim.classname = "trueaim";
+       trueaim = new(trueaim);
+       make_pure(trueaim);
        trueaim.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
-       trueaim_rifle = spawn();
-       trueaim_rifle.classname = "trueaim_rifle";
+       trueaim_rifle = new(trueaim_rifle);
+       make_pure(trueaim_rifle);
        trueaim_rifle.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_CORPSE;
 }
 
@@ -398,7 +397,7 @@ float TrueAimCheck()
        return SHOTTYPE_HITWORLD;
 }
 
-void PostInit(void);
+void PostInit();
 void CSQC_Demo_Camera();
 float HUD_WouldDrawScoreboard();
 float camera_mode;
@@ -830,7 +829,7 @@ void HUD_Crosshair()
                                vortex_charge = getstatf(STAT_VORTEX_CHARGE);
                                vortex_chargepool = getstatf(STAT_VORTEX_CHARGEPOOL);
 
-                               float arc_heat = getstatf(STAT_ARC_HEAT);
+                               float arc_heat = STAT(ARC_HEAT);
 
                                if(vortex_charge_movingavg == 0) // this should only happen if we have just loaded up the game
                                        vortex_charge_movingavg = vortex_charge;
@@ -1005,10 +1004,18 @@ void HUD_Crosshair()
 
 void HUD_Draw()
 {
-       if(getstati(STAT_FROZEN))
-               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, ((getstatf(STAT_REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * getstatf(STAT_REVIVE_PROGRESS)) + ('0 1 1' * getstatf(STAT_REVIVE_PROGRESS) * -1)) : '0.25 0.90 1'), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
-       else if (getstatf(STAT_HEALING_ORB)>time)
-               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, NADE_TYPE_HEAL.m_color, autocvar_hud_colorflash_alpha*getstatf(STAT_HEALING_ORB_ALPHA), DRAWFLAG_ADDITIVE);
+       vector rgb = '0 0 0';
+       float a = 1;
+       if (MUTATOR_CALLHOOK(HUD_Draw_overlay))
+       {
+               rgb = MUTATOR_ARGV(0, vector);
+               a = MUTATOR_ARGV(0, float);
+       }
+       else if(getstati(STAT_FROZEN))
+       {
+               rgb = ((getstatf(STAT_REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * getstatf(STAT_REVIVE_PROGRESS)) + ('0 1 1' * getstatf(STAT_REVIVE_PROGRESS) * -1)) : '0.25 0.90 1');
+       }
+       drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, rgb, autocvar_hud_colorflash_alpha * a, DRAWFLAG_ADDITIVE);
        if(!intermission)
        if(getstatf(STAT_NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death
        {
@@ -1064,6 +1071,7 @@ void CSQC_UpdateView(float w, float h)
 
        ++framecount;
 
+       stats_get();
        hud = getstati(STAT_HUD);
 
        if(hud != HUD_NORMAL && lasthud == HUD_NORMAL)
@@ -1387,9 +1395,6 @@ void CSQC_UpdateView(float w, float h)
 
        ColorTranslateMode = autocvar_cl_stripcolorcodes;
 
-       // next WANTED weapon (for HUD)
-       switchweapon = getstati(STAT_SWITCHWEAPON);
-
        // currently switching-to weapon (for crosshair)
        switchingweapon = getstati(STAT_SWITCHINGWEAPON);
 
@@ -1516,13 +1521,11 @@ void CSQC_UpdateView(float w, float h)
 
                if(!nightvision_noise)
                {
-                       nightvision_noise = spawn();
-                       nightvision_noise.classname = "nightvision_noise";
+                       nightvision_noise = new(nightvision_noise);
                }
                if(!nightvision_noise2)
                {
-                       nightvision_noise2 = spawn();
-                       nightvision_noise2.classname = "nightvision_noise2";
+                       nightvision_noise2 = new(nightvision_noise2);
                }
 
                // color tint in yellow
@@ -1797,7 +1800,7 @@ void CSQC_UpdateView(float w, float h)
                }
 
                // edge detection postprocess handling done second (used by hud_powerup)
-               float sharpen_intensity = 0, strength_finished = getstatf(STAT_STRENGTH_FINISHED), invincible_finished = getstatf(STAT_INVINCIBLE_FINISHED);
+               float sharpen_intensity = 0, strength_finished = STAT(STRENGTH_FINISHED), invincible_finished = STAT(INVINCIBLE_FINISHED);
                if (strength_finished - time > 0) { sharpen_intensity += (strength_finished - time); }
                if (invincible_finished - time > 0) { sharpen_intensity += (invincible_finished - time); }
 
@@ -1823,9 +1826,6 @@ void CSQC_UpdateView(float w, float h)
        else if(cvar("r_glsl_postprocess") == 2)
                cvar_set("r_glsl_postprocess", "0");
 
-       if(menu_visible)
-               menu_show();
-
        /*if(gametype == MAPINFO_TYPE_CTF)
          {
          ctf_view();
@@ -1836,6 +1836,7 @@ void CSQC_UpdateView(float w, float h)
                WITH(entity, self, e, e.draw2d(e));
        }
        Draw_ShowNames_All();
+       Debug_Draw();
 
        scoreboard_active = HUD_WouldDrawScoreboard();
 
index 9da9bb5b658338fdacca81cbc3e7ef2d7dafd90d..2623470c16db54e52fdd8552f86ab6a5ff0fcd37 100644 (file)
@@ -114,8 +114,8 @@ void Ent_Wall_Remove()
        self.bgmscript = string_null;
 }
 
-void Ent_Wall()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_WALL, bool isnew)
+{
        int f;
        var .vector fld;
 
@@ -222,6 +222,8 @@ void Ent_Wall()
                BGMScript_InitEntity(self);
        }
 
+       return = true;
+
        InterpolateOrigin_Note();
 
        self.saved = self.(fld);
index e05bb615edcf8713700d674e46f34be6326578ac..16f87fdd977900c31f4df09d2d995d2dfbf39df1 100644 (file)
@@ -20,5 +20,4 @@ void Ent_Wall_Draw(entity this);
 
 void Ent_Wall_Remove();
 
-void Ent_Wall();
 #endif
index 807d95cb4ca2144cf22a6ccdf0b80bf242cdfe30..9609760c4a43ab168f465395bca180ec7cc45478 100644 (file)
@@ -6,7 +6,6 @@
 #include "../mutators/events.qh"
 
 #include "../../common/constants.qh"
-#include "../../common/nades/all.qh"
 #include "../../common/movetypes/movetypes.qh"
 
 #include "../../lib/csqcmodel/interpolate.qh"
@@ -18,7 +17,8 @@
 .vector colormod;
 
 void SUB_Stop()
-{SELFPARAM();
+{
+       SELFPARAM();
        self.move_velocity = self.move_avelocity = '0 0 0';
        self.move_movetype = MOVETYPE_NONE;
 }
@@ -37,17 +37,19 @@ void Projectile_DrawTrail(entity this, vector to)
        this.trail_oldtime = time;
 
        // force the effect even for stationary firemine
-       if(this.cnt == PROJECTILE_FIREMINE)
-               if(from == to)
+       if (this.cnt == PROJECTILE_FIREMINE)
+               if (from == to)
                        from.z += 1;
 
        if (this.traileffect)
        {
                particles_alphamin = particles_alphamax = particles_fade = sqrt(this.alpha);
-               boxparticles(particleeffectnum(Effects[this.traileffect]), this, from, to, this.velocity, this.velocity, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE | PARTICLES_DRAWASTRAIL);
+               boxparticles(particleeffectnum(Effects_from(this.traileffect)), this, from, to, this.velocity, this.velocity, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE | PARTICLES_DRAWASTRAIL);
        }
 }
 
+bool Projectile_isnade(int proj); // TODO: remove
+
 void Projectile_Draw(entity this)
 {
        vector rot;
@@ -59,20 +61,20 @@ void Projectile_Draw(entity this)
 
        f = self.move_flags;
 
-       if(self.count & 0x80)
+       if (self.count & 0x80)
        {
-               //self.move_flags &= ~FL_ONGROUND;
-               if(self.move_movetype == MOVETYPE_NONE || self.move_movetype == MOVETYPE_FLY)
+               // self.move_flags &= ~FL_ONGROUND;
+               if (self.move_movetype == MOVETYPE_NONE || self.move_movetype == MOVETYPE_FLY)
                        Movetype_Physics_NoMatchServer();
-                       // the trivial movetypes do not have to match the
-                       // server's ticrate as they are ticrate independent
-                       // NOTE: this assumption is only true if MOVETYPE_FLY
-                       // projectiles detonate on impact. If they continue
-                       // moving, we might still be ticrate dependent.
+               // the trivial movetypes do not have to match the
+               // server's ticrate as they are ticrate independent
+               // NOTE: this assumption is only true if MOVETYPE_FLY
+               // projectiles detonate on impact. If they continue
+               // moving, we might still be ticrate dependent.
                else
                        Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
-               if(!(self.move_flags & FL_ONGROUND))
-                       if(self.velocity != '0 0 0')
+               if (!(self.move_flags & FL_ONGROUND))
+                       if (self.velocity != '0 0 0')
                                self.move_angles = self.angles = vectoangles(self.velocity);
        }
        else
@@ -80,7 +82,7 @@ void Projectile_Draw(entity this)
                InterpolateOrigin_Do();
        }
 
-       if(self.count & 0x80)
+       if (self.count & 0x80)
        {
                drawn = (time >= self.spawntime - 0.02);
                t = max(time, self.spawntime);
@@ -91,27 +93,27 @@ void Projectile_Draw(entity this)
                t = time;
        }
 
-       if(!(f & FL_ONGROUND))
+       if (!(f & FL_ONGROUND))
        {
                rot = '0 0 0';
-               switch(self.cnt)
+               switch (self.cnt)
                {
                        /*
                        case PROJECTILE_GRENADE:
-                               rot = '-2000 0 0'; // forward
-                               break;
+                           rot = '-2000 0 0'; // forward
+                           break;
                        */
                        case PROJECTILE_GRENADE_BOUNCING:
                                rot = '0 -1000 0'; // sideways
                                break;
                        case PROJECTILE_HOOKBOMB:
-                               rot = '1000 0 0'; // forward
+                               rot = '1000 0 0';  // forward
                                break;
                        default:
                                break;
                }
 
-               if(Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
+               if (Projectile_isnade(self.cnt))
                        rot = self.avelocity;
 
                self.angles = AnglesTransform_ToAngles(AnglesTransform_Multiply(AnglesTransform_FromAngles(self.angles), rot * (t - self.spawntime)));
@@ -124,12 +126,12 @@ void Projectile_Draw(entity this)
 
        a = 1 - (time - self.fade_time) * self.fade_rate;
        self.alpha = bound(0, self.alphamod * a, 1);
-       if(self.alpha <= 0)
+       if (self.alpha <= 0)
                drawn = 0;
        self.renderflags = 0;
 
        trailorigin = self.origin;
-       switch(self.cnt)
+       switch (self.cnt)
        {
                case PROJECTILE_GRENADE:
                case PROJECTILE_GRENADE_BOUNCING:
@@ -139,20 +141,20 @@ void Projectile_Draw(entity this)
                        break;
        }
 
-       if(Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
+       if (Projectile_isnade(self.cnt))
                trailorigin += v_up * 4;
 
-       if(drawn)
+       if (drawn)
                Projectile_DrawTrail(self, trailorigin);
        else
                Projectile_ResetTrail(self, trailorigin);
 
        self.drawmask = 0;
 
-       if(!drawn)
+       if (!drawn)
                return;
 
-       switch(self.cnt)
+       switch (self.cnt)
        {
                // Possibly add dlights here.
                default:
@@ -163,8 +165,9 @@ void Projectile_Draw(entity this)
 }
 
 void loopsound(entity e, int ch, string samp, float vol, float attn)
-{SELFPARAM();
-       if(self.silent)
+{
+       SELFPARAM();
+       if (self.silent)
                return;
 
        _sound(e, ch, samp, vol, attn);
@@ -172,18 +175,17 @@ void loopsound(entity e, int ch, string samp, float vol, float attn)
 }
 
 void Ent_RemoveProjectile()
-{SELFPARAM();
-       if(self.count & 0x80)
+{
+       SELFPARAM();
+       if (self.count & 0x80)
        {
                tracebox(self.origin, self.mins, self.maxs, self.origin + self.velocity * 0.05, MOVE_NORMAL, self);
                Projectile_DrawTrail(self, trace_endpos);
        }
 }
 
-void Ent_Projectile()
-{SELFPARAM();
-       int f;
-
+NET_HANDLE(ENT_CLIENT_PROJECTILE, bool isnew)
+{
        // projectile properties:
        //   kind (interpolated, or clientside)
        //
@@ -198,21 +200,21 @@ void Ent_Projectile()
        //
        // projectiles don't send angles, because they always follow the velocity
 
-       f = ReadByte();
+       int f = ReadByte();
        self.count = (f & 0x80);
        self.iflags = (self.iflags & IFLAG_INTERNALMASK) | IFLAG_AUTOANGLES | IFLAG_ANGLES | IFLAG_ORIGIN;
        self.solid = SOLID_TRIGGER;
-       //self.effects = EF_NOMODELFLAGS;
+       // self.effects = EF_NOMODELFLAGS;
 
        // this should make collisions with bmodels more exact, but it leads to
        // projectiles no longer being able to lie on a bmodel
        self.move_nomonsters = MOVE_WORLDONLY;
-       if(f & 0x40)
+       if (f & 0x40)
                self.move_flags |= FL_ONGROUND;
        else
                self.move_flags &= ~FL_ONGROUND;
 
-       if(!self.move_time)
+       if (!self.move_time)
        {
                // for some unknown reason, we don't need to care for
                // sv_gameplayfix_delayprojectiles here.
@@ -220,38 +222,40 @@ void Ent_Projectile()
                self.spawntime = time;
        }
        else
+       {
                self.move_time = max(self.move_time, time);
+       }
 
-       if(!(self.count & 0x80))
+       if (!(self.count & 0x80))
                InterpolateOrigin_Undo();
 
-       if(f & 1)
+       if (f & 1)
        {
                self.origin_x = ReadCoord();
                self.origin_y = ReadCoord();
                self.origin_z = ReadCoord();
                setorigin(self, self.origin);
-               if(self.count & 0x80)
+               if (self.count & 0x80)
                {
                        self.velocity_x = ReadCoord();
                        self.velocity_y = ReadCoord();
                        self.velocity_z = ReadCoord();
-                       if(f & 0x10)
+                       if (f & 0x10)
                                self.gravity = ReadCoord();
                        else
-                               self.gravity = 0; // none
+                               self.gravity = 0;  // none
                        self.move_origin = self.origin;
                        self.move_velocity = self.velocity;
                }
 
-               if(time == self.spawntime || (self.count & 0x80) || (f & 0x08))
+               if (time == self.spawntime || (self.count & 0x80) || (f & 0x08))
                {
                        self.trail_oldorigin = self.origin;
-                       if(!(self.count & 0x80))
+                       if (!(self.count & 0x80))
                                InterpolateOrigin_Reset();
                }
 
-               if(f & 0x20)
+               if (f & 0x20)
                {
                        self.fade_time = time + ReadByte() * ticrate;
                        self.fade_rate = 1 / (ReadByte() * ticrate);
@@ -265,7 +269,7 @@ void Ent_Projectile()
                self.team = ReadByte() - 1;
        }
 
-       if(f & 2)
+       if (f & 2)
        {
                self.cnt = ReadByte();
 
@@ -274,8 +278,9 @@ void Ent_Projectile()
 
                self.scale = 1;
                self.traileffect = 0;
-               switch (self.cnt) {
-#define CASE(id) case PROJECTILE_##id: setmodel(self, MDL_PROJECTILE_##id);
+               switch (self.cnt)
+               {
+                       #define CASE(id) case PROJECTILE_##id: setmodel(self, MDL_PROJECTILE_##id);
                        CASE(ELECTRO)            self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
                        CASE(ROCKET)             self.traileffect = EFFECT_TR_ROCKET.m_id; self.scale = 2; break;
                        CASE(CRYLINK)            self.traileffect = EFFECT_TR_CRYLINKPLASMA.m_id; break;
@@ -291,7 +296,6 @@ void Ent_Projectile()
                        CASE(HOOKBOMB)           self.traileffect = EFFECT_TR_KNIGHTSPIKE.m_id; break;
                        CASE(HAGAR)              self.traileffect = EFFECT_HAGAR_ROCKET.m_id; self.scale = 0.75; break;
                        CASE(HAGAR_BOUNCING)     self.traileffect = EFFECT_HAGAR_ROCKET.m_id; self.scale = 0.75; break;
-                       CASE(NAPALM_FOUNTAIN)    // fallthrough // sself.modelindex = 0; self.traileffect = _particleeffectnum("torch_small"); break;
                        CASE(FIREBALL)           self.modelindex = 0; self.traileffect = EFFECT_FIREBALL.m_id; break; // particle effect is good enough
                        CASE(FIREMINE)           self.modelindex = 0; self.traileffect = EFFECT_FIREMINE.m_id; break; // particle effect is good enough
                        CASE(TAG)                self.traileffect = EFFECT_TR_ROCKET.m_id; break;
@@ -317,16 +321,9 @@ void Ent_Projectile()
                        CASE(ROCKETMINSTA_LASER) self.traileffect = EFFECT_ROCKETMINSTA_LASER(self.team).m_id; break;
 #undef CASE
                        default:
-                               if(MUTATOR_CALLHOOK(Ent_Projectile, self))
+                               if (MUTATOR_CALLHOOK(Ent_Projectile, self))
                                        break;
 
-                               if (Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
-                               {
-                                       setmodel(self, MDL_PROJECTILE_NADE);
-                                       entity trail = Nade_TrailEffect(self.cnt, self.team);
-                                       if (trail.eent_eff_name) self.traileffect = trail.m_id;
-                                       break;
-                               }
                                error("Received invalid CSQC projectile, can't work with this!");
                                break;
                }
@@ -338,7 +335,7 @@ void Ent_Projectile()
                self.move_movetype = MOVETYPE_TOSS;
                self.alphamod = 1;
 
-               switch(self.cnt)
+               switch (self.cnt)
                {
                        case PROJECTILE_ELECTRO:
                                // only new engines support sound moving with object
@@ -398,7 +395,6 @@ void Ent_Projectile()
                                self.move_movetype = MOVETYPE_BOUNCE;
                                self.move_touch = func_null;
                                break;
-                       case PROJECTILE_NAPALM_FOUNTAIN:
                        case PROJECTILE_FIREBALL:
                                loopsound(self, CH_SHOTS_SINGLE, SND(FIREBALL_FLY2), VOL_BASE, ATTEN_NORM);
                                self.mins = '-16 -16 -16';
@@ -424,76 +420,61 @@ void Ent_Projectile()
                                self.mins = '-4 -4 -4';
                                self.maxs = '4 4 4';
                                break;
-            case PROJECTILE_RAPTORBOMB:
+                       case PROJECTILE_RAPTORBOMB:
                                self.mins = '-3 -3 -3';
                                self.maxs = '3 3 3';
                                break;
-            case PROJECTILE_RAPTORBOMBLET:
+                       case PROJECTILE_RAPTORBOMBLET:
                                break;
-            case PROJECTILE_RAPTORCANNON:
+                       case PROJECTILE_RAPTORCANNON:
                                break;
-            case PROJECTILE_SPIDERROCKET:
-                loopsound(self, CH_SHOTS_SINGLE, SND(TAG_ROCKET_FLY), VOL_BASE, ATTEN_NORM);
-                               break;
-            case PROJECTILE_WAKIROCKET:
-                loopsound(self, CH_SHOTS_SINGLE, SND(TAG_ROCKET_FLY), VOL_BASE, ATTEN_NORM);
+                       case PROJECTILE_SPIDERROCKET:
+                               loopsound(self, CH_SHOTS_SINGLE, SND(TAG_ROCKET_FLY), VOL_BASE, ATTEN_NORM);
                                break;
-            /*
-            case PROJECTILE_WAKICANNON:
+                       case PROJECTILE_WAKIROCKET:
+                               loopsound(self, CH_SHOTS_SINGLE, SND(TAG_ROCKET_FLY), VOL_BASE, ATTEN_NORM);
                                break;
+                       /*
+                       case PROJECTILE_WAKICANNON:
+                           break;
                        case PROJECTILE_BUMBLE_GUN:
-                               // only new engines support sound moving with object
-                               loopsound(self, CH_SHOTS_SINGLE, SND(ELECTRO_FLY), VOL_BASE, ATTEN_NORM);
-                               self.mins = '0 0 -4';
-                               self.maxs = '0 0 -4';
-                               self.move_movetype = MOVETYPE_BOUNCE;
-                               self.move_touch = func_null;
-                               self.move_bounce_factor = g_balance_electro_secondary_bouncefactor;
-                               self.move_bounce_stopspeed = g_balance_electro_secondary_bouncestop;
-                               break;
+                           // only new engines support sound moving with object
+                           loopsound(self, CH_SHOTS_SINGLE, SND(ELECTRO_FLY), VOL_BASE, ATTEN_NORM);
+                           self.mins = '0 0 -4';
+                           self.maxs = '0 0 -4';
+                           self.move_movetype = MOVETYPE_BOUNCE;
+                           self.move_touch = func_null;
+                           self.move_bounce_factor = g_balance_electro_secondary_bouncefactor;
+                           self.move_bounce_stopspeed = g_balance_electro_secondary_bouncestop;
+                           break;
                        */
                        default:
                                break;
                }
 
-               if(Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
-               {
-                       entity nade_type = Nade_FromProjectile(self.cnt);
-                       self.mins = '-16 -16 -16';
-                       self.maxs = '16 16 16';
-                       self.colormod = nade_type.m_color;
-                       self.move_movetype = MOVETYPE_BOUNCE;
-                       self.move_touch = func_null;
-                       self.scale = 1.5;
-                       self.avelocity = randomvec() * 720;
-
-                       if(nade_type == NADE_TYPE_TRANSLOCATE || nade_type == NADE_TYPE_SPAWN)
-                               self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
-                       else
-                               self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
-               }
-
                MUTATOR_CALLHOOK(EditProjectile, self);
 
                setsize(self, self.mins, self.maxs);
        }
 
-       if(self.gravity)
+       return = true;
+
+       if (self.gravity)
        {
-               if(self.move_movetype == MOVETYPE_FLY)
+               if (self.move_movetype == MOVETYPE_FLY)
                        self.move_movetype = MOVETYPE_TOSS;
-               if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
+               if (self.move_movetype == MOVETYPE_BOUNCEMISSILE)
                        self.move_movetype = MOVETYPE_BOUNCE;
        }
        else
        {
-               if(self.move_movetype == MOVETYPE_TOSS)
+               if (self.move_movetype == MOVETYPE_TOSS)
                        self.move_movetype = MOVETYPE_FLY;
-               if(self.move_movetype == MOVETYPE_BOUNCE)
+               if (self.move_movetype == MOVETYPE_BOUNCE)
                        self.move_movetype = MOVETYPE_BOUNCEMISSILE;
        }
 
-       if(!(self.count & 0x80))
+       if (!(self.count & 0x80))
                InterpolateOrigin_Note();
 
        self.classname = "csqcprojectile";
@@ -501,7 +482,7 @@ void Ent_Projectile()
        self.entremove = Ent_RemoveProjectile;
 }
 
-void Projectile_Precache()
+PRECACHE(Projectiles)
 {
        MUTATOR_CALLHOOK(PrecacheProjectiles);
 }
index 5a0deb4990d20af00bf47f54f265e7f4c562976d..699f48938e9f10f2402c52b06ea575ba6db5875a 100644 (file)
@@ -2,20 +2,20 @@
 #define CLIENT_WEAPONS_PROJECTILE_H
 
 entityclass(Projectile);
-class(Projectile) .int traileffect;
+class(Projectile).int traileffect;
 
-class(Projectile) .vector iorigin1, iorigin2;
-class(Projectile) .float spawntime;
-class(Projectile) .vector trail_oldorigin;
-class(Projectile) .float trail_oldtime;
-class(Projectile) .float fade_time, fade_rate;
+class(Projectile).vector iorigin1, iorigin2;
+class(Projectile).float spawntime;
+class(Projectile).vector trail_oldorigin;
+class(Projectile).float trail_oldtime;
+class(Projectile).float fade_time, fade_rate;
 
-class(Projectile) .float alphamod;
-class(Projectile) .int count; // set if clientside projectile
-class(Projectile) .int cnt; // sound index
-class(Projectile) .float gravity;
-class(Projectile) .int snd_looping;
-class(Projectile) .bool silent;
+class(Projectile).float alphamod;
+class(Projectile).int count; // set if clientside projectile
+class(Projectile).int cnt;   // sound index
+class(Projectile).float gravity;
+class(Projectile).int snd_looping;
+class(Projectile).bool silent;
 
 void SUB_Stop();
 
@@ -29,8 +29,4 @@ void loopsound(entity e, int ch, string samp, float vol, float attn);
 
 void Ent_RemoveProjectile();
 
-void Ent_Projectile();
-
-void Projectile_Precache();
-
 #endif
diff --git a/qcsrc/common/buffs/all.inc b/qcsrc/common/buffs/all.inc
deleted file mode 100644 (file)
index 25fa722..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-REGISTER_BUFF(AMMO) {
-    this.m_prettyName = _("Ammo");
-    this.m_name = "ammo";
-    this.m_skin = 3;
-    this.m_color = '0.76 1 0.1';
-}
-BUFF_SPAWNFUNCS(ammo, BUFF_AMMO)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(ammoregen, BUFF_AMMO)
-
-REGISTER_BUFF(RESISTANCE) {
-    this.m_prettyName = _("Resistance");
-    this.m_name = "resistance";
-    this.m_skin = 0;
-    this.m_color = '0.36 1 0.07';
-}
-BUFF_SPAWNFUNCS(resistance, BUFF_RESISTANCE)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(resistance, BUFF_RESISTANCE)
-
-REGISTER_BUFF(SPEED) {
-    this.m_prettyName = _("Speed");
-    this.m_name = "speed";
-    this.m_skin = 9;
-    this.m_color = '0.1 1 0.84';
-}
-BUFF_SPAWNFUNCS(speed, BUFF_SPEED)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(haste, BUFF_SPEED)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(scout, BUFF_SPEED)
-
-REGISTER_BUFF(MEDIC) {
-    this.m_prettyName = _("Medic");
-    this.m_name = "medic";
-    this.m_skin = 1;
-    this.m_color = '1 0.12 0';
-}
-BUFF_SPAWNFUNCS(medic, BUFF_MEDIC)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(doubler, BUFF_MEDIC)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(medic, BUFF_MEDIC)
-
-REGISTER_BUFF(BASH) {
-    this.m_prettyName = _("Bash");
-    this.m_name = "bash";
-    this.m_skin = 5;
-    this.m_color = '1 0.39 0';
-}
-BUFF_SPAWNFUNCS(bash, BUFF_BASH)
-
-REGISTER_BUFF(VAMPIRE) {
-    this.m_prettyName = _("Vampire");
-    this.m_name = "vampire";
-    this.m_skin = 2;
-    this.m_color = '1 0 0.24';
-}
-BUFF_SPAWNFUNCS(vampire, BUFF_VAMPIRE)
-
-REGISTER_BUFF(DISABILITY) {
-    this.m_prettyName = _("Disability");
-    this.m_name = "disability";
-    this.m_skin = 7;
-    this.m_color = '0.94 0.3 1';
-}
-BUFF_SPAWNFUNCS(disability, BUFF_DISABILITY)
-
-REGISTER_BUFF(VENGEANCE) {
-    this.m_prettyName = _("Vengeance");
-    this.m_name = "vengeance";
-    this.m_skin = 15;
-    this.m_color = '1 0.23 0.61';
-}
-BUFF_SPAWNFUNCS(vengeance, BUFF_VENGEANCE)
-
-REGISTER_BUFF(JUMP) {
-    this.m_prettyName = _("Jump");
-    this.m_name = "jump";
-    this.m_skin = 10;
-    this.m_color = '0.24 0.78 1';
-}
-BUFF_SPAWNFUNCS(jump, BUFF_JUMP)
-
-REGISTER_BUFF(FLIGHT) {
-    this.m_prettyName = _("Flight");
-    this.m_name = "flight";
-    this.m_skin = 11;
-    this.m_color = '0.33 0.56 1';
-}
-BUFF_SPAWNFUNCS(flight, BUFF_FLIGHT)
-
-REGISTER_BUFF(INVISIBLE) {
-    this.m_prettyName = _("Invisible");
-    this.m_name = "invisible";
-    this.m_skin = 12;
-    this.m_color = '0.5 0.5 1';
-}
-BUFF_SPAWNFUNCS(invisible, BUFF_INVISIBLE)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(invis, BUFF_INVISIBLE)
-
-REGISTER_BUFF(INFERNO) {
-    this.m_prettyName = _("Inferno");
-    this.m_name = "inferno";
-    this.m_skin = 16;
-    this.m_color = '1 0.62 0';
-}
-BUFF_SPAWNFUNCS(inferno, BUFF_INFERNO)
-
-REGISTER_BUFF(SWAPPER) {
-    this.m_prettyName = _("Swapper");
-    this.m_name = "swapper";
-    this.m_skin = 17;
-    this.m_color = '0.63 0.36 1';
-}
-BUFF_SPAWNFUNCS(swapper, BUFF_SWAPPER)
-
-REGISTER_BUFF(MAGNET) {
-    this.m_prettyName = _("Magnet");
-    this.m_name = "magnet";
-    this.m_skin = 18;
-    this.m_color = '1 0.95 0.18';
-}
-BUFF_SPAWNFUNCS(magnet, BUFF_MAGNET)
diff --git a/qcsrc/common/buffs/all.qc b/qcsrc/common/buffs/all.qc
deleted file mode 100644 (file)
index c6a6f49..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(CSQC)
-       #include "../../client/defs.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-#include "all.qh"
-
diff --git a/qcsrc/common/buffs/all.qh b/qcsrc/common/buffs/all.qh
deleted file mode 100644 (file)
index 7099034..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef BUFFS_ALL_H
-#define BUFFS_ALL_H
-// Welcome to the stuff behind the scenes
-// Below, you will find the list of buffs
-// Add new buffs here!
-// Note: Buffs also need spawnfuncs, which are set below
-
-#include "../teams.qh"
-#include "../util.qh"
-
-REGISTRY(Buffs, BIT(4))
-REGISTER_REGISTRY(RegisterBuffs)
-
-#define REGISTER_BUFF(id) \
-    REGISTER(RegisterBuffs, BUFF, Buffs, id, m_id, NEW(Buff)); \
-    REGISTER_INIT_POST(BUFF, id) { \
-        this.netname = this.m_name; \
-        this.m_itemid = BIT(this.m_id - 1); \
-        this.m_sprite = strzone(strcat("buff-", this.m_name)); \
-    } \
-    REGISTER_INIT(BUFF, id)
-
-#include "../items/item/pickup.qh"
-CLASS(Buff, Pickup)
-       /** bit index */
-       ATTRIB(Buff, m_itemid, int, 0)
-       ATTRIB(Buff, m_name, string, "buff")
-       ATTRIB(Buff, m_color, vector, '1 1 1')
-       ATTRIB(Buff, m_prettyName, string, "Buff")
-       ATTRIB(Buff, m_skin, int, 0)
-       ATTRIB(Buff, m_sprite, string, "")
-       METHOD(Buff, display, void(entity this, void(string name, string icon) returns)) {
-               returns(this.m_prettyName, sprintf("/gfx/hud/%s/buff_%s", cvar_string("menu_skin"), this.m_name));
-       }
-#ifdef SVQC
-       METHOD(Buff, m_time, float(entity));
-       float Buff_m_time(entity this) { return cvar(strcat("g_buffs_", this.netname, "_time")); }
-#endif
-ENDCLASS(Buff)
-
-#ifdef SVQC
-       .int buffs;
-       void buff_Init(entity ent);
-       void buff_Init_Compat(entity ent, entity replacement);
-       #define BUFF_SPAWNFUNC(e, b, t) spawnfunc(item_buff_##e) { \
-               self.buffs = b.m_itemid; \
-               self.team = t; \
-               buff_Init(self); \
-       }
-       #define BUFF_SPAWNFUNCS(e, b)                       \
-                       BUFF_SPAWNFUNC(e,           b,  0)          \
-                       BUFF_SPAWNFUNC(e##_team1,   b,  NUM_TEAM_1) \
-                       BUFF_SPAWNFUNC(e##_team2,   b,  NUM_TEAM_2) \
-                       BUFF_SPAWNFUNC(e##_team3,   b,  NUM_TEAM_3) \
-                       BUFF_SPAWNFUNC(e##_team4,   b,  NUM_TEAM_4)
-       #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r) spawnfunc(item_##o) { buff_Init_Compat(self, r); }
-#else
-       #define BUFF_SPAWNFUNC(e, b, t)
-       #define BUFF_SPAWNFUNCS(e, b)
-       #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r)
-#endif
-
-REGISTER_BUFF(Null);
-BUFF_SPAWNFUNCS(random, BUFF_Null)
-
-#include "all.inc"
-
-#endif
index 756b36d5987ad3debe1b873d951845d6670bc163..d1eb3cf76e284bf3b1ddc547366bef69218ac1ef 100644 (file)
@@ -2,16 +2,17 @@
 #define COMMON_COMMANDS_ALL_H
 
 #include "command.qh"
-REGISTRY(GENERIC_COMMANDS, 50)
-REGISTER_REGISTRY(RegisterGENERIC_COMMANDS)
-REGISTRY_SORT(GENERIC_COMMANDS, m_name, 0)
+REGISTRY(GENERIC_COMMANDS, BITS(7))
+#define GENERIC_COMMANDS_from(i) _GENERIC_COMMANDS_from(i, NULL)
+REGISTER_REGISTRY(GENERIC_COMMANDS)
+REGISTRY_SORT(GENERIC_COMMANDS, 0)
 
 #define GENERIC_COMMAND(id, description) \
        CLASS(genericcommand_##id, Command) \
                ATTRIB(genericcommand_##id, m_name, string, #id); \
        ATTRIB(genericcommand_##id, m_description, string, description); \
        ENDCLASS(genericcommand_##id) \
-    REGISTER(RegisterGENERIC_COMMANDS, CMD_G, GENERIC_COMMANDS, id, m_id, NEW(genericcommand_##id)); \
+    REGISTER(GENERIC_COMMANDS, CMD_G, id, m_id, NEW(genericcommand_##id)); \
        METHOD(genericcommand_##id, m_invokecmd, void(int request, int arguments, string command))
 
 STATIC_INIT(GENERIC_COMMANDS_aliases) {
index 5412c22b4b8436bc07b36ac2c974a98ab29903b4..9a50894c04116d52427c33abe093a404ff2be72e 100644 (file)
@@ -28,7 +28,7 @@
 // =========================================================
 
 // used by generic commands for better help/usage information
-string GetProgramCommandPrefix(void)
+string GetProgramCommandPrefix()
 {
        #ifdef SVQC
        return "sv_cmd";
index e419824ec8eb8d0aadf82735805bf1193c5bc713..be84c407ca193c3e4316f16d68e7950f4548b082 100644 (file)
@@ -22,7 +22,7 @@ void GenericCommand_macro_write_aliases(float fh);
 float GenericCommand(string command);
 
 // Returns command prefix specific for whatever program it is compiled in
-string GetProgramCommandPrefix(void);
+string GetProgramCommandPrefix();
 
 // used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
 #define CMD_Write(s) fputs(fh, s)
index 254246bdff54a896477a214d96686f5dd4ffb9ce..8d8e8df19fecc4965ebf3242946f04282d972d47 100644 (file)
 // Revision 22: hook shot origin
 #define CSQC_REVISION 22
 
-const int AS_STRING = 1;
-const int AS_INT = 2;
-const int AS_FLOAT_TRUNCATED = 2;
-const int AS_FLOAT = 8;
-
-const int TE_CSQC_MUTATOR = 99;
-#define MUTATOR_HASH(s) crc16(true, s)
-#define WriteMutator(to, s) do { \
-    WriteByte(to, TE_CSQC_MUTATOR); \
-    WriteLong(to, MUTATOR_HASH(#s)); \
-} while (0)
-#define ReadMutator() ReadLong()
-#define ReadMutatorEquals(read, s) (read == MUTATOR_HASH(#s))
-const int TE_CSQC_PICTURE = 100;
-const int TE_CSQC_RACE = 101;
-const int TE_CSQC_VORTEXBEAMPARTICLE = 103;
-const int TE_CSQC_ARC = 104;
-const int TE_CSQC_TEAMNAGGER = 105;
-const int TE_CSQC_PINGPLREPORT = 106;
-const int TE_CSQC_TARGET_MUSIC = 107;
-const int TE_CSQC_WEAPONCOMPLAIN = 108;
-const int TE_CSQC_VORTEX_SCOPE = 109;
-const int TE_CSQC_MINELAYER_MAXMINES = 110;
-const int TE_CSQC_HAGAR_MAXROCKETS = 111;
-const int TE_CSQC_VEHICLESETUP = 112;
-const int TE_CSQC_SVNOTICE = 113;
-const int TE_CSQC_SHOCKWAVEPARTICLE = 114;
+REGISTER_NET_TEMP(TE_CSQC_PICTURE)
+REGISTER_NET_TEMP(TE_CSQC_RACE)
+REGISTER_NET_TEMP(TE_CSQC_TEAMNAGGER)
+REGISTER_NET_TEMP(TE_CSQC_PINGPLREPORT)
+REGISTER_NET_TEMP(TE_CSQC_WEAPONCOMPLAIN)
+REGISTER_NET_TEMP(TE_CSQC_VEHICLESETUP)
 
 const int RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
 const int RACE_NET_CHECKPOINT_CLEAR = 1;
@@ -69,66 +48,39 @@ const int RACE_NET_SERVER_RANKINGS = 11;
 const int RACE_NET_SERVER_STATUS = 12;
 const int RANKINGS_CNT = 15;
 
-const int ENT_CLIENT = 0;
-const int ENT_CLIENT_DEAD = 1;
-const int ENT_CLIENT_ENTCS = 2;
-const int ENT_CLIENT_SCORES_INFO = 3;
-const int ENT_CLIENT_SCORES = 4;
-const int ENT_CLIENT_TEAMSCORES = 5;
-const int ENT_CLIENT_POINTPARTICLES = 6;
-const int ENT_CLIENT_RAINSNOW = 7;
-const int ENT_CLIENT_LASER = 8;
-const int ENT_CLIENT_NAGGER = 9; // flags [votecalledvote]
-const int ENT_CLIENT_RADARLINK = 11; // flags [startorigin] [endorigin] [startcolor+16*endcolor]
-const int ENT_CLIENT_PROJECTILE = 12;
-const int ENT_CLIENT_GIBSPLASH = 13;
-const int ENT_CLIENT_DAMAGEINFO = 14;
-const int ENT_CLIENT_INIT = 16;
-const int ENT_CLIENT_MAPVOTE = 17;
-const int ENT_CLIENT_CLIENTDATA = 18;
-const int ENT_CLIENT_RANDOMSEED = 19;
-const int ENT_CLIENT_WALL = 20;
-const int ENT_CLIENT_SPIDERBOT = 21;
-const int ENT_CLIENT_MODELEFFECT = 22;
-const int ENT_CLIENT_TUBANOTE = 23;
-const int ENT_CLIENT_WARPZONE = 24;
-const int ENT_CLIENT_WARPZONE_CAMERA = 25;
-const int ENT_CLIENT_TRIGGER_MUSIC = 26;
-const int ENT_CLIENT_HOOK = 27;
-const int ENT_CLIENT_INVENTORY = 28;
-const int ENT_CLIENT_ARC_BEAM = 29; // WEAPONTODO: fix numbers
-const int ENT_CLIENT_ACCURACY = 30;
-const int ENT_CLIENT_SHOWNAMES = 31;
-const int ENT_CLIENT_WARPZONE_TELEPORTED = 32;
-const int ENT_CLIENT_MODEL = 33;
-const int ENT_CLIENT_ITEM = 34;
-const int ENT_CLIENT_BUMBLE_RAYGUN = 35;
-const int ENT_CLIENT_SPAWNPOINT = 36;
-const int ENT_CLIENT_SPAWNEVENT = 37;
-const int ENT_CLIENT_NOTIFICATION = 38;
-const int ENT_CLIENT_ELIMINATEDPLAYERS = 39;
-const int ENT_CLIENT_TURRET = 40;
-const int ENT_CLIENT_AUXILIARYXHAIR = 50;
-const int ENT_CLIENT_VEHICLE = 60;
-const int ENT_CLIENT_LADDER = 61;
-const int ENT_CLIENT_TRIGGER_PUSH = 62;
-const int ENT_CLIENT_TARGET_PUSH = 63;
-const int ENT_CLIENT_CONVEYOR = 64;
-const int ENT_CLIENT_DOOR = 65;
-const int ENT_CLIENT_TRAIN = 66;
-const int ENT_CLIENT_PLAT = 67;
-const int ENT_CLIENT_TRIGGER_IMPULSE = 68;
-const int ENT_CLIENT_SWAMP = 69;
-const int ENT_CLIENT_CORNER = 70;
-const int ENT_CLIENT_KEYLOCK = 71;
-const int ENT_CLIENT_GENERATOR = 72;
-const int ENT_CLIENT_CONTROLPOINT_ICON = 73;
-const int ENT_CLIENT_EFFECT = 74;
-const int ENT_CLIENT_MINIGAME = 75;
-const int ENT_CLIENT_VIEWLOC = 78;
-const int ENT_CLIENT_VIEWLOC_TRIGGER = 79;
-
-const int ENT_CLIENT_MUTATOR = TE_CSQC_MUTATOR; // 99
+REGISTER_NET_LINKED(_ENT_CLIENT_INIT)
+#ifdef CSQC
+NET_HANDLE(_ENT_CLIENT_INIT, bool isnew) { return true; }
+#endif
+/** Sent as a temp entity from a persistent linked entity */
+REGISTER_NET_TEMP(ENT_CLIENT_INIT)
+
+REGISTER_NET_LINKED(ENT_CLIENT_ENTCS)
+REGISTER_NET_LINKED(ENT_CLIENT_SCORES_INFO)
+REGISTER_NET_LINKED(ENT_CLIENT_SCORES)
+REGISTER_NET_LINKED(ENT_CLIENT_TEAMSCORES)
+REGISTER_NET_LINKED(ENT_CLIENT_NAGGER) // flags [votecalledvote]
+REGISTER_NET_LINKED(ENT_CLIENT_RADARLINK) // flags [startorigin] [endorigin] [startcolor+16*endcolor]
+REGISTER_NET_LINKED(ENT_CLIENT_PROJECTILE)
+REGISTER_NET_LINKED(ENT_CLIENT_MAPVOTE)
+REGISTER_NET_LINKED(ENT_CLIENT_CLIENTDATA)
+REGISTER_NET_LINKED(ENT_CLIENT_RANDOMSEED)
+REGISTER_NET_LINKED(ENT_CLIENT_ACCURACY)
+REGISTER_NET_LINKED(ENT_CLIENT_ELIMINATEDPLAYERS)
+
+REGISTER_NET_LINKED(ENT_CLIENT_MODEL)
+
+REGISTER_NET_LINKED(ENT_CLIENT_WARPZONE)
+REGISTER_NET_LINKED(ENT_CLIENT_WARPZONE_CAMERA)
+REGISTER_NET_LINKED(ENT_CLIENT_WARPZONE_TELEPORTED)
+
+REGISTER_NET_LINKED(ENT_CLIENT_ARC_BEAM)
+REGISTER_NET_LINKED(ENT_CLIENT_HOOK)
+REGISTER_NET_LINKED(ENT_CLIENT_TUBANOTE)
+
+REGISTER_NET_LINKED(ENT_CLIENT_SPAWNPOINT)
+REGISTER_NET_LINKED(ENT_CLIENT_SPAWNEVENT)
+REGISTER_NET_LINKED(ENT_CLIENT_WALL)
 
 const int SPRITERULE_DEFAULT = 0;
 const int SPRITERULE_TEAMPLAY = 1;
@@ -155,10 +107,6 @@ const int CVAR_READONLY = 4;
 ///////////////////////////
 // csqc communication stuff
 
-const int CTF_STATE_ATTACK = 1;
-const int CTF_STATE_DEFEND = 2;
-const int CTF_STATE_COMMANDER = 3;
-
 const int HUD_NORMAL = 0;
 const int HUD_BUMBLEBEE_GUN = 25;
 
@@ -204,7 +152,7 @@ const int SFL_SORT_PRIO_MASK = 12;
 /**
  * Score indices
  */
-#define MAX_SCORE 10
+#define MAX_SCORE 12
 #define MAX_TEAMSCORE 2
 
 const int ST_SCORE = 0;
@@ -212,36 +160,10 @@ const int SP_KILLS = 0;
 const int SP_DEATHS = 1;
 const int SP_SUICIDES = 2;
 const int SP_SCORE = 3;
+const int SP_DMG = 10;
+const int SP_DMGTAKEN = 11;
 // game mode specific indices are not in common/, but in server/scores_rules.qc!
 
-const int CH_INFO = 0;
-const int CH_TRIGGER = -3;
-const int CH_WEAPON_A = -1;
-const int CH_WEAPON_SINGLE = 1;
-const int CH_VOICE = -2;
-const int CH_BGM_SINGLE = 8;
-const int CH_AMBIENT = -9;
-const int CH_TRIGGER_SINGLE = 3;
-const int CH_SHOTS = -4;
-const int CH_SHOTS_SINGLE = 4;
-const int CH_WEAPON_B = -1;
-const int CH_PAIN = -6;
-const int CH_PAIN_SINGLE = 6;
-const int CH_PLAYER = -7;
-const int CH_PLAYER_SINGLE = 7;
-const int CH_TUBA_SINGLE = 5;
-
-const float ATTEN_NONE = 0;
-const float ATTEN_MIN = 0.015625;
-const float ATTEN_NORM = 0.5;
-const float ATTEN_LARGE = 1;
-const float ATTEN_IDLE = 2;
-const float ATTEN_STATIC = 3;
-const float ATTEN_MAX = 3.984375;
-
-const float VOL_BASE = 0.7;
-const float VOL_BASEVOICE = 1.0;
-
 // WEAPONTODO: move this into separate/new projectile handling code // this sets sounds and other properties of the projectiles in csqc
 const int PROJECTILE_ELECTRO = 1;
 const int PROJECTILE_ROCKET = 2;
index eacc1947e1be0e9a29edbd48b30717db47701594..29a0bf44a599f909796953c9937e41caec87fdc0 100644 (file)
@@ -76,7 +76,9 @@
        CSQCPlayer_SetViewLocation();
 
 // force updates of player entities that often even if unchanged
+#ifndef CSQCPLAYER_FORCE_UPDATES
 #define CSQCPLAYER_FORCE_UPDATES 0.25
+#endif
 
 // mod must define:
 //vector PL_MIN  = ...;
index 4fdafa9a82b6a5d54f92b9349eb9e3098f13f597..823a20f8e0467a5e97d1986c16de124389f1090f 100644 (file)
@@ -3,7 +3,7 @@
 string Deathtype_Name(int deathtype)
 {
        if (DEATH_ISSPECIAL(deathtype)) {
-               entity deathent = Deathtypes[deathtype - DT_FIRST];
+               entity deathent = Deathtypes_from(deathtype - DT_FIRST);
                if (!deathent) { backtrace("Deathtype_Name: Could not find deathtype entity!\n"); return ""; }
                return deathent.nent_name;
        }
index 2bf1169bf77d9f494f43dd7335ad6dac40a8b59a..dcf64b11f3d635b6dac5224de9d93977ac87585c 100644 (file)
@@ -3,15 +3,18 @@
 
 #include "../notifications.qh"
 
-REGISTRY(Deathtypes, BIT(6))
-REGISTER_REGISTRY(RegisterDeathtypes)
+REGISTRY(Deathtypes, BITS(8))
+#define Deathtypes_from(i) _Deathtypes_from(i, NULL)
+REGISTER_REGISTRY(Deathtypes)
+REGISTRY_CHECK(Deathtypes)
 
 .entity death_msgself;
 .entity death_msgmurder;
 .string death_msgextra;
 
 #define REGISTER_DEATHTYPE(id, msg_death, msg_death_by, extra) \
-    REGISTER(RegisterDeathtypes, DEATH, Deathtypes, id, m_id, new(deathtype)) { \
+    REGISTER(Deathtypes, DEATH, id, m_id, new(deathtype)) { \
+        make_pure(this); \
         this.m_id += DT_FIRST; \
         this.nent_name = #id; \
         this.death_msgextra = extra; \
@@ -32,11 +35,11 @@ const int DEATH_HITTYPEMASK = HITTYPE_SECONDARY | HITTYPE_SPLASH | HITTYPE_BOUNC
 const int DT_FIRST = BIT(13);
 
 #define DEATH_ISSPECIAL(t)      (t >= DT_FIRST)
-#define DEATH_IS(t, dt)         (DEATH_ISSPECIAL(t) && (Deathtypes[t - DT_FIRST]) == dt)
-#define DEATH_ENT(t)            (DEATH_ISSPECIAL(t) ?  (Deathtypes[t - DT_FIRST]) : NULL)
-#define DEATH_ISVEHICLE(t)      (DEATH_ISSPECIAL(t) && (Deathtypes[t - DT_FIRST]).death_msgextra == "vehicle")
-#define DEATH_ISTURRET(t)       (DEATH_ISSPECIAL(t) && (Deathtypes[t - DT_FIRST]).death_msgextra == "turret")
-#define DEATH_ISMONSTER(t)      (DEATH_ISSPECIAL(t) && (Deathtypes[t - DT_FIRST]).death_msgextra == "monster")
+#define DEATH_IS(t, dt)         (DEATH_ISSPECIAL(t) && (Deathtypes_from(t - DT_FIRST)) == dt)
+#define DEATH_ENT(t)            (DEATH_ISSPECIAL(t) ?  (Deathtypes_from(t - DT_FIRST)) : NULL)
+#define DEATH_ISVEHICLE(t)      (DEATH_ISSPECIAL(t) && (Deathtypes_from(t - DT_FIRST)).death_msgextra == "vehicle")
+#define DEATH_ISTURRET(t)       (DEATH_ISSPECIAL(t) && (Deathtypes_from(t - DT_FIRST)).death_msgextra == "turret")
+#define DEATH_ISMONSTER(t)      (DEATH_ISSPECIAL(t) && (Deathtypes_from(t - DT_FIRST)).death_msgextra == "monster")
 #define DEATH_WEAPONOF(t)       (DEATH_ISSPECIAL(t) ? WEP_Null : get_weaponinfo((t) & DEATH_WEAPONMASK))
 #define DEATH_ISWEAPON(t, w)    (DEATH_WEAPONOF(t) == (w))
 
diff --git a/qcsrc/common/debug.qh b/qcsrc/common/debug.qh
new file mode 100644 (file)
index 0000000..7301489
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+.bool debug;
+.int sv_entnum;
+REGISTER_NET_TEMP(net_debug)
+#ifdef CSQC
+       NET_HANDLE(net_debug, bool isNew)
+       {
+               Net_Accept(net_debug);
+               this.sv_entnum = ReadShort();
+               if (ReadByte()) make_pure(this);
+               this.origin_x = ReadCoord();
+               this.origin_y = ReadCoord();
+               this.origin_z = ReadCoord();
+               setorigin(this, this.origin);
+               this.debug = true;  // identify server entities by this
+               this.classname = strzone(ReadString());
+               this.sourceLocFile = strzone(ReadString());
+               this.sourceLocLine = ReadInt24_t();
+               return true;
+       }
+#endif
+
+#ifdef SVQC
+       bool debug_send(entity this, entity to, int sf)
+       {
+               int channel = MSG_ONE;
+               msg_entity = to;
+               WriteHeader(channel, net_debug);
+               WriteShort(channel, num_for_edict(this));
+               WriteByte(channel, is_pure(this));
+               WriteCoord(channel, this.origin.x);
+               WriteCoord(channel, this.origin.y);
+               WriteCoord(channel, this.origin.z);
+               WriteString(channel, this.classname);
+               WriteString(channel, this.sourceLocFile);
+               WriteInt24_t(channel, this.sourceLocLine);
+               return true;
+       }
+#endif
+
+bool autocvar_debugdraw;
+
+#ifdef CSQC
+       .int debugdraw_last;
+       vector project_3d_to_2d(vector vec);
+       void Debug_Draw()
+       {
+               if (!autocvar_debugdraw) return;
+               static int debugdraw_frame;
+               ++debugdraw_frame;
+               const int size = 8;
+               for (entity e1 = NULL; (e1 = nextent(e1)); )
+               {
+                       if (e1.debugdraw_last == debugdraw_frame) continue;
+                       int ofs = 0;
+                       for (entity e = findradius(e1.origin, 100); e; e = e.chain)
+                       {
+                               if (e.debugdraw_last == debugdraw_frame) continue;
+                               e.debugdraw_last = debugdraw_frame;
+                               vector rgb = (e.debug) ? '0 0 1' : '1 0 0';
+                               if (is_pure(e))
+                               {
+                                       if (autocvar_debugdraw < 2) continue;
+                                       rgb.y = 1;
+                               }
+                               vector pos = project_3d_to_2d(e.origin);
+                               if (pos.z < 0) continue;
+                               pos.z = 0;
+                               pos.y += ofs * size;
+                               drawcolorcodedstring2(pos,
+                                       sprintf("%d: '%s'@%s:%d", (e.debug ? e.sv_entnum : num_for_edict(e)),
+                                       e.classname, e.sourceLocFile, e.sourceLocLine),
+                                       size * '1 1 0', rgb, 0.5, DRAWFLAG_NORMAL);
+                               ++ofs;
+                       }
+               }
+       }
+#endif
+
+#ifdef SVQC
+       GENERIC_COMMAND(debugdraw_sv, "Dump all server entities")
+       {
+               switch (request)
+               {
+                       case CMD_REQUEST_COMMAND:
+                       {
+                               if (!autocvar_debugdraw) return;
+                               int n = 1000;
+                               int rem = n;
+                               for (entity e = NULL; (e = findfloat(e, debug, 0)) && rem > 0; )
+                               {
+                                       if (autocvar_debugdraw < 2 && is_pure(e)) continue;
+                                       debug_send(e, nextent(NULL), 0);
+                                       e.debug = true;
+                                       --rem;
+                               }
+                               LOG_INFOF("%d server entities sent\n", n - rem);
+                               return;
+                       }
+
+                       default:
+                       case CMD_REQUEST_USAGE:
+                       {
+                               LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " debugdraw_sv"));
+                               return;
+                       }
+               }
+       }
+#endif
+
+#endif
index d53ded907aaebe91e730189fcd5676c8472e45db..b34180056a1a5302c8b0fe46f50c97fe345c8e0e 100644 (file)
@@ -23,6 +23,9 @@ EFFECT(0, ARC_BEAM,                 "arc_beam")
 EFFECT(0, ARC_BEAM_HEAL,            "arc_beam_heal")
 EFFECT(0, ARC_BEAM_HEAL_IMPACT,     "arc_beam_healimpact")
 EFFECT(0, ARC_BEAM_HEAL_IMPACT2,    "healray_impact")
+EFFECT(0, ARC_OVERHEAT,             "arc_overheat")
+EFFECT(0, ARC_OVERHEAT_FIRE,        "arc_overheat_fire")
+EFFECT(0, ARC_SMOKE,                "arc_smoke")
 EFFECT(0, ARC_LIGHTNING,            "arc_lightning")
 EFFECT(0, ARC_LIGHTNING2,           "electro_lightning")
 
@@ -98,8 +101,6 @@ EFFECT(0, HOOK_MUZZLEFLASH,         "grapple_muzzleflash")
 
 EFFECT(0, SEEKER_MUZZLEFLASH,       "seeker_muzzleflash")
 
-EFFECT(0, FLAK_BOUNCE,              "flak_bounce")
-
 EFFECT(1, FIREBALL,                 "fireball")
 EFFECT(0, FIREBALL_BFGDAMAGE,       "fireball_bfgdamage")
 EFFECT(0, FIREBALL_EXPLODE,         "fireball_explode")
@@ -146,54 +147,6 @@ EFFECT(0, SPAWN_PINK,               "spawn_event_pink")
 EFFECT(0, SPAWNPOINT_NEUTRAL,       "spawn_point_neutral")
 EFFECT(0, SPAWN_NEUTRAL,            "spawn_event_neutral")
 
-EFFECT(0, NADE_EXPLODE_RED,         "nade_red_explode")
-EFFECT(0, NADE_EXPLODE_BLUE,        "nade_blue_explode")
-EFFECT(0, NADE_EXPLODE_YELLOW,      "nade_yellow_explode")
-EFFECT(0, NADE_EXPLODE_PINK,        "nade_pink_explode")
-EFFECT(0, NADE_EXPLODE_NEUTRAL,     "nade_neutral_explode")
-entity EFFECT_NADE_EXPLODE(int teamid)
-{
-    switch (teamid) {
-        case NUM_TEAM_1:    return EFFECT_NADE_EXPLODE_RED;
-        case NUM_TEAM_2:    return EFFECT_NADE_EXPLODE_BLUE;
-        case NUM_TEAM_3:    return EFFECT_NADE_EXPLODE_YELLOW;
-        case NUM_TEAM_4:    return EFFECT_NADE_EXPLODE_PINK;
-        default:                   return EFFECT_NADE_EXPLODE_NEUTRAL;
-    }
-}
-
-EFFECT(1, NADE_TRAIL_RED,           "nade_red")
-EFFECT(1, NADE_TRAIL_BLUE,          "nade_blue")
-EFFECT(1, NADE_TRAIL_YELLOW,        "nade_yellow")
-EFFECT(1, NADE_TRAIL_PINK,          "nade_pink")
-EFFECT(1, NADE_TRAIL_NEUTRAL,       "nade_neutral")
-entity EFFECT_NADE_TRAIL(int teamid)
-{
-    switch (teamid) {
-        case NUM_TEAM_1:    return EFFECT_NADE_TRAIL_RED;
-        case NUM_TEAM_2:    return EFFECT_NADE_TRAIL_BLUE;
-        case NUM_TEAM_3:    return EFFECT_NADE_TRAIL_YELLOW;
-        case NUM_TEAM_4:    return EFFECT_NADE_TRAIL_PINK;
-        default:            return EFFECT_NADE_TRAIL_NEUTRAL;
-    }
-}
-
-EFFECT(1, NADE_TRAIL_BURN_RED,      "nade_red_burn")
-EFFECT(1, NADE_TRAIL_BURN_BLUE,     "nade_blue_burn")
-EFFECT(1, NADE_TRAIL_BURN_YELLOW,   "nade_yellow_burn")
-EFFECT(1, NADE_TRAIL_BURN_PINK,     "nade_pink_burn")
-EFFECT(1, NADE_TRAIL_BURN_NEUTRAL,  "nade_neutral_burn")
-entity EFFECT_NADE_TRAIL_BURN(int teamid)
-{
-    switch (teamid) {
-        case NUM_TEAM_1:    return EFFECT_NADE_TRAIL_BURN_RED;
-        case NUM_TEAM_2:    return EFFECT_NADE_TRAIL_BURN_BLUE;
-        case NUM_TEAM_3:    return EFFECT_NADE_TRAIL_BURN_YELLOW;
-        case NUM_TEAM_4:    return EFFECT_NADE_TRAIL_BURN_PINK;
-        default:            return EFFECT_NADE_TRAIL_BURN_NEUTRAL;
-    }
-}
-
 EFFECT(0, ICEORGLASS,               "iceorglass")
 EFFECT(0, ICEFIELD,                 "icefield")
 EFFECT(0, FIREFIELD,                "firefield")
@@ -222,6 +175,16 @@ EFFECT(1, PASS_BLUE,                "blue_pass")
 EFFECT(1, PASS_YELLOW,              "yellow_pass")
 EFFECT(1, PASS_PINK,                "pink_pass")
 EFFECT(1, PASS_NEUTRAL,             "neutral_pass")
+entity EFFECT_PASS(int teamid)
+{
+    switch (teamid) {
+        case NUM_TEAM_1:    return EFFECT_PASS_RED;
+        case NUM_TEAM_2:    return EFFECT_PASS_BLUE;
+        case NUM_TEAM_3:    return EFFECT_PASS_YELLOW;
+        case NUM_TEAM_4:    return EFFECT_PASS_PINK;
+        default:            return EFFECT_PASS_NEUTRAL;
+    }
+}
 
 EFFECT(0, CAP_RED,                  "red_cap")
 EFFECT(0, CAP_BLUE,                 "blue_cap")
index e90f3c615b36dd5c99adc1ac8604ebaa755fc086..347a2111b563f4ebdb4e18de5e561ed1eb956306 100644 (file)
@@ -1,15 +1,17 @@
 #include "all.qh"
 
+REGISTER_NET_TEMP(net_effect)
 #ifdef CSQC
-void Read_Effect(bool is_new)
+NET_HANDLE(net_effect, bool isNew)
 {
        int net_name = (Effects_COUNT >= 255) ? ReadShort() : ReadByte();
 
-       entity eff = Effects[net_name];
+       entity eff = Effects_from(net_name);
 
-       vector v, vel = '0 0 0';
+       vector vel = '0 0 0';
        int eff_cnt = 1;
        bool eff_trail = eff.eent_eff_trail;
+       vector v;
        v_x = ReadCoord();
        v_y = ReadCoord();
        v_z = ReadCoord();
@@ -25,38 +27,38 @@ void Read_Effect(bool is_new)
        if(!eff_trail)
                eff_cnt = ReadByte();
 
-       if(is_new)
-       {
-               if(eff_trail)
-                       WarpZone_TrailParticles(world, particleeffectnum(eff), v, vel);
-               else
-                       pointparticles(particleeffectnum(eff), v, vel, eff_cnt);
-       }
+       if(eff_trail)
+               WarpZone_TrailParticles(world, particleeffectnum(eff), v, vel);
+       else
+               pointparticles(eff, v, vel, eff_cnt);
+       return true;
 }
 #endif
 
 #ifdef SVQC
 bool Net_Write_Effect(entity this, entity client, int sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_EFFECT);
+       int channel = MSG_ONE;
+       msg_entity = client;
+       WriteHeader(channel, net_effect);
        (Effects_COUNT >= 255)
-       ? WriteShort(MSG_ENTITY, self.m_id)
-       : WriteByte(MSG_ENTITY, self.m_id);
-       WriteCoord(MSG_ENTITY, self.eent_net_location_x);
-       WriteCoord(MSG_ENTITY, self.eent_net_location_y);
-       WriteCoord(MSG_ENTITY, self.eent_net_location_z);
+       ? WriteShort(channel, this.m_id)
+       : WriteByte(channel, this.m_id);
+       WriteCoord(channel, this.eent_net_location_x);
+       WriteCoord(channel, this.eent_net_location_y);
+       WriteCoord(channel, this.eent_net_location_z);
 
        // attempt to save a tiny bit more bandwidth by not sending velocity if it isn't set
-       if(self.eent_net_velocity)
+       if(this.eent_net_velocity)
        {
-               WriteByte(MSG_ENTITY, true);
-               WriteCoord(MSG_ENTITY, self.eent_net_velocity_x);
-               WriteCoord(MSG_ENTITY, self.eent_net_velocity_y);
-               WriteCoord(MSG_ENTITY, self.eent_net_velocity_z);
+               WriteByte(channel, true);
+               WriteCoord(channel, this.eent_net_velocity_x);
+               WriteCoord(channel, this.eent_net_velocity_y);
+               WriteCoord(channel, this.eent_net_velocity_z);
        }
-       else { WriteByte(MSG_ENTITY, false); }
+       else { WriteByte(channel, false); }
 
-       if(!self.eent_eff_trail) { WriteByte(MSG_ENTITY, self.eent_net_count); }
+       if(!this.eent_eff_trail) { WriteByte(channel, this.eent_net_count); }
        return true;
 }
 
@@ -64,9 +66,9 @@ void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
 {
        if(!eff) { return; }
        if(!eff.eent_eff_trail && !eff_cnt) { return; } // effect has no count!
-       entity net_eff = spawn();
+       entity net_eff = new(net_effect);
+       make_pure(net_eff);
        net_eff.owner = eff;
-       net_eff.classname = "net_effect";
        //net_eff.eent_broadcast = broadcast;
        net_eff.m_id = eff.m_id;
        net_eff.eent_net_velocity = eff_vel;
@@ -74,10 +76,8 @@ void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
        net_eff.eent_net_count = eff_cnt;
        net_eff.eent_eff_trail = eff.eent_eff_trail;
 
-       net_eff.think = SUB_Remove;
-       net_eff.nextthink = time + 0.2; // don't need to keep this long
-
-       Net_LinkEntity(net_eff, false, 0, Net_Write_Effect);
+       entity e; FOR_EACH_REALCLIENT(e) Net_Write_Effect(net_eff, e, 0);
+       remove(net_eff);
 }
 
 void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt)
@@ -88,6 +88,6 @@ void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt)
                return;
        ));
        // revert to engine handling
-       pointparticles(_particleeffectnum(eff_name), eff_loc, eff_vel, eff_cnt);
+       __pointparticles(_particleeffectnum(eff_name), eff_loc, eff_vel, eff_cnt);
 }
 #endif
index 7046af11bc03c3ce93eae4989d3ef1f280f7f77f..e0e9a3ca869d16b85734356e49802dba3fc706b9 100644 (file)
@@ -3,39 +3,19 @@
 
 #include "effect.qh"
 
-#ifdef CSQC
-void Read_Effect(bool is_new);
-#elif defined(SVQC)
+#ifdef SVQC
 void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt);
 void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt);
 #endif
 
-REGISTRY(Effects, BIT(8))
-REGISTER_REGISTRY(RegisterEffects)
+REGISTRY(Effects, BITS(8))
+#define Effects_from(i) _Effects_from(i, EFFECT_Null)
+REGISTER_REGISTRY(Effects)
+REGISTRY_CHECK(Effects)
 #define EFFECT(istrail, name, realname) \
-    REGISTER(RegisterEffects, EFFECT, Effects, name, m_id, Create_Effect_Entity(realname, istrail));
+    REGISTER(Effects, EFFECT, name, m_id, Create_Effect_Entity(realname, istrail));
 
-void RegisterEffects_First()
-{
-    #ifdef SVQC
-    #define dedi (server_is_dedicated ? "a dedicated " : "")
-    #else
-    #define dedi ""
-    #endif
-
-    LOG_TRACEF("Beginning effect initialization on %s%s program...\n", dedi, PROGNAME);
-    #undef dedi
-}
-
-void RegisterEffects_Done()
-{
-    LOG_TRACE("Effects initialization successful!\n");
-}
-
-// NOW we actually activate the declarations
-ACCUMULATE_FUNCTION(RegisterEffects, RegisterEffects_First)
 EFFECT(0, Null, string_null)
 #include "all.inc"
-ACCUMULATE_FUNCTION(RegisterEffects, RegisterEffects_Done)
 
 #endif
index bd9cd99e5621250e395394bd927567114c325d09..0ae9b489360d84b58df2ecddbef48f9af100ca22 100644 (file)
@@ -1,7 +1,21 @@
 #ifndef EFFECT_H
 #define EFFECT_H
 
-#define particleeffectnum(e) _particleeffectnum(e.eent_eff_name)
+#define particleeffectnum(e) \
+       _particleeffectnum(e.eent_eff_name)
+
+#if defined(SVQC)
+       #define pointparticles(effect, org, vel, howmany) \
+               Send_Effect(effect, org, vel, howmany)
+       #define trailparticles(e, effect, org, vel) \
+               ((!e) ? Send_Effect(effect, org, vel, 0) \
+               : __trailparticles(e, particleeffectnum(effect), org, vel))
+#elif defined(CSQC)
+       #define pointparticles(effect, org, vel, howmany) \
+               __pointparticles(particleeffectnum(effect), org, vel, howmany)
+       #define trailparticles(e, effect, org, vel) \
+               __trailparticles(e, particleeffectnum(effect), org, vel)
+#endif
 
 .int m_id;
 .string eent_eff_name;
@@ -14,6 +28,7 @@
 entity Create_Effect_Entity(string eff_name, bool eff_trail)
 {
        entity this = new(effect_entity);
+       make_pure(this);
        this.eent_eff_name = eff_name;
        this.eent_eff_trail = eff_trail;
        return this;
index deff4dc1563ba74d61d0ba3f7abf912a1d3466d1..f4df3237d4e5ef046bb5909e84652004d2da9f59 100644 (file)
@@ -319,11 +319,12 @@ GENERIC_COMMAND(dumpeffectinfo, "Dump all effectinfo to effectinfo_dump.txt")
 }
 
 
-REGISTRY(EffectInfos, BIT(9))
-REGISTER_REGISTRY(RegisterEffectInfos)
+REGISTRY(EffectInfos, BITS(9))
+#define EffectInfos_from(i) _EffectInfos_from(i, NULL)
+REGISTER_REGISTRY(EffectInfos)
 #define EFFECTINFO(name) \
     [[accumulate]] void effectinfo_##name(EffectInfoGroup parent, EffectInfo this) { } \
-    REGISTER(RegisterEffectInfos, EFFECTINFO, EffectInfos, name, m_id, NEW(EffectInfoGroup)) { \
+    REGISTER(EffectInfos, EFFECTINFO, name, m_id, NEW(EffectInfoGroup)) { \
         effectinfo_##name(this, NULL); \
     }
 
diff --git a/qcsrc/common/effects/qc/all.inc b/qcsrc/common/effects/qc/all.inc
new file mode 100644 (file)
index 0000000..cda1a63
--- /dev/null
@@ -0,0 +1,5 @@
+#include "casings.qc"
+#include "damageeffects.qc"
+#include "gibs.qc"
+#include "lightningarc.qc"
+#include "modeleffects.qc"
diff --git a/qcsrc/common/effects/qc/all.qc b/qcsrc/common/effects/qc/all.qc
new file mode 100644 (file)
index 0000000..f0fc719
--- /dev/null
@@ -0,0 +1,5 @@
+#include "all.qh"
+
+#define IMPLEMENTATION
+#include "all.inc"
+#undef IMPLEMENTATION
diff --git a/qcsrc/common/effects/qc/all.qh b/qcsrc/common/effects/qc/all.qh
new file mode 100644 (file)
index 0000000..5b9b364
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef EFFECTS_QC
+#define EFFECTS_QC
+#include "all.inc"
+#endif
diff --git a/qcsrc/common/effects/qc/casings.qc b/qcsrc/common/effects/qc/casings.qc
new file mode 100644 (file)
index 0000000..815555d
--- /dev/null
@@ -0,0 +1,178 @@
+#ifdef IMPLEMENTATION
+
+#include "../../util.qh"
+
+#ifdef CSQC
+#include "../../movetypes/movetypes.qh"
+#include "rubble.qh"
+#endif
+
+REGISTER_NET_TEMP(casings)
+
+#ifdef SVQC
+void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner)
+{SELFPARAM();
+    .entity weaponentity = weaponentities[0]; // TODO: parameter
+    entity wep = self.(weaponentity);
+    vector org = self.origin + self.view_ofs + wep.spawnorigin.x * v_forward - wep.spawnorigin.y * v_right + wep.spawnorigin.z * v_up;
+
+    if (!sound_allowed(MSG_BROADCAST, casingowner))
+        casingtype |= 0x80;
+
+    WriteHeader(MSG_ALL, casings);
+    WriteByte(MSG_ALL, casingtype);
+    WriteCoord(MSG_ALL, org.x);
+    WriteCoord(MSG_ALL, org.y);
+    WriteCoord(MSG_ALL, org.z);
+    WriteShort(MSG_ALL, compressShortVector(vel)); // actually compressed velocity
+    WriteByte(MSG_ALL, ang.x * 256 / 360);
+    WriteByte(MSG_ALL, ang.y * 256 / 360);
+    WriteByte(MSG_ALL, ang.z * 256 / 360);
+}
+#endif
+
+#ifdef CSQC
+entityclass(Casing);
+class(Casing) .float alpha;
+class(Casing) .bool silent;
+class(Casing) .int state;
+class(Casing) .float cnt;
+
+void Casing_Delete()
+{SELFPARAM();
+    remove(self);
+}
+
+void Casing_Draw(entity this)
+{
+    if (self.move_flags & FL_ONGROUND)
+    {
+        self.move_angles_x = 0;
+        self.move_angles_z = 0;
+        self.flags &= ~FL_ONGROUND;
+    }
+
+    Movetype_Physics_MatchTicrate(autocvar_cl_casings_ticrate, autocvar_cl_casings_sloppy);
+    if (wasfreed(self))
+        return; // deleted by touch function
+
+    self.renderflags = 0;
+    self.alpha = bound(0, self.cnt - time, 1);
+
+    if (self.alpha < ALPHA_MIN_VISIBLE)
+    {
+        Casing_Delete();
+        self.drawmask = 0;
+    }
+}
+
+SOUND(BRASS1, W_Sound("brass1"));
+SOUND(BRASS2, W_Sound("brass2"));
+SOUND(BRASS3, W_Sound("brass3"));
+Sound SND_BRASS_RANDOM() {
+    return Sounds_from(SND_BRASS1.m_id + floor(prandom() * 3));
+}
+SOUND(CASINGS1, W_Sound("casings1"));
+SOUND(CASINGS2, W_Sound("casings2"));
+SOUND(CASINGS3, W_Sound("casings3"));
+Sound SND_CASINGS_RANDOM() {
+    return Sounds_from(SND_CASINGS1.m_id + floor(prandom() * 3));
+}
+
+void Casing_Touch()
+{SELFPARAM();
+    if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+    {
+        Casing_Delete();
+        return;
+    }
+
+    if (!self.silent)
+    if (!trace_ent || trace_ent.solid == SOLID_BSP)
+    {
+        if (vlen(self.velocity) > 50)
+        {
+            if (time >= self.nextthink)
+            {
+                Sound s;
+                switch (self.state)
+                {
+                    case 1:
+                        s = SND_CASINGS_RANDOM();
+                        break;
+                    default:
+                        s = SND_BRASS_RANDOM();
+                        break;
+                }
+
+                sound (self, CH_SHOTS, s, VOL_BASE, ATTEN_LARGE);
+            }
+        }
+    }
+
+    self.nextthink = time + 0.2;
+}
+
+void Casing_Damage(float thisdmg, int hittype, vector org, vector thisforce)
+{SELFPARAM();
+    if (thisforce.z < 0)
+        thisforce.z = 0;
+    self.move_velocity = self.move_velocity + thisforce + '0 0 100';
+    self.move_flags &= ~FL_ONGROUND;
+}
+
+NET_HANDLE(casings, bool isNew)
+{
+    int _state = ReadByte();
+    vector org;
+    org_x = ReadCoord();
+    org_y = ReadCoord();
+    org_z = ReadCoord();
+    vector vel = decompressShortVector(ReadShort());
+    vector ang;
+    ang_x = ReadByte() * 360 / 256;
+    ang_y = ReadByte() * 360 / 256;
+    ang_z = ReadByte() * 360 / 256;
+    return = true;
+
+    if (!autocvar_cl_casings) return;
+
+    Casing casing = RubbleNew("casing");
+    casing.silent = (_state & 0x80);
+    casing.state = (_state & 0x7F);
+    casing.origin = org;
+    setorigin(casing, casing.origin);
+    casing.velocity = vel;
+    casing.angles = ang;
+    casing.drawmask = MASK_NORMAL;
+
+    casing.draw = Casing_Draw;
+    casing.move_origin = casing.origin;
+    casing.move_velocity = casing.velocity + 2 * prandomvec();
+    casing.move_angles = casing.angles;
+    casing.move_avelocity = '0 250 0' + 100 * prandomvec();
+    casing.move_movetype = MOVETYPE_BOUNCE;
+    casing.move_touch = Casing_Touch;
+    casing.move_time = time;
+    casing.event_damage = Casing_Damage;
+    casing.solid = SOLID_TRIGGER;
+
+    switch (casing.state)
+    {
+        case 1:
+            setmodel(casing, MDL_CASING_SHELL);
+            casing.cnt = time + autocvar_cl_casings_shell_time;
+            break;
+        default:
+            setmodel(casing, MDL_CASING_BULLET);
+            casing.cnt = time + autocvar_cl_casings_bronze_time;
+            break;
+    }
+
+    setsize(casing, '0 0 -1', '0 0 -1');
+
+    RubbleLimit("casing", autocvar_cl_casings_maxcount, Casing_Delete);
+}
+
+#endif
+#endif
diff --git a/qcsrc/common/effects/qc/damageeffects.qc b/qcsrc/common/effects/qc/damageeffects.qc
new file mode 100644 (file)
index 0000000..e77f63f
--- /dev/null
@@ -0,0 +1,437 @@
+#ifndef DAMAGEEFFECTS_H
+#define DAMAGEEFFECTS_H
+
+#ifdef CSQC
+#include "../../deathtypes/all.qh"
+#include "../../movetypes/movetypes.qh"
+#include "../../../client/mutators/events.qh"
+#include "../../vehicles/all.qh"
+#include "../../weapons/all.qh"
+#endif
+
+#endif
+
+#ifdef IMPLEMENTATION
+
+REGISTER_NET_LINKED(ENT_CLIENT_DAMAGEINFO)
+
+#ifdef SVQC
+
+bool Damage_DamageInfo_SendEntity(entity this, entity to, int sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_DAMAGEINFO);
+       WriteShort(MSG_ENTITY, self.projectiledeathtype);
+       WriteCoord(MSG_ENTITY, floor(self.origin.x));
+       WriteCoord(MSG_ENTITY, floor(self.origin.y));
+       WriteCoord(MSG_ENTITY, floor(self.origin.z));
+       WriteByte(MSG_ENTITY, bound(1, self.dmg, 255));
+       WriteByte(MSG_ENTITY, bound(0, self.dmg_radius, 255));
+       WriteByte(MSG_ENTITY, bound(1, self.dmg_edge, 255));
+       WriteShort(MSG_ENTITY, self.oldorigin.x);
+       WriteByte(MSG_ENTITY, self.species);
+       return true;
+}
+
+void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, int deathtype, float bloodtype, entity dmgowner)
+{
+       // TODO maybe call this from non-edgedamage too?
+       // TODO maybe make the client do the particle effects for the weapons and the impact sounds using this info?
+
+       entity e;
+
+       if(!sound_allowed(MSG_BROADCAST, dmgowner))
+               deathtype |= 0x8000;
+
+       e = new(damageinfo);
+       make_pure(e);
+       setorigin(e, org);
+       e.projectiledeathtype = deathtype;
+       e.dmg = coredamage;
+       e.dmg_edge = edgedamage;
+       e.dmg_radius = rad;
+       e.dmg_force = vlen(force);
+       e.velocity = force;
+       e.oldorigin_x = compressShortVector(e.velocity);
+       e.species = bloodtype;
+
+       Net_LinkEntity(e, false, 0.2, Damage_DamageInfo_SendEntity);
+}
+
+#endif
+
+#ifdef CSQC
+
+/** number of effects which currently are attached to a player */
+.int total_damages;
+
+.entity tag_entity;
+
+.float cnt;
+.int state;
+.bool isplayermodel;
+
+void DamageEffect_Think()
+{SELFPARAM();
+       // if particle distribution is enabled, slow ticrate by total number of damages
+       if(autocvar_cl_damageeffect_distribute)
+               self.nextthink = time + autocvar_cl_damageeffect_ticrate * self.owner.total_damages;
+       else
+               self.nextthink = time + autocvar_cl_damageeffect_ticrate;
+
+       if(time >= self.cnt || !self.owner || !self.owner.modelindex || !self.owner.drawmask)
+       {
+               // time is up or the player got gibbed / disconnected
+               self.owner.total_damages = max(0, self.owner.total_damages - 1);
+               remove(self);
+               return;
+       }
+       if(self.state && !self.owner.csqcmodel_isdead)
+       {
+               // if the player was dead but is now alive, it means he respawned
+               // if so, clear his damage effects, or damages from his dead body will be copied back
+               self.owner.total_damages = max(0, self.owner.total_damages - 1);
+               remove(self);
+               return;
+       }
+       self.state = self.owner.csqcmodel_isdead;
+       if(self.owner.isplayermodel && (self.owner.entnum == player_localentnum) && !autocvar_chase_active)
+               return; // if we aren't using a third person camera, hide our own effects
+
+       // now generate the particles
+       vector org;
+       org = gettaginfo(self, 0); // origin at attached location
+       __pointparticles(self.team, org, '0 0 0', 1);
+}
+
+string species_prefix(int specnum)
+{
+       switch(specnum)
+       {
+               case SPECIES_HUMAN:       return "";
+               case SPECIES_ALIEN:       return "alien_";
+               case SPECIES_ROBOT_SHINY: return "robot_";
+               case SPECIES_ROBOT_RUSTY: return "robot_"; // use the same effects, only different gibs
+               case SPECIES_ROBOT_SOLID: return "robot_"; // use the same effects, only different gibs
+               case SPECIES_ANIMAL:      return "animal_";
+               case SPECIES_RESERVED:    return "reserved_";
+               default:         return "";
+       }
+}
+
+void DamageEffect(vector hitorg, float thedamage, int type, int specnum)
+{SELFPARAM();
+       // particle effects for players and objects damaged by weapons (eg: flames coming out of victims shot with rockets)
+
+       int nearestbone = 0;
+       float life;
+       string specstr, effectname;
+       entity e;
+
+       if(!autocvar_cl_damageeffect || autocvar_cl_gentle || autocvar_cl_gentle_damage)
+               return;
+       if(!self || !self.modelindex || !self.drawmask)
+               return;
+
+       // if this is a rigged mesh, the effect will show on the bone where damage was dealt
+       // we do this by choosing the skeletal bone closest to the impact, and attaching our entity to it
+       // if there's no skeleton, object origin will automatically be selected
+       FOR_EACH_TAG(self)
+       {
+               if(!tagnum)
+                       continue; // skip empty bones
+               // blacklist bones positioned outside the mesh, or the effect will be floating
+               // TODO: Do we have to do it this way? Why do these bones exist at all?
+               if(gettaginfo_name == "master" || gettaginfo_name == "knee_L" || gettaginfo_name == "knee_R" || gettaginfo_name == "leg_L" || gettaginfo_name == "leg_R")
+                       continue; // player model bone blacklist
+
+               // now choose the bone closest to impact origin
+               if(nearestbone == 0 || vlen(hitorg - gettaginfo(self, tagnum)) <= vlen(hitorg - gettaginfo(self, nearestbone)))
+                       nearestbone = tagnum;
+       }
+       gettaginfo(self, nearestbone); // set gettaginfo_name
+
+       // return if we reached our damage effect limit or damages are disabled
+       // TODO: When the limit is reached, it would be better if the oldest damage was removed instead of not adding a new one
+       if(nearestbone)
+       {
+               if(self.total_damages >= autocvar_cl_damageeffect_bones)
+                       return; // allow multiple damages on skeletal models
+       }
+       else
+       {
+               if(autocvar_cl_damageeffect < 2 || self.total_damages)
+                       return; // allow a single damage on non-skeletal models
+       }
+
+       life = bound(autocvar_cl_damageeffect_lifetime_min, thedamage * autocvar_cl_damageeffect_lifetime, autocvar_cl_damageeffect_lifetime_max);
+
+       effectname = DEATH_WEAPONOF(type).netname;
+
+       if(substring(effectname, strlen(effectname) - 5, 5) == "BLOOD")
+       {
+               if(self.isplayermodel)
+               {
+                       specstr = species_prefix(specnum);
+                       specstr = substring(specstr, 0, strlen(specstr) - 1);
+                       effectname = strreplace("BLOOD", specstr, effectname);
+               }
+               else { return; } // objects don't bleed
+       }
+
+       e = new(damage);
+       make_pure(e);
+       setmodel(e, MDL_Null); // necessary to attach and read origin
+       setattachment(e, self, gettaginfo_name); // attach to the given bone
+       e.owner = self;
+       e.cnt = time + life;
+       e.team = _particleeffectnum(effectname);
+       e.think = DamageEffect_Think;
+       e.nextthink = time;
+       self.total_damages += 1;
+}
+
+NET_HANDLE(ENT_CLIENT_DAMAGEINFO, bool isNew)
+{
+       make_pure(this);
+       float thedamage, rad, edge, thisdmg;
+       bool hitplayer = false;
+       int species, forcemul;
+       vector force, thisforce;
+
+       w_deathtype = ReadShort();
+       w_issilent = (w_deathtype & 0x8000);
+       w_deathtype = (w_deathtype & 0x7FFF);
+
+       w_org.x = ReadCoord();
+       w_org.y = ReadCoord();
+       w_org.z = ReadCoord();
+
+       thedamage = ReadByte();
+       rad = ReadByte();
+       edge = ReadByte();
+       force = decompressShortVector(ReadShort());
+       species = ReadByte();
+
+       return = true;
+
+       if (!isNew)
+               return;
+
+       if(rad < 0)
+       {
+               rad = -rad;
+               forcemul = -1;
+       }
+       else
+               forcemul = 1;
+
+       for(entity e = findradius(w_org, rad + MAX_DAMAGEEXTRARADIUS); e; e = e.chain)
+       {
+               setself(e);
+               // attached ents suck
+               if(self.tag_entity)
+                       continue;
+
+               vector nearest = NearestPointOnBox(self, w_org);
+               if(rad)
+               {
+                       thisdmg = ((vlen (nearest - w_org) - bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
+                       if(thisdmg >= 1)
+                               continue;
+                       if(thisdmg < 0)
+                               thisdmg = 0;
+                       if(thedamage)
+                       {
+                               thisdmg = thedamage + (edge - thedamage) * thisdmg;
+                               thisforce = forcemul * vlen(force) * (thisdmg / thedamage) * normalize(self.origin - w_org);
+                       }
+                       else
+                       {
+                               thisdmg = 0;
+                               thisforce = forcemul * vlen(force) * normalize(self.origin - w_org);
+                       }
+               }
+               else
+               {
+                       if(vlen(nearest - w_org) > bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS))
+                               continue;
+
+                       thisdmg = thedamage;
+                       thisforce = forcemul * force;
+               }
+
+               if(self.damageforcescale)
+                       if(vlen(thisforce))
+                       {
+                               self.move_velocity = self.move_velocity + damage_explosion_calcpush(self.damageforcescale * thisforce, self.move_velocity, autocvar_g_balance_damagepush_speedfactor);
+                               self.move_flags &= ~FL_ONGROUND;
+                       }
+
+               if(w_issilent)
+                       self.silent = 1;
+
+               if(self.event_damage)
+                       self.event_damage(thisdmg, w_deathtype, w_org, thisforce);
+
+               DamageEffect(w_org, thisdmg, w_deathtype, species);
+
+               if(self.isplayermodel)
+                       hitplayer = true; // this impact damaged a player
+       }
+       setself(this);
+
+       if(DEATH_ISVEHICLE(w_deathtype))
+       {
+               traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
+               if(trace_plane_normal != '0 0 0')
+                       w_backoff = trace_plane_normal;
+               else
+                       w_backoff = -1 * normalize(w_org - (w_org + normalize(force) * 16));
+
+               setorigin(self, w_org + w_backoff * 2); // for sound() calls
+
+               switch(DEATH_ENT(w_deathtype))
+               {
+                       case DEATH_VH_CRUSH:
+                               break;
+
+                       // spiderbot
+                       case DEATH_VH_SPID_MINIGUN:
+                               sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+                               pointparticles(EFFECT_SPIDERBOT_MINIGUN_IMPACT, self.origin, w_backoff * 1000, 1);
+                               break;
+                       case DEATH_VH_SPID_ROCKET:
+                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+                               pointparticles(EFFECT_SPIDERBOT_ROCKET_EXPLODE, self.origin, w_backoff * 1000, 1);
+                               break;
+                       case DEATH_VH_SPID_DEATH:
+                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
+                               pointparticles(EFFECT_EXPLOSION_BIG, self.origin, w_backoff * 1000, 1);
+                               break;
+
+                       case DEATH_VH_WAKI_GUN:
+                               sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_NORM);
+                               pointparticles(EFFECT_RACER_IMPACT, self.origin, w_backoff * 1000, 1);
+                               break;
+                       case DEATH_VH_WAKI_ROCKET:
+                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+                               pointparticles(EFFECT_RACER_ROCKET_EXPLODE, self.origin, w_backoff * 1000, 1);
+                               break;
+                       case DEATH_VH_WAKI_DEATH:
+                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
+                               pointparticles(EFFECT_EXPLOSION_BIG, self.origin, w_backoff * 1000, 1);
+                               break;
+
+                       case DEATH_VH_RAPT_CANNON:
+                               sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_NORM);
+                               pointparticles(EFFECT_RAPTOR_CANNON_IMPACT, self.origin, w_backoff * 1000, 1);
+                               break;
+                       case DEATH_VH_RAPT_FRAGMENT:
+                               float i;
+                               vector ang, vel;
+                               for(i = 1; i < 4; ++i)
+                               {
+                                       vel = normalize(w_org - (w_org + normalize(force) * 16)) + randomvec() * 128;
+                                       ang = vectoangles(vel);
+                                       RaptorCBShellfragToss(w_org, vel, ang + '0 0 1' * (120 * i));
+                               }
+                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+                               pointparticles(EFFECT_RAPTOR_BOMB_SPREAD, self.origin, w_backoff * 1000, 1);
+                               break;
+                       case DEATH_VH_RAPT_BOMB:
+                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+                               pointparticles(EFFECT_RAPTOR_BOMB_IMPACT, self.origin, w_backoff * 1000, 1);
+                               break;
+                       case DEATH_VH_RAPT_DEATH:
+                               sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_MIN);
+                               pointparticles(EFFECT_EXPLOSION_BIG, self.origin, w_backoff * 1000, 1);
+                               break;
+                       case DEATH_VH_BUMB_GUN:
+                               sound(self, CH_SHOTS, SND_FIREBALL_IMPACT2, VOL_BASE, ATTEN_NORM);
+                               pointparticles(EFFECT_BIGPLASMA_IMPACT, self.origin, w_backoff * 1000, 1);
+                               break;
+               }
+       }
+
+
+       if(DEATH_ISTURRET(w_deathtype))
+       {
+               traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
+               if(trace_plane_normal != '0 0 0')
+                       w_backoff = trace_plane_normal;
+               else
+                       w_backoff = -1 * normalize(w_org - (w_org + normalize(force) * 16));
+
+               setorigin(self, w_org + w_backoff * 2); // for sound() calls
+
+               switch(DEATH_ENT(w_deathtype))
+               {
+                        case DEATH_TURRET_EWHEEL:
+                               sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTEN_MIN);
+                               pointparticles(EFFECT_BLASTER_IMPACT, self.origin, w_backoff * 1000, 1);
+                               break;
+
+                        case DEATH_TURRET_FLAC:
+                               pointparticles(EFFECT_HAGAR_EXPLODE, w_org, '0 0 0', 1);
+                               sound(self, CH_SHOTS, SND_HAGEXP_RANDOM(), VOL_BASE, ATTEN_NORM);
+                               break;
+
+                        case DEATH_TURRET_MLRS:
+                        case DEATH_TURRET_HK:
+                        case DEATH_TURRET_WALK_ROCKET:
+                        case DEATH_TURRET_HELLION:
+                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_MIN);
+                               pointparticles(EFFECT_ROCKET_EXPLODE, self.origin, w_backoff * 1000, 1);
+                               break;
+
+                        case DEATH_TURRET_MACHINEGUN:
+                        case DEATH_TURRET_WALK_GUN:
+                               sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+                               pointparticles(EFFECT_MACHINEGUN_IMPACT, self.origin, w_backoff * 1000, 1);
+                               break;
+
+                        case DEATH_TURRET_PLASMA:
+                               sound(self, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_MIN);
+                               pointparticles(EFFECT_ELECTRO_IMPACT, self.origin, w_backoff * 1000, 1);
+                               break;
+
+                        case DEATH_TURRET_WALK_MELEE:
+                               sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_MIN);
+                               pointparticles(EFFECT_TE_SPARK, self.origin, w_backoff * 1000, 1);
+                               break;
+
+                        case DEATH_TURRET_PHASER:
+                               break;
+
+                        case DEATH_TURRET_TESLA:
+                               te_smallflash(self.origin);
+                               break;
+
+               }
+       }
+
+       // TODO spawn particle effects and sounds based on w_deathtype
+       if(!DEATH_ISSPECIAL(w_deathtype))
+       if(!hitplayer || rad) // don't show ground impacts for hitscan weapons if a player was hit
+       {
+               Weapon hitwep = DEATH_WEAPONOF(w_deathtype);
+               w_random = prandom();
+
+               traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, world);
+               if(trace_fraction < 1 && hitwep != WEP_VORTEX && hitwep != WEP_VAPORIZER)
+                       w_backoff = trace_plane_normal;
+               else
+                       w_backoff = -1 * normalize(force);
+               setorigin(self, w_org + w_backoff * 2); // for sound() calls
+
+               if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
+               {
+                       if(!MUTATOR_CALLHOOK(Weapon_ImpactEffect, hitwep))
+                               hitwep.wr_impacteffect(hitwep);
+               }
+       }
+}
+
+#endif
+
+#endif
diff --git a/qcsrc/common/effects/qc/gibs.qc b/qcsrc/common/effects/qc/gibs.qc
new file mode 100644 (file)
index 0000000..ab8dbb8
--- /dev/null
@@ -0,0 +1,316 @@
+#ifdef IMPLEMENTATION
+REGISTER_NET_TEMP(net_gibsplash)
+
+#ifdef SVQC
+
+.int state;
+
+bool Violence_GibSplash_SendEntity(entity this, entity to, int sf)
+{
+       int channel = MSG_ONE;
+       msg_entity = to;
+       WriteHeader(channel, net_gibsplash);
+       WriteByte(channel, this.state); // actually type
+       WriteByte(channel, bound(1, this.cnt * 16, 255)); // gibbage amount multiplier
+       WriteShort(channel, floor(this.origin.x / 4)); // not using a coord here, as gibs don't need this accuracy
+       WriteShort(channel, floor(this.origin.y / 4)); // not using a coord here, as gibs don't need this accuracy
+       WriteShort(channel, floor(this.origin.z / 4)); // not using a coord here, as gibs don't need this accuracy
+       WriteShort(channel, this.oldorigin.x); // acrually compressed velocity
+       return true;
+}
+
+void Violence_GibSplash_At(vector org, vector dir, float type, float amount, entity gibowner, entity attacker)
+{SELFPARAM();
+       if(g_cts) // no gibs in CTS
+               return;
+
+       entity e = new(gibsplash);
+       e.cnt = amount;
+       e.state = type; // should stay smaller than 15
+       if(!sound_allowed(MSG_BROADCAST, gibowner) || !sound_allowed(MSG_BROADCAST, attacker))
+               e.state |= 0x40; // "silence" bit
+       e.state |= 8 * self.species; // gib type, ranges from 0 to 15
+
+       // if this is a copied dead body, send the num of its player instead
+       // TODO: remove this field, read from model txt files
+       if(self.classname == "body")
+               e.team = num_for_edict(self.enemy);
+       else
+               e.team = num_for_edict(self);
+
+       setorigin(e, org);
+       e.velocity = dir;
+
+       e.oldorigin_x = compressShortVector(e.velocity);
+
+       entity cl; FOR_EACH_REALCLIENT(cl) Violence_GibSplash_SendEntity(e, cl, 0);
+       remove(e);
+}
+
+void Violence_GibSplash(entity source, float type, float amount, entity attacker)
+{
+       Violence_GibSplash_At(source.origin + source.view_ofs, source.velocity, type, amount, source, attacker);
+}
+#endif
+
+#ifdef CSQC
+
+.vector colormod;
+.bool silent;
+
+#include "rubble.qh"
+#include "../common/movetypes/movetypes.qh"
+
+.float scale;
+.float alpha;
+.float cnt;
+.float gravity;
+
+void Gib_Delete()
+{SELFPARAM();
+       remove(self);
+}
+
+string species_prefix(int specnum);
+
+void Gib_setmodel(entity gib, string mdlname, int specnum)
+{
+       switch(specnum)
+       {
+               case SPECIES_ROBOT_RUSTY:
+               case SPECIES_ROBOT_SHINY:
+               case SPECIES_ROBOT_SOLID:
+                       if(specnum != SPECIES_ROBOT_SOLID || mdlname == "models/gibs/chunk.mdl")
+                       {
+                               if(mdlname == "models/gibs/bloodyskull.md3")
+                                       setmodel(gib, MDL_GIB_ROBO);
+                               else
+                                       setmodel(gib, MDL_GIB_ROBO_RANDOM());
+                               if(specnum == SPECIES_ROBOT_SHINY)
+                               {
+                                       gib.skin = 1;
+                                       gib.colormod = '2 2 2';
+                               }
+                               gib.scale = 1;
+                               break;
+                       }
+               default:
+                       _setmodel(gib, mdlname);
+                       gib.skin = specnum;
+                       break;
+       }
+}
+
+void new_te_bloodshower (int ef, vector org, float explosionspeed, int howmany)
+{
+       float i, pmod;
+       pmod = autocvar_cl_particles_quality;
+       for (i = 0; i < 50 * pmod; ++i)
+               __pointparticles(ef, org, randomvec() * explosionspeed, howmany / 50);
+}
+
+void SUB_RemoveOnNoImpact()
+{
+       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+               Gib_Delete();
+}
+
+void Gib_Touch()
+{SELFPARAM();
+       // TODO maybe bounce of walls, make more gibs, etc.
+
+       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+       {
+               Gib_Delete();
+               return;
+       }
+
+       if(!self.silent)
+               sound(self, CH_PAIN, SND_GIB_SPLAT_RANDOM(), VOL_BASE, ATTEN_NORM);
+       __pointparticles(_particleeffectnum(strcat(species_prefix(self.cnt), "blood")), self.origin + '0 0 1', '0 0 30', 10);
+
+       Gib_Delete();
+}
+
+void Gib_Draw(entity this)
+{
+       vector oldorg;
+       oldorg = self.origin;
+
+       Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
+       if(wasfreed(self))
+               return;
+
+       if(self.touch == Gib_Touch) // don't do this for the "chunk" thingie...
+               // TODO somehow make it spray in a direction dependent on self.angles
+               __trailparticles(self, _particleeffectnum(strcat(species_prefix(self.cnt), EFFECT_TR_SLIGHTBLOOD.eent_eff_name)), oldorg, self.origin);
+       else
+               __trailparticles(self, _particleeffectnum(strcat(species_prefix(self.cnt), EFFECT_TR_BLOOD.eent_eff_name)), oldorg, self.origin);
+
+       self.renderflags = 0;
+
+       // make gibs die faster at low view quality
+       // if view_quality is 0.5, we want to have them die twice as fast
+       self.nextthink -= frametime * (1 / bound(0.01, view_quality, 1.00) - 1);
+
+       self.alpha = bound(0, self.nextthink - time, 1);
+
+       if(self.alpha < ALPHA_MIN_VISIBLE)
+       {
+               self.drawmask = 0;
+               Gib_Delete();
+       }
+}
+
+void TossGib (string mdlname, vector safeorg, vector org, vector vconst, vector vrand, int specnum, bool destroyontouch, bool issilent)
+{
+       entity gib;
+
+       // TODO remove some gibs according to cl_nogibs
+       gib = RubbleNew("gib");
+       gib.move_movetype = MOVETYPE_BOUNCE;
+       gib.gravity = 1;
+       gib.solid = SOLID_CORPSE;
+       gib.cnt = specnum;
+       gib.silent = issilent;
+       Gib_setmodel(gib, mdlname, specnum);
+
+       setsize (gib, '-8 -8 -8', '8 8 8');
+
+       gib.draw = Gib_Draw;
+       if(destroyontouch)
+               gib.move_touch = Gib_Touch;
+       else
+               gib.move_touch = SUB_RemoveOnNoImpact;
+
+       // don't spawn gibs inside solid - just don't
+       if(org != safeorg)
+       {
+               tracebox(safeorg, gib.mins, gib.maxs, org, MOVE_NOMONSTERS, gib);
+               org = trace_endpos;
+       }
+
+       gib.move_origin = org;
+       setorigin(gib, org);
+       gib.move_velocity = vconst * autocvar_cl_gibs_velocity_scale + vrand * autocvar_cl_gibs_velocity_random + '0 0 1' * autocvar_cl_gibs_velocity_up;
+       gib.move_avelocity = prandomvec() * vlen(gib.move_velocity) * autocvar_cl_gibs_avelocity_scale;
+       gib.move_time = time;
+       gib.damageforcescale = autocvar_cl_gibs_damageforcescale;
+
+       gib.nextthink = time + autocvar_cl_gibs_lifetime * (1 + prandom() * 0.15);
+       gib.drawmask = MASK_NORMAL;
+
+       RubbleLimit("gib", autocvar_cl_gibs_maxcount, Gib_Delete);
+}
+
+NET_HANDLE(net_gibsplash, bool isNew)
+{
+       Net_Accept(net_gibsplash);
+
+       string gentle_prefix = "morphed_";
+
+       int type = ReadByte(); // gibbage type
+       int amount = ReadByte() / 16.0; // gibbage amount
+       vector org;
+       org.x = ReadShort() * 4 + 2;
+       org.y = ReadShort() * 4 + 2;
+       org.z = ReadShort() * 4 + 2;
+       vector vel = decompressShortVector(ReadShort());
+
+       return = true;
+
+       float cl_gentle_gibs = autocvar_cl_gentle_gibs;
+       if(cl_gentle_gibs || autocvar_cl_gentle)
+               type |= 0x80; // set gentle bit
+
+       if(type & 0x80)
+       {
+               if(cl_gentle_gibs == 2)
+                       gentle_prefix = "";
+               else if(cl_gentle_gibs == 3)
+                       gentle_prefix = "happy_";
+       }
+       else if(autocvar_cl_particlegibs)
+       {
+               type |= 0x80;
+               gentle_prefix = "particlegibs_";
+       }
+
+       if (!(cl_gentle_gibs || autocvar_cl_gentle))
+               amount *= 1 - autocvar_cl_nogibs;
+
+       if(autocvar_ekg)
+               amount *= 5;
+
+       if(amount <= 0 || !isNew)
+               return;
+
+       setorigin(this, org); // for the sounds
+
+       int specnum = (type & 0x78) / 8; // blood/gibmodel type: using four bits (0..7, bit indexes 3,4,5)
+       bool issilent = (type & 0x40);
+       type = type & 0x87; // remove the species bits: bit 7 = gentle, bit 0,1,2 = kind of gib
+       string specstr = species_prefix(specnum);
+
+       switch(type)
+       {
+               case 0x01:
+                       if(!issilent)
+                               sound (this, CH_PAIN, SND_GIB, VOL_BASE, ATTEN_NORM);
+
+                       if(prandom() < amount)
+                               TossGib ("models/gibs/eye.md3", org, org, vel, prandomvec() * 150, specnum, 0, issilent);
+                       new_te_bloodshower(_particleeffectnum(strcat(specstr, "bloodshower")), org, 1200, amount);
+                       if(prandom() < amount)
+                               TossGib ("models/gibs/bloodyskull.md3", org, org + 16 * prandomvec(), vel, prandomvec() * 100, specnum, 0, issilent);
+
+                       for(int c = 0; c < amount; ++c)
+                       {
+                               int randomvalue = amount - c;
+
+                               if(prandom() < randomvalue)
+                                       TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
+                               if(prandom() < randomvalue)
+                                       TossGib ("models/gibs/arm.md3", org, org + 16 * prandomvec() + '0 0 8', vel, prandomvec() * (prandom() * 120 + 90), specnum,0, issilent);
+                               if(prandom() < randomvalue)
+                                       TossGib ("models/gibs/chest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
+                               if(prandom() < randomvalue)
+                                       TossGib ("models/gibs/smallchest.md3", org, org + 16 * prandomvec(), vel, prandomvec() * (prandom() * 120 + 80), specnum,0, issilent);
+                               if(prandom() < randomvalue)
+                                       TossGib ("models/gibs/leg1.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
+                               if(prandom() < randomvalue)
+                                       TossGib ("models/gibs/leg2.md3", org, org + 16 * prandomvec() + '0 0 -5', vel, prandomvec() * (prandom() * 120 + 85), specnum,0, issilent);
+
+                               // these splat on impact
+                               if(prandom() < randomvalue)
+                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+                               if(prandom() < randomvalue)
+                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+                               if(prandom() < randomvalue)
+                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+                               if(prandom() < randomvalue)
+                                       TossGib ("models/gibs/chunk.mdl", org, org + 16 * prandomvec(), vel, prandomvec() * 450, specnum,1, issilent);
+                       }
+                       break;
+               case 0x02:
+                       __pointparticles(_particleeffectnum(strcat(specstr, "blood")), org, vel, amount * 16);
+                       break;
+               case 0x03:
+                       if(prandom() < amount)
+                               TossGib ("models/gibs/chunk.mdl", org, org, vel, prandomvec() * (prandom() * 30 + 20), specnum, 1, issilent); // TODO maybe adjust to more randomization?
+                       break;
+               case 0x81:
+                       __pointparticles(_particleeffectnum(strcat(gentle_prefix, "damage_dissolve")), org, vel, amount);
+                       break;
+               case 0x82:
+                       __pointparticles(_particleeffectnum(strcat(gentle_prefix, "damage_hit")), org, vel, amount * 16);
+                       break;
+               case 0x83:
+                       // no gibs in gentle mode, sorry
+                       break;
+       }
+       remove(this);
+}
+#endif
+
+#endif
diff --git a/qcsrc/common/effects/qc/lightningarc.qc b/qcsrc/common/effects/qc/lightningarc.qc
new file mode 100644 (file)
index 0000000..5c6b60e
--- /dev/null
@@ -0,0 +1,119 @@
+#ifdef IMPLEMENTATION
+REGISTER_NET_TEMP(TE_CSQC_ARC)
+
+#if defined(SVQC)
+
+       void te_csqc_lightningarc(vector from, vector to)
+       {
+               WriteHeader(MSG_BROADCAST, TE_CSQC_ARC);
+
+               WriteCoord(MSG_BROADCAST, from.x);
+               WriteCoord(MSG_BROADCAST, from.y);
+               WriteCoord(MSG_BROADCAST, from.z);
+               WriteCoord(MSG_BROADCAST, to.x);
+               WriteCoord(MSG_BROADCAST, to.y);
+               WriteCoord(MSG_BROADCAST, to.z);
+       }
+
+#elif defined(CSQC)
+
+/*
+.vector fx_start;
+.vector fx_end;
+.float  fx_with;
+.string fx_texture;
+.float  fx_lifetime;
+
+void b_draw()
+{
+    //Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, 0, time * 3, '1 1 1', 0.7, DRAWFLAG_ADDITIVE, view_origin);
+    Draw_CylindricLine(self.fx_start, self.fx_end, self.fx_with, self.fx_texture, (self.fx_with/256), 0, '1 1 1', 1, DRAWFLAG_ADDITIVE, view_origin);
+
+}
+void b_make(vector s,vector e, string t,float l,float z)
+{
+    entity b;
+    b = spawn();
+    b.fx_texture = t;
+    b.fx_start = s;
+    b.fx_end = e;
+    b.fx_with = z;
+    b.think = SUB_Remove;
+    b.nextthink = time + l;
+    b.draw = b_draw;
+
+    //b.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
+}
+*/
+
+       void cl_effects_lightningarc(vector from, vector to, float seglength, float drifts, float drifte,
+       float branchfactor, float branchfactor_add)
+       {
+               float length = vlen(from - to);
+               if (length < 1) return;
+
+               // Use at most 16 te_lightning1 segments, as these eat up beam list segments.
+               // TODO: Change this to R_BeginPolygon code, then we no longer have this limit.
+               int steps = min(16, floor(length / seglength));
+               if (steps < 1)
+               {
+                       te_lightning1(world, from, to);
+                       return;
+               }
+
+               float steplength = length / steps;
+               vector direction  = normalize(to - from);
+               vector pos_l = from;
+               if (length > seglength)
+               {
+                       for (int i = 1; i < steps; i += 1)
+                       {
+                               float drift = drifts * (1 - (i / steps)) + drifte * (i / steps);
+                               vector dirnew = normalize(direction * (1 - drift) + randomvec() * drift);
+                               vector pos = pos_l +  dirnew * steplength;
+                               te_lightning1(world, pos_l, pos);
+                               // WTF endless recursion if branchfactor is 1.0 (possibly due to adding branchfactor_add). FIXME
+                               // if(random() < branchfactor)
+                               //     cl_effects_lightningarc(pos, pos + (dirnew * length * 0.25),seglength,drifts,drifte,min(branchfactor + branchfactor_add,1),branchfactor_add);
+
+                               pos_l = pos;
+                       }
+                       te_lightning1(world, pos_l, to);
+               }
+               else
+               {
+                       te_lightning1(world, from, to);
+               }
+       }
+
+       NET_HANDLE(TE_CSQC_ARC, bool isNew)
+       {
+               vector from;
+               from.x = ReadCoord();
+               from.y = ReadCoord();
+               from.z = ReadCoord();
+               vector to;
+               to.x = ReadCoord();
+               to.y = ReadCoord();
+               to.z = ReadCoord();
+               return = true;
+
+               if (autocvar_cl_effects_lightningarc_simple)
+               {
+                       te_lightning1(world, from, to);
+               }
+               else
+               {
+                       float seglength        = autocvar_cl_effects_lightningarc_segmentlength;
+                       float drifts           = autocvar_cl_effects_lightningarc_drift_start;
+                       float drifte           = autocvar_cl_effects_lightningarc_drift_end;
+                       float branchfactor     = autocvar_cl_effects_lightningarc_branchfactor_start;
+                       float branchfactor_add = autocvar_cl_effects_lightningarc_branchfactor_add;
+
+                       cl_effects_lightningarc(from, to, seglength, drifts, drifte, branchfactor, branchfactor_add);
+               }
+       }
+
+#endif
+
+#endif
diff --git a/qcsrc/common/effects/qc/modeleffects.qc b/qcsrc/common/effects/qc/modeleffects.qc
new file mode 100644 (file)
index 0000000..41c5ba0
--- /dev/null
@@ -0,0 +1,163 @@
+#ifdef IMPLEMENTATION
+
+REGISTER_NET_LINKED(ENT_CLIENT_MODELEFFECT)
+
+#ifdef SVQC
+
+.float scale2;
+
+bool modeleffect_SendEntity(entity this, entity to, int sf)
+{
+       float f;
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
+
+       f = 0;
+       if(self.velocity != '0 0 0')
+               f |= 1;
+       if(self.angles != '0 0 0')
+               f |= 2;
+       if(self.avelocity != '0 0 0')
+               f |= 4;
+
+       WriteByte(MSG_ENTITY, f);
+       WriteShort(MSG_ENTITY, self.modelindex);
+       WriteByte(MSG_ENTITY, self.skin);
+       WriteByte(MSG_ENTITY, self.frame);
+       WriteCoord(MSG_ENTITY, self.origin.x);
+       WriteCoord(MSG_ENTITY, self.origin.y);
+       WriteCoord(MSG_ENTITY, self.origin.z);
+       if(f & 1)
+       {
+               WriteCoord(MSG_ENTITY, self.velocity.x);
+               WriteCoord(MSG_ENTITY, self.velocity.y);
+               WriteCoord(MSG_ENTITY, self.velocity.z);
+       }
+       if(f & 2)
+       {
+               WriteCoord(MSG_ENTITY, self.angles.x);
+               WriteCoord(MSG_ENTITY, self.angles.y);
+               WriteCoord(MSG_ENTITY, self.angles.z);
+       }
+       if(f & 4)
+       {
+               WriteCoord(MSG_ENTITY, self.avelocity.x);
+               WriteCoord(MSG_ENTITY, self.avelocity.y);
+               WriteCoord(MSG_ENTITY, self.avelocity.z);
+       }
+       WriteShort(MSG_ENTITY, self.scale * 256.0);
+       WriteShort(MSG_ENTITY, self.scale2 * 256.0);
+       WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
+       WriteByte(MSG_ENTITY, self.fade_time * 100.0);
+       WriteByte(MSG_ENTITY, self.alpha * 255.0);
+
+       return true;
+}
+
+void modeleffect_spawn(string m, float s, float f, vector o, vector v, vector ang, vector angv, float s0, float s2, float a, float t1, float t2)
+{
+       entity e = new(modeleffect);
+       _setmodel(e, m);
+       e.frame = f;
+       setorigin(e, o);
+       e.velocity = v;
+       e.angles = ang;
+       e.avelocity = angv;
+       e.alpha = a;
+       e.teleport_time = t1;
+       e.fade_time = t2;
+       e.skin = s;
+       if(s0 >= 0)
+               e.scale = s0 / max6(-e.mins.x, -e.mins.y, -e.mins.z, e.maxs.x, e.maxs.y, e.maxs.z);
+       else
+               e.scale = -s0;
+       if(s2 >= 0)
+               e.scale2 = s2 / max6(-e.mins.x, -e.mins.y, -e.mins.z, e.maxs.x, e.maxs.y, e.maxs.z);
+       else
+               e.scale2 = -s2;
+       float sz = max(e.scale, e.scale2);
+       setsize(e, e.mins * sz, e.maxs * sz);
+       Net_LinkEntity(e, false, 0.1, modeleffect_SendEntity);
+}
+
+#endif
+
+#ifdef CSQC
+
+entityclass(ModelEffect);
+class(ModelEffect) .float frame1time;
+class(ModelEffect) .float lifetime, fadetime;
+class(ModelEffect) .float teleport_time;
+class(ModelEffect) .float scale1, scale2;
+
+.float cnt;
+.float scale;
+.float alpha;
+
+void ModelEffect_Draw(entity this)
+{
+       self.angles = self.angles + frametime * self.avelocity;
+       setorigin(self, self.origin + frametime * self.velocity);
+       self.scale = self.scale1 + (self.scale2 - self.scale1) * (time - self.teleport_time) / (self.lifetime + self.fadetime - self.teleport_time);
+       self.alpha = self.cnt * bound(0, 1 - (time - self.lifetime) / self.fadetime, 1);
+       if(self.alpha < ALPHA_MIN_VISIBLE)
+       {
+               remove(self);
+               return;
+       }
+       self.drawmask = MASK_NORMAL;
+       if(self.scale <= 0)
+       {
+               self.drawmask = 0;
+               return;
+       }
+}
+
+NET_HANDLE(ENT_CLIENT_MODELEFFECT, bool isnew)
+{
+       make_pure(self);
+
+       int f = ReadByte();
+
+       entity e = new(modeleffect);
+       e.model = "from network";
+       e.modelindex = ReadShort();
+       e.skin = ReadByte();
+       e.frame = ReadByte();
+       e.frame1time = time;
+       e.origin_x = ReadCoord();
+       e.origin_y = ReadCoord();
+       e.origin_z = ReadCoord();
+       setorigin(e, e.origin);
+       if(f & 1)
+       {
+               e.velocity_x = ReadCoord();
+               e.velocity_y = ReadCoord();
+               e.velocity_z = ReadCoord();
+       }
+       if(f & 2)
+       {
+               e.angles_x = ReadAngle();
+               e.angles_y = ReadAngle();
+               e.angles_z = ReadAngle();
+       }
+       if(f & 4)
+       {
+               e.avelocity_x = ReadAngle();
+               e.avelocity_y = ReadAngle();
+               e.avelocity_z = ReadAngle();
+       }
+       e.scale1 = ReadShort() / 256.0;
+       e.scale2 = ReadShort() / 256.0;
+       e.lifetime = time + ReadByte() * 0.01;
+       e.fadetime = ReadByte() * 0.01;
+       e.teleport_time = time;
+       e.cnt = ReadByte() / 255.0; // actually alpha
+
+       e.draw = ModelEffect_Draw;
+
+       if (!isnew) remove(e); // yes, this IS stupid, but I don't need to duplicate all the read* stuff then
+       return true;
+}
+#endif
+
+#endif
diff --git a/qcsrc/common/effects/qc/rubble.qh b/qcsrc/common/effects/qc/rubble.qh
new file mode 100644 (file)
index 0000000..1a7cad8
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef RUBBLE_H
+#define RUBBLE_H
+
+#ifdef CSQC
+
+entityclass(Rubble);
+class(Rubble).float creationtime;
+
+void RubbleLimit(string cname, float limit, void() deleteproc)
+{
+       SELFPARAM();
+       entity e;
+       entity oldest;
+       float c;
+       float oldesttime;
+
+       // remove rubble of the same type if it's at the limit
+       // remove multiple rubble if the limit has been decreased
+       while (1)
+       {
+               e = findchain(classname, cname);
+               if (e == world) break;
+               // walk the list and count the entities, find the oldest
+               // initialize our search with the first entity
+               c = 1;
+               oldest = e;
+               oldesttime = e.creationtime;
+               e = e.chain;
+               // compare to all other matching entities
+               while (e)
+               {
+                       c = c + 1;
+                       if (oldesttime > e.creationtime)
+                       {
+                               oldesttime = e.creationtime;
+                               oldest = e;
+                       }
+                       e = e.chain;
+               }
+
+               // stop if there are less than the limit already
+               if (c <= limit) break;
+
+               // delete this oldest one and search again
+               WITH(entity, self, oldest, deleteproc());
+       }
+}
+
+entity RubbleNew(string cname)
+{
+       // spawn a new entity and return it
+       entity e = spawn();
+       e.classname = cname;
+       e.creationtime = time;
+       return e;
+}
+
+#endif
+
+#endif
index 4c24bebf5b256b1e25398ab624d22386dd29f918..bcdcd7c4c0066e3f3fd45b686ddb3292bc08d7fc 100644 (file)
@@ -1 +1,2 @@
-#include "gamemode/nexball/nexball.qc"
+#include "gamemode/nexball/module.inc"
+#include "gamemode/onslaught/module.inc"
diff --git a/qcsrc/common/gamemodes/gamemode/nexball/module.inc b/qcsrc/common/gamemodes/gamemode/nexball/module.inc
new file mode 100644 (file)
index 0000000..0d80962
--- /dev/null
@@ -0,0 +1,2 @@
+#include "nexball.qc"
+#include "weapon.qc"
index 4349a1e5e24d9df7167d69919a4b896a4726c9d7..b4becb3979d7b20981ddc01c28ed5b0defa6be66 100644 (file)
@@ -78,14 +78,14 @@ void LogNB(string mode, entity actor)
        GameLogEcho(s);
 }
 
-void ball_restart(void)
+void ball_restart()
 {SELFPARAM();
        if(self.owner)
                DropBall(self, self.owner.origin, '0 0 0');
        ResetBall();
 }
 
-void nexball_setstatus(void)
+void nexball_setstatus()
 {SELFPARAM();
        self.items &= ~IT_KEY1;
        if(self.ballcarried)
@@ -103,7 +103,7 @@ void nexball_setstatus(void)
        }
 }
 
-void relocate_nexball(void)
+void relocate_nexball()
 {SELFPARAM();
        tracebox(self.origin, BALL_MINS, BALL_MAXS, self.origin, true, self);
        if(trace_startsolid)
@@ -120,7 +120,7 @@ void relocate_nexball(void)
        }
 }
 
-void DropOwner(void)
+void DropOwner()
 {SELFPARAM();
        entity ownr;
        ownr = self.owner;
@@ -132,16 +132,16 @@ void DropOwner(void)
 
 void GiveBall(entity plyr, entity ball)
 {SELFPARAM();
-       entity ownr;
-
-       if((ownr = ball.owner))
+       .entity weaponentity = weaponentities[0]; // TODO: find ballstealer
+       entity ownr = ball.owner;
+       if(ownr)
        {
                ownr.effects &= ~autocvar_g_nexball_basketball_effects_default;
                ownr.ballcarried = world;
                if(ownr.metertime)
                {
                        ownr.metertime = 0;
-                       ownr.weaponentity.state = WS_READY;
+                       ownr.(weaponentity).state = WS_READY;
                }
                WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
        }
@@ -179,8 +179,8 @@ void GiveBall(entity plyr, entity ball)
                ball.nextthink = time + autocvar_g_nexball_basketball_delay_hold;
        }
 
-       plyr.weaponentity.weapons = plyr.weapons;
-       plyr.weaponentity.switchweapon = plyr.weapon;
+       plyr.(weaponentity).weapons = plyr.weapons;
+       plyr.(weaponentity).switchweapon = plyr.weapon;
        plyr.weapons = WEPSET(NEXBALL);
        setself(plyr);
        Weapon w = WEP_NEXBALL;
@@ -210,7 +210,8 @@ void DropBall(entity ball, vector org, vector vel)
        if(ball.owner.metertime)
        {
                ball.owner.metertime = 0;
-               ball.owner.weaponentity.state = WS_READY;
+               .entity weaponentity = weaponentities[0]; // TODO: find ballstealer
+               ball.owner.(weaponentity).state = WS_READY;
        }
 
        WaypointSprite_Kill(ball.owner.waypointsprite_attachedforcarrier);
@@ -221,7 +222,7 @@ void DropBall(entity ball, vector org, vector vel)
        ball.owner = world;
 }
 
-void InitBall(void)
+void InitBall()
 {SELFPARAM();
        if(gameover) return;
        self.flags &= ~FL_ONGROUND;
@@ -241,7 +242,7 @@ void InitBall(void)
        LogNB("init", world);
 }
 
-void ResetBall(void)
+void ResetBall()
 {SELFPARAM();
        if(self.cnt < 2)        // step 1
        {
@@ -277,7 +278,7 @@ void ResetBall(void)
        }
 }
 
-void football_touch(void)
+void football_touch()
 {SELFPARAM();
        if(other.solid == SOLID_BSP)
        {
@@ -323,7 +324,7 @@ void football_touch(void)
        self.avelocity = -250 * v_forward;  // maybe there is a way to make it look better?
 }
 
-void basketball_touch(void)
+void basketball_touch()
 {SELFPARAM();
        if(other.ballcarried)
        {
@@ -345,7 +346,7 @@ void basketball_touch(void)
        }
 }
 
-void GoalTouch(void)
+void GoalTouch()
 {SELFPARAM();
        entity ball;
        float isclient, pscore, otherteam;
@@ -450,16 +451,14 @@ spawnfunc(nexball_team)
 void nb_spawnteam(string teamname, float teamcolor)
 {
        LOG_TRACE("^2spawned team ", teamname, "\n");
-       entity e;
-       e = spawn();
-       e.classname = "nexball_team";
+       entity e = new(nexball_team);
        e.netname = teamname;
        e.cnt = teamcolor;
        e.team = e.cnt + 1;
        nb_teams += 1;
 }
 
-void nb_spawnteams(void)
+void nb_spawnteams()
 {
        bool t_red = false, t_blue = false, t_yellow = false, t_pink = false;
        entity e;
@@ -499,7 +498,7 @@ void nb_spawnteams(void)
        }
 }
 
-void nb_delayedinit(void)
+void nb_delayedinit()
 {
        if(find(world, classname, "nexball_team") == world)
                nb_spawnteams();
@@ -511,7 +510,7 @@ void nb_delayedinit(void)
 //       spawnfuncs       //
 //=======================//
 
-void SpawnBall(void)
+void SpawnBall()
 {SELFPARAM();
        if(!g_nexball) { remove(self); return; }
 
@@ -544,13 +543,13 @@ void SpawnBall(void)
        if(!autocvar_g_nexball_sound_bounce)
                self.noise = "";
        else if(self.noise == "")
-               self.noise = SND(NB_BOUNCE);
+               self.noise = strzone(SND(NB_BOUNCE));
        //bounce sound placeholder (FIXME)
        if(self.noise1 == "")
-               self.noise1 = SND(NB_DROP);
+               self.noise1 = strzone(SND(NB_DROP));
        //ball drop sound placeholder (FIXME)
        if(self.noise2 == "")
-               self.noise2 = SND(NB_STEAL);
+               self.noise2 = strzone(SND(NB_STEAL));
        //stealing sound placeholder (FIXME)
        if(self.noise) precache_sound(self.noise);
        precache_sound(self.noise1);
@@ -607,7 +606,7 @@ float nb_Goal_Customize()
        return true;
 }
 
-void SpawnGoal(void)
+void SpawnGoal()
 {SELFPARAM();
        if(!g_nexball) { remove(self); return; }
 
@@ -652,7 +651,7 @@ spawnfunc(nexball_fault)
 {
        self.team = GOAL_FAULT;
        if(self.noise == "")
-               self.noise = SND(TYPEHIT);
+               self.noise = strzone(SND(TYPEHIT));
        SpawnGoal();
 }
 
@@ -660,7 +659,7 @@ spawnfunc(nexball_out)
 {
        self.team = GOAL_OUT;
        if(self.noise == "")
-               self.noise = SND(TYPEHIT);
+               self.noise = strzone(SND(TYPEHIT));
        SpawnGoal();
 }
 
@@ -718,7 +717,7 @@ void W_Nexball_Think()
        self.nextthink = time;
 }
 
-void W_Nexball_Touch(void)
+void W_Nexball_Touch()
 {SELFPARAM();
        entity ball, attacker;
        attacker = self.owner;
@@ -787,7 +786,7 @@ void W_Nexball_Attack(float t)
 
 vector trigger_push_calculatevelocity(vector org, entity tgt, float ht);
 
-void W_Nexball_Attack2(void)
+void W_Nexball_Attack2()
 {SELFPARAM();
        if(self.ballcarried.enemy)
        {
@@ -803,10 +802,9 @@ void W_Nexball_Attack2(void)
                return;
 
        W_SetupShot(self, false, 2, SND(NB_SHOOT2), CH_WEAPON_A, 0);
-       entity missile = spawn();
+       entity missile = new(ballstealer);
 
        missile.owner = self;
-       missile.classname = "ballstealer";
 
        missile.movetype = MOVETYPE_FLY;
        PROJECTILE_MAKETRIGGER(missile);
@@ -854,34 +852,34 @@ float ball_customize()
        return true;
 }
 
-       METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, bool fire1, bool fire2))
+       METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, .entity weaponentity, int fire))
        {
-               if(fire1)
-                       if(weapon_prepareattack(thiswep, actor, false, autocvar_g_balance_nexball_primary_refire))
+               if(fire & 1)
+                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_balance_nexball_primary_refire))
                                if(autocvar_g_nexball_basketball_meter)
                                {
                                        if(self.ballcarried && !self.metertime)
                                                self.metertime = time;
                                        else
-                                               weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
                                }
                                else
                                {
                                        W_Nexball_Attack(-1);
-                                       weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
                                }
-               if(fire2)
-                       if(weapon_prepareattack(thiswep, actor, true, autocvar_g_balance_nexball_secondary_refire))
+               if(fire & 2)
+                       if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_nexball_secondary_refire))
                        {
                                W_Nexball_Attack2();
-                               weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
+                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
                        }
 
-               if(!fire1 && self.metertime && self.ballcarried)
+               if(!(fire & 1) && self.metertime && self.ballcarried)
                {
                        W_Nexball_Attack(time - self.metertime);
                        // DropBall or stealing will set metertime back to 0
-                       weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
                }
        }
        METHOD(BallStealer, wr_setup, void(BallStealer thiswep))
@@ -967,15 +965,16 @@ MUTATOR_HOOKFUNCTION(nb, PlayerPreThink)
                }
                else
                {
-                       if(self.weaponentity.weapons)
+                       .entity weaponentity = weaponentities[0]; // TODO
+                       if(self.(weaponentity).weapons)
                        {
-                               self.weapons = self.weaponentity.weapons;
+                               self.weapons = self.(weaponentity).weapons;
                                Weapon w = WEP_NEXBALL;
                                w.wr_resetplayer(w);
-                               self.switchweapon = self.weaponentity.switchweapon;
+                               self.switchweapon = self.(weaponentity).switchweapon;
                                W_SwitchWeapon(self.switchweapon);
 
-               self.weaponentity.weapons = '0 0 0';
+                               self.(weaponentity).weapons = '0 0 0';
                        }
                }
 
@@ -996,7 +995,8 @@ MUTATOR_HOOKFUNCTION(nb, PlayerSpawn)
 {
        SELFPARAM();
        this.metertime = 0;
-       this.weaponentity.weapons = '0 0 0';
+       .entity weaponentity = weaponentities[0];
+       this.(weaponentity).weapons = '0 0 0';
 
        if (nexball_mode & NBM_BASKETBALL)
                this.weapons |= WEPSET(NEXBALL);
@@ -1066,10 +1066,6 @@ MUTATOR_HOOKFUNCTION(nb, SendWaypoint)
 
 REGISTER_MUTATOR(nb, g_nexball)
 {
-       ActivateTeamplay();
-       SetLimits(autocvar_g_nexball_goallimit, autocvar_g_nexball_goalleadlimit, -1, -1);
-       have_team_spawns = -1; // request team spawns
-
        MUTATOR_ONADD
        {
                g_nexball_meter_period = autocvar_g_nexball_meter_period;
@@ -1089,6 +1085,10 @@ REGISTER_MUTATOR(nb, g_nexball)
 
                InitializeEntity(world, nb_delayedinit, INITPRIO_GAMETYPE);
                WEP_NEXBALL.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+
+               ActivateTeamplay();
+               SetLimits(autocvar_g_nexball_goallimit, autocvar_g_nexball_goalleadlimit, -1, -1);
+               have_team_spawns = -1; // request team spawns
        }
 
        MUTATOR_ONROLLBACK_OR_REMOVE
index 58bf6ec4dd41032fdce793e9fce985bbbdb7604a..9dd8042be32ab87f369874e7718ca1e19feb2031 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef GAMEMODE_NEXBALL_H
 #define GAMEMODE_NEXBALL_H
 
-#include "weapon.qc"
-
 #ifdef SVQC
 //EF_BRIGHTFIELD|EF_BRIGHTLIGHT|EF_DIMLIGHT|EF_BLUE|EF_RED|EF_FLAME
 const float BALL_EFFECTMASK = 1229;
index ae882bb32a1cca706a45a30b873c03318ae3f97a..c6aa4be215a21fca52c75cf00388f6a7de730af3 100644 (file)
@@ -5,7 +5,7 @@ CLASS(BallStealer, PortoLaunch)
 /* flags     */ ATTRIB(BallStealer, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(BallStealer, impulse, int, 0);
 /* refname   */ ATTRIB(BallStealer, netname, string, "ballstealer");
-/* wepname   */ ATTRIB(BallStealer, message, string, _("Ball Stealer"));
+/* wepname   */ ATTRIB(BallStealer, m_name, string, _("Ball Stealer"));
 ENDCLASS(BallStealer)
 REGISTER_WEAPON(NEXBALL, NEW(BallStealer));
 
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/cl_controlpoint.qc b/qcsrc/common/gamemodes/gamemode/onslaught/cl_controlpoint.qc
new file mode 100644 (file)
index 0000000..28ac85d
--- /dev/null
@@ -0,0 +1,198 @@
+#include "cl_controlpoint.qh"
+
+.vector colormod;
+.float alpha;
+.int count;
+.float pain_finished;
+
+.bool iscaptured;
+
+.vector cp_origin, cp_bob_origin;
+.float cp_bob_spd;
+
+.vector cp_bob_dmg;
+
+.vector punchangle;
+
+.float max_health;
+
+.entity icon_realmodel;
+
+void cpicon_draw(entity this)
+{
+       if(time < this.move_time) { return; }
+
+       if(this.cp_bob_dmg_z > 0)
+               this.cp_bob_dmg_z = this.cp_bob_dmg_z - 3 * frametime;
+       else
+               this.cp_bob_dmg_z = 0;
+       this.cp_bob_origin_z = 4 * PI * (1 - cos(this.cp_bob_spd));
+       this.cp_bob_spd = this.cp_bob_spd + 1.875 * frametime;
+       this.colormod = '1 1 1' * (2 - bound(0, (this.pain_finished - time) / 10, 1));
+
+       if(!this.iscaptured) this.alpha = this.health / this.max_health;
+
+       if(this.iscaptured)
+       {
+               if (this.punchangle_x > 0)
+               {
+                       this.punchangle_x = this.punchangle_x - 60 * frametime;
+                       if (this.punchangle_x < 0)
+                               this.punchangle_x = 0;
+               }
+               else if (this.punchangle_x < 0)
+               {
+                       this.punchangle_x = this.punchangle_x + 60 * frametime;
+                       if (this.punchangle_x > 0)
+                               this.punchangle_x = 0;
+               }
+
+               if (this.punchangle_y > 0)
+               {
+                       this.punchangle_y = this.punchangle_y - 60 * frametime;
+                       if (this.punchangle_y < 0)
+                               this.punchangle_y = 0;
+               }
+               else if (this.punchangle_y < 0)
+               {
+                       this.punchangle_y = this.punchangle_y + 60 * frametime;
+                       if (this.punchangle_y > 0)
+                               this.punchangle_y = 0;
+               }
+
+               if (this.punchangle_z > 0)
+               {
+                       this.punchangle_z = this.punchangle_z - 60 * frametime;
+                       if (this.punchangle_z < 0)
+                               this.punchangle_z = 0;
+               }
+               else if (this.punchangle_z < 0)
+               {
+                       this.punchangle_z = this.punchangle_z + 60 * frametime;
+                       if (this.punchangle_z > 0)
+                               this.punchangle_z = 0;
+               }
+
+               this.angles_x = this.punchangle_x;
+               this.angles_y = this.punchangle_y + this.move_angles_y;
+               this.angles_z = this.punchangle_z;
+               this.move_angles_y = this.move_angles_y + 45 * frametime;
+       }
+
+       setorigin(this, this.cp_origin + this.cp_bob_origin + this.cp_bob_dmg);
+}
+
+void cpicon_damage(entity this, float hp)
+{
+       if(!this.iscaptured) { return; }
+
+       if(hp < this.max_health * 0.25)
+               setmodel(this, MDL_ONS_CP3);
+       else if(hp < this.max_health * 0.50)
+               setmodel(this, MDL_ONS_CP2);
+       else if(hp < this.max_health * 0.75)
+               setmodel(this, MDL_ONS_CP1);
+       else if(hp <= this.max_health || hp >= this.max_health)
+               setmodel(this, MDL_ONS_CP);
+
+       this.punchangle = (2 * randomvec() - '1 1 1') * 45;
+
+       this.cp_bob_dmg_z = (2 * random() - 1) * 15;
+       this.pain_finished = time + 1;
+       this.colormod = '2 2 2';
+
+       setsize(this, CPICON_MIN, CPICON_MAX);
+}
+
+void cpicon_construct(entity this)
+{
+       this.netname = "Control Point Icon";
+
+       setmodel(this, MDL_ONS_CP);
+       setsize(this, CPICON_MIN, CPICON_MAX);
+
+       if(this.icon_realmodel == world)
+       {
+               this.icon_realmodel = spawn();
+               setmodel(this.icon_realmodel, MDL_Null);
+               setorigin(this.icon_realmodel, this.origin);
+               setsize(this.icon_realmodel, CPICON_MIN, CPICON_MAX);
+               this.icon_realmodel.movetype = MOVETYPE_NOCLIP;
+               this.icon_realmodel.solid = SOLID_NOT;
+               this.icon_realmodel.move_origin = this.icon_realmodel.origin;
+       }
+
+       if(this.iscaptured) { this.icon_realmodel.solid = SOLID_BBOX; }
+
+       this.move_movetype      = MOVETYPE_NOCLIP;
+       this.solid                      = SOLID_NOT;
+       this.movetype           = MOVETYPE_NOCLIP;
+       this.move_origin        = this.origin;
+       this.move_time          = time;
+       this.drawmask           = MASK_NORMAL;
+       this.alpha                      = 1;
+       this.draw                       = cpicon_draw;
+       this.cp_origin          = this.origin;
+       this.cp_bob_origin      = '0 0 0.1';
+       this.cp_bob_spd         = 0;
+}
+
+.vector glowmod;
+void cpicon_changeteam(entity this)
+{
+       if(this.team)
+       {
+               this.glowmod = Team_ColorRGB(this.team - 1);
+               this.teamradar_color = Team_ColorRGB(this.team - 1);
+               this.colormap = 1024 + (this.team - 1) * 17;
+       }
+       else
+       {
+               this.colormap = 1024;
+               this.glowmod = '1 1 0';
+               this.teamradar_color = '1 1 0';
+       }
+}
+
+NET_HANDLE(ENT_CLIENT_CONTROLPOINT_ICON, bool isnew)
+{
+       return = true;
+       int sf = ReadByte();
+
+       if(sf & CPSF_SETUP)
+       {
+               this.origin_x = ReadCoord();
+               this.origin_y = ReadCoord();
+               this.origin_z = ReadCoord();
+               setorigin(this, this.origin);
+
+               this.health = ReadByte();
+               this.max_health = ReadByte();
+               this.count = ReadByte();
+               this.team = ReadByte();
+               this.iscaptured = ReadByte();
+
+               if(!this.count)
+                       this.count = (this.health - this.max_health) * frametime;
+
+               cpicon_changeteam(this);
+               cpicon_construct(this);
+       }
+
+       if(sf & CPSF_STATUS)
+       {
+               int _tmp = ReadByte();
+               if(_tmp != this.team)
+               {
+                       this.team = _tmp;
+                       cpicon_changeteam(this);
+               }
+
+               _tmp = ReadByte();
+
+               if(_tmp != this.health)
+                       cpicon_damage(this, _tmp);
+
+               this.health = _tmp;
+       }
+}
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/cl_controlpoint.qh b/qcsrc/common/gamemodes/gamemode/onslaught/cl_controlpoint.qh
new file mode 100644 (file)
index 0000000..15586ea
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef CLIENT_CONTROLPOINT_H
+#define CLIENT_CONTROLPOINT_H
+
+const vector CPICON_MIN = '-32 -32 -9';
+const vector CPICON_MAX = '32 32 25';
+
+const int CPSF_STATUS = 4;
+const int CPSF_SETUP = 8;
+
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/cl_generator.qc b/qcsrc/common/gamemodes/gamemode/onslaught/cl_generator.qc
new file mode 100644 (file)
index 0000000..f5b6111
--- /dev/null
@@ -0,0 +1,223 @@
+#include "cl_generator.qh"
+
+.float alpha;
+.float scale;
+.int count;
+.float max_health;
+
+void ons_generator_ray_draw(entity this)
+{
+       if(time < self.move_time)
+               return;
+
+       self.move_time = time + 0.05;
+
+       if(self.count > 10)
+       {
+               remove(self);
+               return;
+       }
+
+       if(self.count > 5)
+               self.alpha -= 0.1;
+       else
+               self.alpha += 0.1;
+
+       self.scale += 0.2;
+       self.count +=1;
+}
+
+void ons_generator_ray_spawn(vector org)
+{
+       entity e = new(ons_ray);
+       setmodel(e, MDL_ONS_RAY);
+       setorigin(e, org);
+       e.angles = randomvec() * 360;
+       e.move_origin = org;
+       e.movetype = MOVETYPE_NONE;
+       e.alpha = 0;
+       e.scale = random() * 5 + 8;
+       e.move_time = time + 0.05;
+       e.drawmask = MASK_NORMAL;
+       e.draw = ons_generator_ray_draw;
+}
+
+void generator_draw(entity this)
+{
+       if(time < self.move_time)
+               return;
+
+       if(self.health > 0)
+       {
+               // damaged fx (less probable the more damaged is the generator)
+               if(random() < 0.9 - self.health / self.max_health)
+               if(random() < 0.01)
+               {
+                       pointparticles(EFFECT_ELECTRO_BALLEXPLODE, self.origin + randompos('-50 -50 -20', '50 50 50'), '0 0 0', 1);
+                       sound(self, CH_TRIGGER, SND_ONS_ELECTRICITY_EXPLODE, VOL_BASE, ATTEN_NORM);
+               }
+               else
+                       pointparticles(EFFECT_ONS_GENERATOR_DAMAGED, self.origin + randompos('-60 -60 -20', '60 60 60'), '0 0 0', 1);
+
+               self.move_time = time + 0.1;
+
+               return;
+       }
+
+       if(self.count <= 0)
+               return;
+
+       vector org;
+       int i;
+
+       // White shockwave
+       if(self.count==40||self.count==20)
+       {
+               sound(self, CH_TRIGGER, SND_ONS_SHOCKWAVE, VOL_BASE, ATTEN_NORM);
+               pointparticles(EFFECT_ELECTRO_COMBO, self.origin, '0 0 0', 6);
+       }
+
+       // rays
+       if(random() > 0.25)
+       {
+               ons_generator_ray_spawn(self.origin);
+       }
+
+       // Spawn fire balls
+       for(i=0;i < 10;++i)
+       {
+               org = self.origin + randompos('-30 -30 -30' * i + '0 0 -20', '30 30 30' * i + '0 0 20');
+               pointparticles(EFFECT_ONS_GENERATOR_GIB, org, '0 0 0', 1);
+       }
+
+       // Short explosion sound + small explosion
+       if(random() < 0.25)
+       {
+               te_explosion(self.origin);
+               sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
+       }
+
+       // Particles
+       org = self.origin + randompos(self.mins + '8 8 8', self.maxs + '-8 -8 -8');
+       pointparticles(EFFECT_ONS_GENERATOR_EXPLODE, org, '0 0 0', 1);
+
+       // Final explosion
+       if(self.count==1)
+       {
+               org = self.origin;
+               te_explosion(org);
+               pointparticles(EFFECT_ONS_GENERATOR_EXPLODE2, org, '0 0 0', 1);
+               sound(self, CH_TRIGGER, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+       }
+
+       self.move_time = time + 0.05;
+
+       self.count -= 1;
+}
+
+void generator_damage(float hp)
+{SELFPARAM();
+       if(hp <= 0)
+               setmodel(self, MDL_ONS_GEN_DEAD);
+       else if(hp < self.max_health * 0.10)
+               setmodel(self, MDL_ONS_GEN9);
+       else if(hp < self.max_health * 0.20)
+               setmodel(self, MDL_ONS_GEN8);
+       else if(hp < self.max_health * 0.30)
+               setmodel(self, MDL_ONS_GEN7);
+       else if(hp < self.max_health * 0.40)
+               setmodel(self, MDL_ONS_GEN6);
+       else if(hp < self.max_health * 0.50)
+               setmodel(self, MDL_ONS_GEN5);
+       else if(hp < self.max_health * 0.60)
+               setmodel(self, MDL_ONS_GEN4);
+       else if(hp < self.max_health * 0.70)
+               setmodel(self, MDL_ONS_GEN3);
+       else if(hp < self.max_health * 0.80)
+               setmodel(self, MDL_ONS_GEN2);
+       else if(hp < self.max_health * 0.90)
+               setmodel(self, MDL_ONS_GEN1);
+       else if(hp <= self.max_health || hp >= self.max_health)
+               setmodel(self, MDL_ONS_GEN);
+
+       setsize(self, GENERATOR_MIN, GENERATOR_MAX);
+}
+
+void generator_construct()
+{SELFPARAM();
+       self.netname = "Generator";
+       self.classname = "onslaught_generator";
+
+       setorigin(self, self.origin);
+       setmodel(self, MDL_ONS_GEN);
+       setsize(self, GENERATOR_MIN, GENERATOR_MAX);
+
+       self.move_movetype      = MOVETYPE_NOCLIP;
+       self.solid                      = SOLID_BBOX;
+       self.movetype           = MOVETYPE_NOCLIP;
+       self.move_origin        = self.origin;
+       self.move_time          = time;
+       self.drawmask           = MASK_NORMAL;
+       self.alpha                      = 1;
+       self.draw                       = generator_draw;
+}
+
+.vector glowmod;
+void generator_changeteam()
+{SELFPARAM();
+       if(self.team)
+       {
+               self.glowmod = Team_ColorRGB(self.team - 1);
+               self.teamradar_color = Team_ColorRGB(self.team - 1);
+               self.colormap = 1024 + (self.team - 1) * 17;
+       }
+       else
+       {
+               self.colormap = 1024;
+               self.glowmod = '1 1 0';
+               self.teamradar_color = '1 1 0';
+       }
+}
+
+NET_HANDLE(ENT_CLIENT_GENERATOR, bool isnew)
+{
+       return = true;
+       int sf = ReadByte();
+
+       if(sf & GSF_SETUP)
+       {
+               self.origin_x = ReadCoord();
+               self.origin_y = ReadCoord();
+               self.origin_z = ReadCoord();
+               setorigin(self, self.origin);
+
+               self.health = ReadByte();
+               self.max_health = ReadByte();
+               self.count = ReadByte();
+               self.team = ReadByte();
+
+               if(!self.count)
+                       self.count = 40;
+
+               generator_changeteam();
+               generator_construct();
+       }
+
+       if(sf & GSF_STATUS)
+       {
+               int _tmp;
+               _tmp = ReadByte();
+               if(_tmp != self.team)
+               {
+                       self.team = _tmp;
+                       generator_changeteam();
+               }
+
+               _tmp = ReadByte();
+
+               if(_tmp != self.health)
+                       generator_damage(_tmp);
+
+               self.health = _tmp;
+       }
+}
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/cl_generator.qh b/qcsrc/common/gamemodes/gamemode/onslaught/cl_generator.qh
new file mode 100644 (file)
index 0000000..3c0cf28
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef CLIENT_GENERATOR_H
+#define CLIENT_GENERATOR_H
+const vector GENERATOR_MIN = '-52 -52 -14';
+const vector GENERATOR_MAX = '52 52 75';
+
+const int GSF_STATUS = 4;
+const int GSF_SETUP = 8;
+
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/module.inc b/qcsrc/common/gamemodes/gamemode/onslaught/module.inc
new file mode 100644 (file)
index 0000000..fee33b1
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef ONS_CONSTANTS
+       #define ONS_CONSTANTS
+       REGISTER_NET_LINKED(ENT_CLIENT_GENERATOR)
+       REGISTER_NET_LINKED(ENT_CLIENT_CONTROLPOINT_ICON)
+#endif
+
+#if defined(SVQC)
+       #include "onslaught.qc"
+       #ifndef IMPLEMENTATION
+               #include "sv_controlpoint.qh"
+               #include "sv_generator.qh"
+       #else
+               #include "sv_controlpoint.qc"
+               #include "sv_generator.qc"
+       #endif
+#elif defined(CSQC)
+       #ifndef IMPLEMENTATION
+               #include "cl_controlpoint.qh"
+               #include "cl_generator.qh"
+       #else
+               #include "cl_controlpoint.qc"
+               #include "cl_generator.qc"
+       #endif
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/onslaught.qc b/qcsrc/common/gamemodes/gamemode/onslaught/onslaught.qc
new file mode 100644 (file)
index 0000000..04b5a3f
--- /dev/null
@@ -0,0 +1,2326 @@
+#ifndef GAMEMODE_ONSLAUGHT_H
+#define GAMEMODE_ONSLAUGHT_H
+
+float autocvar_g_onslaught_point_limit;
+void ons_Initialize();
+
+REGISTER_MUTATOR(ons, false)
+{
+       MUTATOR_ONADD
+       {
+               if (time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               ons_Initialize();
+
+               ActivateTeamplay();
+               SetLimits(autocvar_g_onslaught_point_limit, -1, -1, -1);
+               have_team_spawns = -1; // request team spawns
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // we actually cannot roll back ons_Initialize here
+               // BUT: we don't need to! If this gets called, adding always
+               // succeeds.
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This is a game type and it cannot be removed at runtime.");
+               return -1;
+       }
+
+       return false;
+}
+
+#ifdef SVQC
+
+.entity ons_toucher; // player who touched the control point
+
+// control point / generator constants
+const float ONS_CP_THINKRATE = 0.2;
+const float GEN_THINKRATE = 1;
+#define CPGEN_SPAWN_OFFSET ('0 0 1' * (PL_MAX_CONST.z - 13))
+const vector CPGEN_WAYPOINT_OFFSET = ('0 0 128');
+const vector CPICON_OFFSET = ('0 0 96');
+
+// list of generators on the map
+entity ons_worldgeneratorlist;
+.entity ons_worldgeneratornext;
+.entity ons_stalegeneratornext;
+
+// list of control points on the map
+entity ons_worldcplist;
+.entity ons_worldcpnext;
+.entity ons_stalecpnext;
+
+// list of links on the map
+entity ons_worldlinklist;
+.entity ons_worldlinknext;
+.entity ons_stalelinknext;
+
+// definitions
+.entity sprite;
+.string target2;
+.int iscaptured;
+.int islinked;
+.int isshielded;
+.float lasthealth;
+.int lastteam;
+.int lastshielded;
+.int lastcaptured;
+
+.bool waslinked;
+
+bool ons_stalemate;
+
+.float teleport_antispam;
+
+.bool ons_roundlost;
+
+// waypoint sprites
+.entity bot_basewaypoint; // generator waypointsprite
+
+.bool isgenneighbor[17];
+.bool iscpneighbor[17];
+float ons_notification_time[17];
+
+.float ons_overtime_damagedelay;
+
+.vector ons_deathloc;
+
+.entity ons_spawn_by;
+
+// declarations for functions used outside gamemode_onslaught.qc
+void ons_Generator_UpdateSprite(entity e);
+void ons_ControlPoint_UpdateSprite(entity e);
+bool ons_ControlPoint_Attackable(entity cp, int teamnumber);
+
+// CaptureShield: Prevent capturing or destroying control point/generator if it is not available yet
+float ons_captureshield_force; // push force of the shield
+
+// bot player logic
+const int HAVOCBOT_ONS_ROLE_NONE               = 0;
+const int HAVOCBOT_ONS_ROLE_DEFENSE    = 2;
+const int HAVOCBOT_ONS_ROLE_ASSISTANT  = 4;
+const int HAVOCBOT_ONS_ROLE_OFFENSE    = 8;
+
+.entity havocbot_ons_target;
+
+.int havocbot_role_flags;
+.float havocbot_attack_time;
+
+void havocbot_role_ons_defense();
+void havocbot_role_ons_offense();
+void havocbot_role_ons_assistant();
+
+void havocbot_ons_reset_role(entity bot);
+void havocbot_goalrating_items(float ratingscale, vector org, float sradius);
+void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradius);
+
+// score rule declarations
+const int ST_ONS_CAPS = 1;
+const int SP_ONS_CAPS = 4;
+const int SP_ONS_TAKES = 6;
+
+#endif
+#endif
+
+#ifdef IMPLEMENTATION
+
+#include "sv_controlpoint.qh"
+#include "sv_generator.qh"
+
+bool g_onslaught;
+
+float autocvar_g_onslaught_debug;
+float autocvar_g_onslaught_teleport_wait;
+bool autocvar_g_onslaught_spawn_at_controlpoints;
+bool autocvar_g_onslaught_spawn_at_generator;
+float autocvar_g_onslaught_cp_proxydecap;
+float autocvar_g_onslaught_cp_proxydecap_distance = 512;
+float autocvar_g_onslaught_cp_proxydecap_dps = 100;
+float autocvar_g_onslaught_spawn_at_controlpoints_chance = 0.5;
+float autocvar_g_onslaught_spawn_at_controlpoints_random;
+float autocvar_g_onslaught_spawn_at_generator_chance;
+float autocvar_g_onslaught_spawn_at_generator_random;
+float autocvar_g_onslaught_cp_buildhealth;
+float autocvar_g_onslaught_cp_buildtime;
+float autocvar_g_onslaught_cp_health;
+float autocvar_g_onslaught_cp_regen;
+float autocvar_g_onslaught_gen_health;
+float autocvar_g_onslaught_shield_force = 100;
+float autocvar_g_onslaught_allow_vehicle_touch;
+float autocvar_g_onslaught_round_timelimit;
+float autocvar_g_onslaught_warmup;
+float autocvar_g_onslaught_teleport_radius;
+float autocvar_g_onslaught_spawn_choose;
+float autocvar_g_onslaught_click_radius;
+
+void FixSize(entity e);
+
+// =======================
+// CaptureShield Functions
+// =======================
+
+bool ons_CaptureShield_Customize()
+{SELFPARAM();
+       entity e = WaypointSprite_getviewentity(other);
+
+       if(!self.enemy.isshielded && (ons_ControlPoint_Attackable(self.enemy, e.team) > 0 || self.enemy.classname != "onslaught_controlpoint")) { return false; }
+       if(SAME_TEAM(self, e)) { return false; }
+
+       return true;
+}
+
+void ons_CaptureShield_Touch()
+{SELFPARAM();
+       if(!self.enemy.isshielded && (ons_ControlPoint_Attackable(self.enemy, other.team) > 0 || self.enemy.classname != "onslaught_controlpoint")) { return; }
+       if(!IS_PLAYER(other)) { return; }
+       if(SAME_TEAM(other, self)) { return; }
+
+       vector mymid = (self.absmin + self.absmax) * 0.5;
+       vector othermid = (other.absmin + other.absmax) * 0.5;
+
+       Damage(other, self, self, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(othermid - mymid) * ons_captureshield_force);
+
+       if(IS_REAL_CLIENT(other))
+       {
+               play2(other, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
+
+               if(self.enemy.classname == "onslaught_generator")
+                       Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_GENERATOR_SHIELDED);
+               else
+                       Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_CONTROLPOINT_SHIELDED);
+       }
+}
+
+void ons_CaptureShield_Reset()
+{SELFPARAM();
+       self.colormap = self.enemy.colormap;
+       self.team = self.enemy.team;
+}
+
+void ons_CaptureShield_Spawn(entity generator, bool is_generator)
+{
+       entity shield = new(ons_captureshield);
+
+       shield.enemy = generator;
+       shield.team = generator.team;
+       shield.colormap = generator.colormap;
+       shield.reset = ons_CaptureShield_Reset;
+       shield.touch = ons_CaptureShield_Touch;
+       shield.customizeentityforclient = ons_CaptureShield_Customize;
+       shield.effects = EF_ADDITIVE;
+       shield.movetype = MOVETYPE_NOCLIP;
+       shield.solid = SOLID_TRIGGER;
+       shield.avelocity = '7 0 11';
+       shield.scale = 1;
+       shield.model = ((is_generator) ? "models/onslaught/generator_shield.md3" : "models/onslaught/controlpoint_shield.md3");
+
+       precache_model(shield.model);
+       setorigin(shield, generator.origin);
+       _setmodel(shield, shield.model);
+       setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
+}
+
+
+// ==========
+// Junk Pile
+// ==========
+
+void ons_debug(string input)
+{
+       switch(autocvar_g_onslaught_debug)
+       {
+               case 1: LOG_TRACE(input); break;
+               case 2: LOG_INFO(input); break;
+       }
+}
+
+void setmodel_fixsize(entity e, Model m)
+{
+       setmodel(e, m);
+       FixSize(e);
+}
+
+void onslaught_updatelinks()
+{
+       entity l;
+       // first check if the game has ended
+       ons_debug("--- updatelinks ---\n");
+       // mark generators as being shielded and networked
+       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+       {
+               if (l.iscaptured)
+                       ons_debug(strcat(etos(l), " (generator) belongs to team ", ftos(l.team), "\n"));
+               else
+                       ons_debug(strcat(etos(l), " (generator) is destroyed\n"));
+               l.islinked = l.iscaptured;
+               l.isshielded = l.iscaptured;
+               l.sprite.SendFlags |= 16;
+       }
+       // mark points as shielded and not networked
+       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+       {
+               l.islinked = false;
+               l.isshielded = true;
+               int i;
+               for(i = 0; i < 17; ++i) { l.isgenneighbor[i] = false; l.iscpneighbor[i] = false; }
+               ons_debug(strcat(etos(l), " (point) belongs to team ", ftos(l.team), "\n"));
+               l.sprite.SendFlags |= 16;
+       }
+       // flow power outward from the generators through the network
+       bool stop = false;
+       while (!stop)
+       {
+               stop = true;
+               for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
+               {
+                       // if both points are captured by the same team, and only one of
+                       // them is powered, mark the other one as powered as well
+                       if (l.enemy.iscaptured && l.goalentity.iscaptured)
+                               if (l.enemy.islinked != l.goalentity.islinked)
+                                       if(SAME_TEAM(l.enemy, l.goalentity))
+                                       {
+                                               if (!l.goalentity.islinked)
+                                               {
+                                                       stop = false;
+                                                       l.goalentity.islinked = true;
+                                                       ons_debug(strcat(etos(l), " (link) is marking ", etos(l.goalentity), " (point) because its team matches ", etos(l.enemy), " (point)\n"));
+                                               }
+                                               else if (!l.enemy.islinked)
+                                               {
+                                                       stop = false;
+                                                       l.enemy.islinked = true;
+                                                       ons_debug(strcat(etos(l), " (link) is marking ", etos(l.enemy), " (point) because its team matches ", etos(l.goalentity), " (point)\n"));
+                                               }
+                                       }
+               }
+       }
+       // now that we know which points are powered we can mark their neighbors
+       // as unshielded if team differs
+       for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
+       {
+               if (l.goalentity.islinked)
+               {
+                       if(DIFF_TEAM(l.goalentity, l.enemy))
+                       {
+                               ons_debug(strcat(etos(l), " (link) is unshielding ", etos(l.enemy), " (point) because its team does not match ", etos(l.goalentity), " (point)\n"));
+                               l.enemy.isshielded = false;
+                       }
+                       if(l.goalentity.classname == "onslaught_generator")
+                               l.enemy.isgenneighbor[l.goalentity.team] = true;
+                       else
+                               l.enemy.iscpneighbor[l.goalentity.team] = true;
+               }
+               if (l.enemy.islinked)
+               {
+                       if(DIFF_TEAM(l.goalentity, l.enemy))
+                       {
+                               ons_debug(strcat(etos(l), " (link) is unshielding ", etos(l.goalentity), " (point) because its team does not match ", etos(l.enemy), " (point)\n"));
+                               l.goalentity.isshielded = false;
+                       }
+                       if(l.enemy.classname == "onslaught_generator")
+                               l.goalentity.isgenneighbor[l.enemy.team] = true;
+                       else
+                               l.goalentity.iscpneighbor[l.enemy.team] = true;
+               }
+       }
+       // now update the generators
+       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+       {
+               if (l.isshielded)
+               {
+                       ons_debug(strcat(etos(l), " (generator) is shielded\n"));
+                       l.takedamage = DAMAGE_NO;
+                       l.bot_attack = false;
+               }
+               else
+               {
+                       ons_debug(strcat(etos(l), " (generator) is not shielded\n"));
+                       l.takedamage = DAMAGE_AIM;
+                       l.bot_attack = true;
+               }
+
+               ons_Generator_UpdateSprite(l);
+       }
+       // now update the takedamage and alpha variables on control point icons
+       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+       {
+               if (l.isshielded)
+               {
+                       ons_debug(strcat(etos(l), " (point) is shielded\n"));
+                       if (l.goalentity)
+                       {
+                               l.goalentity.takedamage = DAMAGE_NO;
+                               l.goalentity.bot_attack = false;
+                       }
+               }
+               else
+               {
+                       ons_debug(strcat(etos(l), " (point) is not shielded\n"));
+                       if (l.goalentity)
+                       {
+                               l.goalentity.takedamage = DAMAGE_AIM;
+                               l.goalentity.bot_attack = true;
+                       }
+               }
+               ons_ControlPoint_UpdateSprite(l);
+       }
+       l = findchain(classname, "ons_captureshield");
+       while(l)
+       {
+               l.team = l.enemy.team;
+               l.colormap = l.enemy.colormap;
+               l = l.chain;
+       }
+}
+
+
+// ===================
+// Main Link Functions
+// ===================
+
+bool ons_Link_Send(entity this, entity to, int sendflags)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_RADARLINK);
+       WriteByte(MSG_ENTITY, sendflags);
+       if(sendflags & 1)
+       {
+               WriteCoord(MSG_ENTITY, self.goalentity.origin_x);
+               WriteCoord(MSG_ENTITY, self.goalentity.origin_y);
+               WriteCoord(MSG_ENTITY, self.goalentity.origin_z);
+       }
+       if(sendflags & 2)
+       {
+               WriteCoord(MSG_ENTITY, self.enemy.origin_x);
+               WriteCoord(MSG_ENTITY, self.enemy.origin_y);
+               WriteCoord(MSG_ENTITY, self.enemy.origin_z);
+       }
+       if(sendflags & 4)
+       {
+               WriteByte(MSG_ENTITY, self.clientcolors); // which is goalentity's color + enemy's color * 16
+       }
+       return true;
+}
+
+void ons_Link_CheckUpdate()
+{SELFPARAM();
+       // TODO check if the two sides have moved (currently they won't move anyway)
+       float cc = 0, cc1 = 0, cc2 = 0;
+
+       if(self.goalentity.islinked || self.goalentity.iscaptured) { cc1 = (self.goalentity.team - 1) * 0x01; }
+       if(self.enemy.islinked || self.enemy.iscaptured) { cc2 = (self.enemy.team - 1) * 0x10; }
+
+       cc = cc1 + cc2;
+
+       if(cc != self.clientcolors)
+       {
+               self.clientcolors = cc;
+               self.SendFlags |= 4;
+       }
+
+       self.nextthink = time;
+}
+
+void ons_DelayedLinkSetup()
+{SELFPARAM();
+       self.goalentity = find(world, targetname, self.target);
+       self.enemy = find(world, targetname, self.target2);
+       if(!self.goalentity) { objerror("can not find target\n"); }
+       if(!self.enemy) { objerror("can not find target2\n"); }
+
+       ons_debug(strcat(etos(self.goalentity), " linked with ", etos(self.enemy), "\n"));
+       self.SendFlags |= 3;
+       self.think = ons_Link_CheckUpdate;
+       self.nextthink = time;
+}
+
+
+// =============================
+// Main Control Point Functions
+// =============================
+
+int ons_ControlPoint_CanBeLinked(entity cp, int teamnumber)
+{
+       if(cp.isgenneighbor[teamnumber]) { return 2; }
+       if(cp.iscpneighbor[teamnumber]) { return 1; }
+
+       return 0;
+}
+
+int ons_ControlPoint_Attackable(entity cp, int teamnumber)
+       // -2: SAME TEAM, attackable by enemy!
+       // -1: SAME TEAM!
+       // 0: off limits
+       // 1: attack it
+       // 2: touch it
+       // 3: attack it (HIGH PRIO)
+       // 4: touch it (HIGH PRIO)
+{
+       int a;
+
+       if(cp.isshielded)
+       {
+               return 0;
+       }
+       else if(cp.goalentity)
+       {
+               // if there's already an icon built, nothing happens
+               if(cp.team == teamnumber)
+               {
+                       a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
+                       if(a) // attackable by enemy?
+                               return -2; // EMERGENCY!
+                       return -1;
+               }
+               // we know it can be linked, so no need to check
+               // but...
+               a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
+               if(a == 2) // near our generator?
+                       return 3; // EMERGENCY!
+               return 1;
+       }
+       else
+       {
+               // free point
+               if(ons_ControlPoint_CanBeLinked(cp, teamnumber))
+               {
+                       a = ons_ControlPoint_CanBeLinked(cp, teamnumber); // why was this here NUM_TEAM_1 + NUM_TEAM_2 - t
+                       if(a == 2)
+                               return 4; // GET THIS ONE NOW!
+                       else
+                               return 2; // TOUCH ME
+               }
+       }
+       return 0;
+}
+
+void ons_ControlPoint_Icon_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{SELFPARAM();
+       if(damage <= 0) { return; }
+
+       if (self.owner.isshielded)
+       {
+               // this is protected by a shield, so ignore the damage
+               if (time > self.pain_finished)
+                       if (IS_PLAYER(attacker))
+                       {
+                               play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
+                               self.pain_finished = time + 1;
+                               attacker.typehitsound += 1; // play both sounds (shield is way too quiet)
+                       }
+
+               return;
+       }
+
+       if(IS_PLAYER(attacker))
+       if(time - ons_notification_time[self.team] > 10)
+       {
+               play2team(self.team, SND(ONS_CONTROLPOINT_UNDERATTACK));
+               ons_notification_time[self.team] = time;
+       }
+
+       self.health = self.health - damage;
+       if(self.owner.iscaptured)
+               WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
+       else
+               WaypointSprite_UpdateBuildFinished(self.owner.sprite, time + (self.max_health - self.health) / (self.count / ONS_CP_THINKRATE));
+       self.pain_finished = time + 1;
+       // particles on every hit
+       pointparticles(EFFECT_SPARKS, hitloc, force*-1, 1);
+       //sound on every hit
+       if (random() < 0.5)
+               sound(self, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE+0.3, ATTEN_NORM);
+       else
+               sound(self, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE+0.3, ATTEN_NORM);
+
+       if (self.health < 0)
+       {
+               sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
+               pointparticles(EFFECT_ROCKET_EXPLODE, self.origin, '0 0 0', 1);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_CPDESTROYED_), self.owner.message, attacker.netname);
+
+               PlayerScore_Add(attacker, SP_ONS_TAKES, 1);
+               PlayerScore_Add(attacker, SP_SCORE, 10);
+
+               self.owner.goalentity = world;
+               self.owner.islinked = false;
+               self.owner.iscaptured = false;
+               self.owner.team = 0;
+               self.owner.colormap = 1024;
+
+               WaypointSprite_UpdateMaxHealth(self.owner.sprite, 0);
+
+               onslaught_updatelinks();
+
+               // Use targets now (somebody make sure this is in the right place..)
+               setself(self.owner);
+               activator = self;
+               SUB_UseTargets ();
+               setself(this);
+
+               self.owner.waslinked = self.owner.islinked;
+               if(self.owner.model != "models/onslaught/controlpoint_pad.md3")
+                       setmodel_fixsize(self.owner, MDL_ONS_CP_PAD1);
+               //setsize(self, '-32 -32 0', '32 32 8');
+
+               remove(self);
+       }
+
+       self.SendFlags |= CPSF_STATUS;
+}
+
+void ons_ControlPoint_Icon_Think()
+{SELFPARAM();
+       self.nextthink = time + ONS_CP_THINKRATE;
+
+       if(autocvar_g_onslaught_cp_proxydecap)
+       {
+        int _enemy_count = 0;
+        int _friendly_count = 0;
+        float _dist;
+        entity _player;
+
+        FOR_EACH_PLAYER(_player)
+        {
+            if(!_player.deadflag)
+            {
+                _dist = vlen(_player.origin - self.origin);
+                if(_dist < autocvar_g_onslaught_cp_proxydecap_distance)
+                {
+                                       if(SAME_TEAM(_player, self))
+                        ++_friendly_count;
+                    else
+                        ++_enemy_count;
+                }
+            }
+        }
+
+        _friendly_count = _friendly_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
+        _enemy_count = _enemy_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
+
+        self.health = bound(0, self.health + (_friendly_count - _enemy_count), self.max_health);
+               self.SendFlags |= CPSF_STATUS;
+        if(self.health <= 0)
+        {
+            ons_ControlPoint_Icon_Damage(self, self, 1, 0, self.origin, '0 0 0');
+            return;
+        }
+    }
+
+       if (time > self.pain_finished + 5)
+       {
+               if(self.health < self.max_health)
+               {
+                       self.health = self.health + self.count;
+                       if (self.health >= self.max_health)
+                               self.health = self.max_health;
+                       WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
+               }
+       }
+
+       if(self.owner.islinked != self.owner.waslinked)
+       {
+               // unteam the spawnpoint if needed
+               int t = self.owner.team;
+               if(!self.owner.islinked)
+                       self.owner.team = 0;
+
+               setself(self.owner);
+               activator = self;
+               SUB_UseTargets ();
+               setself(this);
+
+               self.owner.team = t;
+
+               self.owner.waslinked = self.owner.islinked;
+       }
+
+       // damaged fx
+       if(random() < 0.6 - self.health / self.max_health)
+       {
+               Send_Effect(EFFECT_ELECTRIC_SPARKS, self.origin + randompos('-10 -10 -20', '10 10 20'), '0 0 0', 1);
+
+               if(random() > 0.8)
+                       sound(self, CH_PAIN, SND_ONS_SPARK1, VOL_BASE, ATTEN_NORM);
+               else if (random() > 0.5)
+                       sound(self, CH_PAIN, SND_ONS_SPARK2, VOL_BASE, ATTEN_NORM);
+       }
+}
+
+void ons_ControlPoint_Icon_BuildThink()
+{SELFPARAM();
+       int a;
+
+       self.nextthink = time + ONS_CP_THINKRATE;
+
+       // only do this if there is power
+       a = ons_ControlPoint_CanBeLinked(self.owner, self.owner.team);
+       if(!a)
+               return;
+
+       self.health = self.health + self.count;
+
+       self.SendFlags |= CPSF_STATUS;
+
+       if (self.health >= self.max_health)
+       {
+               self.health = self.max_health;
+               self.count = autocvar_g_onslaught_cp_regen * ONS_CP_THINKRATE; // slow repair rate from now on
+               self.think = ons_ControlPoint_Icon_Think;
+               sound(self, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILT, VOL_BASE, ATTEN_NORM);
+               self.owner.iscaptured = true;
+               self.solid = SOLID_BBOX;
+
+               Send_Effect(EFFECT_CAP(self.owner.team), self.owner.origin, '0 0 0', 1);
+
+               WaypointSprite_UpdateMaxHealth(self.owner.sprite, self.max_health);
+               WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
+
+               if(IS_PLAYER(self.owner.ons_toucher))
+               {
+                       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ONSLAUGHT_CAPTURE, self.owner.ons_toucher.netname, self.owner.message);
+                       Send_Notification(NOTIF_ALL_EXCEPT, self.owner.ons_toucher, MSG_CENTER, APP_TEAM_ENT_4(self.owner.ons_toucher, CENTER_ONS_CAPTURE_), self.owner.message);
+                       Send_Notification(NOTIF_ONE, self.owner.ons_toucher, MSG_CENTER, CENTER_ONS_CAPTURE, self.owner.message);
+                       PlayerScore_Add(self.owner.ons_toucher, SP_ONS_CAPS, 1);
+                       PlayerTeamScore_AddScore(self.owner.ons_toucher, 10);
+               }
+
+               self.owner.ons_toucher = world;
+
+               onslaught_updatelinks();
+
+               // Use targets now (somebody make sure this is in the right place..)
+               setself(self.owner);
+               activator = self;
+               SUB_UseTargets ();
+               setself(this);
+
+               self.SendFlags |= CPSF_SETUP;
+       }
+       if(self.owner.model != MDL_ONS_CP_PAD2.model_str())
+               setmodel_fixsize(self.owner, MDL_ONS_CP_PAD2);
+
+       if(random() < 0.9 - self.health / self.max_health)
+               Send_Effect(EFFECT_RAGE, self.origin + 10 * randomvec(), '0 0 -1', 1);
+}
+
+void onslaught_controlpoint_icon_link(entity e, void() spawnproc);
+
+void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
+{
+       entity e = new(onslaught_controlpoint_icon);
+
+       setsize(e, CPICON_MIN, CPICON_MAX);
+       setorigin(e, cp.origin + CPICON_OFFSET);
+
+       e.owner = cp;
+       e.max_health = autocvar_g_onslaught_cp_health;
+       e.health = autocvar_g_onslaught_cp_buildhealth;
+       e.solid = SOLID_NOT;
+       e.takedamage = DAMAGE_AIM;
+       e.bot_attack = true;
+       e.event_damage = ons_ControlPoint_Icon_Damage;
+       e.team = player.team;
+       e.colormap = 1024 + (e.team - 1) * 17;
+       e.count = (e.max_health - e.health) * ONS_CP_THINKRATE / autocvar_g_onslaught_cp_buildtime; // how long it takes to build
+
+       sound(e, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILD, VOL_BASE, ATTEN_NORM);
+
+       cp.goalentity = e;
+       cp.team = e.team;
+       cp.colormap = e.colormap;
+
+       Send_Effect(EFFECT_FLAG_TOUCH(player.team), e.origin, '0 0 0', 1);
+
+       WaypointSprite_UpdateBuildFinished(cp.sprite, time + (e.max_health - e.health) / (e.count / ONS_CP_THINKRATE));
+       WaypointSprite_UpdateRule(cp.sprite,cp.team,SPRITERULE_TEAMPLAY);
+       cp.sprite.SendFlags |= 16;
+
+       onslaught_controlpoint_icon_link(e, ons_ControlPoint_Icon_BuildThink);
+}
+
+entity ons_ControlPoint_Waypoint(entity e)
+{
+       if(e.team)
+       {
+               int a = ons_ControlPoint_Attackable(e, e.team);
+
+               if(a == -2) { return WP_OnsCPDefend; } // defend now
+               if(a == -1 || a == 1 || a == 2) { return WP_OnsCP; } // touch
+               if(a == 3 || a == 4) { return WP_OnsCPAttack; } // attack
+       }
+       else
+               return WP_OnsCP;
+
+       return WP_Null;
+}
+
+void ons_ControlPoint_UpdateSprite(entity e)
+{
+       entity s1 = ons_ControlPoint_Waypoint(e);
+       WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
+
+       bool sh;
+       sh = !(ons_ControlPoint_CanBeLinked(e, NUM_TEAM_1) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_2) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_3) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_4));
+
+       if(e.lastteam != e.team + 2 || e.lastshielded != sh || e.iscaptured != e.lastcaptured)
+       {
+               if(e.iscaptured) // don't mess up build bars!
+               {
+                       if(sh)
+                       {
+                               WaypointSprite_UpdateMaxHealth(e.sprite, 0);
+                       }
+                       else
+                       {
+                               WaypointSprite_UpdateMaxHealth(e.sprite, e.goalentity.max_health);
+                               WaypointSprite_UpdateHealth(e.sprite, e.goalentity.health);
+                       }
+               }
+               if(e.lastshielded)
+               {
+                       if(e.team)
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, 0.5 * colormapPaletteColor(e.team - 1, false));
+                       else
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.5 0.5 0.5');
+               }
+               else
+               {
+                       if(e.team)
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, colormapPaletteColor(e.team - 1, false));
+                       else
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.75 0.75 0.75');
+               }
+               WaypointSprite_Ping(e.sprite);
+
+               e.lastteam = e.team + 2;
+               e.lastshielded = sh;
+               e.lastcaptured = e.iscaptured;
+       }
+}
+
+void ons_ControlPoint_Touch()
+{SELFPARAM();
+       entity toucher = other;
+       int attackable;
+
+       if(IS_VEHICLE(toucher) && toucher.owner)
+       if(autocvar_g_onslaught_allow_vehicle_touch)
+               toucher = toucher.owner;
+       else
+               return;
+
+       if(!IS_PLAYER(toucher)) { return; }
+       if(toucher.frozen) { return; }
+       if(toucher.deadflag != DEAD_NO) { return; }
+
+       if ( SAME_TEAM(self,toucher) )
+       if ( self.iscaptured )
+       {
+               if(time <= toucher.teleport_antispam)
+                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT_ANTISPAM, rint(toucher.teleport_antispam - time));
+               else
+                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT);
+       }
+
+       attackable = ons_ControlPoint_Attackable(self, toucher.team);
+       if(attackable != 2 && attackable != 4)
+               return;
+       // we've verified that this player has a legitimate claim to this point,
+       // so start building the captured point icon (which only captures this
+       // point if it successfully builds without being destroyed first)
+       ons_ControlPoint_Icon_Spawn(self, toucher);
+
+       self.ons_toucher = toucher;
+
+       onslaught_updatelinks();
+}
+
+void ons_ControlPoint_Think()
+{SELFPARAM();
+       self.nextthink = time + ONS_CP_THINKRATE;
+       CSQCMODEL_AUTOUPDATE(self);
+}
+
+void ons_ControlPoint_Reset()
+{SELFPARAM();
+       if(self.goalentity)
+               remove(self.goalentity);
+
+       self.goalentity = world;
+       self.team = 0;
+       self.colormap = 1024;
+       self.iscaptured = false;
+       self.islinked = false;
+       self.isshielded = true;
+       self.think = ons_ControlPoint_Think;
+       self.ons_toucher = world;
+       self.nextthink = time + ONS_CP_THINKRATE;
+       setmodel_fixsize(self, MDL_ONS_CP_PAD1);
+
+       WaypointSprite_UpdateMaxHealth(self.sprite, 0);
+       WaypointSprite_UpdateRule(self.sprite,self.team,SPRITERULE_TEAMPLAY);
+
+       onslaught_updatelinks();
+
+       activator = self;
+       SUB_UseTargets(); // to reset the structures, playerspawns etc.
+
+       CSQCMODEL_AUTOUPDATE(self);
+}
+
+void ons_DelayedControlPoint_Setup()
+{SELFPARAM();
+       onslaught_updatelinks();
+
+       // captureshield setup
+       ons_CaptureShield_Spawn(self, false);
+
+       CSQCMODEL_AUTOINIT(self);
+}
+
+void ons_ControlPoint_Setup(entity cp)
+{SELFPARAM();
+       // declarations
+       setself(cp); // for later usage with droptofloor()
+
+       // main setup
+       cp.ons_worldcpnext = ons_worldcplist; // link control point into ons_worldcplist
+       ons_worldcplist = cp;
+
+       cp.netname = "Control point";
+       cp.team = 0;
+       cp.solid = SOLID_BBOX;
+       cp.movetype = MOVETYPE_NONE;
+       cp.touch = ons_ControlPoint_Touch;
+       cp.think = ons_ControlPoint_Think;
+       cp.nextthink = time + ONS_CP_THINKRATE;
+       cp.reset = ons_ControlPoint_Reset;
+       cp.colormap = 1024;
+       cp.iscaptured = false;
+       cp.islinked = false;
+       cp.isshielded = true;
+
+       if(cp.message == "") { cp.message = "a"; }
+
+       // appearence
+       setmodel_fixsize(cp, MDL_ONS_CP_PAD1);
+
+       // control point placement
+       if((cp.spawnflags & 1) || cp.noalign) // don't drop to floor, just stay at fixed location
+       {
+               cp.noalign = true;
+               cp.movetype = MOVETYPE_NONE;
+       }
+       else // drop to floor, automatically find a platform and set that as spawn origin
+       {
+               setorigin(cp, cp.origin + '0 0 20');
+               cp.noalign = false;
+               setself(cp);
+               droptofloor();
+               cp.movetype = MOVETYPE_TOSS;
+       }
+
+       // waypointsprites
+       WaypointSprite_SpawnFixed(WP_Null, self.origin + CPGEN_WAYPOINT_OFFSET, self, sprite, RADARICON_NONE);
+       WaypointSprite_UpdateRule(self.sprite, self.team, SPRITERULE_TEAMPLAY);
+
+       InitializeEntity(cp, ons_DelayedControlPoint_Setup, INITPRIO_SETLOCATION);
+}
+
+
+// =========================
+// Main Generator Functions
+// =========================
+
+entity ons_Generator_Waypoint(entity e)
+{
+       if (e.isshielded)
+               return WP_OnsGenShielded;
+       return WP_OnsGen;
+}
+
+void ons_Generator_UpdateSprite(entity e)
+{
+       entity s1 = ons_Generator_Waypoint(e);
+       WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
+
+       if(e.lastteam != e.team + 2 || e.lastshielded != e.isshielded)
+       {
+               e.lastteam = e.team + 2;
+               e.lastshielded = e.isshielded;
+               if(e.lastshielded)
+               {
+                       if(e.team)
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, 0.5 * colormapPaletteColor(e.team - 1, false));
+                       else
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.5 0.5 0.5');
+               }
+               else
+               {
+                       if(e.team)
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, colormapPaletteColor(e.team - 1, false));
+                       else
+                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.75 0.75 0.75');
+               }
+               WaypointSprite_Ping(e.sprite);
+       }
+}
+
+void ons_GeneratorDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{SELFPARAM();
+       if(damage <= 0) { return; }
+       if(warmup_stage || gameover) { return; }
+       if(!round_handler_IsRoundStarted()) { return; }
+
+       if (attacker != self)
+       {
+               if (self.isshielded)
+               {
+                       // this is protected by a shield, so ignore the damage
+                       if (time > self.pain_finished)
+                               if (IS_PLAYER(attacker))
+                               {
+                                       play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
+                                       attacker.typehitsound += 1;
+                                       self.pain_finished = time + 1;
+                               }
+                       return;
+               }
+               if (time > self.pain_finished)
+               {
+                       self.pain_finished = time + 10;
+                       entity head;
+                       FOR_EACH_REALPLAYER(head) if(SAME_TEAM(head, self)) { Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_GENERATOR_UNDERATTACK); }
+                       play2team(self.team, SND(ONS_GENERATOR_UNDERATTACK));
+               }
+       }
+       self.health = self.health - damage;
+       WaypointSprite_UpdateHealth(self.sprite, self.health);
+       // choose an animation frame based on health
+       self.frame = 10 * bound(0, (1 - self.health / self.max_health), 1);
+       // see if the generator is still functional, or dying
+       if (self.health > 0)
+       {
+               self.lasthealth = self.health;
+       }
+       else
+       {
+               if (attacker == self)
+                       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_GENDESTROYED_OVERTIME_));
+               else
+               {
+                       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_GENDESTROYED_));
+                       PlayerScore_Add(attacker, SP_SCORE, 100);
+               }
+               self.iscaptured = false;
+               self.islinked = false;
+               self.isshielded = false;
+               self.takedamage = DAMAGE_NO; // can't be hurt anymore
+               self.event_damage = func_null; // won't do anything if hurt
+               self.count = 0; // reset counter
+               self.think = func_null;
+               self.nextthink = 0;
+               //self.think(); // do the first explosion now
+
+               WaypointSprite_UpdateMaxHealth(self.sprite, 0);
+               WaypointSprite_Ping(self.sprite);
+               //WaypointSprite_Kill(self.sprite); // can't do this yet, code too poor
+
+               onslaught_updatelinks();
+       }
+
+       // Throw some flaming gibs on damage, more damage = more chance for gib
+       if(random() < damage/220)
+       {
+               sound(self, CH_TRIGGER, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+       }
+       else
+       {
+               // particles on every hit
+               Send_Effect(EFFECT_SPARKS, hitloc, force * -1, 1);
+
+               //sound on every hit
+               if (random() < 0.5)
+                       sound(self, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE, ATTEN_NORM);
+               else
+                       sound(self, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE, ATTEN_NORM);
+       }
+
+       self.SendFlags |= GSF_STATUS;
+}
+
+void ons_GeneratorThink()
+{SELFPARAM();
+       entity e;
+       self.nextthink = time + GEN_THINKRATE;
+       if (!gameover)
+       {
+        if(!self.isshielded && self.wait < time)
+        {
+            self.wait = time + 5;
+            FOR_EACH_REALPLAYER(e)
+            {
+                               if(SAME_TEAM(e, self))
+                               {
+                                       Send_Notification(NOTIF_ONE, e, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM);
+                    soundto(MSG_ONE, e, CHAN_AUTO, SND(KH_ALARM), VOL_BASE, ATTEN_NONE);    // FIXME: unique sound?
+                }
+                               else
+                                       Send_Notification(NOTIF_ONE, e, MSG_CENTER, APP_TEAM_NUM_4(self.team, CENTER_ONS_NOTSHIELDED_));
+            }
+        }
+       }
+}
+
+void ons_GeneratorReset()
+{SELFPARAM();
+       self.team = self.team_saved;
+       self.lasthealth = self.max_health = self.health = autocvar_g_onslaught_gen_health;
+       self.takedamage = DAMAGE_AIM;
+       self.bot_attack = true;
+       self.iscaptured = true;
+       self.islinked = true;
+       self.isshielded = true;
+       self.event_damage = ons_GeneratorDamage;
+       self.think = ons_GeneratorThink;
+       self.nextthink = time + GEN_THINKRATE;
+
+       Net_LinkEntity(self, false, 0, generator_send);
+
+       self.SendFlags = GSF_SETUP; // just incase
+       self.SendFlags |= GSF_STATUS;
+
+       WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
+       WaypointSprite_UpdateHealth(self.sprite, self.health);
+       WaypointSprite_UpdateRule(self.sprite,self.team,SPRITERULE_TEAMPLAY);
+
+       onslaught_updatelinks();
+}
+
+void ons_DelayedGeneratorSetup()
+{SELFPARAM();
+       // bot waypoints
+       waypoint_spawnforitem_force(self, self.origin);
+       self.nearestwaypointtimeout = 0; // activate waypointing again
+       self.bot_basewaypoint = self.nearestwaypoint;
+
+       // captureshield setup
+       ons_CaptureShield_Spawn(self, true);
+
+       onslaught_updatelinks();
+
+       Net_LinkEntity(self, false, 0, generator_send);
+}
+
+
+void onslaught_generator_touch()
+{SELFPARAM();
+       if ( IS_PLAYER(other) )
+       if ( SAME_TEAM(self,other) )
+       if ( self.iscaptured )
+       {
+               Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_TELEPORT);
+       }
+}
+
+void ons_GeneratorSetup(entity gen) // called when spawning a generator entity on the map as a spawnfunc
+{SELFPARAM();
+       // declarations
+       int teamnumber = gen.team;
+       setself(gen); // for later usage with droptofloor()
+
+       // main setup
+       gen.ons_worldgeneratornext = ons_worldgeneratorlist; // link generator into ons_worldgeneratorlist
+       ons_worldgeneratorlist = gen;
+
+       gen.netname = sprintf("%s generator", Team_ColoredFullName(teamnumber));
+       gen.classname = "onslaught_generator";
+       gen.solid = SOLID_BBOX;
+       gen.team_saved = teamnumber;
+       gen.movetype = MOVETYPE_NONE;
+       gen.lasthealth = gen.max_health = gen.health = autocvar_g_onslaught_gen_health;
+       gen.takedamage = DAMAGE_AIM;
+       gen.bot_attack = true;
+       gen.event_damage = ons_GeneratorDamage;
+       gen.reset = ons_GeneratorReset;
+       gen.think = ons_GeneratorThink;
+       gen.nextthink = time + GEN_THINKRATE;
+       gen.iscaptured = true;
+       gen.islinked = true;
+       gen.isshielded = true;
+       gen.touch = onslaught_generator_touch;
+
+       // appearence
+       // model handled by CSQC
+       setsize(gen, GENERATOR_MIN, GENERATOR_MAX);
+       setorigin(gen, (gen.origin + CPGEN_SPAWN_OFFSET));
+       gen.colormap = 1024 + (teamnumber - 1) * 17;
+
+       // generator placement
+       setself(gen);
+       droptofloor();
+
+       // waypointsprites
+       WaypointSprite_SpawnFixed(WP_Null, self.origin + CPGEN_WAYPOINT_OFFSET, self, sprite, RADARICON_NONE);
+       WaypointSprite_UpdateRule(self.sprite, self.team, SPRITERULE_TEAMPLAY);
+       WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
+       WaypointSprite_UpdateHealth(self.sprite, self.health);
+
+       InitializeEntity(gen, ons_DelayedGeneratorSetup, INITPRIO_SETLOCATION);
+}
+
+
+// ===============
+//  Round Handler
+// ===============
+
+int total_generators;
+void Onslaught_count_generators()
+{
+       entity e;
+       total_generators = redowned = blueowned = yellowowned = pinkowned = 0;
+       for(e = ons_worldgeneratorlist; e; e = e.ons_worldgeneratornext)
+       {
+               ++total_generators;
+               redowned += (e.team == NUM_TEAM_1 && e.health > 0);
+               blueowned += (e.team == NUM_TEAM_2 && e.health > 0);
+               yellowowned += (e.team == NUM_TEAM_3 && e.health > 0);
+               pinkowned += (e.team == NUM_TEAM_4 && e.health > 0);
+       }
+}
+
+int Onslaught_GetWinnerTeam()
+{
+       int winner_team = 0;
+       if(redowned > 0)
+               winner_team = NUM_TEAM_1;
+       if(blueowned > 0)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_2;
+       }
+       if(yellowowned > 0)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_3;
+       }
+       if(pinkowned > 0)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_4;
+       }
+       if(winner_team)
+               return winner_team;
+       return -1; // no generators left?
+}
+
+void nades_Clear(entity e);
+
+#define ONS_OWNED_GENERATORS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
+#define ONS_OWNED_GENERATORS_OK() (ONS_OWNED_GENERATORS() > 1)
+bool Onslaught_CheckWinner()
+{
+       entity e;
+
+       if ((autocvar_timelimit && time > game_starttime + autocvar_timelimit * 60) || (round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0))
+       {
+               ons_stalemate = true;
+
+               if (!wpforenemy_announced)
+               {
+                       Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT);
+                       sound(world, CH_INFO, SND_ONS_GENERATOR_DECAY, VOL_BASE, ATTEN_NONE);
+
+                       wpforenemy_announced = true;
+               }
+
+               entity tmp_entity; // temporary entity
+               float d;
+               for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext) if(time >= tmp_entity.ons_overtime_damagedelay)
+               {
+                       // tmp_entity.max_health / 300 gives 5 minutes of overtime.
+                       // control points reduce the overtime duration.
+                       d = 1;
+                       for(e = ons_worldcplist; e; e = e.ons_worldcpnext)
+                       {
+                               if(DIFF_TEAM(e, tmp_entity))
+                               if(e.islinked)
+                                       d = d + 1;
+                       }
+
+                       if(autocvar_g_campaign && autocvar__campaign_testrun)
+                               d = d * tmp_entity.max_health;
+                       else
+                               d = d * tmp_entity.max_health / max(30, 60 * autocvar_timelimit_suddendeath);
+
+                       Damage(tmp_entity, tmp_entity, tmp_entity, d, DEATH_HURTTRIGGER.m_id, tmp_entity.origin, '0 0 0');
+
+                       tmp_entity.sprite.SendFlags |= 16;
+
+                       tmp_entity.ons_overtime_damagedelay = time + 1;
+               }
+       }
+       else { wpforenemy_announced = false; ons_stalemate = false; }
+
+       Onslaught_count_generators();
+
+       if(ONS_OWNED_GENERATORS_OK())
+               return 0;
+
+       int winner_team = Onslaught_GetWinnerTeam();
+
+       if(winner_team > 0)
+       {
+               Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM_4(winner_team, CENTER_ROUND_TEAM_WIN_));
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(winner_team, INFO_ROUND_TEAM_WIN_));
+               TeamScore_AddToTeam(winner_team, ST_ONS_CAPS, +1);
+       }
+       else if(winner_team == -1)
+       {
+               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED);
+       }
+
+       ons_stalemate = false;
+
+       play2all(SND(CTF_CAPTURE(winner_team)));
+
+       round_handler_Init(7, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
+
+       FOR_EACH_PLAYER(e)
+       {
+               e.ons_roundlost = true;
+               e.player_blocked = true;
+
+               nades_Clear(e);
+       }
+
+       return 1;
+}
+
+bool Onslaught_CheckPlayers()
+{
+       return 1;
+}
+
+void Onslaught_RoundStart()
+{
+       entity tmp_entity;
+       FOR_EACH_PLAYER(tmp_entity) { tmp_entity.player_blocked = false; }
+
+       for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
+               tmp_entity.sprite.SendFlags |= 16;
+
+       for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
+               tmp_entity.sprite.SendFlags |= 16;
+}
+
+
+// ================
+// Bot player logic
+// ================
+
+// NOTE: LEGACY CODE, needs to be re-written!
+
+void havocbot_goalrating_ons_offenseitems(float ratingscale, vector org, float sradius)
+{SELFPARAM();
+       entity head;
+       float t, c;
+       int i;
+       bool needarmor = false, needweapons = false;
+
+       // Needs armor/health?
+       if(self.health<100)
+               needarmor = true;
+
+       // Needs weapons?
+       c = 0;
+       for(i = WEP_FIRST; i <= WEP_LAST ; ++i)
+       {
+               // Find weapon
+               if(self.weapons & WepSet_FromWeapon(i))
+               if(++c>=4)
+                       break;
+       }
+
+       if(c<4)
+               needweapons = true;
+
+       if(!needweapons && !needarmor)
+               return;
+
+       ons_debug(strcat(self.netname, " needs weapons ", ftos(needweapons) , "\n"));
+       ons_debug(strcat(self.netname, " needs armor ", ftos(needarmor) , "\n"));
+
+       // See what is around
+       head = findchainfloat(bot_pickup, true);
+       while (head)
+       {
+               // gather health and armor only
+               if (head.solid)
+               if ( ((head.health || head.armorvalue) && needarmor) || (head.weapons && needweapons ) )
+               if (vlen(head.origin - org) < sradius)
+               {
+                       t = head.bot_pickupevalfunc(self, head);
+                       if (t > 0)
+                               navigation_routerating(head, t * ratingscale, 500);
+               }
+               head = head.chain;
+       }
+}
+
+void havocbot_role_ons_setrole(entity bot, int role)
+{
+       ons_debug(strcat(bot.netname," switched to "));
+       switch(role)
+       {
+               case HAVOCBOT_ONS_ROLE_DEFENSE:
+                       ons_debug("defense");
+                       bot.havocbot_role = havocbot_role_ons_defense;
+                       bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
+                       bot.havocbot_role_timeout = 0;
+                       break;
+               case HAVOCBOT_ONS_ROLE_ASSISTANT:
+                       ons_debug("assistant");
+                       bot.havocbot_role = havocbot_role_ons_assistant;
+                       bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
+                       bot.havocbot_role_timeout = 0;
+                       break;
+               case HAVOCBOT_ONS_ROLE_OFFENSE:
+                       ons_debug("offense");
+                       bot.havocbot_role = havocbot_role_ons_offense;
+                       bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
+                       bot.havocbot_role_timeout = 0;
+                       break;
+       }
+       ons_debug("\n");
+}
+
+int havocbot_ons_teamcount(entity bot, int role)
+{SELFPARAM();
+       int c = 0;
+       entity head;
+
+       FOR_EACH_PLAYER(head)
+       if(SAME_TEAM(head, self))
+       if(head.havocbot_role_flags & role)
+               ++c;
+
+       return c;
+}
+
+void havocbot_goalrating_ons_controlpoints_attack(float ratingscale)
+{SELFPARAM();
+       entity cp, cp1, cp2, best, pl, wp;
+       float radius, bestvalue;
+       int c;
+       bool found;
+
+       // Filter control points
+       for(cp2 = ons_worldcplist; cp2; cp2 = cp2.ons_worldcpnext)
+       {
+               cp2.wpcost = c = 0;
+               cp2.wpconsidered = false;
+
+               if(cp2.isshielded)
+                       continue;
+
+               // Ignore owned controlpoints
+               if(!(cp2.isgenneighbor[self.team] || cp2.iscpneighbor[self.team]))
+                       continue;
+
+               // Count team mates interested in this control point
+               // (easier and cleaner than keeping counters per cp and teams)
+               FOR_EACH_PLAYER(pl)
+               if(SAME_TEAM(pl, self))
+               if(pl.havocbot_role_flags & HAVOCBOT_ONS_ROLE_OFFENSE)
+               if(pl.havocbot_ons_target==cp2)
+                       ++c;
+
+               // NOTE: probably decrease the cost of attackable control points
+               cp2.wpcost = c;
+               cp2.wpconsidered = true;
+       }
+
+       // We'll consider only the best case
+       bestvalue = 99999999999;
+       cp = world;
+       for(cp1 = ons_worldcplist; cp1; cp1 = cp1.ons_worldcpnext)
+       {
+               if (!cp1.wpconsidered)
+                       continue;
+
+               if(cp1.wpcost<bestvalue)
+               {
+                       bestvalue = cp1.wpcost;
+                       cp = cp1;
+                       self.havocbot_ons_target = cp1;
+               }
+       }
+
+       if (!cp)
+               return;
+
+       ons_debug(strcat(self.netname, " chose cp ranked ", ftos(bestvalue), "\n"));
+
+       if(cp.goalentity)
+       {
+               // Should be attacked
+               // Rate waypoints near it
+               found = false;
+               best = world;
+               bestvalue = 99999999999;
+               for(radius=0; radius<1000 && !found; radius+=500)
+               {
+                       for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
+                       {
+                               if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
+                               if(wp.classname=="waypoint")
+                               if(checkpvs(wp.origin,cp))
+                               {
+                                       found = true;
+                                       if(wp.cnt<bestvalue)
+                                       {
+                                               best = wp;
+                                               bestvalue = wp.cnt;
+                                       }
+                               }
+                       }
+               }
+
+               if(best)
+               {
+                       navigation_routerating(best, ratingscale, 10000);
+                       best.cnt += 1;
+
+                       self.havocbot_attack_time = 0;
+                       if(checkpvs(self.view_ofs,cp))
+                       if(checkpvs(self.view_ofs,best))
+                               self.havocbot_attack_time = time + 2;
+               }
+               else
+               {
+                       navigation_routerating(cp, ratingscale, 10000);
+               }
+               ons_debug(strcat(self.netname, " found an attackable controlpoint at ", vtos(cp.origin) ,"\n"));
+       }
+       else
+       {
+               // Should be touched
+               ons_debug(strcat(self.netname, " found a touchable controlpoint at ", vtos(cp.origin) ,"\n"));
+               found = false;
+
+               // Look for auto generated waypoint
+               if (!bot_waypoints_for_items)
+               for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
+               {
+                       if(wp.classname=="waypoint")
+                       {
+                               navigation_routerating(wp, ratingscale, 10000);
+                               found = true;
+                       }
+               }
+
+               // Nothing found, rate the controlpoint itself
+               if (!found)
+                       navigation_routerating(cp, ratingscale, 10000);
+       }
+}
+
+bool havocbot_goalrating_ons_generator_attack(float ratingscale)
+{SELFPARAM();
+       entity g, wp, bestwp;
+       bool found;
+       int best;
+
+       for(g = ons_worldgeneratorlist; g; g = g.ons_worldgeneratornext)
+       {
+               if(SAME_TEAM(g, self) || g.isshielded)
+                       continue;
+
+               // Should be attacked
+               // Rate waypoints near it
+               found = false;
+               bestwp = world;
+               best = 99999999999;
+
+               for(wp=findradius(g.origin,400); wp; wp=wp.chain)
+               {
+                       if(wp.classname=="waypoint")
+                       if(checkpvs(wp.origin,g))
+                       {
+                               found = true;
+                               if(wp.cnt<best)
+                               {
+                                       bestwp = wp;
+                                       best = wp.cnt;
+                               }
+                       }
+               }
+
+               if(bestwp)
+               {
+                       ons_debug("waypoints found around generator\n");
+                       navigation_routerating(bestwp, ratingscale, 10000);
+                       bestwp.cnt += 1;
+
+                       self.havocbot_attack_time = 0;
+                       if(checkpvs(self.view_ofs,g))
+                       if(checkpvs(self.view_ofs,bestwp))
+                               self.havocbot_attack_time = time + 5;
+
+                       return true;
+               }
+               else
+               {
+                       ons_debug("generator found without waypoints around\n");
+                       // if there aren't waypoints near the generator go straight to it
+                       navigation_routerating(g, ratingscale, 10000);
+                       self.havocbot_attack_time = 0;
+                       return true;
+               }
+       }
+       return false;
+}
+
+void havocbot_role_ons_offense()
+{SELFPARAM();
+       if(self.deadflag != DEAD_NO)
+       {
+               self.havocbot_attack_time = 0;
+               havocbot_ons_reset_role(self);
+               return;
+       }
+
+       // Set the role timeout if necessary
+       if (!self.havocbot_role_timeout)
+               self.havocbot_role_timeout = time + 120;
+
+       if (time > self.havocbot_role_timeout)
+       {
+               havocbot_ons_reset_role(self);
+               return;
+       }
+
+       if(self.havocbot_attack_time>time)
+               return;
+
+       if (self.bot_strategytime < time)
+       {
+               navigation_goalrating_start();
+               havocbot_goalrating_enemyplayers(20000, self.origin, 650);
+               if(!havocbot_goalrating_ons_generator_attack(20000))
+                       havocbot_goalrating_ons_controlpoints_attack(20000);
+               havocbot_goalrating_ons_offenseitems(10000, self.origin, 10000);
+               navigation_goalrating_end();
+
+               self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+       }
+}
+
+void havocbot_role_ons_assistant()
+{SELFPARAM();
+       havocbot_ons_reset_role(self);
+}
+
+void havocbot_role_ons_defense()
+{SELFPARAM();
+       havocbot_ons_reset_role(self);
+}
+
+void havocbot_ons_reset_role(entity bot)
+{SELFPARAM();
+       entity head;
+       int c = 0;
+
+       if(self.deadflag != DEAD_NO)
+               return;
+
+       bot.havocbot_ons_target = world;
+
+       // TODO: Defend control points or generator if necessary
+
+       // if there is only me on the team switch to offense
+       c = 0;
+       FOR_EACH_PLAYER(head)
+       if(SAME_TEAM(head, self))
+               ++c;
+
+       if(c==1)
+       {
+               havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
+               return;
+       }
+
+       havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
+}
+
+
+/*
+ * Find control point or generator owned by the same team self which is nearest to pos
+ * if max_dist is positive, only control points within this range will be considered
+ */
+entity ons_Nearest_ControlPoint(vector pos, float max_dist)
+{SELFPARAM();
+       entity tmp_entity, closest_target = world;
+       tmp_entity = findchain(classname, "onslaught_controlpoint");
+       while(tmp_entity)
+       {
+               if(SAME_TEAM(tmp_entity, self))
+               if(tmp_entity.iscaptured)
+               if(max_dist <= 0 || vlen(tmp_entity.origin - pos) <= max_dist)
+               if(vlen(tmp_entity.origin - pos) <= vlen(closest_target.origin - pos) || closest_target == world)
+                       closest_target = tmp_entity;
+               tmp_entity = tmp_entity.chain;
+       }
+       tmp_entity = findchain(classname, "onslaught_generator");
+       while(tmp_entity)
+       {
+               if(SAME_TEAM(tmp_entity, self))
+               if(max_dist <= 0 || vlen(tmp_entity.origin - pos) < max_dist)
+               if(vlen(tmp_entity.origin - pos) <= vlen(closest_target.origin - pos) || closest_target == world)
+                       closest_target = tmp_entity;
+               tmp_entity = tmp_entity.chain;
+       }
+
+       return closest_target;
+}
+
+/*
+ * Find control point or generator owned by the same team self which is nearest to pos
+ * if max_dist is positive, only control points within this range will be considered
+ * This function only check distances on the XY plane, disregarding Z
+ */
+entity ons_Nearest_ControlPoint_2D(vector pos, float max_dist)
+{SELFPARAM();
+       entity tmp_entity, closest_target = world;
+       vector delta;
+       float smallest_distance = 0, distance;
+
+       tmp_entity = findchain(classname, "onslaught_controlpoint");
+       while(tmp_entity)
+       {
+               delta = tmp_entity.origin - pos;
+               delta_z = 0;
+               distance = vlen(delta);
+
+               if(SAME_TEAM(tmp_entity, self))
+               if(tmp_entity.iscaptured)
+               if(max_dist <= 0 || distance <= max_dist)
+               if(closest_target == world || distance <= smallest_distance )
+               {
+                       closest_target = tmp_entity;
+                       smallest_distance = distance;
+               }
+
+               tmp_entity = tmp_entity.chain;
+       }
+       tmp_entity = findchain(classname, "onslaught_generator");
+       while(tmp_entity)
+       {
+               delta = tmp_entity.origin - pos;
+               delta_z = 0;
+               distance = vlen(delta);
+
+               if(SAME_TEAM(tmp_entity, self))
+               if(max_dist <= 0 || distance <= max_dist)
+               if(closest_target == world || distance <= smallest_distance )
+               {
+                       closest_target = tmp_entity;
+                       smallest_distance = distance;
+               }
+
+               tmp_entity = tmp_entity.chain;
+       }
+
+       return closest_target;
+}
+/**
+ * find the number of control points and generators in the same team as self
+ */
+int ons_Count_SelfControlPoints()
+{SELFPARAM();
+       entity tmp_entity;
+       tmp_entity = findchain(classname, "onslaught_controlpoint");
+       int n = 0;
+       while(tmp_entity)
+       {
+               if(SAME_TEAM(tmp_entity, self))
+               if(tmp_entity.iscaptured)
+                       n++;
+               tmp_entity = tmp_entity.chain;
+       }
+       tmp_entity = findchain(classname, "onslaught_generator");
+       while(tmp_entity)
+       {
+               if(SAME_TEAM(tmp_entity, self))
+                       n++;
+               tmp_entity = tmp_entity.chain;
+       }
+       return n;
+}
+
+/**
+ * Teleport player to a random position near tele_target
+ * if tele_effects is true, teleport sound+particles are created
+ * return false on failure
+ */
+bool ons_Teleport(entity player, entity tele_target, float range, bool tele_effects)
+{
+       if ( !tele_target )
+               return false;
+
+       int i;
+       vector loc;
+       float theta;
+       // narrow the range for each iteration to increase chances that a spawnpoint
+       // can be found even if there's little room around the control point
+       float iteration_scale = 1;
+       for(i = 0; i < 16; ++i)
+       {
+               iteration_scale -= i / 16;
+               theta = random() * 2 * M_PI;
+               loc_y = sin(theta);
+               loc_x = cos(theta);
+               loc_z = 0;
+               loc *= random() * range * iteration_scale;
+
+               loc += tele_target.origin + '0 0 128' * iteration_scale;
+
+               tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, player);
+               if(trace_fraction == 1.0 && !trace_startsolid)
+               {
+                       traceline(tele_target.origin, loc, MOVE_NOMONSTERS, tele_target); // double check to make sure we're not spawning outside the world
+                       if(trace_fraction == 1.0 && !trace_startsolid)
+                       {
+                               if ( tele_effects )
+                               {
+                                       Send_Effect(EFFECT_TELEPORT, player.origin, '0 0 0', 1);
+                                       sound (player, CH_TRIGGER, SND_TELEPORT, VOL_BASE, ATTEN_NORM);
+                               }
+                               setorigin(player, loc);
+                               player.angles = '0 1 0' * ( theta * RAD2DEG + 180 );
+                               makevectors(player.angles);
+                               player.fixangle = true;
+                               player.teleport_antispam = time + autocvar_g_onslaught_teleport_wait;
+
+                               if ( tele_effects )
+                                       Send_Effect(EFFECT_TELEPORT, player.origin + v_forward * 32, '0 0 0', 1);
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+// ==============
+// Hook Functions
+// ==============
+
+MUTATOR_HOOKFUNCTION(ons, reset_map_global)
+{SELFPARAM();
+       entity e;
+       FOR_EACH_PLAYER(e)
+       {
+               e.ons_roundlost = false;
+               e.ons_deathloc = '0 0 0';
+               WITH(entity, self, e, PutClientInServer());
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, ClientDisconnect)
+{SELFPARAM();
+       self.ons_deathloc = '0 0 0';
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, MakePlayerObserver)
+{SELFPARAM();
+       self.ons_deathloc = '0 0 0';
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayerSpawn)
+{SELFPARAM();
+       if(!round_handler_IsRoundStarted())
+       {
+               self.player_blocked = true;
+               return false;
+       }
+
+       entity l;
+       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+       {
+               l.sprite.SendFlags |= 16;
+       }
+       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+       {
+               l.sprite.SendFlags |= 16;
+       }
+
+       if(ons_stalemate) { Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT); }
+
+       if ( autocvar_g_onslaught_spawn_choose )
+       if ( self.ons_spawn_by )
+       if ( ons_Teleport(self,self.ons_spawn_by,autocvar_g_onslaught_teleport_radius,false) )
+       {
+               self.ons_spawn_by = world;
+               return false;
+       }
+
+       if(autocvar_g_onslaught_spawn_at_controlpoints)
+       if(random() <= autocvar_g_onslaught_spawn_at_controlpoints_chance)
+       {
+               float random_target = autocvar_g_onslaught_spawn_at_controlpoints_random;
+               entity tmp_entity, closest_target = world;
+               vector spawn_loc = self.ons_deathloc;
+
+               // new joining player or round reset, don't bother checking
+               if(spawn_loc == '0 0 0') { return false; }
+
+               if(random_target) { RandomSelection_Init(); }
+
+               for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
+               {
+                       if(SAME_TEAM(tmp_entity, self))
+                       if(random_target)
+                               RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
+                       else if(vlen(tmp_entity.origin - spawn_loc) <= vlen(closest_target.origin - spawn_loc) || closest_target == world)
+                               closest_target = tmp_entity;
+               }
+
+               if(random_target) { closest_target = RandomSelection_chosen_ent; }
+
+               if(closest_target)
+               {
+                       float i;
+                       vector loc;
+                       float iteration_scale = 1;
+                       for(i = 0; i < 10; ++i)
+                       {
+                               iteration_scale -= i / 10;
+                               loc = closest_target.origin + '0 0 96' * iteration_scale;
+                               loc += ('0 1 0' * random()) * 128 * iteration_scale;
+                               tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, self);
+                               if(trace_fraction == 1.0 && !trace_startsolid)
+                               {
+                                       traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the world
+                                       if(trace_fraction == 1.0 && !trace_startsolid)
+                                       {
+                                               setorigin(self, loc);
+                                               self.angles = normalize(loc - closest_target.origin) * RAD2DEG;
+                                               return false;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if(autocvar_g_onslaught_spawn_at_generator)
+       if(random() <= autocvar_g_onslaught_spawn_at_generator_chance)
+       {
+               float random_target = autocvar_g_onslaught_spawn_at_generator_random;
+               entity tmp_entity, closest_target = world;
+               vector spawn_loc = self.ons_deathloc;
+
+               // new joining player or round reset, don't bother checking
+               if(spawn_loc == '0 0 0') { return false; }
+
+               if(random_target) { RandomSelection_Init(); }
+
+               for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
+               {
+                       if(random_target)
+                               RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
+                       else
+                       {
+                               if(SAME_TEAM(tmp_entity, self))
+                               if(vlen(tmp_entity.origin - spawn_loc) <= vlen(closest_target.origin - spawn_loc) || closest_target == world)
+                                       closest_target = tmp_entity;
+                       }
+               }
+
+               if(random_target) { closest_target = RandomSelection_chosen_ent; }
+
+               if(closest_target)
+               {
+                       float i;
+                       vector loc;
+                       float iteration_scale = 1;
+                       for(i = 0; i < 10; ++i)
+                       {
+                               iteration_scale -= i / 10;
+                               loc = closest_target.origin + '0 0 128' * iteration_scale;
+                               loc += ('0 1 0' * random()) * 256 * iteration_scale;
+                               tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, self);
+                               if(trace_fraction == 1.0 && !trace_startsolid)
+                               {
+                                       traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the world
+                                       if(trace_fraction == 1.0 && !trace_startsolid)
+                                       {
+                                               setorigin(self, loc);
+                                               self.angles = normalize(loc - closest_target.origin) * RAD2DEG;
+                                               return false;
+                                       }
+                               }
+                       }
+               }
+       }
+
+    return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayerDies)
+{SELFPARAM();
+       frag_target.ons_deathloc = frag_target.origin;
+       entity l;
+       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
+       {
+               l.sprite.SendFlags |= 16;
+       }
+       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
+       {
+               l.sprite.SendFlags |= 16;
+       }
+
+       if ( autocvar_g_onslaught_spawn_choose )
+       if ( ons_Count_SelfControlPoints() > 1 )
+               stuffcmd(self, "qc_cmd_cl hud clickradar\n");
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, MonsterMove)
+{SELFPARAM();
+       entity e = find(world, targetname, self.target);
+       if (e != world)
+               self.team = e.team;
+
+       return false;
+}
+
+void ons_MonsterSpawn_Delayed()
+{SELFPARAM();
+       entity e, own = self.owner;
+
+       if(!own) { remove(self); return; }
+
+       if(own.targetname)
+       {
+               e = find(world, target, own.targetname);
+               if(e != world)
+               {
+                       own.team = e.team;
+
+                       activator = e;
+                       own.use();
+               }
+       }
+
+       remove(self);
+}
+
+MUTATOR_HOOKFUNCTION(ons, MonsterSpawn)
+{SELFPARAM();
+       entity e = spawn();
+       e.owner = self;
+       InitializeEntity(e, ons_MonsterSpawn_Delayed, INITPRIO_FINDTARGET);
+
+       return false;
+}
+
+void ons_TurretSpawn_Delayed()
+{SELFPARAM();
+       entity e, own = self.owner;
+
+       if(!own) { remove(self); return; }
+
+       if(own.targetname)
+       {
+               e = find(world, target, own.targetname);
+               if(e != world)
+               {
+                       own.team = e.team;
+                       own.active = ACTIVE_NOT;
+
+                       activator = e;
+                       own.use();
+               }
+       }
+
+       remove(self);
+}
+
+MUTATOR_HOOKFUNCTION(ons, TurretSpawn)
+{SELFPARAM();
+       entity e = spawn();
+       e.owner = self;
+       InitializeEntity(e, ons_TurretSpawn_Delayed, INITPRIO_FINDTARGET);
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, HavocBot_ChooseRole)
+{SELFPARAM();
+       havocbot_ons_reset_role(self);
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ons, GetTeamCount)
+{
+       // onslaught is special
+       for(entity tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
+       {
+               switch(tmp_entity.team)
+               {
+                       case NUM_TEAM_1: c1 = 0; break;
+                       case NUM_TEAM_2: c2 = 0; break;
+                       case NUM_TEAM_3: c3 = 0; break;
+                       case NUM_TEAM_4: c4 = 0; break;
+               }
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ons, SpectateCopy)
+{SELFPARAM();
+       self.ons_roundlost = other.ons_roundlost; // make spectators see it too
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, SV_ParseClientCommand)
+{SELFPARAM();
+       if(MUTATOR_RETURNVALUE) // command was already handled?
+               return false;
+
+       if ( cmd_name == "ons_spawn" )
+       {
+               vector pos = self.origin;
+               if(cmd_argc > 1)
+                       pos_x = stof(argv(1));
+               if(cmd_argc > 2)
+                       pos_y = stof(argv(2));
+               if(cmd_argc > 3)
+                       pos_z = stof(argv(3));
+
+               if ( IS_PLAYER(self) )
+               {
+                       if ( !self.frozen )
+                       {
+                               entity source_point = ons_Nearest_ControlPoint(self.origin, autocvar_g_onslaught_teleport_radius);
+
+                               if ( !source_point && self.health > 0 )
+                               {
+                                       sprint(self, "\nYou need to be next to a control point\n");
+                                       return 1;
+                               }
+
+
+                               entity closest_target = ons_Nearest_ControlPoint_2D(pos, autocvar_g_onslaught_click_radius);
+
+                               if ( closest_target == world )
+                               {
+                                       sprint(self, "\nNo control point found\n");
+                                       return 1;
+                               }
+
+                               if ( self.health <= 0 )
+                               {
+                                       self.ons_spawn_by = closest_target;
+                                       self.respawn_flags = self.respawn_flags | RESPAWN_FORCE;
+                               }
+                               else
+                               {
+                                       if ( source_point == closest_target )
+                                       {
+                                               sprint(self, "\nTeleporting to the same point\n");
+                                               return 1;
+                                       }
+
+                                       if ( !ons_Teleport(self,closest_target,autocvar_g_onslaught_teleport_radius,true) )
+                                               sprint(self, "\nUnable to teleport there\n");
+                               }
+
+                               return 1;
+                       }
+
+                       sprint(self, "\nNo teleportation for you\n");
+               }
+
+               return 1;
+       }
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayerUseKey)
+{SELFPARAM();
+       if(MUTATOR_RETURNVALUE || gameover) { return false; }
+
+       if((time > self.teleport_antispam) && (self.deadflag == DEAD_NO) && !self.vehicle)
+       {
+               entity source_point = ons_Nearest_ControlPoint(self.origin, autocvar_g_onslaught_teleport_radius);
+               if ( source_point )
+               {
+                       stuffcmd(self, "qc_cmd_cl hud clickradar\n");
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, PlayHitsound)
+{
+       return (frag_victim.classname == "onslaught_generator" && !frag_victim.isshielded)
+               || (frag_victim.classname == "onslaught_controlpoint_icon" && !frag_victim.owner.isshielded);
+}
+
+MUTATOR_HOOKFUNCTION(ons, SendWaypoint)
+{
+       if(wp_sendflags & 16)
+       {
+               if(self.owner.classname == "onslaught_controlpoint")
+               {
+                       entity wp_owner = self.owner;
+                       entity e = WaypointSprite_getviewentity(wp_sendto);
+                       if(SAME_TEAM(e, wp_owner) && wp_owner.goalentity.health >= wp_owner.goalentity.max_health) { wp_flag |= 2; }
+                       if(!ons_ControlPoint_Attackable(wp_owner, e.team)) { wp_flag |= 2; }
+               }
+               if(self.owner.classname == "onslaught_generator")
+               {
+                       entity wp_owner = self.owner;
+                       if(wp_owner.isshielded && wp_owner.health >= wp_owner.max_health) { wp_flag |= 2; }
+                       if(wp_owner.health <= 0) { wp_flag |= 2; }
+               }
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, TurretValidateTarget)
+{
+       if(substring(turret_target.classname, 0, 10) == "onslaught_") // don't attack onslaught targets, that's the player's job!
+       {
+               ret_float = -3;
+               return true;
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ons, TurretThink)
+{
+       // ONS uses somewhat backwards linking.
+       if(self.target)
+       {
+               entity e = find(world, targetname, self.target);
+               if (e != world)
+                       self.team = e.team;
+       }
+
+       if(self.team != self.tur_head.team)
+               turret_respawn();
+
+       return false;
+}
+
+
+// ==========
+// Spawnfuncs
+// ==========
+
+/*QUAKED spawnfunc_onslaught_link (0 .5 .8) (-16 -16 -16) (16 16 16)
+  Link between control points.
+
+  This entity targets two different spawnfunc_onslaught_controlpoint or spawnfunc_onslaught_generator entities, and suppresses shielding on both if they are owned by different teams.
+
+keys:
+"target" - first control point.
+"target2" - second control point.
+ */
+spawnfunc(onslaught_link)
+{
+       if(!g_onslaught) { remove(self); return; }
+
+       if (self.target == "" || self.target2 == "")
+               objerror("target and target2 must be set\n");
+
+       self.ons_worldlinknext = ons_worldlinklist; // link into ons_worldlinklist
+       ons_worldlinklist = self;
+
+       InitializeEntity(self, ons_DelayedLinkSetup, INITPRIO_FINDTARGET);
+       Net_LinkEntity(self, false, 0, ons_Link_Send);
+}
+
+/*QUAKED spawnfunc_onslaught_controlpoint (0 .5 .8) (-32 -32 0) (32 32 128)
+  Control point. Be sure to give this enough clearance so that the shootable part has room to exist
+
+  This should link to an spawnfunc_onslaught_controlpoint entity or spawnfunc_onslaught_generator entity.
+
+keys:
+"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
+"target" - target any entities that are tied to this control point, such as vehicles and buildable structure entities.
+"message" - name of this control point (should reflect the location in the map, such as "center bridge", "north tower", etc)
+ */
+
+spawnfunc(onslaught_controlpoint)
+{
+       if(!g_onslaught) { remove(self); return; }
+
+       ons_ControlPoint_Setup(self);
+}
+
+/*QUAKED spawnfunc_onslaught_generator (0 .5 .8) (-32 -32 -24) (32 32 64)
+  Base generator.
+
+  spawnfunc_onslaught_link entities can target this.
+
+keys:
+"team" - team that owns this generator (5 = red, 14 = blue, etc), MUST BE SET.
+"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
+ */
+spawnfunc(onslaught_generator)
+{
+       if(!g_onslaught) { remove(self); return; }
+       if(!self.team) { objerror("team must be set"); }
+
+       ons_GeneratorSetup(self);
+}
+
+// scoreboard setup
+void ons_ScoreRules()
+{
+       CheckAllowedTeams(world);
+       ScoreRules_basics(((c4>=0) ? 4 : (c3>=0) ? 3 : 2), SFL_SORT_PRIO_PRIMARY, 0, true);
+       ScoreInfo_SetLabel_TeamScore  (ST_ONS_CAPS,     "destroyed", SFL_SORT_PRIO_PRIMARY);
+       ScoreInfo_SetLabel_PlayerScore(SP_ONS_CAPS,     "caps",      SFL_SORT_PRIO_SECONDARY);
+       ScoreInfo_SetLabel_PlayerScore(SP_ONS_TAKES,    "takes",     0);
+       ScoreRules_basics_end();
+}
+
+void ons_DelayedInit() // Do this check with a delay so we can wait for teams to be set up
+{
+       ons_ScoreRules();
+
+       round_handler_Spawn(Onslaught_CheckPlayers, Onslaught_CheckWinner, Onslaught_RoundStart);
+       round_handler_Init(5, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
+}
+
+void ons_Initialize()
+{
+       g_onslaught = true;
+       ons_captureshield_force = autocvar_g_onslaught_shield_force;
+
+       addstat(STAT_ROUNDLOST, AS_INT, ons_roundlost);
+
+       InitializeEntity(world, ons_DelayedInit, INITPRIO_GAMETYPE);
+}
+
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/sv_controlpoint.qc b/qcsrc/common/gamemodes/gamemode/onslaught/sv_controlpoint.qc
new file mode 100644 (file)
index 0000000..4924287
--- /dev/null
@@ -0,0 +1,40 @@
+#include "sv_controlpoint.qh"
+
+.bool iscaptured;
+
+bool cpicon_send(entity this, entity to, int sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_CONTROLPOINT_ICON);
+       WriteByte(MSG_ENTITY, sf);
+       if(sf & CPSF_SETUP)
+       {
+               WriteCoord(MSG_ENTITY, self.origin_x);
+               WriteCoord(MSG_ENTITY, self.origin_y);
+               WriteCoord(MSG_ENTITY, self.origin_z);
+
+               WriteByte(MSG_ENTITY, self.health);
+               WriteByte(MSG_ENTITY, self.max_health);
+               WriteByte(MSG_ENTITY, self.count);
+               WriteByte(MSG_ENTITY, self.team);
+               WriteByte(MSG_ENTITY, self.owner.iscaptured);
+       }
+
+       if(sf & CPSF_STATUS)
+       {
+               WriteByte(MSG_ENTITY, self.team);
+
+               if(self.health <= 0)
+                       WriteByte(MSG_ENTITY, 0);
+               else
+                       WriteByte(MSG_ENTITY, ceil((self.health / self.max_health) * 255));
+       }
+
+       return true;
+}
+
+void onslaught_controlpoint_icon_link(entity e, void() spawnproc)
+{
+       Net_LinkEntity(e, true, 0, cpicon_send);
+       e.think         = spawnproc;
+       e.nextthink     = time * sys_frametime;
+}
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/sv_controlpoint.qh b/qcsrc/common/gamemodes/gamemode/onslaught/sv_controlpoint.qh
new file mode 100644 (file)
index 0000000..d76f0ea
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef CONTROLPOINT_H
+#define CONTROLPOINT_H
+
+const vector CPICON_MIN = '-32 -32 -9';
+const vector CPICON_MAX = '32 32 25';
+
+const int CPSF_STATUS = 4;
+const int CPSF_SETUP = 8;
+
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/sv_generator.qc b/qcsrc/common/gamemodes/gamemode/onslaught/sv_generator.qc
new file mode 100644 (file)
index 0000000..cf8d234
--- /dev/null
@@ -0,0 +1,37 @@
+#include "sv_generator.qh"
+
+bool generator_send(entity this, entity to, int sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_GENERATOR);
+       WriteByte(MSG_ENTITY, sf);
+       if(sf & GSF_SETUP)
+       {
+               WriteCoord(MSG_ENTITY, self.origin_x);
+               WriteCoord(MSG_ENTITY, self.origin_y);
+               WriteCoord(MSG_ENTITY, self.origin_z);
+
+               WriteByte(MSG_ENTITY, self.health);
+               WriteByte(MSG_ENTITY, self.max_health);
+               WriteByte(MSG_ENTITY, self.count);
+               WriteByte(MSG_ENTITY, self.team);
+       }
+
+       if(sf & GSF_STATUS)
+       {
+               WriteByte(MSG_ENTITY, self.team);
+
+               if(self.health <= 0)
+                       WriteByte(MSG_ENTITY, 0);
+               else
+                       WriteByte(MSG_ENTITY, ceil((self.health / self.max_health) * 255));
+       }
+
+       return true;
+}
+
+void generator_link(void() spawnproc)
+{SELFPARAM();
+       Net_LinkEntity(self, true, 0, generator_send);
+       self.think              = spawnproc;
+       self.nextthink  = time;
+}
diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/sv_generator.qh b/qcsrc/common/gamemodes/gamemode/onslaught/sv_generator.qh
new file mode 100644 (file)
index 0000000..003c2b1
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef GENERATOR_H
+#define GENERATOR_H
+const vector GENERATOR_MIN = '-52 -52 -14';
+const vector GENERATOR_MAX = '52 52 75';
+
+const int GSF_STATUS = 4;
+const int GSF_SETUP = 8;
+
+bool generator_send(entity this, entity to, int sf);
+#endif
index a825b4ed16fbfb58a8718ce4ca5cd86d2e9c97cb..ab86ea6736eaca2b592cb6e212bdc1aa6b42392b 100644 (file)
@@ -5,12 +5,14 @@
 
 #include "item.qh"
 
-REGISTRY(Items, BIT(5))
-REGISTER_REGISTRY(RegisterItems)
+REGISTRY(Items, BITS(5))
+#define Items_from(i) _Items_from(i, NULL)
+REGISTER_REGISTRY(Items)
 /** If you register a new item, make sure to add it to all.inc */
-#define REGISTER_ITEM(id, class) REGISTER(RegisterItems, ITEM, Items, id, m_id, NEW(class))
+#define REGISTER_ITEM(id, class) REGISTER(Items, ITEM, id, m_id, NEW(class))
 
-REGISTRY_SORT(Items, m_name, 0)
+REGISTRY_SORT(Items, 0)
+REGISTRY_CHECK(Items)
 STATIC_INIT(Items) { FOREACH(Items, true, LAMBDA(it.m_id = i)); }
 
 void Dump_Items();
@@ -34,5 +36,3 @@ string Item_Model(string item_mdl);
 #endif
 
 #endif
-
-#include "inventory.qh"
index a6d266ae5fba57d3d50727b25cb41d1fe1c396e2..f748dda88405d286d73cb0eab68f84431eda96ff 100644 (file)
@@ -11,16 +11,20 @@ class(Inventory) .int inv_items[Items_MAX];
 /** Player inventory; Inventories also have one inventory for storing the previous state */
 .Inventory inventory;
 
+REGISTER_NET_LINKED(ENT_CLIENT_INVENTORY)
+
 #ifdef CSQC
-void Inventory_Read(Inventory data)
+NET_HANDLE(ENT_CLIENT_INVENTORY, bool isnew)
 {
+    make_pure(this);
     const int bits = ReadInt24_t();
     FOREACH(Items, bits & BIT(it.m_id), LAMBDA(
         .int fld = inv_items[it.m_id];
-        int prev = data.(fld);
-        int next = data.(fld) = ReadByte();
+        int prev = this.(fld);
+        int next = this.(fld) = ReadByte();
         LOG_TRACEF("%s: %.0f -> %.0f\n", it.m_name, prev, next);
     ));
+    return true;
 }
 #endif
 
@@ -42,7 +46,7 @@ void Inventory_Write(Inventory data)
 #ifdef SVQC
 bool Inventory_Send(entity this, entity to, int sf)
 {
-    WriteByte(MSG_ENTITY, ENT_CLIENT_INVENTORY);
+    WriteHeader(MSG_ENTITY, ENT_CLIENT_INVENTORY);
     entity e = self.owner;
     if (IS_SPEC(e)) e = e.enemy;
     Inventory data = e.inventory;
@@ -53,7 +57,7 @@ bool Inventory_Send(entity this, entity to, int sf)
 void Inventory_new(entity e)
 {
     Inventory inv = new(Inventory), bak = new(Inventory);
-    inv.classname = "inventory", bak.classname = "inventory";
+    make_pure(inv); make_pure(bak);
     inv.inventory = bak;
     inv.drawonlytoclient = e;
     Net_LinkEntity((inv.owner = e).inventory = inv, false, 0, Inventory_Send);
index 13a774ebcec18f693120f19e7b89982d688fe788..5bd550838aab3f40b93d7552fad04a96c13b437a 100644 (file)
@@ -5,13 +5,14 @@
 
 #ifndef MENUQC
 MODEL(ArmorSmall_ITEM, Item_Model("item_armor_small.md3"));
+SOUND(ArmorSmall, "misc/armor1");
 #endif
 
 REGISTER_ITEM(ArmorSmall, Armor) {
 #ifndef MENUQC
     this.m_model                =   MDL_ArmorSmall_ITEM;
+    this.m_sound                =   SND_ArmorSmall;
 #endif
-    this.m_sound                =   "misc/armor1.wav";
     this.m_name                 =   "5 Armor";
     this.m_icon                 =   "armor";
 #ifdef SVQC
@@ -24,13 +25,14 @@ REGISTER_ITEM(ArmorSmall, Armor) {
 
 #ifndef MENUQC
 MODEL(ArmorMedium_ITEM, Item_Model("item_armor_medium.md3"));
+SOUND(ArmorMedium, "misc/armor10");
 #endif
 
 REGISTER_ITEM(ArmorMedium, Armor) {
 #ifndef MENUQC
     this.m_model                =   MDL_ArmorMedium_ITEM;
+    this.m_sound                =   SND_ArmorMedium;
 #endif
-    this.m_sound                =   "misc/armor10.wav";
     this.m_name                 =   "25 Armor";
     this.m_icon                 =   "armor";
 #ifdef SVQC
@@ -43,13 +45,14 @@ REGISTER_ITEM(ArmorMedium, Armor) {
 
 #ifndef MENUQC
 MODEL(ArmorLarge_ITEM, Item_Model("item_armor_big.md3"));
+SOUND(ArmorLarge, "misc/armor17_5");
 #endif
 
 REGISTER_ITEM(ArmorLarge, Armor) {
 #ifndef MENUQC
     this.m_model                =   MDL_ArmorLarge_ITEM;
+    this.m_sound                =   SND_ArmorLarge;
 #endif
-    this.m_sound                =   "misc/armor17_5.wav";
     this.m_name                 =   "50 Armor";
     this.m_icon                 =   "armor";
     this.m_color                =   '0 1 0';
@@ -64,13 +67,14 @@ REGISTER_ITEM(ArmorLarge, Armor) {
 
 #ifndef MENUQC
 MODEL(ArmorMega_ITEM, Item_Model("item_armor_large.md3"));
+SOUND(ArmorMega, "misc/armor25");
 #endif
 
 REGISTER_ITEM(ArmorMega, Armor) {
 #ifndef MENUQC
     this.m_model                =   MDL_ArmorMega_ITEM;
+    this.m_sound                =   SND_ArmorMega;
 #endif
-    this.m_sound                =   "misc/armor25.wav";
     this.m_name                 =   "100 Armor";
     this.m_icon                 =   "item_large_armor";
     this.m_color                =   '0 1 0';
index 48a80f886af4f8278d0326e0f85d17969cdfc2b3..adb93e7c94eb8010c2ca8de8da34e6da1e7b7f2f 100644 (file)
@@ -3,6 +3,8 @@
 #include "pickup.qh"
 CLASS(Armor, Pickup)
 #ifdef SVQC
+    ATTRIB(Armor, m_mins, vector, '-16 -16 0')
+    ATTRIB(Armor, m_maxs, vector, '16 16 48')
     ATTRIB(Armor, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
 #endif
 ENDCLASS(Armor)
index b81bde7afc22d1b0bd2152f990d5746725e215b3..6a2b5b13895a4b00ff2dacb05393395bfeae03b8 100644 (file)
@@ -5,13 +5,14 @@
 
 #ifndef MENUQC
 MODEL(HealthSmall_ITEM, Item_Model("g_h1.md3"));
+SOUND(HealthSmall, "misc/minihealth");
 #endif
 
 REGISTER_ITEM(HealthSmall, Health) {
 #ifndef MENUQC
     this.m_model                =   MDL_HealthSmall_ITEM;
+    this.m_sound                =   SND_HealthSmall;
 #endif
-    this.m_sound                =   "misc/minihealth.wav";
     this.m_name                 =   "5 Health";
     this.m_icon                 =   "health";
 #ifdef SVQC
@@ -24,13 +25,14 @@ REGISTER_ITEM(HealthSmall, Health) {
 
 #ifndef MENUQC
 MODEL(HealthMedium_ITEM, Item_Model("g_h25.md3"));
+SOUND(HealthMedium, "misc/mediumhealth");
 #endif
 
 REGISTER_ITEM(HealthMedium, Health) {
 #ifndef MENUQC
     this.m_model                =   MDL_HealthMedium_ITEM;
+    this.m_sound                =   SND_HealthMedium;
 #endif
-    this.m_sound                =   "misc/mediumhealth.wav";
     this.m_name                 =   "25 Health";
     this.m_icon                 =   "health";
 #ifdef SVQC
@@ -43,13 +45,14 @@ REGISTER_ITEM(HealthMedium, Health) {
 
 #ifndef MENUQC
 MODEL(HealthLarge_ITEM, Item_Model("g_h50.md3"));
+SOUND(HealthLarge, "misc/mediumhealth");
 #endif
 
 REGISTER_ITEM(HealthLarge, Health) {
 #ifndef MENUQC
     this.m_model                =   MDL_HealthLarge_ITEM;
+    this.m_sound                =   SND_HealthLarge;
 #endif
-    this.m_sound                =   "misc/mediumhealth.wav";
     this.m_name                 =   "50 Health";
     this.m_icon                 =   "health";
     this.m_color                =   '1 0 0';
@@ -64,13 +67,14 @@ REGISTER_ITEM(HealthLarge, Health) {
 
 #ifndef MENUQC
 MODEL(HealthMega_ITEM, Item_Model("g_h100.md3"));
+SOUND(HealthMega, "misc/megahealth");
 #endif
 
 REGISTER_ITEM(HealthMega, Health) {
 #ifndef MENUQC
     this.m_model                =   MDL_HealthMega_ITEM;
+    this.m_sound                =   SND_HealthMega;
 #endif
-    this.m_sound                =   "misc/megahealth.wav";
     this.m_name                 =   "100 Health";
     this.m_icon                 =   "item_mega_health";
     this.m_color                =   '1 0 0';
index 15f1f8dd91a4213b32c3bd51c10673e2fe76e466..f7bfb5c9386d48e3d0d972fd04db2bc714769dd9 100644 (file)
@@ -3,6 +3,8 @@
 #include "pickup.qh"
 CLASS(Health, Pickup)
 #ifdef SVQC
+    ATTRIB(Health, m_mins, vector, '-16 -16 0')
+    ATTRIB(Health, m_maxs, vector, '16 16 48')
     ATTRIB(Health, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
 #endif
 ENDCLASS(Health)
index ade99c543aeacb710cabd4b9194d5de7bd6fc753..fc958709e87d66af6eb50b958ce71ab8ef8f11b2 100644 (file)
@@ -2,12 +2,6 @@
 
 #ifdef SVQC
 bool ITEM_HANDLE(Pickup, entity this, entity item, entity player) {
-    bool b = this.giveTo(this, item, player);
-    if (b) {
-        LOG_TRACEF("entity %i picked up %s\n", player, this.m_name);
-        player.inventory.inv_items[this.m_id]++;
-        Inventory_update(player);
-    }
-    return b;
+    return this.giveTo(this, item, player);
 }
 #endif
index 6f60337c195a7ab7d79c43a04f5ec937e771ab67..19963278873103d6f8e5386bc8a7b14b7d670ccc 100644 (file)
@@ -1,46 +1,38 @@
 #ifndef PICKUP_H
 #define PICKUP_H
+#include "../inventory.qh"
 #include "../item.qh"
 CLASS(Pickup, GameItem)
 #ifndef MENUQC
     ATTRIB(Pickup, m_model, Model, NULL)
+    ATTRIB(Pickup, m_sound, Sound, SND_ITEMPICKUP)
 #endif
-    ATTRIB(Pickup, m_sound, string, "misc/itempickup.wav")
     ATTRIB(Pickup, m_name, string, string_null)
     METHOD(Pickup, show, void(entity this));
     void Pickup_show(entity this) { LOG_INFOF("%s: %s\n", etos(this), this.m_name); }
 #ifdef SVQC
+    ATTRIB(Pickup, m_mins, vector, '-16 -16 0')
+    ATTRIB(Pickup, m_maxs, vector, '16 16 32')
     ATTRIB(Pickup, m_botvalue, int, 0)
     ATTRIB(Pickup, m_itemflags, int, 0)
     ATTRIB(Pickup, m_itemid, int, 0)
+    float generic_pickupevalfunc(entity player, entity item);
     ATTRIB(Pickup, m_pickupevalfunc, float(entity player, entity item), generic_pickupevalfunc)
     ATTRIB(Pickup, m_respawntime, float(), func_null)
     ATTRIB(Pickup, m_respawntimejitter, float(), func_null)
-    METHOD(Pickup, giveTo, bool(entity this, entity item, entity player));
-    bool Pickup_giveTo(entity this, entity item, entity player) { return Item_GiveTo(item, player); }
+    float Item_GiveTo(entity item, entity player);
+    METHOD(Pickup, giveTo, bool(entity this, entity item, entity player))
+    {
+        bool b = Item_GiveTo(item, player);
+        if (b) {
+            LOG_TRACEF("entity %i picked up %s\n", player, this.m_name);
+            player.inventory.inv_items[this.m_id]++;
+            Inventory_update(player);
+        }
+        return b;
+    }
     bool ITEM_HANDLE(Pickup, entity this, entity item, entity player);
 #endif
 ENDCLASS(Pickup)
 
-#ifdef SVQC
-// For g_pickup_respawntime
-#include "../../../server/defs.qh"
-// Getters to dynamically retrieve the values of g_pickup_respawntime*
-GETTER(float, g_pickup_respawntime_weapon)
-GETTER(float, g_pickup_respawntime_superweapon)
-GETTER(float, g_pickup_respawntime_ammo)
-GETTER(float, g_pickup_respawntime_short)
-GETTER(float, g_pickup_respawntime_medium)
-GETTER(float, g_pickup_respawntime_long)
-GETTER(float, g_pickup_respawntime_powerup)
-GETTER(float, g_pickup_respawntimejitter_weapon)
-GETTER(float, g_pickup_respawntimejitter_superweapon)
-GETTER(float, g_pickup_respawntimejitter_ammo)
-GETTER(float, g_pickup_respawntimejitter_short)
-GETTER(float, g_pickup_respawntimejitter_medium)
-GETTER(float, g_pickup_respawntimejitter_long)
-GETTER(float, g_pickup_respawntimejitter_powerup)
-
-#endif
-
 #endif
index a1b2f14037fcc7394325624c56beb7406f5d5041..7deba67df50bb48c9ddedeed3a455c9bab126c0e 100644 (file)
@@ -6,13 +6,14 @@
 
 #ifndef MENUQC
 MODEL(Strength_ITEM, Item_Model("g_strength.md3"));
+SOUND(Strength, "misc/powerup");
 #endif
 
 REGISTER_ITEM(Strength, Powerup) {
 #ifndef MENUQC
     this.m_model            =   MDL_Strength_ITEM;
+    this.m_sound            =   SND_Strength;
 #endif
-    this.m_sound            =   "misc/powerup.wav";
     this.m_name             =   "Strength Powerup";
     this.m_icon             =   "strength";
     this.m_color            =   '0 0 1';
@@ -23,13 +24,14 @@ REGISTER_ITEM(Strength, Powerup) {
 
 #ifndef MENUQC
 MODEL(Shield_ITEM, Item_Model("g_invincible.md3"));
+SOUND(Shield, "misc/powerup_shield");
 #endif
 
 REGISTER_ITEM(Shield, Powerup) {
 #ifndef MENUQC
     this.m_model            =   MDL_Shield_ITEM;
+    this.m_sound            =   SND_Shield;
 #endif
-    this.m_sound            =   "misc/powerup_shield.wav";
     this.m_name             =   "Shield";
     this.m_icon             =   "shield";
     this.m_color            =   '1 0 1';
index d78bd5563e1e6707f8c191bf14294d0dc0582f23..f443ab0af2a3e8887cf72128cdbbfc54cb0df4e9 100644 (file)
@@ -8,6 +8,8 @@
 #include "pickup.qh"
 CLASS(Powerup, Pickup)
 #ifdef SVQC
+    ATTRIB(Powerup, m_mins, vector, '-16 -16 0')
+    ATTRIB(Powerup, m_maxs, vector, '16 16 48')
     ATTRIB(Powerup, m_botvalue, int, 100000)
     ATTRIB(Powerup, m_itemflags, int, FL_POWERUP)
     ATTRIB(Powerup, m_respawntime, float(), GET(g_pickup_respawntime_powerup))
index 4f856670b8110ee26731dffc67b5305159439e6d..5ca1c3803da30ea19467f6daaa21074ec4ac2d74 100644 (file)
@@ -1,13 +1,11 @@
 #if defined(CSQC)
     #include "../client/defs.qh"
     #include "util.qh"
-    #include "buffs/all.qh"
     #include "weapons/all.qh"
     #include "mapinfo.qh"
 #elif defined(MENUQC)
 #elif defined(SVQC)
     #include "util.qh"
-    #include "buffs/all.qh"
     #include "monsters/all.qh"
     #include "mapinfo.qh"
 #endif
@@ -1019,6 +1017,11 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, int p
                {
                        MapInfo_Map_flags |= MAPINFO_FLAG_NOAUTOMAPLIST;
                }
+               else if(t == "gameversion_min")
+               {
+                       if (cvar("gameversion") < stof(s))
+                               MapInfo_Map_flags |= MAPINFO_FLAG_NOAUTOMAPLIST;
+               }
                else if(t == "type")
                {
                        t = car(s); s = cdr(s);
index 4107290fc0ee97d387b204e43795de8a6269eec5..702798bbf861d3bfcb912ceac3b67a6afcd5052b 100644 (file)
@@ -42,13 +42,15 @@ CLASS(Gametype, Object)
     }
 ENDCLASS(Gametype)
 
-REGISTRY(Gametypes, BIT(4))
-REGISTER_REGISTRY(RegisterGametypes)
+REGISTRY(Gametypes, BITS(4))
+#define Gametypes_from(i) _Gametypes_from(i, NULL)
+REGISTER_REGISTRY(Gametypes)
+REGISTRY_CHECK(Gametypes)
 int MAPINFO_TYPE_ALL;
 #define REGISTER_GAMETYPE(hname, sname, g_name, NAME, gteamplay, mutators, defaults, gdescription)          \
     int MAPINFO_TYPE_##NAME;                                                                                \
     bool NAME##_mapinfo(string k, string v) { return = false; }                                             \
-    REGISTER(RegisterGametypes, MAPINFO_TYPE, Gametypes, g_name, m_id,                                      \
+    REGISTER(Gametypes, MAPINFO_TYPE, g_name, m_id,                                      \
         NEW(Gametype, hname, #sname, #g_name, gteamplay, #sname " " mutators, defaults, gdescription)       \
     ) {                                                                                                     \
         /* same as `1 << m_id` */                                                                           \
@@ -79,7 +81,7 @@ REGISTER_GAMETYPE(_("Race"),rc,g_race,RACE,false,"","timelimit=20 qualifying_tim
 }
 #define g_race IS_GAMETYPE(RACE)
 
-REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,false,"","timelimit=20",_("Race for fastest time."));
+REGISTER_GAMETYPE(_("Race CTS"),cts,g_cts,CTS,false,"cloaked","timelimit=20",_("Race for fastest time."));
 #define g_cts IS_GAMETYPE(CTS)
 
 REGISTER_GAMETYPE(_("Team Deathmatch"),tdm,g_tdm,TEAM_DEATHMATCH,true,"","timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Help your team score the most frags against the enemy team"))
index 38614c7d4629481c9c8fafeb6b029b533e263491..3ea50caad3d0554bb5f1b7b4e389b29bf6052d6b 100644 (file)
@@ -153,8 +153,6 @@ void minigame_player_entremove()
                deactivate_minigame();
 }
 
-vector ReadVector2D() { vector v; v_x = ReadCoord(); v_y = ReadCoord(); v_z = 0; return v; }
-vector ReadVector() { vector v; v_x = ReadCoord(); v_y = ReadCoord(); v_z = ReadCoord(); return v; }
 string() ReadString_Raw = #366;
 string ReadString_Zoned() { return strzone(ReadString_Raw()); }
 #define ReadString ReadString_Zoned
@@ -178,8 +176,8 @@ void minigame_read_owner()
        if ( !self.owner )
                LOG_TRACE("Got a minigame entity without a minigame!\n");
 }
-void ent_read_minigame()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_MINIGAME, bool isnew)
+{
        float sf = ReadByte();
        if ( sf & MINIG_SF_CREATE )
        {
@@ -241,6 +239,7 @@ void ent_read_minigame()
                        " classname:",self.classname," enttype:",ftos(self.enttype) );
                LOG_DEBUG(" sf:",ftos(sf)," netname:",self.netname,"\n\n");
        }
+       return true;
 }
 #undef ReadString
 #undef FIELD
index 016e8a3edf1932665942c13930653246934556a9..f21c6e482d10c5b3310557ee6eba9178d6c28c0e 100644 (file)
@@ -95,9 +95,6 @@ float minigame_isactive()
 #define minigame_cmd(...) minigame_cmd_workaround(0,__VA_ARGS__)
 void minigame_cmd_workaround(float dummy, string...cmdargc);
 
-// Read a minigame entity from the server
-void ent_read_minigame();
-
 // Prompt the player to play in the current minigame
 // (ie: it's their turn and they should get back to the minigame)
 void minigame_prompt();
@@ -114,15 +111,17 @@ void HUD_MinigameMenu_CustomEntry(entity parent, string message, string event_ar
        while( (entityvar = findentity(entityvar,owner,active_minigame)) )
 
 
-REGISTRY(Minigames, BIT(3))
-REGISTER_REGISTRY(RegisterMinigames)
+REGISTRY(Minigames, BITS(3))
+#define Minigames_from(i) _Minigames_from(i, NULL)
+REGISTER_REGISTRY(Minigames)
+REGISTRY_CHECK(Minigames)
 #define REGISTER_MINIGAME(name,nicename) \
-    REGISTER(RegisterMinigames, MINIGAME, Minigames, name, m_id, spawn()); \
+    REGISTER(Minigames, MINIGAME, name, m_id, new(minigame_descriptor)); \
     void name##_hud_board(vector, vector); \
     void name##_hud_status(vector, vector); \
     int name##_client_event(entity, string, ...); \
     REGISTER_INIT_POST(MINIGAME, name) { \
-        this.classname = "minigame_descriptor"; \
+        make_pure(this); \
         this.netname = strzone(strtolower(#name)); \
         this.message = nicename; \
         this.minigame_hud_board = name##_hud_board; \
index 1e4da05075ad20c76b11587a69f4a2e5b3105782..93c88f6570486a6f85290a508d186ab20c2c8532 100644 (file)
@@ -79,9 +79,8 @@ string nmm_tile_build_vmill(entity tile)
 void nmm_spawn_tile(string id, entity minig, int distance)
 {
        // TODO global variable + list_next for simpler tile loops
-       entity e = spawn();
+       entity e = new(minigame_nmm_tile);
        e.origin = minigame_tile_pos(id,7,7);
-       e.classname = "minigame_nmm_tile";
        e.netname = id;
        e.owner = minig;
        e.team = 0;
index 8c5005ed259f301e924a19c781ec2080db2e064a..c3c76376c169cd8b19ab22c715b50c3f47401582 100644 (file)
@@ -642,8 +642,7 @@ int ttt_client_event(entity minigame, string event, ...)
 
                                        if ( spawnai )
                                        {
-                                               entity aiplayer = spawn();
-                                               aiplayer.classname = "minigame_player";
+                                               entity aiplayer = new(minigame_player);
                                                aiplayer.owner = minigame;
                                                aiplayer.team = ai;
                                                aiplayer.minigame_playerslot = 0;
index bc854952e7f9562dea72efdd50d91b15d81bc7b1..8a29bc297f89246abefdbe0773c6f0f42af7ba10 100644 (file)
@@ -1,5 +1,7 @@
 #include "minigames.qh"
 
+REGISTER_NET_LINKED(ENT_CLIENT_MINIGAME)
+
 entity minigame_get_descriptor(string id)
 {
        FOREACH(Minigames, true, LAMBDA(
index 56d0ece1a2a3c944812642e0c0f9dc889b276ab0..f69fc15b548c39ef99759700247db76dfdfedd5f 100644 (file)
@@ -51,8 +51,6 @@ void minigame_rmplayer(entity minigame_session, entity player)
 
 
 #define FIELD(Flags, Type,Name) if ( sf & (Flags) ) Write##Type(MSG_ENTITY, self.Name);
-#define WriteVector(to,Name) WriteCoord(to,Name##_x); WriteCoord(to,Name##_y); WriteCoord(to,Name##_z)
-#define WriteVector2D(to,Name) WriteCoord(to,Name##_x); WriteCoord(to,Name##_y)
 #define MSLE(Name,Fields) \
        else if ( self.classname == #Name ) { \
                if ( sf & MINIG_SF_CREATE ) WriteString(MSG_ENTITY,self.owner.netname); \
@@ -62,7 +60,7 @@ void minigame_rmplayer(entity minigame_session, entity player)
 // only use on minigame entities or entities with a minigame owner
 bool minigame_SendEntity(entity this, entity to, int sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_MINIGAME);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_MINIGAME);
        WriteByte(MSG_ENTITY, sf);
 
        if ( sf & MINIG_SF_CREATE )
@@ -131,12 +129,11 @@ int minigame_addplayer(entity minigame_session, entity player)
                        return 0;
                minigame_rmplayer(player.active_minigame,player);
        }
-       entity player_pointer = spawn();
+       entity player_pointer = new(minigame_player);
        int mgteam = minigame_session.minigame_event(minigame_session,"join",player,player_pointer);
 
        if ( mgteam )
        {
-               player_pointer.classname = "minigame_player";
                player_pointer.owner = minigame_session;
                player_pointer.minigame_players = player;
                player_pointer.team = mgteam;
@@ -171,8 +168,7 @@ entity start_minigame(entity player, string minigame )
        entity e = minigame_get_descriptor(minigame);
        if ( e )
        {
-               entity minig = spawn();
-               minig.classname = "minigame";
+               entity minig = new(minigame);
                minig.netname = strzone(strcat(e.netname,"_",ftos(num_for_edict(minig))));
                minig.descriptor = e;
                minig.minigame_event = e.minigame_event;
index e36d690d9bc743247aabbc104a3f7971e6e24b5a..eb6825ed600e52ad46df1c47af15717d3a10229d 100644 (file)
@@ -46,13 +46,15 @@ entity minigame_sessions;
 
 bool minigame_SendEntity(entity this, entity to, int sf);
 
-REGISTRY(Minigames, BIT(3))
-REGISTER_REGISTRY(RegisterMinigames)
+REGISTRY(Minigames, BITS(3))
+#define Minigames_from(i) _Minigames_from(i, NULL)
+REGISTER_REGISTRY(Minigames)
+REGISTRY_CHECK(Minigames)
 #define REGISTER_MINIGAME(name,nicename) \
-    REGISTER(RegisterMinigames, MINIGAME, Minigames, name, m_id, spawn()); \
+    REGISTER(Minigames, MINIGAME, name, m_id, new(minigame_descriptor)); \
     int name##_server_event(entity, string, ...); \
     REGISTER_INIT_POST(MINIGAME, name) { \
-        this.classname = "minigame_descriptor"; \
+        make_pure(this); \
         this.netname = strzone(strtolower(#name)); \
         this.message = nicename; \
                this.minigame_event = name##_server_event; \
index f675d8a9e1fd2f0b95f5e2a940c26f1f76038255..354df9a41c40f3e7949ac54f66cbfb13aa2d3935 100644 (file)
@@ -5,6 +5,7 @@ string W_Model(string w_mdl);
 
 MODEL(CTF_SHIELD,                       "models/ctf/shield.md3");
 MODEL(CTF_CAPTURE,                      "models/ctf/shockwavetransring.md3");
+MODEL(CTF_FLAG,                         "models/ctf/flags.md3");
 
 MODEL(DOM_NEUTRAL,                      "models/domination/dom_unclaimed.md3");
 MODEL(DOM_RED,                          "models/domination/dom_red.md3");
@@ -144,7 +145,7 @@ MODEL(GIB_ROBO_7,                       "models/gibs/robo7.md3");
 MODEL(GIB_ROBO_8,                       "models/gibs/robo8.md3");
 Model MDL_GIB_ROBO_RANDOM() {
     int i = floor(random() * 8);
-    return Models[MDL_GIB_ROBO_1.m_id + i];
+    return Models_from(MDL_GIB_ROBO_1.m_id + i);
 }
 
 MODEL(CASING_SHELL,                     "models/casing_shell.mdl");
@@ -346,7 +347,7 @@ MODEL(9,                                "models/sprites/9.spr32");
 MODEL(10,                               "models/sprites/10.spr32");
 Model MDL_NUM(int i) {
     if ((i >= 0 && i <= 10))
-        return Models[MDL_0.m_id + i];
+        return Models_from(MDL_0.m_id + i);
     return MDL_Null;
 }
 
index a7ab9088079f8914e35f12d8bddb7be67a9b6d0b..ac95c2c840a697a2b9e14d0d22277956c71a6416 100644 (file)
@@ -3,14 +3,15 @@
 
 #include "model.qh"
 
-REGISTRY(Models, BIT(9))
-REGISTER_REGISTRY(RegisterModels)
+REGISTRY(Models, BITS(9))
+#define Models_from(i) _Models_from(i, MDL_Null)
+REGISTER_REGISTRY(Models)
 
 #define MODEL(name, path) \
     string MDL_##name##_get() { return path; } \
-    REGISTER(RegisterModels, MDL, Models, name, m_id, NEW(Model, MDL_##name##_get))
+    REGISTER(Models, MDL, name, m_id, NEW(Model, MDL_##name##_get))
 
-STATIC_INIT(RegisterModels_precache) {
+PRECACHE(Models) {
     FOREACH(Models, true, LAMBDA({
         it.model_precache(it);
     }));
index f4b2a4bf0bbb5ac7892ccc1f3ec60497bbbf8503..f5c973bd07bd10bb1aacbb32276dbdefb5f318ff 100644 (file)
@@ -1,6 +1,17 @@
 #ifndef MONSTERS_ALL_C
 #define MONSTERS_ALL_C
 
+string M_Model(string m_mdl)
+{
+       string output = strcat("models/monsters/", m_mdl);
+#ifdef SVQC
+       MUTATOR_CALLHOOK(MonsterModel, m_mdl, output);
+       return monster_model_output;
+#else
+       return output;
+#endif
+}
+
 #include "all.qh"
 
 #define IMPLEMENTATION
index 05eb4346db90d2cf958358410ec2d02e5546879a..b771984f212b1b4ef3a680099e19e7059600662e 100644 (file)
@@ -3,23 +3,20 @@
 
 #include "monster.qh"
 
-REGISTRY(Monsters, BIT(4))
-REGISTER_REGISTRY(RegisterMonsters)
+string M_Model(string m_mdl);
+
+REGISTRY(Monsters, BITS(5))
+#define Monsters_from(i) _Monsters_from(i, MON_Null)
+#define get_monsterinfo(i) Monsters_from(i)
+REGISTER_REGISTRY(Monsters)
+REGISTRY_CHECK(Monsters)
 const int MON_FIRST = 1;
 #define MON_LAST (Monsters_COUNT - 1)
 /** If you register a new monster, make sure to add it to all.inc */
-#define REGISTER_MONSTER(id, inst) REGISTER(RegisterMonsters, MON, Monsters, id, monsterid, inst)
+#define REGISTER_MONSTER(id, inst) REGISTER(Monsters, MON, id, monsterid, inst)
 
 REGISTER_MONSTER(Null, NEW(Monster));
 
-Monster get_monsterinfo(int id)
-{
-       if (id >= MON_FIRST && id <= MON_LAST) {
-               Monster m = Monsters[id];
-               if (m) return m;
-       }
-       return MON_Null;
-}
 
 #include "all.inc"
 
index b4559269d71a004247b1b5b4fb20d6dce75d195b..bfbd544e53246a14f31b4b8e0bb5ad0eb80e1791 100644 (file)
@@ -22,6 +22,7 @@ const int MON_FLAG_RANGED = 512; // monster shoots projectiles
 const int MON_FLAG_MELEE = 1024;
 const int MON_FLAG_CRUSH = 2048; // monster can be stomped in special modes
 const int MON_FLAG_RIDE = 4096; // monster can be ridden in special modes
+const int MONSTER_SIZE_QUAKE = 8192;
 
 // entity properties of monsterinfo:
 .bool(int, entity targ) monster_attackfunc;
index 7388ee66f5bce70ddc448466967f302ce79b488c..38b34c425e6d4e254fe5fb1c3f2cabb819c06351 100644 (file)
@@ -2,7 +2,7 @@
 #define MAGE_H
 
 #ifndef MENUQC
-MODEL(MON_MAGE, "models/monsters/mage.dpm");
+MODEL(MON_MAGE, M_Model("mage.dpm"));
 #endif
 
 CLASS(Mage, Monster)
@@ -29,7 +29,7 @@ CLASS(MageSpike, PortoLaunch)
 /* flags     */ ATTRIB(MageSpike, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(MageSpike, impulse, int, 9);
 /* refname   */ ATTRIB(MageSpike, netname, string, "magespike");
-/* wepname   */ ATTRIB(MageSpike, message, string, _("Mage spike"));
+/* wepname   */ ATTRIB(MageSpike, m_name, string, _("Mage spike"));
 ENDCLASS(MageSpike)
 REGISTER_WEAPON(MAGE_SPIKE, NEW(MageSpike));
 
@@ -39,22 +39,23 @@ REGISTER_WEAPON(MAGE_SPIKE, NEW(MageSpike));
 
 #ifdef SVQC
 
+SOUND(MageSpike_FIRE, W_Sound("electro_fire"));
 void M_Mage_Attack_Spike(vector dir);
 void M_Mage_Attack_Push();
-METHOD(MageSpike, wr_think, void(MageSpike thiswep, entity actor, bool fire1, bool fire2)) {
-    if (fire1)
-    if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, false, 0.2)) {
+METHOD(MageSpike, wr_think, void(MageSpike thiswep, entity actor, .entity weaponentity, int fire)) {
+    if (fire & 1)
+    if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, weaponentity, false, 0.2)) {
         if (!actor.target_range) actor.target_range = autocvar_g_monsters_target_range;
         actor.enemy = Monster_FindTarget(actor);
-        W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+        W_SetupShot_Dir(actor, v_forward, false, 0, SND(MageSpike_FIRE), CH_WEAPON_B, 0);
        if (!IS_PLAYER(actor)) w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
         M_Mage_Attack_Spike(w_shotdir);
-        weapon_thinkf(actor, WFRAME_FIRE1, 0, w_ready);
+        weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
     }
-    if (fire2)
-    if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, true, 0.5)) {
+    if (fire & 2)
+    if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, weaponentity, true, 0.5)) {
         M_Mage_Attack_Push();
-        weapon_thinkf(actor, WFRAME_FIRE2, 0, w_ready);
+        weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, 0, w_ready);
     }
 }
 
@@ -297,7 +298,7 @@ void M_Mage_Defend_Heal()
        if(washealed)
        {
                setanim(self, self.anim_shoot, true, true, true);
-               self.attack_finished_single = time + (autocvar_g_monster_mage_heal_delay);
+               self.attack_finished_single[0] = time + (autocvar_g_monster_mage_heal_delay);
                self.anim_finished = time + 1.5;
        }
 }
@@ -309,7 +310,7 @@ void M_Mage_Attack_Push()
        Send_Effect(EFFECT_TE_EXPLOSION, self.origin, '0 0 0', 1);
 
        setanim(self, self.anim_shoot, true, true, true);
-       self.attack_finished_single = time + (autocvar_g_monster_mage_attack_push_delay);
+       self.attack_finished_single[0] = time + (autocvar_g_monster_mage_attack_push_delay);
 }
 
 void M_Mage_Attack_Teleport()
@@ -334,7 +335,7 @@ void M_Mage_Attack_Teleport()
        self.fixangle = true;
        self.velocity *= 0.5;
 
-       self.attack_finished_single = time + 0.2;
+       self.attack_finished_single[0] = time + 0.2;
 }
 
 void M_Mage_Defend_Shield_Remove()
@@ -350,12 +351,13 @@ void M_Mage_Defend_Shield()
        self.armorvalue = (autocvar_g_monster_mage_shield_blockpercent);
        self.mage_shield_time = time + (autocvar_g_monster_mage_shield_time);
        setanim(self, self.anim_shoot, true, true, true);
-       self.attack_finished_single = time + 1;
+       self.attack_finished_single[0] = time + 1;
        self.anim_finished = time + 1;
 }
 
 float M_Mage_Attack(float attack_type, entity targ)
 {SELFPARAM();
+    .entity weaponentity = weaponentities[0];
        switch(attack_type)
        {
                case MONSTER_ATTACK_MELEE:
@@ -363,7 +365,8 @@ float M_Mage_Attack(float attack_type, entity targ)
                        if(random() <= 0.7)
                        {
                                Weapon wep = WEP_MAGE_SPIKE;
-                               wep.wr_think(wep, self, false, true);
+
+                               wep.wr_think(wep, self, weaponentity, 2);
                                return true;
                        }
 
@@ -382,10 +385,10 @@ float M_Mage_Attack(float attack_type, entity targ)
                                else
                                {
                                        setanim(self, self.anim_shoot, true, true, true);
-                                       self.attack_finished_single = time + (autocvar_g_monster_mage_attack_spike_delay);
+                                       self.attack_finished_single[0] = time + (autocvar_g_monster_mage_attack_spike_delay);
                                        self.anim_finished = time + 1;
                                        Weapon wep = WEP_MAGE_SPIKE;
-                                       wep.wr_think(wep, self, true, false);
+                                       wep.wr_think(wep, self, weaponentity, 1);
                                        return true;
                                }
                        }
@@ -421,7 +424,7 @@ spawnfunc(monster_mage) { Monster_Spawn(MON_MAGE.monsterid); }
                        }
 
                        if(self.health < (autocvar_g_monster_mage_heal_minhealth) || need_help)
-                       if(time >= self.attack_finished_single)
+                       if(time >= self.attack_finished_single[0])
                        if(random() < 0.5)
                                M_Mage_Defend_Heal();
 
index 203b597cc0da2b7ee99d19ce40536f753e84506b..67b6808cc7b23346d517f310435cba7ab09d00ae 100644 (file)
@@ -2,7 +2,7 @@
 #define SHAMBLER_H
 
 #ifndef MENUQC
-MODEL(MON_SHAMBLER, "models/monsters/shambler.mdl");
+MODEL(MON_SHAMBLER, M_Model("shambler.mdl"));
 #endif
 
 CLASS(Shambler, Monster)
@@ -77,12 +77,12 @@ void M_Shambler_Attack_Swing()
        if(r && Monster_Attack_Melee(self.enemy, (autocvar_g_monster_shambler_attack_claw_damage), ((r) ? self.anim_melee2 : self.anim_melee3), self.attack_range, 0.8, DEATH_MONSTER_SHAMBLER_CLAW.m_id, true))
        {
                Monster_Delay(1, 0, 0.5, M_Shambler_Attack_Swing);
-               self.attack_finished_single += 0.5;
-               self.anim_finished = self.attack_finished_single;
+               self.attack_finished_single[0] += 0.5;
+               self.anim_finished = self.attack_finished_single[0];
        }
 }
 
-#include "../../../server/csqceffects.qh"
+#include "../../effects/qc/all.qh"
 
 void M_Shambler_Attack_Lightning_Explode()
 {SELFPARAM();
@@ -149,9 +149,8 @@ void M_Shambler_Attack_Lightning()
 
        monster_makevectors(self.enemy);
 
-       gren = spawn ();
+       gren = new(grenade);
        gren.owner = gren.realowner = self;
-       gren.classname = "grenade";
        gren.bot_dodge = true;
        gren.bot_dodgerating = (autocvar_g_monster_shambler_attack_lightning_damage);
        gren.movetype = MOVETYPE_BOUNCE;
@@ -202,7 +201,7 @@ float M_Shambler_Attack(float attack_type, entity targ)
                        {
                                setanim(self, self.anim_melee2, true, true, false);
                                Monster_Delay(1, 0, 0.7, M_Shambler_Attack_Smash);
-                               self.attack_finished_single = time + 1.1;
+                               self.attack_finished_single[0] = time + 1.1;
                                self.anim_finished = time + 1.1;
                                self.state = MONSTER_ATTACK_MELEE; // kinda a melee attack
                                self.shambler_lastattack = time + 3 + random() * 1.5;
@@ -212,7 +211,7 @@ float M_Shambler_Attack(float attack_type, entity targ)
                        {
                                setanim(self, self.anim_shoot, true, true, false);
                                self.state = MONSTER_ATTACK_MELEE; // maybe we should rename this to something more general
-                               self.attack_finished_single = time + 1.1;
+                               self.attack_finished_single[0] = time + 1.1;
                                self.anim_finished = 1.1;
                                self.shambler_lastattack = time + 3 + random() * 1.5;
                                Monster_Delay(1, 0, 0.6, M_Shambler_Attack_Lightning);
index 208ae107993480edc0c4c2d3c90d2e4d13323955..10ee911d95c447dbc093dc676e7cbb895501fcf5 100644 (file)
@@ -2,7 +2,7 @@
 #define SPIDER_H
 
 #ifndef MENUQC
-MODEL(MON_SPIDER, "models/monsters/spider.dpm");
+MODEL(MON_SPIDER, M_Model("spider.dpm"));
 #endif
 
 CLASS(Spider, Monster)
@@ -28,7 +28,7 @@ CLASS(SpiderAttack, PortoLaunch)
 /* flags     */ ATTRIB(SpiderAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(SpiderAttack, impulse, int, 9);
 /* refname   */ ATTRIB(SpiderAttack, netname, string, "spider");
-/* wepname   */ ATTRIB(SpiderAttack, message, string, _("Spider attack"));
+/* wepname   */ ATTRIB(SpiderAttack, m_name, string, _("Spider attack"));
 ENDCLASS(SpiderAttack)
 REGISTER_WEAPON(SPIDER_ATTACK, NEW(SpiderAttack));
 
@@ -50,31 +50,32 @@ float autocvar_g_monster_spider_attack_bite_delay;
 
 void M_Spider_Attack_Web();
 
-METHOD(SpiderAttack, wr_think, void(SpiderAttack thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(SpiderAttack_FIRE, W_Sound("electro_fire"));
+METHOD(SpiderAttack, wr_think, void(SpiderAttack thiswep, entity actor, .entity weaponentity, int fire)) {
     bool isPlayer = IS_PLAYER(actor);
-    if (fire1)
-    if ((!isPlayer && time >= actor.spider_web_delay) || weapon_prepareattack(thiswep, actor, false, autocvar_g_monster_spider_attack_web_delay)) {
+    if (fire & 1)
+    if ((!isPlayer && time >= actor.spider_web_delay) || weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_monster_spider_attack_web_delay)) {
                if (!isPlayer) {
                        actor.spider_web_delay = time + 3;
                        setanim(actor, actor.anim_shoot, true, true, true);
-                       actor.attack_finished_single = time + (autocvar_g_monster_spider_attack_web_delay);
+                       actor.attack_finished_single[0] = time + (autocvar_g_monster_spider_attack_web_delay);
                        actor.anim_finished = time + 1;
                }
         if (isPlayer) actor.enemy = Monster_FindTarget(actor);
-        W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+        W_SetupShot_Dir(actor, v_forward, false, 0, SND(SpiderAttack_FIRE), CH_WEAPON_B, 0);
        if (!isPlayer) w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
                M_Spider_Attack_Web();
-        weapon_thinkf(actor, WFRAME_FIRE1, 0, w_ready);
+        weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
         return;
     }
-    if (fire2)
-    if (!isPlayer || weapon_prepareattack(thiswep, actor, true, 0.5)) {
+    if (fire & 2)
+    if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, true, 0.5)) {
        if (isPlayer) {
                actor.enemy = Monster_FindTarget(actor);
                actor.attack_range = 60;
        }
        Monster_Attack_Melee(actor.enemy, (autocvar_g_monster_spider_attack_bite_damage), ((random() > 0.5) ? self.anim_melee : self.anim_shoot), self.attack_range, (autocvar_g_monster_spider_attack_bite_delay), DEATH_MONSTER_SPIDER.m_id, true);
-        weapon_thinkf(actor, WFRAME_FIRE2, 0, w_ready);
+        weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, 0, w_ready);
     }
 }
 
@@ -121,8 +122,7 @@ void M_Spider_Attack_Web()
 
        sound(self, CH_SHOTS, SND_ELECTRO_FIRE2, VOL_BASE, ATTEN_NORM);
 
-       entity proj = spawn ();
-       proj.classname = "plasma";
+       entity proj = new(plasma);
        proj.owner = proj.realowner = self;
        proj.use = M_Spider_Attack_Web_Explode;
        proj.think = adaptor_think2use_hittype_splash;
@@ -155,17 +155,18 @@ void M_Spider_Attack_Web()
 
 bool M_Spider_Attack(int attack_type, entity targ)
 {SELFPARAM();
+    .entity weaponentity = weaponentities[0];
        switch(attack_type)
        {
                Weapon wep = WEP_SPIDER_ATTACK;
                case MONSTER_ATTACK_MELEE:
                {
-                       wep.wr_think(wep, self, false, true);
+                       wep.wr_think(wep, self, weaponentity, 2);
                        return true;
                }
                case MONSTER_ATTACK_RANGED:
                {
-                       wep.wr_think(wep, self, true, false);
+                       wep.wr_think(wep, self, weaponentity, 1);
                        return true;
                }
        }
index ac9f32205dae432e9104065d29957df55dd7debd..b55c5a42d96eee4f0e3d8501f2369f7face4084e 100644 (file)
@@ -2,7 +2,7 @@
 #define WYVERN_H
 
 #ifndef MENUQC
-MODEL(MON_WYVERN, "models/monsters/wizard.mdl");
+MODEL(MON_WYVERN, M_Model("wizard.mdl"));
 #endif
 
 CLASS(Wyvern, Monster)
@@ -28,7 +28,7 @@ CLASS(WyvernAttack, PortoLaunch)
 /* flags     */ ATTRIB(WyvernAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(WyvernAttack, impulse, int, 9);
 /* refname   */ ATTRIB(WyvernAttack, netname, string, "wyvern");
-/* wepname   */ ATTRIB(WyvernAttack, message, string, _("Wyvern attack"));
+/* wepname   */ ATTRIB(WyvernAttack, m_name, string, _("Wyvern attack"));
 ENDCLASS(WyvernAttack)
 REGISTER_WEAPON(WYVERN_ATTACK, NEW(WyvernAttack));
 
@@ -48,12 +48,13 @@ float autocvar_g_monster_wyvern_attack_fireball_speed;
 void M_Wyvern_Attack_Fireball_Explode();
 void M_Wyvern_Attack_Fireball_Touch();
 
-METHOD(WyvernAttack, wr_think, void(WyvernAttack thiswep, entity actor, bool fire1, bool fire2)) {
-    if (fire1)
-    if (time > actor.attack_finished_single || weapon_prepareattack(thiswep, actor, false, 1.2)) {
-        if (IS_PLAYER(actor)) W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+SOUND(WyvernAttack_FIRE, W_Sound("electro_fire"));
+METHOD(WyvernAttack, wr_think, void(WyvernAttack thiswep, entity actor, .entity weaponentity, int fire)) {
+    if (fire & 1)
+    if (time > actor.attack_finished_single[0] || weapon_prepareattack(thiswep, actor, weaponentity, false, 1.2)) {
+        if (IS_PLAYER(actor)) W_SetupShot_Dir(actor, v_forward, false, 0, SND(WyvernAttack_FIRE), CH_WEAPON_B, 0);
                if (IS_MONSTER(actor)) {
-                       actor.attack_finished_single = time + 1.2;
+                       actor.attack_finished_single[0] = time + 1.2;
                        actor.anim_finished = time + 1.2;
                        monster_makevectors(actor.enemy);
                }
@@ -73,7 +74,7 @@ METHOD(WyvernAttack, wr_think, void(WyvernAttack thiswep, entity actor, bool fir
                missile.touch = M_Wyvern_Attack_Fireball_Touch;
                CSQCProjectile(missile, true, PROJECTILE_FIREMINE, true);
 
-        weapon_thinkf(actor, WFRAME_FIRE1, 0, w_ready);
+        weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
     }
 }
 
@@ -121,6 +122,7 @@ void M_Wyvern_Attack_Fireball_Touch()
 float M_Wyvern_Attack(float attack_type, entity targ)
 {
        SELFPARAM();
+       .entity weaponentity = weaponentities[0];
        switch(attack_type)
        {
                case MONSTER_ATTACK_MELEE:
@@ -128,7 +130,7 @@ float M_Wyvern_Attack(float attack_type, entity targ)
                {
                        w_shotdir = normalize((self.enemy.origin + '0 0 10') - self.origin);
                        Weapon wep = WEP_WYVERN_ATTACK;
-                       wep.wr_think(wep, self, true, false);
+                       wep.wr_think(wep, self, weaponentity, 1);
                        return true;
                }
        }
index e68b7ff5424334b8c979f2c8b6141e2321cda032..d63188b0fe9470c9391c91ef432348b8990bcedc 100644 (file)
@@ -2,7 +2,7 @@
 #define ZOMBIE_H
 
 #ifndef MENUQC
-MODEL(MON_ZOMBIE, "models/monsters/zombie.dpm");
+MODEL(MON_ZOMBIE, M_Model("zombie.dpm"));
 #endif
 
 CLASS(Zombie, Monster)
@@ -111,8 +111,8 @@ float M_Zombie_Defend_Block()
 {SELFPARAM();
        self.armorvalue = 0.9;
        self.state = MONSTER_ATTACK_MELEE; // freeze monster
-       self.attack_finished_single = time + 2.1;
-       self.anim_finished = self.attack_finished_single;
+       self.attack_finished_single[0] = time + 2.1;
+       self.anim_finished = self.attack_finished_single[0];
        setanim(self, self.anim_blockstart, false, true, true);
 
        Monster_Delay(1, 0, 2, M_Zombie_Defend_Block_End);
index ac642fd3cbee0586793d5bf9639d6cadc02bdd23..a3610e17f7e76b27db8f694a1414d4603797ddca 100644 (file)
@@ -36,7 +36,7 @@ void monster_dropitem()
                return;
 
        vector org = self.origin + ((self.mins + self.maxs) * 0.5);
-       entity e = spawn();
+       entity e = new(droppedweapon); // use weapon handling to remove it on touch
        e.spawnfunc_checked = true;
 
        e.monster_loot = self.monster_loot;
@@ -55,7 +55,6 @@ void monster_dropitem()
                setorigin(e, org);
                e.velocity = randomvec() * 175 + '0 0 325';
                e.item_spawnshieldtime = time + 0.7;
-               e.classname = "droppedweapon"; // use weapon handling to remove it on touch
                SUB_SetFade(e, time + autocvar_g_monsters_drop_time, 1);
                setself(this);
        }
@@ -347,7 +346,7 @@ void Monster_Sound(.string samplefield, float sound_delay, float delaytoo, float
        if(delaytoo)
        if(time < self.msound_delay)
                return; // too early
-       GlobalSound(self.(samplefield), chan, VOICETYPE_PLAYERSOUND);
+       _GlobalSound(self.(samplefield), chan, VOICETYPE_PLAYERSOUND, false);
 
        self.msound_delay = time + sound_delay;
 }
@@ -364,9 +363,9 @@ float Monster_Attack_Melee(entity targ, float damg, vector anim, float er, float
        setanim(self, anim, false, true, false);
 
        if(self.animstate_endtime > time && (self.flags & FL_MONSTER))
-               self.attack_finished_single = self.anim_finished = self.animstate_endtime;
+               self.attack_finished_single[0] = self.anim_finished = self.animstate_endtime;
        else
-               self.attack_finished_single = self.anim_finished = time + animtime;
+               self.attack_finished_single[0] = self.anim_finished = time + animtime;
 
        monster_makevectors(targ);
 
@@ -386,7 +385,7 @@ float Monster_Attack_Leap_Check(vector vel)
                return false; // not on the ground
        if(self.health <= 0)
                return false; // called when dead?
-       if(time < self.attack_finished_single)
+       if(time < self.attack_finished_single[0])
                return false; // still attacking
 
        vector old = self.velocity;
@@ -408,9 +407,9 @@ bool Monster_Attack_Leap(vector anm, void() touchfunc, vector vel, float animtim
        setanim(self, anm, false, true, false);
 
        if(self.animstate_endtime > time && (self.flags & FL_MONSTER))
-               self.attack_finished_single = self.anim_finished = self.animstate_endtime;
+               self.attack_finished_single[0] = self.anim_finished = self.animstate_endtime;
        else
-               self.attack_finished_single = self.anim_finished = time + animtime;
+               self.attack_finished_single[0] = self.anim_finished = time + animtime;
 
        if(self.flags & FL_MONSTER)
                self.state = MONSTER_ATTACK_RANGED;
@@ -426,7 +425,7 @@ void Monster_Attack_Check(entity e, entity targ)
 {
        if((e == world || targ == world)
        || (!e.monster_attackfunc)
-       || (time < e.attack_finished_single)
+       || (time < e.attack_finished_single[0])
        ) { return; }
 
        float targ_vlen = vlen(targ.origin - e.origin);
@@ -845,7 +844,7 @@ void Monster_Move(float runspeed, float walkspeed, float stpspeed)
                self.touch = Monster_Touch;
        }
 
-       if(self.state && time >= self.attack_finished_single)
+       if(self.state && time >= self.attack_finished_single[0])
                self.state = 0; // attack is over
 
        if(self.state != MONSTER_ATTACK_MELEE) // don't move if set
@@ -911,12 +910,13 @@ void Monster_Move(float runspeed, float walkspeed, float stpspeed)
 
 void Monster_Remove(entity mon)
 {
+       .entity weaponentity = weaponentities[0];
        if(!mon) { return; }
 
        if(!MUTATOR_CALLHOOK(MonsterRemove, mon))
                Send_Effect(EFFECT_ITEM_PICKUP, mon.origin, '0 0 0', 1);
 
-       if(mon.weaponentity) { remove(mon.weaponentity); }
+       if(mon.(weaponentity)) { remove(mon.(weaponentity)); }
        if(mon.iceblock) { remove(mon.iceblock); }
        WaypointSprite_Kill(mon.sprite);
        remove(mon);
@@ -966,7 +966,7 @@ void Monster_Reset()
        self.velocity = '0 0 0';
        self.enemy = world;
        self.goalentity = world;
-       self.attack_finished_single = 0;
+       self.attack_finished_single[0] = 0;
        self.moveto = self.origin;
 }
 
@@ -1028,7 +1028,7 @@ void Monster_Dead(entity attacker, float gibbed)
        self.touch                      = Monster_Touch; // reset incase monster was pouncing
        self.reset                      = func_null;
        self.state                      = 0;
-       self.attack_finished_single = 0;
+       self.attack_finished_single[0] = 0;
        self.effects = 0;
 
        if(!((self.flags & FL_FLY) || (self.flags & FL_SWIM)))
@@ -1176,7 +1176,7 @@ void Monster_Move_2D(float mspeed, float allow_jumpoff)
        movelib_move_simple_gravity(v_forward, mspeed, 1);
 
        if(time > self.pain_finished)
-       if(time > self.attack_finished_single)
+       if(time > self.attack_finished_single[0])
        if(vlen(self.velocity) > 10)
                setanim(self, self.anim_walk, true, false, false);
        else
@@ -1376,9 +1376,15 @@ bool Monster_Spawn(int mon_id)
                self.movetype = MOVETYPE_FLY;
        }
 
-       if(mon.spawnflags & MONSTER_SIZE_BROKEN)
        if(!(self.spawnflags & MONSTERFLAG_RESPAWNED))
-               self.scale *= 1.3;
+       {
+               if(mon.spawnflags & MONSTER_SIZE_BROKEN)
+                       self.scale *= 1.3;
+
+               if(mon.spawnflags & MONSTER_SIZE_QUAKE)
+               if(autocvar_g_monsters_quake_resize)
+                       self.scale *= 1.3;
+       }
 
        setsize(self, mon.mins * self.scale, mon.maxs * self.scale);
 
index 67cd51e16b7d1e1a153558c2a103dd2115c49663..362075da2d3bfdd2f9a5e22378f547463678e40c 100644 (file)
@@ -2,9 +2,9 @@
 #define MOVETYPES_H
 
 .float move_ltime;
-.void(void)move_think;
+.void()move_think;
 .float move_nextthink;
-.void(void)move_blocked;
+.void()move_blocked;
 
 .float move_movetype;
 .float move_time;
@@ -15,7 +15,7 @@
 .int move_flags;
 .int move_watertype;
 .int move_waterlevel;
-.void(void)move_touch;
+.void()move_touch;
 .void(float, float)contentstransition;
 .float move_bounce_factor;
 .float move_bounce_stopspeed;
index 6b19a0bc6eb2043ab937335f731b675f8c91e24d..bef00c649e890c2b71cb34a392ae4c9d77542b1a 100644 (file)
@@ -1,5 +1,36 @@
-#include "mutator/casings.qc"
-#include "mutator/damagetext.qc"
-#include "mutator/instagib/instagib.qc"
+#include "mutator/waypoints/module.inc"
+
 #include "mutator/itemstime.qc"
-#include "mutator/waypoints/waypointsprites.qc"
+#include "mutator/multijump/module.inc"
+#include "mutator/nades/module.inc"
+#include "mutator/superspec/module.inc"
+
+// completely self contained
+
+#include "mutator/bloodloss/module.inc"
+#include "mutator/breakablehook/module.inc"
+#include "mutator/buffs/module.inc"
+#include "mutator/campcheck/module.inc"
+#include "mutator/cloaked/module.inc"
+#include "mutator/damagetext/module.inc"
+#include "mutator/dodging/module.inc"
+#include "mutator/hook/module.inc"
+#include "mutator/instagib/module.inc"
+#include "mutator/invincibleproj/module.inc"
+#include "mutator/melee_only/module.inc"
+#include "mutator/midair/module.inc"
+#include "mutator/new_toys/module.inc"
+#include "mutator/nix/module.inc"
+#include "mutator/overkill/module.inc"
+#include "mutator/physical_items/module.inc"
+#include "mutator/pinata/module.inc"
+#include "mutator/random_gravity/module.inc"
+#include "mutator/rocketflying/module.inc"
+#include "mutator/rocketminsta/module.inc"
+#include "mutator/running_guns/module.inc"
+#include "mutator/sandbox/module.inc"
+#include "mutator/spawn_near_teammate/module.inc"
+#include "mutator/touchexplode/module.inc"
+#include "mutator/vampirehook/module.inc"
+#include "mutator/vampire/module.inc"
+#include "mutator/weaponarena_random/module.inc"
index ce98cd508e90a9fe0314e70d1baaa09a0cecc8e8..7cfc297896ab7fd9e6ca91789e5e481455a21afa 100644 (file)
@@ -154,7 +154,8 @@ CLASS(Mutator, Object)
     }
 ENDCLASS(Mutator)
 
-REGISTRY(Mutators, BITS(6))
+REGISTRY(Mutators, BITS(7))
+#define Mutators_from(i) _Mutators_from(i, NULL)
 Mutator loaded_mutators[Mutators_MAX];
 
 bool Mutator_Add(Mutator mut)
@@ -209,7 +210,7 @@ void Mutator_Remove(Mutator mut)
         bool ret = MUTATORFUNCTION_##id##_hooks(mode); if (ret) return ret; \
     } \
     bool MUTATOR_##id##_check() { return dependence; } \
-    REGISTER(RegisterMutators, MUTATOR, Mutators, id, m_id, NEW(Mutator, #id, MUTATORFUNCTION_##id)) \
+    REGISTER(Mutators, MUTATOR, id, m_id, NEW(Mutator, #id, MUTATORFUNCTION_##id)) \
     { this.mutatorcheck = MUTATOR_##id##_check; } \
     [[accumulate]] bool MUTATORFUNCTION_##id(int mode)
 
index 7ba24fa7a42a63c20ff3e979c06697683a5c1a51..82898237c53f38e6a212b62ff4f7089ff348bc5b 100644 (file)
@@ -15,7 +15,8 @@ string ret_string;
     _(x, string) \
     /**/
 
-#define MUTATOR_NEWGLOBAL(x, type) type mutator_argv_##type##_##x;
+#define MUTATOR_ARGV(x, type) MUTATOR_ARGV_##x##_##type
+#define MUTATOR_NEWGLOBAL(x, type) type MUTATOR_ARGV(x, type);
 
 MUTATOR_TYPES(MUTATOR_NEWGLOBAL, 0)
 MUTATOR_TYPES(MUTATOR_NEWGLOBAL, 1)
@@ -47,4 +48,17 @@ MUTATOR_HOOKABLE(BuildMutatorsPrettyString, EV_BuildMutatorsPrettyString);
     /**/
 MUTATOR_HOOKABLE(BuildGameplayTipsString, EV_BuildGameplayTipsString);
 
+#define EV_IsFlying(i, o) \
+       /**/ i(entity, MUTATOR_ARGV_0_entity) \
+       /**/
+MUTATOR_HOOKABLE(IsFlying, EV_IsFlying);
+
+#define EV_WP_Format(i, o) \
+    /**/ i(entity, MUTATOR_ARGV_0_entity) \
+    /**/ i(string, MUTATOR_ARGV_0_string) \
+    /**/ o(vector, MUTATOR_ARGV_0_vector) \
+    /**/ o(string, MUTATOR_ARGV_0_string) \
+    /**/
+MUTATOR_HOOKABLE(WP_Format, EV_WP_Format);
+
 #endif
diff --git a/qcsrc/common/mutators/mutator/bloodloss/bloodloss.qc b/qcsrc/common/mutators/mutator/bloodloss/bloodloss.qc
new file mode 100644 (file)
index 0000000..ca37166
--- /dev/null
@@ -0,0 +1,45 @@
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(bloodloss, cvar("g_bloodloss"));
+
+.float bloodloss_timer;
+
+MUTATOR_HOOKFUNCTION(bloodloss, PlayerPreThink)
+{SELFPARAM();
+       if(IS_PLAYER(self))
+       if(self.health <= autocvar_g_bloodloss && self.deadflag == DEAD_NO)
+       {
+               self.BUTTON_CROUCH = true;
+
+               if(time >= self.bloodloss_timer)
+               {
+                       if(self.vehicle)
+                               vehicles_exit(VHEF_RELEASE);
+                       if(self.event_damage)
+                               self.event_damage(self, self, 1, DEATH_ROT.m_id, self.origin, '0 0 0');
+                       self.bloodloss_timer = time + 0.5 + random() * 0.5;
+               }
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(bloodloss, PlayerJump)
+{SELFPARAM();
+       if(self.health <= autocvar_g_bloodloss)
+               return true;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":bloodloss");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Blood loss");
+       return false;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/bloodloss/module.inc b/qcsrc/common/mutators/mutator/bloodloss/module.inc
new file mode 100644 (file)
index 0000000..d3f665a
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "bloodloss.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/breakablehook/breakablehook.qc b/qcsrc/common/mutators/mutator/breakablehook/breakablehook.qc
new file mode 100644 (file)
index 0000000..3ee077c
--- /dev/null
@@ -0,0 +1,29 @@
+#ifdef IMPLEMENTATION
+#include "../../../deathtypes/all.qh"
+#include "../../../../server/g_hook.qh"
+
+REGISTER_MUTATOR(breakablehook, cvar("g_breakablehook"));
+
+bool autocvar_g_breakablehook; // allow toggling mid match?
+bool autocvar_g_breakablehook_owner;
+
+MUTATOR_HOOKFUNCTION(breakablehook, PlayerDamage_Calculate)
+{
+       if(frag_target.classname == "grapplinghook")
+       {
+               if((!autocvar_g_breakablehook)
+               || (!autocvar_g_breakablehook_owner && frag_attacker == frag_target.realowner)
+                       ) { frag_damage = 0; }
+
+               // hurt the owner of the hook
+               if(DIFF_TEAM(frag_attacker, frag_target.realowner))
+               {
+                       Damage (frag_target.realowner, frag_attacker, frag_attacker, 5, WEP_HOOK.m_id | HITTYPE_SPLASH, frag_target.realowner.origin, '0 0 0');
+                       RemoveGrapplingHook(frag_target.realowner);
+                       return false; // dead
+               }
+       }
+
+       return false;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/breakablehook/module.inc b/qcsrc/common/mutators/mutator/breakablehook/module.inc
new file mode 100644 (file)
index 0000000..484eb4c
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "breakablehook.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/buffs/all.inc b/qcsrc/common/mutators/mutator/buffs/all.inc
new file mode 100644 (file)
index 0000000..25fa722
--- /dev/null
@@ -0,0 +1,118 @@
+REGISTER_BUFF(AMMO) {
+    this.m_prettyName = _("Ammo");
+    this.m_name = "ammo";
+    this.m_skin = 3;
+    this.m_color = '0.76 1 0.1';
+}
+BUFF_SPAWNFUNCS(ammo, BUFF_AMMO)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(ammoregen, BUFF_AMMO)
+
+REGISTER_BUFF(RESISTANCE) {
+    this.m_prettyName = _("Resistance");
+    this.m_name = "resistance";
+    this.m_skin = 0;
+    this.m_color = '0.36 1 0.07';
+}
+BUFF_SPAWNFUNCS(resistance, BUFF_RESISTANCE)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(resistance, BUFF_RESISTANCE)
+
+REGISTER_BUFF(SPEED) {
+    this.m_prettyName = _("Speed");
+    this.m_name = "speed";
+    this.m_skin = 9;
+    this.m_color = '0.1 1 0.84';
+}
+BUFF_SPAWNFUNCS(speed, BUFF_SPEED)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(haste, BUFF_SPEED)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(scout, BUFF_SPEED)
+
+REGISTER_BUFF(MEDIC) {
+    this.m_prettyName = _("Medic");
+    this.m_name = "medic";
+    this.m_skin = 1;
+    this.m_color = '1 0.12 0';
+}
+BUFF_SPAWNFUNCS(medic, BUFF_MEDIC)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(doubler, BUFF_MEDIC)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(medic, BUFF_MEDIC)
+
+REGISTER_BUFF(BASH) {
+    this.m_prettyName = _("Bash");
+    this.m_name = "bash";
+    this.m_skin = 5;
+    this.m_color = '1 0.39 0';
+}
+BUFF_SPAWNFUNCS(bash, BUFF_BASH)
+
+REGISTER_BUFF(VAMPIRE) {
+    this.m_prettyName = _("Vampire");
+    this.m_name = "vampire";
+    this.m_skin = 2;
+    this.m_color = '1 0 0.24';
+}
+BUFF_SPAWNFUNCS(vampire, BUFF_VAMPIRE)
+
+REGISTER_BUFF(DISABILITY) {
+    this.m_prettyName = _("Disability");
+    this.m_name = "disability";
+    this.m_skin = 7;
+    this.m_color = '0.94 0.3 1';
+}
+BUFF_SPAWNFUNCS(disability, BUFF_DISABILITY)
+
+REGISTER_BUFF(VENGEANCE) {
+    this.m_prettyName = _("Vengeance");
+    this.m_name = "vengeance";
+    this.m_skin = 15;
+    this.m_color = '1 0.23 0.61';
+}
+BUFF_SPAWNFUNCS(vengeance, BUFF_VENGEANCE)
+
+REGISTER_BUFF(JUMP) {
+    this.m_prettyName = _("Jump");
+    this.m_name = "jump";
+    this.m_skin = 10;
+    this.m_color = '0.24 0.78 1';
+}
+BUFF_SPAWNFUNCS(jump, BUFF_JUMP)
+
+REGISTER_BUFF(FLIGHT) {
+    this.m_prettyName = _("Flight");
+    this.m_name = "flight";
+    this.m_skin = 11;
+    this.m_color = '0.33 0.56 1';
+}
+BUFF_SPAWNFUNCS(flight, BUFF_FLIGHT)
+
+REGISTER_BUFF(INVISIBLE) {
+    this.m_prettyName = _("Invisible");
+    this.m_name = "invisible";
+    this.m_skin = 12;
+    this.m_color = '0.5 0.5 1';
+}
+BUFF_SPAWNFUNCS(invisible, BUFF_INVISIBLE)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(invis, BUFF_INVISIBLE)
+
+REGISTER_BUFF(INFERNO) {
+    this.m_prettyName = _("Inferno");
+    this.m_name = "inferno";
+    this.m_skin = 16;
+    this.m_color = '1 0.62 0';
+}
+BUFF_SPAWNFUNCS(inferno, BUFF_INFERNO)
+
+REGISTER_BUFF(SWAPPER) {
+    this.m_prettyName = _("Swapper");
+    this.m_name = "swapper";
+    this.m_skin = 17;
+    this.m_color = '0.63 0.36 1';
+}
+BUFF_SPAWNFUNCS(swapper, BUFF_SWAPPER)
+
+REGISTER_BUFF(MAGNET) {
+    this.m_prettyName = _("Magnet");
+    this.m_name = "magnet";
+    this.m_skin = 18;
+    this.m_color = '1 0.95 0.18';
+}
+BUFF_SPAWNFUNCS(magnet, BUFF_MAGNET)
diff --git a/qcsrc/common/mutators/mutator/buffs/all.qc b/qcsrc/common/mutators/mutator/buffs/all.qc
new file mode 100644 (file)
index 0000000..b056751
--- /dev/null
@@ -0,0 +1 @@
+#include "all.qh"
diff --git a/qcsrc/common/mutators/mutator/buffs/all.qh b/qcsrc/common/mutators/mutator/buffs/all.qh
new file mode 100644 (file)
index 0000000..94a00b9
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef BUFFS_ALL_H
+#define BUFFS_ALL_H
+// Welcome to the stuff behind the scenes
+// Below, you will find the list of buffs
+// Add new buffs here!
+// Note: Buffs also need spawnfuncs, which are set below
+
+#include "../../../teams.qh"
+#include "../../../util.qh"
+
+REGISTER_WAYPOINT(Buff, _("Buff"), '1 0.5 0', 1);
+REGISTER_RADARICON(Buff, 1);
+
+REGISTRY(Buffs, BITS(4))
+#define Buffs_from(i) _Buffs_from(i, BUFF_Null)
+REGISTER_REGISTRY(Buffs)
+REGISTRY_CHECK(Buffs)
+
+#define REGISTER_BUFF(id) \
+    REGISTER(Buffs, BUFF, id, m_id, NEW(Buff)); \
+    REGISTER_INIT_POST(BUFF, id) { \
+        this.netname = this.m_name; \
+        this.m_itemid = BIT(this.m_id - 1); \
+        this.m_sprite = strzone(strcat("buff-", this.m_name)); \
+    } \
+    REGISTER_INIT(BUFF, id)
+
+#include "../../../items/item/pickup.qh"
+CLASS(Buff, Pickup)
+       /** bit index */
+       ATTRIB(Buff, m_itemid, int, 0)
+       ATTRIB(Buff, m_name, string, "buff")
+       ATTRIB(Buff, m_color, vector, '1 1 1')
+       ATTRIB(Buff, m_prettyName, string, "Buff")
+       ATTRIB(Buff, m_skin, int, 0)
+       ATTRIB(Buff, m_sprite, string, "")
+       METHOD(Buff, display, void(entity this, void(string name, string icon) returns)) {
+               returns(this.m_prettyName, sprintf("/gfx/hud/%s/buff_%s", cvar_string("menu_skin"), this.m_name));
+       }
+#ifdef SVQC
+       METHOD(Buff, m_time, float(Buff this))
+       { return cvar(strcat("g_buffs_", this.netname, "_time")); }
+#endif
+ENDCLASS(Buff)
+
+#ifdef SVQC
+       .int buffs;
+       void buff_Init(entity ent);
+       void buff_Init_Compat(entity ent, entity replacement);
+       #define BUFF_SPAWNFUNC(e, b, t) spawnfunc(item_buff_##e) { \
+               self.buffs = b.m_itemid; \
+               self.team = t; \
+               buff_Init(self); \
+       }
+       #define BUFF_SPAWNFUNCS(e, b)                       \
+                       BUFF_SPAWNFUNC(e,           b,  0)          \
+                       BUFF_SPAWNFUNC(e##_team1,   b,  NUM_TEAM_1) \
+                       BUFF_SPAWNFUNC(e##_team2,   b,  NUM_TEAM_2) \
+                       BUFF_SPAWNFUNC(e##_team3,   b,  NUM_TEAM_3) \
+                       BUFF_SPAWNFUNC(e##_team4,   b,  NUM_TEAM_4)
+       #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r) spawnfunc(item_##o) { buff_Init_Compat(self, r); }
+#else
+       #define BUFF_SPAWNFUNC(e, b, t)
+       #define BUFF_SPAWNFUNCS(e, b)
+       #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r)
+#endif
+
+REGISTER_BUFF(Null);
+BUFF_SPAWNFUNCS(random, BUFF_Null)
+
+#include "all.inc"
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/buffs/buffs.qc b/qcsrc/common/mutators/mutator/buffs/buffs.qc
new file mode 100644 (file)
index 0000000..08f1aa3
--- /dev/null
@@ -0,0 +1,1050 @@
+#ifndef MUTATOR_BUFFS_H
+#define MUTATOR_BUFFS_H
+
+#include "../instagib/module.inc"
+
+bool  autocvar_g_buffs_effects;
+float autocvar_g_buffs_waypoint_distance;
+bool autocvar_g_buffs_randomize;
+float autocvar_g_buffs_random_lifetime;
+bool autocvar_g_buffs_random_location;
+int autocvar_g_buffs_random_location_attempts;
+int autocvar_g_buffs_spawn_count;
+bool autocvar_g_buffs_replace_powerups;
+float autocvar_g_buffs_cooldown_activate;
+float autocvar_g_buffs_cooldown_respawn;
+float autocvar_g_buffs_resistance_blockpercent;
+float autocvar_g_buffs_medic_survive_chance;
+float autocvar_g_buffs_medic_survive_health;
+float autocvar_g_buffs_medic_rot;
+float autocvar_g_buffs_medic_max;
+float autocvar_g_buffs_medic_regen;
+float autocvar_g_buffs_vengeance_damage_multiplier;
+float autocvar_g_buffs_bash_force;
+float autocvar_g_buffs_bash_force_self;
+float autocvar_g_buffs_disability_slowtime;
+float autocvar_g_buffs_disability_speed;
+float autocvar_g_buffs_disability_rate;
+float autocvar_g_buffs_disability_weaponspeed;
+float autocvar_g_buffs_speed_speed;
+float autocvar_g_buffs_speed_rate;
+float autocvar_g_buffs_speed_weaponspeed;
+float autocvar_g_buffs_speed_damage_take;
+float autocvar_g_buffs_speed_regen;
+float autocvar_g_buffs_vampire_damage_steal;
+float autocvar_g_buffs_invisible_alpha;
+float autocvar_g_buffs_flight_gravity;
+float autocvar_g_buffs_jump_height;
+float autocvar_g_buffs_inferno_burntime_factor;
+float autocvar_g_buffs_inferno_burntime_min_time;
+float autocvar_g_buffs_inferno_burntime_target_damage;
+float autocvar_g_buffs_inferno_burntime_target_time;
+float autocvar_g_buffs_inferno_damagemultiplier;
+float autocvar_g_buffs_swapper_range;
+float autocvar_g_buffs_magnet_range_item;
+
+// ammo
+.float buff_ammo_prev_infitems;
+.int buff_ammo_prev_clipload;
+// invisible
+.float buff_invisible_prev_alpha;
+// flight
+.float buff_flight_prev_gravity;
+// disability
+.float buff_disability_time;
+.float buff_disability_effect_time;
+// common buff variables
+.float buff_effect_delay;
+
+// buff definitions
+.float buff_active;
+.float buff_activetime;
+.float buff_activetime_updated;
+.entity buff_waypoint;
+.int oldbuffs; // for updating effects
+.entity buff_model; // controls effects (TODO: make csqc)
+
+const vector BUFF_MIN = ('-16 -16 -20');
+const vector BUFF_MAX = ('16 16 20');
+
+// client side options
+.float cvar_cl_buffs_autoreplace;
+#endif
+
+#ifdef IMPLEMENTATION
+
+#include "../../../triggers/target/music.qh"
+#include "../../../gamemodes/all.qh"
+
+.float buff_time;
+void buffs_DelayedInit();
+
+REGISTER_MUTATOR(buffs, cvar("g_buffs"))
+{
+       MUTATOR_ONADD
+       {
+               addstat(STAT_BUFFS, AS_INT, buffs);
+               addstat(STAT_BUFF_TIME, AS_FLOAT, buff_time);
+
+               InitializeEntity(world, buffs_DelayedInit, INITPRIO_FINDTARGET);
+       }
+}
+
+entity buff_FirstFromFlags(int _buffs)
+{
+       if (flags)
+       {
+               FOREACH(Buffs, it.m_itemid & _buffs, LAMBDA(return it));
+       }
+       return BUFF_Null;
+}
+
+bool buffs_BuffModel_Customize()
+{SELFPARAM();
+       entity player, myowner;
+       bool same_team;
+
+       player = WaypointSprite_getviewentity(other);
+       myowner = self.owner;
+       same_team = (SAME_TEAM(player, myowner) || SAME_TEAM(player, myowner));
+
+       if(myowner.alpha <= 0.5 && !same_team && myowner.alpha != 0)
+               return false;
+
+       if(MUTATOR_CALLHOOK(BuffModel_Customize, self, player))
+               return false;
+
+       if(player == myowner || (IS_SPEC(other) && other.enemy == myowner))
+       {
+               // somewhat hide the model, but keep the glow
+               self.effects = 0;
+               self.alpha = -1;
+       }
+       else
+       {
+               self.effects = EF_FULLBRIGHT | EF_LOWPRECISION;
+               self.alpha = 1;
+       }
+       return true;
+}
+
+void buffs_BuffModel_Spawn(entity player)
+{
+       player.buff_model = spawn();
+       setmodel(player.buff_model, MDL_BUFF);
+       setsize(player.buff_model, '0 0 -40', '0 0 40');
+       setattachment(player.buff_model, player, "");
+       setorigin(player.buff_model, '0 0 1' * (player.buff_model.maxs.z * 1));
+       player.buff_model.owner = player;
+       player.buff_model.scale = 0.7;
+       player.buff_model.pflags = PFLAGS_FULLDYNAMIC;
+       player.buff_model.light_lev = 200;
+       player.buff_model.customizeentityforclient = buffs_BuffModel_Customize;
+}
+
+vector buff_GlowColor(entity buff)
+{
+       //if(buff.team) { return Team_ColorRGB(buff.team); }
+       return buff.m_color;
+}
+
+void buff_Effect(entity player, string eff)
+{SELFPARAM();
+       if(!autocvar_g_buffs_effects) { return; }
+
+       if(time >= self.buff_effect_delay)
+       {
+               Send_Effect_(eff, player.origin + ((player.mins + player.maxs) * 0.5), '0 0 0', 1);
+               self.buff_effect_delay = time + 0.05; // prevent spam
+       }
+}
+
+// buff item
+float buff_Waypoint_visible_for_player(entity plr)
+{SELFPARAM();
+       if(!self.owner.buff_active && !self.owner.buff_activetime)
+               return false;
+
+       if (plr.buffs)
+       {
+               return plr.cvar_cl_buffs_autoreplace == false || plr.buffs != self.owner.buffs;
+       }
+
+       return WaypointSprite_visible_for_player(plr);
+}
+
+void buff_Waypoint_Spawn(entity e)
+{
+       entity buff = buff_FirstFromFlags(e.buffs);
+       entity wp = WaypointSprite_Spawn(WP_Buff, 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, world, e.team, e, buff_waypoint, true, RADARICON_Buff);
+       wp.wp_extra = buff.m_id;
+       WaypointSprite_UpdateTeamRadar(e.buff_waypoint, RADARICON_Buff, e.glowmod);
+       e.buff_waypoint.waypointsprite_visible_for_player = buff_Waypoint_visible_for_player;
+}
+
+void buff_SetCooldown(float cd)
+{SELFPARAM();
+       cd = max(0, cd);
+
+       if(!self.buff_waypoint)
+               buff_Waypoint_Spawn(self);
+
+       WaypointSprite_UpdateBuildFinished(self.buff_waypoint, time + cd);
+       self.buff_activetime = cd;
+       self.buff_active = !cd;
+}
+
+void buff_Respawn(entity ent)
+{SELFPARAM();
+       if(gameover) { return; }
+
+       vector oldbufforigin = ent.origin;
+
+       if(!MoveToRandomMapLocation(ent, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, ((autocvar_g_buffs_random_location_attempts > 0) ? autocvar_g_buffs_random_location_attempts : 10), 1024, 256))
+       {
+               entity spot = SelectSpawnPoint(true);
+               setorigin(ent, spot.origin + '0 0 200');
+               ent.angles = spot.angles;
+       }
+
+       tracebox(ent.origin, ent.mins * 1.5, self.maxs * 1.5, ent.origin, MOVE_NOMONSTERS, ent);
+
+       setorigin(ent, trace_endpos); // attempt to unstick
+
+       ent.movetype = MOVETYPE_TOSS;
+
+       makevectors(ent.angles);
+       ent.velocity = '0 0 200';
+       ent.angles = '0 0 0';
+       if(autocvar_g_buffs_random_lifetime > 0)
+               ent.lifetime = time + autocvar_g_buffs_random_lifetime;
+
+       Send_Effect(EFFECT_ELECTRO_COMBO, oldbufforigin + ((ent.mins + ent.maxs) * 0.5), '0 0 0', 1);
+       Send_Effect(EFFECT_ELECTRO_COMBO, CENTER_OR_VIEWOFS(ent), '0 0 0', 1);
+
+       WaypointSprite_Ping(ent.buff_waypoint);
+
+       sound(ent, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
+}
+
+void buff_Touch()
+{SELFPARAM();
+       if(gameover) { return; }
+
+       if(ITEM_TOUCH_NEEDKILL())
+       {
+               buff_Respawn(self);
+               return;
+       }
+
+       if((self.team && DIFF_TEAM(other, self))
+       || (other.frozen)
+       || (other.vehicle)
+       || (!self.buff_active)
+       )
+       {
+               // can't touch this
+               return;
+       }
+
+       if(MUTATOR_CALLHOOK(BuffTouch, self, other))
+               return;
+
+       if(!IS_PLAYER(other))
+               return; // incase mutator changed other
+
+       if (other.buffs)
+       {
+               if (other.cvar_cl_buffs_autoreplace && other.buffs != self.buffs)
+               {
+                       int buffid = buff_FirstFromFlags(other.buffs).m_id;
+                       //Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_DROP, other.buffs);
+                       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ITEM_BUFF_LOST, other.netname, buffid);
+
+                       other.buffs = 0;
+                       //sound(other, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+               }
+               else { return; } // do nothing
+       }
+
+       self.owner = other;
+       self.buff_active = false;
+       self.lifetime = 0;
+       int buffid = buff_FirstFromFlags(self.buffs).m_id;
+       Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_GOT, buffid);
+       Send_Notification(NOTIF_ALL_EXCEPT, other, MSG_INFO, INFO_ITEM_BUFF, other.netname, buffid);
+
+       Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
+       sound(other, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
+       other.buffs |= (self.buffs);
+}
+
+float buff_Available(entity buff)
+{
+       if (buff == BUFF_Null)
+               return false;
+       if (buff == BUFF_AMMO && ((start_items & IT_UNLIMITED_WEAPON_AMMO) || (start_items & IT_UNLIMITED_AMMO) || (cvar("g_melee_only"))))
+               return false;
+       if (buff == BUFF_VAMPIRE && cvar("g_vampire"))
+               return false;
+       return cvar(strcat("g_buffs_", buff.m_name));
+}
+
+.int buff_seencount;
+
+void buff_NewType(entity ent, float cb)
+{
+       RandomSelection_Init();
+       FOREACH(Buffs, buff_Available(it), LAMBDA(
+               it.buff_seencount += 1;
+               // if it's already been chosen, give it a lower priority
+               RandomSelection_Add(world, it.m_itemid, string_null, 1, max(0.2, 1 / it.buff_seencount));
+       ));
+       ent.buffs = RandomSelection_chosen_float;
+}
+
+void buff_Think()
+{SELFPARAM();
+       if(self.buffs != self.oldbuffs)
+       {
+               entity buff = buff_FirstFromFlags(self.buffs);
+               self.color = buff.m_color;
+               self.glowmod = buff_GlowColor(buff);
+               self.skin = buff.m_skin;
+
+               setmodel(self, MDL_BUFF);
+
+               if(self.buff_waypoint)
+               {
+                       //WaypointSprite_Disown(self.buff_waypoint, 1);
+                       WaypointSprite_Kill(self.buff_waypoint);
+                       buff_Waypoint_Spawn(self);
+                       if(self.buff_activetime)
+                               WaypointSprite_UpdateBuildFinished(self.buff_waypoint, time + self.buff_activetime - frametime);
+               }
+
+               self.oldbuffs = self.buffs;
+       }
+
+       if(!gameover)
+       if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
+       if(!self.buff_activetime_updated)
+       {
+               buff_SetCooldown(self.buff_activetime);
+               self.buff_activetime_updated = true;
+       }
+
+       if(!self.buff_active && !self.buff_activetime)
+       if(!self.owner || self.owner.frozen || self.owner.deadflag != DEAD_NO || !self.owner.iscreature || !(self.owner.buffs & self.buffs))
+       {
+               buff_SetCooldown(autocvar_g_buffs_cooldown_respawn + frametime);
+               self.owner = world;
+               if(autocvar_g_buffs_randomize)
+                       buff_NewType(self, self.buffs);
+
+               if(autocvar_g_buffs_random_location || (self.spawnflags & 64))
+                       buff_Respawn(self);
+       }
+
+       if(self.buff_activetime)
+       if(!gameover)
+       if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
+       {
+               self.buff_activetime = max(0, self.buff_activetime - frametime);
+
+               if(!self.buff_activetime)
+               {
+                       self.buff_active = true;
+                       sound(self, CH_TRIGGER, SND_STRENGTH_RESPAWN, VOL_BASE, ATTN_NORM);
+                       Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
+               }
+       }
+
+       if(self.buff_active)
+       {
+               if(self.team && !self.buff_waypoint)
+                       buff_Waypoint_Spawn(self);
+
+               if(self.lifetime)
+               if(time >= self.lifetime)
+                       buff_Respawn(self);
+       }
+
+       self.nextthink = time;
+       //self.angles_y = time * 110.1;
+}
+
+void buff_Waypoint_Reset()
+{SELFPARAM();
+       WaypointSprite_Kill(self.buff_waypoint);
+
+       if(self.buff_activetime) { buff_Waypoint_Spawn(self); }
+}
+
+void buff_Reset()
+{SELFPARAM();
+       if(autocvar_g_buffs_randomize)
+               buff_NewType(self, self.buffs);
+       self.owner = world;
+       buff_SetCooldown(autocvar_g_buffs_cooldown_activate);
+       buff_Waypoint_Reset();
+       self.buff_activetime_updated = false;
+
+       if(autocvar_g_buffs_random_location || (self.spawnflags & 64))
+               buff_Respawn(self);
+}
+
+float buff_Customize()
+{SELFPARAM();
+       entity player = WaypointSprite_getviewentity(other);
+       if(!self.buff_active || (self.team && DIFF_TEAM(player, self)))
+       {
+               self.alpha = 0.3;
+               if(self.effects & EF_FULLBRIGHT) { self.effects &= ~(EF_FULLBRIGHT); }
+               self.pflags = 0;
+       }
+       else
+       {
+               self.alpha = 1;
+               if(!(self.effects & EF_FULLBRIGHT)) { self.effects |= EF_FULLBRIGHT; }
+               self.light_lev = 220 + 36 * sin(time);
+               self.pflags = PFLAGS_FULLDYNAMIC;
+       }
+       return true;
+}
+
+void buff_Init(entity ent)
+{SELFPARAM();
+       if(!cvar("g_buffs")) { remove(ent); return; }
+
+       if(!teamplay && ent.team) { ent.team = 0; }
+
+       entity buff = buff_FirstFromFlags(self.buffs);
+
+       setself(ent);
+       if(!self.buffs || buff_Available(buff))
+               buff_NewType(self, 0);
+
+       self.classname = "item_buff";
+       self.solid = SOLID_TRIGGER;
+       self.flags = FL_ITEM;
+       self.think = buff_Think;
+       self.touch = buff_Touch;
+       self.reset = buff_Reset;
+       self.nextthink = time + 0.1;
+       self.gravity = 1;
+       self.movetype = MOVETYPE_TOSS;
+       self.scale = 1;
+       self.skin = buff.m_skin;
+       self.effects = EF_FULLBRIGHT | EF_STARDUST | EF_NOSHADOW;
+       self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
+       self.customizeentityforclient = buff_Customize;
+       //self.gravity = 100;
+       self.color = buff.m_color;
+       self.glowmod = buff_GlowColor(self);
+       buff_SetCooldown(autocvar_g_buffs_cooldown_activate + game_starttime);
+       self.buff_active = !self.buff_activetime;
+       self.pflags = PFLAGS_FULLDYNAMIC;
+
+       if(self.spawnflags & 1)
+               self.noalign = true;
+
+       if(self.noalign)
+               self.movetype = MOVETYPE_NONE; // reset by random location
+
+       setmodel(self, MDL_BUFF);
+       setsize(self, BUFF_MIN, BUFF_MAX);
+
+       if(cvar("g_buffs_random_location") || (self.spawnflags & 64))
+               buff_Respawn(self);
+
+       setself(this);
+}
+
+void buff_Init_Compat(entity ent, entity replacement)
+{
+       if (ent.spawnflags & 2)
+               ent.team = NUM_TEAM_1;
+       else if (ent.spawnflags & 4)
+               ent.team = NUM_TEAM_2;
+
+       ent.buffs = replacement.m_itemid;
+
+       buff_Init(ent);
+}
+
+void buff_SpawnReplacement(entity ent, entity old)
+{
+       setorigin(ent, old.origin);
+       ent.angles = old.angles;
+       ent.noalign = (old.noalign || (old.spawnflags & 1));
+
+       buff_Init(ent);
+}
+
+void buff_Vengeance_DelayedDamage()
+{SELFPARAM();
+       if(self.enemy)
+               Damage(self.enemy, self.owner, self.owner, self.dmg, DEATH_BUFF.m_id, self.enemy.origin, '0 0 0');
+
+       remove(self);
+       return;
+}
+
+float buff_Inferno_CalculateTime(float x, float offset_x, float offset_y, float intersect_x, float intersect_y, float base)
+{
+       return offset_y + (intersect_y - offset_y) * logn(((x - offset_x) * ((base - 1) / intersect_x)) + 1, base);
+}
+
+// mutator hooks
+MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_SplitHealthArmor)
+{
+       if(frag_deathtype == DEATH_BUFF.m_id) { return false; }
+
+       if(frag_target.buffs & BUFF_RESISTANCE.m_itemid)
+       {
+               vector v = healtharmor_applydamage(50, autocvar_g_buffs_resistance_blockpercent, frag_deathtype, frag_damage);
+               damage_take = v.x;
+               damage_save = v.y;
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_Calculate)
+{
+       if(frag_deathtype == DEATH_BUFF.m_id) { return false; }
+
+       if(frag_target.buffs & BUFF_SPEED.m_itemid)
+       if(frag_target != frag_attacker)
+               frag_damage *= autocvar_g_buffs_speed_damage_take;
+
+       if(frag_target.buffs & BUFF_MEDIC.m_itemid)
+       if((frag_target.health - frag_damage) <= 0)
+       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+       if(frag_attacker)
+       if(random() <= autocvar_g_buffs_medic_survive_chance)
+               frag_damage = max(5, frag_target.health - autocvar_g_buffs_medic_survive_health);
+
+       if(frag_target.buffs & BUFF_JUMP.m_itemid)
+       if(frag_deathtype == DEATH_FALL.m_id)
+               frag_damage = 0;
+
+       if(frag_target.buffs & BUFF_VENGEANCE.m_itemid)
+       if(frag_attacker)
+       if(frag_attacker != frag_target)
+       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+       {
+               entity dmgent = spawn();
+
+               dmgent.dmg = frag_damage * autocvar_g_buffs_vengeance_damage_multiplier;
+               dmgent.enemy = frag_attacker;
+               dmgent.owner = frag_target;
+               dmgent.think = buff_Vengeance_DelayedDamage;
+               dmgent.nextthink = time + 0.1;
+       }
+
+       if(frag_target.buffs & BUFF_BASH.m_itemid)
+       if(frag_attacker != frag_target)
+       if(vlen(frag_force))
+               frag_force = '0 0 0';
+
+       if(frag_attacker.buffs & BUFF_BASH.m_itemid)
+       if(vlen(frag_force))
+       if(frag_attacker == frag_target)
+               frag_force *= autocvar_g_buffs_bash_force_self;
+       else
+               frag_force *= autocvar_g_buffs_bash_force;
+
+       if(frag_attacker.buffs & BUFF_DISABILITY.m_itemid)
+       if(frag_target != frag_attacker)
+               frag_target.buff_disability_time = time + autocvar_g_buffs_disability_slowtime;
+
+       if(frag_attacker.buffs & BUFF_MEDIC.m_itemid)
+       if(DEATH_WEAPONOF(frag_deathtype) != WEP_ARC)
+       if(SAME_TEAM(frag_attacker, frag_target))
+       if(frag_attacker != frag_target)
+       {
+               frag_target.health = min(g_pickup_healthmega_max, frag_target.health + frag_damage);
+               frag_damage = 0;
+       }
+
+       if(frag_attacker.buffs & BUFF_INFERNO.m_itemid)
+       if(frag_target != frag_attacker) {
+               float time = buff_Inferno_CalculateTime(
+                       frag_damage,
+                       0,
+                       autocvar_g_buffs_inferno_burntime_min_time,
+                       autocvar_g_buffs_inferno_burntime_target_damage,
+                       autocvar_g_buffs_inferno_burntime_target_time,
+                       autocvar_g_buffs_inferno_burntime_factor
+               );
+               Fire_AddDamage(frag_target, frag_attacker, (frag_damage * autocvar_g_buffs_inferno_damagemultiplier) * time, time, DEATH_BUFF.m_id);
+       }
+
+       // this... is ridiculous (TODO: fix!)
+       if(frag_attacker.buffs & BUFF_VAMPIRE.m_itemid)
+       if(!frag_target.vehicle)
+       if(DEATH_WEAPONOF(frag_deathtype) != WEP_ARC)
+       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
+       if(frag_target.deadflag == DEAD_NO)
+       if(IS_PLAYER(frag_target) || IS_MONSTER(frag_target))
+       if(frag_attacker != frag_target)
+       if(!frag_target.frozen)
+       if(frag_target.takedamage)
+       if(DIFF_TEAM(frag_attacker, frag_target))
+       {
+               frag_attacker.health = bound(0, frag_attacker.health + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.health), g_pickup_healthsmall_max);
+               if(frag_target.armorvalue)
+                       frag_attacker.armorvalue = bound(0, frag_attacker.armorvalue + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.armorvalue), g_pickup_armorsmall_max);
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs,PlayerSpawn)
+{SELFPARAM();
+       self.buffs = 0;
+       // reset timers here to prevent them continuing after re-spawn
+       self.buff_disability_time = 0;
+       self.buff_disability_effect_time = 0;
+       return false;
+}
+
+.float stat_sv_maxspeed;
+.float stat_sv_airspeedlimit_nonqw;
+.float stat_sv_jumpvelocity;
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics)
+{SELFPARAM();
+       if(self.buffs & BUFF_SPEED.m_itemid)
+       {
+               self.stat_sv_maxspeed *= autocvar_g_buffs_speed_speed;
+               self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_speed_speed;
+       }
+
+       if(time < self.buff_disability_time)
+       {
+               self.stat_sv_maxspeed *= autocvar_g_buffs_disability_speed;
+               self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_disability_speed;
+       }
+
+       if(self.buffs & BUFF_JUMP.m_itemid)
+       {
+               // automatically reset, no need to worry
+               self.stat_sv_jumpvelocity = autocvar_g_buffs_jump_height;
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerJump)
+{SELFPARAM();
+       if(self.buffs & BUFF_JUMP.m_itemid)
+               player_jumpheight = autocvar_g_buffs_jump_height;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, MonsterMove)
+{SELFPARAM();
+       if(time < self.buff_disability_time)
+       {
+               monster_speed_walk *= autocvar_g_buffs_disability_speed;
+               monster_speed_run *= autocvar_g_buffs_disability_speed;
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerDies)
+{SELFPARAM();
+       if(self.buffs)
+       {
+               int buffid = buff_FirstFromFlags(self.buffs).m_id;
+               Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
+               self.buffs = 0;
+
+               if(self.buff_model)
+               {
+                       remove(self.buff_model);
+                       self.buff_model = world;
+               }
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerUseKey, CBC_ORDER_FIRST)
+{SELFPARAM();
+       if(MUTATOR_RETURNVALUE || gameover) { return false; }
+       if(self.buffs)
+       {
+               int buffid = buff_FirstFromFlags(self.buffs).m_id;
+               Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_BUFF_DROP, buffid);
+               Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
+
+               self.buffs = 0;
+               sound(self, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+               return true;
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon)
+{SELFPARAM();
+       if(MUTATOR_RETURNVALUE || gameover) { return false; }
+
+       if(self.buffs & BUFF_SWAPPER.m_itemid)
+       {
+               float best_distance = autocvar_g_buffs_swapper_range;
+               entity closest = world;
+               entity player;
+               FOR_EACH_PLAYER(player)
+               if(DIFF_TEAM(self, player))
+               if(player.deadflag == DEAD_NO && !player.frozen && !player.vehicle)
+               if(vlen(self.origin - player.origin) <= best_distance)
+               {
+                       best_distance = vlen(self.origin - player.origin);
+                       closest = player;
+               }
+
+               if(closest)
+               {
+                       vector my_org, my_vel, my_ang, their_org, their_vel, their_ang;
+
+                       my_org = self.origin;
+                       my_vel = self.velocity;
+                       my_ang = self.angles;
+                       their_org = closest.origin;
+                       their_vel = closest.velocity;
+                       their_ang = closest.angles;
+
+                       Drop_Special_Items(closest);
+
+                       MUTATOR_CALLHOOK(PortalTeleport, self); // initiate flag dropper
+
+                       setorigin(self, their_org);
+                       setorigin(closest, my_org);
+
+                       closest.velocity = my_vel;
+                       closest.angles = my_ang;
+                       closest.fixangle = true;
+                       closest.oldorigin = my_org;
+                       closest.oldvelocity = my_vel;
+                       self.velocity = their_vel;
+                       self.angles = their_ang;
+                       self.fixangle = true;
+                       self.oldorigin = their_org;
+                       self.oldvelocity = their_vel;
+
+                       // set pusher so self gets the kill if they fall into void
+                       closest.pusher = self;
+                       closest.pushltime = time + autocvar_g_maxpushtime;
+                       closest.istypefrag = closest.BUTTON_CHAT;
+
+                       Send_Effect(EFFECT_ELECTRO_COMBO, their_org, '0 0 0', 1);
+                       Send_Effect(EFFECT_ELECTRO_COMBO, my_org, '0 0 0', 1);
+
+                       sound(self, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
+                       sound(closest, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
+
+                       // TODO: add a counter to handle how many times one can teleport, and a delay to prevent spam
+                       self.buffs = 0;
+                       return true;
+               }
+       }
+       return false;
+}
+
+bool buffs_RemovePlayer(entity player)
+{
+       if(player.buff_model)
+       {
+               remove(player.buff_model);
+               player.buff_model = world;
+       }
+
+       // also reset timers here to prevent them continuing after spectating
+       player.buff_disability_time = 0;
+       player.buff_disability_effect_time = 0;
+
+       return false;
+}
+MUTATOR_HOOKFUNCTION(buffs, MakePlayerObserver) { return buffs_RemovePlayer(self); }
+MUTATOR_HOOKFUNCTION(buffs, ClientDisconnect) { return buffs_RemovePlayer(self); }
+
+MUTATOR_HOOKFUNCTION(buffs, CustomizeWaypoint)
+{SELFPARAM();
+       entity e = WaypointSprite_getviewentity(other);
+
+       // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
+       // but only apply this to real players, not to spectators
+       if((self.owner.flags & FL_CLIENT) && (self.owner.buffs & BUFF_INVISIBLE.m_itemid) && (e == other))
+       if(DIFF_TEAM(self.owner, e))
+               return true;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, OnEntityPreSpawn, CBC_ORDER_LAST)
+{SELFPARAM();
+       if (self.classname == "item_flight" && cvar("g_buffs") && cvar("g_buffs_flight"))
+       {
+               buff_Init_Compat(self, BUFF_FLIGHT);
+               return true;
+       }
+       if(autocvar_g_buffs_replace_powerups)
+       switch(self.classname)
+       {
+               case "item_strength":
+               case "item_invincible":
+               {
+                       entity e = spawn();
+                       buff_SpawnReplacement(e, self);
+                       return true;
+               }
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, WeaponRateFactor)
+{SELFPARAM();
+       if(self.buffs & BUFF_SPEED.m_itemid)
+               weapon_rate *= autocvar_g_buffs_speed_rate;
+
+       if(time < self.buff_disability_time)
+               weapon_rate *= autocvar_g_buffs_disability_rate;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, WeaponSpeedFactor)
+{SELFPARAM();
+       if(self.buffs & BUFF_SPEED.m_itemid)
+               ret_float *= autocvar_g_buffs_speed_weaponspeed;
+
+       if(time < self.buff_disability_time)
+               ret_float *= autocvar_g_buffs_disability_weaponspeed;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
+{SELFPARAM();
+       if(gameover || self.deadflag != DEAD_NO) { return false; }
+
+       if(time < self.buff_disability_time)
+       if(time >= self.buff_disability_effect_time)
+       {
+               Send_Effect(EFFECT_SMOKING, self.origin + ((self.mins + self.maxs) * 0.5), '0 0 0', 1);
+               self.buff_disability_effect_time = time + 0.5;
+       }
+
+       // handle buff lost status
+       // 1: notify everyone else
+       // 2: notify carrier as well
+       int buff_lost = 0;
+
+       if(self.buff_time)
+       if(time >= self.buff_time)
+               buff_lost = 2;
+
+       if(self.frozen) { buff_lost = 1; }
+
+       if(buff_lost)
+       {
+               if(self.buffs)
+               {
+                       int buffid = buff_FirstFromFlags(self.buffs).m_id;
+                       Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
+                       if(buff_lost >= 2)
+                       {
+                               Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_BUFF_DROP, buffid); // TODO: special timeout message?
+                               sound(self, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+                       }
+                       self.buffs = 0;
+               }
+       }
+
+       if(self.buffs & BUFF_MAGNET.m_itemid)
+       {
+               vector pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_item;
+               for(other = world; (other = findflags(other, flags, FL_ITEM)); )
+               if(boxesoverlap(self.absmin - pickup_size, self.absmax + pickup_size, other.absmin, other.absmax))
+               {
+                       setself(other);
+                       other = this;
+                       if(self.touch)
+                               self.touch();
+                       other = self;
+                       setself(this);
+               }
+       }
+
+       if(self.buffs & BUFF_AMMO.m_itemid)
+       if(self.clip_size)
+               self.clip_load = self.(weapon_load[self.switchweapon]) = self.clip_size;
+
+       if((self.buffs & BUFF_INVISIBLE.m_itemid) && (self.oldbuffs & BUFF_INVISIBLE.m_itemid))
+       if(self.alpha != autocvar_g_buffs_invisible_alpha)
+               self.alpha = autocvar_g_buffs_invisible_alpha; // powerups reset alpha, so we must enforce this (TODO)
+
+#define BUFF_ONADD(b) if ( (self.buffs & (b).m_itemid) && !(self.oldbuffs & (b).m_itemid))
+#define BUFF_ONREM(b) if (!(self.buffs & (b).m_itemid) &&  (self.oldbuffs & (b).m_itemid))
+
+       if(self.buffs != self.oldbuffs)
+       {
+               entity buff = buff_FirstFromFlags(self.buffs);
+               float bufftime = buff != BUFF_Null ? buff.m_time(buff) : 0;
+               self.buff_time = (bufftime) ? time + bufftime : 0;
+
+               BUFF_ONADD(BUFF_AMMO)
+               {
+                       self.buff_ammo_prev_infitems = (self.items & IT_UNLIMITED_WEAPON_AMMO);
+                       self.items |= IT_UNLIMITED_WEAPON_AMMO;
+
+                       if(self.clip_load)
+                               self.buff_ammo_prev_clipload = self.clip_load;
+                       self.clip_load = self.(weapon_load[self.switchweapon]) = self.clip_size;
+               }
+
+               BUFF_ONREM(BUFF_AMMO)
+               {
+                       if(self.buff_ammo_prev_infitems)
+                               self.items |= IT_UNLIMITED_WEAPON_AMMO;
+                       else
+                               self.items &= ~IT_UNLIMITED_WEAPON_AMMO;
+
+                       if(self.buff_ammo_prev_clipload)
+                               self.clip_load = self.buff_ammo_prev_clipload;
+               }
+
+               BUFF_ONADD(BUFF_INVISIBLE)
+               {
+                       if(time < self.strength_finished && g_instagib)
+                               self.alpha = autocvar_g_instagib_invis_alpha;
+                       else
+                               self.alpha = self.buff_invisible_prev_alpha;
+                       self.alpha = autocvar_g_buffs_invisible_alpha;
+               }
+
+               BUFF_ONREM(BUFF_INVISIBLE)
+                       self.alpha = self.buff_invisible_prev_alpha;
+
+               BUFF_ONADD(BUFF_FLIGHT)
+               {
+                       self.buff_flight_prev_gravity = self.gravity;
+                       self.gravity = autocvar_g_buffs_flight_gravity;
+               }
+
+               BUFF_ONREM(BUFF_FLIGHT)
+                       self.gravity = self.buff_flight_prev_gravity;
+
+               self.oldbuffs = self.buffs;
+               if(self.buffs)
+               {
+                       if(!self.buff_model)
+                               buffs_BuffModel_Spawn(self);
+
+                       self.buff_model.color = buff.m_color;
+                       self.buff_model.glowmod = buff_GlowColor(self.buff_model);
+                       self.buff_model.skin = buff.m_skin;
+
+                       self.effects |= EF_NOSHADOW;
+               }
+               else
+               {
+                       remove(self.buff_model);
+                       self.buff_model = world;
+
+                       self.effects &= ~(EF_NOSHADOW);
+               }
+       }
+
+       if(self.buff_model)
+       {
+               self.buff_model.effects = self.effects;
+               self.buff_model.effects |= EF_LOWPRECISION;
+               self.buff_model.effects = self.buff_model.effects & EFMASK_CHEAP; // eat performance
+
+               self.buff_model.alpha = self.alpha;
+       }
+
+#undef BUFF_ONADD
+#undef BUFF_ONREM
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, SpectateCopy)
+{SELFPARAM();
+       self.buffs = other.buffs;
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, VehicleEnter)
+{
+       vh_vehicle.buffs = vh_player.buffs;
+       vh_player.buffs = 0;
+       vh_vehicle.buff_time = vh_player.buff_time - time;
+       vh_player.buff_time = 0;
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, VehicleExit)
+{
+       vh_player.buffs = vh_player.oldbuffs = vh_vehicle.buffs;
+       vh_vehicle.buffs = 0;
+       vh_player.buff_time = time + vh_vehicle.buff_time;
+       vh_vehicle.buff_time = 0;
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, PlayerRegen)
+{SELFPARAM();
+       if(self.buffs & BUFF_MEDIC.m_itemid)
+       {
+               regen_mod_rot = autocvar_g_buffs_medic_rot;
+               regen_mod_limit = regen_mod_max = autocvar_g_buffs_medic_max;
+               regen_mod_regen = autocvar_g_buffs_medic_regen;
+       }
+
+       if(self.buffs & BUFF_SPEED.m_itemid)
+               regen_mod_regen = autocvar_g_buffs_speed_regen;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, GetCvars)
+{
+       GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_buffs_autoreplace, "cl_buffs_autoreplace");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":Buffs");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Buffs");
+       return false;
+}
+
+void buffs_DelayedInit()
+{
+       if(autocvar_g_buffs_spawn_count > 0)
+       if(find(world, classname, "item_buff") == world)
+       {
+               float i;
+               for(i = 0; i < autocvar_g_buffs_spawn_count; ++i)
+               {
+                       entity e = spawn();
+                       e.spawnflags |= 64; // always randomize
+                       e.velocity = randomvec() * 250; // this gets reset anyway if random location works
+                       buff_Init(e);
+               }
+       }
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/buffs/module.inc b/qcsrc/common/mutators/mutator/buffs/module.inc
new file mode 100644 (file)
index 0000000..5f24f62
--- /dev/null
@@ -0,0 +1,46 @@
+#include "all.qc"
+#ifdef SVQC
+#include "buffs.qc"
+#endif
+
+#ifdef IMPLEMENTATION
+
+string BUFF_NAME(int i)
+{
+    Buff b = Buffs_from(i);
+    return sprintf("%s%s", rgb_to_hexcolor(b.m_color), b.m_prettyName);
+}
+
+#ifndef MENUQC
+REGISTER_MUTATOR(buffs_flight, true);
+MUTATOR_HOOKFUNCTION(buffs_flight, IsFlying)
+{
+    noref entity e = MUTATOR_ARGV(0, entity);
+       return BUFFS_STAT(e) & BUFF_FLIGHT.m_itemid;
+}
+#endif
+
+#ifdef CSQC
+REGISTER_MUTATOR(cl_buffs, true);
+MUTATOR_HOOKFUNCTION(cl_buffs, HUD_Powerups_add)
+{
+    int allBuffs = getstati(STAT_BUFFS, 0, 24);
+    FOREACH(Buffs, it.m_itemid & allBuffs, LAMBDA(
+               addPowerupItem(it.m_prettyName, strcat("buff_", it.m_name), it.m_color, bound(0, getstatf(STAT_BUFF_TIME) - time, 99), 60);
+       ));
+}
+MUTATOR_HOOKFUNCTION(cl_buffs, WP_Format)
+{
+    entity this = MUTATOR_ARGV(0, entity);
+    string s = MUTATOR_ARGV(0, string);
+    if (s == WP_Buff.netname || s == RADARICON_Buff.netname)
+    {
+        Buff b = Buffs_from(this.wp_extra);
+        MUTATOR_ARGV(0, vector) = b.m_color;
+        MUTATOR_ARGV(0, string) = b.m_prettyName;
+        return true;
+    }
+}
+
+#endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/campcheck/campcheck.qc b/qcsrc/common/mutators/mutator/campcheck/campcheck.qc
new file mode 100644 (file)
index 0000000..0ba0bb6
--- /dev/null
@@ -0,0 +1,90 @@
+#ifdef IMPLEMENTATION
+float autocvar_g_campcheck_damage;
+float autocvar_g_campcheck_distance;
+float autocvar_g_campcheck_interval;
+
+REGISTER_MUTATOR(campcheck, cvar("g_campcheck"));
+
+.float campcheck_nextcheck;
+.float campcheck_traveled_distance;
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerDies)
+{SELFPARAM();
+       Kill_Notification(NOTIF_ONE, self, MSG_CENTER_CPID, CPID_CAMPCHECK);
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerDamage_Calculate)
+{
+       if(IS_PLAYER(frag_target))
+       if(IS_PLAYER(frag_attacker))
+       if(frag_attacker != frag_target)
+       {
+               frag_target.campcheck_traveled_distance = autocvar_g_campcheck_distance;
+               frag_attacker.campcheck_traveled_distance = autocvar_g_campcheck_distance;
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerPreThink)
+{SELFPARAM();
+       if(!gameover)
+       if(!warmup_stage) // don't consider it camping during warmup?
+       if(time >= game_starttime)
+       if(IS_PLAYER(self))
+       if(IS_REAL_CLIENT(self)) // bots may camp, but that's no reason to constantly kill them
+       if(self.deadflag == DEAD_NO)
+       if(!self.frozen)
+       if(!self.BUTTON_CHAT)
+       if(autocvar_g_campcheck_interval)
+       {
+               vector dist;
+
+               // calculate player movement (in 2 dimensions only, so jumping on one spot doesn't count as movement)
+               dist = self.prevorigin - self.origin;
+               dist.z = 0;
+               self.campcheck_traveled_distance += fabs(vlen(dist));
+
+               if((autocvar_g_campaign && !campaign_bots_may_start) || (time < game_starttime) || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
+               {
+                       self.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
+                       self.campcheck_traveled_distance = 0;
+               }
+
+               if(time > self.campcheck_nextcheck)
+               {
+                       if(self.campcheck_traveled_distance < autocvar_g_campcheck_distance)
+                       {
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_CAMPCHECK);
+                               if(self.vehicle)
+                                       Damage(self.vehicle, self, self, autocvar_g_campcheck_damage * 2, DEATH_CAMP.m_id, self.vehicle.origin, '0 0 0');
+                               else
+                                       Damage(self, self, self, bound(0, autocvar_g_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP.m_id, self.origin, '0 0 0');
+                       }
+                       self.campcheck_nextcheck = time + autocvar_g_campcheck_interval;
+                       self.campcheck_traveled_distance = 0;
+               }
+
+               return false;
+       }
+
+       self.campcheck_nextcheck = time + autocvar_g_campcheck_interval; // one of the above checks failed, so keep the timer up to date
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, PlayerSpawn)
+{SELFPARAM();
+       self.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
+       self.campcheck_traveled_distance = 0;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(campcheck, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":CampCheck");
+       return false;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/campcheck/module.inc b/qcsrc/common/mutators/mutator/campcheck/module.inc
new file mode 100644 (file)
index 0000000..9f4181f
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "campcheck.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/casings.qc b/qcsrc/common/mutators/mutator/casings.qc
deleted file mode 100644 (file)
index fe945c9..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-#ifdef IMPLEMENTATION
-
-#include "../../util.qh"
-
-#ifdef CSQC
-#include "../../movetypes/movetypes.qh"
-#include "../../../client/rubble.qh"
-#endif
-
-REGISTER_MUTATOR(casings, true);
-
-#ifdef SVQC
-void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner)
-{SELFPARAM();
-    vector org = self.origin + self.view_ofs + self.weaponentity.spawnorigin.x * v_forward - self.weaponentity.spawnorigin.y * v_right + self.weaponentity.spawnorigin.z * v_up;
-
-    if (!sound_allowed(MSG_BROADCAST, casingowner))
-        casingtype |= 0x80;
-
-    WriteByte(MSG_ALL, SVC_TEMPENTITY);
-    WriteMutator(MSG_ALL, casings);
-    WriteByte(MSG_ALL, casingtype);
-    WriteCoord(MSG_ALL, org.x);
-    WriteCoord(MSG_ALL, org.y);
-    WriteCoord(MSG_ALL, org.z);
-    WriteShort(MSG_ALL, compressShortVector(vel)); // actually compressed velocity
-    WriteByte(MSG_ALL, ang.x * 256 / 360);
-    WriteByte(MSG_ALL, ang.y * 256 / 360);
-    WriteByte(MSG_ALL, ang.z * 256 / 360);
-}
-#endif
-
-#ifdef CSQC
-entityclass(Casing);
-class(Casing) .float alpha;
-class(Casing) .bool silent;
-class(Casing) .int state;
-class(Casing) .float cnt;
-
-void Casing_Delete()
-{SELFPARAM();
-    remove(self);
-}
-
-void Casing_Draw(entity this)
-{
-    if (self.move_flags & FL_ONGROUND)
-    {
-        self.move_angles_x = 0;
-        self.move_angles_z = 0;
-        self.flags &= ~FL_ONGROUND;
-    }
-
-    Movetype_Physics_MatchTicrate(autocvar_cl_casings_ticrate, autocvar_cl_casings_sloppy);
-    if (wasfreed(self))
-        return; // deleted by touch function
-
-    self.renderflags = 0;
-    self.alpha = bound(0, self.cnt - time, 1);
-
-    if (self.alpha < ALPHA_MIN_VISIBLE)
-    {
-        Casing_Delete();
-        self.drawmask = 0;
-    }
-}
-
-SOUND(BRASS1, W_Sound("brass1"));
-SOUND(BRASS2, W_Sound("brass2"));
-SOUND(BRASS3, W_Sound("brass3"));
-Sound SND_BRASS_RANDOM() {
-    return Sounds[SND_BRASS1.m_id + floor(prandom() * 3)];
-}
-SOUND(CASINGS1, W_Sound("casings1"));
-SOUND(CASINGS2, W_Sound("casings2"));
-SOUND(CASINGS3, W_Sound("casings3"));
-Sound SND_CASINGS_RANDOM() {
-    return Sounds[SND_CASINGS1.m_id + floor(prandom() * 3)];
-}
-
-void Casing_Touch()
-{SELFPARAM();
-    if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
-    {
-        Casing_Delete();
-        return;
-    }
-
-    if (!self.silent)
-    if (!trace_ent || trace_ent.solid == SOLID_BSP)
-    {
-        if (vlen(self.velocity) > 50)
-        {
-            if (time >= self.nextthink)
-            {
-                Sound s;
-                switch (self.state)
-                {
-                    case 1:
-                        s = SND_CASINGS_RANDOM();
-                        break;
-                    default:
-                        s = SND_BRASS_RANDOM();
-                        break;
-                }
-
-                sound (self, CH_SHOTS, s, VOL_BASE, ATTEN_LARGE);
-            }
-        }
-    }
-
-    self.nextthink = time + 0.2;
-}
-
-void Casing_Damage(float thisdmg, int hittype, vector org, vector thisforce)
-{SELFPARAM();
-    if (thisforce.z < 0)
-        thisforce.z = 0;
-    self.move_velocity = self.move_velocity + thisforce + '0 0 100';
-    self.move_flags &= ~FL_ONGROUND;
-}
-
-MUTATOR_HOOKFUNCTION(casings, CSQC_Parse_TempEntity)
-{
-    if (MUTATOR_RETURNVALUE) return;
-    if (!ReadMutatorEquals(mutator_argv_int_0, casings)) return;
-    return = true;
-
-    int _state = ReadByte();
-    vector org;
-    org_x = ReadCoord();
-    org_y = ReadCoord();
-    org_z = ReadCoord();
-    vector vel = decompressShortVector(ReadShort());
-    vector ang;
-    ang_x = ReadByte() * 360 / 256;
-    ang_y = ReadByte() * 360 / 256;
-    ang_z = ReadByte() * 360 / 256;
-
-    if (!autocvar_cl_casings) return;
-
-    Casing casing = RubbleNew("casing");
-    casing.silent = (_state & 0x80);
-    casing.state = (_state & 0x7F);
-    casing.origin = org;
-    setorigin(casing, casing.origin);
-    casing.velocity = vel;
-    casing.angles = ang;
-    casing.drawmask = MASK_NORMAL;
-
-    casing.draw = Casing_Draw;
-    casing.move_origin = casing.origin;
-    casing.move_velocity = casing.velocity + 2 * prandomvec();
-    casing.move_angles = casing.angles;
-    casing.move_avelocity = '0 250 0' + 100 * prandomvec();
-    casing.move_movetype = MOVETYPE_BOUNCE;
-    casing.move_touch = Casing_Touch;
-    casing.move_time = time;
-    casing.event_damage = Casing_Damage;
-    casing.solid = SOLID_TRIGGER;
-
-    switch (casing.state)
-    {
-        case 1:
-            setmodel(casing, MDL_CASING_SHELL);
-            casing.cnt = time + autocvar_cl_casings_shell_time;
-            break;
-        default:
-            setmodel(casing, MDL_CASING_BULLET);
-            casing.cnt = time + autocvar_cl_casings_bronze_time;
-            break;
-    }
-
-    setsize(casing, '0 0 -1', '0 0 -1');
-
-    RubbleLimit("casing", autocvar_cl_casings_maxcount, Casing_Delete);
-}
-
-#endif
-#endif
diff --git a/qcsrc/common/mutators/mutator/cloaked/cloaked.qc b/qcsrc/common/mutators/mutator/cloaked/cloaked.qc
new file mode 100644 (file)
index 0000000..f8231f7
--- /dev/null
@@ -0,0 +1,19 @@
+#ifdef IMPLEMENTATION
+
+REGISTER_MUTATOR(cloaked, cvar("g_cloaked"));
+
+float autocvar_g_balance_cloaked_alpha;
+
+MUTATOR_HOOKFUNCTION(cloaked, SetDefaultAlpha)
+{
+    default_player_alpha = autocvar_g_balance_cloaked_alpha;
+    default_weapon_alpha = default_player_alpha;
+    return true;
+}
+
+MUTATOR_HOOKFUNCTION(cloaked, BuildMutatorsPrettyString)
+{
+       if (!g_cts) ret_string = strcat(ret_string, ", Cloaked");
+}
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/cloaked/module.inc b/qcsrc/common/mutators/mutator/cloaked/module.inc
new file mode 100644 (file)
index 0000000..3d3a042
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "cloaked.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/damagetext.qc b/qcsrc/common/mutators/mutator/damagetext.qc
deleted file mode 100644 (file)
index f6e9d5a..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-#ifndef MUTATOR_DAMAGETEXT_H
-#define MUTATOR_DAMAGETEXT_H
-
-#ifdef MENUQC
-#include "../../../menu/xonotic/tab.qc"
-#endif
-
-#endif
-
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(damagetext, true);
-
-#if defined(CSQC) || defined(MENUQC)
-AUTOCVAR_SAVE(cl_damagetext,                    bool,   false,      _("Draw damage dealt. 0: disabled, 1: enabled"));
-AUTOCVAR_SAVE(cl_damagetext_format,             string, "-%3$d",    _("How to format the damage text. 1$ is health, 2$ is armor, 3$ is both"));
-AUTOCVAR_SAVE(cl_damagetext_color,              vector, '1 1 0',    _("Default damage text color"));
-AUTOCVAR_SAVE(cl_damagetext_color_per_weapon,   bool,   false,      _("Damage text uses weapon color"));
-AUTOCVAR_SAVE(cl_damagetext_size,               float,  8,          _("Damage text font size"));
-AUTOCVAR_SAVE(cl_damagetext_alpha_start,        float,  1,          _("Damage text initial alpha"));
-AUTOCVAR_SAVE(cl_damagetext_alpha_lifetime,     float,  3,          _("Damage text lifetime in seconds"));
-AUTOCVAR_SAVE(cl_damagetext_velocity,           vector, '0 0 20',   _("Damage text move direction"));
-AUTOCVAR_SAVE(cl_damagetext_offset,             vector, '0 -40 0',  _("Damage text offset"));
-AUTOCVAR_SAVE(cl_damagetext_accumulate_range,   float,  30,         _("Damage text spawned within this range is accumulated"));
-#endif
-
-#ifdef CSQC
-CLASS(DamageText, Object)
-    ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color)
-    ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size)
-    ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start)
-    ATTRIB(DamageText, fade_rate, float, 1 / autocvar_cl_damagetext_alpha_lifetime)
-    ATTRIB(DamageText, velocity, vector, autocvar_cl_damagetext_velocity)
-    ATTRIB(DamageText, m_group, int, 0)
-    ATTRIB(DamageText, m_damage, int, 0)
-    ATTRIB(DamageText, m_armordamage, int, 0)
-    ATTRIB(DamageText, m_deathtype, int, 0)
-    ATTRIB(DamageText, time_prev, float, time)
-
-    void DamageText_draw2d(DamageText this) {
-        float dt = time - this.time_prev;
-        this.time_prev = time;
-        setorigin(this, this.origin + dt * this.velocity);
-        this.alpha -= dt * this.fade_rate;
-        if (this.alpha < 0) remove(this);
-        vector pos = project_3d_to_2d(this.origin) + autocvar_cl_damagetext_offset;
-        if (pos.z >= 0 && this.m_size > 0) {
-            pos.z = 0;
-            vector rgb = this.m_color;
-            if (autocvar_cl_damagetext_color_per_weapon) {
-                Weapon w = DEATH_WEAPONOF(this.m_deathtype);
-                if (w != WEP_Null) rgb = w.wpcolor;
-            }
-            string s = sprintf(autocvar_cl_damagetext_format, this.m_damage, this.m_armordamage, this.m_damage + this.m_armordamage);
-            drawcolorcodedstring2(pos, s, this.m_size * '1 1 0', rgb, this.alpha, DRAWFLAG_NORMAL);
-        }
-    }
-    ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d)
-
-    void DamageText_update(DamageText this, vector _origin, int _health, int _armor, int _deathtype) {
-        this.m_damage = _health;
-        this.m_armordamage = _armor;
-        this.m_deathtype = _deathtype;
-        setorigin(this, _origin);
-        this.alpha = 1;
-    }
-
-    CONSTRUCTOR(DamageText, int _group, vector _origin, int _health, int _armor, int _deathtype) {
-        CONSTRUCT(DamageText);
-        this.m_group = _group;
-        DamageText_update(this, _origin, _health, _armor, _deathtype);
-    }
-ENDCLASS(DamageText)
-#endif
-
-#ifdef SVQC
-AUTOCVAR(sv_damagetext, int, 2, _("<= 0: disabled, >= 1: spectators, >= 2: players, >= 3: all players"));
-#define SV_DAMAGETEXT_DISABLED()        (autocvar_sv_damagetext <= 0 /* disabled */)
-#define SV_DAMAGETEXT_SPECTATORS_ONLY() (autocvar_sv_damagetext >= 1 /* spectators only */)
-#define SV_DAMAGETEXT_PLAYERS()         (autocvar_sv_damagetext >= 2 /* players */)
-#define SV_DAMAGETEXT_ALL()             (autocvar_sv_damagetext >= 3 /* all players */)
-MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
-    if (SV_DAMAGETEXT_DISABLED()) return;
-    const entity attacker = mutator_argv_entity_0;
-    const entity hit = mutator_argv_entity_1; if (hit == attacker) return;
-    const int health = mutator_argv_int_0;
-    const int armor = mutator_argv_int_1;
-    const int deathtype = mutator_argv_int_2;
-    const vector location = hit.origin;
-    entity e;
-    FOR_EACH_REALCLIENT(e) if (
-        (SV_DAMAGETEXT_ALL()) ||
-        (SV_DAMAGETEXT_PLAYERS() && e == attacker) ||
-        (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(e) && e.enemy == attacker) ||
-        (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(e))
-    ) {
-        msg_entity = e;
-        WriteByte(MSG_ONE, SVC_TEMPENTITY);
-        WriteMutator(MSG_ONE, damagetext);
-        WriteShort(MSG_ONE, health);
-        WriteShort(MSG_ONE, armor);
-        WriteEntity(MSG_ONE, hit);
-        WriteCoord(MSG_ONE, location.x);
-        WriteCoord(MSG_ONE, location.y);
-        WriteCoord(MSG_ONE, location.z);
-        WriteInt24_t(MSG_ONE, deathtype);
-    }
-}
-#endif
-
-#ifdef CSQC
-MUTATOR_HOOKFUNCTION(damagetext, CSQC_Parse_TempEntity) {
-    if (MUTATOR_RETURNVALUE) return false;
-    if (!ReadMutatorEquals(mutator_argv_int_0, damagetext)) return false;
-    int health = ReadShort();
-    int armor = ReadShort();
-    int group = ReadShort();
-    vector location = vec3(ReadCoord(), ReadCoord(), ReadCoord());
-    int deathtype = ReadInt24_t();
-    if (autocvar_cl_damagetext) {
-        if (autocvar_cl_damagetext_accumulate_range) {
-            for (entity e = findradius(location, autocvar_cl_damagetext_accumulate_range); e; e = e.chain) {
-                if (e.instanceOfDamageText && e.m_group == group) {
-                    DamageText_update(e, location, e.m_damage + health, e.m_armordamage + armor, deathtype);
-                    return true;
-                }
-            }
-        }
-        NEW(DamageText, group, location, health, armor, deathtype);
-    }
-    return true;
-}
-#endif
-
-#ifdef MENUQC
-CLASS(XonoticDamageTextSettings, XonoticTab)
-    #include "../../../menu/gamesettings.qh"
-    REGISTER_SETTINGS(damagetext, NEW(XonoticDamageTextSettings));
-    ATTRIB(XonoticDamageTextSettings, title, string, _("Damage text"))
-    ATTRIB(XonoticDamageTextSettings, intendedWidth, float, 0.9)
-    ATTRIB(XonoticDamageTextSettings, rows, float, 13)
-    ATTRIB(XonoticDamageTextSettings, columns, float, 5)
-    INIT(XonoticDamageTextSettings) { this.configureDialog(this); }
-    METHOD(XonoticDamageTextSettings, showNotify, void(entity this)) { loadAllCvars(this); }
-    METHOD(XonoticDamageTextSettings, fill, void(entity this))
-    {
-        this.gotoRC(this, 0, 1); this.setFirstColumn(this, this.currentColumn);
-            this.TD(this, 1, 3, makeXonoticCheckBox(0, "cl_damagetext", _("Draw damage numbers")));
-        this.TR(this);
-            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Font size:")));
-            this.TD(this, 1, 2, makeXonoticSlider(0, 50, 1, "cl_damagetext_size"));
-        this.TR(this);
-            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Accumulate range:")));
-            this.TD(this, 1, 2, makeXonoticSlider(0, 500, 1, "cl_damagetext_accumulate_range"));
-        this.TR(this);
-            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Lifetime:")));
-            this.TD(this, 1, 2, makeXonoticSlider(0, 10, 1, "cl_damagetext_alpha_lifetime"));
-        this.TR(this);
-            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Color:")));
-            this.TD(this, 2, 2, makeXonoticColorpickerString("cl_damagetext_color", "cl_damagetext_color"));
-    }
-ENDCLASS(XonoticDamageTextSettings)
-#endif
-#endif
diff --git a/qcsrc/common/mutators/mutator/damagetext/damagetext.qc b/qcsrc/common/mutators/mutator/damagetext/damagetext.qc
new file mode 100644 (file)
index 0000000..923ca3b
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef MUTATOR_DAMAGETEXT_H
+#define MUTATOR_DAMAGETEXT_H
+
+#ifdef MENUQC
+#include "../../../../menu/xonotic/tab.qc"
+#endif
+
+#endif
+
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(damagetext, true);
+
+#if defined(CSQC) || defined(MENUQC)
+AUTOCVAR_SAVE(cl_damagetext,                    bool,   false,      _("Draw damage dealt. 0: disabled, 1: enabled"));
+AUTOCVAR_SAVE(cl_damagetext_format,             string, "-%3$d",    _("How to format the damage text. 1$ is health, 2$ is armor, 3$ is both"));
+AUTOCVAR_SAVE(cl_damagetext_color,              vector, '1 1 0',    _("Default damage text color"));
+AUTOCVAR_SAVE(cl_damagetext_color_per_weapon,   bool,   false,      _("Damage text uses weapon color"));
+AUTOCVAR_SAVE(cl_damagetext_size,               float,  8,          _("Damage text font size"));
+AUTOCVAR_SAVE(cl_damagetext_alpha_start,        float,  1,          _("Damage text initial alpha"));
+AUTOCVAR_SAVE(cl_damagetext_alpha_lifetime,     float,  3,          _("Damage text lifetime in seconds"));
+AUTOCVAR_SAVE(cl_damagetext_velocity,           vector, '0 0 20',   _("Damage text move direction"));
+AUTOCVAR_SAVE(cl_damagetext_offset,             vector, '0 -40 0',  _("Damage text offset"));
+AUTOCVAR_SAVE(cl_damagetext_accumulate_range,   float,  30,         _("Damage text spawned within this range is accumulated"));
+#endif
+
+#ifdef CSQC
+CLASS(DamageText, Object)
+    ATTRIB(DamageText, m_color, vector, autocvar_cl_damagetext_color)
+    ATTRIB(DamageText, m_size, float, autocvar_cl_damagetext_size)
+    ATTRIB(DamageText, alpha, float, autocvar_cl_damagetext_alpha_start)
+    ATTRIB(DamageText, fade_rate, float, 1 / autocvar_cl_damagetext_alpha_lifetime)
+    ATTRIB(DamageText, velocity, vector, autocvar_cl_damagetext_velocity)
+    ATTRIB(DamageText, m_group, int, 0)
+    ATTRIB(DamageText, m_damage, int, 0)
+    ATTRIB(DamageText, m_armordamage, int, 0)
+    ATTRIB(DamageText, m_deathtype, int, 0)
+    ATTRIB(DamageText, time_prev, float, time)
+
+    void DamageText_draw2d(DamageText this) {
+        float dt = time - this.time_prev;
+        this.time_prev = time;
+        setorigin(this, this.origin + dt * this.velocity);
+        this.alpha -= dt * this.fade_rate;
+        if (this.alpha < 0) remove(this);
+        vector pos = project_3d_to_2d(this.origin) + autocvar_cl_damagetext_offset;
+        if (pos.z >= 0 && this.m_size > 0) {
+            pos.z = 0;
+            vector rgb = this.m_color;
+            if (autocvar_cl_damagetext_color_per_weapon) {
+                Weapon w = DEATH_WEAPONOF(this.m_deathtype);
+                if (w != WEP_Null) rgb = w.wpcolor;
+            }
+            string s = sprintf(autocvar_cl_damagetext_format, this.m_damage, this.m_armordamage, this.m_damage + this.m_armordamage);
+            drawcolorcodedstring2(pos, s, this.m_size * '1 1 0', rgb, this.alpha, DRAWFLAG_NORMAL);
+        }
+    }
+    ATTRIB(DamageText, draw2d, void(DamageText), DamageText_draw2d)
+
+    void DamageText_update(DamageText this, vector _origin, int _health, int _armor, int _deathtype) {
+        this.m_damage = _health;
+        this.m_armordamage = _armor;
+        this.m_deathtype = _deathtype;
+        setorigin(this, _origin);
+        this.alpha = 1;
+    }
+
+    CONSTRUCTOR(DamageText, int _group, vector _origin, int _health, int _armor, int _deathtype) {
+        CONSTRUCT(DamageText);
+        this.m_group = _group;
+        DamageText_update(this, _origin, _health, _armor, _deathtype);
+    }
+ENDCLASS(DamageText)
+#endif
+
+REGISTER_NET_TEMP(damagetext)
+
+#ifdef SVQC
+AUTOCVAR(sv_damagetext, int, 2, _("<= 0: disabled, >= 1: spectators, >= 2: players, >= 3: all players"));
+#define SV_DAMAGETEXT_DISABLED()        (autocvar_sv_damagetext <= 0 /* disabled */)
+#define SV_DAMAGETEXT_SPECTATORS_ONLY() (autocvar_sv_damagetext >= 1 /* spectators only */)
+#define SV_DAMAGETEXT_PLAYERS()         (autocvar_sv_damagetext >= 2 /* players */)
+#define SV_DAMAGETEXT_ALL()             (autocvar_sv_damagetext >= 3 /* all players */)
+MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
+    if (SV_DAMAGETEXT_DISABLED()) return;
+    const entity attacker = MUTATOR_ARGV(0, entity);
+    const entity hit = MUTATOR_ARGV(1, entity); if (hit == attacker) return;
+    const int health = MUTATOR_ARGV(0, int);
+    const int armor = MUTATOR_ARGV(1, int);
+    const int deathtype = MUTATOR_ARGV(2, int);
+    const vector location = hit.origin;
+    entity e;
+    FOR_EACH_REALCLIENT(e) if (
+        (SV_DAMAGETEXT_ALL()) ||
+        (SV_DAMAGETEXT_PLAYERS() && e == attacker) ||
+        (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(e) && e.enemy == attacker) ||
+        (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(e))
+    ) {
+        msg_entity = e;
+        WriteHeader(MSG_ONE, damagetext);
+        WriteShort(MSG_ONE, health);
+        WriteShort(MSG_ONE, armor);
+        WriteEntity(MSG_ONE, hit);
+        WriteCoord(MSG_ONE, location.x);
+        WriteCoord(MSG_ONE, location.y);
+        WriteCoord(MSG_ONE, location.z);
+        WriteInt24_t(MSG_ONE, deathtype);
+    }
+}
+#endif
+
+#ifdef CSQC
+NET_HANDLE(damagetext, bool isNew)
+{
+    int health = ReadShort();
+    int armor = ReadShort();
+    int group = ReadShort();
+    vector location = vec3(ReadCoord(), ReadCoord(), ReadCoord());
+    int deathtype = ReadInt24_t();
+    return = true;
+    if (autocvar_cl_damagetext) {
+        if (autocvar_cl_damagetext_accumulate_range) {
+            for (entity e = findradius(location, autocvar_cl_damagetext_accumulate_range); e; e = e.chain) {
+                if (e.instanceOfDamageText && e.m_group == group) {
+                    DamageText_update(e, location, e.m_damage + health, e.m_armordamage + armor, deathtype);
+                    return;
+                }
+            }
+        }
+        NEW(DamageText, group, location, health, armor, deathtype);
+    }
+}
+#endif
+
+#ifdef MENUQC
+CLASS(XonoticDamageTextSettings, XonoticTab)
+    #include "../../../../menu/gamesettings.qh"
+    REGISTER_SETTINGS(damagetext, NEW(XonoticDamageTextSettings));
+    ATTRIB(XonoticDamageTextSettings, title, string, _("Damage text"))
+    ATTRIB(XonoticDamageTextSettings, intendedWidth, float, 0.9)
+    ATTRIB(XonoticDamageTextSettings, rows, float, 13)
+    ATTRIB(XonoticDamageTextSettings, columns, float, 5)
+    INIT(XonoticDamageTextSettings) { this.configureDialog(this); }
+    METHOD(XonoticDamageTextSettings, showNotify, void(entity this)) { loadAllCvars(this); }
+    METHOD(XonoticDamageTextSettings, fill, void(entity this))
+    {
+        this.gotoRC(this, 0, 1); this.setFirstColumn(this, this.currentColumn);
+            this.TD(this, 1, 3, makeXonoticCheckBox(0, "cl_damagetext", _("Draw damage numbers")));
+        this.TR(this);
+            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Font size:")));
+            this.TD(this, 1, 2, makeXonoticSlider(0, 50, 1, "cl_damagetext_size"));
+        this.TR(this);
+            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Accumulate range:")));
+            this.TD(this, 1, 2, makeXonoticSlider(0, 500, 1, "cl_damagetext_accumulate_range"));
+        this.TR(this);
+            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Lifetime:")));
+            this.TD(this, 1, 2, makeXonoticSlider(0, 10, 1, "cl_damagetext_alpha_lifetime"));
+        this.TR(this);
+            this.TD(this, 1, 1, makeXonoticTextLabel(0, _("Color:")));
+            this.TD(this, 2, 2, makeXonoticColorpickerString("cl_damagetext_color", "cl_damagetext_color"));
+    }
+ENDCLASS(XonoticDamageTextSettings)
+#endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/damagetext/module.inc b/qcsrc/common/mutators/mutator/damagetext/module.inc
new file mode 100644 (file)
index 0000000..8e70be7
--- /dev/null
@@ -0,0 +1 @@
+#include "damagetext.qc"
diff --git a/qcsrc/common/mutators/mutator/dodging/dodging.qc b/qcsrc/common/mutators/mutator/dodging/dodging.qc
new file mode 100644 (file)
index 0000000..f014ebb
--- /dev/null
@@ -0,0 +1,334 @@
+#ifdef IMPLEMENTATION
+
+#ifdef CSQC
+       #define PHYS_DODGING_FRAMETIME                          (1 / (frametime <= 0 ? 60 : frametime))
+       #define PHYS_DODGING                                            getstati(STAT_DODGING)
+       #define PHYS_DODGING_DELAY                                      getstatf(STAT_DODGING_DELAY)
+       #define PHYS_DODGING_TIMEOUT(s)                         getstatf(STAT_DODGING_TIMEOUT)
+       #define PHYS_DODGING_HORIZ_SPEED_FROZEN         getstatf(STAT_DODGING_HORIZ_SPEED_FROZEN)
+       #define PHYS_DODGING_FROZEN_NODOUBLETAP         getstati(STAT_DODGING_FROZEN_NO_DOUBLETAP)
+       #define PHYS_DODGING_HORIZ_SPEED                        getstatf(STAT_DODGING_HORIZ_SPEED)
+       #define PHYS_DODGING_PRESSED_KEYS(s)            s.pressedkeys
+       #define PHYS_DODGING_HEIGHT_THRESHOLD           getstatf(STAT_DODGING_HEIGHT_THRESHOLD)
+       #define PHYS_DODGING_DISTANCE_THRESHOLD         getstatf(STAT_DODGING_DISTANCE_THRESHOLD)
+       #define PHYS_DODGING_RAMP_TIME                          getstatf(STAT_DODGING_RAMP_TIME)
+       #define PHYS_DODGING_UP_SPEED                           getstatf(STAT_DODGING_UP_SPEED)
+       #define PHYS_DODGING_WALL                                       getstatf(STAT_DODGING_WALL)
+#elif defined(SVQC)
+       #define PHYS_DODGING_FRAMETIME                          sys_frametime
+       #define PHYS_DODGING                                            g_dodging
+       #define PHYS_DODGING_DELAY                                      autocvar_sv_dodging_delay
+       #define PHYS_DODGING_TIMEOUT(s)                         s.cvar_cl_dodging_timeout
+       #define PHYS_DODGING_HORIZ_SPEED_FROZEN         autocvar_sv_dodging_horiz_speed_frozen
+       #define PHYS_DODGING_FROZEN_NODOUBLETAP         autocvar_sv_dodging_frozen_doubletap
+       #define PHYS_DODGING_HORIZ_SPEED                        autocvar_sv_dodging_horiz_speed
+       #define PHYS_DODGING_PRESSED_KEYS(s)            s.pressedkeys
+       #define PHYS_DODGING_HEIGHT_THRESHOLD           autocvar_sv_dodging_height_threshold
+       #define PHYS_DODGING_DISTANCE_THRESHOLD         autocvar_sv_dodging_wall_distance_threshold
+       #define PHYS_DODGING_RAMP_TIME                          autocvar_sv_dodging_ramp_time
+       #define PHYS_DODGING_UP_SPEED                           autocvar_sv_dodging_up_speed
+       #define PHYS_DODGING_WALL                                       autocvar_sv_dodging_wall_dodging
+
+       float autocvar_sv_dodging_delay;
+    float autocvar_sv_dodging_height_threshold;
+    float autocvar_sv_dodging_horiz_speed;
+    float autocvar_sv_dodging_horiz_speed_frozen;
+    float autocvar_sv_dodging_ramp_time;
+    bool autocvar_sv_dodging_sound;
+    float autocvar_sv_dodging_up_speed;
+    float autocvar_sv_dodging_wall_distance_threshold;
+    bool autocvar_sv_dodging_wall_dodging;
+    bool autocvar_sv_dodging_frozen_doubletap;
+#endif
+
+#ifdef SVQC
+
+float g_dodging;
+
+// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
+.float dodging_action;
+
+// the jump part of the dodge cannot be ramped
+.float dodging_single_action;
+
+#include "../../../animdecide.qh"
+#include "../../../physics.qh"
+
+.float cvar_cl_dodging_timeout;
+
+.float stat_dodging;
+.float stat_dodging_delay;
+.float stat_dodging_horiz_speed_frozen;
+.float stat_dodging_frozen_nodoubletap;
+.float stat_dodging_frozen;
+.float stat_dodging_horiz_speed;
+.float stat_dodging_height_threshold;
+.float stat_dodging_distance_threshold;
+.float stat_dodging_ramp_time;
+.float stat_dodging_up_speed;
+.float stat_dodging_wall;
+
+REGISTER_MUTATOR(dodging, cvar("g_dodging"))
+{
+       // this just turns on the cvar.
+       MUTATOR_ONADD
+       {
+               g_dodging = cvar("g_dodging");
+               addstat(STAT_DODGING, AS_INT, stat_dodging);
+               addstat(STAT_DODGING_DELAY, AS_FLOAT, stat_dodging_delay);
+               addstat(STAT_DODGING_TIMEOUT, AS_FLOAT, cvar_cl_dodging_timeout); // we stat this, so it is updated on the client when updated on server (otherwise, chaos)
+               addstat(STAT_DODGING_FROZEN_NO_DOUBLETAP, AS_INT, stat_dodging_frozen_nodoubletap);
+               addstat(STAT_DODGING_HORIZ_SPEED_FROZEN, AS_FLOAT, stat_dodging_horiz_speed_frozen);
+               addstat(STAT_DODGING_FROZEN, AS_INT, stat_dodging_frozen);
+               addstat(STAT_DODGING_HORIZ_SPEED, AS_FLOAT, stat_dodging_horiz_speed);
+               addstat(STAT_DODGING_HEIGHT_THRESHOLD, AS_FLOAT, stat_dodging_height_threshold);
+               addstat(STAT_DODGING_DISTANCE_THRESHOLD, AS_FLOAT, stat_dodging_distance_threshold);
+               addstat(STAT_DODGING_RAMP_TIME, AS_FLOAT, stat_dodging_ramp_time);
+               addstat(STAT_DODGING_UP_SPEED, AS_FLOAT, stat_dodging_up_speed);
+               addstat(STAT_DODGING_WALL, AS_FLOAT, stat_dodging_wall);
+       }
+
+       // this just turns off the cvar.
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               g_dodging = 0;
+       }
+
+       return false;
+}
+
+#endif
+
+// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
+.float dodging_action;
+
+// the jump part of the dodge cannot be ramped
+.float dodging_single_action;
+
+
+// these are used to store the last key press time for each of the keys..
+.float last_FORWARD_KEY_time;
+.float last_BACKWARD_KEY_time;
+.float last_LEFT_KEY_time;
+.float last_RIGHT_KEY_time;
+
+// these store the movement direction at the time of the dodge action happening.
+.vector dodging_direction;
+
+// this indicates the last time a dodge was executed. used to check if another one is allowed
+// and to ramp up the dodge acceleration in the physics hook.
+.float last_dodging_time;
+
+// This is the velocity gain to be added over the ramp time.
+// It will decrease from frame to frame during dodging_action = 1
+// until it's 0.
+.float dodging_velocity_gain;
+
+#ifdef CSQC
+.int pressedkeys;
+
+#elif defined(SVQC)
+
+void dodging_UpdateStats()
+{SELFPARAM();
+       self.stat_dodging = PHYS_DODGING;
+       self.stat_dodging_delay = PHYS_DODGING_DELAY;
+       self.stat_dodging_horiz_speed_frozen = PHYS_DODGING_HORIZ_SPEED_FROZEN;
+       self.stat_dodging_frozen = PHYS_DODGING_FROZEN;
+       self.stat_dodging_frozen_nodoubletap = PHYS_DODGING_FROZEN_NODOUBLETAP;
+       self.stat_dodging_height_threshold = PHYS_DODGING_HEIGHT_THRESHOLD;
+       self.stat_dodging_distance_threshold = PHYS_DODGING_DISTANCE_THRESHOLD;
+       self.stat_dodging_ramp_time = PHYS_DODGING_RAMP_TIME;
+       self.stat_dodging_up_speed = PHYS_DODGING_UP_SPEED;
+       self.stat_dodging_wall = PHYS_DODGING_WALL;
+}
+
+#endif
+
+// returns 1 if the player is close to a wall
+bool check_close_to_wall(float threshold)
+{SELFPARAM();
+       if (PHYS_DODGING_WALL == 0) { return false; }
+
+       #define X(OFFSET)                                                                                                                               \
+       tracebox(self.origin, self.mins, self.maxs, self.origin + OFFSET, true, self);  \
+       if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)                \
+               return true;
+       X(1000*v_right);
+       X(-1000*v_right);
+       X(1000*v_forward);
+       X(-1000*v_forward);
+       #undef X
+
+       return false;
+}
+
+bool check_close_to_ground(float threshold)
+{SELFPARAM();
+       return IS_ONGROUND(self) ? true : false;
+}
+
+float PM_dodging_checkpressedkeys()
+{SELFPARAM();
+       if(!PHYS_DODGING)
+               return false;
+
+       float frozen_dodging = (PHYS_FROZEN(self) && PHYS_DODGING_FROZEN);
+       float frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
+
+       // first check if the last dodge is far enough back in time so we can dodge again
+       if ((time - self.last_dodging_time) < PHYS_DODGING_DELAY)
+               return false;
+
+       makevectors(self.angles);
+
+       if (check_close_to_ground(PHYS_DODGING_HEIGHT_THRESHOLD) != 1
+               && check_close_to_wall(PHYS_DODGING_DISTANCE_THRESHOLD) != 1)
+               return true;
+
+       float tap_direction_x = 0;
+       float tap_direction_y = 0;
+       float dodge_detected = 0;
+
+       #define X(COND,BTN,RESULT)                                                                                                                      \
+       if (self.movement_##COND)                                                                                               \
+               /* is this a state change? */                                                                                                   \
+               if(!(PHYS_DODGING_PRESSED_KEYS(self) & KEY_##BTN) || frozen_no_doubletap) {             \
+                               tap_direction_##RESULT;                                                                                                 \
+                               if ((time - self.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(self))   \
+                                       dodge_detected = 1;                                                                                                     \
+                               self.last_##BTN##_KEY_time = time;                                                                              \
+               }
+       X(x < 0, BACKWARD,      x--);
+       X(x > 0, FORWARD,       x++);
+       X(y < 0, LEFT,          y--);
+       X(y > 0, RIGHT,         y++);
+       #undef X
+
+       if (dodge_detected == 1)
+       {
+               self.last_dodging_time = time;
+
+               self.dodging_action = 1;
+               self.dodging_single_action = 1;
+
+               self.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED;
+
+               self.dodging_direction_x = tap_direction_x;
+               self.dodging_direction_y = tap_direction_y;
+
+               // normalize the dodging_direction vector.. (unlike UT99) XD
+               float length = self.dodging_direction_x * self.dodging_direction_x
+                                       + self.dodging_direction_y * self.dodging_direction_y;
+               length = sqrt(length);
+
+               self.dodging_direction_x = self.dodging_direction_x * 1.0 / length;
+               self.dodging_direction_y = self.dodging_direction_y * 1.0 / length;
+               return true;
+       }
+       return false;
+}
+
+void PM_dodging()
+{SELFPARAM();
+       if (!PHYS_DODGING)
+               return;
+
+#ifdef SVQC
+       dodging_UpdateStats();
+#endif
+
+    if (PHYS_DEAD(self))
+        return;
+
+       // when swimming, no dodging allowed..
+       if (self.waterlevel >= WATERLEVEL_SWIMMING)
+       {
+               self.dodging_action = 0;
+               self.dodging_direction_x = 0;
+               self.dodging_direction_y = 0;
+               return;
+       }
+
+       // make sure v_up, v_right and v_forward are sane
+       makevectors(self.angles);
+
+       // if we have e.g. 0.5 sec ramptime and a frametime of 0.25, then the ramp code
+       // will be called ramp_time/frametime times = 2 times. so, we need to
+       // add 0.5 * the total speed each frame until the dodge action is done..
+       float common_factor = PHYS_DODGING_FRAMETIME / PHYS_DODGING_RAMP_TIME;
+
+       // if ramp time is smaller than frametime we get problems ;D
+       common_factor = min(common_factor, 1);
+
+       float horiz_speed = PHYS_FROZEN(self) ? PHYS_DODGING_HORIZ_SPEED_FROZEN : PHYS_DODGING_HORIZ_SPEED;
+       float new_velocity_gain = self.dodging_velocity_gain - (common_factor * horiz_speed);
+       new_velocity_gain = max(0, new_velocity_gain);
+
+       float velocity_difference = self.dodging_velocity_gain - new_velocity_gain;
+
+       // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
+       if (self.dodging_action == 1)
+       {
+               //disable jump key during dodge accel phase
+               if(self.movement_z > 0) { self.movement_z = 0; }
+
+               self.velocity += ((self.dodging_direction_y * velocity_difference) * v_right)
+                                       + ((self.dodging_direction_x * velocity_difference) * v_forward);
+
+               self.dodging_velocity_gain = self.dodging_velocity_gain - velocity_difference;
+       }
+
+       // the up part of the dodge is a single shot action
+       if (self.dodging_single_action == 1)
+       {
+               UNSET_ONGROUND(self);
+
+               self.velocity += PHYS_DODGING_UP_SPEED * v_up;
+
+#ifdef SVQC
+               if (autocvar_sv_dodging_sound)
+                       PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+
+               animdecide_setaction(self, ANIMACTION_JUMP, true);
+#endif
+
+               self.dodging_single_action = 0;
+       }
+
+       // are we done with the dodging ramp yet?
+       if((self.dodging_action == 1) && ((time - self.last_dodging_time) > PHYS_DODGING_RAMP_TIME))
+       {
+               // reset state so next dodge can be done correctly
+               self.dodging_action = 0;
+               self.dodging_direction_x = 0;
+               self.dodging_direction_y = 0;
+       }
+}
+
+#ifdef SVQC
+
+MUTATOR_HOOKFUNCTION(dodging, GetCvars)
+{
+       GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_dodging_timeout, "cl_dodging_timeout");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(dodging, PlayerPhysics)
+{
+       // print("dodging_PlayerPhysics\n");
+       PM_dodging();
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(dodging, GetPressedKeys)
+{
+       PM_dodging_checkpressedkeys();
+
+       return false;
+}
+
+#endif
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/dodging/module.inc b/qcsrc/common/mutators/mutator/dodging/module.inc
new file mode 100644 (file)
index 0000000..6308a21
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "dodging.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/hook/hook.qc b/qcsrc/common/mutators/mutator/hook/hook.qc
new file mode 100644 (file)
index 0000000..b298e7b
--- /dev/null
@@ -0,0 +1,42 @@
+#ifdef IMPLEMENTATION
+AUTOCVAR(g_grappling_hook, bool, false, _("let players spawn with the grappling hook which allows them to pull themselves up"));
+#ifdef SVQC
+REGISTER_MUTATOR(hook, autocvar_g_grappling_hook) {
+    MUTATOR_ONADD {
+        g_grappling_hook = true;
+        WEP_HOOK.ammo_factor = 0;
+    }
+    MUTATOR_ONROLLBACK_OR_REMOVE {
+        g_grappling_hook = false;
+        WEP_HOOK.ammo_factor = 1;
+    }
+}
+
+MUTATOR_HOOKFUNCTION(hook, BuildMutatorsString)
+{
+    ret_string = strcat(ret_string, ":grappling_hook");
+}
+
+MUTATOR_HOOKFUNCTION(hook, BuildMutatorsPrettyString)
+{
+    ret_string = strcat(ret_string, ", Hook");
+}
+
+MUTATOR_HOOKFUNCTION(hook, BuildGameplayTipsString)
+{
+    ret_string = strcat(ret_string, "\n\n^3grappling hook^8 is enabled, press 'e' to use it\n");
+}
+
+MUTATOR_HOOKFUNCTION(hook, PlayerSpawn)
+{
+    SELFPARAM();
+    self.offhand = OFFHAND_HOOK;
+}
+
+MUTATOR_HOOKFUNCTION(hook, FilterItem)
+{
+    return self.weapon == WEP_HOOK.m_id;
+}
+
+#endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/hook/module.inc b/qcsrc/common/mutators/mutator/hook/module.inc
new file mode 100644 (file)
index 0000000..61600c4
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "hook.qc"
+#endif
index 9d5caef000380495b5b24ce91db02d07ed316db9..1810734c64b36d46e36a9f4b401e9eb7769c3244 100644 (file)
@@ -3,13 +3,20 @@
 
 #include "items.qc"
 
+#ifdef SVQC
+float autocvar_g_instagib_invis_alpha;
+#endif
+
 #endif
 
 #ifdef IMPLEMENTATION
 #ifdef SVQC
 
+int autocvar_g_instagib_ammo_drop;
+int autocvar_g_instagib_extralives;
+float autocvar_g_instagib_speed_highspeed;
+
 #include "../../../../server/cl_client.qh"
-#include "../../../buffs/all.qh"
 
 #include "../../../items/all.qc"
 
@@ -19,25 +26,25 @@ spawnfunc(item_minst_cells)
 {
        if (!g_instagib) { remove(self); return; }
        if (!self.ammo_cells) self.ammo_cells = autocvar_g_instagib_ammo_drop;
-       StartItemA(ITEM_VaporizerCells);
+       StartItem(this, ITEM_VaporizerCells);
 }
 
 void instagib_invisibility()
 {SELFPARAM();
        self.strength_finished = autocvar_g_balance_powerup_strength_time;
-       StartItemA(ITEM_Invisibility);
+       StartItem(this, ITEM_Invisibility);
 }
 
 void instagib_extralife()
 {SELFPARAM();
        self.max_health = 1;
-       StartItemA(ITEM_ExtraLife);
+       StartItem(this, ITEM_ExtraLife);
 }
 
 void instagib_speed()
 {SELFPARAM();
        self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
-       StartItemA(ITEM_Speed);
+       StartItem(this, ITEM_Speed);
 }
 
 .float instagib_nextthink;
@@ -325,7 +332,7 @@ MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_Calculate)
                frag_mirrordamage = 0;
        }
 
-       if((frag_target.buffs & BUFF_INVISIBLE.m_itemid) || (frag_target.items & ITEM_Invisibility.m_itemid))
+       if(frag_target.alpha && frag_target.alpha < 1)
                yoda = 1;
 
        return false;
@@ -367,6 +374,7 @@ MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
                e.noalign = self.noalign;
         e.cnt = self.cnt;
         e.team = self.team;
+        e.spawnfunc_checked = true;
                WITH(entity, self, e, spawnfunc_item_minst_cells(e));
                return true;
        }
index 2d804f758b0397ab39cacb8446158c0970aeac92..a069e535f414559a5967677fcd67b13eacba91c5 100644 (file)
@@ -9,13 +9,14 @@ GETTER(float, instagib_respawntimejitter_ammo)
 
 #ifndef MENUQC
 MODEL(VaporizerCells_ITEM, Item_Model("a_cells.md3"));
+SOUND(VaporizerCells, "misc/itempickup");
 #endif
 
 REGISTER_ITEM(VaporizerCells, Ammo) {
 #ifndef MENUQC
     this.m_model                =   MDL_VaporizerCells_ITEM;
+    this.m_sound                =   SND_VaporizerCells;
 #endif
-    this.m_sound                =   "misc/itempickup.wav";
     this.m_name                 =   "Vaporizer Ammo";
     this.m_icon                 =   "ammo_supercells";
 #ifdef SVQC
@@ -28,13 +29,14 @@ REGISTER_ITEM(VaporizerCells, Ammo) {
 
 #ifndef MENUQC
 MODEL(ExtraLife_ITEM, Item_Model("g_h100.md3"));
+SOUND(ExtraLife, "misc/megahealth");
 #endif
 
 REGISTER_ITEM(ExtraLife, Powerup) {
 #ifndef MENUQC
     this.m_model                =   MDL_ExtraLife_ITEM;
+    this.m_sound                =   SND_ExtraLife;
 #endif
-    this.m_sound                =   "misc/megahealth.wav";
     this.m_name                 =   "Extra life";
     this.m_icon                 =   "item_mega_health";
     this.m_color                =   '1 0 0';
@@ -45,13 +47,14 @@ REGISTER_ITEM(ExtraLife, Powerup) {
 
 #ifndef MENUQC
 MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
+SOUND(Invisibility, "misc/powerup");
 #endif
 
 REGISTER_ITEM(Invisibility, Powerup) {
 #ifndef MENUQC
     this.m_model            =   MDL_Invisibility_ITEM;
+    this.m_sound            =   SND_Invisibility;
 #endif
-    this.m_sound            =   "misc/powerup.wav";
     this.m_name             =   "Invisibility";
     this.m_icon             =   "strength";
     this.m_color            =   '0 0 1';
@@ -62,13 +65,14 @@ REGISTER_ITEM(Invisibility, Powerup) {
 
 #ifndef MENUQC
 MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
+SOUND(Speed, "misc/powerup_shield");
 #endif
 
 REGISTER_ITEM(Speed, Powerup) {
 #ifndef MENUQC
     this.m_model            =   MDL_Speed_ITEM;
+    this.m_sound            =   SND_Speed;
 #endif
-    this.m_sound            =   "misc/powerup_shield.wav";
     this.m_name             =   "Speed";
     this.m_icon             =   "shield";
     this.m_color            =   '1 0 1';
diff --git a/qcsrc/common/mutators/mutator/instagib/module.inc b/qcsrc/common/mutators/mutator/instagib/module.inc
new file mode 100644 (file)
index 0000000..7270067
--- /dev/null
@@ -0,0 +1 @@
+#include "instagib.qc"
diff --git a/qcsrc/common/mutators/mutator/invincibleproj/invincibleproj.qc b/qcsrc/common/mutators/mutator/invincibleproj/invincibleproj.qc
new file mode 100644 (file)
index 0000000..5a781a8
--- /dev/null
@@ -0,0 +1,25 @@
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(invincibleprojectiles, cvar("g_invincible_projectiles"));
+
+MUTATOR_HOOKFUNCTION(invincibleprojectiles, EditProjectile)
+{
+       if(other.health)
+       {
+               // disable health which in effect disables damage calculations
+               other.health = 0;
+       }
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":InvincibleProjectiles");
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Invincible Projectiles");
+       return 0;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/invincibleproj/module.inc b/qcsrc/common/mutators/mutator/invincibleproj/module.inc
new file mode 100644 (file)
index 0000000..61d0383
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "invincibleproj.qc"
+#endif
index 170862ad306f1bf5e20634e00a4f5b1d9560373d..d6b256af3ccd349a9c42f67c286d791ccb78b911 100644 (file)
@@ -1,12 +1,13 @@
 #ifdef IMPLEMENTATION
 REGISTER_MUTATOR(itemstime, true);
 
+REGISTER_NET_TEMP(itemstime)
+
 #ifdef SVQC
 void IT_Write(entity e, int i, float f) {
     if (!IS_REAL_CLIENT(e)) return;
     msg_entity = e;
-    WriteByte(MSG_ONE, SVC_TEMPENTITY);
-    WriteMutator(MSG_ONE, itemstime);
+    WriteHeader(MSG_ONE, itemstime);
     WriteByte(MSG_ONE, i);
     WriteFloat(MSG_ONE, f);
 }
@@ -15,13 +16,12 @@ void IT_Write(entity e, int i, float f) {
 #ifdef CSQC
 float ItemsTime_time[Items_MAX];
 float ItemsTime_availableTime[Items_MAX];
-MUTATOR_HOOKFUNCTION(itemstime, CSQC_Parse_TempEntity) {
-    if (MUTATOR_RETURNVALUE) return false;
-    if (!ReadMutatorEquals(mutator_argv_int_0, itemstime)) return false;
+NET_HANDLE(itemstime, bool isNew)
+{
     int i = ReadByte();
     float f = ReadFloat();
+    return = true;
     ItemsTime_time[i] = f;
-    return true;
 }
 #endif
 
@@ -102,7 +102,10 @@ void Item_ItemsTime_SetTime(entity e, float t)
         return;
 
     GameItem item = e.itemdef;
-    it_times[item.m_id] = t;
+    if (item.instanceOfGameItem && !item.instanceOfWeaponPickup)
+    {
+        it_times[item.m_id] = t;
+    }
 }
 
 void Item_ItemsTime_SetTimesForAllPlayers()
diff --git a/qcsrc/common/mutators/mutator/melee_only/melee_only.qc b/qcsrc/common/mutators/mutator/melee_only/melee_only.qc
new file mode 100644 (file)
index 0000000..5b03f46
--- /dev/null
@@ -0,0 +1,40 @@
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(melee_only, cvar("g_melee_only") && !cvar("g_instagib") && !g_nexball);
+
+MUTATOR_HOOKFUNCTION(melee_only, SetStartItems)
+{
+       start_ammo_shells = warmup_start_ammo_shells = 0;
+       start_weapons = warmup_start_weapons = WEPSET(SHOTGUN);
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, ForbidThrowCurrentWeapon)
+{
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, FilterItem)
+{SELFPARAM();
+       switch (self.items)
+       {
+               case ITEM_HealthSmall.m_itemid:
+               case ITEM_ArmorSmall.m_itemid:
+                       return false;
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":MeleeOnly");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Melee Only Arena");
+       return false;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/melee_only/module.inc b/qcsrc/common/mutators/mutator/melee_only/module.inc
new file mode 100644 (file)
index 0000000..c711556
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "melee_only.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/midair/midair.qc b/qcsrc/common/mutators/mutator/midair/midair.qc
new file mode 100644 (file)
index 0000000..aaae006
--- /dev/null
@@ -0,0 +1,50 @@
+#ifdef IMPLEMENTATION
+
+float autocvar_g_midair_shieldtime;
+
+REGISTER_MUTATOR(midair, cvar("g_midair"));
+
+.float midair_shieldtime;
+
+MUTATOR_HOOKFUNCTION(midair, PlayerDamage_Calculate)
+{SELFPARAM();
+       if(IS_PLAYER(frag_attacker))
+       if(IS_PLAYER(frag_target))
+       if(time < self.midair_shieldtime)
+               frag_damage = false;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(midair, PlayerPowerups)
+{SELFPARAM();
+       if(time >= game_starttime)
+       if(self.flags & FL_ONGROUND)
+       {
+               self.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
+               self.midair_shieldtime = max(self.midair_shieldtime, time + autocvar_g_midair_shieldtime);
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(midair, PlayerSpawn)
+{SELFPARAM();
+       if(IS_BOT_CLIENT(self))
+               self.bot_moveskill = 0; // disable bunnyhopping
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(midair, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":midair");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(midair, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Midair");
+       return false;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/midair/module.inc b/qcsrc/common/mutators/mutator/midair/module.inc
new file mode 100644 (file)
index 0000000..10b1789
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "midair.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/multijump/module.inc b/qcsrc/common/mutators/mutator/multijump/module.inc
new file mode 100644 (file)
index 0000000..3103320
--- /dev/null
@@ -0,0 +1,3 @@
+#ifndef MENUQC
+#include "multijump.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/multijump/multijump.qc b/qcsrc/common/mutators/mutator/multijump/multijump.qc
new file mode 100644 (file)
index 0000000..00e22af
--- /dev/null
@@ -0,0 +1,187 @@
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+       #include "../../../../server/antilag.qh"
+#endif
+#include "../../../physics.qh"
+
+.int multijump_count;
+.bool multijump_ready;
+.bool cvar_cl_multijump;
+
+#ifdef CSQC
+
+#define PHYS_MULTIJUMP                                 getstati(STAT_MULTIJUMP)
+#define PHYS_MULTIJUMP_SPEED           getstatf(STAT_MULTIJUMP_SPEED)
+#define PHYS_MULTIJUMP_ADD                     getstati(STAT_MULTIJUMP_ADD)
+#define PHYS_MULTIJUMP_MAXSPEED        getstatf(STAT_MULTIJUMP_MAXSPEED)
+#define PHYS_MULTIJUMP_DODGING                 getstati(STAT_MULTIJUMP_DODGING)
+
+#elif defined(SVQC)
+
+int autocvar_g_multijump;
+float autocvar_g_multijump_add;
+float autocvar_g_multijump_speed;
+float autocvar_g_multijump_maxspeed;
+float autocvar_g_multijump_dodging = 1;
+
+#define PHYS_MULTIJUMP                                 autocvar_g_multijump
+#define PHYS_MULTIJUMP_SPEED           autocvar_g_multijump_speed
+#define PHYS_MULTIJUMP_ADD                     autocvar_g_multijump_add
+#define PHYS_MULTIJUMP_MAXSPEED        autocvar_g_multijump_maxspeed
+#define PHYS_MULTIJUMP_DODGING                 autocvar_g_multijump_dodging
+
+.float stat_multijump;
+.float stat_multijump_speed;
+.float stat_multijump_add;
+.float stat_multijump_maxspeed;
+.float stat_multijump_dodging;
+
+void multijump_UpdateStats()
+{SELFPARAM();
+       self.stat_multijump = PHYS_MULTIJUMP;
+       self.stat_multijump_speed = PHYS_MULTIJUMP_SPEED;
+       self.stat_multijump_add = PHYS_MULTIJUMP_ADD;
+       self.stat_multijump_maxspeed = PHYS_MULTIJUMP_MAXSPEED;
+       self.stat_multijump_dodging = PHYS_MULTIJUMP_DODGING;
+}
+
+void multijump_AddStats()
+{
+       addstat(STAT_MULTIJUMP, AS_INT, stat_multijump);
+       addstat(STAT_MULTIJUMP_SPEED, AS_FLOAT, stat_multijump_speed);
+       addstat(STAT_MULTIJUMP_ADD, AS_INT, stat_multijump_add);
+       addstat(STAT_MULTIJUMP_MAXSPEED, AS_FLOAT, stat_multijump_maxspeed);
+       addstat(STAT_MULTIJUMP_DODGING, AS_INT, stat_multijump_dodging);
+}
+
+#endif
+
+void PM_multijump()
+{SELFPARAM();
+       if(!PHYS_MULTIJUMP) { return; }
+
+       if(IS_ONGROUND(self))
+       {
+               self.multijump_count = 0;
+       }
+}
+
+bool PM_multijump_checkjump()
+{SELFPARAM();
+       if(!PHYS_MULTIJUMP) { return false; }
+
+#ifdef SVQC
+       bool client_multijump = self.cvar_cl_multijump;
+#elif defined(CSQC)
+       bool client_multijump = cvar("cl_multijump");
+
+       if(cvar("cl_multijump") > 1)
+               return false; // nope
+#endif
+
+       if (!IS_JUMP_HELD(self) && !IS_ONGROUND(self) && client_multijump) // jump button pressed this frame and we are in midair
+               self.multijump_ready = true;  // this is necessary to check that we released the jump button and pressed it again
+       else
+               self.multijump_ready = false;
+
+       int phys_multijump = PHYS_MULTIJUMP;
+
+#ifdef CSQC
+       phys_multijump = (PHYS_MULTIJUMP) ? -1 : 0;
+#endif
+
+       if(!player_multijump && self.multijump_ready && (self.multijump_count < phys_multijump || phys_multijump == -1) && self.velocity_z > PHYS_MULTIJUMP_SPEED && (!PHYS_MULTIJUMP_MAXSPEED || vlen(self.velocity) <= PHYS_MULTIJUMP_MAXSPEED))
+       {
+               if (PHYS_MULTIJUMP)
+               {
+                       if (!PHYS_MULTIJUMP_ADD) // in this case we make the z velocity == jumpvelocity
+                       {
+                               if (self.velocity_z < PHYS_JUMPVELOCITY)
+                               {
+                                       player_multijump = true;
+                                       self.velocity_z = 0;
+                               }
+                       }
+                       else
+                               player_multijump = true;
+
+                       if(player_multijump)
+                       {
+                               if(PHYS_MULTIJUMP_DODGING)
+                               if(self.movement_x != 0 || self.movement_y != 0) // don't remove all speed if player isnt pressing any movement keys
+                               {
+                                       float curspeed;
+                                       vector wishvel, wishdir;
+
+/*#ifdef SVQC
+                                       curspeed = max(
+                                               vlen(vec2(self.velocity)), // current xy speed
+                                               vlen(vec2(antilag_takebackavgvelocity(self, max(self.lastteleporttime + sys_frametime, time - 0.25), time))) // average xy topspeed over the last 0.25 secs
+                                       );
+#elif defined(CSQC)*/
+                                       curspeed = vlen(vec2(self.velocity));
+//#endif
+
+                                       makevectors(self.v_angle_y * '0 1 0');
+                                       wishvel = v_forward * self.movement_x + v_right * self.movement_y;
+                                       wishdir = normalize(wishvel);
+
+                                       self.velocity_x = wishdir_x * curspeed; // allow "dodging" at a multijump
+                                       self.velocity_y = wishdir_y * curspeed;
+                                       // keep velocity_z unchanged!
+                               }
+                               if (PHYS_MULTIJUMP > 0)
+                               {
+                                       self.multijump_count += 1;
+                               }
+                       }
+               }
+               self.multijump_ready = false; // require releasing and pressing the jump button again for the next jump
+       }
+
+       return false;
+}
+
+#ifdef SVQC
+REGISTER_MUTATOR(multijump, cvar("g_multijump"))
+{
+       MUTATOR_ONADD
+       {
+               multijump_AddStats();
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(multijump, PlayerPhysics)
+{
+       multijump_UpdateStats();
+       PM_multijump();
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(multijump, PlayerJump)
+{
+       return PM_multijump_checkjump();
+}
+
+MUTATOR_HOOKFUNCTION(multijump, GetCvars)
+{
+       GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_multijump, "cl_multijump");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":multijump");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Multi jump");
+       return false;
+}
+
+#endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/nades/effects.inc b/qcsrc/common/mutators/mutator/nades/effects.inc
new file mode 100644 (file)
index 0000000..cde0016
--- /dev/null
@@ -0,0 +1,47 @@
+EFFECT(0, NADE_EXPLODE_RED,         "nade_red_explode")
+EFFECT(0, NADE_EXPLODE_BLUE,        "nade_blue_explode")
+EFFECT(0, NADE_EXPLODE_YELLOW,      "nade_yellow_explode")
+EFFECT(0, NADE_EXPLODE_PINK,        "nade_pink_explode")
+EFFECT(0, NADE_EXPLODE_NEUTRAL,     "nade_neutral_explode")
+entity EFFECT_NADE_EXPLODE(int teamid)
+{
+    switch (teamid) {
+        case NUM_TEAM_1:    return EFFECT_NADE_EXPLODE_RED;
+        case NUM_TEAM_2:    return EFFECT_NADE_EXPLODE_BLUE;
+        case NUM_TEAM_3:    return EFFECT_NADE_EXPLODE_YELLOW;
+        case NUM_TEAM_4:    return EFFECT_NADE_EXPLODE_PINK;
+        default:                   return EFFECT_NADE_EXPLODE_NEUTRAL;
+    }
+}
+
+EFFECT(1, NADE_TRAIL_RED,           "nade_red")
+EFFECT(1, NADE_TRAIL_BLUE,          "nade_blue")
+EFFECT(1, NADE_TRAIL_YELLOW,        "nade_yellow")
+EFFECT(1, NADE_TRAIL_PINK,          "nade_pink")
+EFFECT(1, NADE_TRAIL_NEUTRAL,       "nade_neutral")
+entity EFFECT_NADE_TRAIL(int teamid)
+{
+    switch (teamid) {
+        case NUM_TEAM_1:    return EFFECT_NADE_TRAIL_RED;
+        case NUM_TEAM_2:    return EFFECT_NADE_TRAIL_BLUE;
+        case NUM_TEAM_3:    return EFFECT_NADE_TRAIL_YELLOW;
+        case NUM_TEAM_4:    return EFFECT_NADE_TRAIL_PINK;
+        default:            return EFFECT_NADE_TRAIL_NEUTRAL;
+    }
+}
+
+EFFECT(1, NADE_TRAIL_BURN_RED,      "nade_red_burn")
+EFFECT(1, NADE_TRAIL_BURN_BLUE,     "nade_blue_burn")
+EFFECT(1, NADE_TRAIL_BURN_YELLOW,   "nade_yellow_burn")
+EFFECT(1, NADE_TRAIL_BURN_PINK,     "nade_pink_burn")
+EFFECT(1, NADE_TRAIL_BURN_NEUTRAL,  "nade_neutral_burn")
+entity EFFECT_NADE_TRAIL_BURN(int teamid)
+{
+    switch (teamid) {
+        case NUM_TEAM_1:    return EFFECT_NADE_TRAIL_BURN_RED;
+        case NUM_TEAM_2:    return EFFECT_NADE_TRAIL_BURN_BLUE;
+        case NUM_TEAM_3:    return EFFECT_NADE_TRAIL_BURN_YELLOW;
+        case NUM_TEAM_4:    return EFFECT_NADE_TRAIL_BURN_PINK;
+        default:            return EFFECT_NADE_TRAIL_BURN_NEUTRAL;
+    }
+}
diff --git a/qcsrc/common/mutators/mutator/nades/module.inc b/qcsrc/common/mutators/mutator/nades/module.inc
new file mode 100644 (file)
index 0000000..e03900d
--- /dev/null
@@ -0,0 +1,4 @@
+#include "nades.qc"
+#ifndef MENUQC
+#include "net.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/nades/nades.inc b/qcsrc/common/mutators/mutator/nades/nades.inc
new file mode 100644 (file)
index 0000000..6d16fd1
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef MENUQC
+#define NADE_PROJECTILE(i, projectile, trail) do { \
+    this.m_projectile[i] = projectile; \
+    this.m_trail[i] = trail; \
+} while (0)
+#else
+#define NADE_PROJECTILE(i, projectile, trail)
+#endif
+
+REGISTER_NADE(NORMAL) {
+    this.m_color = '1 1 1';
+    NADE_PROJECTILE(0, PROJECTILE_NADE, EFFECT_Null);
+    NADE_PROJECTILE(1, PROJECTILE_NADE_BURN, EFFECT_Null);
+}
+
+REGISTER_NADE(NAPALM) {
+    this.m_color = '2 0.5 0';
+    this.m_name = _("Napalm grenade");
+    this.m_icon = "nade_napalm";
+    NADE_PROJECTILE(0, PROJECTILE_NADE_NAPALM, EFFECT_TR_ROCKET);
+    NADE_PROJECTILE(1, PROJECTILE_NADE_NAPALM_BURN, EFFECT_SPIDERBOT_ROCKET_TRAIL);
+}
+
+REGISTER_NADE(ICE) {
+    this.m_color = '0 0.5 2';
+    this.m_name = _("Ice grenade");
+    this.m_icon = "nade_ice";
+    NADE_PROJECTILE(0, PROJECTILE_NADE_ICE, EFFECT_TR_NEXUIZPLASMA);
+    NADE_PROJECTILE(1, PROJECTILE_NADE_ICE_BURN, EFFECT_RACER_ROCKET_TRAIL);
+}
+
+REGISTER_NADE(TRANSLOCATE) {
+    this.m_color = '1 0 1';
+    this.m_name = _("Translocate grenade");
+    this.m_icon = "nade_translocate";
+    NADE_PROJECTILE(0, PROJECTILE_NADE_TRANSLOCATE, EFFECT_TR_CRYLINKPLASMA);
+    NADE_PROJECTILE(1, PROJECTILE_NADE_TRANSLOCATE, EFFECT_TR_CRYLINKPLASMA);
+}
+
+REGISTER_NADE(SPAWN) {
+    this.m_color = '1 0.9 0';
+    this.m_name = _("Spawn grenade");
+    this.m_icon = "nade_spawn";
+    NADE_PROJECTILE(0, PROJECTILE_NADE_SPAWN, EFFECT_NADE_TRAIL_YELLOW);
+    NADE_PROJECTILE(1, PROJECTILE_NADE_SPAWN, EFFECT_NADE_TRAIL_YELLOW);
+}
+
+REGISTER_NADE(HEAL) {
+    this.m_color = '1 0 0';
+    this.m_name = _("Heal grenade");
+    this.m_icon = "nade_heal";
+    NADE_PROJECTILE(0, PROJECTILE_NADE_HEAL, EFFECT_NADE_TRAIL_RED);
+    NADE_PROJECTILE(1, PROJECTILE_NADE_HEAL_BURN, EFFECT_NADE_TRAIL_BURN_RED);
+}
+
+REGISTER_NADE(MONSTER) {
+    this.m_color = '0.25 0.75 0';
+    this.m_name = _("Monster grenade");
+    this.m_icon = "nade_monster";
+    NADE_PROJECTILE(0, PROJECTILE_NADE_MONSTER, EFFECT_NADE_TRAIL_RED);
+    NADE_PROJECTILE(1, PROJECTILE_NADE_MONSTER_BURN, EFFECT_NADE_TRAIL_BURN_RED);
+}
diff --git a/qcsrc/common/mutators/mutator/nades/nades.qc b/qcsrc/common/mutators/mutator/nades/nades.qc
new file mode 100644 (file)
index 0000000..ef021bb
--- /dev/null
@@ -0,0 +1,1323 @@
+#include "nades.qh"
+
+#ifdef IMPLEMENTATION
+
+#ifndef MENUQC
+entity Nade_TrailEffect(int proj, int nade_team)
+{
+    switch (proj)
+    {
+        case PROJECTILE_NADE:       return EFFECT_NADE_TRAIL(nade_team);
+        case PROJECTILE_NADE_BURN:  return EFFECT_NADE_TRAIL_BURN(nade_team);
+    }
+
+    FOREACH(Nades, true, LAMBDA(
+        for (int j = 0; j < 2; j++)
+        {
+            if (it.m_projectile[j] == proj)
+            {
+                string trail = it.m_trail[j].eent_eff_name;
+                if (trail) return it.m_trail[j];
+                break;
+            }
+        }
+    ));
+
+    return EFFECT_Null;
+}
+#endif
+
+#ifdef CSQC
+REGISTER_MUTATOR(cl_nades, true);
+MUTATOR_HOOKFUNCTION(cl_nades, HUD_Draw_overlay)
+{
+       if (getstatf(STAT_HEALING_ORB) <= time) return false;
+       MUTATOR_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
+       MUTATOR_ARGV(0, float) = getstatf(STAT_HEALING_ORB_ALPHA);
+       return true;
+}
+MUTATOR_HOOKFUNCTION(cl_nades, Ent_Projectile)
+{
+       if (self.cnt == PROJECTILE_NAPALM_FOUNTAIN)
+       {
+               self.modelindex = 0;
+               self.traileffect = EFFECT_FIREBALL.m_id;
+               return true;
+       }
+       if (Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
+       {
+               setmodel(self, MDL_PROJECTILE_NADE);
+               entity trail = Nade_TrailEffect(self.cnt, self.team);
+               if (trail.eent_eff_name) self.traileffect = trail.m_id;
+               return true;
+       }
+}
+MUTATOR_HOOKFUNCTION(cl_nades, EditProjectile)
+{
+       if (self.cnt == PROJECTILE_NAPALM_FOUNTAIN)
+       {
+               loopsound(self, CH_SHOTS_SINGLE, SND(FIREBALL_FLY2), VOL_BASE, ATTEN_NORM);
+               self.mins = '-16 -16 -16';
+               self.maxs = '16 16 16';
+       }
+
+       entity nade_type = Nade_FromProjectile(self.cnt);
+       if (nade_type == NADE_TYPE_Null) return;
+       self.mins = '-16 -16 -16';
+       self.maxs = '16 16 16';
+       self.colormod = nade_type.m_color;
+       self.move_movetype = MOVETYPE_BOUNCE;
+       self.move_touch = func_null;
+       self.scale = 1.5;
+       self.avelocity = randomvec() * 720;
+
+       if (nade_type == NADE_TYPE_TRANSLOCATE || nade_type == NADE_TYPE_SPAWN)
+               self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+       else
+               self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
+}
+bool Projectile_isnade(int p)
+{
+       return Nade_FromProjectile(p) != NADE_TYPE_Null;
+}
+void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time)
+{
+       float bonusNades    = getstatf(STAT_NADE_BONUS);
+       float bonusProgress = getstatf(STAT_NADE_BONUS_SCORE);
+       float bonusType     = getstati(STAT_NADE_BONUS_TYPE);
+       Nade def = Nades_from(bonusType);
+       vector nadeColor    = def.m_color;
+       string nadeIcon     = def.m_icon;
+
+       vector iconPos, textPos;
+
+       if(autocvar_hud_panel_ammo_iconalign)
+       {
+               iconPos = myPos + eX * 2 * mySize.y;
+               textPos = myPos;
+       }
+       else
+       {
+               iconPos = myPos;
+               textPos = myPos + eX * mySize.y;
+       }
+
+       if(bonusNades > 0 || bonusProgress > 0)
+       {
+               DrawNadeProgressBar(myPos, mySize, bonusProgress, nadeColor);
+
+               if(autocvar_hud_panel_ammo_text)
+                       drawstring_aspect(textPos, ftos(bonusNades), eX * (2/3) * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+               if(draw_expanding)
+                       drawpic_aspect_skin_expanding(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, expand_time);
+
+               drawpic_aspect_skin(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+}
+#endif
+
+#ifdef SVQC
+
+#include "../../../gamemodes/all.qh"
+#include "../../../monsters/spawn.qh"
+#include "../../../monsters/sv_monsters.qh"
+#include "../../../../server/g_subs.qh"
+
+REGISTER_MUTATOR(nades, cvar("g_nades"))
+{
+       MUTATOR_ONADD
+       {
+               addstat(STAT_NADE_TIMER, AS_FLOAT, nade_timer);
+               addstat(STAT_NADE_BONUS, AS_FLOAT, bonus_nades);
+               addstat(STAT_NADE_BONUS_TYPE, AS_INT, nade_type);
+               addstat(STAT_NADE_BONUS_SCORE, AS_FLOAT, bonus_nade_score);
+               addstat(STAT_HEALING_ORB, AS_FLOAT, stat_healing_orb);
+               addstat(STAT_HEALING_ORB_ALPHA, AS_FLOAT, stat_healing_orb_alpha);
+       }
+
+       return false;
+}
+
+.float nade_time_primed;
+
+.entity nade_spawnloc;
+
+void nade_timer_think()
+{SELFPARAM();
+       self.skin = 8 - (self.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10);
+       self.nextthink = time;
+       if(!self.owner || wasfreed(self.owner))
+               remove(self);
+}
+
+void nade_burn_spawn(entity _nade)
+{
+       CSQCProjectile(_nade, true, Nades_from(_nade.nade_type).m_projectile[true], true);
+}
+
+void nade_spawn(entity _nade)
+{
+       entity timer = new(nade_timer);
+       setmodel(timer, MDL_NADE_TIMER);
+       setattachment(timer, _nade, "");
+       timer.colormap = _nade.colormap;
+       timer.glowmod = _nade.glowmod;
+       timer.think = nade_timer_think;
+       timer.nextthink = time;
+       timer.wait = _nade.wait;
+       timer.owner = _nade;
+       timer.skin = 10;
+
+       _nade.effects |= EF_LOWPRECISION;
+
+       CSQCProjectile(_nade, true, Nades_from(_nade.nade_type).m_projectile[false], true);
+}
+
+void napalm_damage(float dist, float damage, float edgedamage, float burntime)
+{SELFPARAM();
+       entity e;
+       float d;
+       vector p;
+
+       if ( damage < 0 )
+               return;
+
+       RandomSelection_Init();
+       for(e = WarpZone_FindRadius(self.origin, dist, true); e; e = e.chain)
+               if(e.takedamage == DAMAGE_AIM)
+               if(self.realowner != e || autocvar_g_nades_napalm_selfdamage)
+               if(!IS_PLAYER(e) || !self.realowner || DIFF_TEAM(e, self))
+               if(!e.frozen)
+               {
+                       p = e.origin;
+                       p.x += e.mins.x + random() * (e.maxs.x - e.mins.x);
+                       p.y += e.mins.y + random() * (e.maxs.y - e.mins.y);
+                       p.z += e.mins.z + random() * (e.maxs.z - e.mins.z);
+                       d = vlen(WarpZone_UnTransformOrigin(e, self.origin) - p);
+                       if(d < dist)
+                       {
+                               e.fireball_impactvec = p;
+                               RandomSelection_Add(e, 0, string_null, 1 / (1 + d), !Fire_IsBurning(e));
+                       }
+               }
+       if(RandomSelection_chosen_ent)
+       {
+               d = vlen(WarpZone_UnTransformOrigin(RandomSelection_chosen_ent, self.origin) - RandomSelection_chosen_ent.fireball_impactvec);
+               d = damage + (edgedamage - damage) * (d / dist);
+               Fire_AddDamage(RandomSelection_chosen_ent, self.realowner, d * burntime, burntime, self.projectiledeathtype | HITTYPE_BOUNCE);
+               //trailparticles(self, particleeffectnum(EFFECT_FIREBALL_LASER), self.origin, RandomSelection_chosen_ent.fireball_impactvec);
+               Send_Effect(EFFECT_FIREBALL_LASER, self.origin, RandomSelection_chosen_ent.fireball_impactvec - self.origin, 1);
+       }
+}
+
+
+void napalm_ball_think()
+{SELFPARAM();
+       if(round_handler_IsActive())
+       if(!round_handler_IsRoundStarted())
+       {
+               remove(self);
+               return;
+       }
+
+       if(time > self.pushltime)
+       {
+               remove(self);
+               return;
+       }
+
+       vector midpoint = ((self.absmin + self.absmax) * 0.5);
+       if(pointcontents(midpoint) == CONTENT_WATER)
+       {
+               self.velocity = self.velocity * 0.5;
+
+               if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
+                       { self.velocity_z = 200; }
+       }
+
+       self.angles = vectoangles(self.velocity);
+
+       napalm_damage(autocvar_g_nades_napalm_ball_radius,autocvar_g_nades_napalm_ball_damage,
+                                 autocvar_g_nades_napalm_ball_damage,autocvar_g_nades_napalm_burntime);
+
+       self.nextthink = time + 0.1;
+}
+
+
+void nade_napalm_ball()
+{SELFPARAM();
+       entity proj;
+       vector kick;
+
+       spamsound(self, CH_SHOTS, SND(FIREBALL_FIRE), VOL_BASE, ATTEN_NORM);
+
+       proj = new(grenade);
+       proj.owner = self.owner;
+       proj.realowner = self.realowner;
+       proj.team = self.owner.team;
+       proj.bot_dodge = true;
+       proj.bot_dodgerating = autocvar_g_nades_napalm_ball_damage;
+       proj.movetype = MOVETYPE_BOUNCE;
+       proj.projectiledeathtype = DEATH_NADE_NAPALM.m_id;
+       PROJECTILE_MAKETRIGGER(proj);
+       setmodel(proj, MDL_Null);
+       proj.scale = 1;//0.5;
+       setsize(proj, '-4 -4 -4', '4 4 4');
+       setorigin(proj, self.origin);
+       proj.think = napalm_ball_think;
+       proj.nextthink = time;
+       proj.damageforcescale = autocvar_g_nades_napalm_ball_damageforcescale;
+       proj.effects = EF_LOWPRECISION | EF_FLAME;
+
+       kick.x =(random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread;
+       kick.y = (random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread;
+       kick.z = (random()/2+0.5) * autocvar_g_nades_napalm_ball_spread;
+       proj.velocity = kick;
+
+       proj.pushltime = time + autocvar_g_nades_napalm_ball_lifetime;
+
+       proj.angles = vectoangles(proj.velocity);
+       proj.flags = FL_PROJECTILE;
+       proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
+
+       //CSQCProjectile(proj, true, PROJECTILE_NAPALM_FIRE, true);
+}
+
+
+void napalm_fountain_think()
+{SELFPARAM();
+
+       if(round_handler_IsActive())
+       if(!round_handler_IsRoundStarted())
+       {
+               remove(self);
+               return;
+       }
+
+       if(time >= self.ltime)
+       {
+               remove(self);
+               return;
+       }
+
+       vector midpoint = ((self.absmin + self.absmax) * 0.5);
+       if(pointcontents(midpoint) == CONTENT_WATER)
+       {
+               self.velocity = self.velocity * 0.5;
+
+               if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
+                       { self.velocity_z = 200; }
+
+               UpdateCSQCProjectile(self);
+       }
+
+       napalm_damage(autocvar_g_nades_napalm_fountain_radius, autocvar_g_nades_napalm_fountain_damage,
+               autocvar_g_nades_napalm_fountain_edgedamage, autocvar_g_nades_napalm_burntime);
+
+       self.nextthink = time + 0.1;
+       if(time >= self.nade_special_time)
+       {
+               self.nade_special_time = time + autocvar_g_nades_napalm_fountain_delay;
+               nade_napalm_ball();
+       }
+}
+
+void nade_napalm_boom()
+{SELFPARAM();
+       entity fountain;
+       int c;
+       for (c = 0; c < autocvar_g_nades_napalm_ball_count; c++)
+               nade_napalm_ball();
+
+
+       fountain = spawn();
+       fountain.owner = self.owner;
+       fountain.realowner = self.realowner;
+       fountain.origin = self.origin;
+       setorigin(fountain, fountain.origin);
+       fountain.think = napalm_fountain_think;
+       fountain.nextthink = time;
+       fountain.ltime = time + autocvar_g_nades_napalm_fountain_lifetime;
+       fountain.pushltime = fountain.ltime;
+       fountain.team = self.team;
+       fountain.movetype = MOVETYPE_TOSS;
+       fountain.projectiledeathtype = DEATH_NADE_NAPALM.m_id;
+       fountain.bot_dodge = true;
+       fountain.bot_dodgerating = autocvar_g_nades_napalm_fountain_damage;
+       fountain.nade_special_time = time;
+       setsize(fountain, '-16 -16 -16', '16 16 16');
+       CSQCProjectile(fountain, true, PROJECTILE_NAPALM_FOUNTAIN, true);
+}
+
+void nade_ice_freeze(entity freezefield, entity frost_target, float freeze_time)
+{
+       frost_target.frozen_by = freezefield.realowner;
+       Send_Effect(EFFECT_ELECTRO_IMPACT, frost_target.origin, '0 0 0', 1);
+       Freeze(frost_target, 1/freeze_time, 3, false);
+
+       Drop_Special_Items(frost_target);
+}
+
+void nade_ice_think()
+{SELFPARAM();
+
+       if(round_handler_IsActive())
+       if(!round_handler_IsRoundStarted())
+       {
+               remove(self);
+               return;
+       }
+
+       if(time >= self.ltime)
+       {
+               if ( autocvar_g_nades_ice_explode )
+               {
+                       entity expef = EFFECT_NADE_EXPLODE(self.realowner.team);
+                       Send_Effect(expef, self.origin + '0 0 1', '0 0 0', 1);
+                       sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+
+                       RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
+                               autocvar_g_nades_nade_radius, self, world, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
+                       Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
+                               autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
+               }
+               remove(self);
+               return;
+       }
+
+
+       self.nextthink = time+0.1;
+
+       // gaussian
+       float randomr;
+       randomr = random();
+       randomr = exp(-5*randomr*randomr)*autocvar_g_nades_nade_radius;
+       float randomw;
+       randomw = random()*M_PI*2;
+       vector randomp;
+       randomp.x = randomr*cos(randomw);
+       randomp.y = randomr*sin(randomw);
+       randomp.z = 1;
+       Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, self.origin + randomp, '0 0 0', 1);
+
+       if(time >= self.nade_special_time)
+       {
+               self.nade_special_time = time+0.7;
+
+               Send_Effect(EFFECT_ELECTRO_IMPACT, self.origin, '0 0 0', 1);
+               Send_Effect(EFFECT_ICEFIELD, self.origin, '0 0 0', 1);
+       }
+
+
+       float current_freeze_time = self.ltime - time - 0.1;
+
+       entity e;
+       for(e = findradius(self.origin, autocvar_g_nades_nade_radius); e; e = e.chain)
+       if(e != self)
+       if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(e, self.realowner) || e == self.realowner))
+       if(e.takedamage && e.deadflag == DEAD_NO)
+       if(e.health > 0)
+       if(!e.revival_time || ((time - e.revival_time) >= 1.5))
+       if(!e.frozen)
+       if(current_freeze_time > 0)
+               nade_ice_freeze(self, e, current_freeze_time);
+}
+
+void nade_ice_boom()
+{SELFPARAM();
+       entity fountain;
+       fountain = spawn();
+       fountain.owner = self.owner;
+       fountain.realowner = self.realowner;
+       fountain.origin = self.origin;
+       setorigin(fountain, fountain.origin);
+       fountain.think = nade_ice_think;
+       fountain.nextthink = time;
+       fountain.ltime = time + autocvar_g_nades_ice_freeze_time;
+       fountain.pushltime = fountain.wait = fountain.ltime;
+       fountain.team = self.team;
+       fountain.movetype = MOVETYPE_TOSS;
+       fountain.projectiledeathtype = DEATH_NADE_ICE.m_id;
+       fountain.bot_dodge = false;
+       setsize(fountain, '-16 -16 -16', '16 16 16');
+       fountain.nade_special_time = time+0.3;
+       fountain.angles = self.angles;
+
+       if ( autocvar_g_nades_ice_explode )
+       {
+               setmodel(fountain, MDL_PROJECTILE_GRENADE);
+               entity timer = new(nade_timer);
+               setmodel(timer, MDL_NADE_TIMER);
+               setattachment(timer, fountain, "");
+               timer.colormap = self.colormap;
+               timer.glowmod = self.glowmod;
+               timer.think = nade_timer_think;
+               timer.nextthink = time;
+               timer.wait = fountain.ltime;
+               timer.owner = fountain;
+               timer.skin = 10;
+       }
+       else
+               setmodel(fountain, MDL_Null);
+}
+
+void nade_translocate_boom()
+{SELFPARAM();
+       if(self.realowner.vehicle)
+               return;
+
+       vector locout = self.origin + '0 0 1' * (1 - self.realowner.mins.z - 24);
+       tracebox(locout, self.realowner.mins, self.realowner.maxs, locout, MOVE_NOMONSTERS, self.realowner);
+       locout = trace_endpos;
+
+       makevectors(self.realowner.angles);
+
+       MUTATOR_CALLHOOK(PortalTeleport, self.realowner);
+
+       TeleportPlayer(self, self.realowner, locout, self.realowner.angles, v_forward * vlen(self.realowner.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
+}
+
+void nade_spawn_boom()
+{SELFPARAM();
+       entity spawnloc = spawn();
+       setorigin(spawnloc, self.origin);
+       setsize(spawnloc, self.realowner.mins, self.realowner.maxs);
+       spawnloc.movetype = MOVETYPE_NONE;
+       spawnloc.solid = SOLID_NOT;
+       spawnloc.drawonlytoclient = self.realowner;
+       spawnloc.effects = EF_STARDUST;
+       spawnloc.cnt = autocvar_g_nades_spawn_count;
+
+       if(self.realowner.nade_spawnloc)
+       {
+               remove(self.realowner.nade_spawnloc);
+               self.realowner.nade_spawnloc = world;
+       }
+
+       self.realowner.nade_spawnloc = spawnloc;
+}
+
+void nade_heal_think()
+{SELFPARAM();
+       if(time >= self.ltime)
+       {
+               remove(self);
+               return;
+       }
+
+       self.nextthink = time;
+
+       if(time >= self.nade_special_time)
+       {
+               self.nade_special_time = time+0.25;
+               self.nade_show_particles = 1;
+       }
+       else
+               self.nade_show_particles = 0;
+}
+
+void nade_heal_touch()
+{SELFPARAM();
+       float maxhealth;
+       float health_factor;
+       if(IS_PLAYER(other) || IS_MONSTER(other))
+       if(other.deadflag == DEAD_NO)
+       if(!other.frozen)
+       {
+               health_factor = autocvar_g_nades_heal_rate*frametime/2;
+               if ( other != self.realowner )
+               {
+                       if ( SAME_TEAM(other,self) )
+                               health_factor *= autocvar_g_nades_heal_friend;
+                       else
+                               health_factor *= autocvar_g_nades_heal_foe;
+               }
+               if ( health_factor > 0 )
+               {
+                       maxhealth = (IS_MONSTER(other)) ? other.max_health : g_pickup_healthmega_max;
+                       if ( other.health < maxhealth )
+                       {
+                               if ( self.nade_show_particles )
+                                       Send_Effect(EFFECT_HEALING, other.origin, '0 0 0', 1);
+                               other.health = min(other.health+health_factor, maxhealth);
+                       }
+                       other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
+               }
+               else if ( health_factor < 0 )
+               {
+                       Damage(other,self,self.realowner,-health_factor,DEATH_NADE_HEAL.m_id,other.origin,'0 0 0');
+               }
+
+       }
+
+       if ( IS_REAL_CLIENT(other) || IS_VEHICLE(other) )
+       {
+               entity show_red = (IS_VEHICLE(other)) ? other.owner : other;
+               show_red.stat_healing_orb = time+0.1;
+               show_red.stat_healing_orb_alpha = 0.75 * (self.ltime - time) / self.healer_lifetime;
+       }
+}
+
+void nade_heal_boom()
+{SELFPARAM();
+       entity healer;
+       healer = spawn();
+       healer.owner = self.owner;
+       healer.realowner = self.realowner;
+       setorigin(healer, self.origin);
+       healer.healer_lifetime = autocvar_g_nades_heal_time; // save the cvar
+       healer.ltime = time + healer.healer_lifetime;
+       healer.team = self.realowner.team;
+       healer.bot_dodge = false;
+       healer.solid = SOLID_TRIGGER;
+       healer.touch = nade_heal_touch;
+
+       setmodel(healer, MDL_NADE_HEAL);
+       healer.healer_radius = autocvar_g_nades_nade_radius;
+       vector size = '1 1 1' * healer.healer_radius / 2;
+       setsize(healer,-size,size);
+
+       Net_LinkEntity(healer, true, 0, healer_send);
+
+       healer.think = nade_heal_think;
+       healer.nextthink = time;
+       healer.SendFlags |= 1;
+}
+
+void nade_monster_boom()
+{SELFPARAM();
+       entity e = spawnmonster(self.pokenade_type, 0, self.realowner, self.realowner, self.origin, false, false, 1);
+
+       if(autocvar_g_nades_pokenade_monster_lifetime > 0)
+               e.monster_lifetime = time + autocvar_g_nades_pokenade_monster_lifetime;
+       e.monster_skill = MONSTER_SKILL_INSANE;
+}
+
+void nade_boom()
+{SELFPARAM();
+       entity expef = NULL;
+       bool nade_blast = true;
+
+       switch ( Nades_from(self.nade_type) )
+       {
+               case NADE_TYPE_NAPALM:
+                       nade_blast = autocvar_g_nades_napalm_blast;
+                       expef = EFFECT_EXPLOSION_MEDIUM;
+                       break;
+               case NADE_TYPE_ICE:
+                       nade_blast = false;
+                       expef = EFFECT_ELECTRO_COMBO; // hookbomb_explode electro_combo bigplasma_impact
+                       break;
+               case NADE_TYPE_TRANSLOCATE:
+                       nade_blast = false;
+                       break;
+               case NADE_TYPE_MONSTER:
+               case NADE_TYPE_SPAWN:
+                       nade_blast = false;
+                       switch(self.realowner.team)
+                       {
+                               case NUM_TEAM_1: expef = EFFECT_SPAWN_RED; break;
+                               case NUM_TEAM_2: expef = EFFECT_SPAWN_BLUE; break;
+                               case NUM_TEAM_3: expef = EFFECT_SPAWN_YELLOW; break;
+                               case NUM_TEAM_4: expef = EFFECT_SPAWN_PINK; break;
+                               default: expef = EFFECT_SPAWN_NEUTRAL; break;
+                       }
+                       break;
+               case NADE_TYPE_HEAL:
+                       nade_blast = false;
+                       expef = EFFECT_SPAWN_RED;
+                       break;
+
+               default:
+               case NADE_TYPE_NORMAL:
+                       expef = EFFECT_NADE_EXPLODE(self.realowner.team);
+                       break;
+       }
+
+       if(expef)
+               Send_Effect(expef, findbetterlocation(self.origin, 8), '0 0 0', 1);
+
+       sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
+       sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+
+       self.event_damage = func_null; // prevent somehow calling damage in the next call
+
+       if(nade_blast)
+       {
+               RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
+                                autocvar_g_nades_nade_radius, self, world, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
+               Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
+       }
+
+       if(self.takedamage)
+       switch ( Nades_from(self.nade_type) )
+       {
+               case NADE_TYPE_NAPALM: nade_napalm_boom(); break;
+               case NADE_TYPE_ICE: nade_ice_boom(); break;
+               case NADE_TYPE_TRANSLOCATE: nade_translocate_boom(); break;
+               case NADE_TYPE_SPAWN: nade_spawn_boom(); break;
+               case NADE_TYPE_HEAL: nade_heal_boom(); break;
+               case NADE_TYPE_MONSTER: nade_monster_boom(); break;
+       }
+
+       entity head;
+       for(head = world; (head = find(head, classname, "grapplinghook")); )
+       if(head.aiment == self)
+               RemoveGrapplingHook(head.realowner);
+
+       remove(self);
+}
+
+void nade_touch()
+{SELFPARAM();
+       /*float is_weapclip = 0;
+       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW)
+       if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID))
+       if (!(trace_dphitcontents & DPCONTENTS_OPAQUE))
+               is_weapclip = 1;*/
+       if(ITEM_TOUCH_NEEDKILL()) // || is_weapclip)
+       {
+               entity head;
+               for(head = world; (head = find(head, classname, "grapplinghook")); )
+               if(head.aiment == self)
+                       RemoveGrapplingHook(head.realowner);
+               remove(self);
+               return;
+       }
+
+       PROJECTILE_TOUCH;
+
+       //setsize(self, '-2 -2 -2', '2 2 2');
+       //UpdateCSQCProjectile(self);
+       if(self.health == self.max_health)
+       {
+               spamsound(self, CH_SHOTS, SND(GRENADE_BOUNCE_RANDOM()), VOL_BASE, ATTEN_NORM);
+               return;
+       }
+
+       self.enemy = other;
+       nade_boom();
+}
+
+void nade_beep()
+{SELFPARAM();
+       sound(self, CH_SHOTS_SINGLE, SND_NADE_BEEP, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
+       self.think = nade_boom;
+       self.nextthink = max(self.wait, time);
+}
+
+void nade_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{SELFPARAM();
+       if(ITEM_DAMAGE_NEEDKILL(deathtype))
+       {
+               self.takedamage = DAMAGE_NO;
+               nade_boom();
+               return;
+       }
+
+       if(self.nade_type == NADE_TYPE_TRANSLOCATE.m_id || self.nade_type == NADE_TYPE_SPAWN.m_id)
+               return;
+
+       if (MUTATOR_CALLHOOK(Nade_Damage, DEATH_WEAPONOF(deathtype), force, damage)) {}
+       else if(DEATH_ISWEAPON(deathtype, WEP_BLASTER))
+       {
+               force *= 1.5;
+               damage = 0;
+       }
+       else if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER) && (deathtype & HITTYPE_SECONDARY))
+       {
+               force *= 0.5; // too much
+               damage = 0;
+       }
+       else if(DEATH_ISWEAPON(deathtype, WEP_VORTEX) || DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
+       {
+               force *= 6;
+               damage = self.max_health * 0.55;
+       }
+       else if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN))
+               damage = self.max_health * 0.1;
+       else if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE) || DEATH_ISWEAPON(deathtype, WEP_SHOTGUN)) // WEAPONTODO
+       {
+               if(deathtype & HITTYPE_SECONDARY)
+               {
+                       damage = self.max_health * 0.1;
+                       force *= 10;
+               }
+               else
+                       damage = self.max_health * 1.15;
+       }
+
+       self.velocity += force;
+       UpdateCSQCProjectile(self);
+
+       if(damage <= 0 || ((self.flags & FL_ONGROUND) && IS_PLAYER(attacker)))
+               return;
+
+       if(self.health == self.max_health)
+       {
+               sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
+               self.nextthink = max(time + autocvar_g_nades_nade_lifetime, time);
+               self.think = nade_beep;
+       }
+
+       self.health -= damage;
+
+       if ( self.nade_type != NADE_TYPE_HEAL.m_id || IS_PLAYER(attacker) )
+               self.realowner = attacker;
+
+       if(self.health <= 0)
+               W_PrepareExplosionByDamage(attacker, nade_boom);
+       else
+               nade_burn_spawn(self);
+}
+
+void toss_nade(entity e, vector _velocity, float _time)
+{SELFPARAM();
+       if(e.nade == world)
+               return;
+
+       entity _nade = e.nade;
+       e.nade = world;
+
+       remove(e.fake_nade);
+       e.fake_nade = world;
+
+       makevectors(e.v_angle);
+
+       W_SetupShot(e, false, false, "", CH_WEAPON_A, 0);
+
+       Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_NADES);
+
+       vector offset = (v_forward * autocvar_g_nades_throw_offset.x)
+                                 + (v_right * autocvar_g_nades_throw_offset.y)
+                                 + (v_up * autocvar_g_nades_throw_offset.z);
+       if(autocvar_g_nades_throw_offset == '0 0 0')
+               offset = '0 0 0';
+
+       setorigin(_nade, w_shotorg + offset + (v_right * 25) * -1);
+       //setmodel(_nade, MDL_PROJECTILE_NADE);
+       //setattachment(_nade, world, "");
+       PROJECTILE_MAKETRIGGER(_nade);
+       setsize(_nade, '-16 -16 -16', '16 16 16');
+       _nade.movetype = MOVETYPE_BOUNCE;
+
+       tracebox(_nade.origin, _nade.mins, _nade.maxs, _nade.origin, false, _nade);
+       if (trace_startsolid)
+               setorigin(_nade, e.origin);
+
+       if(self.v_angle.x >= 70 && self.v_angle.x <= 110 && self.BUTTON_CROUCH)
+               _nade.velocity = '0 0 100';
+       else if(autocvar_g_nades_nade_newton_style == 1)
+               _nade.velocity = e.velocity + _velocity;
+       else if(autocvar_g_nades_nade_newton_style == 2)
+               _nade.velocity = _velocity;
+       else
+               _nade.velocity = W_CalculateProjectileVelocity(e.velocity, _velocity, true);
+
+       _nade.touch = nade_touch;
+       _nade.health = autocvar_g_nades_nade_health;
+       _nade.max_health = _nade.health;
+       _nade.takedamage = DAMAGE_AIM;
+       _nade.event_damage = nade_damage;
+       _nade.customizeentityforclient = func_null;
+       _nade.exteriormodeltoclient = world;
+       _nade.traileffectnum = 0;
+       _nade.teleportable = true;
+       _nade.pushable = true;
+       _nade.gravity = 1;
+       _nade.missile_flags = MIF_SPLASH | MIF_ARC;
+       _nade.damagedbycontents = true;
+       _nade.angles = vectoangles(_nade.velocity);
+       _nade.flags = FL_PROJECTILE;
+       _nade.projectiledeathtype = DEATH_NADE.m_id;
+       _nade.toss_time = time;
+       _nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX);
+
+       if(_nade.nade_type == NADE_TYPE_TRANSLOCATE.m_id || _nade.nade_type == NADE_TYPE_SPAWN.m_id)
+               _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+       else
+               _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
+
+       nade_spawn(_nade);
+
+       if(_time)
+       {
+               _nade.think = nade_boom;
+               _nade.nextthink = _time;
+       }
+
+       e.nade_refire = time + autocvar_g_nades_nade_refire;
+       e.nade_timer = 0;
+}
+
+void nades_GiveBonus(entity player, float score)
+{
+       if (autocvar_g_nades)
+       if (autocvar_g_nades_bonus)
+       if (IS_REAL_CLIENT(player))
+       if (IS_PLAYER(player) && player.bonus_nades < autocvar_g_nades_bonus_max)
+       if (player.frozen == 0)
+       if (player.deadflag == DEAD_NO)
+       {
+               if ( player.bonus_nade_score < 1 )
+                       player.bonus_nade_score += score/autocvar_g_nades_bonus_score_max;
+
+               if ( player.bonus_nade_score >= 1 )
+               {
+                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_NADE_BONUS);
+                       play2(player, SND(KH_ALARM));
+                       player.bonus_nades++;
+                       player.bonus_nade_score -= 1;
+               }
+       }
+}
+
+/** Remove all bonus nades from a player */
+void nades_RemoveBonus(entity player)
+{
+       player.bonus_nades = player.bonus_nade_score = 0;
+}
+
+MUTATOR_HOOKFUNCTION(nades, PutClientInServer)
+{
+       nades_RemoveBonus(self);
+}
+
+float nade_customize()
+{SELFPARAM();
+       //if(IS_SPEC(other)) { return false; }
+       if(other == self.realowner || (IS_SPEC(other) && other.enemy == self.realowner))
+       {
+               // somewhat hide the model, but keep the glow
+               //self.effects = 0;
+               if(self.traileffectnum)
+                       self.traileffectnum = 0;
+               self.alpha = -1;
+       }
+       else
+       {
+               //self.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+               if(!self.traileffectnum)
+                       self.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(self.nade_type).m_projectile[false], self.team).eent_eff_name);
+               self.alpha = 1;
+       }
+
+       return true;
+}
+
+void nade_prime()
+{SELFPARAM();
+       if(autocvar_g_nades_bonus_only)
+       if(!self.bonus_nades)
+               return; // only allow bonus nades
+
+       if(self.nade)
+               remove(self.nade);
+
+       if(self.fake_nade)
+               remove(self.fake_nade);
+
+       entity n = new(nade), fn = new(fake_nade);
+
+       if(self.items & ITEM_Strength.m_itemid && autocvar_g_nades_bonus_onstrength)
+               n.nade_type = self.nade_type;
+       else if (self.bonus_nades >= 1)
+       {
+               n.nade_type = self.nade_type;
+               n.pokenade_type = self.pokenade_type;
+               self.bonus_nades -= 1;
+       }
+       else
+       {
+               n.nade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_nade_type : autocvar_g_nades_nade_type);
+               n.pokenade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_pokenade_type : autocvar_g_nades_pokenade_monster_type);
+       }
+
+       n.nade_type = bound(1, n.nade_type, Nades_COUNT);
+
+       setmodel(n, MDL_PROJECTILE_NADE);
+       //setattachment(n, self, "bip01 l hand");
+       n.exteriormodeltoclient = self;
+       n.customizeentityforclient = nade_customize;
+       n.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(n.nade_type).m_projectile[false], self.team).eent_eff_name);
+       n.colormod = Nades_from(n.nade_type).m_color;
+       n.realowner = self;
+       n.colormap = self.colormap;
+       n.glowmod = self.glowmod;
+       n.wait = time + autocvar_g_nades_nade_lifetime;
+       n.nade_time_primed = time;
+       n.think = nade_beep;
+       n.nextthink = max(n.wait - 3, time);
+       n.projectiledeathtype = DEATH_NADE.m_id;
+
+       setmodel(fn, MDL_NADE_VIEW);
+       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+       setattachment(fn, self.(weaponentity), "");
+       fn.realowner = fn.owner = self;
+       fn.colormod = Nades_from(n.nade_type).m_color;
+       fn.colormap = self.colormap;
+       fn.glowmod = self.glowmod;
+       fn.think = SUB_Remove;
+       fn.nextthink = n.wait;
+
+       self.nade = n;
+       self.fake_nade = fn;
+}
+
+float CanThrowNade()
+{SELFPARAM();
+       if(self.vehicle)
+               return false;
+
+       if(gameover)
+               return false;
+
+       if(self.deadflag != DEAD_NO)
+               return false;
+
+       if (!autocvar_g_nades)
+               return false; // allow turning them off mid match
+
+       if(forbidWeaponUse(self))
+               return false;
+
+       if (!IS_PLAYER(self))
+               return false;
+
+       return true;
+}
+
+.bool nade_altbutton;
+
+void nades_CheckThrow()
+{SELFPARAM();
+       if(!CanThrowNade())
+               return;
+
+       entity held_nade = self.nade;
+       if (!held_nade)
+       {
+               self.nade_altbutton = true;
+               if(time > self.nade_refire)
+               {
+                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_NADE_THROW);
+                       nade_prime();
+                       self.nade_refire = time + autocvar_g_nades_nade_refire;
+               }
+       }
+       else
+       {
+               self.nade_altbutton = false;
+               if (time >= held_nade.nade_time_primed + 1) {
+                       makevectors(self.v_angle);
+                       float _force = time - held_nade.nade_time_primed;
+                       _force /= autocvar_g_nades_nade_lifetime;
+                       _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));
+                       toss_nade(self, (v_forward * 0.75 + v_up * 0.2 + v_right * 0.05) * _force, 0);
+               }
+       }
+}
+
+void nades_Clear(entity player)
+{
+       if(player.nade)
+               remove(player.nade);
+       if(player.fake_nade)
+               remove(player.fake_nade);
+
+       player.nade = player.fake_nade = world;
+       player.nade_timer = 0;
+}
+
+MUTATOR_HOOKFUNCTION(nades, VehicleEnter)
+{
+       if(vh_player.nade)
+               toss_nade(vh_player, '0 0 100', max(vh_player.nade.wait, time + 0.05));
+
+       return false;
+}
+
+CLASS(NadeOffhand, OffhandWeapon)
+    METHOD(NadeOffhand, offhand_think, void(NadeOffhand this, entity player, bool key_pressed))
+    {
+       entity held_nade = player.nade;
+               if (held_nade)
+               {
+                       player.nade_timer = bound(0, (time - held_nade.nade_time_primed) / autocvar_g_nades_nade_lifetime, 1);
+                       // LOG_TRACEF("%d %d\n", player.nade_timer, time - held_nade.nade_time_primed);
+                       makevectors(player.angles);
+                       held_nade.velocity = player.velocity;
+                       setorigin(held_nade, player.origin + player.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0);
+                       held_nade.angles_y = player.angles.y;
+
+                       if (time + 0.1 >= held_nade.wait)
+                               toss_nade(player, '0 0 0', time + 0.05);
+               }
+
+        if (!CanThrowNade()) return;
+        if (!(time > player.nade_refire)) return;
+               if (key_pressed) {
+                       if (!held_nade) {
+                               nade_prime();
+                               held_nade = player.nade;
+                       }
+               } else if (time >= held_nade.nade_time_primed + 1) {
+                       if (held_nade) {
+                               makevectors(player.v_angle);
+                               float _force = time - held_nade.nade_time_primed;
+                               _force /= autocvar_g_nades_nade_lifetime;
+                               _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));
+                               toss_nade(player, (v_forward * 0.7 + v_up * 0.2 + v_right * 0.1) * _force, 0);
+                       }
+               }
+    }
+ENDCLASS(NadeOffhand)
+NadeOffhand OFFHAND_NADE; STATIC_INIT(OFFHAND_NADE) { OFFHAND_NADE = NEW(NadeOffhand); }
+
+MUTATOR_HOOKFUNCTION(nades, ForbidThrowCurrentWeapon, CBC_ORDER_LAST)
+{
+       if (self.offhand != OFFHAND_NADE || (self.weapons & WEPSET(HOOK)) || autocvar_g_nades_override_dropweapon) {
+               nades_CheckThrow();
+               return true;
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
+{SELFPARAM();
+       if (!IS_PLAYER(self)) { return false; }
+
+       if (self.nade && (self.offhand != OFFHAND_NADE || (self.weapons & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, self, self.nade_altbutton);
+
+       if(IS_PLAYER(self))
+       {
+               if ( autocvar_g_nades_bonus && autocvar_g_nades )
+               {
+                       entity key;
+                       float key_count = 0;
+                       FOR_EACH_KH_KEY(key) if(key.owner == self) { ++key_count; }
+
+                       float time_score;
+                       if(self.flagcarried || self.ballcarried) // this player is important
+                               time_score = autocvar_g_nades_bonus_score_time_flagcarrier;
+                       else
+                               time_score = autocvar_g_nades_bonus_score_time;
+
+                       if(key_count)
+                               time_score = autocvar_g_nades_bonus_score_time_flagcarrier * key_count; // multiply by the number of keys the player is holding
+
+                       if(autocvar_g_nades_bonus_client_select)
+                       {
+                               self.nade_type = self.cvar_cl_nade_type;
+                               self.pokenade_type = self.cvar_cl_pokenade_type;
+                       }
+                       else
+                       {
+                               self.nade_type = autocvar_g_nades_bonus_type;
+                               self.pokenade_type = autocvar_g_nades_pokenade_monster_type;
+                       }
+
+                       self.nade_type = bound(1, self.nade_type, Nades_COUNT);
+
+                       if(self.bonus_nade_score >= 0 && autocvar_g_nades_bonus_score_max)
+                               nades_GiveBonus(self, time_score / autocvar_g_nades_bonus_score_max);
+               }
+               else
+               {
+                       self.bonus_nades = self.bonus_nade_score = 0;
+               }
+       }
+
+       float n = 0;
+       entity o = world;
+       if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
+               n = -1;
+       else
+       {
+               vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
+               n = 0;
+               FOR_EACH_PLAYER(other) if(self != other)
+               {
+                       if(other.deadflag == DEAD_NO)
+                       if(other.frozen == 0)
+                       if(SAME_TEAM(other, self))
+                       if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
+                       {
+                               if(!o)
+                                       o = other;
+                               if(self.frozen == 1)
+                                       other.reviving = true;
+                               ++n;
+                       }
+               }
+       }
+
+       if(n && self.frozen == 3) // OK, there is at least one teammate reviving us
+       {
+               self.revive_progress = bound(0, self.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
+               self.health = max(1, self.revive_progress * start_health);
+
+               if(self.revive_progress >= 1)
+               {
+                       Unfreeze(self);
+
+                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
+                       Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, self.netname);
+               }
+
+               FOR_EACH_PLAYER(other) if(other.reviving)
+               {
+                       other.revive_progress = self.revive_progress;
+                       other.reviving = false;
+               }
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, PlayerSpawn)
+{SELFPARAM();
+       if(autocvar_g_nades_spawn)
+               self.nade_refire = time + autocvar_g_spawnshieldtime;
+       else
+               self.nade_refire  = time + autocvar_g_nades_nade_refire;
+
+       if(autocvar_g_nades_bonus_client_select)
+               self.nade_type = self.cvar_cl_nade_type;
+
+       self.nade_timer = 0;
+
+       if (!self.offhand) self.offhand = OFFHAND_NADE;
+
+       if(self.nade_spawnloc)
+       {
+               setorigin(self, self.nade_spawnloc.origin);
+               self.nade_spawnloc.cnt -= 1;
+
+               if(self.nade_spawnloc.cnt <= 0)
+               {
+                       remove(self.nade_spawnloc);
+                       self.nade_spawnloc = world;
+               }
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, PlayerDies, CBC_ORDER_LAST)
+{
+       if(frag_target.nade)
+       if(!frag_target.frozen || !autocvar_g_freezetag_revive_nade)
+               toss_nade(frag_target, '0 0 100', max(frag_target.nade.wait, time + 0.05));
+
+       float killcount_bonus = ((frag_attacker.killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * frag_attacker.killcount, autocvar_g_nades_bonus_score_medium) : autocvar_g_nades_bonus_score_minor);
+
+       if(IS_PLAYER(frag_attacker))
+       {
+               if (SAME_TEAM(frag_attacker, frag_target) || frag_attacker == frag_target)
+                       nades_RemoveBonus(frag_attacker);
+               else if(frag_target.flagcarried)
+                       nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_medium);
+               else if(autocvar_g_nades_bonus_score_spree && frag_attacker.killcount > 1)
+               {
+                       #define SPREE_ITEM(counta,countb,center,normal,gentle) \
+                               case counta: { nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_spree); break; }
+                       switch(frag_attacker.killcount)
+                       {
+                               KILL_SPREE_LIST
+                               default: nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor); break;
+                       }
+                       #undef SPREE_ITEM
+               }
+               else
+                       nades_GiveBonus(frag_attacker, killcount_bonus);
+       }
+
+       nades_RemoveBonus(frag_target);
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, PlayerDamage_Calculate)
+{
+       if(frag_target.frozen)
+       if(autocvar_g_freezetag_revive_nade)
+       if(frag_attacker == frag_target)
+       if(frag_deathtype == DEATH_NADE.m_id)
+       if(time - frag_inflictor.toss_time <= 0.1)
+       {
+               Unfreeze(frag_target);
+               frag_target.health = autocvar_g_freezetag_revive_nade_health;
+               Send_Effect(EFFECT_ICEORGLASS, frag_target.origin, '0 0 0', 3);
+               frag_damage = 0;
+               frag_force = '0 0 0';
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED_NADE, frag_target.netname);
+               Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF);
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, MonsterDies)
+{SELFPARAM();
+       if(IS_PLAYER(frag_attacker))
+       if(DIFF_TEAM(frag_attacker, self))
+       if(!(self.spawnflags & MONSTERFLAG_SPAWNED))
+               nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor);
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, DropSpecialItems)
+{
+       if(frag_target.nade)
+               toss_nade(frag_target, '0 0 0', time + 0.05);
+
+       return false;
+}
+
+bool nades_RemovePlayer()
+{SELFPARAM();
+       nades_Clear(self);
+       nades_RemoveBonus(self);
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, MakePlayerObserver) { nades_RemovePlayer(); }
+MUTATOR_HOOKFUNCTION(nades, ClientDisconnect) { nades_RemovePlayer(); }
+MUTATOR_HOOKFUNCTION(nades, reset_map_global) { nades_RemovePlayer(); }
+
+MUTATOR_HOOKFUNCTION(nades, SpectateCopy)
+{SELFPARAM();
+       self.nade_timer = other.nade_timer;
+       self.nade_type = other.nade_type;
+       self.pokenade_type = other.pokenade_type;
+       self.bonus_nades = other.bonus_nades;
+       self.bonus_nade_score = other.bonus_nade_score;
+       self.stat_healing_orb = other.stat_healing_orb;
+       self.stat_healing_orb_alpha = other.stat_healing_orb_alpha;
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, GetCvars)
+{
+       GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_nade_type, "cl_nade_type");
+       GetCvars_handleString(get_cvars_s, get_cvars_f, cvar_cl_pokenade_type, "cl_pokenade_type");
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":Nades");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(nades, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Nades");
+       return false;
+}
+#endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/nades/nades.qh b/qcsrc/common/mutators/mutator/nades/nades.qh
new file mode 100644 (file)
index 0000000..2e48293
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef NADES_ALL_H
+#define NADES_ALL_H
+
+#include "../../../teams.qh"
+
+// use slots 70-100
+const int PROJECTILE_NADE = 71;
+const int PROJECTILE_NADE_BURN = 72;
+const int PROJECTILE_NADE_NAPALM = 73;
+const int PROJECTILE_NADE_NAPALM_BURN = 74;
+const int PROJECTILE_NAPALM_FOUNTAIN = 75;
+const int PROJECTILE_NADE_ICE = 76;
+const int PROJECTILE_NADE_ICE_BURN = 77;
+const int PROJECTILE_NADE_TRANSLOCATE = 78;
+const int PROJECTILE_NADE_SPAWN = 79;
+const int PROJECTILE_NADE_HEAL = 80;
+const int PROJECTILE_NADE_HEAL_BURN = 81;
+const int PROJECTILE_NADE_MONSTER = 82;
+const int PROJECTILE_NADE_MONSTER_BURN = 83;
+
+REGISTRY(Nades, BITS(4))
+#define Nades_from(i) _Nades_from(i, NADE_TYPE_Null)
+REGISTER_REGISTRY(Nades)
+REGISTRY_CHECK(Nades)
+
+#define REGISTER_NADE(id) REGISTER(Nades, NADE_TYPE, id, m_id, NEW(Nade))
+
+CLASS(Nade, Object)
+    ATTRIB(Nade, m_id, int, 0)
+    ATTRIB(Nade, m_color, vector, '0 0 0')
+    ATTRIB(Nade, m_name, string, _("Grenade"))
+    ATTRIB(Nade, m_icon, string, "nade_normal")
+    ATTRIBARRAY(Nade, m_projectile, int, 2)
+    ATTRIBARRAY(Nade, m_trail, entity, 2)
+    METHOD(Nade, display, void(entity this, void(string name, string icon) returns)) {
+        returns(this.m_name, sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.m_icon));
+    }
+ENDCLASS(Nade)
+
+REGISTER_NADE(Null);
+
+Nade Nade_FromProjectile(int proj)
+{
+    FOREACH(Nades, true, LAMBDA(
+        for (int j = 0; j < 2; j++)
+        {
+            if (it.m_projectile[j] == proj) return it;
+        }
+    ));
+    return NADE_TYPE_Null;
+}
+
+#ifndef MENUQC
+#include "effects.inc"
+#endif
+
+#include "nades.inc"
+
+.float healer_lifetime;
+.float healer_radius;
+
+#ifdef SVQC
+
+.entity nade;
+.entity fake_nade;
+.float nade_timer;
+.float nade_refire;
+.float bonus_nades;
+.float nade_special_time;
+.float bonus_nade_score;
+.float nade_type;
+.string pokenade_type;
+.entity nade_damage_target;
+.float cvar_cl_nade_type;
+.string cvar_cl_pokenade_type;
+.float toss_time;
+.float stat_healing_orb;
+.float stat_healing_orb_alpha;
+.float nade_show_particles;
+
+bool healer_send(entity this, entity to, int sf);
+
+// Remove nades that are being thrown
+void nades_Clear(entity player);
+
+// Give a bonus grenade to a player
+void(entity player, float score) nades_GiveBonus;
+
+/**
+ * called to adjust nade damage and force on hit
+ */
+#define EV_Nade_Damage(i, o) \
+       /** weapon */ i(entity, MUTATOR_ARGV_0_entity) \
+    /** force */  i(vector, MUTATOR_ARGV_0_vector) \
+    /**/          o(vector, MUTATOR_ARGV_0_vector) \
+       /** damage */ i(float,  MUTATOR_ARGV_0_float) \
+    /**/          o(float,  MUTATOR_ARGV_0_float) \
+    /**/
+MUTATOR_HOOKABLE(Nade_Damage, EV_Nade_Damage);
+
+#endif
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/nades/net.qc b/qcsrc/common/mutators/mutator/nades/net.qc
new file mode 100644 (file)
index 0000000..072f507
--- /dev/null
@@ -0,0 +1,84 @@
+#include "nades.qh"
+
+#ifdef IMPLEMENTATION
+
+#ifdef CSQC
+.float ltime;
+void healer_draw(entity this)
+{
+       float dt = time - self.move_time;
+       self.move_time = time;
+       if(dt <= 0)
+               return;
+
+       self.alpha = (self.ltime - time) / self.healer_lifetime;
+       self.scale = min((1 - self.alpha)*self.healer_lifetime*4,1)*self.healer_radius;
+}
+
+void healer_setup(entity e)
+{
+       setmodel(e, MDL_NADE_HEAL);
+
+       setorigin(e, e.origin);
+
+       float model_radius = e.maxs.x;
+       vector size = '1 1 1' * e.healer_radius / 2;
+       setsize(e,-size,size);
+       e.healer_radius = e.healer_radius/model_radius*0.6;
+
+       e.draw = healer_draw;
+       e.health = 255;
+       e.movetype = MOVETYPE_NONE;
+       e.solid = SOLID_NOT;
+       e.drawmask = MASK_NORMAL;
+       e.scale = 0.01;
+       e.avelocity = e.move_avelocity = '7 0 11';
+       e.colormod = '1 0 0';
+       e.renderflags |= RF_ADDITIVE;
+}
+#endif
+
+REGISTER_NET_LINKED(Nade_Heal)
+
+#ifdef CSQC
+NET_HANDLE(Nade_Heal, bool isNew)
+{
+       Net_Accept(Nade_Heal);
+       int sf = ReadByte();
+       if (sf & 1) {
+               this.origin_x = ReadCoord();
+               this.origin_y = ReadCoord();
+               this.origin_z = ReadCoord();
+               setorigin(this, this.origin);
+               this.healer_lifetime = ReadByte();
+               this.healer_radius = ReadShort();
+               this.ltime = time + ReadByte()/10.0;
+               // this.ltime = time + this.healer_lifetime;
+               healer_setup(this);
+       }
+       return true;
+}
+#endif
+
+#ifdef SVQC
+bool healer_send(entity this, entity to, int sf)
+{
+       int channel = MSG_ENTITY;
+       WriteHeader(channel, Nade_Heal);
+       WriteByte(channel, sf);
+       if (sf & 1) {
+               WriteCoord(channel, this.origin.x);
+               WriteCoord(channel, this.origin.y);
+               WriteCoord(channel, this.origin.z);
+
+               WriteByte(channel, this.healer_lifetime);
+               //WriteByte(MSG_ENTITY, this.ltime - time + 1);
+               WriteShort(channel, this.healer_radius);
+               // round time delta to a 1/10th of a second
+               WriteByte(channel, (this.ltime - time)*10.0+0.5);
+       }
+       return true;
+}
+#endif
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/new_toys/module.inc b/qcsrc/common/mutators/mutator/new_toys/module.inc
new file mode 100644 (file)
index 0000000..1217177
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "new_toys.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/new_toys/new_toys.qc b/qcsrc/common/mutators/mutator/new_toys/new_toys.qc
new file mode 100644 (file)
index 0000000..78904ff
--- /dev/null
@@ -0,0 +1,227 @@
+#ifdef IMPLEMENTATION
+/*
+
+CORE    laser   vortex     lg      rl      cry     gl      elec    hagar   fireb   hook
+                                                                       vaporizer  porto
+                                                                       tuba
+
+NEW             rifle   hlac    minel                           seeker
+IDEAS                                   OPEN    flak    OPEN            FUN FUN FUN FUN
+
+
+
+How this mutator works:
+ =======================
+
+When a gun tries to spawn, this mutator is called. It will provide alternate
+weaponreplace lists.
+
+Entity:
+
+{
+"classname" "weapon_vortex"
+"new_toys" "rifle"
+}
+-> This will spawn as Rifle in this mutator ONLY, and as Vortex otherwise.
+
+{
+"classname" "weapon_vortext"
+"new_toys" "vortex rifle"
+}
+-> This will spawn as either Vortex or Rifle in this mutator ONLY, and as Vortex otherwise.
+
+{
+"classname" "weapon_vortex"
+"new_toys" "vortex"
+}
+-> This is always a Vortex.
+
+If the map specifies no "new_toys" argument
+
+There will be two default replacements selectable: "replace all" and "replace random".
+In "replace all" mode, e.g. Vortex will have the default replacement "rifle".
+In "replace random" mode, Vortex will have the default replacement "vortex rifle".
+
+This mutator's replacements run BEFORE regular weaponreplace!
+
+The New Toys guns do NOT get a spawn function, so they can only ever be spawned
+when this mutator is active.
+
+Likewise, warmup, give all, give ALL and impulse 99 will not give them unless
+this mutator is active.
+
+Outside this mutator, they still can be spawned by:
+- setting their start weapon cvar to 1
+- give weaponname
+- weaponreplace
+- weaponarena (but all and most weapons arena again won't include them)
+
+This mutator performs the default replacements on the DEFAULTS of the
+start weapon selection.
+
+These weapons appear in the menu's priority list, BUT get a suffix
+"(Mutator weapon)".
+
+Picking up a "new toys" weapon will not play standard weapon pickup sound, but
+roflsound "New toys, new toys!" sound.
+
+*/
+
+bool nt_IsNewToy(int w);
+
+REGISTER_MUTATOR(nt, cvar("g_new_toys") && !cvar("g_instagib") && !cvar("g_overkill"))
+{
+       MUTATOR_ONADD
+       {
+               if(time > 1) // game loads at time 1
+                       error("This cannot be added at runtime\n");
+
+               // mark the guns as ok to use by e.g. impulse 99
+               for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
+                       if(nt_IsNewToy(i))
+                               get_weaponinfo(i).spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
+                       if(nt_IsNewToy(i))
+                               get_weaponinfo(i).spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This cannot be removed at runtime\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+.string new_toys;
+
+float autocvar_g_new_toys_autoreplace;
+bool autocvar_g_new_toys_use_pickupsound = true;
+const float NT_AUTOREPLACE_NEVER = 0;
+const float NT_AUTOREPLACE_ALWAYS = 1;
+const float NT_AUTOREPLACE_RANDOM = 2;
+
+MUTATOR_HOOKFUNCTION(nt, SetModname)
+{
+       modname = "NewToys";
+       return 0;
+}
+
+bool nt_IsNewToy(int w)
+{
+       switch(w)
+       {
+               case WEP_SEEKER.m_id:
+               case WEP_MINE_LAYER.m_id:
+               case WEP_HLAC.m_id:
+               case WEP_RIFLE.m_id:
+               case WEP_SHOCKWAVE.m_id:
+                       return true;
+               default:
+                       return false;
+       }
+}
+
+string nt_GetFullReplacement(string w)
+{
+       switch(w)
+       {
+               case "hagar": return "seeker";
+               case "devastator": return "minelayer";
+               case "machinegun": return "hlac";
+               case "vortex": return "rifle";
+               //case "shotgun": return "shockwave";
+               default: return string_null;
+       }
+}
+
+string nt_GetReplacement(string w, float m)
+{
+       if(m == NT_AUTOREPLACE_NEVER)
+               return w;
+       string s = nt_GetFullReplacement(w);
+       if (!s)
+               return w;
+       if(m == NT_AUTOREPLACE_RANDOM)
+               s = strcat(w, " ", s);
+       return s;
+}
+
+MUTATOR_HOOKFUNCTION(nt, SetStartItems)
+{
+       // rearrange start_weapon_default
+       // apply those bits that are set by start_weapon_defaultmask
+       // same for warmup
+
+       float i, j, k, n;
+
+       WepSet newdefault;
+       WepSet warmup_newdefault;
+
+       newdefault = '0 0 0';
+       warmup_newdefault = '0 0 0';
+
+       for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+       {
+               entity e = get_weaponinfo(i);
+               if(!e.weapon)
+                       continue;
+
+               n = tokenize_console(nt_GetReplacement(e.netname, autocvar_g_new_toys_autoreplace));
+
+               for(j = 0; j < n; ++j)
+                       for(k = WEP_FIRST; k <= WEP_LAST; ++k)
+                               if(get_weaponinfo(k).netname == argv(j))
+                               {
+                                       if(start_weapons & WepSet_FromWeapon(i))
+                                               newdefault |= WepSet_FromWeapon(k);
+                                       if(warmup_start_weapons & WepSet_FromWeapon(i))
+                                               warmup_newdefault |= WepSet_FromWeapon(k);
+                               }
+       }
+
+       newdefault &= start_weapons_defaultmask;
+       start_weapons &= ~start_weapons_defaultmask;
+       start_weapons |= newdefault;
+
+       warmup_newdefault &= warmup_start_weapons_defaultmask;
+       warmup_start_weapons &= ~warmup_start_weapons_defaultmask;
+       warmup_start_weapons |= warmup_newdefault;
+
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nt, SetWeaponreplace)
+{SELFPARAM();
+       // otherwise, we do replace
+       if(self.new_toys)
+       {
+               // map defined replacement:
+               ret_string = self.new_toys;
+       }
+       else
+       {
+               // auto replacement:
+               ret_string = nt_GetReplacement(other.netname, autocvar_g_new_toys_autoreplace);
+       }
+
+       // apply regular weaponreplace
+       ret_string = W_Apply_Weaponreplace(ret_string);
+
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nt, FilterItem)
+{SELFPARAM();
+       if(nt_IsNewToy(self.weapon) && autocvar_g_new_toys_use_pickupsound) {
+               self.item_pickupsound = string_null;
+               self.item_pickupsound_ent = SND_WEAPONPICKUP_NEW_TOYS;
+       }
+       return 0;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/nix/module.inc b/qcsrc/common/mutators/mutator/nix/module.inc
new file mode 100644 (file)
index 0000000..fb4f9ec
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "nix.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/nix/nix.qc b/qcsrc/common/mutators/mutator/nix/nix.qc
new file mode 100644 (file)
index 0000000..1a8089c
--- /dev/null
@@ -0,0 +1,291 @@
+#ifdef IMPLEMENTATION
+int autocvar_g_balance_nix_ammo_cells;
+int autocvar_g_balance_nix_ammo_plasma;
+int autocvar_g_balance_nix_ammo_fuel;
+int autocvar_g_balance_nix_ammo_nails;
+int autocvar_g_balance_nix_ammo_rockets;
+int autocvar_g_balance_nix_ammo_shells;
+int autocvar_g_balance_nix_ammoincr_cells;
+int autocvar_g_balance_nix_ammoincr_plasma;
+int autocvar_g_balance_nix_ammoincr_fuel;
+int autocvar_g_balance_nix_ammoincr_nails;
+int autocvar_g_balance_nix_ammoincr_rockets;
+int autocvar_g_balance_nix_ammoincr_shells;
+float autocvar_g_balance_nix_incrtime;
+float autocvar_g_balance_nix_roundtime;
+bool autocvar_g_nix_with_healtharmor;
+bool autocvar_g_nix_with_blaster;
+bool autocvar_g_nix_with_powerups;
+int autocvar_g_pickup_cells_max;
+int autocvar_g_pickup_plasma_max;
+int autocvar_g_pickup_fuel_max;
+int autocvar_g_pickup_nails_max;
+int autocvar_g_pickup_rockets_max;
+int autocvar_g_pickup_shells_max;
+
+float g_nix_with_blaster;
+// WEAPONTODO
+int nix_weapon;
+float nix_nextchange;
+float nix_nextweapon;
+.float nix_lastchange_id;
+.float nix_lastinfotime;
+.float nix_nextincr;
+
+bool NIX_CanChooseWeapon(int wpn);
+
+REGISTER_MUTATOR(nix, cvar("g_nix") && !cvar("g_instagib") && !cvar("g_overkill"))
+{
+       MUTATOR_ONADD
+       {
+               g_nix_with_blaster = autocvar_g_nix_with_blaster;
+
+               nix_nextchange = 0;
+               nix_nextweapon = 0;
+
+               for (int i = WEP_FIRST; i <= WEP_LAST; ++i)
+                       if (NIX_CanChooseWeapon(i)) {
+                               Weapon w = get_weaponinfo(i);
+                               w.wr_init(w);
+                       }
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // nothing to roll back
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
+               entity e;
+               FOR_EACH_PLAYER(e) if(e.deadflag == DEAD_NO)
+               {
+                       e.ammo_cells = start_ammo_cells;
+                       e.ammo_plasma = start_ammo_plasma;
+                       e.ammo_shells = start_ammo_shells;
+                       e.ammo_nails = start_ammo_nails;
+                       e.ammo_rockets = start_ammo_rockets;
+                       e.ammo_fuel = start_ammo_fuel;
+                       e.weapons = start_weapons;
+                       if(!client_hasweapon(e, e.weapon, true, false))
+                               e.switchweapon = w_getbestweapon(self);
+               }
+       }
+
+       return 0;
+}
+
+bool NIX_CanChooseWeapon(int wpn)
+{
+       entity e = get_weaponinfo(wpn);
+       if(!e.weapon) // skip dummies
+               return false;
+       if(g_weaponarena)
+       {
+               if(!(g_weaponarena_weapons & WepSet_FromWeapon(wpn)))
+                       return false;
+       }
+       else
+       {
+               if(wpn == WEP_BLASTER.m_id && g_nix_with_blaster)
+                       return false;
+               if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
+                       return false;
+               if (!(e.spawnflags & WEP_FLAG_NORMAL))
+                       return false;
+       }
+       return true;
+}
+void NIX_ChooseNextWeapon()
+{
+       float j;
+       RandomSelection_Init();
+       for(j = WEP_FIRST; j <= WEP_LAST; ++j)
+               if(NIX_CanChooseWeapon(j))
+                       RandomSelection_Add(world, j, string_null, 1, (j != nix_weapon));
+       nix_nextweapon = RandomSelection_chosen_float;
+}
+
+void NIX_GiveCurrentWeapon()
+{SELFPARAM();
+       float dt;
+
+       if(!nix_nextweapon)
+               NIX_ChooseNextWeapon();
+
+       dt = ceil(nix_nextchange - time);
+
+       if(dt <= 0)
+       {
+               nix_weapon = nix_nextweapon;
+               nix_nextweapon = 0;
+               if (!nix_nextchange) // no round played yet?
+                       nix_nextchange = time; // start the first round now!
+               else
+                       nix_nextchange = time + autocvar_g_balance_nix_roundtime;
+               // Weapon w = get_weaponinfo(nix_weapon);
+               // w.wr_init(w); // forget it, too slow
+       }
+
+       // get weapon info
+       entity e = get_weaponinfo(nix_weapon);
+
+       if(nix_nextchange != self.nix_lastchange_id) // this shall only be called once per round!
+       {
+               self.ammo_shells = self.ammo_nails = self.ammo_rockets = self.ammo_cells = self.ammo_plasma = self.ammo_fuel = 0;
+
+               if(self.items & IT_UNLIMITED_WEAPON_AMMO)
+               {
+                       switch(e.ammo_field)
+                       {
+                               case ammo_shells:  self.ammo_shells  = autocvar_g_pickup_shells_max;  break;
+                               case ammo_nails:   self.ammo_nails   = autocvar_g_pickup_nails_max;   break;
+                               case ammo_rockets: self.ammo_rockets = autocvar_g_pickup_rockets_max; break;
+                               case ammo_cells:   self.ammo_cells   = autocvar_g_pickup_cells_max;   break;
+                               case ammo_plasma:  self.ammo_plasma  = autocvar_g_pickup_plasma_max;   break;
+                               case ammo_fuel:    self.ammo_fuel    = autocvar_g_pickup_fuel_max;    break;
+                       }
+               }
+               else
+               {
+                       switch(e.ammo_field)
+                       {
+                               case ammo_shells:  self.ammo_shells  = autocvar_g_balance_nix_ammo_shells;  break;
+                               case ammo_nails:   self.ammo_nails   = autocvar_g_balance_nix_ammo_nails;   break;
+                               case ammo_rockets: self.ammo_rockets = autocvar_g_balance_nix_ammo_rockets; break;
+                               case ammo_cells:   self.ammo_cells   = autocvar_g_balance_nix_ammo_cells;   break;
+                               case ammo_plasma:  self.ammo_plasma  = autocvar_g_balance_nix_ammo_plasma;   break;
+                               case ammo_fuel:    self.ammo_fuel    = autocvar_g_balance_nix_ammo_fuel;    break;
+                       }
+               }
+
+               self.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
+               if(dt >= 1 && dt <= 5)
+                       self.nix_lastinfotime = -42;
+               else
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
+
+               Weapon w = get_weaponinfo(nix_weapon);
+               w.wr_resetplayer(w);
+
+               // all weapons must be fully loaded when we spawn
+               if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
+                       self.(weapon_load[nix_weapon]) = e.reloading_ammo;
+
+               // vortex too
+               if(WEP_CVAR(vortex, charge))
+               {
+                       if(WEP_CVAR_SEC(vortex, chargepool))
+                               self.vortex_chargepool_ammo = 1;
+                       self.vortex_charge = WEP_CVAR(vortex, charge_start);
+               }
+
+               // set last change info
+               self.nix_lastchange_id = nix_nextchange;
+       }
+       if(self.nix_lastinfotime != dt)
+       {
+               self.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
+               if(dt >= 1 && dt <= 5)
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
+       }
+
+       if(!(self.items & IT_UNLIMITED_WEAPON_AMMO) && time > self.nix_nextincr)
+       {
+               switch(e.ammo_field)
+               {
+                       case ammo_shells:  self.ammo_shells  += autocvar_g_balance_nix_ammoincr_shells;  break;
+                       case ammo_nails:   self.ammo_nails   += autocvar_g_balance_nix_ammoincr_nails;   break;
+                       case ammo_rockets: self.ammo_rockets += autocvar_g_balance_nix_ammoincr_rockets; break;
+                       case ammo_cells:   self.ammo_cells   += autocvar_g_balance_nix_ammoincr_cells;   break;
+                       case ammo_plasma:  self.ammo_plasma  += autocvar_g_balance_nix_ammoincr_plasma;   break;
+                       case ammo_fuel:    self.ammo_fuel    += autocvar_g_balance_nix_ammoincr_fuel;    break;
+               }
+
+               self.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
+       }
+
+       self.weapons = '0 0 0';
+       if(g_nix_with_blaster)
+               self.weapons |= WEPSET(BLASTER);
+       self.weapons |= WepSet_FromWeapon(nix_weapon);
+
+       if(self.switchweapon != nix_weapon)
+               if(!client_hasweapon(self, self.switchweapon, true, false))
+                       if(client_hasweapon(self, nix_weapon, true, false))
+                               W_SwitchWeapon(nix_weapon);
+}
+
+MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
+{
+       return 1; // no throwing in NIX
+}
+
+MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":NIX");
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", NIX");
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nix, FilterItem)
+{SELFPARAM();
+       switch (self.items)
+       {
+               case ITEM_HealthSmall.m_itemid:
+               case ITEM_HealthMedium.m_itemid:
+               case ITEM_HealthLarge.m_itemid:
+               case ITEM_HealthMega.m_itemid:
+               case ITEM_ArmorSmall.m_itemid:
+               case ITEM_ArmorMedium.m_itemid:
+               case ITEM_ArmorLarge.m_itemid:
+               case ITEM_ArmorMega.m_itemid:
+                       if (autocvar_g_nix_with_healtharmor)
+                               return 0;
+                       break;
+               case ITEM_Strength.m_itemid:
+               case ITEM_Shield.m_itemid:
+                       if (autocvar_g_nix_with_powerups)
+                               return 0;
+                       break;
+       }
+
+       return 1; // delete all other items
+}
+
+MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
+{SELFPARAM();
+       if(self.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
+               return 1;
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
+{SELFPARAM();
+       if(!intermission_running)
+       if(self.deadflag == DEAD_NO)
+       if(IS_PLAYER(self))
+               NIX_GiveCurrentWeapon();
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
+{SELFPARAM();
+       self.nix_lastchange_id = -1;
+       NIX_GiveCurrentWeapon(); // overrides the weapons you got when spawning
+       self.items |= IT_UNLIMITED_SUPERWEAPONS;
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nix, SetModname, CBC_ORDER_LAST)
+{
+       modname = "NIX";
+       return 0;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/hmg.qc b/qcsrc/common/mutators/mutator/overkill/hmg.qc
new file mode 100644 (file)
index 0000000..7f2341f
--- /dev/null
@@ -0,0 +1,178 @@
+#ifndef IMPLEMENTATION
+CLASS(HeavyMachineGun, Weapon)
+/* ammotype  */ ATTRIB(HeavyMachineGun, ammo_field, .int, ammo_nails)
+/* impulse   */ ATTRIB(HeavyMachineGun, impulse, int, 3)
+/* flags     */ ATTRIB(HeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
+/* rating    */ ATTRIB(HeavyMachineGun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
+/* color     */ ATTRIB(HeavyMachineGun, wpcolor, vector, '0.5 0.5 0');
+/* modelname */ ATTRIB(HeavyMachineGun, mdl, string, "ok_hmg");
+#ifndef MENUQC
+/* model     */ ATTRIB(HeavyMachineGun, m_model, Model, MDL_HMG_ITEM);
+#endif
+/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair, string, "gfx/crosshairuzi");
+/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair_size, float, 0.6);
+/* wepimg    */ ATTRIB(HeavyMachineGun, model2, string, "weaponhmg");
+/* refname   */ ATTRIB(HeavyMachineGun, netname, string, "hmg");
+/* wepname   */ ATTRIB(HeavyMachineGun, m_name, string, _("Heavy Machine Gun"));
+ENDCLASS(HeavyMachineGun)
+REGISTER_WEAPON(HMG, NEW(HeavyMachineGun));
+
+#define HMG_SETTINGS(w_cvar,w_prop) HMG_SETTINGS_LIST(w_cvar, w_prop, HMG, hmg)
+#define HMG_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
+       w_cvar(id, sn, NONE, spread_min) \
+       w_cvar(id, sn, NONE, spread_max) \
+       w_cvar(id, sn, NONE, spread_add) \
+       w_cvar(id, sn, NONE, solidpenetration) \
+       w_cvar(id, sn, NONE, damage) \
+       w_cvar(id, sn, NONE, force) \
+       w_cvar(id, sn, NONE, refire) \
+       w_cvar(id, sn, NONE, ammo) \
+       w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
+       w_prop(id, sn, float,  reloading_time, reload_time) \
+       w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
+       w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
+       w_prop(id, sn, string, weaponreplace, weaponreplace) \
+       w_prop(id, sn, float,  weaponstart, weaponstart) \
+       w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride) \
+       w_prop(id, sn, float,  weaponthrowable, weaponthrowable)
+
+#ifdef SVQC
+HMG_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
+#endif
+#endif
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+
+REGISTER_MUTATOR(hmg_nadesupport, true);
+MUTATOR_HOOKFUNCTION(hmg_nadesupport, Nade_Damage)
+{
+       if (MUTATOR_ARGV(0, entity) != WEP_HMG) return;
+       return = true;
+       MUTATOR_ARGV(0, float) /* damage */ = self.max_health * 0.1;
+}
+
+spawnfunc(weapon_hmg) { weapon_defaultspawnfunc(this, WEP_HMG); }
+
+void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
+{
+       if (!actor.BUTTON_ATCK)
+       {
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+
+       Weapon w = get_weaponinfo(actor.weapon);
+       if(!w.wr_checkammo1(w))
+       if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+       {
+               W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+
+       W_DecreaseAmmo(WEP_HMG, self, WEP_CVAR(hmg, ammo));
+
+       W_SetupShot (actor, true, 0, SND(UZI_FIRE), CH_WEAPON_A, WEP_CVAR(hmg, damage));
+
+       if(!autocvar_g_norecoil)
+       {
+               actor.punchangle_x = random () - 0.5;
+               actor.punchangle_y = random () - 0.5;
+       }
+
+       float hmg_spread = bound(WEP_CVAR(hmg, spread_min), WEP_CVAR(hmg, spread_min) + (WEP_CVAR(hmg, spread_add) * actor.misc_bulletcounter), WEP_CVAR(hmg, spread_max));
+       fireBullet(w_shotorg, w_shotdir, hmg_spread, WEP_CVAR(hmg, solidpenetration), WEP_CVAR(hmg, damage), WEP_CVAR(hmg, force), WEP_HMG.m_id, 0);
+
+       actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
+
+       Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+
+       W_MachineGun_MuzzleFlash();
+       W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
+
+       if (autocvar_g_casings >= 2) // casing code
+               SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
+
+       int slot = weaponslot(weaponentity);
+       ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(hmg, refire) * W_WeaponRateFactor();
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(hmg, refire), W_HeavyMachineGun_Attack_Auto);
+}
+
+               METHOD(HeavyMachineGun, wr_aim, void(entity thiswep))
+               {
+                       if(vlen(self.origin-self.enemy.origin) < 3000 - bound(0, skill, 10) * 200)
+                               self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, false);
+                       else
+                               self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, false);
+               }
+               METHOD(HeavyMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+               {
+                       if(WEP_CVAR(hmg, reload_ammo) && actor.clip_load < WEP_CVAR(hmg, ammo)) { // forced reload
+                               Weapon w = get_weaponinfo(actor.weapon);
+                               w.wr_reload(w);
+                       } else
+                       {
+                               if (fire & 1)
+                               if (weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
+                               {
+                                       actor.misc_bulletcounter = 0;
+                                       W_HeavyMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
+                               }
+                       }
+               }
+               METHOD(HeavyMachineGun, wr_init, void(entity thiswep))
+               {
+                       HMG_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
+               }
+               METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep))
+               {
+                       float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
+
+                       if(autocvar_g_balance_hmg_reload_ammo)
+                               ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
+
+                       return ammo_amount;
+               }
+               METHOD(HeavyMachineGun, wr_checkammo2, bool(entity thiswep))
+               {
+                       float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
+
+                       if(autocvar_g_balance_hmg_reload_ammo)
+                               ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
+
+                       return ammo_amount;
+               }
+               METHOD(HeavyMachineGun, wr_config, void(entity thiswep))
+               {
+                       HMG_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
+               }
+               METHOD(HeavyMachineGun, wr_reload, void(entity thiswep))
+               {
+                       W_Reload(self, WEP_CVAR(hmg, ammo), SND(RELOAD));
+               }
+               METHOD(HeavyMachineGun, wr_suicidemessage, int(entity thiswep))
+               {
+                       return WEAPON_THINKING_WITH_PORTALS;
+               }
+               METHOD(HeavyMachineGun, wr_killmessage, int(entity thiswep))
+               {
+                       if(w_deathtype & HITTYPE_SECONDARY)
+                               return WEAPON_HMG_MURDER_SNIPE;
+                       else
+                               return WEAPON_HMG_MURDER_SPRAY;
+               }
+
+#endif
+#ifdef CSQC
+
+               METHOD(HeavyMachineGun, wr_impacteffect, void(entity thiswep))
+               {
+                       vector org2;
+                       org2 = w_org + w_backoff * 2;
+                       pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
+                       if(!w_issilent)
+                               sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+               }
+
+#endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/module.inc b/qcsrc/common/mutators/mutator/overkill/module.inc
new file mode 100644 (file)
index 0000000..a8bde27
--- /dev/null
@@ -0,0 +1,6 @@
+#include "hmg.qc"
+#include "rpc.qc"
+
+#ifdef SVQC
+       #include "overkill.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/overkill.qc b/qcsrc/common/mutators/mutator/overkill/overkill.qc
new file mode 100644 (file)
index 0000000..c146f1c
--- /dev/null
@@ -0,0 +1,385 @@
+#ifdef IMPLEMENTATION
+bool autocvar_g_overkill_powerups_replace;
+float autocvar_g_overkill_superguns_respawn_time;
+bool autocvar_g_overkill_100h_anyway;
+bool autocvar_g_overkill_100a_anyway;
+bool autocvar_g_overkill_ammo_charge;
+float autocvar_g_overkill_ammo_charge_notice;
+float autocvar_g_overkill_ammo_charge_limit;
+
+.vector ok_deathloc;
+.float ok_spawnsys_timer;
+.float ok_lastwep;
+.float ok_item;
+
+.float ok_notice_time;
+.float ammo_charge[Weapons_MAX];
+.float ok_use_ammocharge;
+.float ok_ammo_charge;
+
+.float ok_pauseregen_finished;
+
+void(entity ent, float wep) ok_DecreaseCharge;
+
+void ok_Initialize();
+
+REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
+{
+       MUTATOR_ONADD
+       {
+               ok_Initialize();
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, W_DecreaseAmmo)
+{
+       entity actor = MUTATOR_ARGV(0, entity);
+       if (actor.ok_use_ammocharge)
+       {
+               ok_DecreaseCharge(actor, actor.weapon);
+               return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ok, W_Reload)
+{
+       entity actor = MUTATOR_ARGV(0, entity);
+       return actor.ok_use_ammocharge;
+}
+
+void W_Blaster_Attack(entity, float, float, float, float, float, float, float, float, float, float);
+spawnfunc(weapon_hmg);
+spawnfunc(weapon_rpc);
+
+void ok_DecreaseCharge(entity ent, int wep)
+{
+       if(!ent.ok_use_ammocharge) return;
+
+       entity wepent = get_weaponinfo(wep);
+
+       if(wepent.weapon == 0)
+               return; // dummy
+
+       ent.ammo_charge[wep] -= max(0, cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
+}
+
+void ok_IncreaseCharge(entity ent, int wep)
+{
+       entity wepent = get_weaponinfo(wep);
+
+       if(wepent.weapon == 0)
+               return; // dummy
+
+       if(ent.ok_use_ammocharge)
+       if(!ent.BUTTON_ATCK) // not while attacking?
+               ent.ammo_charge[wep] = min(autocvar_g_overkill_ammo_charge_limit, ent.ammo_charge[wep] + cvar(sprintf("g_overkill_ammo_charge_rate_%s", wepent.netname)) * frametime / W_TICSPERFRAME);
+}
+
+float ok_CheckWeaponCharge(entity ent, int wep)
+{
+       if(!ent.ok_use_ammocharge) return true;
+
+       entity wepent = get_weaponinfo(wep);
+
+       if(wepent.weapon == 0)
+               return 0; // dummy
+
+       return (ent.ammo_charge[wep] >= cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDamage_Calculate, CBC_ORDER_LAST)
+{
+       if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target))
+       if(DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
+       {
+               frag_damage = 0;
+
+               if(frag_attacker != frag_target)
+               if(frag_target.health > 0)
+               if(frag_target.frozen == 0)
+               if(frag_target.deadflag == DEAD_NO)
+               {
+                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE);
+                       frag_force = '0 0 0';
+               }
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDamage_SplitHealthArmor)
+{SELFPARAM();
+       if(damage_take)
+               self.ok_pauseregen_finished = max(self.ok_pauseregen_finished, time + 2);
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerDies)
+{SELFPARAM();
+       entity targ = ((frag_attacker) ? frag_attacker : frag_target);
+
+       if(IS_MONSTER(self))
+       {
+               remove(other); // remove default item
+               other = world;
+       }
+
+       setself(new(droppedweapon)); // hax
+       self.ok_item = true;
+       self.noalign = true;
+       self.pickup_anyway = true;
+       spawnfunc_item_armor_small(this);
+       self.movetype = MOVETYPE_TOSS;
+       self.gravity = 1;
+       self.reset = SUB_Remove;
+       setorigin(self, frag_target.origin + '0 0 32');
+       self.velocity = '0 0 200' + normalize(targ.origin - self.origin) * 500;
+       SUB_SetFade(self, time + 5, 1);
+       setself(this);
+
+       self.ok_lastwep = self.switchweapon;
+
+       return false;
+}
+MUTATOR_HOOKFUNCTION(ok, MonsterDropItem) { ok_PlayerDies(); }
+
+MUTATOR_HOOKFUNCTION(ok, PlayerRegen)
+{SELFPARAM();
+       // overkill's values are different, so use custom regen
+       if(!self.frozen)
+       {
+               self.armorvalue = CalcRotRegen(self.armorvalue, autocvar_g_balance_armor_regenstable, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, 1 * frametime * (time > self.ok_pauseregen_finished), 0, 0, 1, 1 * frametime * (time > self.pauserotarmor_finished), autocvar_g_balance_armor_limit);
+               self.health = CalcRotRegen(self.health, autocvar_g_balance_health_regenstable, 0, 100, 1 * frametime * (time > self.ok_pauseregen_finished), 200, 0, autocvar_g_balance_health_rotlinear, 1 * frametime * (time > self.pauserothealth_finished), autocvar_g_balance_health_limit);
+
+               float minf, maxf, limitf;
+
+               maxf = autocvar_g_balance_fuel_rotstable;
+               minf = autocvar_g_balance_fuel_regenstable;
+               limitf = autocvar_g_balance_fuel_limit;
+
+               self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > self.pauseregen_finished) * ((self.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > self.pauserotfuel_finished), limitf);
+       }
+       return true; // return true anyway, as frozen uses no regen
+}
+
+MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
+{
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
+{SELFPARAM();
+       if(intermission_running || gameover)
+               return false;
+
+       if(self.deadflag != DEAD_NO || !IS_PLAYER(self) || self.frozen)
+               return false;
+
+       if(self.ok_lastwep)
+       {
+               self.switchweapon = self.ok_lastwep;
+               self.ok_lastwep = 0;
+       }
+
+       ok_IncreaseCharge(self, self.weapon);
+
+       if(self.BUTTON_ATCK2)
+       if(!forbidWeaponUse(self) || self.weapon_blocked) // allow if weapon is blocked
+       if(time >= self.jump_interval)
+       {
+               self.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor();
+               makevectors(self.v_angle);
+
+               int oldwep = self.weapon;
+               self.weapon = WEP_BLASTER.m_id;
+               W_Blaster_Attack(
+                       self,
+                       WEP_BLASTER.m_id | HITTYPE_SECONDARY,
+                       WEP_CVAR_SEC(vaporizer, shotangle),
+                       WEP_CVAR_SEC(vaporizer, damage),
+                       WEP_CVAR_SEC(vaporizer, edgedamage),
+                       WEP_CVAR_SEC(vaporizer, radius),
+                       WEP_CVAR_SEC(vaporizer, force),
+                       WEP_CVAR_SEC(vaporizer, speed),
+                       WEP_CVAR_SEC(vaporizer, spread),
+                       WEP_CVAR_SEC(vaporizer, delay),
+                       WEP_CVAR_SEC(vaporizer, lifetime)
+               );
+               self.weapon = oldwep;
+       }
+
+       self.weapon_blocked = false;
+
+       self.ok_ammo_charge = self.ammo_charge[self.weapon];
+
+       if(self.ok_use_ammocharge)
+       if(!ok_CheckWeaponCharge(self, self.weapon))
+       {
+               if(autocvar_g_overkill_ammo_charge_notice && time > self.ok_notice_time && self.BUTTON_ATCK && IS_REAL_CLIENT(self) && self.weapon == self.switchweapon)
+               {
+                       //Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_OVERKILL_CHARGE);
+                       self.ok_notice_time = time + 2;
+                       play2(self, SND(DRYFIRE));
+               }
+               Weapon wpn = get_weaponinfo(self.weapon);
+               .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+               if(self.(weaponentity).state != WS_CLEAR)
+                       w_ready(wpn, self, weaponentity, (self.BUTTON_ATCK ? 1 : 0) | (self.BUTTON_ATCK2 ? 2 : 0));
+
+               self.weapon_blocked = true;
+       }
+
+       self.BUTTON_ATCK2 = 0;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, PlayerSpawn)
+{SELFPARAM();
+       if(autocvar_g_overkill_ammo_charge)
+       {
+               for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
+                       self.ammo_charge[i] = autocvar_g_overkill_ammo_charge_limit;
+
+               self.ok_use_ammocharge = 1;
+               self.ok_notice_time = time;
+       }
+       else
+               self.ok_use_ammocharge = 0;
+
+       self.ok_pauseregen_finished = time + 2;
+
+       return false;
+}
+
+void _spawnfunc_weapon_hmg() { SELFPARAM(); spawnfunc_weapon_hmg(this); }
+void _spawnfunc_weapon_rpc() { SELFPARAM(); spawnfunc_weapon_rpc(this); }
+
+MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
+{SELFPARAM();
+       if(autocvar_g_powerups)
+       if(autocvar_g_overkill_powerups_replace)
+       {
+               if(self.classname == "item_strength")
+               {
+                       entity wep = new(weapon_hmg);
+                       setorigin(wep, self.origin);
+                       setmodel(wep, MDL_OK_HMG);
+                       wep.ok_item = true;
+                       wep.noalign = self.noalign;
+                       wep.cnt = self.cnt;
+                       wep.team = self.team;
+                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
+                       wep.pickup_anyway = true;
+                       wep.think = _spawnfunc_weapon_hmg;
+                       wep.nextthink = time + 0.1;
+                       return true;
+               }
+
+               if(self.classname == "item_invincible")
+               {
+                       entity wep = new(weapon_rpc);
+                       setorigin(wep, self.origin);
+                       setmodel(wep, MDL_OK_RPC);
+                       wep.ok_item = true;
+                       wep.noalign = self.noalign;
+                       wep.cnt = self.cnt;
+                       wep.team = self.team;
+                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
+                       wep.pickup_anyway = true;
+                       wep.think = _spawnfunc_weapon_rpc;
+                       wep.nextthink = time + 0.1;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, FilterItem)
+{SELFPARAM();
+       if(self.ok_item)
+               return false;
+
+       switch(self.items)
+       {
+               case ITEM_HealthMega.m_itemid: return !(autocvar_g_overkill_100h_anyway);
+               case ITEM_ArmorMega.m_itemid: return !(autocvar_g_overkill_100a_anyway);
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ok, SpectateCopy)
+{SELFPARAM();
+       self.ammo_charge[self.weapon] = other.ammo_charge[other.weapon];
+       self.ok_use_ammocharge = other.ok_use_ammocharge;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, SetStartItems)
+{
+       WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
+
+       if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
+       if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
+
+       start_items |= IT_UNLIMITED_WEAPON_AMMO;
+       start_weapons = warmup_start_weapons = ok_start_items;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":OK");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Overkill");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ok, SetModname)
+{
+       modname = "Overkill";
+       return true;
+}
+
+void ok_SetCvars()
+{
+       // hack to force overkill playermodels
+       cvar_settemp("sv_defaultcharacter", "1");
+       cvar_settemp("sv_defaultplayermodel", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
+       cvar_settemp("sv_defaultplayermodel_red", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm");
+       cvar_settemp("sv_defaultplayermodel_blue", "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
+}
+
+void ok_Initialize()
+{
+       ok_SetCvars();
+
+       precache_all_playermodels("models/ok_player/*.dpm");
+
+       addstat(STAT_OK_AMMO_CHARGE, AS_FLOAT, ok_use_ammocharge);
+       addstat(STAT_OK_AMMO_CHARGEPOOL, AS_FLOAT, ok_ammo_charge);
+
+       WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+       WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+
+       WEP_SHOTGUN.mdl = "ok_shotgun";
+       WEP_MACHINEGUN.mdl = "ok_mg";
+       WEP_VORTEX.mdl = "ok_sniper";
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/rpc.qc b/qcsrc/common/mutators/mutator/overkill/rpc.qc
new file mode 100644 (file)
index 0000000..05aa923
--- /dev/null
@@ -0,0 +1,231 @@
+#ifndef IMPLEMENTATION
+CLASS(RocketPropelledChainsaw, Weapon)
+/* ammotype  */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets)
+/* impulse   */ ATTRIB(RocketPropelledChainsaw, impulse, int, 7)
+/* flags     */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
+/* rating    */ ATTRIB(RocketPropelledChainsaw, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
+/* color     */ ATTRIB(RocketPropelledChainsaw, wpcolor, vector, '0.5 0.5 0');
+/* modelname */ ATTRIB(RocketPropelledChainsaw, mdl, string, "ok_rl");
+#ifndef MENUQC
+/* model     */ ATTRIB(RocketPropelledChainsaw, m_model, Model, MDL_RPC_ITEM);
+#endif
+/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair, string, "gfx/crosshairrocketlauncher");
+/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair_size, float, 0.6);
+/* wepimg    */ ATTRIB(RocketPropelledChainsaw, model2, string, "weaponrpc");
+/* refname   */ ATTRIB(RocketPropelledChainsaw, netname, string, "rpc");
+/* wepname   */ ATTRIB(RocketPropelledChainsaw, m_name, string, _("Rocket Propelled Chainsaw"));
+ENDCLASS(RocketPropelledChainsaw)
+REGISTER_WEAPON(RPC, NEW(RocketPropelledChainsaw));
+
+#define RPC_SETTINGS(w_cvar,w_prop) RPC_SETTINGS_LIST(w_cvar, w_prop, RPC, rpc)
+#define RPC_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
+       w_cvar(id, sn, NONE, ammo) \
+       w_cvar(id, sn, NONE, animtime) \
+       w_cvar(id, sn, NONE, damage) \
+       w_cvar(id, sn, NONE, damage2) \
+       w_cvar(id, sn, NONE, damageforcescale) \
+       w_cvar(id, sn, NONE, edgedamage) \
+       w_cvar(id, sn, NONE, force) \
+       w_cvar(id, sn, NONE, health) \
+       w_cvar(id, sn, NONE, lifetime) \
+       w_cvar(id, sn, NONE, radius) \
+       w_cvar(id, sn, NONE, refire) \
+       w_cvar(id, sn, NONE, speed) \
+       w_cvar(id, sn, NONE, speedaccel) \
+       w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
+       w_prop(id, sn, float,  reloading_time, reload_time) \
+       w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
+       w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
+       w_prop(id, sn, string, weaponreplace, weaponreplace) \
+       w_prop(id, sn, float,  weaponstart, weaponstart) \
+       w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride) \
+       w_prop(id, sn, float,  weaponthrowable, weaponthrowable)
+
+#ifdef SVQC
+RPC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
+#endif
+#endif
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+spawnfunc(weapon_rpc) { weapon_defaultspawnfunc(this, WEP_RPC); }
+
+void W_RocketPropelledChainsaw_Explode()
+{SELFPARAM();
+       self.event_damage = func_null;
+       self.takedamage = DAMAGE_NO;
+
+       RadiusDamage (self, self.realowner, WEP_CVAR(rpc, damage), WEP_CVAR(rpc, edgedamage), WEP_CVAR(rpc, radius), world, world, WEP_CVAR(rpc, force), self.projectiledeathtype, other);
+
+       remove (self);
+}
+
+void W_RocketPropelledChainsaw_Touch ()
+{SELFPARAM();
+       if(WarpZone_Projectile_Touch())
+               if(wasfreed(self))
+                       return;
+
+       W_RocketPropelledChainsaw_Explode();
+}
+
+void W_RocketPropelledChainsaw_Damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{SELFPARAM();
+       if (self.health <= 0)
+               return;
+
+       if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
+               return; // g_projectiles_damage says to halt
+
+       self.health = self.health - damage;
+
+       if (self.health <= 0)
+               W_PrepareExplosionByDamage(attacker, W_RocketPropelledChainsaw_Explode);
+}
+
+void W_RocketPropelledChainsaw_Think()
+{SELFPARAM();
+       if(self.cnt <= time)
+       {
+               remove(self);
+               return;
+       }
+
+       self.cnt = vlen(self.velocity);
+       self.wait = self.cnt * sys_frametime;
+       self.pos1 = normalize(self.velocity);
+
+       tracebox(self.origin, self.mins, self.maxs, self.origin + self.pos1 * (2 * self.wait), MOVE_NORMAL, self);
+       if(IS_PLAYER(trace_ent))
+               Damage (trace_ent, self, self.realowner, WEP_CVAR(rpc, damage2), self.projectiledeathtype, self.origin, normalize(self.origin - other.origin) * WEP_CVAR(rpc, force));
+
+       self.velocity = self.pos1 * (self.cnt + (WEP_CVAR(rpc, speedaccel) * sys_frametime));
+
+       UpdateCSQCProjectile(self);
+       self.nextthink = time;
+}
+
+void W_RocketPropelledChainsaw_Attack (Weapon thiswep)
+{SELFPARAM();
+       entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(self);
+       entity flash = spawn ();
+
+       W_DecreaseAmmo(thiswep, self, WEP_CVAR(rpc, ammo));
+       W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', false, 5, SND(ROCKET_FIRE), CH_WEAPON_A, WEP_CVAR(rpc, damage));
+       Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+       PROJECTILE_MAKETRIGGER(missile);
+
+       missile.owner = missile.realowner = self;
+       missile.bot_dodge = true;
+       missile.bot_dodgerating = WEP_CVAR(rpc, damage) * 2;
+
+       missile.takedamage = DAMAGE_YES;
+       missile.damageforcescale = WEP_CVAR(rpc, damageforcescale);
+       missile.health = WEP_CVAR(rpc, health);
+       missile.event_damage = W_RocketPropelledChainsaw_Damage;
+       missile.damagedbycontents = true;
+       missile.movetype = MOVETYPE_FLY;
+
+       missile.projectiledeathtype = WEP_RPC.m_id;
+       setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
+
+       setorigin (missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
+       W_SetupProjVelocity_Basic(missile, WEP_CVAR(rpc, speed), 0);
+
+       missile.touch = W_RocketPropelledChainsaw_Touch;
+
+       missile.think = W_RocketPropelledChainsaw_Think;
+       missile.cnt = time + WEP_CVAR(rpc, lifetime);
+       missile.nextthink = time;
+       missile.flags = FL_PROJECTILE;
+
+       CSQCProjectile(missile, true, PROJECTILE_RPC, false);
+
+       setmodel(flash, MDL_RPC_MUZZLEFLASH); // precision set below
+       SUB_SetFade (flash, time, 0.1);
+       flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+       W_AttachToShotorg(self, flash, '5 0 0');
+       missile.pos1 = missile.velocity;
+
+       MUTATOR_CALLHOOK(EditProjectile, self, missile);
+}
+
+               METHOD(RocketPropelledChainsaw, wr_aim, void(entity thiswep))
+               {
+                       self.BUTTON_ATCK = bot_aim(WEP_CVAR(rpc, speed), 0, WEP_CVAR(rpc, lifetime), false);
+               }
+               METHOD(RocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+               {
+                       if(WEP_CVAR(rpc, reload_ammo) && actor.clip_load < WEP_CVAR(rpc, ammo)) {
+                               Weapon w = get_weaponinfo(actor.weapon);
+                               w.wr_reload(w);
+                       } else
+                       {
+                               if (fire & 1)
+                               {
+                                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(rpc, refire)))
+                                       {
+                                               W_RocketPropelledChainsaw_Attack(thiswep);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(rpc, animtime), w_ready);
+                                       }
+                               }
+
+                               if (fire & 2)
+                               {
+                                       // to-do
+                               }
+                       }
+               }
+               METHOD(RocketPropelledChainsaw, wr_init, void(entity thiswep))
+               {
+                       RPC_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
+               }
+               METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep))
+               {
+                       float ammo_amount = self.WEP_AMMO(RPC) >= WEP_CVAR(rpc, ammo);
+                       ammo_amount += self.(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo);
+                       return ammo_amount;
+               }
+               METHOD(RocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep))
+               {
+                       return false;
+               }
+               METHOD(RocketPropelledChainsaw, wr_config, void(entity thiswep))
+               {
+                       RPC_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
+               }
+               METHOD(RocketPropelledChainsaw, wr_reload, void(entity thiswep))
+               {
+                       W_Reload(self, WEP_CVAR(rpc, ammo), SND(RELOAD));
+               }
+               METHOD(RocketPropelledChainsaw, wr_suicidemessage, int(entity thiswep))
+               {
+                       if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+                               return WEAPON_RPC_SUICIDE_SPLASH;
+                       else
+                               return WEAPON_RPC_SUICIDE_DIRECT;
+               }
+               METHOD(RocketPropelledChainsaw, wr_killmessage, int(entity thiswep))
+               {
+                       if(w_deathtype & HITTYPE_SECONDARY)
+                               return WEAPON_BLASTER_MURDER;
+                       else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+                               return WEAPON_RPC_MURDER_SPLASH;
+                       else
+                               return WEAPON_RPC_MURDER_DIRECT;
+               }
+
+#endif
+
+#ifdef CSQC
+
+               METHOD(RocketPropelledChainsaw, wr_impacteffect, void(entity thiswep))
+               {
+                       vector org2;
+                       org2 = w_org + w_backoff * 12;
+                       pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
+                       if(!w_issilent)
+                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+               }
+
+#endif
+#endif
diff --git a/qcsrc/common/mutators/mutator/physical_items/module.inc b/qcsrc/common/mutators/mutator/physical_items/module.inc
new file mode 100644 (file)
index 0000000..7ed9b03
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "physical_items.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/physical_items/physical_items.qc b/qcsrc/common/mutators/mutator/physical_items/physical_items.qc
new file mode 100644 (file)
index 0000000..6fbe77b
--- /dev/null
@@ -0,0 +1,143 @@
+#ifdef IMPLEMENTATION
+int autocvar_g_physical_items;
+float autocvar_g_physical_items_damageforcescale;
+float autocvar_g_physical_items_reset;
+
+REGISTER_MUTATOR(physical_items, cvar("g_physical_items"))
+{
+       // check if we have a physics engine
+       MUTATOR_ONADD
+       {
+               if (!(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")))
+               {
+                       LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.\n");
+                       return -1;
+               }
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // nothing to roll back
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               LOG_INFO("This cannot be removed at runtime\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+.vector spawn_origin, spawn_angles;
+
+void physical_item_think()
+{SELFPARAM();
+       self.nextthink = time;
+
+       self.alpha = self.owner.alpha; // apply fading and ghosting
+
+       if(!self.cnt) // map item, not dropped
+       {
+               // copy ghost item properties
+               self.colormap = self.owner.colormap;
+               self.colormod = self.owner.colormod;
+               self.glowmod = self.owner.glowmod;
+
+               // if the item is not spawned, make sure the invisible / ghost item returns to its origin and stays there
+               if(autocvar_g_physical_items_reset)
+               {
+                       if(self.owner.wait > time) // awaiting respawn
+                       {
+                               setorigin(self, self.spawn_origin);
+                               self.angles = self.spawn_angles;
+                               self.solid = SOLID_NOT;
+                               self.alpha = -1;
+                               self.movetype = MOVETYPE_NONE;
+                       }
+                       else
+                       {
+                               self.alpha = 1;
+                               self.solid = SOLID_CORPSE;
+                               self.movetype = MOVETYPE_PHYSICS;
+                       }
+               }
+       }
+
+       if(!self.owner.modelindex)
+               remove(self); // the real item is gone, remove this
+}
+
+void physical_item_touch()
+{SELFPARAM();
+       if(!self.cnt) // not for dropped items
+       if (ITEM_TOUCH_NEEDKILL())
+       {
+               setorigin(self, self.spawn_origin);
+               self.angles = self.spawn_angles;
+       }
+}
+
+void physical_item_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+{SELFPARAM();
+       if(!self.cnt) // not for dropped items
+       if(ITEM_DAMAGE_NEEDKILL(deathtype))
+       {
+               setorigin(self, self.spawn_origin);
+               self.angles = self.spawn_angles;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(physical_items, Item_Spawn)
+{SELFPARAM();
+       if(self.owner == world && autocvar_g_physical_items <= 1)
+               return false;
+       if (self.spawnflags & 1) // floating item
+               return false;
+
+       // The actual item can't be physical and trigger at the same time, so make it invisible and use a second entity for physics.
+       // Ugly hack, but unless SOLID_TRIGGER is gotten to work with MOVETYPE_PHYSICS in the engine it can't be fixed.
+       entity wep;
+       wep = spawn();
+       _setmodel(wep, self.model);
+       setsize(wep, self.mins, self.maxs);
+       setorigin(wep, self.origin);
+       wep.angles = self.angles;
+       wep.velocity = self.velocity;
+
+       wep.owner = self;
+       wep.solid = SOLID_CORPSE;
+       wep.movetype = MOVETYPE_PHYSICS;
+       wep.takedamage = DAMAGE_AIM;
+       wep.effects |= EF_NOMODELFLAGS; // disable the spinning
+       wep.colormap = self.owner.colormap;
+       wep.glowmod = self.owner.glowmod;
+       wep.damageforcescale = autocvar_g_physical_items_damageforcescale;
+       wep.dphitcontentsmask = self.dphitcontentsmask;
+       wep.cnt = (self.owner != world);
+
+       wep.think = physical_item_think;
+       wep.nextthink = time;
+       wep.touch = physical_item_touch;
+       wep.event_damage = physical_item_damage;
+
+       if(!wep.cnt)
+       {
+               // fix the spawn origin
+               setorigin(wep, wep.origin + '0 0 1');
+               entity oldself;
+               oldself = self;
+               WITH(entity, self, wep, builtin_droptofloor());
+       }
+
+       wep.spawn_origin = wep.origin;
+       wep.spawn_angles = self.angles;
+
+       self.effects |= EF_NODRAW; // hide the original weapon
+       self.movetype = MOVETYPE_FOLLOW;
+       self.aiment = wep; // attach the original weapon
+       self.SendEntity = func_null;
+
+       return false;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/pinata/module.inc b/qcsrc/common/mutators/mutator/pinata/module.inc
new file mode 100644 (file)
index 0000000..4e22966
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "pinata.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/pinata/pinata.qc b/qcsrc/common/mutators/mutator/pinata/pinata.qc
new file mode 100644 (file)
index 0000000..a806b29
--- /dev/null
@@ -0,0 +1,27 @@
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(pinata, cvar("g_pinata") && !cvar("g_instagib") && !cvar("g_overkill"));
+
+MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
+{SELFPARAM();
+       for(int j = WEP_FIRST; j <= WEP_LAST; ++j)
+       if(self.weapons & WepSet_FromWeapon(j))
+       if(self.switchweapon != j)
+       if(W_IsWeaponThrowable(j))
+               W_ThrowNewWeapon(self, j, false, self.origin + (self.mins + self.maxs) * 0.5, randomvec() * 175 + '0 0 325');
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":Pinata");
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Piñata");
+       return false;
+}
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/random_gravity/module.inc b/qcsrc/common/mutators/mutator/random_gravity/module.inc
new file mode 100644 (file)
index 0000000..91baa43
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "random_gravity.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/random_gravity/random_gravity.qc b/qcsrc/common/mutators/mutator/random_gravity/random_gravity.qc
new file mode 100644 (file)
index 0000000..80abfe3
--- /dev/null
@@ -0,0 +1,56 @@
+#ifdef IMPLEMENTATION
+// Random Gravity
+//
+// Mutator by Mario
+// Inspired by Player 2
+
+float autocvar_g_random_gravity_negative_chance;
+float autocvar_g_random_gravity_min;
+float autocvar_g_random_gravity_max;
+float autocvar_g_random_gravity_positive;
+float autocvar_g_random_gravity_negative;
+float autocvar_g_random_gravity_delay;
+
+REGISTER_MUTATOR(random_gravity, cvar("g_random_gravity"))
+{
+       MUTATOR_ONADD
+       {
+               cvar_settemp("sv_gravity", cvar_string("sv_gravity")); // settemp current gravity so it's restored on match end
+       }
+
+       return false;
+}
+
+float gravity_delay;
+
+MUTATOR_HOOKFUNCTION(random_gravity, SV_StartFrame)
+{
+       if(gameover || !cvar("g_random_gravity")) return false;
+       if(time < gravity_delay) return false;
+       if(time < game_starttime) return false;
+       if(round_handler_IsActive() && !round_handler_IsRoundStarted()) return false;
+
+    if(random() >= autocvar_g_random_gravity_negative_chance)
+        cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() - random() * -autocvar_g_random_gravity_negative, autocvar_g_random_gravity_max)));
+    else
+        cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() * autocvar_g_random_gravity_positive, autocvar_g_random_gravity_max)));
+
+       gravity_delay = time + autocvar_g_random_gravity_delay;
+
+       LOG_TRACE("Gravity is now: ", ftos(autocvar_sv_gravity), "\n");
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":RandomGravity");
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Random gravity");
+       return 0;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/rocketflying/module.inc b/qcsrc/common/mutators/mutator/rocketflying/module.inc
new file mode 100644 (file)
index 0000000..7036bc4
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "rocketflying.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/rocketflying/rocketflying.qc b/qcsrc/common/mutators/mutator/rocketflying/rocketflying.qc
new file mode 100644 (file)
index 0000000..f23d991
--- /dev/null
@@ -0,0 +1,25 @@
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(rocketflying, cvar("g_rocket_flying"));
+
+MUTATOR_HOOKFUNCTION(rocketflying, EditProjectile)
+{
+       if(other.classname == "rocket" || other.classname == "mine")
+       {
+               // kill detonate delay of rockets
+               other.spawnshieldtime = time;
+       }
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":RocketFlying");
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Rocket Flying");
+       return 0;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/rocketminsta/module.inc b/qcsrc/common/mutators/mutator/rocketminsta/module.inc
new file mode 100644 (file)
index 0000000..b7d02a9
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "rocketminsta.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/rocketminsta/rocketminsta.qc b/qcsrc/common/mutators/mutator/rocketminsta/rocketminsta.qc
new file mode 100644 (file)
index 0000000..6ddd6db
--- /dev/null
@@ -0,0 +1,35 @@
+#ifdef IMPLEMENTATION
+#include "../../../deathtypes/all.qh"
+#include "../../../../server/round_handler.qh"
+
+REGISTER_MUTATOR(rm, cvar("g_instagib"));
+
+MUTATOR_HOOKFUNCTION(rm, PlayerDamage_Calculate)
+{
+       // we do it this way, so rm can be toggled during the match
+       if(!autocvar_g_rm) { return false; }
+
+       if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR))
+       if(frag_attacker == frag_target || frag_target.classname == "nade")
+               frag_damage = 0;
+
+       if(autocvar_g_rm_laser)
+       if(DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
+       if(frag_attacker == frag_target || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
+               frag_damage = 0;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(rm, PlayerDies)
+{
+       // we do it this way, so rm can be toggled during the match
+       if(!autocvar_g_rm) { return false; }
+
+       if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR) || DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
+               frag_damage = 1000; // always gib if it was a vaporizer death
+
+       return false;
+}
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/running_guns/module.inc b/qcsrc/common/mutators/mutator/running_guns/module.inc
new file mode 100644 (file)
index 0000000..036b70f
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "running_guns.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/running_guns/running_guns.qc b/qcsrc/common/mutators/mutator/running_guns/running_guns.qc
new file mode 100644 (file)
index 0000000..cad4d5f
--- /dev/null
@@ -0,0 +1,14 @@
+#ifdef IMPLEMENTATION
+
+bool autocvar_g_running_guns;
+
+REGISTER_MUTATOR(running_guns, autocvar_g_running_guns);
+
+MUTATOR_HOOKFUNCTION(running_guns, SetDefaultAlpha)
+{
+       default_player_alpha = -1;
+       default_weapon_alpha = +1;
+       return true;
+}
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/sandbox/module.inc b/qcsrc/common/mutators/mutator/sandbox/module.inc
new file mode 100644 (file)
index 0000000..0715d5b
--- /dev/null
@@ -0,0 +1,4 @@
+#ifdef SVQC
+#include "sandbox.qc"
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/sandbox/sandbox.qc b/qcsrc/common/mutators/mutator/sandbox/sandbox.qc
new file mode 100644 (file)
index 0000000..e1decc8
--- /dev/null
@@ -0,0 +1,842 @@
+#ifdef IMPLEMENTATION
+int autocvar_g_sandbox_info;
+bool autocvar_g_sandbox_readonly;
+string autocvar_g_sandbox_storage_name;
+float autocvar_g_sandbox_storage_autosave;
+bool autocvar_g_sandbox_storage_autoload;
+float autocvar_g_sandbox_editor_flood;
+int autocvar_g_sandbox_editor_maxobjects;
+int autocvar_g_sandbox_editor_free;
+float autocvar_g_sandbox_editor_distance_spawn;
+float autocvar_g_sandbox_editor_distance_edit;
+float autocvar_g_sandbox_object_scale_min;
+float autocvar_g_sandbox_object_scale_max;
+float autocvar_g_sandbox_object_material_velocity_min;
+float autocvar_g_sandbox_object_material_velocity_factor;
+
+float autosave_time;
+void sandbox_Database_Load();
+
+REGISTER_MUTATOR(sandbox, cvar("g_sandbox"))
+{
+       MUTATOR_ONADD
+       {
+               autosave_time = time + autocvar_g_sandbox_storage_autosave; // don't save the first server frame
+               if(autocvar_g_sandbox_storage_autoload)
+                       sandbox_Database_Load();
+       }
+
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               // nothing to roll back
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               // nothing to remove
+       }
+
+       return false;
+}
+
+const float MAX_STORAGE_ATTACHMENTS = 16;
+float object_count;
+.float object_flood;
+.entity object_attach;
+.string material;
+
+.float touch_timer;
+void sandbox_ObjectFunction_Touch()
+{SELFPARAM();
+       // apply material impact effects
+
+       if(!self.material)
+               return;
+       if(self.touch_timer > time)
+               return; // don't execute each frame
+       self.touch_timer = time + 0.1;
+
+       // make particle count and sound volume depend on impact speed
+       float intensity;
+       intensity = vlen(self.velocity) + vlen(other.velocity);
+       if(intensity) // avoid divisions by 0
+               intensity /= 2; // average the two velocities
+       if (!(intensity >= autocvar_g_sandbox_object_material_velocity_min))
+               return; // impact not strong enough to do anything
+       // now offset intensity and apply it to the effects
+       intensity -= autocvar_g_sandbox_object_material_velocity_min; // start from minimum velocity, not actual velocity
+       intensity = bound(0, intensity * autocvar_g_sandbox_object_material_velocity_factor, 1);
+
+       _sound(self, CH_TRIGGER, strcat("object/impact_", self.material, "_", ftos(ceil(random() * 5)) , ".wav"), VOL_BASE * intensity, ATTEN_NORM);
+       Send_Effect_(strcat("impact_", self.material), self.origin, '0 0 0', ceil(intensity * 10)); // allow a count from 1 to 10
+}
+
+void sandbox_ObjectFunction_Think()
+{SELFPARAM();
+       entity e;
+
+       // decide if and how this object can be grabbed
+       if(autocvar_g_sandbox_readonly)
+               self.grab = 0; // no grabbing
+       else if(autocvar_g_sandbox_editor_free < 2 && self.crypto_idfp)
+               self.grab = 1; // owner only
+       else
+               self.grab = 3; // anyone
+
+       // Object owner is stored via player UID, but we also need the owner as an entity (if the player is available on the server).
+       // Therefore, scan for all players, and update the owner as long as the player is present. We must always do this,
+       // since if the owning player disconnects, the object's owner should also be reset.
+       FOR_EACH_REALPLAYER(e) // bots can't have objects
+       {
+               if(self.crypto_idfp == e.crypto_idfp)
+               {
+                       self.realowner = e;
+                       break;
+               }
+               self.realowner = world;
+       }
+
+       self.nextthink = time;
+
+       CSQCMODEL_AUTOUPDATE(self);
+}
+
+.float old_solid, old_movetype;
+entity sandbox_ObjectEdit_Get(float permissions)
+{SELFPARAM();
+       // Returns the traced entity if the player can edit it, and world if not.
+       // If permissions if false, the object is returned regardless of editing rights.
+       // Attached objects are SOLID_NOT and do not get traced.
+
+       crosshair_trace_plusvisibletriggers(self);
+       if(vlen(self.origin - trace_ent.origin) > autocvar_g_sandbox_editor_distance_edit)
+               return world; // out of trace range
+       if(trace_ent.classname != "object")
+               return world; // entity is not an object
+       if(!permissions)
+               return trace_ent; // don't check permissions, anyone can edit this object
+       if(trace_ent.crypto_idfp == "")
+               return trace_ent; // the player who spawned this object did not have an UID, so anyone can edit it
+       if (!(trace_ent.realowner != self && autocvar_g_sandbox_editor_free < 2))
+               return trace_ent; // object does not belong to the player, and players can only edit their own objects on this server
+       return world;
+}
+
+void sandbox_ObjectEdit_Scale(entity e, float f)
+{
+       e.scale = f;
+       if(e.scale)
+       {
+               e.scale = bound(autocvar_g_sandbox_object_scale_min, e.scale, autocvar_g_sandbox_object_scale_max);
+               _setmodel(e, e.model); // reset mins and maxs based on mesh
+               setsize(e, e.mins * e.scale, e.maxs * e.scale); // adapt bounding box size to model size
+       }
+}
+
+void sandbox_ObjectAttach_Remove(entity e);
+void sandbox_ObjectAttach_Set(entity e, entity parent, string s)
+{
+       // attaches e to parent on string s
+
+       // we can't attach to an attachment, for obvious reasons
+       sandbox_ObjectAttach_Remove(e);
+
+       e.old_solid = e.solid; // persist solidity
+       e.old_movetype = e.movetype; // persist physics
+       e.movetype = MOVETYPE_FOLLOW;
+       e.solid = SOLID_NOT;
+       e.takedamage = DAMAGE_NO;
+
+       setattachment(e, parent, s);
+       e.owner = parent;
+}
+
+void sandbox_ObjectAttach_Remove(entity e)
+{
+       // detaches any object attached to e
+
+       entity head;
+       for(head = world; (head = find(head, classname, "object")); )
+       {
+               if(head.owner == e)
+               {
+                       vector org;
+                       org = gettaginfo(head, 0);
+                       setattachment(head, world, "");
+                       head.owner = world;
+
+                       // objects change origin and angles when detached, so apply previous position
+                       setorigin(head, org);
+                       head.angles = e.angles; // don't allow detached objects to spin or roll
+
+                       head.solid = head.old_solid; // restore persisted solidity
+                       head.movetype = head.old_movetype; // restore persisted physics
+                       head.takedamage = DAMAGE_AIM;
+               }
+       }
+}
+
+entity sandbox_ObjectSpawn(float database)
+{SELFPARAM();
+       // spawn a new object with default properties
+
+       entity e = new(object);
+       e.takedamage = DAMAGE_AIM;
+       e.damageforcescale = 1;
+       e.solid = SOLID_BBOX; // SOLID_BSP would be best, but can lag the server badly
+       e.movetype = MOVETYPE_TOSS;
+       e.frame = 0;
+       e.skin = 0;
+       e.material = string_null;
+       e.touch = sandbox_ObjectFunction_Touch;
+       e.think = sandbox_ObjectFunction_Think;
+       e.nextthink = time;
+       //e.effects |= EF_SELECTABLE; // don't do this all the time, maybe just when editing objects?
+
+       if(!database)
+       {
+               // set the object's owner via player UID
+               // if the player does not have an UID, the owner cannot be stored and his objects may be edited by anyone
+               if(self.crypto_idfp != "")
+                       e.crypto_idfp = strzone(self.crypto_idfp);
+               else
+                       print_to(self, "^1SANDBOX - WARNING: ^7You spawned an object, but lack a player UID. ^1Your objects are not secured and can be edited by any player!");
+
+               // set public object information
+               e.netname = strzone(self.netname); // name of the owner
+               e.message = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // creation time
+               e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // last editing time
+
+               // set origin and direction based on player position and view angle
+               makevectors(self.v_angle);
+               WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * autocvar_g_sandbox_editor_distance_spawn, MOVE_NORMAL, self);
+               setorigin(e, trace_endpos);
+               e.angles_y = self.v_angle.y;
+       }
+
+       WITH(entity, self, e, CSQCMODEL_AUTOINIT(e));
+
+       object_count += 1;
+       return e;
+}
+
+void sandbox_ObjectRemove(entity e)
+{
+       sandbox_ObjectAttach_Remove(e); // detach child objects
+
+       // if the object being removed has been selected for attachment by a player, unset it
+       entity head;
+       FOR_EACH_REALPLAYER(head) // bots can't have objects
+       {
+               if(head.object_attach == e)
+                       head.object_attach = world;
+       }
+
+       if(e.material)  {       strunzone(e.material);  e.material = string_null;       }
+       if(e.crypto_idfp)       {       strunzone(e.crypto_idfp);       e.crypto_idfp = string_null;    }
+       if(e.netname)   {       strunzone(e.netname);   e.netname = string_null;        }
+       if(e.message)   {       strunzone(e.message);   e.message = string_null;        }
+       if(e.message2)  {       strunzone(e.message2);  e.message2 = string_null;       }
+       remove(e);
+       e = world;
+
+       object_count -= 1;
+}
+
+string port_string[MAX_STORAGE_ATTACHMENTS]; // fteqcc crashes if this isn't defined as a global
+
+string sandbox_ObjectPort_Save(entity e, float database)
+{
+       // save object properties, and return them as a string
+       float i = 0;
+       string s;
+       entity head;
+
+       for(head = world; (head = find(head, classname, "object")); )
+       {
+               // the main object needs to be first in the array [0] with attached objects following
+               float slot, physics, solidity;
+               if(head == e) // this is the main object, place it first
+               {
+                       slot = 0;
+                       solidity = head.solid; // applied solidity is normal solidity for children
+                       physics = head.movetype; // applied physics are normal physics for parents
+               }
+               else if(head.owner == e) // child object, list them in order
+               {
+                       i += 1; // children start from 1
+                       slot = i;
+                       solidity = head.old_solid; // persisted solidity is normal solidity for children
+                       physics = head.old_movetype; // persisted physics are normal physics for children
+                       gettaginfo(head.owner, head.tag_index); // get the name of the tag our object is attached to, used further below
+               }
+               else
+                       continue;
+
+               // ---------------- OBJECT PROPERTY STORAGE: SAVE ----------------
+               if(slot)
+               {
+                       // properties stored only for child objects
+                       if(gettaginfo_name)     port_string[slot] = strcat(port_string[slot], "\"", gettaginfo_name, "\" ");    else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+               }
+               else
+               {
+                       // properties stored only for parent objects
+                       if(database)
+                       {
+                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.origin), " ");
+                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.angles), " ");
+                       }
+               }
+               // properties stored for all objects
+               port_string[slot] = strcat(port_string[slot], "\"", head.model, "\" ");
+               port_string[slot] = strcat(port_string[slot], ftos(head.skin), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(head.alpha), " ");
+               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.colormod), " ");
+               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.glowmod), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(head.frame), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(head.scale), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(solidity), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(physics), " ");
+               port_string[slot] = strcat(port_string[slot], ftos(head.damageforcescale), " ");
+               if(head.material)       port_string[slot] = strcat(port_string[slot], "\"", head.material, "\" ");      else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+               if(database)
+               {
+                       // properties stored only for the database
+                       if(head.crypto_idfp)    port_string[slot] = strcat(port_string[slot], "\"", head.crypto_idfp, "\" ");   else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
+                       port_string[slot] = strcat(port_string[slot], "\"", e.netname, "\" ");
+                       port_string[slot] = strcat(port_string[slot], "\"", e.message, "\" ");
+                       port_string[slot] = strcat(port_string[slot], "\"", e.message2, "\" ");
+               }
+       }
+
+       // now apply the array to a simple string, with the ; symbol separating objects
+       s = "";
+       for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
+       {
+               if(port_string[i])
+                       s = strcat(s, port_string[i], "; ");
+               port_string[i] = string_null; // fully clear the string
+       }
+
+       return s;
+}
+
+entity sandbox_ObjectPort_Load(string s, float database)
+{
+       // load object properties, and spawn a new object with them
+       float n, i;
+       entity e = world, parent = world;
+
+       // separate objects between the ; symbols
+       n = tokenizebyseparator(s, "; ");
+       for(i = 0; i < n; ++i)
+               port_string[i] = argv(i);
+
+       // now separate and apply the properties of each object
+       for(i = 0; i < n; ++i)
+       {
+               float argv_num;
+               string tagname = string_null;
+               argv_num = 0;
+               tokenize_console(port_string[i]);
+               e = sandbox_ObjectSpawn(database);
+
+               // ---------------- OBJECT PROPERTY STORAGE: LOAD ----------------
+               if(i)
+               {
+                       // properties stored only for child objects
+                       if(argv(argv_num) != "")        tagname = argv(argv_num);       else tagname = string_null;     ++argv_num;
+               }
+               else
+               {
+                       // properties stored only for parent objects
+                       if(database)
+                       {
+                               setorigin(e, stov(argv(argv_num)));     ++argv_num;
+                               e.angles = stov(argv(argv_num));        ++argv_num;
+                       }
+                       parent = e; // mark parent objects as such
+               }
+               // properties stored for all objects
+               _setmodel(e, argv(argv_num));   ++argv_num;
+               e.skin = stof(argv(argv_num));  ++argv_num;
+               e.alpha = stof(argv(argv_num)); ++argv_num;
+               e.colormod = stov(argv(argv_num));      ++argv_num;
+               e.glowmod = stov(argv(argv_num));       ++argv_num;
+               e.frame = stof(argv(argv_num)); ++argv_num;
+               sandbox_ObjectEdit_Scale(e, stof(argv(argv_num)));      ++argv_num;
+               e.solid = e.old_solid = stof(argv(argv_num));   ++argv_num;
+               e.movetype = e.old_movetype = stof(argv(argv_num));     ++argv_num;
+               e.damageforcescale = stof(argv(argv_num));      ++argv_num;
+               if(e.material)  strunzone(e.material);  if(argv(argv_num) != "")        e.material = strzone(argv(argv_num));   else    e.material = string_null;       ++argv_num;
+               if(database)
+               {
+                       // properties stored only for the database
+                       if(e.crypto_idfp)       strunzone(e.crypto_idfp);       if(argv(argv_num) != "")        e.crypto_idfp = strzone(argv(argv_num));        else    e.crypto_idfp = string_null;    ++argv_num;
+                       if(e.netname)   strunzone(e.netname);   e.netname = strzone(argv(argv_num));    ++argv_num;
+                       if(e.message)   strunzone(e.message);   e.message = strzone(argv(argv_num));    ++argv_num;
+                       if(e.message2)  strunzone(e.message2);  e.message2 = strzone(argv(argv_num));   ++argv_num;
+               }
+
+               // attach last
+               if(i)
+                       sandbox_ObjectAttach_Set(e, parent, tagname);
+       }
+
+       for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
+               port_string[i] = string_null; // fully clear the string
+
+       return e;
+}
+
+void sandbox_Database_Save()
+{
+       // saves all objects to the database file
+       entity head;
+       string file_name;
+       float file_get;
+
+       file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
+       file_get = fopen(file_name, FILE_WRITE);
+       fputs(file_get, strcat("// sandbox storage \"", autocvar_g_sandbox_storage_name, "\" for map \"", GetMapname(), "\" last updated ", strftime(true, "%d-%m-%Y %H:%M:%S")));
+       fputs(file_get, strcat(" containing ", ftos(object_count), " objects\n"));
+
+       for(head = world; (head = find(head, classname, "object")); )
+       {
+               // attached objects are persisted separately, ignore them here
+               if(head.owner != world)
+                       continue;
+
+               // use a line of text for each object, listing all properties
+               fputs(file_get, strcat(sandbox_ObjectPort_Save(head, true), "\n"));
+       }
+       fclose(file_get);
+}
+
+void sandbox_Database_Load()
+{
+       // loads all objects from the database file
+       string file_read, file_name;
+       float file_get, i;
+
+       file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
+       file_get = fopen(file_name, FILE_READ);
+       if(file_get < 0)
+       {
+               if(autocvar_g_sandbox_info > 0)
+                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7could not find storage file ^3", file_name, "^7, no objects were loaded\n"));
+       }
+       else
+       {
+               for (;;)
+               {
+                       file_read = fgets(file_get);
+                       if(file_read == "")
+                               break;
+                       if(substring(file_read, 0, 2) == "//")
+                               continue;
+                       if(substring(file_read, 0, 1) == "#")
+                               continue;
+
+                       entity e;
+                       e = sandbox_ObjectPort_Load(file_read, true);
+
+                       if(e.material)
+                       {
+                               // since objects are being loaded for the first time, precache material sounds for each
+                               for (i = 1; i <= 5; i++) // 5 sounds in total
+                                       precache_sound(strcat("object/impact_", e.material, "_", ftos(i), ".wav"));
+                       }
+               }
+               if(autocvar_g_sandbox_info > 0)
+                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7successfully loaded storage file ^3", file_name, "\n"));
+       }
+       fclose(file_get);
+}
+
+MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
+{SELFPARAM();
+       if(MUTATOR_RETURNVALUE) // command was already handled?
+               return false;
+       if(cmd_name == "g_sandbox")
+       {
+               if(autocvar_g_sandbox_readonly)
+               {
+                       print_to(self, "^2SANDBOX - INFO: ^7Sandbox mode is active, but in read-only mode. Sandbox commands cannot be used");
+                       return true;
+               }
+               if(cmd_argc < 2)
+               {
+                       print_to(self, "^2SANDBOX - INFO: ^7Sandbox mode is active. For usage information, type 'sandbox help'");
+                       return true;
+               }
+
+               switch(argv(1))
+               {
+                       entity e;
+                       float i;
+                       string s;
+
+                       // ---------------- COMMAND: HELP ----------------
+                       case "help":
+                               print_to(self, "You can use the following sandbox commands:");
+                               print_to(self, "^7\"^2object_spawn ^3models/foo/bar.md3^7\" spawns a new object in front of the player, and gives it the specified model");
+                               print_to(self, "^7\"^2object_remove^7\" removes the object the player is looking at. Players can only remove their own objects");
+                               print_to(self, "^7\"^2object_duplicate ^3value^7\" duplicates the object, if the player has copying rights over the original");
+                               print_to(self, "^3copy value ^7- copies the properties of the object to the specified client cvar");
+                               print_to(self, "^3paste value ^7- spawns an object with the given properties. Properties or cvars must be specified as follows; eg1: \"0 1 2 ...\", eg2: \"$cl_cvar\"");
+                               print_to(self, "^7\"^2object_attach ^3property value^7\" attaches one object to another. Players can only attach their own objects");
+                               print_to(self, "^3get ^7- selects the object you are facing as the object to be attached");
+                               print_to(self, "^3set value ^7- attaches the previously selected object to the object you are facing, on the specified bone");
+                               print_to(self, "^3remove ^7- detaches all objects from the object you are facing");
+                               print_to(self, "^7\"^2object_edit ^3property value^7\" edits the given property of the object. Players can only edit their own objects");
+                               print_to(self, "^3skin value ^7- changes the skin of the object");
+                               print_to(self, "^3alpha value ^7- sets object transparency");
+                               print_to(self, "^3colormod \"value_x value_y value_z\" ^7- main object color");
+                               print_to(self, "^3glowmod \"value_x value_y value_z\" ^7- glow object color");
+                               print_to(self, "^3frame value ^7- object animation frame, for self-animated models");
+                               print_to(self, "^3scale value ^7- changes object scale. 0.5 is half size and 2 is double size");
+                               print_to(self, "^3solidity value ^7- object collisions, 0 = non-solid, 1 = solid");
+                               print_to(self, "^3physics value ^7- object physics, 0 = static, 1 = movable, 2 = physical");
+                               print_to(self, "^3force value ^7- amount of force applied to objects that are shot");
+                               print_to(self, "^3material value ^7- sets the material of the object. Default materials are: metal, stone, wood, flesh");
+                               print_to(self, "^7\"^2object_claim^7\" sets the player as the owner of the object, if he has the right to edit it");
+                               print_to(self, "^7\"^2object_info ^3value^7\" shows public information about the object");
+                               print_to(self, "^3object ^7- prints general information about the object, such as owner and creation / editing date");
+                               print_to(self, "^3mesh ^7- prints information about the object's mesh, including skeletal bones");
+                               print_to(self, "^3attachments ^7- prints information about the object's attachments");
+                               print_to(self, "^7The ^1drag object ^7key can be used to grab and carry objects. Players can only grab their own objects");
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, SPAWN ----------------
+                       case "object_spawn":
+                               if(time < self.object_flood)
+                               {
+                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(self.object_flood - time), " ^7seconds beofore spawning another object"));
+                                       return true;
+                               }
+                               self.object_flood = time + autocvar_g_sandbox_editor_flood;
+                               if(object_count >= autocvar_g_sandbox_editor_maxobjects)
+                               {
+                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
+                                       return true;
+                               }
+                               if(cmd_argc < 3)
+                               {
+                                       print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object without specifying a model. Please specify the path to your model file after the 'object_spawn' command");
+                                       return true;
+                               }
+                               if (!(fexists(argv(2))))
+                               {
+                                       print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object with a non-existent model. Make sure the path to your model file is correct");
+                                       return true;
+                               }
+
+                               e = sandbox_ObjectSpawn(false);
+                               _setmodel(e, argv(2));
+
+                               if(autocvar_g_sandbox_info > 0)
+                                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " spawned an object at origin ^3", vtos(e.origin), "\n"));
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, REMOVE ----------------
+                       case "object_remove":
+                               e = sandbox_ObjectEdit_Get(true);
+                               if(e != world)
+                               {
+                                       if(autocvar_g_sandbox_info > 0)
+                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " removed an object at origin ^3", vtos(e.origin), "\n"));
+                                       sandbox_ObjectRemove(e);
+                                       return true;
+                               }
+
+                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be removed. Make sure you are facing an object that you have edit rights over");
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, DUPLICATE ----------------
+                       case "object_duplicate":
+                               switch(argv(2))
+                               {
+                                       case "copy":
+                                               // copies customizable properties of the selected object to the clipboard cvar
+                                               e = sandbox_ObjectEdit_Get(autocvar_g_sandbox_editor_free); // can we copy objects we can't edit?
+                                               if(e != world)
+                                               {
+                                                       s = sandbox_ObjectPort_Save(e, false);
+                                                       s = strreplace("\"", "\\\"", s);
+                                                       stuffcmd(self, strcat("set ", argv(3), " \"", s, "\""));
+
+                                                       print_to(self, "^2SANDBOX - INFO: ^7Object copied to clipboard");
+                                                       return true;
+                                               }
+                                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be copied. Make sure you are facing an object that you have copy rights over");
+                                               return true;
+
+                                       case "paste":
+                                               // spawns a new object using the properties in the player's clipboard cvar
+                                               if(time < self.object_flood)
+                                               {
+                                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(self.object_flood - time), " ^7seconds beofore spawning another object"));
+                                                       return true;
+                                               }
+                                               self.object_flood = time + autocvar_g_sandbox_editor_flood;
+                                               if(argv(3) == "") // no object in clipboard
+                                               {
+                                                       print_to(self, "^1SANDBOX - WARNING: ^7No object in clipboard. You must copy an object before you can paste it");
+                                                       return true;
+                                               }
+                                               if(object_count >= autocvar_g_sandbox_editor_maxobjects)
+                                               {
+                                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
+                                                       return true;
+                                               }
+                                               e = sandbox_ObjectPort_Load(argv(3), false);
+
+                                               print_to(self, "^2SANDBOX - INFO: ^7Object pasted successfully");
+                                               if(autocvar_g_sandbox_info > 0)
+                                                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " pasted an object at origin ^3", vtos(e.origin), "\n"));
+                                               return true;
+                               }
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, ATTACH ----------------
+                       case "object_attach":
+                               switch(argv(2))
+                               {
+                                       case "get":
+                                               // select e as the object as meant to be attached
+                                               e = sandbox_ObjectEdit_Get(true);
+                                               if(e != world)
+                                               {
+                                                       self.object_attach = e;
+                                                       print_to(self, "^2SANDBOX - INFO: ^7Object selected for attachment");
+                                                       return true;
+                                               }
+                                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be selected for attachment. Make sure you are facing an object that you have edit rights over");
+                                               return true;
+                                       case "set":
+                                               if(self.object_attach == world)
+                                               {
+                                                       print_to(self, "^1SANDBOX - WARNING: ^7No object selected for attachment. Please select an object to be attached first.");
+                                                       return true;
+                                               }
+
+                                               // attaches the previously selected object to e
+                                               e = sandbox_ObjectEdit_Get(true);
+                                               if(e != world)
+                                               {
+                                                       sandbox_ObjectAttach_Set(self.object_attach, e, argv(3));
+                                                       self.object_attach = world; // object was attached, no longer keep it scheduled for attachment
+                                                       print_to(self, "^2SANDBOX - INFO: ^7Object attached successfully");
+                                                       if(autocvar_g_sandbox_info > 1)
+                                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " attached objects at origin ^3", vtos(e.origin), "\n"));
+                                                       return true;
+                                               }
+                                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be attached to the parent. Make sure you are facing an object that you have edit rights over");
+                                               return true;
+                                       case "remove":
+                                               // removes e if it was attached
+                                               e = sandbox_ObjectEdit_Get(true);
+                                               if(e != world)
+                                               {
+                                                       sandbox_ObjectAttach_Remove(e);
+                                                       print_to(self, "^2SANDBOX - INFO: ^7Child objects detached successfully");
+                                                       if(autocvar_g_sandbox_info > 1)
+                                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " detached objects at origin ^3", vtos(e.origin), "\n"));
+                                                       return true;
+                                               }
+                                               print_to(self, "^1SANDBOX - WARNING: ^7Child objects could not be detached. Make sure you are facing an object that you have edit rights over");
+                                               return true;
+                               }
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, EDIT ----------------
+                       case "object_edit":
+                               if(argv(2) == "")
+                               {
+                                       print_to(self, "^1SANDBOX - WARNING: ^7Too few parameters. You must specify a property to edit");
+                                       return true;
+                               }
+
+                               e = sandbox_ObjectEdit_Get(true);
+                               if(e != world)
+                               {
+                                       switch(argv(2))
+                                       {
+                                               case "skin":
+                                                       e.skin = stof(argv(3));
+                                                       break;
+                                               case "alpha":
+                                                       e.alpha = stof(argv(3));
+                                                       break;
+                                               case "color_main":
+                                                       e.colormod = stov(argv(3));
+                                                       break;
+                                               case "color_glow":
+                                                       e.glowmod = stov(argv(3));
+                                                       break;
+                                               case "frame":
+                                                       e.frame = stof(argv(3));
+                                                       break;
+                                               case "scale":
+                                                       sandbox_ObjectEdit_Scale(e, stof(argv(3)));
+                                                       break;
+                                               case "solidity":
+                                                       switch(argv(3))
+                                                       {
+                                                               case "0": // non-solid
+                                                                       e.solid = SOLID_TRIGGER;
+                                                                       break;
+                                                               case "1": // solid
+                                                                       e.solid = SOLID_BBOX;
+                                                                       break;
+                                                               default:
+                                                                       break;
+                                                       }
+                                               case "physics":
+                                                       switch(argv(3))
+                                                       {
+                                                               case "0": // static
+                                                                       e.movetype = MOVETYPE_NONE;
+                                                                       break;
+                                                               case "1": // movable
+                                                                       e.movetype = MOVETYPE_TOSS;
+                                                                       break;
+                                                               case "2": // physical
+                                                                       e.movetype = MOVETYPE_PHYSICS;
+                                                                       break;
+                                                               default:
+                                                                       break;
+                                                       }
+                                                       break;
+                                               case "force":
+                                                       e.damageforcescale = stof(argv(3));
+                                                       break;
+                                               case "material":
+                                                       if(e.material)  strunzone(e.material);
+                                                       if(argv(3))
+                                                       {
+                                                               for (i = 1; i <= 5; i++) // precache material sounds, 5 in total
+                                                                       precache_sound(strcat("object/impact_", argv(3), "_", ftos(i), ".wav"));
+                                                               e.material = strzone(argv(3));
+                                                       }
+                                                       else
+                                                               e.material = string_null; // no material
+                                                       break;
+                                               default:
+                                                       print_to(self, "^1SANDBOX - WARNING: ^7Invalid object property. For usage information, type 'sandbox help'");
+                                                       return true;
+                                       }
+
+                                       // update last editing time
+                                       if(e.message2)  strunzone(e.message2);
+                                       e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S"));
+
+                                       if(autocvar_g_sandbox_info > 1)
+                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " edited property ^3", argv(2), " ^7of an object at origin ^3", vtos(e.origin), "\n"));
+                                       return true;
+                               }
+
+                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be edited. Make sure you are facing an object that you have edit rights over");
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, CLAIM ----------------
+                       case "object_claim":
+                               // if the player can edit an object but is not its owner, this can be used to claim that object
+                               if(self.crypto_idfp == "")
+                               {
+                                       print_to(self, "^1SANDBOX - WARNING: ^7You do not have a player UID, and cannot claim objects");
+                                       return true;
+                               }
+                               e = sandbox_ObjectEdit_Get(true);
+                               if(e != world)
+                               {
+                                       // update the owner's name
+                                       // Do this before checking if you're already the owner and skipping if such, so we
+                                       // also update the player's nickname if he changed it (but has the same player UID)
+                                       if(e.netname != self.netname)
+                                       {
+                                               if(e.netname)   strunzone(e.netname);
+                                               e.netname = strzone(self.netname);
+                                               print_to(self, "^2SANDBOX - INFO: ^7Object owner name updated");
+                                       }
+
+                                       if(e.crypto_idfp == self.crypto_idfp)
+                                       {
+                                               print_to(self, "^2SANDBOX - INFO: ^7Object is already yours, nothing to claim");
+                                               return true;
+                                       }
+
+                                       if(e.crypto_idfp)       strunzone(e.crypto_idfp);
+                                       e.crypto_idfp = strzone(self.crypto_idfp);
+
+                                       print_to(self, "^2SANDBOX - INFO: ^7Object claimed successfully");
+                               }
+                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be claimed. Make sure you are facing an object that you have edit rights over");
+                               return true;
+
+                       // ---------------- COMMAND: OBJECT, INFO ----------------
+                       case "object_info":
+                               // prints public information about the object to the player
+                               e = sandbox_ObjectEdit_Get(false);
+                               if(e != world)
+                               {
+                                       switch(argv(2))
+                                       {
+                                               case "object":
+                                                       print_to(self, strcat("^2SANDBOX - INFO: ^7Object is owned by \"^7", e.netname, "^7\", created \"^3", e.message, "^7\", last edited \"^3", e.message2, "^7\""));
+                                                       return true;
+                                               case "mesh":
+                                                       s = "";
+                                                       FOR_EACH_TAG(e)
+                                                               s = strcat(s, "^7\"^5", gettaginfo_name, "^7\", ");
+                                                       print_to(self, strcat("^2SANDBOX - INFO: ^7Object mesh is \"^3", e.model, "^7\" at animation frame ^3", ftos(e.frame), " ^7containing the following tags: ", s));
+                                                       return true;
+                                               case "attachments":
+                                                       // this should show the same info as 'mesh' but for attachments
+                                                       s = "";
+                                                       entity head;
+                                                       i = 0;
+                                                       for(head = world; (head = find(head, classname, "object")); )
+                                                       {
+                                                               if(head.owner == e)
+                                                               {
+                                                                       ++i; // start from 1
+                                                                       gettaginfo(e, head.tag_index);
+                                                                       s = strcat(s, "^1attachment ", ftos(i), "^7 has mesh \"^3", head.model, "^7\" at animation frame ^3", ftos(head.frame));
+                                                                       s = strcat(s, "^7 and is attached to bone \"^5", gettaginfo_name, "^7\", ");
+                                                               }
+                                                       }
+                                                       if(i) // object contains attachments
+                                                               print_to(self, strcat("^2SANDBOX - INFO: ^7Object contains the following ^1", ftos(i), "^7 attachment(s): ", s));
+                                                       else
+                                                               print_to(self, "^2SANDBOX - INFO: ^7Object contains no attachments");
+                                                       return true;
+                                       }
+                               }
+                               print_to(self, "^1SANDBOX - WARNING: ^7No information could be found. Make sure you are facing an object");
+                               return true;
+
+                       // ---------------- COMMAND: DEFAULT ----------------
+                       default:
+                               print_to(self, "Invalid command. For usage information, type 'sandbox help'");
+                               return true;
+               }
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(sandbox, SV_StartFrame)
+{
+       if(!autocvar_g_sandbox_storage_autosave)
+               return false;
+       if(time < autosave_time)
+               return false;
+       autosave_time = time + autocvar_g_sandbox_storage_autosave;
+
+       sandbox_Database_Save();
+
+       return true;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/spawn_near_teammate/module.inc b/qcsrc/common/mutators/mutator/spawn_near_teammate/module.inc
new file mode 100644 (file)
index 0000000..f88a768
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "spawn_near_teammate.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/spawn_near_teammate/spawn_near_teammate.qc b/qcsrc/common/mutators/mutator/spawn_near_teammate/spawn_near_teammate.qc
new file mode 100644 (file)
index 0000000..cd78b40
--- /dev/null
@@ -0,0 +1,175 @@
+#ifdef IMPLEMENTATION
+
+float autocvar_g_spawn_near_teammate_distance;
+int autocvar_g_spawn_near_teammate_ignore_spawnpoint;
+float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
+float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
+int autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
+bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath;
+
+REGISTER_MUTATOR(spawn_near_teammate, cvar("g_spawn_near_teammate") && teamplay);
+
+.entity msnt_lookat;
+
+.float msnt_timer;
+.vector msnt_deathloc;
+
+.float cvar_cl_spawn_near_teammate;
+
+MUTATOR_HOOKFUNCTION(spawn_near_teammate, Spawn_Score)
+{SELFPARAM();
+       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && self.cvar_cl_spawn_near_teammate))
+               return 0;
+
+       entity p;
+
+       spawn_spot.msnt_lookat = world;
+
+       if(!teamplay)
+               return 0;
+
+       RandomSelection_Init();
+       FOR_EACH_PLAYER(p) if(p != self) if(p.team == self.team) if(!p.deadflag)
+       {
+               float l = vlen(spawn_spot.origin - p.origin);
+               if(l > autocvar_g_spawn_near_teammate_distance)
+                       continue;
+               if(l < 48)
+                       continue;
+               if(!checkpvs(spawn_spot.origin, p))
+                       continue;
+               RandomSelection_Add(p, 0, string_null, 1, 1);
+       }
+
+       if(RandomSelection_chosen_ent)
+       {
+               spawn_spot.msnt_lookat = RandomSelection_chosen_ent;
+               spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_FOUND;
+       }
+       else if(self.team == spawn_spot.team)
+               spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM; // prefer same team, if we can't find a spawn near teammate
+
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
+{SELFPARAM();
+       // Note: when entering this, fixangle is already set.
+       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && self.cvar_cl_spawn_near_teammate))
+       {
+               if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death)
+                       self.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
+
+               entity team_mate, best_mate = world;
+               vector best_spot = '0 0 0';
+               float pc = 0, best_dist = 0, dist = 0;
+               FOR_EACH_PLAYER(team_mate)
+               {
+                       if((autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health >= 0 && team_mate.health >= autocvar_g_balance_health_regenstable) || autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health == 0)
+                       if(team_mate.deadflag == DEAD_NO)
+                       if(team_mate.msnt_timer < time)
+                       if(SAME_TEAM(self, team_mate))
+                       if(time > team_mate.spawnshieldtime) // spawn shielding
+                       if(team_mate.frozen == 0)
+                       if(team_mate != self)
+                       {
+                               tracebox(team_mate.origin, PL_MIN, PL_MAX, team_mate.origin - '0 0 100', MOVE_WORLDONLY, team_mate);
+                               if(trace_fraction != 1.0)
+                               if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
+                               {
+                                       pc = pointcontents(trace_endpos + '0 0 1');
+                                       if(pc == CONTENT_EMPTY)
+                                       {
+                                               if(vlen(team_mate.velocity) > 5)
+                                                       fixedmakevectors(vectoangles(team_mate.velocity));
+                                               else
+                                                       fixedmakevectors(team_mate.angles);
+
+                                               for(pc = 0; pc != 5; ++pc) // test 5 diffrent spots close to mate
+                                               {
+                                                       switch(pc)
+                                                       {
+                                                               case 0:
+                                                                       tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin + v_right * 128, MOVE_NORMAL, team_mate);
+                                                                       break;
+                                                               case 1:
+                                                                       tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_right * 128 , MOVE_NORMAL, team_mate);
+                                                                       break;
+                                                               case 2:
+                                                                       tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin + v_right * 64 - v_forward * 64, MOVE_NORMAL, team_mate);
+                                                                       break;
+                                                               case 3:
+                                                                       tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_right * 64 - v_forward * 64, MOVE_NORMAL, team_mate);
+                                                                       break;
+                                                               case 4:
+                                                                       tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_forward * 128, MOVE_NORMAL, team_mate);
+                                                                       break;
+                                                       }
+
+                                                       if(trace_fraction == 1.0)
+                                                       {
+                                                               traceline(trace_endpos + '0 0 4', trace_endpos - '0 0 100', MOVE_NORMAL, team_mate);
+                                                               if(trace_fraction != 1.0)
+                                                               {
+                                                                       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
+                                                                       {
+                                                                               dist = vlen(trace_endpos - self.msnt_deathloc);
+                                                                               if(dist < best_dist || best_dist == 0)
+                                                                               {
+                                                                                       best_dist = dist;
+                                                                                       best_spot = trace_endpos;
+                                                                                       best_mate = team_mate;
+                                                                               }
+                                                                       }
+                                                                       else
+                                                                       {
+                                                                               setorigin(self, trace_endpos);
+                                                                               self.angles = team_mate.angles;
+                                                                               self.angles_z = 0; // never spawn tilted even if the spot says to
+                                                                               team_mate.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
+                                                                               return 0;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
+               if(best_dist)
+               {
+                       setorigin(self, best_spot);
+                       self.angles = best_mate.angles;
+                       self.angles_z = 0; // never spawn tilted even if the spot says to
+                       best_mate.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
+               }
+       }
+       else if(spawn_spot.msnt_lookat)
+       {
+               self.angles = vectoangles(spawn_spot.msnt_lookat.origin - self.origin);
+               self.angles_x = -self.angles.x;
+               self.angles_z = 0; // never spawn tilted even if the spot says to
+               /*
+               sprint(self, "You should be looking at ", spawn_spot.msnt_lookat.netname, "^7.\n");
+               sprint(self, "distance: ", vtos(spawn_spot.msnt_lookat.origin - self.origin), "\n");
+               sprint(self, "angles: ", vtos(self.angles), "\n");
+               */
+       }
+
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerDies)
+{SELFPARAM();
+       self.msnt_deathloc = self.origin;
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(spawn_near_teammate, GetCvars)
+{
+       GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_spawn_near_teammate, "cl_spawn_near_teammate");
+       return false;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/superspec/module.inc b/qcsrc/common/mutators/mutator/superspec/module.inc
new file mode 100644 (file)
index 0000000..8e0a998
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "superspec.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/superspec/superspec.qc b/qcsrc/common/mutators/mutator/superspec/superspec.qc
new file mode 100644 (file)
index 0000000..887b184
--- /dev/null
@@ -0,0 +1,480 @@
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(superspec, cvar("g_superspectate"));
+
+#define _SSMAGIX "SUPERSPEC_OPTIONSFILE_V1"
+#define _ISLOCAL ((edict_num(1) == self) ? true : false)
+
+const float ASF_STRENGTH               = BIT(0);
+const float ASF_SHIELD                         = BIT(1);
+const float ASF_MEGA_AR                = BIT(2);
+const float ASF_MEGA_HP                = BIT(3);
+const float ASF_FLAG_GRAB              = BIT(4);
+const float ASF_OBSERVER_ONLY  = BIT(5);
+const float ASF_SHOWWHAT               = BIT(6);
+const float ASF_SSIM                   = BIT(7);
+const float ASF_FOLLOWKILLER   = BIT(8);
+const float ASF_ALL                    = 0xFFFFFF;
+.float autospec_flags;
+
+const float SSF_SILENT = 1;
+const float SSF_VERBOSE = 2;
+const float SSF_ITEMMSG = 4;
+.float superspec_flags;
+
+.string superspec_itemfilter; //"classname1 classname2 ..."
+
+bool superspec_Spectate(entity _player)
+{SELFPARAM();
+       if(Spectate(_player) == 1)
+               self.classname = STR_SPECTATOR;
+
+       return true;
+}
+
+void superspec_save_client_conf()
+{SELFPARAM();
+       string fn = "superspec-local.options";
+       float fh;
+
+       if (!_ISLOCAL)
+       {
+               if(self.crypto_idfp == "")
+                       return;
+
+               fn = sprintf("superspec-%s.options", uri_escape(self.crypto_idfp));
+       }
+
+       fh = fopen(fn, FILE_WRITE);
+       if(fh < 0)
+       {
+               LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for writing.\n");
+       }
+       else
+       {
+               fputs(fh, _SSMAGIX);
+               fputs(fh, "\n");
+               fputs(fh, ftos(self.autospec_flags));
+               fputs(fh, "\n");
+               fputs(fh, ftos(self.superspec_flags));
+               fputs(fh, "\n");
+               fputs(fh, self.superspec_itemfilter);
+               fputs(fh, "\n");
+               fclose(fh);
+       }
+}
+
+void superspec_msg(string _center_title, string _con_title, entity _to, string _msg, float _spamlevel)
+{
+       sprint(_to, strcat(_con_title, _msg));
+
+       if(_to.superspec_flags & SSF_SILENT)
+               return;
+
+       if(_spamlevel > 1)
+               if (!(_to.superspec_flags & SSF_VERBOSE))
+                       return;
+
+       centerprint(_to, strcat(_center_title, _msg));
+}
+
+float superspec_filteritem(entity _for, entity _item)
+{
+       float i;
+
+       if(_for.superspec_itemfilter == "")
+               return true;
+
+       if(_for.superspec_itemfilter == "")
+               return true;
+
+       float l = tokenize_console(_for.superspec_itemfilter);
+       for(i = 0; i < l; ++i)
+       {
+               if(argv(i) == _item.classname)
+                       return true;
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, ItemTouch)
+{SELFPARAM();
+       entity _item = self;
+
+       entity e;
+       FOR_EACH_CLIENT(e) if (IS_SPEC(e) || IS_OBSERVER(e))
+       {
+               setself(e);
+               if(self.superspec_flags & SSF_ITEMMSG)
+                       if(superspec_filteritem(self, _item))
+                       {
+                               if(self.superspec_flags & SSF_VERBOSE)
+                                       superspec_msg("", "", self, sprintf("Player %s^7 just picked up ^3%s\n", other.netname, _item.netname), 1);
+                               else
+                                       superspec_msg("", "", self, sprintf("Player %s^7 just picked up ^3%s\n^8(%s^8)\n", other.netname, _item.netname, _item.classname), 1);
+                               if((self.autospec_flags & ASF_SSIM) && self.enemy != other)
+                               {
+                                       superspec_Spectate(other);
+
+                                       setself(this);
+                                       return MUT_ITEMTOUCH_CONTINUE;
+                               }
+                       }
+
+               if((self.autospec_flags & ASF_SHIELD && _item.invincible_finished) ||
+                       (self.autospec_flags & ASF_STRENGTH && _item.strength_finished) ||
+                       (self.autospec_flags & ASF_MEGA_AR && _item.itemdef == ITEM_ArmorMega) ||
+                       (self.autospec_flags & ASF_MEGA_HP && _item.itemdef == ITEM_HealthMega) ||
+                       (self.autospec_flags & ASF_FLAG_GRAB && _item.classname == "item_flag_team"))
+               {
+
+                       if((self.enemy != other) || IS_OBSERVER(self))
+                       {
+                               if(self.autospec_flags & ASF_OBSERVER_ONLY && !IS_OBSERVER(self))
+                               {
+                                       if(self.superspec_flags & SSF_VERBOSE)
+                                               superspec_msg("", "", self, sprintf("^8Ignored that ^7%s^8 grabbed %s^8 since the observer_only option is ON\n", other.netname, _item.netname), 2);
+                               }
+                               else
+                               {
+                                       if(self.autospec_flags & ASF_SHOWWHAT)
+                                               superspec_msg("", "", self, sprintf("^7Following %s^7 due to picking up %s\n", other.netname, _item.netname), 2);
+
+                                       superspec_Spectate(other);
+                               }
+                       }
+               }
+       }
+
+       setself(this);
+
+       return MUT_ITEMTOUCH_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, SV_ParseClientCommand)
+{SELFPARAM();
+#define OPTIONINFO(flag,var,test,text,long,short) \
+    var = strcat(var, ((flag & test) ? "^2[ON]  ^7" : "^1[OFF] ^7")); \
+    var = strcat(var, text," ^7(^3 ", long, "^7 | ^3", short, " ^7)\n")
+
+       if(MUTATOR_RETURNVALUE) // command was already handled?
+               return false;
+
+       if(IS_PLAYER(self))
+               return false;
+
+       if(cmd_name == "superspec_itemfilter")
+       {
+               if(argv(1) == "help")
+               {
+                       string _aspeco;
+                       _aspeco = "^7 superspec_itemfilter ^3\"item_classname1 item_classname2\"^7 only show thise items when ^2superspec ^3item_message^7 is on\n";
+                       _aspeco = strcat(_aspeco, "^3 clear^7 Remove the filter (show all pickups)\n");
+                       _aspeco = strcat(_aspeco, "^3 show ^7 Display current filter\n");
+                       superspec_msg("^3superspec_itemfilter help:\n\n\n", "\n^3superspec_itemfilter help:\n", self, _aspeco, 1);
+               }
+               else if(argv(1) == "clear")
+               {
+                       if(self.superspec_itemfilter != "")
+                               strunzone(self.superspec_itemfilter);
+
+                       self.superspec_itemfilter = "";
+               }
+               else if(argv(1) == "show" || argv(1) == "")
+               {
+                       if(self.superspec_itemfilter == "")
+                       {
+                               superspec_msg("^3superspec_itemfilter^7 is ^1not^7 set", "\n^3superspec_itemfilter^7 is ^1not^7 set\n", self, "", 1);
+                               return true;
+                       }
+                       float i;
+                       float l = tokenize_console(self.superspec_itemfilter);
+                       string _msg = "";
+                       for(i = 0; i < l; ++i)
+                               _msg = strcat(_msg, "^3#", ftos(i), " ^7", argv(i), "\n");
+                               //_msg = sprintf("^3#%d^7 %s\n%s", i, _msg, argv(i));
+
+                       _msg = strcat(_msg,"\n");
+
+                       superspec_msg("^3superspec_itemfilter is:\n\n\n", "\n^3superspec_itemfilter is:\n", self, _msg, 1);
+               }
+               else
+               {
+                       if(self.superspec_itemfilter != "")
+                               strunzone(self.superspec_itemfilter);
+
+                       self.superspec_itemfilter = strzone(argv(1));
+               }
+
+               return true;
+       }
+
+       if(cmd_name == "superspec")
+       {
+               string _aspeco;
+
+               if(cmd_argc > 1)
+               {
+                       float i, _bits = 0, _start = 1;
+                       if(argv(1) == "help")
+                       {
+                               _aspeco = "use cmd superspec [option] [on|off] to set options\n\n";
+                               _aspeco = strcat(_aspeco, "^3 silent ^7(short^5 si^7) supresses ALL messages from superspectate.\n");
+                               _aspeco = strcat(_aspeco, "^3 verbose ^7(short^5 ve^7) makes superspectate print some additional information.\n");
+                               _aspeco = strcat(_aspeco, "^3 item_message ^7(short^5 im^7) makes superspectate print items that were picked up.\n");
+                               _aspeco = strcat(_aspeco, "^7    Use cmd superspec_itemfilter \"item_class1 item_class2\" to set up a filter of what to show with ^3item_message.\n");
+                               superspec_msg("^2Available Super Spectate ^3options:\n\n\n", "\n^2Available Super Spectate ^3options:\n", self, _aspeco, 1);
+                               return true;
+                       }
+
+                       if(argv(1) == "clear")
+                       {
+                               self.superspec_flags = 0;
+                               _start = 2;
+                       }
+
+                       for(i = _start; i < cmd_argc; ++i)
+                       {
+                               if(argv(i) == "on" || argv(i) == "1")
+                               {
+                                       self.superspec_flags |= _bits;
+                                       _bits = 0;
+                               }
+                               else if(argv(i) == "off" || argv(i) == "0")
+                               {
+                                       if(_start == 1)
+                                               self.superspec_flags &= ~_bits;
+
+                                       _bits = 0;
+                               }
+                               else
+                               {
+                                       if((argv(i) == "silent") || (argv(i) == "si")) _bits |= SSF_SILENT ;
+                                       if((argv(i) == "verbose") || (argv(i) == "ve")) _bits |= SSF_VERBOSE;
+                                       if((argv(i) == "item_message") || (argv(i) == "im")) _bits |= SSF_ITEMMSG;
+                               }
+                       }
+               }
+
+               _aspeco = "";
+               OPTIONINFO(self.superspec_flags, _aspeco, SSF_SILENT, "Silent", "silent", "si");
+               OPTIONINFO(self.superspec_flags, _aspeco, SSF_VERBOSE, "Verbose", "verbose", "ve");
+               OPTIONINFO(self.superspec_flags, _aspeco, SSF_ITEMMSG, "Item pickup messages", "item_message", "im");
+
+               superspec_msg("^3Current Super Spectate options are:\n\n\n\n\n", "\n^3Current Super Spectate options are:\n", self, _aspeco, 1);
+
+               return true;
+       }
+
+/////////////////////
+
+       if(cmd_name == "autospec")
+       {
+               string _aspeco;
+               if(cmd_argc > 1)
+               {
+                       if(argv(1) == "help")
+                       {
+                               _aspeco = "use cmd autospec [option] [on|off] to set options\n\n";
+                               _aspeco = strcat(_aspeco, "^3 strength ^7(short^5 st^7) for automatic spectate on strength powerup\n");
+                               _aspeco = strcat(_aspeco, "^3 shield ^7(short^5 sh^7) for automatic spectate on shield powerup\n");
+                               _aspeco = strcat(_aspeco, "^3 mega_health ^7(short^5 mh^7) for automatic spectate on mega health\n");
+                               _aspeco = strcat(_aspeco, "^3 mega_armor ^7(short^5 ma^7) for automatic spectate on mega armor\n");
+                               _aspeco = strcat(_aspeco, "^3 flag_grab ^7(short^5 fg^7) for automatic spectate on CTF flag grab\n");
+                               _aspeco = strcat(_aspeco, "^3 observer_only ^7(short^5 oo^7) for automatic spectate only if in observer mode\n");
+                               _aspeco = strcat(_aspeco, "^3 show_what ^7(short^5 sw^7) to display what event triggered autospectate\n");
+                               _aspeco = strcat(_aspeco, "^3 item_msg ^7(short^5 im^7) to autospec when item_message in superspectate is triggered\n");
+                               _aspeco = strcat(_aspeco, "^3 followkiller ^7(short ^5fk^7) to autospec the killer/off\n");
+                               _aspeco = strcat(_aspeco, "^3 all ^7(short ^5aa^7) to turn everything on/off\n");
+                               superspec_msg("^2Available Auto Spectate ^3options:\n\n\n", "\n^2Available Auto Spectate ^3options:\n", self, _aspeco, 1);
+                               return true;
+                       }
+
+                       float i, _bits = 0, _start = 1;
+                       if(argv(1) == "clear")
+                       {
+                               self.autospec_flags = 0;
+                               _start = 2;
+                       }
+
+                       for(i = _start; i < cmd_argc; ++i)
+                       {
+                               if(argv(i) == "on" || argv(i) == "1")
+                               {
+                                       self.autospec_flags |= _bits;
+                                       _bits = 0;
+                               }
+                               else if(argv(i) == "off" || argv(i) == "0")
+                               {
+                                       if(_start == 1)
+                                               self.autospec_flags &= ~_bits;
+
+                                       _bits = 0;
+                               }
+                               else
+                               {
+                                       if((argv(i) == "strength") || (argv(i) == "st")) _bits |= ASF_STRENGTH;
+                                       if((argv(i) == "shield") || (argv(i) == "sh")) _bits |= ASF_SHIELD;
+                                       if((argv(i) == "mega_health") || (argv(i) == "mh")) _bits |= ASF_MEGA_HP;
+                                       if((argv(i) == "mega_armor") || (argv(i) == "ma")) _bits |= ASF_MEGA_AR;
+                                       if((argv(i) == "flag_grab") || (argv(i) == "fg")) _bits |= ASF_FLAG_GRAB;
+                                       if((argv(i) == "observer_only") || (argv(i) == "oo")) _bits |= ASF_OBSERVER_ONLY;
+                                       if((argv(i) == "show_what") || (argv(i) == "sw")) _bits |= ASF_SHOWWHAT;
+                                       if((argv(i) == "item_msg") || (argv(i) == "im")) _bits |= ASF_SSIM;
+                                       if((argv(i) == "followkiller") || (argv(i) == "fk")) _bits |= ASF_FOLLOWKILLER;
+                                       if((argv(i) == "all") || (argv(i) == "aa")) _bits |= ASF_ALL;
+                               }
+                       }
+               }
+
+               _aspeco = "";
+               OPTIONINFO(self.autospec_flags, _aspeco, ASF_STRENGTH, "Strength", "strength", "st");
+               OPTIONINFO(self.autospec_flags, _aspeco, ASF_SHIELD, "Shield", "shield", "sh");
+               OPTIONINFO(self.autospec_flags, _aspeco, ASF_MEGA_HP, "Mega Health", "mega_health", "mh");
+               OPTIONINFO(self.autospec_flags, _aspeco, ASF_MEGA_AR, "Mega Armor", "mega_armor", "ma");
+               OPTIONINFO(self.autospec_flags, _aspeco, ASF_FLAG_GRAB, "Flag grab", "flag_grab","fg");
+               OPTIONINFO(self.autospec_flags, _aspeco, ASF_OBSERVER_ONLY, "Only switch if observer", "observer_only", "oo");
+               OPTIONINFO(self.autospec_flags, _aspeco, ASF_SHOWWHAT, "Show what item triggered spectate", "show_what", "sw");
+               OPTIONINFO(self.autospec_flags, _aspeco, ASF_SSIM, "Switch on superspec item message", "item_msg", "im");
+               OPTIONINFO(self.autospec_flags, _aspeco, ASF_FOLLOWKILLER, "Followkiller", "followkiller", "fk");
+
+               superspec_msg("^3Current auto spectate options are:\n\n\n\n\n", "\n^3Current auto spectate options are:\n", self, _aspeco, 1);
+               return true;
+       }
+
+       if(cmd_name == "followpowerup")
+       {
+               entity _player;
+               FOR_EACH_PLAYER(_player)
+               {
+                       if(_player.strength_finished > time || _player.invincible_finished > time)
+                               return superspec_Spectate(_player);
+               }
+
+               superspec_msg("", "", self, "No active powerup\n", 1);
+               return true;
+       }
+
+       if(cmd_name == "followstrength")
+       {
+               entity _player;
+               FOR_EACH_PLAYER(_player)
+               {
+                       if(_player.strength_finished > time)
+                               return superspec_Spectate(_player);
+               }
+
+               superspec_msg("", "", self, "No active Strength\n", 1);
+               return true;
+       }
+
+       if(cmd_name == "followshield")
+       {
+               entity _player;
+               FOR_EACH_PLAYER(_player)
+               {
+                       if(_player.invincible_finished > time)
+                               return superspec_Spectate(_player);
+               }
+
+               superspec_msg("", "", self, "No active Shield\n", 1);
+               return true;
+       }
+
+       return false;
+#undef OPTIONINFO
+}
+
+MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":SS");
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Super Spectators");
+       return 0;
+}
+
+void superspec_hello()
+{SELFPARAM();
+       if(self.enemy.crypto_idfp == "")
+               Send_Notification(NOTIF_ONE_ONLY, self.enemy, MSG_INFO, INFO_SUPERSPEC_MISSING_UID);
+
+       remove(self);
+}
+
+MUTATOR_HOOKFUNCTION(superspec, ClientConnect)
+{SELFPARAM();
+       if(!IS_REAL_CLIENT(self))
+               return false;
+
+       string fn = "superspec-local.options";
+       float fh;
+
+       self.superspec_flags = SSF_VERBOSE;
+       self.superspec_itemfilter = "";
+
+       entity _hello = spawn();
+       _hello.enemy = self;
+       _hello.think = superspec_hello;
+       _hello.nextthink = time + 5;
+
+       if (!_ISLOCAL)
+       {
+               if(self.crypto_idfp == "")
+                       return false;
+
+               fn = sprintf("superspec-%s.options", uri_escape(self.crypto_idfp));
+       }
+
+       fh = fopen(fn, FILE_READ);
+       if(fh < 0)
+       {
+               LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for reading.\n");
+       }
+       else
+       {
+               string _magic = fgets(fh);
+               if(_magic != _SSMAGIX)
+               {
+                       LOG_TRACE("^1ERROR^7 While reading superspec options file: unknown magic\n");
+               }
+               else
+               {
+                       self.autospec_flags = stof(fgets(fh));
+                       self.superspec_flags = stof(fgets(fh));
+                       self.superspec_itemfilter = strzone(fgets(fh));
+               }
+               fclose(fh);
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, PlayerDies)
+{SELFPARAM();
+       entity e;
+       FOR_EACH_SPEC(e)
+       {
+               setself(e);
+               if(self.autospec_flags & ASF_FOLLOWKILLER && IS_PLAYER(frag_attacker) && self.enemy == this)
+               {
+                       if(self.autospec_flags & ASF_SHOWWHAT)
+                               superspec_msg("", "", self, sprintf("^7Following %s^7 due to followkiller\n", frag_attacker.netname), 2);
+
+                       superspec_Spectate(frag_attacker);
+               }
+       }
+
+       setself(this);
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(superspec, ClientDisconnect)
+{
+       superspec_save_client_conf();
+       return false;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/touchexplode/module.inc b/qcsrc/common/mutators/mutator/touchexplode/module.inc
new file mode 100644 (file)
index 0000000..d3b0ea5
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "touchexplode.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/touchexplode/touchexplode.qc b/qcsrc/common/mutators/mutator/touchexplode/touchexplode.qc
new file mode 100644 (file)
index 0000000..ec43948
--- /dev/null
@@ -0,0 +1,48 @@
+#ifdef IMPLEMENTATION
+float autocvar_g_touchexplode_radius;
+float autocvar_g_touchexplode_damage;
+float autocvar_g_touchexplode_edgedamage;
+float autocvar_g_touchexplode_force;
+
+REGISTER_MUTATOR(touchexplode, cvar("g_touchexplode"));
+
+.float touchexplode_time;
+
+void PlayerTouchExplode(entity p1, entity p2)
+{SELFPARAM();
+       vector org = (p1.origin + p2.origin) * 0.5;
+       org.z += (p1.mins.z + p2.mins.z) * 0.5;
+
+       sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
+       Send_Effect(EFFECT_EXPLOSION_SMALL, org, '0 0 0', 1);
+
+       entity e = spawn();
+       setorigin(e, org);
+       RadiusDamage(e, world, autocvar_g_touchexplode_damage, autocvar_g_touchexplode_edgedamage, autocvar_g_touchexplode_radius, world, world, autocvar_g_touchexplode_force, DEATH_TOUCHEXPLODE.m_id, world);
+       remove(e);
+}
+
+MUTATOR_HOOKFUNCTION(touchexplode, PlayerPreThink)
+{SELFPARAM();
+       if(time > self.touchexplode_time)
+       if(!gameover)
+       if(!self.frozen)
+       if(IS_PLAYER(self))
+       if(self.deadflag == DEAD_NO)
+       if (!IS_INDEPENDENT_PLAYER(self))
+       FOR_EACH_PLAYER(other) if(self != other)
+       {
+               if(time > other.touchexplode_time)
+               if(!other.frozen)
+               if(other.deadflag == DEAD_NO)
+               if (!IS_INDEPENDENT_PLAYER(other))
+               if(boxesoverlap(self.absmin, self.absmax, other.absmin, other.absmax))
+               {
+                       PlayerTouchExplode(self, other);
+                       self.touchexplode_time = other.touchexplode_time = time + 0.2;
+               }
+       }
+
+       return false;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/vampire/module.inc b/qcsrc/common/mutators/mutator/vampire/module.inc
new file mode 100644 (file)
index 0000000..864ea28
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "vampire.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/vampire/vampire.qc b/qcsrc/common/mutators/mutator/vampire/vampire.qc
new file mode 100644 (file)
index 0000000..315da7d
--- /dev/null
@@ -0,0 +1,28 @@
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(vampire, cvar("g_vampire") && !cvar("g_instagib"));
+
+MUTATOR_HOOKFUNCTION(vampire, PlayerDamage_SplitHealthArmor)
+{
+       if(time >= frag_target.spawnshieldtime)
+       if(frag_target != frag_attacker)
+       if(frag_target.deadflag == DEAD_NO)
+       {
+               frag_attacker.health += bound(0, damage_take, frag_target.health);
+               frag_attacker.health = bound(0, frag_attacker.health, autocvar_g_balance_health_limit);
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsString)
+{
+       ret_string = strcat(ret_string, ":Vampire");
+       return 0;
+}
+
+MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsPrettyString)
+{
+       ret_string = strcat(ret_string, ", Vampire");
+       return 0;
+}
+#endif
diff --git a/qcsrc/common/mutators/mutator/vampirehook/module.inc b/qcsrc/common/mutators/mutator/vampirehook/module.inc
new file mode 100644 (file)
index 0000000..17ecf60
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "vampirehook.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/vampirehook/vampirehook.qc b/qcsrc/common/mutators/mutator/vampirehook/vampirehook.qc
new file mode 100644 (file)
index 0000000..f669f6a
--- /dev/null
@@ -0,0 +1,38 @@
+#ifdef IMPLEMENTATION
+REGISTER_MUTATOR(vh, cvar("g_vampirehook"));
+
+bool autocvar_g_vampirehook_teamheal;
+float autocvar_g_vampirehook_damage;
+float autocvar_g_vampirehook_damagerate;
+float autocvar_g_vampirehook_health_steal;
+
+.float last_dmg;
+
+MUTATOR_HOOKFUNCTION(vh, GrappleHookThink)
+{SELFPARAM();
+       entity dmgent = ((SAME_TEAM(self.owner, self.aiment) && autocvar_g_vampirehook_teamheal) ? self.owner : self.aiment);
+
+       if(IS_PLAYER(self.aiment))
+       if(self.last_dmg < time)
+       if(!self.aiment.frozen)
+       if(time >= game_starttime)
+       if(DIFF_TEAM(self.owner, self.aiment) || autocvar_g_vampirehook_teamheal)
+       if(self.aiment.health > 0)
+       if(autocvar_g_vampirehook_damage)
+       {
+               self.last_dmg = time + autocvar_g_vampirehook_damagerate;
+               self.owner.damage_dealt += autocvar_g_vampirehook_damage;
+               Damage(dmgent, self, self.owner, autocvar_g_vampirehook_damage, WEP_HOOK.m_id, self.origin, '0 0 0');
+               if(SAME_TEAM(self.owner, self.aiment))
+                       self.aiment.health = min(self.aiment.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
+               else
+                       self.owner.health = min(self.owner.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
+
+               if(dmgent == self.owner)
+                       dmgent.health -= autocvar_g_vampirehook_damage; // FIXME: friendly fire?!
+       }
+
+       return false;
+}
+
+#endif
index 47fafe7ed5490169352a47e918ec4ea7f781b0a6..c74715ea714f6c2b92652a369a9e59a6d8de0973 100644 (file)
@@ -54,8 +54,6 @@ REGISTER_WAYPOINT(OnsCPAttack, _("Control point"), '1 0.5 0', 2);
 REGISTER_WAYPOINT(OnsGen, _("Generator"), '1 0.5 0', 1);
 REGISTER_WAYPOINT(OnsGenShielded, _("Generator"), '1 0.5 0', 1);
 
-REGISTER_WAYPOINT(Buff, _("Buff"), '1 0.5 0', 1);
-
 REGISTER_WAYPOINT(Weapon, _("Weapon"), '0 0 0', 1);
 
 REGISTER_WAYPOINT(Monster, _("Monster"), '1 0 0', 1);
index f7fd03837d46449f3d28df90dbe615aeade36813..9693d2809050cb5ff88b7d0072981795dfccb18c 100644 (file)
@@ -3,10 +3,13 @@
 
 #include "waypointsprites.qh"
 
-REGISTRY(Waypoints, BIT(6))
-REGISTER_REGISTRY(RegisterWaypoints)
+REGISTRY(Waypoints, BITS(6))
+#define Waypoints_from(i) _Waypoints_from(i, WP_Null)
+REGISTER_REGISTRY(Waypoints)
+REGISTRY_CHECK(Waypoints)
+
 /** If you register a new waypoint, make sure to add it to all.inc */
-#define REGISTER_WAYPOINT_(id, init) REGISTER(RegisterWaypoints, WP, Waypoints, id, m_id, init)
+#define REGISTER_WAYPOINT_(id, init) REGISTER(Waypoints, WP, id, m_id, init)
 
 CLASS(Waypoint, Object)
     ATTRIB(Waypoint, m_id, int, 0)
@@ -26,9 +29,12 @@ ENDCLASS(Waypoint)
 #define REGISTER_WAYPOINT(id, text, color, blink) REGISTER_WAYPOINT_(id, NEW(Waypoint, #id, text, color, blink))
 
 REGISTRY(RadarIcons, BITS(7))
-REGISTER_REGISTRY(RegisterRadarIcons)
+#define RadarIcons_from(i) _RadarIcons_from(i, RADARICON_NONE)
+REGISTER_REGISTRY(RadarIcons)
+REGISTRY_CHECK(RadarIcons)
+
 .int m_radaricon;
-#define REGISTER_RADARICON(id, num) REGISTER(RegisterRadarIcons, RADARICON, RadarIcons, id, m_id, new(RadarIcon)) { this.m_radaricon = num; this.netname = #id; }
+#define REGISTER_RADARICON(id, num) REGISTER(RadarIcons, RADARICON, id, m_id, new(RadarIcon)) { make_pure(this); this.m_radaricon = num; this.netname = #id; }
 
 REGISTER_WAYPOINT(Null, "", '0 0 0', 1);
 
@@ -48,7 +54,6 @@ REGISTER_RADARICON(OBJECTIVE,       1);
 REGISTER_RADARICON(DOMPOINT,        1);
 REGISTER_RADARICON(TAGGED,          1);
 
-REGISTER_RADARICON(Buff,            1);
 REGISTER_RADARICON(Item,            1);
 REGISTER_RADARICON(Vehicle,         1);
 REGISTER_RADARICON(Weapon,          1);
diff --git a/qcsrc/common/mutators/mutator/waypoints/module.inc b/qcsrc/common/mutators/mutator/waypoints/module.inc
new file mode 100644 (file)
index 0000000..50bb5b4
--- /dev/null
@@ -0,0 +1 @@
+#include "waypointsprites.qc"
index f0b768c5741986aca921eb5a77be1ee83e73947c..a11feab9eceac5b1947e22290cd6177cc8df5c17 100644 (file)
@@ -4,11 +4,13 @@
 
 REGISTER_MUTATOR(waypointsprites, true);
 
+REGISTER_NET_LINKED(waypointsprites)
+
 #ifdef SVQC
 /** flags origin [team displayrule] [spritename] [spritename2] [spritename3] [lifetime maxdistance hideable] */
 bool WaypointSprite_SendEntity(entity this, entity to, float sendflags)
 {
-    WriteMutator(MSG_ENTITY, waypointsprites);
+    WriteHeader(MSG_ENTITY, waypointsprites);
 
     sendflags = sendflags & 0x7F;
 
@@ -97,9 +99,7 @@ bool WaypointSprite_SendEntity(entity this, entity to, float sendflags)
 
 #ifdef CSQC
 void Ent_WaypointSprite();
-MUTATOR_HOOKFUNCTION(waypointsprites, CSQC_Ent_Update) {
-    if (MUTATOR_RETURNVALUE) return false;
-    if (!ReadMutatorEquals(mutator_argv_int_0, waypointsprites)) return false;
+NET_HANDLE(waypointsprites, bool isnew) {
     Ent_WaypointSprite();
     return true;
 }
@@ -224,7 +224,7 @@ float spritelookupblinkvalue(string s)
         if (get_weaponinfo(self.wp_extra).spawnflags & WEP_FLAG_SUPERWEAPON)
             return 2;
     }
-    if (s == WP_Item.netname) return Items[self.wp_extra].m_waypointblink;
+    if (s == WP_Item.netname) return Items_from(self.wp_extra).m_waypointblink;
 
     return 1;
 }
@@ -232,18 +232,24 @@ float spritelookupblinkvalue(string s)
 vector spritelookupcolor(entity this, string s, vector def)
 {
     if (s == WP_Weapon.netname  || s == RADARICON_Weapon.netname) return get_weaponinfo(this.wp_extra).wpcolor;
-    if (s == WP_Item.netname    || s == RADARICON_Item.netname) return Items[this.wp_extra].m_color;
-    if (s == WP_Buff.netname    || s == RADARICON_Buff.netname) return Buffs[this.wp_extra].m_color;
+    if (s == WP_Item.netname    || s == RADARICON_Item.netname) return Items_from(this.wp_extra).m_color;
+    if (MUTATOR_CALLHOOK(WP_Format, this, s))
+    {
+        return MUTATOR_ARGV(0, vector);
+    }
     return def;
 }
 
 string spritelookuptext(string s)
 {SELFPARAM();
     if (s == WP_RaceStartFinish.netname) return (race_checkpointtime || race_mycheckpointtime) ? _("Finish") : _("Start");
-    if (s == WP_Weapon.netname) return get_weaponinfo(self.wp_extra).message;
-    if (s == WP_Item.netname) return Items[self.wp_extra].m_waypoint;
-    if (s == WP_Buff.netname) return Buffs[self.wp_extra].m_prettyName;
+    if (s == WP_Weapon.netname) return get_weaponinfo(self.wp_extra).m_name;
+    if (s == WP_Item.netname) return Items_from(self.wp_extra).m_waypoint;
     if (s == WP_Monster.netname) return get_monsterinfo(self.wp_extra).monster_name;
+    if (MUTATOR_CALLHOOK(WP_Format, this, s))
+    {
+        return MUTATOR_ARGV(0, string);
+    }
 
     // need to loop, as our netname could be one of three
     FOREACH(Waypoints, it.netname == s, LAMBDA(
@@ -371,11 +377,13 @@ vector drawspritetext(vector o, float ang, float minwidth, vector rgb, float a,
     if (fabs(sa) > fabs(ca))
     {
         algnx = (sa < 0);
-        algny = 0.5 - 0.5 * ca / fabs(sa);
+        float f = fabs(sa);
+        algny = 0.5 - 0.5 * (f ? (ca / f) : 0);
     }
     else
     {
-        algnx = 0.5 - 0.5 * sa / fabs(ca);
+        float f = fabs(ca);
+        algnx = 0.5 - 0.5 * (f ? (sa / f) : 0);
         algny = (ca < 0);
     }
 
@@ -993,6 +1001,7 @@ entity WaypointSprite_Spawn(
 )
 {
     entity wp = new(sprite_waypoint);
+    make_pure(wp);
     wp.teleport_time = time + _lifetime;
     wp.fade_time = _lifetime;
     wp.exteriormodeltoclient = ref;
diff --git a/qcsrc/common/mutators/mutator/weaponarena_random/module.inc b/qcsrc/common/mutators/mutator/weaponarena_random/module.inc
new file mode 100644 (file)
index 0000000..b7a5f66
--- /dev/null
@@ -0,0 +1,3 @@
+#ifdef SVQC
+#include "weaponarena_random.qc"
+#endif
diff --git a/qcsrc/common/mutators/mutator/weaponarena_random/weaponarena_random.qc b/qcsrc/common/mutators/mutator/weaponarena_random/weaponarena_random.qc
new file mode 100644 (file)
index 0000000..5c82100
--- /dev/null
@@ -0,0 +1,13 @@
+#ifdef IMPLEMENTATION
+// WEAPONTODO: rename the cvars
+REGISTER_MUTATOR(weaponarena_random, true);
+
+MUTATOR_HOOKFUNCTION(weaponarena_random, PlayerSpawn) {
+    SELFPARAM();
+    if (!g_weaponarena_random) return;
+    if (g_weaponarena_random_with_blaster) this.weapons &= ~WEPSET(BLASTER);
+    W_RandomWeapons(this, g_weaponarena_random);
+    if (g_weaponarena_random_with_blaster) this.weapons |= WEPSET(BLASTER);
+}
+
+#endif
diff --git a/qcsrc/common/nades/all.inc b/qcsrc/common/nades/all.inc
deleted file mode 100644 (file)
index 90326ed..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#define NADE_PROJECTILE(i, projectile, trail) do { \
-    this.m_projectile[i] = projectile; \
-    this.m_trail[i] = trail; \
-} while (0)
-
-REGISTER_NADE(NORMAL) {
-    this.m_color = '1 1 1';
-    NADE_PROJECTILE(0, PROJECTILE_NADE, EFFECT_Null);
-    NADE_PROJECTILE(1, PROJECTILE_NADE_BURN, EFFECT_Null);
-}
-
-REGISTER_NADE(NAPALM) {
-    this.m_color = '2 0.5 0';
-    this.m_name = _("Napalm grenade");
-    this.m_icon = "nade_napalm";
-    NADE_PROJECTILE(0, PROJECTILE_NADE_NAPALM, EFFECT_TR_ROCKET);
-    NADE_PROJECTILE(1, PROJECTILE_NADE_NAPALM_BURN, EFFECT_SPIDERBOT_ROCKET_TRAIL);
-}
-
-REGISTER_NADE(ICE) {
-    this.m_color = '0 0.5 2';
-    this.m_name = _("Ice grenade");
-    this.m_icon = "nade_ice";
-    NADE_PROJECTILE(0, PROJECTILE_NADE_ICE, EFFECT_TR_NEXUIZPLASMA);
-    NADE_PROJECTILE(1, PROJECTILE_NADE_ICE_BURN, EFFECT_RACER_ROCKET_TRAIL);
-}
-
-REGISTER_NADE(TRANSLOCATE) {
-    this.m_color = '1 0 1';
-    this.m_name = _("Translocate grenade");
-    this.m_icon = "nade_translocate";
-    NADE_PROJECTILE(0, PROJECTILE_NADE_TRANSLOCATE, EFFECT_TR_CRYLINKPLASMA);
-    NADE_PROJECTILE(1, PROJECTILE_NADE_TRANSLOCATE, EFFECT_TR_CRYLINKPLASMA);
-}
-
-REGISTER_NADE(SPAWN) {
-    this.m_color = '1 0.9 0';
-    this.m_name = _("Spawn grenade");
-    this.m_icon = "nade_spawn";
-    NADE_PROJECTILE(0, PROJECTILE_NADE_SPAWN, EFFECT_NADE_TRAIL_YELLOW);
-    NADE_PROJECTILE(1, PROJECTILE_NADE_SPAWN, EFFECT_NADE_TRAIL_YELLOW);
-}
-
-REGISTER_NADE(HEAL) {
-    this.m_color = '1 0 0';
-    this.m_name = _("Heal grenade");
-    this.m_icon = "nade_heal";
-    NADE_PROJECTILE(0, PROJECTILE_NADE_HEAL, EFFECT_NADE_TRAIL_RED);
-    NADE_PROJECTILE(1, PROJECTILE_NADE_HEAL_BURN, EFFECT_NADE_TRAIL_BURN_RED);
-}
-
-REGISTER_NADE(MONSTER) {
-    this.m_color = '0.25 0.75 0';
-    this.m_name = _("Monster grenade");
-    this.m_icon = "nade_monster";
-    NADE_PROJECTILE(0, PROJECTILE_NADE_MONSTER, EFFECT_NADE_TRAIL_RED);
-    NADE_PROJECTILE(1, PROJECTILE_NADE_MONSTER_BURN, EFFECT_NADE_TRAIL_BURN_RED);
-}
diff --git a/qcsrc/common/nades/all.qc b/qcsrc/common/nades/all.qc
deleted file mode 100644 (file)
index 30ad178..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#if defined(CSQC)
-       #include "../../client/defs.qh"
-       #include "all.qh"
-       #include "../buffs/all.qh"
-       #include "../movetypes/movetypes.qh"
-       #include "../../client/main.qh"
-       #include "../../lib/csqcmodel/cl_model.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include "../constants.qh"
-    #include "../../server/constants.qh"
-       #include "../turrets/sv_turrets.qh"
-#endif
-
-
-#ifdef CSQC
-.float ltime;
-void healer_draw(entity this)
-{
-       float dt = time - self.move_time;
-       self.move_time = time;
-       if(dt <= 0)
-               return;
-
-       self.alpha = (self.ltime - time) / self.healer_lifetime;
-       self.scale = min((1 - self.alpha)*self.healer_lifetime*4,1)*self.healer_radius;
-}
-
-void healer_setup(entity e)
-{
-       setmodel(e, MDL_NADE_HEAL);
-
-       setorigin(e, e.origin);
-
-       float model_radius = e.maxs.x;
-       vector size = '1 1 1' * e.healer_radius / 2;
-       setsize(e,-size,size);
-       e.healer_radius = e.healer_radius/model_radius*0.6;
-
-       e.draw = healer_draw;
-       e.health = 255;
-       e.movetype = MOVETYPE_NONE;
-       e.solid = SOLID_NOT;
-       e.drawmask = MASK_NORMAL;
-       e.scale = 0.01;
-       e.avelocity = e.move_avelocity = '7 0 11';
-       e.colormod = '1 0 0';
-       e.renderflags |= RF_ADDITIVE;
-}
-#endif // CSQC
-
-REGISTER_NET_LINKED(Nade_Heal, bool isNew)
-#ifdef CSQC
-{
-       Net_Accept();
-       int sf = ReadByte();
-       if (sf & 1) {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
-               setorigin(this, this.origin);
-               this.healer_lifetime = ReadByte();
-               this.healer_radius = ReadShort();
-               this.ltime = time + ReadByte()/10.0;
-               // this.ltime = time + this.healer_lifetime;
-               healer_setup(this);
-       }
-}
-#endif
-
-#ifdef SVQC
-bool healer_send(entity this, entity to, int sf)
-{
-       int channel = MSG_ENTITY;
-       WriteHeader(channel, Nade_Heal);
-       WriteByte(channel, sf);
-       if (sf & 1) {
-               WriteCoord(channel, this.origin.x);
-               WriteCoord(channel, this.origin.y);
-               WriteCoord(channel, this.origin.z);
-
-               WriteByte(channel, this.healer_lifetime);
-               //WriteByte(MSG_ENTITY, this.ltime - time + 1);
-               WriteShort(channel, this.healer_radius);
-               // round time delta to a 1/10th of a second
-               WriteByte(channel, (this.ltime - time)*10.0+0.5);
-       }
-       return true;
-}
-#endif // SVQC
diff --git a/qcsrc/common/nades/all.qh b/qcsrc/common/nades/all.qh
deleted file mode 100644 (file)
index ad51a1e..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef NADES_ALL_H
-#define NADES_ALL_H
-
-#include "../teams.qh"
-
-.float healer_lifetime;
-.float healer_radius;
-
-// use slots 70-100
-const int PROJECTILE_NADE = 71;
-const int PROJECTILE_NADE_BURN = 72;
-const int PROJECTILE_NADE_NAPALM = 73;
-const int PROJECTILE_NADE_NAPALM_BURN = 74;
-const int PROJECTILE_NAPALM_FOUNTAIN = 75;
-const int PROJECTILE_NADE_ICE = 76;
-const int PROJECTILE_NADE_ICE_BURN = 77;
-const int PROJECTILE_NADE_TRANSLOCATE = 78;
-const int PROJECTILE_NADE_SPAWN = 79;
-const int PROJECTILE_NADE_HEAL = 80;
-const int PROJECTILE_NADE_HEAL_BURN = 81;
-const int PROJECTILE_NADE_MONSTER = 82;
-const int PROJECTILE_NADE_MONSTER_BURN = 83;
-
-REGISTRY(Nades, BIT(3))
-REGISTER_REGISTRY(RegisterNades)
-#define REGISTER_NADE(id) REGISTER(RegisterNades, NADE_TYPE, Nades, id, m_id, NEW(Nade))
-
-CLASS(Nade, Object)
-    ATTRIB(Nade, m_id, int, 0)
-    ATTRIB(Nade, m_color, vector, '0 0 0')
-    ATTRIB(Nade, m_name, string, _("Grenade"))
-    ATTRIB(Nade, m_icon, string, "nade_normal")
-    ATTRIBARRAY(Nade, m_projectile, int, 2)
-    ATTRIBARRAY(Nade, m_trail, entity, 2)
-    METHOD(Nade, display, void(entity this, void(string name, string icon) returns)) {
-        returns(this.m_name, sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.m_icon));
-    }
-ENDCLASS(Nade)
-
-REGISTER_NADE(Null);
-
-#ifdef SVQC
-bool healer_send(entity this, entity to, int sf);
-#endif
-
-entity Nade_FromProjectile(float proj)
-{
-    FOREACH(Nades, true, LAMBDA(
-        for (int j = 0; j < 2; j++)
-        {
-            if (it.m_projectile[j] == proj) return it;
-        }
-    ));
-    return NADE_TYPE_Null;
-}
-
-entity Nade_TrailEffect(int proj, int nade_team)
-{
-    switch (proj)
-    {
-        case PROJECTILE_NADE:       return EFFECT_NADE_TRAIL(nade_team);
-        case PROJECTILE_NADE_BURN:  return EFFECT_NADE_TRAIL_BURN(nade_team);
-    }
-
-    FOREACH(Nades, true, LAMBDA(
-        for (int j = 0; j < 2; j++)
-        {
-            if (it.m_projectile[j] == proj)
-            {
-                string trail = it.m_trail[j].eent_eff_name;
-                if (trail) return it.m_trail[j];
-                break;
-            }
-        }
-    ));
-
-    return EFFECT_Null;
-}
-
-#include "all.inc"
-
-#endif
index f748f9903825ad96ec0073a99af653e533717278..63e318d2f7c03d4d4b3e9f7b043615993b3126c0 100644 (file)
@@ -1,5 +1,7 @@
 #include "net_notice.qh"
 
+REGISTER_NET_TEMP(TE_CSQC_SVNOTICE)
+
 #ifdef SVQC
 void sv_notice_join_think()
 {SELFPARAM();
@@ -29,8 +31,7 @@ void sv_notice_join()
 void sv_notice_to(entity _to, string _notice, float _howlong, float _modal)
 {
        msg_entity = _to;
-       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-       WriteByte(MSG_ONE, TE_CSQC_SVNOTICE);
+       WriteHeader(MSG_ONE, TE_CSQC_SVNOTICE);
        WriteString(MSG_ONE, _notice);
        WriteLong(MSG_ONE, _howlong);
        WriteByte(MSG_ONE, _modal);
@@ -47,13 +48,16 @@ void sv_notice_toall(string _notice, float _howlong, float _modal)
 #endif // SVQC
 
 #ifdef CSQC
+NET_HANDLE(TE_CSQC_SVNOTICE, bool isNew)
+{
+       cl_notice_read();
+       return true;
+}
 void cl_notice_read()
 {
-    entity _notice;
     //float _done;
     //float _modal;
-    _notice = spawn();
-    _notice.classname = "sv_notice";
+    entity _notice = new(sv_notice);
     _notice.netname = strzone(ReadString());
     _notice.alpha = ReadLong() + time;
     _notice.skin = ReadByte();
@@ -68,8 +72,8 @@ float cl_notice_run()
     _notes = findchain(classname, "sv_notice");
     if(!_notes)
         return false;
-    #define M1 30
-    #define M2 10
+    const int M1 = 30;
+    const int M2 = 10;
 
     vector v1, v2 = '0 0 0', v3;
     v1 = '1 1 0' * M1;
@@ -107,8 +111,6 @@ float cl_notice_run()
     }
 
     #undef OUT
-    #undef M1
-    #undef M2
 
     return m;
 }
index 811e7007c63e21b69548a607de73d3918698efa2..94a46d94aed1774daf01790a11414ca9509b329e 100644 (file)
@@ -1,4 +1,5 @@
 #if defined(CSQC)
+       #include "../client/announcer.qh"
 #elif defined(MENUQC)
 #elif defined(SVQC)
     #include "constants.qh"
@@ -233,7 +234,7 @@ void Destroy_Notification_Entity(entity notif)
        remove(notif);
 }
 
-void Destroy_All_Notifications(void)
+void Destroy_All_Notifications()
 {
        entity notif;
        int i;
@@ -523,6 +524,7 @@ void Create_Notification_Entity(
        //  Global Entity Setup
        // =====================
        entity notif = spawn();
+       make_pure(notif);
        switch(typeId)
        {
                case MSG_ANNCE:
@@ -595,7 +597,7 @@ void Create_Notification_Entity(
                                {
                                        if(notif.nent_enabled)
                                        {
-                                               precache_sound(sprintf("announcer/%s/%s.wav", autocvar_cl_announcer, snd));
+                                               precache_sound(sprintf("announcer/%s/%s.wav", AnnouncerOption(), snd));
                                                notif.nent_channel = channel;
                                                notif.nent_snd = strzone(snd);
                                                notif.nent_vol = vol;
@@ -941,7 +943,7 @@ void Create_Notification_Entity(
 
 // used by MSG_CHOICE to build list of choices
 #ifdef SVQC
-void Notification_GetCvars(void)
+void Notification_GetCvars()
 {
        for(int i = 0; i <= NOTIF_CHOICE_COUNT; ++i)
        {
@@ -1276,7 +1278,7 @@ void Local_Notification_sound(
                        soundchannel,
                        sprintf(
                                "announcer/%s/%s.wav",
-                               autocvar_cl_announcer,
+                               AnnouncerOption(),
                                soundfile
                        ),
                        soundvolume,
@@ -1289,7 +1291,7 @@ void Local_Notification_sound(
                        soundchannel,
                        sprintf(
                                "announcer/%s/%s.wav",
-                               autocvar_cl_announcer,
+                               AnnouncerOption(),
                                soundfile
                        ),
                        soundvolume,
@@ -1311,7 +1313,7 @@ void Local_Notification_sound(
                        soundchannel,
                        sprintf(
                                "announcer/%s/%s.wav",
-                               autocvar_cl_announcer,
+                               AnnouncerOption(),
                                soundfile
                        ),
                        soundvolume,
@@ -1677,11 +1679,14 @@ void Local_Notification_WOVA(
 //  Notification Networking
 // =========================
 
+REGISTER_NET_LINKED(ENT_CLIENT_NOTIFICATION)
+
 #ifdef CSQC
-void Read_Notification(float is_new)
+NET_HANDLE(ENT_CLIENT_NOTIFICATION, bool is_new)
 {
        int net_type = ReadByte();
        int net_name = ReadShort();
+       return = true;
 
        entity notif;
 
@@ -1775,7 +1780,7 @@ bool Net_Write_Notification(entity this, entity client, int sf)
 {
        if(Notification_ShouldSend(self.nent_broadcast, client, self.nent_client))
        {
-               WriteByte(MSG_ENTITY, ENT_CLIENT_NOTIFICATION);
+               WriteHeader(MSG_ENTITY, ENT_CLIENT_NOTIFICATION);
                WriteByte(MSG_ENTITY, self.nent_net_type);
                WriteShort(MSG_ENTITY, self.nent_net_name);
                for(int i = 0; i < self.nent_stringcount; ++i) { WriteString(MSG_ENTITY, self.nent_strings[i]); }
@@ -1841,8 +1846,8 @@ void Kill_Notification(
 
        if(killed_cpid != NO_CPID)
        {
-               net_notif = spawn();
-               net_notif.classname = "net_kill_notification";
+               net_notif = new(net_kill_notification);
+               make_pure(net_notif);
                net_notif.nent_broadcast = broadcast;
                net_notif.nent_client = client;
                net_notif.nent_net_type = MSG_CENTER_CPID;
@@ -2092,9 +2097,9 @@ void Send_Notification(
        }
        else
        {
-               entity net_notif = spawn();
+               entity net_notif = new(net_notification);
+               make_pure(net_notif);
                net_notif.owner = notif;
-               net_notif.classname = "net_notification";
                net_notif.nent_broadcast = broadcast;
                net_notif.nent_client = client;
                net_notif.nent_net_type = net_type;
index 6c6aa0f8248ea959c06bd97e970e69e574dfee4a..f3cd0ba494ea482f77b60441f0d7219cc365a815 100644 (file)
@@ -50,7 +50,7 @@ const int NOTIF_ABORT = -1234;   // allows Send_Notification to safely abort sen
     VARITEM(3, 4, XPD(s1, s2, s3, f1, f2, f3, f4)) \
     VARITEM(4, 4, XPD(s1, s2, s3, s4, f1, f2, f3, f4))
 
-void Destroy_All_Notifications(void);
+void Destroy_All_Notifications();
 void Create_Notification_Entity(
     float var_default,
     float var_cvar,
@@ -148,7 +148,6 @@ void Local_Notification_WOVA(
     float f1, float f2, float f3, float f4);
 
 #ifdef CSQC // CLIENT ONLY
-void Read_Notification(float is_new);
 string prev_soundfile;
 float prev_soundtime;
 #endif
@@ -203,7 +202,7 @@ float autocvar_notification_debug = false;
 
 #ifdef SVQC
 .float FRAG_VERBOSE;
-void Notification_GetCvars(void);
+void Notification_GetCvars();
 float autocvar_notification_server_allows_location = 1; // 0 = no, 1 = yes
 #else
 float autocvar_notification_item_centerprinttime = 1.5;
@@ -285,6 +284,8 @@ const float ARG_DC = 6; // unique result to durcnt/centerprint
 // todo possible idea.... declare how many floats/strings each arg needs, and then dynamically increment the input
 // this way, we don't need to have duplicates like i.e. s2loc and s3loc?
 
+string BUFF_NAME(int i);
+
 #define NOTIF_ARGUMENT_LIST \
     ARG_CASE(ARG_CS_SV_HA,  "s1",            s1) \
     ARG_CASE(ARG_CS_SV_HA,  "s2",            s2) \
@@ -318,8 +319,8 @@ const float ARG_DC = 6; // unique result to durcnt/centerprint
     ARG_CASE(ARG_CS_SV,     "spree_end",     (autocvar_notification_show_sprees ? notif_arg_spree_inf(-1, "", "", f1) : "")) \
     ARG_CASE(ARG_CS_SV,     "spree_lost",    (autocvar_notification_show_sprees ? notif_arg_spree_inf(-2, "", "", f1) : "")) \
     ARG_CASE(ARG_CS_SV,     "item_wepname",  WEP_NAME(f1)) \
-    ARG_CASE(ARG_CS_SV,     "item_buffname", sprintf("%s%s", rgb_to_hexcolor(Buffs[f1].m_color), Buffs[f1].m_prettyName)) \
-    ARG_CASE(ARG_CS_SV,     "f3buffname",    sprintf("%s%s", rgb_to_hexcolor(Buffs[f3].m_color), Buffs[f3].m_prettyName)) \
+    ARG_CASE(ARG_CS_SV,     "item_buffname", BUFF_NAME(f1)) \
+    ARG_CASE(ARG_CS_SV,     "f3buffname",    BUFF_NAME(f3)) \
     ARG_CASE(ARG_CS_SV,     "item_wepammo",  (s1 != "" ? sprintf(_(" with %s"), s1) : "")) \
     ARG_CASE(ARG_DC,        "item_centime",  ftos(autocvar_notification_item_centerprinttime)) \
     ARG_CASE(ARG_SV,        "death_team",    Team_ColoredFullName(f1)) \
@@ -574,11 +575,11 @@ float NOTIF_MULTI_COUNT;
 float NOTIF_CHOICE_COUNT;
 
 // notification limits -- INCREASE AS NECESSARY
-const float NOTIF_ANNCE_MAX   = 100;
-const float NOTIF_INFO_MAX    = 350;
-const float NOTIF_CENTER_MAX  = 250;
-const float NOTIF_MULTI_MAX   = 200;
-const float NOTIF_CHOICE_MAX  = 30;
+const float NOTIF_ANNCE_MAX   = 400;
+const float NOTIF_INFO_MAX    = 450;
+const float NOTIF_CENTER_MAX  = 350;
+const float NOTIF_MULTI_MAX   = 300;
+const float NOTIF_CHOICE_MAX  = 50;
 
 // notification entities
 entity msg_annce_notifs[NOTIF_ANNCE_MAX];
index b3954d2eefd8cead759f5cde23e747fc8b463a64..a49f79df833d9d1652cae099adada98937d134a7 100644 (file)
@@ -535,7 +535,7 @@ When you press the jump key
 returns true if handled
 =============
 */
-bool PlayerJump (void)
+bool PlayerJump ()
 {SELFPARAM();
        if (PHYS_FROZEN(self))
                return true; // no jumping in freezetag when frozen
@@ -1012,7 +1012,7 @@ float PM_check_specialcommand(float buttons)
        return false;
 }
 
-void PM_check_nickspam(void)
+void PM_check_nickspam()
 {SELFPARAM();
 #ifdef SVQC
        if (time >= self.nickspamtime)
@@ -1057,7 +1057,7 @@ void PM_check_punch()
 #endif
 }
 
-void PM_check_spider(void)
+void PM_check_spider()
 {SELFPARAM();
 #ifdef SVQC
        if (time >= self.spider_slowness)
@@ -1070,7 +1070,7 @@ void PM_check_spider(void)
 }
 
 // predict frozen movement, as frozen players CAN move in some cases
-void PM_check_frozen(void)
+void PM_check_frozen()
 {SELFPARAM();
        if (!PHYS_FROZEN(self))
                return;
@@ -1115,16 +1115,16 @@ void PM_check_hitground()
                        if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS))
                        {
                                if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)
-                                       GlobalSound(globalsound_metalfall, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+                                       GlobalSound(GS_FALL_METAL, CH_PLAYER, VOICETYPE_PLAYERSOUND);
                                else
-                                       GlobalSound(globalsound_fall, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+                                       GlobalSound(GS_FALL, CH_PLAYER, VOICETYPE_PLAYERSOUND);
                        }
                }
        }
 #endif
 }
 
-void PM_check_blocked(void)
+void PM_check_blocked()
 {SELFPARAM();
 #ifdef SVQC
        if (!self.player_blocked)
@@ -1134,7 +1134,7 @@ void PM_check_blocked(void)
 #endif
 }
 
-void PM_check_vortex(void)
+void PM_check_vortex()
 {SELFPARAM();
 #ifdef SVQC
        // WEAPONTODO
@@ -1819,7 +1819,7 @@ void PM_Main()
                RaceCarPhysics();
 #endif
 
-       else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_FLY_WORLDONLY || (BUFFS_STAT(self) & BUFF_FLIGHT.m_itemid))
+       else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_FLY_WORLDONLY || MUTATOR_CALLHOOK(IsFlying, self))
                PM_fly(maxspeed_mod);
 
        else if (self.waterlevel >= WATERLEVEL_SWIMMING)
@@ -1858,9 +1858,9 @@ void PM_Main()
 }
 
 #ifdef SVQC
-void SV_PlayerPhysics(void)
+void SV_PlayerPhysics()
 #elif defined(CSQC)
-void CSQC_ClientMovement_PlayerMove_Frame(void)
+void CSQC_ClientMovement_PlayerMove_Frame()
 #endif
 {SELFPARAM();
        PM_Main();
index d1f82991cd3308f4e5f45c70043e3f2ad076b0a9..5ee8954d0c1bd9cbdeb8232f0aef5692672d7b7d 100644 (file)
@@ -33,6 +33,7 @@ bool IsFlying(entity a);
        void PM_multijump();
 
        .float watertype;
+       .float waterlevel;
        .int items;
 
        .vector movement;
index 0fcbd4259ad82071ad8f198724116ea5d7bcb4f4..7584e3353c081c50fe7768682f81ec871d5e08d5 100644 (file)
@@ -11,7 +11,7 @@
 #endif
 
 #ifdef SVQC
-void PlayerStats_Prematch(void)
+void PlayerStats_Prematch()
 {
        //foobar
 }
@@ -635,7 +635,7 @@ void PlayerStats_PlayerDetail_AddItem(string event, string data)
        LOG_TRACE("Added item ", sprintf("#%s", event), "=", data, " to PS_D_IN_DB\n");
 }
 
-void PlayerStats_PlayerDetail(void)
+void PlayerStats_PlayerDetail()
 {
        // http://stats.xonotic.org/player/me
        if((autocvar_g_playerstats_playerdetail_uri != "") && (crypto_getmyidstatus(0) > 0))
@@ -668,7 +668,7 @@ void PlayerStats_PlayerDetail(void)
        }
 }
 
-void PlayerStats_PlayerDetail_CheckUpdate(void)
+void PlayerStats_PlayerDetail_CheckUpdate()
 {
        // determine whether we should retrieve playerdetail information again
        float gamecount = cvar("cl_matchcount");
index e77cdbff594f42c874f836d57d47ee537bcb370c..ec309c4f4c191fc9d46500e57ff8de3d0571e2ab 100644 (file)
@@ -112,8 +112,8 @@ const float PS_D_STATUS_RECEIVED = 1;
 float PlayerStats_PlayerDetail_Status = PS_D_STATUS_IDLE;
 string autocvar_g_playerstats_playerdetail_uri = "http://stats.xonotic.org/player/me";
 float autocvar_g_playerstats_playerdetail_autoupdatetime = 1800; // automatically update every 30 minutes anyway
-void PlayerStats_PlayerDetail(void);
-void PlayerStats_PlayerDetail_CheckUpdate(void);
+void PlayerStats_PlayerDetail();
+void PlayerStats_PlayerDetail_CheckUpdate();
 void PlayerStats_PlayerDetail_Handler(entity fh, entity p, float status);
 #endif
 #endif
index 8a7dbbca37fafc2c155ba5b0fb2d40a3bc7b7456..69a95be0cce22074d75686a5aaf52c90c017ad80 100644 (file)
@@ -36,7 +36,7 @@ SOUND(GRENADE_BOUNCE4, W_Sound("grenade_bounce4"));
 SOUND(GRENADE_BOUNCE5, W_Sound("grenade_bounce5"));
 SOUND(GRENADE_BOUNCE6, W_Sound("grenade_bounce6"));
 Sound SND_GRENADE_BOUNCE_RANDOM() {
-    return Sounds[SND_GRENADE_BOUNCE1.m_id + rint(random() * 5)];
+    return Sounds_from(SND_GRENADE_BOUNCE1.m_id + rint(random() * 5));
 }
 SOUND(GRENADE_FIRE, W_Sound("grenade_fire"));
 SOUND(GRENADE_IMPACT, W_Sound("grenade_impact"));
@@ -48,7 +48,7 @@ SOUND(HAGEXP1, W_Sound("hagexp1"));
 SOUND(HAGEXP2, W_Sound("hagexp2"));
 SOUND(HAGEXP3, W_Sound("hagexp3"));
 Sound SND_HAGEXP_RANDOM() {
-    return Sounds[SND_HAGEXP1.m_id + rint(random() * 2)];
+    return Sounds_from(SND_HAGEXP1.m_id + rint(random() * 2));
 }
 
 SOUND(HOOKBOMB_FIRE, W_Sound("hookbomb_fire"));
@@ -71,7 +71,7 @@ SOUND(NEXWHOOSH1, W_Sound("nexwhoosh1"));
 SOUND(NEXWHOOSH2, W_Sound("nexwhoosh2"));
 SOUND(NEXWHOOSH3, W_Sound("nexwhoosh3"));
 Sound SND_NEXWHOOSH_RANDOM() {
-    return Sounds[SND_NEXWHOOSH1.m_id + rint(random() * 2)];
+    return Sounds_from(SND_NEXWHOOSH1.m_id + rint(random() * 2));
 }
 SOUND(RELOAD, W_Sound("reload")); // until weapons have individual reload sounds, precache the reload sound here
 
@@ -79,7 +79,7 @@ SOUND(RIC1, W_Sound("ric1"));
 SOUND(RIC2, W_Sound("ric2"));
 SOUND(RIC3, W_Sound("ric3"));
 Sound SND_RIC_RANDOM() {
-    return Sounds[SND_RIC1.m_id + rint(random() * 2)];
+    return Sounds_from(SND_RIC1.m_id + rint(random() * 2));
 }
 
 SOUND(ROCKET_DET, W_Sound("rocket_det"));
@@ -106,11 +106,11 @@ SOUND(WEAPONPICKUP, W_Sound("weaponpickup"));
 SOUND(WEAPONPICKUP_NEW_TOYS, W_Sound("weaponpickup_new_toys"));
 SOUND(WEAPON_SWITCH, W_Sound("weapon_switch"));
 
-SOUND(CTF_CAPTURE_NEUTRAL, "ctf/capture.ogg");
-SOUND(CTF_CAPTURE_RED, "ctf/red_capture.wav");
-SOUND(CTF_CAPTURE_BLUE, "ctf/blue_capture.wav");
-SOUND(CTF_CAPTURE_YELLOW, "ctf/yellow_capture.ogg");
-SOUND(CTF_CAPTURE_PINK, "ctf/pink_capture.ogg");
+SOUND(CTF_CAPTURE_NEUTRAL, "ctf/capture");
+SOUND(CTF_CAPTURE_RED, "ctf/red_capture");
+SOUND(CTF_CAPTURE_BLUE, "ctf/blue_capture");
+SOUND(CTF_CAPTURE_YELLOW, "ctf/yellow_capture");
+SOUND(CTF_CAPTURE_PINK, "ctf/pink_capture");
 Sound SND_CTF_CAPTURE(int teamid) {
     switch (teamid) {
         case NUM_TEAM_1:    return SND_CTF_CAPTURE_RED;
@@ -121,11 +121,11 @@ Sound SND_CTF_CAPTURE(int teamid) {
     }
 }
 
-SOUND(CTF_DROPPED_NEUTRAL,  "ctf/neutral_dropped.wav");
-SOUND(CTF_DROPPED_RED,      "ctf/red_dropped.wav");
-SOUND(CTF_DROPPED_BLUE,     "ctf/blue_dropped.wav");
-SOUND(CTF_DROPPED_YELLOW,   "ctf/yellow_dropped.wav");
-SOUND(CTF_DROPPED_PINK,     "ctf/pink_dropped.wav");
+SOUND(CTF_DROPPED_NEUTRAL,  "ctf/neutral_dropped");
+SOUND(CTF_DROPPED_RED,      "ctf/red_dropped");
+SOUND(CTF_DROPPED_BLUE,     "ctf/blue_dropped");
+SOUND(CTF_DROPPED_YELLOW,   "ctf/yellow_dropped");
+SOUND(CTF_DROPPED_PINK,     "ctf/pink_dropped");
 Sound SND_CTF_DROPPED(int teamid) {
     switch (teamid) {
         case NUM_TEAM_1:    return SND_CTF_DROPPED_RED;
@@ -136,14 +136,14 @@ Sound SND_CTF_DROPPED(int teamid) {
     }
 }
 
-SOUND(CTF_PASS, "ctf/pass.wav");
-SOUND(CTF_RESPAWN, "ctf/flag_respawn.wav");
+SOUND(CTF_PASS, "ctf/pass");
+SOUND(CTF_RESPAWN, "ctf/flag_respawn");
 
-SOUND(CTF_RETURNED_NEUTRAL,  "ctf/return.wav");
-SOUND(CTF_RETURNED_RED,      "ctf/red_returned.wav");
-SOUND(CTF_RETURNED_BLUE,     "ctf/blue_returned.wav");
-SOUND(CTF_RETURNED_YELLOW,   "ctf/yellow_returned.wav");
-SOUND(CTF_RETURNED_PINK,     "ctf/pink_returned.wav");
+SOUND(CTF_RETURNED_NEUTRAL,  "ctf/return");
+SOUND(CTF_RETURNED_RED,      "ctf/red_returned");
+SOUND(CTF_RETURNED_BLUE,     "ctf/blue_returned");
+SOUND(CTF_RETURNED_YELLOW,   "ctf/yellow_returned");
+SOUND(CTF_RETURNED_PINK,     "ctf/pink_returned");
 Sound SND_CTF_RETURNED(int teamid) {
     switch (teamid) {
         case NUM_TEAM_1:    return SND_CTF_RETURNED_RED;
@@ -154,11 +154,11 @@ Sound SND_CTF_RETURNED(int teamid) {
     }
 }
 
-SOUND(CTF_TAKEN_NEUTRAL,  "ctf/neutral_taken.wav");
-SOUND(CTF_TAKEN_RED,      "ctf/red_taken.wav");
-SOUND(CTF_TAKEN_BLUE,     "ctf/blue_taken.wav");
-SOUND(CTF_TAKEN_YELLOW,   "ctf/yellow_taken.wav");
-SOUND(CTF_TAKEN_PINK,     "ctf/pink_taken.wav");
+SOUND(CTF_TAKEN_NEUTRAL,  "ctf/neutral_taken");
+SOUND(CTF_TAKEN_RED,      "ctf/red_taken");
+SOUND(CTF_TAKEN_BLUE,     "ctf/blue_taken");
+SOUND(CTF_TAKEN_YELLOW,   "ctf/yellow_taken");
+SOUND(CTF_TAKEN_PINK,     "ctf/pink_taken");
 Sound SND_CTF_TAKEN(int teamid) {
     switch (teamid) {
         case NUM_TEAM_1:    return SND_CTF_TAKEN_RED;
@@ -169,109 +169,109 @@ Sound SND_CTF_TAKEN(int teamid) {
     }
 }
 
-SOUND(CTF_TOUCH, "ctf/touch.wav");
-
-SOUND(DOM_CLAIM, "domination/claim.wav");
-
-SOUND(KA_DROPPED, "keepaway/dropped.wav");
-SOUND(KA_PICKEDUP, "keepaway/pickedup.wav");
-SOUND(KA_RESPAWN, "keepaway/respawn.wav");
-SOUND(KA_TOUCH, "keepaway/touch.wav");
-
-SOUND(KH_ALARM, "kh/alarm.wav");
-SOUND(KH_CAPTURE, "kh/capture.wav");
-SOUND(KH_COLLECT, "kh/collect.wav");
-SOUND(KH_DESTROY, "kh/destroy.wav");
-SOUND(KH_DROP, "kh/drop.wav");
-
-SOUND(NB_BOUNCE, "nexball/bounce.ogg");
-SOUND(NB_DROP, "nexball/drop.ogg");
-SOUND(NB_SHOOT1, "nexball/shoot1.ogg");
-SOUND(NB_SHOOT2, "nexball/shoot2.ogg");
-SOUND(NB_STEAL, "nexball/steal.ogg");
-
-SOUND(ONS_CONTROLPOINT_BUILD, "onslaught/controlpoint_build.ogg");
-SOUND(ONS_CONTROLPOINT_BUILT, "onslaught/controlpoint_built.ogg");
-SOUND(ONS_CONTROLPOINT_UNDERATTACK, "onslaught/controlpoint_underattack.ogg");
-SOUND(ONS_DAMAGEBLOCKEDBYSHIELD, "onslaught/damageblockedbyshield.wav");
-SOUND(ONS_ELECTRICITY_EXPLODE, "onslaught/electricity_explode.ogg");
-SOUND(ONS_GENERATOR_DECAY, "onslaught/generator_decay.ogg");
-SOUND(ONS_GENERATOR_UNDERATTACK, "onslaught/generator_underattack.ogg");
-SOUND(ONS_HIT1, "onslaught/ons_hit1.ogg");
-SOUND(ONS_HIT2, "onslaught/ons_hit2.ogg");
-SOUND(ONS_SPARK1, "onslaught/ons_spark1.ogg");
-SOUND(ONS_SPARK2, "onslaught/ons_spark2.ogg");
-SOUND(ONS_SHOCKWAVE, "onslaught/shockwave.ogg");
-
-SOUND(PORTO_BOUNCE, "porto/bounce.ogg");
-SOUND(PORTO_CREATE, "porto/create.ogg");
-SOUND(PORTO_EXPIRE, "porto/expire.ogg");
-SOUND(PORTO_EXPLODE, "porto/explode.ogg");
-SOUND(PORTO_FIRE, "porto/fire.ogg");
-SOUND(PORTO_UNSUPPORTED, "porto/unsupported.ogg");
-
-SOUND(TUR_PHASER, "turrets/phaser.ogg");
-
-SOUND(VEH_ALARM, "vehicles/alarm.wav");
-SOUND(VEH_ALARM_SHIELD, "vehicles/alarm_shield.wav");
-SOUND(VEH_MISSILE_ALARM, "vehicles/missile_alarm.wav");
+SOUND(CTF_TOUCH, "ctf/touch");
+
+SOUND(DOM_CLAIM, "domination/claim");
+
+SOUND(KA_DROPPED, "keepaway/dropped");
+SOUND(KA_PICKEDUP, "keepaway/pickedup");
+SOUND(KA_RESPAWN, "keepaway/respawn");
+SOUND(KA_TOUCH, "keepaway/touch");
+
+SOUND(KH_ALARM, "kh/alarm");
+SOUND(KH_CAPTURE, "kh/capture");
+SOUND(KH_COLLECT, "kh/collect");
+SOUND(KH_DESTROY, "kh/destroy");
+SOUND(KH_DROP, "kh/drop");
+
+SOUND(NB_BOUNCE, "nexball/bounce");
+SOUND(NB_DROP, "nexball/drop");
+SOUND(NB_SHOOT1, "nexball/shoot1");
+SOUND(NB_SHOOT2, "nexball/shoot2");
+SOUND(NB_STEAL, "nexball/steal");
+
+SOUND(ONS_CONTROLPOINT_BUILD, "onslaught/controlpoint_build");
+SOUND(ONS_CONTROLPOINT_BUILT, "onslaught/controlpoint_built");
+SOUND(ONS_CONTROLPOINT_UNDERATTACK, "onslaught/controlpoint_underattack");
+SOUND(ONS_DAMAGEBLOCKEDBYSHIELD, "onslaught/damageblockedbyshield");
+SOUND(ONS_ELECTRICITY_EXPLODE, "onslaught/electricity_explode");
+SOUND(ONS_GENERATOR_DECAY, "onslaught/generator_decay");
+SOUND(ONS_GENERATOR_UNDERATTACK, "onslaught/generator_underattack");
+SOUND(ONS_HIT1, "onslaught/ons_hit1");
+SOUND(ONS_HIT2, "onslaught/ons_hit2");
+SOUND(ONS_SPARK1, "onslaught/ons_spark1");
+SOUND(ONS_SPARK2, "onslaught/ons_spark2");
+SOUND(ONS_SHOCKWAVE, "onslaught/shockwave");
+
+SOUND(PORTO_BOUNCE, "porto/bounce");
+SOUND(PORTO_CREATE, "porto/create");
+SOUND(PORTO_EXPIRE, "porto/expire");
+SOUND(PORTO_EXPLODE, "porto/explode");
+SOUND(PORTO_FIRE, "porto/fire");
+SOUND(PORTO_UNSUPPORTED, "porto/unsupported");
+
+SOUND(TUR_PHASER, "turrets/phaser");
+
+SOUND(VEH_ALARM, "vehicles/alarm");
+SOUND(VEH_ALARM_SHIELD, "vehicles/alarm_shield");
+SOUND(VEH_MISSILE_ALARM, "vehicles/missile_alarm");
 
 SOUND(VEH_BUMBLEBEE_FIRE, W_Sound("flacexp3"));
 
-SOUND(VEH_RACER_BOOST, "vehicles/racer_boost.wav");
-SOUND(VEH_RACER_IDLE, "vehicles/racer_idle.wav");
-SOUND(VEH_RACER_MOVE, "vehicles/racer_move.wav");
+SOUND(VEH_RACER_BOOST, "vehicles/racer_boost");
+SOUND(VEH_RACER_IDLE, "vehicles/racer_idle");
+SOUND(VEH_RACER_MOVE, "vehicles/racer_move");
 
-SOUND(VEH_RAPTOR_FLY, "vehicles/raptor_fly.wav");
-SOUND(VEH_RAPTOR_SPEED, "vehicles/raptor_speed.wav");
+SOUND(VEH_RAPTOR_FLY, "vehicles/raptor_fly");
+SOUND(VEH_RAPTOR_SPEED, "vehicles/raptor_speed");
 
-SOUND(VEH_SPIDERBOT_DIE, "vehicles/spiderbot_die.wav");
-SOUND(VEH_SPIDERBOT_IDLE, "vehicles/spiderbot_idle.wav");
-SOUND(VEH_SPIDERBOT_JUMP, "vehicles/spiderbot_jump.wav");
-SOUND(VEH_SPIDERBOT_LAND, "vehicles/spiderbot_land.wav");
-SOUND(VEH_SPIDERBOT_STRAFE, "vehicles/spiderbot_strafe.wav");
-SOUND(VEH_SPIDERBOT_WALK, "vehicles/spiderbot_walk.wav");
+SOUND(VEH_SPIDERBOT_DIE, "vehicles/spiderbot_die");
+SOUND(VEH_SPIDERBOT_IDLE, "vehicles/spiderbot_idle");
+SOUND(VEH_SPIDERBOT_JUMP, "vehicles/spiderbot_jump");
+SOUND(VEH_SPIDERBOT_LAND, "vehicles/spiderbot_land");
+SOUND(VEH_SPIDERBOT_STRAFE, "vehicles/spiderbot_strafe");
+SOUND(VEH_SPIDERBOT_WALK, "vehicles/spiderbot_walk");
 
-SOUND(NADE_BEEP, "overkill/grenadebip.ogg");
+SOUND(NADE_BEEP, "overkill/grenadebip");
 
-SOUND(BUFF_LOST, "relics/relic_effect.wav");
+SOUND(BUFF_LOST, "relics/relic_effect");
 
-SOUND(POWEROFF, "misc/poweroff.wav");
-SOUND(POWERUP, "misc/powerup.ogg");
-SOUND(SHIELD_RESPAWN, "misc/shield_respawn.wav");
-SOUND(STRENGTH_RESPAWN, "misc/strength_respawn.wav");
+SOUND(POWEROFF, "misc/poweroff");
+SOUND(POWERUP, "misc/powerup");
+SOUND(SHIELD_RESPAWN, "misc/shield_respawn");
+SOUND(STRENGTH_RESPAWN, "misc/strength_respawn");
 
-SOUND(ARMOR25, "misc/armor25.wav");
-SOUND(ARMORIMPACT, "misc/armorimpact.wav");
-SOUND(BODYIMPACT1, "misc/bodyimpact1.wav");
-SOUND(BODYIMPACT2, "misc/bodyimpact2.wav");
+SOUND(ARMOR25, "misc/armor25");
+SOUND(ARMORIMPACT, "misc/armorimpact");
+SOUND(BODYIMPACT1, "misc/bodyimpact1");
+SOUND(BODYIMPACT2, "misc/bodyimpact2");
 
-SOUND(ITEMPICKUP, "misc/itempickup.ogg");
-SOUND(ITEMRESPAWNCOUNTDOWN, "misc/itemrespawncountdown.ogg");
-SOUND(ITEMRESPAWN, "misc/itemrespawn.ogg");
-SOUND(MEGAHEALTH, "misc/megahealth.ogg");
+SOUND(ITEMPICKUP, "misc/itempickup");
+SOUND(ITEMRESPAWNCOUNTDOWN, "misc/itemrespawncountdown");
+SOUND(ITEMRESPAWN, "misc/itemrespawn");
+SOUND(MEGAHEALTH, "misc/megahealth");
 
-SOUND(LAVA, "player/lava.wav");
-SOUND(SLIME, "player/slime.wav");
+SOUND(LAVA, "player/lava");
+SOUND(SLIME, "player/slime");
 
-SOUND(GIB, "misc/gib.wav");
-SOUND(GIB_SPLAT01, "misc/gib_splat01.wav");
-SOUND(GIB_SPLAT02, "misc/gib_splat02.wav");
-SOUND(GIB_SPLAT03, "misc/gib_splat03.wav");
-SOUND(GIB_SPLAT04, "misc/gib_splat04.wav");
+SOUND(GIB, "misc/gib");
+SOUND(GIB_SPLAT01, "misc/gib_splat01");
+SOUND(GIB_SPLAT02, "misc/gib_splat02");
+SOUND(GIB_SPLAT03, "misc/gib_splat03");
+SOUND(GIB_SPLAT04, "misc/gib_splat04");
 Sound SND_GIB_SPLAT_RANDOM() {
-    return Sounds[SND_GIB_SPLAT01.m_id + floor(prandom() * 4)];
+    return Sounds_from(SND_GIB_SPLAT01.m_id + floor(prandom() * 4));
 }
 
-SOUND(HIT, "misc/hit.wav");
-SOUND(TYPEHIT, "misc/typehit.wav");
+SOUND(HIT, "misc/hit");
+SOUND(TYPEHIT, "misc/typehit");
 
-SOUND(SPAWN, "misc/spawn.ogg");
+SOUND(SPAWN, "misc/spawn");
 
-SOUND(TALK, "misc/talk.wav");
+SOUND(TALK, "misc/talk");
 
-SOUND(TELEPORT, "misc/teleport.ogg");
+SOUND(TELEPORT, "misc/teleport");
 
-SOUND(INVSHOT, "misc/invshot.wav");
+SOUND(INVSHOT, "misc/invshot");
 
-SOUND(JETPACK_FLY, "misc/jetpack_fly.ogg");
+SOUND(JETPACK_FLY, "misc/jetpack_fly");
diff --git a/qcsrc/common/sounds/all.qc b/qcsrc/common/sounds/all.qc
new file mode 100644 (file)
index 0000000..92c5ef0
--- /dev/null
@@ -0,0 +1,144 @@
+#ifdef SVQC
+
+bool autocvar_bot_sound_monopoly;
+
+.entity realowner;
+bool sound_allowed(int to, entity e)
+{
+       for ( ; ; )
+       {
+               if (e.classname == "body") e = e.enemy;
+               else if (e.realowner && e.realowner != e) e = e.realowner;
+               else if (e.owner && e.owner != e) e = e.owner;
+               else break;
+       }
+       // sounds to self may always pass
+       if (to == MSG_ONE && e == msg_entity) return true;
+       // sounds by players can be removed
+       if (autocvar_bot_sound_monopoly && IS_REAL_CLIENT(e)) return false;
+       // anything else may pass
+       return true;
+}
+
+/** hack: string precache_sound(string s) = #19; */
+int precache_sound_index(string s) = #19;
+
+const int SVC_SOUND = 6;
+const int SVC_STOPSOUND = 16;
+
+const int SND_VOLUME = BIT(0);
+const int SND_ATTENUATION = BIT(1);
+const int SND_LARGEENTITY = BIT(3);
+const int SND_LARGESOUND = BIT(4);
+
+void soundtoat(int to, entity e, vector o, int chan, string samp, float vol, float attenu)
+{
+       if (!sound_allowed(to, e)) return;
+       int entno = etof(e);
+       int idx = precache_sound_index(samp);
+       attenu = floor(attenu * 64);
+       vol = floor(vol * 255);
+       int sflags = 0;
+       if (vol != 255) sflags |= SND_VOLUME;
+       if (attenu != 64) sflags |= SND_ATTENUATION;
+       if (entno >= 8192 || chan < 0 || chan > 7) sflags |= SND_LARGEENTITY;
+       if (idx >= 256) sflags |= SND_LARGESOUND;
+       WriteByte(to, SVC_SOUND);
+       WriteByte(to, sflags);
+       if (sflags & SND_VOLUME) WriteByte(to, vol);
+       if (sflags & SND_ATTENUATION) WriteByte(to, attenu);
+       if (sflags & SND_LARGEENTITY)
+       {
+               WriteShort(to, entno);
+               WriteByte(to, chan);
+       }
+       else
+       {
+               WriteShort(to, (entno << 3) | chan);
+       }
+       if (sflags & SND_LARGESOUND) WriteShort(to, idx);
+       else WriteByte(to, idx);
+       WriteCoord(to, o.x);
+       WriteCoord(to, o.y);
+       WriteCoord(to, o.z);
+}
+
+void soundto(int _dest, entity e, int chan, string samp, float vol, float _atten)
+{
+       if (!sound_allowed(_dest, e)) return;
+       vector o = e.origin + 0.5 * (e.mins + e.maxs);
+       soundtoat(_dest, e, o, chan, samp, vol, _atten);
+}
+void soundat(entity e, vector o, int chan, string samp, float vol, float _atten)
+{
+       soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, _atten);
+}
+void stopsoundto(int _dest, entity e, int chan)
+{
+       if (!sound_allowed(_dest, e)) return;
+       int entno = num_for_edict(e);
+       if (entno >= 8192 || chan < 0 || chan > 7)
+       {
+               int idx = precache_sound_index(SND(Null));
+               int sflags = SND_LARGEENTITY;
+               if (idx >= 256) sflags |= SND_LARGESOUND;
+               WriteByte(_dest, SVC_SOUND);
+               WriteByte(_dest, sflags);
+               WriteShort(_dest, entno);
+               WriteByte(_dest, chan);
+               if (sflags & SND_LARGESOUND) WriteShort(_dest, idx);
+               else WriteByte(_dest, idx);
+               WriteCoord(_dest, e.origin.x);
+               WriteCoord(_dest, e.origin.y);
+               WriteCoord(_dest, e.origin.z);
+       }
+       else
+       {
+               WriteByte(_dest, SVC_STOPSOUND);
+               WriteShort(_dest, entno * 8 + chan);
+       }
+}
+void stopsound(entity e, int chan)
+{
+       if (!sound_allowed(MSG_BROADCAST, e)) return;
+       stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
+       stopsoundto(MSG_ALL, e, chan);       // in case of packet loss
+}
+
+void play2(entity e, string filename)
+{
+       msg_entity = e;
+       soundtoat(MSG_ONE, world, '0 0 0', CH_INFO, filename, VOL_BASE, ATTEN_NONE);
+}
+
+.float spamtime;
+/** use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame) */
+float spamsound(entity e, int chan, string samp, float vol, float _atten)
+{
+       if (!sound_allowed(MSG_BROADCAST, e)) return false;
+       if (time > e.spamtime)
+       {
+               e.spamtime = time;
+               _sound(e, chan, samp, vol, _atten);
+               return true;
+       }
+       return false;
+}
+
+void play2team(float t, string filename)
+{
+       if (autocvar_bot_sound_monopoly) return;
+       entity head;
+       FOR_EACH_REALPLAYER(head)
+       {
+               if (head.team == t) play2(head, filename);
+       }
+}
+
+void play2all(string samp)
+{
+       if (autocvar_bot_sound_monopoly) return;
+       _sound(world, CH_INFO, samp, VOL_BASE, ATTEN_NONE);
+}
+
+#endif
index d39c701d7f0a2887295f557a01747bbb4c8bf18a..8225db7368c30f5593c2c1e435897b0123cbb8d5 100644 (file)
@@ -4,22 +4,23 @@
 #include "sound.qh"
 
 REGISTRY(Sounds, BITS(8))
-REGISTER_REGISTRY(RegisterSounds)
+#define Sounds_from(i) _Sounds_from(i, SND_Null)
+REGISTER_REGISTRY(Sounds)
 
 #define SOUND(name, path) \
     string SND_##name##_get() { return path; } \
-    REGISTER(RegisterSounds, SND, Sounds, name, m_id, NEW(Sound, SND_##name##_get))
+    REGISTER(Sounds, SND, name, m_id, NEW(Sound, SND_##name##_get))
 
 // Used in places where a string is required
-#define SND(id) (SND_##id.sound_str())
+#define SND(id) Sound_fixpath(SND_##id)
 
-STATIC_INIT(RegisterSounds_precache) {
+PRECACHE(Sounds) {
     FOREACH(Sounds, true, LAMBDA({
         it.sound_precache(it);
     }));
 }
 
-SOUND(Null, "misc/null.wav");
+SOUND(Null, "misc/null");
 #include "all.inc"
-
+#include "all.qc"
 #endif
index bc393dda3d218e67929daed1c3675db4cdd8ff39..36bdaa833085db167c5190b946d7a701e5592faa 100644 (file)
 #ifndef SOUND_H
 #define SOUND_H
 
+const int CH_INFO = 0;
+const int CH_TRIGGER = -3;
+const int CH_WEAPON_A = -1;
+const int CH_WEAPON_SINGLE = 1;
+const int CH_VOICE = -2;
+const int CH_BGM_SINGLE = 8;
+const int CH_AMBIENT = -9;
+const int CH_TRIGGER_SINGLE = 3;
+const int CH_SHOTS = -4;
+const int CH_SHOTS_SINGLE = 4;
+const int CH_WEAPON_B = -1;
+const int CH_PAIN = -6;
+const int CH_PAIN_SINGLE = 6;
+const int CH_PLAYER = -7;
+const int CH_PLAYER_SINGLE = 7;
+const int CH_TUBA_SINGLE = 5;
+
+const float ATTEN_NONE = 0;
+const float ATTEN_MIN = 0.015625;
+const float ATTEN_NORM = 0.5;
+const float ATTEN_LARGE = 1;
+const float ATTEN_IDLE = 2;
+const float ATTEN_STATIC = 3;
+const float ATTEN_MAX = 3.984375;
+
+const float VOL_BASE = 0.7;
+const float VOL_BASEVOICE = 1.0;
+
 // Play all sounds via sound7, for access to the extra channels.
 // Otherwise, channels 8 to 15 would be blocked for a weird QW feature.
 #ifdef SVQC
-    #define _sound(e, c, s, v, a) do { \
-        entity __e = e; \
-        if (!sound_allowed(MSG_BROADCAST, __e)) break; \
-        sound7(__e, c, s, v, a, 0, 0); \
-    } while (0)
+       #define _sound(e, c, s, v, a) \
+               do \
+               { \
+                       entity __e = e; \
+                       if (!sound_allowed(MSG_BROADCAST, __e)) break; \
+                       sound7(__e, c, s, v, a, 0, 0); \
+               } \
+               while (0)
 #else
-    #define _sound(e, c, s, v, a) sound7(e, c, s, v, a, 0, 0)
+       #define _sound(e, c, s, v, a) sound7(e, c, s, v, a, 0, 0)
 #endif
-#define sound(e, c, s, v, a) _sound(e, c, s.sound_str(), v, a)
+#define sound(e, c, s, v, a) _sound(e, c, Sound_fixpath(s), v, a)
+
+/**
+ * because sound7 didn't have origin
+ *
+ * @param e sound owner
+ * @param o sound origin
+ * @param chan sound channel
+ * @param samp sound filename
+ * @param vol sound volume
+ * @param atten sound attenuation
+ * @param speed
+ * @param sf
+ */
+#define sound8(e, o, chan, samp, vol, atten, speed, sf) \
+       do \
+       { \
+               entity __e = e; \
+               vector old_origin = __e.origin; \
+               vector old_mins = __e.mins; \
+               vector old_maxs = __e.maxs; \
+               setorigin(__e, o); \
+               setsize(__e, '0 0 0', '0 0 0'); \
+               sound7(__e, chan, samp, vol, atten, speed, sf); \
+               setorigin(__e, old_origin); \
+               setsize(__e, old_mins, old_maxs); \
+       } \
+       while (0)
 
 CLASS(Sound, Object)
-    ATTRIB(Sound, m_id, int, 0)
-    ATTRIB(Sound, sound_str, string(), func_null)
-    CONSTRUCTOR(Sound, string() path)
-    {
-        CONSTRUCT(Sound);
-        this.sound_str = path;
-    }
-    METHOD(Sound, sound_precache, void(entity this)) {
-        string s = this.sound_str();
-        if (s && s != "" && !fexists(strcat("sound/", s))) {
-            LOG_WARNINGF("Missing sound: \"%s\"\n", s);
-            return;
-        }
-        LOG_TRACEF("precache_sound(\"%s\")\n", s);
-        precache_sound(s);
-    }
+       ATTRIB(Sound, m_id, int, 0)
+       ATTRIB(Sound, sound_str, string(), func_null)
+       CONSTRUCTOR(Sound, string() path)
+       {
+               CONSTRUCT(Sound);
+               this.sound_str = path;
+       }
+       #define Sound_fixpath(this) _Sound_fixpath((this).sound_str())
+       string _Sound_fixpath(string base)
+       {
+               if (base == "") return string_null;
+               #define extensions(x) \
+                       x(wav) \
+                       x(ogg) \
+                       x(flac) \
+                       /**/
+               string full, relative;
+               #define tryext(ext) { if (fexists(full = strcat("sound/", relative = strcat(base, "." #ext)))) break; }
+               do
+               {
+                       extensions(tryext);
+#undef tryext
+#undef extensions
+                       LOG_WARNINGF("Missing sound: \"%s\"\n", full);
+                       return string_null;
+               }
+               while (0);
+               return relative;
+       }
+       METHOD(Sound, sound_precache, void(entity this))
+       {
+               string s = Sound_fixpath(this);
+               if (!s) return;
+               LOG_TRACEF("precache_sound(\"%s\")\n", s);
+               precache_sound(s);
+       }
 ENDCLASS(Sound)
 
 #endif
index 9bdcb5773a5e4bcff57fe8079b53542babfa2bef..cbf54fef2918cc9f694c08913afe1c7251303926 100644 (file)
@@ -52,225 +52,203 @@ const int STAT_VIEWZOOM               = 21;
 // 29 empty?
 // 30 empty?
 // 31 empty?
-const int STAT_KH_KEYS                = 32;
-const int STAT_CTF_STATE              = 33;
-// 34 empty?
-const int STAT_WEAPONS                = 35;
-const int STAT_SWITCHWEAPON           = 36;
-const int STAT_GAMESTARTTIME          = 37;
-const int STAT_STRENGTH_FINISHED      = 38;
-const int STAT_INVINCIBLE_FINISHED    = 39;
-// 40 empty?
-const int STAT_ARC_HEAT               = 41;
-const int STAT_PRESSED_KEYS           = 42;
-const int STAT_ALLOW_OLDVORTEXBEAM    = 43; // this stat could later contain some other bits of info, like, more server-side particle config
-const int STAT_FUEL                   = 44;
-const int STAT_NB_METERSTART          = 45;
-const int STAT_SHOTORG                = 46; // compressShotOrigin
-const int STAT_LEADLIMIT              = 47;
-const int STAT_WEAPON_CLIPLOAD        = 48;
-const int STAT_WEAPON_CLIPSIZE        = 49;
-const int STAT_VORTEX_CHARGE          = 50;
-const int STAT_LAST_PICKUP            = 51;
-const int STAT_HUD                    = 52;
-const int STAT_VORTEX_CHARGEPOOL      = 53;
-const int STAT_HIT_TIME               = 54;
-const int STAT_DAMAGE_DEALT_TOTAL     = 55;
-const int STAT_TYPEHIT_TIME           = 56;
-const int STAT_LAYED_MINES            = 57;
-const int STAT_HAGAR_LOAD             = 58;
-const int STAT_SWITCHINGWEAPON        = 59;
-const int STAT_SUPERWEAPONS_FINISHED  = 60;
-const int STAT_VEHICLESTAT_HEALTH     = 61;
-const int STAT_VEHICLESTAT_SHIELD     = 62;
-const int STAT_VEHICLESTAT_ENERGY     = 63;
-const int STAT_VEHICLESTAT_AMMO1      = 64;
-const int STAT_VEHICLESTAT_RELOAD1    = 65;
-const int STAT_VEHICLESTAT_AMMO2      = 66;
-const int STAT_VEHICLESTAT_RELOAD2    = 67;
-const int STAT_VEHICLESTAT_W2MODE     = 68;
-const int STAT_NADE_TIMER             = 69;
-const int STAT_SECRETS_TOTAL          = 70;
-const int STAT_SECRETS_FOUND          = 71;
-const int STAT_RESPAWN_TIME           = 72;
-const int STAT_ROUNDSTARTTIME         = 73;
-const int STAT_WEAPONS2               = 74;
-const int STAT_WEAPONS3               = 75;
-const int STAT_MONSTERS_TOTAL         = 76;
-const int STAT_MONSTERS_KILLED        = 77;
-const int STAT_BUFFS                  = 78;
-const int STAT_NADE_BONUS             = 79;
-const int STAT_NADE_BONUS_TYPE        = 80;
-const int STAT_NADE_BONUS_SCORE       = 81;
-const int STAT_HEALING_ORB            = 82;
-const int STAT_HEALING_ORB_ALPHA      = 83;
-const int STAT_PLASMA                 = 84;
-const int STAT_OK_AMMO_CHARGE         = 85;
-const int STAT_OK_AMMO_CHARGEPOOL     = 86;
-const int STAT_FROZEN                 = 87;
-const int STAT_REVIVE_PROGRESS        = 88;
-// 89 empty?
-// 90 empty?
-// 91 empty?
-// 92 empty?
-// 93 empty?
-// 94 empty?
-// 95 empty?
-// 96 empty?
-// 97 empty?
-// 98 empty?
-const int STAT_ROUNDLOST              = 99;
+
+enum {
+    STAT_WEAPONS = 32,
+    STAT_WEAPONS2,
+    STAT_WEAPONS3,
+
+    STAT_WEAPONSINMAP,
+    STAT_WEAPONSINMAP2,
+    STAT_WEAPONSINMAP3,
+
+    STAT_PL_VIEW_OFS1,
+    STAT_PL_VIEW_OFS2,
+    STAT_PL_VIEW_OFS3,
+
+    STAT_PL_CROUCH_VIEW_OFS1,
+    STAT_PL_CROUCH_VIEW_OFS2,
+    STAT_PL_CROUCH_VIEW_OFS3,
+
+    STAT_PL_MIN1,
+    STAT_PL_MIN2,
+    STAT_PL_MIN3,
+
+    STAT_PL_MAX1,
+    STAT_PL_MAX2,
+    STAT_PL_MAX3,
+
+    STAT_PL_CROUCH_MIN1,
+    STAT_PL_CROUCH_MIN2,
+    STAT_PL_CROUCH_MIN3,
+
+    STAT_PL_CROUCH_MAX1,
+    STAT_PL_CROUCH_MAX2,
+    STAT_PL_CROUCH_MAX3,
+
+    STAT_LAST_VECTOR
+};
+
+const int REGISTERED_STATS = 6;
+
+REGISTER_STAT(KH_KEYS, int)
+/** weapon requested to switch to; next WANTED weapon (for HUD) */
+REGISTER_STAT(SWITCHWEAPON, int)
+REGISTER_STAT(GAMESTARTTIME, float)
+REGISTER_STAT(STRENGTH_FINISHED, float)
+REGISTER_STAT(INVINCIBLE_FINISHED, float)
+/** arc heat in [0,1] */
+REGISTER_STAT(ARC_HEAT, float)
+
+enum {
+    STAT_FIRST_MAIN = (STAT_LAST_VECTOR - 1) + REGISTERED_STATS,
+
+    STAT_PRESSED_KEYS,
+    /** this stat could later contain some other bits of info, like, more server-side particle config */ STAT_ALLOW_OLDVORTEXBEAM,
+    STAT_FUEL,
+    STAT_NB_METERSTART,
+    /** compressShotOrigin */ STAT_SHOTORG,
+    STAT_LEADLIMIT,
+    STAT_WEAPON_CLIPLOAD,
+    STAT_WEAPON_CLIPSIZE,
+    STAT_VORTEX_CHARGE,
+    STAT_LAST_PICKUP,
+    STAT_HUD,
+    STAT_VORTEX_CHARGEPOOL,
+    STAT_HIT_TIME,
+    STAT_DAMAGE_DEALT_TOTAL,
+    STAT_TYPEHIT_TIME,
+    STAT_LAYED_MINES,
+    STAT_HAGAR_LOAD,
+    STAT_SWITCHINGWEAPON,
+    STAT_SUPERWEAPONS_FINISHED,
+    STAT_VEHICLESTAT_HEALTH,
+    STAT_VEHICLESTAT_SHIELD,
+    STAT_VEHICLESTAT_ENERGY,
+    STAT_VEHICLESTAT_AMMO1,
+    STAT_VEHICLESTAT_RELOAD1,
+    STAT_VEHICLESTAT_AMMO2,
+    STAT_VEHICLESTAT_RELOAD2,
+    STAT_VEHICLESTAT_W2MODE,
+    STAT_NADE_TIMER,
+    STAT_SECRETS_TOTAL,
+    STAT_SECRETS_FOUND,
+    STAT_RESPAWN_TIME,
+    STAT_ROUNDSTARTTIME,
+    STAT_MONSTERS_TOTAL,
+    STAT_MONSTERS_KILLED,
+    STAT_BUFFS,
+    STAT_NADE_BONUS,
+    STAT_NADE_BONUS_TYPE,
+    STAT_NADE_BONUS_SCORE,
+    STAT_HEALING_ORB,
+    STAT_HEALING_ORB_ALPHA,
+    STAT_PLASMA,
+    STAT_OK_AMMO_CHARGE,
+    STAT_OK_AMMO_CHARGEPOOL,
+    STAT_FROZEN,
+    STAT_REVIVE_PROGRESS,
+    STAT_ROUNDLOST,
+    STAT_BUFF_TIME,
+    STAT_CTF_FLAGSTATUS,
+    STAT_MULTIJUMP_DODGING,
+    STAT_MULTIJUMP_MAXSPEED,
+    STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND,
+    STAT_BUGRIGS_REVERSE_STOPPING,
+    STAT_BUGRIGS_REVERSE_SPINNING,
+    STAT_BUGRIGS_CAR_JUMPING,
+    STAT_BUGRIGS_FRICTION_AIR,
+    STAT_BUGRIGS_STEER,
+    STAT_BUGRIGS_SPEED_POW,
+    STAT_BUGRIGS_SPEED_REF,
+    STAT_BUGRIGS_ACCEL,
+    STAT_BUGRIGS_FRICTION_BRAKE,
+    STAT_BUGRIGS_AIR_STEERING,
+    STAT_BUGRIGS_FRICTION_FLOOR,
+    STAT_BUGRIGS_REVERSE_SPEEDING,
+    STAT_BUGRIGS_PLANAR_MOVEMENT,
+    STAT_BUGRIGS_ANGLE_SMOOTHING,
+    STAT_BUGRIGS,
+    STAT_GAMEPLAYFIX_STEPDOWN,
+    STAT_MOVEVARS_JUMPSTEP,
+    STAT_NOSTEP,
+    STAT_GAMEPLAYFIX_UNSTICKPLAYERS,
+    STAT_GAMEPLAYFIX_STEPMULTIPLETIMES,
+    STAT_GAMEPLAYFIX_DOWNTRACEONGROUND,
+    STAT_GAMEPLAYFIX_EASIERWATERJUMP,
+    STAT_MOVEVARS_FRICTION_SLICK,
+    STAT_MOVEVARS_FRICTION_ONLAND,
+    STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS,
+    STAT_MOVEVARS_TRACK_CANJUMP,
+    STAT_DOUBLEJUMP,
+    STAT_MOVEVARS_CL_TRACK_CANJUMP,
+    STAT_MULTIJUMP_ADD,
+    STAT_MULTIJUMP_SPEED,
+    STAT_MULTIJUMP,
+    STAT_DODGING_TIMEOUT,
+    STAT_DODGING_WALL,
+    STAT_DODGING_UP_SPEED,
+    STAT_DODGING_RAMP_TIME,
+    STAT_DODGING_HEIGHT_THRESHOLD,
+    STAT_DODGING_DISTANCE_THRESHOLD,
+    STAT_DODGING_HORIZ_SPEED,
+    STAT_DODGING_DELAY,
+    STAT_DODGING_FROZEN_NO_DOUBLETAP,
+    STAT_DODGING_HORIZ_SPEED_FROZEN,
+    STAT_DODGING,
+    STAT_DODGING_FROZEN,
+    STAT_JETPACK_MAXSPEED_UP,
+    STAT_JETPACK_MAXSPEED_SIDE,
+    STAT_JETPACK_FUEL,
+    STAT_JETPACK_ANTIGRAVITY,
+    STAT_JETPACK_ACCEL_SIDE,
+    STAT_JETPACK_ACCEL_UP,
+    STAT_MOVEVARS_HIGHSPEED,
+
+    STAT_LAST_MAIN
+};
+
+const int STAT_LAST = STAT_LAST_MAIN + 5;
 
 /* The following stats change depending on the gamemode, so can share the same ID */
-// IDs 100 to 104 reserved for gamemodes
 
 // freeze tag, clan arena, jailbreak
-const int STAT_REDALIVE               = 100;
-const int STAT_BLUEALIVE              = 101;
-const int STAT_YELLOWALIVE            = 102;
-const int STAT_PINKALIVE              = 103;
+enum {
+    STAT_REDALIVE = STAT_LAST_MAIN,
+    STAT_BLUEALIVE,
+    STAT_YELLOWALIVE,
+    STAT_PINKALIVE,
+};
 
 // domination
-const int STAT_DOM_TOTAL_PPS          = 100;
-const int STAT_DOM_PPS_RED            = 101;
-const int STAT_DOM_PPS_BLUE           = 102;
-const int STAT_DOM_PPS_YELLOW         = 103;
-const int STAT_DOM_PPS_PINK           = 104;
+enum {
+    STAT_DOM_TOTAL_PPS = STAT_LAST_MAIN,
+    STAT_DOM_PPS_RED,
+    STAT_DOM_PPS_BLUE,
+    STAT_DOM_PPS_YELLOW,
+    STAT_DOM_PPS_PINK,
+};
 
 // vip
-const int STAT_VIP                    = 100;
-const int STAT_VIP_RED                = 101;
-const int STAT_VIP_BLUE               = 102;
-const int STAT_VIP_YELLOW             = 103;
-const int STAT_VIP_PINK               = 104;
+enum {
+    STAT_VIP = STAT_LAST_MAIN,
+    STAT_VIP_RED,
+    STAT_VIP_BLUE,
+    STAT_VIP_YELLOW,
+    STAT_VIP_PINK,
+};
 
 // key hunt
-const int STAT_KH_REDKEY_TEAM         = 100;
-const int STAT_KH_BLUEKEY_TEAM        = 101;
-const int STAT_KH_YELLOWKEY_TEAM      = 102;
-const int STAT_KH_PINKKEY_TEAM        = 103;
+enum {
+    STAT_KH_REDKEY_TEAM = STAT_LAST_MAIN,
+    STAT_KH_BLUEKEY_TEAM,
+    STAT_KH_YELLOWKEY_TEAM,
+    STAT_KH_PINKKEY_TEAM,
+};
 
-/* Gamemode-specific stats end here */
+#define ASSERT_LESS(name, var, const) noref int name[(const - var + 1)];
+ASSERT_LESS(stat_limit, STAT_LAST, 220)
 
-const int STAT_PL_VIEW_OFS1           = 105;
-const int STAT_PL_VIEW_OFS2           = 106;
-const int STAT_PL_VIEW_OFS3           = 107;
-const int STAT_PL_MIN1                = 108;
-const int STAT_PL_MIN2                = 109;
-const int STAT_PL_MIN3                = 110;
-const int STAT_PL_MAX1                = 111;
-const int STAT_PL_MAX2                = 112;
-const int STAT_PL_MAX3                = 113;
-const int STAT_PL_CROUCH_MIN1         = 114;
-const int STAT_PL_CROUCH_MIN2         = 115;
-const int STAT_PL_CROUCH_MIN3         = 116;
-const int STAT_PL_CROUCH_MAX1         = 117;
-const int STAT_PL_CROUCH_MAX2         = 118;
-const int STAT_PL_CROUCH_MAX3         = 119;
-const int STAT_PL_CROUCH_VIEW_OFS1    = 117;
-const int STAT_PL_CROUCH_VIEW_OFS2    = 118;
-const int STAT_PL_CROUCH_VIEW_OFS3    = 119;
-const int STAT_WEAPONSINMAP           = 120;
-const int STAT_WEAPONSINMAP2          = 121;
-const int STAT_WEAPONSINMAP3          = 122;
-const int STAT_BUFF_TIME              = 123;
-const int STAT_CTF_FLAGSTATUS         = 124;
-// 125 empty?
-// 126 empty?
-// 127 empty?
-// 128 empty?
-// 129 empty?
-// 130 empty?
-// 131 empty?
-// 132 empty?
-// 133 empty?
-// 134 empty?
-// 135 empty?
-// 136 empty?
-// 137 empty?
-// 138 empty?
-// 139 empty?
-// 140 reserved
-// 141 reserved
-// 142 reserved
-// 143 reserved
-// 144 reserved
-// 145 reserved
-// 146 reserved
-// 147 reserved
-// 148 reserved
-// 149 reserved
-// 150 reserved
-// 151 reserved
-// 152 reserved
-// 153 reserved
-// 154 reserved
-// 155 reserved
-// 156 empty?
-// 157 empty?
-// 158 empty?
-// 159 empty?
-// 160 empty?
-// 161 empty?
-// 162 empty?
-// 162 empty?
-// 163 empty?
-// 164 empty?
-// 165 empty?
-const int STAT_MULTIJUMP_DODGING                      = 166;
-const int STAT_MULTIJUMP_MAXSPEED                     = 167;
-const int STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND   = 168;
-const int STAT_BUGRIGS_REVERSE_STOPPING               = 169;
-const int STAT_BUGRIGS_REVERSE_SPINNING               = 170;
-const int STAT_BUGRIGS_CAR_JUMPING                    = 171;
-const int STAT_BUGRIGS_FRICTION_AIR                   = 172;
-const int STAT_BUGRIGS_STEER                          = 173;
-const int STAT_BUGRIGS_SPEED_POW                      = 174;
-const int STAT_BUGRIGS_SPEED_REF                      = 175;
-const int STAT_BUGRIGS_ACCEL                          = 176;
-const int STAT_BUGRIGS_FRICTION_BRAKE                 = 177;
-const int STAT_BUGRIGS_AIR_STEERING                   = 178;
-const int STAT_BUGRIGS_FRICTION_FLOOR                 = 179;
-const int STAT_BUGRIGS_REVERSE_SPEEDING               = 180;
-const int STAT_BUGRIGS_PLANAR_MOVEMENT                = 181;
-const int STAT_BUGRIGS_ANGLE_SMOOTHING                = 182;
-const int STAT_BUGRIGS                                = 183;
-const int STAT_GAMEPLAYFIX_STEPDOWN                   = 184;
-const int STAT_MOVEVARS_JUMPSTEP                      = 185;
-const int STAT_NOSTEP                                 = 186;
-const int STAT_GAMEPLAYFIX_UNSTICKPLAYERS             = 187;
-const int STAT_GAMEPLAYFIX_STEPMULTIPLETIMES          = 188;
-const int STAT_GAMEPLAYFIX_DOWNTRACEONGROUND          = 189;
-const int STAT_GAMEPLAYFIX_EASIERWATERJUMP            = 190;
-const int STAT_MOVEVARS_FRICTION_SLICK                = 191;
-const int STAT_MOVEVARS_FRICTION_ONLAND               = 192;
-const int STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS  = 193;
-const int STAT_MOVEVARS_TRACK_CANJUMP                 = 194;
-// 195 empty?
-const int STAT_DOUBLEJUMP                             = 196;
-const int STAT_MOVEVARS_CL_TRACK_CANJUMP              = 197;
-const int STAT_MULTIJUMP_ADD                          = 198;
-const int STAT_MULTIJUMP_SPEED                        = 199;
-const int STAT_MULTIJUMP                              = 200;
-const int STAT_DODGING_TIMEOUT                        = 201;
-const int STAT_DODGING_WALL                           = 202;
-const int STAT_DODGING_UP_SPEED                       = 203;
-const int STAT_DODGING_RAMP_TIME                      = 204;
-const int STAT_DODGING_HEIGHT_THRESHOLD               = 205;
-const int STAT_DODGING_DISTANCE_THRESHOLD             = 206;
-const int STAT_DODGING_HORIZ_SPEED                    = 207;
-const int STAT_DODGING_DELAY                          = 208;
-const int STAT_DODGING_FROZEN_NO_DOUBLETAP            = 209;
-const int STAT_DODGING_HORIZ_SPEED_FROZEN             = 210;
-const int STAT_DODGING                                = 211;
-const int STAT_DODGING_FROZEN                         = 212;
-const int STAT_JETPACK_MAXSPEED_UP                    = 213;
-const int STAT_JETPACK_MAXSPEED_SIDE                  = 214;
-const int STAT_JETPACK_FUEL                           = 215;
-const int STAT_JETPACK_ANTIGRAVITY                    = 216;
-const int STAT_JETPACK_ACCEL_SIDE                     = 217;
-const int STAT_JETPACK_ACCEL_UP                       = 218;
-const int STAT_MOVEVARS_HIGHSPEED                     = 219;
 const int STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR     = 220;
 const int STAT_MOVEVARS_AIRCONTROL_PENALTY            = 221;
 const int STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW           = 222;
index 8c7000d933ee1c8fd4418912dd8b7e0bbcc909d2..909f5cd975c59381fc5ded443c4ae578466f35f4 100644 (file)
@@ -69,8 +69,7 @@ spawnfunc(func_bobbing)
                return;
 
        // wait for targets to spawn
-       controller = spawn();
-       controller.classname = "func_bobbing_controller";
+       controller = new(func_bobbing_controller);
        controller.owner = self;
        controller.nextthink = time + 1;
        controller.think = func_bobbing_controller_think;
index 4164f8341ac8feaa2969f18a879d635ae7433676..e03e23ea73c022f16cbf61f493967c2c52a8e808 100644 (file)
@@ -211,7 +211,7 @@ void func_breakable_destroy()
                RadiusDamage(self, activator, self.dmg, self.dmg_edge, self.dmg_radius, self, world, self.dmg_force, DEATH_HURTTRIGGER.m_id, world);
 
        if(self.cnt) // TODO
-               pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);
+               __pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);
 
        if(self.respawntime)
        {
index 73f22b99b69a7a8129b767597c62772cea0c6a1b..ac30dda43deb43f5dcb1197e7adbed9fe498f1ea 100644 (file)
@@ -1,3 +1,5 @@
+REGISTER_NET_LINKED(ENT_CLIENT_CONVEYOR)
+
 void conveyor_think()
 {SELFPARAM();
 #ifdef CSQC
@@ -72,7 +74,7 @@ void conveyor_reset()
 
 bool conveyor_send(entity this, entity to, int sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_CONVEYOR);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_CONVEYOR);
        WriteByte(MSG_ENTITY, sf);
 
        if(sf & 1)
@@ -160,8 +162,8 @@ void conveyor_init()
        self.move_time = time;
 }
 
-void ent_conveyor()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_CONVEYOR, bool isnew)
+{
        float sf = ReadByte();
 
        if(sf & 1)
@@ -195,5 +197,7 @@ void ent_conveyor()
 
        if(sf & 2)
                self.state = ReadByte();
+
+       return true;
 }
 #endif
diff --git a/qcsrc/common/triggers/func/conveyor.qh b/qcsrc/common/triggers/func/conveyor.qh
deleted file mode 100644 (file)
index f272030..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef CSQC
-void ent_conveyor();
-#endif
index 4ce3d261b00e8af6285a68c2875e96613b7e1810..6c825655664e18722470be94299c031897da2de2 100644 (file)
@@ -293,6 +293,7 @@ void door_damage(entity inflictor, entity attacker, float damage, int deathtype,
        }
 }
 
+.float door_finished;
 
 /*
 ================
@@ -306,10 +307,10 @@ void door_touch()
 {SELFPARAM();
        if (!IS_PLAYER(other))
                return;
-       if (self.owner.attack_finished_single > time)
+       if (self.owner.door_finished > time)
                return;
 
-       self.owner.attack_finished_single = time + 2;
+       self.owner.door_finished = time + 2;
 
 #ifdef SVQC
        if (!(self.owner.dmg) && (self.owner.message != ""))
@@ -437,14 +438,14 @@ void door_trigger_touch()
 #endif
                        return;
 
-       if (time < self.attack_finished_single)
+       if (time < self.door_finished)
                return;
 
        // check if door is locked
        if (!door_check_keys(self, other))
                return;
 
-       self.attack_finished_single = time + 1;
+       self.door_finished = time + 1;
 
        activator = other;
 
@@ -457,8 +458,7 @@ void door_spawnfield(vector fmins, vector fmaxs)
        entity  trigger;
        vector  t1 = fmins, t2 = fmaxs;
 
-       trigger = spawn();
-       trigger.classname = "doortriggerfield";
+       trigger = new(doortriggerfield);
        trigger.movetype = MOVETYPE_NONE;
        trigger.solid = SOLID_TRIGGER;
        trigger.owner = self;
@@ -599,6 +599,8 @@ void LinkDoors()
        door_spawnfield(cmins, cmaxs);
 }
 
+REGISTER_NET_LINKED(ENT_CLIENT_DOOR)
+
 #ifdef SVQC
 /*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
 if two doors touch, they are assumed to be connected and operate as a unit.
@@ -631,7 +633,7 @@ FIXME: only one sound set available at the time being
 
 float door_send(entity to, float sf)
 {SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_DOOR);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_DOOR);
        WriteByte(MSG_ENTITY, sf);
 
        if(sf & SF_TRIGGER_INIT)
@@ -804,8 +806,8 @@ void door_draw(entity this)
        trigger_draw_generic(this);
 }
 
-void ent_door()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_DOOR, bool isnew)
+{
        float sf = ReadByte();
 
        if(sf & SF_TRIGGER_INIT)
@@ -874,6 +876,7 @@ void ent_door()
                self.pos2_y = ReadCoord();
                self.pos2_z = ReadCoord();
        }
+       return true;
 }
 
 #endif
index adfc060e80257653aa447a341ccf076581ce9a0f..f7ed28c5bbc463c3371e16959b38270cbae7d25f 100644 (file)
@@ -12,8 +12,6 @@ const int SPAWNFLAGS_SILVER_KEY = 16;
 
 #ifdef CSQC
 // stuff for preload
-void ent_door();
 
-// abused
-.float attack_finished_single;
+.float door_finished;
 #endif
index a0b70ecebee27fdfd2645552b2c2bce195e3befc..4d6b9b48a176d324673e2e0c5a4c0fcdfcb989af 100644 (file)
@@ -133,11 +133,13 @@ void fd_secret_done()
                _sound(self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTEN_NORM);
 }
 
+.float door_finished;
+
 void secret_blocked()
 {SELFPARAM();
-       if (time < self.attack_finished_single)
+       if (time < self.door_finished)
                return;
-       self.attack_finished_single = time + 0.5;
+       self.door_finished = time + 0.5;
        //T_Damage (other, self, self, self.dmg, self.dmg, self.deathtype, DT_IMPACT, (self.absmin + self.absmax) * 0.5, '0 0 0', Obituary_Generic);
 }
 
@@ -152,10 +154,10 @@ void secret_touch()
 {SELFPARAM();
        if (!other.iscreature)
                return;
-       if (self.attack_finished_single > time)
+       if (self.door_finished > time)
                return;
 
-       self.attack_finished_single = time + 2;
+       self.door_finished = time + 2;
 
        if (self.message)
        {
index 2b3d07f6ea41dbc57dc441861290f00895fb5502..31e3835914ecb59d5722942ed35f1b824dbf83aa 100644 (file)
@@ -73,8 +73,7 @@ spawnfunc(func_fourier)
        self.active = ACTIVE_ACTIVE;
 
        // wait for targets to spawn
-       controller = spawn();
-       controller.classname = "func_fourier_controller";
+       controller = new(func_fourier_controller);
        controller.owner = self;
        controller.nextthink = time + 1;
        controller.think = func_fourier_controller_think;
index 624c0b5c8e0bf617d032954e1298fede1603bbef..628355cb79aa0280f2173848d03c0bca5387e419 100644 (file)
@@ -1,12 +1,8 @@
 #ifndef TRIGGERS_FUNC_INCLUDE_H
 #define TRIGGERS_FUNC_INCLUDE_H
 
-#include "conveyor.qh"
 #include "door.qh"
 #include "ladder.qh"
-#include "plat.qh"
-#include "rainsnow.qh"
-#include "pointparticles.qh"
 #include "train.qh"
 
 #endif
index c27dd2ce08604e576c642d855d03fbbc2af67a67..0ddf08eef07cb0585143f276a06c8b5fb139ce0f 100644 (file)
@@ -1,3 +1,5 @@
+REGISTER_NET_LINKED(ENT_CLIENT_LADDER)
+
 void func_ladder_touch()
 {SELFPARAM();
 #ifdef SVQC
@@ -20,7 +22,7 @@ void func_ladder_touch()
 #ifdef SVQC
 bool func_ladder_send(entity this, entity to, float sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_LADDER);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_LADDER);
 
        WriteString(MSG_ENTITY, self.classname);
        WriteByte(MSG_ENTITY, self.skin);
@@ -60,14 +62,17 @@ spawnfunc(func_water)
 #elif defined(CSQC)
 .float speed;
 
-void ent_func_ladder()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_LADDER, bool isnew)
+{
        self.classname = strzone(ReadString());
        self.skin = ReadByte();
        self.speed = ReadByte();
        self.model = strzone(ReadString());
 
        trigger_common_read(false);
+
+       return = true;
+
        self.mins = self.maxs = '0 0 0';
 
        self.solid = SOLID_TRIGGER;
index 11eeeda26aed6182fa44cf8eccd39f083a75164f..774e7cf408857c945a1a8a85a29a99512ab09795 100644 (file)
@@ -1,6 +1,2 @@
 .float ladder_time;
 .entity ladder_entity;
-
-#ifdef CSQC
-void ent_func_ladder();
-#endif
index d8bab869e2f743310b01163fb23c96c3e773c941..2d8aea35cfa1a756c3f7981984f772dc9b87e16e 100644 (file)
@@ -62,8 +62,7 @@ spawnfunc(func_pendulum)
        self.cnt = self.angles_z;
 
        // wait for targets to spawn
-       controller = spawn();
-       controller.classname = "func_pendulum_controller";
+       controller = new(func_pendulum_controller);
        controller.owner = self;
        controller.nextthink = time + 1;
        controller.think = func_pendulum_controller_think;
index fc62341a85a3a09b65b158d09d6e4d2fce92cf40..cb2cc3a49cbeb47c065c05bbd071323657e15581 100644 (file)
@@ -1,3 +1,5 @@
+REGISTER_NET_LINKED(ENT_CLIENT_PLAT)
+
 #ifdef SVQC
 void plat_link();
 
@@ -9,7 +11,7 @@ void plat_delayedinit()
 
 float plat_send(entity to, float sf)
 {SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_PLAT);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_PLAT);
        WriteByte(MSG_ENTITY, sf);
 
        if(sf & SF_TRIGGER_INIT)
@@ -133,8 +135,8 @@ void plat_draw(entity this)
        //Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
 }
 
-void ent_plat()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_PLAT, bool isnew)
+{
        float sf = ReadByte();
 
        if(sf & SF_TRIGGER_INIT)
@@ -197,5 +199,6 @@ void ent_plat()
                self.move_angles = self.angles;
                self.move_time = time;
        }
+       return true;
 }
 #endif
diff --git a/qcsrc/common/triggers/func/plat.qh b/qcsrc/common/triggers/func/plat.qh
deleted file mode 100644 (file)
index e3562f4..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef CSQC
-void ent_plat();
-#endif
index a4f31b2fd81c0e2b25e4597b0234b3c327a1329c..ef42c93eb06514c8547a9cca55b916a41d35f2a8 100644 (file)
@@ -1,13 +1,11 @@
-#ifdef CSQC
-       #include "../../../client/particles.qh"
-#endif
+REGISTER_NET_LINKED(ENT_CLIENT_POINTPARTICLES)
 
 #ifdef SVQC
 // NOTE: also contains func_sparks
 
 bool pointparticles_SendEntity(entity this, entity to, float fl)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
 
        // optional features to save space
        fl = fl & 0x0F;
@@ -183,6 +181,21 @@ spawnfunc(func_sparks)
 }
 #elif defined(CSQC)
 
+.int dphitcontentsmask;
+
+entityclass(PointParticles);
+class(PointParticles) .int cnt; // effect number
+class(PointParticles) .vector velocity; // particle velocity
+class(PointParticles) .float waterlevel; // direction jitter
+class(PointParticles) .int count; // count multiplier
+class(PointParticles) .int impulse; // density
+class(PointParticles) .string noise; // sound
+class(PointParticles) .float atten;
+class(PointParticles) .float volume;
+class(PointParticles) .float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
+class(PointParticles) .vector movedir; // trace direction
+class(PointParticles) .float glow_color; // palette index
+
 void Draw_PointParticles(entity this)
 {
        float n, i, fail;
@@ -221,11 +234,11 @@ void Draw_PointParticles(entity this)
                        {
                                traceline(p, p + normalize(self.movedir) * 4096, 0, world);
                                p = trace_endpos;
-                               pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count);
+                               __pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count);
                        }
                        else
                        {
-                               pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count);
+                               __pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count);
                        }
                        if(self.noise != "")
                        {
@@ -253,8 +266,8 @@ void Ent_PointParticles_Remove()
        self.bgmscript = string_null;
 }
 
-void Ent_PointParticles()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_POINTPARTICLES, bool isnew)
+{
        float i;
        vector v;
        int f = ReadByte();
@@ -340,6 +353,8 @@ void Ent_PointParticles()
                BGMScript_InitEntity(self);
        }
 
+       return = true;
+
        if(f & 2)
        {
                self.absolute = (self.impulse >= 0);
diff --git a/qcsrc/common/triggers/func/pointparticles.qh b/qcsrc/common/triggers/func/pointparticles.qh
deleted file mode 100644 (file)
index f08ea48..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef CSQC
-
-void Ent_PointParticles();
-
-#endif
index 18c2c0a0fb91c9cb9adecb5fc5bb5a253530e93b..7ed9c558c33b55d2914c3bca4ca638ec1f9370d3 100644 (file)
@@ -1,7 +1,9 @@
+REGISTER_NET_LINKED(ENT_CLIENT_RAINSNOW)
+
 #ifdef SVQC
 bool rainsnow_SendEntity(entity this, entity to, float sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
        WriteByte(MSG_ENTITY, self.state);
        WriteCoord(MSG_ENTITY, self.origin_x + self.mins_x);
        WriteCoord(MSG_ENTITY, self.origin_y + self.mins_y);
@@ -100,8 +102,8 @@ void Draw_Snow(entity this)
     te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
 }
 
-void Ent_RainOrSnow()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_RAINSNOW, bool isnew)
+{
        self.impulse = ReadByte(); // Rain, Snow, or Whatever
        self.origin_x = ReadCoord();
        self.origin_y = ReadCoord();
@@ -113,6 +115,8 @@ void Ent_RainOrSnow()
        self.count = ReadShort() * 10;
        self.glow_color = ReadByte(); // color
 
+       return = true;
+
        self.mins    = -0.5 * self.maxs;
        self.maxs    =  0.5 * self.maxs;
        self.origin  = self.origin - self.mins;
diff --git a/qcsrc/common/triggers/func/rainsnow.qh b/qcsrc/common/triggers/func/rainsnow.qh
deleted file mode 100644 (file)
index 5d8d923..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef CSQC
-void Ent_RainOrSnow();
-#endif
index 65414548b2e27f3926e41d5d4c3ad6416db7c568..0f827a60e37e4bdef4c8c031a84c5b927f9c11f7 100644 (file)
@@ -101,10 +101,12 @@ void train_next()
                _sound(self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_IDLE);
 }
 
+REGISTER_NET_LINKED(ENT_CLIENT_TRAIN)
+
 #ifdef SVQC
 float train_send(entity to, float sf)
 {SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_TRAIN);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRAIN);
        WriteByte(MSG_ENTITY, sf);
 
        if(sf & SF_TRIGGER_INIT)
@@ -245,8 +247,8 @@ void train_draw(entity this)
        Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
 }
 
-void ent_train()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TRAIN, bool isnew)
+{
        float sf = ReadByte();
 
        if(sf & SF_TRIGGER_INIT)
@@ -321,6 +323,8 @@ void ent_train()
        {
                // TODO: make a reset function for trains
        }
+
+       return true;
 }
 
 #endif
index f69515f5a7393c8ff501bea67c8c52b9c5e849fd..d42d8a8a0c98b031d6666c82557d8aef14421e25 100644 (file)
@@ -1,4 +1,3 @@
 #ifdef CSQC
 .float dmgtime;
-void ent_train();
 #endif
index 57d3a0636fafefb5f7036c2c0ef2f5cfa1e235f8..5c2086477475abe8e6541374f1d6b12843a996a9 100644 (file)
@@ -91,8 +91,7 @@ void func_vectormamamam_findtarget()
        self.destvec = self.origin - func_vectormamamam_origin(self, 0);
 
        entity controller;
-       controller = spawn();
-       controller.classname = "func_vectormamamam_controller";
+       controller = new(func_vectormamamam_controller);
        controller.owner = self;
        controller.nextthink = time + 1;
        controller.think = func_vectormamamam_controller_think;
index 138d26786be12ff0c3b78864a7c21185049678b8..f69a72b0a2bb0c48a4fe5c1d71ad126e6de47507 100644 (file)
@@ -13,9 +13,6 @@
 // func
 #include "func/include.qh"
 
-// misc
-#include "misc/include.qh"
-
 // target
 #include "target/include.qh"
 
index ccac77b6c9c402b7340c68ad12263531a066a486..d1bfe00de3c0c2ba41245f90ee1e0b4809023247 100644 (file)
@@ -1,7 +1,9 @@
+REGISTER_NET_LINKED(ENT_CLIENT_CORNER)
+
 #ifdef SVQC
 bool corner_send(entity to, int sf)
 {SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_CORNER);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_CORNER);
 
        WriteString(MSG_ENTITY, self.platmovetype);
 
@@ -57,8 +59,8 @@ void corner_remove()
        self.platmovetype = string_null;
 }
 
-void ent_corner()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_CORNER, bool isnew)
+{
        self.platmovetype = strzone(ReadString());
 
        self.origin_x = ReadCoord();
@@ -75,6 +77,8 @@ void ent_corner()
 
        self.wait = ReadByte();
 
+       return = true;
+
        self.classname = "path_corner";
        self.drawmask = MASK_NORMAL;
        self.entremove = corner_remove;
diff --git a/qcsrc/common/triggers/misc/corner.qh b/qcsrc/common/triggers/misc/corner.qh
deleted file mode 100644 (file)
index 62b3aae..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef CSQC
-void ent_corner();
-#endif
index c05f8c376b8e77de457a7efc4894b0144daa87d1..8965c62906e01e349fb2b5f85867746414907878 100644 (file)
@@ -1,5 +1,3 @@
-#include "include.qh"
-
 #include "corner.qc"
 #include "follow.qc"
 #include "laser.qc"
diff --git a/qcsrc/common/triggers/misc/include.qh b/qcsrc/common/triggers/misc/include.qh
deleted file mode 100644 (file)
index 71b2205..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef TRIGGERS_MISC_INCLUDE_H
-#define TRIGGERS_MISC_INCLUDE_H
-
-#include "corner.qh"
-#include "laser.qh"
-
-#endif
index 06ca7054352696b92061a23a1ce3aa52ce61acb3..8bfa35f40da77688d516a8e36688628e766781c6 100644 (file)
@@ -1,5 +1,4 @@
 #if defined(CSQC)
-       #include "../../buffs/all.qh"
        #include "../../../lib/csqcmodel/interpolate.qh"
        #include "../../../client/main.qh"
        #include "../../../lib/csqcmodel/cl_model.qh"
@@ -7,6 +6,8 @@
 #elif defined(SVQC)
 #endif
 
+REGISTER_NET_LINKED(ENT_CLIENT_LASER)
+
 #ifdef SVQC
 .float modelscale;
 void misc_laser_aim()
@@ -124,7 +125,7 @@ void misc_laser_think()
 
 bool laser_SendEntity(entity this, entity to, float fl)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_LASER);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_LASER);
        fl = fl - (fl & 0xF0); // use that bit to indicate finite length laser
        if(self.spawnflags & 2)
                fl |= 0x80;
@@ -316,14 +317,14 @@ void Draw_Laser(entity this)
        if (!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
        {
                if(self.cnt >= 0)
-                       pointparticles(self.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
+                       __pointparticles(self.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
                if(self.colormod != '0 0 0' && self.modelscale != 0)
                        adddynamiclight(trace_endpos + trace_plane_normal * 1, self.modelscale, self.colormod * 5);
        }
 }
 
-void Ent_Laser()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_LASER, bool isnew)
+{
        InterpolateOrigin_Undo();
 
        // 30 bytes, or 13 bytes for just moving
@@ -379,6 +380,9 @@ void Ent_Laser()
        }
        if(f & 4)
                self.state = ReadByte();
+
+       return = true;
+
        InterpolateOrigin_Note();
        self.draw = Draw_Laser;
 }
diff --git a/qcsrc/common/triggers/misc/laser.qh b/qcsrc/common/triggers/misc/laser.qh
deleted file mode 100644 (file)
index a77c4c5..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifdef CSQC
-void Ent_Laser();
-#endif
index d9de97301b9d068d8569bf1f8503723201918083..a0f60bb32f03a2f3cd99da0924d6e02c4cd6db09 100644 (file)
@@ -1,4 +1,4 @@
-void SUB_NullThink(void) { }
+void SUB_NullThink() { }
 
 void()  SUB_CalcMoveDone;
 void() SUB_CalcAngleMoveDone;
@@ -12,7 +12,7 @@ Applies some friction to self
 ==================
 */
 .float friction;
-void SUB_Friction (void)
+void SUB_Friction ()
 {SELFPARAM();
        self.SUB_NEXTTHINK = time;
        if(self.SUB_FLAGS & FL_ONGROUND)
@@ -45,7 +45,7 @@ void SUB_VanishOrRemove (entity ent)
        }
 }
 
-void SUB_SetFade_Think (void)
+void SUB_SetFade_Think ()
 {SELFPARAM();
        if(self.alpha == 0)
                self.alpha = 1;
@@ -80,7 +80,7 @@ calculate self.SUB_VELOCITY and self.SUB_NEXTTHINK to reach dest from
 self.SUB_ORIGIN traveling at speed
 ===============
 */
-void SUB_CalcMoveDone (void)
+void SUB_CalcMoveDone ()
 {SELFPARAM();
        // After moving, set origin to exact final destination
 
@@ -92,7 +92,7 @@ void SUB_CalcMoveDone (void)
 }
 
 .float platmovetype_turn;
-void SUB_CalcMove_controller_think (void)
+void SUB_CalcMove_controller_think ()
 {SELFPARAM();
        entity oldself;
        float traveltime;
@@ -222,8 +222,7 @@ void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeedtype, float
                return;
        }
 
-       controller = spawn();
-       controller.classname = "SUB_CalcMove_controller";
+       controller = new(SUB_CalcMove_controller);
        controller.owner = self;
        controller.platmovetype = self.platmovetype;
        controller.platmovetype_start = self.platmovetype_start;
@@ -309,7 +308,7 @@ self.angles rotating
 The calling function should make sure self.SUB_THINK is valid
 ===============
 */
-void SUB_CalcAngleMoveDone (void)
+void SUB_CalcAngleMoveDone ()
 {SELFPARAM();
        // After rotating, set angle to exact final angle
        self.angles = self.finalangle;
index ebecb18e317e3da64b8999a4624914722d298a0a..283b8afb47767a1d8be8029e52c827493eb930e0 100644 (file)
@@ -6,6 +6,9 @@
     #include "../../../server/defs.qh"
 #endif
 
+REGISTER_NET_TEMP(TE_CSQC_TARGET_MUSIC)
+REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_MUSIC)
+
 #ifdef SVQC
 
 // values:
@@ -19,8 +22,7 @@
 // when targetname is not set, THIS ONE is default
 void target_music_sendto(float to, float is)
 {SELFPARAM();
-       WriteByte(to, SVC_TEMPENTITY);
-       WriteByte(to, TE_CSQC_TARGET_MUSIC);
+       WriteHeader(to, TE_CSQC_TARGET_MUSIC);
        WriteShort(to, num_for_edict(self));
        WriteByte(to, self.volume * 255.0 * is);
        WriteByte(to, self.fade_time * 16.0);
@@ -88,7 +90,7 @@ void TargetMusic_RestoreGame()
 // when triggered, it is disabled/enabled for everyone
 bool trigger_music_SendEntity(entity this, entity to, float sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
        sf &= ~0x80;
        if(self.cnt)
                sf |= 0x80;
@@ -165,7 +167,7 @@ void TargetMusic_Advance()
                best = music_target;
        if(music_trigger)
                best = music_trigger;
-       for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); ) if(e.noise)
+       for(e = world; (e = findfloat(e, enttype, NET_ENT_CLIENT_TRIGGER_MUSIC.m_id)); ) if(e.noise)
        {
                vol0 = e.lastvol;
                if(getsoundtime(e, CH_BGM_SINGLE) < 0)
@@ -206,6 +208,12 @@ void TargetMusic_Advance()
                bgmtime = gettime(GETTIME_CDTRACK);
 }
 
+NET_HANDLE(TE_CSQC_TARGET_MUSIC, bool isNew)
+{
+       Net_TargetMusic();
+       return true;
+}
+
 void Net_TargetMusic()
 {
        int id = ReadShort();
@@ -216,7 +224,7 @@ void Net_TargetMusic()
        string noi = ReadString();
 
        entity e;
-       for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); )
+       for(e = world; (e = findfloat(e, enttype, NET_ENT_CLIENT_TRIGGER_MUSIC.m_id)); )
        {
                if(e.count == id)
                        break;
@@ -224,7 +232,7 @@ void Net_TargetMusic()
        if(!e)
        {
                e = spawn();
-               e.enttype = ENT_CLIENT_TRIGGER_MUSIC;
+               e.enttype = NET_ENT_CLIENT_TRIGGER_MUSIC.m_id;
                e.count = id;
        }
        if(e.noise != noi)
@@ -281,8 +289,8 @@ void Ent_TriggerMusic_Remove()
        self.noise = string_null;
 }
 
-void Ent_ReadTriggerMusic()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TRIGGER_MUSIC, bool isnew)
+{
        int f = ReadByte();
        if(f & 4)
        {
@@ -335,6 +343,7 @@ void Ent_ReadTriggerMusic()
        self.cnt = 1;
        self.think = Ent_TriggerMusic_Think;
        self.nextthink = time;
+       return true;
 }
 
 #endif
index d46c460554c83d26829ecc0083cec760926017e4..1884879764f20d0e21f3f75f83cb56a8d5f5a093 100644 (file)
@@ -22,8 +22,6 @@ void Ent_TriggerMusic_Think();
 
 void Ent_TriggerMusic_Remove();
 
-void Ent_ReadTriggerMusic();
-
 #elif defined(SVQC)
 void target_music_kill();
 #endif
index 92575384f710656c6159e44edce1910213540254..1f0c00e5e8e2d36211cffe95d5bd1b26390b7771 100644 (file)
@@ -177,7 +177,7 @@ entity Simple_TeleportPlayer(entity teleporter, entity player)
        return e;
 }
 
-void teleport_findtarget (void)
+void teleport_findtarget ()
 {SELFPARAM();
        entity e;
        float n;
index bdd24ddeff3b916ebf239ef0f4a2ab314b406eb9..01e738e43de17e3be53160ea1b91866c5cfb14cb 100644 (file)
@@ -53,9 +53,9 @@ void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angle
 
 entity Simple_TeleportPlayer(entity teleporter, entity player);
 
-void Teleport_Touch (void);
+void Teleport_Touch ();
 
-void teleport_findtarget (void);
+void teleport_findtarget ();
 
 entity Teleport_Find(vector mi, vector ma);
 
index c40fed3a8387bc1da25a54f180de0efdafa3c197..77c491c356b58647ad0c34c2d467b2e138d92c4b 100644 (file)
@@ -113,6 +113,8 @@ void trigger_impulse_touch3()
 #endif
 }
 
+REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_IMPULSE)
+
 /*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
 -------- KEYS --------
 target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
@@ -133,7 +135,7 @@ in directional and sperical mode. For damper/accelerator mode this is not nesses
 #ifdef SVQC
 bool trigger_impulse_send(entity to, int sf)
 {SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_IMPULSE);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_IMPULSE);
 
        WriteCoord(MSG_ENTITY, self.radius);
        WriteCoord(MSG_ENTITY, self.strength);
@@ -180,15 +182,15 @@ spawnfunc(trigger_impulse)
        trigger_impulse_link();
 }
 #elif defined(CSQC)
-void ent_trigger_impulse()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TRIGGER_IMPULSE, bool isnew)
+{
        self.radius = ReadCoord();
        self.strength = ReadCoord();
        self.falloff = ReadByte();
        self.active = ReadByte();
 
        trigger_common_read(true);
-
+       return = true;
 
        self.classname = "trigger_impulse";
        self.solid = SOLID_TRIGGER;
index a4c248dcad95d5fde88f57b2f91aa15a43ad8153..67d6361fbed2ea61c76c4bafb8e2952d6f06d485 100644 (file)
@@ -7,8 +7,4 @@
 .float strength;
 .float lastpushtime;
 
-#ifdef CSQC
-void ent_trigger_impulse();
-#endif
-
 #endif
index 7e25751bba7a70309abd64279fdfad7a6437f388..0b3be0056de03bb8dafd15683d77eb73b919d38d 100644 (file)
@@ -13,6 +13,9 @@ void trigger_push_use()
 }
 #endif
 
+REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_PUSH)
+REGISTER_NET_LINKED(ENT_CLIENT_TARGET_PUSH)
+
 /*
        trigger_push_calculatevelocity
 
@@ -317,7 +320,7 @@ void trigger_push_findtarget()
 #ifdef SVQC
 float trigger_push_send(entity to, float sf)
 {SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH);
        WriteByte(MSG_ENTITY, sf);
 
        if(sf & 1)
@@ -388,7 +391,7 @@ spawnfunc(trigger_push)
 
 bool target_push_send(entity this, entity to, float sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH);
 
        WriteByte(MSG_ENTITY, self.cnt);
        WriteString(MSG_ENTITY, self.targetname);
@@ -401,20 +404,20 @@ bool target_push_send(entity this, entity to, float sf)
 
 void target_push_link()
 {SELFPARAM();
-       Net_LinkEntity(self, false, 0, target_push_send);
-       self.SendFlags |= 1; // update
+       //Net_LinkEntity(self, false, 0, target_push_send);
+       //self.SendFlags |= 1; // update
 }
 
 spawnfunc(target_push) { target_push_link(); }
 spawnfunc(info_notnull) { target_push_link(); }
-spawnfunc(target_position) { target_push_link(); }
+spawnfunc(target_position) { make_pure(this); target_push_link(); }
 
 #endif
 
 #ifdef CSQC
 
-void ent_trigger_push()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TRIGGER_PUSH, bool isnew)
+{
        float sf = ReadByte();
 
        if(sf & 1)
@@ -441,6 +444,7 @@ void ent_trigger_push()
                self.team = ReadByte();
                self.active = ReadByte();
        }
+       return true;
 }
 
 void target_push_remove()
@@ -454,14 +458,17 @@ void target_push_remove()
        self.targetname = string_null;
 }
 
-void ent_target_push()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TARGET_PUSH, bool isnew)
+{
        self.classname = "push_target";
        self.cnt = ReadByte();
        self.targetname = strzone(ReadString());
        self.origin_x = ReadCoord();
        self.origin_y = ReadCoord();
        self.origin_z = ReadCoord();
+
+       return = true;
+
        setorigin(self, self.origin);
 
        self.drawmask = MASK_NORMAL;
index efce0df62d95600473019f016e4ac656ad0699f9..0c4180849667aeef916314c2c128486052954367 100644 (file)
@@ -19,12 +19,6 @@ void() SUB_UseTargets;
 void trigger_push_use();
 #endif
 
-#ifdef CSQC
-void ent_trigger_push();
-
-void ent_target_push();
-#endif
-
 /*
        trigger_push_calculatevelocity
 
index 365c6f5a908d01a7ea8a3f7f76a51ce2545e0b70..98b121d6eebc9eca44930c10f61ea0f442775b1a 100644 (file)
@@ -94,10 +94,12 @@ void trigger_keylock_touch()
 
 }
 
+REGISTER_NET_LINKED(ENT_CLIENT_KEYLOCK)
+
 #ifdef SVQC
 bool trigger_keylock_send(entity to, int sf)
 {SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_KEYLOCK);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_KEYLOCK);
 
        WriteInt24_t(MSG_ENTITY, self.itemkeys);
        WriteByte(MSG_ENTITY, self.height);
@@ -146,7 +148,7 @@ spawnfunc(trigger_keylock)
                if(self.sounds == 1)
                        self.noise = "misc/secret.wav";
                else if(self.sounds == 2)
-                       self.noise = SND(TALK);
+                       self.noise = strzone(SND(TALK));
                else //if (self.sounds == 3) {
                        self.noise = "misc/trigger1.wav";
        }
@@ -195,13 +197,15 @@ void keylock_remove()
        self.targetname = string_null;
 }
 
-void ent_keylock()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_KEYLOCK, bool isnew)
+{
        self.itemkeys = ReadInt24_t();
        self.height = ReadByte();
 
        trigger_common_read(true);
 
+       return = true;
+
        self.classname = "trigger_keylock";
        self.drawmask = MASK_NORMAL;
        self.draw = trigger_draw_generic;
index bbec0182f3952130d5314ddadd372ff95e0c1482..a59cb3f69583856eb921f07a708b9cb8abf8ac78 100644 (file)
@@ -1,5 +1,4 @@
 #ifdef CSQC
-void ent_keylock();
 bool item_keys_usekey(entity l, entity p)
 {
        int valid = (l.itemkeys & p.itemkeys);
index bc5821c809383597f1b8d1d92b0fea2229b86436..91bfc99834b2953611707678ab25268269f3244e 100644 (file)
@@ -153,7 +153,7 @@ spawnfunc(trigger_multiple)
        }
        else if (self.sounds == 2)
        {
-               self.noise = SND(TALK);
+               self.noise = strzone(SND(TALK));
        }
        else if (self.sounds == 3)
        {
index a906fcd313d53f21eaac86df915fd429bf418491..ae29a75342fa4fee0a6446a85cf41a5d48ca7e75 100644 (file)
@@ -22,7 +22,7 @@
 #ifdef SVQC
 spawnfunc(trigger_swamp);
 #endif
-void swamp_touch(void);
+void swamp_touch();
 void swampslug_think();
 
 
@@ -36,7 +36,7 @@ void swampslug_think();
 *
 * I do it this way becuz there is no "untouch" event.
 */
-void swampslug_think(void)
+void swampslug_think()
 {SELFPARAM();
        //Slowly kill the slug
        self.health = self.health - 1;
@@ -60,7 +60,7 @@ void swampslug_think(void)
        self.nextthink = time + self.swamp_interval;
 }
 
-void swamp_touch(void)
+void swamp_touch()
 {SELFPARAM();
        // If whatever thats touching the swamp is not a player
        // or if its a dead player, just dont care abt it.
@@ -92,10 +92,12 @@ void swamp_touch(void)
        other.swampslug.health = 2;
 }
 
+REGISTER_NET_LINKED(ENT_CLIENT_SWAMP)
+
 #ifdef SVQC
 float swamp_send(entity to, float sf)
 {SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_LADDER);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_SWAMP);
 
        WriteByte(MSG_ENTITY, self.dmg); // can probably get away with using a single byte here
        WriteByte(MSG_ENTITY, self.swamp_slowdown);
@@ -134,14 +136,16 @@ spawnfunc(trigger_swamp)
 
 #elif defined(CSQC)
 
-void ent_swamp()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_SWAMP, bool isnew)
+{
        self.dmg = ReadByte();
        self.swamp_slowdown = ReadByte();
        self.swamp_interval = ReadByte();
 
        trigger_common_read(false);
 
+       return = true;
+
        self.classname = "trigger_swamp";
        self.solid = SOLID_TRIGGER;
        self.draw = trigger_draw_generic;
index 86b14315b06fb69fa9a4e187bda33a05735e06a6..7ae50bac42a9b7d4bbc7fc6ba5582b6fd2fd4993 100644 (file)
@@ -8,8 +8,4 @@
 .float in_swamp;              // bool
 .entity swampslug;            // Uses this to release from swamp ("untouch" fix)
 
-#ifdef CSQC
-void ent_swamp();
-#endif
-
 #endif
index 95bd7fbbd4ff0ab788035aff177c7e0d52d47e95..6522669200dee79b380f9c9b9d26bbe94c973c24 100644 (file)
@@ -8,7 +8,7 @@ void trigger_teleport_use()
 #endif
 }
 
-void Teleport_Touch (void)
+void Teleport_Touch ()
 {SELFPARAM();
        string s;
 
index c21fe6b5484b2e935fabe09ebf0d0282bbe9665b..af67533a831fe4622afc39a7b519b369a92917cb 100644 (file)
@@ -5,6 +5,9 @@
     #include "../../../server/defs.qh"
 #endif
 
+REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC)
+REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC_TRIGGER)
+
 #ifdef SVQC
 
 void viewloc_think()
@@ -40,7 +43,7 @@ void viewloc_think()
 bool trigger_viewloc_send(entity this, entity to, int sf)
 {
        // CSQC doesn't need to know our origin (yet), as we're only available for referencing
-       WriteByte(MSG_ENTITY, ENT_CLIENT_VIEWLOC_TRIGGER);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC_TRIGGER);
 
        WriteEntity(MSG_ENTITY, self.enemy);
        WriteEntity(MSG_ENTITY, self.goalentity);
@@ -90,7 +93,7 @@ spawnfunc(trigger_viewlocation)
 
 bool viewloc_send(entity this, entity to, int sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_VIEWLOC);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC);
 
        WriteByte(MSG_ENTITY, self.cnt);
 
@@ -137,8 +140,8 @@ void trigger_viewloc_updatelink()
        self.goalentity = findfloat(world, entnum, self.count);
 }
 
-void ent_viewloc_trigger()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_VIEWLOC_TRIGGER, bool isnew)
+{
        float point1 = ReadShort();
        float point2 = ReadShort();
 
@@ -148,6 +151,9 @@ void ent_viewloc_trigger()
        self.origin_x = ReadCoord();
        self.origin_y = ReadCoord();
        self.origin_z = ReadCoord();
+
+       return = true;
+
        setorigin(self, self.origin);
 
        self.cnt = point1;
@@ -160,8 +166,8 @@ void ent_viewloc_trigger()
        self.drawmask = MASK_NORMAL; // not so concerned, but better keep it alive
 }
 
-void ent_viewloc()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_VIEWLOC, bool isnew)
+{
        self.cnt = ReadByte();
 
        self.origin_x = ReadCoord();
@@ -173,6 +179,8 @@ void ent_viewloc()
        self.movedir_y = ReadCoord();
        self.movedir_z = ReadCoord();
 
+       return = true;
+
        self.classname = ((self.cnt == 2) ? "target_viewlocation_end" : "target_viewlocation_start");
        self.drawmask = MASK_NORMAL; // don't cull it
 }
index 6708a8e47f6ee0c6fdee2f6d357bff4272ea5c9b..881197a3b82fb57b7c96bc4f16ed3c14fd527b04 100644 (file)
@@ -7,9 +7,6 @@
 .entity goalentity;
 .entity enemy;
 .vector movedir;
-
-void ent_viewloc();
-void ent_viewloc_trigger();
 #endif
 
 #endif
index b97d2b1d9d94c6e8239482da45ae5a3360f11501..41180dd2cc806b020a441b50f03cb2ff08f9f160 100644 (file)
@@ -148,8 +148,7 @@ void SUB_UseTargets()
        if (self.delay)
        {
        // create a temp object to fire at a later time
-               t = spawn();
-               t.classname = "DelayedUse";
+               t = new(DelayedUse);
                t.nextthink = time + self.delay;
                t.think = DelayThink;
                t.enemy = activator;
index d996778e65397e3621908c737891af1ee16de764..bbd0d6811ab42401fd4d33e2d684f3fc75b8a30d 100644 (file)
@@ -1,13 +1,11 @@
 #include "all.qh"
 
+REGISTER_NET_LINKED(ENT_CLIENT_TURRET)
+
 #ifdef SVQC
 #include "sv_turrets.qh"
 #endif
 
-#ifdef CSQC
-#include "cl_turrets.qh"
-#endif
-
 #define IMPLEMENTATION
 #include "all.inc"
 #undef IMPLEMENTATION
index 3f9eba4f37d4e942aac5ccdd160dfb226dee42de..fc79400434e4fd58fd4fbfdf85b9a30bc7a990e2 100644 (file)
@@ -6,8 +6,11 @@
 
 #include "turret.qh"
 
-REGISTRY(Turrets, BIT(5))
-REGISTER_REGISTRY(RegisterTurrets)
+REGISTRY(Turrets, BITS(5))
+#define Turrets_from(i) _Turrets_from(i, TUR_Null)
+#define get_turretinfo(i) Turrets_from(i)
+REGISTER_REGISTRY(Turrets)
+REGISTRY_CHECK(Turrets)
 
 
 GENERIC_COMMAND(dumpturrets, "Dump all turrets into turrets_dump.txt")
@@ -67,19 +70,10 @@ GENERIC_COMMAND(dumpturrets, "Dump all turrets into turrets_dump.txt")
 const int TUR_FIRST = 1;
 #define TUR_LAST (Turrets_COUNT - 1)
 
-#define REGISTER_TURRET(id, inst) REGISTER(RegisterTurrets, TUR, Turrets, id, m_id, inst)
+#define REGISTER_TURRET(id, inst) REGISTER(Turrets, TUR, id, m_id, inst)
 
 REGISTER_TURRET(Null, NEW(Turret));
 
-Turret get_turretinfo(int id)
-{
-    if (id >= TUR_FIRST && id <= TUR_LAST) {
-        Turret t = Turrets[id];
-        if (t) return t;
-    }
-    return TUR_Null;
-}
-
 #include "all.inc"
 
 #endif
index 582113cf807e9b48eecc85ac0c5db3d6f2e3aaba..07378804f612efce71148c0ff2ac6db67e3f05d7 100644 (file)
@@ -45,11 +45,11 @@ void turret_draw(entity this)
 
        if(self.health < 85)
        if(dt < 0.01)
-               pointparticles(particleeffectnum(EFFECT_SMOKE_LARGE), (self.origin + (randomvec() * 80)), '0 0 0', 1);
+               pointparticles(EFFECT_SMOKE_LARGE, (self.origin + (randomvec() * 80)), '0 0 0', 1);
 
        if(self.health < 32)
        if(dt < 0.015)
-               pointparticles(particleeffectnum(EFFECT_SMOKE_SMALL), (self.origin + (randomvec() * 80)), '0 0 0', 1);
+               pointparticles(EFFECT_SMOKE_SMALL, (self.origin + (randomvec() * 80)), '0 0 0', 1);
 
 }
 
@@ -273,7 +273,7 @@ void turret_gibboom()
        float i;
 
        sound (self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-       pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), self.origin, '0 0 0', 1);
+       pointparticles(EFFECT_ROCKET_EXPLODE, self.origin, '0 0 0', 1);
 
        for (i = 1; i < 5; i = i + 1)
                turret_gibtoss(strcat("models/turrets/head-gib", ftos(i), ".md3"), self.origin + '0 0 2', self.velocity + randomvec() * 700, '0 0 0', false);
@@ -287,7 +287,7 @@ entity turret_gibtoss(string _model, vector _from, vector _to, vector _cmod, flo
        if(trace_startsolid)
                return world;
 
-       gib = spawn();
+       gib = new(turret_gib);
        setorigin(gib, _from);
        _setmodel(gib, _model);
        gib.colormod    = _cmod;
@@ -311,7 +311,6 @@ entity turret_gibtoss(string _model, vector _from, vector _to, vector _cmod, flo
        gib.move_avelocity  = prandomvec() * 32;
        gib.move_time      = time;
        gib.damageforcescale = 1;
-       gib.classname = "turret_gib";
 
        return gib;
 }
@@ -319,7 +318,7 @@ entity turret_gibtoss(string _model, vector _from, vector _to, vector _cmod, flo
 void turret_die()
 {SELFPARAM();
        sound (self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-       pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), self.origin, '0 0 0', 1);
+       pointparticles(EFFECT_ROCKET_EXPLODE, self.origin, '0 0 0', 1);
        if (!autocvar_cl_nogibs)
        {
                // Base
@@ -355,8 +354,8 @@ void turret_die()
        setmodel(self.tur_head, MDL_Null);
 }
 
-void ent_turret()
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_TURRET, bool isnew)
+{
        float sf;
        sf = ReadByte();
 
@@ -442,4 +441,5 @@ void ent_turret()
                self.health = _tmp;
        }
        //self.enemy.health = self.health / 255;
+       return true;
 }
diff --git a/qcsrc/common/turrets/cl_turrets.qh b/qcsrc/common/turrets/cl_turrets.qh
deleted file mode 100644 (file)
index 0f8ff94..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef CL_TURRETS_H
-#define CL_TURRETS_H
-
-void ent_turret();
-
-#endif
index c2a609b15ca42f1764b0115f4bd9baf4ee0257b8..34cf50eacc3d5f632d2ff4726232fe137344c050 100644 (file)
@@ -25,7 +25,7 @@ float T_Config_Queue_Compare(float root, float child, entity pass)
        return 0;
 }
 
-void Dump_Turret_Settings(void)
+void Dump_Turret_Settings()
 {
        float x, totalsettings = 0;
        FOREACH(Turrets, it != TUR_Null, LAMBDA({
index 4d35ee3b38528d0ca7bfed081df868f7d602f72e..bb2a81b847eb740251b5ba126335dfd8295e5e49 100644 (file)
@@ -3,7 +3,7 @@
 
 #ifdef SVQC
 
-void Dump_Turret_Settings(void);
+void Dump_Turret_Settings();
 float tur_config_file;
 float tur_config_alsoprint;
 
index ec7ce3711e95f21c13a0834703bb4962045c9afb..9ab9a32118c7e81e70c8daff361741c38473ab15 100644 (file)
@@ -13,7 +13,7 @@ vector turret_aim_generic()
        if(self.aim_flags & TFL_AIM_SIMPLE)
                return real_origin(self.enemy);
 
-       mintime = max(self.attack_finished_single - time,0) + sys_frametime;
+       mintime = max(self.attack_finished_single[0] - time,0) + sys_frametime;
 
        // Baseline
        pre_pos = real_origin(self.enemy);
@@ -302,7 +302,7 @@ void turrets_setframe(float _frame, float client_only)
 bool turret_send(entity this, entity to, float sf)
 {
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_TURRET);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TURRET);
        WriteByte(MSG_ENTITY, sf);
        if(sf & TNSF_SETUP)
        {
@@ -913,7 +913,7 @@ float turret_firecheck()
 
        // Ready?
        if (self.firecheck_flags & TFL_FIRECHECK_REFIRE)
-               if (self.attack_finished_single > time) return 0;
+               if (self.attack_finished_single[0] > time) return 0;
 
        // Special case: volly fire turret that has to fire a full volly if a shot was fired.
        if (self.shoot_flags & TFL_SHOOT_VOLLYALWAYS)
@@ -996,7 +996,7 @@ void turret_fire()
        Turret info = get_turretinfo(self.m_id);
        info.tr_attack(info);
 
-       self.attack_finished_single = time + self.shot_refire;
+       self.attack_finished_single[0] = time + self.shot_refire;
        self.ammo -= self.shot_dmg;
        self.volly_counter = self.volly_counter - 1;
 
@@ -1008,7 +1008,7 @@ void turret_fire()
                        self.enemy = world;
 
                if (self.shot_volly > 1)
-                       self.attack_finished_single = time + self.shot_volly_refire;
+                       self.attack_finished_single[0] = time + self.shot_volly_refire;
        }
 
 #ifdef TURRET_DEBUG
@@ -1267,8 +1267,7 @@ float turret_initialize(Turret tur)
        entity e = find(world, classname, "turret_manager");
        if(!e)
        {
-               e = spawn();
-               e.classname = "turret_manager";
+               e = new(turret_manager);
                e.think = turrets_manager_think;
                e.nextthink = time + 2;
        }
@@ -1353,13 +1352,13 @@ float turret_initialize(Turret tur)
        self.nextthink                          = time + 1;
        self.nextthink                     += turret_count * sys_frametime;
 
-       self.tur_head = spawn();
+       self.tur_head = new(turret_head);
        _setmodel(self.tur_head, tur.head_model);
        setsize(self.tur_head, '0 0 0', '0 0 0');
        setorigin(self.tur_head, '0 0 0');
        setattachment(self.tur_head, self, "tag_head");
 
-       self.tur_head.netname           = self.tur_head.classname = "turret_head";
+       self.tur_head.netname           = self.tur_head.classname;
        self.tur_head.team                      = self.team;
        self.tur_head.owner                     = self;
        self.tur_head.takedamage        = DAMAGE_NO;
index 8862f47d7763ce8640192bee5048fadd9fb048d7..dcb641404a2e869e6e05cc2c7a4e903aa809dc1a 100644 (file)
@@ -43,11 +43,14 @@ CLASS(Turret, Object)
 
     }
     ATTRIB(Turret, m_weapon, Weapon, WEP_Null)
+#ifdef SVQC
     /** (SERVER) called when turret attacks */
     METHOD(Turret, tr_attack, void(Turret this)) {
         Weapon w = this.m_weapon;
-        w.wr_think(w, self, true, false);
+        .entity weaponentity = weaponentities[0];
+        w.wr_think(w, self, weaponentity, 1);
     }
+#endif
     /** (ALL) */
     METHOD(Turret, tr_config, void(Turret this)) {
         // TODO
index 34e5a598689d7fd9e8d0e00163b48d2ffc397c22..e7ce7050021ac175bac93a5e8f25bacc4a5cedb2 100644 (file)
@@ -5,7 +5,7 @@ CLASS(EWheelAttack, PortoLaunch)
 /* flags     */ ATTRIB(EWheelAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(EWheelAttack, impulse, int, 5);
 /* refname   */ ATTRIB(EWheelAttack, netname, string, "turret_ewheel");
-/* wepname   */ ATTRIB(EWheelAttack, message, string, _("eWheel"));
+/* wepname   */ ATTRIB(EWheelAttack, m_name, string, _("eWheel"));
 ENDCLASS(EWheelAttack)
 REGISTER_WEAPON(EWHEEL, NEW(EWheelAttack));
 
@@ -16,17 +16,18 @@ REGISTER_WEAPON(EWHEEL, NEW(EWheelAttack));
 #ifdef SVQC
 
 void turret_initparams(entity);
-METHOD(EWheelAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(EWheelAttack_FIRE, W_Sound("electro_fire"));
+METHOD(EWheelAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
     bool isPlayer = IS_PLAYER(actor);
-    if (fire1)
-    if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+    if (fire & 1)
+    if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, v_forward, false, 0, SND(EWheelAttack_FIRE), CH_WEAPON_B, 0);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
-            weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+            weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
         }
 
         turret_do_updates(actor);
index 834f255dae95375d5cd7232f5dc43598d26be223..d1b560bfb2ffbaa58b1274b5a796406cff52a9e0 100644 (file)
@@ -5,7 +5,7 @@ CLASS(FlacAttack, PortoLaunch)
 /* flags     */ ATTRIB(FlacAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(FlacAttack, impulse, int, 5);
 /* refname   */ ATTRIB(FlacAttack, netname, string, "turret_flac");
-/* wepname   */ ATTRIB(FlacAttack, message, string, _("FLAC"));
+/* wepname   */ ATTRIB(FlacAttack, m_name, string, _("FLAC"));
 ENDCLASS(FlacAttack)
 REGISTER_WEAPON(FLAC, NEW(FlacAttack));
 
@@ -16,18 +16,19 @@ REGISTER_WEAPON(FLAC, NEW(FlacAttack));
 #ifdef SVQC
 
 void turret_flac_projectile_think_explode();
-METHOD(FlacAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(FlacAttack_FIRE, W_Sound("electro_fire"));
+METHOD(FlacAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
     bool isPlayer = IS_PLAYER(actor);
-    if (fire1)
-    if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+    if (fire & 1)
+    if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, v_forward, false, 0, SND(FlacAttack_FIRE), CH_WEAPON_B, 0);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
             actor.tur_impacttime = 10;
-            weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+            weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
         }
 
         turret_tag_fire_update();
index 1077d5c635bf7848dc34af3f2765aa0fda130877..3f51c06c327bede49d1bc6cc77ec413ce6a0d5cf 100644 (file)
@@ -19,7 +19,7 @@ REGISTER_TURRET(FUSIONREACTOR, NEW(FusionReactor));
 #ifdef SVQC
 bool turret_fusionreactor_firecheck()
 {SELFPARAM();
-    if (self.attack_finished_single > time)
+    if (self.attack_finished_single[0] > time)
         return false;
 
     if (self.enemy.deadflag != DEAD_NO)
index 2d754e877d0396951cc5173c125bcefe269c3c96..77aeb7c7e1d670297dc0ebf2ed2b591fc99c698d 100644 (file)
@@ -5,7 +5,7 @@ CLASS(HellionAttack, PortoLaunch)
 /* flags     */ ATTRIB(HellionAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(HellionAttack, impulse, int, 9);
 /* refname   */ ATTRIB(HellionAttack, netname, string, "turret_hellion");
-/* wepname   */ ATTRIB(HellionAttack, message, string, _("Hellion"));
+/* wepname   */ ATTRIB(HellionAttack, m_name, string, _("Hellion"));
 ENDCLASS(HellionAttack)
 REGISTER_WEAPON(HELLION, NEW(HellionAttack));
 
@@ -19,18 +19,19 @@ float autocvar_g_turrets_unit_hellion_shot_speed_gain;
 float autocvar_g_turrets_unit_hellion_shot_speed_max;
 
 void turret_hellion_missile_think();
-METHOD(HellionAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(HellionAttack_FIRE, W_Sound("electro_fire"));
+METHOD(HellionAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
     bool isPlayer = IS_PLAYER(actor);
-    if (fire1)
-    if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+    if (fire & 1)
+    if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, v_forward, false, 0, SND(HellionAttack_FIRE), CH_WEAPON_B, 0);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
             actor.shot_radius = 500;
-            weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+            weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
         }
         if (!isPlayer) {
             if (actor.tur_head.frame != 0)
index 98bff57575a181011906ceeedfb8c31742bfc3bb..b083c6830eda791bcaa7de0f43cd3a44c4cfa08c 100644 (file)
@@ -5,7 +5,7 @@ CLASS(HunterKillerAttack, PortoLaunch)
 /* flags     */ ATTRIB(HunterKillerAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(HunterKillerAttack, impulse, int, 9);
 /* refname   */ ATTRIB(HunterKillerAttack, netname, string, "turret_hk");
-/* wepname   */ ATTRIB(HunterKillerAttack, message, string, _("Hunter-Killer"));
+/* wepname   */ ATTRIB(HunterKillerAttack, m_name, string, _("Hunter-Killer"));
 ENDCLASS(HunterKillerAttack)
 REGISTER_WEAPON(HK, NEW(HunterKillerAttack));
 
@@ -23,18 +23,19 @@ float autocvar_g_turrets_unit_hk_shot_speed_max;
 float autocvar_g_turrets_unit_hk_shot_speed_turnrate;
 
 void turret_hk_missile_think();
-METHOD(HunterKillerAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+SOUND(HunterKillerAttack_FIRE, W_Sound("electro_fire"));
+METHOD(HunterKillerAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
 {
        bool isPlayer = IS_PLAYER(actor);
-       if (fire1)
-       if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+       if (fire & 1)
+       if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
                if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, v_forward, false, 0, SND(HunterKillerAttack_FIRE), CH_WEAPON_B, 0);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
-            weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+            weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
         }
         entity missile = turret_projectile(SND(ROCKET_FIRE), 6, 10, DEATH_TURRET_HK.m_id, PROJECTILE_ROCKET, FALSE, FALSE);
         te_explosion (missile.origin);
index a20bdb22cf051cb3446bf6728a7514e17a940fd1..7bd8b4086890ac2c65433cfe17358afb5f3a8db1 100644 (file)
@@ -5,7 +5,7 @@ CLASS(MachineGunTurretAttack, PortoLaunch)
 /* flags     */ ATTRIB(MachineGunTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(MachineGunTurretAttack, impulse, int, 9);
 /* refname   */ ATTRIB(MachineGunTurretAttack, netname, string, "turret_machinegun");
-/* wepname   */ ATTRIB(MachineGunTurretAttack, message, string, _("Machinegun"));
+/* wepname   */ ATTRIB(MachineGunTurretAttack, m_name, string, _("Machinegun"));
 ENDCLASS(MachineGunTurretAttack)
 REGISTER_WEAPON(TUR_MACHINEGUN, NEW(MachineGunTurretAttack));
 
@@ -16,19 +16,19 @@ REGISTER_WEAPON(TUR_MACHINEGUN, NEW(MachineGunTurretAttack));
 #ifdef SVQC
 
 void W_MachineGun_MuzzleFlash();
-
-METHOD(MachineGunTurretAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+SOUND(MachineGunTurretAttack_FIRE, W_Sound("electro_fire"));
+METHOD(MachineGunTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
 {
     bool isPlayer = IS_PLAYER(actor);
-    if (fire1)
-    if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR(machinegun, sustained_refire))) {
+    if (fire & 1)
+    if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(machinegun, sustained_refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, v_forward, false, 0, SND(MachineGunTurretAttack_FIRE), CH_WEAPON_B, 0);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
-            weapon_thinkf(actor, WFRAME_FIRE1, 0, w_ready);
+            weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
         }
         fireBullet (actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_MACHINEGUN.m_id, 0);
         W_MachineGun_MuzzleFlash();
index 05933591364da90799e92292d5e8471bd241e8b5..abd7b0fc4e77ba60598b903f77744ec6da3050b4 100644 (file)
@@ -5,7 +5,7 @@ CLASS(MLRSTurretAttack, PortoLaunch)
 /* flags     */ ATTRIB(MLRSTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(MLRSTurretAttack, impulse, int, 9);
 /* refname   */ ATTRIB(MLRSTurretAttack, netname, string, "turret_mlrs");
-/* wepname   */ ATTRIB(MLRSTurretAttack, message, string, _("MLRS"));
+/* wepname   */ ATTRIB(MLRSTurretAttack, m_name, string, _("MLRS"));
 ENDCLASS(MLRSTurretAttack)
 REGISTER_WEAPON(TUR_MLRS, NEW(MLRSTurretAttack));
 
@@ -14,20 +14,20 @@ REGISTER_WEAPON(TUR_MLRS, NEW(MLRSTurretAttack));
 #ifdef IMPLEMENTATION
 
 #ifdef SVQC
-
-METHOD(MLRSTurretAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+SOUND(MLRSTurretAttack_FIRE, W_Sound("electro_fire"));
+METHOD(MLRSTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
 {
     bool isPlayer = IS_PLAYER(actor);
-    if (fire1)
-    if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR(machinegun, sustained_refire))) {
+    if (fire & 1)
+    if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(machinegun, sustained_refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, v_forward, false, 0, SND(MLRSTurretAttack_FIRE), CH_WEAPON_B, 0);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
             actor.shot_radius = 500;
-            weapon_thinkf(actor, WFRAME_FIRE1, 0, w_ready);
+            weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
         }
         turret_tag_fire_update();
         entity missile = turret_projectile(SND(ROCKET_FIRE), 6, 10, DEATH_TURRET_MLRS.m_id, PROJECTILE_ROCKET, TRUE, TRUE);
index c4529ae267b872c47da45fda096208d4331a8d21..087ade8d47b2c1e7e23ac18b1e647433eab2a4b9 100644 (file)
@@ -5,7 +5,7 @@ CLASS(PhaserTurretAttack, PortoLaunch)
 /* flags     */ ATTRIB(PhaserTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(PhaserTurretAttack, impulse, int, 9);
 /* refname   */ ATTRIB(PhaserTurretAttack, netname, string, "turret_phaser");
-/* wepname   */ ATTRIB(PhaserTurretAttack, message, string, _("Phaser"));
+/* wepname   */ ATTRIB(PhaserTurretAttack, m_name, string, _("Phaser"));
 ENDCLASS(PhaserTurretAttack)
 REGISTER_WEAPON(PHASER, NEW(PhaserTurretAttack));
 
@@ -17,20 +17,20 @@ REGISTER_WEAPON(PHASER, NEW(PhaserTurretAttack));
 void beam_think();
 
 .int fireflag;
-
-METHOD(PhaserTurretAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+SOUND(PhaserTurretAttack_FIRE, W_Sound("electro_fire"));
+METHOD(PhaserTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
 {
     bool isPlayer = IS_PLAYER(actor);
-    if (fire1)
-    if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+    if (fire & 1)
+    if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, v_forward, false, 0, SND(PhaserTurretAttack_FIRE), CH_WEAPON_B, 0);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
             actor.shot_speed = 1;
-            weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+            weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
         }
         entity beam = spawn();
         beam.ticrate = 0.1; //autocvar_sys_ticrate;
@@ -51,8 +51,8 @@ METHOD(PhaserTurretAttack, wr_think, void(entity thiswep, entity actor, bool fir
         sound (beam, CH_SHOTS_SINGLE, SND_TUR_PHASER, VOL_BASE, ATTEN_NORM);
         actor.fireflag = 1;
 
-        beam.attack_finished_single = actor.attack_finished_single;
-        actor.attack_finished_single = time; // + autocvar_sys_ticrate;
+        beam.attack_finished_single[0] = actor.attack_finished_single[0];
+        actor.attack_finished_single[0] = time; // + autocvar_sys_ticrate;
 
         setattachment(beam,actor.tur_head, "tag_fire");
 
@@ -67,7 +67,7 @@ void beam_think()
 {SELFPARAM();
     if ((time > self.cnt) || (self.owner.deadflag != DEAD_NO))
     {
-        self.owner.attack_finished_single = time + self.owner.shot_refire;
+        self.owner.attack_finished_single[0] = time + self.owner.shot_refire;
         self.owner.fireflag = 2;
         self.owner.tur_head.frame = 10;
         sound (self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
@@ -86,7 +86,7 @@ void beam_think()
 
     self.nextthink = time + self.ticrate;
 
-    self.owner.attack_finished_single = time + frametime;
+    self.owner.attack_finished_single[0] = time + frametime;
     setself(self.owner);
     FireImoBeam (   self.tur_shotorg,
                     self.tur_shotorg + self.tur_shotdir_updated * self.target_range,
index 318f4e8ae69e2e31f28d33434fb26dde9e1841c2..7ed255911b4d57f5ccea0d3c0f58838585446639 100644 (file)
@@ -41,7 +41,7 @@ METHOD(PlasmaTurret, tr_attack, void(PlasmaTurret this))
     }
     else
     {
-        super.tr_attack(this);
+        SUPER(PlasmaTurret).tr_attack(this);
     }
     if (self.tur_head.frame == 0)
         self.tur_head.frame = 1;
index 387ae44a594dc8f851b06d85834f119d092ca5a5..cb78547a26cdc9705c53508f01717b4a463bddfc 100644 (file)
@@ -3,7 +3,7 @@
 
 CLASS(PlasmaDualAttack, PlasmaAttack)
 /* refname   */ ATTRIB(PlasmaDualAttack, netname, string, "turret_plasma_dual");
-/* wepname   */ ATTRIB(PlasmaDualAttack, message, string, _("Dual plasma"));
+/* wepname   */ ATTRIB(PlasmaDualAttack, m_name, string, _("Dual plasma"));
 ENDCLASS(PlasmaDualAttack)
 REGISTER_WEAPON(PLASMA_DUAL, NEW(PlasmaDualAttack));
 
@@ -41,7 +41,7 @@ METHOD(DualPlasmaTurret, tr_attack, void(DualPlasmaTurret this))
         vector v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
         WarpZone_TrailParticles(world, particleeffectnum(EFFECT_VAPORIZER(self.team)), self.tur_shotorg, v);
     } else {
-        super.vtblbase.tr_attack(this);
+        SUPER(PlasmaTurret).tr_attack(this);
     }
     self.tur_head.frame += 1;
 }
index 2141fe64f287daed129b5de618f1b6fdf5e56a66..65e182be387b25781eef23f05f1a166f70ab67d2 100644 (file)
@@ -5,7 +5,7 @@ CLASS(PlasmaAttack, PortoLaunch)
 /* flags     */ ATTRIB(PlasmaAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(PlasmaAttack, impulse, int, 5);
 /* refname   */ ATTRIB(PlasmaAttack, netname, string, "turret_plasma");
-/* wepname   */ ATTRIB(PlasmaAttack, message, string, _("Plasma"));
+/* wepname   */ ATTRIB(PlasmaAttack, m_name, string, _("Plasma"));
 ENDCLASS(PlasmaAttack)
 REGISTER_WEAPON(PLASMA, NEW(PlasmaAttack));
 
@@ -14,18 +14,18 @@ REGISTER_WEAPON(PLASMA, NEW(PlasmaAttack));
 #ifdef IMPLEMENTATION
 
 #ifdef SVQC
-
-METHOD(PlasmaAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(PlasmaAttack_FIRE, W_Sound("electro_fire"));
+METHOD(PlasmaAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
        bool isPlayer = IS_PLAYER(actor);
-       if (fire1)
-       if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+       if (fire & 1)
+       if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
                if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, v_forward, false, 0, SND(PlasmaAttack_FIRE), CH_WEAPON_B, 0);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
-            weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+            weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
         }
         entity missile = turret_projectile(SND(HAGAR_FIRE), 1, 0, DEATH_TURRET_PLASMA.m_id, PROJECTILE_ELECTRO_BEAM, true, true);
         missile.missile_flags = MIF_SPLASH;
index 3ae039c3ccbb3f1f6cf00f65c6787565a00dff20..16a9e423d3844875bf3f2bca448466f64c912e9d 100644 (file)
@@ -42,7 +42,7 @@ METHOD(TeslaCoil, tr_think, void(TeslaCoil thistur))
     {
         self.tur_head.avelocity = '0 180 0' * (self.ammo / self.shot_dmg);
 
-        if(self.attack_finished_single > time)
+        if(self.attack_finished_single[0] > time)
             return;
 
         float f;
index 4391472f739b06e7c97c6b3e7f9cb781e2cfa96a..7e9108cb423750d3e9fb2a76e4be50c94531e7e5 100644 (file)
@@ -5,7 +5,7 @@ CLASS(TeslaCoilTurretAttack, PortoLaunch)
 /* flags     */ ATTRIB(TeslaCoilTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(TeslaCoilTurretAttack, impulse, int, 9);
 /* refname   */ ATTRIB(TeslaCoilTurretAttack, netname, string, "turret_tesla");
-/* wepname   */ ATTRIB(TeslaCoilTurretAttack, message, string, _("Tesla Coil"));
+/* wepname   */ ATTRIB(TeslaCoilTurretAttack, m_name, string, _("Tesla Coil"));
 ENDCLASS(TeslaCoilTurretAttack)
 REGISTER_WEAPON(TESLA, NEW(TeslaCoilTurretAttack));
 
@@ -16,17 +16,18 @@ REGISTER_WEAPON(TESLA, NEW(TeslaCoilTurretAttack));
 #ifdef SVQC
 
 entity toast(entity from, float range, float damage);
-METHOD(TeslaCoilTurretAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(TeslaCoilTurretAttack_FIRE, W_Sound("electro_fire"));
+METHOD(TeslaCoilTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
     bool isPlayer = IS_PLAYER(actor);
-    if (fire1)
-    if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+    if (fire & 1)
+    if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, v_forward, false, 0, SND(TeslaCoilTurretAttack_FIRE), CH_WEAPON_B, 0);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
-            weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+            weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
         }
 
         float d = actor.shot_dmg;
@@ -43,7 +44,7 @@ METHOD(TeslaCoilTurretAttack, wr_think, void(entity thiswep, entity actor, bool
 
         actor.target_validate_flags = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_MISSILES | TFL_TARGETSELECT_TEAMCHECK;
 
-        actor.attack_finished_single = time + actor.shot_refire;
+        actor.attack_finished_single[0] = time + actor.shot_refire;
         for (int i = 0; i < 10; ++i) {
             d *= 0.75;
             r *= 0.85;
index cbdeb5e8e704e3b08fe36c856b7f5500164d2207..eac40d22094eea782c12fdde95eced356a505469 100644 (file)
@@ -233,13 +233,12 @@ void walker_fire_rocket(vector org)
 
     te_explosion (org);
 
-    rocket = spawn ();
+    rocket = new(walker_rocket);
     setorigin(rocket, org);
 
     sound (self, CH_WEAPON_A, SND_HAGAR_FIRE, VOL_BASE, ATTEN_NORM);
     setsize (rocket, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
 
-    rocket.classname             = "walker_rocket";
     rocket.owner                         = self;
     rocket.bot_dodge             = true;
     rocket.bot_dodgerating     = 50;
@@ -429,7 +428,7 @@ spawnfunc(turret_walker) { if(!turret_initialize(TUR_WALKER)) remove(self); }
                         self.animflag = ANIM_MELEE;
                     }
                 }
-                else if (self.tur_head.attack_finished_single < time)
+                else if (self.tur_head.attack_finished_single[0] < time)
                 {
                     if(self.tur_head.shot_volly)
                     {
@@ -437,9 +436,9 @@ spawnfunc(turret_walker) { if(!turret_initialize(TUR_WALKER)) remove(self); }
 
                         self.tur_head.shot_volly = self.tur_head.shot_volly -1;
                         if(self.tur_head.shot_volly == 0)
-                            self.tur_head.attack_finished_single = time + (autocvar_g_turrets_unit_walker_rocket_refire);
+                            self.tur_head.attack_finished_single[0] = time + (autocvar_g_turrets_unit_walker_rocket_refire);
                         else
-                            self.tur_head.attack_finished_single = time + 0.2;
+                            self.tur_head.attack_finished_single[0] = time + 0.2;
 
                         if(self.tur_head.shot_volly > 1)
                             walker_fire_rocket(gettaginfo(self, gettagindex(self, "tag_rocket01")));
index 4da45df7fd203ecf894c5b8d990cb086b36a1ae9..a3150d820d5ab6aaea18c829fabb9ea42ddee072 100644 (file)
@@ -5,7 +5,7 @@ CLASS(WalkerTurretAttack, PortoLaunch)
 /* flags     */ ATTRIB(WalkerTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(WalkerTurretAttack, impulse, int, 5);
 /* refname   */ ATTRIB(WalkerTurretAttack, netname, string, "turret_walker");
-/* wepname   */ ATTRIB(WalkerTurretAttack, message, string, _("Walker"));
+/* wepname   */ ATTRIB(WalkerTurretAttack, m_name, string, _("Walker"));
 ENDCLASS(WalkerTurretAttack)
 REGISTER_WEAPON(WALKER, NEW(WalkerTurretAttack));
 
@@ -15,17 +15,18 @@ REGISTER_WEAPON(WALKER, NEW(WalkerTurretAttack));
 
 #ifdef SVQC
 
-METHOD(WalkerTurretAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+SOUND(WalkerTurretAttack_FIRE, W_Sound("electro_fire"));
+METHOD(WalkerTurretAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
     bool isPlayer = IS_PLAYER(actor);
-    if (fire1)
-    if (!isPlayer || weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire))) {
+    if (fire & 1)
+    if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, v_forward, false, 0, SND(WalkerTurretAttack_FIRE), CH_WEAPON_B, 0);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
-            weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+            weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
         }
         sound (actor, CH_WEAPON_A, SND_UZI_FIRE, VOL_BASE, ATTEN_NORM);
         fireBullet (actor.tur_shotorg, actor.tur_shotdir_updated, actor.shot_spread, 0, actor.shot_dmg, actor.shot_force, DEATH_TURRET_WALK_GUN.m_id, 0);
index 53c5fb74df629f2628d3e97216b1ff948b3f2a9a..b0667c89afb0146084749acbfd4e5ba105dbe099 100644 (file)
@@ -224,10 +224,7 @@ void marker_think()
 
 void mark_error(vector where,float lifetime)
 {
-       entity err;
-
-       err = spawn();
-       err.classname = "error_marker";
+       entity err = new(error_marker);
        setmodel(err, MDL_MARKER);
        setorigin(err,where);
        err.movetype = MOVETYPE_NONE;
@@ -240,10 +237,7 @@ void mark_error(vector where,float lifetime)
 
 void mark_info(vector where,float lifetime)
 {
-       entity err;
-
-       err = spawn();
-       err.classname = "info_marker";
+       entity err = spawn(info_marker);
        setmodel(err, MDL_MARKER);
        setorigin(err,where);
        err.movetype = MOVETYPE_NONE;
@@ -256,10 +250,7 @@ void mark_info(vector where,float lifetime)
 
 entity mark_misc(vector where,float lifetime)
 {
-       entity err;
-
-       err = spawn();
-       err.classname = "mark_misc";
+       entity err = spawn(mark_misc);
        setmodel(err, MDL_MARKER);
        setorigin(err,where);
        err.movetype = MOVETYPE_NONE;
index 7ac910f998fa7b0c533840dbdc74d90b98aebb6a..3e380ca696d06e0a66b0d3bde2423c997fccaa93 100644 (file)
@@ -163,205 +163,6 @@ void depthfirst(entity start, .entity up, .entity downleft, .entity right, void(
        }
 }
 
-// converts a number to a string with the indicated number of decimals
-// works for up to 10 decimals!
-string ftos_decimals(float number, float decimals)
-{
-       // inhibit stupid negative zero
-       if(number == 0)
-               number = 0;
-       // we have sprintf...
-       return sprintf("%.*f", decimals, number);
-}
-
-// Databases (hash tables)
-const float DB_BUCKETS = 8192;
-void db_save(float db, string pFilename)
-{
-       float fh, i, n;
-       fh = fopen(pFilename, FILE_WRITE);
-       if(fh < 0)
-       {
-               LOG_INFO(strcat("^1Can't write DB to ", pFilename));
-               return;
-       }
-       n = buf_getsize(db);
-       fputs(fh, strcat(ftos(DB_BUCKETS), "\n"));
-       for(i = 0; i < n; ++i)
-               fputs(fh, strcat(bufstr_get(db, i), "\n"));
-       fclose(fh);
-}
-
-int db_create()
-{
-       return buf_create();
-}
-
-int db_load(string pFilename)
-{
-       float db, fh, i, j, n;
-       string l;
-       db = buf_create();
-       if(db < 0)
-               return -1;
-       fh = fopen(pFilename, FILE_READ);
-       if(fh < 0)
-               return db;
-       l = fgets(fh);
-       if(stof(l) == DB_BUCKETS)
-       {
-               i = 0;
-               while((l = fgets(fh)))
-               {
-                       if(l != "")
-                               bufstr_set(db, i, l);
-                       ++i;
-               }
-       }
-       else
-       {
-               // different count of buckets, or a dump?
-               // need to reorganize the database then (SLOW)
-               //
-               // note: we also parse the first line (l) in case the DB file is
-               // missing the bucket count
-               do
-               {
-                       n = tokenizebyseparator(l, "\\");
-                       for(j = 2; j < n; j += 2)
-                               db_put(db, argv(j-1), uri_unescape(argv(j)));
-               }
-               while((l = fgets(fh)));
-       }
-       fclose(fh);
-       return db;
-}
-
-void db_dump(float db, string pFilename)
-{
-       float fh, i, j, n, m;
-       fh = fopen(pFilename, FILE_WRITE);
-       if(fh < 0)
-               error(strcat("Can't dump DB to ", pFilename));
-       n = buf_getsize(db);
-       fputs(fh, "0\n");
-       for(i = 0; i < n; ++i)
-       {
-               m = tokenizebyseparator(bufstr_get(db, i), "\\");
-               for(j = 2; j < m; j += 2)
-                       fputs(fh, strcat("\\", argv(j-1), "\\", argv(j), "\n"));
-       }
-       fclose(fh);
-}
-
-void db_close(float db)
-{
-       buf_del(db);
-}
-
-string db_get(float db, string pKey)
-{
-       float h;
-       h = crc16(false, pKey) % DB_BUCKETS;
-       return uri_unescape(infoget(bufstr_get(db, h), pKey));
-}
-
-void db_put(float db, string pKey, string pValue)
-{
-       float h;
-       h = crc16(false, pKey) % DB_BUCKETS;
-       bufstr_set(db, h, infoadd(bufstr_get(db, h), pKey, uri_escape(pValue)));
-}
-
-void db_test()
-{
-       float db, i;
-       LOG_INFO("LOAD...\n");
-       db = db_load("foo.db");
-       LOG_INFO("LOADED. FILL...\n");
-       for(i = 0; i < DB_BUCKETS; ++i)
-               db_put(db, ftos(random()), "X");
-       LOG_INFO("FILLED. SAVE...\n");
-       db_save(db, "foo.db");
-       LOG_INFO("SAVED. CLOSE...\n");
-       db_close(db);
-       LOG_INFO("CLOSED.\n");
-}
-
-// Multiline text file buffers
-int buf_load(string pFilename)
-{
-       float buf, fh, i;
-       string l;
-       buf = buf_create();
-       if(buf < 0)
-               return -1;
-       fh = fopen(pFilename, FILE_READ);
-       if(fh < 0)
-       {
-               buf_del(buf);
-               return -1;
-       }
-       i = 0;
-       while((l = fgets(fh)))
-       {
-               bufstr_set(buf, i, l);
-               ++i;
-       }
-       fclose(fh);
-       return buf;
-}
-
-void buf_save(float buf, string pFilename)
-{
-       float fh, i, n;
-       fh = fopen(pFilename, FILE_WRITE);
-       if(fh < 0)
-               error(strcat("Can't write buf to ", pFilename));
-       n = buf_getsize(buf);
-       for(i = 0; i < n; ++i)
-               fputs(fh, strcat(bufstr_get(buf, i), "\n"));
-       fclose(fh);
-}
-
-string format_time(float seconds)
-{
-       float days, hours, minutes;
-       seconds = floor(seconds + 0.5);
-        days = floor(seconds / 864000);
-        seconds -= days * 864000;
-        hours = floor(seconds / 36000);
-        seconds -= hours * 36000;
-       minutes = floor(seconds / 600);
-       seconds -= minutes * 600;
-        if (days > 0)
-                return sprintf(_("%d days, %02d:%02d:%02d"), days, hours, minutes, seconds);
-        else
-                return sprintf(_("%02d:%02d:%02d"), hours, minutes, seconds);
-}
-
-string mmsss(float tenths)
-{
-       float minutes;
-       string s;
-       tenths = floor(tenths + 0.5);
-       minutes = floor(tenths / 600);
-       tenths -= minutes * 600;
-       s = ftos(1000 + tenths);
-       return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 1));
-}
-
-string mmssss(float hundredths)
-{
-       float minutes;
-       string s;
-       hundredths = floor(hundredths + 0.5);
-       minutes = floor(hundredths / 6000);
-       hundredths -= minutes * 6000;
-       s = ftos(10000 + hundredths);
-       return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 2));
-}
-
 string ScoreString(int pFlags, float pValue)
 {
        string valstr;
@@ -624,23 +425,6 @@ string swapInPriorityList(string order, float i, float j)
        return order;
 }
 
-float cvar_value_issafe(string s)
-{
-       if(strstrofs(s, "\"", 0) >= 0)
-               return 0;
-       if(strstrofs(s, "\\", 0) >= 0)
-               return 0;
-       if(strstrofs(s, ";", 0) >= 0)
-               return 0;
-       if(strstrofs(s, "$", 0) >= 0)
-               return 0;
-       if(strstrofs(s, "\r", 0) >= 0)
-               return 0;
-       if(strstrofs(s, "\n", 0) >= 0)
-               return 0;
-       return 1;
-}
-
 #ifndef MENUQC
 void get_mi_min_max(float mode)
 {
@@ -803,8 +587,8 @@ float cvar_settemp(string tmp_cvar, string tmp_value)
        if(created_saved_value != -1)
        {
                // creating a new entity to keep track of this cvar
-               e = spawn();
-               e.classname = "saved_cvar_value";
+               e = new(saved_cvar_value);
+               make_pure(e);
                e.netname = strzone(tmp_cvar);
                e.message = strzone(cvar_string(tmp_cvar));
                created_saved_value = 1;
@@ -835,150 +619,6 @@ float cvar_settemp_restore()
        return i;
 }
 
-float rgb_mi_ma_to_hue(vector rgb, float mi, float ma)
-{
-       if(mi == ma)
-               return 0;
-       else if(ma == rgb.x)
-       {
-               if(rgb.y >= rgb.z)
-                       return (rgb.y - rgb.z) / (ma - mi);
-               else
-                       return (rgb.y - rgb.z) / (ma - mi) + 6;
-       }
-       else if(ma == rgb.y)
-               return (rgb.z - rgb.x) / (ma - mi) + 2;
-       else // if(ma == rgb_z)
-               return (rgb.x - rgb.y) / (ma - mi) + 4;
-}
-
-vector hue_mi_ma_to_rgb(float hue, float mi, float ma)
-{
-       vector rgb;
-
-       hue -= 6 * floor(hue / 6);
-
-       //else if(ma == rgb_x)
-       //      hue = 60 * (rgb_y - rgb_z) / (ma - mi);
-       if(hue <= 1)
-       {
-               rgb.x = ma;
-               rgb.y = hue * (ma - mi) + mi;
-               rgb.z = mi;
-       }
-       //else if(ma == rgb_y)
-       //      hue = 60 * (rgb_z - rgb_x) / (ma - mi) + 120;
-       else if(hue <= 2)
-       {
-               rgb.x = (2 - hue) * (ma - mi) + mi;
-               rgb.y = ma;
-               rgb.z = mi;
-       }
-       else if(hue <= 3)
-       {
-               rgb.x = mi;
-               rgb.y = ma;
-               rgb.z = (hue - 2) * (ma - mi) + mi;
-       }
-       //else // if(ma == rgb_z)
-       //      hue = 60 * (rgb_x - rgb_y) / (ma - mi) + 240;
-       else if(hue <= 4)
-       {
-               rgb.x = mi;
-               rgb.y = (4 - hue) * (ma - mi) + mi;
-               rgb.z = ma;
-       }
-       else if(hue <= 5)
-       {
-               rgb.x = (hue - 4) * (ma - mi) + mi;
-               rgb.y = mi;
-               rgb.z = ma;
-       }
-       //else if(ma == rgb_x)
-       //      hue = 60 * (rgb_y - rgb_z) / (ma - mi);
-       else // if(hue <= 6)
-       {
-               rgb.x = ma;
-               rgb.y = mi;
-               rgb.z = (6 - hue) * (ma - mi) + mi;
-       }
-
-       return rgb;
-}
-
-vector rgb_to_hsv(vector rgb)
-{
-       float mi, ma;
-       vector hsv;
-
-       mi = min(rgb.x, rgb.y, rgb.z);
-       ma = max(rgb.x, rgb.y, rgb.z);
-
-       hsv.x = rgb_mi_ma_to_hue(rgb, mi, ma);
-       hsv.z = ma;
-
-       if(ma == 0)
-               hsv.y = 0;
-       else
-               hsv.y = 1 - mi/ma;
-
-       return hsv;
-}
-
-vector hsv_to_rgb(vector hsv)
-{
-       return hue_mi_ma_to_rgb(hsv.x, hsv.z * (1 - hsv.y), hsv.z);
-}
-
-vector rgb_to_hsl(vector rgb)
-{
-       float mi, ma;
-       vector hsl;
-
-       mi = min(rgb.x, rgb.y, rgb.z);
-       ma = max(rgb.x, rgb.y, rgb.z);
-
-       hsl.x = rgb_mi_ma_to_hue(rgb, mi, ma);
-
-       hsl.z = 0.5 * (mi + ma);
-       if(mi == ma)
-               hsl.y = 0;
-       else if(hsl.z <= 0.5)
-               hsl.y = (ma - mi) / (2*hsl.z);
-       else // if(hsl_z > 0.5)
-               hsl.y = (ma - mi) / (2 - 2*hsl.z);
-
-       return hsl;
-}
-
-vector hsl_to_rgb(vector hsl)
-{
-       float mi, ma, maminusmi;
-
-       if(hsl.z <= 0.5)
-               maminusmi = hsl.y * 2 * hsl.z;
-       else
-               maminusmi = hsl.y * (2 - 2 * hsl.z);
-
-       // hsl_z     = 0.5 * mi + 0.5 * ma
-       // maminusmi =     - mi +       ma
-       mi = hsl.z - 0.5 * maminusmi;
-       ma = hsl.z + 0.5 * maminusmi;
-
-       return hue_mi_ma_to_rgb(hsl.x, mi, ma);
-}
-
-string rgb_to_hexcolor(vector rgb)
-{
-       return
-               strcat(
-                       "^x",
-                       DEC_TO_HEXDIGIT(floor(rgb.x * 15 + 0.5)),
-                       DEC_TO_HEXDIGIT(floor(rgb.y * 15 + 0.5)),
-                       DEC_TO_HEXDIGIT(floor(rgb.z * 15 + 0.5))
-               );
-}
-
 float textLengthUpToWidth(string theText, float maxWidth, vector theSize, textLengthUpToWidth_widthFunction_t w)
 {
        // STOP.
@@ -1297,60 +937,6 @@ float isGametypeInFilter(float gt, float tp, float ts, string pattern)
        return 1;
 }
 
-vector solve_quadratic(float a, float b, float c) // ax^2 + bx + c = 0
-{
-       vector v;
-       float D;
-       v = '0 0 0';
-       if(a == 0)
-       {
-               if(b != 0)
-               {
-                       v.x = v.y = -c / b;
-                       v.z = 1;
-               }
-               else
-               {
-                       if(c == 0)
-                       {
-                               // actually, every number solves the equation!
-                               v.z = 1;
-                       }
-               }
-       }
-       else
-       {
-               D = b*b - 4*a*c;
-               if(D >= 0)
-               {
-                       D = sqrt(D);
-                       if(a > 0) // put the smaller solution first
-                       {
-                               v.x = ((-b)-D) / (2*a);
-                               v.y = ((-b)+D) / (2*a);
-                       }
-                       else
-                       {
-                               v.x = (-b+D) / (2*a);
-                               v.y = (-b-D) / (2*a);
-                       }
-                       v.z = 1;
-               }
-               else
-               {
-                       // complex solutions!
-                       D = sqrt(-D);
-                       v.x = -b / (2*a);
-                       if(a > 0)
-                               v.y =  D / (2*a);
-                       else
-                               v.y = -D / (2*a);
-                       v.z = 0;
-               }
-       }
-       return v;
-}
-
 vector solve_shotdirection(vector myorg, vector myvel, vector eorg, vector evel, float spd, float newton_style)
 {
        vector ret;
@@ -1535,27 +1121,6 @@ string getcurrentmod()
                return argv(n - 1);
 }
 
-// from the GNU Scientific Library
-float gsl_ran_gaussian_lastvalue;
-float gsl_ran_gaussian_lastvalue_set;
-float gsl_ran_gaussian(float sigma)
-{
-       float a, b;
-       if(gsl_ran_gaussian_lastvalue_set)
-       {
-               gsl_ran_gaussian_lastvalue_set = 0;
-               return sigma * gsl_ran_gaussian_lastvalue;
-       }
-       else
-       {
-               a = random() * 2 * M_PI;
-               b = sqrt(-2 * log(random()));
-               gsl_ran_gaussian_lastvalue = cos(a) * b;
-               gsl_ran_gaussian_lastvalue_set = 1;
-               return sigma * sin(a) * b;
-       }
-}
-
 float matchacl(string acl, string str)
 {
        string t, s;
@@ -1713,57 +1278,6 @@ float get_model_parameters(string m, float sk)
        return 1;
 }
 
-float vercmp_recursive(string v1, string v2)
-{
-       float dot1, dot2;
-       string s1, s2;
-       float r;
-
-       dot1 = strstrofs(v1, ".", 0);
-       dot2 = strstrofs(v2, ".", 0);
-       if(dot1 == -1)
-               s1 = v1;
-       else
-               s1 = substring(v1, 0, dot1);
-       if(dot2 == -1)
-               s2 = v2;
-       else
-               s2 = substring(v2, 0, dot2);
-
-       r = stof(s1) - stof(s2);
-       if(r != 0)
-               return r;
-
-       r = strcasecmp(s1, s2);
-       if(r != 0)
-               return r;
-
-       if(dot1 == -1)
-               if(dot2 == -1)
-                       return 0;
-               else
-                       return -1;
-       else
-               if(dot2 == -1)
-                       return 1;
-               else
-                       return vercmp_recursive(substring(v1, dot1 + 1, 999), substring(v2, dot2 + 1, 999));
-}
-
-float vercmp(string v1, string v2)
-{
-       if(strcasecmp(v1, v2) == 0) // early out check
-               return 0;
-
-       // "git" beats all
-       if(v1 == "git")
-               return 1;
-       if(v2 == "git")
-               return -1;
-
-       return vercmp_recursive(v1, v2);
-}
-
 // x-encoding (encoding as zero length invisible string)
 const string XENCODE_2  = "xX";
 const string XENCODE_22 = "0123456789abcdefABCDEF";
@@ -1807,16 +1321,6 @@ string strlimitedlen(string input, string truncation, float strip_colors, float
                return strcat(substring(input, 0, (strlen(input) - strlen(truncation))), truncation);
 }*/
 
-#ifdef CSQC
-entity ReadCSQCEntity()
-{
-       int f = ReadShort();
-       if(f == 0)
-               return world;
-       return findfloat(world, entnum, f);
-}
-#endif
-
 float shutdown_running;
 #ifdef SVQC
 void SV_Shutdown()
@@ -1840,44 +1344,6 @@ void m_shutdown()
        cvar_settemp_restore(); // this must be done LAST, but in any case
 }
 
-const float APPROXPASTTIME_ACCURACY_REQUIREMENT = 0.05;
-#define APPROXPASTTIME_MAX (16384 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
-#define APPROXPASTTIME_RANGE (64 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
-// this will use the value:
-//   128
-// accuracy near zero is APPROXPASTTIME_MAX/(256*255)
-// accuracy at x is 1/derivative, i.e.
-//   APPROXPASTTIME_MAX * (1 + 256 * (dt / APPROXPASTTIME_MAX))^2 / 65536
-#ifdef SVQC
-void WriteApproxPastTime(float dst, float t)
-{
-       float dt = time - t;
-
-       // warning: this is approximate; do not resend when you don't have to!
-       // be careful with sendflags here!
-       // we want: 0 -> 0.05, 1 -> 0.1, ..., 255 -> 12.75
-
-       // map to range...
-       dt = 256 * (dt / ((APPROXPASTTIME_MAX / 256) + dt));
-
-       // round...
-       dt = rint(bound(0, dt, 255));
-
-       WriteByte(dst, dt);
-}
-#endif
-#ifdef CSQC
-float ReadApproxPastTime()
-{
-       float dt = ReadByte();
-
-       // map from range...PPROXPASTTIME_MAX / 256
-       dt = (APPROXPASTTIME_MAX / 256) * (dt / (256 - dt));
-
-       return servertime - dt;
-}
-#endif
-
 #ifndef MENUQC
 .float skeleton_bones_index;
 void Skeleton_SetBones(entity e)
index 8bedccf0ae44b38d9935e48686c154de7a362479..f0d180dad1d0bdb868baea5767806ab52208c75f 100644 (file)
@@ -101,11 +101,6 @@ float almost_in_bounds(float a, float b, float c);
 float power2of(float e);
 float log2of(float x);
 
-const string HEXDIGITS = "0123456789ABCDEF0123456789abcdef";
-#define HEXDIGIT_TO_DEC_RAW(d) (strstrofs(HEXDIGITS, (d), 0))
-#define HEXDIGIT_TO_DEC(d) ((HEXDIGIT_TO_DEC_RAW(d) | 0x10) - 0x10)
-#define DEC_TO_HEXDIGIT(d) (substring(HEXDIGITS, (d), 1))
-
 vector rgb_to_hsl(vector rgb);
 vector hsl_to_rgb(vector hsl);
 vector rgb_to_hsv(vector rgb);
@@ -174,11 +169,7 @@ float float2range01(float f);
 
 float gsl_ran_gaussian(float sigma);
 
-string car(string s); // returns first word
-string cdr(string s); // returns all but first word
 float matchacl(string acl, string str); // matches str against ACL acl (with entries +foo*, +foo, +*foo, +*foo*, and same with - for forbidding)
-float startsWith(string haystack, string needle);
-float startsWithNocase(string haystack, string needle);
 
 string get_model_datafilename(string mod, float skn, string fil); // skin -1 will return wildcard, mod string_null will also put wildcard there
 string get_model_parameters_modelname;
@@ -215,10 +206,6 @@ const float XENCODE_LEN = 5;
 string xencode(float f);
 float xdecode(string s);
 
-#ifdef CSQC
-entity ReadCSQCEntity();
-#endif
-
 #ifndef MENUQC
 string strtolower(string s);
 #endif
@@ -282,11 +269,6 @@ string CCR(string input);
        #define normal_or_gentle(normal, gentle) (GENTLE ? ((gentle != "") ? gentle : normal) : normal)
 #endif
 
-// allow writing to also pass through to spectators (like so spectators see the same centerprints as players for example)
-#define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname
-#define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
-#define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
-
 vector vec3(float x, float y, float z);
 
 #ifndef MENUQC
index 72d72d29d19d14a1cd7de16ce51a8399c1347d74..c7b84582239e1c129ab4de4d95d2e79fb6a82f66 100644 (file)
@@ -23,6 +23,8 @@ STATIC_INIT(vehicles_common_initialize)
 }
 #endif
 
+REGISTER_NET_LINKED(ENT_CLIENT_AUXILIARYXHAIR)
+
 #if defined(SVQC)
        #include "sv_vehicles.qc"
 #elif defined(CSQC)
index a44eb2209e673768ada5904ab7043e70df5e8273..3867cf1edd5490b7403750de6f38a5c12c436606 100644 (file)
@@ -3,13 +3,17 @@
 
 #include "vehicle.qh"
 
-REGISTRY(Vehicles, BIT(3))
-REGISTER_REGISTRY(RegisterVehicles)
+REGISTRY(Vehicles, BITS(3))
+#define Vehicles_from(i) _Vehicles_from(i, VEH_Null)
+#define get_vehicleinfo(i) Vehicles_from(i)
+REGISTER_REGISTRY(Vehicles)
+REGISTRY_CHECK(Vehicles)
+
 const int VEH_FIRST = 1;
 #define VEH_LAST (Vehicles_COUNT - 1)
 
 /** If you register a new vehicle, make sure to add it to all.inc */
-#define REGISTER_VEHICLE(id, inst) REGISTER(RegisterVehicles, VEH, Vehicles, id, vehicleid, inst)
+#define REGISTER_VEHICLE(id, inst) REGISTER(Vehicles, VEH, id, vehicleid, inst)
 
 #if defined(SVQC)
        #include "sv_vehicles.qh"
@@ -19,15 +23,6 @@ const int VEH_FIRST = 1;
 
 REGISTER_VEHICLE(Null, NEW(Vehicle));
 
-Vehicle get_vehicleinfo(int id)
-{
-       if (id >= VEH_FIRST && id <= VEH_LAST) {
-               Vehicle v = Vehicles[id];
-               if (v) return v;
-       }
-       return VEH_Null;
-}
-
 #include "all.inc"
 
 #endif
index b24097c03303a11f7fa30168c155c4214b8a6999..be615772a9d5714eae39657e3c4b736c57a3ad5d 100644 (file)
@@ -45,7 +45,7 @@ void AuxiliaryXhair_Draw2D(entity this)
                self.draw2d = func_null;
 }
 
-void Net_AuXair2(bool bIsNew)
+NET_HANDLE(ENT_CLIENT_AUXILIARYXHAIR, bool isnew)
 {
        int axh_id      = bound(0, ReadByte(), MAX_AXH);
        entity axh              = AuxiliaryXhair[axh_id];
@@ -70,11 +70,13 @@ void Net_AuXair2(bool bIsNew)
        axh.colormod_z          = ReadByte() / 255;
        axh.cnt                         = time;
        axh.draw2d                      = AuxiliaryXhair_Draw2D;
+       return true;
 }
 
-void Net_VehicleSetup()
-{SELFPARAM();
+NET_HANDLE(TE_CSQC_VEHICLESETUP, bool isnew)
+{
        int hud_id = ReadByte();
+       return = true;
 
        // hud_id == 0 means we exited a vehicle, so stop alarm sound/s
        if(hud_id == 0)
index 87f0751af81d78623caecc21fe266c5ba3b9822a..fbaf88c6f916526f1694ac2f0c2ca493bfc15b34 100644 (file)
@@ -4,10 +4,6 @@
 vector vehicleHud_Size;
 vector vehicleHud_Pos;
 
-void Net_AuXair2(float bIsNew);
-
-void Net_VehicleSetup();
-
 void RaptorCBShellfragDraw(entity this);
 void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang);
 
index a00cdcfa343dd4e8b207b2ab3ed06e3370557f36..7f0537eeb502583fdcdd16ab8ebb74e423e9a359 100644 (file)
@@ -40,7 +40,7 @@ bool vehicle_send(entity to, int sf)
 bool SendAuxiliaryXhair(entity this, entity to, int sf)
 {
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR);
 
        WriteByte(MSG_ENTITY, self.cnt);
 
@@ -87,8 +87,7 @@ void CSQCVehicleSetup(entity own, int vehicle_id)
 
        msg_entity = own;
 
-       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-       WriteByte(MSG_ONE, TE_CSQC_VEHICLESETUP);
+       WriteHeader(MSG_ONE, TE_CSQC_VEHICLESETUP);
        WriteByte(MSG_ONE, vehicle_id);
 }
 
@@ -455,10 +454,8 @@ void vehicles_reset_colors()
 
 void vehicles_clearreturn(entity veh)
 {
-       entity ret;
        // Remove "return helper", if any.
-       ret = findchain(classname, "vehicle_return");
-       while(ret)
+       for (entity ret = findchain(classname, "vehicle_return"); ret; ret = ret.chain)
        {
                if(ret.wp00 == veh)
                {
@@ -471,7 +468,6 @@ void vehicles_clearreturn(entity veh)
 
                        return;
                }
-               ret = ret.chain;
        }
 }
 
@@ -548,8 +544,7 @@ void vehicles_setreturn(entity veh)
 
        vehicles_clearreturn(veh);
 
-       ret = spawn();
-       ret.classname   = "vehicle_return";
+       ret = new(vehicle_return);
        ret.wp00           = veh;
        ret.team                = veh.team;
        ret.think          = vehicles_showwp;
@@ -634,7 +629,7 @@ void vehicles_painframe()
                float _ftmp;
                _ftmp = self.owner.vehicle_health / 50;
                self.pain_frame = time + 0.1 + (random() * 0.5 * _ftmp);
-               pointparticles(particleeffectnum(EFFECT_SMOKE_SMALL), (self.origin + (randomvec() * 80)), '0 0 0', 1);
+               pointparticles(EFFECT_SMOKE_SMALL, (self.origin + (randomvec() * 80)), '0 0 0', 1);
 
                if(self.vehicle_flags & VHF_DMGSHAKE)
                        self.velocity += randomvec() * 30;
@@ -1234,9 +1229,9 @@ bool vehicle_initialize(entity veh, bool nodrop)
 
        self.vehicle_flags |= VHF_ISVEHICLE;
 
-       self.vehicle_viewport           = spawn();
-       self.vehicle_hudmodel           = spawn();
-       self.tur_head                           = spawn();
+       self.vehicle_viewport           = new(vehicle_viewport);
+       self.vehicle_hudmodel           = new(vehicle_hudmodel);
+       self.tur_head                           = new(tur_head);
        self.tur_head.owner                     = self;
        self.takedamage                         = DAMAGE_NO;
        self.bot_attack                         = true;
index 2eee4dcf5af11a90ae40b077f1962c9fd3e2133b..244b4e2f6126e7fbabf9ca5533b4e24405618332 100644 (file)
@@ -174,13 +174,13 @@ float bumblebee_gunner_frame()
 
        if(!forbidWeaponUse(gunner))
        if(gunner.BUTTON_ATCK)
-               if(time > gun.attack_finished_single)
+               if(time > gun.attack_finished_single[0])
                        if(gun.vehicle_energy >= autocvar_g_vehicle_bumblebee_cannon_cost)
                        {
                                gun.vehicle_energy -= autocvar_g_vehicle_bumblebee_cannon_cost;
                                bumblebee_fire_cannon(gun, "fire", gunner);
                                gun.delay = time;
-                               gun.attack_finished_single = time + autocvar_g_vehicle_bumblebee_cannon_refire;
+                               gun.attack_finished_single[0] = time + autocvar_g_vehicle_bumblebee_cannon_refire;
                        }
 
        VEHICLE_UPDATE_PLAYER(gunner, health, bumblebee);
@@ -859,9 +859,9 @@ spawnfunc(vehicle_bumblebee)
                                self.vehicle_shieldent.alpha = -1;
                                self.vehicle_shieldent.effects = EF_LOWPRECISION | EF_NODRAW;
 
-                               self.gun1 = spawn();
-                               self.gun2 = spawn();
-                               self.gun3 = spawn();
+                               self.gun1 = new(vehicle_playerslot);
+                               self.gun2 = new(vehicle_playerslot);
+                               self.gun3 = new(bumblebee_raygun);
 
                                self.vehicle_flags |= VHF_MULTISLOT;
 
@@ -869,8 +869,6 @@ spawnfunc(vehicle_bumblebee)
                                self.gun2.owner = self;
                                self.gun3.owner = self;
 
-                               self.gun1.classname = self.gun2.classname = "vehicle_playerslot";
-
                                setmodel(self.gun1, MDL_VEH_BUMBLEBEE_CANNON_RIGHT);
                                setmodel(self.gun2, MDL_VEH_BUMBLEBEE_CANNON_LEFT);
                                setmodel(self.gun3, MDL_VEH_BUMBLEBEE_CANNON_CENTER);
index 7c387e44864993070eaf89768d70d48027825112..b043038921460bb2768aca34238932a49352e566 100644 (file)
@@ -2,7 +2,6 @@
 #define BUMBLEBEE_H
 
 #ifdef CSQC
-void bumble_raygun_read(bool bIsNew);
 
 void CSQC_BUMBLE_GUN_HUD();
 #endif
index 722c6852e7ddf56d66844cdcc14b8de294c95a7e..8ff604579c246715959e4164c7290bab31bd79bd 100644 (file)
@@ -7,6 +7,8 @@
 
 #ifdef IMPLEMENTATION
 
+REGISTER_NET_LINKED(ENT_CLIENT_BUMBLE_RAYGUN)
+
 #ifdef SVQC
 
 float autocvar_g_vehicle_bumblebee_cannon_cost;
@@ -30,7 +32,7 @@ void bumblebee_fire_cannon(entity _gun, string _tagname, entity _owner)
 
 bool bumble_raygun_send(entity this, entity to, float sf)
 {
-    WriteByte(MSG_ENTITY, ENT_CLIENT_BUMBLE_RAYGUN);
+    WriteHeader(MSG_ENTITY, ENT_CLIENT_BUMBLE_RAYGUN);
 
     WriteByte(MSG_ENTITY, sf);
     if(sf & BRG_SETUP)
@@ -63,8 +65,8 @@ bool bumble_raygun_send(entity this, entity to, float sf)
 
 void bumble_raygun_draw(entity this);
 
-void bumble_raygun_read(bool bIsNew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_BUMBLE_RAYGUN, bool isnew)
+{
     int sf = ReadByte();
 
     if(sf & BRG_SETUP)
@@ -99,8 +101,10 @@ void bumble_raygun_read(bool bIsNew)
         self.move_origin_y = ReadCoord();
         self.move_origin_z = ReadCoord();
     }
+    return true;
 }
 
+.float bumble_raygun_nextdraw;
 void bumble_raygun_draw(entity this)
 {
     float _len;
@@ -110,11 +114,11 @@ void bumble_raygun_draw(entity this)
     _len = vlen(self.origin - self.move_origin);
     _dir = normalize(self.move_origin - self.origin);
 
-    if(self.total_damages < time)
+    if(self.bumble_raygun_nextdraw < time)
     {
-        boxparticles(particleeffectnum(Effects[self.traileffect]), self, self.origin, self.origin + _dir * -64, _dir * -_len , _dir * -_len, 1, PARTICLES_USEALPHA);
+        boxparticles(particleeffectnum(Effects_from(self.traileffect)), self, self.origin, self.origin + _dir * -64, _dir * -_len , _dir * -_len, 1, PARTICLES_USEALPHA);
         boxparticles(self.lip, self, self.move_origin, self.move_origin + _dir * -64, _dir * -200 , _dir * -200, 1, PARTICLES_USEALPHA);
-        self.total_damages = time + 0.1;
+        self.bumble_raygun_nextdraw = time + 0.1;
     }
 
     float i, df, sz, al;
index 8c45b4aa9dc5802c500d8cad3fab15428b79d9f0..38e343f65e8827a9a9e5a7b3c33b1e0de5638b7b 100644 (file)
@@ -153,11 +153,11 @@ void racer_align4point(float _delta)
        self.angles_z *= 1 - (autocvar_g_vehicle_racer_anglestabilizer * _delta);
 }
 
-void racer_fire_rocket_aim(string tagname, entity trg)
+void racer_fire_rocket_aim(entity player, string tagname, entity trg)
 {
-       SELFPARAM();
-       vector v = gettaginfo(self, gettagindex(self, tagname));
-       racer_fire_rocket(v, v_forward, trg);
+       entity racer = player.vehicle;
+       vector v = gettaginfo(racer, gettagindex(racer, tagname));
+       racer_fire_rocket(player, v, v_forward, trg);
 }
 
 float racer_frame()
@@ -257,7 +257,7 @@ float racer_frame()
        {
 #ifdef SVQC
                if(time - racer.wait > 0.2)
-                       pointparticles(particleeffectnum(EFFECT_RACER_BOOSTER), self.origin - v_forward * 32, v_forward  * vlen(self.velocity), 1);
+                       pointparticles(EFFECT_RACER_BOOSTER, self.origin - v_forward * 32, v_forward  * vlen(self.velocity), 1);
 #endif
 
                racer.wait = time;
@@ -278,7 +278,7 @@ float racer_frame()
                {
                        traceline(racer.origin, racer.origin - '0 0 256', MOVE_NORMAL, self);
                        if(trace_fraction != 1.0)
-                               pointparticles(particleeffectnum(EFFECT_SMOKE_SMALL), trace_endpos, '0 0 0', 1);
+                               pointparticles(EFFECT_SMOKE_SMALL, trace_endpos, '0 0 0', 1);
 
                        racer.invincible_finished = time + 0.1 + (random() * 0.1);
                }
@@ -321,7 +321,8 @@ float racer_frame()
                // Fix z-aim (for chase mode)
                crosshair_trace(player);
                w_shotdir.z = normalize(trace_endpos - org).z * 0.5;
-               wep1.wr_think(wep1, self, true, false);
+               .entity weaponentity = weaponentities[0];
+               wep1.wr_think(wep1, self, weaponentity, 1);
        }
 
        if(autocvar_g_vehicle_racer_rocket_locktarget)
@@ -350,12 +351,12 @@ float racer_frame()
 
                if(racer.misc_bulletcounter == 1)
                {
-                       racer_fire_rocket_aim("tag_rocket_r", (racer.lock_strength == 1 && racer.lock_target) ? racer.lock_target : world);
+                       racer_fire_rocket_aim(player, "tag_rocket_r", (racer.lock_strength == 1 && racer.lock_target) ? racer.lock_target : world);
                        player.vehicle_ammo2 = 50;
                }
                else if(racer.misc_bulletcounter == 2)
                {
-                       racer_fire_rocket_aim("tag_rocket_l", (racer.lock_strength == 1 && racer.lock_target) ? racer.lock_target : world);
+                       racer_fire_rocket_aim(player, "tag_rocket_l", (racer.lock_strength == 1 && racer.lock_target) ? racer.lock_target : world);
                        racer.lock_strength  = 0;
                        racer.lock_target       = world;
                        racer.misc_bulletcounter = 0;
index 6a2339f1e3a4878bee67a59657113595064faae7..21f4313c6337a716d37b8a09caa7b3a1c4ca704a 100644 (file)
@@ -7,14 +7,14 @@ CLASS(RacerAttack, PortoLaunch)
 /* flags     */ ATTRIB(RacerAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(RacerAttack, impulse, int, 3);
 /* refname   */ ATTRIB(RacerAttack, netname, string, "racercannon");
-/* wepname   */ ATTRIB(RacerAttack, message, string, _("Racer cannon"));
+/* wepname   */ ATTRIB(RacerAttack, m_name, string, _("Racer cannon"));
 ENDCLASS(RacerAttack)
 REGISTER_WEAPON(RACER, NEW(RacerAttack));
 
 // TODO: move into implementation
 #ifdef SVQC
 float autocvar_g_vehicle_racer_rocket_refire;
-void racer_fire_rocket(vector org, vector dir, entity trg);
+void racer_fire_rocket(entity player, vector org, vector dir, entity trg);
 #endif
 
 #endif
@@ -41,14 +41,14 @@ float autocvar_g_vehicle_racer_rocket_turnrate;
 float autocvar_g_vehicle_racer_rocket_climbspeed;
 float autocvar_g_vehicle_racer_rocket_locked_maxangle;
 
-void racer_fire_rocket(vector org, vector dir, entity trg);
-METHOD(RacerAttack, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+void racer_fire_rocket(entity player, vector org, vector dir, entity trg);
+METHOD(RacerAttack, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
 {
     bool isPlayer = IS_PLAYER(actor);
     entity player = isPlayer ? actor : actor.owner;
     entity veh = player.vehicle;
-    if (fire1)
-    if (weapon_prepareattack(thiswep, player, false, autocvar_g_vehicle_racer_cannon_refire)) {
+    if (fire & 1)
+    if (weapon_prepareattack(thiswep, player, weaponentity, false, autocvar_g_vehicle_racer_cannon_refire)) {
         if (veh) {
             veh.vehicle_energy -= autocvar_g_vehicle_racer_cannon_cost;
             veh.wait = time;
@@ -61,13 +61,13 @@ METHOD(RacerAttack, wr_think, void(entity thiswep, entity actor, bool fire1, boo
                                autocvar_g_vehicle_racer_cannon_damage, autocvar_g_vehicle_racer_cannon_radius, autocvar_g_vehicle_racer_cannon_force,  0,
                                DEATH_VH_WAKI_GUN.m_id, PROJECTILE_WAKICANNON, 0, true, true, player);
         bolt.velocity = normalize(dir) * autocvar_g_vehicle_racer_cannon_speed;
-        weapon_thinkf(player, WFRAME_FIRE1, 0, w_ready);
+        weapon_thinkf(player, weaponentity, WFRAME_FIRE1, 0, w_ready);
     }
-    if (fire2)
-    if (!isPlayer || weapon_prepareattack(thiswep, actor, false, 0.2)) {
+    if (fire & 2)
+    if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, 0.2)) {
         if (isPlayer) W_SetupShot_Dir(actor, v_forward, false, 0, SND(Null), CH_WEAPON_B, 0);
-        racer_fire_rocket(w_shotorg, w_shotdir, NULL);
-        weapon_thinkf(actor, WFRAME_FIRE2, 0, w_ready);
+        racer_fire_rocket(player, w_shotorg, w_shotdir, NULL);
+        weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, 0, w_ready);
     }
 }
 
@@ -83,12 +83,12 @@ METHOD(RacerAttack, wr_checkammo1, bool(RacerAttack thiswep))
 void racer_rocket_tracker();
 void racer_rocket_groundhugger();
 
-void racer_fire_rocket(vector org, vector dir, entity trg)
+void racer_fire_rocket(entity player, vector org, vector dir, entity trg)
 {SELFPARAM();
     entity rocket = vehicles_projectile(EFFECT_RACER_ROCKETLAUNCH.eent_eff_name, SND(ROCKET_FIRE),
                            org, dir * autocvar_g_vehicle_racer_rocket_speed,
                            autocvar_g_vehicle_racer_rocket_damage, autocvar_g_vehicle_racer_rocket_radius, autocvar_g_vehicle_racer_rocket_force, 3,
-                           DEATH_VH_WAKI_ROCKET.m_id, PROJECTILE_WAKIROCKET, 20, false, false, self.owner);
+                           DEATH_VH_WAKI_ROCKET.m_id, PROJECTILE_WAKIROCKET, 20, false, false, player);
 
     rocket.lip                   = autocvar_g_vehicle_racer_rocket_accel * sys_frametime;
     rocket.wait                         = autocvar_g_vehicle_racer_rocket_turnrate;
index 58a189a85074bf53fb6cce14fe5b0868271eaa6d..866a69eb2e8c59720f82774449835e8a0e6e38bb 100644 (file)
@@ -392,7 +392,8 @@ float raptor_frame()
        if(player.BUTTON_ATCK)
        if (wep1.wr_checkammo1(wep1))
        {
-               wep1.wr_think(wep1, self, true, false);
+           .entity weaponentity = weaponentities[0];
+               wep1.wr_think(wep1, self, weaponentity, 1);
        }
 
        if(self.vehicle_flags  & VHF_SHIELDREGEN)
@@ -411,7 +412,8 @@ float raptor_frame()
                if(time > raptor.lip + autocvar_g_vehicle_raptor_bombs_refire)
                if(player.BUTTON_ATCK2)
                {
-                       wep2a.wr_think(wep2a, self, false, true);
+                   .entity weaponentity = weaponentities[1];
+                       wep2a.wr_think(wep2a, self, weaponentity, 2);
                        raptor.delay = time + autocvar_g_vehicle_raptor_bombs_refire;
                        raptor.lip   = time;
                }
@@ -422,7 +424,8 @@ float raptor_frame()
                if(time > raptor.lip + autocvar_g_vehicle_raptor_flare_refire)
                if(player.BUTTON_ATCK2)
                {
-                       wep2b.wr_think(wep2b, self, false, true);
+                   .entity weaponentity = weaponentities[1];
+                       wep2b.wr_think(wep2b, self, weaponentity, 2);
                        raptor.delay = time + autocvar_g_vehicle_raptor_flare_refire;
                        raptor.lip   = time;
                }
@@ -671,10 +674,10 @@ spawnfunc(vehicle_raptor)
 
                                self.frame = 0;
 
-                               self.bomb1 = spawn();
-                               self.bomb2 = spawn();
-                               self.gun1  = spawn();
-                               self.gun2  = spawn();
+                               self.bomb1 = new(raptor_bomb);
+                               self.bomb2 = new(raptor_bomb);
+                               self.gun1  = new(raptor_gun);
+                               self.gun2  = new(raptor_gun);
 
                                setmodel(self.bomb1, MDL_VEH_RAPTOR_CB_FOLDED);
                                setmodel(self.bomb2, MDL_VEH_RAPTOR_CB_FOLDED);
@@ -705,7 +708,7 @@ spawnfunc(vehicle_raptor)
                                self.angles = self.bomb1.angles;
                                self.bomb1.angles = '0 0 0';
 
-                               spinner = spawn();
+                               spinner = new(raptor_spinner);
                                spinner.owner = self;
                                setmodel(spinner, MDL_VEH_RAPTOR_PROP);
                                setattachment(spinner, self, "engine_left");
@@ -713,7 +716,7 @@ spawnfunc(vehicle_raptor)
                                spinner.avelocity = '0 90 0';
                                self.bomb1.gun1 = spinner;
 
-                               spinner = spawn();
+                               spinner = new(raptor_spinner);
                                spinner.owner = self;
                                setmodel(spinner, MDL_VEH_RAPTOR_PROP);
                                setattachment(spinner, self, "engine_right");
index 69d981beb3e35c0229ebfcfafe54c4043061bef0..6783a92cc9a4aa1d128ded8cdb73572b3b30e337 100644 (file)
@@ -7,7 +7,7 @@ CLASS(RaptorCannon, PortoLaunch)
 /* flags     */ ATTRIB(RaptorCannon, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(RaptorCannon, impulse, int, 3);
 /* refname   */ ATTRIB(RaptorCannon, netname, string, "raptorcannon");
-/* wepname   */ ATTRIB(RaptorCannon, message, string, _("Raptor cannon"));
+/* wepname   */ ATTRIB(RaptorCannon, m_name, string, _("Raptor cannon"));
 ENDCLASS(RaptorCannon)
 REGISTER_WEAPON(RAPTOR, NEW(RaptorCannon));
 
@@ -15,7 +15,7 @@ CLASS(RaptorBomb, PortoLaunch)
 /* flags     */ ATTRIB(RaptorBomb, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(RaptorBomb, impulse, int, 3);
 /* refname   */ ATTRIB(RaptorBomb, netname, string, "raptorbomb");
-/* wepname   */ ATTRIB(RaptorBomb, message, string, _("Raptor bomb"));
+/* wepname   */ ATTRIB(RaptorBomb, m_name, string, _("Raptor bomb"));
 ENDCLASS(RaptorBomb)
 REGISTER_WEAPON(RAPTOR_BOMB, NEW(RaptorBomb));
 
@@ -23,7 +23,7 @@ CLASS(RaptorFlare, PortoLaunch)
 /* flags     */ ATTRIB(RaptorFlare, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(RaptorFlare, impulse, int, 3);
 /* refname   */ ATTRIB(RaptorFlare, netname, string, "raptorflare");
-/* wepname   */ ATTRIB(RaptorFlare, message, string, _("Raptor flare"));
+/* wepname   */ ATTRIB(RaptorFlare, m_name, string, _("Raptor flare"));
 ENDCLASS(RaptorFlare)
 REGISTER_WEAPON(RAPTOR_FLARE, NEW(RaptorFlare));
 
@@ -51,14 +51,14 @@ float autocvar_g_vehicle_raptor_bomblet_radius;
 float autocvar_g_vehicle_raptor_bomblet_force;
 float autocvar_g_vehicle_raptor_bomblet_explode_delay;
 
-METHOD(RaptorCannon, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+METHOD(RaptorCannon, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
     bool isPlayer = IS_PLAYER(actor);
     entity player = isPlayer ? actor : actor.owner;
     entity veh = player.vehicle;
     // 1 [wait] 1 [wait] 2 [wait] 2 [wait] [wait]
     float t = autocvar_g_vehicle_raptor_cannon_refire * (1 + veh.misc_bulletcounter == 4);
-    if (fire1)
-    if (weapon_prepareattack(thiswep, player, false, t)) {
+    if (fire & 1)
+    if (weapon_prepareattack(thiswep, player, weaponentity, false, t)) {
         if (isPlayer) W_SetupShot_Dir(player, v_forward, false, 0, SND(Null), CH_WEAPON_B, 0);
         vector org = w_shotorg;
         vector dir = w_shotdir;
@@ -74,7 +74,7 @@ METHOD(RaptorCannon, wr_think, void(entity thiswep, entity actor, bool fire1, bo
                                org, normalize(dir + randomvec() * autocvar_g_vehicle_raptor_cannon_spread) * autocvar_g_vehicle_raptor_cannon_speed,
                                autocvar_g_vehicle_raptor_cannon_damage, autocvar_g_vehicle_raptor_cannon_radius, autocvar_g_vehicle_raptor_cannon_force,  0,
                                DEATH_VH_RAPT_CANNON.m_id, PROJECTILE_RAPTORCANNON, 0, true, true, player);
-        weapon_thinkf(player, WFRAME_FIRE1, 0, w_ready);
+        weapon_thinkf(player, weaponentity, WFRAME_FIRE1, 0, w_ready);
     }
 }
 METHOD(RaptorCannon, wr_checkammo1, bool(RacerAttack thiswep)) {
@@ -88,15 +88,15 @@ METHOD(RaptorCannon, wr_checkammo1, bool(RacerAttack thiswep)) {
 float autocvar_g_vehicle_raptor_bombs_refire;
 
 void raptor_bombdrop();
-METHOD(RaptorBomb, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+METHOD(RaptorBomb, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
     bool isPlayer = IS_PLAYER(actor);
     entity player = isPlayer ? actor : actor.owner;
     entity veh = player.vehicle;
-    if (fire2)
-    if (!isPlayer || weapon_prepareattack(thiswep, player, true, autocvar_g_vehicle_raptor_bombs_refire)) {
+    if (fire & 2)
+    if (!isPlayer || weapon_prepareattack(thiswep, player, weaponentity, true, autocvar_g_vehicle_raptor_bombs_refire)) {
         if (veh) setself(veh);
         raptor_bombdrop();
-        weapon_thinkf(player, WFRAME_FIRE2, 0, w_ready);
+        weapon_thinkf(player, weaponentity, WFRAME_FIRE2, 0, w_ready);
     }
 }
 
@@ -109,12 +109,12 @@ void raptor_flare_think();
 void raptor_flare_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
 void raptor_flare_touch();
 
-METHOD(RaptorFlare, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2)) {
+METHOD(RaptorFlare, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
     bool isPlayer = IS_PLAYER(actor);
     entity player = isPlayer ? actor : actor.owner;
     entity veh = player.vehicle;
-    if (fire2)
-    if (!isPlayer || weapon_prepareattack(thiswep, player, true, autocvar_g_vehicle_raptor_flare_refire)) {
+    if (fire & 2)
+    if (!isPlayer || weapon_prepareattack(thiswep, player, weaponentity, true, autocvar_g_vehicle_raptor_flare_refire)) {
         for(int i = 0; i < 3; ++i) {
             entity _flare = spawn();
             setmodel(_flare, MDL_VEH_RAPTOR_FLARE);
@@ -134,7 +134,7 @@ METHOD(RaptorFlare, wr_think, void(entity thiswep, entity actor, bool fire1, boo
             _flare.tur_impacttime = time + autocvar_g_vehicle_raptor_flare_lifetime;
             _flare.touch = raptor_flare_touch;
         }
-        weapon_thinkf(player, WFRAME_FIRE2, 0, w_ready);
+        weapon_thinkf(player, weaponentity, WFRAME_FIRE2, 0, w_ready);
     }
 }
 
index 019f5889e0590210d61ced4d128d941a6dade569..8cb2487811d61da7bbe89d4286b6f596f5165c55 100644 (file)
@@ -276,7 +276,7 @@ float spiderbot_frame()
        if(player.BUTTON_ATCK)
        {
                spider.cnt = time;
-               if(spider.vehicle_ammo1 >= autocvar_g_vehicle_spiderbot_minigun_ammo_cost && spider.tur_head.attack_finished_single <= time)
+               if(spider.vehicle_ammo1 >= autocvar_g_vehicle_spiderbot_minigun_ammo_cost && spider.tur_head.attack_finished_single[0] <= time)
                {
                        entity gun;
                        vector v;
@@ -295,12 +295,12 @@ float spiderbot_frame()
 
                        sound (gun, CH_WEAPON_A, SND_UZI_FIRE, VOL_BASE, ATTEN_NORM);
                        //trailparticles(self, _particleeffectnum("spiderbot_minigun_trail"), v, trace_endpos);
-                       pointparticles(particleeffectnum(EFFECT_SPIDERBOT_MINIGUN_MUZZLEFLASH), v, v_forward * 2500, 1);
+                       pointparticles(EFFECT_SPIDERBOT_MINIGUN_MUZZLEFLASH, v, v_forward * 2500, 1);
 
                        setself(spider);
 
                        spider.vehicle_ammo1 -= autocvar_g_vehicle_spiderbot_minigun_ammo_cost;
-                       spider.tur_head.attack_finished_single = time + autocvar_g_vehicle_spiderbot_minigun_refire;
+                       spider.tur_head.attack_finished_single[0] = time + autocvar_g_vehicle_spiderbot_minigun_refire;
                        player.vehicle_ammo1 = (spider.vehicle_ammo1 / autocvar_g_vehicle_spiderbot_minigun_ammo_max) * 100;
                        spider.gun1.angles_z += 45;
                        spider.gun2.angles_z -= 45;
@@ -332,7 +332,7 @@ float spiderbot_frame()
        if(spider.gun2.cnt <= time)
                player.vehicle_reload2 = 100;
        else
-               player.vehicle_reload2 = 100 - ((spider.gun2.cnt - time) / spider.attack_finished_single) * 100;
+               player.vehicle_reload2 = 100 - ((spider.gun2.cnt - time) / spider.attack_finished_single[0]) * 100;
 
        setorigin(player, spider.origin + '0 0 1' * spider.maxs_z);
        player.velocity = spider.velocity;
index 421a15a910b1cbdd700ab346db89fa67241b2427..bccd8b0ae2634dad0e18990ec26878cd35f98ba3 100644 (file)
@@ -271,11 +271,11 @@ void spiderbot_rocket_do()
 
     self.tur_head.frame += 1;
     if (self.tur_head.frame == 9)
-        self.attack_finished_single = autocvar_g_vehicle_spiderbot_rocket_reload;
+        self.attack_finished_single[0] = autocvar_g_vehicle_spiderbot_rocket_reload;
     else
-        self.attack_finished_single = ((self.vehicle_weapon2mode ==  SBRM_VOLLY) ? autocvar_g_vehicle_spiderbot_rocket_refire2 : autocvar_g_vehicle_spiderbot_rocket_refire);
+        self.attack_finished_single[0] = ((self.vehicle_weapon2mode ==  SBRM_VOLLY) ? autocvar_g_vehicle_spiderbot_rocket_refire2 : autocvar_g_vehicle_spiderbot_rocket_refire);
 
-    self.gun2.cnt = time + self.attack_finished_single;
+    self.gun2.cnt = time + self.attack_finished_single[0];
 }
 
 #endif
index fc89a0cd20360dc8f447542253a57c3e886d61d6..99c7225ac1a4402f475e907a820d07b6d97bfc3f 100644 (file)
@@ -25,5 +25,3 @@
 #include "weapon/seeker.qc"
 #include "weapon/shockwave.qc"
 #include "weapon/arc.qc"
-#include "weapon/hmg.qc"
-#include "weapon/rpc.qc"
index ffbc0712da186a0d5d73972c7f385ed3498b016e..452438add97a3c87fa202cc55f9074728cc2717b 100644 (file)
@@ -11,7 +11,6 @@
        #include "../../lib/warpzone/common.qh"
        #include "../../lib/warpzone/client.qh"
        #include "../util.qh"
-       #include "../buffs/all.qh"
        #include "../../client/autocvars.qh"
        #include "../deathtypes/all.qh"
        #include "../../lib/csqcmodel/interpolate.qh"
@@ -28,7 +27,6 @@
     #include "../stats.qh"
     #include "../teams.qh"
     #include "../util.qh"
-    #include "../buffs/all.qh"
     #include "../monsters/all.qh"
     #include "config.qh"
     #include "../../server/weapons/csqcprojectile.qh"
@@ -291,16 +289,7 @@ int GetAmmoStat(.int ammotype)
 
 string W_Sound(string w_snd)
 {
-       #define extensions(X) X(wav) X(ogg)
-       #define tryext(ext) { if (fexists(strcat("sound/", output = strcat("weapons/", w_snd, "."#ext)))) break; }
-       string output;
-       do {
-               extensions(tryext);
-               #undef tryext
-               #undef extensions
-               output = strcat("weapons/", w_snd);
-       } while (0);
-
+       string output = strcat("weapons/", w_snd);
 #ifdef SVQC
        MUTATOR_CALLHOOK(WeaponSound, w_snd, output);
        return weapon_sound_output;
index e3f6c7e7ccdaf63aac741030160ee334e68241eb..93df313c05f6e75bd38a4d777d6dbad8799fb7bb 100644 (file)
@@ -2,6 +2,7 @@
 #define WEAPONS_ALL_H
 
 #include "../command/all.qh"
+#include "../stats.qh"
 #include "config.qh"
 
 // weapon sets
@@ -34,8 +35,10 @@ WepSet ReadWepSet();
 #endif
 
 REGISTRY(Weapons, 72) // Increase as needed. Can be up to 72.
-REGISTER_REGISTRY(RegisterWeapons)
-entity get_weaponinfo(int id);
+#define Weapons_from(i) _Weapons_from(i, WEP_Null)
+#define get_weaponinfo(i) Weapons_from(i)
+REGISTER_REGISTRY(Weapons)
+STATIC_INIT(WeaponPickup) { FOREACH(Weapons, true, LAMBDA(it.m_pickup = NEW(WeaponPickup, it))); }
 
 
 GENERIC_COMMAND(dumpweapons, "Dump all weapons into weapons_dump.txt") // WEAPONTODO: make this work with other progs than just server
@@ -93,7 +96,7 @@ GENERIC_COMMAND(dumpweapons, "Dump all weapons into weapons_dump.txt") // WEAPON
 
 #define REGISTER_WEAPON(id, inst) \
     /* WepSet WEPSET_##id; */ \
-    REGISTER(RegisterWeapons, WEP, Weapons, id, m_id, inst)
+    REGISTER(Weapons, WEP, id, m_id, inst)
 
 // create cvars for weapon settings
 #define WEP_ADD_CVAR_NONE(wepname,name) [[last]] float autocvar_g_balance_##wepname##_##name;
@@ -130,23 +133,15 @@ REGISTER_WEAPON(Null, NEW(Weapon));
 
 #include "all.inc"
 
-entity get_weaponinfo(int id)
-{
-    if (id >= WEP_FIRST && id <= WEP_LAST) {
-        Weapon w = Weapons[id];
-        if (w) return w;
-    }
-    return WEP_Null;
-}
-
 // TODO: remove after 0.8.2. Retains impulse number compatibility because 0.8.1 clients don't reload the weapons.cfg
-#define WEP_HARDCODED_IMPULSES 22
+#define WEP_HARDCODED_IMPULSES 20
 
 // TODO: invert after 0.8.2. Will require moving 'best weapon' impulses
 #define WEP_IMPULSE_BEGIN 230
 #define WEP_IMPULSE_END bound(WEP_IMPULSE_BEGIN, WEP_IMPULSE_BEGIN + (Weapons_COUNT - 1) - 1, 253)
 
-REGISTRY_SORT(Weapons, netname, WEP_HARDCODED_IMPULSES + 1)
+REGISTRY_SORT(Weapons, WEP_HARDCODED_IMPULSES + 1)
+REGISTRY_CHECK(Weapons)
 
 STATIC_INIT(register_weapons_done)
 {
@@ -168,7 +163,7 @@ STATIC_INIT(register_weapons_done)
     #endif
     weaponorder_byid = "";
     for (int i = Weapons_MAX - 1; i >= 1; --i)
-        if (Weapons[i])
+        if (Weapons_from(i))
             weaponorder_byid = strcat(weaponorder_byid, " ", ftos(i));
     weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1));
 }
index 7d1b4e3d262067f491fd6a555f46d1bd1f020769..3ee4a684a26bff97bd44c17482e62ca6b5137a8c 100644 (file)
@@ -22,7 +22,7 @@ float W_Config_Queue_Compare(int root, int child, entity pass)
        return strcmp(wep_config_queue[root], wep_config_queue[child]);
 }
 
-void Dump_Weapon_Settings(void)
+void Dump_Weapon_Settings()
 {
        int i, x, totalsettings = 0;
        for(i = WEP_FIRST; i <= WEP_LAST; ++i)
index c50c1e544041fc2a8960b214371c3df27c1d9a14..b232bbcda358bf977b87e21cc75ee8e8a1b0bdc0 100644 (file)
@@ -6,7 +6,7 @@
 //  Balance Config Generator
 // ==========================
 
-void Dump_Weapon_Settings(void);
+void Dump_Weapon_Settings();
 int wep_config_file;
 bool wep_config_alsoprint;
 
index a4eb7b71d02ba8f4b139b6c5e23f8edd2f14ffc1..3a878a461d1f933a93160409ae4f873e5aae5ff7 100644 (file)
@@ -1,5 +1,21 @@
 #ifndef WEAPON_H
 #define WEAPON_H
+#include "../items/item/pickup.qh"
+
+const int MAX_WEAPONSLOTS = 2;
+.entity weaponentities[MAX_WEAPONSLOTS];
+
+int weaponslot(.entity weaponentity)
+{
+       for (int i = 0; i < MAX_WEAPONSLOTS; ++i)
+       {
+               if (weaponentities[i] == weaponentity)
+               {
+                       return i;
+               }
+       }
+       return 0;
+}
 
 .int ammo_shells;
 .int ammo_nails;
@@ -42,12 +58,14 @@ CLASS(Weapon, Object)
     /** M: refname   : reference name name */
     ATTRIB(Weapon, netname, string, "");
     /** M: wepname   : human readable name */
-    ATTRIB(Weapon, message, string, "AOL CD Thrower");
+    ATTRIB(Weapon, m_name, string, "AOL CD Thrower");
+
+    ATTRIB(Weapon, m_pickup, entity, NULL);
 
     /** (SERVER) setup weapon data */
     METHOD(Weapon, wr_setup, void(Weapon this)) {}
     /** (SERVER) logic to run every frame */
-    METHOD(Weapon, wr_think, void(Weapon this, entity actor, bool fire1, bool fire2)) {}
+    METHOD(Weapon, wr_think, void(Weapon this, entity actor, .entity weaponentity, int fire)) {}
     /** (SERVER) checks ammo for weapon primary */
     METHOD(Weapon, wr_checkammo1, bool(Weapon this)) {return false;}
     /** (SERVER) checks ammo for weapon second */
@@ -83,10 +101,45 @@ CLASS(Weapon, Object)
     METHOD(Weapon, wr_pickup, void(Weapon this)) {}
 
        METHOD(Weapon, display, void(entity this, void(string name, string icon) returns)) {
-               returns(this.message, this.model2 ? sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.model2) : string_null);
+               returns(this.m_name, this.model2 ? sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.model2) : string_null);
        }
 ENDCLASS(Weapon)
 
+#include "../items/all.qh"
+CLASS(WeaponPickup, Pickup)
+    ATTRIB(WeaponPickup, m_weapon, Weapon, NULL)
+    ATTRIB(WeaponPickup, m_name, string, string_null)
+#ifndef MENUQC
+    ATTRIB(WeaponPickup, m_sound, Sound, SND_WEAPONPICKUP)
+#endif
+#ifdef SVQC
+    ATTRIB(WeaponPickup, m_itemflags, int, FL_WEAPON)
+    float weapon_pickupevalfunc(entity player, entity item);
+    ATTRIB(WeaponPickup, m_pickupevalfunc, float(entity player, entity item), weapon_pickupevalfunc)
+#endif
+    CONSTRUCTOR(WeaponPickup, Weapon w) {
+        CONSTRUCT(WeaponPickup);
+        this.m_weapon = w;
+        this.m_name = w.m_name;
+#ifndef MENUQC
+        this.m_model = w.m_model;
+#endif
+#ifdef SVQC
+        this.m_botvalue = w.bot_pickupbasevalue;
+#endif
+    }
+#ifdef SVQC
+    METHOD(WeaponPickup, giveTo, bool(entity this, entity item, entity player))
+    {
+        bool b = Item_GiveTo(item, player);
+        if (b) {
+            LOG_TRACEF("entity %i picked up %s\n", player, this.m_name);
+        }
+        return b;
+    }
+#endif
+ENDCLASS(WeaponPickup)
+
 CLASS(OffhandWeapon, Object)
     METHOD(OffhandWeapon, offhand_think, void(OffhandWeapon this, entity player, bool key_pressed)) {}
 ENDCLASS(OffhandWeapon)
@@ -140,6 +193,6 @@ string W_Model(string w_mdl);
 
 // other useful macros
 #define WEP_AMMO(wpn) (WEP_##wpn.ammo_field) // only used inside weapon files/with direct name, don't duplicate prefix
-#define WEP_NAME(wpn) ((get_weaponinfo(wpn)).message)
+#define WEP_NAME(wpn) ((get_weaponinfo(wpn)).m_name)
 
 #endif
index b05132cb1648bfb76efdf2f94a7fdbd1ad0d6bf3..b873e62388d1c5f19755a9d3c6f5b0da5cdc63a0 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Arc, Weapon)
 /* crosshair */ ATTRIB(Arc, w_crosshair_size, float, 0.7);
 /* wepimg    */ ATTRIB(Arc, model2, string, "weaponarc");
 /* refname   */ ATTRIB(Arc, netname, string, "arc");
-/* wepname   */ ATTRIB(Arc, message, string, _("Arc"));
+/* wepname   */ ATTRIB(Arc, m_name, string, _("Arc"));
 ENDCLASS(Arc)
 REGISTER_WEAPON(ARC, NEW(Arc));
 
@@ -92,19 +92,18 @@ ARC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 .float beam_heat; // (beam) amount of heat produced
 .float arc_overheat; // (dropped arc/player) time during which it's too hot
 .float arc_cooldown; // (dropped arc/player) cooling speed
-.float arc_heat_percent; // (player) arc heat in [0,1] (stat)
+.float arc_heat_percent = _STAT(ARC_HEAT);
 .float arc_smoke_sound;
 #endif
 #ifdef CSQC
-void Ent_ReadArcBeam(float isnew);
 
 .vector beam_color;
 .float beam_alpha;
 .float beam_thickness;
-.float beam_traileffect;
-.float beam_hiteffect;
+.entity beam_traileffect;
+.entity beam_hiteffect;
 .float beam_hitlight[4]; // 0: radius, 123: rgb
-.float beam_muzzleeffect;
+.entity beam_muzzleeffect;
 .float beam_muzzlelight[4]; // 0: radius, 123: rgb
 .string beam_image;
 
@@ -128,11 +127,11 @@ vector Draw_ArcBeam_callback_last_bottom; // NOTE: in same coordinate system as
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_arc) { weapon_defaultspawnfunc(WEP_ARC.m_id); }
+spawnfunc(weapon_arc) { weapon_defaultspawnfunc(this, WEP_ARC); }
 
 bool W_Arc_Beam_Send(entity this, entity to, int sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_ARC_BEAM);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_ARC_BEAM);
 
        // Truncate information when this beam is displayed to the owner client
        // - The owner client has no use for beam start position or directions,
@@ -214,7 +213,7 @@ void Arc_Player_SetHeat(entity player)
        //dprint("Heat: ",ftos(player.arc_heat_percent*100),"%\n");
 }
 
-void W_Arc_Beam_Think(void)
+void W_Arc_Beam_Think()
 {SELFPARAM();
        if(self != self.owner.arc_beam)
        {
@@ -267,7 +266,7 @@ void W_Arc_Beam_Think(void)
 
                        if ( WEP_CVAR(arc, overheat_max) > 0 && self.beam_heat >= WEP_CVAR(arc, overheat_max) )
                        {
-                               Send_Effect_("arc_overheat",
+                               Send_Effect(EFFECT_ARC_OVERHEAT,
                                        self.beam_start, self.beam_wantdir, 1 );
                                sound(self, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM);
                        }
@@ -584,8 +583,7 @@ void W_Arc_Beam(float burst)
        if(time - self.beam_prev > 1)
                sound(self, CH_WEAPON_A, SND_ARC_FIRE, VOL_BASE, ATTN_NORM);
 
-       entity beam = self.arc_beam = spawn();
-       beam.classname = "W_Arc_Beam";
+       entity beam = self.arc_beam = new(W_Arc_Beam);
        beam.solid = SOLID_NOT;
        beam.think = W_Arc_Beam_Think;
        beam.owner = self;
@@ -607,10 +605,10 @@ void Arc_Smoke()
        if ( self.arc_overheat > time )
        {
                if ( random() < self.arc_heat_percent )
-                       Send_Effect_("arc_smoke", smoke_origin, '0 0 0', 1 );
+                       Send_Effect(EFFECT_ARC_SMOKE, smoke_origin, '0 0 0', 1 );
                if ( self.BUTTON_ATCK || self.BUTTON_ATCK2 )
                {
-                       Send_Effect_("arc_overheat_fire", smoke_origin, w_shotdir, 1 );
+                       Send_Effect(EFFECT_ARC_OVERHEAT_FIRE, smoke_origin, w_shotdir, 1 );
                        if ( !self.arc_smoke_sound )
                        {
                                self.arc_smoke_sound = 1;
@@ -623,7 +621,7 @@ void Arc_Smoke()
        {
                if ( random() < (self.arc_beam.beam_heat-WEP_CVAR(arc, overheat_min)) /
                                ( WEP_CVAR(arc, overheat_max)-WEP_CVAR(arc, overheat_min) ) )
-                       Send_Effect_("arc_smoke", smoke_origin, '0 0 0', 1 );
+                       Send_Effect(EFFECT_ARC_SMOKE, smoke_origin, '0 0 0', 1 );
        }
 
        if (  self.arc_smoke_sound && ( self.arc_overheat <= time ||
@@ -656,34 +654,34 @@ void Arc_Smoke()
                                );
                        }
                }
-               METHOD(Arc, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        Arc_Player_SetHeat(actor);
                        Arc_Smoke();
 
                        if (time >= actor.arc_overheat)
-                       if (fire1 || fire2 || actor.arc_beam.beam_bursting)
+                       if ((fire & 1) || (fire & 2) || actor.arc_beam.beam_bursting)
                        {
 
                                if(actor.arc_BUTTON_ATCK_prev)
                                {
                                        #if 0
                                        if(actor.animstate_startframe == actor.anim_shoot.x && actor.animstate_numframes == actor.anim_shoot.y)
-                                               weapon_thinkf(actor, WFRAME_DONTCHANGE, autocvar_g_balance_arc_primary_animtime, w_ready);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, autocvar_g_balance_arc_primary_animtime, w_ready);
                                        else
                                        #endif
-                                               weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
                                }
 
                                if((!actor.arc_beam) || wasfreed(actor.arc_beam))
                                {
-                                       if(weapon_prepareattack(thiswep, actor, fire2, 0))
+                                       if(weapon_prepareattack(thiswep, actor, weaponentity, boolean(fire & 2), 0))
                                        {
-                                               W_Arc_Beam(fire2);
+                                               W_Arc_Beam(boolean(fire & 2));
 
                                                if(!actor.arc_BUTTON_ATCK_prev)
                                                {
-                                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
+                                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
                                                        actor.arc_BUTTON_ATCK_prev = true;
                                                }
                                        }
@@ -695,18 +693,19 @@ void Arc_Smoke()
                        if(actor.arc_BUTTON_ATCK_prev)
                        {
                                sound(actor, CH_WEAPON_A, SND_ARC_STOP, VOL_BASE, ATTN_NORM);
-                               weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
-                               ATTACK_FINISHED(actor) = time + WEP_CVAR(arc, beam_refire) * W_WeaponRateFactor();
+                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, beam_animtime), w_ready);
+                               int slot = weaponslot(weaponentity);
+                               ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(arc, beam_refire) * W_WeaponRateFactor();
                        }
                        actor.arc_BUTTON_ATCK_prev = false;
 
                        #if 0
-                       if(fire2)
-                       if(weapon_prepareattack(thiswep, actor, true, autocvar_g_balance_arc_secondary_refire))
+                       if(fire & 2)
+                       if(weapon_prepareattack(thiswep, actor, weaponentity, true, autocvar_g_balance_arc_secondary_refire))
                        {
                                W_Arc_Attack2();
                                actor.arc_count = autocvar_g_balance_arc_secondary_count;
-                               weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_balance_arc_secondary_animtime, w_arc_checkattack);
+                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_arc_secondary_animtime, w_arc_checkattack);
                                actor.arc_secondarytime = time + autocvar_g_balance_arc_secondary_refire2 * W_WeaponRateFactor();
                        }
                        #endif
@@ -839,7 +838,7 @@ void Draw_ArcBeam_callback(vector start, vector hit, vector end)
        Draw_ArcBeam_callback_last_bottom = WarpZone_UnTransformOrigin(WarpZone_trace_transform, bottom);
 }
 
-void Reset_ArcBeam(void)
+void Reset_ArcBeam()
 {
        entity e;
        for (e = world; (e = findfloat(e, beam_usevieworigin, 1)); ) {
@@ -1143,14 +1142,14 @@ void Draw_ArcBeam(entity this)
        Draw_ArcBeam_callback_last_bottom = '0 0 0';
 }
 
-void Remove_ArcBeam(void)
+void Remove_ArcBeam()
 {SELFPARAM();
        remove(self.beam_muzzleentity);
        sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
 }
 
-void Ent_ReadArcBeam(float isnew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
+{
        int sf = ReadByte();
        entity flash;
 
@@ -1258,18 +1257,18 @@ void Ent_ReadArcBeam(float isnew)
                                self.beam_color = '1 1 1';
                                self.beam_alpha = 0.5;
                                self.beam_thickness = 8;
-                               self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
-                               self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+                               self.beam_traileffect = (EFFECT_ARC_BEAM);
+                               self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
                                self.beam_hitlight[0] = 0;
                                self.beam_hitlight[1] = 1;
                                self.beam_hitlight[2] = 1;
                                self.beam_hitlight[3] = 1;
-                               self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+                               self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
                                self.beam_muzzlelight[0] = 0;
                                self.beam_muzzlelight[1] = 1;
                                self.beam_muzzlelight[2] = 1;
                                self.beam_muzzlelight[3] = 1;
-                               if(self.beam_muzzleeffect >= 0)
+                               if(self.beam_muzzleeffect)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = self.beam_alpha;
@@ -1283,19 +1282,19 @@ void Ent_ReadArcBeam(float isnew)
                                self.beam_color = '1 1 1';
                                self.beam_alpha = 0.5;
                                self.beam_thickness = 8;
-                               self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
-                               self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+                               self.beam_traileffect = (EFFECT_ARC_BEAM);
+                               self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
                                self.beam_hitlight[0] = 0;
                                self.beam_hitlight[1] = 1;
                                self.beam_hitlight[2] = 1;
                                self.beam_hitlight[3] = 1;
-                               self.beam_muzzleeffect = -1; // particleeffectnum(EFFECT_GRENADE_MUZZLEFLASH);
+                               self.beam_muzzleeffect = NULL; // (EFFECT_GRENADE_MUZZLEFLASH);
                                self.beam_muzzlelight[0] = 0;
                                self.beam_muzzlelight[1] = 1;
                                self.beam_muzzlelight[2] = 1;
                                self.beam_muzzlelight[3] = 1;
                                self.beam_image = "particles/lgbeam";
-                               if(self.beam_muzzleeffect >= 0)
+                               if(self.beam_muzzleeffect)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = self.beam_alpha;
@@ -1309,19 +1308,19 @@ void Ent_ReadArcBeam(float isnew)
                                self.beam_color = '1 1 1';
                                self.beam_alpha = 0.5;
                                self.beam_thickness = 8;
-                               self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM_HEAL);
-                               self.beam_hiteffect = particleeffectnum(EFFECT_ARC_BEAM_HEAL_IMPACT);
+                               self.beam_traileffect = (EFFECT_ARC_BEAM_HEAL);
+                               self.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT);
                                self.beam_hitlight[0] = 0;
                                self.beam_hitlight[1] = 1;
                                self.beam_hitlight[2] = 1;
                                self.beam_hitlight[3] = 1;
-                               self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+                               self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
                                self.beam_muzzlelight[0] = 0;
                                self.beam_muzzlelight[1] = 1;
                                self.beam_muzzlelight[2] = 1;
                                self.beam_muzzlelight[3] = 1;
                                self.beam_image = "particles/lgbeam";
-                               if(self.beam_muzzleeffect >= 0)
+                               if(self.beam_muzzleeffect)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = self.beam_alpha;
@@ -1335,19 +1334,19 @@ void Ent_ReadArcBeam(float isnew)
                                self.beam_color = '1 1 1';
                                self.beam_alpha = 0.5;
                                self.beam_thickness = 8;
-                               self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
-                               self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+                               self.beam_traileffect = (EFFECT_ARC_BEAM);
+                               self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
                                self.beam_hitlight[0] = 20;
                                self.beam_hitlight[1] = 1;
                                self.beam_hitlight[2] = 0;
                                self.beam_hitlight[3] = 0;
-                               self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+                               self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
                                self.beam_muzzlelight[0] = 50;
                                self.beam_muzzlelight[1] = 1;
                                self.beam_muzzlelight[2] = 0;
                                self.beam_muzzlelight[3] = 0;
                                self.beam_image = "particles/lgbeam";
-                               if(self.beam_muzzleeffect >= 0)
+                               if(self.beam_muzzleeffect)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = self.beam_alpha;
@@ -1361,19 +1360,19 @@ void Ent_ReadArcBeam(float isnew)
                                self.beam_color = '1 1 1';
                                self.beam_alpha = 0.5;
                                self.beam_thickness = 14;
-                               self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
-                               self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+                               self.beam_traileffect = (EFFECT_ARC_BEAM);
+                               self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
                                self.beam_hitlight[0] = 0;
                                self.beam_hitlight[1] = 1;
                                self.beam_hitlight[2] = 1;
                                self.beam_hitlight[3] = 1;
-                               self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+                               self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
                                self.beam_muzzlelight[0] = 0;
                                self.beam_muzzlelight[1] = 1;
                                self.beam_muzzlelight[2] = 1;
                                self.beam_muzzlelight[3] = 1;
                                self.beam_image = "particles/lgbeam";
-                               if(self.beam_muzzleeffect >= 0)
+                               if(self.beam_muzzleeffect)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = self.beam_alpha;
@@ -1387,19 +1386,19 @@ void Ent_ReadArcBeam(float isnew)
                                self.beam_color = '1 1 1';
                                self.beam_alpha = 0.5;
                                self.beam_thickness = 14;
-                               self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
-                               self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+                               self.beam_traileffect = (EFFECT_ARC_BEAM);
+                               self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
                                self.beam_hitlight[0] = 0;
                                self.beam_hitlight[1] = 1;
                                self.beam_hitlight[2] = 1;
                                self.beam_hitlight[3] = 1;
-                               self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+                               self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
                                self.beam_muzzlelight[0] = 0;
                                self.beam_muzzlelight[1] = 1;
                                self.beam_muzzlelight[2] = 1;
                                self.beam_muzzlelight[3] = 1;
                                self.beam_image = "particles/lgbeam";
-                               if(self.beam_muzzleeffect >= 0)
+                               if(self.beam_muzzleeffect)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = self.beam_alpha;
@@ -1413,19 +1412,19 @@ void Ent_ReadArcBeam(float isnew)
                                self.beam_color = '1 1 1';
                                self.beam_alpha = 0.5;
                                self.beam_thickness = 14;
-                               self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM_HEAL);
-                               self.beam_hiteffect = particleeffectnum(EFFECT_ARC_BEAM_HEAL_IMPACT2);
+                               self.beam_traileffect = (EFFECT_ARC_BEAM_HEAL);
+                               self.beam_hiteffect = (EFFECT_ARC_BEAM_HEAL_IMPACT2);
                                self.beam_hitlight[0] = 0;
                                self.beam_hitlight[1] = 1;
                                self.beam_hitlight[2] = 1;
                                self.beam_hitlight[3] = 1;
-                               self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+                               self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
                                self.beam_muzzlelight[0] = 0;
                                self.beam_muzzlelight[1] = 1;
                                self.beam_muzzlelight[2] = 1;
                                self.beam_muzzlelight[3] = 1;
                                self.beam_image = "particles/lgbeam";
-                               if(self.beam_muzzleeffect >= 0)
+                               if(self.beam_muzzleeffect)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = self.beam_alpha;
@@ -1439,19 +1438,19 @@ void Ent_ReadArcBeam(float isnew)
                                self.beam_color = '1 1 1';
                                self.beam_alpha = 0.5;
                                self.beam_thickness = 14;
-                               self.beam_traileffect = particleeffectnum(EFFECT_ARC_BEAM);
-                               self.beam_hiteffect = particleeffectnum(EFFECT_ARC_LIGHTNING);
+                               self.beam_traileffect = (EFFECT_ARC_BEAM);
+                               self.beam_hiteffect = (EFFECT_ARC_LIGHTNING);
                                self.beam_hitlight[0] = 0;
                                self.beam_hitlight[1] = 1;
                                self.beam_hitlight[2] = 1;
                                self.beam_hitlight[3] = 1;
-                               self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+                               self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
                                self.beam_muzzlelight[0] = 0;
                                self.beam_muzzlelight[1] = 1;
                                self.beam_muzzlelight[2] = 1;
                                self.beam_muzzlelight[3] = 1;
                                self.beam_image = "particles/lgbeam";
-                               if(self.beam_muzzleeffect >= 0)
+                               if(self.beam_muzzleeffect)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = self.beam_alpha;
@@ -1467,19 +1466,19 @@ void Ent_ReadArcBeam(float isnew)
                                self.beam_color = randomvec();
                                self.beam_alpha = 1;
                                self.beam_thickness = 8;
-                               self.beam_traileffect = false;
-                               self.beam_hiteffect = false;
+                               self.beam_traileffect = NULL;
+                               self.beam_hiteffect = NULL;
                                self.beam_hitlight[0] = 0;
                                self.beam_hitlight[1] = 1;
                                self.beam_hitlight[2] = 1;
                                self.beam_hitlight[3] = 1;
-                               self.beam_muzzleeffect = -1; //particleeffectnum(EFFECT_VORTEX_MUZZLEFLASH);
+                               self.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
                                self.beam_muzzlelight[0] = 0;
                                self.beam_muzzlelight[1] = 1;
                                self.beam_muzzlelight[2] = 1;
                                self.beam_muzzlelight[3] = 1;
                                self.beam_image = "particles/lgbeam";
-                               if(self.beam_muzzleeffect >= 0)
+                               if(self.beam_muzzleeffect)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = self.beam_alpha;
@@ -1495,6 +1494,7 @@ void Ent_ReadArcBeam(float isnew)
        {
                InterpolateOrigin_Note();
        }
+       return true;
 }
 
 #endif
index d7792fac4aef157ea91a93f6a8b72a54c0facb8b..055293e930b990ef0fee44d662536ffa5a92112e 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Blaster, Weapon)
 /* crosshair */ ATTRIB(Blaster, w_crosshair_size, float, 0.5);
 /* wepimg    */ ATTRIB(Blaster, model2, string, "weaponlaser");
 /* refname   */ ATTRIB(Blaster, netname, string, "blaster");
-/* wepname   */ ATTRIB(Blaster, message, string, _("Blaster"));
+/* wepname   */ ATTRIB(Blaster, m_name, string, _("Blaster"));
 ENDCLASS(Blaster)
 REGISTER_WEAPON(BLASTER, NEW(Blaster));
 
@@ -50,10 +50,10 @@ BLASTER_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_blaster) { weapon_defaultspawnfunc(WEP_BLASTER.m_id); }
+spawnfunc(weapon_blaster) { weapon_defaultspawnfunc(this, WEP_BLASTER); }
 spawnfunc(weapon_laser) { spawnfunc_weapon_blaster(this); }
 
-void W_Blaster_Touch(void)
+void W_Blaster_Touch()
 {SELFPARAM();
        PROJECTILE_TOUCH;
 
@@ -75,7 +75,7 @@ void W_Blaster_Touch(void)
        remove(self);
 }
 
-void W_Blaster_Think(void)
+void W_Blaster_Think()
 {SELFPARAM();
        self.movetype = MOVETYPE_FLY;
        self.think = SUB_Remove;
@@ -101,9 +101,8 @@ void W_Blaster_Attack(
        W_SetupShot_Dir(actor, s_forward, false, 3, SND(LASERGUN_FIRE), CH_WEAPON_B, atk_damage);
        Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       entity missile = spawn();
+       entity missile = new(blasterbolt);
        missile.owner = missile.realowner = actor;
-       missile.classname = "blasterbolt";
        missile.bot_dodge = true;
        missile.bot_dodgerating = atk_damage;
        PROJECTILE_MAKETRIGGER(missile);
@@ -161,11 +160,11 @@ void W_Blaster_Attack(
                                { self.BUTTON_ATCK = bot_aim(WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false); }
                }
 
-               METHOD(Blaster, wr_think, void(Blaster thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Blaster, wr_think, void(Blaster thiswep, entity actor, .entity weaponentity, int fire))
                {
-                       if(fire1)
+                       if(fire & 1)
                        {
-                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(blaster, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(blaster, refire)))
                                {
                                        W_Blaster_Attack(
                                                actor,
@@ -180,10 +179,10 @@ void W_Blaster_Attack(
                                                WEP_CVAR_PRI(blaster, delay),
                                                WEP_CVAR_PRI(blaster, lifetime)
                                        );
-                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(blaster, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(blaster, animtime), w_ready);
                                }
                        }
-                       else if(fire2)
+                       else if(fire & 2)
                        {
                                switch(WEP_CVAR(blaster, secondary))
                                {
@@ -196,7 +195,7 @@ void W_Blaster_Attack(
 
                                        case 1: // normal projectile secondary
                                        {
-                                               if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(blaster, refire)))
+                                               if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(blaster, refire)))
                                                {
                                                        W_Blaster_Attack(
                                                                actor,
@@ -211,7 +210,7 @@ void W_Blaster_Attack(
                                                                WEP_CVAR_SEC(blaster, delay),
                                                                WEP_CVAR_SEC(blaster, lifetime)
                                                        );
-                                                       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(blaster, animtime), w_ready);
+                                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(blaster, animtime), w_ready);
                                                }
 
                                                break;
@@ -262,7 +261,7 @@ void W_Blaster_Attack(
                {
                        vector org2;
                        org2 = w_org + w_backoff * 6;
-                       pointparticles(particleeffectnum(EFFECT_BLASTER_IMPACT), org2, w_backoff * 1000, 1);
+                       pointparticles(EFFECT_BLASTER_IMPACT, org2, w_backoff * 1000, 1);
                        if(!w_issilent) { sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTN_NORM); }
                }
 
index 75d8146de4eb67b1d4fcf18b3241dc7632eaea41..252cc56dc80929c2d935b0db16697b515f3339ce 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Crylink, Weapon)
 /* crosshair */ ATTRIB(Crylink, w_crosshair_size, float, 0.5);
 /* wepimg    */ ATTRIB(Crylink, model2, string, "weaponcrylink");
 /* refname   */ ATTRIB(Crylink, netname, string, "crylink");
-/* wepname   */ ATTRIB(Crylink, message, string, _("Crylink"));
+/* wepname   */ ATTRIB(Crylink, m_name, string, _("Crylink"));
 ENDCLASS(Crylink)
 REGISTER_WEAPON(CRYLINK, NEW(Crylink));
 
@@ -66,7 +66,7 @@ CRYLINK_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_crylink) { weapon_defaultspawnfunc(WEP_CRYLINK.m_id); }
+spawnfunc(weapon_crylink) { weapon_defaultspawnfunc(this, WEP_CRYLINK); }
 
 void W_Crylink_CheckLinks(entity e)
 {
@@ -108,7 +108,7 @@ void W_Crylink_Dequeue(entity e)
        W_Crylink_Dequeue_Raw(e.realowner, e.queueprev, e, e.queuenext);
 }
 
-void W_Crylink_Reset(void)
+void W_Crylink_Reset()
 {SELFPARAM();
        W_Crylink_Dequeue(self);
        remove(self);
@@ -225,7 +225,7 @@ vector W_Crylink_LinkJoin(entity e, float jspeed)
        return targ_origin;
 }
 
-void W_Crylink_LinkJoinEffect_Think(void)
+void W_Crylink_LinkJoinEffect_Think()
 {SELFPARAM();
        // is there at least 2 projectiles very close?
        entity e, p;
@@ -290,7 +290,7 @@ float W_Crylink_Touch_WouldHitFriendly(entity projectile, float rad)
 }
 
 // NO bounce protection, as bounces are limited!
-void W_Crylink_Touch(void)
+void W_Crylink_Touch()
 {SELFPARAM();
        float finalhit;
        float f;
@@ -335,7 +335,7 @@ void W_Crylink_Touch(void)
        //      CSQCProjectile(proj, true, PROJECTILE_CRYLINK, true);
 }
 
-void W_Crylink_Fadethink(void)
+void W_Crylink_Fadethink()
 {SELFPARAM();
        W_Crylink_Dequeue(self);
        remove(self);
@@ -366,10 +366,9 @@ void W_Crylink_Attack(Weapon thiswep)
        proj = prevproj = firstproj = world;
        for(counter = 0; counter < shots; ++counter)
        {
-               proj = spawn();
+               proj = new(spike);
                proj.reset = W_Crylink_Reset;
                proj.realowner = proj.owner = self;
-               proj.classname = "spike";
                proj.bot_dodge = true;
                proj.bot_dodgerating = WEP_CVAR_PRI(crylink, damage);
                if(shots == 1) {
@@ -475,10 +474,9 @@ void W_Crylink_Attack2(Weapon thiswep)
        proj = prevproj = firstproj = world;
        for(counter = 0; counter < shots; ++counter)
        {
-               proj = spawn();
+               proj = new(spike);
                proj.reset = W_Crylink_Reset;
                proj.realowner = proj.owner = self;
-               proj.classname = "spike";
                proj.bot_dodge = true;
                proj.bot_dodgerating = WEP_CVAR_SEC(crylink, damage);
                if(shots == 1) {
@@ -574,34 +572,34 @@ void W_Crylink_Attack2(Weapon thiswep)
                        else
                                self.BUTTON_ATCK2 = bot_aim(WEP_CVAR_SEC(crylink, speed), 0, WEP_CVAR_SEC(crylink, middle_lifetime), false);
                }
-               METHOD(Crylink, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Crylink, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(autocvar_g_balance_crylink_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(crylink, ammo), WEP_CVAR_SEC(crylink, ammo))) { // forced reload
                                Weapon w = get_weaponinfo(actor.weapon);
                                w.wr_reload(w);
                        }
 
-                       if(fire1)
+                       if(fire & 1)
                        {
                                if(actor.crylink_waitrelease != 1)
-                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(crylink, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(crylink, refire)))
                                {
                                        W_Crylink_Attack(thiswep);
-                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(crylink, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(crylink, animtime), w_ready);
                                }
                        }
 
-                       if(fire2 && autocvar_g_balance_crylink_secondary)
+                       if((fire & 2) && autocvar_g_balance_crylink_secondary)
                        {
                                if(actor.crylink_waitrelease != 2)
-                               if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(crylink, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(crylink, refire)))
                                {
                                        W_Crylink_Attack2(thiswep);
-                                       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(crylink, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(crylink, animtime), w_ready);
                                }
                        }
 
-                       if((actor.crylink_waitrelease == 1 && !fire1) || (actor.crylink_waitrelease == 2 && !fire2))
+                       if((actor.crylink_waitrelease == 1 && !(fire & 1)) || (actor.crylink_waitrelease == 2 && !(fire & 2)))
                        {
                                if(!actor.crylink_lastgroup || time > actor.crylink_lastgroup.teleport_time)
                                {
@@ -614,9 +612,8 @@ void W_Crylink_Attack2(Weapon thiswep)
 
                                                pos = W_Crylink_LinkJoin(actor.crylink_lastgroup, WEP_CVAR_BOTH(crylink, isprimary, joinspread) * WEP_CVAR_BOTH(crylink, isprimary, speed));
 
-                                               linkjoineffect = spawn();
+                                               linkjoineffect = new(linkjoineffect);
                                                linkjoineffect.think = W_Crylink_LinkJoinEffect_Think;
-                                               linkjoineffect.classname = "linkjoineffect";
                                                linkjoineffect.nextthink = time + w_crylink_linkjoin_time;
                                                linkjoineffect.owner = actor;
                                                setorigin(linkjoineffect, pos);
@@ -683,13 +680,13 @@ void W_Crylink_Attack2(Weapon thiswep)
                        org2 = w_org + w_backoff * 2;
                        if(w_deathtype & HITTYPE_SECONDARY)
                        {
-                               pointparticles(particleeffectnum(EFFECT_CRYLINK_IMPACT2), org2, '0 0 0', 1);
+                               pointparticles(EFFECT_CRYLINK_IMPACT2, org2, '0 0 0', 1);
                                if(!w_issilent)
                                        sound(self, CH_SHOTS, SND_CRYLINK_IMPACT2, VOL_BASE, ATTN_NORM);
                        }
                        else
                        {
-                               pointparticles(particleeffectnum(EFFECT_CRYLINK_IMPACT), org2, '0 0 0', 1);
+                               pointparticles(EFFECT_CRYLINK_IMPACT, org2, '0 0 0', 1);
                                if(!w_issilent)
                                        sound(self, CH_SHOTS, SND_CRYLINK_IMPACT, VOL_BASE, ATTN_NORM);
                        }
index b9cc0358bbd28c83601549e37f3af0456e73a9c6..d6ffd50d68b5acd281a97aa91cd24f7419eb09dd 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Devastator, Weapon)
 /* crosshair */ ATTRIB(Devastator, w_crosshair_size, float, 0.7);
 /* wepimg    */ ATTRIB(Devastator, model2, string, "weaponrocketlauncher");
 /* refname   */ ATTRIB(Devastator, netname, string, "devastator");
-/* wepname   */ ATTRIB(Devastator, message, string, _("Devastator"));
+/* wepname   */ ATTRIB(Devastator, m_name, string, _("Devastator"));
 ENDCLASS(Devastator)
 REGISTER_WEAPON(DEVASTATOR, NEW(Devastator));
 
@@ -64,12 +64,12 @@ DEVASTATOR_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_devastator) { weapon_defaultspawnfunc(WEP_DEVASTATOR.m_id); }
+spawnfunc(weapon_devastator) { weapon_defaultspawnfunc(this, WEP_DEVASTATOR); }
 spawnfunc(weapon_rocketlauncher) { spawnfunc_weapon_devastator(this); }
 
 .entity lastrocket;
 
-void W_Devastator_Unregister(void)
+void W_Devastator_Unregister()
 {SELFPARAM();
        if(self.realowner && self.realowner.lastrocket == self)
        {
@@ -78,7 +78,7 @@ void W_Devastator_Unregister(void)
        }
 }
 
-void W_Devastator_Explode(void)
+void W_Devastator_Explode()
 {SELFPARAM();
        W_Devastator_Unregister();
 
@@ -111,14 +111,15 @@ void W_Devastator_Explode(void)
                if(!(self.realowner.items & IT_UNLIMITED_WEAPON_AMMO))
                {
                        self.realowner.cnt = WEP_DEVASTATOR.m_id;
-                       ATTACK_FINISHED(self.realowner) = time;
+                       int slot = 0; // TODO: unhardcode
+                       ATTACK_FINISHED(self.realowner, slot) = time;
                        self.realowner.switchweapon = w_getbestweapon(self.realowner);
                }
        }
        remove(self);
 }
 
-void W_Devastator_DoRemoteExplode(void)
+void W_Devastator_DoRemoteExplode(.entity weaponentity)
 {SELFPARAM();
        W_Devastator_Unregister();
 
@@ -190,14 +191,15 @@ void W_Devastator_DoRemoteExplode(void)
                if(!(self.realowner.items & IT_UNLIMITED_WEAPON_AMMO))
                {
                        self.realowner.cnt = WEP_DEVASTATOR.m_id;
-                       ATTACK_FINISHED(self.realowner) = time;
+                       int slot = weaponslot(weaponentity);
+                       ATTACK_FINISHED(self.realowner, slot) = time;
                        self.realowner.switchweapon = w_getbestweapon(self.realowner);
                }
        }
        remove(self);
 }
 
-void W_Devastator_RemoteExplode(void)
+void W_Devastator_RemoteExplode(.entity weaponentity)
 {SELFPARAM();
        if(self.realowner.deadflag == DEAD_NO)
        if(self.realowner.lastrocket)
@@ -207,7 +209,7 @@ void W_Devastator_RemoteExplode(void)
                        : (vlen(NearestPointOnBox(self.realowner, self.origin) - self.origin) > WEP_CVAR(devastator, remote_radius)) // safety device
                )
                {
-                       W_Devastator_DoRemoteExplode();
+                       W_Devastator_DoRemoteExplode(weaponentity);
                }
        }
 }
@@ -245,7 +247,7 @@ vector W_Devastator_SteerTo(vector thisdir, vector goaldir, float maxturn_cos)
 //   normalize(thisdir + goaldir)
 //   normalize(0)
 
-void W_Devastator_Think(void)
+void W_Devastator_Think()
 {SELFPARAM();
        vector desireddir, olddir, newdir, desiredorigin, goal;
        float velspeed, f;
@@ -304,15 +306,16 @@ void W_Devastator_Think(void)
                        }
                }
 
+               .entity weaponentity = weaponentities[0]; // TODO: unhardcode
                if(self.rl_detonate_later)
-                       W_Devastator_RemoteExplode();
+                       W_Devastator_RemoteExplode(weaponentity);
        }
 
        if(self.csqcprojectile_clientanimate == 0)
                UpdateCSQCProjectile(self);
 }
 
-void W_Devastator_Touch(void)
+void W_Devastator_Touch()
 {SELFPARAM();
        if(WarpZone_Projectile_Touch())
        {
@@ -520,26 +523,26 @@ void W_Devastator_Attack(Weapon thiswep)
                        }
                }
                #endif
-               METHOD(Devastator, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(WEP_CVAR(devastator, reload_ammo) && actor.clip_load < WEP_CVAR(devastator, ammo)) { // forced reload
                                Weapon w = get_weaponinfo(actor.weapon);
                                w.wr_reload(w);
                        } else {
-                               if(fire1)
+                               if(fire & 1)
                                {
                                        if(actor.rl_release || WEP_CVAR(devastator, guidestop))
-                                       if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(devastator, refire)))
+                                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(devastator, refire)))
                                        {
                                                W_Devastator_Attack(thiswep);
-                                               weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(devastator, animtime), w_ready);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(devastator, animtime), w_ready);
                                                actor.rl_release = 0;
                                        }
                                }
                                else
                                        actor.rl_release = 1;
 
-                               if(fire2)
+                               if(fire & 2)
                                if(actor.switchweapon == WEP_DEVASTATOR.m_id)
                                {
                                        entity rock;
@@ -569,7 +572,7 @@ void W_Devastator_Attack(Weapon thiswep)
                {
                        #if 0
                        // don't switch while guiding a missile
-                       if(ATTACK_FINISHED(self) <= time || self.weapon != WEP_DEVASTATOR.m_id)
+                       if(ATTACK_FINISHED(self, slot) <= time || self.weapon != WEP_DEVASTATOR.m_id)
                        {
                                ammo_amount = false;
                                if(WEP_CVAR(devastator, reload_ammo))
@@ -637,7 +640,7 @@ void W_Devastator_Attack(Weapon thiswep)
                {
                        vector org2;
                        org2 = w_org + w_backoff * 12;
-                       pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), org2, '0 0 0', 1);
+                       pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
                        if(!w_issilent)
                                sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTN_NORM);
                }
index 7321d38f2aed1fcd60b90b1552783013e8e59a27..0f48bb2591688df274c36ccea961186d9d94140a 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Electro, Weapon)
 /* crosshair */ ATTRIB(Electro, w_crosshair_size, float, 0.6);
 /* wepimg    */ ATTRIB(Electro, model2, string, "weaponelectro");
 /* refname   */ ATTRIB(Electro, netname, string, "electro");
-/* wepname   */ ATTRIB(Electro, message, string, _("Electro"));
+/* wepname   */ ATTRIB(Electro, m_name, string, _("Electro"));
 ENDCLASS(Electro)
 REGISTER_WEAPON(ELECTRO, NEW(Electro));
 
@@ -64,12 +64,12 @@ REGISTER_WEAPON(ELECTRO, NEW(Electro));
 ELECTRO_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 .float electro_count;
 .float electro_secondarytime;
-void W_Electro_ExplodeCombo(void);
+void W_Electro_ExplodeCombo();
 #endif
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_electro) { weapon_defaultspawnfunc(WEP_ELECTRO.m_id); }
+spawnfunc(weapon_electro) { weapon_defaultspawnfunc(this, WEP_ELECTRO); }
 
 void W_Electro_TriggerCombo(vector org, float rad, entity own)
 {
@@ -118,7 +118,7 @@ void W_Electro_TriggerCombo(vector org, float rad, entity own)
        }
 }
 
-void W_Electro_ExplodeCombo(void)
+void W_Electro_ExplodeCombo()
 {SELFPARAM();
        W_Electro_TriggerCombo(self.origin, WEP_CVAR(electro, combo_comboradius), self.realowner);
 
@@ -140,7 +140,7 @@ void W_Electro_ExplodeCombo(void)
        remove(self);
 }
 
-void W_Electro_Explode(void)
+void W_Electro_Explode()
 {SELFPARAM();
        if(other.takedamage == DAMAGE_AIM)
                if(IS_PLAYER(other))
@@ -187,13 +187,13 @@ void W_Electro_Explode(void)
        remove(self);
 }
 
-void W_Electro_TouchExplode(void)
+void W_Electro_TouchExplode()
 {
        PROJECTILE_TOUCH;
        W_Electro_Explode();
 }
 
-void W_Electro_Bolt_Think(void)
+void W_Electro_Bolt_Think()
 {SELFPARAM();
        if(time >= self.ltime)
        {
@@ -264,8 +264,7 @@ void W_Electro_Attack_Bolt(Weapon thiswep)
 
        Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       proj = spawn();
-       proj.classname = "electro_bolt";
+       proj = new(electro_bolt);
        proj.owner = proj.realowner = self;
        proj.bot_dodge = true;
        proj.bot_dodgerating = WEP_CVAR_PRI(electro, damage);
@@ -290,7 +289,7 @@ void W_Electro_Attack_Bolt(Weapon thiswep)
        MUTATOR_CALLHOOK(EditProjectile, self, proj);
 }
 
-void W_Electro_Orb_Touch(void)
+void W_Electro_Orb_Touch()
 {SELFPARAM();
        PROJECTILE_TOUCH;
        if(other.takedamage == DAMAGE_AIM)
@@ -364,8 +363,7 @@ void W_Electro_Attack_Orb(Weapon thiswep)
 
        Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       entity proj = spawn();
-       proj.classname = "electro_orb";
+       entity proj = new(electro_orb);
        proj.owner = proj.realowner = self;
        proj.use = W_Electro_Explode;
        proj.think = adaptor_think2use_hittype_splash;
@@ -406,19 +404,19 @@ void W_Electro_Attack_Orb(Weapon thiswep)
        MUTATOR_CALLHOOK(EditProjectile, self, proj);
 }
 
-void W_Electro_CheckAttack(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Electro_CheckAttack(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {SELFPARAM();
        if(self.electro_count > 1)
        if(self.BUTTON_ATCK2)
-       if(weapon_prepareattack(thiswep, actor, true, -1))
+       if(weapon_prepareattack(thiswep, actor, weaponentity, true, -1))
        {
                W_Electro_Attack_Orb(WEP_ELECTRO);
                self.electro_count -= 1;
-               weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
                return;
        }
        // WEAPONTODO: when the player releases the button, cut down the length of refire2?
-       w_ready(thiswep, actor, fire1, fire2);
+       w_ready(thiswep, actor, weaponentity, fire);
 }
 
 .float bot_secondary_electromooth;
@@ -451,7 +449,7 @@ void W_Electro_CheckAttack(Weapon thiswep, entity actor, bool fire1, bool fire2)
                                }
                        }
                }
-               METHOD(Electro, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Electro, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(autocvar_g_balance_electro_reload_ammo) // forced reload // WEAPONTODO
                        {
@@ -469,22 +467,22 @@ void W_Electro_CheckAttack(Weapon thiswep, entity actor, bool fire1, bool fire2)
                                }
                        }
 
-                       if(fire1)
+                       if(fire & 1)
                        {
-                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(electro, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire)))
                                {
                                                W_Electro_Attack_Bolt(thiswep);
-                                               weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
                                }
                        }
-                       else if(fire2)
+                       else if(fire & 2)
                        {
                                if(time >= actor.electro_secondarytime)
-                               if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(electro, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(electro, refire)))
                                {
                                        W_Electro_Attack_Orb(thiswep);
                                        actor.electro_count = WEP_CVAR_SEC(electro, count);
-                                       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(electro, animtime), W_Electro_CheckAttack);
                                        actor.electro_secondarytime = time + WEP_CVAR_SEC(electro, refire2) * W_WeaponRateFactor();
                                }
                        }
@@ -557,7 +555,7 @@ void W_Electro_CheckAttack(Weapon thiswep, entity actor, bool fire1, bool fire2)
                        org2 = w_org + w_backoff * 6;
                        if(w_deathtype & HITTYPE_SECONDARY)
                        {
-                               pointparticles(particleeffectnum(EFFECT_ELECTRO_BALLEXPLODE), org2, '0 0 0', 1);
+                               pointparticles(EFFECT_ELECTRO_BALLEXPLODE, org2, '0 0 0', 1);
                                if(!w_issilent)
                                        sound(self, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_NORM);
                        }
@@ -566,13 +564,13 @@ void W_Electro_CheckAttack(Weapon thiswep, entity actor, bool fire1, bool fire2)
                                if(w_deathtype & HITTYPE_BOUNCE)
                                {
                                        // this is sent as "primary (w_deathtype & HITTYPE_BOUNCE)" to distinguish it from (w_deathtype & HITTYPE_SECONDARY) bounced balls
-                                       pointparticles(particleeffectnum(EFFECT_ELECTRO_COMBO), org2, '0 0 0', 1);
+                                       pointparticles(EFFECT_ELECTRO_COMBO, org2, '0 0 0', 1);
                                        if(!w_issilent)
                                                sound(self, CH_SHOTS, SND_ELECTRO_IMPACT_COMBO, VOL_BASE, ATTEN_NORM);
                                }
                                else
                                {
-                                       pointparticles(particleeffectnum(EFFECT_ELECTRO_IMPACT), org2, '0 0 0', 1);
+                                       pointparticles(EFFECT_ELECTRO_IMPACT, org2, '0 0 0', 1);
                                        if(!w_issilent)
                                                sound(self, CH_SHOTS, SND_ELECTRO_IMPACT, VOL_BASE, ATTEN_NORM);
                                }
index b0761b2c2ad1006623ab473ca9b7cbe912476c99..7b96971e9247e1178f975d4297e4a10f322512a4 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Fireball, Weapon)
 /* crosshair */ //ATTRIB(Fireball, w_crosshair_size, float, 0.65);
 /* wepimg    */ ATTRIB(Fireball, model2, string, "weaponfireball");
 /* refname   */ ATTRIB(Fireball, netname, string, "fireball");
-/* wepname   */ ATTRIB(Fireball, message, string, _("Fireball"));
+/* wepname   */ ATTRIB(Fireball, m_name, string, _("Fireball"));
 ENDCLASS(Fireball)
 REGISTER_WEAPON(FIREBALL, NEW(Fireball));
 
@@ -57,9 +57,9 @@ FIREBALL_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_fireball) { weapon_defaultspawnfunc(WEP_FIREBALL.m_id); }
+spawnfunc(weapon_fireball) { weapon_defaultspawnfunc(this, WEP_FIREBALL); }
 
-void W_Fireball_Explode(void)
+void W_Fireball_Explode()
 {SELFPARAM();
        entity e;
        float dist;
@@ -109,7 +109,7 @@ void W_Fireball_Explode(void)
        remove(self);
 }
 
-void W_Fireball_TouchExplode(void)
+void W_Fireball_TouchExplode()
 {
        PROJECTILE_TOUCH;
        W_Fireball_Explode();
@@ -149,7 +149,7 @@ void W_Fireball_LaserPlay(float dt, float dist, float damage, float edgedamage,
        }
 }
 
-void W_Fireball_Think(void)
+void W_Fireball_Think()
 {SELFPARAM();
        if(time > self.pushltime)
        {
@@ -180,7 +180,7 @@ void W_Fireball_Damage(entity inflictor, entity attacker, float damage, int deat
        }
 }
 
-void W_Fireball_Attack1(void)
+void W_Fireball_Attack1()
 {SELFPARAM();
        entity proj;
 
@@ -188,8 +188,7 @@ void W_Fireball_Attack1(void)
 
        Send_Effect(EFFECT_FIREBALL_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       proj = spawn();
-       proj.classname = "plasma_prim";
+       proj = new(plasma_prim);
        proj.owner = proj.realowner = self;
        proj.bot_dodge = true;
        proj.bot_dodgerating = WEP_CVAR_PRI(fireball, damage);
@@ -226,38 +225,38 @@ void W_Fireball_AttackEffect(float i, vector f_diff)
        Send_Effect(EFFECT_FIREBALL_PRE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 }
 
-void W_Fireball_Attack1_Frame4(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Fireball_Attack1_Frame4(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        W_Fireball_Attack1();
-       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), w_ready);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), w_ready);
 }
 
-void W_Fireball_Attack1_Frame3(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Fireball_Attack1_Frame3(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        W_Fireball_AttackEffect(0, '+1.25 +3.75 0');
-       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame4);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame4);
 }
 
-void W_Fireball_Attack1_Frame2(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Fireball_Attack1_Frame2(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        W_Fireball_AttackEffect(0, '-1.25 +3.75 0');
-       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame3);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame3);
 }
 
-void W_Fireball_Attack1_Frame1(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Fireball_Attack1_Frame1(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        W_Fireball_AttackEffect(1, '+1.25 -3.75 0');
-       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame2);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame2);
 }
 
-void W_Fireball_Attack1_Frame0(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Fireball_Attack1_Frame0(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {SELFPARAM();
        W_Fireball_AttackEffect(0, '-1.25 -3.75 0');
        sound(self, CH_WEAPON_SINGLE, SND_FIREBALL_PREFIRE2, VOL_BASE, ATTEN_NORM);
-       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame1);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(fireball, animtime), W_Fireball_Attack1_Frame1);
 }
 
-void W_Fireball_Firemine_Think(void)
+void W_Fireball_Firemine_Think()
 {SELFPARAM();
        if(time > self.pushltime)
        {
@@ -283,7 +282,7 @@ void W_Fireball_Firemine_Think(void)
        self.nextthink = time + 0.1;
 }
 
-void W_Fireball_Firemine_Touch(void)
+void W_Fireball_Firemine_Touch()
 {SELFPARAM();
        PROJECTILE_TOUCH;
        if(other.takedamage == DAMAGE_AIM)
@@ -295,7 +294,7 @@ void W_Fireball_Firemine_Touch(void)
        self.projectiledeathtype |= HITTYPE_BOUNCE;
 }
 
-void W_Fireball_Attack2(void)
+void W_Fireball_Attack2()
 {SELFPARAM();
        entity proj;
        vector f_diff;
@@ -324,9 +323,8 @@ void W_Fireball_Attack2(void)
 
        Send_Effect(EFFECT_FIREBALL_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       proj = spawn();
+       proj = new(grenade);
        proj.owner = proj.realowner = self;
-       proj.classname = "grenade";
        proj.bot_dodge = true;
        proj.bot_dodgerating = WEP_CVAR_SEC(fireball, damage);
        proj.movetype = MOVETYPE_BOUNCE;
@@ -371,23 +369,23 @@ void W_Fireball_Attack2(void)
                                }
                        }
                }
-               METHOD(Fireball, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Fireball, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
-                       if(fire1)
+                       if(fire & 1)
                        {
                                if(time >= actor.fireball_primarytime)
-                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(fireball, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(fireball, refire)))
                                {
-                                       W_Fireball_Attack1_Frame0(thiswep, actor, fire1, fire2);
+                                       W_Fireball_Attack1_Frame0(thiswep, actor, weaponentity, fire);
                                        actor.fireball_primarytime = time + WEP_CVAR_PRI(fireball, refire2) * W_WeaponRateFactor();
                                }
                        }
-                       else if(fire2)
+                       else if(fire & 2)
                        {
-                               if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(fireball, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(fireball, refire)))
                                {
                                        W_Fireball_Attack2();
-                                       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(fireball, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(fireball, animtime), w_ready);
                                }
                        }
                }
@@ -443,7 +441,7 @@ void W_Fireball_Attack2(void)
                        else
                        {
                                org2 = w_org + w_backoff * 16;
-                               pointparticles(particleeffectnum(EFFECT_FIREBALL_EXPLODE), org2, '0 0 0', 1);
+                               pointparticles(EFFECT_FIREBALL_EXPLODE, org2, '0 0 0', 1);
                                if(!w_issilent)
                                        sound(self, CH_SHOTS, SND_FIREBALL_IMPACT2, VOL_BASE, ATTEN_NORM * 0.25); // long range boom
                        }
index 37f6875b5595118009cace956d568318439194b8..859b54c959416077166498d37e5f097e3d59b773 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Hagar, Weapon)
 /* crosshair */ ATTRIB(Hagar, w_crosshair_size, float, 0.8);
 /* wepimg    */ ATTRIB(Hagar, model2, string, "weaponhagar");
 /* refname   */ ATTRIB(Hagar, netname, string, "hagar");
-/* wepname   */ ATTRIB(Hagar, message, string, _("Hagar"));
+/* wepname   */ ATTRIB(Hagar, m_name, string, _("Hagar"));
 ENDCLASS(Hagar)
 REGISTER_WEAPON(HAGAR, NEW(Hagar));
 
@@ -58,11 +58,11 @@ HAGAR_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_hagar) { weapon_defaultspawnfunc(WEP_HAGAR.m_id); }
+spawnfunc(weapon_hagar) { weapon_defaultspawnfunc(this, WEP_HAGAR); }
 
 // NO bounce protection, as bounces are limited!
 
-void W_Hagar_Explode(void)
+void W_Hagar_Explode()
 {SELFPARAM();
        self.event_damage = func_null;
        RadiusDamage(self, self.realowner, WEP_CVAR_PRI(hagar, damage), WEP_CVAR_PRI(hagar, edgedamage), WEP_CVAR_PRI(hagar, radius), world, world, WEP_CVAR_PRI(hagar, force), self.projectiledeathtype, other);
@@ -70,7 +70,7 @@ void W_Hagar_Explode(void)
        remove(self);
 }
 
-void W_Hagar_Explode2(void)
+void W_Hagar_Explode2()
 {SELFPARAM();
        self.event_damage = func_null;
        RadiusDamage(self, self.realowner, WEP_CVAR_SEC(hagar, damage), WEP_CVAR_SEC(hagar, edgedamage), WEP_CVAR_SEC(hagar, radius), world, world, WEP_CVAR_SEC(hagar, force), self.projectiledeathtype, other);
@@ -102,13 +102,13 @@ void W_Hagar_Damage(entity inflictor, entity attacker, float damage, int deathty
                W_PrepareExplosionByDamage(attacker, self.think);
 }
 
-void W_Hagar_Touch(void)
+void W_Hagar_Touch()
 {SELFPARAM();
        PROJECTILE_TOUCH;
        self.use();
 }
 
-void W_Hagar_Touch2(void)
+void W_Hagar_Touch2()
 {SELFPARAM();
        PROJECTILE_TOUCH;
 
@@ -133,9 +133,8 @@ void W_Hagar_Attack(Weapon thiswep)
 
        Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       missile = spawn();
+       missile = new(missile);
        missile.owner = missile.realowner = self;
-       missile.classname = "missile";
        missile.bot_dodge = true;
        missile.bot_dodgerating = WEP_CVAR_PRI(hagar, damage);
 
@@ -176,9 +175,8 @@ void W_Hagar_Attack2(Weapon thiswep)
 
        Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       missile = spawn();
+       missile = new(missile);
        missile.owner = missile.realowner = self;
-       missile.classname = "missile";
        missile.bot_dodge = true;
        missile.bot_dodgerating = WEP_CVAR_SEC(hagar, damage);
 
@@ -211,7 +209,7 @@ void W_Hagar_Attack2(Weapon thiswep)
 }
 
 .float hagar_loadstep, hagar_loadblock, hagar_loadbeep, hagar_warning;
-void W_Hagar_Attack2_Load_Release(void)
+void W_Hagar_Attack2_Load_Release(.entity weaponentity)
 {SELFPARAM();
        // time to release the rockets we've loaded
 
@@ -223,7 +221,7 @@ void W_Hagar_Attack2_Load_Release(void)
        if(!self.hagar_load)
                return;
 
-       weapon_prepareattack_do(self, true, WEP_CVAR_SEC(hagar, refire));
+       weapon_prepareattack_do(self, weaponentity, true, WEP_CVAR_SEC(hagar, refire));
 
        W_SetupShot(self, false, 2, SND(HAGAR_FIRE), CH_WEAPON_A, WEP_CVAR_SEC(hagar, damage));
        Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
@@ -236,9 +234,8 @@ void W_Hagar_Attack2_Load_Release(void)
        missile = world;
        for(counter = 0; counter < shots; ++counter)
        {
-               missile = spawn();
+               missile = new(missile);
                missile.owner = missile.realowner = self;
-               missile.classname = "missile";
                missile.bot_dodge = true;
                missile.bot_dodgerating = WEP_CVAR_SEC(hagar, damage);
 
@@ -286,12 +283,12 @@ void W_Hagar_Attack2_Load_Release(void)
                MUTATOR_CALLHOOK(EditProjectile, self, missile);
        }
 
-       weapon_thinkf(self, WFRAME_FIRE2, WEP_CVAR_SEC(hagar, load_animtime), w_ready);
+       weapon_thinkf(self, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hagar, load_animtime), w_ready);
        self.hagar_loadstep = time + WEP_CVAR_SEC(hagar, refire) * W_WeaponRateFactor();
        self.hagar_load = 0;
 }
 
-void W_Hagar_Attack2_Load(Weapon thiswep)
+void W_Hagar_Attack2_Load(Weapon thiswep, .entity weaponentity)
 {SELFPARAM();
        // loadable hagar secondary attack, must always run each frame
 
@@ -318,7 +315,7 @@ void W_Hagar_Attack2_Load(Weapon thiswep)
                        if(self.hagar_load)
                        {
                                // if we pressed primary fire while loading, unload all rockets and abort
-                               self.weaponentity.state = WS_READY;
+                               self.(weaponentity).state = WS_READY;
                                W_DecreaseAmmo(thiswep, self, WEP_CVAR_SEC(hagar, ammo) * self.hagar_load * -1); // give back ammo
                                self.hagar_load = 0;
                                sound(self, CH_WEAPON_A, SND_HAGAR_BEEP, VOL_BASE, ATTN_NORM);
@@ -338,7 +335,7 @@ void W_Hagar_Attack2_Load(Weapon thiswep)
                                if(!self.hagar_loadblock && self.hagar_loadstep < time)
                                {
                                        W_DecreaseAmmo(thiswep, self, WEP_CVAR_SEC(hagar, ammo));
-                                       self.weaponentity.state = WS_INUSE;
+                                       self.(weaponentity).state = WS_INUSE;
                                        self.hagar_load += 1;
                                        sound(self, CH_WEAPON_B, SND_HAGAR_LOAD, VOL_BASE * 0.8, ATTN_NORM); // sound is too loud according to most
 
@@ -379,8 +376,8 @@ void W_Hagar_Attack2_Load(Weapon thiswep)
                // release if player let go of button or if they've held it in too long
                if(!self.BUTTON_ATCK2 || (stopped && self.hagar_loadstep < time && WEP_CVAR_SEC(hagar, load_hold) >= 0))
                {
-                       self.weaponentity.state = WS_READY;
-                       W_Hagar_Attack2_Load_Release();
+                       self.(weaponentity).state = WS_READY;
+                       W_Hagar_Attack2_Load_Release(weaponentity);
                }
        }
        else
@@ -407,30 +404,30 @@ void W_Hagar_Attack2_Load(Weapon thiswep)
                        else // not using secondary_speed since these are only 15% and should cause some ricochets without re-aiming
                                self.BUTTON_ATCK2 = bot_aim(WEP_CVAR_PRI(hagar, speed), 0, WEP_CVAR_PRI(hagar, lifetime), false);
                }
-               METHOD(Hagar, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Hagar, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        float loadable_secondary;
                        loadable_secondary = (WEP_CVAR_SEC(hagar, load) && WEP_CVAR(hagar, secondary));
 
                        if(loadable_secondary)
-                               W_Hagar_Attack2_Load(thiswep); // must always run each frame
+                               W_Hagar_Attack2_Load(thiswep, weaponentity); // must always run each frame
                        if(autocvar_g_balance_hagar_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(hagar, ammo), WEP_CVAR_SEC(hagar, ammo))) { // forced reload
                                Weapon w = get_weaponinfo(actor.weapon);
                                w.wr_reload(w);
-                       } else if(fire1 && !actor.hagar_load && !actor.hagar_loadblock) // not while secondary is loaded or awaiting reset
+                       } else if((fire & 1) && !actor.hagar_load && !actor.hagar_loadblock) // not while secondary is loaded or awaiting reset
                        {
-                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(hagar, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(hagar, refire)))
                                {
                                        W_Hagar_Attack(thiswep);
-                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(hagar, refire), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hagar, refire), w_ready);
                                }
                        }
-                       else if(fire2 && !loadable_secondary && WEP_CVAR(hagar, secondary))
+                       else if((fire & 2) && !loadable_secondary && WEP_CVAR(hagar, secondary))
                        {
-                               if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(hagar, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(hagar, refire)))
                                {
                                        W_Hagar_Attack2(thiswep);
-                                       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(hagar, refire), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hagar, refire), w_ready);
                                }
                        }
                }
@@ -439,8 +436,9 @@ void W_Hagar_Attack2_Load(Weapon thiswep)
                        // we lost the weapon and want to prepare switching away
                        if(self.hagar_load)
                        {
-                               self.weaponentity.state = WS_READY;
-                               W_Hagar_Attack2_Load_Release();
+                               .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+                               self.(weaponentity).state = WS_READY;
+                               W_Hagar_Attack2_Load_Release(weaponentity);
                        }
                }
                METHOD(Hagar, wr_init, void(entity thiswep))
@@ -479,9 +477,10 @@ void W_Hagar_Attack2_Load(Weapon thiswep)
                }
                METHOD(Hagar, wr_playerdeath, void(entity thiswep))
                {
+                       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
                        // if we have any rockets loaded when we die, release them
                        if(self.hagar_load && WEP_CVAR_SEC(hagar, load_releasedeath))
-                               W_Hagar_Attack2_Load_Release();
+                               W_Hagar_Attack2_Load_Release(weaponentity);
                }
                METHOD(Hagar, wr_reload, void(entity thiswep))
                {
@@ -507,7 +506,7 @@ void W_Hagar_Attack2_Load(Weapon thiswep)
                {
                        vector org2;
                        org2 = w_org + w_backoff * 6;
-                       pointparticles(particleeffectnum(EFFECT_HAGAR_EXPLODE), org2, '0 0 0', 1);
+                       pointparticles(EFFECT_HAGAR_EXPLODE, org2, '0 0 0', 1);
                        if(!w_issilent)
                        {
                                if(w_random<0.15)
index 616939d1e80abd1a83c259d626f91d699ff931ed..9c4d8b2a66e86923de98617f0d3d6280941bd732 100644 (file)
@@ -13,7 +13,7 @@ CLASS(HLAC, Weapon)
 /* crosshair */ ATTRIB(HLAC, w_crosshair_size, float, 0.6);
 /* wepimg    */ ATTRIB(HLAC, model2, string, "weaponhlac");
 /* refname   */ ATTRIB(HLAC, netname, string, "hlac");
-/* wepname   */ ATTRIB(HLAC, message, string, _("Heavy Laser Assault Cannon"));
+/* wepname   */ ATTRIB(HLAC, m_name, string, _("Heavy Laser Assault Cannon"));
 ENDCLASS(HLAC)
 REGISTER_WEAPON(HLAC, NEW(HLAC));
 
@@ -50,9 +50,9 @@ HLAC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_hlac) { weapon_defaultspawnfunc(WEP_HLAC.m_id); }
+spawnfunc(weapon_hlac) { weapon_defaultspawnfunc(this, WEP_HLAC); }
 
-void W_HLAC_Touch(void)
+void W_HLAC_Touch()
 {SELFPARAM();
        float isprimary;
 
@@ -87,9 +87,8 @@ void W_HLAC_Attack(Weapon thiswep)
                self.punchangle_y = random() - 0.5;
        }
 
-       missile = spawn();
+       missile = new(hlacbolt);
        missile.owner = missile.realowner = self;
-       missile.classname = "hlacbolt";
        missile.bot_dodge = true;
 
     missile.bot_dodgerating = WEP_CVAR_PRI(hlac, damage);
@@ -116,7 +115,7 @@ void W_HLAC_Attack(Weapon thiswep)
        MUTATOR_CALLHOOK(EditProjectile, self, missile);
 }
 
-void W_HLAC_Attack2(void)
+void W_HLAC_Attack2()
 {SELFPARAM();
        entity missile;
     float spread;
@@ -130,9 +129,8 @@ void W_HLAC_Attack2(void)
        W_SetupShot(self, false, 3, SND(LASERGUN_FIRE), CH_WEAPON_A, WEP_CVAR_SEC(hlac, damage));
        Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       missile = spawn();
+       missile = new(hlacbolt);
        missile.owner = missile.realowner = self;
-       missile.classname = "hlacbolt";
        missile.bot_dodge = true;
 
     missile.bot_dodgerating = WEP_CVAR_SEC(hlac, damage);
@@ -161,11 +159,11 @@ void W_HLAC_Attack2(void)
 }
 
 // weapon frames
-void W_HLAC_Attack_Frame(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_HLAC_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        if(actor.weapon != actor.switchweapon) // abort immediately if switching
        {
-               w_ready(thiswep, actor, fire1, fire2);
+               w_ready(thiswep, actor, weaponentity, fire);
                return;
        }
 
@@ -176,18 +174,19 @@ void W_HLAC_Attack_Frame(Weapon thiswep, entity actor, bool fire1, bool fire2)
                if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
                {
                        W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
-                       w_ready(thiswep, actor, fire1, fire2);
+                       w_ready(thiswep, actor, weaponentity, fire);
                        return;
                }
 
-               ATTACK_FINISHED(actor) = time + WEP_CVAR_PRI(hlac, refire) * W_WeaponRateFactor();
+               int slot = weaponslot(weaponentity);
+               ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(hlac, refire) * W_WeaponRateFactor();
                W_HLAC_Attack(WEP_HLAC);
                actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
-        weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame);
+        weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame);
        }
        else
        {
-               weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, animtime), w_ready);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, animtime), w_ready);
        }
 }
 
@@ -211,27 +210,27 @@ void W_HLAC_Attack2_Frame(Weapon thiswep)
                {
                        self.BUTTON_ATCK = bot_aim(WEP_CVAR_PRI(hlac, speed), 0, WEP_CVAR_PRI(hlac, lifetime), false);
                }
-               METHOD(HLAC, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(HLAC, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(autocvar_g_balance_hlac_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(hlac, ammo), WEP_CVAR_SEC(hlac, ammo))) { // forced reload
                                Weapon w = get_weaponinfo(actor.weapon);
                                w.wr_reload(w);
-                       } else if(fire1)
+                       } else if(fire & 1)
                        {
-                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(hlac, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(hlac, refire)))
                                {
                                        actor.misc_bulletcounter = 0;
                                        W_HLAC_Attack(thiswep);
-                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hlac, refire), W_HLAC_Attack_Frame);
                                }
                        }
 
-                       else if(fire2 && WEP_CVAR(hlac, secondary))
+                       else if((fire & 2) && WEP_CVAR(hlac, secondary))
                        {
-                               if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(hlac, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(hlac, refire)))
                                {
                                        W_HLAC_Attack2_Frame(thiswep);
-                                       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(hlac, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hlac, animtime), w_ready);
                                }
                        }
                }
@@ -275,7 +274,7 @@ void W_HLAC_Attack2_Frame(Weapon thiswep)
                {
                        vector org2;
                        org2 = w_org + w_backoff * 6;
-                       pointparticles(particleeffectnum(EFFECT_BLASTER_IMPACT), org2, w_backoff * 1000, 1);
+                       pointparticles(EFFECT_BLASTER_IMPACT, org2, w_backoff * 1000, 1);
                        if(!w_issilent)
                                sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTN_NORM);
                }
diff --git a/qcsrc/common/weapons/weapon/hmg.qc b/qcsrc/common/weapons/weapon/hmg.qc
deleted file mode 100644 (file)
index 6707a7c..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-#ifndef IMPLEMENTATION
-CLASS(HeavyMachineGun, Weapon)
-/* ammotype  */ ATTRIB(HeavyMachineGun, ammo_field, .int, ammo_nails)
-/* impulse   */ ATTRIB(HeavyMachineGun, impulse, int, 3)
-/* flags     */ ATTRIB(HeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
-/* rating    */ ATTRIB(HeavyMachineGun, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
-/* color     */ ATTRIB(HeavyMachineGun, wpcolor, vector, '0.5 0.5 0');
-/* modelname */ ATTRIB(HeavyMachineGun, mdl, string, "ok_hmg");
-#ifndef MENUQC
-/* model     */ ATTRIB(HeavyMachineGun, m_model, Model, MDL_HMG_ITEM);
-#endif
-/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair, string, "gfx/crosshairuzi");
-/* crosshair */ ATTRIB(HeavyMachineGun, w_crosshair_size, float, 0.6);
-/* wepimg    */ ATTRIB(HeavyMachineGun, model2, string, "weaponhmg");
-/* refname   */ ATTRIB(HeavyMachineGun, netname, string, "hmg");
-/* wepname   */ ATTRIB(HeavyMachineGun, message, string, _("Heavy Machine Gun"));
-ENDCLASS(HeavyMachineGun)
-REGISTER_WEAPON(HMG, NEW(HeavyMachineGun));
-
-#define HMG_SETTINGS(w_cvar,w_prop) HMG_SETTINGS_LIST(w_cvar, w_prop, HMG, hmg)
-#define HMG_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
-       w_cvar(id, sn, NONE, spread_min) \
-       w_cvar(id, sn, NONE, spread_max) \
-       w_cvar(id, sn, NONE, spread_add) \
-       w_cvar(id, sn, NONE, solidpenetration) \
-       w_cvar(id, sn, NONE, damage) \
-       w_cvar(id, sn, NONE, force) \
-       w_cvar(id, sn, NONE, refire) \
-       w_cvar(id, sn, NONE, ammo) \
-       w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
-       w_prop(id, sn, float,  reloading_time, reload_time) \
-       w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
-       w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
-       w_prop(id, sn, string, weaponreplace, weaponreplace) \
-       w_prop(id, sn, float,  weaponstart, weaponstart) \
-       w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride) \
-       w_prop(id, sn, float,  weaponthrowable, weaponthrowable)
-
-#ifdef SVQC
-HMG_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
-#endif
-#endif
-#ifdef IMPLEMENTATION
-#ifdef SVQC
-
-spawnfunc(weapon_hmg) { weapon_defaultspawnfunc(WEP_HMG.m_id); }
-
-void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, bool fire1, bool fire2)
-{
-       if (!actor.BUTTON_ATCK)
-       {
-               w_ready(thiswep, actor, fire1, fire2);
-               return;
-       }
-
-       Weapon w = get_weaponinfo(actor.weapon);
-       if(!w.wr_checkammo1(w))
-       if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
-       {
-               W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
-               w_ready(thiswep, actor, fire1, fire2);
-               return;
-       }
-
-       W_DecreaseAmmo(WEP_HMG, self, WEP_CVAR(hmg, ammo));
-
-       W_SetupShot (actor, true, 0, SND(UZI_FIRE), CH_WEAPON_A, WEP_CVAR(hmg, damage));
-
-       if(!autocvar_g_norecoil)
-       {
-               actor.punchangle_x = random () - 0.5;
-               actor.punchangle_y = random () - 0.5;
-       }
-
-       float hmg_spread = bound(WEP_CVAR(hmg, spread_min), WEP_CVAR(hmg, spread_min) + (WEP_CVAR(hmg, spread_add) * actor.misc_bulletcounter), WEP_CVAR(hmg, spread_max));
-       fireBullet(w_shotorg, w_shotdir, hmg_spread, WEP_CVAR(hmg, solidpenetration), WEP_CVAR(hmg, damage), WEP_CVAR(hmg, force), WEP_HMG.m_id, 0);
-
-       actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
-
-       Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
-
-       W_MachineGun_MuzzleFlash();
-       W_AttachToShotorg(actor, actor.muzzle_flash, '5 0 0');
-
-       if (autocvar_g_casings >= 2) // casing code
-               SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
-
-       ATTACK_FINISHED(actor) = time + WEP_CVAR(hmg, refire) * W_WeaponRateFactor();
-       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(hmg, refire), W_HeavyMachineGun_Attack_Auto);
-}
-
-               METHOD(HeavyMachineGun, wr_aim, void(entity thiswep))
-               {
-                       if(vlen(self.origin-self.enemy.origin) < 3000 - bound(0, skill, 10) * 200)
-                               self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, false);
-                       else
-                               self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, false);
-               }
-               METHOD(HeavyMachineGun, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
-               {
-                       if(WEP_CVAR(hmg, reload_ammo) && actor.clip_load < WEP_CVAR(hmg, ammo)) { // forced reload
-                               Weapon w = get_weaponinfo(actor.weapon);
-                               w.wr_reload(w);
-                       } else
-                       {
-                               if (fire1)
-                               if (weapon_prepareattack(thiswep, actor, false, 0))
-                               {
-                                       actor.misc_bulletcounter = 0;
-                                       W_HeavyMachineGun_Attack_Auto(thiswep, actor, fire1, fire2);
-                               }
-                       }
-               }
-               METHOD(HeavyMachineGun, wr_init, void(entity thiswep))
-               {
-                       HMG_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
-               }
-               METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep))
-               {
-                       float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
-
-                       if(autocvar_g_balance_hmg_reload_ammo)
-                               ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
-
-                       return ammo_amount;
-               }
-               METHOD(HeavyMachineGun, wr_checkammo2, bool(entity thiswep))
-               {
-                       float ammo_amount = self.ammo_nails >= WEP_CVAR(hmg, ammo);
-
-                       if(autocvar_g_balance_hmg_reload_ammo)
-                               ammo_amount += self.(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
-
-                       return ammo_amount;
-               }
-               METHOD(HeavyMachineGun, wr_config, void(entity thiswep))
-               {
-                       HMG_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
-               }
-               METHOD(HeavyMachineGun, wr_reload, void(entity thiswep))
-               {
-                       W_Reload(self, WEP_CVAR(hmg, ammo), SND(RELOAD));
-               }
-               METHOD(HeavyMachineGun, wr_suicidemessage, int(entity thiswep))
-               {
-                       return WEAPON_THINKING_WITH_PORTALS;
-               }
-               METHOD(HeavyMachineGun, wr_killmessage, int(entity thiswep))
-               {
-                       if(w_deathtype & HITTYPE_SECONDARY)
-                               return WEAPON_HMG_MURDER_SNIPE;
-                       else
-                               return WEAPON_HMG_MURDER_SPRAY;
-               }
-
-#endif
-#ifdef CSQC
-
-               METHOD(HeavyMachineGun, wr_impacteffect, void(entity thiswep))
-               {
-                       vector org2;
-                       org2 = w_org + w_backoff * 2;
-                       pointparticles(particleeffectnum(EFFECT_MACHINEGUN_IMPACT), org2, w_backoff * 1000, 1);
-                       if(!w_issilent)
-                               if(w_random < 0.05)
-                                       sound(self, CH_SHOTS, SND_RIC1, VOL_BASE, ATTEN_NORM);
-                               else if(w_random < 0.1)
-                                       sound(self, CH_SHOTS, SND_RIC2, VOL_BASE, ATTEN_NORM);
-                               else if(w_random < 0.2)
-                                       sound(self, CH_SHOTS, SND_RIC3, VOL_BASE, ATTEN_NORM);
-               }
-
-#endif
-#endif
index c158d1c3289be58c1881360c35fa8512717dbde8..4e3722f138032c5aefbe1512923864901c48bbf7 100644 (file)
@@ -13,17 +13,20 @@ CLASS(Hook, Weapon)
 /* crosshair */ ATTRIB(Hook, w_crosshair_size, float, 0.5);
 /* wepimg    */ ATTRIB(Hook, model2, string, "weaponhook");
 /* refname   */ ATTRIB(Hook, netname, string, "hook");
-/* wepname   */ ATTRIB(Hook, message, string, _("Grappling Hook"));
+/* wepname   */ ATTRIB(Hook, m_name, string, _("Grappling Hook"));
        ATTRIB(Hook, ammo_factor, float, 1)
 ENDCLASS(Hook)
 REGISTER_WEAPON(HOOK, NEW(Hook));
 
 CLASS(OffhandHook, OffhandWeapon)
+#ifdef SVQC
     METHOD(OffhandHook, offhand_think, void(OffhandHook this, entity actor, bool key_pressed))
     {
        Weapon wep = WEP_HOOK;
-       wep.wr_think(wep, actor, key_pressed, false);
+       .entity weaponentity = weaponentities[1];
+       wep.wr_think(wep, actor, weaponentity, key_pressed ? 1 : 0);
     }
+#endif
 ENDCLASS(OffhandHook)
 OffhandHook OFFHAND_HOOK; STATIC_INIT(OFFHAND_HOOK) { OFFHAND_HOOK = NEW(OffhandHook); }
 
@@ -71,9 +74,9 @@ HOOK_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #ifdef IMPLEMENTATION
 #ifdef SVQC
 
-spawnfunc(weapon_hook) { weapon_defaultspawnfunc(WEP_HOOK.m_id); }
+spawnfunc(weapon_hook) { weapon_defaultspawnfunc(this, WEP_HOOK); }
 
-void W_Hook_ExplodeThink(void)
+void W_Hook_ExplodeThink()
 {SELFPARAM();
        float dt, dmg_remaining_next, f;
 
@@ -93,7 +96,7 @@ void W_Hook_ExplodeThink(void)
                remove(self);
 }
 
-void W_Hook_Explode2(void)
+void W_Hook_Explode2()
 {SELFPARAM();
        self.event_damage = func_null;
        self.touch = func_null;
@@ -126,7 +129,7 @@ void W_Hook_Damage(entity inflictor, entity attacker, float damage, int deathtyp
                W_PrepareExplosionByDamage(self.realowner, W_Hook_Explode2);
 }
 
-void W_Hook_Touch2(void)
+void W_Hook_Touch2()
 {SELFPARAM();
        PROJECTILE_TOUCH;
        self.use();
@@ -174,30 +177,30 @@ void W_Hook_Attack2(Weapon thiswep, entity actor)
        MUTATOR_CALLHOOK(EditProjectile, actor, gren);
 }
 
-               METHOD(Hook, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Hook, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
-                       if (fire1) {
+                       if (fire & 1) {
                                if(!actor.hook)
                                if(!(actor.hook_state & HOOK_WAITING_FOR_RELEASE))
                                if(time > actor.hook_refire)
-                               if(weapon_prepareattack(thiswep, actor, false, -1))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, -1))
                                {
                                        W_DecreaseAmmo(thiswep, actor, thiswep.ammo_factor * WEP_CVAR_PRI(hook, ammo));
                                        actor.hook_state |= HOOK_FIRING;
                                        actor.hook_state |= HOOK_WAITING_FOR_RELEASE;
-                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(hook, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(hook, animtime), w_ready);
                                }
                        } else {
                                actor.hook_state |= HOOK_REMOVING;
                                actor.hook_state &= ~HOOK_WAITING_FOR_RELEASE;
                        }
 
-                       if(fire2)
+                       if(fire & 2)
                        {
-                               if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(hook, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(hook, refire)))
                                {
                                        W_Hook_Attack2(thiswep, actor);
-                                       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(hook, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hook, animtime), w_ready);
                                }
                        }
 
@@ -313,7 +316,7 @@ void W_Hook_Attack2(Weapon thiswep, entity actor)
                {
                        vector org2;
                        org2 = w_org + w_backoff * 2;
-                       pointparticles(particleeffectnum(EFFECT_HOOK_EXPLODE), org2, '0 0 0', 1);
+                       pointparticles(EFFECT_HOOK_EXPLODE, org2, '0 0 0', 1);
                        if(!w_issilent)
                                sound(self, CH_SHOTS, SND_HOOKBOMB_IMPACT, VOL_BASE, ATTN_NORM);
                }
index 90a4471f17bbf6110bca905b19da7b0883821c20..4679ef38f747cbb287fb73388bd09583ae59b97a 100644 (file)
@@ -13,7 +13,7 @@ CLASS(MachineGun, Weapon)
 /* crosshair */ ATTRIB(MachineGun, w_crosshair_size, float, 0.6);
 /* wepimg    */ ATTRIB(MachineGun, model2, string, "weaponuzi");
 /* refname   */ ATTRIB(MachineGun, netname, string, "machinegun");
-/* wepname   */ ATTRIB(MachineGun, message, string, _("MachineGun"));
+/* wepname   */ ATTRIB(MachineGun, m_name, string, _("MachineGun"));
 ENDCLASS(MachineGun)
 REGISTER_WEAPON(MACHINEGUN, NEW(MachineGun));
 
@@ -62,14 +62,14 @@ spawnfunc(weapon_machinegun)
        if(autocvar_sv_q3acompat_machineshotgunswap)
        if(self.classname != "droppedweapon")
        {
-               weapon_defaultspawnfunc(WEP_SHOCKWAVE.m_id);
+               weapon_defaultspawnfunc(this, WEP_SHOCKWAVE);
                return;
        }
-       weapon_defaultspawnfunc(WEP_MACHINEGUN.m_id);
+       weapon_defaultspawnfunc(this, WEP_MACHINEGUN);
 }
 spawnfunc(weapon_uzi) { spawnfunc_weapon_machinegun(this); }
 
-void W_MachineGun_MuzzleFlash_Think(void)
+void W_MachineGun_MuzzleFlash_Think()
 {SELFPARAM();
        self.frame = self.frame + 2;
        self.scale = self.scale * 0.5;
@@ -86,7 +86,7 @@ void W_MachineGun_MuzzleFlash_Think(void)
 
 }
 
-void W_MachineGun_MuzzleFlash(void)
+void W_MachineGun_MuzzleFlash()
 {SELFPARAM();
        if(self.muzzle_flash == world)
                self.muzzle_flash = spawn();
@@ -104,7 +104,7 @@ void W_MachineGun_MuzzleFlash(void)
        self.muzzle_flash.owner = self.muzzle_flash.realowner = self;
 }
 
-void W_MachineGun_Attack(Weapon thiswep, int deathtype)
+void W_MachineGun_Attack(Weapon thiswep, int deathtype, .entity weaponentity)
 {SELFPARAM();
        W_SetupShot(self, true, 0, SND(UZI_FIRE), CH_WEAPON_A, ((self.misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage)));
        if(!autocvar_g_norecoil)
@@ -112,9 +112,9 @@ void W_MachineGun_Attack(Weapon thiswep, int deathtype)
                self.punchangle_x = random() - 0.5;
                self.punchangle_y = random() - 0.5;
        }
-
+       int slot = weaponslot(weaponentity);
        // this attack_finished just enforces a cooldown at the end of a burst
-       ATTACK_FINISHED(self) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor();
+       ATTACK_FINISHED(self, slot) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor();
 
        if(self.misc_bulletcounter == 1)
                fireBullet(w_shotorg, w_shotdir, WEP_CVAR(machinegun, first_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, first_damage), WEP_CVAR(machinegun, first_force), deathtype, 0);
@@ -137,11 +137,11 @@ void W_MachineGun_Attack(Weapon thiswep, int deathtype)
 }
 
 // weapon frames
-void W_MachineGun_Attack_Frame(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_MachineGun_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        if(actor.weapon != actor.switchweapon) // abort immediately if switching
        {
-               w_ready(thiswep, actor, fire1, fire2);
+               w_ready(thiswep, actor, weaponentity, fire);
                return;
        }
        if(actor.BUTTON_ATCK)
@@ -151,25 +151,25 @@ void W_MachineGun_Attack_Frame(Weapon thiswep, entity actor, bool fire1, bool fi
                if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
                {
                        W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
-                       w_ready(thiswep, actor, fire1, fire2);
+                       w_ready(thiswep, actor, weaponentity, fire);
                        return;
                }
                actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
-               W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id);
-               weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Frame);
+               W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id, weaponentity);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Frame);
        }
        else
-               weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), w_ready);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), w_ready);
 }
 
 
-void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        float machinegun_spread;
 
-       if(!fire1)
+       if(!(fire & 1))
        {
-               w_ready(thiswep, actor, fire1, fire2);
+               w_ready(thiswep, actor, weaponentity, fire);
                return;
        }
 
@@ -178,7 +178,7 @@ void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, bool fire1, bool fir
        if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
        {
                W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
-               w_ready(thiswep, actor, fire1, fire2);
+               w_ready(thiswep, actor, weaponentity, fire);
                return;
        }
 
@@ -204,11 +204,12 @@ void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, bool fire1, bool fir
        if(autocvar_g_casings >= 2) // casing code
                SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor);
 
-       ATTACK_FINISHED(actor) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor();
-       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Auto);
+       int slot = weaponslot(weaponentity);
+       ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(machinegun, first_refire) * W_WeaponRateFactor();
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Auto);
 }
 
-void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        W_SetupShot(actor, true, 0, SND(UZI_FIRE), CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage));
        if(!autocvar_g_norecoil)
@@ -230,12 +231,13 @@ void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, bool fire1, bool fi
        actor.misc_bulletcounter = actor.misc_bulletcounter + 1;
        if(actor.misc_bulletcounter == 0)
        {
-               ATTACK_FINISHED(actor) = time + WEP_CVAR(machinegun, burst_refire2) * W_WeaponRateFactor();
-               weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(machinegun, burst_animtime), w_ready);
+               int slot = weaponslot(weaponentity);
+               ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(machinegun, burst_refire2) * W_WeaponRateFactor();
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(machinegun, burst_animtime), w_ready);
        }
        else
        {
-               weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(machinegun, burst_refire), W_MachineGun_Attack_Burst);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(machinegun, burst_refire), W_MachineGun_Attack_Burst);
        }
 
 }
@@ -247,7 +249,7 @@ void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, bool fire1, bool fi
                        else
                                self.BUTTON_ATCK2 = bot_aim(1000000, 0, 0.001, false);
                }
-               METHOD(MachineGun, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(MachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(WEP_CVAR(machinegun, reload_ammo) && actor.clip_load < min(max(WEP_CVAR(machinegun, sustained_ammo), WEP_CVAR(machinegun, first_ammo)), WEP_CVAR(machinegun, burst_ammo))) { // forced reload
                                Weapon w = get_weaponinfo(actor.weapon);
@@ -255,48 +257,48 @@ void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, bool fire1, bool fi
                        } else
                        if(WEP_CVAR(machinegun, mode) == 1)
                        {
-                               if(fire1)
-                               if(weapon_prepareattack(thiswep, actor, false, 0))
+                               if(fire & 1)
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
                                {
                                        actor.misc_bulletcounter = 0;
-                                       W_MachineGun_Attack_Auto(thiswep, actor, fire1, fire2);
+                                       W_MachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
                                }
 
-                               if(fire2)
-                               if(weapon_prepareattack(thiswep, actor, true, 0))
+                               if(fire & 2)
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, true, 0))
                                {
                                        Weapon w = get_weaponinfo(actor.weapon);
                                        if(!w.wr_checkammo2(w))
                                        if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
                                        {
                                                W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
-                                               w_ready(thiswep, actor, fire1, fire2);
+                                               w_ready(thiswep, actor, weaponentity, fire);
                                                return;
                                        }
 
                                        W_DecreaseAmmo(thiswep, actor, WEP_CVAR(machinegun, burst_ammo));
 
                                        actor.misc_bulletcounter = WEP_CVAR(machinegun, burst) * -1;
-                                       W_MachineGun_Attack_Burst(thiswep, actor, fire1, fire2);
+                                       W_MachineGun_Attack_Burst(thiswep, actor, weaponentity, fire);
                                }
                        }
                        else
                        {
 
-                               if(fire1)
-                               if(weapon_prepareattack(thiswep, actor, false, 0))
+                               if(fire & 1)
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
                                {
                                        actor.misc_bulletcounter = 1;
-                                       W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id); // sets attack_finished
-                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Frame);
+                                       W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id, weaponentity); // sets attack_finished
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Frame);
                                }
 
-                               if(fire2 && WEP_CVAR(machinegun, first))
-                               if(weapon_prepareattack(thiswep, actor, true, 0))
+                               if((fire & 2) && WEP_CVAR(machinegun, first))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, true, 0))
                                {
                                        actor.misc_bulletcounter = 1;
-                                       W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id | HITTYPE_SECONDARY); // sets attack_finished
-                                       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(machinegun, first_refire), w_ready);
+                                       W_MachineGun_Attack(WEP_MACHINEGUN, WEP_MACHINEGUN.m_id | HITTYPE_SECONDARY, weaponentity); // sets attack_finished
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(machinegun, first_refire), w_ready);
                                }
                        }
                }
@@ -365,14 +367,9 @@ void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, bool fire1, bool fi
                {
                        vector org2;
                        org2 = w_org + w_backoff * 2;
-                       pointparticles(particleeffectnum(EFFECT_MACHINEGUN_IMPACT), org2, w_backoff * 1000, 1);
+                       pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
                        if(!w_issilent)
-                               if(w_random < 0.05)
-                                       sound(self, CH_SHOTS, SND_RIC1, VOL_BASE, ATTN_NORM);
-                               else if(w_random < 0.1)
-                                       sound(self, CH_SHOTS, SND_RIC2, VOL_BASE, ATTN_NORM);
-                               else if(w_random < 0.2)
-                                       sound(self, CH_SHOTS, SND_RIC3, VOL_BASE, ATTN_NORM);
+                               sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTN_NORM);
                }
 
 #endif
index 548ede96606e08d786ca252624c4d0353e89e737..1365e61b992c62646e6d47489be593580a1e563c 100644 (file)
@@ -13,7 +13,7 @@ CLASS(MineLayer, Weapon)
 /* crosshair */ ATTRIB(MineLayer, w_crosshair_size, float, 0.9);
 /* wepimg    */ ATTRIB(MineLayer, model2, string, "weaponminelayer");
 /* refname   */ ATTRIB(MineLayer, netname, string, "minelayer");
-/* wepname   */ ATTRIB(MineLayer, message, string, _("Mine Layer"));
+/* wepname   */ ATTRIB(MineLayer, m_name, string, _("Mine Layer"));
 ENDCLASS(MineLayer)
 REGISTER_WEAPON(MINE_LAYER, NEW(MineLayer));
 
@@ -51,7 +51,7 @@ REGISTER_WEAPON(MINE_LAYER, NEW(MineLayer));
 
 #ifdef SVQC
 MINELAYER_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
-void W_MineLayer_Think(void);
+void W_MineLayer_Think();
 .float minelayer_detonate, mine_explodeanyway;
 .float mine_time;
 .vector mine_orientation;
@@ -59,7 +59,7 @@ void W_MineLayer_Think(void);
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_minelayer) { weapon_defaultspawnfunc(WEP_MINE_LAYER.m_id); }
+spawnfunc(weapon_minelayer) { weapon_defaultspawnfunc(this, WEP_MINE_LAYER); }
 
 void W_MineLayer_Stick(entity to)
 {SELFPARAM();
@@ -67,8 +67,7 @@ void W_MineLayer_Stick(entity to)
 
        // in order for mines to face properly when sticking to the ground, they must be a server side entity rather than a csqc projectile
 
-       entity newmine;
-       newmine = spawn();
+       entity newmine = spawn();
        newmine.classname = self.classname;
 
        newmine.bot_dodge = self.bot_dodge;
@@ -108,7 +107,7 @@ void W_MineLayer_Stick(entity to)
                SetMovetypeFollow(self, to);
 }
 
-void W_MineLayer_Explode(void)
+void W_MineLayer_Explode()
 {SELFPARAM();
        if(other.takedamage == DAMAGE_AIM)
                if(IS_PLAYER(other))
@@ -129,7 +128,8 @@ void W_MineLayer_Explode(void)
                if(!w.wr_checkammo1(w))
                {
                        self.cnt = WEP_MINE_LAYER.m_id;
-                       ATTACK_FINISHED(self) = time;
+                       int slot = 0; // TODO: unhardcode
+                       ATTACK_FINISHED(self, slot) = time;
                        self.switchweapon = w_getbestweapon(self);
                }
                setself(this);
@@ -138,7 +138,7 @@ void W_MineLayer_Explode(void)
        remove(self);
 }
 
-void W_MineLayer_DoRemoteExplode(void)
+void W_MineLayer_DoRemoteExplode()
 {SELFPARAM();
        self.event_damage = func_null;
        self.takedamage = DAMAGE_NO;
@@ -155,7 +155,8 @@ void W_MineLayer_DoRemoteExplode(void)
                if(!w.wr_checkammo1(w))
                {
                        self.cnt = WEP_MINE_LAYER.m_id;
-                       ATTACK_FINISHED(self) = time;
+                       int slot = 0; // TODO: unhardcode
+                       ATTACK_FINISHED(self, slot) = time;
                        self.switchweapon = w_getbestweapon(self);
                }
                setself(this);
@@ -164,7 +165,7 @@ void W_MineLayer_DoRemoteExplode(void)
        remove(self);
 }
 
-void W_MineLayer_RemoteExplode(void)
+void W_MineLayer_RemoteExplode()
 {SELFPARAM();
        if(self.realowner.deadflag == DEAD_NO)
                if((self.spawnshieldtime >= 0)
@@ -176,7 +177,7 @@ void W_MineLayer_RemoteExplode(void)
                }
 }
 
-void W_MineLayer_ProximityExplode(void)
+void W_MineLayer_ProximityExplode()
 {SELFPARAM();
        // make sure no friend is in the mine's radius. If there is any, explosion is delayed until he's at a safe distance
        if(WEP_CVAR(minelayer, protection) && self.mine_explodeanyway == 0)
@@ -205,7 +206,7 @@ int W_MineLayer_Count(entity e)
        return minecount;
 }
 
-void W_MineLayer_Think(void)
+void W_MineLayer_Think()
 {SELFPARAM();
        entity head;
 
@@ -268,7 +269,7 @@ void W_MineLayer_Think(void)
                W_MineLayer_RemoteExplode();
 }
 
-void W_MineLayer_Touch(void)
+void W_MineLayer_Touch()
 {SELFPARAM();
        if(self.movetype == MOVETYPE_NONE || self.movetype == MOVETYPE_FOLLOW)
                return; // we're already a stuck mine, why do we get called? TODO does this even happen?
@@ -499,7 +500,7 @@ float W_MineLayer_PlacedMines(float detonate)
                                if(self.BUTTON_ATCK2 == true) self.BUTTON_ATCK = false;
                        }
                }
-               METHOD(MineLayer, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(MineLayer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(autocvar_g_balance_minelayer_reload_ammo && actor.clip_load < WEP_CVAR(minelayer, ammo)) // forced reload
                        {
@@ -509,16 +510,16 @@ float W_MineLayer_PlacedMines(float detonate)
                                        w.wr_reload(w);
                                }
                        }
-                       else if(fire1)
+                       else if(fire & 1)
                        {
-                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(minelayer, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(minelayer, refire)))
                                {
                                        W_MineLayer_Attack(thiswep);
-                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(minelayer, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(minelayer, animtime), w_ready);
                                }
                        }
 
-                       if(fire2)
+                       if(fire & 2)
                        {
                                if(W_MineLayer_PlacedMines(true))
                                        sound(actor, CH_WEAPON_B, SND_MINE_DET, VOL_BASE, ATTN_NORM);
@@ -530,8 +531,9 @@ float W_MineLayer_PlacedMines(float detonate)
                }
                METHOD(MineLayer, wr_checkammo1, bool(entity thiswep))
                {
+                       int slot = 0; // TODO: unhardcode
                        // don't switch while placing a mine
-                       if(ATTACK_FINISHED(self) <= time || self.weapon != WEP_MINE_LAYER.m_id)
+                       if(ATTACK_FINISHED(self, slot) <= time || self.weapon != WEP_MINE_LAYER.m_id)
                        {
                                float ammo_amount = self.WEP_AMMO(MINE_LAYER) >= WEP_CVAR(minelayer, ammo);
                                ammo_amount += self.(weapon_load[WEP_MINE_LAYER.m_id]) >= WEP_CVAR(minelayer, ammo);
@@ -574,7 +576,7 @@ float W_MineLayer_PlacedMines(float detonate)
                {
                        vector org2;
                        org2 = w_org + w_backoff * 12;
-                       pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), org2, '0 0 0', 1);
+                       pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
                        if(!w_issilent)
                                sound(self, CH_SHOTS, SND_MINE_EXP, VOL_BASE, ATTN_NORM);
                }
index c1995745816ba1d7059743728ab81244d8f06309..36a3c0c9e66f9c5ee515ad17d057cf8bff2dc4d6 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Mortar, Weapon)
 /* crosshair */ ATTRIB(Mortar, w_crosshair_size, float, 0.7);
 /* wepimg    */ ATTRIB(Mortar, model2, string, "weapongrenadelauncher");
 /* refname   */ ATTRIB(Mortar, netname, string, "mortar");
-/* wepname   */ ATTRIB(Mortar, message, string, _("Mortar"));
+/* wepname   */ ATTRIB(Mortar, m_name, string, _("Mortar"));
 ENDCLASS(Mortar)
 REGISTER_WEAPON(MORTAR, NEW(Mortar));
 
@@ -58,10 +58,10 @@ MORTAR_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #ifdef IMPLEMENTATION
 #ifdef SVQC
 
-spawnfunc(weapon_mortar) { weapon_defaultspawnfunc(WEP_MORTAR.m_id); }
+spawnfunc(weapon_mortar) { weapon_defaultspawnfunc(this, WEP_MORTAR); }
 spawnfunc(weapon_grenadelauncher) { spawnfunc_weapon_mortar(this); }
 
-void W_Mortar_Grenade_Explode(void)
+void W_Mortar_Grenade_Explode()
 {SELFPARAM();
        if(other.takedamage == DAMAGE_AIM)
                if(IS_PLAYER(other))
@@ -81,7 +81,7 @@ void W_Mortar_Grenade_Explode(void)
        remove(self);
 }
 
-void W_Mortar_Grenade_Explode2(void)
+void W_Mortar_Grenade_Explode2()
 {SELFPARAM();
        if(other.takedamage == DAMAGE_AIM)
                if(IS_PLAYER(other))
@@ -116,7 +116,7 @@ void W_Mortar_Grenade_Damage(entity inflictor, entity attacker, float damage, in
                W_PrepareExplosionByDamage(attacker, self.use);
 }
 
-void W_Mortar_Grenade_Think1(void)
+void W_Mortar_Grenade_Think1()
 {SELFPARAM();
        self.nextthink = time;
        if(time > self.cnt)
@@ -130,7 +130,7 @@ void W_Mortar_Grenade_Think1(void)
                W_Mortar_Grenade_Explode();
 }
 
-void W_Mortar_Grenade_Touch1(void)
+void W_Mortar_Grenade_Touch1()
 {SELFPARAM();
        PROJECTILE_TOUCH;
        if(other.takedamage == DAMAGE_AIM || WEP_CVAR_PRI(mortar, type) == 0) // always explode when hitting a player, or if normal mortar projectile
@@ -162,7 +162,7 @@ void W_Mortar_Grenade_Touch1(void)
        }
 }
 
-void W_Mortar_Grenade_Touch2(void)
+void W_Mortar_Grenade_Touch2()
 {SELFPARAM();
        PROJECTILE_TOUCH;
        if(other.takedamage == DAMAGE_AIM || WEP_CVAR_SEC(mortar, type) == 0) // always explode when hitting a player, or if normal mortar projectile
@@ -209,9 +209,8 @@ void W_Mortar_Attack(Weapon thiswep)
 
        Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       gren = spawn();
+       gren = new(grenade);
        gren.owner = gren.realowner = self;
-       gren.classname = "grenade";
        gren.bot_dodge = true;
        gren.bot_dodgerating = WEP_CVAR_PRI(mortar, damage);
        gren.movetype = MOVETYPE_BOUNCE;
@@ -258,9 +257,8 @@ void W_Mortar_Attack2(Weapon thiswep)
 
        Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       gren = spawn();
+       gren = new(grenade);
        gren.owner = gren.realowner = self;
-       gren.classname = "grenade";
        gren.bot_dodge = true;
        gren.bot_dodgerating = WEP_CVAR_SEC(mortar, damage);
        gren.movetype = MOVETYPE_BOUNCE;
@@ -334,20 +332,20 @@ void W_Mortar_Attack2(Weapon thiswep)
                        wepinfo_sec_dps = (WEP_CVAR_SEC(mortar, damage) * (1 / max3(sys_frametime, WEP_CVAR_SEC(mortar, refire), WEP_CVAR_SEC(mortar, animtime))));
                        wepinfo_ter_dps = 0;
                        */
-               METHOD(Mortar, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Mortar, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(autocvar_g_balance_mortar_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(mortar, ammo), WEP_CVAR_SEC(mortar, ammo))) { // forced reload
                                Weapon w = get_weaponinfo(actor.weapon);
                                w.wr_reload(w);
-                       } else if(fire1)
+                       } else if(fire & 1)
                        {
-                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(mortar, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(mortar, refire)))
                                {
                                        W_Mortar_Attack(thiswep);
-                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(mortar, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(mortar, animtime), w_ready);
                                }
                        }
-                       else if(fire2)
+                       else if(fire & 2)
                        {
                                if(WEP_CVAR_SEC(mortar, remote_detonateprimary))
                                {
@@ -364,10 +362,10 @@ void W_Mortar_Attack2(Weapon thiswep)
                                        if(nadefound)
                                                sound(actor, CH_WEAPON_B, SND_ROCKET_DET, VOL_BASE, ATTN_NORM);
                                }
-                               else if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(mortar, refire)))
+                               else if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(mortar, refire)))
                                {
                                        W_Mortar_Attack2(thiswep);
-                                       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(mortar, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(mortar, animtime), w_ready);
                                }
                        }
                }
@@ -417,7 +415,7 @@ void W_Mortar_Attack2(Weapon thiswep)
                {
                        vector org2;
                        org2 = w_org + w_backoff * 12;
-                       pointparticles(particleeffectnum(EFFECT_GRENADE_EXPLODE), org2, '0 0 0', 1);
+                       pointparticles(EFFECT_GRENADE_EXPLODE, org2, '0 0 0', 1);
                        if(!w_issilent)
                                sound(self, CH_SHOTS, SND_GRENADE_IMPACT, VOL_BASE, ATTN_NORM);
                }
index 790ab53caff9d5fddabf450efb60d017d2bc9d43..b8c54c4165af491c655055e9c2a886a2c16a4b05 100644 (file)
@@ -13,7 +13,7 @@ CLASS(PortoLaunch, Weapon)
 /* crosshair */ ATTRIB(PortoLaunch, w_crosshair_size, float, 0.6);
 /* wepimg    */ ATTRIB(PortoLaunch, model2, string, "weaponporto");
 /* refname   */ ATTRIB(PortoLaunch, netname, string, "porto");
-/* wepname   */ ATTRIB(PortoLaunch, message, string, _("Port-O-Launch"));
+/* wepname   */ ATTRIB(PortoLaunch, m_name, string, _("Port-O-Launch"));
 ENDCLASS(PortoLaunch)
 REGISTER_WEAPON(PORTO, NEW(PortoLaunch));
 
@@ -44,7 +44,7 @@ PORTO_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #ifdef SVQC
 #include "../../triggers/trigger/jumppads.qh"
 
-spawnfunc(weapon_porto) { weapon_defaultspawnfunc(WEP_PORTO.m_id); }
+spawnfunc(weapon_porto) { weapon_defaultspawnfunc(this, WEP_PORTO); }
 
 REGISTER_MUTATOR(porto_ticker, true);
 MUTATOR_HOOKFUNCTION(porto_ticker, SV_StartFrame) {
@@ -53,7 +53,7 @@ MUTATOR_HOOKFUNCTION(porto_ticker, SV_StartFrame) {
                e.porto_forbidden = max(0, e.porto_forbidden - 1);
 }
 
-void W_Porto_Success(void)
+void W_Porto_Success()
 {SELFPARAM();
        if(self.realowner == world)
        {
@@ -109,7 +109,7 @@ void W_Porto_Remove(entity p)
        }
 }
 
-void W_Porto_Think(void)
+void W_Porto_Think()
 {SELFPARAM();
        trace_plane_normal = '0 0 0';
        if(self.realowner.playerid != self.playerid)
@@ -118,7 +118,7 @@ void W_Porto_Think(void)
                W_Porto_Fail(0);
 }
 
-void W_Porto_Touch(void)
+void W_Porto_Touch()
 {SELFPARAM();
        vector norm;
 
@@ -251,11 +251,10 @@ void W_Porto_Attack(float type)
 
        //Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       gren = spawn();
+       gren = new(porto);
        gren.cnt = type;
        gren.owner = gren.realowner = self;
        gren.playerid = self.playerid;
-       gren.classname = "porto";
        gren.bot_dodge = true;
        gren.bot_dodgerating = 200;
        gren.movetype = MOVETYPE_BOUNCEMISSILE;
@@ -306,33 +305,33 @@ void W_Porto_Attack(float type)
                {
                        PORTO_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
                }
-               METHOD(PortoLaunch, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(PortoLaunch, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(WEP_CVAR(porto, secondary))
                        {
-                               if(fire1)
+                               if(fire & 1)
                                if(!actor.porto_current)
                                if(!actor.porto_forbidden)
-                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(porto, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(porto, refire)))
                                {
                                        W_Porto_Attack(0);
-                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
                                }
 
-                               if(fire2)
+                               if(fire & 2)
                                if(!actor.porto_current)
                                if(!actor.porto_forbidden)
-                               if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(porto, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(porto, refire)))
                                {
                                        W_Porto_Attack(1);
-                                       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(porto, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(porto, animtime), w_ready);
                                }
                        }
                        else
                        {
                                if(actor.porto_v_angle_held)
                                {
-                                       if(!fire2)
+                                       if(!(fire & 2))
                                        {
                                                actor.porto_v_angle_held = 0;
 
@@ -341,7 +340,7 @@ void W_Porto_Attack(float type)
                                }
                                else
                                {
-                                       if(fire2)
+                                       if(fire & 2)
                                        {
                                                actor.porto_v_angle = actor.v_angle;
                                                actor.porto_v_angle_held = 1;
@@ -352,13 +351,13 @@ void W_Porto_Attack(float type)
                                if(actor.porto_v_angle_held)
                                        makevectors(actor.porto_v_angle); // override the previously set angles
 
-                               if(fire1)
+                               if(fire & 1)
                                if(!actor.porto_current)
                                if(!actor.porto_forbidden)
-                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(porto, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(porto, refire)))
                                {
                                        W_Porto_Attack(-1);
-                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
                                }
                        }
                }
index 49b3931566fd829e61e31a77253d5f5a8bfa2f25..e7cd2606c1c4a5abbeb8ab5589a53708dc274dbb 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Rifle, Weapon)
 /* crosshair */ ATTRIB(Rifle, w_crosshair_size, float, 0.6);
 /* wepimg    */ ATTRIB(Rifle, model2, string, "weaponrifle");
 /* refname   */ ATTRIB(Rifle, netname, string, "rifle");
-/* wepname   */ ATTRIB(Rifle, message, string, _("Rifle"));
+/* wepname   */ ATTRIB(Rifle, m_name, string, _("Rifle"));
 ENDCLASS(Rifle)
 REGISTER_WEAPON(RIFLE, NEW(Rifle));
 
@@ -49,7 +49,7 @@ RIFLE_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_rifle) { weapon_defaultspawnfunc(WEP_RIFLE.m_id); }
+spawnfunc(weapon_rifle) { weapon_defaultspawnfunc(this, WEP_RIFLE); }
 spawnfunc(weapon_campingrifle) { spawnfunc_weapon_rifle(this); }
 spawnfunc(weapon_sniperrifle) { spawnfunc_weapon_rifle(this); }
 
@@ -76,46 +76,44 @@ void W_Rifle_FireBullet(Weapon thiswep, float pSpread, float pDamage, float pFor
                SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self);
 }
 
-void W_Rifle_Attack(void)
+void W_Rifle_Attack()
 {
        W_Rifle_FireBullet(WEP_RIFLE, WEP_CVAR_PRI(rifle, spread), WEP_CVAR_PRI(rifle, damage), WEP_CVAR_PRI(rifle, force), WEP_CVAR_PRI(rifle, solidpenetration), WEP_CVAR_PRI(rifle, ammo), WEP_RIFLE.m_id, WEP_CVAR_PRI(rifle, tracer), WEP_CVAR_PRI(rifle, shots), SND(CAMPINGRIFLE_FIRE));
 }
 
-void W_Rifle_Attack2(void)
+void W_Rifle_Attack2()
 {
        W_Rifle_FireBullet(WEP_RIFLE, WEP_CVAR_SEC(rifle, spread), WEP_CVAR_SEC(rifle, damage), WEP_CVAR_SEC(rifle, force), WEP_CVAR_SEC(rifle, solidpenetration), WEP_CVAR_SEC(rifle, ammo), WEP_RIFLE.m_id | HITTYPE_SECONDARY, WEP_CVAR_SEC(rifle, tracer), WEP_CVAR_SEC(rifle, shots), SND(CAMPINGRIFLE_FIRE2));
 }
 
-.void(void) rifle_bullethail_attackfunc;
+.void() rifle_bullethail_attackfunc;
 .float rifle_bullethail_frame;
 .float rifle_bullethail_animtime;
 .float rifle_bullethail_refire;
-void W_Rifle_BulletHail_Continue(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Rifle_BulletHail_Continue(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        float r, sw, af;
 
        sw = actor.switchweapon; // make it not detect weapon changes as reason to abort firing
-       af = ATTACK_FINISHED(actor);
+       int slot = weaponslot(weaponentity);
+       af = ATTACK_FINISHED(actor, slot);
        actor.switchweapon = actor.weapon;
-       ATTACK_FINISHED(actor) = time;
-       LOG_INFO(ftos(actor.WEP_AMMO(RIFLE)), "\n");
-       r = weapon_prepareattack(thiswep, actor, actor.rifle_bullethail_frame == WFRAME_FIRE2, actor.rifle_bullethail_refire);
+       ATTACK_FINISHED(actor, slot) = time;
+       r = weapon_prepareattack(thiswep, actor, weaponentity, actor.rifle_bullethail_frame == WFRAME_FIRE2, actor.rifle_bullethail_refire);
        if(actor.switchweapon == actor.weapon)
                actor.switchweapon = sw;
        if(r)
        {
                actor.rifle_bullethail_attackfunc();
-               weapon_thinkf(actor, actor.rifle_bullethail_frame, actor.rifle_bullethail_animtime, W_Rifle_BulletHail_Continue);
-               LOG_INFO("thinkf set\n");
+               weapon_thinkf(actor, weaponentity, actor.rifle_bullethail_frame, actor.rifle_bullethail_animtime, W_Rifle_BulletHail_Continue);
        }
        else
        {
-               ATTACK_FINISHED(actor) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
-               LOG_INFO("out of ammo... ", ftos(actor.weaponentity.state), "\n");
+               ATTACK_FINISHED(actor, slot) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
        }
 }
 
-void W_Rifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animtime, float refire)
+void W_Rifle_BulletHail(.entity weaponentity, float mode, void() AttackFunc, float fr, float animtime, float refire)
 {SELFPARAM();
        // if we get here, we have at least one bullet to fire
        AttackFunc();
@@ -126,12 +124,12 @@ void W_Rifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animt
                self.rifle_bullethail_frame = fr;
                self.rifle_bullethail_animtime = animtime;
                self.rifle_bullethail_refire = refire;
-               weapon_thinkf(self, fr, animtime, W_Rifle_BulletHail_Continue);
+               weapon_thinkf(self, weaponentity, fr, animtime, W_Rifle_BulletHail_Continue);
        }
        else
        {
                // just one shot
-               weapon_thinkf(self, fr, animtime, w_ready);
+               weapon_thinkf(self, weaponentity, fr, animtime, w_ready);
        }
 }
 
@@ -160,7 +158,7 @@ void W_Rifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animt
                                }
                        }
                }
-               METHOD(Rifle, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Rifle, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(autocvar_g_balance_rifle_reload_ammo && actor.clip_load < min(WEP_CVAR_PRI(rifle, ammo), WEP_CVAR_SEC(rifle, ammo))) { // forced reload
                                Weapon w = get_weaponinfo(actor.weapon);
@@ -168,15 +166,15 @@ void W_Rifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animt
                        } else
                        {
                                actor.rifle_accumulator = bound(time - WEP_CVAR(rifle, bursttime), actor.rifle_accumulator, time);
-                               if(fire1)
-                               if(weapon_prepareattack_check(thiswep, actor, false, WEP_CVAR_PRI(rifle, refire)))
+                               if(fire & 1)
+                               if(weapon_prepareattack_check(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(rifle, refire)))
                                if(time >= actor.rifle_accumulator + WEP_CVAR_PRI(rifle, burstcost))
                                {
-                                       weapon_prepareattack_do(actor, false, WEP_CVAR_PRI(rifle, refire));
-                                       W_Rifle_BulletHail(WEP_CVAR_PRI(rifle, bullethail), W_Rifle_Attack, WFRAME_FIRE1, WEP_CVAR_PRI(rifle, animtime), WEP_CVAR_PRI(rifle, refire));
+                                       weapon_prepareattack_do(actor, weaponentity, false, WEP_CVAR_PRI(rifle, refire));
+                                       W_Rifle_BulletHail(weaponentity, WEP_CVAR_PRI(rifle, bullethail), W_Rifle_Attack, WFRAME_FIRE1, WEP_CVAR_PRI(rifle, animtime), WEP_CVAR_PRI(rifle, refire));
                                        actor.rifle_accumulator += WEP_CVAR_PRI(rifle, burstcost);
                                }
-                               if(fire2)
+                               if(fire & 2)
                                {
                                        if(WEP_CVAR(rifle, secondary))
                                        {
@@ -185,11 +183,11 @@ void W_Rifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animt
                                                        w.wr_reload(w);
                                                } else
                                                {
-                                                       if(weapon_prepareattack_check(thiswep, actor, true, WEP_CVAR_SEC(rifle, refire)))
+                                                       if(weapon_prepareattack_check(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(rifle, refire)))
                                                        if(time >= actor.rifle_accumulator + WEP_CVAR_SEC(rifle, burstcost))
                                                        {
-                                                               weapon_prepareattack_do(actor, true, WEP_CVAR_SEC(rifle, refire));
-                                                               W_Rifle_BulletHail(WEP_CVAR_SEC(rifle, bullethail), W_Rifle_Attack2, WFRAME_FIRE2, WEP_CVAR_SEC(rifle, animtime), WEP_CVAR_PRI(rifle, refire));
+                                                               weapon_prepareattack_do(actor, weaponentity, true, WEP_CVAR_SEC(rifle, refire));
+                                                               W_Rifle_BulletHail(weaponentity, WEP_CVAR_SEC(rifle, bullethail), W_Rifle_Attack2, WFRAME_FIRE2, WEP_CVAR_SEC(rifle, animtime), WEP_CVAR_PRI(rifle, refire));
                                                                actor.rifle_accumulator += WEP_CVAR_SEC(rifle, burstcost);
                                                        }
                                                }
@@ -254,15 +252,10 @@ void W_Rifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animt
                {
                        vector org2;
                        org2 = w_org + w_backoff * 2;
-                       pointparticles(particleeffectnum(EFFECT_RIFLE_IMPACT), org2, w_backoff * 1000, 1);
+                       pointparticles(EFFECT_RIFLE_IMPACT, org2, w_backoff * 1000, 1);
                        if(!w_issilent)
                        {
-                               if(w_random < 0.2)
-                                       sound(self, CH_SHOTS, SND_RIC1, VOL_BASE, ATTN_NORM);
-                               else if(w_random < 0.4)
-                                       sound(self, CH_SHOTS, SND_RIC2, VOL_BASE, ATTN_NORM);
-                               else if(w_random < 0.5)
-                                       sound(self, CH_SHOTS, SND_RIC3, VOL_BASE, ATTN_NORM);
+                               sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTN_NORM);
                        }
                }
                METHOD(Rifle, wr_init, void(entity thiswep))
diff --git a/qcsrc/common/weapons/weapon/rpc.qc b/qcsrc/common/weapons/weapon/rpc.qc
deleted file mode 100644 (file)
index 71ddaa6..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-#ifndef IMPLEMENTATION
-CLASS(RocketPropelledChainsaw, Weapon)
-/* ammotype  */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets)
-/* impulse   */ ATTRIB(RocketPropelledChainsaw, impulse, int, 7)
-/* flags     */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
-/* rating    */ ATTRIB(RocketPropelledChainsaw, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
-/* color     */ ATTRIB(RocketPropelledChainsaw, wpcolor, vector, '0.5 0.5 0');
-/* modelname */ ATTRIB(RocketPropelledChainsaw, mdl, string, "ok_rl");
-#ifndef MENUQC
-/* model     */ ATTRIB(RocketPropelledChainsaw, m_model, Model, MDL_RPC_ITEM);
-#endif
-/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair, string, "gfx/crosshairrocketlauncher");
-/* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair_size, float, 0.6);
-/* wepimg    */ ATTRIB(RocketPropelledChainsaw, model2, string, "weaponrpc");
-/* refname   */ ATTRIB(RocketPropelledChainsaw, netname, string, "rpc");
-/* wepname   */ ATTRIB(RocketPropelledChainsaw, message, string, _("Rocket Propelled Chainsaw"));
-ENDCLASS(RocketPropelledChainsaw)
-REGISTER_WEAPON(RPC, NEW(RocketPropelledChainsaw));
-
-#define RPC_SETTINGS(w_cvar,w_prop) RPC_SETTINGS_LIST(w_cvar, w_prop, RPC, rpc)
-#define RPC_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
-       w_cvar(id, sn, NONE, ammo) \
-       w_cvar(id, sn, NONE, animtime) \
-       w_cvar(id, sn, NONE, damage) \
-       w_cvar(id, sn, NONE, damage2) \
-       w_cvar(id, sn, NONE, damageforcescale) \
-       w_cvar(id, sn, NONE, edgedamage) \
-       w_cvar(id, sn, NONE, force) \
-       w_cvar(id, sn, NONE, health) \
-       w_cvar(id, sn, NONE, lifetime) \
-       w_cvar(id, sn, NONE, radius) \
-       w_cvar(id, sn, NONE, refire) \
-       w_cvar(id, sn, NONE, speed) \
-       w_cvar(id, sn, NONE, speedaccel) \
-       w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
-       w_prop(id, sn, float,  reloading_time, reload_time) \
-       w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
-       w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
-       w_prop(id, sn, string, weaponreplace, weaponreplace) \
-       w_prop(id, sn, float,  weaponstart, weaponstart) \
-       w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride) \
-       w_prop(id, sn, float,  weaponthrowable, weaponthrowable)
-
-#ifdef SVQC
-RPC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
-#endif
-#endif
-#ifdef IMPLEMENTATION
-#ifdef SVQC
-spawnfunc(weapon_rpc) { weapon_defaultspawnfunc(WEP_RPC.m_id); }
-
-void W_RocketPropelledChainsaw_Explode()
-{SELFPARAM();
-       self.event_damage = func_null;
-       self.takedamage = DAMAGE_NO;
-
-       RadiusDamage (self, self.realowner, WEP_CVAR(rpc, damage), WEP_CVAR(rpc, edgedamage), WEP_CVAR(rpc, radius), world, world, WEP_CVAR(rpc, force), self.projectiledeathtype, other);
-
-       remove (self);
-}
-
-void W_RocketPropelledChainsaw_Touch (void)
-{SELFPARAM();
-       if(WarpZone_Projectile_Touch())
-               if(wasfreed(self))
-                       return;
-
-       W_RocketPropelledChainsaw_Explode();
-}
-
-void W_RocketPropelledChainsaw_Damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
-       if (self.health <= 0)
-               return;
-
-       if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
-               return; // g_projectiles_damage says to halt
-
-       self.health = self.health - damage;
-
-       if (self.health <= 0)
-               W_PrepareExplosionByDamage(attacker, W_RocketPropelledChainsaw_Explode);
-}
-
-void W_RocketPropelledChainsaw_Think()
-{SELFPARAM();
-       if(self.cnt <= time)
-       {
-               remove(self);
-               return;
-       }
-
-       self.cnt = vlen(self.velocity);
-       self.wait = self.cnt * sys_frametime;
-       self.pos1 = normalize(self.velocity);
-
-       tracebox(self.origin, self.mins, self.maxs, self.origin + self.pos1 * (2 * self.wait), MOVE_NORMAL, self);
-       if(IS_PLAYER(trace_ent))
-               Damage (trace_ent, self, self.realowner, WEP_CVAR(rpc, damage2), self.projectiledeathtype, self.origin, normalize(self.origin - other.origin) * WEP_CVAR(rpc, force));
-
-       self.velocity = self.pos1 * (self.cnt + (WEP_CVAR(rpc, speedaccel) * sys_frametime));
-
-       UpdateCSQCProjectile(self);
-       self.nextthink = time;
-}
-
-void W_RocketPropelledChainsaw_Attack (Weapon thiswep)
-{SELFPARAM();
-       entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(self);
-       entity flash = spawn ();
-
-       W_DecreaseAmmo(thiswep, self, WEP_CVAR(rpc, ammo));
-       W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', false, 5, SND(ROCKET_FIRE), CH_WEAPON_A, WEP_CVAR(rpc, damage));
-       Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
-       PROJECTILE_MAKETRIGGER(missile);
-
-       missile.owner = missile.realowner = self;
-       missile.bot_dodge = true;
-       missile.bot_dodgerating = WEP_CVAR(rpc, damage) * 2;
-
-       missile.takedamage = DAMAGE_YES;
-       missile.damageforcescale = WEP_CVAR(rpc, damageforcescale);
-       missile.health = WEP_CVAR(rpc, health);
-       missile.event_damage = W_RocketPropelledChainsaw_Damage;
-       missile.damagedbycontents = true;
-       missile.movetype = MOVETYPE_FLY;
-
-       missile.projectiledeathtype = WEP_RPC.m_id;
-       setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
-
-       setorigin (missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
-       W_SetupProjVelocity_Basic(missile, WEP_CVAR(rpc, speed), 0);
-
-       missile.touch = W_RocketPropelledChainsaw_Touch;
-
-       missile.think = W_RocketPropelledChainsaw_Think;
-       missile.cnt = time + WEP_CVAR(rpc, lifetime);
-       missile.nextthink = time;
-       missile.flags = FL_PROJECTILE;
-
-       CSQCProjectile(missile, true, PROJECTILE_RPC, false);
-
-       setmodel(flash, MDL_RPC_MUZZLEFLASH); // precision set below
-       SUB_SetFade (flash, time, 0.1);
-       flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
-       W_AttachToShotorg(self, flash, '5 0 0');
-       missile.pos1 = missile.velocity;
-
-       MUTATOR_CALLHOOK(EditProjectile, self, missile);
-}
-
-               METHOD(RocketPropelledChainsaw, wr_aim, void(entity thiswep))
-               {
-                       self.BUTTON_ATCK = bot_aim(WEP_CVAR(rpc, speed), 0, WEP_CVAR(rpc, lifetime), false);
-               }
-               METHOD(RocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
-               {
-                       if(WEP_CVAR(rpc, reload_ammo) && actor.clip_load < WEP_CVAR(rpc, ammo)) {
-                               Weapon w = get_weaponinfo(actor.weapon);
-                               w.wr_reload(w);
-                       } else
-                       {
-                               if (fire1)
-                               {
-                                       if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(rpc, refire)))
-                                       {
-                                               W_RocketPropelledChainsaw_Attack(thiswep);
-                                               weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(rpc, animtime), w_ready);
-                                       }
-                               }
-
-                               if (fire2)
-                               {
-                                       // to-do
-                               }
-                       }
-               }
-               METHOD(RocketPropelledChainsaw, wr_init, void(entity thiswep))
-               {
-                       RPC_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
-               }
-               METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep))
-               {
-                       float ammo_amount = self.WEP_AMMO(RPC) >= WEP_CVAR(rpc, ammo);
-                       ammo_amount += self.(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo);
-                       return ammo_amount;
-               }
-               METHOD(RocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep))
-               {
-                       return false;
-               }
-               METHOD(RocketPropelledChainsaw, wr_config, void(entity thiswep))
-               {
-                       RPC_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
-               }
-               METHOD(RocketPropelledChainsaw, wr_reload, void(entity thiswep))
-               {
-                       W_Reload(self, WEP_CVAR(rpc, ammo), SND(RELOAD));
-               }
-               METHOD(RocketPropelledChainsaw, wr_suicidemessage, int(entity thiswep))
-               {
-                       if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
-                               return WEAPON_RPC_SUICIDE_SPLASH;
-                       else
-                               return WEAPON_RPC_SUICIDE_DIRECT;
-               }
-               METHOD(RocketPropelledChainsaw, wr_killmessage, int(entity thiswep))
-               {
-                       if(w_deathtype & HITTYPE_SECONDARY)
-                               return WEAPON_BLASTER_MURDER;
-                       else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
-                               return WEAPON_RPC_MURDER_SPLASH;
-                       else
-                               return WEAPON_RPC_MURDER_DIRECT;
-               }
-
-#endif
-
-#ifdef CSQC
-
-               METHOD(RocketPropelledChainsaw, wr_impacteffect, void(entity thiswep))
-               {
-                       vector org2;
-                       org2 = w_org + w_backoff * 12;
-                       pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), org2, '0 0 0', 1);
-                       if(!w_issilent)
-                               sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-               }
-
-#endif
-#endif
index 645bd9eb9b4475ec31156c64cf358614ec59cf13..faf20a4fb9a05095957e48a84a52545042d2b5b7 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Seeker, Weapon)
 /* crosshair */ ATTRIB(Seeker, w_crosshair_size, float, 0.8);
 /* wepimg    */ ATTRIB(Seeker, model2, string, "weaponseeker");
 /* refname   */ ATTRIB(Seeker, netname, string, "seeker");
-/* wepname   */ ATTRIB(Seeker, message, string, _("T.A.G. Seeker"));
+/* wepname   */ ATTRIB(Seeker, m_name, string, _("T.A.G. Seeker"));
 ENDCLASS(Seeker)
 REGISTER_WEAPON(SEEKER, NEW(Seeker));
 
@@ -86,12 +86,12 @@ SEEKER_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_seeker) { weapon_defaultspawnfunc(WEP_SEEKER.m_id); }
+spawnfunc(weapon_seeker) { weapon_defaultspawnfunc(this, WEP_SEEKER); }
 
 // ============================
 // Begin: Missile functions, these are general functions to be manipulated by other code
 // ============================
-void W_Seeker_Missile_Explode(void)
+void W_Seeker_Missile_Explode()
 {SELFPARAM();
        self.event_damage = func_null;
        RadiusDamage(self, self.realowner, WEP_CVAR(seeker, missile_damage), WEP_CVAR(seeker, missile_edgedamage), WEP_CVAR(seeker, missile_radius), world, world, WEP_CVAR(seeker, missile_force), self.projectiledeathtype, other);
@@ -99,14 +99,14 @@ void W_Seeker_Missile_Explode(void)
        remove(self);
 }
 
-void W_Seeker_Missile_Touch(void)
+void W_Seeker_Missile_Touch()
 {
        PROJECTILE_TOUCH;
 
        W_Seeker_Missile_Explode();
 }
 
-void W_Seeker_Missile_Think(void)
+void W_Seeker_Missile_Think()
 {SELFPARAM();
        entity e;
        vector desireddir, olddir, newdir, eorg;
@@ -221,7 +221,7 @@ void W_Seeker_Missile_Damage(entity inflictor, entity attacker, float damage, in
 }
 
 /*
-void W_Seeker_Missile_Animate(void)
+void W_Seeker_Missile_Animate()
 {
        self.frame = self.frame +1;
        self.nextthink = time + 0.05;
@@ -258,9 +258,8 @@ void W_Seeker_Fire_Missile(Weapon thiswep, vector f_diff, entity m_target)
 
        //self.detornator         = false;
 
-       missile                 = spawn();
+       missile                 = new(seeker_missile);
        missile.owner           = missile.realowner = self;
-       missile.classname       = "seeker_missile";
        missile.bot_dodge       = true;
        missile.bot_dodgerating = WEP_CVAR(seeker, missile_damage);
 
@@ -302,7 +301,7 @@ void W_Seeker_Fire_Missile(Weapon thiswep, vector f_diff, entity m_target)
 // ============================
 // Begin: FLAC, close range attack meant for defeating rockets which are coming at you.
 // ============================
-void W_Seeker_Flac_Explode(void)
+void W_Seeker_Flac_Explode()
 {SELFPARAM();
        self.event_damage = func_null;
 
@@ -311,7 +310,7 @@ void W_Seeker_Flac_Explode(void)
        remove(self);
 }
 
-void W_Seeker_Flac_Touch(void)
+void W_Seeker_Flac_Touch()
 {
        PROJECTILE_TOUCH;
 
@@ -348,9 +347,8 @@ void W_Seeker_Fire_Flac(Weapon thiswep)
 
        Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
-       missile                                 = spawn();
+       missile                                 = new(missile);
        missile.owner                   = missile.realowner = self;
-       missile.classname               = "missile";
        missile.bot_dodge               = true;
        missile.bot_dodgerating = WEP_CVAR(seeker, flac_damage);
        missile.touch                   = W_Seeker_Flac_Explode;
@@ -390,7 +388,7 @@ entity W_Seeker_Tagged_Info(entity isowner, entity istarget)
        return world;
 }
 
-void W_Seeker_Attack(void)
+void W_Seeker_Attack()
 {SELFPARAM();
        entity tracker, closest_target;
 
@@ -413,7 +411,7 @@ void W_Seeker_Attack(void)
        W_Seeker_Fire_Missile(WEP_SEEKER, '0 0 0', closest_target);
 }
 
-void W_Seeker_Vollycontroller_Think(void) // TODO: Merge this with W_Seeker_Attack
+void W_Seeker_Vollycontroller_Think() // TODO: Merge this with W_Seeker_Attack
 {SELFPARAM();
        float c;
        entity oldenemy;
@@ -454,7 +452,7 @@ void W_Seeker_Vollycontroller_Think(void) // TODO: Merge this with W_Seeker_Atta
        setself(this);
 }
 
-void W_Seeker_Tracker_Think(void)
+void W_Seeker_Tracker_Think()
 {SELFPARAM();
        // commit suicide if: You die OR target dies OR you switch away from the seeker OR commit suicide if lifetime is up
        if((self.realowner.deadflag != DEAD_NO) || (self.tag_target.deadflag != DEAD_NO) || (self.realowner.switchweapon != WEP_SEEKER.m_id)
@@ -475,7 +473,7 @@ void W_Seeker_Tracker_Think(void)
 // ============================
 // Begin: Tag projectile
 // ============================
-void W_Seeker_Tag_Explode(void)
+void W_Seeker_Tag_Explode()
 {SELFPARAM();
        //if(other==self.realowner)
        //    return;
@@ -493,7 +491,7 @@ void W_Seeker_Tag_Damage(entity inflictor, entity attacker, float damage, int de
                W_Seeker_Tag_Explode();
 }
 
-void W_Seeker_Tag_Touch(void)
+void W_Seeker_Tag_Touch()
 {SELFPARAM();
        vector dir;
        vector org2;
@@ -524,9 +522,8 @@ void W_Seeker_Tag_Touch(void)
                else
                {
                        //sprint(self.realowner, strcat("You just tagged ^2", other.netname, "^7 with a tracking device!\n"));
-                       e             = spawn();
+                       e             = new(tag_tracker);
                        e.cnt         = WEP_CVAR(seeker, missile_count);
-                       e.classname   = "tag_tracker";
                        e.owner       = self.owner;
                        e.realowner   = self.realowner;
 
@@ -563,9 +560,8 @@ void W_Seeker_Fire_Tag(Weapon thiswep)
 
        W_SetupShot_ProjectileSize(self, '-2 -2 -2', '2 2 2', false, 2, SND(TAG_FIRE), CH_WEAPON_A, WEP_CVAR(seeker, missile_damage) * WEP_CVAR(seeker, missile_count));
 
-       missile                 = spawn();
+       missile                 = new(seeker_tag);
        missile.owner           = missile.realowner = self;
-       missile.classname       = "seeker_tag";
        missile.bot_dodge       = true;
        missile.bot_dodgerating = 50;
        missile.touch           = W_Seeker_Tag_Touch;
@@ -608,47 +604,47 @@ void W_Seeker_Fire_Tag(Weapon thiswep)
                        else
                                self.BUTTON_ATCK = bot_aim(WEP_CVAR(seeker, tag_speed), 0, WEP_CVAR(seeker, tag_lifetime), false);
                }
-               METHOD(Seeker, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Seeker, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(autocvar_g_balance_seeker_reload_ammo && actor.clip_load < min(WEP_CVAR(seeker, missile_ammo), WEP_CVAR(seeker, tag_ammo))) { // forced reload
                                Weapon w = get_weaponinfo(actor.weapon);
                                w.wr_reload(w);
-                       } else if(fire1)
+                       } else if(fire & 1)
                        {
                                if(WEP_CVAR(seeker, type) == 1)
                                {
-                                       if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(seeker, missile_refire)))
+                                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, missile_refire)))
                                        {
                                                W_Seeker_Attack();
-                                               weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(seeker, missile_animtime), w_ready);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, missile_animtime), w_ready);
                                        }
                                }
                                else
                                {
-                                       if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(seeker, tag_refire)))
+                                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, tag_refire)))
                                        {
                                                W_Seeker_Fire_Tag(thiswep);
-                                               weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(seeker, tag_animtime), w_ready);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, tag_animtime), w_ready);
                                        }
                                }
                        }
 
-                       else if(fire2)
+                       else if(fire & 2)
                        {
                                if(WEP_CVAR(seeker, type) == 1)
                                {
-                                       if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(seeker, tag_refire)))
+                                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, tag_refire)))
                                        {
                                                W_Seeker_Fire_Tag(thiswep);
-                                               weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(seeker, tag_animtime), w_ready);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, tag_animtime), w_ready);
                                        }
                                }
                                else
                                {
-                                       if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(seeker, flac_refire)))
+                                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(seeker, flac_refire)))
                                        {
                                                W_Seeker_Fire_Flac(thiswep);
-                                               weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(seeker, flac_animtime), w_ready);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(seeker, flac_animtime), w_ready);
                                        }
                                }
                        }
@@ -723,7 +719,7 @@ void W_Seeker_Fire_Tag(Weapon thiswep)
                                }
                                else
                                {
-                                       pointparticles(particleeffectnum(EFFECT_HAGAR_EXPLODE), org2, '0 0 0', 1);
+                                       pointparticles(EFFECT_HAGAR_EXPLODE, org2, '0 0 0', 1);
                                        if(!w_issilent)
                                        {
                                                if(w_random<0.15)
@@ -737,7 +733,7 @@ void W_Seeker_Fire_Tag(Weapon thiswep)
                        }
                        else
                        {
-                               pointparticles(particleeffectnum(EFFECT_HAGAR_EXPLODE), org2, '0 0 0', 1);
+                               pointparticles(EFFECT_HAGAR_EXPLODE, org2, '0 0 0', 1);
                                if(!w_issilent)
                                {
                                        if(w_random<0.15)
index cc4daf0486732f99be82c67237c5eb1aba086496..b795cb7e9f393559e6d2d02a9226bafecebc4c18 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Shockwave, Weapon)
 /* crosshair */ ATTRIB(Shockwave, w_crosshair_size, float, 0.7);
 /* wepimg    */ ATTRIB(Shockwave, model2, string, "weaponshotgun");
 /* refname   */ ATTRIB(Shockwave, netname, string, "shockwave");
-/* wepname   */ ATTRIB(Shockwave, message, string, _("Shockwave"));
+/* wepname   */ ATTRIB(Shockwave, m_name, string, _("Shockwave"));
 ENDCLASS(Shockwave)
 REGISTER_WEAPON(SHOCKWAVE, NEW(Shockwave));
 
@@ -73,7 +73,7 @@ REGISTER_WEAPON(SHOCKWAVE, NEW(Shockwave));
 SHOCKWAVE_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #ifdef CSQC
-void Net_ReadShockwaveParticle(void);
+void Net_ReadShockwaveParticle();
 .vector sw_shotorg;
 .vector sw_shotdir;
 .float sw_distance;
@@ -83,6 +83,9 @@ void Net_ReadShockwaveParticle(void);
 #endif
 #endif
 #ifdef IMPLEMENTATION
+
+REGISTER_NET_TEMP(TE_CSQC_SHOCKWAVEPARTICLE)
+
 #ifdef SVQC
 spawnfunc(weapon_shockwave)
 {
@@ -90,10 +93,10 @@ spawnfunc(weapon_shockwave)
        if(autocvar_sv_q3acompat_machineshotgunswap)
        if(self.classname != "droppedweapon")
        {
-               weapon_defaultspawnfunc(WEP_MACHINEGUN.m_id);
+               weapon_defaultspawnfunc(this, WEP_MACHINEGUN);
                return;
        }
-       weapon_defaultspawnfunc(WEP_SHOCKWAVE.m_id);
+       weapon_defaultspawnfunc(this, WEP_SHOCKWAVE);
 }
 
 const float MAX_SHOCKWAVE_HITS = 10;
@@ -107,7 +110,7 @@ float shockwave_hit_damage[MAX_SHOCKWAVE_HITS];
 vector shockwave_hit_force[MAX_SHOCKWAVE_HITS];
 
 // MELEE ATTACK MODE
-void W_Shockwave_Melee_Think(void)
+void W_Shockwave_Melee_Think()
 {SELFPARAM();
        // declarations
        float i, f, swing, swing_factor, swing_damage, meleetime, is_player;
@@ -229,13 +232,13 @@ void W_Shockwave_Melee_Think(void)
        }
 }
 
-void W_Shockwave_Melee(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Shockwave_Melee(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        sound(actor, CH_WEAPON_A, SND_SHOTGUN_MELEE, VOL_BASE, ATTN_NORM);
-       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR(shockwave, melee_animtime), w_ready);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(shockwave, melee_animtime), w_ready);
 
-       entity meleetemp;
-       meleetemp = spawn();
+       entity meleetemp = new(meleetemp);
+       make_pure(meleetemp);
        meleetemp.owner = meleetemp.realowner = actor;
        meleetemp.think = W_Shockwave_Melee_Think;
        meleetemp.nextthink = time + WEP_CVAR(shockwave, melee_delay) * W_WeaponRateFactor();
@@ -335,10 +338,9 @@ float W_Shockwave_Attack_CheckHit(
        return true;
 }
 
-void W_Shockwave_Send(void)
+void W_Shockwave_Send()
 {SELFPARAM();
-       WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-       WriteByte(MSG_BROADCAST, TE_CSQC_SHOCKWAVEPARTICLE);
+       WriteHeader(MSG_BROADCAST, TE_CSQC_SHOCKWAVEPARTICLE);
        WriteCoord(MSG_BROADCAST, w_shotorg.x);
        WriteCoord(MSG_BROADCAST, w_shotorg.y);
        WriteCoord(MSG_BROADCAST, w_shotorg.z);
@@ -351,7 +353,7 @@ void W_Shockwave_Send(void)
        WriteByte(MSG_BROADCAST, num_for_edict(self));
 }
 
-void W_Shockwave_Attack(void)
+void W_Shockwave_Attack()
 {SELFPARAM();
        // declarations
        float multiplier, multiplier_from_accuracy, multiplier_from_distance;
@@ -675,28 +677,28 @@ void W_Shockwave_Attack(void)
                        else
                                { self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, false); }
                }
-               METHOD(Shockwave, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Shockwave, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
-                       if(fire1)
+                       if(fire & 1)
                        {
                                if(time >= actor.shockwave_blasttime) // handle refire separately so the secondary can be fired straight after a primary
                                {
-                                       if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(shockwave, blast_animtime)))
+                                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(shockwave, blast_animtime)))
                                        {
                                                W_Shockwave_Attack();
                                                actor.shockwave_blasttime = time + WEP_CVAR(shockwave, blast_refire) * W_WeaponRateFactor();
-                                               weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(shockwave, blast_animtime), w_ready);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(shockwave, blast_animtime), w_ready);
                                        }
                                }
                        }
-                       else if(fire2)
+                       else if(fire & 2)
                        {
                                //if(actor.clip_load >= 0) // we are not currently reloading
                                if(!actor.crouch) // no crouchmelee please
-                               if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR(shockwave, melee_refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR(shockwave, melee_refire)))
                                {
                                        // attempt forcing playback of the anim by switching to another anim (that we never play) here...
-                                       weapon_thinkf(actor, WFRAME_FIRE1, 0, W_Shockwave_Melee);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, W_Shockwave_Melee);
                                }
                        }
                }
@@ -833,7 +835,13 @@ void Draw_Shockwave(entity this)
        }
 }
 
-void Net_ReadShockwaveParticle(void)
+NET_HANDLE(TE_CSQC_SHOCKWAVEPARTICLE, bool isNew)
+{
+       Net_ReadShockwaveParticle();
+       return true;
+}
+
+void Net_ReadShockwaveParticle()
 {
        entity shockwave;
        shockwave = spawn();
@@ -856,7 +864,7 @@ void Net_ReadShockwaveParticle(void)
                        // handled by Net_ReadShockwaveParticle
                        //vector org2;
                        //org2 = w_org + w_backoff * 2;
-                       //pointparticles(particleeffectnum(EFFECT_BLASTER_IMPACT), org2, w_backoff * 1000, 1);
+                       //pointparticles(EFFECT_BLASTER_IMPACT, org2, w_backoff * 1000, 1);
                }
 
 #endif
index a5cb397737267127c620db7a4e7269fb31a7f7d1..e7ad8b042027e6df03f0567e283d421a32ea6838 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Shotgun, Weapon)
 /* crosshair */ ATTRIB(Shotgun, w_crosshair_size, float, 0.65);
 /* wepimg    */ ATTRIB(Shotgun, model2, string, "weaponshotgun");
 /* refname   */ ATTRIB(Shotgun, netname, string, "shotgun");
-/* wepname   */ ATTRIB(Shotgun, message, string, _("Shotgun"));
+/* wepname   */ ATTRIB(Shotgun, m_name, string, _("Shotgun"));
 ENDCLASS(Shotgun)
 REGISTER_WEAPON(SHOTGUN, NEW(Shotgun));
 
@@ -54,7 +54,7 @@ SHOTGUN_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_shotgun) { weapon_defaultspawnfunc(WEP_SHOTGUN.m_id); }
+spawnfunc(weapon_shotgun) { weapon_defaultspawnfunc(this, WEP_SHOTGUN); }
 
 void W_Shotgun_Attack(Weapon thiswep, float isprimary)
 {SELFPARAM();
@@ -85,7 +85,7 @@ void W_Shotgun_Attack(Weapon thiswep, float isprimary)
 
 .float swing_prev;
 .entity swing_alreadyhit;
-void W_Shotgun_Melee_Think(void)
+void W_Shotgun_Melee_Think()
 {SELFPARAM();
        // declarations
        float i, f, swing, swing_factor, swing_damage, meleetime, is_player;
@@ -181,13 +181,13 @@ void W_Shotgun_Melee_Think(void)
        }
 }
 
-void W_Shotgun_Attack2(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Shotgun_Attack2(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        sound(actor, CH_WEAPON_A, SND_SHOTGUN_MELEE, VOL_BASE, ATTEN_NORM);
-       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(shotgun, animtime), w_ready);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(shotgun, animtime), w_ready);
 
-       entity meleetemp;
-       meleetemp = spawn();
+       entity meleetemp = new(meleetemp);
+       make_pure(meleetemp);
        meleetemp.realowner = actor;
        meleetemp.think = W_Shotgun_Melee_Think;
        meleetemp.nextthink = time + WEP_CVAR_SEC(shotgun, melee_delay) * W_WeaponRateFactor();
@@ -195,34 +195,34 @@ void W_Shotgun_Attack2(Weapon thiswep, entity actor, bool fire1, bool fire2)
 }
 
 // alternate secondary weapon frames
-void W_Shotgun_Attack3_Frame2(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Shotgun_Attack3_Frame2(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        Weapon w = get_weaponinfo(actor.weapon);
        if (!w.wr_checkammo2(w))
        if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
        {
                W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
-               w_ready(thiswep, actor, fire1, fire2);
+               w_ready(thiswep, actor, weaponentity, fire);
                return;
        }
 
        sound(actor, CH_WEAPON_SINGLE, SND_Null, VOL_BASE, ATTN_NORM); // kill previous sound
        W_Shotgun_Attack(WEP_SHOTGUN, true); // actually is secondary, but we trick the last shot into playing full reload sound
-       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), w_ready);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), w_ready);
 }
-void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        Weapon w = get_weaponinfo(actor.weapon);
        if (!w.wr_checkammo2(w))
        if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
        {
                W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
-               w_ready(thiswep, actor, fire1, fire2);
+               w_ready(thiswep, actor, weaponentity, fire);
                return;
        }
 
        W_Shotgun_Attack(WEP_SHOTGUN, false);
-       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame2);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame2);
 }
 
 .float shotgun_primarytime;
@@ -234,7 +234,7 @@ void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, bool fire1, bool fir
                        else
                                self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, false);
                }
-               METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(WEP_CVAR(shotgun, reload_ammo) && actor.clip_load < WEP_CVAR_PRI(shotgun, ammo)) // forced reload
                        {
@@ -246,27 +246,27 @@ void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, bool fire1, bool fir
                        }
                        else
                        {
-                               if(fire1)
+                               if(fire & 1)
                                {
                                        if(time >= actor.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary
                                        {
-                                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(shotgun, animtime)))
+                                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(shotgun, animtime)))
                                                {
                                                        W_Shotgun_Attack(thiswep, true);
                                                        actor.shotgun_primarytime = time + WEP_CVAR_PRI(shotgun, refire) * W_WeaponRateFactor();
-                                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(shotgun, animtime), w_ready);
+                                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(shotgun, animtime), w_ready);
                                                }
                                        }
                                }
-                               else if(fire2 && WEP_CVAR(shotgun, secondary) == 2)
+                               else if((fire & 2) && WEP_CVAR(shotgun, secondary) == 2)
                                {
                                        if(time >= actor.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary
                                        {
-                                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_SEC(shotgun, alt_animtime)))
+                                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(shotgun, alt_animtime)))
                                                {
                                                        W_Shotgun_Attack(thiswep, false);
                                                        actor.shotgun_primarytime = time + WEP_CVAR_SEC(shotgun, alt_refire) * W_WeaponRateFactor();
-                                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame1);
+                                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame1);
                                                }
                                        }
                                }
@@ -274,11 +274,11 @@ void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, bool fire1, bool fir
                        if(actor.clip_load >= 0) // we are not currently reloading
                        if(!actor.crouch) // no crouchmelee please
                        if(WEP_CVAR(shotgun, secondary) == 1)
-                       if((fire1 && actor.WEP_AMMO(SHOTGUN) <= 0 && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || fire2)
-                       if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR_SEC(shotgun, refire)))
+                       if(((fire & 1) && actor.WEP_AMMO(SHOTGUN) <= 0 && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (fire & 2))
+                       if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(shotgun, refire)))
                        {
                                // attempt forcing playback of the anim by switching to another anim (that we never play) here...
-                               weapon_thinkf(actor, WFRAME_FIRE1, 0, W_Shotgun_Attack2);
+                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, W_Shotgun_Attack2);
                        }
                }
                METHOD(Shotgun, wr_init, void(entity thiswep))
@@ -339,15 +339,11 @@ void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, bool fire1, bool fir
                METHOD(Shotgun, wr_impacteffect, void(entity thiswep))
                {
                        vector org2 = w_org + w_backoff * 2;
-                       pointparticles(particleeffectnum(EFFECT_SHOTGUN_IMPACT), org2, w_backoff * 1000, 1);
+                       pointparticles(EFFECT_SHOTGUN_IMPACT, org2, w_backoff * 1000, 1);
                        if(!w_issilent && time - self.prevric > 0.25)
                        {
-                               if(w_random < 0.0165)
-                                       sound(self, CH_SHOTS, SND_RIC1, VOL_BASE, ATTEN_NORM);
-                               else if(w_random < 0.033)
-                                       sound(self, CH_SHOTS, SND_RIC2, VOL_BASE, ATTEN_NORM);
-                               else if(w_random < 0.05)
-                                       sound(self, CH_SHOTS, SND_RIC3, VOL_BASE, ATTEN_NORM);
+                               if(w_random < 0.05)
+                                       sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
                                self.prevric = time;
                        }
                }
index 66ea8f7b5165151bdb4040bb01883068dd452bf1..308d43fc122f5d9e7ddc82a12f69f31b06ae7057 100644 (file)
@@ -14,7 +14,7 @@ CLASS(Tuba, Weapon)
 /* wepimg    */ ATTRIB(Tuba, model2, string, "weapontuba");
 /* refname   */ ATTRIB(Tuba, netname, string, "tuba");
 /* xgettext:no-c-format */
-/* wepname   */ ATTRIB(Tuba, message, string, _("@!#%'n Tuba"));
+/* wepname   */ ATTRIB(Tuba, m_name, string, _("@!#%'n Tuba"));
 ENDCLASS(Tuba)
 REGISTER_WEAPON(TUBA, NEW(Tuba));
 
@@ -56,7 +56,7 @@ float W_Tuba_MarkClientOnlyFieldsAsUsed() {
 #endif
 #ifdef IMPLEMENTATION
 #ifdef SVQC
-spawnfunc(weapon_tuba) { weapon_defaultspawnfunc(WEP_TUBA.m_id); }
+spawnfunc(weapon_tuba) { weapon_defaultspawnfunc(this, WEP_TUBA); }
 
 bool W_Tuba_HasPlayed(entity pl, string melody, int instrument, bool ignorepitch, float mintempo, float maxtempo)
 {
@@ -149,7 +149,7 @@ bool W_Tuba_HasPlayed(entity pl, string melody, int instrument, bool ignorepitch
        return true;
 }
 
-void W_Tuba_NoteOff(void)
+void W_Tuba_NoteOff()
 {SELFPARAM();
        // we have a note:
        //   on: self.spawnshieldtime
@@ -261,7 +261,7 @@ bool W_Tuba_NoteSendEntity(entity this, entity to, int sf)
        if(!sound_allowed(MSG_ONE, self.realowner))
                return false;
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_TUBANOTE);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TUBANOTE);
        WriteByte(MSG_ENTITY, sf);
        if(sf & 1)
        {
@@ -281,7 +281,7 @@ bool W_Tuba_NoteSendEntity(entity this, entity to, int sf)
        return true;
 }
 
-void W_Tuba_NoteThink(void)
+void W_Tuba_NoteThink()
 {SELFPARAM();
        float dist_mult;
        float vol0, vol1;
@@ -379,25 +379,25 @@ void W_Tuba_NoteOn(float hittype)
                                        self.BUTTON_ATCK2 = 1;
                        }
                }
-               METHOD(Tuba, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Tuba, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
-                       if(fire1)
-                       if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR(tuba, refire)))
+                       if(fire & 1)
+                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(tuba, refire)))
                        {
                                W_Tuba_NoteOn(0);
                                //weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_tuba_animtime, w_ready);
-                               weapon_thinkf(actor, WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready);
+                               weapon_thinkf(actor, weaponentity, WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready);
                        }
-                       if(fire2)
-                       if(weapon_prepareattack(thiswep, actor, true, WEP_CVAR(tuba, refire)))
+                       if(fire & 2)
+                       if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR(tuba, refire)))
                        {
                                W_Tuba_NoteOn(HITTYPE_SECONDARY);
                                //weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_balance_tuba_animtime, w_ready);
-                               weapon_thinkf(actor, WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready);
+                               weapon_thinkf(actor, weaponentity, WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready);
                        }
                        if(actor.tuba_note)
                        {
-                               if(!fire1 && !fire2)
+                               if(!(fire & 1) && !(fire & 2))
                                {
                                        WITH(entity, self, actor.tuba_note, W_Tuba_NoteOff());
                                }
@@ -414,8 +414,9 @@ void W_Tuba_NoteOn(float hittype)
                }
                METHOD(Tuba, wr_reload, void(entity thiswep))
                {
+                       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
                        // switch to alternate instruments :)
-                       if(self.weaponentity.state == WS_READY)
+                       if(self.(weaponentity).state == WS_READY)
                        {
                                switch(self.tuba_instrument)
                                {
@@ -434,8 +435,8 @@ void W_Tuba_NoteOn(float hittype)
                                }
                                W_SetupShot(self, false, 0, "", 0, 0);
                                Send_Effect(EFFECT_TELEPORT, w_shotorg, '0 0 0', 1);
-                               self.weaponentity.state = WS_INUSE;
-                               weapon_thinkf(self, WFRAME_RELOAD, 0.5, w_ready);
+                               self.(weaponentity).state = WS_INUSE;
+                               weapon_thinkf(self, weaponentity, WFRAME_RELOAD, 0.5, w_ready);
                        }
                }
                METHOD(Tuba, wr_checkammo1, bool(entity thiswep))
index f7aceee20f3f531f0519610d3a1de5e511ad2b17..dc449d35d0ae8d58a11f4f07d2d28e40eb2c0f70 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Vaporizer, Weapon)
 /* crosshair */ ATTRIB(Vaporizer, w_crosshair_size, float, 0.6);
 /* wepimg    */ ATTRIB(Vaporizer, model2, string, "weaponminstanex");
 /* refname   */ ATTRIB(Vaporizer, netname, string, "vaporizer");
-/* wepname   */ ATTRIB(Vaporizer, message, string, _("Vaporizer"));
+/* wepname   */ ATTRIB(Vaporizer, m_name, string, _("Vaporizer"));
 ENDCLASS(Vaporizer)
 REGISTER_WEAPON(VAPORIZER, NEW(Vaporizer));
 
@@ -56,8 +56,101 @@ VAPORIZER_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #endif
 #ifdef IMPLEMENTATION
+
+REGISTER_NET_TEMP(TE_CSQC_VAPORBEAMPARTICLE)
+
+#if defined(SVQC)
+void SendCSQCVaporizerBeamParticle(entity player, int hit) {
+       vector v;
+       v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
+       WriteHeader(MSG_BROADCAST, TE_CSQC_VAPORBEAMPARTICLE);
+       WriteCoord(MSG_BROADCAST, w_shotorg.x);
+       WriteCoord(MSG_BROADCAST, w_shotorg.y);
+       WriteCoord(MSG_BROADCAST, w_shotorg.z);
+       WriteCoord(MSG_BROADCAST, v.x);
+       WriteCoord(MSG_BROADCAST, v.y);
+       WriteCoord(MSG_BROADCAST, v.z);
+       WriteByte(MSG_BROADCAST, hit);
+       WriteShort(MSG_BROADCAST, num_for_edict(player));
+       WriteByte(MSG_BROADCAST, player.team);
+}
+#elif defined(CSQC)
+bool autocvar_cl_vaporizerbeam_particle = false;
+float autocvar_cl_vaporizerbeam_lifetime = 0.8;
+float autocvar_cl_vaporizerbeam_colorboost = 0.7;
+
+string Draw_VaporizerBeam_trace_callback_tex;
+float Draw_VaporizerBeam_trace_callback_rnd;
+vector Draw_VaporizerBeam_trace_callback_rgb;
+float Draw_VaporizerBeam_trace_callback_a;
+void Draw_VaporizerBeam_trace_callback(vector start, vector hit, vector end)
+{
+       float i;
+       vector vorg;
+       vorg = WarpZone_TransformOrigin(WarpZone_trace_transform, view_origin);
+       for(i = 0; i < Draw_VaporizerBeam_trace_callback_a; ++i)
+               Draw_CylindricLine(hit, start, 8, Draw_VaporizerBeam_trace_callback_tex, 0.25, Draw_VaporizerBeam_trace_callback_rnd, Draw_VaporizerBeam_trace_callback_rgb, min(1, Draw_VaporizerBeam_trace_callback_a - i), DRAWFLAG_NORMAL, vorg);
+       Draw_VaporizerBeam_trace_callback_rnd += 0.25 * vlen(hit - start) / 8;
+}
+
+.vector vorg1, vorg2;
+.float spawn_time;
+void VaporizerBeam_Draw(entity this)
+{
+       //draw either the old v2.3 beam or the new beam
+       particles_alphamin = particles_alphamax = particles_fade = 1;
+
+       string tex = "particles/lgbeam";
+       if(this.cnt)
+               tex = "particles/gauntletbeam";
+       vector rgb = getcsqcplayercolor(this.sv_entnum);
+       rgb *= (1 + autocvar_cl_vaporizerbeam_colorboost);
+
+       float fail = (self.nextthink - time);
+
+       Draw_VaporizerBeam_trace_callback_tex = tex;
+       Draw_VaporizerBeam_trace_callback_rnd = 0;
+       Draw_VaporizerBeam_trace_callback_rgb = rgb;
+       Draw_VaporizerBeam_trace_callback_a = bound(0, fail, 1);
+       WarpZone_TraceBox_ThroughZone(this.vorg1, '0 0 0', '0 0 0', this.vorg2, MOVE_NOTHING, world, world, Draw_VaporizerBeam_trace_callback);
+       Draw_VaporizerBeam_trace_callback_tex = string_null;
+
+       /*if(!MUTATOR_CALLHOOK(Particles_VaporizerBeam, this.vorg1, this.vorg2))
+       if(autocvar_cl_particles_oldvortexbeam && (getstati(STAT_ALLOW_OLDVORTEXBEAM) || isdemo()))
+               WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM_OLD), this.vorg1, this.vorg2, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
+       else
+               WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM), this.vorg1, this.vorg2, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);*/
+}
+
+NET_HANDLE(TE_CSQC_VAPORBEAMPARTICLE, bool isNew)
+{
+       Net_Accept(vortex_beam);
+       this.think = SUB_Remove;
+       this.nextthink = time + bound(0, autocvar_cl_vaporizerbeam_lifetime, 10);
+       this.draw = VaporizerBeam_Draw;
+       this.drawmask = MASK_NORMAL;
+
+       this.vorg1_x = ReadCoord(); this.vorg1_y = ReadCoord(); this.vorg1_z = ReadCoord();
+       this.vorg2_x = ReadCoord(); this.vorg2_y = ReadCoord(); this.vorg2_z = ReadCoord();
+       this.cnt = ReadByte();
+       this.sv_entnum = ReadShort();
+       this.team = ReadByte() - 1;
+
+       if(autocvar_cl_vaporizerbeam_particle)
+       {
+               WarpZone_TrailParticles(world, particleeffectnum(((this.cnt) ? EFFECT_VAPORIZER_HIT(this.team) : EFFECT_VAPORIZER(this.team))), this.vorg1, this.vorg2);
+               this.draw = func_null;
+               this.drawmask = MASK_NORMAL;
+               remove(this);
+       }
+
+       pointparticles(EFFECT_VORTEX_MUZZLEFLASH, this.vorg1, normalize(this.vorg2 - this.vorg1) * 1000, 1);
+       return true;
+}
+#endif
+
 #ifdef SVQC
-spawnfunc(weapon_vaporizer) { weapon_defaultspawnfunc(WEP_VAPORIZER.m_id); }
+spawnfunc(weapon_vaporizer) { weapon_defaultspawnfunc(this, WEP_VAPORIZER); }
 spawnfunc(weapon_minstanex) { spawnfunc_weapon_vaporizer(this); }
 
 void W_RocketMinsta_Explosion(vector loc)
@@ -85,6 +178,9 @@ void W_Vaporizer_Attack(Weapon thiswep)
        damage_goodhits = 0;
        FireRailgunBullet(w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, vaporizer_damage, 800, 0, 0, 0, 0, WEP_VAPORIZER.m_id);
 
+       // do this now, as goodhits is disabled below
+       SendCSQCVaporizerBeamParticle(self, damage_goodhits);
+
        if(yoda && flying)
                Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
        if(damage_goodhits && self.vaporizer_lasthit)
@@ -95,12 +191,6 @@ void W_Vaporizer_Attack(Weapon thiswep)
 
        self.vaporizer_lasthit = damage_goodhits;
 
-       Send_Effect(EFFECT_VORTEX_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
-
-       // teamcolor / hit beam effect
-       vector v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
-       Send_Effect((damage_goodhits ? EFFECT_VAPORIZER_HIT(self.team) : EFFECT_VAPORIZER(self.team)), w_shotorg, v, 1);
-
        if(autocvar_g_rm)
        if(!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
                W_RocketMinsta_Explosion(trace_endpos);
@@ -108,7 +198,7 @@ void W_Vaporizer_Attack(Weapon thiswep)
        W_DecreaseAmmo(thiswep, self, ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo)));
 }
 
-void W_RocketMinsta_Laser_Explode (void)
+void W_RocketMinsta_Laser_Explode ()
 {SELFPARAM();
        if(other.takedamage == DAMAGE_AIM)
                if(IS_PLAYER(other))
@@ -123,7 +213,7 @@ void W_RocketMinsta_Laser_Explode (void)
        remove(self);
 }
 
-void W_RocketMinsta_Laser_Touch (void)
+void W_RocketMinsta_Laser_Touch ()
 {SELFPARAM();
        PROJECTILE_TOUCH;
        //W_RocketMinsta_Laser_Explode ();
@@ -131,7 +221,7 @@ void W_RocketMinsta_Laser_Touch (void)
        remove(self);
 }
 
-void W_RocketMinsta_Attack2(void)
+void W_RocketMinsta_Attack2()
 {SELFPARAM();
        makevectors(self.v_angle);
 
@@ -150,8 +240,7 @@ void W_RocketMinsta_Attack2(void)
 
     while(counter < total)
        {
-        proj = spawn ();
-        proj.classname = "plasma_prim";
+        proj = new(plasma_prim);
         proj.owner = proj.realowner = self;
         proj.bot_dodge = true;
         proj.bot_dodgerating = autocvar_g_rm_laser_damage;
@@ -186,7 +275,7 @@ void W_RocketMinsta_Attack2(void)
     }
 }
 
-void W_RocketMinsta_Attack3 (void)
+void W_RocketMinsta_Attack3 ()
 {SELFPARAM();
        makevectors(self.v_angle);
 
@@ -203,8 +292,7 @@ void W_RocketMinsta_Attack3 (void)
 
     while(counter < total)
        {
-        proj = spawn ();
-        proj.classname = "plasma_prim";
+        proj = new(plasma_prim);
         proj.owner = proj.realowner = self;
         proj.bot_dodge = true;
         proj.bot_dodgerating = autocvar_g_rm_laser_damage;
@@ -244,7 +332,7 @@ void W_RocketMinsta_Attack3 (void)
                        else
                                self.BUTTON_ATCK2 = bot_aim(WEP_CVAR_SEC(vaporizer, speed), 0, WEP_CVAR_SEC(vaporizer, lifetime), false); // WEAPONTODO: replace with proper vaporizer cvars
                }
-               METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        float vaporizer_ammo = ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo));
                        // if the laser uses load, we also consider its ammo for reloading
@@ -255,15 +343,15 @@ void W_RocketMinsta_Attack3 (void)
                                Weapon w = get_weaponinfo(actor.weapon);
                                w.wr_reload(w);
                        }
-                       if(fire1 && (actor.ammo_cells || !autocvar_g_rm) && !forbidWeaponUse(actor))
+                       if((fire & 1) && (actor.ammo_cells || !autocvar_g_rm) && !forbidWeaponUse(actor))
                        {
-                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(vaporizer, refire)))
+                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(vaporizer, refire)))
                                {
                                        W_Vaporizer_Attack(thiswep);
-                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(vaporizer, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(vaporizer, animtime), w_ready);
                                }
                        }
-                       if(fire2 || (fire1 && !actor.ammo_cells && autocvar_g_rm))
+                       if((fire & 2) || ((fire & 1) && !actor.ammo_cells && autocvar_g_rm))
                        {
                                if((autocvar_g_rm && autocvar_g_rm_laser) || autocvar_g_rm_laser == 2)
                                {
@@ -314,7 +402,7 @@ void W_RocketMinsta_Attack3 (void)
                                        actor.weapon = oldwep;
 
                                        // now do normal refire
-                                       weapon_thinkf(actor, WFRAME_FIRE2, WEP_CVAR_SEC(vaporizer, animtime), w_ready);
+                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(vaporizer, animtime), w_ready);
                                }
                        }
                        else
@@ -381,12 +469,12 @@ void W_RocketMinsta_Attack3 (void)
                        vector org2 = w_org + w_backoff * 6;
                        if(w_deathtype & HITTYPE_SECONDARY)
                        {
-                               pointparticles(particleeffectnum(EFFECT_BLASTER_IMPACT), org2, w_backoff * 1000, 1);
+                               pointparticles(EFFECT_BLASTER_IMPACT, org2, w_backoff * 1000, 1);
                                if(!w_issilent) { sound(self, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTN_NORM); }
                        }
                        else
                        {
-                               pointparticles(particleeffectnum(EFFECT_VORTEX_IMPACT), org2, '0 0 0', 1);
+                               pointparticles(EFFECT_VORTEX_IMPACT, org2, '0 0 0', 1);
                                if(!w_issilent) { sound(self, CH_SHOTS, SND_NEXIMPACT, VOL_BASE, ATTN_NORM); }
                        }
                }
index 5aca18183e9edfb949e697bf327ffaf537714dfa..8a90679b81a2690428328e79dd4598ccf40ce183 100644 (file)
@@ -13,7 +13,7 @@ CLASS(Vortex, Weapon)
 /* crosshair */ ATTRIB(Vortex, w_crosshair_size, float, 0.65);
 /* wepimg    */ ATTRIB(Vortex, model2, string, "weaponnex");
 /* refname   */ ATTRIB(Vortex, netname, string, "vortex");
-/* wepname   */ ATTRIB(Vortex, message, string, _("Vortex"));
+/* wepname   */ ATTRIB(Vortex, m_name, string, _("Vortex"));
 ENDCLASS(Vortex)
 REGISTER_WEAPON(VORTEX, NEW(Vortex));
 
@@ -60,15 +60,14 @@ VORTEX_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
 #endif
 #endif
 #ifdef IMPLEMENTATION
-#ifdef SVQC
-spawnfunc(weapon_vortex) { weapon_defaultspawnfunc(WEP_VORTEX.m_id); }
-spawnfunc(weapon_nex) { spawnfunc_weapon_vortex(this); }
 
+REGISTER_NET_TEMP(TE_CSQC_VORTEXBEAMPARTICLE)
+
+#if defined(SVQC)
 void SendCSQCVortexBeamParticle(float charge) {
        vector v;
        v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
-       WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-       WriteByte(MSG_BROADCAST, TE_CSQC_VORTEXBEAMPARTICLE);
+       WriteHeader(MSG_BROADCAST, TE_CSQC_VORTEXBEAMPARTICLE);
        WriteCoord(MSG_BROADCAST, w_shotorg.x);
        WriteCoord(MSG_BROADCAST, w_shotorg.y);
        WriteCoord(MSG_BROADCAST, w_shotorg.z);
@@ -77,6 +76,33 @@ void SendCSQCVortexBeamParticle(float charge) {
        WriteCoord(MSG_BROADCAST, v.z);
        WriteByte(MSG_BROADCAST, bound(0, 255 * charge, 255));
 }
+#elif defined(CSQC)
+NET_HANDLE(TE_CSQC_VORTEXBEAMPARTICLE, bool isNew)
+{
+       vector shotorg, endpos;
+       float charge;
+       shotorg.x = ReadCoord(); shotorg.y = ReadCoord(); shotorg.z = ReadCoord();
+       endpos.x = ReadCoord(); endpos.y = ReadCoord(); endpos.z = ReadCoord();
+       charge = ReadByte() / 255.0;
+
+       pointparticles(EFFECT_VORTEX_MUZZLEFLASH, shotorg, normalize(endpos - shotorg) * 1000, 1);
+
+       //draw either the old v2.3 beam or the new beam
+       charge = sqrt(charge); // divide evenly among trail spacing and alpha
+       particles_alphamin = particles_alphamax = particles_fade = charge;
+
+       if(!MUTATOR_CALLHOOK(Particles_VortexBeam, shotorg, endpos))
+       if(autocvar_cl_particles_oldvortexbeam && (getstati(STAT_ALLOW_OLDVORTEXBEAM) || isdemo()))
+               WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM_OLD), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
+       else
+               WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
+       return true;
+}
+#endif
+
+#ifdef SVQC
+spawnfunc(weapon_vortex) { weapon_defaultspawnfunc(this, WEP_VORTEX); }
+spawnfunc(weapon_nex) { spawnfunc_weapon_vortex(this); }
 
 void W_Vortex_Attack(Weapon thiswep, float issecondary)
 {SELFPARAM();
@@ -143,7 +169,7 @@ void W_Vortex_Attack(Weapon thiswep, float issecondary)
                                        self.BUTTON_ATCK2 = true;
                        }
                }
-               METHOD(Vortex, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
+               METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
                {
                        if(WEP_CVAR(vortex, charge) && actor.vortex_charge < WEP_CVAR(vortex, charge_limit))
                                actor.vortex_charge = min(1, actor.vortex_charge + WEP_CVAR(vortex, charge_rate) * frametime / W_TICSPERFRAME);
@@ -161,15 +187,15 @@ void W_Vortex_Attack(Weapon thiswep, float issecondary)
                                w.wr_reload(w);
                        } else
                        {
-                               if(fire1)
+                               if(fire & 1)
                                {
-                                       if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_PRI(vortex, refire)))
+                                       if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(vortex, refire)))
                                        {
                                                W_Vortex_Attack(thiswep, 0);
-                                               weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_PRI(vortex, animtime), w_ready);
+                                               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(vortex, animtime), w_ready);
                                        }
                                }
-                               if((WEP_CVAR(vortex, charge) && !WEP_CVAR(vortex, secondary)) ? (actor.BUTTON_ZOOM | actor.BUTTON_ZOOMSCRIPT) : fire2)
+                               if((WEP_CVAR(vortex, charge) && !WEP_CVAR(vortex, secondary)) ? (actor.BUTTON_ZOOM | actor.BUTTON_ZOOMSCRIPT) : (fire & 2))
                                {
                                        if(WEP_CVAR(vortex, charge))
                                        {
@@ -196,7 +222,7 @@ void W_Vortex_Attack(Weapon thiswep, float issecondary)
 
                                                        else if(WEP_CVAR_SEC(vortex, ammo))
                                                        {
-                                                               if(fire2) // only eat ammo when the button is pressed
+                                                               if(fire & 2) // only eat ammo when the button is pressed
                                                                {
                                                                        dt = min(dt, (1 - actor.vortex_charge) / WEP_CVAR(vortex, charge_rate));
                                                                        if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
@@ -235,10 +261,10 @@ void W_Vortex_Attack(Weapon thiswep, float issecondary)
                                        }
                                        else if(WEP_CVAR(vortex, secondary))
                                        {
-                                               if(weapon_prepareattack(thiswep, actor, false, WEP_CVAR_SEC(vortex, refire)))
+                                               if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(vortex, refire)))
                                                {
                                                        W_Vortex_Attack(thiswep, 1);
-                                                       weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR_SEC(vortex, animtime), w_ready);
+                                                       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(vortex, animtime), w_ready);
                                                }
                                        }
                                }
@@ -306,7 +332,7 @@ float autocvar_g_balance_vortex_secondary = 0; // WEAPONTODO
                METHOD(Vortex, wr_impacteffect, void(entity thiswep))
                {
                        vector org2 = w_org + w_backoff * 6;
-                       pointparticles(particleeffectnum(EFFECT_VORTEX_IMPACT), org2, '0 0 0', 1);
+                       pointparticles(EFFECT_VORTEX_IMPACT, org2, '0 0 0', 1);
                        if(!w_issilent)
                                sound(self, CH_SHOTS, SND_NEXIMPACT, VOL_BASE, ATTN_NORM);
                }
index 6ad27242aaf3f6a22161d17db4f4e3bd44d3575a..b9bcec58e60c6df31679667ea4a7ded1397333b5 100644 (file)
@@ -10,6 +10,8 @@
 
 #define spawn _spawn
 #define particleeffectnum _particleeffectnum
+#define trailparticles __trailparticles
+#define pointparticles __pointparticles
 #define setmodel _setmodel
 
 #include "upstream/csprogsdefs.qc"
 
 #undef spawn
 #undef particleeffectnum
+#undef trailparticles
+#undef pointparticles
 #undef setmodel
 
 #pragma noref 0
 
-#define ReadFloat() ReadCoord()
-
 #endif
index 7b437082f191096ac3aadd7b2bfc6583b50c3eae..ff9214844b3e5c181878b7ef31c40621e85a59e3 100644 (file)
@@ -4,10 +4,14 @@
 #pragma noref 1
 
 #define particleeffectnum __particleeffectnum
+#define trailparticles __trailparticles
+#define pointparticles __pointparticles
 
 #include "upstream/dpextensions.qc"
 
 #undef particleeffectnum
+#undef trailparticles
+#undef pointparticles
 
 int(entity ent, string tagname) _gettagindex = #451;
 #define gettagindex _gettagindex
index 5a93a2444c472d555b643fa18a601b4b0b8e76b4..535c3b6f7c3504e8ba3113a385ec7e489bcb29fa 100644 (file)
@@ -23,6 +23,4 @@
 
 #pragma noref 0
 
-#define WriteFloat(to, f) WriteCoord(to, f)
-
 #endif
index 9bc9ca2aefdc29f1cd96ffa5d8cbb0af8497659e..ceb59b780a7db71dd87640d9831cd78d810534b5 100644 (file)
@@ -1,28 +1,28 @@
 #ifndef NOCOMPAT
-    #define COMPAT_NO_MOD_IS_XONOTIC
+       #define COMPAT_NO_MOD_IS_XONOTIC
 #endif
 
 #include "compiler.qh"
 
 #ifndef QCC_SUPPORT_INT
-    #define int float
+       #define int float
 #endif
 
 #ifndef QCC_SUPPORT_BOOL
-    #define bool float
+       #define bool float
 #endif
 
 #if defined(CSQC)
-    #include "../dpdefs/csprogsdefs.qh"
-    #include "../dpdefs/keycodes.qh"
+       #include "../dpdefs/csprogsdefs.qh"
+       #include "../dpdefs/keycodes.qh"
 #elif defined(SVQC)
-    #include "../server/sys-pre.qh"
-    #include "../dpdefs/progsdefs.qh"
-    #include "../dpdefs/dpextensions.qh"
-    #include "../server/sys-post.qh"
+       #include "../server/sys-pre.qh"
+       #include "../dpdefs/progsdefs.qh"
+       #include "../dpdefs/dpextensions.qh"
+       #include "../server/sys-post.qh"
 #elif defined(MENUQC)
-    #include "../dpdefs/menudefs.qh"
-    #include "../dpdefs/keycodes.qh"
+       #include "../dpdefs/menudefs.qh"
+       #include "../dpdefs/keycodes.qh"
 #endif
 
 #include "warpzone/mathlib.qc"
@@ -43,6 +43,7 @@
 #include "lazy.qh"
 #include "linkedlist.qh"
 #include "log.qh"
+#include "map.qc"
 #include "math.qh"
 #include "misc.qh"
 #include "net.qh"
 #include "progname.qh"
 #include "random.qc"
 #include "registry.qh"
+#include "registry_net.qh"
 #include "replicate.qh"
 #include "self.qh"
 #include "sortlist.qc"
 #include "sort.qh"
 #include "spawnfunc.qh"
 #include "static.qh"
+#include "stats.qh"
 #include "string.qh"
 #include "struct.qh"
 #include "test.qc"
index 7e1a1edc0f7906ebd6dd9afa925196da47fdf894..e3d17b9f26848ae9f473b1c844878729274fd784 100644 (file)
@@ -2,51 +2,59 @@
 #define ACCUMULATE_H
 
 #ifdef QCC_SUPPORT_ACCUMULATE
-# define ACCUMULATE_FUNCTION(func, otherfunc) \
-    [[accumulate]] void func() { otherfunc(); }
-# define CALL_ACCUMULATED_FUNCTION(func) \
-    func()
+       #define ACCUMULATE_FUNCTION(func, otherfunc) \
+               [[accumulate]] void func() \
+               { \
+                       otherfunc(); \
+               }
+       #define CALL_ACCUMULATED_FUNCTION(func) \
+               func()
 #else
-#ifdef HAVE_YO_DAWG_CPP
+       #ifdef HAVE_YO_DAWG_CPP
 // TODO make ascii art pic of xzibit
 // YO DAWG!
 // I HERD YO LIEK MACROS
 // SO I PUT A MACRO DEFINITION IN YO MACRO DEFINITION
 // SO YO CAN EXPAND MACROS WHILE YO EXPAND MACROS
-# define ACCUMULATE_FUNCTION(func,otherfunc) \
-    #ifdef func \
-    void __merge__##otherfunc() { func(); otherfunc(); } \
-    #undef func \
-    #define func __merge__##otherfunc \
-    #else \
-    #define func otherfunc \
-    #endif
-# define CALL_ACCUMULATED_FUNCTION(func) \
-    func()
-#else
-# define ACCUMULATE_FUNCTION(func,otherfunc) \
-    .float _ACCUMULATE_##func##__##otherfunc;
-void ACCUMULATE_call(string func)
-{
-    float i;
-    float n = numentityfields();
-    string funcprefix = strcat("_ACCUMULATE_", func, "__");
-    float funcprefixlen = strlen(funcprefix);
-    for(i = 0; i < n; ++i)
-    {
-        string name = entityfieldname(i);
-        if(substring(name, 0, funcprefixlen) == funcprefix)
-            callfunction(substring(name, funcprefixlen, -1));
-    }
-}
-# define CALL_ACCUMULATED_FUNCTION(func) \
-    ACCUMULATE_call(#func)
-#endif
+               #define ACCUMULATE_FUNCTION(func, otherfunc) \
+                       #ifdef func \
+                       void __merge__##otherfunc() \
+                       { \
+                               func(); otherfunc(); \
+                       } \
+                       #undef func \
+                       #define func __merge__##otherfunc \
+                       #else \
+                               #define func otherfunc \
+                               #endif
+               #define CALL_ACCUMULATED_FUNCTION(func) \
+                       func()
+       #else
+               #define ACCUMULATE_FUNCTION(func, otherfunc) \
+                       .float _ACCUMULATE_##func##__##otherfunc;
+               void ACCUMULATE_call(string func)
+               {
+                       float i;
+                       float n = numentityfields();
+                       string funcprefix = strcat("_ACCUMULATE_", func, "__");
+                       float funcprefixlen = strlen(funcprefix);
+                       for (i = 0; i < n; ++i)
+                       {
+                               string name = entityfieldname(i);
+                               if (substring(name, 0, funcprefixlen) == funcprefix) callfunction(substring(name, funcprefixlen, -1));
+                       }
+               }
+               #define CALL_ACCUMULATED_FUNCTION(func) \
+                       ACCUMULATE_call( #func)
+       #endif
 #endif
 
 // used for simplifying ACCUMULATE_FUNCTIONs
-#define SET_FIRST_OR_LAST(input,first,count) if(!input) { input = (first + count); }
-#define SET_FIELD_COUNT(field,first,count) if(!field) { field = (first + count); ++count; }
-#define CHECK_MAX_COUNT(name,max,count,type) if(count > max) { error(strcat("Maximum ", type, " hit: ", #name, ": ", ftos(count), ".\n")); }
+#define SET_FIRST_OR_LAST(input, first, count) \
+       if (!input) { input = (first + count); }
+#define SET_FIELD_COUNT(field, first, count) \
+       if (!field) { field = (first + count); ++count; }
+#define CHECK_MAX_COUNT(name, max, count, type) \
+       if (count > max) { error(strcat("Maximum ", type, " hit: ", #name, ": ", ftos(count), ".\n")); }
 
 #endif
index 86b5df5970c0d1aa07387ec1de973399d581ab14..001984a632e0f8f9451354797879b31c5b7e67f4 100644 (file)
 #ifndef BITS_H
 #define BITS_H
+#include "log.qh"
 
 #define BIT(n) (1 << (n))
 #define BITS(n) (BIT(n) - 1)
 #ifndef BRANCHLESS_BITSET
-    #define BITSET(var, mask, flag) (flag ? (var) | (mask) : (var) &~ (mask))
+       #define BITSET(var, mask, flag) (flag ? (var) | (mask) : (var) & ~(mask))
 #else
-    #define BITSET(var, mask, flag) ((var) ^ (-(flag) ^ (var)) & (mask))
+       #define BITSET(var, mask, flag) ((var) ^ (-(flag) ^ (var)) & (mask))
 #endif
 
 int lowestbit(int f)
 {
-    f &= ~(f << 1);
-    f &= ~(f << 2);
-    f &= ~(f << 4);
-    f &= ~(f << 8);
-    f &= ~(f << 16);
-    return f;
+       f &= ~(f << 1);
+       f &= ~(f << 2);
+       f &= ~(f << 4);
+       f &= ~(f << 8);
+       f &= ~(f << 16);
+       return f;
+}
+
+int randombit(int bits)
+{
+       if (!(bits & (bits - 1)))  // this ONLY holds for powers of two!
+               return bits;
+
+       int r = random();
+       int b = 0;
+       int n = 0;
+
+       for (int f = 1; f <= bits; f *= 2)
+       {
+               if (bits & f)
+               {
+                       ++n;
+                       r *= n;
+                       if (r <= 1) b = f;
+                       else r = (r - 1) / (n - 1);
+               }
+       }
+       return b;
+}
+
+int randombits(int bits, int k, bool error_return)
+{
+       int r = 0;
+       while (k > 0 && bits != r)
+       {
+               r += randombit(bits - r);
+               --k;
+       }
+       if (error_return)
+               if (k > 0) return -1;
+       // all
+       return r;
+}
+
+void randombit_test(int bits, int iter)
+{
+       while (iter > 0)
+       {
+               LOG_INFO(ftos(randombit(bits)), "\n");
+               --iter;
+       }
+}
+
+enum {
+       OP_SET,
+       OP_MIN,
+       OP_MAX,
+       OP_PLUS,
+       OP_MINUS
+};
+
+bool GiveBit(entity e, .int fld, int bit, int op, int val)
+{
+       int v0 = (e.(fld) & bit);
+       switch (op)
+       {
+               case OP_SET:
+                       if (val > 0) e.(fld) |= bit;
+                       else e.(fld) &= ~bit;
+                       break;
+               case OP_MIN:
+               case OP_PLUS:
+                       if (val > 0) e.(fld) |= bit;
+                       break;
+               case OP_MAX:
+                       if (val <= 0) e.(fld) &= ~bit;
+                       break;
+               case OP_MINUS:
+                       if (val > 0) e.(fld) &= ~bit;
+                       break;
+       }
+       int v1 = (e.(fld) & bit);
+       return v0 != v1;
+}
+
+bool GiveValue(entity e, .int fld, int op, int val)
+{
+       int v0 = e.(fld);
+       switch (op)
+       {
+               case OP_SET:
+                       e.(fld) = val;
+                       break;
+               case OP_MIN:
+                       e.(fld) = max(e.(fld), val);  // min 100 cells = at least 100 cells
+                       break;
+               case OP_MAX:
+                       e.(fld) = min(e.(fld), val);
+                       break;
+               case OP_PLUS:
+                       e.(fld) += val;
+                       break;
+               case OP_MINUS:
+                       e.(fld) -= val;
+                       break;
+       }
+       int v1 = e.(fld);
+       return v0 != v1;
 }
 
 #endif
index 7a719af409ca1aaa49cc602518ab12529341495f..5510c171cfcc357487f4cd92182e8b987f88d7ea 100644 (file)
@@ -2,36 +2,34 @@
 #define BOOL_H
 
 #ifndef QCC_SUPPORT_BOOL
-    // Boolean Constants
-    const int true     = 1;
-    const int false = 0;
+       // Boolean Constants
+       const int true  = 1;
+       const int false = 0;
 #endif
 
 // Transitional aliases
-[[deprecated("use true")]] [[alias("true")]] const bool TRUE;
-[[deprecated("use false")]] [[alias("false")]] const bool FALSE;
+[[deprecated("use true")]][[alias("true")]] const bool TRUE;
+[[deprecated("use false")]][[alias("false")]] const bool FALSE;
+
+#define boolean(value) ((value) != 0)
 
 // get true/false value of a string with multiple different inputs
 float InterpretBoolean(string input)
 {
-    switch (strtolower(input))
-    {
-        case "yes":
-        case "true":
-        case "on":
-            return true;
-
-        case "no":
-        case "false":
-        case "off":
-            return false;
+       switch (strtolower(input))
+       {
+               case "yes":
+               case "true":
+               case "on":
+                       return true;
 
-        default: return stof(input);
-    }
-}
+               case "no":
+               case "false":
+               case "off":
+                       return false;
 
-float boolean(float value) { // if value is 0 return false (0), otherwise return true (1)
-    return (value == 0) ? false : true;
+               default: return boolean(stof(input));
+       }
 }
 
 #endif
index d21dab84ea99f317831d4caa336b005f52972192..442d8ee89ea762ce8459981487b9a4631ef745a6 100644 (file)
 #ifndef COLOR_H
 #define COLOR_H
 
+#include "string.qh"
+
 #define colormapPaletteColor(c, isPants) colormapPaletteColor_(c, isPants, time)
 vector colormapPaletteColor_(int c, bool isPants, float t)
 {
-    switch (c) {
-        case  0: return '1.000000 1.000000 1.000000';
-        case  1: return '1.000000 0.333333 0.000000';
-        case  2: return '0.000000 1.000000 0.501961';
-        case  3: return '0.000000 1.000000 0.000000';
-        case  4: return '1.000000 0.000000 0.000000';
-        case  5: return '0.000000 0.666667 1.000000';
-        case  6: return '0.000000 1.000000 1.000000';
-        case  7: return '0.501961 1.000000 0.000000';
-        case  8: return '0.501961 0.000000 1.000000';
-        case  9: return '1.000000 0.000000 1.000000';
-        case 10: return '1.000000 0.000000 0.501961';
-        case 11: return '0.000000 0.000000 1.000000';
-        case 12: return '1.000000 1.000000 0.000000';
-        case 13: return '0.000000 0.333333 1.000000';
-        case 14: return '1.000000 0.666667 0.000000';
-        case 15:
-            if (isPants)
-                return
-                      '1 0 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 0.0000000000))
-                    + '0 1 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 2.0943951024))
-                    + '0 0 1' * (0.502 + 0.498 * sin(t / 2.7182818285 + 4.1887902048));
-            else
-                return
-                      '1 0 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 5.2359877560))
-                    + '0 1 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 3.1415926536))
-                    + '0 0 1' * (0.502 + 0.498 * sin(t / 3.1415926536 + 1.0471975512));
-        default: return '0.000 0.000 0.000';
-    }
+       switch (c)
+       {
+               case  0: return '1.000000 1.000000 1.000000';
+               case  1: return '1.000000 0.333333 0.000000';
+               case  2: return '0.000000 1.000000 0.501961';
+               case  3: return '0.000000 1.000000 0.000000';
+               case  4: return '1.000000 0.000000 0.000000';
+               case  5: return '0.000000 0.666667 1.000000';
+               case  6: return '0.000000 1.000000 1.000000';
+               case  7: return '0.501961 1.000000 0.000000';
+               case  8: return '0.501961 0.000000 1.000000';
+               case  9: return '1.000000 0.000000 1.000000';
+               case 10: return '1.000000 0.000000 0.501961';
+               case 11: return '0.000000 0.000000 1.000000';
+               case 12: return '1.000000 1.000000 0.000000';
+               case 13: return '0.000000 0.333333 1.000000';
+               case 14: return '1.000000 0.666667 0.000000';
+               case 15:
+                       if (isPants)
+                               return '1 0 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 0.0000000000))
+                                      + '0 1 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 2.0943951024))
+                                      + '0 0 1' * (0.502 + 0.498 * sin(t / 2.7182818285 + 4.1887902048));
+                       else
+                               return '1 0 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 5.2359877560))
+                                      + '0 1 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 3.1415926536))
+                                      + '0 0 1' * (0.502 + 0.498 * sin(t / 3.1415926536 + 1.0471975512));
+               default: return '0.000 0.000 0.000';
+       }
+}
+
+float rgb_mi_ma_to_hue(vector rgb, float mi, float ma)
+{
+       if (mi == ma)
+       {
+               return 0;
+       }
+       else if (ma == rgb.x)
+       {
+               if (rgb.y >= rgb.z) return (rgb.y - rgb.z) / (ma - mi);
+               else return (rgb.y - rgb.z) / (ma - mi) + 6;
+       }
+       else if (ma == rgb.y)
+       {
+               return (rgb.z - rgb.x) / (ma - mi) + 2;
+       }
+       else  // if(ma == rgb_z)
+       {
+               return (rgb.x - rgb.y) / (ma - mi) + 4;
+       }
+}
+
+vector hue_mi_ma_to_rgb(float hue, float mi, float ma)
+{
+       vector rgb;
+
+       hue -= 6 * floor(hue / 6);
+
+       // else if(ma == rgb_x)
+       //      hue = 60 * (rgb_y - rgb_z) / (ma - mi);
+       if (hue <= 1)
+       {
+               rgb.x = ma;
+               rgb.y = hue * (ma - mi) + mi;
+               rgb.z = mi;
+       }
+       // else if(ma == rgb_y)
+       //      hue = 60 * (rgb_z - rgb_x) / (ma - mi) + 120;
+       else if (hue <= 2)
+       {
+               rgb.x = (2 - hue) * (ma - mi) + mi;
+               rgb.y = ma;
+               rgb.z = mi;
+       }
+       else if (hue <= 3)
+       {
+               rgb.x = mi;
+               rgb.y = ma;
+               rgb.z = (hue - 2) * (ma - mi) + mi;
+       }
+       // else // if(ma == rgb_z)
+       //      hue = 60 * (rgb_x - rgb_y) / (ma - mi) + 240;
+       else if (hue <= 4)
+       {
+               rgb.x = mi;
+               rgb.y = (4 - hue) * (ma - mi) + mi;
+               rgb.z = ma;
+       }
+       else if (hue <= 5)
+       {
+               rgb.x = (hue - 4) * (ma - mi) + mi;
+               rgb.y = mi;
+               rgb.z = ma;
+       }
+       // else if(ma == rgb_x)
+       //      hue = 60 * (rgb_y - rgb_z) / (ma - mi);
+       else  // if(hue <= 6)
+       {
+               rgb.x = ma;
+               rgb.y = mi;
+               rgb.z = (6 - hue) * (ma - mi) + mi;
+       }
+
+       return rgb;
+}
+
+vector rgb_to_hsv(vector rgb)
+{
+       float mi, ma;
+       vector hsv;
+
+       mi = min(rgb.x, rgb.y, rgb.z);
+       ma = max(rgb.x, rgb.y, rgb.z);
+
+       hsv.x = rgb_mi_ma_to_hue(rgb, mi, ma);
+       hsv.z = ma;
+
+       if (ma == 0) hsv.y = 0;
+       else hsv.y = 1 - mi / ma;
+
+       return hsv;
+}
+
+vector hsv_to_rgb(vector hsv)
+{
+       return hue_mi_ma_to_rgb(hsv.x, hsv.z * (1 - hsv.y), hsv.z);
+}
+
+vector rgb_to_hsl(vector rgb)
+{
+       float mi, ma;
+       vector hsl;
+
+       mi = min(rgb.x, rgb.y, rgb.z);
+       ma = max(rgb.x, rgb.y, rgb.z);
+
+       hsl.x = rgb_mi_ma_to_hue(rgb, mi, ma);
+
+       hsl.z = 0.5 * (mi + ma);
+       if (mi == ma) hsl.y = 0;
+       else if (hsl.z <= 0.5) hsl.y = (ma - mi) / (2 * hsl.z);
+       else  // if(hsl_z > 0.5)
+               hsl.y = (ma - mi) / (2 - 2 * hsl.z);
+
+       return hsl;
+}
+
+vector hsl_to_rgb(vector hsl)
+{
+       float mi, ma, maminusmi;
+
+       if (hsl.z <= 0.5) maminusmi = hsl.y * 2 * hsl.z;
+       else maminusmi = hsl.y * (2 - 2 * hsl.z);
+
+       // hsl_z     = 0.5 * mi + 0.5 * ma
+       // maminusmi =     - mi +       ma
+       mi = hsl.z - 0.5 * maminusmi;
+       ma = hsl.z + 0.5 * maminusmi;
+
+       return hue_mi_ma_to_rgb(hsl.x, mi, ma);
+}
+
+string rgb_to_hexcolor(vector rgb)
+{
+       return strcat(
+               "^x",
+               DEC_TO_HEXDIGIT(floor(rgb.x * 15 + 0.5)),
+               DEC_TO_HEXDIGIT(floor(rgb.y * 15 + 0.5)),
+               DEC_TO_HEXDIGIT(floor(rgb.z * 15 + 0.5))
+                    );
 }
 
 #endif
index 69aad5c54abe1711a5010d4eb545371f07476bbb..d389248b0ed24f8460f1f54b691f021b5a8015c8 100644 (file)
@@ -2,15 +2,15 @@
 #define COMPILER_H
 
 #ifndef QCC_SUPPORT_ACCUMULATE
-    #ifdef GMQCC
-        #define QCC_SUPPORT_ACCUMULATE
-    #endif
+       #ifdef GMQCC
+               #define QCC_SUPPORT_ACCUMULATE
+       #endif
 #endif
 
 #ifndef QCC_SUPPORT_NIL
-    #ifdef GMQCC
-        #define QCC_SUPPORT_NIL
-    #endif
+       #ifdef GMQCC
+               #define QCC_SUPPORT_NIL
+       #endif
 #endif
 
 #endif
index 81103a51cabb8e068de2c3b03897177b132f4431..24ce56d70cfc9925fc6fe22f356a14c5b8641517 100644 (file)
@@ -7,54 +7,60 @@
 //  Time processing and counting functions/macros
 // ===============================================
 
-#define count_years_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s years")), ftos_decimals(time, decs))
-#define count_years(time) count_fill(time, \
-               ZCTX(_("CI_ZER^%d years")), /* zeroth */ \
-               ZCTX(_("CI_FIR^%d year")),  /* first */ \
-               ZCTX(_("CI_SEC^%d years")), /* year */ \
-               ZCTX(_("CI_THI^%d years")), /* third */ \
-               ZCTX(_("CI_MUL^%d years"))) /* multi */
-
-#define count_weeks_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s weeks")), ftos_decimals(time, decs))
-#define count_weeks(time) count_fill(time, \
-               ZCTX(_("CI_ZER^%d weeks")), /* zeroth */ \
-               ZCTX(_("CI_FIR^%d week")),  /* first */ \
-               ZCTX(_("CI_SEC^%d weeks")), /* week */ \
-               ZCTX(_("CI_THI^%d weeks")), /* third */ \
-               ZCTX(_("CI_MUL^%d weeks"))) /* multi */
-
-#define count_days_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s days")), ftos_decimals(time, decs))
-#define count_days(time) count_fill(time, \
-               ZCTX(_("CI_ZER^%d days")), /* zeroth */ \
-               ZCTX(_("CI_FIR^%d day")),  /* first */ \
-               ZCTX(_("CI_SEC^%d days")), /* day */ \
-               ZCTX(_("CI_THI^%d days")), /* third */ \
-               ZCTX(_("CI_MUL^%d days"))) /* multi */
-
-#define count_hours_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s hours")), ftos_decimals(time, decs))
-#define count_hours(time) count_fill(time, \
-               ZCTX(_("CI_ZER^%d hours")), /* zeroth */ \
-               ZCTX(_("CI_FIR^%d hour")),  /* first */ \
-               ZCTX(_("CI_SEC^%d hours")), /* hour */ \
-               ZCTX(_("CI_THI^%d hours")), /* third */ \
-               ZCTX(_("CI_MUL^%d hours"))) /* multi */
-
-
-#define count_minutes_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s minutes")), ftos_decimals(time, decs))
-#define count_minutes(time) count_fill(time, \
-               ZCTX(_("CI_ZER^%d minutes")), /* zeroth */ \
-               ZCTX(_("CI_FIR^%d minute")),  /* first */ \
-               ZCTX(_("CI_SEC^%d minutes")), /* minute */ \
-               ZCTX(_("CI_THI^%d minutes")), /* third */ \
-               ZCTX(_("CI_MUL^%d minutes"))) /* multi */
-
-#define count_seconds_decs(time,decs) sprintf(ZCTX(_("CI_DEC^%s seconds")), ftos_decimals(time, decs))
-#define count_seconds(time) count_fill(time, \
-               ZCTX(_("CI_ZER^%d seconds")), /* zeroth */ \
-               ZCTX(_("CI_FIR^%d second")),  /* first */ \
-               ZCTX(_("CI_SEC^%d seconds")), /* second */ \
-               ZCTX(_("CI_THI^%d seconds")), /* third */ \
-               ZCTX(_("CI_MUL^%d seconds"))) /* multi */
+#define count_years_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s years")), ftos_decimals(time, decs))
+#define count_years(time) \
+       count_fill(time, \
+       ZCTX(_("CI_ZER^%d years")), /* zeroth */ \
+       ZCTX(_("CI_FIR^%d year")),  /* first */ \
+       ZCTX(_("CI_SEC^%d years")), /* year */ \
+       ZCTX(_("CI_THI^%d years")), /* third */ \
+       ZCTX(_("CI_MUL^%d years"))) /* multi */
+
+#define count_weeks_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s weeks")), ftos_decimals(time, decs))
+#define count_weeks(time) \
+       count_fill(time, \
+       ZCTX(_("CI_ZER^%d weeks")), /* zeroth */ \
+       ZCTX(_("CI_FIR^%d week")),  /* first */ \
+       ZCTX(_("CI_SEC^%d weeks")), /* week */ \
+       ZCTX(_("CI_THI^%d weeks")), /* third */ \
+       ZCTX(_("CI_MUL^%d weeks"))) /* multi */
+
+#define count_days_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s days")), ftos_decimals(time, decs))
+#define count_days(time) \
+       count_fill(time, \
+       ZCTX(_("CI_ZER^%d days")), /* zeroth */ \
+       ZCTX(_("CI_FIR^%d day")),  /* first */ \
+       ZCTX(_("CI_SEC^%d days")), /* day */ \
+       ZCTX(_("CI_THI^%d days")), /* third */ \
+       ZCTX(_("CI_MUL^%d days"))) /* multi */
+
+#define count_hours_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s hours")), ftos_decimals(time, decs))
+#define count_hours(time) \
+       count_fill(time, \
+       ZCTX(_("CI_ZER^%d hours")), /* zeroth */ \
+       ZCTX(_("CI_FIR^%d hour")),  /* first */ \
+       ZCTX(_("CI_SEC^%d hours")), /* hour */ \
+       ZCTX(_("CI_THI^%d hours")), /* third */ \
+       ZCTX(_("CI_MUL^%d hours"))) /* multi */
+
+
+#define count_minutes_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s minutes")), ftos_decimals(time, decs))
+#define count_minutes(time) \
+       count_fill(time, \
+       ZCTX(_("CI_ZER^%d minutes")), /* zeroth */ \
+       ZCTX(_("CI_FIR^%d minute")),  /* first */ \
+       ZCTX(_("CI_SEC^%d minutes")), /* minute */ \
+       ZCTX(_("CI_THI^%d minutes")), /* third */ \
+       ZCTX(_("CI_MUL^%d minutes"))) /* multi */
+
+#define count_seconds_decs(time, decs) sprintf(ZCTX(_("CI_DEC^%s seconds")), ftos_decimals(time, decs))
+#define count_seconds(time) \
+       count_fill(time, \
+       ZCTX(_("CI_ZER^%d seconds")), /* zeroth */ \
+       ZCTX(_("CI_FIR^%d second")),  /* first */ \
+       ZCTX(_("CI_SEC^%d seconds")), /* second */ \
+       ZCTX(_("CI_THI^%d seconds")), /* third */ \
+       ZCTX(_("CI_MUL^%d seconds"))) /* multi */
 
 string count_ordinal(int interval)
 {
@@ -65,10 +71,10 @@ string count_ordinal(int interval)
        // Basically, it just allows you to represent a number or count in different ways
        // depending on the number... like, with count_ordinal you can provide integers
        // and retrieve 1st, 2nd, 3rd, nth ordinal numbers in a clean and simple way.
-       if(floor((interval % 100)/10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block
+       if (floor((interval % 100) / 10) * 10 != 10)  // examples: 12th, 111th, 213th will not execute this block
        {
                // otherwise, check normally for 1st,2nd,3rd insertions
-               switch(interval % 10)
+               switch (interval % 10)
                {
                        case 1: return sprintf(_("%dst"), interval);
                        case 2: return sprintf(_("%dnd"), interval);
@@ -95,15 +101,14 @@ string count_fill(float interval, string zeroth, string first, string second, st
        //   3 seconds
        //   etc... minutes, hours, days, etc.
 
-       switch(floor(interval))
+       switch (floor(interval))
        {
                case 0: return sprintf(zeroth, interval);
                case 1:
                {
-                       if(interval == 1) // EXACTLY value of 1
+                       if (interval == 1)  // EXACTLY value of 1
                                return sprintf(first, interval);
-                       else
-                               return sprintf(multi, interval);
+                       else return sprintf(multi, interval);
                }
                case 2: return sprintf(second, interval);
                case 3: return sprintf(third, interval);
@@ -119,26 +124,26 @@ string process_time(float outputtype, float seconds)
 
        tmp_seconds = floor(seconds);
 
-       if(tmp_seconds)
+       if (tmp_seconds)
        {
                tmp_minutes = floor(tmp_seconds / 60);
 
-               if(tmp_minutes)
+               if (tmp_minutes)
                {
                        tmp_seconds -= (tmp_minutes * 60);
                        tmp_hours = floor(tmp_minutes / 60);
 
-                       if(tmp_hours)
+                       if (tmp_hours)
                        {
                                tmp_minutes -= (tmp_hours * 60);
                                tmp_days = floor(tmp_hours / 24);
 
-                               if(tmp_days)
+                               if (tmp_days)
                                {
                                        tmp_hours -= (tmp_days * 24);
                                        tmp_weeks = floor(tmp_days / 7);
 
-                                       if(tmp_weeks)
+                                       if (tmp_weeks)
                                        {
                                                tmp_days -= (tmp_weeks * 7);
                                                tmp_years = floor(tmp_weeks / 52);
@@ -148,7 +153,7 @@ string process_time(float outputtype, float seconds)
                }
        }
 
-       switch(outputtype)
+       switch (outputtype)
        {
                case 1: return sprintf("%02d:%02d:%02d", tmp_hours, tmp_minutes, tmp_seconds);
                case 2:
@@ -157,7 +162,7 @@ string process_time(float outputtype, float seconds)
 
                        output = count_seconds(tmp_seconds);
 
-                       if(tmp_minutes)
+                       if (tmp_minutes)
                        {
                                output = sprintf(
                                        "%s%s",
@@ -165,7 +170,7 @@ string process_time(float outputtype, float seconds)
                                        ((output != "") ? sprintf(", %s", output) : ""));
                        }
 
-                       if(tmp_hours)
+                       if (tmp_hours)
                        {
                                output = sprintf(
                                        "%s%s",
@@ -173,7 +178,7 @@ string process_time(float outputtype, float seconds)
                                        ((output != "") ? sprintf(", %s", output) : ""));
                        }
 
-                       if(tmp_days)
+                       if (tmp_days)
                        {
                                output = sprintf(
                                        "%s%s",
@@ -181,7 +186,7 @@ string process_time(float outputtype, float seconds)
                                        ((output != "") ? sprintf(", %s", output) : ""));
                        }
 
-                       if(tmp_weeks)
+                       if (tmp_weeks)
                        {
                                output = sprintf(
                                        "%s%s",
@@ -189,7 +194,7 @@ string process_time(float outputtype, float seconds)
                                        ((output != "") ? sprintf(", %s", output) : ""));
                        }
 
-                       if(tmp_years)
+                       if (tmp_years)
                        {
                                output = sprintf(
                                        "%s%s",
@@ -205,9 +210,9 @@ string process_time(float outputtype, float seconds)
 
                        output = count_hours(tmp_hours);
 
-                       if(tmp_weeks) { tmp_days += (tmp_weeks * 7); }
-                       if(tmp_years) { tmp_days += (tmp_years * 365); }
-                       if(tmp_days)
+                       if (tmp_weeks) tmp_days += (tmp_weeks * 7);
+                       if (tmp_years) tmp_days += (tmp_years * 365);
+                       if (tmp_days)
                        {
                                output = sprintf(
                                        "%s%s",
index 8d3d4ab930745485c165aeb88eb27a2be8465b43..a656fb7908bb39cb6e5a4cf03b1486ec4b0f196a 100644 (file)
@@ -209,8 +209,8 @@ void CSQCModel_Draw()
        self.csqcmodel_teleported = 0;
 }
 
-void CSQCModel_Read(bool isnew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_MODEL, bool isnew)
+{
        int sf = ReadInt24_t();
 
        // some nice flags for CSQCMODEL_IF and the hooks
@@ -279,6 +279,7 @@ void CSQCModel_Read(bool isnew)
        // draw it
        self.drawmask = MASK_NORMAL;
        self.predraw = CSQCModel_Draw;
+       return true;
 }
 
 entity CSQCModel_server2csqc(float pl)
index 55401e4b4d22157fc15b11728bb42b16d33718ef..179350f9500bfa9b3ce5c10bcec0dac1342044dd 100644 (file)
@@ -24,8 +24,6 @@
 
 #include "common.qh"
 
-void CSQCModel_Read(bool isnew);
-
 #define CSQCMODEL_IF(cond)
 #define CSQCMODEL_ENDIF
 #define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
index c39ee879708a8aba8f0d4fa2b6a9370a91d8c952..155ad7f9229103526c52881c4a42106aa8827d2a 100644 (file)
@@ -146,7 +146,7 @@ void PM_Movement_Move()
 #endif
 }
 
-void CSQCPlayer_Physics(void)
+void CSQCPlayer_Physics()
 {
        switch(autocvar_cl_movement)
        {
index e922453afec8e6a0458462ffd886e36d61ff8865..6da742a04e34944d814827d1e7618ce74f006682 100644 (file)
@@ -61,7 +61,7 @@ const int CSQCMODEL_PROPERTY_ORIGIN = BIT(20);
 const int CSQCMODEL_PROPERTY_YAW = BIT(19);
 const int CSQCMODEL_PROPERTY_PITCHROLL = BIT(18);
 const int CSQCMODEL_PROPERTY_FRAME2 = BIT(17);
-const int CSQCMODEL_PROPERTY_LERPFRAC = BIT(BIT(4));
+const int CSQCMODEL_PROPERTY_LERPFRAC = BIT(16);
 const int CSQCMODEL_PROPERTY_SIZE = BIT(15);
 
 #define ALLPROPERTIES_COMMON \
index 8fcdcfbee675d4e0a399dc3e95eb12f291fa8114..cadb77467cd97605131d50edd425d8b03508dd9d 100644 (file)
@@ -41,7 +41,7 @@ bool CSQCModel_Send(entity to, int sf)
        unused_float = islocalplayer;
        unused_float = isnolocalplayer;
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_MODEL);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_MODEL);
        WriteInt24_t(MSG_ENTITY, sf);
 
 #define CSQCMODEL_IF(cond) if(cond) {
@@ -61,7 +61,7 @@ bool CSQCModel_Send(entity to, int sf)
        return true;
 }
 
-#ifdef CSQCPLAYER_FORCE_UPDATES
+#if CSQCPLAYER_FORCE_UPDATES
 .float csqcmodel_nextforcedupdate;
 #endif
 void CSQCModel_CheckUpdate(entity e)
@@ -75,7 +75,7 @@ void CSQCModel_CheckUpdate(entity e)
        unused_float = islocalplayer;
        unused_float = isnolocalplayer;
 
-#ifdef CSQCPLAYER_FORCE_UPDATES
+#if CSQCPLAYER_FORCE_UPDATES
        if(isplayer && time > e.csqcmodel_nextforcedupdate)
        {
                e.SendFlags |= CSQCMODEL_PROPERTY_ORIGIN;
index 5ee3222bc6367908243d56899535728ddd2d2b97..d79ae11544d5467ccbc93e9d7e3bdbb954cd0b19 100644 (file)
@@ -5,7 +5,18 @@
 #include "progname.qh"
 #include "static.qh"
 
-void RegisterCvars(void(string name, string def, string desc, bool archive, string file) f) { }
+void RegisterCvars(void(string name, string def, string desc, bool archive, string file) f) {}
+
+bool cvar_value_issafe(string s)
+{
+       if (strstrofs(s, "\"", 0) >= 0) return false;
+       if (strstrofs(s, "\\", 0) >= 0) return false;
+       if (strstrofs(s, ";", 0) >= 0) return false;
+       if (strstrofs(s, "$", 0) >= 0) return false;
+       if (strstrofs(s, "\r", 0) >= 0) return false;
+       if (strstrofs(s, "\n", 0) >= 0) return false;
+       return true;
+}
 
 /** escape the string to make it safe for consoles */
 string MakeConsoleSafe(string input)
@@ -17,34 +28,38 @@ string MakeConsoleSafe(string input)
        return input;
 }
 
-void cvar_describe(string name, string desc) {
-    localcmd(sprintf("\nset %1$s \"$%1$s\" \"%2$s\"\n", name, MakeConsoleSafe(desc)));
+void cvar_describe(string name, string desc)
+{
+       localcmd(sprintf("\nset %1$s \"$%1$s\" \"%2$s\"\n", name, MakeConsoleSafe(desc)));
 }
 
-void cvar_archive(string name) {
-    localcmd(sprintf("\nseta %1$s \"$%1$s\"\n", name));
+void cvar_archive(string name)
+{
+       localcmd(sprintf("\nseta %1$s \"$%1$s\"\n", name));
 }
 
 void RegisterCvars_Set(string name, string def, string desc, bool archive, string file)
 {
-    cvar_describe(name, desc);
-    if (archive) cvar_archive(name);
+       cvar_describe(name, desc);
+       if (archive) cvar_archive(name);
 }
 
 int RegisterCvars_Save_fd;
 void RegisterCvars_Save(string name, string def, string desc, bool archive, string file)
 {
-    if (!archive) return;
-    fputs(RegisterCvars_Save_fd, sprintf("seta %s \"%s\"\n", name, def));
+       if (!archive) return;
+       fputs(RegisterCvars_Save_fd, sprintf("seta %s \"%s\"\n", name, def));
 }
 
-STATIC_INIT_LATE(Cvars) {
-    RegisterCvars(RegisterCvars_Set);
-    RegisterCvars_Save_fd = fopen(sprintf("default%s.cfg", PROGNAME), FILE_WRITE);
-    if (RegisterCvars_Save_fd >= 0) {
-        RegisterCvars(RegisterCvars_Save);
-        fclose(RegisterCvars_Save_fd);
-    }
+STATIC_INIT_LATE(Cvars)
+{
+       RegisterCvars(RegisterCvars_Set);
+       RegisterCvars_Save_fd = fopen(sprintf("default%s.cfg", PROGNAME), FILE_WRITE);
+       if (RegisterCvars_Save_fd >= 0)
+       {
+               RegisterCvars(RegisterCvars_Save);
+               fclose(RegisterCvars_Save_fd);
+       }
 }
 
 const noref bool default_bool = false;
@@ -53,19 +68,22 @@ const noref float default_float = 0;
 const noref string default_string = "";
 const noref vector default_vector = '0 0 0';
 
-#define repr_cvar_bool(x)   ((x) ? "1" : "0")
-#define repr_cvar_int(x)    (ftos(x))
-#define repr_cvar_float(x)  (ftos(x))
+#define repr_cvar_bool(x) ((x) ? "1" : "0")
+#define repr_cvar_int(x) (ftos(x))
+#define repr_cvar_float(x) (ftos(x))
 #define repr_cvar_string(x) (x)
 #define repr_cvar_vector(x) (sprintf("%v", x))
 
 #define __AUTOCVAR(file, archive, var, type, desc, default) \
-    [[accumulate]] void RegisterCvars(void(string, string, string, bool, string) f) { f(#var, repr_cvar_##type(default), desc, archive, file); } \
-    type autocvar_##var = default
+       [[accumulate]] void RegisterCvars(void(string, string, string, bool, string) f) \
+       { \
+               f( #var, repr_cvar_##type(default), desc, archive, file); \
+       } \
+       type autocvar_##var = default
 #define AUTOCVAR_5(file, archive, var, type, desc) \
-    __AUTOCVAR(file, archive, var, type, desc, default_##type)
+       __AUTOCVAR(file, archive, var, type, desc, default_##type)
 #define AUTOCVAR_6(file, archive, var, type, default, desc) \
-    __AUTOCVAR(file, archive, var, type, desc, default)
+       __AUTOCVAR(file, archive, var, type, desc, default)
 #define _AUTOCVAR(...) EVAL(OVERLOAD(AUTOCVAR, __FILE__, __VA_ARGS__))
 #define AUTOCVAR_SAVE(...) _AUTOCVAR(true, __VA_ARGS__)
 #define AUTOCVAR(...) _AUTOCVAR(false, __VA_ARGS__)
index 6c495663452c2a0dffe4bf001b450c2c8a01498f..749e4a665ec882a23f2e247551fbdc91f7c5f404 100644 (file)
@@ -1,14 +1,14 @@
-#ifndef MENUQC
 #ifndef DEFER_H
 #define DEFER_H
+#ifndef MENUQC
 
-#include "oo.qh"
-#include "self.qh"
+       #include "oo.qh"
+       #include "self.qh"
 
-entityclass(Defer);
-class(Defer) .entity owner;
-class(Defer) .void() think;
-class(Defer) .float nextthink;
+       entityclass(Defer);
+       class(Defer).entity owner;
+       class(Defer).void() think;
+       class(Defer).float nextthink;
 
 /*
 ==================
@@ -17,32 +17,35 @@ SUB_Remove
 Remove self
 ==================
 */
-void SUB_Remove()
-{SELFPARAM();
-       remove (self);
-}
-
-void defer_think()
-{SELFPARAM();
-    self.think     = SUB_Remove;
-    self.nextthink = time;
-    WITH(entity, self, self.owner, self.use());
-}
+       void SUB_Remove()
+       {
+               SELFPARAM();
+               remove(self);
+       }
+
+       void defer_think()
+       {
+               SELFPARAM();
+               self.think     = SUB_Remove;
+               self.nextthink = time;
+               WITH(entity, self, self.owner, self.use());
+       }
 
 /*
     Execute func() after time + fdelay.
     self when func is executed = self when defer is called
 */
-void defer(float fdelay, void() func)
-{SELFPARAM();
-    entity e;
-
-    e           = spawn();
-    e.owner     = self;
-    e.use       = func;
-    e.think     = defer_think;
-    e.nextthink = time + fdelay;
-}
+       void defer(float fdelay, void() func)
+       {
+               SELFPARAM();
+
+               entity e    = new(deferred);
+               make_pure(e);
+               e.owner     = this;
+               e.use       = func;
+               e.think     = defer_think;
+               e.nextthink = time + fdelay;
+       }
 
 #endif
 #endif
index 90abcb2d3b31e7164a4f90565e7b598cc964f0c4..40900b8772314837defb913413fb9f60dabb6c4c 100644 (file)
@@ -1,38 +1,38 @@
 #ifdef CSQC
 #ifndef DRAW_H
-#define DRAW_H
+       #define DRAW_H
 
-#include "i18n.qh"
-#include "vector.qh"
+       #include "i18n.qh"
+       #include "vector.qh"
 
-#include "../client/defs.qh"
+       #include "../client/defs.qh"
 
-void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg)
-{
-       // I want to draw a quad...
-       // from and to are MIDPOINTS.
+       void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg)
+       {
+               // I want to draw a quad...
+               // from and to are MIDPOINTS.
 
-       vector axis, thickdir, A, B, C, D;
-       float length_tex;
+               vector axis, thickdir, A, B, C, D;
+               float length_tex;
 
-       axis = normalize(to - from);
-       length_tex = aspect * vlen(to - from) / thickness;
+               axis = normalize(to - from);
+               length_tex = aspect * vlen(to - from) / thickness;
 
-       // direction is perpendicular to the view normal, and perpendicular to the axis
-       thickdir = normalize(cross(axis, vieworg - from));
+               // direction is perpendicular to the view normal, and perpendicular to the axis
+               thickdir = normalize(cross(axis, vieworg - from));
 
-       A = from - thickdir * (thickness / 2);
-       B = from + thickdir * (thickness / 2);
-       C = to + thickdir * (thickness / 2);
-       D = to - thickdir * (thickness / 2);
+               A = from - thickdir * (thickness / 2);
+               B = from + thickdir * (thickness / 2);
+               C = to + thickdir * (thickness / 2);
+               D = to - thickdir * (thickness / 2);
 
-       R_BeginPolygon(texture, drawflag);
-       R_PolygonVertex(A, '0 0 0' + shift * '1 0 0', rgb, theAlpha);
-       R_PolygonVertex(B, '0 1 0' + shift * '1 0 0', rgb, theAlpha);
-       R_PolygonVertex(C, '0 1 0' + (shift + length_tex) * '1 0 0', rgb, theAlpha);
-       R_PolygonVertex(D, '0 0 0' + (shift + length_tex) * '1 0 0', rgb, theAlpha);
-       R_EndPolygon();
-}
+               R_BeginPolygon(texture, drawflag);
+               R_PolygonVertex(A, '0 0 0' + shift * '1 0 0', rgb, theAlpha);
+               R_PolygonVertex(B, '0 1 0' + shift * '1 0 0', rgb, theAlpha);
+               R_PolygonVertex(C, '0 1 0' + (shift + length_tex) * '1 0 0', rgb, theAlpha);
+               R_PolygonVertex(D, '0 0 0' + (shift + length_tex) * '1 0 0', rgb, theAlpha);
+               R_EndPolygon();
+       }
 
 // a border picture is a texture containing nine parts:
 //   1/4 width: left part
@@ -42,92 +42,92 @@ void Draw_CylindricLine(vector from, vector to, float thickness, string texture,
 //   1/4 height: top part
 //   1/2 height: middle part (stretched)
 //   1/4 height: bottom part
-void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha, vector theBorderSize)
-{
-    if (theBorderSize.x < 0 && theBorderSize.y < 0) // draw whole image as it is
-    {
-               drawpic(theOrigin, pic, theSize, theColor, theAlpha, 0);
-               return;
-    }
-       if (theBorderSize.x == 0 && theBorderSize.y == 0) // no border
+       void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha, vector theBorderSize)
        {
-               // draw only the central part
-               drawsubpic(theOrigin, theSize, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
-               return;
-       }
-
-       vector dX, dY;
-       vector width, height;
-       vector bW, bH;
-       //pic = draw_UseSkinFor(pic);
-       width = eX * theSize.x;
-       height = eY * theSize.y;
-       if(theSize.x <= theBorderSize.x * 2)
-       {
-               // not wide enough... draw just left and right then
-               bW = eX * (0.25 * theSize.x / (theBorderSize.x * 2));
-               if(theSize.y <= theBorderSize.y * 2)
+               if (theBorderSize.x < 0 && theBorderSize.y < 0)  // draw whole image as it is
                {
-                       // not high enough... draw just corners
-                       bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
-                       drawsubpic(theOrigin,                 width * 0.5 + height * 0.5, pic, '0 0 0',           bW + bH, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + width   * 0.5, width * 0.5 + height * 0.5, pic, eX - bW,           bW + bH, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + height  * 0.5, width * 0.5 + height * 0.5, pic, eY - bH,           bW + bH, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + theSize * 0.5, width * 0.5 + height * 0.5, pic, eX + eY - bW - bH, bW + bH, theColor, theAlpha, 0);
+                       drawpic(theOrigin, pic, theSize, theColor, theAlpha, 0);
+                       return;
                }
-               else
+               if (theBorderSize.x == 0 && theBorderSize.y == 0)  // no border
                {
-                       dY = theBorderSize.x * eY;
-                       drawsubpic(theOrigin,                             width * 0.5          +     dY, pic, '0 0    0',           '0 0.25 0' + bW, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + width * 0.5,               width * 0.5          +     dY, pic, '0 0    0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin                        + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0',           '0 0.5  0' + bW, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + width * 0.5          + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0' + eX - bW, '0 0.5  0' + bW, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin               + height - dY, width * 0.5          +     dY, pic, '0 0.75 0',           '0 0.25 0' + bW, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + width * 0.5 + height - dY, width * 0.5          +     dY, pic, '0 0.75 0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
+                       // draw only the central part
+                       drawsubpic(theOrigin, theSize, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
+                       return;
                }
-       }
-       else
-       {
-               if(theSize.y <= theBorderSize.y * 2)
+
+               vector dX, dY;
+               vector width, height;
+               vector bW, bH;
+               // pic = draw_UseSkinFor(pic);
+               width = eX * theSize.x;
+               height = eY * theSize.y;
+               if (theSize.x <= theBorderSize.x * 2)
                {
-                       // not high enough... draw just top and bottom then
-                       bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
-                       dX = theBorderSize.x * eX;
-                       drawsubpic(theOrigin,                                         dX + height * 0.5, pic, '0    0 0',           '0.25 0 0' + bH, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + dX,                        width - 2 * dX + height * 0.5, pic, '0.25 0 0',           '0.5  0 0' + bH, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + width - dX,                            dX + height * 0.5, pic, '0.75 0 0',           '0.25 0 0' + bH, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin              + height * 0.5,             dX + height * 0.5, pic, '0    0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + dX         + height * 0.5, width - 2 * dX + height * 0.5, pic, '0.25 0 0' + eY - bH, '0.5  0 0' + bH, theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + width - dX + height * 0.5,             dX + height * 0.5, pic, '0.75 0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
+                       // not wide enough... draw just left and right then
+                       bW = eX * (0.25 * theSize.x / (theBorderSize.x * 2));
+                       if (theSize.y <= theBorderSize.y * 2)
+                       {
+                               // not high enough... draw just corners
+                               bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
+                               drawsubpic(theOrigin,                 width * 0.5 + height * 0.5, pic, '0 0 0',           bW + bH, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + width   * 0.5, width * 0.5 + height * 0.5, pic, eX - bW,           bW + bH, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + height  * 0.5, width * 0.5 + height * 0.5, pic, eY - bH,           bW + bH, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + theSize * 0.5, width * 0.5 + height * 0.5, pic, eX + eY - bW - bH, bW + bH, theColor, theAlpha, 0);
+                       }
+                       else
+                       {
+                               dY = theBorderSize.x * eY;
+                               drawsubpic(theOrigin,                             width * 0.5          +     dY, pic, '0 0    0',           '0 0.25 0' + bW, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + width * 0.5,               width * 0.5          +     dY, pic, '0 0    0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin                        + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0',           '0 0.5  0' + bW, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + width * 0.5          + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0' + eX - bW, '0 0.5  0' + bW, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin               + height - dY, width * 0.5          +     dY, pic, '0 0.75 0',           '0 0.25 0' + bW, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + width * 0.5 + height - dY, width * 0.5          +     dY, pic, '0 0.75 0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
+                       }
                }
                else
                {
-                       dX = theBorderSize.x * eX;
-                       dY = theBorderSize.x * eY;
-                       drawsubpic(theOrigin,                                        dX          +     dY, pic, '0    0    0', '0.25 0.25 0', theColor, theAlpha, 0);
-                       drawsubpic(theOrigin                  + dX,      width - 2 * dX          +     dY, pic, '0.25 0    0', '0.5  0.25 0', theColor, theAlpha, 0);
-                       drawsubpic(theOrigin          + width - dX,                  dX          +     dY, pic, '0.75 0    0', '0.25 0.25 0', theColor, theAlpha, 0);
-                       drawsubpic(theOrigin          + dY,                          dX + height - 2 * dY, pic, '0    0.25 0', '0.25 0.5  0', theColor, theAlpha, 0);
-                       drawsubpic(theOrigin          + dY         + dX, width - 2 * dX + height - 2 * dY, pic, '0.25 0.25 0', '0.5  0.5  0', theColor, theAlpha, 0);
-                       drawsubpic(theOrigin          + dY + width - dX,             dX + height - 2 * dY, pic, '0.75 0.25 0', '0.25 0.5  0', theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + height - dY,                          dX          +     dY, pic, '0    0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + height - dY         + dX, width - 2 * dX          +     dY, pic, '0.25 0.75 0', '0.5  0.25 0', theColor, theAlpha, 0);
-                       drawsubpic(theOrigin + height - dY + width - dX,             dX          +     dY, pic, '0.75 0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
+                       if (theSize.y <= theBorderSize.y * 2)
+                       {
+                               // not high enough... draw just top and bottom then
+                               bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
+                               dX = theBorderSize.x * eX;
+                               drawsubpic(theOrigin,                                         dX + height * 0.5, pic, '0    0 0',           '0.25 0 0' + bH, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + dX,                        width - 2 * dX + height * 0.5, pic, '0.25 0 0',           '0.5  0 0' + bH, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + width - dX,                            dX + height * 0.5, pic, '0.75 0 0',           '0.25 0 0' + bH, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin              + height * 0.5,             dX + height * 0.5, pic, '0    0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + dX         + height * 0.5, width - 2 * dX + height * 0.5, pic, '0.25 0 0' + eY - bH, '0.5  0 0' + bH, theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + width - dX + height * 0.5,             dX + height * 0.5, pic, '0.75 0 0' + eY - bH, '0.25 0 0' + bH, theColor, theAlpha, 0);
+                       }
+                       else
+                       {
+                               dX = theBorderSize.x * eX;
+                               dY = theBorderSize.x * eY;
+                               drawsubpic(theOrigin,                                        dX          +     dY, pic, '0    0    0', '0.25 0.25 0', theColor, theAlpha, 0);
+                               drawsubpic(theOrigin                  + dX,      width - 2 * dX          +     dY, pic, '0.25 0    0', '0.5  0.25 0', theColor, theAlpha, 0);
+                               drawsubpic(theOrigin          + width - dX,                  dX          +     dY, pic, '0.75 0    0', '0.25 0.25 0', theColor, theAlpha, 0);
+                               drawsubpic(theOrigin          + dY,                          dX + height - 2 * dY, pic, '0    0.25 0', '0.25 0.5  0', theColor, theAlpha, 0);
+                               drawsubpic(theOrigin          + dY         + dX, width - 2 * dX + height - 2 * dY, pic, '0.25 0.25 0', '0.5  0.5  0', theColor, theAlpha, 0);
+                               drawsubpic(theOrigin          + dY + width - dX,             dX + height - 2 * dY, pic, '0.75 0.25 0', '0.25 0.5  0', theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + height - dY,                          dX          +     dY, pic, '0    0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + height - dY         + dX, width - 2 * dX          +     dY, pic, '0.25 0.75 0', '0.5  0.25 0', theColor, theAlpha, 0);
+                               drawsubpic(theOrigin + height - dY + width - dX,             dX          +     dY, pic, '0.75 0.75 0', '0.25 0.25 0', theColor, theAlpha, 0);
+                       }
                }
        }
-}
 
-void drawstringright(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
-{
-       position.x -= 2 / 3 * strlen(text) * theScale.x;
-       drawstring(position, text, theScale, rgb, theAlpha, flag);
-}
+       void drawstringright(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
+       {
+               position.x -= 2 / 3 * strlen(text) * theScale.x;
+               drawstring(position, text, theScale, rgb, theAlpha, flag);
+       }
 
-void drawstringcenter(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
-{
-       position.x = 0.5 * (vid_conwidth - 0.6025 * strlen(text) * theScale.x);
-       drawstring(position, text, theScale, rgb, theAlpha, flag);
-}
+       void drawstringcenter(vector position, string text, vector theScale, vector rgb, float theAlpha, int flag)
+       {
+               position.x = 0.5 * (vid_conwidth - 0.6025 * strlen(text) * theScale.x);
+               drawstring(position, text, theScale, rgb, theAlpha, flag);
+       }
 
 #endif
 #endif
index f732bfe2c1c53e3d2922a6b3e744cf5c30148ef8..87d1460250a1c007b5ebe0c23103208093fbc8cf 100644 (file)
@@ -3,11 +3,10 @@
 
 bool fexists(string f)
 {
-    int fh = fopen(f, FILE_READ);
-    if (fh < 0)
-        return false;
-    fclose(fh);
-    return true;
+       int fh = fopen(f, FILE_READ);
+       if (fh < 0) return false;
+       fclose(fh);
+       return true;
 }
 
 #endif
index 2bbe7d59dfe3a664aa5a641095d89112b9e177d1..237492d90056fd54da37f3aeae91796bc9b1d0b2 100644 (file)
@@ -3,24 +3,24 @@
 
 #define MAP(f, ...) EVAL(OVERLOAD(MAP, f, __VA_ARGS__))
 #define MAP_2(f, it) f(it)
-#define MAP_3(f, it, ...) f(it)MAP_2(f, __VA_ARGS__)
-#define MAP_4(f, it, ...) f(it)MAP_3(f, __VA_ARGS__)
-#define MAP_5(f, it, ...) f(it)MAP_4(f, __VA_ARGS__)
-#define MAP_6(f, it, ...) f(it)MAP_5(f, __VA_ARGS__)
-#define MAP_7(f, it, ...) f(it)MAP_6(f, __VA_ARGS__)
-#define MAP_8(f, it, ...) f(it)MAP_7(f, __VA_ARGS__)
-#define MAP_9(f, it, ...) f(it)MAP_8(f, __VA_ARGS__)
-#define MAP_10(f, it, ...) f(it)MAP_9(f, __VA_ARGS__)
-#define MAP_11(f, it, ...) f(it)MAP_10(f, __VA_ARGS__)
-#define MAP_12(f, it, ...) f(it)MAP_11(f, __VA_ARGS__)
-#define MAP_13(f, it, ...) f(it)MAP_12(f, __VA_ARGS__)
-#define MAP_14(f, it, ...) f(it)MAP_13(f, __VA_ARGS__)
-#define MAP_15(f, it, ...) f(it)MAP_14(f, __VA_ARGS__)
-#define MAP_16(f, it, ...) f(it)MAP_15(f, __VA_ARGS__)
-#define MAP_17(f, it, ...) f(it)MAP_16(f, __VA_ARGS__)
-#define MAP_18(f, it, ...) f(it)MAP_17(f, __VA_ARGS__)
-#define MAP_19(f, it, ...) f(it)MAP_18(f, __VA_ARGS__)
-#define MAP_20(f, it, ...) f(it)MAP_19(f, __VA_ARGS__)
+#define MAP_3(f, it, ...) f(it) MAP_2(f, __VA_ARGS__)
+#define MAP_4(f, it, ...) f(it) MAP_3(f, __VA_ARGS__)
+#define MAP_5(f, it, ...) f(it) MAP_4(f, __VA_ARGS__)
+#define MAP_6(f, it, ...) f(it) MAP_5(f, __VA_ARGS__)
+#define MAP_7(f, it, ...) f(it) MAP_6(f, __VA_ARGS__)
+#define MAP_8(f, it, ...) f(it) MAP_7(f, __VA_ARGS__)
+#define MAP_9(f, it, ...) f(it) MAP_8(f, __VA_ARGS__)
+#define MAP_10(f, it, ...) f(it) MAP_9(f, __VA_ARGS__)
+#define MAP_11(f, it, ...) f(it) MAP_10(f, __VA_ARGS__)
+#define MAP_12(f, it, ...) f(it) MAP_11(f, __VA_ARGS__)
+#define MAP_13(f, it, ...) f(it) MAP_12(f, __VA_ARGS__)
+#define MAP_14(f, it, ...) f(it) MAP_13(f, __VA_ARGS__)
+#define MAP_15(f, it, ...) f(it) MAP_14(f, __VA_ARGS__)
+#define MAP_16(f, it, ...) f(it) MAP_15(f, __VA_ARGS__)
+#define MAP_17(f, it, ...) f(it) MAP_16(f, __VA_ARGS__)
+#define MAP_18(f, it, ...) f(it) MAP_17(f, __VA_ARGS__)
+#define MAP_19(f, it, ...) f(it) MAP_18(f, __VA_ARGS__)
+#define MAP_20(f, it, ...) f(it) MAP_19(f, __VA_ARGS__)
 
 #define IDENTITY(it) it
 
 #define APPLY(f, ...) f(__VA_ARGS__)
 
 #ifdef SVQC
-    #define SV(f, ...) f(__VA_ARGS__)
+       #define SV(f, ...) f(__VA_ARGS__)
 #else
-    #define SV(f, ...)
+       #define SV(f, ...)
 #endif
 
 #ifdef CSQC
-    #define CL(f, ...) f(__VA_ARGS__)
+       #define CL(f, ...) f(__VA_ARGS__)
 #else
-    #define CL(f, ...)
+       #define CL(f, ...)
 #endif
 
 #define IF(cond, f, ...) cond(f, __VA_ARGS__)
index 87c41cda5dc209f228c1dc15481340acc817fab7..3773e16d1d2fdde2c904f6ac37812aab2d5a08a2 100644 (file)
@@ -8,25 +8,23 @@ string prvm_language;
 
 string language_filename(string s)
 {
-    string fn = prvm_language;
-    if (fn == "" || fn == "dump")
-        return s;
-    fn = strcat(s, ".", fn);
-    int fh = fopen(fn, FILE_READ);
-    if (fh >= 0)
-    {
-        fclose(fh);
-        return fn;
-    }
-    return s;
+       string fn = prvm_language;
+       if (fn == "" || fn == "dump") return s;
+       fn = strcat(s, ".", fn);
+       int fh = fopen(fn, FILE_READ);
+       if (fh >= 0)
+       {
+               fclose(fh);
+               return fn;
+       }
+       return s;
 }
 
 string CTX(string s)
 {
-    int p = strstrofs(s, "^", 0);
-    if (p < 0)
-        return s;
-    return substring(s, p + 1, -1);
+       int p = strstrofs(s, "^", 0);
+       if (p < 0) return s;
+       return substring(s, p + 1, -1);
 }
 
 #define ZCTX(s) strzone(CTX(s))
index d9ea61f0c8f3be1f76c368f4119b22a081a71d9a..9bd129b9e1f726fc27a4b05b393abd62a269427a 100644 (file)
@@ -2,13 +2,13 @@
 #define INT_H
 
 #ifndef QCC_SUPPORT_INT
-    #define stoi(s) stof(s)
-    #define stob(s) stof(s)
-    #define itos(i) ftos(i)
+       #define stoi(s) stof(s)
+       #define stob(s) stof(s)
+       #define itos(i) ftos(i)
 #else
-    #define stoi(s) ((int) stof(s))
-    #define stob(s) ((bool) stof(s))
-    #define itos(i) ftos(i)
+       #define stoi(s) ((int) stof(s))
+       #define stob(s) ((bool) stof(s))
+       #define itos(i) ftos(i)
 #endif
 
 #endif
index 53b3d662992f23668fc77be6e45a4cb91a0422d2..f3214a24865afe3af5ca5c3554777be9dacb122b 100644 (file)
@@ -1,19 +1,40 @@
 #ifndef ITER_H
 #define ITER_H
 
-#define FOREACH_ARRAY(arr, start, end, cond, body) do { \
-    for (int i = start; i < end; ++i) {                 \
-        const noref entity it = arr[i];                 \
-        if (cond) { body }                              \
-    }                                                   \
-} while(0)
+#define FOREACH_ARRAY(arr, start, end, cond, body) \
+       do \
+       { \
+               for (int i = start; i < end; ++i) \
+               { \
+                       const noref entity it = arr[i]; \
+                       if (cond) { body } \
+               } \
+       } \
+       while (0)
 
-#define FOREACH_LIST(list, next, cond, body) do {               \
-    noref int i = 0;                                            \
-    for (entity it = list##_first; it; (it = it.next, ++i)) {   \
-        if (cond) { body }                                      \
-    }                                                           \
-} while(0)
+#define FOREACH_LIST(list, next, cond, body) \
+       do \
+       { \
+               int i = 0; \
+               for (entity it = list##_first; it; (it = it.next, ++i)) \
+               { \
+                       if (cond) { body } \
+               } \
+       } \
+       while (0)
+
+#define FOREACH_WORD(words, cond, body) \
+       do \
+       { \
+               string _words = words; \
+               int i = 0; \
+               for (string _it; (_it = car(_words)); (_words = cdr(_words), ++i)) \
+               { \
+                       const noref string it = _it; \
+                       if (cond) { body } \
+               } \
+       } \
+       while (0)
 
 #define FOREACH(list, cond, body) FOREACH_LIST(list, enemy, cond, body)
 
index f632b38c32be69e446ba3a34e1183352bb27430b..5e0329bd206c21e4c94881bd8e947fea7afc51b2 100644 (file)
@@ -4,15 +4,19 @@
 #include "oo.qh"
 
 CLASS(Lazy, Object)
-    ATTRIB(Lazy, m_get, entity(), func_null);
-    CONSTRUCTOR(Lazy, entity() _compute) { this.m_get = _compute; }
+       ATTRIB(Lazy, m_get, entity(), func_null);
+       CONSTRUCTOR(Lazy, entity() _compute)
+       {
+               this.m_get = _compute;
+       }
 ENDCLASS(Lazy)
 
 #define LAZY(id) __lazy_##id
-#define LAZY_NEW(id, compute) entity LAZY(id)() { \
-    static bool done; \
-    static entity it; \
-    if (!done) { it = compute; done = true; } \
-    return it; \
-}
+#define LAZY_NEW(id, compute) \
+       entity LAZY(id)() { \
+               static bool done; \
+               static entity it; \
+               if (!done) { it = compute; done = true; } \
+               return it; \
+       }
 #endif
index be57bb5bf9c890b6b5abd90f6cdcd701ed93a2e4..2d07527c87169fb7fd3422fb922f48c9eb68fbdf 100644 (file)
@@ -2,14 +2,14 @@
 #define LINKEDLIST_H
 
 CLASS(LinkedListNode, Object)
-    ATTRIB(LinkedListNode, ll_data, entity, NULL)
-    ATTRIB(LinkedListNode, ll_prev, LinkedListNode, NULL)
-    ATTRIB(LinkedListNode, ll_next, LinkedListNode, NULL)
+       ATTRIB(LinkedListNode, ll_data, entity, NULL)
+       ATTRIB(LinkedListNode, ll_prev, LinkedListNode, NULL)
+       ATTRIB(LinkedListNode, ll_next, LinkedListNode, NULL)
 ENDCLASS(LinkedListNode)
 
 CLASS(LinkedList, Object)
-    ATTRIB(LinkedList, ll_head, LinkedListNode, NULL);
-    ATTRIB(LinkedList, ll_tail, LinkedListNode, NULL);
+       ATTRIB(LinkedList, ll_head, LinkedListNode, NULL);
+       ATTRIB(LinkedList, ll_tail, LinkedListNode, NULL);
 ENDCLASS(LinkedList)
 
 #define LL_NEW() NEW(LinkedList)
@@ -17,41 +17,39 @@ ENDCLASS(LinkedList)
 /**
  * Push to tail
  */
-entity LL_PUSH(LinkedList this, entity e) {
-    LinkedListNode n = NEW(LinkedListNode);
-    n.ll_data = e;
-    n.ll_prev = this.ll_tail;
-    LinkedListNode tail = this.ll_tail;
-    if (tail) {
-        tail.ll_next = n;
-    } else {
-        this.ll_head = this.ll_tail = n;
-    }
-    return e;
+entity LL_PUSH(LinkedList this, entity e)
+{
+       LinkedListNode n = NEW(LinkedListNode);
+       n.ll_data = e;
+       LinkedListNode tail = n.ll_prev = this.ll_tail;
+       this.ll_tail = (tail) ? tail.ll_next = n : this.ll_head = n;
+       return e;
 }
 
 /**
  * Pop from tail
  */
-entity LL_POP(LinkedList this) {
-    if (!this.ll_tail) return NULL;
-    LinkedListNode n = this.ll_tail;
-    entity e = n.ll_data;
-    LinkedListNode prev = n.ll_prev;
-    if (prev) {
-        prev.ll_next = NULL;
-    } else {
-        this.ll_head = this.ll_tail = NULL;
-    }
-    return e;
+entity LL_POP(LinkedList this)
+{
+       if (!this.ll_tail) return NULL;
+       LinkedListNode n = this.ll_tail;
+       entity e = n.ll_data;
+       LinkedListNode prev = n.ll_prev;
+       if (prev) prev.ll_next = NULL;
+       else this.ll_head = this.ll_tail = NULL;
+       return e;
 }
 
-#define LL_EACH(list, cond, body) do {                                  \
-    noref int i = 0;                                                    \
-    for (entity _it = list.ll_head; _it; (_it = _it.ll_next, ++i)) {    \
-        noref entity it = _it.ll_data;                                  \
-        if (cond) { body }                                              \
-    }                                                                   \
-} while(0)
+#define LL_EACH(list, cond, body) \
+       do                                                                  \
+       {                                                                   \
+               noref int i = 0;                                                \
+               for (entity _it = list.ll_head; _it; (_it = _it.ll_next, ++i))  \
+               {                                                               \
+                       noref entity it = _it.ll_data;                              \
+                       if (cond) { body }                                          \
+               }                                                               \
+       }                                                                   \
+       while (0)
 
 #endif
index 3d186e38945ea267fe4fac3456aa1f3c690eb6de..e24bd8f05def2f24d60af912fa645ad290ce82d3 100644 (file)
@@ -1,64 +1,94 @@
 #ifndef LOG_H
 #define LOG_H
 
-#define _printferr(...)     error(sprintf(__VA_ARGS__))
-#define _printfbt(...)      backtrace(sprintf(__VA_ARGS__))
-#define printf(...)         print(sprintf(__VA_ARGS__))
-#define dprintf(...)        dprint(sprintf(__VA_ARGS__))
-#define _dprintf2(...)      do { if (autocvar_developer > 1) dprintf(__VA_ARGS__); } while (0)
+#define _printferr(...) error(sprintf(__VA_ARGS__))
+#define _printfbt(...) backtrace(sprintf(__VA_ARGS__))
+#define printf(...) print(sprintf(__VA_ARGS__))
+#define dprintf(...) dprint(sprintf(__VA_ARGS__))
+#define _dprintf2(...) \
+       do \
+       { \
+               if (autocvar_developer > 1) dprintf(__VA_ARGS__); \
+       } \
+       while (0)
 
-#define assert(expr, ...)   do { if (!(expr)) LOG_WARNINGF(__VA_ARGS__); } while (0)
+#define assert(expr, ...) \
+       do \
+       { \
+               if (!(expr)) LOG_WARNINGF(__VA_ARGS__); \
+       } \
+       while (0)
 
-#define _LOG(f, level, s)   f("[::"level"] ["__FILE__":%s:%.0f] %s", __FUNC__, __LINE__, s)
+#define _LOG(f, level, s) f("[::"level "] ["__FILE__ ":%s:%.0f] %s", __FUNC__, __LINE__, s)
 
-#define  LOG_FATAL(...)     _LOG_FATAL(strcat("", __VA_ARGS__))
-#define  LOG_FATALF(...)    _LOG_FATAL(sprintf(__VA_ARGS__))
-#define _LOG_FATAL(s)       _LOG(_printferr, "FATAL", s)
+#define  LOG_FATAL(...) _LOG_FATAL(strcat("", __VA_ARGS__))
+#define  LOG_FATALF(...) _LOG_FATAL(sprintf(__VA_ARGS__))
+#define _LOG_FATAL(s) _LOG(_printferr, "FATAL", s)
 
-#define  LOG_SEVERE(...)    _LOG_SEVERE(strcat("", __VA_ARGS__))
-#define  LOG_SEVEREF(...)   _LOG_SEVERE(sprintf(__VA_ARGS__))
-#define _LOG_SEVERE(s)      _LOG(_printfbt, "SEVERE", s)
+#define  LOG_SEVERE(...) _LOG_SEVERE(strcat("", __VA_ARGS__))
+#define  LOG_SEVEREF(...) _LOG_SEVERE(sprintf(__VA_ARGS__))
+#define _LOG_SEVERE(s) _LOG(_printfbt, "SEVERE", s)
 
-#define  LOG_WARNING(...)   _LOG_WARNING(strcat("", __VA_ARGS__))
-#define  LOG_WARNINGF(...)  _LOG_WARNING(sprintf(__VA_ARGS__))
-#define _LOG_WARNING(s)     _LOG(printf, "WARNING", s)
+#define  LOG_WARNING(...) _LOG_WARNING(strcat("", __VA_ARGS__))
+#define  LOG_WARNINGF(...) _LOG_WARNING(sprintf(__VA_ARGS__))
+#define _LOG_WARNING(s) _LOG(printf, "WARNING", s)
 
-#define  LOG_INFO(...)      do { if (autocvar_developer) _LOG_INFO(strcat("", __VA_ARGS__)); else print (__VA_ARGS__); } while (0)
-#define  LOG_INFOF(...)     do { if (autocvar_developer) _LOG_INFO(sprintf(__VA_ARGS__));    else printf(__VA_ARGS__); } while (0)
-#define _LOG_INFO(s)        _LOG(printf, "INFO", s)
+#define  LOG_INFO(...) \
+       do \
+       { \
+               if (autocvar_developer) _LOG_INFO(strcat("", __VA_ARGS__)); \
+               else print(__VA_ARGS__); \
+       } \
+       while (0)
+#define  LOG_INFOF(...) \
+       do \
+       { \
+               if (autocvar_developer) _LOG_INFO(sprintf(__VA_ARGS__)); \
+               else printf(__VA_ARGS__); \
+       } \
+       while (0)
+#define _LOG_INFO(s) _LOG(printf, "INFO", s)
 
-#define  LOG_TRACE(...)     _LOG_TRACE(strcat("", __VA_ARGS__))
-#define  LOG_TRACEF(...)    _LOG_TRACE(sprintf(__VA_ARGS__))
-#define _LOG_TRACE(s)       _LOG(dprintf, "TRACE", s)
+#define  LOG_TRACE(...) _LOG_TRACE(strcat("", __VA_ARGS__))
+#define  LOG_TRACEF(...) _LOG_TRACE(sprintf(__VA_ARGS__))
+#define _LOG_TRACE(s) _LOG(dprintf, "TRACE", s)
 
-#define  LOG_DEBUG(...)     _LOG_DEBUG(strcat("", __VA_ARGS__))
-#define  LOG_DEBUGF(...)    _LOG_DEBUG(sprintf(__VA_ARGS__))
-#define _LOG_DEBUG(s)       _LOG(_dprintf2, "DEBUG", s)
+#define  LOG_DEBUG(...) _LOG_DEBUG(strcat("", __VA_ARGS__))
+#define  LOG_DEBUGF(...) _LOG_DEBUG(sprintf(__VA_ARGS__))
+#define _LOG_DEBUG(s) _LOG(_dprintf2, "DEBUG", s)
 
 // TODO: this sucks, lets find a better way to do backtraces?
 #ifdef SVQC
-void builtin_remove(entity);
-#define _backtrace() builtin_remove(NULL)
+       void builtin_remove(entity);
+       #define _backtrace() builtin_remove(NULL)
 #else
-void remove(entity);
-#define _backtrace() remove(NULL)
+       void remove(entity);
+       #define _backtrace() remove(NULL)
 #endif
 
 noref int autocvar_developer;
 noref bool autocvar_prvm_backtraceforwarnings;
 
-#define backtrace(msg) do { \
-    int dev = autocvar_developer; \
-    bool war = autocvar_prvm_backtraceforwarnings; \
-    cvar_set("developer", "1"); \
-    cvar_set("prvm_backtraceforwarnings", "1"); \
-    print("\n--- CUT HERE ---\n", msg, "\n"); \
-    _backtrace(); \
-    print("\n--- CUT UNTIL HERE ---\n"); \
-    cvar_set("developer", ftos(dev)); \
-    cvar_set("prvm_backtraceforwarnings", ftos(war)); \
-} while (0)
+#define backtrace(msg) \
+       do \
+       { \
+               int dev = autocvar_developer; \
+               bool war = autocvar_prvm_backtraceforwarnings; \
+               cvar_set("developer", "1"); \
+               cvar_set("prvm_backtraceforwarnings", "1"); \
+               print("\n--- CUT HERE ---\n", msg, "\n"); \
+               _backtrace(); \
+               print("\n--- CUT UNTIL HERE ---\n"); \
+               cvar_set("developer", ftos(dev)); \
+               cvar_set("prvm_backtraceforwarnings", ftos(war)); \
+       } \
+       while (0)
 
-#define ASSERT(expr) do { if (!(expr)) LOG_FATAL("assertion failed: " #expr "\n"); } while (0)
+#define ASSERT(expr) \
+       do \
+       { \
+               if (!(expr)) LOG_FATAL("assertion failed: " #expr "\n"); \
+       } \
+       while (0)
 
 #endif
diff --git a/qcsrc/lib/map.qc b/qcsrc/lib/map.qc
new file mode 100644 (file)
index 0000000..d71c263
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef MAP_H
+#define MAP_H
+
+// Databases (hash tables)
+const float DB_BUCKETS = 8192;
+void db_save(float db, string pFilename)
+{
+       int fh = fopen(pFilename, FILE_WRITE);
+       if (fh < 0)
+       {
+               LOG_INFO(strcat("^1Can't write DB to ", pFilename));
+               return;
+       }
+       int n = buf_getsize(db);
+       fputs(fh, strcat(ftos(DB_BUCKETS), "\n"));
+       for (int i = 0; i < n; ++i)
+               fputs(fh, strcat(bufstr_get(db, i), "\n"));
+       fclose(fh);
+}
+
+int db_create()
+{
+       return buf_create();
+}
+
+void db_put(float db, string pKey, string pValue);
+
+int db_load(string pFilename)
+{
+       int db = buf_create();
+       if (db < 0) return -1;
+       int fh = fopen(pFilename, FILE_READ);
+       if (fh < 0) return db;
+       string l = fgets(fh);
+       if (stof(l) == DB_BUCKETS)
+       {
+               for (int i = 0; (l = fgets(fh)); ++i)
+               {
+                       if (l != "") bufstr_set(db, i, l);
+               }
+       }
+       else
+       {
+               // different count of buckets, or a dump?
+               // need to reorganize the database then (SLOW)
+               //
+               // note: we also parse the first line (l) in case the DB file is
+               // missing the bucket count
+               do
+               {
+                       int n = tokenizebyseparator(l, "\\");
+                       for (int j = 2; j < n; j += 2)
+                               db_put(db, argv(j - 1), uri_unescape(argv(j)));
+               }
+               while ((l = fgets(fh)));
+       }
+       fclose(fh);
+       return db;
+}
+
+void db_dump(float db, string pFilename)
+{
+       int fh = fopen(pFilename, FILE_WRITE);
+       if (fh < 0) error(strcat("Can't dump DB to ", pFilename));
+       int n = buf_getsize(db);
+       fputs(fh, "0\n");
+       for (int i = 0; i < n; ++i)
+       {
+               int m = tokenizebyseparator(bufstr_get(db, i), "\\");
+               for (int j = 2; j < m; j += 2)
+                       fputs(fh, strcat("\\", argv(j - 1), "\\", argv(j), "\n"));
+       }
+       fclose(fh);
+}
+
+void db_close(float db)
+{
+       buf_del(db);
+}
+
+string db_get(float db, string pKey)
+{
+       int h = crc16(false, pKey) % DB_BUCKETS;
+       return uri_unescape(infoget(bufstr_get(db, h), pKey));
+}
+
+void db_put(float db, string pKey, string pValue)
+{
+       int h = crc16(false, pKey) % DB_BUCKETS;
+       bufstr_set(db, h, infoadd(bufstr_get(db, h), pKey, uri_escape(pValue)));
+}
+
+void db_test()
+{
+       LOG_INFO("LOAD...\n");
+       int db = db_load("foo.db");
+       LOG_INFO("LOADED. FILL...\n");
+       for (int i = 0; i < DB_BUCKETS; ++i)
+               db_put(db, ftos(random()), "X");
+       LOG_INFO("FILLED. SAVE...\n");
+       db_save(db, "foo.db");
+       LOG_INFO("SAVED. CLOSE...\n");
+       db_close(db);
+       LOG_INFO("CLOSED.\n");
+}
+
+#endif
index 1a707a435cfa6a28e7efc92521598fd036b74d97..a32e9b47c7bed891127f9da79479388d10c89541 100644 (file)
@@ -3,40 +3,25 @@
 
 void mean_accumulate(entity e, .float a, .float c, float mean, float value, float weight)
 {
-    if (weight == 0)
-        return;
-    if (mean == 0)
-        e.(a) *= pow(value, weight);
-    else
-        e.(a) += pow(value, mean) * weight;
-    e.(c) += weight;
+       if (weight == 0) return;
+       if (mean == 0) e.(a) *= pow(value, weight);
+       else e.(a) += pow(value, mean) * weight;
+       e.(c) += weight;
 }
 
 float mean_evaluate(entity e, .float a, .float c, float mean)
 {
-    if (e.(c) == 0)
-        return 0;
-    if (mean == 0)
-        return pow(e.(a), 1.0 / e.(c));
-    else
-        return pow(e.(a) / e.(c), 1.0 / mean);
+       if (e.(c) == 0) return 0;
+       if (mean == 0) return pow(e.(a), 1.0 / e.(c));
+       else return pow(e.(a) / e.(c), 1.0 / mean);
 }
 
-#define MEAN_ACCUMULATE(prefix,v,w) mean_accumulate(self,prefix##_accumulator,prefix##_count,prefix##_mean,v,w)
-#define MEAN_EVALUATE(prefix) mean_evaluate(self,prefix##_accumulator,prefix##_count,prefix##_mean)
-#define MEAN_DECLARE(prefix,m) float prefix##_mean = m; .float prefix##_count, prefix##_accumulator
+#define MEAN_ACCUMULATE(prefix, v, w) mean_accumulate(self, prefix##_accumulator, prefix##_count, prefix##_mean, v, w)
+#define MEAN_EVALUATE(prefix) mean_evaluate(self, prefix##_accumulator, prefix##_count, prefix##_mean)
+#define MEAN_DECLARE(prefix, m) float prefix##_mean = m; .float prefix##_count, prefix##_accumulator
 
-/*
-==================
-crandom
-
-Returns a random number between -1.0 and 1.0
-==================
-*/
-float crandom()
-{
-    return 2 * (random() - 0.5);
-}
+/** Returns a random number between -1.0 and 1.0 */
+#define crandom() (2 * (random() - 0.5))
 
 
 /*
@@ -48,236 +33,271 @@ Angc used for animations
 
 float angc(float a1, float a2)
 {
-    while (a1 > 180) a1 -= 360;
-    while (a1 < -179) a1 += 360;
-    while (a2 > 180) a2 -= 360;
-    while (a2 < -179) a2 += 360;
-    float a = a1 - a2;
-    while (a > 180) a -= 360;
-    while (a < -179) a += 360;
-    return a;
+       while (a1 > 180)
+               a1 -= 360;
+       while (a1 < -179)
+               a1 += 360;
+       while (a2 > 180)
+               a2 -= 360;
+       while (a2 < -179)
+               a2 += 360;
+       float a = a1 - a2;
+       while (a > 180)
+               a -= 360;
+       while (a < -179)
+               a += 360;
+       return a;
 }
 
-float fsnap(float val,float fsize)
+float fsnap(float val, float fsize)
 {
-    return rint(val / fsize) * fsize;
+       return rint(val / fsize) * fsize;
 }
 
-vector vsnap(vector point,float fsize)
+vector vsnap(vector point, float fsize)
 {
-    vector vret;
+       vector vret;
 
-    vret.x = rint(point.x / fsize) * fsize;
-    vret.y = rint(point.y / fsize) * fsize;
-    vret.z = ceil(point.z / fsize) * fsize;
+       vret.x = rint(point.x / fsize) * fsize;
+       vret.y = rint(point.y / fsize) * fsize;
+       vret.z = ceil(point.z / fsize) * fsize;
 
-    return vret;
+       return vret;
 }
 
 vector lerpv(float t0, vector v0, float t1, vector v1, float t)
 {
-    return v0 + (v1 - v0) * ((t - t0) / (t1 - t0));
+       return v0 + (v1 - v0) * ((t - t0) / (t1 - t0));
 }
 
 vector bezier_quadratic_getpoint(vector a, vector b, vector c, float t)
 {
-    return
-        (c - 2 * b + a) * (t * t) +
-        (b - a) * (2 * t) +
-        a;
+       return (c - 2 * b + a) * (t * t)
+              + (b - a) * (2 * t)
+              + a;
 }
 
 vector bezier_quadratic_getderivative(vector a, vector b, vector c, float t)
 {
-    return
-        (c - 2 * b + a) * (2 * t) +
-        (b - a) * 2;
+       return (c - 2 * b + a) * (2 * t)
+              + (b - a) * 2;
 }
 
 float cubic_speedfunc(float startspeedfactor, float endspeedfactor, float x)
 {
-    return
-        (((     startspeedfactor + endspeedfactor - 2
-        ) * x - 2 * startspeedfactor - endspeedfactor + 3
-        ) * x + startspeedfactor
-        ) * x;
+       return (((startspeedfactor + endspeedfactor - 2
+                ) * x - 2 * startspeedfactor - endspeedfactor + 3
+               ) * x + startspeedfactor
+              ) * x;
 }
 
 bool cubic_speedfunc_is_sane(float startspeedfactor, float endspeedfactor)
 {
-    if (startspeedfactor < 0 || endspeedfactor < 0)
-        return false;
-
-    /*
-    // if this is the case, the possible zeros of the first derivative are outside
-    // 0..1
-    We can calculate this condition as condition
-    if(se <= 3)
-        return true;
-    */
-
-    // better, see below:
-    if (startspeedfactor <= 3 && endspeedfactor <= 3)
-        return true;
-
-    // if this is the case, the first derivative has no zeros at all
-    float se = startspeedfactor + endspeedfactor;
-    float s_e = startspeedfactor - endspeedfactor;
-    if (3 * (se - 4) * (se - 4) + s_e * s_e <= 12) // an ellipse
-        return true;
-
-    // Now let s <= 3, s <= 3, s+e >= 3 (triangle) then we get se <= 6 (top right corner).
-    // we also get s_e <= 6 - se
-    // 3 * (se - 4)^2 + (6 - se)^2
-    // is quadratic, has value 12 at 3 and 6, and value < 12 in between.
-    // Therefore, above "better" check works!
-
-    return false;
-
-    // known good cases:
-    // (0, [0..3])
-    // (0.5, [0..3.8])
-    // (1, [0..4])
-    // (1.5, [0..3.9])
-    // (2, [0..3.7])
-    // (2.5, [0..3.4])
-    // (3, [0..3])
-    // (3.5, [0.2..2.3])
-    // (4, 1)
-
-    /*
-       On another note:
-       inflection point is always at (2s + e - 3) / (3s + 3e - 6).
-
-       s + e - 2 == 0: no inflection
-
-       s + e > 2:
-       0 < inflection < 1 if:
-       0 < 2s + e - 3 < 3s + 3e - 6
-       2s + e > 3 and 2e + s > 3
-
-       s + e < 2:
-       0 < inflection < 1 if:
-       0 > 2s + e - 3 > 3s + 3e - 6
-       2s + e < 3 and 2e + s < 3
-
-       Therefore: there is an inflection point iff:
-       e outside (3 - s)/2 .. 3 - s*2
-
-       in other words, if (s,e) in triangle (1,1)(0,3)(0,1.5) or in triangle (1,1)(3,0)(1.5,0)
-    */
+       if (startspeedfactor < 0 || endspeedfactor < 0) return false;
+
+       /*
+       // if this is the case, the possible zeros of the first derivative are outside
+       // 0..1
+       We can calculate this condition as condition
+       if(se <= 3)
+           return true;
+       */
+
+       // better, see below:
+       if (startspeedfactor <= 3 && endspeedfactor <= 3) return true;
+
+       // if this is the case, the first derivative has no zeros at all
+       float se = startspeedfactor + endspeedfactor;
+       float s_e = startspeedfactor - endspeedfactor;
+       if (3 * (se - 4) * (se - 4) + s_e * s_e <= 12)  // an ellipse
+               return true;
+
+       // Now let s <= 3, s <= 3, s+e >= 3 (triangle) then we get se <= 6 (top right corner).
+       // we also get s_e <= 6 - se
+       // 3 * (se - 4)^2 + (6 - se)^2
+       // is quadratic, has value 12 at 3 and 6, and value < 12 in between.
+       // Therefore, above "better" check works!
+
+       return false;
+
+       // known good cases:
+       // (0, [0..3])
+       // (0.5, [0..3.8])
+       // (1, [0..4])
+       // (1.5, [0..3.9])
+       // (2, [0..3.7])
+       // (2.5, [0..3.4])
+       // (3, [0..3])
+       // (3.5, [0.2..2.3])
+       // (4, 1)
+
+       /*
+          On another note:
+          inflection point is always at (2s + e - 3) / (3s + 3e - 6).
+
+          s + e - 2 == 0: no inflection
+
+          s + e > 2:
+          0 < inflection < 1 if:
+          0 < 2s + e - 3 < 3s + 3e - 6
+          2s + e > 3 and 2e + s > 3
+
+          s + e < 2:
+          0 < inflection < 1 if:
+          0 > 2s + e - 3 > 3s + 3e - 6
+          2s + e < 3 and 2e + s < 3
+
+          Therefore: there is an inflection point iff:
+          e outside (3 - s)/2 .. 3 - s*2
+
+          in other words, if (s,e) in triangle (1,1)(0,3)(0,1.5) or in triangle (1,1)(3,0)(1.5,0)
+       */
 }
 
 /** continuous function mapping all reals into -1..1 */
 float float2range11(float f)
 {
-    return f / (fabs(f) + 1);
+       return f / (fabs(f) + 1);
 }
 
 /** continuous function mapping all reals into 0..1 */
 float float2range01(float f)
 {
-    return 0.5 + 0.5 * float2range11(f);
+       return 0.5 + 0.5 * float2range11(f);
 }
 
 float median(float a, float b, float c)
 {
-    return (a < c) ? bound(a, b, c) : bound(c, b, a);
+       return (a < c) ? bound(a, b, c) : bound(c, b, a);
 }
 
 float almost_equals(float a, float b)
 {
-    float eps = (max(a, -a) + max(b, -b)) * 0.001;
-    return a - b < eps && b - a < eps;
+       float eps = (max(a, -a) + max(b, -b)) * 0.001;
+       return a - b < eps && b - a < eps;
 }
 
 float almost_in_bounds(float a, float b, float c)
 {
-    float eps = (max(a, -a) + max(c, -c)) * 0.001;
-    if (a > c)
-        eps = -eps;
-    return b == median(a - eps, b, c + eps);
+       float eps = (max(a, -a) + max(c, -c)) * 0.001;
+       if (a > c) eps = -eps;
+       return b == median(a - eps, b, c + eps);
+}
+
+float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
+{
+       if (halflifedist > 0) return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
+       else if (halflifedist < 0) return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
+       else return 1;
 }
 
 float power2of(float e)
 {
-    return pow(2, e);
+       return pow(2, e);
 }
 
 float log2of(float x)
 {
-    // NOTE: generated code
-    if (x > 2048)
-        if (x > 131072)
-            if (x > 1048576)
-                if (x > 4194304)
-                    return 23;
-                else
-                    if (x > 2097152)
-                        return 22;
-                    else
-                        return 21;
-            else
-                if (x > 524288)
-                    return 20;
-                else
-                    if (x > 262144)
-                        return 19;
-                    else
-                        return 18;
-        else
-            if (x > 16384)
-                if (x > 65536)
-                    return 17;
-                else
-                    if (x > 32768)
-                        return 16;
-                    else
-                        return 15;
-            else
-                if (x > 8192)
-                    return 14;
-                else
-                    if (x > 4096)
-                        return 13;
-                    else
-                        return 12;
-    else
-        if (x > 32)
-            if (x > 256)
-                if (x > 1024)
-                    return 11;
-                else
-                    if (x > 512)
-                        return 10;
-                    else
-                        return 9;
-            else
-                if (x > 128)
-                    return 8;
-                else
-                    if (x > 64)
-                        return 7;
-                    else
-                        return 6;
-        else
-            if (x > 4)
-                if (x > 16)
-                    return 5;
-                else
-                    if (x > 8)
-                        return 4;
-                    else
-                        return 3;
-            else
-                if (x > 2)
-                    return 2;
-                else
-                    if (x > 1)
-                        return 1;
-                    else
-                        return 0;
+       // NOTE: generated code
+       if (x > 2048)
+               if (x > 131072)
+                       if (x > 1048576)
+                               if (x > 4194304) return 23;
+                               else
+                                       if (x > 2097152) return 22;
+                                       else return 21;
+                       else
+                               if (x > 524288) return 20;
+                               else
+                                       if (x > 262144) return 19;
+                                       else return 18;
+               else
+                       if (x > 16384)
+                               if (x > 65536) return 17;
+                               else
+                                       if (x > 32768) return 16;
+                                       else return 15;
+                       else
+                               if (x > 8192) return 14;
+                               else
+                                       if (x > 4096) return 13;
+                                       else return 12;
+       else
+               if (x > 32)
+                       if (x > 256)
+                               if (x > 1024) return 11;
+                               else
+                                       if (x > 512) return 10;
+                                       else return 9;
+                       else
+                               if (x > 128) return 8;
+                               else
+                                       if (x > 64) return 7;
+                                       else return 6;
+               else
+                       if (x > 4)
+                               if (x > 16) return 5;
+                               else
+                                       if (x > 8) return 4;
+                                       else return 3;
+                       else
+                               if (x > 2) return 2;
+                               else
+                                       if (x > 1) return 1;
+                                       else return 0;
 }
 
+/** ax^2 + bx + c = 0 */
+vector solve_quadratic(float a, float b, float c)
+{
+       vector v;
+       float D;
+       v = '0 0 0';
+       if (a == 0)
+       {
+               if (b != 0)
+               {
+                       v.x = v.y = -c / b;
+                       v.z = 1;
+               }
+               else
+               {
+                       if (c == 0)
+                       {
+                               // actually, every number solves the equation!
+                               v.z = 1;
+                       }
+               }
+       }
+       else
+       {
+               D = b * b - 4 * a * c;
+               if (D >= 0)
+               {
+                       D = sqrt(D);
+                       if (a > 0)  // put the smaller solution first
+                       {
+                               v.x = ((-b) - D) / (2 * a);
+                               v.y = ((-b) + D) / (2 * a);
+                       }
+                       else
+                       {
+                               v.x = (-b + D) / (2 * a);
+                               v.y = (-b - D) / (2 * a);
+                       }
+                       v.z = 1;
+               }
+               else
+               {
+                       // complex solutions!
+                       D = sqrt(-D);
+                       v.x = -b / (2 * a);
+                       if (a > 0) v.y =  D / (2 * a);
+                       else v.y = -D / (2 * a);
+                       v.z = 0;
+               }
+       }
+       return v;
+}
 
 #endif
index 8a6e117a774d30ca00ada81cc6ea8caf770d1672..e0ac0a478074b6778ab39b34ecf4e069e8c2d979 100644 (file)
@@ -2,38 +2,55 @@
 #define MISC_H
 
 #ifdef GMQCC
-    #define EVAL(...)           __VA_ARGS__
+       #define EVAL(...) __VA_ARGS__
 
-    #define OVERLOAD_(F, ...)   F##_##__VA_COUNT__(__VA_ARGS__)
-    #define OVERLOAD(F, ...)    F##_##__VA_COUNT__(__VA_ARGS__)
+       #define OVERLOAD_(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
+       #define OVERLOAD(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
 #else
-    #define EMPTY()
-    #define DEFER(id) id EMPTY()
-
-    #define EVAL(...)  EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
-    #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
-    #define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
-    #define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
-    #define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
-    #define EVAL5(...) __VA_ARGS__
-
-    #define OVERLOAD___(F,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,n,...) F##_##n
-    #define OVERLOAD__(F, ...)  OVERLOAD___(F,##__VA_ARGS__,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
-    #define OVERLOAD_(...)      DEFER(OVERLOAD__(__VA_ARGS__))
-    #define OVERLOAD(F, ...)    OVERLOAD_(F,##__VA_ARGS__)(__VA_ARGS__)
+       #define EMPTY()
+       #define DEFER(id) id EMPTY()
+
+       #define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
+       #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
+       #define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
+       #define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
+       #define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
+       #define EVAL5(...) __VA_ARGS__
+
+       #define OVERLOAD___(F, _16, _15, _14, _13, _12, _11, _10, _9, _8, _7, _6, _5, _4, _3, _2, _1, n, ...) F##_##n
+       #define OVERLOAD__(F, ...) OVERLOAD___(F,##__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
+       #define OVERLOAD_(...) DEFER(OVERLOAD__(__VA_ARGS__))
+       #define OVERLOAD(F, ...) OVERLOAD_(F,##__VA_ARGS__)(__VA_ARGS__)
 #endif
 
-#define GET(name) name##get
-#define GETTER(type, name) type GET(name)() { return name; }
+#if defined(CSQC)
+       #define etof(e) num_for_edict(e)
+       #define ftoe(i) entitybyindex(i)
+#elif defined(SVQC)
+       #define etof(e) num_for_edict(e)
+       #define ftoe(i) edict_num(i)
+#elif defined(MENUQC)
+       // already defined
+#endif
 
-#define LAMBDA(...) { __VA_ARGS__ ; }
+#undef etof
+// avoid bounds checks
+#define etof(e) stof(sprintf("%i", e))
 
-// Can't wrap with do-while as block may contain continue or break
-#define WITH(type, name, value, block) { \
-    type __with_save = (name); \
-    name = (value); \
-    LAMBDA(block) \
-    name = __with_save; \
-} do { } while (0)
+#define GET(name) name##get
+#define GETTER(type, name) type GET(name)() { return name; }
+#define PROPERTY(type, name) type name; GETTER(type, name)
+#define LAMBDA(...) { __VA_ARGS__; }
+
+// With block may not contain continue or break
+#define WITH(type, name, value, block) \
+       do \
+       { \
+               type __with_save = (name); \
+               name = (value); \
+               LAMBDA(block) \
+               name = __with_save; \
+       } \
+       while (0)
 
 #endif
index 834de760f503e8a2739b3b3bcda3b448bc811566..3daa1cede585acd12b5d982afa396635e03d2281 100644 (file)
@@ -2,52 +2,53 @@
 #define NET_H
 
 #ifdef SVQC
-.int Version; // deprecated, use SendFlags
-.int SendFlags;
-.bool(entity to, int sendflags) SendEntity;
-.bool(entity this, entity to, int sendflags) SendEntity3;
+       .int Version;  // deprecated, use SendFlags
+       .int SendFlags;
+       .bool(entity to, int sendflags) SendEntity;
+       .bool(entity this, entity to, int sendflags) SendEntity3;
 
-bool SendEntity_self(entity to, int sendflags) { return self.SendEntity3(self, to, sendflags); }
+       bool SendEntity_self(entity to, int sendflags) { return self.SendEntity3(self, to, sendflags); }
 
-void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
-{
-    if (e.classname == "") e.classname = "net_linked";
+       void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
+       {
+               if (e.classname == "") e.classname = "net_linked";
 
-    if (e.model == "" || self.modelindex == 0) {
-        vector mi = e.mins;
-        vector ma = e.maxs;
-        _setmodel(e, "null");
-        setsize(e, mi, ma);
-    }
+               if (e.model == "" || self.modelindex == 0)
+               {
+                       vector mi = e.mins;
+                       vector ma = e.maxs;
+                       _setmodel(e, "null");
+                       setsize(e, mi, ma);
+               }
 
-    e.SendEntity = SendEntity_self;
-    e.SendEntity3 = sendfunc;
-    e.SendFlags = 0xFFFFFF;
+               e.SendEntity = SendEntity_self;
+               e.SendEntity3 = sendfunc;
+               e.SendFlags = 0xFFFFFF;
 
-    if (!docull) e.effects |= EF_NODEPTHTEST;
+               if (!docull) e.effects |= EF_NODEPTHTEST;
 
-    if (dt) {
-        e.nextthink = time + dt;
-        e.think = SUB_Remove;
-    }
-}
+               if (dt)
+               {
+                       e.nextthink = time + dt;
+                       e.think = SUB_Remove;
+               }
+       }
 
-.void() uncustomizeentityforclient;
-.float uncustomizeentityforclient_set;
+       .void() uncustomizeentityforclient;
+       .float uncustomizeentityforclient_set;
 
-void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
-{
-    e.customizeentityforclient = customizer;
-    e.uncustomizeentityforclient = uncustomizer;
-    e.uncustomizeentityforclient_set = !!uncustomizer;
-}
+       void SetCustomizer(entity e, float() customizer, void() uncustomizer)
+       {
+               e.customizeentityforclient = customizer;
+               e.uncustomizeentityforclient = uncustomizer;
+               e.uncustomizeentityforclient_set = !!uncustomizer;
+       }
 
-void UncustomizeEntitiesRun()
-{
-    for (entity e = NULL; (e = findfloat(e, uncustomizeentityforclient_set, 1)); ) {
-        WITH(entity, self, e, e.uncustomizeentityforclient());
-    }
-}
+       void UncustomizeEntitiesRun()
+       {
+               for (entity e = NULL; (e = findfloat(e, uncustomizeentityforclient_set, 1)); )
+                       WITH(entity, self, e, e.uncustomizeentityforclient());
+       }
 
 #endif
 
@@ -56,111 +57,211 @@ void UncustomizeEntitiesRun()
 
 .string netname;
 .int m_id;
-.void(entity this, bool isNew) m_read;
+.bool(entity this, bool isNew) m_read;
 
 #ifdef CSQC
-    #define Net_Accept() do { if (!this)    this = spawn(); } while (0)
-    #define Net_Reject() do { if (this)     remove(this);   } while (0)
+       #define Net_Accept(classname) \
+               do \
+               { \
+                       if (!this)    this = new(classname); \
+               } \
+               while (0)
+       #define Net_Reject() \
+               do \
+               { \
+                       if (this)     remove(this); \
+               } \
+               while (0)
+       #define NET_HANDLE(id, param) \
+               bool Net_Handle_##id(entity this, param)
 #else
-    #define WriteHeader(to, id) do { \
-        if (NET_##id##_istemp) WriteByte(to, SVC_TEMPENTITY); \
-        WriteByte(to, NET_##id.m_id); \
-    } while (0)
+       #define WriteHeader(to, id) \
+               do \
+               { \
+                       if (NET_##id##_istemp) WriteByte(to, SVC_TEMPENTITY); \
+                       WriteByte(to, NET_##id.m_id); \
+               } \
+               while (0)
 #endif
 
 #ifdef CSQC
-    #define REGISTER_NET_LINKED(id, param) \
-        void Ent_Read##id(entity this, param) { this = self; } \
-        REGISTER(RegisterLinkedEntities, NET, LinkedEntities, id, m_id, spawn()) { \
-            this.netname = #id; \
-            this.m_read = Ent_Read##id; \
-        } \
-        [[accumulate]] void Ent_Read##id(entity this, param)
+       #define REGISTER_NET_LINKED(id) \
+               [[accumulate]] NET_HANDLE(id, bool) \
+               { \
+                       this = self; \
+                       this.sourceLocFile = __FILE__; \
+                       this.sourceLocLine = __LINE__; \
+               } \
+               REGISTER(LinkedEntities, NET, id, m_id, new(net_linked_packet)) \
+               { \
+                       make_pure(this); \
+                       this.netname = #id; \
+                       this.m_read = Net_Handle_##id; \
+               }
 #else
-    #define REGISTER_NET_LINKED(id, param) \
-        const bool NET_##id##_istemp = false; \
-        REGISTER(RegisterLinkedEntities, NET, LinkedEntities, id, m_id, spawn()) { \
-            this.netname = #id; \
-        }
+       #define REGISTER_NET_LINKED(id) \
+               const bool NET_##id##_istemp = false; \
+               REGISTER(LinkedEntities, NET, id, m_id, new(net_linked_packet)) \
+               { \
+                       make_pure(this); \
+                       this.netname = #id; \
+               }
 #endif
 
-REGISTRY(LinkedEntities, BIT(0))
-REGISTER_REGISTRY(RegisterLinkedEntities)
-REGISTRY_SORT(LinkedEntities, netname, 0)
-STATIC_INIT(RegisterLinkedEntities_renumber) {
-    for (int i = 0; i < LinkedEntities_COUNT; ++i) {
-        LinkedEntities[i].m_id = 100 + i;
-    }
+REGISTRY(LinkedEntities, BITS(8) - 1)
+#define LinkedEntities_from(i) _LinkedEntities_from(i, NULL)
+REGISTER_REGISTRY(LinkedEntities)
+REGISTRY_SORT(LinkedEntities, 0)
+REGISTRY_CHECK(LinkedEntities)
+STATIC_INIT(RegisterLinkedEntities_renumber)
+{
+       for (int i = 0; i < LinkedEntities_COUNT; ++i)
+               LinkedEntities_from(i).m_id = 1 + i;
 }
 
 #ifdef CSQC
-    #define REGISTER_NET_TEMP(id, param) \
-        void Net_Read##id(entity this, param); \
-        REGISTER(RegisterTempEntities, NET, TempEntities, id, m_id, spawn()) { \
-            this.netname = #id; \
-            this.m_read = Net_Read##id; \
-        } \
-        void Net_Read##id(entity this, param)
+       #define REGISTER_NET_TEMP(id) \
+               NET_HANDLE(id, bool); \
+               REGISTER(TempEntities, NET, id, m_id, new(net_temp_packet)) \
+               { \
+                       make_pure(this); \
+                       this.netname = #id; \
+                       this.m_read = Net_Handle_##id; \
+               }
 #else
-    #define REGISTER_NET_TEMP(id, param) \
-        const bool NET_##id##_istemp = true; \
-        REGISTER(RegisterTempEntities, NET, TempEntities, id, m_id, spawn()) { \
-            this.netname = #id; \
-        }
+       #define REGISTER_NET_TEMP(id) \
+               const bool NET_##id##_istemp = true; \
+               REGISTER(TempEntities, NET, id, m_id, new(net_temp_packet)) \
+               { \
+                       make_pure(this); \
+                       this.netname = #id; \
+               }
 #endif
 
-REGISTRY(TempEntities, BIT(0))
-REGISTER_REGISTRY(RegisterTempEntities)
-REGISTRY_SORT(TempEntities, netname, 0)
-STATIC_INIT(RegisterTempEntities_renumber) {
-    for (int i = 0; i < TempEntities_COUNT; ++i) {
-        TempEntities[i].m_id = 115 + i;
-    }
+REGISTRY(TempEntities, BITS(8) - 80)
+#define TempEntities_from(i) _TempEntities_from(i, NULL)
+REGISTER_REGISTRY(TempEntities)
+REGISTRY_SORT(TempEntities, 0)
+REGISTRY_CHECK(TempEntities)
+STATIC_INIT(RegisterTempEntities_renumber)
+{
+       for (int i = 0; i < TempEntities_COUNT; ++i)
+               TempEntities_from(i).m_id = 80 + i;
 }
 
 #ifndef MENUQC
-#ifdef CSQC
-int ReadInt24_t()
-{
-    int v = ReadShort() << 8; // note: this is signed
-    v += ReadByte(); // note: this is unsigned
-    return v;
-}
-vector ReadInt48_t()
-{
-    vector v;
-    v.x = ReadInt24_t();
-    v.y = ReadInt24_t();
-    v.z = 0;
-    return v;
-}
-vector ReadInt72_t()
-{
-    vector v;
-    v.x = ReadInt24_t();
-    v.y = ReadInt24_t();
-    v.z = ReadInt24_t();
-    return v;
-}
-#else
-void WriteInt24_t(float dst, float val)
-{
-    float v;
-    WriteShort(dst, (v = floor(val >> 8)));
-    WriteByte(dst, val - (v << 8)); // 0..255
-}
-void WriteInt48_t(float dst, vector val)
-{
-    WriteInt24_t(dst, val.x);
-    WriteInt24_t(dst, val.y);
-}
-void WriteInt72_t(float dst, vector val)
-{
-    WriteInt24_t(dst, val.x);
-    WriteInt24_t(dst, val.y);
-    WriteInt24_t(dst, val.z);
-}
-#endif
+       const float APPROXPASTTIME_ACCURACY_REQUIREMENT = 0.05;
+       #define APPROXPASTTIME_MAX (16384 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
+       #define APPROXPASTTIME_RANGE (64 * APPROXPASTTIME_ACCURACY_REQUIREMENT)
+
+       #ifdef CSQC
+               entity ReadCSQCEntity()
+               {
+                       int f = ReadShort();
+                       if (f == 0) return world;
+                       return findfloat(world, entnum, f);
+               }
+               int ReadInt24_t()
+               {
+                       int v = ReadShort() << 8; // note: this is signed
+                       v += ReadByte();          // note: this is unsigned
+                       return v;
+               }
+               vector ReadInt48_t()
+               {
+                       vector v;
+                       v.x = ReadInt24_t();
+                       v.y = ReadInt24_t();
+                       v.z = 0;
+                       return v;
+               }
+               vector ReadInt72_t()
+               {
+                       vector v;
+                       v.x = ReadInt24_t();
+                       v.y = ReadInt24_t();
+                       v.z = ReadInt24_t();
+                       return v;
+               }
+
+               #define ReadFloat() ReadCoord()
+        vector ReadVector() { vector v; v.x = ReadFloat(); v_y = ReadFloat(); v.z = ReadFloat(); return v; }
+               vector ReadVector2D() { vector v; v.x = ReadFloat(); v.y = ReadFloat(); v.z = 0; return v; }
+
+               float ReadApproxPastTime()
+               {
+                       float dt = ReadByte();
+
+                       // map from range...PPROXPASTTIME_MAX / 256
+                       dt = (APPROXPASTTIME_MAX / 256) * (dt / (256 - dt));
+
+                       return servertime - dt;
+               }
+
+       #else
+               const int MSG_ENTITY = 5;
+
+               void WriteInt24_t(float dst, float val)
+               {
+                       float v;
+                       WriteShort(dst, (v = floor(val >> 8)));
+                       WriteByte(dst, val - (v << 8));  // 0..255
+               }
+               void WriteInt48_t(float dst, vector val)
+               {
+                       WriteInt24_t(dst, val.x);
+                       WriteInt24_t(dst, val.y);
+               }
+               void WriteInt72_t(float dst, vector val)
+               {
+                       WriteInt24_t(dst, val.x);
+                       WriteInt24_t(dst, val.y);
+                       WriteInt24_t(dst, val.z);
+               }
+
+        #define WriteFloat(to, f) WriteCoord(to, f)
+               #define WriteVector(to, v) do { WriteFloat(to, v.x); WriteFloat(to, v.y); WriteFloat(to, v.z); } while (0)
+        #define WriteVector2D(to, v) do { WriteFloat(to, v.x); WriteFloat(to, v.y); } while (0)
+
+               // this will use the value:
+               //   128
+               // accuracy near zero is APPROXPASTTIME_MAX/(256*255)
+               // accuracy at x is 1/derivative, i.e.
+               //   APPROXPASTTIME_MAX * (1 + 256 * (dt / APPROXPASTTIME_MAX))^2 / 65536
+               void WriteApproxPastTime(float dst, float t)
+               {
+                       float dt = time - t;
+
+                       // warning: this is approximate; do not resend when you don't have to!
+                       // be careful with sendflags here!
+                       // we want: 0 -> 0.05, 1 -> 0.1, ..., 255 -> 12.75
+
+                       // map to range...
+                       dt = 256 * (dt / ((APPROXPASTTIME_MAX / 256) + dt));
+
+                       // round...
+                       dt = rint(bound(0, dt, 255));
+
+                       WriteByte(dst, dt);
+               }
+
+               // allow writing to also pass through to spectators (like so spectators see the same centerprints as players for example)
+               #define WRITESPECTATABLE_MSG_ONE_VARNAME(varname, statement) \
+                       entity varname; varname = msg_entity; \
+                       FOR_EACH_REALCLIENT(msg_entity) \
+                       if (msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) \
+                               statement msg_entity = varname
+               #define WRITESPECTATABLE_MSG_ONE(statement) \
+                       do \
+                       { \
+                               WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement); \
+                       } \
+                       while (0)
+               #define WRITESPECTATABLE(msg, statement) \
+                       if (msg == MSG_ONE) WRITESPECTATABLE_MSG_ONE(statement); \
+                       else \
+                               statement float WRITESPECTATABLE_workaround = 0
+       #endif
 #endif
 
 #endif
index 87e3aea5e545a9a09d6c6c5136915ab3c509bc24..8067cf1ad422b1776ec4c71c798faca64feecc7d 100644 (file)
@@ -2,12 +2,12 @@
 #define NIL_H
 
 #ifdef QCC_SUPPORT_NIL
-#define func_null nil
-#define string_null nil
+       #define func_null nil
+       #define string_null nil
 #else
 // the NULL function
-var void func_null(void);
-string string_null;
+       var void func_null();
+       string string_null;
 #endif
 
 #endif
index 5bd6ad650b1ee585d56e733717f4a8e15fcf085e..2987f78e64cbe08a0016c5cf6b79dc1a8ebe94b3 100644 (file)
@@ -1,14 +1,14 @@
 // noises "usually" start in the range -1..1
 entityclass(Noise);
-class(Noise) .float noise_baccum;
-class(Noise) .float noise_paccum;
-class(Noise) .float noise_paccum2;
-class(Noise) .float noise_paccum3;
-class(Noise) .float noise_bstate;
+class(Noise).float noise_baccum;
+class(Noise).float noise_paccum;
+class(Noise).float noise_paccum2;
+class(Noise).float noise_paccum3;
+class(Noise).float noise_bstate;
 
 float Noise_Brown(entity e, float dt)
 {
-       e.noise_baccum += random() * sqrt(dt); // same stddev for all dt
+       e.noise_baccum += random() * sqrt(dt);  // same stddev for all dt
        return e.noise_baccum;
 }
 float Noise_Pink(entity e, float dt)
@@ -16,12 +16,9 @@ float Noise_Pink(entity e, float dt)
        float f;
        f = dt * 60;
        // http://home.earthlink.net/~ltrammell/tech/pinkalg.htm
-       if(random() > pow(0.3190, f))
-               e.noise_paccum = 0.34848 * (2 * random() - 1);
-       if(random() > pow(0.7756, f))
-               e.noise_paccum2 = 0.28768 * (2 * random() - 1);
-       if(random() > pow(0.9613, f))
-               e.noise_paccum3 = 0.43488 * (2 * random() - 1);
+       if (random() > pow(0.3190, f)) e.noise_paccum = 0.34848 * (2 * random() - 1);
+       if (random() > pow(0.7756, f)) e.noise_paccum2 = 0.28768 * (2 * random() - 1);
+       if (random() > pow(0.9613, f)) e.noise_paccum3 = 0.43488 * (2 * random() - 1);
        return e.noise_paccum + e.noise_paccum2 + e.noise_paccum3;
 }
 float Noise_White(entity e, float dt)
@@ -31,7 +28,6 @@ float Noise_White(entity e, float dt)
 /** +1 or -1 */
 float Noise_Burst(entity e, float dt, float p)
 {
-       if(random() > pow(p, dt))
-               e.noise_bstate = !e.noise_bstate;
+       if (random() > pow(p, dt)) e.noise_bstate = !e.noise_bstate;
        return 2 * e.noise_bstate - 1;
 }
index 0615282c3e1a7f7031aa1571eb8e51f5d9ce8e53..a0d6f35db34b9ba8e76ba2af2c1aa3457779d1bb 100644 (file)
 
 #include "misc.qh"
 #include "nil.qh"
+#include "static.qh"
 
 #ifdef MENUQC
-    #define NULL (null_entity)
+       #define NULL (null_entity)
 #else
-    #define NULL (world)
+       #define NULL (world)
 #endif
 
+.vector origin;
+.bool pure_data;
+#define make_pure(e) \
+       do \
+       { \
+               (e).pure_data = true; \
+       } \
+       while (0)
+#define is_pure(e) ((e).pure_data)
+
 .string classname;
 /** Location entity was spawned from in source */
 .string sourceLocFile;
 .int sourceLocLine;
 entity _spawn();
-entity __spawn(string _classname, string _sourceFile, int _sourceLine) {
-    entity this = _spawn();
-    this.classname = _classname;
-    this.sourceLocFile = _sourceFile;
-    this.sourceLocLine = _sourceLine;
-    return this;
+entity __spawn(string _classname, string _sourceFile, int _sourceLine, bool pure)
+{
+       entity this = _spawn();
+       this.classname = _classname;
+       this.sourceLocFile = _sourceFile;
+       this.sourceLocLine = _sourceLine;
+       if (pure) make_pure(this);
+       return this;
 }
 
 
-
 #define entityclass(...) EVAL(OVERLOAD(entityclass, __VA_ARGS__))
 #define entityclass_1(name) entityclass_2(name, Object)
 #ifndef QCC_SUPPORT_ENTITYCLASS
-    #define entityclass_2(name, base) typedef entity name
-    #define class(name)
-    #define new(class) __spawn(#class, __FILE__, __LINE__)
+       #define entityclass_2(name, base) typedef entity name
+       #define class(name)
+       #define new(class) __spawn( #class, __FILE__, __LINE__, false)
 #else
-    #define entityclass_2(name, base) entityclass name : base {}
-    #define class(name) [[class(name)]]
-    #define new(class) ((class) __spawn(#class, __FILE__, __LINE__))
+       #define entityclass_2(name, base) entityclass name : base {}
+       #define class(name) [[class(name)]]
+       #define new(class) ((class) __spawn( #class, __FILE__, __LINE__, false))
+#endif
+#define spawn() __spawn("entity", __FILE__, __LINE__, false)
+
+entity _clearentity_ent;
+STATIC_INIT(clearentity)
+{
+       _clearentity_ent = new(clearentity);
+}
+void clearentity(entity e)
+{
+#ifdef CSQC
+               int n = e.entnum;
+#endif
+       copyentity(_clearentity_ent, e);
+#ifdef CSQC
+               e.entnum = n;
 #endif
-#define spawn() new(entity)
+}
 
 // Classes have a `spawn##cname(entity)` constructor
 // The parameter is used across [[accumulate]] functions
 
 // Macros to hide this implementation detail:
 #ifdef GMQCC
-#define NEW(cname, ...) \
-    OVERLOAD(spawn##cname, new(cname), ##__VA_ARGS__)
+       #define NEW(cname, ...) \
+               OVERLOAD(spawn##cname, new(cname),##__VA_ARGS__)
 
-#define CONSTRUCT(cname, ...) \
-    OVERLOAD(spawn##cname, this, ##__VA_ARGS__)
+       #define CONSTRUCT(cname, ...) \
+               OVERLOAD(spawn##cname, this,##__VA_ARGS__)
 #else
-#define NEW_(cname, ...) \
-    OVERLOAD_(spawn##cname, __VA_ARGS__)
-#define NEW(cname, ...) \
-    NEW_(cname, new(cname), ##__VA_ARGS__)(new(cname), ##__VA_ARGS__)
-
-#define CONSTRUCT_(cname, ...) \
-    OVERLOAD_(spawn##cname, __VA_ARGS__)
-#define CONSTRUCT(cname, ...) \
-    CONSTRUCT_(cname, this, ##__VA_ARGS__)(this, ##__VA_ARGS__)
+       #define NEW_(cname, ...) \
+               OVERLOAD_(spawn##cname, __VA_ARGS__)
+       #define NEW(cname, ...) \
+               NEW_(cname, new(cname),##__VA_ARGS__)(new(cname),##__VA_ARGS__)
+
+       #define CONSTRUCT_(cname, ...) \
+               OVERLOAD_(spawn##cname, __VA_ARGS__)
+       #define CONSTRUCT(cname, ...) \
+               CONSTRUCT_(cname, this,##__VA_ARGS__)(this,##__VA_ARGS__)
 #endif
 
 #define CONSTRUCTOR(cname, ...) \
-    cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) { return = this; } \
-    [[accumulate]] cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__)
+       cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) \
+       { \
+               return = this; \
+       } \
+       [[accumulate]] cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__)
 
 .string vtblname;
 .entity vtblbase;
 
-void RegisterClasses() { }
-STATIC_INIT(RegisterClasses) { RegisterClasses(); }
+void RegisterClasses() {}
+STATIC_INIT(RegisterClasses)
+{
+       RegisterClasses();
+}
 
 #define VTBL(cname, base) \
-    INIT_STATIC(cname); \
-    entity cname##_vtbl; \
-    void cname##_vtbl_init() { \
-        cname e = new(vtbl); \
-        spawn##cname##_static(e); \
-        e.vtblname = #cname; \
-        /* Top level objects refer to themselves */ \
-        e.vtblbase = base##_vtbl ? base##_vtbl : e; \
-        cname##_vtbl = e; \
-    } \
-    ACCUMULATE_FUNCTION(RegisterClasses, cname##_vtbl_init)
+       INIT_STATIC(cname); \
+       entity cname##_vtbl; \
+       void cname##_vtbl_init() \
+       { \
+               cname e = new(vtbl); \
+               make_pure(e); \
+               spawn##cname##_static(e); \
+               e.vtblname = #cname; \
+               /* Top level objects refer to themselves */ \
+               e.vtblbase = base##_vtbl ? base##_vtbl : e; \
+               cname##_vtbl = e; \
+       } \
+       ACCUMULATE_FUNCTION(RegisterClasses, cname##_vtbl_init)
 
 #define INIT_STATIC(cname) [[accumulate]] void spawn##cname##_static(cname this)
 #define INIT(cname) [[accumulate]] cname spawn##cname##_1(cname this)
 
 #define CLASS(cname, base)                  \
-    entityclass(cname, base);               \
-    class(cname) .bool instanceOf##cname;   \
-    VTBL(cname, base)                       \
-    INIT_STATIC(cname) {                    \
-        if (cname##_vtbl) {                 \
-            copyentity(cname##_vtbl, this); \
-            return;                         \
-        }                                   \
-        spawn##base##_static(this);         \
-        this.instanceOf##cname = true;      \
-    }                                       \
-    INIT(cname) {                           \
-        /* Only statically initialize the current class, it contains everything it inherits */ \
-        if (cname##_vtbl.vtblname == this.classname) { \
-            spawn##cname##_static(this);    \
-            this.classname = #cname;        \
-            this.vtblname = string_null;    \
-            this.vtblbase = cname##_vtbl;   \
-        }                                   \
-        spawn##base##_1(this);              \
-    }
+       entityclass(cname, base);               \
+       class(cname).bool instanceOf##cname;   \
+       VTBL(cname, base)                       \
+       INIT_STATIC(cname) \
+       {                    \
+               if (cname##_vtbl) \
+               {                 \
+                       copyentity(cname##_vtbl, this); \
+                       return;                         \
+               }                                   \
+               spawn##base##_static(this);         \
+               this.instanceOf##cname = true;      \
+       }                                       \
+       INIT(cname) \
+       {                           \
+               /* Only statically initialize the current class, it contains everything it inherits */ \
+               if (cname##_vtbl.vtblname == this.classname) \
+               { \
+                       spawn##cname##_static(this);    \
+                       this.classname = #cname;        \
+                       this.vtblname = string_null;    \
+                       this.vtblbase = cname##_vtbl;   \
+               }                                   \
+               spawn##base##_1(this);              \
+       }
 
 #define METHOD(cname, name, prototype)      \
-    class(cname) .prototype name;           \
-    prototype cname##_##name;               \
-    INIT_STATIC(cname) { this.name = cname##_##name; } \
-    prototype cname##_##name
+       class(cname).prototype name;           \
+       prototype cname##_##name;               \
+       INIT_STATIC(cname) \
+       { \
+               this.name = cname##_##name; \
+       } \
+       prototype cname##_##name
 
 #define ATTRIB(cname, name, type, val)      \
-    class(cname) .type name;                \
-    INIT(cname) { this.name = val; }
+       class(cname).type name;                \
+       INIT(cname) \
+       { \
+               this.name = val; \
+       }
 
 #define ATTRIBARRAY(cname, name, type, cnt) \
-    class(cname) .type name[cnt];
+       class(cname).type name[cnt];
 
 #define ENDCLASS(cname) \
-    [[last]] INIT(cname) { return this; }
+       INIT(cname) \
+       { \
+               return this; \
+       }
 
 #define SUPER(cname) (cname##_vtbl.vtblbase)
-#define super (this.vtblbase.vtblbase)
 
 #define spawn_static(this)
 #define spawn_1(this)
 #define _vtbl NULL
 CLASS(Object, );
-    METHOD(Object, describe, string(entity this)) {
-        string s = _("No description");
-        if (cvar("developer")) {
-            for (int i = 0, n = numentityfields(); i < n; ++i) {
-                string value = getentityfieldstring(i, this);
-                if (value != "") s = sprintf("%s\n%s = %s", s, entityfieldname(i), value);
-            }
-        }
-        return s;
-    }
-    METHOD(Object, display, void(entity this, void(string name, string icon) returns)) {
-        returns(sprintf("entity %i", this), "nopreview_map");
-    }
+       METHOD(Object, describe, string(entity this))
+       {
+               string s = _("No description");
+               if (cvar("developer"))
+               {
+                       for (int i = 0, n = numentityfields(); i < n; ++i)
+                       {
+                               string value = getentityfieldstring(i, this);
+                               if (value != "") s = sprintf("%s\n%s = %s", s, entityfieldname(i), value);
+                       }
+               }
+               return s;
+       }
+       METHOD(Object, display, void(entity this, void(string name, string icon) returns))
+       {
+               returns(sprintf("entity %i", this), "nopreview_map");
+       }
 ENDCLASS(Object)
 #undef spawn_static
 #undef spawn_1
index 85c5396d7ed72cfdba1e22494fed169e68c53450..ac04034dda1d9d9714a7397de8899b1887fa271e 100644 (file)
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 
-vector vec_bias(vector v, float f){
+vector vec_bias(vector v, float f)
+{
        vector c;
        c_x = v_x + f;
        c_y = v_y + f;
        c_z = v_z + f;
        return c;
 }
-vector vec_to_min (vector a, vector b) {
+vector vec_to_min(vector a, vector b)
+{
        vector c;
-       c_x = min (a_x, b_x);
-       c_y = min (a_y, b_y);
-       c_z = min (a_z, b_z);
+       c_x = min(a_x, b_x);
+       c_y = min(a_y, b_y);
+       c_z = min(a_z, b_z);
        return c;
 }
 
-vector vec_to_max (vector a, vector b) {
+vector vec_to_max(vector a, vector b)
+{
        vector c;
-       c_x = max (a_x, b_x);
-       c_y = max (a_y, b_y);
-       c_z = max (a_z, b_z);
+       c_x = max(a_x, b_x);
+       c_y = max(a_y, b_y);
+       c_z = max(a_z, b_z);
        return c;
 }
 
 // there may already be a function for bounding a vector in this manner, however my very quick search did not reveal one -- Player_2
-vector vec_bounds_in (vector point, vector a, vector b) {
+vector vec_bounds_in(vector point, vector a, vector b)
+{
        vector c, d, e;
 
-       d = vec_to_min(a,b);
-       e = vec_to_max(a,b);
+       d = vec_to_min(a, b);
+       e = vec_to_max(a, b);
 
        c = vec_to_max(point, d);
        c = vec_to_min(c, e);
 
        return c;
-
 }
 
-vector vec_bounds_out (vector point, vector a, vector b) {
+vector vec_bounds_out(vector point, vector a, vector b)
+{
        vector c, d, e;
 
-       d = vec_to_max(a,b);
-       e = vec_to_min(a,b);
+       d = vec_to_max(a, b);
+       e = vec_to_min(a, b);
 
        c = vec_to_max(point, d);
        c = vec_to_min(c, e);
 
        return c;
-
 }
 
-float angle_snap_f (float f, float increment){
-
+float angle_snap_f(float f, float increment)
+{
        float i;
-       for (i = 0; i <= 360; ){
-               if (f <= i - increment)
-                       return  i - increment;
+       for (i = 0; i <= 360; )
+       {
+               if (f <= i - increment) return i - increment;
                i = i + increment;
        }
 
        return 0;
 }
 
-vector angle_snap_vec (vector v,  float increment) {
+vector angle_snap_vec(vector v,  float increment)
+{
        vector c;
-       c_x = angle_snap_f (v_x, increment);
-       c_y = angle_snap_f (v_y, increment);
-       c_z = angle_snap_f (v_z, increment);
+       c_x = angle_snap_f(v_x, increment);
+       c_y = angle_snap_f(v_y, increment);
+       c_z = angle_snap_f(v_z, increment);
        return c;
 }
 
-vector aim_vec (vector origin, vector target) {
+vector aim_vec(vector origin, vector target)
+{
        vector v;
-       //we float around x and y, but rotate around z
+       // we float around x and y, but rotate around z
        v_x = target_x - origin_x;
        v_y = target_y - origin_y;
        v_z = origin_z - target_z;
-       //get the angles actual
+       // get the angles actual
        return vectoangles(normalize(v));
 }
index c92f26a912f145ef42f3f8380533d58adaae10b4..b1886ae1268802c1011b31ccdfe6ebdcb671e3b4 100644 (file)
 vector vec_bias(vector v, float f);
 
 
-vector vec_to_min (vector a, vector b);
-vector vec_to_max (vector a, vector b);
+vector vec_to_min(vector a, vector b);
+vector vec_to_max(vector a, vector b);
 
 // there may already be a function for bounding a vector in this manner, however my very quick search did not reveal one -- Player_2
-vector vec_bounds_in (vector point, vector a, vector b);
-vector vec_bounds_out (vector point, vector a, vector b);
+vector vec_bounds_in(vector point, vector a, vector b);
+vector vec_bounds_out(vector point, vector a, vector b);
 
-float angle_snap_f (float f, float increment);
-vector angle_snap_vec (vector v,  float increment);
+float angle_snap_f(float f, float increment);
+vector angle_snap_vec(vector v,  float increment);
 
-vector aim_vec (vector origin, vector target);
+vector aim_vec(vector origin, vector target);
index f89a3b07a8a72d67b97962ad0fdd9f9d9be29227..6a8ce038c4d1a00fdcce2da1cab44652a2a02721 100644 (file)
@@ -1,34 +1,30 @@
 #ifdef CSQC
 #ifndef PLAYER_H
-#define PLAYER_H
+       #define PLAYER_H
 
-#include "string.qh"
+       #include "string.qh"
 
-#include "../client/main.qh"
-#include "../common/teams.qh"
+       #include "../client/main.qh"
+       #include "../common/teams.qh"
 
-int GetPlayerColorForce(int i)
-{
-       if(!teamplay)
-               return 0;
-       else
-               return stof(getplayerkeyvalue(i, "colors")) & 15;
-}
+       int GetPlayerColorForce(int i)
+       {
+               if (!teamplay) return 0;
+               else return stof(getplayerkeyvalue(i, "colors")) & 15;
+       }
 
-int GetPlayerColor(int i)
-{
-       if(!playerslots[i].gotscores) // unconnected
-               return NUM_SPECTATOR;
-       else if(stof(getplayerkeyvalue(i, "frags")) == FRAGS_SPECTATOR)
-               return NUM_SPECTATOR;
-       else
-               return GetPlayerColorForce(i);
-}
+       int GetPlayerColor(int i)
+       {
+               if (!playerslots[i].gotscores)  // unconnected
+                       return NUM_SPECTATOR;
+               else if (stof(getplayerkeyvalue(i, "frags")) == FRAGS_SPECTATOR) return NUM_SPECTATOR;
+               else return GetPlayerColorForce(i);
+       }
 
-string GetPlayerName(int i)
-{
-       return ColorTranslateRGB(getplayerkeyvalue(i, "name"));
-}
+       string GetPlayerName(int i)
+       {
+               return ColorTranslateRGB(getplayerkeyvalue(i, "name"));
+       }
 
 #endif
 #endif
index ed112a5c2b7df09f24163bb101ac29cf9ab39bc8..f0729460e5984ec6bcdb14b3bca21df21f40949a 100644 (file)
@@ -2,13 +2,13 @@
 #define PROGNAME_H
 
 #if defined(MENUQC)
-    #define PROGNAME "MENUQC"
+       #define PROGNAME "MENUQC"
 #elif defined(SVQC)
-    #define PROGNAME "SVQC"
+       #define PROGNAME "SVQC"
 #elif defined(CSQC)
-    #define PROGNAME "CSQC"
+       #define PROGNAME "CSQC"
 #else
-    #error "Unable to detect PROGNAME"
+       #error "Unable to detect PROGNAME"
 #endif
 
 #endif
index 149323b8fa8b00194e599f3700a869fa2b1ddb61..aff961c55da56b9dcde016c90335dbee7026d5e9 100644 (file)
 
 void RandomSelection_Init()
 {
-    RandomSelection_totalweight = 0;
-    RandomSelection_chosen_ent = NULL;
-    RandomSelection_chosen_float = 0;
-    RandomSelection_chosen_string = string_null;
-    RandomSelection_best_priority = -1;
+       RandomSelection_totalweight = 0;
+       RandomSelection_chosen_ent = NULL;
+       RandomSelection_chosen_float = 0;
+       RandomSelection_chosen_string = string_null;
+       RandomSelection_best_priority = -1;
 }
 
 void RandomSelection_Add(entity e, float f, string s, float weight, float priority)
 {
-    if (priority > RandomSelection_best_priority)
-    {
-        RandomSelection_best_priority = priority;
-        RandomSelection_chosen_ent = e;
-        RandomSelection_chosen_float = f;
-        RandomSelection_chosen_string = s;
-        RandomSelection_totalweight = weight;
-    }
-    else if (priority == RandomSelection_best_priority)
-    {
-        RandomSelection_totalweight += weight;
-        if (random() * RandomSelection_totalweight <= weight)
-        {
-            RandomSelection_chosen_ent = e;
-            RandomSelection_chosen_float = f;
-            RandomSelection_chosen_string = s;
-        }
-    }
+       if (priority > RandomSelection_best_priority)
+       {
+               RandomSelection_best_priority = priority;
+               RandomSelection_chosen_ent = e;
+               RandomSelection_chosen_float = f;
+               RandomSelection_chosen_string = s;
+               RandomSelection_totalweight = weight;
+       }
+       else if (priority == RandomSelection_best_priority)
+       {
+               RandomSelection_totalweight += weight;
+               if (random() * RandomSelection_totalweight <= weight)
+               {
+                       RandomSelection_chosen_ent = e;
+                       RandomSelection_chosen_float = f;
+                       RandomSelection_chosen_string = s;
+               }
+       }
 }
 
+float DistributeEvenly_amount;
+float DistributeEvenly_totalweight;
 
-// prandom - PREDICTABLE random number generator (not seeded yet)
-
-#ifdef USE_PRANDOM
-float prandom_seed;
-float prandom()
+void DistributeEvenly_Init(float amount, float totalweight)
 {
-    float c;
-    c = crc16(false, strcat(ftos(prandom_seed), ftos(prandom_seed + M_PI)));
-    prandom_seed = c;
-
-#ifdef USE_PRANDOM_DEBUG
-    LOG_TRACE("RANDOM -> ", ftos(c), "\n");
-#endif
-
-    return c / 65536; // in [0..1[
+       if (DistributeEvenly_amount)
+       {
+               LOG_TRACE("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
+               LOG_TRACE(ftos(DistributeEvenly_totalweight), " left!)\n");
+       }
+       if (totalweight == 0) DistributeEvenly_amount = 0;
+       else DistributeEvenly_amount = amount;
+       DistributeEvenly_totalweight = totalweight;
 }
 
-vector prandomvec()
+float DistributeEvenly_Get(float weight)
 {
-    vector v;
-
-    do
-    {
-        v.x = prandom();
-        v.y = prandom();
-        v.z = prandom();
-    }
-    while(v * v > 1);
-
-    return v;
+       float f;
+       if (weight <= 0) return 0;
+       f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
+       DistributeEvenly_totalweight -= weight;
+       DistributeEvenly_amount -= f;
+       return f;
 }
 
-void psrandom(float seed)
+float DistributeEvenly_GetRandomized(float weight)
 {
-    prandom_seed = seed;
-#ifdef USE_PRANDOM_DEBUG
-    LOG_TRACE("SRANDOM ", ftos(seed), "\n");
-#endif
+       float f;
+       if (weight <= 0) return 0;
+       f = floor(random() + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
+       DistributeEvenly_totalweight -= weight;
+       DistributeEvenly_amount -= f;
+       return f;
 }
 
-#ifdef USE_PRANDOM_DEBUG
-void prandom_debug()
+// from the GNU Scientific Library
+float gsl_ran_gaussian_lastvalue;
+float gsl_ran_gaussian_lastvalue_set;
+float gsl_ran_gaussian(float sigma)
 {
-    LOG_TRACE("Current random seed = ", ftos(prandom_seed), "\n");
+       if (gsl_ran_gaussian_lastvalue_set)
+       {
+               gsl_ran_gaussian_lastvalue_set = 0;
+               return sigma * gsl_ran_gaussian_lastvalue;
+       }
+       else
+       {
+               float a = random() * 2 * M_PI;
+               float b = sqrt(-2 * log(random()));
+               gsl_ran_gaussian_lastvalue = cos(a) * b;
+               gsl_ran_gaussian_lastvalue_set = 1;
+               return sigma * sin(a) * b;
+       }
 }
-#endif
+
+// prandom - PREDICTABLE random number generator (not seeded yet)
+
+#ifdef USE_PRANDOM
+       float prandom_seed;
+       float prandom()
+       {
+               float c;
+               c = crc16(false, strcat(ftos(prandom_seed), ftos(prandom_seed + M_PI)));
+               prandom_seed = c;
+
+       #ifdef USE_PRANDOM_DEBUG
+                       LOG_TRACE("RANDOM -> ", ftos(c), "\n");
+       #endif
+
+               return c / 65536;  // in [0..1[
+       }
+
+       vector prandomvec()
+       {
+               vector v;
+
+               do
+               {
+                       v.x = prandom();
+                       v.y = prandom();
+                       v.z = prandom();
+               }
+               while (v * v > 1);
+
+               return v;
+       }
+
+       void psrandom(float seed)
+       {
+               prandom_seed = seed;
+       #ifdef USE_PRANDOM_DEBUG
+                       LOG_TRACE("SRANDOM ", ftos(seed), "\n");
+       #endif
+       }
+
+       #ifdef USE_PRANDOM_DEBUG
+               void prandom_debug()
+               {
+                       LOG_TRACE("Current random seed = ", ftos(prandom_seed), "\n");
+               }
+       #endif
 #endif
index 551cf216d99cec90a8fc5eb2367bedad5c4e58a1..5b7fb0d3cce723e58d9b7ca4ecb27edde91d9542 100644 (file)
@@ -15,19 +15,19 @@ void RandomSelection_Add(entity e, float f, string s, float weight, float priori
 #define USE_PRANDOM
 
 #ifdef USE_PRANDOM
-float prandom();
-vector prandomvec();
+       float prandom();
+       vector prandomvec();
 
-void psrandom(float seed);
-#ifdef USE_PRANDOM_DEBUG
-void prandom_debug();
+       void psrandom(float seed);
+       #ifdef USE_PRANDOM_DEBUG
+               void prandom_debug();
+       #else
+               #define prandom_debug()
+       #endif
 #else
-#define prandom_debug()
-#endif
-#else
-#define prandom random
-#define prandomvec randomvec
-#define psrandom(x)
-#define prandom_debug()
+       #define prandom random
+       #define prandomvec randomvec
+       #define psrandom(x)
+       #define prandom_debug()
 #endif
 #endif
index 4c39a9dec6e59379f719e24b865857e9503c5ebe..52ab23377454bb92dfe75708ace67d428eac92e5 100644 (file)
 
 #include "oo.qh"
 
-#define REGISTER_INIT(ns, id) [[accumulate]] void Register_##ns##_##id##_init(entity this)
-#define REGISTER_INIT_POST(ns, id) [[accumulate]] void Register_##ns##_##id##_init_post(entity this)
-
+/**
+ * Declare a new registry.
+ *
+ * Don't forget to call `REGISTER_REGISTRY`:
+ *     REGISTER_REGISTRY(Foos)
+ */
 #define REGISTRY(id, max) \
-    void Register##id() {} \
-    const int id##_MAX = max; \
-    noref entity id[id##_MAX], id##_first, id##_last; \
-    int id##_COUNT;
+       void Register##id() {} \
+       const int id##_MAX = max; \
+       noref entity _##id[id##_MAX], id##_first, id##_last; \
+       int id##_COUNT; \
+       entity _##id##_from(int i, entity null) { if (i >= 0 && i < id##_COUNT) { entity e = _##id[i]; if (e) return e; } return null; }
+
+REGISTRY(Registries, BITS(8))
+
+/** registered item identifier */
+.string registered_id;
 
 /**
- * Register a new entity with a global constructor.
+ * Register a new entity with a registry.
  * Must be followed by a semicolon or a function body with a `this` parameter.
  * Wrapper macros may perform actions after user initialization like so:
  *     #define REGISTER_FOO(id) \
- *         REGISTER(RegisterFoos, FOO, FOOS, id, m_id, NEW(Foo)); \
+ *         REGISTER(Foos, FOO, id, m_id, NEW(Foo)); \
  *         REGISTER_INIT_POST(FOO, id) { \
  *             print("Registering foo #", this.m_id + 1, "\n"); \
  *         } \
  *         REGISTER_INIT(FOO, id)
  *
- * Don't forget to forward declare `initfunc` and call `REGISTER_REGISTRY`:
- *     void RegisterFoos();
- *     REGISTER_REGISTRY(RegisterFoos)
  *
- * @param initfunc  The global constructor to accumulate into
+ * @param registry  The registry to add each entity to.
  * @param ns        Short for namespace, prefix for each global (ns##_##id)
- * @param array     The array to add each entity to. Also requires `array##_first` and `array##_last` to be defined
  * @param id        The identifier of the current entity being registered
- * @param fld       The field to store the current count into
+ * @param fld       The field to store the locally unique unique entity id
  * @param inst      An expression to create a new instance, invoked for every registration
  */
-#define REGISTER(initfunc, ns, array, id, fld, inst)                \
-    entity ns##_##id;                                               \
-    REGISTER_INIT(ns, id) { }                                       \
-    REGISTER_INIT_POST(ns, id) { }                                  \
-    void Register_##ns##_##id() {                                   \
-        if (array##_COUNT >= array##_MAX) LOG_FATALF("Registry capacity exceeded (%s)", ftos(array##_MAX)); \
-        entity this = inst;                                         \
-        ns##_##id = this;                                           \
-        this.fld = array##_COUNT;                                   \
-        array[array##_COUNT++] = this;                              \
-        if (!array##_first)    array##_first = this;                \
-        if ( array##_last)     array##_last.REGISTRY_NEXT = this;   \
-        array##_last = this;                                        \
-        Register_##ns##_##id##_init(this);                          \
-        Register_##ns##_##id##_init_post(this);                     \
-    }                                                               \
-    ACCUMULATE_FUNCTION(initfunc, Register_##ns##_##id)             \
-    REGISTER_INIT(ns, id)
+#define REGISTER(registry, ns, id, fld, inst) \
+       entity ns##_##id; \
+       REGISTER_INIT(ns, id) {} \
+       REGISTER_INIT_POST(ns, id) {} \
+       void Register_##ns##_##id() \
+       { \
+               if (registry##_COUNT >= registry##_MAX) LOG_FATALF("Registry capacity exceeded (%s)", ftos(registry##_MAX)); \
+               entity this = ns##_##id = inst; \
+               this.registered_id = #id; \
+               this.fld = registry##_COUNT; \
+               _##registry[registry##_COUNT] = this; \
+               ++registry##_COUNT; \
+               if (!registry##_first) registry##_first = this; \
+               if (registry##_last)   registry##_last.REGISTRY_NEXT = this; \
+               registry##_last = this; \
+               Register_##ns##_##id##_init(this); \
+               Register_##ns##_##id##_init_post(this); \
+       } \
+       ACCUMULATE_FUNCTION(Register##registry, Register_##ns##_##id) \
+       REGISTER_INIT(ns, id)
+
+#define REGISTER_INIT(ns, id) [[accumulate]] void Register_##ns##_##id##_init(entity this)
+#define REGISTER_INIT_POST(ns, id) [[accumulate]] void Register_##ns##_##id##_init_post(entity this)
 
 /** internal next pointer */
 #define REGISTRY_NEXT enemy
 .entity REGISTRY_NEXT;
 
-#define REGISTRY_SORT(id, field, skip)                              \
-    void _REGISTRY_SWAP_##id(int i, int j, entity pass) {           \
-        i += skip; j += skip;                                       \
-                                                                    \
-        entity a = id[i], b = id[j];                                \
-        id[i] = b;                                                  \
-        id[j] = a;                                                  \
-                                                                    \
-        entity a_next = a.REGISTRY_NEXT, b_next = b.REGISTRY_NEXT;  \
-        a.REGISTRY_NEXT = b_next;                                   \
-        b.REGISTRY_NEXT = a_next;                                   \
-                                                                    \
-        if (i == 0) id##_first = b;                                 \
-        else id[i - 1].REGISTRY_NEXT = b;                           \
-                                                                    \
-        if (j == 0) id##_first = a;                                 \
-        else id[j - 1].REGISTRY_NEXT = a;                           \
-    }                                                               \
-    float _REGISTRY_CMP_##id(int i, int j, entity pass) {           \
-        i += skip; j += skip;                                       \
-        string a = id[i].field;                                     \
-        string b = id[j].field;                                     \
-        return strcasecmp(a, b);                                    \
-    }                                                               \
-    STATIC_INIT(Registry_sort_##id) {                               \
-        heapsort(id##_COUNT - (skip), _REGISTRY_SWAP_##id, _REGISTRY_CMP_##id, NULL); \
-    }
+#define REGISTRY_SORT(id, skip) \
+       void _REGISTRY_SWAP_##id(int i, int j, entity pass) \
+       { \
+               i += skip; j += skip; \
+               \
+               entity a = _##id[i], b = _##id[j]; \
+               _##id[i] = b; \
+               _##id[j] = a; \
+        \
+               entity a_next = a.REGISTRY_NEXT, b_next = b.REGISTRY_NEXT; \
+               a.REGISTRY_NEXT = b_next; \
+               b.REGISTRY_NEXT = a_next; \
+        \
+               if (i == 0) id##_first = b; \
+               else _##id[i - 1].REGISTRY_NEXT = b; \
+        \
+               if (j == 0) id##_first = a; \
+               else _##id[j - 1].REGISTRY_NEXT = a; \
+       } \
+       int _REGISTRY_CMP_##id(int i, int j, entity pass) \
+       { \
+               i += skip; j += skip; \
+               string a = _##id[i].registered_id; \
+               string b = _##id[j].registered_id; \
+               return strcmp(a, b); \
+       } \
+       STATIC_INIT(Registry_sort_##id) \
+       { \
+               heapsort(id##_COUNT - (skip), _REGISTRY_SWAP_##id, _REGISTRY_CMP_##id, NULL); \
+       }
+
+#define REGISTRY_HASH(id) Registry_hash_##id
+
+[[accumulate]] void Registry_check(string r, string server) { }
+[[accumulate]] void Registry_send_all() { }
+
+#ifdef SVQC
+void Registry_send(string id, string hash);
+#else
+#define Registry_send(id, hash)
+#endif
+
+#define REGISTRY_CHECK(id) \
+       string REGISTRY_HASH(id); \
+       STATIC_INIT(Registry_check_##id) \
+       { \
+               string algo = "SHA256"; \
+               string join = ":"; \
+               string s = ""; \
+               FOREACH(id, true, LAMBDA(s = strcat(s, join, it.registered_id))); \
+               s = substring(s, strlen(join), -1); \
+               string h = REGISTRY_HASH(id) = strzone(digest_hex(algo, s)); \
+               LOG_TRACEF(#id ": %s\n[%s]\n", h, s); \
+       } \
+       void Registry_check(string r, string sv) \
+       { \
+               if (r == #id) \
+               { \
+                       string cl = REGISTRY_HASH(id); \
+                       if (cl != sv) \
+                       { \
+                               LOG_FATALF("client/server mismatch (%s).\nCL: %s\nSV: %s\n", r, cl, sv); \
+                       } \
+               } \
+       } \
+       void Registry_send_all() { Registry_send(#id, REGISTRY_HASH(id)); } \
+
+#define REGISTER_REGISTRY(...) EVAL(OVERLOAD(REGISTER_REGISTRY, __VA_ARGS__))
+#define REGISTER_REGISTRY_1(id) REGISTER_REGISTRY_2(id, #id)
+#define REGISTER_REGISTRY_2(id, str) \
+       ACCUMULATE_FUNCTION(__static_init, Register##id) \
+       CLASS(id##Registry, Object) \
+               ATTRIB(id##Registry, m_name, string, str) \
+               ATTRIB(id##Registry, REGISTRY_NEXT, entity, id##_first) \
+       ENDCLASS(id##Registry) \
+       REGISTER(Registries, REGISTRY, id, m_id, NEW(id##Registry));
+
 
 #endif
diff --git a/qcsrc/lib/registry_net.qh b/qcsrc/lib/registry_net.qh
new file mode 100644 (file)
index 0000000..14e4dbc
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef REGISTRY_NET_H
+#define REGISTRY_NET_H
+
+#include "net.qh"
+
+REGISTER_NET_TEMP(registry)
+
+#ifdef CSQC
+NET_HANDLE(registry, bool isnew)
+{
+       string k = ReadString();
+       string v = ReadString();
+       Registry_check(k, v);
+       return true;
+}
+#endif
+
+#ifdef SVQC
+void Registry_send(string id, string hash)
+{
+       int channel = MSG_ONE;
+       WriteHeader(channel, registry);
+       WriteString(channel, id);
+       WriteString(channel, hash);
+}
+#endif
+
+#endif
index 6ff77139f83e76f05f089edd397d137592535c10..b74a881f35b8761f667165c6649b992bd07ed834 100644 (file)
@@ -2,48 +2,55 @@
 #define REPLICATE_H
 #ifndef MENUQC
 
-#define REPLICATE(...) EVAL(OVERLOAD(REPLICATE, __VA_ARGS__))
+       #define REPLICATE(...) EVAL(OVERLOAD(REPLICATE, __VA_ARGS__))
 
-[[accumulate]] void ReplicateVars(entity this, string thisname, int i) { }
+       [[accumulate]] void ReplicateVars(entity this, string thisname, int i) {}
 
-#define REPLICATE_3(fld, type, var)         REPLICATE_4(fld, type, var, )
-#define REPLICATE_4(fld, type, var, func)   REPLICATE_##type(fld, var, func)
-#define REPLICATE_string(fld, var, func)    REPLICATE_7(fld, string, var, , \
-    { if (field) strunzone(field); field = strzone(it); }, \
-    { if (field) strunzone(field); field = string_null; }, \
-    { \
-        /* also initialize to the default value of func when requesting cvars */ \
-        string s = func(field); \
-        if (s != field) { \
-            strunzone(field); \
-            field = strzone(s); \
-        } \
-    })
-#define REPLICATE_float(fld, var, func)     REPLICATE_7(fld, float, var, func,  { field = stof(it); },          , )
-#define REPLICATE_bool(fld, var, func)      REPLICATE_7(fld, bool, var, func,   { field = boolean(stoi(it)); }, , )
-#define REPLICATE_int(fld, var, func)       REPLICATE_7(fld, int, var, func,    { field = stoi(it); },          , )
+       #define REPLICATE_3(fld, type, var) REPLICATE_4(fld, type, var, )
+       #define REPLICATE_4(fld, type, var, func) REPLICATE_##type(fld, var, func)
+       #define REPLICATE_string(fld, var, func) \
+               REPLICATE_7(fld, string, var, , \
+       { if (field) strunzone(field); field = strzone(it); }, \
+       { if (field) strunzone(field); field = string_null; }, \
+       { \
+               /* also initialize to the default value of func when requesting cvars */ \
+               string s = func(field); \
+               if (s != field) \
+               { \
+                   strunzone(field); \
+                   field = strzone(s); \
+               } \
+       })
+       #define REPLICATE_float(fld, var, func) REPLICATE_7(fld, float, var, func,  { field = stof(it); },          , )
+       #define REPLICATE_bool(fld, var, func) REPLICATE_7(fld, bool, var, func,   { field = boolean(stoi(it)); }, , )
+       #define REPLICATE_int(fld, var, func) REPLICATE_7(fld, int, var, func,    { field = stoi(it); },          , )
 
-#if defined(SVQC)
-    #define REPLICATE_7(fld, type, var, func, create, destroy, after) \
-        void ReplicateVars(entity this, string thisname, int i) { \
-            type field = this.fld; \
-            if (i < 0) { destroy } \
-            else { \
-                string it = func(argv(i + 1)); \
-                bool current = thisname == var; \
-                if (i > 0) { \
-                    if (current) { create } \
-                } else { \
-                    stuffcmd(this, "cl_cmd sendcvar " var "\n"); \
-                } \
-                if (current) { after } \
-            } \
-            this.fld = field; \
-        }
-#elif defined(CSQC)
-    // TODO
-    #define REPLICATE_7(fld, type, var, func, create, destroy, after)
-#endif
+       #if defined(SVQC)
+               #define REPLICATE_7(fld, type, var, func, create, destroy, after) \
+                       void ReplicateVars(entity this, string thisname, int i) \
+                       { \
+                               type field = this.fld; \
+                               if (i < 0) { destroy } \
+                               else \
+                               { \
+                                       string it = func(argv(i + 1)); \
+                                       bool current = thisname == var; \
+                                       if (i > 0) \
+                                       { \
+                                               if (current) { create } \
+                                       } \
+                                       else \
+                                       { \
+                                               stuffcmd(this, "cl_cmd sendcvar " var "\n"); \
+                                       } \
+                                       if (current) { after } \
+                               } \
+                               this.fld = field; \
+                       }
+       #elif defined(CSQC)
+               // TODO
+               #define REPLICATE_7(fld, type, var, func, create, destroy, after)
+       #endif
 
 #endif
 #endif
index eac0c644a664ce0afd52a0311994d111ddc3d21e..743214ab5f48f75dc635fac62dea992cbedf31b8 100644 (file)
@@ -7,31 +7,31 @@
 
 // Step 1: auto oldself
 #if 1
-#define SELFPARAM() noref entity this = __self
-#define setself(s) (__self = s)
-#define self __self
+       #define SELFPARAM() noref entity this = __self
+       #define setself(s) (__self = s)
+       #define self __self
 #endif
 
 // Step 2: check SELFPARAM() is present for functions that use self
 #if 0
-#define SELFPARAM() [[alias("__self")]] noref entity this = __self
-#define setself(s) (__self = s)
-#define self this
+       #define SELFPARAM() [[alias("__self")]] noref entity this = __self
+       #define setself(s) (__self = s)
+       #define self this
 #endif
 
 // Step 3: const self
 #if 0
-#define SELFPARAM() noref const entity this = __self
-entity setself(entity e) { return self = e; }
-entity getself() { return self; }
-#define self getself()
+       #define SELFPARAM() noref const entity this = __self
+       entity setself(entity e) { return self = e; }
+       entity getself() { return self; }
+       #define self getself()
 #endif
 
 // Step 4: enable when possible
 // TODO: Remove SELFPARAM in favor of a parameter
 #if 0
-#define SELFPARAM() noref const entity this = __self
-#define self this
+       #define SELFPARAM() noref const entity this = __self
+       #define self this
 #endif
 
 #endif
index 0d3177a98a8fadfdb118b3a06d7ceef5024a6065..748bd2b2748efe82a071e4583771adbe338de146 100644 (file)
@@ -2,74 +2,62 @@
 #define SORT_H
 
 /** is only ever called for i1 < i2 */
-typedef void(float i1, float i2, entity pass) swapfunc_t;
+typedef void (int i1, int i2, entity pass) swapfunc_t;
 /** <0 for <, ==0 for ==, >0 for > (like strcmp) */
-typedef float(float i1, float i2, entity pass) comparefunc_t;
+typedef int (int i1, int i2, entity pass) comparefunc_t;
 
-void heapsort(float n, swapfunc_t swap, comparefunc_t cmp, entity pass)
+void heapsort(int n, swapfunc_t swap, comparefunc_t cmp, entity pass)
 {
-    int root, child;
+       #define heapify(_count) \
+               do \
+               { \
+                       for (int start = floor(((_count) - 2) / 2); start >= 0; --start) \
+                       { \
+                               siftdown(start, (_count) - 1); \
+                       } \
+               } \
+               while (0)
 
-    // heapify
-    int start = floor((n - 2) / 2);
-    while (start >= 0) {
-        // siftdown(start, n - 1);
-        root = start;
-        while (root * 2 + 1 <= n - 1) {
-            child = root * 2 + 1;
-            if (child < n - 1 && cmp(child, child + 1, pass) < 0) {
-                child += 1;
-            }
-            if (cmp(root, child, pass) < 0) {
-                swap(root, child, pass);
-                root = child;
-            } else {
-                break;
-            }
-        }
-        // end of siftdown
-        --start;
-    }
+       #define siftdown(_start, _end) \
+               do \
+               { \
+                       for (int root = (_start); root * 2 + 1 <= (_end); ) \
+                       { \
+                               int child = root * 2 + 1; \
+                               if (child < (_end) && cmp(child, child + 1, pass) < 0) child += 1; \
+                               if (cmp(root, child, pass) >= 0) break; \
+                               swap(root, child, pass); \
+                               root = child; \
+                       } \
+               } \
+               while (0)
 
-    // extract
-    int end = n - 1;
-    while (end > 0) {
-        swap(0, end, pass);
-        end -= 1;
-        // siftdown(0, end);
-        root = 0;
-        while (root * 2 + 1 <= end) {
-            child = root * 2 + 1;
-            if (child < end && cmp(child, child+1, pass) < 0) {
-                child += 1;
-            }
-            if (cmp(root, child, pass) < 0) {
-                swap(root, child, pass);
-                root = child;
-            } else {
-                break;
-            }
-        }
-        // end of siftdown
-    }
+       heapify(n);
+       int end = n - 1;
+       while (end > 0)
+       {
+               swap(0, end, pass);
+               end -= 1;
+               siftdown(0, end);
+       }
 }
 
 void shuffle(float n, swapfunc_t swap, entity pass)
 {
-    for (int i = 1; i < n; ++i) {
-        // swap i-th item at a random position from 0 to i
-        // proof for even distribution:
-        //   n = 1: obvious
-        //   n -> n+1:
-        //     item n+1 gets at any position with chance 1/(n+1)
-        //     all others will get their 1/n chance reduced by factor n/(n+1)
-        //     to be on place n+1, their chance will be 1/(n+1)
-        //     1/n * n/(n+1) = 1/(n+1)
-        //     q.e.d.
-        int j = floor(random() * (i + 1));
-        if (j != i)
-            swap(j, i, pass);
-    }
+       for (int i = 1; i < n; ++i)
+       {
+               // swap i-th item at a random position from 0 to i
+               // proof for even distribution:
+               //   n = 1: obvious
+               //   n -> n+1:
+               //     item n+1 gets at any position with chance 1/(n+1)
+               //     all others will get their 1/n chance reduced by factor n/(n+1)
+               //     to be on place n+1, their chance will be 1/(n+1)
+               //     1/n * n/(n+1) = 1/(n+1)
+               //     q.e.d.
+               int j = floor(random() * (i + 1));
+               if (j != i) swap(j, i, pass);
+       }
 }
 
 #endif
index fcaf6be50dcee4f510ff447d01884c11531efb3f..fecc79bdff0900068d804b8f36273662bd890106 100644 (file)
@@ -2,8 +2,8 @@
 
 entity Sort_Spawn()
 {
-       entity sort;
-       sort = spawn();
+       entity sort = new(sortlist);
+       make_pure(sort);
        sort.sort_next = NULL;
        sort.chain = sort;
        return sort;
@@ -11,111 +11,111 @@ entity Sort_Spawn()
 /*
 entity Sort_New(float(entity,entity) cmp)
 {
-       entity sort;
-       sort = spawn();
-       sort.sort_cmp = cmp;
-       sort.sort_next = world;
-       sort.chain = sort;
-       return sort;
+    entity sort;
+    sort = spawn();
+    sort.sort_cmp = cmp;
+    sort.sort_next = world;
+    sort.chain = sort;
+    return sort;
 }
 
 void Sort_Remove(entity sort)
 {
-       entity next;
-       while(sort.sort_next)
-       {
-               next = sort.sort_next;
-               remove(sort);
-               sort = next;
-       }
-       remove(sort);
+    entity next;
+    while(sort.sort_next)
+    {
+        next = sort.sort_next;
+        remove(sort);
+        sort = next;
+    }
+    remove(sort);
 }
 
 void Sort_Add(entity sort, entity ent)
 {
-       entity next, parent;
-       parent = sort;
-       next = sort.sort_next;
-       while(next)
-       {
-               if(!sort.sort_cmp(next, ent))
-                       break;
-               parent = next;
-               next = next.sort_next;
-       }
-       ent.sort_next = next;
-       ent.sort_prev = parent;
-       parent.sort_next = ent;
-       if(next)
-               next.sort_prev = ent;
+    entity next, parent;
+    parent = sort;
+    next = sort.sort_next;
+    while(next)
+    {
+        if(!sort.sort_cmp(next, ent))
+            break;
+        parent = next;
+        next = next.sort_next;
+    }
+    ent.sort_next = next;
+    ent.sort_prev = parent;
+    parent.sort_next = ent;
+    if(next)
+        next.sort_prev = ent;
 }
 
 void Sort_Reset(entity sort)
 {
-       sort.chain = sort;
+    sort.chain = sort;
 }
 
 float Sort_HasNext(entity sort)
 {
-       return (sort.chain.sort_next != world);
+    return (sort.chain.sort_next != world);
 }
 
 entity Sort_Next(entity sort)
 {
-       entity next;
-       next = sort.chain.sort_next;
-       if(!next) {
-               next = spawn();
-               sort.chain.sort_next = next;
-               next.sort_prev = sort.chain;
-               next.sort_next = world;
-       }
-       sort.chain = next;
-       return next;
+    entity next;
+    next = sort.chain.sort_next;
+    if(!next) {
+        next = spawn();
+        sort.chain.sort_next = next;
+        next.sort_prev = sort.chain;
+        next.sort_next = world;
+    }
+    sort.chain = next;
+    return next;
 }
 
 void Sort_Finish(entity sort)
 {
-       entity next;
-       next = sort.chain;
-       if(!next)
-               return;
+    entity next;
+    next = sort.chain;
+    if(!next)
+        return;
 
-       while(next.sort_next)
-       {
-               sort = next.sort_next;
-               next.sort_next = sort.sort_next;
-               remove(sort);
-       }
+    while(next.sort_next)
+    {
+        sort = next.sort_next;
+        next.sort_next = sort.sort_next;
+        remove(sort);
+    }
 }
 
 entity Sort_Get(entity sort, float i)
 {
-       for (; sort.sort_next && i > 0; --i)
-               sort = sort.sort_next;
-       return sort;
+    for (; sort.sort_next && i > 0; --i)
+        sort = sort.sort_next;
+    return sort;
 }
 */
 
 /*
 void Sort_Erase(entity ent)
 {
-       ent.sort_prev.sort_next = ent.sort_next;
-       if(ent.sort_next)
-               ent.sort_next.sort_prev = ent.sort_prev;
-       remove(ent);
+    ent.sort_prev.sort_next = ent.sort_next;
+    if(ent.sort_next)
+        ent.sort_next.sort_prev = ent.sort_prev;
+    remove(ent);
 }
 
 void Sort_RemoveOld(entity sort)
 {
-       entity tmp;
-       for(tmp = sort.sort_next; tmp; tmp = tmp.sort_next)
-       {
-               if(tmp.frame < time)
-               {
-                       tmp = tmp.sort_prev;
-                       Sort_Erase(tmp.sort_next);
-               }
-       }
+    entity tmp;
+    for(tmp = sort.sort_next; tmp; tmp = tmp.sort_next)
+    {
+        if(tmp.frame < time)
+        {
+            tmp = tmp.sort_prev;
+            Sort_Erase(tmp.sort_next);
+        }
+    }
 }
 */
index d4a1f183e15bc2e51fa9d94ec273b9054eae399b..eb8103f8fd51e8c8d7b185f3cd9a87fec4ce2b1b 100644 (file)
@@ -2,8 +2,8 @@
 #define SORTLIST_H
 
 entityclass(Sort);
-//.float(entity,entity) sort_cmp;
-class(Sort) .entity chain, sort_next, sort_prev;
+// .float(entity,entity) sort_cmp;
+class(Sort).entity chain, sort_next, sort_prev;
 
 entity Sort_Spawn();
 
@@ -12,12 +12,12 @@ entity Sort_Spawn();
  * @param a FIRST entity
  * @param b entity after a
  */
-#define SORT_SWAP(a,b)                                                                 \
-       b.sort_prev = a.sort_prev;                                                      \
-       a.sort_next = b.sort_next;                                                      \
-       if(b.sort_next) b.sort_next.sort_prev = a;                      \
-       if(a.sort_prev) a.sort_prev.sort_next = b;                      \
-       a.sort_prev = b;                                                                        \
+#define SORT_SWAP(a, b)                                  \
+       b.sort_prev = a.sort_prev;                          \
+       a.sort_next = b.sort_next;                          \
+       if (b.sort_next) b.sort_next.sort_prev = a;          \
+       if (a.sort_prev) a.sort_prev.sort_next = b;          \
+       a.sort_prev = b;                                    \
        b.sort_next = a
 
 #endif
index 1ab059cdf916ff62e6c46c56e526c14ef7db39ff..8a17854cb924af606baaaf77ffe7efdb477019ad 100644 (file)
@@ -7,161 +7,175 @@ noref bool require_spawnfunc_prefix;
 
 // Optional type checking; increases compile time too much to be enabled by default
 #if 0
-bool entityfieldassignablefromeditor(int i) {
-    switch (entityfieldtype(i)) {
-        case FIELD_STRING:
-        case FIELD_FLOAT:
-        case FIELD_VECTOR:
-            return true;
-    }
-    return false;
-}
+       bool entityfieldassignablefromeditor(int i)
+       {
+               switch (entityfieldtype(i))
+               {
+                       case FIELD_STRING:
+                       case FIELD_FLOAT:
+                       case FIELD_VECTOR:
+                               return true;
+               }
+               return false;
+       }
 
-#define _spawnfunc_checktypes(fld) if (fieldname == #fld) \
-    if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted\n", fieldname);
+       #define _spawnfunc_checktypes(fld) \
+               if (fieldname == #fld) \
+                       if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted\n", fieldname);
 #else
-#define _spawnfunc_checktypes(fld)
+       #define _spawnfunc_checktypes(fld)
 #endif
-#define _spawnfunc_check(fld) if (fieldname == #fld) \
-    continue;
+       #define _spawnfunc_check(fld) \
+               if (fieldname == #fld) continue;
 
-#define spawnfunc_1(id, whitelist) spawnfunc_2(id, whitelist)
-#define spawnfunc_2(id, whitelist) void spawnfunc_##id(entity this) { \
-    this = self; \
-    if (!this.spawnfunc_checked) { \
-        for (int i = 0, n = numentityfields(); i < n; ++i) { \
-            string value = getentityfieldstring(i, this); \
-            string fieldname = entityfieldname(i); \
-            whitelist(_spawnfunc_checktypes) \
-            if (value == "") continue; \
-            if (fieldname == "") continue; \
-            FIELDS_COMMON(_spawnfunc_check) \
-            whitelist(_spawnfunc_check) \
-            LOG_WARNINGF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue.\n"), #id, fieldname, value); \
-        } \
-        this.spawnfunc_checked = true; \
-    } \
-} \
-[[accumulate]] void spawnfunc_##id(entity this)
+               #define spawnfunc_1(id, whitelist) spawnfunc_2(id, whitelist)
+       #define spawnfunc_2(id, whitelist) \
+               void spawnfunc_##id(entity this) \
+               { \
+                       this = self; \
+                       if (!this.sourceLocFile) \
+                       { \
+                               this.sourceLocFile = __FILE__; \
+                               this.sourceLocLine = __LINE__; \
+                       } \
+                       if (!this.spawnfunc_checked) \
+                       { \
+                               for (int i = 0, n = numentityfields(); i < n; ++i) \
+                               { \
+                                       string value = getentityfieldstring(i, this); \
+                                       string fieldname = entityfieldname(i); \
+                                       whitelist(_spawnfunc_checktypes) \
+                                       if (value == "") continue; \
+                                       if (fieldname == "") continue; \
+                                       FIELDS_COMMON(_spawnfunc_check) \
+                                       whitelist(_spawnfunc_check) \
+                                       LOG_WARNINGF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue.\n"), #id, fieldname, value); \
+                               } \
+                               this.spawnfunc_checked = true; \
+                       } \
+               } \
+               [[accumulate]] void spawnfunc_##id(entity this)
 
-#define FIELD_SCALAR(fld, n) \
-    fld(n)
-#define FIELD_VEC(fld, n) \
-    fld(n) \
-    fld(n##_x) \
-    fld(n##_y) \
-    fld(n##_z)
+       #define FIELD_SCALAR(fld, n) \
+               fld(n)
+       #define FIELD_VEC(fld, n) \
+               fld(n) \
+               fld(n##_x) \
+               fld(n##_y) \
+               fld(n##_z)
 
-#define FIELDS_NONE(fld)
-#define FIELDS_ALL(fld) if (false)
+       #define FIELDS_NONE(fld)
+       #define FIELDS_ALL(fld) if (false)
 
-#define FIELDS_COMMON(fld) \
-    FIELD_SCALAR(fld, classname) \
-    FIELD_SCALAR(fld, spawnfunc_checked) \
-    /**/
+       #define FIELDS_COMMON(fld) \
+               FIELD_SCALAR(fld, classname) \
+               FIELD_SCALAR(fld, spawnfunc_checked) \
+               /**/
 
-#define FIELDS_UNION(fld) \
-    FIELD_SCALAR(fld, Version) \
-    FIELD_SCALAR(fld, ammo_cells) \
-    FIELD_SCALAR(fld, ammo_nails) \
-    FIELD_SCALAR(fld, ammo_rockets) \
-    FIELD_SCALAR(fld, armorvalue) \
-    FIELD_SCALAR(fld, atten) \
-    FIELD_SCALAR(fld, bgmscriptdecay) \
-    FIELD_SCALAR(fld, bgmscriptsustain) \
-    FIELD_SCALAR(fld, bgmscript) \
-    FIELD_SCALAR(fld, button0) \
-    FIELD_SCALAR(fld, cnt) \
-    FIELD_SCALAR(fld, colormap) \
-    FIELD_SCALAR(fld, count) \
-    FIELD_SCALAR(fld, curvetarget) \
-    FIELD_SCALAR(fld, cvarfilter) \
-    FIELD_SCALAR(fld, debrisdamageforcescale) \
-    FIELD_SCALAR(fld, debrisfadetime) \
-    FIELD_SCALAR(fld, debristimejitter) \
-    FIELD_SCALAR(fld, debristime) \
-    FIELD_SCALAR(fld, debris) \
-    FIELD_SCALAR(fld, delay) \
-    FIELD_SCALAR(fld, dmgtime) \
-    FIELD_SCALAR(fld, dmg) \
-    FIELD_SCALAR(fld, dmg_edge) \
-    FIELD_SCALAR(fld, dmg_force) \
-    FIELD_SCALAR(fld, dmg_radius) \
-    FIELD_SCALAR(fld, effects) \
-    FIELD_SCALAR(fld, flags) \
-    FIELD_SCALAR(fld, fog) \
-    FIELD_SCALAR(fld, frags) \
-    FIELD_SCALAR(fld, frame) \
-    FIELD_SCALAR(fld, gametypefilter) \
-    FIELD_SCALAR(fld, geomtype) \
-    FIELD_SCALAR(fld, gravity) \
-    FIELD_SCALAR(fld, health) \
-    FIELD_SCALAR(fld, height) \
-    FIELD_SCALAR(fld, impulse) \
-    FIELD_SCALAR(fld, killtarget) \
-    FIELD_SCALAR(fld, lerpfrac) \
-    FIELD_SCALAR(fld, light_lev) \
-    FIELD_SCALAR(fld, lip) \
-    FIELD_SCALAR(fld, loddistance1) \
-    FIELD_SCALAR(fld, lodmodel1) \
-    FIELD_SCALAR(fld, ltime) \
-    FIELD_SCALAR(fld, mdl) \
-    FIELD_SCALAR(fld, message2) \
-    FIELD_SCALAR(fld, message) \
-    FIELD_SCALAR(fld, modelindex) \
-    FIELD_SCALAR(fld, modelscale) \
-    FIELD_SCALAR(fld, model) \
-    FIELD_SCALAR(fld, monster_moveflags) \
-    FIELD_SCALAR(fld, movetype) \
-    FIELD_SCALAR(fld, netname) \
-    FIELD_SCALAR(fld, nextthink) \
-    FIELD_SCALAR(fld, noalign) \
-    FIELD_SCALAR(fld, noise1) \
-    FIELD_SCALAR(fld, noise2) \
-    FIELD_SCALAR(fld, noise) \
-    FIELD_SCALAR(fld, phase) \
-    FIELD_SCALAR(fld, platmovetype) \
-    FIELD_SCALAR(fld, race_place) \
-    FIELD_SCALAR(fld, radius) \
-    FIELD_SCALAR(fld, respawntimejitter) \
-    FIELD_SCALAR(fld, respawntime) \
-    FIELD_SCALAR(fld, restriction) \
-    FIELD_SCALAR(fld, scale) \
-    FIELD_SCALAR(fld, skin) \
-    FIELD_SCALAR(fld, solid) \
-    FIELD_SCALAR(fld, sound1) \
-    FIELD_SCALAR(fld, sounds) \
-    FIELD_SCALAR(fld, spawnflags) \
-    FIELD_SCALAR(fld, speed) \
-    FIELD_SCALAR(fld, strength) \
-    FIELD_SCALAR(fld, target2) \
-    FIELD_SCALAR(fld, target3) \
-    FIELD_SCALAR(fld, target4) \
-    FIELD_SCALAR(fld, targetname) \
-    FIELD_SCALAR(fld, target) \
-    FIELD_SCALAR(fld, target_random) \
-    FIELD_SCALAR(fld, target_range) \
-    FIELD_SCALAR(fld, team) \
-    FIELD_SCALAR(fld, turret_scale_health) \
-    FIELD_SCALAR(fld, turret_scale_range) \
-    FIELD_SCALAR(fld, turret_scale_respawn) \
-    FIELD_SCALAR(fld, volume) \
-    FIELD_SCALAR(fld, wait) \
-    FIELD_SCALAR(fld, warpzone_fadeend) \
-    FIELD_SCALAR(fld, warpzone_fadestart) \
-    FIELD_SCALAR(fld, weapon) \
-    FIELD_VEC(fld, absmax) \
-    FIELD_VEC(fld, absmin) \
-    FIELD_VEC(fld, angles) \
-    FIELD_VEC(fld, avelocity) \
-    FIELD_VEC(fld, maxs) \
-    FIELD_VEC(fld, maxs) \
-    FIELD_VEC(fld, mins) \
-    FIELD_VEC(fld, modelscale_vec) \
-    FIELD_VEC(fld, origin) \
-    FIELD_VEC(fld, velocity) \
-    /**/
+       #define FIELDS_UNION(fld) \
+               FIELD_SCALAR(fld, sourceLocFile) \
+               FIELD_SCALAR(fld, sourceLocLine) \
+               FIELD_SCALAR(fld, Version) \
+               FIELD_SCALAR(fld, ammo_cells) \
+               FIELD_SCALAR(fld, ammo_nails) \
+               FIELD_SCALAR(fld, ammo_rockets) \
+               FIELD_SCALAR(fld, armorvalue) \
+               FIELD_SCALAR(fld, atten) \
+               FIELD_SCALAR(fld, bgmscriptdecay) \
+               FIELD_SCALAR(fld, bgmscriptsustain) \
+               FIELD_SCALAR(fld, bgmscript) \
+               FIELD_SCALAR(fld, button0) \
+               FIELD_SCALAR(fld, cnt) \
+               FIELD_SCALAR(fld, colormap) \
+               FIELD_SCALAR(fld, count) \
+               FIELD_SCALAR(fld, curvetarget) \
+               FIELD_SCALAR(fld, cvarfilter) \
+               FIELD_SCALAR(fld, debrisdamageforcescale) \
+               FIELD_SCALAR(fld, debrisfadetime) \
+               FIELD_SCALAR(fld, debristimejitter) \
+               FIELD_SCALAR(fld, debristime) \
+               FIELD_SCALAR(fld, debris) \
+               FIELD_SCALAR(fld, delay) \
+               FIELD_SCALAR(fld, dmgtime) \
+               FIELD_SCALAR(fld, dmg) \
+               FIELD_SCALAR(fld, dmg_edge) \
+               FIELD_SCALAR(fld, dmg_force) \
+               FIELD_SCALAR(fld, dmg_radius) \
+               FIELD_SCALAR(fld, effects) \
+               FIELD_SCALAR(fld, flags) \
+               FIELD_SCALAR(fld, fog) \
+               FIELD_SCALAR(fld, frags) \
+               FIELD_SCALAR(fld, frame) \
+               FIELD_SCALAR(fld, gametypefilter) \
+               FIELD_SCALAR(fld, geomtype) \
+               FIELD_SCALAR(fld, gravity) \
+               FIELD_SCALAR(fld, health) \
+               FIELD_SCALAR(fld, height) \
+               FIELD_SCALAR(fld, impulse) \
+               FIELD_SCALAR(fld, killtarget) \
+               FIELD_SCALAR(fld, lerpfrac) \
+               FIELD_SCALAR(fld, light_lev) \
+               FIELD_SCALAR(fld, lip) \
+               FIELD_SCALAR(fld, loddistance1) \
+               FIELD_SCALAR(fld, lodmodel1) \
+               FIELD_SCALAR(fld, ltime) \
+               FIELD_SCALAR(fld, mdl) \
+               FIELD_SCALAR(fld, message2) \
+               FIELD_SCALAR(fld, message) \
+               FIELD_SCALAR(fld, modelindex) \
+               FIELD_SCALAR(fld, modelscale) \
+               FIELD_SCALAR(fld, model) \
+               FIELD_SCALAR(fld, monster_moveflags) \
+               FIELD_SCALAR(fld, movetype) \
+               FIELD_SCALAR(fld, netname) \
+               FIELD_SCALAR(fld, nextthink) \
+               FIELD_SCALAR(fld, noalign) \
+               FIELD_SCALAR(fld, noise1) \
+               FIELD_SCALAR(fld, noise2) \
+               FIELD_SCALAR(fld, noise) \
+               FIELD_SCALAR(fld, phase) \
+               FIELD_SCALAR(fld, platmovetype) \
+               FIELD_SCALAR(fld, race_place) \
+               FIELD_SCALAR(fld, radius) \
+               FIELD_SCALAR(fld, respawntimejitter) \
+               FIELD_SCALAR(fld, respawntime) \
+               FIELD_SCALAR(fld, restriction) \
+               FIELD_SCALAR(fld, scale) \
+               FIELD_SCALAR(fld, skin) \
+               FIELD_SCALAR(fld, solid) \
+               FIELD_SCALAR(fld, sound1) \
+               FIELD_SCALAR(fld, sounds) \
+               FIELD_SCALAR(fld, spawnflags) \
+               FIELD_SCALAR(fld, speed) \
+               FIELD_SCALAR(fld, strength) \
+               FIELD_SCALAR(fld, target2) \
+               FIELD_SCALAR(fld, target3) \
+               FIELD_SCALAR(fld, target4) \
+               FIELD_SCALAR(fld, targetname) \
+               FIELD_SCALAR(fld, target) \
+               FIELD_SCALAR(fld, target_random) \
+               FIELD_SCALAR(fld, target_range) \
+               FIELD_SCALAR(fld, team) \
+               FIELD_SCALAR(fld, turret_scale_health) \
+               FIELD_SCALAR(fld, turret_scale_range) \
+               FIELD_SCALAR(fld, turret_scale_respawn) \
+               FIELD_SCALAR(fld, volume) \
+               FIELD_SCALAR(fld, wait) \
+               FIELD_SCALAR(fld, warpzone_fadeend) \
+               FIELD_SCALAR(fld, warpzone_fadestart) \
+               FIELD_SCALAR(fld, weapon) \
+               FIELD_VEC(fld, absmax) \
+               FIELD_VEC(fld, absmin) \
+               FIELD_VEC(fld, angles) \
+               FIELD_VEC(fld, avelocity) \
+               FIELD_VEC(fld, maxs) \
+               FIELD_VEC(fld, maxs) \
+               FIELD_VEC(fld, mins) \
+               FIELD_VEC(fld, modelscale_vec) \
+               FIELD_VEC(fld, origin) \
+               FIELD_VEC(fld, velocity) \
+               /**/
 
-#define spawnfunc(...) EVAL(OVERLOAD(spawnfunc, __VA_ARGS__, FIELDS_UNION))
+       #define spawnfunc(...) EVAL(OVERLOAD(spawnfunc, __VA_ARGS__, FIELDS_UNION))
 
 #endif
index f7bcdcc296688e5ac8303a424284544561147e16..70eafd1b7d16ad89eb06e16d9d7d93bdae1dc983 100644 (file)
@@ -1,19 +1,20 @@
 #ifndef STATIC_H
 #define STATIC_H
 
-void __static_init() { }
+void __static_init() {}
 #define static_init() CALL_ACCUMULATED_FUNCTION(__static_init)
-void __static_init_late() {  }
+void __static_init_late() {}
 #define static_init_late() CALL_ACCUMULATED_FUNCTION(__static_init_late)
-
-#define REGISTER_REGISTRY(func) ACCUMULATE_FUNCTION(__static_init, func)
+void __static_init_precache() {}
+#define static_init_precache() CALL_ACCUMULATED_FUNCTION(__static_init_precache)
 
 #define _STATIC_INIT(where, func) \
-    void _static_##func(); \
-    ACCUMULATE_FUNCTION(where, _static_##func) \
-    void _static_##func()
+       void _static_##func(); \
+       ACCUMULATE_FUNCTION(where, _static_##func) \
+       void _static_##func()
 
-#define STATIC_INIT(func)       _STATIC_INIT(__static_init,         func)
-#define STATIC_INIT_LATE(func)  _STATIC_INIT(__static_init_late,    func##_late)
+#define STATIC_INIT(func) _STATIC_INIT(__static_init,           func)
+#define STATIC_INIT_LATE(func) _STATIC_INIT(__static_init_late, func##_late)
+#define PRECACHE(func) _STATIC_INIT(__static_init_precache,     func##_precache)
 
 #endif
diff --git a/qcsrc/lib/stats.qh b/qcsrc/lib/stats.qh
new file mode 100644 (file)
index 0000000..7dd2706
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef LIB_STATS_H
+#define LIB_STATS_H
+
+#include "registry.qh"
+#include "sort.qh"
+
+.int m_id;
+
+#if defined(CSQC)
+       /** Get all stats and store them as globals, access with `STAT(ID)` */
+       void stats_get() {}
+       #define STAT(...) EVAL(OVERLOAD(STAT, __VA_ARGS__))
+    #define STAT_1(id) STAT_2(id, NULL)
+       #define STAT_2(id, cl) (0, _STAT(id))
+
+       #define getstat_int(id) getstati(id, 0, 24)
+       #define getstat_bool(id) boolean(getstati(id))
+       #define getstat_float(id) getstatf(id)
+
+       #define _STAT(id) g_stat_##id
+       #define REGISTER_STAT(id, type) \
+               type _STAT(id); \
+               REGISTER(Stats, STAT, id, m_id, new(stat)) \
+               { \
+                       make_pure(this); \
+               } \
+               [[accumulate]] void stats_get() \
+               { \
+                       _STAT(id) = getstat_##type(STAT_##id.m_id); \
+               }
+#elif defined(SVQC)
+       /** Add all registered stats, access with `STAT(ID, player)` or `.type stat = _STAT(ID); player.stat` */
+       void stats_add() {}
+       #define STAT(id, cl) (cl._STAT(id))
+
+       #define addstat_int(id, fld) addstat(id, AS_INT, fld)
+       #define addstat_bool(id, fld) addstat(id, AS_INT, fld)
+       #define addstat_float(id, fld) addstat(id, AS_FLOAT, fld)
+       const int AS_STRING = 1;
+       const int AS_INT = 2;
+       const int AS_FLOAT = 8;
+
+       #define _STAT(id) stat_##id
+       #define REGISTER_STAT(id, type) \
+               .type _STAT(id); \
+               REGISTER(Stats, STAT, id, m_id, new(stat)) \
+               { \
+                       make_pure(this); \
+               } \
+               [[accumulate]] void stats_add() \
+               { \
+                       addstat_##type(STAT_##id.m_id, _STAT(id)); \
+               }
+#else
+       #define REGISTER_STAT(id, type)
+#endif
+
+const int STATS_ENGINE_RESERVE = 32 + (8 * 3); // Not sure how to handle vector stats yet, reserve them too
+
+REGISTRY(Stats, 220 - STATS_ENGINE_RESERVE)
+REGISTER_REGISTRY(Stats)
+REGISTRY_SORT(Stats, 0)
+REGISTRY_CHECK(Stats)
+STATIC_INIT(RegisterStats_renumber)
+{
+       FOREACH(Stats, true, LAMBDA(it.m_id = STATS_ENGINE_RESERVE + i));
+}
+#ifdef SVQC
+STATIC_INIT(stats_add) { stats_add(); }
+#endif
+
+#endif
index ede2edf1f4c6fa11278e5244b226db939eb56994..6f61155800d5af390011bd645b005655b61e14ae 100644 (file)
@@ -1,33 +1,66 @@
 #ifndef STRING_H
 #define STRING_H
 
+#include "nil.qh"
+#include "sort.qh"
+#include "oo.qh"
+
 #ifndef SVQC
-float stringwidth_colors(string s, vector theSize)
+       float stringwidth_colors(string s, vector theSize)
+       {
+               return stringwidth(s, true, theSize);
+       }
+
+       float stringwidth_nocolors(string s, vector theSize)
+       {
+               return stringwidth(s, false, theSize);
+       }
+#endif
+
+// TODO: macro
+string seconds_tostring(float sec)
 {
-    return stringwidth(s, true, theSize);
+       float minutes = floor(sec / 60);
+       sec -= minutes * 60;
+       return sprintf("%d:%02d", minutes, sec);
 }
 
-float stringwidth_nocolors(string s, vector theSize)
+string format_time(float seconds)
 {
-    return stringwidth(s, false, theSize);
+       seconds = floor(seconds + 0.5);
+       float days = floor(seconds / 864000);
+       seconds -= days * 864000;
+       float hours = floor(seconds / 36000);
+       seconds -= hours * 36000;
+       float minutes = floor(seconds / 600);
+       seconds -= minutes * 600;
+       if (days > 0) return sprintf(_("%d days, %02d:%02d:%02d"), days, hours, minutes, seconds);
+       else return sprintf(_("%02d:%02d:%02d"), hours, minutes, seconds);
 }
-#endif
 
-// Timer (#5)
-//
-// TODO: macro
-string seconds_tostring(float sec)
+string mmsss(float tenths)
+{
+       tenths = floor(tenths + 0.5);
+       float minutes = floor(tenths / 600);
+       tenths -= minutes * 600;
+       string s = ftos(1000 + tenths);
+       return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 1));
+}
+
+string mmssss(float hundredths)
 {
-    float minutes = floor(sec / 60);
-    sec -= minutes * 60;
-    return sprintf("%d:%02d", minutes, sec);
+       hundredths = floor(hundredths + 0.5);
+       float minutes = floor(hundredths / 6000);
+       hundredths -= minutes * 6000;
+       string s = ftos(10000 + hundredths);
+       return strcat(ftos(minutes), ":", substring(s, 1, 2), ".", substring(s, 3, 2));
 }
 
 int ColorTranslateMode;
 
 string ColorTranslateRGB(string s)
 {
-    return (ColorTranslateMode & 1) ? strdecolorize(s) : s;
+       return (ColorTranslateMode & 1) ? strdecolorize(s) : s;
 }
 
 // color code replace, place inside of sprintf and parse the string... defaults described as constants
@@ -37,155 +70,251 @@ string autocvar_hud_colorset_foreground_2 = "3"; // F2 - Yellow // secondary pri
 string autocvar_hud_colorset_foreground_3 = "4"; // F3 - Blue   // tertiary priority or relatively inconsequential text
 string autocvar_hud_colorset_foreground_4 = "1"; // F4 - Red    // notice/attention grabbing texting
 // "kill" colors
-string autocvar_hud_colorset_kill_1 = "1"; // K1 - Red    // "bad" or "dangerous" text (death messages against you, kill notifications, etc)
-string autocvar_hud_colorset_kill_2 = "3"; // K2 - Yellow // similar to above, but less important... OR, a highlight out of above message type
-string autocvar_hud_colorset_kill_3 = "4"; // K3 - Blue   // "good" or "beneficial" text (you fragging someone, etc)
+string autocvar_hud_colorset_kill_1 = "1";       // K1 - Red    // "bad" or "dangerous" text (death messages against you, kill notifications, etc)
+string autocvar_hud_colorset_kill_2 = "3";       // K2 - Yellow // similar to above, but less important... OR, a highlight out of above message type
+string autocvar_hud_colorset_kill_3 = "4";       // K3 - Blue   // "good" or "beneficial" text (you fragging someone, etc)
 // background color
-string autocvar_hud_colorset_background = "7"; // BG - White // neutral/unimportant text
+string autocvar_hud_colorset_background = "7";   // BG - White // neutral/unimportant text
 
 /** color code replace, place inside of sprintf and parse the string */
 string CCR(string input)
 {
-    // See the autocvar declarations in util.qh for default values
+       // See the autocvar declarations in util.qh for default values
 
-    // foreground/normal colors
-    input = strreplace("^F1", strcat("^", autocvar_hud_colorset_foreground_1), input);
-    input = strreplace("^F2", strcat("^", autocvar_hud_colorset_foreground_2), input);
-    input = strreplace("^F3", strcat("^", autocvar_hud_colorset_foreground_3), input);
-    input = strreplace("^F4", strcat("^", autocvar_hud_colorset_foreground_4), input);
+       // foreground/normal colors
+       input = strreplace("^F1", strcat("^", autocvar_hud_colorset_foreground_1), input);
+       input = strreplace("^F2", strcat("^", autocvar_hud_colorset_foreground_2), input);
+       input = strreplace("^F3", strcat("^", autocvar_hud_colorset_foreground_3), input);
+       input = strreplace("^F4", strcat("^", autocvar_hud_colorset_foreground_4), input);
 
-    // "kill" colors
-    input = strreplace("^K1", strcat("^", autocvar_hud_colorset_kill_1), input);
-    input = strreplace("^K2", strcat("^", autocvar_hud_colorset_kill_2), input);
-    input = strreplace("^K3", strcat("^", autocvar_hud_colorset_kill_3), input);
+       // "kill" colors
+       input = strreplace("^K1", strcat("^", autocvar_hud_colorset_kill_1), input);
+       input = strreplace("^K2", strcat("^", autocvar_hud_colorset_kill_2), input);
+       input = strreplace("^K3", strcat("^", autocvar_hud_colorset_kill_3), input);
 
-    // background colors
-    input = strreplace("^BG", strcat("^", autocvar_hud_colorset_background), input);
-    input = strreplace("^N", "^7", input); // "none"-- reset to white...
-    return input;
+       // background colors
+       input = strreplace("^BG", strcat("^", autocvar_hud_colorset_background), input);
+       input = strreplace("^N", "^7", input);  // "none"-- reset to white...
+       return input;
 }
 
-bool startsWith(string haystack, string needle)
-{
-    return substring(haystack, 0, strlen(needle)) == needle;
-}
+#define startsWith(haystack, needle) (strstrofs(haystack, needle, 0) == 0)
 
 bool startsWithNocase(string haystack, string needle)
 {
-    return strcasecmp(substring(haystack, 0, strlen(needle)), needle) == 0;
+       return strcasecmp(substring(haystack, 0, strlen(needle)), needle) == 0;
 }
 
 /** unzone the string, and return it as tempstring. Safe to be called on string_null */
 string fstrunzone(string s)
 {
-    if (!s) return s;
-    string sc = strcat(s, "");
-    strunzone(s);
-    return sc;
+       if (!s) return s;
+       string sc = strcat(s, "");
+       strunzone(s);
+       return sc;
 }
 
+/** returns first word */
 string car(string s)
 {
-    int o = strstrofs(s, " ", 0);
-    if (o < 0) return s;
-    return substring(s, 0, o);
+       int o = strstrofs(s, " ", 0);
+       if (o < 0) return s;
+       return substring(s, 0, o);
 }
 
+/** returns all but first word */
 string cdr(string s)
 {
-    int o = strstrofs(s, " ", 0);
-    if (o < 0) return string_null;
-    return substring(s, o + 1, strlen(s) - (o + 1));
+       int o = strstrofs(s, " ", 0);
+       if (o < 0) return string_null;
+       return substring(s, o + 1, strlen(s) - (o + 1));
 }
 
 string substring_range(string s, float b, float e)
 {
-    return substring(s, b, e - b);
+       return substring(s, b, e - b);
 }
 
 string swapwords(string str, float i, float j)
 {
-    float n;
-    string s1, s2, s3, s4, s5;
-    float si, ei, sj, ej, s0, en;
-    n = tokenizebyseparator(str, " "); // must match g_maplist processing in ShuffleMaplist and "shuffle"
-    si = argv_start_index(i);
-    sj = argv_start_index(j);
-    ei = argv_end_index(i);
-    ej = argv_end_index(j);
-    s0 = argv_start_index(0);
-    en = argv_end_index(n-1);
-    s1 = substring_range(str, s0, si);
-    s2 = substring_range(str, si, ei);
-    s3 = substring_range(str, ei, sj);
-    s4 = substring_range(str, sj, ej);
-    s5 = substring_range(str, ej, en);
-    return strcat(s1, s4, s3, s2, s5);
+       float n;
+       string s1, s2, s3, s4, s5;
+       float si, ei, sj, ej, s0, en;
+       n = tokenizebyseparator(str, " ");  // must match g_maplist processing in ShuffleMaplist and "shuffle"
+       si = argv_start_index(i);
+       sj = argv_start_index(j);
+       ei = argv_end_index(i);
+       ej = argv_end_index(j);
+       s0 = argv_start_index(0);
+       en = argv_end_index(n - 1);
+       s1 = substring_range(str, s0, si);
+       s2 = substring_range(str, si, ei);
+       s3 = substring_range(str, ei, sj);
+       s4 = substring_range(str, sj, ej);
+       s5 = substring_range(str, ej, en);
+       return strcat(s1, s4, s3, s2, s5);
 }
 
 string _shufflewords_str;
 void _shufflewords_swapfunc(float i, float j, entity pass)
 {
-    _shufflewords_str = swapwords(_shufflewords_str, i, j);
+       _shufflewords_str = swapwords(_shufflewords_str, i, j);
 }
 string shufflewords(string str)
 {
-    _shufflewords_str = str;
-    int n = tokenizebyseparator(str, " ");
-    shuffle(n, _shufflewords_swapfunc, NULL);
-    str = _shufflewords_str;
-    _shufflewords_str = string_null;
-    return str;
+       _shufflewords_str = str;
+       int n = tokenizebyseparator(str, " ");
+       shuffle(n, _shufflewords_swapfunc, NULL);
+       str = _shufflewords_str;
+       _shufflewords_str = string_null;
+       return str;
 }
 
 string unescape(string in)
 {
-    in = strzone(in); // but it doesn't seem to be necessary in my tests at least
-
-    int len = strlen(in);
-    string str = "";
-    for (int i = 0; i < len; ++i) {
-        string s = substring(in, i, 1);
-        if (s == "\\") {
-            s = substring(in, i + 1, 1);
-            if (s == "n")
-                str = strcat(str, "\n");
-            else if (s == "\\")
-                str = strcat(str, "\\");
-            else
-                str = strcat(str, substring(in, i, 2));
-            ++i;
-            continue;
-        }
-        str = strcat(str, s);
-    }
-    strunzone(in);
-    return str;
+       in = strzone(in);  // but it doesn't seem to be necessary in my tests at least
+
+       int len = strlen(in);
+       string str = "";
+       for (int i = 0; i < len; ++i)
+       {
+               string s = substring(in, i, 1);
+               if (s == "\\")
+               {
+                       s = substring(in, i + 1, 1);
+                       if (s == "n") str = strcat(str, "\n");
+                       else if (s == "\\") str = strcat(str, "\\");
+                       else str = strcat(str, substring(in, i, 2));
+                       ++i;
+                       continue;
+               }
+               str = strcat(str, s);
+       }
+       strunzone(in);
+       return str;
 }
 
 string strwords(string s, int w)
 {
-    int endpos = 0;
-    for (; w && endpos >= 0; --w) endpos = strstrofs(s, " ", endpos + 1);
-    if (endpos < 0) return s;
-    return substring(s, 0, endpos);
+       int endpos = 0;
+       for ( ; w && endpos >= 0; --w)
+               endpos = strstrofs(s, " ", endpos + 1);
+       if (endpos < 0) return s;
+       return substring(s, 0, endpos);
 }
 
-bool strhasword(string s, string w)
+#define strhasword(s, w) (strstrofs(strcat(" ", s, " "), strcat(" ", w, " "), 0) >= 0)
+
+int u8_strsize(string s)
 {
-    return strstrofs(strcat(" ", s, " "), strcat(" ", w, " "), 0) >= 0;
+       int l = 0;
+       for (int i = 0, c; (c = str2chr(s, i)) > 0; ++i, ++l)
+       {
+               l += (c >= 0x80);
+               l += (c >= 0x800);
+               l += (c >= 0x10000);
+       }
+       return l;
 }
 
-int u8_strsize(string s)
+bool isInvisibleString(string s)
+{
+       s = strdecolorize(s);
+       bool utf8 = cvar("utf8_enable");
+       for (int i = 0, n = strlen(s); i < n; ++i)
+       {
+               int c = str2chr(s, i);
+               switch (c)
+               {
+                       case 0:
+                       case 32:           // space
+                               break;
+                       case 192:          // charmap space
+                               if (!utf8) break;
+                               return false;
+                       case 160:          // space in unicode fonts
+                       case 0xE000 + 192: // utf8 charmap space
+                               if (utf8) break;
+                       default:
+                               return false;
+               }
+       }
+       return true;
+}
+
+// Multiline text file buffers
+
+int buf_load(string pFilename)
+{
+       int buf = buf_create();
+       if (buf < 0) return -1;
+       int fh = fopen(pFilename, FILE_READ);
+       if (fh < 0)
+       {
+               buf_del(buf);
+               return -1;
+       }
+       string l;
+       for (int i = 0; (l = fgets(fh)); ++i)
+               bufstr_set(buf, i, l);
+       fclose(fh);
+       return buf;
+}
+
+void buf_save(float buf, string pFilename)
+{
+       int fh = fopen(pFilename, FILE_WRITE);
+       if (fh < 0) error(strcat("Can't write buf to ", pFilename));
+       int n = buf_getsize(buf);
+       for (int i = 0; i < n; ++i)
+               fputs(fh, strcat(bufstr_get(buf, i), "\n"));
+       fclose(fh);
+}
+
+/**
+ * converts a number to a string with the indicated number of decimals
+ * works for up to 10 decimals!
+ */
+string ftos_decimals(float number, int decimals)
+{
+       // inhibit stupid negative zero
+       if (number == 0) number = 0;
+       // we have sprintf...
+       return sprintf("%.*f", decimals, number);
+}
+
+int vercmp_recursive(string v1, string v2)
+{
+       int dot1 = strstrofs(v1, ".", 0);
+       int dot2 = strstrofs(v2, ".", 0);
+       string s1 = (dot1 == -1) ? v1 : substring(v1, 0, dot1);
+       string s2 = (dot2 == -1) ? v2 : substring(v2, 0, dot2);
+
+       float r;
+       r = stof(s1) - stof(s2);
+       if (r != 0) return r;
+
+       r = strcasecmp(s1, s2);
+       if (r != 0) return r;
+
+       if (dot1 == -1) return (dot2 == -1) ? 0 : -1;
+       else return (dot2 == -1) ? 1 : vercmp_recursive(substring(v1, dot1 + 1, 999), substring(v2, dot2 + 1, 999));
+}
+
+int vercmp(string v1, string v2)
 {
-    int l = 0;
-    for (int i = 0, c; (c = str2chr(s, i)) > 0; ++i, ++l)
-    {
-        l += (c >= 0x80);
-        l += (c >= 0x800);
-        l += (c >= 0x10000);
-    }
-    return l;
+       if (strcasecmp(v1, v2) == 0) return 0;  // early out check
+
+       // "git" beats all
+       if (v1 == "git") return 1;
+       if (v2 == "git") return -1;
+
+       return vercmp_recursive(v1, v2);
 }
 
+const string HEXDIGITS = "0123456789ABCDEF0123456789abcdef";
+#define HEXDIGIT_TO_DEC_RAW(d) (strstrofs(HEXDIGITS, (d), 0))
+#define HEXDIGIT_TO_DEC(d) ((HEXDIGIT_TO_DEC_RAW(d) | 0x10) - 0x10)
+#define DEC_TO_HEXDIGIT(d) (substring(HEXDIGITS, (d), 1))
+
 #endif
index 507c417f57afba820771429592d7867267c6ff6c..bce19f4fd674e807cc0ee4beb749ddf80ec4c3dd 100644 (file)
@@ -2,34 +2,34 @@
 #define STRUCT_H
 
 #ifndef QCC_SUPPORT_STRUCT
-    #define _STRUCT_DECLARE(x, id, type, END) noref type x ##_## id ;
-    #define STRUCT_DECLARE(id, s) s(_STRUCT_DECLARE, id)
+       #define _STRUCT_DECLARE(x, id, type, END) noref type x##_##id;
+       #define STRUCT_DECLARE(id, s) s(_STRUCT_DECLARE, id)
 
-    #define _STRUCT_PARAM_(x, id, type) type x ##_## id ,
-    #define _STRUCT_PARAM_END(x, id, type) type x ##_## id
-    #define _STRUCT_PARAM(x, id, type, isend) _STRUCT_PARAM_##isend(x, id, type)
-    #define STRUCT_PARAM(id, s) s(_STRUCT_PARAM, id)
+       #define _STRUCT_PARAM_(x, id, type) type x##_##id,
+       #define _STRUCT_PARAM_END(x, id, type) type x##_##id
+       #define _STRUCT_PARAM(x, id, type, isend) _STRUCT_PARAM_##isend(x, id, type)
+       #define STRUCT_PARAM(id, s) s(_STRUCT_PARAM, id)
 
-    #define _STRUCT_PASS_(x, id, type) x ##_## id ,
-    #define _STRUCT_PASS_END(x, id, type) x ##_## id
-    #define _STRUCT_PASS(x, id, type, END) _STRUCT_PASS_##END(x, id, type)
-    #define STRUCT_PASS(id, s) s(_STRUCT_PASS, id)
+       #define _STRUCT_PASS_(x, id, type) x##_##id,
+       #define _STRUCT_PASS_END(x, id, type) x##_##id
+       #define _STRUCT_PASS(x, id, type, END) _STRUCT_PASS_##END(x, id, type)
+       #define STRUCT_PASS(id, s) s(_STRUCT_PASS, id)
 
-    #define _STRUCT_STORE_DST(_, it) it
-    #define _STRUCT_STORE_SRC(it, _) it
-    #define _CONCAT3_(a, b, c) a ## b ## c
-    #define _CONCAT3(a, b, c) _CONCAT3_(a, b, c)
-    #define _STRUCT_STORE(x, id, type, END) _CONCAT3(_STRUCT_STORE_DST x, _, id) = _CONCAT3(_STRUCT_STORE_SRC x, _, id);
-    #define STRUCT_STORE(from, to, s) s(_STRUCT_STORE, (from, to))
+       #define _STRUCT_STORE_DST(_, it) it
+       #define _STRUCT_STORE_SRC(it, _) it
+       #define _CONCAT3_(a, b, c) a##b##c
+       #define _CONCAT3(a, b, c) _CONCAT3_(a, b, c)
+       #define _STRUCT_STORE(x, id, type, END) _CONCAT3(_STRUCT_STORE_DST x, _, id) = _CONCAT3(_STRUCT_STORE_SRC x, _, id);
+       #define STRUCT_STORE(from, to, s) s(_STRUCT_STORE, (from, to))
 
-    #define STRUCT(id, ...)
+       #define STRUCT(id, ...)
 #else
-    #define STRUCT_DECLARE(id, type) type id;
-    #define STRUCT_PARAM(id, type) type id
-    #define STRUCT_PASS(id, type) id
-    #define STRUCT_STORE(from, to, s) to = from
-    #define _STRUCT_MEMBER(my, id, type, END) type id;
-    #define STRUCT(id, s) struct STRUCT_##id { s(_STRUCT_MEMBER, ) };
+       #define STRUCT_DECLARE(id, type) type id;
+       #define STRUCT_PARAM(id, type) type id
+       #define STRUCT_PASS(id, type) id
+       #define STRUCT_STORE(from, to, s) to = from
+       #define _STRUCT_MEMBER(my, id, type, END) type id;
+       #define STRUCT(id, s) struct STRUCT_##id { s(_STRUCT_MEMBER, ) };
 #endif
 
 #endif
index 23907fe5f15ed4106c69fae466807abd79fe2911..3929bf1c3893cbd48433b6df03821dc4bbd4d7f1 100644 (file)
@@ -6,7 +6,7 @@ float TEST_ok;
 void TEST_Fail(string cond)
 {
        LOG_INFOF("Assertion failed: ", cond);
-       //backtrace();
+       // backtrace();
        ++TEST_failed;
 }
 
@@ -19,14 +19,13 @@ float TEST_RunAll()
 {
        int f = 0;
        float n = numentityfields();
-       for(int i = 0; i < n; ++i)
+       for (int i = 0; i < n; ++i)
        {
                string name = entityfieldname(i);
-               if(substring(name, 0, 6) == "_TEST_")
-                       if(!TEST_Run(substring(name, 6, -1)))
-                               ++f;
+               if (substring(name, 0, 6) == "_TEST_")
+                       if (!TEST_Run(substring(name, 6, -1))) ++f;
        }
-       if(f)
+       if (f)
        {
                LOG_INFOF("%d tests failed\n", f);
                return 1;
@@ -43,12 +42,12 @@ float TEST_Run(string s)
        LOG_INFOF("%s: testing...\n", s);
        TEST_failed = TEST_ok = 0;
        callfunction(strcat("_TEST_", s));
-       if(TEST_failed > 0)
+       if (TEST_failed > 0)
        {
                LOG_INFOF("%s: %d items failed.\n", s, TEST_failed);
                return 0;
        }
-       else if(!TEST_ok)
+       else if (!TEST_ok)
        {
                LOG_INFOF("%s: did not complete.\n", s);
                return 0;
index edc2f5bf37ff959f3b6fe6375d29923b5f9b086b..6cddb12e50b1257ac5fe60a56ff3c298889420bc 100644 (file)
@@ -1,7 +1,12 @@
 #ifndef TEST_H
 #define TEST_H
 
-#define TEST_Check(cond) do { if(!(cond)) TEST_Fail(#cond); } while(0)
+#define TEST_Check(cond) \
+       do \
+       { \
+               if (!(cond)) TEST_Fail( #cond); \
+       } \
+       while (0)
 
 void TEST_OK();
 void TEST_Fail(string cond);
index 9648b2080f5abb0cae734a96d3a220dcd93ae5c2..0a48ef6cd3b84b656d2cebd5d685b64d67f54d66 100644 (file)
@@ -24,16 +24,13 @@ int autocvar__urllib_nextslot;
 
 float url_URI_Get_Callback(int id, float status, string data)
 {
-       if(id < MIN_URL_ID)
-               return 0;
+       if (id < MIN_URL_ID) return 0;
        id -= MIN_URL_ID;
-       if(id >= NUM_URL_ID)
-               return 0;
+       if (id >= NUM_URL_ID) return 0;
        entity e;
        e = url_fromid[id];
-       if(!e)
-               return 0;
-       if(e.url_rbuf >= 0 || e.url_wbuf >= 0)
+       if (!e) return 0;
+       if (e.url_rbuf >= 0 || e.url_wbuf >= 0)
        {
                LOG_INFOF("WARNING: handle %d (%s) has already received data?!?\n", id + NUM_URL_ID, e.url_url);
                return 0;
@@ -43,16 +40,15 @@ float url_URI_Get_Callback(int id, float status, string data)
        url_fromid[id] = NULL;
 
        // if we get here, we MUST have both buffers cleared
-       if(e.url_rbuf != -1 || e.url_wbuf != -1 || e.url_fh != URL_FH_CURL)
-               error("url_URI_Get_Callback: not a request waiting for data");
+       if (e.url_rbuf != -1 || e.url_wbuf != -1 || e.url_fh != URL_FH_CURL) error("url_URI_Get_Callback: not a request waiting for data");
 
-       if(status == 0)
+       if (status == 0)
        {
                // WE GOT DATA!
                float n, i;
                n = tokenizebyseparator(data, "\n");
                e.url_rbuf = buf_create();
-               if(e.url_rbuf < 0)
+               if (e.url_rbuf < 0)
                {
                        LOG_INFO("url_URI_Get_Callback: out of memory in buf_create\n");
                        e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
@@ -61,7 +57,7 @@ float url_URI_Get_Callback(int id, float status, string data)
                        return 1;
                }
                e.url_rbufpos = 0;
-               if(e.url_rbuf < 0)
+               if (e.url_rbuf < 0)
                {
                        LOG_INFO("url_URI_Get_Callback: out of memory in buf_create\n");
                        e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
@@ -69,7 +65,7 @@ float url_URI_Get_Callback(int id, float status, string data)
                        remove(e);
                        return 1;
                }
-               for(i = 0; i < n; ++i)
+               for (i = 0; i < n; ++i)
                        bufstr_set(e.url_rbuf, i, argv(i));
                e.url_ready(e, e.url_ready_pass, URL_READY_CANREAD);
                return 1;
@@ -88,9 +84,9 @@ void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
 {
        entity e;
        int i;
-       if(strstrofs(url, "://", 0) >= 0)
+       if (strstrofs(url, "://", 0) >= 0)
        {
-               switch(mode)
+               switch (mode)
                {
                        case FILE_WRITE:
                        case FILE_APPEND:
@@ -98,12 +94,12 @@ void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
                                // attempts to close will result in a reading handle
 
                                // create a writing end that does nothing yet
-                               e = spawn();
-                               e.classname = "url_single_fopen_file";
+                               e = new(url_single_fopen_file);
+                               make_pure(e);
                                e.url_url = strzone(url);
                                e.url_fh = URL_FH_CURL;
                                e.url_wbuf = buf_create();
-                               if(e.url_wbuf < 0)
+                               if (e.url_wbuf < 0)
                                {
                                        LOG_INFO("url_single_fopen: out of memory in buf_create\n");
                                        rdy(e, pass, URL_READY_ERROR);
@@ -122,15 +118,13 @@ void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
                                // read data only
 
                                // get slot for HTTP request
-                               for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
-                                       if(url_fromid[i] == NULL)
-                                               break;
-                               if(i >= NUM_URL_ID)
+                               for (i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
+                                       if (url_fromid[i] == NULL) break;
+                               if (i >= NUM_URL_ID)
                                {
-                                       for(i = 0; i < autocvar__urllib_nextslot; ++i)
-                                               if(url_fromid[i] == NULL)
-                                                       break;
-                                       if(i >= autocvar__urllib_nextslot)
+                                       for (i = 0; i < autocvar__urllib_nextslot; ++i)
+                                               if (url_fromid[i] == NULL) break;
+                                       if (i >= autocvar__urllib_nextslot)
                                        {
                                                LOG_INFO("url_single_fopen: too many concurrent requests\n");
                                                rdy(NULL, pass, URL_READY_ERROR);
@@ -139,7 +133,7 @@ void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
                                }
 
                                // GET the data
-                               if(!crypto_uri_postbuf(url, i + MIN_URL_ID, string_null, string_null, -1, 0))
+                               if (!crypto_uri_postbuf(url, i + MIN_URL_ID, string_null, string_null, -1, 0))
                                {
                                        LOG_INFO("url_single_fopen: failure in crypto_uri_postbuf\n");
                                        rdy(NULL, pass, URL_READY_ERROR);
@@ -149,8 +143,8 @@ void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
                                // Make a dummy handle object (no buffers at
                                // all). Wait for data to come from the
                                // server, then call the callback
-                               e = spawn();
-                               e.classname = "url_single_fopen_file";
+                               e = new(url_single_fopen_file);
+                               make_pure(e);
                                e.url_url = strzone(url);
                                e.url_fh = URL_FH_CURL;
                                e.url_rbuf = -1;
@@ -165,14 +159,14 @@ void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
                                break;
                }
        }
-       else if(url == "-")
+       else if (url == "-")
        {
-               switch(mode)
+               switch (mode)
                {
                        case FILE_WRITE:
                        case FILE_APPEND:
-                               e = spawn();
-                               e.classname = "url_single_fopen_stdout";
+                               e = new(url_single_fopen_stdout);
+                               make_pure(e);
                                e.url_fh = URL_FH_STDOUT;
                                e.url_ready = rdy;
                                e.url_ready_pass = pass;
@@ -188,22 +182,20 @@ void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
        {
                float fh;
                fh = fopen(url, mode);
-               if(fh < 0)
+               if (fh < 0)
                {
                        rdy(NULL, pass, URL_READY_ERROR);
                        return;
                }
                else
                {
-                       e = spawn();
-                       e.classname = "url_single_fopen_file";
+                       e = new(url_single_fopen_file);
+                       make_pure(e);
                        e.url_fh = fh;
                        e.url_ready = rdy;
                        e.url_ready_pass = pass;
-                       if(mode == FILE_READ)
-                               rdy(e, pass, URL_READY_CANREAD);
-                       else
-                               rdy(e, pass, URL_READY_CANWRITE);
+                       if (mode == FILE_READ) rdy(e, pass, URL_READY_CANREAD);
+                       else rdy(e, pass, URL_READY_CANWRITE);
                }
        }
 }
@@ -213,30 +205,28 @@ void url_fclose(entity e)
 {
        int i;
 
-       if(e.url_fh == URL_FH_CURL)
+       if (e.url_fh == URL_FH_CURL)
        {
-               if(e.url_rbuf == -1 || e.url_wbuf != -1) // not(post GET/POST request)
-               if(e.url_rbuf != -1 || e.url_wbuf == -1) // not(pre POST request)
-                       error("url_fclose: not closable in current state");
+               if (e.url_rbuf == -1 || e.url_wbuf != -1)     // not(post GET/POST request)
+                       if (e.url_rbuf != -1 || e.url_wbuf == -1) // not(pre POST request)
+                               error("url_fclose: not closable in current state");
 
                // closing an URL!
-               if(e.url_wbuf >= 0)
+               if (e.url_wbuf >= 0)
                {
                        // we are closing the write end (HTTP POST request)
 
                        // get slot for HTTP request
-                       for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
-                               if(url_fromid[i] == NULL)
-                                       break;
-                       if(i >= NUM_URL_ID)
+                       for (i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
+                               if (url_fromid[i] == NULL) break;
+                       if (i >= NUM_URL_ID)
                        {
-                               for(i = 0; i < autocvar__urllib_nextslot; ++i)
-                                       if(url_fromid[i] == NULL)
-                                               break;
-                               if(i >= autocvar__urllib_nextslot)
+                               for (i = 0; i < autocvar__urllib_nextslot; ++i)
+                                       if (url_fromid[i] == NULL) break;
+                               if (i >= autocvar__urllib_nextslot)
                                {
                                        LOG_INFO("url_fclose: too many concurrent requests\n");
-                                       e.url_ready(e,e.url_ready_pass, URL_READY_ERROR);
+                                       e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
                                        buf_del(e.url_wbuf);
                                        strunzone(e.url_url);
                                        remove(e);
@@ -245,7 +235,7 @@ void url_fclose(entity e)
                        }
 
                        // POST the data
-                       if(!crypto_uri_postbuf(e.url_url, i + MIN_URL_ID, "text/plain", "", e.url_wbuf, 0))
+                       if (!crypto_uri_postbuf(e.url_url, i + MIN_URL_ID, "text/plain", "", e.url_wbuf, 0))
                        {
                                LOG_INFO("url_fclose: failure in crypto_uri_postbuf\n");
                                e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
@@ -275,16 +265,16 @@ void url_fclose(entity e)
                        remove(e);
                }
        }
-       else if(e.url_fh == URL_FH_STDOUT)
+       else if (e.url_fh == URL_FH_STDOUT)
        {
-               e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
+               e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED);  // closing creates no reading handle
                remove(e);
        }
        else
        {
                // file
                fclose(e.url_fh);
-               e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
+               e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED);  // closing creates no reading handle
                remove(e);
        }
 }
@@ -292,17 +282,16 @@ void url_fclose(entity e)
 // with \n (blame FRIK_FILE)
 string url_fgets(entity e)
 {
-       if(e.url_fh == URL_FH_CURL)
+       if (e.url_fh == URL_FH_CURL)
        {
-               if(e.url_rbuf == -1)
-                       error("url_fgets: not readable in current state");
+               if (e.url_rbuf == -1) error("url_fgets: not readable in current state");
                // curl
                string s;
                s = bufstr_get(e.url_rbuf, e.url_rbufpos);
                e.url_rbufpos += 1;
                return s;
        }
-       else if(e.url_fh == URL_FH_STDOUT)
+       else if (e.url_fh == URL_FH_STDOUT)
        {
                // stdout
                return string_null;
@@ -317,15 +306,14 @@ string url_fgets(entity e)
 // without \n (blame FRIK_FILE)
 void url_fputs(entity e, string s)
 {
-       if(e.url_fh == URL_FH_CURL)
+       if (e.url_fh == URL_FH_CURL)
        {
-               if(e.url_wbuf == -1)
-                       error("url_fputs: not writable in current state");
+               if (e.url_wbuf == -1) error("url_fputs: not writable in current state");
                // curl
                bufstr_set(e.url_wbuf, e.url_wbufpos, s);
                e.url_wbufpos += 1;
        }
-       else if(e.url_fh == URL_FH_STDOUT)
+       else if (e.url_fh == URL_FH_STDOUT)
        {
                // stdout
                LOG_INFO(s);
@@ -341,9 +329,9 @@ void url_fputs(entity e, string s)
 void url_multi_ready(entity fh, entity me, float status)
 {
        float n;
-       if(status == URL_READY_ERROR || status < 0)
+       if (status == URL_READY_ERROR || status < 0)
        {
-               if(status == -422) // Unprocessable Entity
+               if (status == -422)  // Unprocessable Entity
                {
                        LOG_INFO("uri_multi_ready: got HTTP error 422, data is in unusable format - not continuing\n");
                        me.url_ready(fh, me.url_ready_pass, status);
@@ -353,7 +341,7 @@ void url_multi_ready(entity fh, entity me, float status)
                }
                me.url_attempt += 1;
                n = tokenize_console(me.url_url);
-               if(n <= me.url_attempt)
+               if (n <= me.url_attempt)
                {
                        me.url_ready(fh, me.url_ready_pass, status);
                        strunzone(me.url_url);
@@ -369,16 +357,15 @@ void url_multi_fopen(string url, int mode, url_ready_func rdy, entity pass)
 {
        float n;
        n = tokenize_console(url);
-       if(n <= 0)
+       if (n <= 0)
        {
                LOG_INFO("url_multi_fopen: need at least one URL\n");
                rdy(NULL, pass, URL_READY_ERROR);
                return;
        }
 
-       entity me;
-       me = spawn();
-       me.classname = "url_multi";
+       entity me = new(url_multi);
+       make_pure(me);
        me.url_url = strzone(url);
        me.url_attempt = 0;
        me.url_mode = mode;
index e4b8a8f27312f5d096817262abb6e1908363a057..918504ff8b64fdc44a168b7e1aae026fa5d83124 100644 (file)
@@ -16,7 +16,7 @@ const float URL_READY_CLOSED   =  0;
 const float URL_READY_CANWRITE =  1;
 const float URL_READY_CANREAD  =  2;
 // errors: -1, or negative HTTP status code
-typedef void(entity handle, entity pass, float status) url_ready_func;
+typedef void (entity handle, entity pass, float status) url_ready_func;
 
 void url_single_fopen(string url, float mode, url_ready_func rdy, entity pass);
 void url_fclose(entity e);
index b57e27aeb9583a9952ac80207c619814097ac982..0cda013c0e8238ba26e259c0a232befd690ee9de 100644 (file)
 #ifndef VECTOR_H
 #define VECTOR_H
 
+#define cross(a, b) ((a) >< (b))
+/*
+vector cross(vector a, vector b)
+{
+       return
+               '1 0 0' * (a.y * b.z - a.z * b.y)
+       +       '0 1 0' * (a.z * b.x - a.x * b.z)
+       +       '0 0 1' * (a.x * b.y - a.y * b.x);
+}
+*/
+
 const vector eX = '1 0 0';
 const vector eY = '0 1 0';
 const vector eZ = '0 0 1';
 
 vector randompos(vector m1, vector m2)
 {
-    vector v;
-    m2 = m2 - m1;
-    v_x = m2_x * random() + m1_x;
-    v_y = m2_y * random() + m1_y;
-    v_z = m2_z * random() + m1_z;
-    return     v;
+       vector v;
+       m2 = m2 - m1;
+       v_x = m2_x * random() + m1_x;
+       v_y = m2_y * random() + m1_y;
+       v_z = m2_z * random() + m1_z;
+       return v;
 }
 
 float vlen2d(vector v)
 {
-    return sqrt(v.x * v.x + v.y * v.y);
+       return sqrt(v.x * v.x + v.y * v.y);
 }
 
 float vlen_maxnorm2d(vector v)
 {
-    return max(v.x, v.y, -v.x, -v.y);
+       return max(v.x, v.y, -v.x, -v.y);
 }
 
 float vlen_minnorm2d(vector v)
 {
-    return min(max(v.x, -v.x), max(v.y, -v.y));
+       return min(max(v.x, -v.x), max(v.y, -v.y));
 }
 
 float dist_point_line(vector p, vector l0, vector ldir)
 {
-    ldir = normalize(ldir);
+       ldir = normalize(ldir);
 
-    // remove the component in line direction
-    p = p - (p * ldir) * ldir;
+       // remove the component in line direction
+       p = p - (p * ldir) * ldir;
 
-    // vlen of the remaining vector
-    return vlen(p);
+       // vlen of the remaining vector
+       return vlen(p);
 }
 
 /** requires that m2>m1 in all coordinates, and that m4>m3 */
-float boxesoverlap(vector m1, vector m2, vector m3, vector m4) {return m2_x >= m3_x && m1_x <= m4_x && m2_y >= m3_y && m1_y <= m4_y && m2_z >= m3_z && m1_z <= m4_z;}
+float boxesoverlap(vector m1, vector m2, vector m3, vector m4) { return m2_x >= m3_x && m1_x <= m4_x && m2_y >= m3_y && m1_y <= m4_y && m2_z >= m3_z && m1_z <= m4_z; }
 
 /** requires the same as boxesoverlap, but is a stronger condition */
-float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs) {return smins.x >= bmins.x && smaxs.x <= bmaxs.x && smins.y >= bmins.y && smaxs.y <= bmaxs.y && smins.z >= bmins.z && smaxs.z <= bmaxs.z;}
+float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs) { return smins.x >= bmins.x && smaxs.x <= bmaxs.x && smins.y >= bmins.y && smaxs.y <= bmaxs.y && smins.z >= bmins.z && smaxs.z <= bmaxs.z; }
 
 
 vector vec2(vector v)
 {
-    v.z = 0;
-    return v;
+       v.z = 0;
+       return v;
 }
 
 vector vec3(float x, float y, float z)
 {
-    vector v; v.x = x; v.y = y; v.z = z;
-    return v;
+       vector v;
+       v.x = x;
+       v.y = y;
+       v.z = z;
+       return v;
 }
 
-#ifndef MENUQC
-vector get_corner_position(entity box, int corner)
+vector rotate(vector v, float a)
 {
-    switch (corner) {
-        case 1: return vec3(box.absmin.x, box.absmin.y, box.absmin.z);
-        case 2: return vec3(box.absmax.x, box.absmin.y, box.absmin.z);
-        case 3: return vec3(box.absmin.x, box.absmax.y, box.absmin.z);
-        case 4: return vec3(box.absmin.x, box.absmin.y, box.absmax.z);
-        case 5: return vec3(box.absmax.x, box.absmax.y, box.absmin.z);
-        case 6: return vec3(box.absmin.x, box.absmax.y, box.absmax.z);
-        case 7: return vec3(box.absmax.x, box.absmin.y, box.absmax.z);
-        case 8: return vec3(box.absmax.x, box.absmax.y, box.absmax.z);
-        default: return '0 0 0';
-    }
+       float a_sin = sin(a), a_cos = cos(a);
+       vector r = '0 0 0';
+       r.x =      v.x * a_cos + v.y * a_sin;
+       r.y = -1 * v.x * a_sin + v.y * a_cos;
+       return r;
 }
 
-vector NearestPointOnBox(entity box, vector org)
+vector yinvert(vector v)
 {
-    vector m1 = box.mins + box.origin;
-    vector m2 = box.maxs + box.origin;
-
-    vector ret;
-    ret.x = bound(m1.x, org.x, m2.x);
-    ret.y = bound(m1.y, org.y, m2.y);
-    ret.z = bound(m1.z, org.z, m2.z);
-    return ret;
+       v.y = 1 - v.y;
+       return v;
 }
+
+#ifndef MENUQC
+       vector get_corner_position(entity box, int corner)
+       {
+               switch (corner)
+               {
+                       case 1: return vec3(box.absmin.x, box.absmin.y, box.absmin.z);
+                       case 2: return vec3(box.absmax.x, box.absmin.y, box.absmin.z);
+                       case 3: return vec3(box.absmin.x, box.absmax.y, box.absmin.z);
+                       case 4: return vec3(box.absmin.x, box.absmin.y, box.absmax.z);
+                       case 5: return vec3(box.absmax.x, box.absmax.y, box.absmin.z);
+                       case 6: return vec3(box.absmin.x, box.absmax.y, box.absmax.z);
+                       case 7: return vec3(box.absmax.x, box.absmin.y, box.absmax.z);
+                       case 8: return vec3(box.absmax.x, box.absmax.y, box.absmax.z);
+                       default: return '0 0 0';
+               }
+       }
+
+       vector NearestPointOnBox(entity box, vector org)
+       {
+               vector m1 = box.mins + box.origin;
+               vector m2 = box.maxs + box.origin;
+
+               vector ret;
+               ret.x = bound(m1.x, org.x, m2.x);
+               ret.y = bound(m1.y, org.y, m2.y);
+               ret.z = bound(m1.z, org.z, m2.z);
+               return ret;
+       }
 #endif
 
 #endif
index aba39c2cb70226b8e36967db5e224ebaf7829166..dd2b5cc9a115b2d606e5dfffc05480ac31940d7d 100644 (file)
@@ -25,13 +25,12 @@ void WarpZone_Fade_PreDraw()
                self.drawmask = MASK_NORMAL;
 }
 
-void WarpZone_Read(float isnew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_WARPZONE, bool isnew)
+{
        warpzone_warpzones_exist = 1;
        if (!self.enemy)
        {
-               self.enemy = spawn();
-               self.enemy.classname = "warpzone_from";
+               self.enemy = new(warpzone_from);
        }
        self.classname = "trigger_warpzone";
 
@@ -88,10 +87,11 @@ void WarpZone_Read(float isnew)
        // how to draw
        // engine currently wants this
        self.predraw = WarpZone_Fade_PreDraw;
+       return true;
 }
 
-void WarpZone_Camera_Read(float isnew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_WARPZONE_CAMERA, bool isnew)
+{
        warpzone_cameras_exist = 1;
        self.classname = "func_warpzone_camera";
 
@@ -144,18 +144,19 @@ void WarpZone_Camera_Read(float isnew)
        // how to draw
        // engine currently wants this
        self.predraw = WarpZone_Fade_PreDraw;
+       return true;
 }
 
 void CL_RotateMoves(vector ang) = #638;
-void WarpZone_Teleported_Read(float isnew)
-{SELFPARAM();
-       vector v;
+NET_HANDLE(ENT_CLIENT_WARPZONE_TELEPORTED, bool isnew)
+{
        self.classname = "warpzone_teleported";
+       vector v;
        v.x = ReadCoord();
        v.y = ReadCoord();
        v.z = ReadCoord();
-       if(!isnew)
-               return;
+       return = true;
+       if (!isnew) return;
        self.warpzone_transform = v;
        setproperty(VF_CL_VIEWANGLES, WarpZone_TransformVAngles(self, getpropertyvec(VF_CL_VIEWANGLES)));
        if(checkextension("DP_CSQC_ROTATEMOVES"))
@@ -279,10 +280,6 @@ void WarpZone_FixView()
                setproperty(VF_ORIGIN, org + o);
 }
 
-void WarpZone_Init()
-{
-}
-
 void WarpZone_Shutdown()
 {
        WarpZone_View_Outside();
index 016ac58822c258319c0792714e76cf374e24128b..8f3e643b5c0eabae6e8d30817a40ccebc071a7df 100644 (file)
@@ -1,14 +1,9 @@
 #ifndef LIB_WARPZONE_CLIENT_H
 #define LIB_WARPZONE_CLIENT_H
 
-void WarpZone_Read(float bIsNewEntity);
-void WarpZone_Camera_Read(float bIsNewEntity);
-void WarpZone_Teleported_Read(float bIsNewEntity);
-
 void WarpZone_FixPMove();
 void WarpZone_FixView();
 
-void WarpZone_Init();
 void WarpZone_Shutdown();
 
 vector warpzone_save_view_origin;
index 6fe901bd87d3cf7f860be73b05aee99ddfef89aa..50339a73038121a5b8541200be0aede37db6bd1a 100644 (file)
@@ -186,8 +186,8 @@ void WarpZone_Trace_InitTransform()
 {
        if(!WarpZone_trace_transform)
        {
-               WarpZone_trace_transform = spawn();
-               WarpZone_trace_transform.classname = "warpzone_trace_transform";
+               WarpZone_trace_transform = new(warpzone_trace_transform);
+               make_pure(WarpZone_trace_transform);
        }
        WarpZone_Accumulator_Clear(WarpZone_trace_transform);
 }
@@ -457,7 +457,7 @@ entity WarpZone_TrailParticles_trace_callback_own;
 float WarpZone_TrailParticles_trace_callback_eff;
 void WarpZone_TrailParticles_trace_callback(vector from, vector endpos, vector to)
 {
-       trailparticles(WarpZone_TrailParticles_trace_callback_own, WarpZone_TrailParticles_trace_callback_eff, from, endpos);
+       __trailparticles(WarpZone_TrailParticles_trace_callback_own, WarpZone_TrailParticles_trace_callback_eff, from, endpos);
 }
 
 void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
@@ -572,37 +572,20 @@ vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
 
 bool WarpZoneLib_BadEntity(entity e)
 {
-       string myclassname = e.classname;
-       if (e.instanceOfObject) return true;
-       switch(myclassname)
+       string s = e.classname;
+       if (is_pure(e)) return true;
+       switch (s)
        {
-               case "deathtype":
-               case "weaponentity":
-               case "exteriorweaponentity":
-               case "csqc_score_team":
-               case "pingplreport":
-               case "ent_client_scoreinfo":
-               case "saved_cvar_value":
-               case "accuracy":
                case "entcs_sender":
                case "entcs_receiver":
-               case "clientinit":
-               case "sprite_waypoint":
-               case "waypoint":
-               case "gibsplash":
-               //case "net_linked": // actually some real entities are linked without classname, fail
+               // case "net_linked": // actually some real entities are linked without classname, fail
                case "":
                        return true;
        }
 
-       if(startsWith(myclassname, "msg_"))
-               return true;
-
-       if(startsWith(myclassname, "target_"))
-               return true;
+       if (startsWith(s, "target_")) return true;
 
-       if(startsWith(myclassname, "info_"))
-               return true;
+       if (startsWith(s, "info_")) return true;
 
        return false;
 }
@@ -703,8 +686,7 @@ void WarpZone_RefSys_CheckCreate(entity me)
 {
        if(me.WarpZone_refsys.owner != me)
        {
-               me.WarpZone_refsys = spawn();
-               me.WarpZone_refsys.classname = "warpzone_refsys";
+               me.WarpZone_refsys = new(warpzone_refsys);
                me.WarpZone_refsys.owner = me;
                me.WarpZone_refsys.think = WarpZone_RefSys_GC;
                me.WarpZone_refsys.nextthink = time + 1;
index 92b7ee14dd9080d2fac9d17527042f929cbe3433..ac3b65ff1a276a3dd35c36f1c12d206055fd9fb0 100644 (file)
@@ -290,11 +290,3 @@ int isunordered(float x, float y)
 {
        return !(x < y || x == y || x > y);
 }
-
-vector cross(vector a, vector b)
-{
-       return
-               '1 0 0' * (a.y * b.z - a.z * b.y)
-       +       '0 1 0' * (a.z * b.x - a.x * b.z)
-       +       '0 0 1' * (a.x * b.y - a.y * b.x);
-}
index 9acece2ab2befeacad137ddc049ac01b1b41f407..c3de3838dde28cb70ed0d9e915751554436ccd49 100644 (file)
@@ -115,7 +115,4 @@ const float M_2_SQRTPI = 1.12837916709551257390;  /* 2/sqrt(pi) */
 const float M_SQRT2    = 1.41421356237309504880;  /* sqrt(2) */
 const float M_SQRT1_2  = 0.70710678118654752440;  /* 1/sqrt(2) */
 
-// Non-<math.h> stuff follows here.
-vector cross(vector a, vector b);
-
 #endif
index e21e4cab4942029f951c755498b06c2a758785ec..27640770a1b5ea1ff88a9fbb58b43dd0fd669d86 100644 (file)
@@ -53,7 +53,7 @@ void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector
 
 bool WarpZone_Teleported_Send(entity to, int sf)
 {SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED);
        WriteCoord(MSG_ENTITY, self.angles.x);
        WriteCoord(MSG_ENTITY, self.angles.y);
        WriteCoord(MSG_ENTITY, self.angles.z);
@@ -137,7 +137,7 @@ float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
                // instead of fixangle, send the transform to the client for smoother operation
                player.fixangle = false;
 
-               entity ts = spawn();
+               entity ts = new(warpzone_teleported);
                setmodel(ts, MDL_Null);
                ts.SendEntity = WarpZone_Teleported_Send;
                ts.SendFlags = 0xFFFFFF;
@@ -147,7 +147,6 @@ float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
                ts.owner = player;
                ts.enemy = wz;
                ts.effects = EF_NODEPTHTEST;
-               ts.classname = "warpzone_teleported";
                ts.angles = wz.warpzone_transform;
        }
 #endif
@@ -155,7 +154,7 @@ float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
        return 1;
 }
 
-void WarpZone_Touch (void)
+void WarpZone_Touch ()
 {SELFPARAM();
        if(other.classname == "trigger_warpzone")
                return;
@@ -217,7 +216,7 @@ void WarpZone_Touch (void)
 
 bool WarpZone_Send(entity to, int sendflags)
 {SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_WARPZONE);
 
        // we must send this flag for clientside to match properly too
        int f = 0;
@@ -272,7 +271,7 @@ bool WarpZone_Send(entity to, int sendflags)
 bool WarpZone_Camera_Send(entity to, int sendflags)
 {SELFPARAM();
        int f = 0;
-       WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA);
 
        if(self.warpzone_fadestart)
                BITSET_ASSIGN(f, 2);
@@ -486,7 +485,7 @@ void WarpZonePosition_InitStep_FindTarget()
        self.enemy.aiment = self;
 }
 
-void WarpZoneCamera_Think(void)
+void WarpZoneCamera_Think()
 {SELFPARAM();
        if(self.warpzone_save_origin != self.origin
        || self.warpzone_save_angles != self.angles
@@ -885,7 +884,7 @@ spawnfunc(target_warpzone_reconnect)
        spawnfunc_trigger_warpzone_reconnect(this); // both names make sense here :(
 }
 
-void WarpZone_PlayerPhysics_FixVAngle(void)
+void WarpZone_PlayerPhysics_FixVAngle()
 {SELFPARAM();
 #ifndef WARPZONE_DONT_FIX_VANGLE
        if(IS_REAL_CLIENT(self))
index 943f0322a677f4ecb0816ea32a6d1e05852f56be..b96b7b3361e3d3c6ce12c063fa27839d2052d384 100644 (file)
@@ -12,7 +12,7 @@ float WarpZone_Projectile_Touch_ImpactFilter_Callback();
 //const float ENT_CLIENT_WARPZONE;
 //const float ENT_CLIENT_WARPZONE_CAMERA;
 
-void WarpZone_PlayerPhysics_FixVAngle(void);
+void WarpZone_PlayerPhysics_FixVAngle();
 
-void WarpZone_PostInitialize_Callback(void);
+void WarpZone_PostInitialize_Callback();
 #endif
index d24220fefae0ab9fe4695d8287fcc21c1a2a7bcd..09bf77217f142c28d62c491df1e86241af3b8e2f 100644 (file)
 #ifndef ANIM_ANIMATION_H
-#define ANIM_ANIMATION_H
-void setterDummy(entity, float);
-CLASS(Animation, Object)
-       METHOD(Animation, configureAnimation, void(entity, entity, void(entity, float), float, float, float, float));
-       METHOD(Animation, update, void(entity, float, float, float));
-       METHOD(Animation, setTimeStartEnd, void(entity, float, float));
-       METHOD(Animation, setTimeStartDuration, void(entity, float, float));
-       METHOD(Animation, setValueStartEnd, void(entity, float, float));
-       METHOD(Animation, setValueStartDelta, void(entity, float, float));
-       METHOD(Animation, setObjectSetter, void(entity, entity, void(entity, float)));
-       METHOD(Animation, tick, void(entity, float));
-       METHOD(Animation, calcValue, float(entity, float, float, float, float));
-       METHOD(Animation, isStopped, float(entity));
-       METHOD(Animation, stopAnim, void(entity));
-       METHOD(Animation, resumeAnim, void(entity));
-       METHOD(Animation, isFinished, float(entity));
-       METHOD(Animation, finishAnim, void(entity));
-       ATTRIB(Animation, object, entity, NULL)
-       ATTRIB(Animation, setter, void(entity, float), setterDummy)
-       ATTRIB(Animation, value, float, 0)
-       ATTRIB(Animation, startTime, float, 0)
-       ATTRIB(Animation, duration, float, 0)
-       ATTRIB(Animation, startValue, float, 0)
-       ATTRIB(Animation, delta, float, 0)
-       ATTRIB(Animation, stopped, float, false)
-       ATTRIB(Animation, finished, float, false)
-ENDCLASS(Animation)
+       #define ANIM_ANIMATION_H
+       CLASS(Animation, Object)
+               METHOD(Animation, configureAnimation, void(entity, entity, void(entity, float), float, float, float, float));
+               METHOD(Animation, update, void(entity, float, float, float));
+               METHOD(Animation, setTimeStartEnd, void(entity, float, float));
+               METHOD(Animation, setTimeStartDuration, void(entity, float, float));
+               METHOD(Animation, setValueStartEnd, void(entity, float, float));
+               METHOD(Animation, setValueStartDelta, void(entity, float, float));
+               METHOD(Animation, setObjectSetter, void(entity, entity, void(entity, float)));
+               METHOD(Animation, tick, void(entity, float));
+               METHOD(Animation, calcValue, float(entity, float, float, float, float));
+               METHOD(Animation, isStopped, float(entity));
+               METHOD(Animation, stopAnim, void(entity));
+               METHOD(Animation, resumeAnim, void(entity));
+               METHOD(Animation, isFinished, float(entity));
+               METHOD(Animation, finishAnim, void(entity));
+               ATTRIB(Animation, object, entity, NULL)
+               void setterDummy(entity, float) {}
+               ATTRIB(Animation, setter, void(entity, float), setterDummy)
+               ATTRIB(Animation, value, float, 0)
+               ATTRIB(Animation, startTime, float, 0)
+               ATTRIB(Animation, duration, float, 0)
+               ATTRIB(Animation, startValue, float, 0)
+               ATTRIB(Animation, delta, float, 0)
+               ATTRIB(Animation, stopped, float, false)
+               ATTRIB(Animation, finished, float, false)
+       ENDCLASS(Animation)
 #endif
 
 #ifdef IMPLEMENTATION
-void Animation_configureAnimation(entity me, entity obj, void(entity, float) objSetter, float animStartTime, float animDuration, float animStartValue, float animEndValue)
-{
-       me.setObjectSetter(me, obj, objSetter);
-       me.setTimeStartDuration(me, animStartTime, animDuration);
-       me.setValueStartEnd(me, animStartValue, animEndValue);
-}
-
-void Animation_update(entity me, float animDuration, float animStartValue, float animEndValue)
-{
-       me.setTimeStartDuration(me, time, animDuration);
-       me.setValueStartEnd(me, animStartValue, animEndValue);
-}
-
-void Animation_setTimeStartEnd(entity me, float s, float e)
-{
-       me.startTime = s;
-       me.duration = e - s;
-}
-
-void Animation_setTimeStartDuration(entity me, float s, float d)
-{
-       me.startTime = s;
-       me.duration = d;
-}
-
-void Animation_setValueStartEnd(entity me, float s, float e)
-{
-       me.startValue = s;
-       me.delta = e - s;
-}
-
-void Animation_setValueStartDelta(entity me, float s, float d)
-{
-       me.startValue = s;
-       me.delta = d;
-}
-
-void Animation_setObjectSetter(entity me, entity o, void(entity, float) s)
-{
-       me.object = o;
-       me.setter = s;
-}
-
-void Animation_tick(entity me, float tickTime)
-{
-       if (me.isStopped(me) || me.isFinished(me) || (tickTime < me.startTime))
-               return;
-
-       if (tickTime >= (me.startTime + me.duration))
-               me.finishAnim(me);
-       else
-               me.value = me.calcValue(me, (tickTime - me.startTime), me.duration, me.startValue, me.delta);
-
-       me.setter(me.object, me.value);
-}
-
-float Animation_calcValue(entity me, float tickTime, float animDuration, float animStartValue, float animDelta)
-{
-       return animStartValue;
-}
-
-float Animation_isStopped(entity me)
-{
-       return me.stopped;
-}
-
-void Animation_stopAnim(entity me)
-{
-       me.stopped = true;
-}
-
-void Animation_resumeAnim(entity me)
-{
-       me.stopped = false;
-}
-
-float Animation_isFinished(entity me)
-{
-       return me.finished;
-}
-
-void Animation_finishAnim(entity me)
-{
-       me.value = me.delta + me.startValue;
-       me.finished = true;
-       me.setter(me.object, me.value);
-}
-
-void setterDummy(entity obj, float objValue)
-{
-}
+       METHOD(Animation, configureAnimation, void(entity this, entity obj, void(entity, float) objSetter, float animStartTime, float animDuration, float animStartValue, float animEndValue))
+       {
+               this.setObjectSetter(this, obj, objSetter);
+               this.setTimeStartDuration(this, animStartTime, animDuration);
+               this.setValueStartEnd(this, animStartValue, animEndValue);
+       }
+
+       METHOD(Animation, update, void(entity this, float animDuration, float animStartValue, float animEndValue))
+       {
+               this.setTimeStartDuration(this, time, animDuration);
+               this.setValueStartEnd(this, animStartValue, animEndValue);
+       }
+
+       METHOD(Animation, setTimeStartEnd, void(entity this, float s, float e))
+       {
+               this.startTime = s;
+               this.duration = e - s;
+       }
+
+       METHOD(Animation, setTimeStartDuration, void(entity this, float s, float d))
+       {
+               this.startTime = s;
+               this.duration = d;
+       }
+
+       METHOD(Animation, setValueStartEnd, void(entity this, float s, float e))
+       {
+               this.startValue = s;
+               this.delta = e - s;
+       }
+
+       METHOD(Animation, setValueStartDelta, void(entity this, float s, float d))
+       {
+               this.startValue = s;
+               this.delta = d;
+       }
+
+       METHOD(Animation, setObjectSetter, void(entity this, entity o, void(entity, float) s))
+       {
+               this.object = o;
+               this.setter = s;
+       }
+
+       METHOD(Animation, tick, void(entity this, float tickTime))
+       {
+               if (this.isStopped(this) || this.isFinished(this) || (tickTime < this.startTime)) return;
+
+               if (tickTime >= (this.startTime + this.duration)) this.finishAnim(this);
+               else this.value = this.calcValue(this, (tickTime - this.startTime), this.duration, this.startValue, this.delta);
+
+               this.setter(this.object, this.value);
+       }
+
+       METHOD(Animation, calcValue, float(entity this, float tickTime, float animDuration, float animStartValue, float animDelta))
+       {
+               return animStartValue;
+       }
+
+       METHOD(Animation, isStopped, bool(entity this))
+       {
+               return this.stopped;
+       }
+
+       METHOD(Animation, stopAnim, void(entity this))
+       {
+               this.stopped = true;
+       }
+
+       METHOD(Animation, resumeAnim, void(entity this))
+       {
+               this.stopped = false;
+       }
+
+       METHOD(Animation, isFinished, bool(entity this))
+       {
+               return this.finished;
+       }
+
+       METHOD(Animation, finishAnim, void(entity this))
+       {
+               this.value = this.delta + this.startValue;
+               this.finished = true;
+               this.setter(this.object, this.value);
+       }
 
 #endif
index 55ca901dc50f83378c2697df3010f2cb4d4f75fc..7826a47b79523f3de5ac730be832bf1fbe6b7423 100644 (file)
 #include "../menu.qh"
 
 #ifndef ANIM_ANIMHOST_H
-#define ANIM_ANIMHOST_H
-CLASS(AnimHost, Object)
-       METHOD(AnimHost, addAnim, void(entity, entity));
-       METHOD(AnimHost, removeAnim, void(entity, entity));
-       METHOD(AnimHost, removeAllAnim, void(entity));
-       METHOD(AnimHost, removeObjAnim, void(entity, entity));
-       METHOD(AnimHost, stopAllAnim, void(entity));
-       METHOD(AnimHost, stopObjAnim, void(entity, entity));
-       METHOD(AnimHost, resumeAllAnim, void(entity));
-       METHOD(AnimHost, resumeObjAnim, void(entity, entity));
-       METHOD(AnimHost, finishAllAnim, void(entity));
-       METHOD(AnimHost, finishObjAnim, void(entity, entity));
-       METHOD(AnimHost, tickAll, void(entity));
-       ATTRIB(AnimHost, firstChild, entity, NULL)
-       ATTRIB(AnimHost, lastChild, entity, NULL)
-ENDCLASS(AnimHost)
-.entity nextSibling;
-.entity prevSibling;
+       #define ANIM_ANIMHOST_H
+       CLASS(AnimHost, Object)
+               METHOD(AnimHost, addAnim, void(entity, entity));
+               METHOD(AnimHost, removeAnim, void(entity, entity));
+               METHOD(AnimHost, removeAllAnim, void(entity));
+               METHOD(AnimHost, removeObjAnim, void(entity, entity));
+               METHOD(AnimHost, stopAllAnim, void(entity));
+               METHOD(AnimHost, stopObjAnim, void(entity, entity));
+               METHOD(AnimHost, resumeAllAnim, void(entity));
+               METHOD(AnimHost, resumeObjAnim, void(entity, entity));
+               METHOD(AnimHost, finishAllAnim, void(entity));
+               METHOD(AnimHost, finishObjAnim, void(entity, entity));
+               METHOD(AnimHost, tickAll, void(entity));
+               ATTRIB(AnimHost, firstChild, entity, NULL)
+               ATTRIB(AnimHost, lastChild, entity, NULL)
+       ENDCLASS(AnimHost)
+       .entity nextSibling;
+       .entity prevSibling;
 #endif
 
 #ifdef IMPLEMENTATION
-void AnimHost_addAnim(entity me, entity other)
-{
-       if(other.parent)
-               error("Can't add already added anim!");
-
-       if(other.isFinished(other))
-               error("Can't add finished anim!");
-
-       other.parent = me;
-
-       entity l;
-       l = me.lastChild;
-
-       if(l)
-               l.nextSibling = other;
-       else
-               me.firstChild = other;
-
-       other.prevSibling = l;
-       other.nextSibling = NULL;
-       me.lastChild = other;
-}
-
-void AnimHost_removeAnim(entity me, entity other)
-{
-       if(other.parent != me)
-               error("Can't remove from wrong AnimHost!");
-
-       other.parent = NULL;
-
-       entity n, p;
-       n = other.nextSibling;
-       p = other.prevSibling;
-
-       if(p)
-               p.nextSibling = n;
-       else
-               me.firstChild = n;
-
-       if(n)
-               n.prevSibling = p;
-       else
-               me.lastChild = p;
-       remove(other);
-}
-
-void AnimHost_removeAllAnim(entity me)
-{
-       entity e, tmp;
-       for(e = me.firstChild; e; e = e.nextSibling)
+       METHOD(AnimHost, addAnim, void(entity this, entity other))
        {
-               tmp = e;
-               e = tmp.prevSibling;
-               me.removeAnim(me, tmp);
+               if (other.parent) error("Can't add already added anim!");
+
+               if (other.isFinished(other)) error("Can't add finished anim!");
+
+               other.parent = this;
+
+               entity l = this.lastChild;
+
+               if (l) l.nextSibling = other;
+               else this.firstChild = other;
+
+               other.prevSibling = l;
+               other.nextSibling = NULL;
+               this.lastChild = other;
+       }
+
+       METHOD(AnimHost, removeAnim, void(entity this, entity other))
+       {
+               if (other.parent != this) error("Can't remove from wrong AnimHost!");
+
+               other.parent = NULL;
+
+               entity n = other.nextSibling;
+               entity p = other.prevSibling;
+
+               if (p) p.nextSibling = n;
+               else this.firstChild = n;
+
+               if (n) n.prevSibling = p;
+               else this.lastChild = p;
+               remove(other);
        }
-}
 
-void AnimHost_removeObjAnim(entity me, entity obj)
-{
-       entity e, tmp;
-       for(e = me.firstChild; e; e = e.nextSibling)
+       METHOD(AnimHost, removeAllAnim, void(entity this))
        {
-               if (e.object == obj)
+               for (entity e = this.firstChild; e; e = e.nextSibling)
                {
-                       tmp = e;
+                       entity tmp = e;
                        e = tmp.prevSibling;
-                       me.removeAnim(me, tmp);
+                       this.removeAnim(this, tmp);
                }
        }
-}
 
-void AnimHost_stopAllAnim(entity me)
-{
-       entity e;
-       for(e = me.firstChild; e; e = e.nextSibling)
+       METHOD(AnimHost, removeObjAnim, void(entity this, entity obj))
        {
-               e.stopAnim(e);
+               for (entity e = this.firstChild; e; e = e.nextSibling)
+               {
+                       if (e.object == obj)
+                       {
+                               entity tmp = e;
+                               e = tmp.prevSibling;
+                               this.removeAnim(this, tmp);
+                       }
+               }
        }
-}
 
-void AnimHost_stopObjAnim(entity me, entity obj)
-{
-       entity e;
-       for(e = me.firstChild; e; e = e.nextSibling)
+       METHOD(AnimHost, stopAllAnim, void(entity this))
        {
-               if (e.object == obj)
-               {
+               for (entity e = this.firstChild; e; e = e.nextSibling)
                        e.stopAnim(e);
-               }
        }
-}
 
-void AnimHost_resumeAllAnim(entity me)
-{
-       entity e;
-       for(e = me.firstChild; e; e = e.nextSibling)
+       METHOD(AnimHost, stopObjAnim, void(entity this, entity obj))
        {
-               e.resumeAnim(e);
+               for (entity e = this.firstChild; e; e = e.nextSibling)
+                       if (e.object == obj) e.stopAnim(e);
        }
-}
 
-void AnimHost_resumeObjAnim(entity me, entity obj)
-{
-       entity e;
-       for(e = me.firstChild; e; e = e.nextSibling)
+       METHOD(AnimHost, resumeAllAnim, void(entity this))
        {
-               if (e.object == obj)
-               {
+               for (entity e = this.firstChild; e; e = e.nextSibling)
                        e.resumeAnim(e);
-               }
        }
-}
 
-void AnimHost_finishAllAnim(entity me)
-{
-       entity e, tmp;
-       for(e = me.firstChild; e; e = e.nextSibling)
+       METHOD(AnimHost, resumeObjAnim, void(entity this, entity obj))
        {
-               tmp = e;
-               e = tmp.prevSibling;
-               tmp.finishAnim(tmp);
+               for (entity e = this.firstChild; e; e = e.nextSibling)
+                       if (e.object == obj) e.resumeAnim(e);
        }
-}
 
-void AnimHost_finishObjAnim(entity me, entity obj)
-{
-       entity e, tmp;
-       for(e = me.firstChild; e; e = e.nextSibling)
+       METHOD(AnimHost, finishAllAnim, void(entity this))
        {
-               if (e.object == obj)
+               for (entity e = this.firstChild; e; e = e.nextSibling)
                {
-                       tmp = e;
+                       entity tmp = e;
                        e = tmp.prevSibling;
                        tmp.finishAnim(tmp);
                }
        }
-}
 
-void AnimHost_tickAll(entity me)
-{
-       entity e, tmp;
-       for(e = me.firstChild; e; e = e.nextSibling)
+       METHOD(AnimHost, finishObjAnim, void(entity this, entity obj))
        {
-               e.tick(e, time);
-               if (e.isFinished(e))
+               for (entity e = this.firstChild; e; e = e.nextSibling)
                {
-                       tmp = e;
-                       e = tmp.prevSibling;
-                       me.removeAnim(me, tmp);
+                       if (e.object == obj)
+                       {
+                               entity tmp = e;
+                               e = tmp.prevSibling;
+                               tmp.finishAnim(tmp);
+                       }
+               }
+       }
+
+       METHOD(AnimHost, tickAll, void(entity this))
+       {
+               for (entity e = this.firstChild; e; e = e.nextSibling)
+               {
+                       e.tick(e, time);
+                       if (e.isFinished(e))
+                       {
+                               entity tmp = e;
+                               e = tmp.prevSibling;
+                               this.removeAnim(this, tmp);
+                       }
                }
        }
-}
 #endif
index f1962719f8b9a7dfe2f07076eb70165828d67000..080f390ba9314245cff104f5761d9976d455a6a6 100644 (file)
@@ -1,74 +1,66 @@
 #ifndef ANIM_EASING_H
-#define ANIM_EASING_H
-#include "animation.qc"
-entity makeHostedEasing(entity, void(entity, float), float(float, float, float, float), float, float, float);
-entity makeEasing(entity, void(entity, float), float(float, float, float, float), float, float, float, float);
-float easingLinear(float, float, float, float);
-float easingQuadIn(float, float, float, float);
-float easingQuadOut(float, float, float, float);
-float easingQuadInOut(float, float, float, float);
-CLASS(Easing, Animation)
-       METHOD(Easing, calcValue, float(entity, float, float, float, float));
-       METHOD(Easing, setMath, void(entity, float(float, float, float, float)));
-       ATTRIB(Easing, math, float(float, float, float, float), easingLinear)
-ENDCLASS(Easing)
+       #define ANIM_EASING_H
+       #include "animation.qc"
+       entity makeHostedEasing(entity, void(entity, float), float(float, float, float, float), float, float, float);
+       entity makeEasing(entity, void(entity, float), float(float, float, float, float), float, float, float, float);
+       float easingLinear(float, float, float, float);
+       float easingQuadIn(float, float, float, float);
+       float easingQuadOut(float, float, float, float);
+       float easingQuadInOut(float, float, float, float);
+       CLASS(Easing, Animation)
+               METHOD(Easing, calcValue, float(entity, float, float, float, float));
+               METHOD(Easing, setMath, void(entity, float(float, float, float, float)));
+               ATTRIB(Easing, math, float(float, float, float, float), easingLinear)
+       ENDCLASS(Easing)
 #endif
 
 #ifdef IMPLEMENTATION
-entity makeHostedEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animDuration, float animStartValue, float animEnd)
-{
-       entity me;
-       me = makeEasing(obj, objSetter, func, time, animDuration, animStartValue, animEnd);
-       anim.addAnim(anim, me);
-       return me;
-}
-
-entity makeEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animStartTime, float animDuration, float animStartValue, float animEnd)
-{
-       entity me;
-       me = NEW(Easing);
-       me.configureAnimation(me, obj, objSetter, animStartTime, animDuration, animStartValue, animEnd);
-       me.setMath(me, func);
-       return me;
-}
+       entity makeHostedEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animDuration, float animStartValue, float animEnd)
+       {
+               entity this = makeEasing(obj, objSetter, func, time, animDuration, animStartValue, animEnd);
+               anim.addAnim(anim, this);
+               return this;
+       }
 
-float Easing_calcValue(entity me, float tickTime, float animDuration, float animStart, float animDelta)
-{
-       return me.math(tickTime, animDuration, animStart, animDelta);
-}
+       entity makeEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animStartTime, float animDuration, float animStartValue, float animEnd)
+       {
+               entity this = NEW(Easing);
+               this.configureAnimation(this, obj, objSetter, animStartTime, animDuration, animStartValue, animEnd);
+               this.setMath(this, func);
+               return this;
+       }
 
-void Easing_setMath(entity me, float(float, float, float, float) func)
-{
-       me.math = func;
-}
+       METHOD(Easing, calcValue, float(entity this, float tickTime, float animDuration, float animStart, float animDelta))
+       {
+               return this.math(tickTime, animDuration, animStart, animDelta);
+       }
 
-float easingLinear(float tickTime, float animDuration, float animStart, float animDelta)
-{
-       return (animDelta * (tickTime / animDuration)) + animStart;
-}
+       METHOD(Easing, setMath, void(entity this, float(float, float, float, float) func))
+       {
+               this.math = func;
+       }
 
-float easingQuadIn(float tickTime, float animDuration, float animStart, float animDelta)
-{
-       float frac = tickTime / animDuration;
-       return (animDelta * frac * frac) + animStart;
-}
+       float easingLinear(float tickTime, float animDuration, float animStart, float animDelta)
+       {
+               return (animDelta * (tickTime / animDuration)) + animStart;
+       }
 
-float easingQuadOut(float tickTime, float animDuration, float animStart, float animDelta)
-{
-       float frac = tickTime / animDuration;
-       return (-animDelta * frac * (frac - 2)) + animStart;
-}
+       float easingQuadIn(float tickTime, float animDuration, float animStart, float animDelta)
+       {
+               float frac = tickTime / animDuration;
+               return (animDelta * frac * frac) + animStart;
+       }
 
-float easingQuadInOut(float tickTime, float animDuration, float animStart, float animDelta)
-{
-       if (tickTime < (animDuration / 2))
+       float easingQuadOut(float tickTime, float animDuration, float animStart, float animDelta)
        {
-               return easingQuadIn(tickTime, (animDuration / 2), animStart, (animDelta / 2));
+               float frac = tickTime / animDuration;
+               return (-animDelta * frac * (frac - 2)) + animStart;
        }
-       else
+
+       float easingQuadInOut(float tickTime, float animDuration, float animStart, float animDelta)
        {
-               return easingQuadOut((tickTime - (animDuration / 2)), (animDuration / 2), (animStart + (animDelta / 2)), (animDelta / 2));
+               if (tickTime < (animDuration / 2)) return easingQuadIn(tickTime, (animDuration / 2), animStart, (animDelta / 2));
+               else return easingQuadOut((tickTime - (animDuration / 2)), (animDuration / 2), (animStart + (animDelta / 2)), (animDelta / 2));
        }
-}
 
 #endif
index d83a2cbd4927e80ef69748beb2aa4eea01e3cc67..eec5c03aec2698f33db516d7c671fec3c86e9274 100644 (file)
 #ifndef ANIM_KEYFRAME_H
-#define ANIM_KEYFRAME_H
-#include "animation.qc"
-CLASS(Keyframe, Animation)
-       METHOD(Keyframe, addEasing, entity(entity, float, float, float(float, float, float, float)));
-       METHOD(Keyframe, addAnim, void(entity, entity));
-       METHOD(Keyframe, calcValue, float(entity, float, float, float, float));
-       ATTRIB(Keyframe, currentChild, entity, NULL)
-       ATTRIB(Keyframe, firstChild, entity, NULL)
-       ATTRIB(Keyframe, lastChild, entity, NULL)
-ENDCLASS(Keyframe)
-entity makeHostedKeyframe(entity, void(entity, float), float, float, float);
-entity makeKeyframe(entity, void(entity, float), float, float, float);
-float getNewChildStart(entity);
-float getNewChildDuration(entity, float);
-float getNewChildValue(entity);
+       #define ANIM_KEYFRAME_H
+       #include "animation.qc"
+       CLASS(Keyframe, Animation)
+               METHOD(Keyframe, addEasing, entity(entity, float, float, float(float, float, float, float)));
+               METHOD(Keyframe, addAnim, void(entity, entity));
+               METHOD(Keyframe, calcValue, float(entity, float, float, float, float));
+               ATTRIB(Keyframe, currentChild, entity, NULL)
+               ATTRIB(Keyframe, firstChild, entity, NULL)
+               ATTRIB(Keyframe, lastChild, entity, NULL)
+       ENDCLASS(Keyframe)
+       entity makeHostedKeyframe(entity, void(entity, float), float, float, float);
+       entity makeKeyframe(entity, void(entity, float), float, float, float);
+       float getNewChildStart(entity);
+       float getNewChildDuration(entity, float);
+       float getNewChildValue(entity);
 #endif
 
 #ifdef IMPLEMENTATION
-entity makeHostedKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
-{
-       entity me;
-       me = makeKeyframe(obj, objSetter, animDuration, animStart, animEnd);
-       anim.addAnim(anim, me);
-       return me;
-}
+       entity makeHostedKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
+       {
+               entity this = makeKeyframe(obj, objSetter, animDuration, animStart, animEnd);
+               anim.addAnim(anim, this);
+               return this;
+       }
 
-entity makeKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
-{
-       entity me;
-       me = NEW(Keyframe);
-       me.configureAnimation(me, obj, objSetter, time, animDuration, animStart, animEnd);
-       return me;
-}
+       entity makeKeyframe(entity obj, void(entity, float) objSetter, float animDuration, float animStart, float animEnd)
+       {
+               entity this = NEW(Keyframe);
+               this.configureAnimation(this, obj, objSetter, time, animDuration, animStart, animEnd);
+               return this;
+       }
 
-entity Keyframe_addEasing(entity me, float animDurationTime, float animEnd, float(float, float, float, float) func)
-{
-       entity other;
-       other = makeEasing(me.object, me.setter, func, getNewChildStart(me), getNewChildDuration(me, animDurationTime), getNewChildValue(me), animEnd);
-       me.addAnim(me, other);
-       return other;
-}
+       METHOD(Keyframe, addEasing, entity(entity this, float animDurationTime, float animEnd, float(float, float, float, float) func))
+       {
+               entity other = makeEasing(this.object, this.setter, func, getNewChildStart(this), getNewChildDuration(this, animDurationTime), getNewChildValue(this), animEnd);
+               this.addAnim(this, other);
+               return other;
+       }
+
+       float getNewChildStart(entity this)
+       {
+               if (this.lastChild) return this.lastChild.startTime + this.lastChild.duration;
+               else return 0;
+       }
 
-float getNewChildStart(entity me)
-{
-       if (me.lastChild)
-               return (me.lastChild.startTime + me.lastChild.duration);
-       else
-               return 0;
-}
+       float getNewChildDuration(entity this, float durationTime)
+       {
+               float maxDura = this.duration;
+               if (this.lastChild) maxDura = maxDura - (this.lastChild.startTime + this.lastChild.duration);
+               float dura = durationTime;
+               if (0 >= dura || dura > maxDura) dura = maxDura;
+               return dura;
+       }
 
-float getNewChildDuration(entity me, float durationTime)
-{
-       float dura, maxDura;
-       maxDura = me.duration;
-       if (me.lastChild) maxDura = maxDura - (me.lastChild.startTime + me.lastChild.duration);
-       dura = durationTime;
-       if (0 >= dura || dura > maxDura) dura = maxDura;
-       return dura;
-}
+       float getNewChildValue(entity this)
+       {
+               if (this.lastChild) return this.lastChild.startValue + this.lastChild.delta;
+               else return this.startValue;
+       }
 
-float getNewChildValue(entity me)
-{
-       if (me.lastChild)
-               return (me.lastChild.startValue + me.lastChild.delta);
-       else
-               return me.startValue;
-}
+       METHOD(Keyframe, addAnim, void(entity this, entity other))
+       {
+               if (other.parent) error("Can't add already added anim!");
 
-void Keyframe_addAnim(entity me, entity other)
-{
-       if(other.parent)
-               error("Can't add already added anim!");
+               if (other.isFinished(other)) error("Can't add finished anim!");
 
-       if(other.isFinished(other))
-               error("Can't add finished anim!");
+               other.parent = this;
 
-       other.parent = me;
+               entity l = this.lastChild;
 
-       entity l;
-       l = me.lastChild;
+               if (l)
+               {
+                       l.nextSibling = other;
+               }
+               else
+               {
+                       this.currentChild = other;
+                       this.firstChild = other;
+               }
 
-       if(l)
-               l.nextSibling = other;
-       else
-       {
-               me.currentChild = other;
-               me.firstChild = other;
+               other.prevSibling = l;
+               other.nextSibling = NULL;
+               this.lastChild = other;
        }
 
-       other.prevSibling = l;
-       other.nextSibling = NULL;
-       me.lastChild = other;
-}
+       METHOD(Keyframe, calcValue, float(entity this, float tickTime, float animDuration, float animStartValue, float animDelta))
+       {
+               if (this.currentChild)
+                       if (this.currentChild.isFinished(this.currentChild)) this.currentChild = this.currentChild.nextSibling;
 
-float Keyframe_calcValue(entity me, float tickTime, float animDuration, float animStartValue, float animDelta)
-{
-       if (me.currentChild)
-               if (me.currentChild.isFinished(me.currentChild))
-                       me.currentChild = me.currentChild.nextSibling;
+               if (this.currentChild)
+               {
+                       this.currentChild.tick(this.currentChild, tickTime);
+                       return this.currentChild.value;
+               }
 
-       if (me.currentChild)
-       {
-               me.currentChild.tick(me.currentChild, tickTime);
-               return me.currentChild.value;
+               return animStartValue + animDelta;
        }
-
-       return animStartValue + animDelta;
-}
 #endif
diff --git a/qcsrc/menu/classes.qc b/qcsrc/menu/classes.qc
new file mode 100644 (file)
index 0000000..9454a31
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef CLASSES_H
+#define CLASSES_H
+
+#include "classes.inc"
+#define IMPLEMENTATION
+#include "classes.inc"
+#undef IMPLEMENTATION
+
+#endif
index 179dc1949bad8c371ab1c0c2c901d6b6befbbb20..5a5fe26a68ea7b191497c89d9793c8902d9abbb8 100644 (file)
@@ -1,7 +1,9 @@
 #include "menu_cmd.qh"
 
 #include "../menu.qh"
-#include "../oo/classes.qc"
+#include "../classes.qc"
+
+#include "../mutators/events.qh"
 
 #include "../../common/command/generic.qh"
 
@@ -12,22 +14,22 @@ void _dumptree_open(entity pass, entity me)
 {
        string s;
        s = me.toString(me);
-       if(s == "")
-               s = me.classname;
-       else
-               s = strcat(me.classname, ": ", s);
+       if (s == "") s = me.classname;
+       else s = strcat(me.classname, ": ", s);
        LOG_INFO(_dumptree_space, etos(me), " (", s, ")");
-       if(me.firstChild)
+       if (me.firstChild)
        {
                LOG_INFO(" {\n");
                _dumptree_space = strcat(_dumptree_space, "  ");
        }
        else
+       {
                LOG_INFO("\n");
+       }
 }
 void _dumptree_close(entity pass, entity me)
 {
-       if(me.firstChild)
+       if (me.firstChild)
        {
                _dumptree_space = substring(_dumptree_space, 0, strlen(_dumptree_space) - 2);
                LOG_INFO(_dumptree_space, "}\n");
@@ -38,10 +40,10 @@ float updateConwidths(float width, float height, float pixelheight);
 
 void GameCommand(string theCommand)
 {
-       float argc;
-       argc = tokenize_console(theCommand);
+       int argc = tokenize_console(theCommand);
+       string ss = strtolower(argv(0));
 
-       if(argv(0) == "help" || argc == 0)
+       if (argv(0) == "help" || argc == 0)
        {
                LOG_INFO(_("Usage: menu_cmd command..., where possible commands are:\n"));
                LOG_INFO(_("  sync - reloads all cvars on the current menu page\n"));
@@ -53,82 +55,81 @@ void GameCommand(string theCommand)
                return;
        }
 
-       if(GenericCommand(theCommand))
-               return;
+       if (GenericCommand(theCommand)) return;
 
-       if(argv(0) == "sync")
+       if (argv(0) == "sync")
        {
                m_sync();
                return;
        }
 
-       if(argv(0) == "update_conwidths_before_vid_restart")
+       if (argv(0) == "update_conwidths_before_vid_restart")
        {
                updateConwidths(cvar("vid_width"), cvar("vid_height"), cvar("vid_pixelheight"));
                return;
        }
 
-       if(argv(0) == "directmenu" || argv(0) == "directpanelhudmenu")
+       if (argv(0) == "directmenu" || argv(0) == "directpanelhudmenu")
        {
                string filter = string_null;
-               if(argv(0) == "directpanelhudmenu")
-                       filter = strzone("HUD");
+               if (argv(0) == "directpanelhudmenu") filter = strzone("HUD");
 
-               if(argc == 1)
+               if (argc == 1)
                {
                        LOG_INFO(_("Available options:\n"));
                        float i;
                        entity e;
                        string s;
 
-                       for(i = 0, e = NULL; (e = nextent(e)); )
-                               if(e.classname != "vtbl" && e.name != "")
+                       for (i = 0, e = NULL; (e = nextent(e)); )
+                               if (e.classname != "vtbl" && e.name != "")
                                {
                                        s = e.name;
-                                       if(filter)
+                                       if (filter)
                                        {
-                                               if(substring(s, 0, strlen(filter)) != filter)
-                                                       continue;
+                                               if (substring(s, 0, strlen(filter)) != filter) continue;
                                                s = substring(s, strlen(filter), strlen(s) - strlen(filter));
                                        }
-                                       LOG_INFO(strcat(" ", s ,"\n"));
+                                       LOG_INFO(strcat(" ", s"\n"));
                                        ++i;
                                }
                }
-               else if(argc == 2 && !isdemo()) // don't allow this command in demos
+               else if (argc == 2 && !isdemo())     // don't allow this command in demos
                {
                        m_play_click_sound(MENU_SOUND_OPEN);
                        m_goto(strcat(filter, argv(1))); // switch to a menu item
                }
-               if(filter)
-                       strunzone(filter);
+               if (filter) strunzone(filter);
                return;
        }
 
-       if(argv(0) == "skinselect")
+       if (argv(0) == "skinselect")
        {
                m_goto("skinselector");
                return;
        }
 
-       if(argv(0) == "languageselect")
+       if (argv(0) == "languageselect")
        {
                m_goto("languageselector");
                return;
        }
 
-       if(argv(0) == "videosettings")
+       if (argv(0) == "videosettings")
        {
                m_goto("videosettings");
                return;
        }
 
-       if(argv(0) == "dumptree")
+       if (argv(0) == "dumptree")
        {
                _dumptree_space = "";
                depthfirst(main, parent, firstChild, nextSibling, _dumptree_open, _dumptree_close, NULL);
                return;
        }
 
+       if(MUTATOR_CALLHOOK(Menu_ConsoleCommand, ss, argc, theCommand)) // handled by a mutator
+               return;
+
        LOG_INFO(_("Invalid command. For a list of supported commands, try menu_cmd help.\n"));
 }
index 7edc6eff50d8a4c172371d19c026e10fecba6b46..b2ce50382a5e16b7a647085f93cd59ad16aede0f 100644 (file)
@@ -27,16 +27,6 @@ void draw_reset(float cw, float ch, float ox, float oy)
        draw_endBoldFont();
 }
 
-void draw_beginBoldFont()
-{
-       drawfont = FONT_USER+3;
-}
-
-void draw_endBoldFont()
-{
-       drawfont = FONT_USER+0;
-}
-
 vector globalToBox(vector v, vector theOrigin, vector theScale)
 {
        v -= theOrigin;
index 873ccb6df31e3695760db9b33002da2fe1a23665..bb12e29c8162efc889bbf84f1c5109c8113e01cf 100644 (file)
@@ -10,8 +10,8 @@ vector draw_scale;
 float draw_alpha;
 
 void draw_reset(float cw, float ch, float ox, float oy);
-void draw_beginBoldFont();
-void draw_endBoldFont();
+#define draw_beginBoldFont() do { drawfont = FONT_USER + 3; } while (0)
+#define draw_endBoldFont() do { drawfont = FONT_USER + 0; } while (0)
 void draw_setMousePointer(string pic, vector theSize, vector theOffset);
 void draw_drawMousePointer(vector where);
 
index cf0916ce9c6168cba438831b1a2bbc2641e564d1..0db9f77f2e08faf4c98d61205561c7e5af704e6f 100644 (file)
@@ -4,11 +4,12 @@
 
 #include "xonotic/tab.qc"
 
-REGISTRY(Settings, BIT(3))
-REGISTER_REGISTRY(RegisterSettings)
+REGISTRY(Settings, BITS(3))
+#define Settings_from(i) _Settings_from(i, NULL)
+REGISTER_REGISTRY(Settings)
 #define REGISTER_SETTINGS(id, impl) \
     LAZY_NEW(id, impl) \
-    REGISTER(RegisterSettings, MENU, Settings, id, m_id, NEW(Lazy, LAZY(id)))
+    REGISTER(Settings, MENU, id, m_id, NEW(Lazy, LAZY(id)))
 
 #endif
 #endif
index fa6161a9779337d7587799b4d99f54693a6f0944..12132affb4a267baf6124ee9cb7ff73b0321392a 100644 (file)
@@ -2,21 +2,21 @@
 #define ITEM_H
 #include "skin.qh"
 CLASS(Item, Object)
-       METHOD(Item, draw, void(entity));
-       METHOD(Item, keyDown, float(entity, float, float, float));
-       METHOD(Item, keyUp, float(entity, float, float, float));
-       METHOD(Item, mouseMove, float(entity, vector));
-       METHOD(Item, mousePress, float(entity, vector));
-       METHOD(Item, mouseDrag, float(entity, vector));
-       METHOD(Item, mouseRelease, float(entity, vector));
-       METHOD(Item, focusEnter, void(entity));
-       METHOD(Item, focusLeave, void(entity));
-       METHOD(Item, resizeNotify, void(entity, vector, vector, vector, vector));
-       METHOD(Item, relinquishFocus, void(entity));
-       METHOD(Item, showNotify, void(entity));
-       METHOD(Item, hideNotify, void(entity));
-       METHOD(Item, toString, string(entity));
-       METHOD(Item, destroy, void(entity));
+       METHOD(Item, draw, void(Item));
+       METHOD(Item, keyDown, float(Item, float, float, float));
+       METHOD(Item, keyUp, float(Item, float, float, float));
+       METHOD(Item, mouseMove, float(Item, vector));
+       METHOD(Item, mousePress, float(Item, vector));
+       METHOD(Item, mouseDrag, float(Item, vector));
+       METHOD(Item, mouseRelease, float(Item, vector));
+       METHOD(Item, focusEnter, void(Item));
+       METHOD(Item, focusLeave, void(Item));
+       METHOD(Item, resizeNotify, void(Item, vector, vector, vector, vector));
+       METHOD(Item, relinquishFocus, void(Item));
+       METHOD(Item, showNotify, void(Item));
+       METHOD(Item, hideNotify, void(Item));
+       METHOD(Item, toString, string(Item));
+       METHOD(Item, destroy, void(Item));
        ATTRIB(Item, focused, float, 0)
        ATTRIB(Item, focusable, float, 0)
        ATTRIB(Item, allowFocusSound, float, 0)
@@ -29,111 +29,102 @@ ENDCLASS(Item)
 #endif
 
 #ifdef IMPLEMENTATION
-void Item_destroy(entity me)
-{
-       // free memory associated with me
-}
-
-void Item_relinquishFocus(entity me)
-{
-       if(me.parent)
-               if(me.parent.instanceOfContainer)
-                       me.parent.setFocus(me.parent, NULL);
-}
-
-void Item_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.origin = absOrigin;
-       me.size = absSize;
-}
-
-float autocvar_menu_showboxes;
-void Item_draw(entity me)
-{
-       if(autocvar_menu_showboxes)
+       METHOD(Item, destroy, void(Item this))
        {
+               // free memory associated with this
+       }
+
+       METHOD(Item, relinquishFocus, void(Item this))
+       {
+               entity par = this.parent;
+               if (!par) return;
+               if (par.instanceOfContainer) par.setFocus(par, NULL);
+       }
+
+       METHOD(Item, resizeNotify, void(Item this, vector relOrigin, vector relSize, vector absOrigin, vector absSize))
+       {
+               this.origin = absOrigin;
+               this.size = absSize;
+       }
+
+       int autocvar_menu_showboxes;
+       METHOD(Item, draw, void(Item this))
+       {
+               if (!autocvar_menu_showboxes) return;
                vector rgb = '1 0 1';
                float a = fabs(autocvar_menu_showboxes);
 
                // don't draw containers and border images
-               if(me.instanceOfContainer || me.instanceOfBorderImage)
+               if (this.instanceOfContainer || this.instanceOfBorderImage)
                {
                        rgb = '0 0 0';
                        a = 0;
                }
 
-#if 0
-               // hack to detect multi drawing
-               float r = random() * 3;
-               if(r >= 2)
-                       rgb = '1 0 0';
-               else if(r >= 1)
-                       rgb = '0 1 0';
-               else
-                       rgb = '0 0 1';
-#endif
-               if(autocvar_menu_showboxes < 0)
+               #if 0
+                       // hack to detect multi drawing
+                       float r = random() * 3;
+                       if (r >= 2) rgb = '1 0 0';
+                       else if (r >= 1) rgb = '0 1 0';
+                       else rgb = '0 0 1';
+               #endif
+               if (autocvar_menu_showboxes < 0)
                {
                        draw_Fill('0 0 0', '0.5 0.5 0', rgb, a);
                        draw_Fill('0.5 0.5 0', '0.5 0.5 0', rgb, a);
                }
-               if(autocvar_menu_showboxes > 0)
+               else if (autocvar_menu_showboxes > 0)
                {
                        draw_Fill('0 0 0', '1 1 0', rgb, a);
                }
        }
-}
-
-void Item_showNotify(entity me)
-{
-}
-
-void Item_hideNotify(entity me)
-{
-}
-
-float Item_keyDown(entity me, float scan, float ascii, float shift)
-{
-       return 0; // unhandled
-}
-
-float Item_keyUp(entity me, float scan, float ascii, float shift)
-{
-       return 0; // unhandled
-}
-
-float Item_mouseMove(entity me, vector pos)
-{
-       return 0; // unhandled
-}
-
-float Item_mousePress(entity me, vector pos)
-{
-       return 0; // unhandled
-}
-
-float Item_mouseDrag(entity me, vector pos)
-{
-       return 0; // unhandled
-}
-
-float Item_mouseRelease(entity me, vector pos)
-{
-       return 0; // unhandled
-}
-
-void Item_focusEnter(entity me)
-{
-       if(me.allowFocusSound)
-               m_play_focus_sound();
-}
-
-void Item_focusLeave(entity me)
-{
-}
-
-string Item_toString(entity me)
-{
-       return string_null;
-}
+
+       METHOD(Item, showNotify, void(Item this))
+       {}
+
+       METHOD(Item, hideNotify, void(Item this))
+       {}
+
+       METHOD(Item, keyDown, float(Item this, float scan, float ascii, float shift))
+       {
+               return 0;  // unhandled
+       }
+
+       METHOD(Item, keyUp, float(Item this, float scan, float ascii, float shift))
+       {
+               return 0;  // unhandled
+       }
+
+       METHOD(Item, mouseMove, float(Item this, vector pos))
+       {
+               return 0;  // unhandled
+       }
+
+       METHOD(Item, mousePress, float(Item this, vector pos))
+       {
+               return 0;  // unhandled
+       }
+
+       METHOD(Item, mouseDrag, float(Item this, vector pos))
+       {
+               return 0;  // unhandled
+       }
+
+       METHOD(Item, mouseRelease, float(Item this, vector pos))
+       {
+               return 0;  // unhandled
+       }
+
+       METHOD(Item, focusEnter, void(Item this))
+       {
+               if (this.allowFocusSound) m_play_focus_sound();
+       }
+
+       METHOD(Item, focusLeave, void(Item this))
+       {}
+
+       METHOD(Item, toString, string(Item this))
+       {
+               return string_null;
+       }
 #endif
index bcbd408edd25d6860962b6f4613ce4aea659e85f..4acf33d86115c50f3f787cc6ddc6b48256d1574d 100644 (file)
 #ifndef ITEM_BORDERIMAGE_H
-#define ITEM_BORDERIMAGE_H
-#include "label.qc"
-CLASS(BorderImage, Label)
-       METHOD(BorderImage, configureBorderImage, void(entity, string, float, vector, string, float));
-       METHOD(BorderImage, resizeNotify, void(entity, vector, vector, vector, vector));
-       METHOD(BorderImage, recalcPositionWithText, void(entity, string));
-       ATTRIB(BorderImage, isBold, float, 1)
-       METHOD(BorderImage, draw, void(entity));
-       ATTRIB(BorderImage, src, string, string_null)
-       ATTRIB(BorderImage, borderHeight, float, 0)
-       ATTRIB(BorderImage, borderVec, vector, '0 0 0')
-       ATTRIB(BorderImage, color, vector, '1 1 1')
-       ATTRIB(BorderImage, closeButton, entity, NULL)
-       ATTRIB(BorderImage, realFontSize_Nexposeed, vector, '0 0 0')
-       ATTRIB(BorderImage, realOrigin_Nexposeed, vector, '0 0 0')
-       ATTRIB(BorderImage, isNexposeeTitleBar, float, 0)
-       ATTRIB(BorderImage, zoomedOutTitleBarPosition, float, 0)
-       ATTRIB(BorderImage, zoomedOutTitleBar, float, 0)
-       ATTRIB(BorderImage, overrideRealOrigin, vector, '0 1 0')
-       ATTRIB(BorderImage, saveRelOrigin, vector, '0 0 0')
-       ATTRIB(BorderImage, saveRelSize, vector, '0 0 0')
-ENDCLASS(BorderImage)
+       #define ITEM_BORDERIMAGE_H
+       #include "label.qc"
+       CLASS(BorderImage, Label)
+               METHOD(BorderImage, configureBorderImage, void(entity, string, float, vector, string, float));
+               METHOD(BorderImage, resizeNotify, void(entity, vector, vector, vector, vector));
+               METHOD(BorderImage, recalcPositionWithText, void(entity, string));
+               ATTRIB(BorderImage, isBold, float, 1)
+               METHOD(BorderImage, draw, void(entity));
+               ATTRIB(BorderImage, src, string, string_null)
+               ATTRIB(BorderImage, borderHeight, float, 0)
+               ATTRIB(BorderImage, borderVec, vector, '0 0 0')
+               ATTRIB(BorderImage, color, vector, '1 1 1')
+               ATTRIB(BorderImage, closeButton, entity, NULL)
+               ATTRIB(BorderImage, realFontSize_Nexposeed, vector, '0 0 0')
+               ATTRIB(BorderImage, realOrigin_Nexposeed, vector, '0 0 0')
+               ATTRIB(BorderImage, isNexposeeTitleBar, float, 0)
+               ATTRIB(BorderImage, zoomedOutTitleBarPosition, float, 0)
+               ATTRIB(BorderImage, zoomedOutTitleBar, float, 0)
+               ATTRIB(BorderImage, overrideRealOrigin, vector, '0 1 0')
+               ATTRIB(BorderImage, saveRelOrigin, vector, '0 0 0')
+               ATTRIB(BorderImage, saveRelSize, vector, '0 0 0')
+       ENDCLASS(BorderImage)
 #endif
 
 #ifdef IMPLEMENTATION
-void BorderImage_recalcPositionWithText(entity me, string t)
-{
-       if(me.isNexposeeTitleBar)
+       void BorderImage_recalcPositionWithText(entity me, string t)
        {
-               vector scrs;
-               scrs = eX * conwidth + eY * conheight;
-               me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_smallOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_smallSize, scrs));
+               if (me.isNexposeeTitleBar)
+               {
+                       vector scrs;
+                       scrs = eX * conwidth + eY * conheight;
+                       me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_smallOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_smallSize, scrs));
+                       SUPER(BorderImage).recalcPositionWithText(me, t);
+                       me.realOrigin_y = me.realFontSize.y * me.zoomedOutTitleBarPosition;
+                       me.realOrigin_Nexposeed = me.realOrigin;
+                       me.realFontSize_Nexposeed = me.realFontSize;
+                       me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_initialOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_initialSize, scrs));
+               }
                SUPER(BorderImage).recalcPositionWithText(me, t);
-               me.realOrigin_y = me.realFontSize.y * me.zoomedOutTitleBarPosition;
-               me.realOrigin_Nexposeed = me.realOrigin;
-               me.realFontSize_Nexposeed = me.realFontSize;
-               me.resizeNotify(me, me.saveRelOrigin, me.saveRelSize, boxToGlobal(me.parent.Nexposee_initialOrigin, '0 0 0', scrs), boxToGlobalSize(me.parent.Nexposee_initialSize, scrs));
        }
-       SUPER(BorderImage).recalcPositionWithText(me, t);
-}
-void BorderImage_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.isNexposeeTitleBar = 0;
-       if(me.zoomedOutTitleBar)
-               if(me.parent.parent.instanceOfNexposee)
-                       if(me.parent.instanceOfDialog)
-                               if(me == me.parent.frame)
-                                       me.isNexposeeTitleBar = 1;
-       me.saveRelOrigin = relOrigin;
-       me.saveRelSize = relSize;
-       SUPER(BorderImage).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       me.borderVec_x = me.borderHeight / absSize.x;
-       me.borderVec_y = me.borderHeight / absSize.y;
-       me.realOrigin_y = 0.5 * (me.borderVec.y - me.realFontSize.y);
-       if(me.closeButton)
+       void BorderImage_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
        {
-               // move the close button to the right place
-               me.closeButton.Container_origin = '1 0 0' * (1 - me.borderVec.x);
-               me.closeButton.Container_size = me.borderVec;
-               me.closeButton.color = me.color;
-               me.closeButton.colorC = me.color;
-               me.closeButton.colorF = me.color;
+               me.isNexposeeTitleBar = 0;
+               if (me.zoomedOutTitleBar)
+                       if (me.parent.parent.instanceOfNexposee)
+                               if (me.parent.instanceOfDialog)
+                                       if (me == me.parent.frame) me.isNexposeeTitleBar = 1;
+               me.saveRelOrigin = relOrigin;
+               me.saveRelSize = relSize;
+               SUPER(BorderImage).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+               me.borderVec_x = me.borderHeight / absSize.x;
+               me.borderVec_y = me.borderHeight / absSize.y;
+               me.realOrigin_y = 0.5 * (me.borderVec.y - me.realFontSize.y);
+               if (me.closeButton)
+               {
+                       // move the close button to the right place
+                       me.closeButton.Container_origin = '1 0 0' * (1 - me.borderVec.x);
+                       me.closeButton.Container_size = me.borderVec;
+                       me.closeButton.color = me.color;
+                       me.closeButton.colorC = me.color;
+                       me.closeButton.colorF = me.color;
+               }
        }
-}
-void BorderImage_configureBorderImage(entity me, string theTitle, float sz, vector theColor, string path, float theBorderHeight)
-{
-       me.configureLabel(me, theTitle, sz, 0.5);
-       me.src = path;
-       me.color = theColor;
-       me.borderHeight = theBorderHeight;
-}
-void BorderImage_draw(entity me)
-{
-       if(me.src)
-               draw_BorderPicture('0 0 0', me.src, '1 1 0', me.color, 1, me.borderVec);
-
-       if(me.fontSize > 0)
+       void BorderImage_configureBorderImage(entity me, string theTitle, float sz, vector theColor, string path, float theBorderHeight)
+       {
+               me.configureLabel(me, theTitle, sz, 0.5);
+               me.src = path;
+               me.color = theColor;
+               me.borderHeight = theBorderHeight;
+       }
+       void BorderImage_draw(entity me)
        {
-               if(me.recalcPos)
-                       me.recalcPositionWithText(me, me.text);
+               if (me.src) draw_BorderPicture('0 0 0', me.src, '1 1 0', me.color, 1, me.borderVec);
 
-               if(me.isNexposeeTitleBar)
+               if (me.fontSize > 0)
                {
-                       vector ro, rf, df;
+                       if (me.recalcPos) me.recalcPositionWithText(me, me.text);
 
-                       // me.parent.Nexposee_animationFactor 0 (small) or 1 (full)
-                       // default values are for 1
-                       ro = me.realOrigin;
-                       rf = me.realFontSize;
-                       df = draw_fontscale;
-                       me.realOrigin = ro * me.parent.Nexposee_animationFactor + me.realOrigin_Nexposeed * (1 - me.parent.Nexposee_animationFactor);
-                       me.realFontSize = rf * me.parent.Nexposee_animationFactor + me.realFontSize_Nexposeed * (1 - me.parent.Nexposee_animationFactor);
-                       draw_fontscale = globalToBoxSize(boxToGlobalSize(df, me.realFontSize), rf);
+                       if (me.isNexposeeTitleBar)
+                       {
+                               vector ro, rf, df;
 
-                       SUPER(BorderImage).draw(me);
+                               // me.parent.Nexposee_animationFactor 0 (small) or 1 (full)
+                               // default values are for 1
+                               ro = me.realOrigin;
+                               rf = me.realFontSize;
+                               df = draw_fontscale;
+                               me.realOrigin = ro * me.parent.Nexposee_animationFactor + me.realOrigin_Nexposeed * (1 - me.parent.Nexposee_animationFactor);
+                               me.realFontSize = rf * me.parent.Nexposee_animationFactor + me.realFontSize_Nexposeed * (1 - me.parent.Nexposee_animationFactor);
+                               draw_fontscale = globalToBoxSize(boxToGlobalSize(df, me.realFontSize), rf);
+
+                               SUPER(BorderImage).draw(me);
 
-                       // me.Nexposee_animationState 0 (small) or 1 (full)
-                       // default values are for 1
-                       me.realOrigin = ro;
-                       me.realFontSize = rf;
-                       draw_fontscale = df;
+                               // me.Nexposee_animationState 0 (small) or 1 (full)
+                               // default values are for 1
+                               me.realOrigin = ro;
+                               me.realFontSize = rf;
+                               draw_fontscale = df;
+                       }
+                       else
+                       {
+                               SUPER(BorderImage).draw(me);
+                       }
                }
                else
+               {
                        SUPER(BorderImage).draw(me);
+               }
        }
-       else
-       {
-               SUPER(BorderImage).draw(me);
-       }
-}
 #endif
index 934e8cd3426e0579ff5066fea55349e2c3760dd8..a9112b88ff0ebd6dd2c730499ef3b90e1d2b1e46 100644 (file)
 #ifndef ITEM_BUTTON_H
-#define ITEM_BUTTON_H
-#include "label.qc"
-CLASS(Button, Label)
-       METHOD(Button, configureButton, void(entity, string, float, string));
-       METHOD(Button, draw, void(entity));
-       METHOD(Button, showNotify, void(entity));
-       METHOD(Button, resizeNotify, void(entity, vector, vector, vector, vector));
-       METHOD(Button, keyDown, float(entity, float, float, float));
-       METHOD(Button, mousePress, float(entity, vector));
-       METHOD(Button, mouseDrag, float(entity, vector));
-       METHOD(Button, mouseRelease, float(entity, vector));
-       METHOD(Button, playClickSound, void(entity));
-       ATTRIB(Button, onClick, void(entity, entity), func_null)
-       ATTRIB(Button, onClickEntity, entity, NULL)
-       ATTRIB(Button, src, string, string_null)
-       ATTRIB(Button, srcSuffix, string, string_null)
-       ATTRIB(Button, src2, string, string_null) // is centered, same aspect, and stretched to label size
-       ATTRIB(Button, src2scale, float, 1)
-       ATTRIB(Button, srcMulti, float, 1) // 0: button square left, text right; 1: button stretched, text over it
-       ATTRIB(Button, buttonLeftOfText, float, 0)
-       ATTRIB(Button, focusable, float, 1)
-       ATTRIB(Button, allowFocusSound, float, 1)
-       ATTRIB(Button, pressed, float, 0)
-       ATTRIB(Button, clickTime, float, 0)
-       ATTRIB(Button, disabled, float, 0)
-       ATTRIB(Button, disabledAlpha, float, 0.3)
-       ATTRIB(Button, forcePressed, float, 0)
-       ATTRIB(Button, color, vector, '1 1 1')
-       ATTRIB(Button, colorC, vector, '1 1 1')
-       ATTRIB(Button, colorF, vector, '1 1 1')
-       ATTRIB(Button, colorD, vector, '1 1 1')
-       ATTRIB(Button, color2, vector, '1 1 1')
-       ATTRIB(Button, alpha2, float, 1)
+       #define ITEM_BUTTON_H
+       #include "label.qc"
+       CLASS(Button, Label)
+               METHOD(Button, configureButton, void(entity, string, float, string));
+               METHOD(Button, draw, void(entity));
+               METHOD(Button, showNotify, void(entity));
+               METHOD(Button, resizeNotify, void(entity, vector, vector, vector, vector));
+               METHOD(Button, keyDown, float(entity, float, float, float));
+               METHOD(Button, mousePress, float(entity, vector));
+               METHOD(Button, mouseDrag, float(entity, vector));
+               METHOD(Button, mouseRelease, float(entity, vector));
+               METHOD(Button, playClickSound, void(entity));
+               ATTRIB(Button, onClick, void(entity, entity), func_null)
+               ATTRIB(Button, onClickEntity, entity, NULL)
+               ATTRIB(Button, src, string, string_null)
+               ATTRIB(Button, srcSuffix, string, string_null)
+               ATTRIB(Button, src2, string, string_null) // is centered, same aspect, and stretched to label size
+               ATTRIB(Button, src2scale, float, 1)
+               ATTRIB(Button, srcMulti, float, 1)        // 0: button square left, text right; 1: button stretched, text over it
+               ATTRIB(Button, buttonLeftOfText, float, 0)
+               ATTRIB(Button, focusable, float, 1)
+               ATTRIB(Button, allowFocusSound, float, 1)
+               ATTRIB(Button, pressed, float, 0)
+               ATTRIB(Button, clickTime, float, 0)
+               ATTRIB(Button, disabled, float, 0)
+               ATTRIB(Button, disabledAlpha, float, 0.3)
+               ATTRIB(Button, forcePressed, float, 0)
+               ATTRIB(Button, color, vector, '1 1 1')
+               ATTRIB(Button, colorC, vector, '1 1 1')
+               ATTRIB(Button, colorF, vector, '1 1 1')
+               ATTRIB(Button, colorD, vector, '1 1 1')
+               ATTRIB(Button, color2, vector, '1 1 1')
+               ATTRIB(Button, alpha2, float, 1)
 
-       ATTRIB(Button, origin, vector, '0 0 0')
-       ATTRIB(Button, size, vector, '0 0 0')
-ENDCLASS(Button)
+               ATTRIB(Button, origin, vector, '0 0 0')
+               ATTRIB(Button, size, vector, '0 0 0')
+       ENDCLASS(Button)
 #endif
 
 #ifdef IMPLEMENTATION
-void Button_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       if(me.srcMulti)
-               me.keepspaceLeft = 0;
-       else
-               me.keepspaceLeft = min(0.8, absSize.x == 0 ? 0 : (absSize.y / absSize.x));
-       SUPER(Button).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-}
-void Button_configureButton(entity me, string txt, float sz, string gfx)
-{
-       SUPER(Button).configureLabel(me, txt, sz, me.srcMulti ? 0.5 : 0);
-       me.src = gfx;
-}
-float Button_keyDown(entity me, float key, float ascii, float shift)
-{
-       if(key == K_ENTER || key == K_SPACE || key == K_KP_ENTER)
+       void Button_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
        {
-               me.playClickSound(me);
-               me.clickTime = 0.1; // delayed for effect
-               return 1;
+               if (me.srcMulti) me.keepspaceLeft = 0;
+               else me.keepspaceLeft = min(0.8, absSize.x == 0 ? 0 : (absSize.y / absSize.x));
+               SUPER(Button).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+       }
+       void Button_configureButton(entity me, string txt, float sz, string gfx)
+       {
+               SUPER(Button).configureLabel(me, txt, sz, me.srcMulti ? 0.5 : 0);
+               me.src = gfx;
        }
-       return 0;
-}
-float Button_mouseDrag(entity me, vector pos)
-{
-       me.pressed = 1;
-       if(pos.x < 0) me.pressed = 0;
-       if(pos.y < 0) me.pressed = 0;
-       if(pos.x >= 1) me.pressed = 0;
-       if(pos.y >= 1) me.pressed = 0;
-       return 1;
-}
-float Button_mousePress(entity me, vector pos)
-{
-       me.mouseDrag(me, pos); // verify coordinates
-       return 1;
-}
-float Button_mouseRelease(entity me, vector pos)
-{
-       me.mouseDrag(me, pos); // verify coordinates
-       if(me.pressed)
+       float Button_keyDown(entity me, float key, float ascii, float shift)
        {
-               if (!me.disabled)
+               if (key == K_ENTER || key == K_SPACE || key == K_KP_ENTER)
                {
                        me.playClickSound(me);
-                       if(me.onClick)
-                               me.onClick(me, me.onClickEntity);
+                       me.clickTime = 0.1;  // delayed for effect
+                       return 1;
                }
-               me.pressed = 0;
+               return 0;
        }
-       return 1;
-}
-void Button_showNotify(entity me)
-{
-       me.focusable = !me.disabled;
-}
-void Button_draw(entity me)
-{
-       vector bOrigin, bSize;
-       float save;
-
-       me.focusable = !me.disabled;
-
-       save = draw_alpha;
-       if(me.disabled)
-               draw_alpha *= me.disabledAlpha;
-
-       if(me.src)
+       float Button_mouseDrag(entity me, vector pos)
+       {
+               me.pressed = 1;
+               if (pos.x < 0) me.pressed = 0;
+               if (pos.y < 0) me.pressed = 0;
+               if (pos.x >= 1) me.pressed = 0;
+               if (pos.y >= 1) me.pressed = 0;
+               return 1;
+       }
+       float Button_mousePress(entity me, vector pos)
        {
-               if(me.srcMulti)
+               me.mouseDrag(me, pos);  // verify coordinates
+               return 1;
+       }
+       float Button_mouseRelease(entity me, vector pos)
+       {
+               me.mouseDrag(me, pos);  // verify coordinates
+               if (me.pressed)
                {
-                       bOrigin = '0 0 0';
-                       bSize = '1 1 0';
-                       if(me.disabled)
-                               draw_ButtonPicture(bOrigin, strcat(me.src, "_d", me.srcSuffix), bSize, me.colorD, 1);
-                       else if(me.forcePressed || me.pressed || me.clickTime > 0)
-                               draw_ButtonPicture(bOrigin, strcat(me.src, "_c", me.srcSuffix), bSize, me.colorC, 1);
-                       else if(me.focused)
-                               draw_ButtonPicture(bOrigin, strcat(me.src, "_f", me.srcSuffix), bSize, me.colorF, 1);
-                       else
-                               draw_ButtonPicture(bOrigin, strcat(me.src, "_n", me.srcSuffix), bSize, me.color, 1);
+                       if (!me.disabled)
+                       {
+                               me.playClickSound(me);
+                               if (me.onClick) me.onClick(me, me.onClickEntity);
+                       }
+                       me.pressed = 0;
                }
-               else
+               return 1;
+       }
+       void Button_showNotify(entity me)
+       {
+               me.focusable = !me.disabled;
+       }
+       void Button_draw(entity me)
+       {
+               vector bOrigin, bSize;
+               float save;
+
+               me.focusable = !me.disabled;
+
+               save = draw_alpha;
+               if (me.disabled) draw_alpha *= me.disabledAlpha;
+
+               if (me.src)
                {
-                       if(me.realFontSize_y == 0)
+                       if (me.srcMulti)
                        {
                                bOrigin = '0 0 0';
                                bSize = '1 1 0';
+                               if (me.disabled) draw_ButtonPicture(bOrigin, strcat(me.src, "_d", me.srcSuffix), bSize, me.colorD, 1);
+                               else if (me.forcePressed || me.pressed || me.clickTime > 0) draw_ButtonPicture(bOrigin, strcat(me.src, "_c", me.srcSuffix), bSize, me.colorC, 1);
+                               else if (me.focused) draw_ButtonPicture(bOrigin, strcat(me.src, "_f", me.srcSuffix), bSize, me.colorF, 1);
+                               else draw_ButtonPicture(bOrigin, strcat(me.src, "_n", me.srcSuffix), bSize, me.color, 1);
                        }
                        else
                        {
-                               bOrigin = eY * (0.5 * (1 - me.realFontSize.y)) + eX * (0.5 * (me.keepspaceLeft - me.realFontSize.x));
-                               bSize = me.realFontSize;
+                               if (me.realFontSize_y == 0)
+                               {
+                                       bOrigin = '0 0 0';
+                                       bSize = '1 1 0';
+                               }
+                               else
+                               {
+                                       bOrigin = eY * (0.5 * (1 - me.realFontSize.y)) + eX * (0.5 * (me.keepspaceLeft - me.realFontSize.x));
+                                       bSize = me.realFontSize;
+                               }
+                               if (me.disabled) draw_Picture(bOrigin, strcat(me.src, "_d", me.srcSuffix), bSize, me.colorD, 1);
+                               else if (me.forcePressed || me.pressed || me.clickTime > 0) draw_Picture(bOrigin, strcat(me.src, "_c", me.srcSuffix), bSize, me.colorC, 1);
+                               else if (me.focused) draw_Picture(bOrigin, strcat(me.src, "_f", me.srcSuffix), bSize, me.colorF, 1);
+                               else draw_Picture(bOrigin, strcat(me.src, "_n", me.srcSuffix), bSize, me.color, 1);
                        }
-                       if(me.disabled)
-                               draw_Picture(bOrigin, strcat(me.src, "_d", me.srcSuffix), bSize, me.colorD, 1);
-                       else if(me.forcePressed || me.pressed || me.clickTime > 0)
-                               draw_Picture(bOrigin, strcat(me.src, "_c", me.srcSuffix), bSize, me.colorC, 1);
-                       else if(me.focused)
-                               draw_Picture(bOrigin, strcat(me.src, "_f", me.srcSuffix), bSize, me.colorF, 1);
-                       else
-                               draw_Picture(bOrigin, strcat(me.src, "_n", me.srcSuffix), bSize, me.color, 1);
                }
-       }
-       if(me.src2)
-       {
-               bOrigin = me.keepspaceLeft * eX;
-               bSize = eY + eX * (1 - me.keepspaceLeft);
+               if (me.src2)
+               {
+                       bOrigin = me.keepspaceLeft * eX;
+                       bSize = eY + eX * (1 - me.keepspaceLeft);
 
-               bOrigin += bSize * (0.5 - 0.5 * me.src2scale);
-               bSize = bSize * me.src2scale;
+                       bOrigin += bSize * (0.5 - 0.5 * me.src2scale);
+                       bSize = bSize * me.src2scale;
 
-               draw_Picture(bOrigin, me.src2, bSize, me.color2, me.alpha2);
-       }
+                       draw_Picture(bOrigin, me.src2, bSize, me.color2, me.alpha2);
+               }
+
+               draw_alpha = save;
 
-       draw_alpha = save;
+               if (me.clickTime > 0 && me.clickTime <= frametime)
+               {
+                       // keyboard click timer expired? Fire the event then.
+                       if (!me.disabled)
+                               if (me.onClick) me.onClick(me, me.onClickEntity);
+               }
+               me.clickTime -= frametime;
 
-       if(me.clickTime > 0 && me.clickTime <= frametime)
+               SUPER(Button).draw(me);
+       }
+       void Dialog_Close(entity button, entity me);
+       void Button_playClickSound(entity me)
        {
-               // keyboard click timer expired? Fire the event then.
-               if (!me.disabled)
-                       if(me.onClick)
-                               me.onClick(me, me.onClickEntity);
+               if (me.onClick == DialogOpenButton_Click) m_play_click_sound(MENU_SOUND_OPEN);
+               else if (me.onClick == Dialog_Close) m_play_click_sound(MENU_SOUND_CLOSE);
+               else m_play_click_sound(MENU_SOUND_EXECUTE);
        }
-       me.clickTime -= frametime;
-
-       SUPER(Button).draw(me);
-}
-void Dialog_Close(entity button, entity me);
-void Button_playClickSound(entity me)
-{
-       if(me.onClick == DialogOpenButton_Click)
-               m_play_click_sound(MENU_SOUND_OPEN);
-       else if(me.onClick == Dialog_Close)
-               m_play_click_sound(MENU_SOUND_CLOSE);
-       else
-               m_play_click_sound(MENU_SOUND_EXECUTE);
-}
 #endif
index cda07c518bace964a9d7548fbf123d0c6843f1dd..17bc50103e262850a8707a281fa9615f0af060c9 100644 (file)
@@ -1,55 +1,57 @@
 #ifndef ITEM_CHECKBOX_H
-#define ITEM_CHECKBOX_H
-#include "button.qc"
-void CheckBox_Click(entity me, entity other);
-CLASS(CheckBox, Button)
-       METHOD(CheckBox, configureCheckBox, void(entity, string, float, string));
-       METHOD(CheckBox, draw, void(entity));
-       METHOD(CheckBox, playClickSound, void(entity));
-       METHOD(CheckBox, toString, string(entity));
-       METHOD(CheckBox, setChecked, void(entity, float));
-       ATTRIB(CheckBox, useDownAsChecked, float, 0)
-       ATTRIB(CheckBox, checked, float, 0)
-       ATTRIB(CheckBox, onClick, void(entity, entity), CheckBox_Click)
-       ATTRIB(CheckBox, srcMulti, float, 0)
-       ATTRIB(CheckBox, disabled, float, 0)
-ENDCLASS(CheckBox)
+       #define ITEM_CHECKBOX_H
+       #include "button.qc"
+       void CheckBox_Click(entity me, entity other);
+       CLASS(CheckBox, Button)
+               METHOD(CheckBox, configureCheckBox, void(entity, string, float, string));
+               METHOD(CheckBox, draw, void(entity));
+               METHOD(CheckBox, playClickSound, void(entity));
+               METHOD(CheckBox, toString, string(entity));
+               METHOD(CheckBox, setChecked, void(entity, float));
+               ATTRIB(CheckBox, useDownAsChecked, float, 0)
+               ATTRIB(CheckBox, checked, float, 0)
+               ATTRIB(CheckBox, onClick, void(entity, entity), CheckBox_Click)
+               ATTRIB(CheckBox, srcMulti, float, 0)
+               ATTRIB(CheckBox, disabled, float, 0)
+       ENDCLASS(CheckBox)
 #endif
 
 #ifdef IMPLEMENTATION
-void CheckBox_setChecked(entity me, float val)
-{
-       me.checked = val;
-}
-void CheckBox_Click(entity me, entity other)
-{
-       me.setChecked(me, !me.checked);
-}
-string CheckBox_toString(entity me)
-{
-       return strcat(SUPER(CheckBox).toString(me), ", ", me.checked ? "checked" : "unchecked");
-}
-void CheckBox_configureCheckBox(entity me, string txt, float sz, string gfx)
-{
-       me.configureButton(me, txt, sz, gfx);
-       me.align = 0;
-}
-void CheckBox_draw(entity me)
-{
-       float s;
-       s = me.pressed;
-       if(me.useDownAsChecked)
+       void CheckBox_setChecked(entity me, float val)
        {
-               me.srcSuffix = string_null;
-               me.forcePressed = me.checked;
+               me.checked = val;
+       }
+       void CheckBox_Click(entity me, entity other)
+       {
+               me.setChecked(me, !me.checked);
+       }
+       string CheckBox_toString(entity me)
+       {
+               return strcat(SUPER(CheckBox).toString(me), ", ", me.checked ? "checked" : "unchecked");
+       }
+       void CheckBox_configureCheckBox(entity me, string txt, float sz, string gfx)
+       {
+               me.configureButton(me, txt, sz, gfx);
+               me.align = 0;
+       }
+       void CheckBox_draw(entity me)
+       {
+               float s;
+               s = me.pressed;
+               if (me.useDownAsChecked)
+               {
+                       me.srcSuffix = string_null;
+                       me.forcePressed = me.checked;
+               }
+               else
+               {
+                       me.srcSuffix = (me.checked ? "1" : "0");
+               }
+               me.pressed = s;
+               SUPER(CheckBox).draw(me);
+       }
+       void CheckBox_playClickSound(entity me)
+       {
+               m_play_click_sound(MENU_SOUND_SELECT);
        }
-       else
-               me.srcSuffix = (me.checked ? "1" : "0");
-       me.pressed = s;
-       SUPER(CheckBox).draw(me);
-}
-void CheckBox_playClickSound(entity me)
-{
-       m_play_click_sound(MENU_SOUND_SELECT);
-}
 #endif
index cacb0124a2123ddf65294a6754ddb86f1945ab2d..23857dcead1d04e0089347114c32dd07733889f5 100644 (file)
 #ifndef ITEM_CONTAINER_H
-#define ITEM_CONTAINER_H
-#include "../item.qc"
-CLASS(Container, Item)
-       METHOD(Container, draw, void(entity));
-       METHOD(Container, keyUp, float(entity, float, float, float));
-       METHOD(Container, keyDown, float(entity, float, float, float));
-       METHOD(Container, mouseMove, float(entity, vector));
-       METHOD(Container, mousePress, float(entity, vector));
-       METHOD(Container, mouseDrag, float(entity, vector));
-       METHOD(Container, mouseRelease, float(entity, vector));
-       METHOD(Container, focusLeave, void(entity));
-       METHOD(Container, resizeNotify, void(entity, vector, vector, vector, vector));
-       METHOD(Container, resizeNotifyLie, void(entity, vector, vector, vector, vector, .vector, .vector, .vector));
-       METHOD(Container, addItem, void(entity, entity, vector, vector, float));
-       METHOD(Container, addItemCentered, void(entity, entity, vector, float));
-       METHOD(Container, addItemRightCentered, void(entity, entity, vector, float));
-       METHOD(Container, moveItemAfter, void(entity, entity, entity));
-       METHOD(Container, removeItem, void(entity, entity));
-       METHOD(Container, setFocus, void(entity, entity));
-       METHOD(Container, saveFocus, void(entity));
-       METHOD(Container, setAlphaOf, void(entity, entity, float));
-       METHOD(Container, itemFromPoint, entity(entity, vector));
-       METHOD(Container, showNotify, void(entity));
-       METHOD(Container, hideNotify, void(entity));
-       METHOD(Container, preferredFocusedGrandChild, entity(entity));
-       ATTRIB(Container, focusable, float, 0)
-       ATTRIB(Container, firstChild, entity, NULL)
-       ATTRIB(Container, lastChild, entity, NULL)
-       ATTRIB(Container, focusedChild, entity, NULL)
-       ATTRIB(Container, savedFocus, entity, NULL)
-       ATTRIB(Container, shown, float, 0)
-
-       METHOD(Container, enterSubitem, void(entity, entity));
-       METHOD(Container, enterLieSubitem, void(entity, vector, vector, vector, float));
-       METHOD(Container, leaveSubitem, void(entity));
-ENDCLASS(Container)
-.entity nextSibling;
-.entity prevSibling;
-.float resized;
-.vector Container_origin;
-.vector Container_size;
-.vector Container_fontscale;
-.float Container_alpha;
-.vector Container_save_shift;
-.vector Container_save_scale;
-.vector Container_save_fontscale;
-.float Container_save_alpha;
+       #define ITEM_CONTAINER_H
+       #include "../item.qc"
+       CLASS(Container, Item)
+               METHOD(Container, draw, void(entity));
+               METHOD(Container, keyUp, float(entity, float, float, float));
+               METHOD(Container, keyDown, float(entity, float, float, float));
+               METHOD(Container, mouseMove, float(entity, vector));
+               METHOD(Container, mousePress, float(entity, vector));
+               METHOD(Container, mouseDrag, float(entity, vector));
+               METHOD(Container, mouseRelease, float(entity, vector));
+               METHOD(Container, focusLeave, void(entity));
+               METHOD(Container, resizeNotify, void(entity, vector, vector, vector, vector));
+               METHOD(Container, resizeNotifyLie, void(entity, vector, vector, vector, vector, .vector, .vector, .vector));
+               METHOD(Container, addItem, void(entity, entity, vector, vector, float));
+               METHOD(Container, addItemCentered, void(entity, entity, vector, float));
+               METHOD(Container, addItemRightCentered, void(entity, entity, vector, float));
+               METHOD(Container, moveItemAfter, void(entity, entity, entity));
+               METHOD(Container, removeItem, void(entity, entity));
+               METHOD(Container, setFocus, void(entity, entity));
+               METHOD(Container, saveFocus, void(entity));
+               METHOD(Container, setAlphaOf, void(entity, entity, float));
+               METHOD(Container, itemFromPoint, entity(entity, vector));
+               METHOD(Container, showNotify, void(entity));
+               METHOD(Container, hideNotify, void(entity));
+               METHOD(Container, preferredFocusedGrandChild, entity(entity));
+               ATTRIB(Container, focusable, float, 0)
+               ATTRIB(Container, firstChild, entity, NULL)
+               ATTRIB(Container, lastChild, entity, NULL)
+               ATTRIB(Container, focusedChild, entity, NULL)
+               ATTRIB(Container, savedFocus, entity, NULL)
+               ATTRIB(Container, shown, float, 0)
+
+               METHOD(Container, enterSubitem, void(entity, entity));
+               METHOD(Container, enterLieSubitem, void(entity, vector, vector, vector, float));
+               METHOD(Container, leaveSubitem, void(entity));
+       ENDCLASS(Container)
+       .entity nextSibling;
+       .entity prevSibling;
+       .float resized;
+       .vector Container_origin;
+       .vector Container_size;
+       .vector Container_fontscale;
+       .float Container_alpha;
+       .vector Container_save_shift;
+       .vector Container_save_scale;
+       .vector Container_save_fontscale;
+       .float Container_save_alpha;
 #endif
 
 #ifdef IMPLEMENTATION
-void Container_enterSubitem(entity me, entity sub)
-{
-       me.enterLieSubitem(me, sub.Container_origin, sub.Container_size, sub.Container_fontscale, sub.Container_alpha);
-}
-
-void Container_enterLieSubitem(entity me, vector o, vector s, vector f, float a)
-{
-       me.Container_save_shift = draw_shift;
-       me.Container_save_scale = draw_scale;
-       me.Container_save_alpha = draw_alpha;
-       me.Container_save_fontscale = draw_fontscale;
-
-       draw_shift = boxToGlobal(o, draw_shift, draw_scale);
-       draw_scale = boxToGlobalSize(s, draw_scale);
-       if(f != '0 0 0')
-               draw_fontscale = boxToGlobalSize(f, draw_fontscale);
-       draw_alpha *= a;
-}
-
-void Container_leaveSubitem(entity me)
-{
-       draw_shift = me.Container_save_shift;
-       draw_scale = me.Container_save_scale;
-       draw_alpha = me.Container_save_alpha;
-       draw_fontscale = me.Container_save_fontscale;
-}
-
-void Container_showNotify(entity me)
-{
-       entity e;
-       if(me.shown)
-               return;
-       me.shown = 1;
-       for(e = me.firstChild; e; e = e.nextSibling)
-               if(e.Container_alpha > 0)
-                       e.showNotify(e);
-}
-
-void Container_hideNotify(entity me)
-{
-       entity e;
-       if (!me.shown)
-               return;
-       me.shown = 0;
-       for(e = me.firstChild; e; e = e.nextSibling)
-               if(e.Container_alpha > 0)
-                       e.hideNotify(e);
-}
-
-void Container_setAlphaOf(entity me, entity other, float theAlpha)
-{
-       if(theAlpha <= 0)
+       void Container_enterSubitem(entity me, entity sub)
        {
-               if(other.Container_alpha > 0)
-                       other.hideNotify(other);
+               me.enterLieSubitem(me, sub.Container_origin, sub.Container_size, sub.Container_fontscale, sub.Container_alpha);
        }
-       else // value > 0
+
+       void Container_enterLieSubitem(entity me, vector o, vector s, vector f, float a)
        {
-               if(other.Container_alpha <= 0)
-                       other.showNotify(other);
+               me.Container_save_shift = draw_shift;
+               me.Container_save_scale = draw_scale;
+               me.Container_save_alpha = draw_alpha;
+               me.Container_save_fontscale = draw_fontscale;
+
+               draw_shift = boxToGlobal(o, draw_shift, draw_scale);
+               draw_scale = boxToGlobalSize(s, draw_scale);
+               if (f != '0 0 0') draw_fontscale = boxToGlobalSize(f, draw_fontscale);
+               draw_alpha *= a;
        }
-       other.Container_alpha = theAlpha;
-}
-
-void Container_resizeNotifyLie(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize, .vector originField, .vector sizeField, .vector fontScaleField)
-{
-       entity e;
-       vector o, s;
-       float d;
-       for(e = me.firstChild; e; e = e.nextSibling)
+
+       void Container_leaveSubitem(entity me)
        {
-               o = e.(originField);
-               s = e.(sizeField);
-               me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
-               e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
-               me.leaveSubitem(me);
+               draw_shift = me.Container_save_shift;
+               draw_scale = me.Container_save_scale;
+               draw_alpha = me.Container_save_alpha;
+               draw_fontscale = me.Container_save_fontscale;
        }
-       do
+
+       void Container_showNotify(entity me)
        {
-               d = 0;
-               for(e = me.firstChild; e; e = e.nextSibling)
-                       if(e.resized)
-                       {
-                               e.resized = 0;
-                               d = 1;
-                               o = e.(originField);
-                               s = e.(sizeField);
-                               me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
-                               e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
-                               me.leaveSubitem(me);
-                       }
+               entity e;
+               if (me.shown) return;
+               me.shown = 1;
+               for (e = me.firstChild; e; e = e.nextSibling)
+                       if (e.Container_alpha > 0) e.showNotify(e);
+       }
+
+       void Container_hideNotify(entity me)
+       {
+               entity e;
+               if (!me.shown) return;
+               me.shown = 0;
+               for (e = me.firstChild; e; e = e.nextSibling)
+                       if (e.Container_alpha > 0) e.hideNotify(e);
+       }
+
+       void Container_setAlphaOf(entity me, entity other, float theAlpha)
+       {
+               if (theAlpha <= 0)
+               {
+                       if (other.Container_alpha > 0) other.hideNotify(other);
+               }
+               else  // value > 0
+               {
+                       if (other.Container_alpha <= 0) other.showNotify(other);
+               }
+               other.Container_alpha = theAlpha;
        }
-       while(d);
-       SUPER(Container).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-}
-
-void Container_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Container_origin, Container_size, Container_fontscale);
-}
-
-entity Container_itemFromPoint(entity me, vector pos)
-{
-       entity e;
-       vector o, s;
-       for(e = me.lastChild; e; e = e.prevSibling)
+
+       void Container_resizeNotifyLie(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize, .vector originField, .vector sizeField, .vector fontScaleField)
        {
-               o = e.Container_origin;
-               s = e.Container_size;
-               if(pos.x < o.x) continue;
-               if(pos.y < o.y) continue;
-               if(pos.x >= o.x + s.x) continue;
-               if(pos.y >= o.y + s.y) continue;
-               return e;
+               entity e;
+               vector o, s;
+               float d;
+               for (e = me.firstChild; e; e = e.nextSibling)
+               {
+                       o = e.(originField);
+                       s = e.(sizeField);
+                       me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
+                       e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
+                       me.leaveSubitem(me);
+               }
+               do
+               {
+                       d = 0;
+                       for (e = me.firstChild; e; e = e.nextSibling)
+                               if (e.resized)
+                               {
+                                       e.resized = 0;
+                                       d = 1;
+                                       o = e.(originField);
+                                       s = e.(sizeField);
+                                       me.enterLieSubitem(me, o, s, e.(fontScaleField), e.Container_alpha);
+                                       e.resizeNotify(e, o, s, boxToGlobal(o, absOrigin, absSize), boxToGlobalSize(s, absSize));
+                                       me.leaveSubitem(me);
+                               }
+               }
+               while (d);
+               SUPER(Container).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
        }
-       return NULL;
-}
 
-void Container_draw(entity me)
-{
-       entity e;
+       void Container_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+       {
+               me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Container_origin, Container_size, Container_fontscale);
+       }
 
-       me.focusable = 0;
-       for(e = me.firstChild; e; e = e.nextSibling)
+       entity Container_itemFromPoint(entity me, vector pos)
        {
-               if(e.focusable)
-                       me.focusable += 1;
-               if(e.Container_alpha < 0.003) // can't change color values anyway
-                       continue;
-               me.enterSubitem(me, e);
-               e.draw(e);
-               me.leaveSubitem(me);
+               entity e;
+               vector o, s;
+               for (e = me.lastChild; e; e = e.prevSibling)
+               {
+                       o = e.Container_origin;
+                       s = e.Container_size;
+                       if (pos.x < o.x) continue;
+                       if (pos.y < o.y) continue;
+                       if (pos.x >= o.x + s.x) continue;
+                       if (pos.y >= o.y + s.y) continue;
+                       return e;
+               }
+               return NULL;
        }
 
-       SUPER(Container).draw(me);
-}
+       void Container_draw(entity me)
+       {
+               entity e;
+
+               me.focusable = 0;
+               for (e = me.firstChild; e; e = e.nextSibling)
+               {
+                       if (e.focusable) me.focusable += 1;
+                       if (e.Container_alpha < 0.003)  // can't change color values anyway
+                               continue;
+                       me.enterSubitem(me, e);
+                       e.draw(e);
+                       me.leaveSubitem(me);
+               }
 
-void Container_focusLeave(entity me)
-{
-       me.setFocus(me, NULL);
-}
+               SUPER(Container).draw(me);
+       }
 
-float Container_keyUp(entity me, float scan, float ascii, float shift)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
+       void Container_focusLeave(entity me)
        {
-               me.enterSubitem(me, f);
-               r = f.keyUp(f, scan, ascii, shift);
-               me.leaveSubitem(me);
-               return r;
+               me.setFocus(me, NULL);
        }
-       return 0;
-}
-
-float Container_keyDown(entity me, float scan, float ascii, float shift)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
+
+       float Container_keyUp(entity me, float scan, float ascii, float shift)
        {
-               me.enterSubitem(me, f);
-               r = f.keyDown(f, scan, ascii, shift);
-               me.leaveSubitem(me);
-               return r;
+               entity f;
+               float r;
+               f = me.focusedChild;
+               if (f)
+               {
+                       me.enterSubitem(me, f);
+                       r = f.keyUp(f, scan, ascii, shift);
+                       me.leaveSubitem(me);
+                       return r;
+               }
+               return 0;
        }
-       return 0;
-}
-
-float Container_mouseMove(entity me, vector pos)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
+
+       float Container_keyDown(entity me, float scan, float ascii, float shift)
        {
-               me.enterSubitem(me, f);
-               r = f.mouseMove(f, globalToBox(pos, f.Container_origin, f.Container_size));
-               me.leaveSubitem(me);
-               return r;
+               entity f;
+               float r;
+               f = me.focusedChild;
+               if (f)
+               {
+                       me.enterSubitem(me, f);
+                       r = f.keyDown(f, scan, ascii, shift);
+                       me.leaveSubitem(me);
+                       return r;
+               }
+               return 0;
        }
-       return 0;
-}
-float Container_mousePress(entity me, vector pos)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
+
+       float Container_mouseMove(entity me, vector pos)
        {
-               me.enterSubitem(me, f);
-               r = f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size));
-               me.leaveSubitem(me);
-               return r;
+               entity f;
+               float r;
+               f = me.focusedChild;
+               if (f)
+               {
+                       me.enterSubitem(me, f);
+                       r = f.mouseMove(f, globalToBox(pos, f.Container_origin, f.Container_size));
+                       me.leaveSubitem(me);
+                       return r;
+               }
+               return 0;
        }
-       return 0;
-}
-float Container_mouseDrag(entity me, vector pos)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
+       float Container_mousePress(entity me, vector pos)
        {
-               me.enterSubitem(me, f);
-               r = f.mouseDrag(f, globalToBox(pos, f.Container_origin, f.Container_size));
-               me.leaveSubitem(me);
-               return r;
+               entity f;
+               float r;
+               f = me.focusedChild;
+               if (f)
+               {
+                       me.enterSubitem(me, f);
+                       r = f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size));
+                       me.leaveSubitem(me);
+                       return r;
+               }
+               return 0;
        }
-       return 0;
-}
-float Container_mouseRelease(entity me, vector pos)
-{
-       entity f;
-       float r;
-       f = me.focusedChild;
-       if(f)
+       float Container_mouseDrag(entity me, vector pos)
        {
-               me.enterSubitem(me, f);
-               r = f.mouseRelease(f, globalToBox(pos, f.Container_origin, f.Container_size));
-               me.leaveSubitem(me);
-               return r;
+               entity f;
+               float r;
+               f = me.focusedChild;
+               if (f)
+               {
+                       me.enterSubitem(me, f);
+                       r = f.mouseDrag(f, globalToBox(pos, f.Container_origin, f.Container_size));
+                       me.leaveSubitem(me);
+                       return r;
+               }
+               return 0;
+       }
+       float Container_mouseRelease(entity me, vector pos)
+       {
+               entity f;
+               float r;
+               f = me.focusedChild;
+               if (f)
+               {
+                       me.enterSubitem(me, f);
+                       r = f.mouseRelease(f, globalToBox(pos, f.Container_origin, f.Container_size));
+                       me.leaveSubitem(me);
+                       return r;
+               }
+               return 0;
        }
-       return 0;
-}
-
-void Container_addItemCentered(entity me, entity other, vector theSize, float theAlpha)
-{
-       me.addItem(me, other, '0.5 0.5 0' - 0.5 * theSize, theSize, theAlpha);
-}
-
-void Container_addItemRightCentered(entity me, entity other, vector theSize, float theAlpha)
-{
-       me.addItem(me, other, '1 0.5 0' - 0.5 * theSize, theSize, theAlpha);
-}
-
-void Container_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
-{
-       if(other.parent)
-               error("Can't add already added item!");
 
-       if(other.focusable)
-               me.focusable += 1;
+       void Container_addItemCentered(entity me, entity other, vector theSize, float theAlpha)
+       {
+               me.addItem(me, other, '0.5 0.5 0' - 0.5 * theSize, theSize, theAlpha);
+       }
 
-       if(theSize.x > 1)
+       void Container_addItemRightCentered(entity me, entity other, vector theSize, float theAlpha)
        {
-               theOrigin.x -= 0.5 * (theSize.x - 1);
-               theSize.x = 1;
+               me.addItem(me, other, '1 0.5 0' - 0.5 * theSize, theSize, theAlpha);
        }
-       if(theSize.y > 1)
+
+       void Container_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
        {
-               theOrigin.y -= 0.5 * (theSize.y - 1);
-               theSize.y = 1;
+               if (other.parent) error("Can't add already added item!");
+
+               if (other.focusable) me.focusable += 1;
+
+               if (theSize.x > 1)
+               {
+                       theOrigin.x -= 0.5 * (theSize.x - 1);
+                       theSize.x = 1;
+               }
+               if (theSize.y > 1)
+               {
+                       theOrigin.y -= 0.5 * (theSize.y - 1);
+                       theSize.y = 1;
+               }
+               theOrigin.x = bound(0, theOrigin.x, 1 - theSize.x);
+               theOrigin.y = bound(0, theOrigin.y, 1 - theSize.y);
+
+               other.parent = me;
+               other.Container_origin = theOrigin;
+               other.Container_size = theSize;
+               me.setAlphaOf(me, other, theAlpha);
+
+               entity l;
+               l = me.lastChild;
+
+               if (l) l.nextSibling = other;
+               else me.firstChild = other;
+
+               other.prevSibling = l;
+               other.nextSibling = NULL;
+               me.lastChild = other;
        }
-       theOrigin.x = bound(0, theOrigin.x, 1 - theSize.x);
-       theOrigin.y = bound(0, theOrigin.y, 1 - theSize.y);
-
-       other.parent = me;
-       other.Container_origin = theOrigin;
-       other.Container_size = theSize;
-       me.setAlphaOf(me, other, theAlpha);
-
-       entity l;
-       l = me.lastChild;
-
-       if(l)
-               l.nextSibling = other;
-       else
-               me.firstChild = other;
-
-       other.prevSibling = l;
-       other.nextSibling = NULL;
-       me.lastChild = other;
-}
-
-void Container_removeItem(entity me, entity other)
-{
-       if(other.parent != me)
-               error("Can't remove from wrong container!");
-
-       if(other.focusable)
-               me.focusable -= 1;
-
-       other.parent = NULL;
-
-       entity n, p;
-       n = other.nextSibling;
-       p = other.prevSibling;
-
-       if(p)
-               p.nextSibling = n;
-       else
-               me.firstChild = n;
-
-       if(n)
-               n.prevSibling = p;
-       else
-               me.lastChild = p;
-}
-
-void Container_setFocus(entity me, entity other)
-{
-       if(me.focusedChild == other)
-               return;
-
-       if(me.focusedChild)
+
+       void Container_removeItem(entity me, entity other)
        {
-               me.focusedChild.focused = 0;
-               me.focusedChild.focusLeave(me.focusedChild);
-               me.focusedChild = NULL;
+               if (other.parent != me) error("Can't remove from wrong container!");
+
+               if (other.focusable) me.focusable -= 1;
+
+               other.parent = NULL;
+
+               entity n, p;
+               n = other.nextSibling;
+               p = other.prevSibling;
+
+               if (p) p.nextSibling = n;
+               else me.firstChild = n;
+
+               if (n) n.prevSibling = p;
+               else me.lastChild = p;
        }
 
-       if(other)
+       void Container_setFocus(entity me, entity other)
        {
-               if(!me.focused)
-                       error("Trying to set focus in a non-focused control!");
+               if (me.focusedChild == other) return;
 
-               if(me.savedFocus)
+               if (me.focusedChild)
                {
-                       me.focusedChild = me.savedFocus;
-                       me.savedFocus = NULL;
-                       me.focusedChild.focused = 1;
-                       me.focusedChild.focusEnter(me.focusedChild);
-
-                       if(me.focusedChild.instanceOfContainer)
-                               me.focusedChild.setFocus(me.focusedChild, me.focusedChild.savedFocus);
+                       me.focusedChild.focused = 0;
+                       me.focusedChild.focusLeave(me.focusedChild);
+                       me.focusedChild = NULL;
                }
-               else
+
+               if (other)
                {
-                       me.focusedChild = other;
-                       me.focusedChild.focused = 1;
-                       me.focusedChild.focusEnter(me.focusedChild);
+                       if (!me.focused) error("Trying to set focus in a non-focused control!");
+
+                       if (me.savedFocus)
+                       {
+                               me.focusedChild = me.savedFocus;
+                               me.savedFocus = NULL;
+                               me.focusedChild.focused = 1;
+                               me.focusedChild.focusEnter(me.focusedChild);
+
+                               if (me.focusedChild.instanceOfContainer) me.focusedChild.setFocus(me.focusedChild, me.focusedChild.savedFocus);
+                       }
+                       else
+                       {
+                               me.focusedChild = other;
+                               me.focusedChild.focused = 1;
+                               me.focusedChild.focusEnter(me.focusedChild);
+                       }
                }
        }
-}
-
-void Container_saveFocus(entity me)
-{
-       me.savedFocus = me.focusedChild;
-
-       if(me.focusedChild.instanceOfContainer)
-               me.focusedChild.saveFocus(me.focusedChild);
-}
-
-void Container_moveItemAfter(entity me, entity other, entity dest)
-{
-       // first: remove other from the chain
-       entity n, p;
-
-       if(other.parent != me)
-               error("Can't move in wrong container!");
-
-       n = other.nextSibling;
-       p = other.prevSibling;
-
-       if(p)
-               p.nextSibling = n;
-       else
-               me.firstChild = n;
-
-       if(n)
-               n.prevSibling = p;
-       else
-               me.lastChild = p;
-
-       // now other got removed. Insert it behind dest now.
-       other.prevSibling = dest;
-       if(dest)
-               other.nextSibling = dest.nextSibling;
-       else
-               other.nextSibling = me.firstChild;
-
-       if(dest)
-               dest.nextSibling = other;
-       else
-               me.firstChild = other;
-
-       if(other.nextSibling)
-               other.nextSibling.prevSibling = other;
-       else
-               me.lastChild = other;
-}
 
-entity Container_preferredFocusedGrandChild(entity me)
-{
-       entity e, e2;
-       entity best;
+       void Container_saveFocus(entity me)
+       {
+               me.savedFocus = me.focusedChild;
+
+               if (me.focusedChild.instanceOfContainer) me.focusedChild.saveFocus(me.focusedChild);
+       }
+
+       void Container_moveItemAfter(entity me, entity other, entity dest)
+       {
+               // first: remove other from the chain
+               entity n, p;
+
+               if (other.parent != me) error("Can't move in wrong container!");
 
-       best = NULL;
+               n = other.nextSibling;
+               p = other.prevSibling;
 
-       for(e = me.firstChild; e; e = e.nextSibling)
+               if (p) p.nextSibling = n;
+               else me.firstChild = n;
+
+               if (n) n.prevSibling = p;
+               else me.lastChild = p;
+
+               // now other got removed. Insert it behind dest now.
+               other.prevSibling = dest;
+               if (dest) other.nextSibling = dest.nextSibling;
+               else other.nextSibling = me.firstChild;
+
+               if (dest) dest.nextSibling = other;
+               else me.firstChild = other;
+
+               if (other.nextSibling) other.nextSibling.prevSibling = other;
+               else me.lastChild = other;
+       }
+
+       entity Container_preferredFocusedGrandChild(entity me)
        {
-               if(e.instanceOfContainer)
+               entity e, e2;
+               entity best;
+
+               best = NULL;
+
+               for (e = me.firstChild; e; e = e.nextSibling)
                {
-                       e2 = e.preferredFocusedGrandChild(e);
-                       if(e2)
-                               if(!best || best.preferredFocusPriority < e2.preferredFocusPriority)
-                                       best = e2;
+                       if (e.instanceOfContainer)
+                       {
+                               e2 = e.preferredFocusedGrandChild(e);
+                               if (e2)
+                                       if (!best || best.preferredFocusPriority < e2.preferredFocusPriority) best = e2;
+                       }
+                       if (e)
+                               if (!best || best.preferredFocusPriority < e.preferredFocusPriority) best = e;
                }
-               if(e)
-                       if(!best || best.preferredFocusPriority < e.preferredFocusPriority)
-                               best = e;
-       }
 
-       return best;
-}
+               return best;
+       }
 #endif
index f02be5b53f0e61889a904d52d80ea128a88155ba..fc14d9222b1a76f1bd8535333da563d1cc54626c 100644 (file)
 // a subclass may help with using this as a tab
 
 #ifndef ITEM_DIALOG_H
-#define ITEM_DIALOG_H
-#include "inputcontainer.qc"
-CLASS(Dialog, InputContainer)
-       METHOD(Dialog, configureDialog, void(entity)); // no runtime configuration, all parameters are given in the code!
-       METHOD(Dialog, fill, void(entity)); // to be overridden by user to fill the dialog with controls
-       METHOD(Dialog, keyDown, float(entity, float, float, float));
-       METHOD(Dialog, close, void(entity));
-       METHOD(Dialog, addItemSimple, void(entity, float, float, float, float, entity, vector));
-
-       METHOD(Dialog, TD, void(entity, float, float, entity));
-       METHOD(Dialog, TDNoMargin, void(entity, float, float, entity, vector));
-       METHOD(Dialog, TDempty, void(entity, float));
-       METHOD(Dialog, setFirstColumn, void(entity, float));
-       METHOD(Dialog, TR, void(entity));
-       METHOD(Dialog, gotoRC, void(entity, float, float));
-
-       ATTRIB(Dialog, isTabRoot, float, 1)
-       ATTRIB(Dialog, closeButton, entity, NULL)
-       ATTRIB(Dialog, intendedHeight, float, 0)
-       ATTRIB(Dialog, itemOrigin, vector, '0 0 0')
-       ATTRIB(Dialog, itemSize, vector, '0 0 0')
-       ATTRIB(Dialog, itemSpacing, vector, '0 0 0')
-       ATTRIB(Dialog, currentRow, float, 0)
-       ATTRIB(Dialog, currentColumn, float, 0)
-       ATTRIB(Dialog, firstColumn, float, 0)
-
-       // to be customized
-       ATTRIB(Dialog, closable, float, 1)
-       ATTRIB(Dialog, title, string, "Form1") // ;)
-       ATTRIB(Dialog, color, vector, '1 0.5 1')
-       ATTRIB(Dialog, intendedWidth, float, 0)
-       ATTRIB(Dialog, rows, float, 3)
-       ATTRIB(Dialog, columns, float, 2)
-
-       ATTRIB(Dialog, marginTop, float, 0) // pixels
-       ATTRIB(Dialog, marginBottom, float, 0) // pixels
-       ATTRIB(Dialog, marginLeft, float, 0) // pixels
-       ATTRIB(Dialog, marginRight, float, 0) // pixels
-       ATTRIB(Dialog, columnSpacing, float, 0) // pixels
-       ATTRIB(Dialog, rowSpacing, float, 0) // pixels
-       ATTRIB(Dialog, rowHeight, float, 0) // pixels
-       ATTRIB(Dialog, titleHeight, float, 0) // pixels
-       ATTRIB(Dialog, titleFontSize, float, 0) // pixels; if 0, title causes no margin
-       ATTRIB(Dialog, zoomedOutTitleBarPosition, float, 0)
-       ATTRIB(Dialog, zoomedOutTitleBar, float, 0)
-
-       ATTRIB(Dialog, requiresConnection, float, 0) // set to true if the dialog requires a connection to be opened
-
-       ATTRIB(Dialog, backgroundImage, string, string_null)
-       ATTRIB(Dialog, borderLines, float, 1)
-       ATTRIB(Dialog, closeButtonImage, string, string_null)
-
-       ATTRIB(Dialog, frame, entity, NULL)
-ENDCLASS(Dialog)
+       #define ITEM_DIALOG_H
+       #include "inputcontainer.qc"
+       CLASS(Dialog, InputContainer)
+               METHOD(Dialog, configureDialog, void(entity)); // no runtime configuration, all parameters are given in the code!
+               METHOD(Dialog, fill, void(entity));            // to be overridden by user to fill the dialog with controls
+               METHOD(Dialog, keyDown, float(entity, float, float, float));
+               METHOD(Dialog, close, void(entity));
+               METHOD(Dialog, addItemSimple, void(entity, float, float, float, float, entity, vector));
+
+               METHOD(Dialog, TD, void(entity, float, float, entity));
+               METHOD(Dialog, TDNoMargin, void(entity, float, float, entity, vector));
+               METHOD(Dialog, TDempty, void(entity, float));
+               METHOD(Dialog, setFirstColumn, void(entity, float));
+               METHOD(Dialog, TR, void(entity));
+               METHOD(Dialog, gotoRC, void(entity, float, float));
+
+               ATTRIB(Dialog, isTabRoot, float, 1)
+               ATTRIB(Dialog, closeButton, entity, NULL)
+               ATTRIB(Dialog, intendedHeight, float, 0)
+               ATTRIB(Dialog, itemOrigin, vector, '0 0 0')
+               ATTRIB(Dialog, itemSize, vector, '0 0 0')
+               ATTRIB(Dialog, itemSpacing, vector, '0 0 0')
+               ATTRIB(Dialog, currentRow, float, 0)
+               ATTRIB(Dialog, currentColumn, float, 0)
+               ATTRIB(Dialog, firstColumn, float, 0)
+
+               // to be customized
+               ATTRIB(Dialog, closable, float, 1)
+               ATTRIB(Dialog, title, string, "Form1")  // ;)
+               ATTRIB(Dialog, color, vector, '1 0.5 1')
+               ATTRIB(Dialog, intendedWidth, float, 0)
+               ATTRIB(Dialog, rows, float, 3)
+               ATTRIB(Dialog, columns, float, 2)
+
+               ATTRIB(Dialog, marginTop, float, 0)     // pixels
+               ATTRIB(Dialog, marginBottom, float, 0)  // pixels
+               ATTRIB(Dialog, marginLeft, float, 0)    // pixels
+               ATTRIB(Dialog, marginRight, float, 0)   // pixels
+               ATTRIB(Dialog, columnSpacing, float, 0) // pixels
+               ATTRIB(Dialog, rowSpacing, float, 0)    // pixels
+               ATTRIB(Dialog, rowHeight, float, 0)     // pixels
+               ATTRIB(Dialog, titleHeight, float, 0)   // pixels
+               ATTRIB(Dialog, titleFontSize, float, 0) // pixels; if 0, title causes no margin
+               ATTRIB(Dialog, zoomedOutTitleBarPosition, float, 0)
+               ATTRIB(Dialog, zoomedOutTitleBar, float, 0)
+
+               ATTRIB(Dialog, requiresConnection, float, 0)  // set to true if the dialog requires a connection to be opened
+
+               ATTRIB(Dialog, backgroundImage, string, string_null)
+               ATTRIB(Dialog, borderLines, float, 1)
+               ATTRIB(Dialog, closeButtonImage, string, string_null)
+
+               ATTRIB(Dialog, frame, entity, NULL)
+       ENDCLASS(Dialog)
 #endif
 
 #ifdef IMPLEMENTATION
-void Dialog_Close(entity button, entity me)
-{
-       me.close(me);
-}
-
-void Dialog_fill(entity me)
-{
-}
-
-void Dialog_addItemSimple(entity me, float row, float col, float rowspan, float colspan, entity e, vector v)
-{
-       vector o, s;
-       o = me.itemOrigin + eX * ( col          * me.itemSpacing.x) + eY * ( row          * me.itemSpacing.y);
-       s = me.itemSize   + eX * ((colspan - 1) * me.itemSpacing.x) + eY * ((rowspan - 1) * me.itemSpacing.y);
-       o.x -= 0.5 * (me.itemSpacing.x - me.itemSize.x) * v.x;
-       s.x +=       (me.itemSpacing.x - me.itemSize.x) * v.x;
-       o.y -= 0.5 * (me.itemSpacing.y - me.itemSize.y) * v.y;
-       s.y +=       (me.itemSpacing.y - me.itemSize.y) * v.y;
-       me.addItem(me, e, o, s, 1);
-}
-
-void Dialog_gotoRC(entity me, float row, float col)
-{
-       me.currentRow = row;
-       me.currentColumn = col;
-}
-
-void Dialog_TR(entity me)
-{
-       me.currentRow += 1;
-       me.currentColumn = me.firstColumn;
-}
-
-void Dialog_TD(entity me, float rowspan, float colspan, entity e)
-{
-       me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, '0 0 0');
-       me.currentColumn += colspan;
-}
-
-void Dialog_TDNoMargin(entity me, float rowspan, float colspan, entity e, vector v)
-{
-       me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, v);
-       me.currentColumn += colspan;
-}
-
-void Dialog_setFirstColumn(entity me, float col)
-{
-       me.firstColumn = col;
-}
-
-void Dialog_TDempty(entity me, float colspan)
-{
-       me.currentColumn += colspan;
-}
-
-void Dialog_configureDialog(entity me)
-{
-       float absWidth, absHeight;
-
-       if(me.isTabRoot)
+       void Dialog_Close(entity button, entity me)
        {
-               me.frame = NEW(BorderImage);
-               me.frame.configureBorderImage(me.frame, me.title, me.titleFontSize, me.color, me.backgroundImage, me.borderLines * me.titleHeight);
-               me.frame.zoomedOutTitleBarPosition = me.zoomedOutTitleBarPosition;
-               me.frame.zoomedOutTitleBar = me.zoomedOutTitleBar;
-               me.frame.alpha = me.alpha;
-               me.addItem(me, me.frame, '0 0 0', '1 1 0', 1);
+               me.close(me);
        }
 
-       if (!me.titleFontSize)
-               me.titleHeight = 0; // no title bar
-
-       absWidth = me.intendedWidth * conwidth;
-       absHeight = me.borderLines * me.titleHeight + me.marginTop + me.rows * me.rowHeight + (me.rows - 1) * me.rowSpacing + me.marginBottom;
-       me.itemOrigin  = eX * (me.marginLeft / absWidth)
-                      + eY * ((me.borderLines * me.titleHeight + me.marginTop) / absHeight);
-       me.itemSize    = eX * ((1 - (me.marginLeft + me.marginRight + me.columnSpacing * (me.columns - 1)) / absWidth) / me.columns)
-                      + eY * (me.rowHeight / absHeight);
-       me.itemSpacing = me.itemSize
-                      + eX * (me.columnSpacing / absWidth)
-                      + eY * (me.rowSpacing / absHeight);
-       me.intendedHeight = absHeight / conheight;
-       me.currentRow = -1;
-       me.currentColumn = -1;
-
-       me.fill(me);
-
-       if(me.isTabRoot && me.closable && me.borderLines > 0)
+       void Dialog_fill(entity me)
+       {}
+
+       void Dialog_addItemSimple(entity me, float row, float col, float rowspan, float colspan, entity e, vector v)
+       {
+               vector o, s;
+               o = me.itemOrigin + eX * (col          * me.itemSpacing.x) + eY * (row          * me.itemSpacing.y);
+               s = me.itemSize   + eX * ((colspan - 1) * me.itemSpacing.x) + eY * ((rowspan - 1) * me.itemSpacing.y);
+               o.x -= 0.5 * (me.itemSpacing.x - me.itemSize.x) * v.x;
+               s.x +=       (me.itemSpacing.x - me.itemSize.x) * v.x;
+               o.y -= 0.5 * (me.itemSpacing.y - me.itemSize.y) * v.y;
+               s.y +=       (me.itemSpacing.y - me.itemSize.y) * v.y;
+               me.addItem(me, e, o, s, 1);
+       }
+
+       void Dialog_gotoRC(entity me, float row, float col)
        {
-               entity closebutton;
-               closebutton = me.closeButton = me.frame.closeButton = NEW(Button);
-               closebutton.configureButton(closebutton, "", 0, me.closeButtonImage);
-               closebutton.onClick = Dialog_Close; closebutton.onClickEntity = me;
-               closebutton.srcMulti = 0;
-               me.addItem(me, closebutton, '0 0 0', '1 1 0', 1); // put it as LAST
+               me.currentRow = row;
+               me.currentColumn = col;
        }
-}
 
-void Dialog_close(entity me)
-{
-       if(me.parent.instanceOfNexposee)
+       void Dialog_TR(entity me)
        {
-               ExposeeCloseButton_Click(me, me.parent);
+               me.currentRow += 1;
+               me.currentColumn = me.firstColumn;
        }
-       else if(me.parent.instanceOfModalController)
+
+       void Dialog_TD(entity me, float rowspan, float colspan, entity e)
+       {
+               me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, '0 0 0');
+               me.currentColumn += colspan;
+       }
+
+       void Dialog_TDNoMargin(entity me, float rowspan, float colspan, entity e, vector v)
+       {
+               me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, v);
+               me.currentColumn += colspan;
+       }
+
+       void Dialog_setFirstColumn(entity me, float col)
+       {
+               me.firstColumn = col;
+       }
+
+       void Dialog_TDempty(entity me, float colspan)
+       {
+               me.currentColumn += colspan;
+       }
+
+       void Dialog_configureDialog(entity me)
+       {
+               float absWidth, absHeight;
+
+               if (me.isTabRoot)
+               {
+                       me.frame = NEW(BorderImage);
+                       me.frame.configureBorderImage(me.frame, me.title, me.titleFontSize, me.color, me.backgroundImage, me.borderLines * me.titleHeight);
+                       me.frame.zoomedOutTitleBarPosition = me.zoomedOutTitleBarPosition;
+                       me.frame.zoomedOutTitleBar = me.zoomedOutTitleBar;
+                       me.frame.alpha = me.alpha;
+                       me.addItem(me, me.frame, '0 0 0', '1 1 0', 1);
+               }
+
+               if (!me.titleFontSize) me.titleHeight = 0;  // no title bar
+
+               absWidth = me.intendedWidth * conwidth;
+               absHeight = me.borderLines * me.titleHeight + me.marginTop + me.rows * me.rowHeight + (me.rows - 1) * me.rowSpacing + me.marginBottom;
+               me.itemOrigin  = eX * (me.marginLeft / absWidth)
+                   + eY * ((me.borderLines * me.titleHeight + me.marginTop) / absHeight);
+               me.itemSize    = eX * ((1 - (me.marginLeft + me.marginRight + me.columnSpacing * (me.columns - 1)) / absWidth) / me.columns)
+                   + eY * (me.rowHeight / absHeight);
+               me.itemSpacing = me.itemSize
+                   + eX * (me.columnSpacing / absWidth)
+                   + eY * (me.rowSpacing / absHeight);
+               me.intendedHeight = absHeight / conheight;
+               me.currentRow = -1;
+               me.currentColumn = -1;
+
+               me.fill(me);
+
+               if (me.isTabRoot && me.closable && me.borderLines > 0)
+               {
+                       entity closebutton;
+                       closebutton = me.closeButton = me.frame.closeButton = NEW(Button);
+                       closebutton.configureButton(closebutton, "", 0, me.closeButtonImage);
+                       closebutton.onClick = Dialog_Close;
+                       closebutton.onClickEntity = me;
+                       closebutton.srcMulti = 0;
+                       me.addItem(me, closebutton, '0 0 0', '1 1 0', 1);  // put it as LAST
+               }
+       }
+
+       void Dialog_close(entity me)
        {
-               DialogCloseButton_Click(me, me);
+               if (me.parent.instanceOfNexposee) ExposeeCloseButton_Click(me, me.parent);
+               else if (me.parent.instanceOfModalController) DialogCloseButton_Click(me, me);
        }
-}
 
-float Dialog_keyDown(entity me, float key, float ascii, float shift)
-{
-       if(me.closable)
+       float Dialog_keyDown(entity me, float key, float ascii, float shift)
        {
-               if(key == K_ESCAPE)
+               if (me.closable)
                {
-                       m_play_click_sound(MENU_SOUND_CLOSE);
-                       me.close(me);
-                       return 1;
+                       if (key == K_ESCAPE)
+                       {
+                               m_play_click_sound(MENU_SOUND_CLOSE);
+                               me.close(me);
+                               return 1;
+                       }
                }
+               return SUPER(Dialog).keyDown(me, key, ascii, shift);
        }
-       return SUPER(Dialog).keyDown(me, key, ascii, shift);
-}
 #endif
index baa5d6157389f348cb2b207b58e14024b112a720..2a28c78b1d89d94b1edfc50a03c1077a57c7b5ac 100644 (file)
 #ifndef ITEM_IMAGE_H
-#define ITEM_IMAGE_H
-#include "../item.qc"
-CLASS(Image, Item)
-       METHOD(Image, configureImage, void(entity, string));
-       METHOD(Image, draw, void(entity));
-       METHOD(Image, toString, string(entity));
-       METHOD(Image, resizeNotify, void(entity, vector, vector, vector, vector));
-       METHOD(Image, updateAspect, void(entity));
-       METHOD(Image, initZoom, void(entity));
-       METHOD(Image, setZoom, void(entity, float, float));
-       METHOD(Image, drag_setStartPos, float(entity, vector));
-       METHOD(Image, drag, float(entity, vector));
-       ATTRIB(Image, src, string, string_null)
-       ATTRIB(Image, color, vector, '1 1 1')
-       ATTRIB(Image, forcedAspect, float, 0) // special values: -1 keep image aspect ratio, -2 keep image size but bound to the containing box, -3 always keep image size
-       ATTRIB(Image, zoomBox, float, 0) // used by forcedAspect -2 when the image is larger than the containing box
-       ATTRIB(Image, zoomFactor, float, 1)
-       ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0')
-       ATTRIB(Image, zoomSnapToTheBox, float, 1) // snap the zoomed in image to the box borders when zooming/dragging it
-       ATTRIB(Image, zoomTime, float, 0)
-       ATTRIB(Image, zoomLimitedByTheBox, float, 0) // forbids zoom if image would be larger than the containing box
-       ATTRIB(Image, zoomMax, float, 0)
-       ATTRIB(Image, start_zoomOffset, vector, '0 0 0')
-       ATTRIB(Image, start_coords, vector, '0 0 0')
-       ATTRIB(Image, imgOrigin, vector, '0 0 0')
-       ATTRIB(Image, imgSize, vector, '0 0 0')
-ENDCLASS(Image)
+       #define ITEM_IMAGE_H
+       #include "../item.qc"
+       CLASS(Image, Item)
+               METHOD(Image, configureImage, void(entity, string));
+               METHOD(Image, draw, void(entity));
+               METHOD(Image, toString, string(entity));
+               METHOD(Image, resizeNotify, void(entity, vector, vector, vector, vector));
+               METHOD(Image, updateAspect, void(entity));
+               METHOD(Image, initZoom, void(entity));
+               METHOD(Image, setZoom, void(entity, float, float));
+               METHOD(Image, drag_setStartPos, float(entity, vector));
+               METHOD(Image, drag, float(entity, vector));
+               ATTRIB(Image, src, string, string_null)
+               ATTRIB(Image, color, vector, '1 1 1')
+               ATTRIB(Image, forcedAspect, float, 0)        // special values: -1 keep image aspect ratio, -2 keep image size but bound to the containing box, -3 always keep image size
+               ATTRIB(Image, zoomBox, float, 0)             // used by forcedAspect -2 when the image is larger than the containing box
+               ATTRIB(Image, zoomFactor, float, 1)
+               ATTRIB(Image, zoomOffset, vector, '0.5 0.5 0')
+               ATTRIB(Image, zoomSnapToTheBox, float, 1)    // snap the zoomed in image to the box borders when zooming/dragging it
+               ATTRIB(Image, zoomTime, float, 0)
+               ATTRIB(Image, zoomLimitedByTheBox, float, 0) // forbids zoom if image would be larger than the containing box
+               ATTRIB(Image, zoomMax, float, 0)
+               ATTRIB(Image, start_zoomOffset, vector, '0 0 0')
+               ATTRIB(Image, start_coords, vector, '0 0 0')
+               ATTRIB(Image, imgOrigin, vector, '0 0 0')
+               ATTRIB(Image, imgSize, vector, '0 0 0')
+       ENDCLASS(Image)
 #endif
 
 #ifdef IMPLEMENTATION
-string Image_toString(entity me)
-{
-       return me.src;
-}
-void Image_configureImage(entity me, string path)
-{
-       me.src = path;
-}
-void Image_initZoom(entity me)
-{
-       me.zoomOffset = '0.5 0.5 0';
-       me.zoomFactor = 1;
-       if (me.forcedAspect == -2)
-               me.zoomBox = -1; // calculate zoomBox at the first updateAspect call
-       if (me.zoomLimitedByTheBox)
-               me.zoomMax = -1; // calculate zoomMax at the first updateAspect call
-}
+       string Image_toString(entity me)
+       {
+               return me.src;
+       }
+       void Image_configureImage(entity me, string path)
+       {
+               me.src = path;
+       }
+       void Image_initZoom(entity me)
+       {
+               me.zoomOffset = '0.5 0.5 0';
+               me.zoomFactor = 1;
+               if (me.forcedAspect == -2) me.zoomBox = -1;  // calculate zoomBox at the first updateAspect call
+               if (me.zoomLimitedByTheBox) me.zoomMax = -1; // calculate zoomMax at the first updateAspect call
+       }
 
-void Image_draw(entity me)
-{
-       if(me.imgSize.x > 1 || me.imgSize.y > 1)
-               draw_SetClip();
-       draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
-       if(me.imgSize.x > 1 || me.imgSize.y > 1)
-               draw_ClearClip();
-       SUPER(Image).draw(me);
-}
-void Image_updateAspect(entity me)
-{
-       float asp = 0;
-       if(me.size.x <= 0 || me.size.y <= 0)
-               return;
-       if(me.forcedAspect == 0)
+       void Image_draw(entity me)
        {
-               me.imgOrigin = '0 0 0';
-               me.imgSize = '1 1 0';
+               if (me.imgSize.x > 1 || me.imgSize.y > 1) draw_SetClip();
+               draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
+               if (me.imgSize.x > 1 || me.imgSize.y > 1) draw_ClearClip();
+               SUPER(Image).draw(me);
        }
-       else
+       void Image_updateAspect(entity me)
        {
-               vector sz = '0 0 0';
-               if(me.forcedAspect < 0)
+               float asp = 0;
+               if (me.size.x <= 0 || me.size.y <= 0) return;
+               if (me.forcedAspect == 0)
                {
-                       if (me.src != "")
-                               sz = draw_PictureSize(me.src);
-                       if(sz.x <= 0 || sz.y <= 0)
-                       {
-                               // image is broken or doesn't exist, set the size for the placeholder image
-                               sz.x = me.size.x;
-                               sz.y = me.size.y;
-                       }
-                       asp = sz.x / sz.y;
+                       me.imgOrigin = '0 0 0';
+                       me.imgSize = '1 1 0';
                }
                else
-                       asp = me.forcedAspect;
-
-               if(me.forcedAspect <= -2)
                {
-                       me.imgSize_x = sz.x / me.size.x;
-                       me.imgSize_y = sz.y / me.size.y;
-                       if(me.zoomBox < 0 && (me.imgSize.x > 1 || me.imgSize.y > 1))
+                       vector sz = '0 0 0';
+                       if (me.forcedAspect < 0)
                        {
-                               // image larger than the containing box, zoom it out to fit into the box
-                               if(me.size.x > asp * me.size.y)
-                                       me.zoomBox = (me.size.y * asp / me.size.x) / me.imgSize.x;
-                               else
-                                       me.zoomBox = (me.size.x / (asp * me.size.y)) / me.imgSize.y;
-                               me.zoomFactor = me.zoomBox;
+                               if (me.src != "") sz = draw_PictureSize(me.src);
+                               if (sz.x <= 0 || sz.y <= 0)
+                               {
+                                       // image is broken or doesn't exist, set the size for the placeholder image
+                                       sz.x = me.size.x;
+                                       sz.y = me.size.y;
+                               }
+                               asp = sz.x / sz.y;
                        }
-               }
-               else
-               {
-                       if(me.size.x > asp * me.size.y)
+                       else
                        {
-                               // x too large, so center x-wise
-                               me.imgSize = eY + eX * (me.size.y * asp / me.size.x);
+                               asp = me.forcedAspect;
+                       }
+
+                       if (me.forcedAspect <= -2)
+                       {
+                               me.imgSize_x = sz.x / me.size.x;
+                               me.imgSize_y = sz.y / me.size.y;
+                               if (me.zoomBox < 0 && (me.imgSize.x > 1 || me.imgSize.y > 1))
+                               {
+                                       // image larger than the containing box, zoom it out to fit into the box
+                                       if (me.size.x > asp * me.size.y) me.zoomBox = (me.size.y * asp / me.size.x) / me.imgSize.x;
+                                       else me.zoomBox = (me.size.x / (asp * me.size.y)) / me.imgSize.y;
+                                       me.zoomFactor = me.zoomBox;
+                               }
                        }
                        else
                        {
-                               // y too large, so center y-wise
-                               me.imgSize = eX + eY * (me.size.x / (asp * me.size.y));
+                               if (me.size.x > asp * me.size.y)
+                               {
+                                       // x too large, so center x-wise
+                                       me.imgSize = eY + eX * (me.size.y * asp / me.size.x);
+                               }
+                               else
+                               {
+                                       // y too large, so center y-wise
+                                       me.imgSize = eX + eY * (me.size.x / (asp * me.size.y));
+                               }
                        }
                }
-       }
 
-       if (me.zoomMax < 0)
-       {
-               if(me.zoomBox > 0)
-                       me.zoomMax = me.zoomBox;
-               else
+               if (me.zoomMax < 0)
                {
-                       if(me.size.x > asp * me.size.y)
-                               me.zoomMax = (me.size.y * asp / me.size.x) / me.imgSize.x;
+                       if (me.zoomBox > 0)
+                       {
+                               me.zoomMax = me.zoomBox;
+                       }
                        else
-                               me.zoomMax = (me.size.x / (asp * me.size.y)) / me.imgSize.y;
+                       {
+                               if (me.size.x > asp * me.size.y) me.zoomMax = (me.size.y * asp / me.size.x) / me.imgSize.x;
+                               else me.zoomMax = (me.size.x / (asp * me.size.y)) / me.imgSize.y;
+                       }
                }
-       }
 
-       if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
-               me.zoomFactor = me.zoomMax;
-       if (me.zoomFactor)
-               me.imgSize = me.imgSize * me.zoomFactor;
+               if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax) me.zoomFactor = me.zoomMax;
+               if (me.zoomFactor) me.imgSize = me.imgSize * me.zoomFactor;
 
-       if(me.imgSize.x > 1 || me.imgSize.y > 1)
-       {
-               if(me.zoomSnapToTheBox)
+               if (me.imgSize.x > 1 || me.imgSize.y > 1)
                {
-                       if(me.imgSize.x > 1)
-                               me.zoomOffset_x = bound(0.5/me.imgSize.x, me.zoomOffset.x, 1 - 0.5/me.imgSize.x);
-                       else
-                               me.zoomOffset_x = bound(1 - 0.5/me.imgSize.x, me.zoomOffset.x, 0.5/me.imgSize.x);
+                       if (me.zoomSnapToTheBox)
+                       {
+                               if (me.imgSize.x > 1) me.zoomOffset_x = bound(0.5 / me.imgSize.x, me.zoomOffset.x, 1 - 0.5 / me.imgSize.x);
+                               else me.zoomOffset_x = bound(1 - 0.5 / me.imgSize.x, me.zoomOffset.x, 0.5 / me.imgSize.x);
 
-                       if(me.imgSize.y > 1)
-                               me.zoomOffset_y = bound(0.5/me.imgSize.y, me.zoomOffset.y, 1 - 0.5/me.imgSize.y);
+                               if (me.imgSize.y > 1) me.zoomOffset_y = bound(0.5 / me.imgSize.y, me.zoomOffset.y, 1 - 0.5 / me.imgSize.y);
+                               else me.zoomOffset_y = bound(1 - 0.5 / me.imgSize.y, me.zoomOffset.y, 0.5 / me.imgSize.y);
+                       }
                        else
-                               me.zoomOffset_y = bound(1 - 0.5/me.imgSize.y, me.zoomOffset.y, 0.5/me.imgSize.y);
+                       {
+                               me.zoomOffset_x = bound(0, me.zoomOffset.x, 1);
+                               me.zoomOffset_y = bound(0, me.zoomOffset.y, 1);
+                       }
                }
                else
                {
-                       me.zoomOffset_x = bound(0, me.zoomOffset.x, 1);
-                       me.zoomOffset_y = bound(0, me.zoomOffset.y, 1);
+                       me.zoomOffset = '0.5 0.5 0';
                }
-       }
-       else
-               me.zoomOffset = '0.5 0.5 0';
 
-       me.imgOrigin_x = 0.5 - me.zoomOffset.x * me.imgSize.x;
-       me.imgOrigin_y = 0.5 - me.zoomOffset.y * me.imgSize.y;
-}
-float Image_drag_setStartPos(entity me, vector coords)
-{
-       //if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
-       {
-               me.start_zoomOffset = me.zoomOffset;
-               me.start_coords = coords;
-       }
-       return 1;
-}
-float Image_drag(entity me, vector coords)
-{
-       if(me.imgSize.x > 1 || me.imgSize.y > 1)
-       {
-               me.zoomOffset_x = me.start_zoomOffset.x + (me.start_coords.x - coords.x) / me.imgSize.x;
-               me.zoomOffset_y = me.start_zoomOffset.y + (me.start_coords.y - coords.y) / me.imgSize.y;
-               me.updateAspect(me);
+               me.imgOrigin_x = 0.5 - me.zoomOffset.x * me.imgSize.x;
+               me.imgOrigin_y = 0.5 - me.zoomOffset.y * me.imgSize.y;
        }
-       return 1;
-}
-void Image_setZoom(entity me, float z, float atMousePosition)
-{
-       float prev_zoomFactor;
-       prev_zoomFactor = me.zoomFactor;
-       if (z < 0) // multiply by the current zoomFactor (but can also snap to real dimensions or to box)
+       float Image_drag_setStartPos(entity me, vector coords)
        {
-               me.zoomFactor *= -z;
-               float realSize_in_the_middle, boxSize_in_the_middle;
-               realSize_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
-               boxSize_in_the_middle = (me.zoomBox > 0 && (prev_zoomFactor - me.zoomBox) * (me.zoomFactor - me.zoomBox) < 0);
-               if (realSize_in_the_middle && boxSize_in_the_middle)
+               // if(me.imgSize_x > 1 || me.imgSize_y > 1) // check disabled: mousewheel zoom may start from a non-zoomed-in image
                {
-                       // snap to real dimensions or to box
-                       if (prev_zoomFactor < me.zoomFactor)
-                               me.zoomFactor = min(1, me.zoomBox);
-                       else
-                               me.zoomFactor = max(1, me.zoomBox);
+                       me.start_zoomOffset = me.zoomOffset;
+                       me.start_coords = coords;
                }
-               else if (realSize_in_the_middle)
-                       me.zoomFactor = 1; // snap to real dimensions
-               else if (boxSize_in_the_middle)
-                       me.zoomFactor = me.zoomBox; // snap to box
+               return 1;
        }
-       else if (z == 0) // reset (no zoom)
+       float Image_drag(entity me, vector coords)
        {
-               if (me.zoomBox > 0)
-                       me.zoomFactor = me.zoomBox;
-               else
-                       me.zoomFactor = 1;
+               if (me.imgSize.x > 1 || me.imgSize.y > 1)
+               {
+                       me.zoomOffset_x = me.start_zoomOffset.x + (me.start_coords.x - coords.x) / me.imgSize.x;
+                       me.zoomOffset_y = me.start_zoomOffset.y + (me.start_coords.y - coords.y) / me.imgSize.y;
+                       me.updateAspect(me);
+               }
+               return 1;
        }
-       else // directly set
-               me.zoomFactor = z;
-       me.zoomFactor = bound(1/16, me.zoomFactor, 16);
-       if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax)
-               me.zoomFactor = me.zoomMax;
-       if (prev_zoomFactor != me.zoomFactor)
+       void Image_setZoom(entity me, float z, float atMousePosition)
        {
-               me.zoomTime = time;
-               if (atMousePosition)
+               float prev_zoomFactor;
+               prev_zoomFactor = me.zoomFactor;
+               if (z < 0)  // multiply by the current zoomFactor (but can also snap to real dimensions or to box)
+               {
+                       me.zoomFactor *= -z;
+                       float realSize_in_the_middle, boxSize_in_the_middle;
+                       realSize_in_the_middle = ((prev_zoomFactor - 1) * (me.zoomFactor - 1) < 0);
+                       boxSize_in_the_middle = (me.zoomBox > 0 && (prev_zoomFactor - me.zoomBox) * (me.zoomFactor - me.zoomBox) < 0);
+                       if (realSize_in_the_middle && boxSize_in_the_middle)
+                       {
+                               // snap to real dimensions or to box
+                               if (prev_zoomFactor < me.zoomFactor) me.zoomFactor = min(1, me.zoomBox);
+                               else me.zoomFactor = max(1, me.zoomBox);
+                       }
+                       else if (realSize_in_the_middle)
+                       {
+                               me.zoomFactor = 1;  // snap to real dimensions
+                       }
+                       else if (boxSize_in_the_middle)
+                       {
+                               me.zoomFactor = me.zoomBox; // snap to box
+                       }
+               }
+               else if (z == 0)                    // reset (no zoom)
+               {
+                       if (me.zoomBox > 0) me.zoomFactor = me.zoomBox;
+                       else me.zoomFactor = 1;
+               }
+               else  // directly set
                {
-                       me.zoomOffset_x = me.start_zoomOffset.x + (me.start_coords.x - 0.5) / me.imgSize.x;
-                       me.zoomOffset_y = me.start_zoomOffset.y + (me.start_coords.y - 0.5) / me.imgSize.y;
-                       // updateAspect will reset zoomOffset to '0.5 0.5 0' if
-                       // with this zoomFactor the image will not be zoomed in
-                       // (updateAspect will check the new values of imgSize).
+                       me.zoomFactor = z;
                }
+               me.zoomFactor = bound(1 / 16, me.zoomFactor, 16);
+               if (me.zoomMax > 0 && me.zoomFactor > me.zoomMax) me.zoomFactor = me.zoomMax;
+               if (prev_zoomFactor != me.zoomFactor)
+               {
+                       me.zoomTime = time;
+                       if (atMousePosition)
+                       {
+                               me.zoomOffset_x = me.start_zoomOffset.x + (me.start_coords.x - 0.5) / me.imgSize.x;
+                               me.zoomOffset_y = me.start_zoomOffset.y + (me.start_coords.y - 0.5) / me.imgSize.y;
+                               // updateAspect will reset zoomOffset to '0.5 0.5 0' if
+                               // with this zoomFactor the image will not be zoomed in
+                               // (updateAspect will check the new values of imgSize).
+                       }
+               }
+               me.updateAspect(me);
+       }
+       void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+       {
+               SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+               me.updateAspect(me);
        }
-       me.updateAspect(me);
-}
-void Image_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(Image).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       me.updateAspect(me);
-}
 #endif
index 35ffe44d8bfa387446e55faea7c894ebcf29a693..89adfaae934425dcc46ca6b024a79fac384dc24e 100644 (file)
 #ifndef ITEM_INPUTBOX_H
-#define ITEM_INPUTBOX_H
-#include "label.qc"
-CLASS(InputBox, Label)
-       METHOD(InputBox, configureInputBox, void(entity, string, float, float, string));
-       METHOD(InputBox, draw, void(entity));
-       METHOD(InputBox, setText, void(entity, string));
-       METHOD(InputBox, enterText, void(entity, string));
-       METHOD(InputBox, keyDown, float(entity, float, float, float));
-       METHOD(InputBox, mouseMove, float(entity, vector));
-       METHOD(InputBox, mouseRelease, float(entity, vector));
-       METHOD(InputBox, mousePress, float(entity, vector));
-       METHOD(InputBox, mouseDrag, float(entity, vector));
-       METHOD(InputBox, showNotify, void(entity));
-       METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector));
-
-       ATTRIB(InputBox, src, string, string_null)
-
-       ATTRIB(InputBox, cursorPos, float, 0) // characters
-       ATTRIB(InputBox, scrollPos, float, 0) // widths
-
-       ATTRIB(InputBox, focusable, float, 1)
-       ATTRIB(InputBox, allowFocusSound, float, 1)
-       ATTRIB(InputBox, disabled, float, 0)
-       ATTRIB(InputBox, lastChangeTime, float, 0)
-       ATTRIB(InputBox, dragScrollTimer, float, 0)
-       ATTRIB(InputBox, dragScrollPos, vector, '0 0 0')
-       ATTRIB(InputBox, pressed, float, 0)
-       ATTRIB(InputBox, editColorCodes, float, 1)
-       ATTRIB(InputBox, forbiddenCharacters, string, "")
-       ATTRIB(InputBox, color, vector, '1 1 1')
-       ATTRIB(InputBox, colorF, vector, '1 1 1')
-       ATTRIB(InputBox, maxLength, float, 255) // if negative, it counts bytes, not chars
-
-       ATTRIB(InputBox, enableClearButton, float, 1)
-       ATTRIB(InputBox, clearButton, entity, NULL)
-       ATTRIB(InputBox, cb_width, float, 0)
-       ATTRIB(InputBox, cb_pressed, float, 0)
-       ATTRIB(InputBox, cb_focused, float, 0)
-       ATTRIB(InputBox, cb_color, vector, '1 1 1')
-       ATTRIB(InputBox, cb_colorF, vector, '1 1 1')
-       ATTRIB(InputBox, cb_colorC, vector, '1 1 1')
-ENDCLASS(InputBox)
+       #define ITEM_INPUTBOX_H
+       #include "label.qc"
+       CLASS(InputBox, Label)
+               METHOD(InputBox, configureInputBox, void(entity, string, float, float, string));
+               METHOD(InputBox, draw, void(entity));
+               METHOD(InputBox, setText, void(entity, string));
+               METHOD(InputBox, enterText, void(entity, string));
+               METHOD(InputBox, keyDown, float(entity, float, float, float));
+               METHOD(InputBox, mouseMove, float(entity, vector));
+               METHOD(InputBox, mouseRelease, float(entity, vector));
+               METHOD(InputBox, mousePress, float(entity, vector));
+               METHOD(InputBox, mouseDrag, float(entity, vector));
+               METHOD(InputBox, showNotify, void(entity));
+               METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector));
+
+               ATTRIB(InputBox, src, string, string_null)
+
+               ATTRIB(InputBox, cursorPos, float, 0)  // characters
+               ATTRIB(InputBox, scrollPos, float, 0)  // widths
+
+               ATTRIB(InputBox, focusable, float, 1)
+               ATTRIB(InputBox, allowFocusSound, float, 1)
+               ATTRIB(InputBox, disabled, float, 0)
+               ATTRIB(InputBox, lastChangeTime, float, 0)
+               ATTRIB(InputBox, dragScrollTimer, float, 0)
+               ATTRIB(InputBox, dragScrollPos, vector, '0 0 0')
+               ATTRIB(InputBox, pressed, float, 0)
+               ATTRIB(InputBox, editColorCodes, float, 1)
+               ATTRIB(InputBox, forbiddenCharacters, string, "")
+               ATTRIB(InputBox, color, vector, '1 1 1')
+               ATTRIB(InputBox, colorF, vector, '1 1 1')
+               ATTRIB(InputBox, maxLength, float, 255)  // if negative, it counts bytes, not chars
+
+               ATTRIB(InputBox, enableClearButton, float, 1)
+               ATTRIB(InputBox, clearButton, entity, NULL)
+               ATTRIB(InputBox, cb_width, float, 0)
+               ATTRIB(InputBox, cb_pressed, float, 0)
+               ATTRIB(InputBox, cb_focused, float, 0)
+               ATTRIB(InputBox, cb_color, vector, '1 1 1')
+               ATTRIB(InputBox, cb_colorF, vector, '1 1 1')
+               ATTRIB(InputBox, cb_colorC, vector, '1 1 1')
+       ENDCLASS(InputBox)
 #endif
 
 #ifdef IMPLEMENTATION
-void InputBox_configureInputBox(entity me, string theText, float theCursorPos, float theFontSize, string gfx)
-{
-       SUPER(InputBox).configureLabel(me, theText, theFontSize, 0.0);
-       me.src = gfx;
-       me.cursorPos = theCursorPos;
-}
-void InputBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(InputBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       if (me.enableClearButton)
+       void InputBox_configureInputBox(entity me, string theText, float theCursorPos, float theFontSize, string gfx)
        {
-               me.cb_width = absSize.y / absSize.x;
-               me.cb_offset = bound(-1, me.cb_offset, 0) * me.cb_width; // bound to range -1, 0
-               me.keepspaceRight = me.keepspaceRight - me.cb_offset + me.cb_width;
+               SUPER(InputBox).configureLabel(me, theText, theFontSize, 0.0);
+               me.src = gfx;
+               me.cursorPos = theCursorPos;
        }
-}
-
-void InputBox_setText(entity me, string txt)
-{
-       if(me.text)
-               strunzone(me.text);
-       SUPER(InputBox).setText(me, strzone(txt));
-}
-
-float over_ClearButton(entity me, vector pos)
-{
-       if (pos.x >= 1 + me.cb_offset - me.cb_width)
-       if (pos.x < 1 + me.cb_offset)
-       if (pos.y >= 0)
-       if (pos.y < 1)
-               return 1;
-       return 0;
-}
-
-float InputBox_mouseMove(entity me, vector pos)
-{
-       if (me.enableClearButton)
+       void InputBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
        {
-               if (over_ClearButton(me, pos))
+               SUPER(InputBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+               if (me.enableClearButton)
                {
-                       me.cb_focused = 1;
-                       return 1;
+                       me.cb_width = absSize.y / absSize.x;
+                       me.cb_offset = bound(-1, me.cb_offset, 0) * me.cb_width;  // bound to range -1, 0
+                       me.keepspaceRight = me.keepspaceRight - me.cb_offset + me.cb_width;
                }
-               me.cb_focused = 0;
        }
-       return 1;
-}
 
-float InputBox_mouseDrag(entity me, vector pos)
-{
-       float p;
-       if(me.pressed)
+       void InputBox_setText(entity me, string txt)
        {
-               me.dragScrollPos = pos;
-               p = me.scrollPos + pos.x - me.keepspaceLeft;
-               me.cursorPos = draw_TextLengthUpToWidth(me.text, p, 0, me.realFontSize);
-               me.lastChangeTime = time;
+               if (me.text) strunzone(me.text);
+               SUPER(InputBox).setText(me, strzone(txt));
        }
-       else if (me.enableClearButton)
+
+       float over_ClearButton(entity me, vector pos)
        {
-               if (over_ClearButton(me, pos))
-               {
-                       me.cb_pressed = 1;
-                       return 1;
-               }
+               if (pos.x >= 1 + me.cb_offset - me.cb_width)
+                       if (pos.x < 1 + me.cb_offset)
+                               if (pos.y >= 0)
+                                       if (pos.y < 1) return 1;
+               return 0;
        }
-       me.cb_pressed = 0;
-       return 1;
-}
-
-float InputBox_mousePress(entity me, vector pos)
-{
-       if (me.enableClearButton)
-       if (over_ClearButton(me, pos))
+
+       float InputBox_mouseMove(entity me, vector pos)
        {
-               me.cb_pressed = 1;
+               if (me.enableClearButton)
+               {
+                       if (over_ClearButton(me, pos))
+                       {
+                               me.cb_focused = 1;
+                               return 1;
+                       }
+                       me.cb_focused = 0;
+               }
                return 1;
        }
-       me.dragScrollTimer = time;
-       me.pressed = 1;
-       return InputBox_mouseDrag(me, pos);
-}
-
-float InputBox_mouseRelease(entity me, vector pos)
-{
-       if(me.cb_pressed)
-       if (over_ClearButton(me, pos))
+
+       float InputBox_mouseDrag(entity me, vector pos)
        {
-               m_play_click_sound(MENU_SOUND_CLEAR);
-               me.setText(me, "");
+               float p;
+               if (me.pressed)
+               {
+                       me.dragScrollPos = pos;
+                       p = me.scrollPos + pos.x - me.keepspaceLeft;
+                       me.cursorPos = draw_TextLengthUpToWidth(me.text, p, 0, me.realFontSize);
+                       me.lastChangeTime = time;
+               }
+               else if (me.enableClearButton)
+               {
+                       if (over_ClearButton(me, pos))
+                       {
+                               me.cb_pressed = 1;
+                               return 1;
+                       }
+               }
                me.cb_pressed = 0;
                return 1;
        }
-       float r = InputBox_mouseDrag(me, pos);
-       //reset cb_pressed after mouseDrag, mouseDrag could set cb_pressed in this case:
-       //mouse press out of the clear button, drag and then mouse release over the clear button
-       me.cb_pressed = 0;
-       me.pressed = 0;
-       return r;
-}
-
-void InputBox_enterText(entity me, string ch)
-{
-       float i;
-       for(i = 0; i < strlen(ch); ++i)
-               if(strstrofs(me.forbiddenCharacters, substring(ch, i, 1), 0) > -1)
-                       return;
-       if(me.maxLength > 0)
+
+       float InputBox_mousePress(entity me, vector pos)
        {
-               if(strlen(ch) + strlen(me.text) > me.maxLength)
-                       return;
+               if (me.enableClearButton)
+                       if (over_ClearButton(me, pos))
+                       {
+                               me.cb_pressed = 1;
+                               return 1;
+                       }
+               me.dragScrollTimer = time;
+               me.pressed = 1;
+               return InputBox_mouseDrag(me, pos);
        }
-       else if(me.maxLength < 0)
+
+       float InputBox_mouseRelease(entity me, vector pos)
        {
-               if(u8_strsize(ch) + u8_strsize(me.text) > -me.maxLength)
-                       return;
+               if (me.cb_pressed)
+                       if (over_ClearButton(me, pos))
+                       {
+                               m_play_click_sound(MENU_SOUND_CLEAR);
+                               me.setText(me, "");
+                               me.cb_pressed = 0;
+                               return 1;
+                       }
+               float r = InputBox_mouseDrag(me, pos);
+               // reset cb_pressed after mouseDrag, mouseDrag could set cb_pressed in this case:
+               // mouse press out of the clear button, drag and then mouse release over the clear button
+               me.cb_pressed = 0;
+               me.pressed = 0;
+               return r;
        }
-       me.setText(me, strcat(substring(me.text, 0, me.cursorPos), ch, substring(me.text, me.cursorPos, strlen(me.text) - me.cursorPos)));
-       me.cursorPos += strlen(ch);
-}
-
-float InputBox_keyDown(entity me, float key, float ascii, float shift)
-{
-       me.lastChangeTime = time;
-       me.dragScrollTimer = time;
-       if(ascii >= 32 && ascii != 127)
+
+       void InputBox_enterText(entity me, string ch)
        {
-               me.enterText(me, chr(ascii));
-               return 1;
+               float i;
+               for (i = 0; i < strlen(ch); ++i)
+                       if (strstrofs(me.forbiddenCharacters, substring(ch, i, 1), 0) > -1) return;
+               if (me.maxLength > 0)
+               {
+                       if (strlen(ch) + strlen(me.text) > me.maxLength) return;
+               }
+               else if (me.maxLength < 0)
+               {
+                       if (u8_strsize(ch) + u8_strsize(me.text) > -me.maxLength) return;
+               }
+               me.setText(me, strcat(substring(me.text, 0, me.cursorPos), ch, substring(me.text, me.cursorPos, strlen(me.text) - me.cursorPos)));
+               me.cursorPos += strlen(ch);
        }
-       switch(key)
+
+       float InputBox_keyDown(entity me, float key, float ascii, float shift)
        {
-               case K_KP_LEFTARROW:
-               case K_LEFTARROW:
-                       me.cursorPos -= 1;
-                       return 1;
-               case K_KP_RIGHTARROW:
-               case K_RIGHTARROW:
-                       me.cursorPos += 1;
-                       return 1;
-               case K_KP_HOME:
-               case K_HOME:
-                       me.cursorPos = 0;
-                       return 1;
-               case K_KP_END:
-               case K_END:
-                       me.cursorPos = strlen(me.text);
+               me.lastChangeTime = time;
+               me.dragScrollTimer = time;
+               if (ascii >= 32 && ascii != 127)
+               {
+                       me.enterText(me, chr(ascii));
                        return 1;
-               case K_BACKSPACE:
-                       if(me.cursorPos > 0)
-                       {
+               }
+               switch (key)
+               {
+                       case K_KP_LEFTARROW:
+                       case K_LEFTARROW:
                                me.cursorPos -= 1;
-                               me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
-                       }
-                       return 1;
-               case K_KP_DEL:
-               case K_DEL:
-                       if(shift & S_CTRL)
-                       {
-                               m_play_click_sound(MENU_SOUND_CLEAR);
-                               me.setText(me, "");
-                       }
-                       else
-                               me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
-                       return 1;
+                               return 1;
+                       case K_KP_RIGHTARROW:
+                       case K_RIGHTARROW:
+                               me.cursorPos += 1;
+                               return 1;
+                       case K_KP_HOME:
+                       case K_HOME:
+                               me.cursorPos = 0;
+                               return 1;
+                       case K_KP_END:
+                       case K_END:
+                               me.cursorPos = strlen(me.text);
+                               return 1;
+                       case K_BACKSPACE:
+                               if (me.cursorPos > 0)
+                               {
+                                       me.cursorPos -= 1;
+                                       me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
+                               }
+                               return 1;
+                       case K_KP_DEL:
+                       case K_DEL:
+                               if (shift & S_CTRL)
+                               {
+                                       m_play_click_sound(MENU_SOUND_CLEAR);
+                                       me.setText(me, "");
+                               }
+                               else
+                               {
+                                       me.setText(me, strcat(substring(me.text, 0, me.cursorPos), substring(me.text, me.cursorPos + 1, strlen(me.text) - me.cursorPos - 1)));
+                               }
+                               return 1;
+               }
+               return 0;
        }
-       return 0;
-}
 
-void InputBox_draw(entity me)
-{
-       string CURSOR = "_";
-       float cursorPosInWidths, totalSizeInWidths;
+       void InputBox_draw(entity me)
+       {
+               string CURSOR = "_";
+               float cursorPosInWidths, totalSizeInWidths;
 
-       if(me.pressed)
-               me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
+               if (me.pressed) me.mouseDrag(me, me.dragScrollPos);  // simulate mouseDrag event
 
-       if(me.recalcPos)
-               me.recalcPositionWithText(me, me.text);
+               if (me.recalcPos) me.recalcPositionWithText(me, me.text);
 
-       me.focusable = !me.disabled;
-       if(me.disabled)
-               draw_alpha *= me.disabledAlpha;
+               me.focusable = !me.disabled;
+               if (me.disabled) draw_alpha *= me.disabledAlpha;
 
-       if(me.src)
-       {
-               if(me.focused && !me.disabled)
-                       draw_ButtonPicture('0 0 0', strcat(me.src, "_f"), '1 1 0', me.colorF, 1);
-               else
-                       draw_ButtonPicture('0 0 0', strcat(me.src, "_n"), '1 1 0', me.color, 1);
-       }
+               if (me.src)
+               {
+                       if (me.focused && !me.disabled) draw_ButtonPicture('0 0 0', strcat(me.src, "_f"), '1 1 0', me.colorF, 1);
+                       else draw_ButtonPicture('0 0 0', strcat(me.src, "_n"), '1 1 0', me.color, 1);
+               }
 
-       me.cursorPos = bound(0, me.cursorPos, strlen(me.text));
-       cursorPosInWidths = draw_TextWidth(substring(me.text, 0, me.cursorPos), 0, me.realFontSize);
-       totalSizeInWidths = draw_TextWidth(strcat(me.text, CURSOR), 0, me.realFontSize);
+               me.cursorPos = bound(0, me.cursorPos, strlen(me.text));
+               cursorPosInWidths = draw_TextWidth(substring(me.text, 0, me.cursorPos), 0, me.realFontSize);
+               totalSizeInWidths = draw_TextWidth(strcat(me.text, CURSOR), 0, me.realFontSize);
 
-       if(me.dragScrollTimer < time)
-       {
-               float save;
-               save = me.scrollPos;
-               me.scrollPos = bound(cursorPosInWidths - (0.875 - me.keepspaceLeft - me.keepspaceRight), me.scrollPos, cursorPosInWidths - 0.125);
-               if(me.scrollPos != save)
-                       me.dragScrollTimer = time + 0.2;
-       }
-       me.scrollPos = min(me.scrollPos, totalSizeInWidths - (1 - me.keepspaceRight - me.keepspaceLeft));
-       me.scrollPos = max(0, me.scrollPos);
+               if (me.dragScrollTimer < time)
+               {
+                       float save;
+                       save = me.scrollPos;
+                       me.scrollPos = bound(cursorPosInWidths - (0.875 - me.keepspaceLeft - me.keepspaceRight), me.scrollPos, cursorPosInWidths - 0.125);
+                       if (me.scrollPos != save) me.dragScrollTimer = time + 0.2;
+               }
+               me.scrollPos = min(me.scrollPos, totalSizeInWidths - (1 - me.keepspaceRight - me.keepspaceLeft));
+               me.scrollPos = max(0, me.scrollPos);
 
-       draw_SetClipRect(eX * me.keepspaceLeft, eX * (1 - me.keepspaceLeft - me.keepspaceRight) + eY);
-       if(me.editColorCodes)
-       {
-               string ch, ch2;
-               float i, n;
-               vector theColor;
-               float theAlpha;    //float theVariableAlpha;
-               vector p;
-               vector theTempColor;
-               float component;
-
-               p = me.realOrigin - eX * me.scrollPos;
-               theColor = '1 1 1';
-               theAlpha = 1;    //theVariableAlpha = 1; // changes when ^ax found
-
-               n = strlen(me.text);
-               for(i = 0; i < n; ++i)
+               draw_SetClipRect(eX * me.keepspaceLeft, eX * (1 - me.keepspaceLeft - me.keepspaceRight) + eY);
+               if (me.editColorCodes)
                {
-                       ch = substring(me.text, i, 1);
-                       if(ch == "^")
+                       string ch, ch2;
+                       float i, n;
+                       vector theColor;
+                       float theAlpha;  // float theVariableAlpha;
+                       vector p;
+                       vector theTempColor;
+                       float component;
+
+                       p = me.realOrigin - eX * me.scrollPos;
+                       theColor = '1 1 1';
+                       theAlpha = 1;  // theVariableAlpha = 1; // changes when ^ax found
+
+                       n = strlen(me.text);
+                       for (i = 0; i < n; ++i)
                        {
-                               float w;
-                               ch2 = substring(me.text, i+1, 1);
-                               w = draw_TextWidth(strcat(ch, ch2), 0, me.realFontSize);
-                               if(ch2 == "^")
-                               {
-                                       draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
-                                       draw_Text(p + eX * 0.25 * w, "^", me.realFontSize, theColor, theAlpha, 0);
-                               }
-                               else if(ch2 == "0" || stof(ch2)) // digit?
+                               ch = substring(me.text, i, 1);
+                               if (ch == "^")
                                {
-                                       switch(stof(ch2))
+                                       float w;
+                                       ch2 = substring(me.text, i + 1, 1);
+                                       w = draw_TextWidth(strcat(ch, ch2), 0, me.realFontSize);
+                                       if (ch2 == "^")
                                        {
-                                               case 0: theColor = '0 0 0'; theAlpha = 1; break;
-                                               case 1: theColor = '1 0 0'; theAlpha = 1; break;
-                                               case 2: theColor = '0 1 0'; theAlpha = 1; break;
-                                               case 3: theColor = '1 1 0'; theAlpha = 1; break;
-                                               case 4: theColor = '0 0 1'; theAlpha = 1; break;
-                                               case 5: theColor = '0 1 1'; theAlpha = 1; break;
-                                               case 6: theColor = '1 0 1'; theAlpha = 1; break;
-                                               case 7: theColor = '1 1 1'; theAlpha = 1; break;
-                                               case 8: theColor = '1 1 1'; theAlpha = 0.5; break;
-                                               case 9: theColor = '0.5 0.5 0.5'; theAlpha = 1; break;
+                                               draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
+                                               draw_Text(p + eX * 0.25 * w, "^", me.realFontSize, theColor, theAlpha, 0);
                                        }
-                                       draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
-                                       draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
-                               }
-                               else if(ch2 == "x") // ^x found
-                               {
-                                       theColor = '1 1 1';
-
-                                       component = HEXDIGIT_TO_DEC(substring(me.text, i+2, 1));
-                                       if (component >= 0) // ^xr found
+                                       else if (ch2 == "0" || stof(ch2))  // digit?
+                                       {
+                                               switch (stof(ch2))
+                                               {
+                                                       case 0: theColor = '0 0 0';
+                                                               theAlpha = 1;
+                                                               break;
+                                                       case 1: theColor = '1 0 0';
+                                                               theAlpha = 1;
+                                                               break;
+                                                       case 2: theColor = '0 1 0';
+                                                               theAlpha = 1;
+                                                               break;
+                                                       case 3: theColor = '1 1 0';
+                                                               theAlpha = 1;
+                                                               break;
+                                                       case 4: theColor = '0 0 1';
+                                                               theAlpha = 1;
+                                                               break;
+                                                       case 5: theColor = '0 1 1';
+                                                               theAlpha = 1;
+                                                               break;
+                                                       case 6: theColor = '1 0 1';
+                                                               theAlpha = 1;
+                                                               break;
+                                                       case 7: theColor = '1 1 1';
+                                                               theAlpha = 1;
+                                                               break;
+                                                       case 8: theColor = '1 1 1';
+                                                               theAlpha = 0.5;
+                                                               break;
+                                                       case 9: theColor = '0.5 0.5 0.5';
+                                                               theAlpha = 1;
+                                                               break;
+                                               }
+                                               draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
+                                               draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
+                                       }
+                                       else if (ch2 == "x")  // ^x found
                                        {
-                                               theTempColor.x = component/15;
+                                               theColor = '1 1 1';
 
-                                               component = HEXDIGIT_TO_DEC(substring(me.text, i+3, 1));
-                                               if (component >= 0) // ^xrg found
+                                               component = HEXDIGIT_TO_DEC(substring(me.text, i + 2, 1));
+                                               if (component >= 0)  // ^xr found
                                                {
-                                                       theTempColor.y = component/15;
+                                                       theTempColor.x = component / 15;
 
-                                                       component = HEXDIGIT_TO_DEC(substring(me.text, i+4, 1));
-                                                       if (component >= 0) // ^xrgb found
+                                                       component = HEXDIGIT_TO_DEC(substring(me.text, i + 3, 1));
+                                                       if (component >= 0)  // ^xrg found
                                                        {
-                                                               theTempColor.z = component/15;
-                                                               theColor = theTempColor;
-                                                               w = draw_TextWidth(substring(me.text, i, 5), 0, me.realFontSize);
-
-                                                               draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
-                                                               draw_Text(p, substring(me.text, i, 5), me.realFontSize, theColor, 1, 0);    // theVariableAlpha instead of 1 using alpha tags ^ax
-                                                               i += 3;
+                                                               theTempColor.y = component / 15;
+
+                                                               component = HEXDIGIT_TO_DEC(substring(me.text, i + 4, 1));
+                                                               if (component >= 0)  // ^xrgb found
+                                                               {
+                                                                       theTempColor.z = component / 15;
+                                                                       theColor = theTempColor;
+                                                                       w = draw_TextWidth(substring(me.text, i, 5), 0, me.realFontSize);
+
+                                                                       draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
+                                                                       draw_Text(p, substring(me.text, i, 5), me.realFontSize, theColor, 1, 0);  // theVariableAlpha instead of 1 using alpha tags ^ax
+                                                                       i += 3;
+                                                               }
+                                                               else
+                                                               {
+                                                                       // blue missing
+                                                                       w = draw_TextWidth(substring(me.text, i, 4), 0, me.realFontSize);
+                                                                       draw_Fill(p, eX * w + eY * me.realFontSize.y, eZ, 0.5);
+                                                                       draw_Text(p, substring(me.text, i, 4), me.realFontSize, '1 1 1', theAlpha, 0);
+                                                                       i += 2;
+                                                               }
                                                        }
                                                        else
                                                        {
-                                                               // blue missing
-                                                               w = draw_TextWidth(substring(me.text, i, 4), 0, me.realFontSize);
-                                                               draw_Fill(p, eX * w + eY * me.realFontSize.y, eZ, 0.5);
-                                                               draw_Text(p, substring(me.text, i, 4), me.realFontSize, '1 1 1', theAlpha, 0);
-                                                               i += 2;
+                                                               // green missing
+                                                               w = draw_TextWidth(substring(me.text, i, 3), 0, me.realFontSize);
+                                                               draw_Fill(p, eX * w + eY * me.realFontSize.y, eY, 0.5);
+                                                               draw_Text(p, substring(me.text, i, 3), me.realFontSize, '1 1 1', theAlpha, 0);
+                                                               i += 1;
                                                        }
                                                }
                                                else
                                                {
-                                                       // green missing
-                                                       w = draw_TextWidth(substring(me.text, i, 3), 0, me.realFontSize);
-                                                       draw_Fill(p, eX * w + eY * me.realFontSize.y, eY, 0.5);
-                                                       draw_Text(p, substring(me.text, i, 3), me.realFontSize, '1 1 1', theAlpha, 0);
-                                                       i += 1;
+                                                       // red missing
+                                                       // w = draw_TextWidth(substring(me.text, i, 2), 0) * me.realFontSize_x;
+                                                       draw_Fill(p, eX * w + eY * me.realFontSize.y, eX, 0.5);
+                                                       draw_Text(p, substring(me.text, i, 2), me.realFontSize, '1 1 1', theAlpha, 0);
                                                }
                                        }
                                        else
                                        {
-                                               // red missing
-                                               //w = draw_TextWidth(substring(me.text, i, 2), 0) * me.realFontSize_x;
-                                               draw_Fill(p, eX * w + eY * me.realFontSize.y, eX, 0.5);
-                                               draw_Text(p, substring(me.text, i, 2), me.realFontSize, '1 1 1', theAlpha, 0);
+                                               draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
+                                               draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
                                        }
+                                       p += w * eX;
+                                       ++i;
+                                       continue;
                                }
-                               else
-                               {
-                                       draw_Fill(p, eX * w + eY * me.realFontSize.y, '1 1 1', 0.5);
-                                       draw_Text(p, strcat(ch, ch2), me.realFontSize, theColor, theAlpha, 0);
-                               }
-                               p += w * eX;
-                               ++i;
-                               continue;
+                               draw_Text(p, ch, me.realFontSize, theColor, theAlpha, 0);  // TODO theVariableAlpha
+                               p += eX * draw_TextWidth(ch, 0, me.realFontSize);
                        }
-                       draw_Text(p, ch, me.realFontSize, theColor, theAlpha, 0); // TODO theVariableAlpha
-                       p += eX * draw_TextWidth(ch, 0, me.realFontSize);
                }
-       }
-       else
-               draw_Text(me.realOrigin - eX * me.scrollPos, me.text, me.realFontSize, '1 1 1', 1, 0);
+               else
+               {
+                       draw_Text(me.realOrigin - eX * me.scrollPos, me.text, me.realFontSize, '1 1 1', 1, 0);
+               }
 
-       if(!me.focused || (time - me.lastChangeTime) < floor(time - me.lastChangeTime) + 0.5)
-               draw_Text(me.realOrigin + eX * (cursorPosInWidths - me.scrollPos), CURSOR, me.realFontSize, '1 1 1', 1, 0);
+               if (!me.focused || (time - me.lastChangeTime) < floor(time - me.lastChangeTime) + 0.5) draw_Text(me.realOrigin + eX * (cursorPosInWidths - me.scrollPos), CURSOR, me.realFontSize, '1 1 1', 1, 0);
 
-       draw_ClearClip();
+               draw_ClearClip();
 
-       if (me.enableClearButton)
-       if (me.text != "")
-       {
-               if(me.focused && me.cb_pressed)
-                       draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_c"), eX * me.cb_width + eY, me.cb_colorC, 1);
-               else if(me.focused && me.cb_focused)
-                       draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_f"), eX * me.cb_width + eY, me.cb_colorF, 1);
-               else
-                       draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_n"), eX * me.cb_width + eY, me.cb_color, 1);
-       }
+               if (me.enableClearButton)
+                       if (me.text != "")
+                       {
+                               if (me.focused && me.cb_pressed) draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_c"), eX * me.cb_width + eY, me.cb_colorC, 1);
+                               else if (me.focused && me.cb_focused) draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_f"), eX * me.cb_width + eY, me.cb_colorF, 1);
+                               else draw_Picture(eX * (1 + me.cb_offset - me.cb_width), strcat(me.cb_src, "_n"), eX * me.cb_width + eY, me.cb_color, 1);
+                       }
 
-       // skipping SUPER(InputBox).draw(me);
-       Item_draw(me);
-}
+               // skipping SUPER(InputBox).draw(me);
+               Item_draw(me);
+       }
 
-void InputBox_showNotify(entity me)
-{
-       me.focusable = !me.disabled;
-}
+       void InputBox_showNotify(entity me)
+       {
+               me.focusable = !me.disabled;
+       }
 #endif
index 8e7f24f73d55dc128a109bbecc959113e5dad464..45f60854f9499308bb9dc8af1694fedc1a794195 100644 (file)
 #ifndef ITEM_INPUTCONTAINER_H
-#define ITEM_INPUTCONTAINER_H
-#include "container.qc"
-CLASS(InputContainer, Container)
-       METHOD(InputContainer, keyDown, float(entity, float, float, float));
-       METHOD(InputContainer, mouseMove, float(entity, vector));
-       METHOD(InputContainer, mousePress, float(entity, vector));
-       METHOD(InputContainer, mouseRelease, float(entity, vector));
-       METHOD(InputContainer, mouseDrag, float(entity, vector));
-       METHOD(InputContainer, focusLeave, void(entity));
-       METHOD(InputContainer, resizeNotify, void(entity, vector, vector, vector, vector));
+       #define ITEM_INPUTCONTAINER_H
+       #include "container.qc"
+       CLASS(InputContainer, Container)
+               METHOD(InputContainer, keyDown, float(entity, float, float, float));
+               METHOD(InputContainer, mouseMove, float(entity, vector));
+               METHOD(InputContainer, mousePress, float(entity, vector));
+               METHOD(InputContainer, mouseRelease, float(entity, vector));
+               METHOD(InputContainer, mouseDrag, float(entity, vector));
+               METHOD(InputContainer, focusLeave, void(entity));
+               METHOD(InputContainer, resizeNotify, void(entity, vector, vector, vector, vector));
 
-       METHOD(InputContainer, _changeFocusXY, bool(entity this, vector pos));
-       ATTRIB(InputContainer, mouseFocusedChild, entity, NULL)
-       ATTRIB(InputContainer, isTabRoot, float, 0)
-ENDCLASS(InputContainer)
+               METHOD(InputContainer, _changeFocusXY, bool(entity this, vector pos));
+               ATTRIB(InputContainer, mouseFocusedChild, entity, NULL)
+               ATTRIB(InputContainer, isTabRoot, float, 0)
+       ENDCLASS(InputContainer)
 #endif
 
 #ifdef IMPLEMENTATION
-void InputContainer_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(InputContainer).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       /*
-       if(me.parent.instanceOfInputContainer)
-               me.isTabRoot = 0;
-       else
-               me.isTabRoot = 1;
-       */
-}
+       void InputContainer_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+       {
+               SUPER(InputContainer).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+               /*
+               if(me.parent.instanceOfInputContainer)
+                   me.isTabRoot = 0;
+               else
+                   me.isTabRoot = 1;
+               */
+       }
 
-void InputContainer_focusLeave(entity me)
-{
-       SUPER(InputContainer).focusLeave(me);
-       me.mouseFocusedChild = NULL;
-}
+       void InputContainer_focusLeave(entity me)
+       {
+               SUPER(InputContainer).focusLeave(me);
+               me.mouseFocusedChild = NULL;
+       }
 
-float InputContainer_keyDown(entity me, float scan, float ascii, float shift)
-{
-       entity f, ff;
-       if(SUPER(InputContainer).keyDown(me, scan, ascii, shift))
-               return 1;
-       if(scan == K_ESCAPE)
+       float InputContainer_keyDown(entity me, float scan, float ascii, float shift)
        {
-               f = me.focusedChild;
-               if(f)
+               entity f, ff;
+               if (SUPER(InputContainer).keyDown(me, scan, ascii, shift)) return 1;
+               if (scan == K_ESCAPE)
                {
-                       me.setFocus(me, NULL);
-                       return 1;
+                       f = me.focusedChild;
+                       if (f)
+                       {
+                               me.setFocus(me, NULL);
+                               return 1;
+                       }
+                       return 0;
                }
-               return 0;
-       }
-       if(scan == K_TAB)
-       {
-               f = me.focusedChild;
-               if(shift & S_SHIFT)
+               if (scan == K_TAB)
                {
-                       if(f)
+                       f = me.focusedChild;
+                       if (shift & S_SHIFT)
                        {
-                               for(ff = f.prevSibling; ff; ff = ff.prevSibling)
+                               if (f)
                                {
-                                       if (!ff.focusable)
-                                               continue;
-                                       me.setFocus(me, ff);
-                                       return 1;
+                                       for (ff = f.prevSibling; ff; ff = ff.prevSibling)
+                                       {
+                                               if (!ff.focusable) continue;
+                                               me.setFocus(me, ff);
+                                               return 1;
+                                       }
                                }
-                       }
-                       if(!f || me.isTabRoot)
-                       {
-                               for(ff = me.lastChild; ff; ff = ff.prevSibling)
+                               if (!f || me.isTabRoot)
                                {
-                                       if (!ff.focusable)
-                                               continue;
-                                       me.setFocus(me, ff);
-                                       return 1;
+                                       for (ff = me.lastChild; ff; ff = ff.prevSibling)
+                                       {
+                                               if (!ff.focusable) continue;
+                                               me.setFocus(me, ff);
+                                               return 1;
+                                       }
+                                       return 0;  // AIIIIEEEEE!
                                }
-                               return 0; // AIIIIEEEEE!
                        }
-               }
-               else
-               {
-                       if(f)
+                       else
                        {
-                               for(ff = f.nextSibling; ff; ff = ff.nextSibling)
+                               if (f)
                                {
-                                       if (!ff.focusable)
-                                               continue;
-                                       me.setFocus(me, ff);
-                                       return 1;
+                                       for (ff = f.nextSibling; ff; ff = ff.nextSibling)
+                                       {
+                                               if (!ff.focusable) continue;
+                                               me.setFocus(me, ff);
+                                               return 1;
+                                       }
                                }
-                       }
-                       if(!f || me.isTabRoot)
-                       {
-                               for(ff = me.firstChild; ff; ff = ff.nextSibling)
+                               if (!f || me.isTabRoot)
                                {
-                                       if (!ff.focusable)
-                                               continue;
-                                       me.setFocus(me, ff);
-                                       return 1;
+                                       for (ff = me.firstChild; ff; ff = ff.nextSibling)
+                                       {
+                                               if (!ff.focusable) continue;
+                                               me.setFocus(me, ff);
+                                               return 1;
+                                       }
+                                       return 0;  // AIIIIEEEEE!
                                }
-                               return 0; // AIIIIEEEEE!
                        }
                }
+               return 0;
        }
-       return 0;
-}
 
-bool InputContainer__changeFocusXY(entity this, vector pos)
-{
-       entity e = this.itemFromPoint(this, pos);
-       if (e && !e.focusable) e = NULL;
-       entity prev = this.mouseFocusedChild;
-       this.mouseFocusedChild = e;
-       if (!e) return false; // keep focus when hovering over non-focusable elements
-       if (e != prev) {
-               this.setFocus(this, e);
-               if (e.instanceOfInputContainer) {
-                       e.focusedChild = NULL;
-                       e._changeFocusXY(e, globalToBox(pos, e.Container_origin, e.Container_size));
+       bool InputContainer__changeFocusXY(entity this, vector pos)
+       {
+               entity e = this.itemFromPoint(this, pos);
+               if (e && !e.focusable) e = NULL;
+               entity prev = this.mouseFocusedChild;
+               this.mouseFocusedChild = e;
+               if (!e) return false;  // keep focus when hovering over non-focusable elements
+               if (e != prev)
+               {
+                       this.setFocus(this, e);
+                       if (e.instanceOfInputContainer)
+                       {
+                               e.focusedChild = NULL;
+                               e._changeFocusXY(e, globalToBox(pos, e.Container_origin, e.Container_size));
+                       }
                }
+               return true;  // have focus
        }
-       return true; // have focus
-}
 
-float InputContainer_mouseDrag(entity me, vector pos)
-{
-       if(SUPER(InputContainer).mouseDrag(me, pos))
-               return 1;
-       if(pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1)
-               return 1;
-       return 0;
-}
-float InputContainer_mouseMove(entity me, vector pos)
-{
-       if(me.mouseFocusedChild != me.focusedChild) // if the keyboard moved the focus away
-               me.mouseFocusedChild = NULL; // force focusing
-       if(me._changeFocusXY(me, pos))
-               if(SUPER(InputContainer).mouseMove(me, pos))
-                       return 1;
-       if(pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1)
-               return 1;
-       return 0;
-}
-float InputContainer_mousePress(entity me, vector pos)
-{
-       me.mouseFocusedChild = NULL; // force focusing
-       if(me._changeFocusXY(me, pos))
-               if(SUPER(InputContainer).mousePress(me, pos))
-                       return 1;
-       if(pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1)
-               return 1;
-       return 0;
-}
-float InputContainer_mouseRelease(entity me, vector pos)
-{
-       SUPER(InputContainer).mouseRelease(me, pos); // return value?
-       if(me.focused) // am I still eligible for this? (UGLY HACK, but a mouse event could have changed focus away)
-               if(me._changeFocusXY(me, pos))
-                       return 1;
-       if(pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1)
-               return 1;
-       return 0;
-}
+       float InputContainer_mouseDrag(entity me, vector pos)
+       {
+               if (SUPER(InputContainer).mouseDrag(me, pos)) return 1;
+               if (pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1) return 1;
+               return 0;
+       }
+       float InputContainer_mouseMove(entity me, vector pos)
+       {
+               if (me.mouseFocusedChild != me.focusedChild) // if the keyboard moved the focus away
+                       me.mouseFocusedChild = NULL;             // force focusing
+               if (me._changeFocusXY(me, pos))
+                       if (SUPER(InputContainer).mouseMove(me, pos)) return 1;
+               if (pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1) return 1;
+               return 0;
+       }
+       float InputContainer_mousePress(entity me, vector pos)
+       {
+               me.mouseFocusedChild = NULL;  // force focusing
+               if (me._changeFocusXY(me, pos))
+                       if (SUPER(InputContainer).mousePress(me, pos)) return 1;
+               if (pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1) return 1;
+               return 0;
+       }
+       float InputContainer_mouseRelease(entity me, vector pos)
+       {
+               SUPER(InputContainer).mouseRelease(me, pos); // return value?
+               if (me.focused)                              // am I still eligible for this? (UGLY HACK, but a mouse event could have changed focus away)
+                       if (me._changeFocusXY(me, pos)) return 1;
+               if (pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1) return 1;
+               return 0;
+       }
 #endif
index ea170777eaf7245c26645fcd6c2a3dc8f5ed138e..6d9b9cda1f4953bd7bebf68d44a8f22286a25923 100644 (file)
 #ifndef ITEM_LABEL_H
-#define ITEM_LABEL_H
-#include "../item.qc"
-CLASS(Label, Item)
-       METHOD(Label, configureLabel, void(entity, string, float, float));
-       METHOD(Label, draw, void(entity));
-       METHOD(Label, resizeNotify, void(entity, vector, vector, vector, vector));
-       METHOD(Label, setText, void(entity, string));
-       METHOD(Label, toString, string(entity));
-       METHOD(Label, recalcPositionWithText, void(entity, string));
-       ATTRIB(Label, isBold, float, 0)
-       ATTRIB(Label, text, string, string_null)
-       ATTRIB(Label, currentText, string, string_null)
-       ATTRIB(Label, fontSize, float, 8)
-       ATTRIB(Label, align, float, 0.5)
-       ATTRIB(Label, allowCut, float, 0)
-       ATTRIB(Label, allowColors, float, 0)
-       ATTRIB(Label, keepspaceLeft, float, 0) // for use by subclasses (radiobuttons for example)
-       ATTRIB(Label, keepspaceRight, float, 0)
-       ATTRIB(Label, marginLeft, float, 0) // alternate way to specify keepspace* (in characters from the font)
-       ATTRIB(Label, marginRight, float, 0)
-       ATTRIB(Label, realFontSize, vector, '0 0 0')
-       ATTRIB(Label, realOrigin, vector, '0 0 0')
-       ATTRIB(Label, alpha, float, 0.7)
-       ATTRIB(Label, colorL, vector, SKINCOLOR_TEXT)
-       ATTRIB(Label, disabled, float, 0)
-       ATTRIB(Label, disabledAlpha, float, 0.3)
-       ATTRIB(Label, textEntity, entity, NULL)
-       ATTRIB(Label, allowWrap, float, 0)
-       ATTRIB(Label, recalcPos, float, 0)
-       ATTRIB(Label, condenseFactor, float, 1)
-       ATTRIB(Label, overrideRealOrigin, vector, '0 0 0')
-       ATTRIB(Label, overrideCondenseFactor, float, 0)
-ENDCLASS(Label)
+       #define ITEM_LABEL_H
+       #include "../item.qc"
+       CLASS(Label, Item)
+               METHOD(Label, configureLabel, void(entity, string, float, float));
+               METHOD(Label, draw, void(entity));
+               METHOD(Label, resizeNotify, void(entity, vector, vector, vector, vector));
+               METHOD(Label, setText, void(entity, string));
+               METHOD(Label, toString, string(entity));
+               METHOD(Label, recalcPositionWithText, void(entity, string));
+               ATTRIB(Label, isBold, float, 0)
+               ATTRIB(Label, text, string, string_null)
+               ATTRIB(Label, currentText, string, string_null)
+               ATTRIB(Label, fontSize, float, 8)
+               ATTRIB(Label, align, float, 0.5)
+               ATTRIB(Label, allowCut, float, 0)
+               ATTRIB(Label, allowColors, float, 0)
+               ATTRIB(Label, keepspaceLeft, float, 0) // for use by subclasses (radiobuttons for example)
+               ATTRIB(Label, keepspaceRight, float, 0)
+               ATTRIB(Label, marginLeft, float, 0)    // alternate way to specify keepspace* (in characters from the font)
+               ATTRIB(Label, marginRight, float, 0)
+               ATTRIB(Label, realFontSize, vector, '0 0 0')
+               ATTRIB(Label, realOrigin, vector, '0 0 0')
+               ATTRIB(Label, alpha, float, 0.7)
+               ATTRIB(Label, colorL, vector, SKINCOLOR_TEXT)
+               ATTRIB(Label, disabled, float, 0)
+               ATTRIB(Label, disabledAlpha, float, 0.3)
+               ATTRIB(Label, textEntity, entity, NULL)
+               ATTRIB(Label, allowWrap, float, 0)
+               ATTRIB(Label, recalcPos, float, 0)
+               ATTRIB(Label, condenseFactor, float, 1)
+               ATTRIB(Label, overrideRealOrigin, vector, '0 0 0')
+               ATTRIB(Label, overrideCondenseFactor, float, 0)
+       ENDCLASS(Label)
 #endif
 
 #ifdef IMPLEMENTATION
-string Label_toString(entity me)
-{
-       return me.text;
-}
-void Label_setText(entity me, string txt)
-{
-       me.text = txt;
-       if(txt != me.currentText)
+       string Label_toString(entity me)
        {
-               if(me.currentText)
-                       strunzone(me.currentText);
-               me.currentText = strzone(txt);
-               me.recalcPos = 1;
+               return me.text;
        }
-}
-void Label_recalcPositionWithText(entity me, string t)
-{
-       float spaceAvail;
-       spaceAvail = 1 - me.keepspaceLeft - me.keepspaceRight;
-
-       if(me.isBold)
-               draw_beginBoldFont();
-
-       float spaceUsed;
-       spaceUsed = draw_TextWidth(t, me.allowColors, me.realFontSize);
-
-       if(spaceUsed <= spaceAvail)
+       void Label_setText(entity me, string txt)
        {
-               if(!me.overrideRealOrigin_x)
-                       me.realOrigin_x = me.align * (spaceAvail - spaceUsed) + me.keepspaceLeft;
-               if(!me.overrideCondenseFactor)
-                       me.condenseFactor = 1;
-       }
-       else if(me.allowCut || me.allowWrap)
-       {
-               if(!me.overrideRealOrigin_x)
-                       me.realOrigin_x = me.keepspaceLeft;
-               if(!me.overrideCondenseFactor)
-                       me.condenseFactor = 1;
-       }
-       else
-       {
-               if(!me.overrideRealOrigin_x)
-                       me.realOrigin_x = me.keepspaceLeft;
-               if(!me.overrideCondenseFactor)
-                       me.condenseFactor = spaceAvail / spaceUsed;
-               LOG_TRACEF("NOTE: label text %s too wide for label, condensed by factor %f\n", t, me.condenseFactor);
+               me.text = txt;
+               if (txt != me.currentText)
+               {
+                       if (me.currentText) strunzone(me.currentText);
+                       me.currentText = strzone(txt);
+                       me.recalcPos = 1;
+               }
        }
-
-       if(!me.overrideRealOrigin_y)
+       void Label_recalcPositionWithText(entity me, string t)
        {
-               float lines;
-               vector dfs;
-               vector fs;
+               float spaceAvail;
+               spaceAvail = 1 - me.keepspaceLeft - me.keepspaceRight;
 
-               // set up variables to draw in condensed size, but use hinting for original size
-               fs = me.realFontSize;
-               fs.x *= me.condenseFactor;
+               if (me.isBold) draw_beginBoldFont();
 
-               dfs = draw_fontscale;
-               draw_fontscale.x *= me.condenseFactor;
+               float spaceUsed;
+               spaceUsed = draw_TextWidth(t, me.allowColors, me.realFontSize);
 
-               if(me.allowCut) // FIXME allowCut incompatible with align != 0
-                       lines = 1;
-               else if(me.allowWrap) // FIXME allowWrap incompatible with align != 0
+               if (spaceUsed <= spaceAvail)
                {
-                       getWrappedLine_remaining = me.text;
-                       lines = 0;
-                       while(getWrappedLine_remaining)
-                       {
-                               if (me.allowColors)
-                                       getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
-                               else
-                                       getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
-                               ++lines;
-                       }
+                       if (!me.overrideRealOrigin_x) me.realOrigin_x = me.align * (spaceAvail - spaceUsed) + me.keepspaceLeft;
+                       if (!me.overrideCondenseFactor) me.condenseFactor = 1;
+               }
+               else if (me.allowCut || me.allowWrap)
+               {
+                       if (!me.overrideRealOrigin_x) me.realOrigin_x = me.keepspaceLeft;
+                       if (!me.overrideCondenseFactor) me.condenseFactor = 1;
                }
                else
-                       lines = 1;
-
-               draw_fontscale = dfs;
-
-               me.realOrigin_y = 0.5 * (1 - lines * me.realFontSize.y);
-       }
-
-       if(me.isBold)
-               draw_endBoldFont();
-
-       me.recalcPos = 0;
-}
-void Label_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(Label).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-
-       // absSize_y is height of label
-       me.realFontSize_y = absSize.y == 0 ? 0 : (me.fontSize / absSize.y);
-       me.realFontSize_x = absSize.x == 0 ? 0 : (me.fontSize / absSize.x);
-       if(me.marginLeft)
-               me.keepspaceLeft = me.marginLeft * me.realFontSize.x;
-       if(me.marginRight)
-               me.keepspaceRight = me.marginRight * me.realFontSize.x;
-
-       me.recalcPos = 1;
-}
-void Label_configureLabel(entity me, string txt, float sz, float algn)
-{
-       me.fontSize = sz;
-       me.align = algn;
-       me.setText(me, txt);
-}
-void Label_draw(entity me)
-{
-       string t;
-       vector o;
-       if(me.disabled)
-               draw_alpha *= me.disabledAlpha;
-
-       if(me.textEntity)
-       {
-               t = me.textEntity.toString(me.textEntity);
-               if(t != me.currentText)
                {
-                       if(me.currentText)
-                               strunzone(me.currentText);
-                       me.currentText = strzone(t);
-                       me.recalcPos = 1;
+                       if (!me.overrideRealOrigin_x) me.realOrigin_x = me.keepspaceLeft;
+                       if (!me.overrideCondenseFactor) me.condenseFactor = spaceAvail / spaceUsed;
+                       LOG_TRACEF("NOTE: label text %s too wide for label, condensed by factor %f\n", t, me.condenseFactor);
                }
-       }
-       else
-               t = me.text;
 
-       if(me.recalcPos)
-               me.recalcPositionWithText(me, t);
-
-       if(me.fontSize)
-               if(t)
+               if (!me.overrideRealOrigin_y)
                {
+                       float lines;
                        vector dfs;
                        vector fs;
 
-                       if(me.isBold)
-                               draw_beginBoldFont();
-
                        // set up variables to draw in condensed size, but use hinting for original size
                        fs = me.realFontSize;
                        fs.x *= me.condenseFactor;
@@ -185,31 +89,117 @@ void Label_draw(entity me)
                        dfs = draw_fontscale;
                        draw_fontscale.x *= me.condenseFactor;
 
-                       if(me.allowCut) // FIXME allowCut incompatible with align != 0
-                               draw_Text(me.realOrigin, draw_TextShortenToWidth(t, (1 - me.keepspaceLeft - me.keepspaceRight), me.allowColors, fs), fs, me.colorL, me.alpha, me.allowColors);
-                       else if(me.allowWrap) // FIXME allowWrap incompatible with align != 0
+                       if (me.allowCut)  // FIXME allowCut incompatible with align != 0
                        {
-                               getWrappedLine_remaining = t;
-                               o = me.realOrigin;
-                               while(getWrappedLine_remaining)
+                               lines = 1;
+                       }
+                       else if (me.allowWrap)  // FIXME allowWrap incompatible with align != 0
+                       {
+                               getWrappedLine_remaining = me.text;
+                               lines = 0;
+                               while (getWrappedLine_remaining)
                                {
-                                       if (me.allowColors)
-                                               t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
-                                       else
-                                               t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
-                                       draw_Text(o, t, fs, me.colorL, me.alpha, me.allowColors);
-                                       o.y += me.realFontSize.y;
+                                       if (me.allowColors) getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
+                                       else getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
+                                       ++lines;
                                }
                        }
                        else
-                               draw_Text(me.realOrigin, t, fs, me.colorL, me.alpha, me.allowColors);
+                       {
+                               lines = 1;
+                       }
 
                        draw_fontscale = dfs;
 
-                       if(me.isBold)
-                               draw_endBoldFont();
+                       me.realOrigin_y = 0.5 * (1 - lines * me.realFontSize.y);
                }
 
-       SUPER(Label).draw(me);
-}
+               if (me.isBold) draw_endBoldFont();
+
+               me.recalcPos = 0;
+       }
+       void Label_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+       {
+               SUPER(Label).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+
+               // absSize_y is height of label
+               me.realFontSize_y = absSize.y == 0 ? 0 : (me.fontSize / absSize.y);
+               me.realFontSize_x = absSize.x == 0 ? 0 : (me.fontSize / absSize.x);
+               if (me.marginLeft) me.keepspaceLeft = me.marginLeft * me.realFontSize.x;
+               if (me.marginRight) me.keepspaceRight = me.marginRight * me.realFontSize.x;
+
+               me.recalcPos = 1;
+       }
+       void Label_configureLabel(entity me, string txt, float sz, float algn)
+       {
+               me.fontSize = sz;
+               me.align = algn;
+               me.setText(me, txt);
+       }
+       void Label_draw(entity me)
+       {
+               string t;
+               vector o;
+               if (me.disabled) draw_alpha *= me.disabledAlpha;
+
+               if (me.textEntity)
+               {
+                       t = me.textEntity.toString(me.textEntity);
+                       if (t != me.currentText)
+                       {
+                               if (me.currentText) strunzone(me.currentText);
+                               me.currentText = strzone(t);
+                               me.recalcPos = 1;
+                       }
+               }
+               else
+               {
+                       t = me.text;
+               }
+
+               if (me.recalcPos) me.recalcPositionWithText(me, t);
+
+               if (me.fontSize)
+                       if (t)
+                       {
+                               vector dfs;
+                               vector fs;
+
+                               if (me.isBold) draw_beginBoldFont();
+
+                               // set up variables to draw in condensed size, but use hinting for original size
+                               fs = me.realFontSize;
+                               fs.x *= me.condenseFactor;
+
+                               dfs = draw_fontscale;
+                               draw_fontscale.x *= me.condenseFactor;
+
+                               if (me.allowCut)  // FIXME allowCut incompatible with align != 0
+                               {
+                                       draw_Text(me.realOrigin, draw_TextShortenToWidth(t, (1 - me.keepspaceLeft - me.keepspaceRight), me.allowColors, fs), fs, me.colorL, me.alpha, me.allowColors);
+                               }
+                               else if (me.allowWrap)  // FIXME allowWrap incompatible with align != 0
+                               {
+                                       getWrappedLine_remaining = t;
+                                       o = me.realOrigin;
+                                       while (getWrappedLine_remaining)
+                                       {
+                                               if (me.allowColors) t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithColors);
+                                               else t = getWrappedLine((1 - me.keepspaceLeft - me.keepspaceRight), fs, draw_TextWidth_WithoutColors);
+                                               draw_Text(o, t, fs, me.colorL, me.alpha, me.allowColors);
+                                               o.y += me.realFontSize.y;
+                                       }
+                               }
+                               else
+                               {
+                                       draw_Text(me.realOrigin, t, fs, me.colorL, me.alpha, me.allowColors);
+                               }
+
+                               draw_fontscale = dfs;
+
+                               if (me.isBold) draw_endBoldFont();
+                       }
+
+               SUPER(Label).draw(me);
+       }
 #endif
index 9210e14b384c90e262ece0be368b87e397cd1178..7f303fda7a17b2b891776d008ab8fe9ab56b574a 100644 (file)
 #ifndef ITEM_LISTBOX_H
-#define ITEM_LISTBOX_H
-#include "../item.qc"
-CLASS(ListBox, Item)
-       METHOD(ListBox, resizeNotify, void(entity, vector, vector, vector, vector));
-       METHOD(ListBox, configureListBox, void(entity, float, float));
-       METHOD(ListBox, draw, void(entity));
-       METHOD(ListBox, keyDown, float(entity, float, float, float));
-       METHOD(ListBox, mouseMove, float(entity, vector));
-       METHOD(ListBox, mousePress, float(entity, vector));
-       METHOD(ListBox, mouseDrag, float(entity, vector));
-       METHOD(ListBox, mouseRelease, float(entity, vector));
-       METHOD(ListBox, focusLeave, void(entity));
-       ATTRIB(ListBox, focusable, float, 1)
-       ATTRIB(ListBox, focusedItem, int, -1)
-       ATTRIB(ListBox, focusedItemAlpha, float, 0.3)
-       METHOD(ListBox, setFocusedItem, void(entity, int));
-       ATTRIB(ListBox, mouseMoveOffset, float, -1) // let know where the cursor is when the list scrolls without moving the cursor
-       ATTRIB(ListBox, allowFocusSound, float, 1)
-       ATTRIB(ListBox, selectedItem, int, 0)
-       ATTRIB(ListBox, size, vector, '0 0 0')
-       ATTRIB(ListBox, origin, vector, '0 0 0')
-       ATTRIB(ListBox, scrollPos, float, 0) // measured in window heights, fixed when needed
-       ATTRIB(ListBox, scrollPosTarget, float, 0)
-       METHOD(ListBox, isScrolling, bool(entity));
-       ATTRIB(ListBox, needScrollToItem, float, -1)
-       METHOD(ListBox, scrollToItem, void(entity, int));
-       ATTRIB(ListBox, previousValue, float, 0)
-       ATTRIB(ListBox, pressed, float, 0) // 0 = normal, 1 = scrollbar dragging, 2 = item dragging, 3 = released
-       ATTRIB(ListBox, pressOffset, float, 0)
+       #define ITEM_LISTBOX_H
+       #include "../item.qc"
+       CLASS(ListBox, Item)
+               METHOD(ListBox, resizeNotify, void(entity, vector, vector, vector, vector));
+               METHOD(ListBox, configureListBox, void(entity, float, float));
+               METHOD(ListBox, draw, void(entity));
+               METHOD(ListBox, keyDown, float(entity, float, float, float));
+               METHOD(ListBox, mouseMove, float(entity, vector));
+               METHOD(ListBox, mousePress, float(entity, vector));
+               METHOD(ListBox, mouseDrag, float(entity, vector));
+               METHOD(ListBox, mouseRelease, float(entity, vector));
+               METHOD(ListBox, focusLeave, void(entity));
+               ATTRIB(ListBox, focusable, float, 1)
+               ATTRIB(ListBox, focusedItem, int, -1)
+               ATTRIB(ListBox, focusedItemAlpha, float, 0.3)
+               METHOD(ListBox, setFocusedItem, void(entity, int));
+               ATTRIB(ListBox, mouseMoveOffset, float, -1)  // let know where the cursor is when the list scrolls without moving the cursor
+               ATTRIB(ListBox, allowFocusSound, float, 1)
+               ATTRIB(ListBox, selectedItem, int, 0)
+               ATTRIB(ListBox, size, vector, '0 0 0')
+               ATTRIB(ListBox, origin, vector, '0 0 0')
+               ATTRIB(ListBox, scrollPos, float, 0)  // measured in window heights, fixed when needed
+               ATTRIB(ListBox, scrollPosTarget, float, 0)
+               METHOD(ListBox, isScrolling, bool(entity));
+               ATTRIB(ListBox, needScrollToItem, float, -1)
+               METHOD(ListBox, scrollToItem, void(entity, int));
+               ATTRIB(ListBox, previousValue, float, 0)
+               ATTRIB(ListBox, pressed, float, 0)  // 0 = normal, 1 = scrollbar dragging, 2 = item dragging, 3 = released
+               ATTRIB(ListBox, pressOffset, float, 0)
 
-       METHOD(ListBox, updateControlTopBottom, void(entity));
-       ATTRIB(ListBox, controlTop, float, 0)
-       ATTRIB(ListBox, controlBottom, float, 0)
-       ATTRIB(ListBox, controlWidth, float, 0)
-       ATTRIB(ListBox, dragScrollPos, vector, '0 0 0')
-       ATTRIB(ListBox, selectionDoesntMatter, bool, false) // improves scrolling by keys for lists that don't need to show an active selection
+               METHOD(ListBox, updateControlTopBottom, void(entity));
+               ATTRIB(ListBox, controlTop, float, 0)
+               ATTRIB(ListBox, controlBottom, float, 0)
+               ATTRIB(ListBox, controlWidth, float, 0)
+               ATTRIB(ListBox, dragScrollPos, vector, '0 0 0')
+               ATTRIB(ListBox, selectionDoesntMatter, bool, false) // improves scrolling by keys for lists that don't need to show an active selection
 
-       ATTRIB(ListBox, src, string, string_null) // scrollbar
-       ATTRIB(ListBox, color, vector, '1 1 1')
-       ATTRIB(ListBox, color2, vector, '1 1 1')
-       ATTRIB(ListBox, colorC, vector, '1 1 1')
-       ATTRIB(ListBox, colorF, vector, '1 1 1')
-       ATTRIB(ListBox, tolerance, vector, '0 0 0') // drag tolerance
-       ATTRIB(ListBox, scrollbarWidth, float, 0) // pixels
-       ATTRIB(ListBox, nItems, float, 42)
-       ATTRIB(ListBox, itemHeight, float, 0)
-       ATTRIB(ListBox, colorBG, vector, '0 0 0')
-       ATTRIB(ListBox, alphaBG, float, 0)
+               ATTRIB(ListBox, src, string, string_null)           // scrollbar
+               ATTRIB(ListBox, color, vector, '1 1 1')
+               ATTRIB(ListBox, color2, vector, '1 1 1')
+               ATTRIB(ListBox, colorC, vector, '1 1 1')
+               ATTRIB(ListBox, colorF, vector, '1 1 1')
+               ATTRIB(ListBox, tolerance, vector, '0 0 0') // drag tolerance
+               ATTRIB(ListBox, scrollbarWidth, float, 0)   // pixels
+               ATTRIB(ListBox, nItems, float, 42)
+               ATTRIB(ListBox, itemHeight, float, 0)
+               ATTRIB(ListBox, colorBG, vector, '0 0 0')
+               ATTRIB(ListBox, alphaBG, float, 0)
 
-       ATTRIB(ListBox, lastClickedItem, float, -1)
-       ATTRIB(ListBox, lastClickedTime, float, 0)
+               ATTRIB(ListBox, lastClickedItem, float, -1)
+               ATTRIB(ListBox, lastClickedTime, float, 0)
 
-       METHOD(ListBox, drawListBoxItem, void(entity, int, vector, bool, bool)); // item number, width/height, isSelected, isFocused
-       METHOD(ListBox, clickListBoxItem, void(entity, float, vector)); // item number, relative clickpos
-       METHOD(ListBox, doubleClickListBoxItem, void(entity, float, vector)); // item number, relative clickpos
-       METHOD(ListBox, setSelected, void(entity, float));
-       METHOD(ListBox, focusedItemChangeNotify, void(entity));
+               METHOD(ListBox, drawListBoxItem, void(entity, int, vector, bool, bool)); // item number, width/height, isSelected, isFocused
+               METHOD(ListBox, clickListBoxItem, void(entity, float, vector));          // item number, relative clickpos
+               METHOD(ListBox, doubleClickListBoxItem, void(entity, float, vector));    // item number, relative clickpos
+               METHOD(ListBox, setSelected, void(entity, float));
+               METHOD(ListBox, focusedItemChangeNotify, void(entity));
 
-       METHOD(ListBox, getLastFullyVisibleItemAtScrollPos, float(entity, float));
-       METHOD(ListBox, getFirstFullyVisibleItemAtScrollPos, float(entity, float));
+               METHOD(ListBox, getLastFullyVisibleItemAtScrollPos, float(entity, float));
+               METHOD(ListBox, getFirstFullyVisibleItemAtScrollPos, float(entity, float));
 
-       // NOTE: override these four methods if you want variable sized list items
-       METHOD(ListBox, getTotalHeight, float(entity));
-       METHOD(ListBox, getItemAtPos, float(entity, float));
-       METHOD(ListBox, getItemStart, float(entity, float));
-       METHOD(ListBox, getItemHeight, float(entity, float));
-       // NOTE: if getItemAt* are overridden, it may make sense to cache the
-       // start and height of the last item returned by getItemAtPos and fast
-       // track returning their properties for getItemStart and getItemHeight.
-       // The "hot" code path calls getItemAtPos first, then will query
-       // getItemStart and getItemHeight on it soon.
-       // When overriding, the following consistency rules must hold:
-       // getTotalHeight() == SUM(getItemHeight(i), i, 0, me.nItems-1)
-       // getItemStart(i+1) == getItemStart(i) + getItemHeight(i)
-       //   for 0 <= i < me.nItems-1
-       // getItemStart(0) == 0
-       // getItemStart(getItemAtPos(p)) <= p
-       //   if p >= 0
-       // getItemAtPos(p) == 0
-       //   if p < 0
-       // getItemStart(getItemAtPos(p)) + getItemHeight(getItemAtPos(p)) > p
-       //   if p < getTotalHeigt()
-       // getItemAtPos(p) == me.nItems - 1
-       //   if p >= getTotalHeight()
-ENDCLASS(ListBox)
+               // NOTE: override these four methods if you want variable sized list items
+               METHOD(ListBox, getTotalHeight, float(entity));
+               METHOD(ListBox, getItemAtPos, float(entity, float));
+               METHOD(ListBox, getItemStart, float(entity, float));
+               METHOD(ListBox, getItemHeight, float(entity, float));
+               // NOTE: if getItemAt* are overridden, it may make sense to cache the
+               // start and height of the last item returned by getItemAtPos and fast
+               // track returning their properties for getItemStart and getItemHeight.
+               // The "hot" code path calls getItemAtPos first, then will query
+               // getItemStart and getItemHeight on it soon.
+               // When overriding, the following consistency rules must hold:
+               // getTotalHeight() == SUM(getItemHeight(i), i, 0, me.nItems-1)
+               // getItemStart(i+1) == getItemStart(i) + getItemHeight(i)
+               //   for 0 <= i < me.nItems-1
+               // getItemStart(0) == 0
+               // getItemStart(getItemAtPos(p)) <= p
+               //   if p >= 0
+               // getItemAtPos(p) == 0
+               //   if p < 0
+               // getItemStart(getItemAtPos(p)) + getItemHeight(getItemAtPos(p)) > p
+               //   if p < getTotalHeigt()
+               // getItemAtPos(p) == me.nItems - 1
+               //   if p >= getTotalHeight()
+       ENDCLASS(ListBox)
 #endif
 
 #ifdef IMPLEMENTATION
-bool ListBox_isScrolling(entity me)
-{
-       return (me.scrollPos != me.scrollPosTarget);
-}
-
-void ListBox_scrollToItem(entity me, int i)
-{
-       // scroll doesn't work properly until itemHeight is set to the correct value
-       // at the first resizeNotify call
-       if(me.itemHeight == 1) // initial temporary value of itemHeight is 1
+       bool ListBox_isScrolling(entity me)
        {
-               me.needScrollToItem = i;
-               return;
+               return me.scrollPos != me.scrollPosTarget;
        }
 
-       i = bound(0, i, me.nItems - 1);
+       void ListBox_scrollToItem(entity me, int i)
+       {
+               // scroll doesn't work properly until itemHeight is set to the correct value
+               // at the first resizeNotify call
+               if (me.itemHeight == 1)  // initial temporary value of itemHeight is 1
+               {
+                       me.needScrollToItem = i;
+                       return;
+               }
+
+               i = bound(0, i, me.nItems - 1);
+
+               // scroll the list to make sure the selected item is visible
+               // (even if the selected item doesn't change).
+               if (i < me.getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos))
+               {
+                       // above visible area
+                       me.scrollPosTarget = me.getItemStart(me, i);
+               }
+               else if (i > me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos))
+               {
+                       // below visible area
+                       if (i == me.nItems - 1) me.scrollPosTarget = me.getTotalHeight(me) - 1;
+                       else me.scrollPosTarget = me.getItemStart(me, i + 1) - 1;
+               }
+       }
 
-       // scroll the list to make sure the selected item is visible
-       // (even if the selected item doesn't change).
-       if(i < me.getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos))
+       void ListBox_setSelected(entity me, float i)
        {
-               // above visible area
-               me.scrollPosTarget = me.getItemStart(me, i);
+               i = bound(0, i, me.nItems - 1);
+               me.scrollToItem(me, i);
+               me.selectedItem = i;
        }
-       else if(i > me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos))
+       void ListBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
        {
-               // below visible area
-               if(i == me.nItems - 1)
-                       me.scrollPosTarget = me.getTotalHeight(me) - 1;
-               else
-                       me.scrollPosTarget = me.getItemStart(me, i + 1) - 1;
+               SUPER(ListBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+               me.controlWidth = me.scrollbarWidth / absSize.x;
+       }
+       void ListBox_configureListBox(entity me, float theScrollbarWidth, float theItemHeight)
+       {
+               me.scrollbarWidth = theScrollbarWidth;
+               me.itemHeight = theItemHeight;
        }
-}
-
-void ListBox_setSelected(entity me, float i)
-{
-       i = bound(0, i, me.nItems - 1);
-       me.scrollToItem(me, i);
-       me.selectedItem = i;
-}
-void ListBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(ListBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       me.controlWidth = me.scrollbarWidth / absSize.x;
-}
-void ListBox_configureListBox(entity me, float theScrollbarWidth, float theItemHeight)
-{
-       me.scrollbarWidth = theScrollbarWidth;
-       me.itemHeight = theItemHeight;
-}
 
-float ListBox_getTotalHeight(entity me)
-{
-       return me.nItems * me.itemHeight;
-}
-float ListBox_getItemAtPos(entity me, float pos)
-{
-       return floor(pos / me.itemHeight);
-}
-float ListBox_getItemStart(entity me, float i)
-{
-       return me.itemHeight * i;
-}
-float ListBox_getItemHeight(entity me, float i)
-{
-       return me.itemHeight;
-}
+       float ListBox_getTotalHeight(entity me)
+       {
+               return me.nItems * me.itemHeight;
+       }
+       float ListBox_getItemAtPos(entity me, float pos)
+       {
+               return floor(pos / me.itemHeight);
+       }
+       float ListBox_getItemStart(entity me, float i)
+       {
+               return me.itemHeight * i;
+       }
+       float ListBox_getItemHeight(entity me, float i)
+       {
+               return me.itemHeight;
+       }
 
-float ListBox_getLastFullyVisibleItemAtScrollPos(entity me, float pos)
-{
-       return me.getItemAtPos(me, pos + 0.999) - 1;
-}
-float ListBox_getFirstFullyVisibleItemAtScrollPos(entity me, float pos)
-{
-       return me.getItemAtPos(me, pos + 0.001) + 1;
-}
-float ListBox_keyDown(entity me, float key, float ascii, float shift)
-{
-       if(key == K_MWHEELUP)
+       float ListBox_getLastFullyVisibleItemAtScrollPos(entity me, float pos)
        {
-               me.scrollPosTarget = max(me.scrollPosTarget - 0.5, 0);
+               return me.getItemAtPos(me, pos + 0.999) - 1;
        }
-       else if(key == K_MWHEELDOWN)
+       float ListBox_getFirstFullyVisibleItemAtScrollPos(entity me, float pos)
        {
-               me.scrollPosTarget = min(me.scrollPosTarget + 0.5, max(0, me.getTotalHeight(me) - 1));
+               return me.getItemAtPos(me, pos + 0.001) + 1;
        }
-       else if(key == K_PGUP || key == K_KP_PGUP)
+       float ListBox_keyDown(entity me, float key, float ascii, float shift)
        {
-               if(me.selectionDoesntMatter)
+               if (key == K_MWHEELUP)
                {
                        me.scrollPosTarget = max(me.scrollPosTarget - 0.5, 0);
-                       return 1;
                }
+               else if (key == K_MWHEELDOWN)
+               {
+                       me.scrollPosTarget = min(me.scrollPosTarget + 0.5, max(0, me.getTotalHeight(me) - 1));
+               }
+               else if (key == K_PGUP || key == K_KP_PGUP)
+               {
+                       if (me.selectionDoesntMatter)
+                       {
+                               me.scrollPosTarget = max(me.scrollPosTarget - 0.5, 0);
+                               return 1;
+                       }
 
-               float i = me.selectedItem;
-               float a = me.getItemHeight(me, i);
-               for (;;)
+                       float i = me.selectedItem;
+                       float a = me.getItemHeight(me, i);
+                       for ( ; ; )
+                       {
+                               --i;
+                               if (i < 0) break;
+                               a += me.getItemHeight(me, i);
+                               if (a >= 1) break;
+                       }
+                       me.setSelected(me, i + 1);
+               }
+               else if (key == K_PGDN || key == K_KP_PGDN)
                {
-                       --i;
-                       if (i < 0)
-                               break;
-                       a += me.getItemHeight(me, i);
-                       if (a >= 1)
-                               break;
+                       if (me.selectionDoesntMatter)
+                       {
+                               me.scrollPosTarget = min(me.scrollPosTarget + 0.5, me.nItems * me.itemHeight - 1);
+                               return 1;
+                       }
+
+                       float i = me.selectedItem;
+                       float a = me.getItemHeight(me, i);
+                       for ( ; ; )
+                       {
+                               ++i;
+                               if (i >= me.nItems) break;
+                               a += me.getItemHeight(me, i);
+                               if (a >= 1) break;
+                       }
+                       me.setSelected(me, i - 1);
                }
-               me.setSelected(me, i + 1);
-       }
-       else if(key == K_PGDN || key == K_KP_PGDN)
-       {
-               if(me.selectionDoesntMatter)
+               else if (key == K_UPARROW || key == K_KP_UPARROW)
                {
-                       me.scrollPosTarget = min(me.scrollPosTarget + 0.5, me.nItems * me.itemHeight - 1);
-                       return 1;
+                       if (me.selectionDoesntMatter)
+                       {
+                               me.scrollPosTarget = max(me.scrollPosTarget - me.itemHeight, 0);
+                               return 1;
+                       }
+
+                       me.setSelected(me, me.selectedItem - 1);
                }
+               else if (key == K_DOWNARROW || key == K_KP_DOWNARROW)
+               {
+                       if (me.selectionDoesntMatter)
+                       {
+                               me.scrollPosTarget = min(me.scrollPosTarget + me.itemHeight, me.nItems * me.itemHeight - 1);
+                               return 1;
+                       }
 
-               float i = me.selectedItem;
-               float a = me.getItemHeight(me, i);
-               for (;;)
+                       me.setSelected(me, me.selectedItem + 1);
+               }
+               else if (key == K_HOME || key == K_KP_HOME)
                {
-                       ++i;
-                       if (i >= me.nItems)
-                               break;
-                       a += me.getItemHeight(me, i);
-                       if (a >= 1)
-                               break;
+                       me.setSelected(me, 0);
                }
-               me.setSelected(me, i - 1);
-       }
-       else if(key == K_UPARROW || key == K_KP_UPARROW)
-       {
-               if(me.selectionDoesntMatter)
+               else if (key == K_END || key == K_KP_END)
                {
-                       me.scrollPosTarget = max(me.scrollPosTarget - me.itemHeight, 0);
-                       return 1;
+                       me.setSelected(me, me.nItems - 1);
                }
-
-               me.setSelected(me, me.selectedItem - 1);
-       }
-       else if(key == K_DOWNARROW || key == K_KP_DOWNARROW)
-       {
-               if(me.selectionDoesntMatter)
+               else
                {
-                       me.scrollPosTarget = min(me.scrollPosTarget + me.itemHeight, me.nItems * me.itemHeight - 1);
-                       return 1;
+                       return 0;
                }
-
-               me.setSelected(me, me.selectedItem + 1);
+               return 1;
        }
-       else if(key == K_HOME || key == K_KP_HOME)
-               me.setSelected(me, 0);
-       else if(key == K_END || key == K_KP_END)
-               me.setSelected(me, me.nItems - 1);
-       else
-               return 0;
-       return 1;
-}
-float ListBox_mouseMove(entity me, vector pos)
-{
-       me.mouseMoveOffset = -1;
-       if(pos_x < 0) return 0;
-       if(pos_y < 0) return 0;
-       if(pos_x >= 1) return 0;
-       if(pos_y >= 1) return 0;
-       if(pos_x < 1 - me.controlWidth)
-               me.mouseMoveOffset = pos.y;
-       else
+       float ListBox_mouseMove(entity me, vector pos)
        {
-               me.setFocusedItem(me, -1);
                me.mouseMoveOffset = -1;
-       }
-       return 1;
-}
-float ListBox_mouseDrag(entity me, vector pos)
-{
-       float hit;
-       me.updateControlTopBottom(me);
-       me.dragScrollPos = pos;
-       if(me.pressed == 1)
-       {
-               hit = 1;
-               if(pos.x < 1 - me.controlWidth - me.tolerance.y * me.controlWidth) hit = 0;
-               if(pos.y < 0 - me.tolerance.x) hit = 0;
-               if(pos.x >= 1 + me.tolerance.y * me.controlWidth) hit = 0;
-               if(pos.y >= 1 + me.tolerance.x) hit = 0;
-               if(hit)
+               if (pos_x < 0) return 0;
+               if (pos_y < 0) return 0;
+               if (pos_x >= 1) return 0;
+               if (pos_y >= 1) return 0;
+               if (pos_x < 1 - me.controlWidth)
                {
-                       // calculate new pos to v
-                       float d;
-                       d = (pos.y - me.pressOffset) / (1 - (me.controlBottom - me.controlTop)) * (me.getTotalHeight(me) - 1);
-                       me.scrollPosTarget = me.previousValue + d;
+                       me.mouseMoveOffset = pos.y;
                }
                else
-                       me.scrollPosTarget = me.previousValue;
-               me.scrollPosTarget = min(me.scrollPosTarget, me.getTotalHeight(me) - 1);
-               me.scrollPosTarget = max(me.scrollPosTarget, 0);
-       }
-       else if(me.pressed == 2)
-       {
-               me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
-               me.setFocusedItem(me, me.selectedItem);
-               me.mouseMoveOffset = -1;
+               {
+                       me.setFocusedItem(me, -1);
+                       me.mouseMoveOffset = -1;
+               }
+               return 1;
        }
-       return 1;
-}
-float ListBox_mousePress(entity me, vector pos)
-{
-       if(pos.x < 0) return 0;
-       if(pos.y < 0) return 0;
-       if(pos.x >= 1) return 0;
-       if(pos.y >= 1) return 0;
-       me.dragScrollPos = pos;
-       me.updateControlTopBottom(me);
-       if(pos.x >= 1 - me.controlWidth)
+       float ListBox_mouseDrag(entity me, vector pos)
        {
-               // if hit, set me.pressed, otherwise scroll by one page
-               if(pos.y < me.controlTop)
+               float hit;
+               me.updateControlTopBottom(me);
+               me.dragScrollPos = pos;
+               if (me.pressed == 1)
+               {
+                       hit = 1;
+                       if (pos.x < 1 - me.controlWidth - me.tolerance.y * me.controlWidth) hit = 0;
+                       if (pos.y < 0 - me.tolerance.x) hit = 0;
+                       if (pos.x >= 1 + me.tolerance.y * me.controlWidth) hit = 0;
+                       if (pos.y >= 1 + me.tolerance.x) hit = 0;
+                       if (hit)
+                       {
+                               // calculate new pos to v
+                               float d;
+                               d = (pos.y - me.pressOffset) / (1 - (me.controlBottom - me.controlTop)) * (me.getTotalHeight(me) - 1);
+                               me.scrollPosTarget = me.previousValue + d;
+                       }
+                       else
+                       {
+                               me.scrollPosTarget = me.previousValue;
+                       }
+                       me.scrollPosTarget = min(me.scrollPosTarget, me.getTotalHeight(me) - 1);
+                       me.scrollPosTarget = max(me.scrollPosTarget, 0);
+               }
+               else if (me.pressed == 2)
                {
-                       // page up
-                       me.scrollPosTarget = max(me.scrollPosTarget - 1, 0);
+                       me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
+                       me.setFocusedItem(me, me.selectedItem);
+                       me.mouseMoveOffset = -1;
                }
-               else if(pos.y > me.controlBottom)
+               return 1;
+       }
+       float ListBox_mousePress(entity me, vector pos)
+       {
+               if (pos.x < 0) return 0;
+               if (pos.y < 0) return 0;
+               if (pos.x >= 1) return 0;
+               if (pos.y >= 1) return 0;
+               me.dragScrollPos = pos;
+               me.updateControlTopBottom(me);
+               if (pos.x >= 1 - me.controlWidth)
                {
-                       // page down
-                       me.scrollPosTarget = min(me.scrollPosTarget + 1, me.getTotalHeight(me) - 1);
+                       // if hit, set me.pressed, otherwise scroll by one page
+                       if (pos.y < me.controlTop)
+                       {
+                               // page up
+                               me.scrollPosTarget = max(me.scrollPosTarget - 1, 0);
+                       }
+                       else if (pos.y > me.controlBottom)
+                       {
+                               // page down
+                               me.scrollPosTarget = min(me.scrollPosTarget + 1, me.getTotalHeight(me) - 1);
+                       }
+                       else
+                       {
+                               me.pressed = 1;
+                               me.pressOffset = pos.y;
+                               me.previousValue = me.scrollPos;
+                       }
                }
                else
                {
-                       me.pressed = 1;
-                       me.pressOffset = pos.y;
-                       me.previousValue = me.scrollPos;
+                       // continue doing that while dragging (even when dragging outside). When releasing, forward the click to the then selected item.
+                       me.pressed = 2;
+                       // an item has been clicked. Select it, ...
+                       me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
+                       me.setFocusedItem(me, me.selectedItem);
                }
+               return 1;
        }
-       else
-       {
-               // continue doing that while dragging (even when dragging outside). When releasing, forward the click to the then selected item.
-               me.pressed = 2;
-               // an item has been clicked. Select it, ...
-               me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
-               me.setFocusedItem(me, me.selectedItem);
-       }
-       return 1;
-}
-void ListBox_setFocusedItem(entity me, int item)
-{
-       float focusedItem_save = me.focusedItem;
-       me.focusedItem = (item < me.nItems) ? item : -1;
-       if(focusedItem_save != me.focusedItem)
+       void ListBox_setFocusedItem(entity me, int item)
        {
-               me.focusedItemChangeNotify(me);
-               if(me.focusedItem >= 0)
-                       me.focusedItemAlpha = SKINALPHA_LISTBOX_FOCUSED;
-       }
-}
-float ListBox_mouseRelease(entity me, vector pos)
-{
-       if(me.pressed == 1)
-       {
-               // slider dragging mode
-               // in that case, nothing happens on releasing
+               float focusedItem_save = me.focusedItem;
+               me.focusedItem = (item < me.nItems) ? item : -1;
+               if (focusedItem_save != me.focusedItem)
+               {
+                       me.focusedItemChangeNotify(me);
+                       if (me.focusedItem >= 0) me.focusedItemAlpha = SKINALPHA_LISTBOX_FOCUSED;
+               }
        }
-       else if(me.pressed == 2)
+       float ListBox_mouseRelease(entity me, vector pos)
        {
-               me.pressed = 3; // do that here, so setSelected can know the mouse has been released
-               // item dragging mode
-               // select current one one last time...
-               me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
-               me.setFocusedItem(me, me.selectedItem);
-               // and give it a nice click event
-               if(me.nItems > 0)
+               if (me.pressed == 1)
+               {
+                       // slider dragging mode
+                       // in that case, nothing happens on releasing
+               }
+               else if (me.pressed == 2)
                {
-                       vector where = globalToBox(pos, eY * (me.getItemStart(me, me.selectedItem) - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, me.selectedItem));
+                       me.pressed = 3;  // do that here, so setSelected can know the mouse has been released
+                       // item dragging mode
+                       // select current one one last time...
+                       me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
+                       me.setFocusedItem(me, me.selectedItem);
+                       // and give it a nice click event
+                       if (me.nItems > 0)
+                       {
+                               vector where = globalToBox(pos, eY * (me.getItemStart(me, me.selectedItem) - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, me.selectedItem));
 
-                       if((me.selectedItem == me.lastClickedItem) && (time < me.lastClickedTime + 0.3))
-                               me.doubleClickListBoxItem(me, me.selectedItem, where);
-                       else
-                               me.clickListBoxItem(me, me.selectedItem, where);
+                               if ((me.selectedItem == me.lastClickedItem) && (time < me.lastClickedTime + 0.3)) me.doubleClickListBoxItem(me, me.selectedItem, where);
+                               else me.clickListBoxItem(me, me.selectedItem, where);
 
-                       me.lastClickedItem = me.selectedItem;
-                       me.lastClickedTime = time;
+                               me.lastClickedItem = me.selectedItem;
+                               me.lastClickedTime = time;
+                       }
                }
+               me.pressed = 0;
+               return 1;
        }
-       me.pressed = 0;
-       return 1;
-}
-void ListBox_focusLeave(entity me)
-{
-       // Reset the var pressed in case listbox loses focus
-       // by a mouse click on an item of the list
-       // for example showing a dialog on right click
-       me.pressed = 0;
-       me.setFocusedItem(me, -1);
-       me.mouseMoveOffset = -1;
-}
-void ListBox_updateControlTopBottom(entity me)
-{
-       float f;
-       // scrollPos is in 0..1 and indicates where the "page" currently shown starts.
-       if(me.getTotalHeight(me) <= 1)
+       void ListBox_focusLeave(entity me)
        {
-               // we don't need no stinkin' scrollbar, we don't need no view control...
-               me.controlTop = 0;
-               me.controlBottom = 1;
-               me.scrollPos = 0;
+               // Reset the var pressed in case listbox loses focus
+               // by a mouse click on an item of the list
+               // for example showing a dialog on right click
+               me.pressed = 0;
+               me.setFocusedItem(me, -1);
+               me.mouseMoveOffset = -1;
        }
-       else
+       void ListBox_updateControlTopBottom(entity me)
        {
-               // if scroll pos is below end of list, fix it
-               me.scrollPos = min(me.scrollPos, me.getTotalHeight(me) - 1);
-               // if scroll pos is above beginning of list, fix it
-               me.scrollPos = max(me.scrollPos, 0);
-               // now that we know where the list is scrolled to, find out where to draw the control
-               me.controlTop = max(0, me.scrollPos / me.getTotalHeight(me));
-               me.controlBottom = min((me.scrollPos + 1) / me.getTotalHeight(me), 1);
-
-               float minfactor;
-               minfactor = 2 * me.controlWidth / me.size.y * me.size.x;
-               f = me.controlBottom - me.controlTop;
-               if(f < minfactor) // FIXME good default?
+               float f;
+               // scrollPos is in 0..1 and indicates where the "page" currently shown starts.
+               if (me.getTotalHeight(me) <= 1)
                {
-                       // f * X + 1 * (1-X) = minfactor
-                       // (f - 1) * X + 1 = minfactor
-                       // (f - 1) * X = minfactor - 1
-                       // X = (minfactor - 1) / (f - 1)
-                       f = (minfactor - 1) / (f - 1);
-                       me.controlTop = me.controlTop * f + 0 * (1 - f);
-                       me.controlBottom = me.controlBottom * f + 1 * (1 - f);
+                       // we don't need no stinkin' scrollbar, we don't need no view control...
+                       me.controlTop = 0;
+                       me.controlBottom = 1;
+                       me.scrollPos = 0;
+               }
+               else
+               {
+                       // if scroll pos is below end of list, fix it
+                       me.scrollPos = min(me.scrollPos, me.getTotalHeight(me) - 1);
+                       // if scroll pos is above beginning of list, fix it
+                       me.scrollPos = max(me.scrollPos, 0);
+                       // now that we know where the list is scrolled to, find out where to draw the control
+                       me.controlTop = max(0, me.scrollPos / me.getTotalHeight(me));
+                       me.controlBottom = min((me.scrollPos + 1) / me.getTotalHeight(me), 1);
+
+                       float minfactor;
+                       minfactor = 2 * me.controlWidth / me.size.y * me.size.x;
+                       f = me.controlBottom - me.controlTop;
+                       if (f < minfactor)  // FIXME good default?
+                       {
+                               // f * X + 1 * (1-X) = minfactor
+                               // (f - 1) * X + 1 = minfactor
+                               // (f - 1) * X = minfactor - 1
+                               // X = (minfactor - 1) / (f - 1)
+                               f = (minfactor - 1) / (f - 1);
+                               me.controlTop = me.controlTop * f + 0 * (1 - f);
+                               me.controlBottom = me.controlBottom * f + 1 * (1 - f);
+                       }
                }
        }
-}
-AUTOCVAR(menu_scroll_averaging_time, float, 0.16, "smooth scroll averaging time");
+       AUTOCVAR(menu_scroll_averaging_time, float, 0.16, "smooth scroll averaging time");
 // scroll faster while dragging the scrollbar
-AUTOCVAR(menu_scroll_averaging_time_pressed, float, 0.06, "smooth scroll averaging time when dragging the scrollbar");
-void ListBox_draw(entity me)
-{
-       float i;
-       vector absSize, fillSize = '0 0 0';
-       vector oldshift, oldscale;
+       AUTOCVAR(menu_scroll_averaging_time_pressed, float, 0.06, "smooth scroll averaging time when dragging the scrollbar");
+       void ListBox_draw(entity me)
+       {
+               float i;
+               vector absSize, fillSize = '0 0 0';
+               vector oldshift, oldscale;
 
-       // we can't do this in mouseMove as the list can scroll without moving the cursor
-       if(me.mouseMoveOffset != -1)
-               me.setFocusedItem(me, me.getItemAtPos(me, me.scrollPos + me.mouseMoveOffset));
+               // we can't do this in mouseMove as the list can scroll without moving the cursor
+               if (me.mouseMoveOffset != -1) me.setFocusedItem(me, me.getItemAtPos(me, me.scrollPos + me.mouseMoveOffset));
 
-       if(me.needScrollToItem >= 0)
-       {
-               me.scrollToItem(me, me.needScrollToItem);
-               me.needScrollToItem = -1;
-       }
-       if(me.scrollPos != me.scrollPosTarget)
-       {
-               float averaging_time = (me.pressed == 1)
-                       ? autocvar_menu_scroll_averaging_time_pressed
-                       : autocvar_menu_scroll_averaging_time;
-               // this formula works with whatever framerate
-               float f = averaging_time ? exp(-frametime / averaging_time) : 0;
-               me.scrollPos = me.scrollPos * f + me.scrollPosTarget * (1 - f);
-               if(fabs(me.scrollPos - me.scrollPosTarget) < 0.001)
-                       me.scrollPos = me.scrollPosTarget;
-       }
+               if (me.needScrollToItem >= 0)
+               {
+                       me.scrollToItem(me, me.needScrollToItem);
+                       me.needScrollToItem = -1;
+               }
+               if (me.scrollPos != me.scrollPosTarget)
+               {
+                       float averaging_time = (me.pressed == 1)
+                           ? autocvar_menu_scroll_averaging_time_pressed
+                               : autocvar_menu_scroll_averaging_time;
+                       // this formula works with whatever framerate
+                       float f = averaging_time ? exp(-frametime / averaging_time) : 0;
+                       me.scrollPos = me.scrollPos * f + me.scrollPosTarget * (1 - f);
+                       if (fabs(me.scrollPos - me.scrollPosTarget) < 0.001) me.scrollPos = me.scrollPosTarget;
+               }
 
-       if(me.pressed == 2)
-               me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
-       me.updateControlTopBottom(me);
-       fillSize.x = (1 - me.controlWidth);
-       if(me.alphaBG)
-               draw_Fill('0 0 0', '0 1 0' + fillSize, me.colorBG, me.alphaBG);
-       if(me.controlWidth)
-       {
-               draw_VertButtonPicture(eX * (1 - me.controlWidth), strcat(me.src, "_s"), eX * me.controlWidth + eY, me.color2, 1);
-               if(me.getTotalHeight(me) > 1)
+               if (me.pressed == 2) me.mouseDrag(me, me.dragScrollPos);  // simulate mouseDrag event
+               me.updateControlTopBottom(me);
+               fillSize.x = (1 - me.controlWidth);
+               if (me.alphaBG) draw_Fill('0 0 0', '0 1 0' + fillSize, me.colorBG, me.alphaBG);
+               if (me.controlWidth)
                {
-                       vector o, s;
-                       o = eX * (1 - me.controlWidth) + eY * me.controlTop;
-                       s = eX * me.controlWidth + eY * (me.controlBottom - me.controlTop);
-                       if(me.pressed == 1)
-                               draw_VertButtonPicture(o, strcat(me.src, "_c"), s, me.colorC, 1);
-                       else if(me.focused)
-                               draw_VertButtonPicture(o, strcat(me.src, "_f"), s, me.colorF, 1);
-                       else
-                               draw_VertButtonPicture(o, strcat(me.src, "_n"), s, me.color, 1);
+                       draw_VertButtonPicture(eX * (1 - me.controlWidth), strcat(me.src, "_s"), eX * me.controlWidth + eY, me.color2, 1);
+                       if (me.getTotalHeight(me) > 1)
+                       {
+                               vector o, s;
+                               o = eX * (1 - me.controlWidth) + eY * me.controlTop;
+                               s = eX * me.controlWidth + eY * (me.controlBottom - me.controlTop);
+                               if (me.pressed == 1) draw_VertButtonPicture(o, strcat(me.src, "_c"), s, me.colorC, 1);
+                               else if (me.focused) draw_VertButtonPicture(o, strcat(me.src, "_f"), s, me.colorF, 1);
+                               else draw_VertButtonPicture(o, strcat(me.src, "_n"), s, me.color, 1);
+                       }
                }
-       }
-       draw_SetClip();
-       oldshift = draw_shift;
-       oldscale = draw_scale;
+               draw_SetClip();
+               oldshift = draw_shift;
+               oldscale = draw_scale;
 
-       float y;
-       i = me.getItemAtPos(me, me.scrollPos);
-       y = me.getItemStart(me, i) - me.scrollPos;
-       for (; i < me.nItems && y < 1; ++i)
-       {
-               draw_shift = boxToGlobal(eY * y, oldshift, oldscale);
-               vector relSize = eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, i);
-               absSize = boxToGlobalSize(relSize, me.size);
-               draw_scale = boxToGlobalSize(relSize, oldscale);
-               me.drawListBoxItem(me, i, absSize, (me.selectedItem == i), (me.focusedItem == i));
-               y += relSize.y;
-       }
-       draw_ClearClip();
+               float y;
+               i = me.getItemAtPos(me, me.scrollPos);
+               y = me.getItemStart(me, i) - me.scrollPos;
+               for ( ; i < me.nItems && y < 1; ++i)
+               {
+                       draw_shift = boxToGlobal(eY * y, oldshift, oldscale);
+                       vector relSize = eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, i);
+                       absSize = boxToGlobalSize(relSize, me.size);
+                       draw_scale = boxToGlobalSize(relSize, oldscale);
+                       me.drawListBoxItem(me, i, absSize, (me.selectedItem == i), (me.focusedItem == i));
+                       y += relSize.y;
+               }
+               draw_ClearClip();
 
-       draw_shift = oldshift;
-       draw_scale = oldscale;
-       SUPER(ListBox).draw(me);
-}
+               draw_shift = oldshift;
+               draw_scale = oldscale;
+               SUPER(ListBox).draw(me);
+       }
 
-void ListBox_focusedItemChangeNotify(entity me)
-{
-}
+       void ListBox_focusedItemChangeNotify(entity me)
+       {}
 
-void ListBox_clickListBoxItem(entity me, float i, vector where)
-{
-       // template method
-}
+       void ListBox_clickListBoxItem(entity me, float i, vector where)
+       {
+               // template method
+       }
 
-void ListBox_doubleClickListBoxItem(entity me, float i, vector where)
-{
-       // template method
-}
+       void ListBox_doubleClickListBoxItem(entity me, float i, vector where)
+       {
+               // template method
+       }
 
-void ListBox_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
-{
-       draw_Text('0 0 0', sprintf(_("Item %d"), i), eX * (8 / absSize.x) + eY * (8 / absSize.y), (isSelected ? '0 1 0' : '1 1 1'), 1, 0);
-}
+       void ListBox_drawListBoxItem(entity me, int i, vector absSize, bool isSelected, bool isFocused)
+       {
+               draw_Text('0 0 0', sprintf(_("Item %d"), i), eX * (8 / absSize.x) + eY * (8 / absSize.y), (isSelected ? '0 1 0' : '1 1 1'), 1, 0);
+       }
 #endif
index 046d8e1942a18f72f80e3f935a396baa0cdb2264..ed02a0cef3249260c3a8d015cd39fc02bba9cada 100644 (file)
@@ -1,31 +1,31 @@
 #ifndef ITEM_MODALCONTROLLER_H
-#define ITEM_MODALCONTROLLER_H
-#include "container.qc"
-CLASS(ModalController, Container)
-       METHOD(ModalController, resizeNotify, void(entity, vector, vector, vector, vector));
-       METHOD(ModalController, draw, void(entity));
-       METHOD(ModalController, showChild, void(entity, entity, vector, vector, float));
-       METHOD(ModalController, hideChild, void(entity, entity, float));
-       METHOD(ModalController, hideAll, void(entity, float));
-       METHOD(ModalController, addItem, void(entity, entity, vector, vector, float));
-       METHOD(ModalController, addTab, void(entity, entity, entity));
+       #define ITEM_MODALCONTROLLER_H
+       #include "container.qc"
+       CLASS(ModalController, Container)
+               METHOD(ModalController, resizeNotify, void(entity, vector, vector, vector, vector));
+               METHOD(ModalController, draw, void(entity));
+               METHOD(ModalController, showChild, void(entity, entity, vector, vector, float));
+               METHOD(ModalController, hideChild, void(entity, entity, float));
+               METHOD(ModalController, hideAll, void(entity, float));
+               METHOD(ModalController, addItem, void(entity, entity, vector, vector, float));
+               METHOD(ModalController, addTab, void(entity, entity, entity));
 
-       METHOD(ModalController, initializeDialog, void(entity, entity));
+               METHOD(ModalController, initializeDialog, void(entity, entity));
 
-       METHOD(ModalController, switchState, void(entity, entity, float, float));
-       ATTRIB(ModalController, origin, vector, '0 0 0')
-       ATTRIB(ModalController, size, vector, '0 0 0')
-       ATTRIB(ModalController, previousButton, entity, NULL)
-       ATTRIB(ModalController, fadedAlpha, float, 0.3)
-ENDCLASS(ModalController)
+               METHOD(ModalController, switchState, void(entity, entity, float, float));
+               ATTRIB(ModalController, origin, vector, '0 0 0')
+               ATTRIB(ModalController, size, vector, '0 0 0')
+               ATTRIB(ModalController, previousButton, entity, NULL)
+               ATTRIB(ModalController, fadedAlpha, float, 0.3)
+       ENDCLASS(ModalController)
 
-.entity tabSelectingButton;
-.vector origin;
-.vector size;
-void TabButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
-void DialogOpenButton_Click(entity button, entity tab); // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
-void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize);
-void DialogCloseButton_Click(entity button, entity tab); // assumes a button has set the above fields to the tab to close
+       .entity tabSelectingButton;
+       .vector origin;
+       .vector size;
+       void TabButton_Click(entity button, entity tab);         // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
+       void DialogOpenButton_Click(entity button, entity tab);  // assumes a button has set the above fields to its own absolute origin, its size, and the tab to activate
+       void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize);
+       void DialogCloseButton_Click(entity button, entity tab); // assumes a button has set the above fields to the tab to close
 #endif
 
 #ifdef IMPLEMENTATION
@@ -51,246 +51,238 @@ void DialogCloseButton_Click(entity button, entity tab); // assumes a button has
 //   - to initialize: me.hideAll(me, 1); me.showChild(me, me.firstChild, '0 0 0', '0 0 0', 1);
 //   - to show a tab: me.hideChild(me, currentTab, 0); me.showChild(me, newTab, buttonAbsOrigin, buttonAbsSize, 0);
 
-.vector ModalController_initialSize;
-.vector ModalController_initialOrigin;
-.vector ModalController_initialFontScale;
-.float ModalController_initialAlpha;
-.vector ModalController_buttonSize;
-.vector ModalController_buttonOrigin;
-.float ModalController_state;
-.float ModalController_factor;
-.entity ModalController_controllingButton;
+       .vector ModalController_initialSize;
+       .vector ModalController_initialOrigin;
+       .vector ModalController_initialFontScale;
+       .float ModalController_initialAlpha;
+       .vector ModalController_buttonSize;
+       .vector ModalController_buttonOrigin;
+       .float ModalController_state;
+       .float ModalController_factor;
+       .entity ModalController_controllingButton;
 
-void ModalController_initializeDialog(entity me, entity root)
-{
-       me.hideAll(me, 1);
-       me.showChild(me, root, '0 0 0', '0 0 0', 1); // someone else animates for us
-}
-
-void TabButton_Click(entity button, entity tab)
-{
-       if(tab.ModalController_state == 1)
-               return;
-       tab.parent.hideAll(tab.parent, 0);
-       button.forcePressed = 1;
-       tab.ModalController_controllingButton = button;
-       tab.parent.showChild(tab.parent, tab, button.origin, button.size, 0);
-}
-
-void DialogOpenButton_Click(entity button, entity tab)
-{
-       DialogOpenButton_Click_withCoords(button, tab, button.origin, button.size);
-}
+       void ModalController_initializeDialog(entity me, entity root)
+       {
+               me.hideAll(me, 1);
+               me.showChild(me, root, '0 0 0', '0 0 0', 1);  // someone else animates for us
+       }
 
-void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize)
-{
-       if(tab.ModalController_state)
-               return;
-       if(button)
+       void TabButton_Click(entity button, entity tab)
+       {
+               if (tab.ModalController_state == 1) return;
+               tab.parent.hideAll(tab.parent, 0);
                button.forcePressed = 1;
-       if(tab.parent.focusedChild)
-               tab.parent.focusedChild.saveFocus(tab.parent.focusedChild);
-       tab.ModalController_controllingButton = button;
-       tab.parent.showChild(tab.parent, tab, theOrigin, theSize, 0);
-}
+               tab.ModalController_controllingButton = button;
+               tab.parent.showChild(tab.parent, tab, button.origin, button.size, 0);
+       }
 
-void DialogCloseButton_Click(entity button, entity tab)
-{
-       tab.parent.hideChild(tab.parent, tab, 0);
-}
+       void DialogOpenButton_Click(entity button, entity tab)
+       {
+               DialogOpenButton_Click_withCoords(button, tab, button.origin, button.size);
+       }
 
-void ModalController_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, ModalController_initialOrigin, ModalController_initialSize, ModalController_initialFontScale);
-}
+       void DialogOpenButton_Click_withCoords(entity button, entity tab, vector theOrigin, vector theSize)
+       {
+               if (tab.ModalController_state) return;
+               if (button) button.forcePressed = 1;
+               if (tab.parent.focusedChild) tab.parent.focusedChild.saveFocus(tab.parent.focusedChild);
+               tab.ModalController_controllingButton = button;
+               tab.parent.showChild(tab.parent, tab, theOrigin, theSize, 0);
+       }
 
-void ModalController_switchState(entity me, entity other, float state, float skipAnimation)
-{
-       float previousState;
-       previousState = other.ModalController_state;
-       if(state == previousState && !skipAnimation)
-               return;
-       other.ModalController_state = state;
-       switch(state)
+       void DialogCloseButton_Click(entity button, entity tab)
        {
-               case 0:
-                       other.ModalController_factor = 1 - other.Container_alpha / other.ModalController_initialAlpha;
-                       // fading out
-                       break;
-               case 1:
-                       other.ModalController_factor = other.Container_alpha / other.ModalController_initialAlpha;
-                       if(previousState == 0 && !skipAnimation)
-                       {
-                               other.Container_origin = other.ModalController_buttonOrigin;
-                               other.Container_size = other.ModalController_buttonSize;
-                       }
-                       // zooming in
-                       break;
-               case 2:
-                       other.ModalController_factor = bound(0, (1 - other.Container_alpha / other.ModalController_initialAlpha) / me.fadedAlpha, 1);
-                       // fading out halfway
-                       break;
+               tab.parent.hideChild(tab.parent, tab, 0);
        }
-       if(skipAnimation)
-               other.ModalController_factor = 1;
-}
 
-void ModalController_draw(entity me)
-{
-       entity e;
-       entity front;
-       float animating;
-       float f; // animation factor
-       float df; // animation step size
-       float prevFactor, targetFactor;
-       vector targetOrigin, targetSize; float targetAlpha;
-       vector fs;
-       animating = 0;
+       void ModalController_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+       {
+               me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, ModalController_initialOrigin, ModalController_initialSize, ModalController_initialFontScale);
+       }
 
-       front = NULL;
-       for(e = me.firstChild; e; e = e.nextSibling)
-               if(e.ModalController_state)
+       void ModalController_switchState(entity me, entity other, float state, float skipAnimation)
+       {
+               float previousState;
+               previousState = other.ModalController_state;
+               if (state == previousState && !skipAnimation) return;
+               other.ModalController_state = state;
+               switch (state)
                {
-                       if(front)
-                               me.switchState(me, front, 2, 0);
-                       front = e;
+                       case 0:
+                               other.ModalController_factor = 1 - other.Container_alpha / other.ModalController_initialAlpha;
+                               // fading out
+                               break;
+                       case 1:
+                               other.ModalController_factor = other.Container_alpha / other.ModalController_initialAlpha;
+                               if (previousState == 0 && !skipAnimation)
+                               {
+                                       other.Container_origin = other.ModalController_buttonOrigin;
+                                       other.Container_size = other.ModalController_buttonSize;
+                               }
+                               // zooming in
+                               break;
+                       case 2:
+                               other.ModalController_factor = bound(0, (1 - other.Container_alpha / other.ModalController_initialAlpha) / me.fadedAlpha, 1);
+                               // fading out halfway
+                               break;
                }
-       if(front)
-               me.switchState(me, front, 1, 0);
-
-       df = frametime * 3; // animation speed
+               if (skipAnimation) other.ModalController_factor = 1;
+       }
 
-       for(e = me.firstChild; e; e = e.nextSibling)
+       void ModalController_draw(entity me)
        {
-               if(e.ModalController_state == 2)
-               {
-                       // fading out partially
-                       targetOrigin = e.Container_origin; // stay as is
-                       targetSize = e.Container_size; // stay as is
-                       targetAlpha = me.fadedAlpha * e.ModalController_initialAlpha;
-               }
-               else if(e.ModalController_state == 1)
-               {
-                       // zooming in
-                       targetOrigin = e.ModalController_initialOrigin;
-                       targetSize = e.ModalController_initialSize;
-                       targetAlpha = e.ModalController_initialAlpha;
-               }
-               else
-               {
-                       // fading out
-                       targetOrigin = e.Container_origin; // stay as is
-                       targetSize = e.Container_size; // stay as is
-                       targetAlpha = 0;
-               }
+               entity e;
+               entity front;
+               float animating;
+               float f;  // animation factor
+               float df; // animation step size
+               float prevFactor, targetFactor;
+               vector targetOrigin, targetSize;
+               float targetAlpha;
+               vector fs;
+               animating = 0;
 
-               f = (e.ModalController_factor = min(1, e.ModalController_factor + df));
-               if(f == 1)
-               {
-                       prevFactor = 0;
-                       targetFactor = 1;
-                       e.Container_origin = targetOrigin;
-                       e.Container_size = targetSize;
-                       me.setAlphaOf(me, e, targetAlpha);
-               }
-               else
+               front = NULL;
+               for (e = me.firstChild; e; e = e.nextSibling)
+                       if (e.ModalController_state)
+                       {
+                               if (front) me.switchState(me, front, 2, 0);
+                               front = e;
+                       }
+               if (front) me.switchState(me, front, 1, 0);
+
+               df = frametime * 3;  // animation speed
+
+               for (e = me.firstChild; e; e = e.nextSibling)
                {
-                       prevFactor = (1 - f) / (1 - f + df);
-                       if(!e.ModalController_state) // optimize code and avoid precision errors
-                               me.setAlphaOf(me, e, e.Container_alpha  * prevFactor);
+                       if (e.ModalController_state == 2)
+                       {
+                               // fading out partially
+                               targetOrigin = e.Container_origin; // stay as is
+                               targetSize = e.Container_size;     // stay as is
+                               targetAlpha = me.fadedAlpha * e.ModalController_initialAlpha;
+                       }
+                       else if (e.ModalController_state == 1)
+                       {
+                               // zooming in
+                               targetOrigin = e.ModalController_initialOrigin;
+                               targetSize = e.ModalController_initialSize;
+                               targetAlpha = e.ModalController_initialAlpha;
+                       }
                        else
                        {
-                               animating = 1;
-                               targetFactor = df / (1 - f + df);
+                               // fading out
+                               targetOrigin = e.Container_origin; // stay as is
+                               targetSize = e.Container_size;     // stay as is
+                               targetAlpha = 0;
+                       }
 
-                               if(e.ModalController_state == 1)
+                       f = (e.ModalController_factor = min(1, e.ModalController_factor + df));
+                       if (f == 1)
+                       {
+                               prevFactor = 0;
+                               targetFactor = 1;
+                               e.Container_origin = targetOrigin;
+                               e.Container_size = targetSize;
+                               me.setAlphaOf(me, e, targetAlpha);
+                       }
+                       else
+                       {
+                               prevFactor = (1 - f) / (1 - f + df);
+                               if (!e.ModalController_state)  // optimize code and avoid precision errors
+                               {
+                                       me.setAlphaOf(me, e, e.Container_alpha  * prevFactor);
+                               }
+                               else
                                {
-                                       e.Container_origin = e.Container_origin * prevFactor + targetOrigin * targetFactor;
-                                       e.Container_size   = e.Container_size   * prevFactor + targetSize   * targetFactor;
+                                       animating = 1;
+                                       targetFactor = df / (1 - f + df);
+
+                                       if (e.ModalController_state == 1)
+                                       {
+                                               e.Container_origin = e.Container_origin * prevFactor + targetOrigin * targetFactor;
+                                               e.Container_size   = e.Container_size   * prevFactor + targetSize   * targetFactor;
+                                       }
+                                       me.setAlphaOf(me, e, e.Container_alpha  * prevFactor + targetAlpha  * targetFactor);
                                }
-                               me.setAlphaOf(me, e, e.Container_alpha  * prevFactor + targetAlpha  * targetFactor);
+                       }
+                       // assume: o == to * f_prev + X * (1 - f_prev)
+                       // make:   o' = to * f  + X * (1 - f)
+                       // -->
+                       // X == (o - to * f_prev) / (1 - f_prev)
+                       // o' = to * f + (o - to * f_prev) / (1 - f_prev) * (1 - f)
+                       // --> (maxima)
+                       // o' = (to * (f - f_prev) + o * (1 - f)) / (1 - f_prev)
+
+                       if (e.ModalController_state == 1)
+                       {
+                               fs = globalToBoxSize(e.Container_size, e.ModalController_initialSize);
+                               e.Container_fontscale_x = fs.x * e.ModalController_initialFontScale.x;
+                               e.Container_fontscale_y = fs.y * e.ModalController_initialFontScale.y;
                        }
                }
-               // assume: o == to * f_prev + X * (1 - f_prev)
-               // make:   o' = to * f  + X * (1 - f)
-               // -->
-               // X == (o - to * f_prev) / (1 - f_prev)
-               // o' = to * f + (o - to * f_prev) / (1 - f_prev) * (1 - f)
-               // --> (maxima)
-               // o' = (to * (f - f_prev) + o * (1 - f)) / (1 - f_prev)
 
-               if(e.ModalController_state == 1)
+               if (animating || !me.focused) me.setFocus(me, NULL);
+               else me.setFocus(me, front);
+               SUPER(ModalController).draw(me);
+       }
+
+       void ModalController_addTab(entity me, entity other, entity tabButton)
+       {
+               me.addItem(me, other, '0 0 0', '1 1 1', 1);
+               tabButton.onClick = TabButton_Click;
+               tabButton.onClickEntity = other;
+               other.tabSelectingButton = tabButton;
+               if (other == me.firstChild)
                {
-                       fs = globalToBoxSize(e.Container_size, e.ModalController_initialSize);
-                       e.Container_fontscale_x = fs.x * e.ModalController_initialFontScale.x;
-                       e.Container_fontscale_y = fs.y * e.ModalController_initialFontScale.y;
+                       tabButton.forcePressed = 1;
+                       other.ModalController_controllingButton = tabButton;
+                       me.showChild(me, other, '0 0 0', '0 0 0', 1);
                }
        }
 
-       if(animating || !me.focused)
-               me.setFocus(me, NULL);
-       else
-               me.setFocus(me, front);
-       SUPER(ModalController).draw(me);
-}
-
-void ModalController_addTab(entity me, entity other, entity tabButton)
-{
-       me.addItem(me, other, '0 0 0', '1 1 1', 1);
-       tabButton.onClick = TabButton_Click;
-       tabButton.onClickEntity = other;
-       other.tabSelectingButton = tabButton;
-       if(other == me.firstChild)
+       void ModalController_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
        {
-               tabButton.forcePressed = 1;
-               other.ModalController_controllingButton = tabButton;
-               me.showChild(me, other, '0 0 0', '0 0 0', 1);
+               SUPER(ModalController).addItem(me, other, theOrigin, theSize, (other == me.firstChild) ? theAlpha : 0);
+               other.ModalController_initialFontScale = other.Container_fontscale;
+               other.ModalController_initialSize = other.Container_size;
+               other.ModalController_initialOrigin = other.Container_origin;
+               other.ModalController_initialAlpha = theAlpha;  // hope Container never modifies this
+               if (other.ModalController_initialFontScale == '0 0 0') other.ModalController_initialFontScale = '1 1 0';
        }
-}
 
-void ModalController_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
-{
-       SUPER(ModalController).addItem(me, other, theOrigin, theSize, (other == me.firstChild) ? theAlpha : 0);
-       other.ModalController_initialFontScale = other.Container_fontscale;
-       other.ModalController_initialSize = other.Container_size;
-       other.ModalController_initialOrigin = other.Container_origin;
-       other.ModalController_initialAlpha = theAlpha; // hope Container never modifies this
-       if(other.ModalController_initialFontScale == '0 0 0')
-               other.ModalController_initialFontScale = '1 1 0';
-}
-
-void ModalController_showChild(entity me, entity other, vector theOrigin, vector theSize, float skipAnimation)
-{
-       if(other.ModalController_state == 0 || skipAnimation)
+       void ModalController_showChild(entity me, entity other, vector theOrigin, vector theSize, float skipAnimation)
        {
-               me.setFocus(me, NULL);
-               if(!skipAnimation)
+               if (other.ModalController_state == 0 || skipAnimation)
                {
-                       other.ModalController_buttonOrigin = globalToBox(theOrigin, me.origin, me.size);
-                       other.ModalController_buttonSize = globalToBoxSize(theSize, me.size);
-               }
-               me.switchState(me, other, 1, skipAnimation);
-       } // zoom in from button (factor increases)
-}
+                       me.setFocus(me, NULL);
+                       if (!skipAnimation)
+                       {
+                               other.ModalController_buttonOrigin = globalToBox(theOrigin, me.origin, me.size);
+                               other.ModalController_buttonSize = globalToBoxSize(theSize, me.size);
+                       }
+                       me.switchState(me, other, 1, skipAnimation);
+               }  // zoom in from button (factor increases)
+       }
 
-void ModalController_hideAll(entity me, float skipAnimation)
-{
-       entity e;
-       for(e = me.firstChild; e; e = e.nextSibling)
-               me.hideChild(me, e, skipAnimation);
-}
+       void ModalController_hideAll(entity me, float skipAnimation)
+       {
+               entity e;
+               for (e = me.firstChild; e; e = e.nextSibling)
+                       me.hideChild(me, e, skipAnimation);
+       }
 
-void ModalController_hideChild(entity me, entity other, float skipAnimation)
-{
-       if(other.ModalController_state || skipAnimation)
+       void ModalController_hideChild(entity me, entity other, float skipAnimation)
        {
-               me.setFocus(me, NULL);
-               me.switchState(me, other, 0, skipAnimation);
-               if(other.ModalController_controllingButton)
+               if (other.ModalController_state || skipAnimation)
                {
-                       other.ModalController_controllingButton.forcePressed = 0;
-                       other.ModalController_controllingButton = NULL;
-               }
-       } // just alpha fade out (factor increases and decreases alpha)
-}
+                       me.setFocus(me, NULL);
+                       me.switchState(me, other, 0, skipAnimation);
+                       if (other.ModalController_controllingButton)
+                       {
+                               other.ModalController_controllingButton.forcePressed = 0;
+                               other.ModalController_controllingButton = NULL;
+                       }
+               }  // just alpha fade out (factor increases and decreases alpha)
+       }
 #endif
index 06616e68f597f2b4a82f444dbab0f1b291596354..e35909493c635e08918fbe98b7bc0dba6955b42d 100644 (file)
@@ -1,30 +1,30 @@
 #ifndef ITEM_NEXPOSEE_H
-#define ITEM_NEXPOSEE_H
-#include "container.qc"
-CLASS(Nexposee, Container)
-       METHOD(Nexposee, draw, void(entity));
-       METHOD(Nexposee, keyDown, float(entity, float, float, float));
-       METHOD(Nexposee, keyUp, float(entity, float, float, float));
-       METHOD(Nexposee, mousePress, float(entity, vector));
-       METHOD(Nexposee, mouseMove, float(entity, vector));
-       METHOD(Nexposee, mouseRelease, float(entity, vector));
-       METHOD(Nexposee, mouseDrag, float(entity, vector));
-       METHOD(Nexposee, resizeNotify, void(entity, vector, vector, vector, vector));
-       METHOD(Nexposee, focusEnter, void(entity));
-       METHOD(Nexposee, close, void(entity));
-
-       ATTRIB(Nexposee, animationState, float, -1)
-       ATTRIB(Nexposee, animationFactor, float, 0)
-       ATTRIB(Nexposee, selectedChild, entity, NULL)
-       ATTRIB(Nexposee, mouseFocusedChild, entity, NULL)
-       METHOD(Nexposee, addItem, void(entity, entity, vector, vector, float));
-       METHOD(Nexposee, calc, void(entity));
-       METHOD(Nexposee, setNexposee, void(entity, entity, vector, float, float));
-       ATTRIB(Nexposee, mousePosition, vector, '0 0 0')
-       METHOD(Nexposee, pullNexposee, void(entity, entity, vector));
-ENDCLASS(Nexposee)
-
-void ExposeeCloseButton_Click(entity button, entity other); // un-exposees the current state
+       #define ITEM_NEXPOSEE_H
+       #include "container.qc"
+       CLASS(Nexposee, Container)
+               METHOD(Nexposee, draw, void(entity));
+               METHOD(Nexposee, keyDown, float(entity, float, float, float));
+               METHOD(Nexposee, keyUp, float(entity, float, float, float));
+               METHOD(Nexposee, mousePress, float(entity, vector));
+               METHOD(Nexposee, mouseMove, float(entity, vector));
+               METHOD(Nexposee, mouseRelease, float(entity, vector));
+               METHOD(Nexposee, mouseDrag, float(entity, vector));
+               METHOD(Nexposee, resizeNotify, void(entity, vector, vector, vector, vector));
+               METHOD(Nexposee, focusEnter, void(entity));
+               METHOD(Nexposee, close, void(entity));
+
+               ATTRIB(Nexposee, animationState, float, -1)
+               ATTRIB(Nexposee, animationFactor, float, 0)
+               ATTRIB(Nexposee, selectedChild, entity, NULL)
+               ATTRIB(Nexposee, mouseFocusedChild, entity, NULL)
+               METHOD(Nexposee, addItem, void(entity, entity, vector, vector, float));
+               METHOD(Nexposee, calc, void(entity));
+               METHOD(Nexposee, setNexposee, void(entity, entity, vector, float, float));
+               ATTRIB(Nexposee, mousePosition, vector, '0 0 0')
+               METHOD(Nexposee, pullNexposee, void(entity, entity, vector));
+       ENDCLASS(Nexposee)
+
+       void ExposeeCloseButton_Click(entity button, entity other);  // un-exposees the current state
 
 // animation states:
 //   0 = thumbnails seen
@@ -32,337 +32,315 @@ void ExposeeCloseButton_Click(entity button, entity other); // un-exposees the c
 //   2 = zoomed in
 //   3 = zooming out
 // animation factor: 0 = minimum theSize, 1 = maximum theSize
-.vector Nexposee_initialSize;
-.vector Nexposee_initialFontScale;
-.vector Nexposee_initialOrigin;
-.float Nexposee_initialAlpha;
-
-.vector Nexposee_smallSize;
-.vector Nexposee_smallOrigin;
-.float Nexposee_smallAlpha;
-.float Nexposee_mediumAlpha;
-.vector Nexposee_scaleCenter;
-.vector Nexposee_align;
-.float Nexposee_animationFactor;
+       .vector Nexposee_initialSize;
+       .vector Nexposee_initialFontScale;
+       .vector Nexposee_initialOrigin;
+       .float Nexposee_initialAlpha;
+
+       .vector Nexposee_smallSize;
+       .vector Nexposee_smallOrigin;
+       .float Nexposee_smallAlpha;
+       .float Nexposee_mediumAlpha;
+       .vector Nexposee_scaleCenter;
+       .vector Nexposee_align;
+       .float Nexposee_animationFactor;
 
 #endif
 
 #ifdef IMPLEMENTATION
-void Nexposee_close(entity me)
-{
-       // user must override this
-}
-
-void ExposeeCloseButton_Click(entity button, entity other)
-{
-       other.selectedChild = other.focusedChild;
-       other.setFocus(other, NULL);
-       other.animationState = 3;
-}
-
-void Nexposee_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       me.calc(me);
-       me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Nexposee_initialOrigin, Nexposee_initialSize, Nexposee_initialFontScale);
-}
-
-void Nexposee_Calc_Scale(entity me, float scale)
-{
-       entity e;
-       for(e = me.firstChild; e; e = e.nextSibling)
+       void Nexposee_close(entity me)
        {
-               e.Nexposee_smallOrigin = (e.Nexposee_initialOrigin - e.Nexposee_scaleCenter) * scale + e.Nexposee_scaleCenter;
-               e.Nexposee_smallSize = e.Nexposee_initialSize * scale;
-               if(e.Nexposee_align.x > 0)
-                       e.Nexposee_smallOrigin_x = 1 - e.Nexposee_align.x * scale;
-               if(e.Nexposee_align.x < 0)
-                       e.Nexposee_smallOrigin_x = -e.Nexposee_smallSize.x + e.Nexposee_align.x * scale;
-               if(e.Nexposee_align.y > 0)
-                       e.Nexposee_smallOrigin_y = 1 - e.Nexposee_align.y * scale;
-               if(e.Nexposee_align.y < 0)
-                       e.Nexposee_smallOrigin_y = -e.Nexposee_smallSize.y + e.Nexposee_align.y * scale;
+               // user must override this
        }
-}
-
-void Nexposee_calc(entity me)
-{
-       /*
-        * patented by Apple
-        * can't put that here ;)
-        */
-       float scale;
-       entity e, e2;
-       vector emins, emaxs, e2mins, e2maxs;
-
-       for(scale = 0.7;; scale *= 0.99)
+
+       void ExposeeCloseButton_Click(entity button, entity other)
        {
-               Nexposee_Calc_Scale(me, scale);
+               other.selectedChild = other.focusedChild;
+               other.setFocus(other, NULL);
+               other.animationState = 3;
+       }
 
-               for(e = me.firstChild; e; e = e.nextSibling)
+       void Nexposee_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
+       {
+               me.calc(me);
+               me.resizeNotifyLie(me, relOrigin, relSize, absOrigin, absSize, Nexposee_initialOrigin, Nexposee_initialSize, Nexposee_initialFontScale);
+       }
+
+       void Nexposee_Calc_Scale(entity me, float scale)
+       {
+               entity e;
+               for (e = me.firstChild; e; e = e.nextSibling)
                {
-                       emins = e.Nexposee_smallOrigin;
-                       emaxs = emins + e.Nexposee_smallSize;
-                       for(e2 = e.nextSibling; e2; e2 = e2.nextSibling)
-                       {
-                               e2mins = e2.Nexposee_smallOrigin;
-                               e2maxs = e2mins + e2.Nexposee_smallSize;
-
-                               // two intervals [amins, amaxs] and [bmins, bmaxs] overlap if:
-                               //   amins < bmins < amaxs < bmaxs
-                               // for which suffices
-                               //   bmins < amaxs
-                               //   amins < bmaxs
-                               if((e2mins.x - emaxs.x) * (emins.x - e2maxs.x) > 0) // x overlap
-                                       if((e2mins.y - emaxs.y) * (emins.y - e2maxs.y) > 0) // y overlap
-                                       {
-                                               goto have_overlap;
-                                       }
-                       }
+                       e.Nexposee_smallOrigin = (e.Nexposee_initialOrigin - e.Nexposee_scaleCenter) * scale + e.Nexposee_scaleCenter;
+                       e.Nexposee_smallSize = e.Nexposee_initialSize * scale;
+                       if (e.Nexposee_align.x > 0) e.Nexposee_smallOrigin_x = 1 - e.Nexposee_align.x * scale;
+                       if (e.Nexposee_align.x < 0) e.Nexposee_smallOrigin_x = -e.Nexposee_smallSize.x + e.Nexposee_align.x * scale;
+                       if (e.Nexposee_align.y > 0) e.Nexposee_smallOrigin_y = 1 - e.Nexposee_align.y * scale;
+                       if (e.Nexposee_align.y < 0) e.Nexposee_smallOrigin_y = -e.Nexposee_smallSize.y + e.Nexposee_align.y * scale;
                }
-
-               break;
-:have_overlap
        }
 
-       scale *= 0.95;
+       void Nexposee_calc(entity me)
+       {
+               /*
+                * patented by Apple
+                * can't put that here ;)
+                */
+               float scale;
+               entity e, e2;
+               vector emins, emaxs, e2mins, e2maxs;
+
+               for (scale = 0.7; ; scale *= 0.99)
+               {
+                       Nexposee_Calc_Scale(me, scale);
 
-       Nexposee_Calc_Scale(me, scale);
-}
+                       for (e = me.firstChild; e; e = e.nextSibling)
+                       {
+                               emins = e.Nexposee_smallOrigin;
+                               emaxs = emins + e.Nexposee_smallSize;
+                               for (e2 = e.nextSibling; e2; e2 = e2.nextSibling)
+                               {
+                                       e2mins = e2.Nexposee_smallOrigin;
+                                       e2maxs = e2mins + e2.Nexposee_smallSize;
+
+                                       // two intervals [amins, amaxs] and [bmins, bmaxs] overlap if:
+                                       //   amins < bmins < amaxs < bmaxs
+                                       // for which suffices
+                                       //   bmins < amaxs
+                                       //   amins < bmaxs
+                                       if ((e2mins.x - emaxs.x) * (emins.x - e2maxs.x) > 0)     // x overlap
+                                               if ((e2mins.y - emaxs.y) * (emins.y - e2maxs.y) > 0) // y overlap
+                                                       goto have_overlap;
+                               }
+                       }
+
+                       break;
+                       : have_overlap
+               }
 
-void Nexposee_setNexposee(entity me, entity other, vector scalecenter, float a0, float a1)
-{
-       other.Nexposee_scaleCenter = scalecenter;
-       other.Nexposee_smallAlpha = a0;
-       me.setAlphaOf(me, other, a0);
-       other.Nexposee_mediumAlpha = a1;
-}
+               scale *= 0.95;
 
-void Nexposee_draw(entity me)
-{
-       float a;
-       float a0;
-       entity e;
-       float f;
-       vector fs;
+               Nexposee_Calc_Scale(me, scale);
+       }
 
-       if(me.animationState == -1)
+       void Nexposee_setNexposee(entity me, entity other, vector scalecenter, float a0, float a1)
        {
-               me.animationState = 0;
+               other.Nexposee_scaleCenter = scalecenter;
+               other.Nexposee_smallAlpha = a0;
+               me.setAlphaOf(me, other, a0);
+               other.Nexposee_mediumAlpha = a1;
        }
 
-       f = min(1, frametime * 5);
-       switch(me.animationState)
+       void Nexposee_draw(entity me)
        {
-               case 0:
-                       me.animationFactor = 0;
-                       break;
-               case 1:
-                       me.animationFactor += f;
-                       if(me.animationFactor >= 1)
-                       {
+               float a;
+               float a0;
+               entity e;
+               float f;
+               vector fs;
+
+               if (me.animationState == -1) me.animationState = 0;
+
+               f = min(1, frametime * 5);
+               switch (me.animationState)
+               {
+                       case 0:
+                               me.animationFactor = 0;
+                               break;
+                       case 1:
+                               me.animationFactor += f;
+                               if (me.animationFactor >= 1)
+                               {
+                                       me.animationFactor = 1;
+                                       me.animationState = 2;
+                                       SUPER(Nexposee).setFocus(me, me.selectedChild);
+                               }
+                               break;
+                       case 2:
                                me.animationFactor = 1;
-                               me.animationState = 2;
-                               SUPER(Nexposee).setFocus(me, me.selectedChild);
+                               break;
+                       case 3:
+                               me.animationFactor -= f;
+                               me.mouseFocusedChild = me.itemFromPoint(me, me.mousePosition);
+                               if (me.animationFactor <= 0)
+                               {
+                                       me.animationFactor = 0;
+                                       me.animationState = 0;
+                                       me.selectedChild = me.mouseFocusedChild;
+                               }
+                               break;
+               }
+
+               f = min(1, frametime * 10);
+               for (e = me.firstChild; e; e = e.nextSibling)
+               {
+                       if (e == me.selectedChild)
+                       {
+                               e.Container_origin = e.Nexposee_smallOrigin * (1 - me.animationFactor) + e.Nexposee_initialOrigin * me.animationFactor;
+                               e.Container_size = e.Nexposee_smallSize * (1 - me.animationFactor) + e.Nexposee_initialSize * me.animationFactor;
+                               e.Nexposee_animationFactor = me.animationFactor;
+                               a0 = e.Nexposee_mediumAlpha;
+                               if (me.animationState == 3)
+                                       if (e != me.mouseFocusedChild) a0 = e.Nexposee_smallAlpha;
+                               a = a0 * (1 - me.animationFactor) + me.animationFactor;
                        }
-                       break;
-               case 2:
-                       me.animationFactor = 1;
-                       break;
-               case 3:
-                       me.animationFactor -= f;
-                       me.mouseFocusedChild = me.itemFromPoint(me, me.mousePosition);
-                       if(me.animationFactor <= 0)
+                       else
                        {
-                               me.animationFactor = 0;
-                               me.animationState = 0;
-                               me.selectedChild = me.mouseFocusedChild;
+                               // minimum theSize counts
+                               e.Container_origin = e.Nexposee_smallOrigin;
+                               e.Container_size = e.Nexposee_smallSize;
+                               e.Nexposee_animationFactor = 0;
+                               a = e.Nexposee_smallAlpha * (1 - me.animationFactor);
                        }
-                       break;
+                       me.setAlphaOf(me, e, e.Container_alpha * (1 - f) + a * f);
+
+                       fs = globalToBoxSize(e.Container_size, e.Nexposee_initialSize);
+                       e.Container_fontscale_x = fs.x * e.Nexposee_initialFontScale.x;
+                       e.Container_fontscale_y = fs.y * e.Nexposee_initialFontScale.y;
+               }
+
+               SUPER(Nexposee).draw(me);
        }
 
-       f = min(1, frametime * 10);
-       for(e = me.firstChild; e; e = e.nextSibling)
+       float Nexposee_mousePress(entity me, vector pos)
        {
-               if(e == me.selectedChild)
+               if (me.animationState == 0)
                {
-                       e.Container_origin = e.Nexposee_smallOrigin * (1 - me.animationFactor) + e.Nexposee_initialOrigin * me.animationFactor;
-                       e.Container_size = e.Nexposee_smallSize * (1 - me.animationFactor) + e.Nexposee_initialSize * me.animationFactor;
-                       e.Nexposee_animationFactor = me.animationFactor;
-                       a0 = e.Nexposee_mediumAlpha;
-                       if(me.animationState == 3)
-                               if(e != me.mouseFocusedChild)
-                                       a0 = e.Nexposee_smallAlpha;
-                       a = a0 * (1 - me.animationFactor) + me.animationFactor;
+                       me.mouseFocusedChild = NULL;
+                       Nexposee_mouseMove(me, pos);
+                       if (me.mouseFocusedChild)
+                       {
+                               m_play_click_sound(MENU_SOUND_OPEN);
+                               me.animationState = 1;
+                               SUPER(Nexposee).setFocus(me, NULL);
+                       }
+                       else
+                       {
+                               me.close(me);
+                       }
+                       return 1;
                }
-               else
+               else if (me.animationState == 2)
                {
-                       // minimum theSize counts
-                       e.Container_origin = e.Nexposee_smallOrigin;
-                       e.Container_size = e.Nexposee_smallSize;
-                       e.Nexposee_animationFactor = 0;
-                       a = e.Nexposee_smallAlpha * (1 - me.animationFactor);
+                       if (!(SUPER(Nexposee).mousePress(me, pos)))
+                       {
+                               m_play_click_sound(MENU_SOUND_CLOSE);
+                               me.animationState = 3;
+                               SUPER(Nexposee).setFocus(me, NULL);
+                       }
+                       return 1;
                }
-               me.setAlphaOf(me, e, e.Container_alpha * (1 - f) + a * f);
-
-               fs = globalToBoxSize(e.Container_size, e.Nexposee_initialSize);
-               e.Container_fontscale_x = fs.x * e.Nexposee_initialFontScale.x;
-               e.Container_fontscale_y = fs.y * e.Nexposee_initialFontScale.y;
+               return 0;
        }
 
-       SUPER(Nexposee).draw(me);
-}
+       float Nexposee_mouseRelease(entity me, vector pos)
+       {
+               if (me.animationState == 2) return SUPER(Nexposee).mouseRelease(me, pos);
+               return 0;
+       }
 
-float Nexposee_mousePress(entity me, vector pos)
-{
-       if(me.animationState == 0)
+       float Nexposee_mouseDrag(entity me, vector pos)
        {
-               me.mouseFocusedChild = NULL;
-               Nexposee_mouseMove(me, pos);
-               if(me.mouseFocusedChild)
-               {
-                       m_play_click_sound(MENU_SOUND_OPEN);
-                       me.animationState = 1;
-                       SUPER(Nexposee).setFocus(me, NULL);
-               }
-               else
-                       me.close(me);
-               return 1;
+               if (me.animationState == 2) return SUPER(Nexposee).mouseDrag(me, pos);
+               return 0;
        }
-       else if(me.animationState == 2)
+
+       float Nexposee_mouseMove(entity me, vector pos)
        {
-               if (!(SUPER(Nexposee).mousePress(me, pos)))
+               entity e;
+               me.mousePosition = pos;
+               e = me.mouseFocusedChild;
+               me.mouseFocusedChild = me.itemFromPoint(me, pos);
+               if (me.animationState == 2) return SUPER(Nexposee).mouseMove(me, pos);
+               if (me.animationState == 0)
                {
-                       m_play_click_sound(MENU_SOUND_CLOSE);
-                       me.animationState = 3;
-                       SUPER(Nexposee).setFocus(me, NULL);
+                       if (me.mouseFocusedChild)
+                               if (me.mouseFocusedChild != e || me.mouseFocusedChild != me.selectedChild) me.selectedChild = me.mouseFocusedChild;
+                       return 1;
                }
-               return 1;
+               return 0;
        }
-       return 0;
-}
-
-float Nexposee_mouseRelease(entity me, vector pos)
-{
-       if(me.animationState == 2)
-               return SUPER(Nexposee).mouseRelease(me, pos);
-       return 0;
-}
-
-float Nexposee_mouseDrag(entity me, vector pos)
-{
-       if(me.animationState == 2)
-               return SUPER(Nexposee).mouseDrag(me, pos);
-       return 0;
-}
-
-float Nexposee_mouseMove(entity me, vector pos)
-{
-       entity e;
-       me.mousePosition = pos;
-       e = me.mouseFocusedChild;
-       me.mouseFocusedChild = me.itemFromPoint(me, pos);
-       if(me.animationState == 2)
-               return SUPER(Nexposee).mouseMove(me, pos);
-       if(me.animationState == 0)
+
+       float Nexposee_keyUp(entity me, float scan, float ascii, float shift)
        {
-               if(me.mouseFocusedChild)
-                       if(me.mouseFocusedChild != e || me.mouseFocusedChild != me.selectedChild)
-                               me.selectedChild = me.mouseFocusedChild;
-               return 1;
+               if (me.animationState == 2) return SUPER(Nexposee).keyUp(me, scan, ascii, shift);
+               return 0;
        }
-       return 0;
-}
-
-float Nexposee_keyUp(entity me, float scan, float ascii, float shift)
-{
-       if(me.animationState == 2)
-               return SUPER(Nexposee).keyUp(me, scan, ascii, shift);
-       return 0;
-}
-
-float Nexposee_keyDown(entity me, float scan, float ascii, float shift)
-{
-       float nexposeeKey = 0;
-       if(me.animationState == 2)
-               if(SUPER(Nexposee).keyDown(me, scan, ascii, shift))
-                       return 1;
-       if(scan == K_TAB)
+
+       float Nexposee_keyDown(entity me, float scan, float ascii, float shift)
        {
-               if(me.animationState == 0)
+               float nexposeeKey = 0;
+               if (me.animationState == 2)
+                       if (SUPER(Nexposee).keyDown(me, scan, ascii, shift)) return 1;
+               if (scan == K_TAB)
                {
-                       if(shift & S_SHIFT)
-                       {
-                               if(me.selectedChild)
-                                       me.selectedChild = me.selectedChild.prevSibling;
-                               if (!me.selectedChild)
-                                       me.selectedChild = me.lastChild;
-                       }
-                       else
+                       if (me.animationState == 0)
                        {
-                               if(me.selectedChild)
-                                       me.selectedChild = me.selectedChild.nextSibling;
-                               if (!me.selectedChild)
-                                       me.selectedChild = me.firstChild;
+                               if (shift & S_SHIFT)
+                               {
+                                       if (me.selectedChild) me.selectedChild = me.selectedChild.prevSibling;
+                                       if (!me.selectedChild) me.selectedChild = me.lastChild;
+                               }
+                               else
+                               {
+                                       if (me.selectedChild) me.selectedChild = me.selectedChild.nextSibling;
+                                       if (!me.selectedChild) me.selectedChild = me.firstChild;
+                               }
                        }
                }
-       }
-       switch(me.animationState)
-       {
-               default:
-               case 0:
-               case 3:
-                       nexposeeKey = ((scan == K_SPACE) || (scan == K_ENTER) || (scan == K_KP_ENTER));
-                       break;
-               case 1:
-               case 2:
-                       nexposeeKey = (scan == K_ESCAPE);
-                       break;
-       }
-       if(nexposeeKey)
-       {
-               switch(me.animationState)
+               switch (me.animationState)
                {
                        default:
                        case 0:
                        case 3:
-                               m_play_click_sound(MENU_SOUND_OPEN);
-                               me.animationState = 1;
+                               nexposeeKey = ((scan == K_SPACE) || (scan == K_ENTER) || (scan == K_KP_ENTER));
                                break;
                        case 1:
                        case 2:
-                               m_play_click_sound(MENU_SOUND_CLOSE);
-                               me.animationState = 3;
+                               nexposeeKey = (scan == K_ESCAPE);
                                break;
                }
-               if(me.focusedChild)
-                       me.selectedChild = me.focusedChild;
-               if (!me.selectedChild)
-                       me.animationState = 0;
-               SUPER(Nexposee).setFocus(me, NULL);
-               return 1;
+               if (nexposeeKey)
+               {
+                       switch (me.animationState)
+                       {
+                               default:
+                               case 0:
+                               case 3:
+                                       m_play_click_sound(MENU_SOUND_OPEN);
+                                       me.animationState = 1;
+                                       break;
+                               case 1:
+                               case 2:
+                                       m_play_click_sound(MENU_SOUND_CLOSE);
+                                       me.animationState = 3;
+                                       break;
+                       }
+                       if (me.focusedChild) me.selectedChild = me.focusedChild;
+                       if (!me.selectedChild) me.animationState = 0;
+                       SUPER(Nexposee).setFocus(me, NULL);
+                       return 1;
+               }
+               return 0;
+       }
+
+       void Nexposee_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
+       {
+               SUPER(Nexposee).addItem(me, other, theOrigin, theSize, theAlpha);
+               other.Nexposee_initialFontScale = other.Container_fontscale;
+               other.Nexposee_initialSize = other.Container_size;
+               other.Nexposee_initialOrigin = other.Container_origin;
+               other.Nexposee_initialAlpha = other.Container_alpha;
+               if (other.Nexposee_initialFontScale == '0 0 0') other.Nexposee_initialFontScale = '1 1 0';
+       }
+
+       void Nexposee_focusEnter(entity me)
+       {
+               if (me.animationState == 2) SUPER(Nexposee).setFocus(me, me.selectedChild);
+       }
+
+       void Nexposee_pullNexposee(entity me, entity other, vector theAlign)
+       {
+               other.Nexposee_align = theAlign;
        }
-       return 0;
-}
-
-void Nexposee_addItem(entity me, entity other, vector theOrigin, vector theSize, float theAlpha)
-{
-       SUPER(Nexposee).addItem(me, other, theOrigin, theSize, theAlpha);
-       other.Nexposee_initialFontScale = other.Container_fontscale;
-       other.Nexposee_initialSize = other.Container_size;
-       other.Nexposee_initialOrigin = other.Container_origin;
-       other.Nexposee_initialAlpha = other.Container_alpha;
-       if(other.Nexposee_initialFontScale == '0 0 0')
-               other.Nexposee_initialFontScale = '1 1 0';
-}
-
-void Nexposee_focusEnter(entity me)
-{
-       if(me.animationState == 2)
-               SUPER(Nexposee).setFocus(me, me.selectedChild);
-}
-
-void Nexposee_pullNexposee(entity me, entity other, vector theAlign)
-{
-       other.Nexposee_align = theAlign;
-}
 #endif
index 4dfadd2d569ce47132ee2f833460b439e59a8da9..dac17b1415643f8c522cd100a668ad719f78c5aa 100644 (file)
@@ -1,39 +1,37 @@
 #ifndef ITEM_RADIOBUTTON_H
-#define ITEM_RADIOBUTTON_H
-#include "checkbox.qc"
-void RadioButton_Click(entity me, entity other);
-CLASS(RadioButton, CheckBox)
-       METHOD(RadioButton, configureRadioButton, void(entity, string, float, string, float, float));
-       ATTRIB(RadioButton, checked, float, 0)
-       ATTRIB(RadioButton, group, float, 0)
-       ATTRIB(RadioButton, allowDeselect, float, 0)
-       ATTRIB(RadioButton, onClick, void(entity, entity), RadioButton_Click)
-ENDCLASS(RadioButton)
+       #define ITEM_RADIOBUTTON_H
+       #include "checkbox.qc"
+       void RadioButton_Click(entity me, entity other);
+       CLASS(RadioButton, CheckBox)
+               METHOD(RadioButton, configureRadioButton, void(entity, string, float, string, float, float));
+               ATTRIB(RadioButton, checked, float, 0)
+               ATTRIB(RadioButton, group, float, 0)
+               ATTRIB(RadioButton, allowDeselect, float, 0)
+               ATTRIB(RadioButton, onClick, void(entity, entity), RadioButton_Click)
+       ENDCLASS(RadioButton)
 #endif
 
 #ifdef IMPLEMENTATION
-void RadioButton_configureRadioButton(entity me, string txt, float sz, string gfx, float theGroup, float doAllowDeselect)
-{
-       me.configureCheckBox(me, txt, sz, gfx);
-       me.align = 0;
-       me.group = theGroup;
-       me.allowDeselect = doAllowDeselect;
-}
-void RadioButton_Click(entity me, entity other)
-{
-       if(me.checked)
+       void RadioButton_configureRadioButton(entity me, string txt, float sz, string gfx, float theGroup, float doAllowDeselect)
        {
-               if(me.allowDeselect)
-                       me.setChecked(me, 0);
+               me.configureCheckBox(me, txt, sz, gfx);
+               me.align = 0;
+               me.group = theGroup;
+               me.allowDeselect = doAllowDeselect;
        }
-       else
+       void RadioButton_Click(entity me, entity other)
        {
-               entity e;
-               for(e = me.parent.firstChild; e; e = e.nextSibling)
-                       if(e != me)
-                               if(e.group == me.group)
-                                       e.setChecked(e, 0);
-               me.setChecked(me, 1);
+               if (me.checked)
+               {
+                       if (me.allowDeselect) me.setChecked(me, 0);
+               }
+               else
+               {
+                       entity e;
+                       for (e = me.parent.firstChild; e; e = e.nextSibling)
+                               if (e != me)
+                                       if (e.group == me.group) e.setChecked(e, 0);
+                       me.setChecked(me, 1);
+               }
        }
-}
 #endif
index 3bde6565a6b6f16d1b436336479d5e32a091d510..f065e34b18071f8173c567469ab6a83586782f8c 100644 (file)
 // Note:
 //   to use this, you FIRST call configureSliderVisuals, then configureSliderValues
 #ifndef ITEM_SLIDER_H
-#define ITEM_SLIDER_H
-#include "label.qc"
-CLASS(Slider, Label)
-       METHOD(Slider, resizeNotify, void(entity, vector, vector, vector, vector));
-       METHOD(Slider, configureSliderVisuals, void(entity, float, float, float, string));
-       METHOD(Slider, configureSliderValues, void(entity, float, float, float, float, float, float));
-       METHOD(Slider, draw, void(entity));
-       METHOD(Slider, keyDown, float(entity, float, float, float));
-       METHOD(Slider, keyUp, float(entity, float, float, float));
-       METHOD(Slider, mousePress, float(entity, vector));
-       METHOD(Slider, mouseDrag, float(entity, vector));
-       METHOD(Slider, mouseRelease, float(entity, vector));
-       METHOD(Slider, valueToText, string(entity, float));
-       METHOD(Slider, toString, string(entity));
-       METHOD(Slider, setValue_allowAnim, void(entity, float, bool));
-       METHOD(Slider, setValue_noAnim, void(entity, float));
-       METHOD(Slider, setValue, void(entity, float));
-       METHOD(Slider, setSliderValue, void(entity, float));
-       METHOD(Slider, showNotify, void(entity));
-       ATTRIB(Slider, src, string, string_null)
-       ATTRIB(Slider, focusable, float, 1)
-       ATTRIB(Slider, allowFocusSound, float, 1)
-       ATTRIB(Slider, value, float, 0)
-       ATTRIB(Slider, animated, float, 1)
-       ATTRIB(Slider, sliderValue, float, 0)
-       ATTRIB(Slider, sliderAnim, entity, NULL)
-       ATTRIB(Slider, valueMin, float, 0)
-       ATTRIB(Slider, valueMax, float, 0)
-       ATTRIB(Slider, valueStep, float, 0)
-       ATTRIB(Slider, valueDigits, float, 0)
-       ATTRIB(Slider, valueKeyStep, float, 0)
-       ATTRIB(Slider, valuePageStep, float, 0)
-       ATTRIB(Slider, valueDisplayMultiplier, float, 1.0)
-       ATTRIB(Slider, textSpace, float, 0)
-       ATTRIB(Slider, controlWidth, float, 0)
-       ATTRIB(Slider, pressed, float, 0)
-       ATTRIB(Slider, pressOffset, float, 0)
-       ATTRIB(Slider, previousValue, float, 0)
-       ATTRIB(Slider, tolerance, vector, '0 0 0')
-       ATTRIB(Slider, disabled, float, 0)
-       ATTRIB(Slider, color, vector, '1 1 1')
-       ATTRIB(Slider, color2, vector, '1 1 1')
-       ATTRIB(Slider, colorD, vector, '1 1 1')
-       ATTRIB(Slider, colorC, vector, '1 1 1')
-       ATTRIB(Slider, colorF, vector, '1 1 1')
-       ATTRIB(Slider, disabledAlpha, float, 0.3)
-ENDCLASS(Slider)
+       #define ITEM_SLIDER_H
+       #include "label.qc"
+       CLASS(Slider, Label)
+               METHOD(Slider, resizeNotify, void(entity, vector, vector, vector, vector));
+               METHOD(Slider, configureSliderVisuals, void(entity, float, float, float, string));
+               METHOD(Slider, configureSliderValues, void(entity, float, float, float, float, float, float));
+               METHOD(Slider, draw, void(entity));
+               METHOD(Slider, keyDown, float(entity, float, float, float));
+               METHOD(Slider, keyUp, float(entity, float, float, float));
+               METHOD(Slider, mousePress, float(entity, vector));
+               METHOD(Slider, mouseDrag, float(entity, vector));
+               METHOD(Slider, mouseRelease, float(entity, vector));
+               METHOD(Slider, valueToText, string(entity, float));
+               METHOD(Slider, toString, string(entity));
+               METHOD(Slider, setValue_allowAnim, void(entity, float, bool));
+               METHOD(Slider, setValue_noAnim, void(entity, float));
+               METHOD(Slider, setValue, void(entity, float));
+               METHOD(Slider, setSliderValue, void(entity, float));
+               METHOD(Slider, showNotify, void(entity));
+               ATTRIB(Slider, src, string, string_null)
+               ATTRIB(Slider, focusable, float, 1)
+               ATTRIB(Slider, allowFocusSound, float, 1)
+               ATTRIB(Slider, value, float, 0)
+               ATTRIB(Slider, animated, float, 1)
+               ATTRIB(Slider, sliderValue, float, 0)
+               ATTRIB(Slider, sliderAnim, entity, NULL)
+               ATTRIB(Slider, valueMin, float, 0)
+               ATTRIB(Slider, valueMax, float, 0)
+               ATTRIB(Slider, valueStep, float, 0)
+               ATTRIB(Slider, valueDigits, float, 0)
+               ATTRIB(Slider, valueKeyStep, float, 0)
+               ATTRIB(Slider, valuePageStep, float, 0)
+               ATTRIB(Slider, valueDisplayMultiplier, float, 1.0)
+               ATTRIB(Slider, textSpace, float, 0)
+               ATTRIB(Slider, controlWidth, float, 0)
+               ATTRIB(Slider, pressed, float, 0)
+               ATTRIB(Slider, pressOffset, float, 0)
+               ATTRIB(Slider, previousValue, float, 0)
+               ATTRIB(Slider, tolerance, vector, '0 0 0')
+               ATTRIB(Slider, disabled, float, 0)
+               ATTRIB(Slider, color, vector, '1 1 1')
+               ATTRIB(Slider, color2, vector, '1 1 1')
+               ATTRIB(Slider, colorD, vector, '1 1 1')
+               ATTRIB(Slider, colorC, vector, '1 1 1')
+               ATTRIB(Slider, colorF, vector, '1 1 1')
+               ATTRIB(Slider, disabledAlpha, float, 0.3)
+       ENDCLASS(Slider)
 #endif
 
 #ifdef IMPLEMENTATION
-void Slider_setValue_allowAnim(entity me, float val, bool allowAnim)
-{
-       if(allowAnim && me.animated) {
-               float t = 0.5;
-               if(!me.sliderAnim)
-                       me.sliderAnim = makeHostedEasing(me, Slider_setSliderValue, easingQuadOut, t, me.sliderValue, val);
+       void Slider_setValue_allowAnim(entity me, float val, bool allowAnim)
+       {
+               if (allowAnim && me.animated)
+               {
+                       float t = 0.5;
+                       if (!me.sliderAnim) me.sliderAnim = makeHostedEasing(me, Slider_setSliderValue, easingQuadOut, t, me.sliderValue, val);
+                       else me.sliderAnim.update(me.sliderAnim, t, me.sliderValue, val);
+               }
                else
-                       me.sliderAnim.update(me.sliderAnim, t, me.sliderValue, val);
-       } else {
-               me.setSliderValue(me, val);
+               {
+                       me.setSliderValue(me, val);
+               }
+               me.value = val;
        }
-       me.value = val;
-}
-void Slider_setValue_noAnim(entity me, float val)
-{
-       Slider_setValue_allowAnim(me, val, false);
-}
-void Slider_setValue(entity me, float val)
-{
-       Slider_setValue_allowAnim(me, val, true);
-}
-void Slider_setSliderValue(entity me, float val)
-{
-       me.sliderValue = val;
-}
-string Slider_toString(entity me)
-{
-       return sprintf("%d (%s)", me.value, me.valueToText(me, me.value));
-}
-void Slider_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
-{
-       SUPER(Slider).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
-       me.controlWidth = absSize.x == 0 ? 0 : (absSize.y / absSize.x);
-}
-string Slider_valueToText(entity me, float val)
-{
-       if(almost_in_bounds(me.valueMin, val, me.valueMax))
-               return ftos_decimals(val * me.valueDisplayMultiplier, me.valueDigits);
-       return "";
-}
-void Slider_configureSliderVisuals(entity me, float sz, float theAlign, float theTextSpace, string gfx)
-{
-       SUPER(Slider).configureLabel(me, string_null, sz, theAlign);
-       me.textSpace = theTextSpace;
-       me.keepspaceLeft = (theTextSpace == 0) ? 0 : (1 - theTextSpace);
-       me.src = gfx;
-}
-void Slider_configureSliderValues(entity me, float theValueMin, float theValue, float theValueMax, float theValueStep, float theValueKeyStep, float theValuePageStep)
-{
-       me.value = theValue;
-       me.sliderValue = theValue;
-       me.valueStep = theValueStep;
-       me.valueMin = theValueMin;
-       me.valueMax = theValueMax;
-       me.valueKeyStep = theValueKeyStep;
-       me.valuePageStep = theValuePageStep;
-       me.valueDigits = 3;
-       if(fabs(floor(me.valueStep * 100 + 0.5) - (me.valueStep * 100)) < 0.01) // about a whole number of 100ths
-               me.valueDigits = 2;
-       if(fabs(floor(me.valueStep * 10 + 0.5) - (me.valueStep * 10)) < 0.01) // about a whole number of 10ths
-               me.valueDigits = 1;
-       if(fabs(floor(me.valueStep * 1 + 0.5) - (me.valueStep * 1)) < 0.01) // about a whole number
-               me.valueDigits = 0;
-}
-float Slider_keyDown(entity me, float key, float ascii, float shift)
-{
-       float inRange;
-       if(me.disabled)
-               return 0;
-       inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
-       if(key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELDOWN)
+       void Slider_setValue_noAnim(entity me, float val)
        {
-               if(inRange)
-                       me.setValue(me, median(me.valueMin, me.value - me.valueKeyStep, me.valueMax));
-               else
-                       me.setValue(me, me.valueMax);
-               return 1;
+               Slider_setValue_allowAnim(me, val, false);
        }
-       if(key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MWHEELUP)
+       void Slider_setValue(entity me, float val)
        {
-               if(inRange)
-                       me.setValue(me, median(me.valueMin, me.value + me.valueKeyStep, me.valueMax));
-               else
-                       me.setValue(me, me.valueMin);
-               return 1;
+               Slider_setValue_allowAnim(me, val, true);
        }
-       if(key == K_PGDN || key == K_KP_PGDN)
+       void Slider_setSliderValue(entity me, float val)
        {
-               if(inRange)
-                       me.setValue(me, median(me.valueMin, me.value - me.valuePageStep, me.valueMax));
-               else
-                       me.setValue(me, me.valueMax);
-               return 1;
+               me.sliderValue = val;
        }
-       if(key == K_PGUP || key == K_KP_PGUP)
+       string Slider_toString(entity me)
        {
-               if(inRange)
-                       me.setValue(me, median(me.valueMin, me.value + me.valuePageStep, me.valueMax));
-               else
-                       me.setValue(me, me.valueMin);
-               return 1;
+               return sprintf("%d (%s)", me.value, me.valueToText(me, me.value));
        }
-       if(key == K_HOME || key == K_KP_HOME)
+       void Slider_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
        {
-               me.setValue(me, me.valueMin);
-               return 1;
+               SUPER(Slider).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
+               me.controlWidth = absSize.x == 0 ? 0 : (absSize.y / absSize.x);
        }
-       if(key == K_END || key == K_KP_END)
+       string Slider_valueToText(entity me, float val)
        {
-               me.setValue(me, me.valueMax);
-               return 1;
+               if (almost_in_bounds(me.valueMin, val, me.valueMax)) return ftos_decimals(val * me.valueDisplayMultiplier, me.valueDigits);
+               return "";
        }
-       // TODO more keys (NOTE also add them to Slider_keyUp)
-       return 0;
-}
-float Slider_keyUp(entity me, float key, float ascii, float shift)
-{
-       if(me.disabled)
-               return 0;
-       switch(key)
+       void Slider_configureSliderVisuals(entity me, float sz, float theAlign, float theTextSpace, string gfx)
        {
-               case K_LEFTARROW:
-               case K_KP_LEFTARROW:
-               case K_RIGHTARROW:
-               case K_KP_RIGHTARROW:
-               case K_PGUP:
-               case K_KP_PGUP:
-               case K_PGDN:
-               case K_KP_PGDN:
-               case K_HOME:
-               case K_KP_HOME:
-               case K_END:
-               case K_KP_END:
-                       m_play_click_sound(MENU_SOUND_SLIDE);
+               SUPER(Slider).configureLabel(me, string_null, sz, theAlign);
+               me.textSpace = theTextSpace;
+               me.keepspaceLeft = (theTextSpace == 0) ? 0 : (1 - theTextSpace);
+               me.src = gfx;
        }
-       return 0;
-}
-float Slider_mouseDrag(entity me, vector pos)
-{
-       float hit;
-       float v;
-       if(me.disabled)
-               return 0;
-
-       if(me.pressed)
+       void Slider_configureSliderValues(entity me, float theValueMin, float theValue, float theValueMax, float theValueStep, float theValueKeyStep, float theValuePageStep)
        {
-               hit = 1;
-               if(pos.x < 0 - me.tolerance.x) hit = 0;
-               if(pos.y < 0 - me.tolerance.y) hit = 0;
-               if(pos.x >= 1 - me.textSpace + me.tolerance.x) hit = 0;
-               if(pos.y >= 1 + me.tolerance.y) hit = 0;
-               if(hit)
+               me.value = theValue;
+               me.sliderValue = theValue;
+               me.valueStep = theValueStep;
+               me.valueMin = theValueMin;
+               me.valueMax = theValueMax;
+               me.valueKeyStep = theValueKeyStep;
+               me.valuePageStep = theValuePageStep;
+               me.valueDigits = 3;
+               if (fabs(floor(me.valueStep * 100 + 0.5) - (me.valueStep * 100)) < 0.01) // about a whole number of 100ths
+                       me.valueDigits = 2;
+               if (fabs(floor(me.valueStep * 10 + 0.5) - (me.valueStep * 10)) < 0.01)   // about a whole number of 10ths
+                       me.valueDigits = 1;
+               if (fabs(floor(me.valueStep * 1 + 0.5) - (me.valueStep * 1)) < 0.01)     // about a whole number
+                       me.valueDigits = 0;
+       }
+       float Slider_keyDown(entity me, float key, float ascii, float shift)
+       {
+               float inRange;
+               if (me.disabled) return 0;
+               inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
+               if (key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELDOWN)
                {
-                       // handle dragging
-                       me.pressed = 2;
-
-                       v = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
-                       if(me.valueStep)
-                               v = floor(0.5 + v / me.valueStep) * me.valueStep;
-                       me.setValue_noAnim(me, v);
+                       if (inRange) me.setValue(me, median(me.valueMin, me.value - me.valueKeyStep, me.valueMax));
+                       else me.setValue(me, me.valueMax);
+                       return 1;
                }
-               else
-                       me.setValue(me, me.previousValue);
-       }
-
-       return 1;
-}
-float Slider_mousePress(entity me, vector pos)
-{
-       float controlCenter;
-       if(me.disabled)
+               if (key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MWHEELUP)
+               {
+                       if (inRange) me.setValue(me, median(me.valueMin, me.value + me.valueKeyStep, me.valueMax));
+                       else me.setValue(me, me.valueMin);
+                       return 1;
+               }
+               if (key == K_PGDN || key == K_KP_PGDN)
+               {
+                       if (inRange) me.setValue(me, median(me.valueMin, me.value - me.valuePageStep, me.valueMax));
+                       else me.setValue(me, me.valueMax);
+                       return 1;
+               }
+               if (key == K_PGUP || key == K_KP_PGUP)
+               {
+                       if (inRange) me.setValue(me, median(me.valueMin, me.value + me.valuePageStep, me.valueMax));
+                       else me.setValue(me, me.valueMin);
+                       return 1;
+               }
+               if (key == K_HOME || key == K_KP_HOME)
+               {
+                       me.setValue(me, me.valueMin);
+                       return 1;
+               }
+               if (key == K_END || key == K_KP_END)
+               {
+                       me.setValue(me, me.valueMax);
+                       return 1;
+               }
+               // TODO more keys (NOTE also add them to Slider_keyUp)
                return 0;
-       if(pos.x < 0) return 0;
-       if(pos.y < 0) return 0;
-       if(pos.x >= 1 - me.textSpace) return 0;
-       if(pos.y >= 1) return 0;
-       controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
-       if(fabs(pos.x - controlCenter) <= 0.5 * me.controlWidth)
-       {
-               me.pressed = 1;
-               me.pressOffset = pos.x - controlCenter;
-               me.previousValue = me.value;
-               //me.mouseDrag(me, pos);
        }
-       else
+       float Slider_keyUp(entity me, float key, float ascii, float shift)
        {
-               float clickValue, pageValue, inRange;
-               clickValue = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
-               inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
-               if(pos.x < controlCenter)
+               if (me.disabled) return 0;
+               switch (key)
                {
-                       pageValue = me.value - me.valuePageStep;
-                       if(me.valueStep)
-                               clickValue = floor(clickValue / me.valueStep) * me.valueStep;
-                       pageValue = max(pageValue, clickValue);
-                       if(inRange)
-                               me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
-                       else
-                               me.setValue(me, me.valueMax);
+                       case K_LEFTARROW:
+                       case K_KP_LEFTARROW:
+                       case K_RIGHTARROW:
+                       case K_KP_RIGHTARROW:
+                       case K_PGUP:
+                       case K_KP_PGUP:
+                       case K_PGDN:
+                       case K_KP_PGDN:
+                       case K_HOME:
+                       case K_KP_HOME:
+                       case K_END:
+                       case K_KP_END:
+                               m_play_click_sound(MENU_SOUND_SLIDE);
                }
-               else
+               return 0;
+       }
+       float Slider_mouseDrag(entity me, vector pos)
+       {
+               float hit;
+               float v;
+               if (me.disabled) return 0;
+
+               if (me.pressed)
                {
-                       pageValue = me.value + me.valuePageStep;
-                       if(me.valueStep)
-                               clickValue = ceil(clickValue / me.valueStep) * me.valueStep;
-                       pageValue = min(pageValue, clickValue);
-                       if(inRange)
-                               me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
+                       hit = 1;
+                       if (pos.x < 0 - me.tolerance.x) hit = 0;
+                       if (pos.y < 0 - me.tolerance.y) hit = 0;
+                       if (pos.x >= 1 - me.textSpace + me.tolerance.x) hit = 0;
+                       if (pos.y >= 1 + me.tolerance.y) hit = 0;
+                       if (hit)
+                       {
+                               // handle dragging
+                               me.pressed = 2;
+
+                               v = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
+                               if (me.valueStep) v = floor(0.5 + v / me.valueStep) * me.valueStep;
+                               me.setValue_noAnim(me, v);
+                       }
                        else
-                               me.setValue(me, me.valueMax);
+                       {
+                               me.setValue(me, me.previousValue);
+                       }
                }
-               if(pageValue == clickValue)
+
+               return 1;
+       }
+       float Slider_mousePress(entity me, vector pos)
+       {
+               float controlCenter;
+               if (me.disabled) return 0;
+               if (pos.x < 0) return 0;
+               if (pos.y < 0) return 0;
+               if (pos.x >= 1 - me.textSpace) return 0;
+               if (pos.y >= 1) return 0;
+               controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
+               if (fabs(pos.x - controlCenter) <= 0.5 * me.controlWidth)
                {
-                       controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
                        me.pressed = 1;
                        me.pressOffset = pos.x - controlCenter;
                        me.previousValue = me.value;
-                       //me.mouseDrag(me, pos);
+                       // me.mouseDrag(me, pos);
                }
+               else
+               {
+                       float clickValue, pageValue, inRange;
+                       clickValue = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
+                       inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
+                       if (pos.x < controlCenter)
+                       {
+                               pageValue = me.value - me.valuePageStep;
+                               if (me.valueStep) clickValue = floor(clickValue / me.valueStep) * me.valueStep;
+                               pageValue = max(pageValue, clickValue);
+                               if (inRange) me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
+                               else me.setValue(me, me.valueMax);
+                       }
+                       else
+                       {
+                               pageValue = me.value + me.valuePageStep;
+                               if (me.valueStep) clickValue = ceil(clickValue / me.valueStep) * me.valueStep;
+                               pageValue = min(pageValue, clickValue);
+                               if (inRange) me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
+                               else me.setValue(me, me.valueMax);
+                       }
+                       if (pageValue == clickValue)
+                       {
+                               controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
+                               me.pressed = 1;
+                               me.pressOffset = pos.x - controlCenter;
+                               me.previousValue = me.value;
+                               // me.mouseDrag(me, pos);
+                       }
+               }
+               return 1;
        }
-       return 1;
-}
-float Slider_mouseRelease(entity me, vector pos)
-{
-       me.pressed = 0;
-       if(me.disabled)
-               return 0;
-       m_play_click_sound(MENU_SOUND_SLIDE);
-       return 1;
-}
-void Slider_showNotify(entity me)
-{
-       me.focusable = !me.disabled;
-}
-void Slider_draw(entity me)
-{
-       float controlLeft;
-       float save;
-       me.focusable = !me.disabled;
-       save = draw_alpha;
-       if(me.disabled)
-               draw_alpha *= me.disabledAlpha;
-       draw_ButtonPicture('0 0 0', strcat(me.src, "_s"), eX * (1 - me.textSpace) + eY, me.color2, 1);
-       if(almost_in_bounds(me.valueMin, me.sliderValue, me.valueMax))
+       float Slider_mouseRelease(entity me, vector pos)
        {
-               controlLeft = (me.sliderValue - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth);
-               if(me.disabled)
-                       draw_Picture(eX * controlLeft, strcat(me.src, "_d"), eX * me.controlWidth + eY, me.colorD, 1);
-               else if(me.pressed)
-                       draw_Picture(eX * controlLeft, strcat(me.src, "_c"), eX * me.controlWidth + eY, me.colorC, 1);
-               else if(me.focused)
-                       draw_Picture(eX * controlLeft, strcat(me.src, "_f"), eX * me.controlWidth + eY, me.colorF, 1);
-               else
-                       draw_Picture(eX * controlLeft, strcat(me.src, "_n"), eX * me.controlWidth + eY, me.color, 1);
+               me.pressed = 0;
+               if (me.disabled) return 0;
+               m_play_click_sound(MENU_SOUND_SLIDE);
+               return 1;
        }
-
-       if(me.sliderAnim)
-       if(me.sliderAnim.isFinished(me.sliderAnim))
+       void Slider_showNotify(entity me)
        {
-               anim.removeObjAnim(anim, me);
-               me.sliderAnim = NULL;
+               me.focusable = !me.disabled;
        }
+       void Slider_draw(entity me)
+       {
+               float controlLeft;
+               float save;
+               me.focusable = !me.disabled;
+               save = draw_alpha;
+               if (me.disabled) draw_alpha *= me.disabledAlpha;
+               draw_ButtonPicture('0 0 0', strcat(me.src, "_s"), eX * (1 - me.textSpace) + eY, me.color2, 1);
+               if (almost_in_bounds(me.valueMin, me.sliderValue, me.valueMax))
+               {
+                       controlLeft = (me.sliderValue - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth);
+                       if (me.disabled) draw_Picture(eX * controlLeft, strcat(me.src, "_d"), eX * me.controlWidth + eY, me.colorD, 1);
+                       else if (me.pressed) draw_Picture(eX * controlLeft, strcat(me.src, "_c"), eX * me.controlWidth + eY, me.colorC, 1);
+                       else if (me.focused) draw_Picture(eX * controlLeft, strcat(me.src, "_f"), eX * me.controlWidth + eY, me.colorF, 1);
+                       else draw_Picture(eX * controlLeft, strcat(me.src, "_n"), eX * me.controlWidth + eY, me.color, 1);
+               }
 
-       me.setText(me, me.valueToText(me, me.value));
-       draw_alpha = save;
-       SUPER(Slider).draw(me);
-       me.text = string_null; // TEMPSTRING!
-}
+               if (me.sliderAnim)
+                       if (me.sliderAnim.isFinished(me.sliderAnim))
+                       {
+                               anim.removeObjAnim(anim, me);
+                               me.sliderAnim = NULL;
+                       }
+
+               me.setText(me, me.valueToText(me, me.value));
+               draw_alpha = save;
+               SUPER(Slider).draw(me);
+               me.text = string_null;  // TEMPSTRING!
+       }
 #endif
index fbbf77668750c26a27b5e1b1e018e0805d0cb822..7564f02cf8a783fed8e7fb8f1f145837328b54bb 100644 (file)
@@ -1,29 +1,29 @@
 #ifndef ITEM_TAB_H
-#define ITEM_TAB_H
-#include "dialog.qc"
-CLASS(Tab, Dialog)
-       ATTRIB(Tab, isTabRoot, float, 0)
-       ATTRIB(Tab, closable, float, 0)
-       ATTRIB(Tab, rootDialog, float, 0)
-       ATTRIB(Tab, title, string, string_null)
-       ATTRIB(Tab, titleFontSize, float, 0) // pixels
+       #define ITEM_TAB_H
+       #include "dialog.qc"
+       CLASS(Tab, Dialog)
+               ATTRIB(Tab, isTabRoot, float, 0)
+               ATTRIB(Tab, closable, float, 0)
+               ATTRIB(Tab, rootDialog, float, 0)
+               ATTRIB(Tab, title, string, string_null)
+               ATTRIB(Tab, titleFontSize, float, 0)  // pixels
 
-       // still to be customized
-       ATTRIB(Tab, intendedWidth, float, 0)
-       ATTRIB(Tab, rows, float, 3)
-       ATTRIB(Tab, columns, float, 2)
+               // still to be customized
+               ATTRIB(Tab, intendedWidth, float, 0)
+               ATTRIB(Tab, rows, float, 3)
+               ATTRIB(Tab, columns, float, 2)
 
-       ATTRIB(Tab, marginTop, float, 0) // pixels
-       ATTRIB(Tab, marginBottom, float, 0) // pixels
-       ATTRIB(Tab, marginLeft, float, 0) // pixels
-       ATTRIB(Tab, marginRight, float, 0) // pixels
-       ATTRIB(Tab, columnSpacing, float, 0) // pixels
-       ATTRIB(Tab, rowSpacing, float, 0) // pixels
-       ATTRIB(Tab, rowHeight, float, 0) // pixels
-       ATTRIB(Tab, titleHeight, float, 0) // pixels
+               ATTRIB(Tab, marginTop, float, 0)     // pixels
+               ATTRIB(Tab, marginBottom, float, 0)  // pixels
+               ATTRIB(Tab, marginLeft, float, 0)    // pixels
+               ATTRIB(Tab, marginRight, float, 0)   // pixels
+               ATTRIB(Tab, columnSpacing, float, 0) // pixels
+               ATTRIB(Tab, rowSpacing, float, 0)    // pixels
+               ATTRIB(Tab, rowHeight, float, 0)     // pixels
+               ATTRIB(Tab, titleHeight, float, 0)   // pixels
 
-       ATTRIB(Tab, backgroundImage, string, string_null)
-ENDCLASS(Tab)
+               ATTRIB(Tab, backgroundImage, string, string_null)
+       ENDCLASS(Tab)
 #endif
 
 #ifdef IMPLEMENTATION
index 30b80c196d96884117def79c2c55496e65f34598..4c23ff9a095b65c766bb137d0736a9042f6dc640 100644 (file)
@@ -1,90 +1,86 @@
 // Note:
 //   to use this, you FIRST call configureSliderVisuals, then multiple times addValue, then configureTextSlider
 #ifndef ITEM_TEXTSLIDER_H
-#define ITEM_TEXTSLIDER_H
-#include "slider.qc"
-CLASS(TextSlider, Slider)
-       METHOD(TextSlider, valueToText, string(entity, float));
-       METHOD(TextSlider, valueToIdentifier, string(entity, float));
-       METHOD(TextSlider, setValueFromIdentifier_allowAnim, void(entity, string, bool));
-       METHOD(TextSlider, setValueFromIdentifier_noAnim, void(entity, string));
-       METHOD(TextSlider, setValueFromIdentifier, void(entity, string));
-       METHOD(TextSlider, getIdentifier, string(entity));
-       METHOD(TextSlider, clearValues, void(entity));
-       METHOD(TextSlider, addValue, void(entity, string, string));
-       METHOD(TextSlider, insertValue, void(entity, float, string, string));
-       METHOD(TextSlider, configureTextSliderValues, void(entity, string));
-       ATTRIBARRAY(TextSlider, valueStrings, string, 256)
-       ATTRIBARRAY(TextSlider, valueIdentifiers, string, 256)
-       ATTRIB(TextSlider, nValues, int, 0)
-ENDCLASS(TextSlider)
+       #define ITEM_TEXTSLIDER_H
+       #include "slider.qc"
+       CLASS(TextSlider, Slider)
+               METHOD(TextSlider, valueToText, string(entity, float));
+               METHOD(TextSlider, valueToIdentifier, string(entity, float));
+               METHOD(TextSlider, setValueFromIdentifier_allowAnim, void(entity, string, bool));
+               METHOD(TextSlider, setValueFromIdentifier_noAnim, void(entity, string));
+               METHOD(TextSlider, setValueFromIdentifier, void(entity, string));
+               METHOD(TextSlider, getIdentifier, string(entity));
+               METHOD(TextSlider, clearValues, void(entity));
+               METHOD(TextSlider, addValue, void(entity, string, string));
+               METHOD(TextSlider, insertValue, void(entity, float, string, string));
+               METHOD(TextSlider, configureTextSliderValues, void(entity, string));
+               ATTRIBARRAY(TextSlider, valueStrings, string, 256)
+               ATTRIBARRAY(TextSlider, valueIdentifiers, string, 256)
+               ATTRIB(TextSlider, nValues, int, 0)
+       ENDCLASS(TextSlider)
 #endif
 
 #ifdef IMPLEMENTATION
-string TextSlider_valueToIdentifier(entity me, int val)
-{
-       if(val >= me.nValues)
-               return "custom";
-       if(val < 0)
-               return "custom";
-       return me.(valueIdentifiers[val]);
-}
-string TextSlider_valueToText(entity me, int val)
-{
-       if(val >= me.nValues)
-               return _("Custom");
-       if(val < 0)
-               return _("Custom");
-       return me.(valueStrings[val]);
-}
-void TextSlider_setValueFromIdentifier_allowAnim(entity me, string id, bool allowAnim)
-{
-       int i;
-       for(i = 0; i < me.nValues; ++i)
-               if(me.valueToIdentifier(me, i) == id)
+       string TextSlider_valueToIdentifier(entity me, int val)
+       {
+               if (val >= me.nValues) return "custom";
+               if (val < 0) return "custom";
+               return me.(valueIdentifiers[val]);
+       }
+       string TextSlider_valueToText(entity me, int val)
+       {
+               if (val >= me.nValues) return _("Custom");
+               if (val < 0) return _("Custom");
+               return me.(valueStrings[val]);
+       }
+       void TextSlider_setValueFromIdentifier_allowAnim(entity me, string id, bool allowAnim)
+       {
+               int i;
+               for (i = 0; i < me.nValues; ++i)
+                       if (me.valueToIdentifier(me, i) == id)
+                       {
+                               SUPER(TextSlider).setValue_allowAnim(me, i, allowAnim);
+                               return;
+                       }
+               SUPER(TextSlider).setValue_allowAnim(me, -1, allowAnim);
+       }
+       void TextSlider_setValueFromIdentifier_noAnim(entity me, string id)
+       {
+               TextSlider_setValueFromIdentifier_allowAnim(me, id, false);
+       }
+       void TextSlider_setValueFromIdentifier(entity me, string id)
+       {
+               TextSlider_setValueFromIdentifier_allowAnim(me, id, true);
+       }
+       string TextSlider_getIdentifier(entity me)
+       {
+               return me.valueToIdentifier(me, me.value);
+       }
+       void TextSlider_clearValues(entity me)
+       {
+               me.nValues = 0;
+       }
+       void TextSlider_addValue(entity me, string theString, string theIdentifier)
+       {
+               me.(valueStrings[me.nValues]) = theString;
+               me.(valueIdentifiers[me.nValues]) = theIdentifier;
+               me.nValues += 1;
+       }
+       void TextSlider_insertValue(entity me, int pos, string theString, string theIdentifier)
+       {
+               int i;
+               for (i = me.nValues; i > pos; --i)
                {
-                       SUPER(TextSlider).setValue_allowAnim(me, i, allowAnim);
-                       return;
+                       me.(valueStrings[i]) = me.(valueStrings[i - 1]);
+                       me.(valueIdentifiers[i]) = me.(valueIdentifiers[i - 1]);
                }
-       SUPER(TextSlider).setValue_allowAnim(me, -1, allowAnim);
-}
-void TextSlider_setValueFromIdentifier_noAnim(entity me, string id)
-{
-       TextSlider_setValueFromIdentifier_allowAnim(me, id, false);
-}
-void TextSlider_setValueFromIdentifier(entity me, string id)
-{
-       TextSlider_setValueFromIdentifier_allowAnim(me, id, true);
-}
-string TextSlider_getIdentifier(entity me)
-{
-       return me.valueToIdentifier(me, me.value);
-}
-void TextSlider_clearValues(entity me)
-{
-       me.nValues = 0;
-}
-void TextSlider_addValue(entity me, string theString, string theIdentifier)
-{
-       me.(valueStrings[me.nValues]) = theString;
-       me.(valueIdentifiers[me.nValues]) = theIdentifier;
-       me.nValues += 1;
-}
-void TextSlider_insertValue(entity me, int pos, string theString, string theIdentifier)
-{
-       int i;
-       for (i = me.nValues; i > pos; --i)
+               me.(valueStrings[pos]) = theString;
+               me.(valueIdentifiers[pos]) = theIdentifier;
+               me.nValues += 1;
+       }
+       void TextSlider_configureTextSliderValues(entity me, string theDefault)
        {
-               me.(valueStrings[i]) = me.(valueStrings[i-1]);
-               me.(valueIdentifiers[i]) = me.(valueIdentifiers[i-1]);
+               me.configureSliderValues(me, 0, 0, me.nValues - 1, 1, 1, 1);
+               me.setValueFromIdentifier_noAnim(me, theDefault);
        }
-       me.(valueStrings[pos]) = theString;
-       me.(valueIdentifiers[pos]) = theIdentifier;
-       me.nValues += 1;
-}
-void TextSlider_configureTextSliderValues(entity me, string theDefault)
-{
-       me.configureSliderValues(me, 0, 0, me.nValues - 1, 1, 1, 1);
-       me.setValueFromIdentifier_noAnim(me, theDefault);
-}
 #endif
index 13d8fcd49ef2d1b154b544ad02c0d09f344b29f8..899de0ec97185b66bdf500a10e883dd87dc9cbd0 100644 (file)
@@ -1,5 +1,5 @@
 #include "menu.qh"
-#include "oo/classes.qc"
+#include "classes.qc"
 #include "xonotic/util.qh"
 
 #include "../common/items/all.qh"
@@ -7,31 +7,25 @@
 #include "../common/mapinfo.qh"
 #include "../common/mutators/base.qh"
 
-///////////////////////////////////////////////
-// Menu Source File
-///////////////////////
-// This file belongs to dpmod/darkplaces
-// AK contains all menu functions (especially the required ones)
-///////////////////////////////////////////////
-
-float mouseButtonsPressed;
+int mouseButtonsPressed;
 vector menuMousePos;
 int menuShiftState;
 float menuPrevTime;
 float menuAlpha;
 float menuLogoAlpha;
 float prevMenuAlpha;
-float menuInitialized;
-float menuNotTheFirstFrame;
-float menuMouseMode;
+bool menuInitialized;
+bool menuNotTheFirstFrame;
+int menuMouseMode;
 
-float conwidth_s, conheight_s, vidwidth_s, vidheight_s, vidpixelheight_s,
-      realconwidth, realconheight;
+float conwidth_s, conheight_s;
+float vidwidth_s, vidheight_s, vidpixelheight_s;
+float realconwidth, realconheight;
 
 void m_sync()
 {
        updateCompression();
-       vidwidth_s = vidheight_s = vidpixelheight_s = 0;  // Force updateConwidths on next draw.
+       vidwidth_s = vidheight_s = vidpixelheight_s = 0;  // Force updateConwidths on next draw
 
        loadAllCvars(main);
 }
@@ -39,43 +33,37 @@ void m_sync()
 void m_gamestatus()
 {
        gamestatus = 0;
-       if(isserver())
-               gamestatus = gamestatus | GAME_ISSERVER;
-       if(clientstate() == CS_CONNECTED || isdemo())
-               gamestatus = gamestatus | GAME_CONNECTED;
-       if(cvar("developer"))
-               gamestatus = gamestatus | GAME_DEVELOPER;
+       if (isserver()) gamestatus |= GAME_ISSERVER;
+       if (clientstate() == CS_CONNECTED || isdemo()) gamestatus |= GAME_CONNECTED;
+       if (cvar("developer")) gamestatus |= GAME_DEVELOPER;
 }
 
 void m_init()
 {
-       float restarting = 0;
+       bool restarting = false;
        cvar_set("_menu_alpha", "0");
        prvm_language = cvar_string("prvm_language");
-       if(prvm_language == "")
+       if (prvm_language == "")
        {
                prvm_language = "en";
                cvar_set("prvm_language", prvm_language);
                localcmd("\nmenu_restart\n");
-               restarting = 1;
+               restarting = true;
        }
        prvm_language = strzone(prvm_language);
        cvar_set("_menu_prvm_language", prvm_language);
 
 #ifdef WATERMARK
-       LOG_TRACEF("^4MQC Build information: ^1%s\n", WATERMARK);
+               LOG_INFOF("^4MQC Build information: ^1%s\n", WATERMARK);
 #endif
 
        // list all game dirs (TEST)
-       if(cvar("developer"))
+       if (cvar("developer"))
        {
-               float i;
-               string s;
-               for(i = 0; ; ++i)
+               for (int i = 0; ; ++i)
                {
-                       s = getgamedirinfo(i, GETGAMEDIRINFO_NAME);
-                       if (!s)
-                               break;
+                       string s = getgamedirinfo(i, GETGAMEDIRINFO_NAME);
+                       if (!s) break;
                        LOG_TRACE(s, ": ", getgamedirinfo(i, GETGAMEDIRINFO_DESCRIPTION));
                }
        }
@@ -83,27 +71,25 @@ void m_init()
        // needs to be done so early because of the constants they create
        static_init();
        static_init_late();
+       static_init_precache();
 
        RegisterSLCategories();
 
        float ddsload = cvar("r_texture_dds_load");
        float texcomp = cvar("gl_texturecompression");
        updateCompression();
-       if(ddsload != cvar("r_texture_dds_load") || texcomp != cvar("gl_texturecompression"))
-               localcmd("\nr_restart\n");
+       if (ddsload != cvar("r_texture_dds_load") || texcomp != cvar("gl_texturecompression")) localcmd("\nr_restart\n");
 
-       if(!restarting)
+       if (!restarting)
        {
-               if(cvar("_menu_initialized")) // always show menu after menu_restart
+               if (cvar("_menu_initialized"))  // always show menu after menu_restart
                        m_display();
-               else
-                       m_hide();
+               else m_hide();
                cvar_set("_menu_initialized", "1");
        }
-
 }
 
-const float MENU_ASPECT = 1.25; // 1280x1024
+const float MENU_ASPECT = 1280 / 1024;
 
 void draw_reset_cropped()
 {
@@ -118,8 +104,7 @@ void UpdateConWidthHeight(float w, float h, float p)
 {
        if (w != vidwidth_s || h != vidheight_s || p != vidpixelheight_s)
        {
-               if (updateConwidths(w, h, p))
-                       localcmd(sprintf("\nexec %s\n", cvar_string("menu_font_cfg")));
+               if (updateConwidths(w, h, p)) localcmd(sprintf("\nexec %s\n", cvar_string("menu_font_cfg")));
                vidwidth_s = w;
                vidheight_s = h;
                vidpixelheight_s = p;
@@ -128,7 +113,7 @@ void UpdateConWidthHeight(float w, float h, float p)
        conheight_s = conheight;
        realconwidth = cvar("vid_conwidth");
        realconheight = cvar("vid_conheight");
-       if(realconwidth / realconheight > MENU_ASPECT)
+       if (realconwidth / realconheight > MENU_ASPECT)
        {
                // widescreen
                conwidth = realconheight * MENU_ASPECT;
@@ -140,9 +125,9 @@ void UpdateConWidthHeight(float w, float h, float p)
                conwidth = realconwidth;
                conheight = realconwidth / MENU_ASPECT;
        }
-       if(main)
+       if (main)
        {
-               if(conwidth_s != conwidth || conheight_s != conheight)
+               if (conwidth_s != conwidth || conheight_s != conheight)
                {
                        draw_reset_cropped();
                        main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);
@@ -150,64 +135,53 @@ void UpdateConWidthHeight(float w, float h, float p)
        }
        else
        {
-               vidwidth_s = vidheight_s = vidpixelheight_s = 0; // retry next frame
+               vidwidth_s = vidheight_s = vidpixelheight_s = 0;  // retry next frame
        }
 }
 
 string m_goto_buffer;
 void m_init_delayed()
 {
-       float fh, glob, n, i;
-       string s;
-
        draw_reset_cropped();
 
-       menuInitialized = 0;
-       if(!preMenuInit())
-               return;
-       menuInitialized = 1;
+       menuInitialized = false;
+       if (!preMenuInit()) return;
+       menuInitialized = true;
 
-       fh = -1;
-       if(cvar_string("menu_skin") != "")
+       int fh = -1;
+       if (cvar_string("menu_skin") != "")
        {
                draw_currentSkin = strcat("gfx/menu/", cvar_string("menu_skin"));
                fh = fopen(language_filename(strcat(draw_currentSkin, "/skinvalues.txt")), FILE_READ);
        }
-       if(fh < 0)
-       if(cvar_defstring("menu_skin") != "")
+       if (fh < 0 && cvar_defstring("menu_skin") != "")
        {
                cvar_set("menu_skin", cvar_defstring("menu_skin"));
                draw_currentSkin = strcat("gfx/menu/", cvar_string("menu_skin"));
                fh = fopen(language_filename(strcat(draw_currentSkin, "/skinvalues.txt")), FILE_READ);
        }
-       if(fh < 0)
+       if (fh < 0)
        {
                draw_currentSkin = "gfx/menu/default";
                fh = fopen(language_filename(strcat(draw_currentSkin, "/skinvalues.txt")), FILE_READ);
        }
-       if(fh < 0)
-       {
-               error("cannot load any menu skin\n");
-       }
+       if (fh < 0) error("cannot load any menu skin\n");
        draw_currentSkin = strzone(draw_currentSkin);
-       while((s = fgets(fh)))
+       for (string s; (s = fgets(fh)); )
        {
                // these two are handled by skinlist.qc
-               if(substring(s, 0, 6) == "title ")
-                       continue;
-               if(substring(s, 0, 7) == "author ")
-                       continue;
-               n = tokenize_console(s);
-               if(n >= 2)
-                       Skin_ApplySetting(argv(0), substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
+               if (substring(s, 0, 6) == "title ") continue;
+               if (substring(s, 0, 7) == "author ") continue;
+               int n = tokenize_console(s);
+               if (n < 2) continue;
+               Skin_ApplySetting(argv(0), substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
        }
        fclose(fh);
 
-       glob = search_begin(strcat(draw_currentSkin, "/*.tga"), true, true);
-       if(glob >= 0)
+       int glob = search_begin(strcat(draw_currentSkin, "/*.tga"), true, true);
+       if (glob >= 0)
        {
-               n = search_getsize(glob);
-               for(i = 0; i < n; ++i)
+               for (int i = 0, n = search_getsize(glob); i < n; ++i)
                        precache_pic(search_getfilename(glob, i));
                search_end(glob);
        }
@@ -215,117 +189,110 @@ void m_init_delayed()
        draw_setMousePointer(SKINGFX_CURSOR, SKINSIZE_CURSOR, SKINOFFSET_CURSOR);
 
        anim = NEW(AnimHost);
-       main = NEW(MainWindow); main.configureMainWindow(main);
+       main = NEW(MainWindow);
+       main.configureMainWindow(main);
 
        main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);
-       main.focused = 1;
+       main.focused = true;
        menuShiftState = 0;
        menuMousePos = '0.5 0.5 0';
 
        m_sync();
 
-       if(m_goto_buffer)
+       if (m_goto_buffer)
        {
                m_goto(m_goto_buffer);
                strunzone(m_goto_buffer);
                m_goto_buffer = string_null;
        }
 
-       if(Menu_Active)
-               m_display(); // delayed menu display
+       if (Menu_Active) m_display();  // delayed menu display
 }
 
-void m_keyup (float key, float ascii)
+void m_keyup(float key, float ascii)
 {
-       if(!menuInitialized)
-               return;
-       if(!Menu_Active)
-               return;
+       if (!menuInitialized) return;
+       if (!Menu_Active) return;
        draw_reset_cropped();
        main.keyUp(main, key, ascii, menuShiftState);
-       if(key >= K_MOUSE1 && key <= K_MOUSE3)
+       if (key >= K_MOUSE1 && key <= K_MOUSE3)
        {
                --mouseButtonsPressed;
-               if(!mouseButtonsPressed)
-                       main.mouseRelease(main, menuMousePos);
-               if(mouseButtonsPressed < 0)
+               if (!mouseButtonsPressed) main.mouseRelease(main, menuMousePos);
+               if (mouseButtonsPressed < 0)
                {
                        mouseButtonsPressed = 0;
                        LOG_TRACE("Warning: released an already released button\n");
                }
        }
-       if(key == K_ALT) menuShiftState -= (menuShiftState & S_ALT);
-       if(key == K_CTRL) menuShiftState -= (menuShiftState & S_CTRL);
-       if(key == K_SHIFT) menuShiftState -= (menuShiftState & S_SHIFT);
+       if (key == K_ALT) menuShiftState &= ~S_ALT;
+       if (key == K_CTRL) menuShiftState &= ~S_CTRL;
+       if (key == K_SHIFT) menuShiftState &= ~S_SHIFT;
 }
 
 void m_keydown(float key, float ascii)
 {
-       if(!menuInitialized)
-               return;
-       if(!Menu_Active)
-               return;
+       if (!menuInitialized) return;
+       if (!Menu_Active) return;
 
-       if(menuMouseMode)
-       if(key >= K_MOUSE1 && key <= K_MOUSE3)
+       if (menuMouseMode && key >= K_MOUSE1 && key <= K_MOUSE3)
        {
                // detect a click outside of the game window
                vector p = getmousepos();
-               if(p.x < 0 || p.x > realconwidth || p.y < 0 || p.y > realconheight)
+               if (p.x < 0 || p.x > realconwidth || p.y < 0 || p.y > realconheight)
                {
                        ++mouseButtonsPressed;
                        return;
                }
        }
 
-       if(keyGrabber)
+       if (keyGrabber)
        {
-               entity e;
-               e = keyGrabber;
+               entity e = keyGrabber;
                keyGrabber = NULL;
                e.keyGrabbed(e, key, ascii);
        }
        else
        {
                draw_reset_cropped();
-               if(key >= K_MOUSE1 && key <= K_MOUSE3)
-                       if(!mouseButtonsPressed)
-                               main.mousePress(main, menuMousePos);
-               if(!main.keyDown(main, key, ascii, menuShiftState))
-                       if(key == K_ESCAPE)
-                               if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED)) // don't back out to console only
-                                       m_hide(); // disable menu on unhandled ESC
+               if (!mouseButtonsPressed && key >= K_MOUSE1 && key <= K_MOUSE3) main.mousePress(main, menuMousePos);
+               if (!main.keyDown(main, key, ascii, menuShiftState))
+               {
+                       // disable menu on unhandled ESC
+                       if (key == K_ESCAPE)
+                               if (gamestatus & (GAME_ISSERVER | GAME_CONNECTED))  // don't back out to console only
+                                       m_hide();
+               }
        }
-       if(key >= K_MOUSE1 && key <= K_MOUSE3)
+       if (key >= K_MOUSE1 && key <= K_MOUSE3)
        {
                ++mouseButtonsPressed;
-               if(mouseButtonsPressed > 10)
+               if (mouseButtonsPressed > 10)
                {
                        mouseButtonsPressed = 10;
                        LOG_TRACE("Warning: pressed an already pressed button\n");
                }
        }
-       if(key == K_ALT) menuShiftState |= S_ALT;
-       if(key == K_CTRL) menuShiftState |= S_CTRL;
-       if(key == K_SHIFT) menuShiftState |= S_SHIFT;
+       if (key == K_ALT) menuShiftState |= S_ALT;
+       if (key == K_CTRL) menuShiftState |= S_CTRL;
+       if (key == K_SHIFT) menuShiftState |= S_SHIFT;
 }
 
-const float SCALEMODE_CROP = 0;
-const float SCALEMODE_LETTERBOX = 1;
-const float SCALEMODE_WIDTH = 2;
-const float SCALEMODE_HEIGHT = 3;
-const float SCALEMODE_STRETCH = 4;
+enum {
+       SCALEMODE_CROP,
+       SCALEMODE_LETTERBOX,
+       SCALEMODE_WIDTH,
+       SCALEMODE_HEIGHT,
+       SCALEMODE_STRETCH,
+};
 void draw_Picture_Aligned(vector algn, float scalemode, string img, float a)
 {
-       vector sz, org, isz, isz_w, isz_h;
-       float width_is_larger;
-
-       sz = draw_PictureSize(img);
-       width_is_larger = (sz.x * draw_scale.y >= sz.y * draw_scale.x);
-       isz_w = '1 0 0' + '0 1 0' * ((sz.y / sz.x) * (draw_scale.x / draw_scale.y));
-       isz_h = '0 1 0' + '1 0 0' * ((sz.x / sz.y) * (draw_scale.y / draw_scale.x));
-
-       switch(scalemode)
+       vector sz = draw_PictureSize(img);
+       bool width_is_larger = (sz.x * draw_scale.y >= sz.y * draw_scale.x);
+       vector isz_w = '1 0 0' + '0 1 0' * ((sz.y / sz.x) * (draw_scale.x / draw_scale.y));
+       vector isz_h = '0 1 0' + '1 0 0' * ((sz.x / sz.y) * (draw_scale.y / draw_scale.x));
+       vector isz;
+       switch (scalemode)
        {
                default:
                case SCALEMODE_CROP:
@@ -344,170 +311,174 @@ void draw_Picture_Aligned(vector algn, float scalemode, string img, float a)
                        isz = '1 1 0';
                        break;
        }
-
-       org = eX * (algn.x * (1 - isz.x)) + eY * (algn.y * (1 - isz.y));
+       vector org = eX * (algn.x * (1 - isz.x)) + eY * (algn.y * (1 - isz.y));
        draw_Picture(org, img, isz, '1 1 1', a);
 }
 
 void drawBackground(string img, float a, string algn, float force1)
 {
-       if(main.mainNexposee.ModalController_state == 0)
-               return;
-
-       vector v;
-       float i, l;
-       string c;
-       float scalemode;
-
-       v.z = 0;
-
-       scalemode = SCALEMODE_CROP;
-
-       l = 0;
-       for(i = 0; i < strlen(algn); ++i)
+       if (main.mainNexposee.ModalController_state == 0) return;
+       vector v = '0 0 0';
+       int scalemode = SCALEMODE_CROP;
+       for (int i = 0, l = 0; i < strlen(algn); ++i)
        {
-               c = substring(algn, i, 1);
-               switch(c)
+               string c = substring(algn, i, 1);
+               switch (c)
                {
-                       case "c": scalemode = SCALEMODE_CROP; goto nopic;
-                       case "l": scalemode = SCALEMODE_LETTERBOX; goto nopic;
-                       case "h": scalemode = SCALEMODE_HEIGHT; goto nopic;
-                       case "w": scalemode = SCALEMODE_WIDTH; goto nopic;
-                       case "s": scalemode = SCALEMODE_STRETCH; goto nopic;
-                       case "1": case "4": case "7": v.x = 0.0; break;
-                       case "2": case "5": case "8": v.x = 0.5; break;
-                       case "3": case "6": case "9": v.x = 1.0; break;
-                       default: v.x = random(); break;
+                       case "c":
+                               scalemode = SCALEMODE_CROP;
+                               goto nopic;
+                       case "l":
+                               scalemode = SCALEMODE_LETTERBOX;
+                               goto nopic;
+                       case "h":
+                               scalemode = SCALEMODE_HEIGHT;
+                               goto nopic;
+                       case "w":
+                               scalemode = SCALEMODE_WIDTH;
+                               goto nopic;
+                       case "s":
+                               scalemode = SCALEMODE_STRETCH;
+                               goto nopic;
+                       case "1": case "4": case "7":
+                               v.x = 0.0;
+                               break;
+                       case "2": case "5": case "8":
+                               v.x = 0.5;
+                               break;
+                       case "3": case "6": case "9":
+                               v.x = 1.0;
+                               break;
+                       default:
+                               v.x = random();
+                               break;
                }
-               switch(c)
+               switch (c)
                {
-                       case "7": case "8": case "9": v.y = 0.0; break;
-                       case "4": case "5": case "6": v.y = 0.5; break;
-                       case "1": case "2": case "3": v.y = 1.0; break;
-                       default: v.y = random(); break;
+                       case "7": case "8": case "9":
+                               v.y = 0.0;
+                               break;
+                       case "4": case "5": case "6":
+                               v.y = 0.5;
+                               break;
+                       case "1": case "2": case "3":
+                               v.y = 1.0;
+                               break;
+                       default:
+                               v.y = random();
+                               break;
                }
-               if(l == 0)
+               if (l == 0)
+               {
                        draw_Picture_Aligned(v, scalemode, img, a);
-               else if(force1)
+               }
+               else if (force1)
+               {
                        // force all secondary layers to use alpha 1. Prevents ugly issues
                        // with overlap. It's a flag because it cannot be used for the
                        // ingame background
-                       draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l+1)), 1);
+                       draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l + 1)), 1);
+               }
                else
-                       draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l+1)), a);
+               {
+                       draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l + 1)), a);
+               }
                ++l;
-:nopic
+               : nopic
        }
 }
 
-float menu_tooltips;
-float menu_tooltips_old;
+int menu_tooltips;
+int menu_tooltips_old;
 vector menuTooltipAveragedMousePos;
 entity menuTooltipItem;
 vector menuTooltipOrigin;
 vector menuTooltipSize;
 float menuTooltipAlpha;
 string menuTooltipText;
-float menuTooltipState; // 0: static, 1: fading in, 2: fading out, 3: forced fading out
-float m_testmousetooltipbox(vector pos)
+int menuTooltipState;  // 0: static, 1: fading in, 2: fading out, 3: forced fading out
+bool m_testmousetooltipbox(vector pos)
 {
-       if(pos.x >= menuTooltipOrigin.x && pos.x < menuTooltipOrigin.x + menuTooltipSize.x)
-       if(pos.y >= menuTooltipOrigin.y && pos.y < menuTooltipOrigin.y + menuTooltipSize.y)
-               return false;
-       return true;
+       return !(
+           (pos.x >= menuTooltipOrigin.x && pos.x < menuTooltipOrigin.x + menuTooltipSize.x)
+           && (pos.y >= menuTooltipOrigin.y && pos.y < menuTooltipOrigin.y + menuTooltipSize.y)
+               );
 }
-float m_testtooltipbox(vector tooltippos)
+bool m_testtooltipbox(vector tooltippos)
 {
-       if(tooltippos.x < 0)
-               return false;
-       if(tooltippos.y < 0)
-               return false;
-       if(tooltippos.x + menuTooltipSize.x > 1)
-               return false;
-       if(tooltippos.y + menuTooltipSize.y > 1)
-               return false;
+       if (tooltippos.x < 0) return false;
+       if (tooltippos.y < 0) return false;
+       if (tooltippos.x + menuTooltipSize.x > 1) return false;
+       if (tooltippos.y + menuTooltipSize.y > 1) return false;
        menuTooltipOrigin = tooltippos;
        return true;
 }
-float m_allocatetooltipbox(vector pos)
+bool m_allocatetooltipbox(vector pos)
 {
-       vector avoidplus, avoidminus;
-       vector v;
-
+       vector avoidplus;
        avoidplus.x = (SKINAVOID_TOOLTIP_x + SKINSIZE_CURSOR_x - SKINOFFSET_CURSOR_x * SKINSIZE_CURSOR_x) / conwidth;
        avoidplus.y = (SKINAVOID_TOOLTIP_y + SKINSIZE_CURSOR_y - SKINOFFSET_CURSOR_y * SKINSIZE_CURSOR_y) / conheight;
        avoidplus.z = 0;
 
+       vector avoidminus;
        avoidminus.x = (SKINAVOID_TOOLTIP_x + SKINOFFSET_CURSOR_x * SKINSIZE_CURSOR_x) / conwidth + menuTooltipSize.x;
        avoidminus.y = (SKINAVOID_TOOLTIP_y + SKINOFFSET_CURSOR_y * SKINSIZE_CURSOR_y) / conheight + menuTooltipSize.y;
        avoidminus.z = 0;
 
        // bottom right
-       v = pos + avoidplus;
-       if(m_testtooltipbox(v))
-               return true;
+       vector v = pos + avoidplus;
+       if (m_testtooltipbox(v)) return true;
 
        // bottom center
        v.x = pos.x - menuTooltipSize.x * 0.5;
-       if(m_testtooltipbox(v))
-               return true;
+       if (m_testtooltipbox(v)) return true;
 
        // bottom left
        v.x = pos.x - avoidminus.x;
-       if(m_testtooltipbox(v))
-               return true;
+       if (m_testtooltipbox(v)) return true;
 
        // top left
        v.y = pos.y - avoidminus.y;
-       if(m_testtooltipbox(v))
-               return true;
+       if (m_testtooltipbox(v)) return true;
 
        // top center
        v.x = pos.x - menuTooltipSize.x * 0.5;
-       if(m_testtooltipbox(v))
-               return true;
+       if (m_testtooltipbox(v)) return true;
 
        // top right
        v.x = pos.x + avoidplus.x;
-       if(m_testtooltipbox(v))
-               return true;
+       if (m_testtooltipbox(v)) return true;
 
        return false;
 }
 entity m_findtooltipitem(entity root, vector pos)
 {
-       entity it;
-       entity best;
-
-       best = NULL;
-       it = root;
-
-       while(it.instanceOfContainer)
+       entity best = NULL;
+       for (entity it = root; it.instanceOfContainer; )
        {
-               while(it.instanceOfNexposee && it.focusedChild)
+               while (it.instanceOfNexposee && it.focusedChild)
                {
                        it = it.focusedChild;
                        pos = globalToBox(pos, it.Container_origin, it.Container_size);
                }
-               if(it.instanceOfNexposee)
+               if (it.instanceOfNexposee)
                {
                        it = it.itemFromPoint(it, pos);
-                       if(it.tooltip)
-                               best = it;
-                       else if(menu_tooltips == 2 && (it.cvarName || it.onClickCommand))
-                               best = it;
+                       if (it.tooltip) best = it;
+                       else if (menu_tooltips == 2 && (it.cvarName || it.onClickCommand)) best = it;
                        it = NULL;
                }
-               else if(it.instanceOfModalController)
+               else if (it.instanceOfModalController)
+               {
                        it = it.focusedChild;
+               }
                else
+               {
                        it = it.itemFromPoint(it, pos);
-               if(!it)
-                       break;
-               if(it.tooltip)
-                       best = it;
-               else if(menu_tooltips == 2 && (it.cvarName || it.onClickCommand))
-                       best = it;
+               }
+               if (!it) break;
+               if (it.tooltip) best = it;
+               else if (menu_tooltips == 2 && (it.cvarName || it.onClickCommand)) best = it;
                pos = globalToBox(pos, it.Container_origin, it.Container_size);
        }
 
@@ -520,74 +491,72 @@ string gettooltip()
                string s;
                if (menuTooltipItem.cvarName)
                {
-                       if (getCvarsMulti(menuTooltipItem))
-                               s = strcat("[", menuTooltipItem.cvarName, " ", getCvarsMulti(menuTooltipItem), "]");
-                       else
-                               s = strcat("[", menuTooltipItem.cvarName, "]");
+                       if (getCvarsMulti(menuTooltipItem)) s =
+                                   strcat("[", menuTooltipItem.cvarName, " ", getCvarsMulti(menuTooltipItem), "]");
+                       else s = strcat("[", menuTooltipItem.cvarName, "]");
                }
                else if (menuTooltipItem.onClickCommand)
+               {
                        s = strcat("<", menuTooltipItem.onClickCommand, ">");
+               }
                else
+               {
                        return menuTooltipItem.tooltip;
-               if (menuTooltipItem.tooltip)
-                       return strcat(menuTooltipItem.tooltip, " ", s);
+               }
+               if (menuTooltipItem.tooltip) return strcat(menuTooltipItem.tooltip, " ", s);
                return s;
        }
        return menuTooltipItem.tooltip;
 }
-string prev_tooltip;
 void m_tooltip(vector pos)
 {
-       float f, i, w;
+       static string prev_tooltip;
        entity it;
-       vector fontsize, p;
-       string s;
-
        menu_tooltips = cvar("menu_tooltips");
        if (!menu_tooltips)
        {
                // don't return immediately, fade out the active tooltip first
-               if (menuTooltipItem == NULL)
-                       return;
+               if (menuTooltipItem == NULL) return;
                it = NULL;
                menu_tooltips_old = menu_tooltips;
        }
        else
        {
-               f = bound(0, frametime * 2, 1);
+               float f = bound(0, frametime * 2, 1);
                menuTooltipAveragedMousePos = menuTooltipAveragedMousePos * (1 - f) + pos * f;
                f = vlen(pos - menuTooltipAveragedMousePos);
-               if(f < 0.01)
+               if (f < 0.01)
                {
                        it = m_findtooltipitem(main, pos);
 
-                       if(it.instanceOfListBox && it.isScrolling(it))
-                               it = world;
+                       if (it.instanceOfListBox && it.isScrolling(it)) it = world;
 
-                       if(it && prev_tooltip != it.tooltip)
+                       if (it && prev_tooltip != it.tooltip)
                        {
                                // fade out if tooltip of a certain item has changed
                                menuTooltipState = 3;
-                               if(prev_tooltip)
-                                       strunzone(prev_tooltip);
+                               if (prev_tooltip) strunzone(prev_tooltip);
                                prev_tooltip = strzone(it.tooltip);
                        }
-                       else if(menuTooltipItem && !m_testmousetooltipbox(pos))
-                               menuTooltipState = 3; // fade out if mouse touches it
-
+                       else if (menuTooltipItem && !m_testmousetooltipbox(pos))
+                       {
+                               menuTooltipState = 3;  // fade out if mouse touches it
+                       }
                }
                else
+               {
                        it = NULL;
+               }
        }
-       fontsize = '1 0 0' * (SKINFONTSIZE_TOOLTIP / conwidth) + '0 1 0' * (SKINFONTSIZE_TOOLTIP / conheight);
+       vector fontsize = '1 0 0' * (SKINFONTSIZE_TOOLTIP / conwidth) + '0 1 0' * (SKINFONTSIZE_TOOLTIP / conheight);
 
        // float menuTooltipState; // 0: static, 1: fading in, 2: fading out, 3: forced fading out
-       if(it != menuTooltipItem)
+       if (it != menuTooltipItem)
        {
-               switch(menuTooltipState)
+               switch (menuTooltipState)
                {
                        case 0:
-                               if(menuTooltipItem)
+                               if (menuTooltipItem)
                                {
                                        // another item: fade out first
                                        menuTooltipState = 2;
@@ -598,22 +567,18 @@ void m_tooltip(vector pos)
                                        menuTooltipState = 1;
                                        menuTooltipItem = it;
 
-                                       menuTooltipOrigin.x = -1; // unallocated
+                                       menuTooltipOrigin.x = -1;  // unallocated
 
-                                       if (menuTooltipText)
-                                               strunzone(menuTooltipText);
+                                       if (menuTooltipText) strunzone(menuTooltipText);
                                        menuTooltipText = strzone(gettooltip());
 
-                                       i = 0;
-                                       w = 0;
-                                       getWrappedLine_remaining = menuTooltipText;
-                                       while(getWrappedLine_remaining)
+                                       int i = 0;
+                                       float w = 0;
+                                       for (getWrappedLine_remaining = menuTooltipText; getWrappedLine_remaining; ++i)
                                        {
-                                               s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);
-                                               ++i;
-                                               f = draw_TextWidth(s, false, fontsize);
-                                               if(f > w)
-                                                       w = f;
+                                               string s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);
+                                               float f = draw_TextWidth(s, false, fontsize);
+                                               if (f > w) w = f;
                                        }
                                        menuTooltipSize.x = w + 2 * (SKINMARGIN_TOOLTIP_x / conwidth);
                                        menuTooltipSize.y = i * fontsize.y + 2 * (SKINMARGIN_TOOLTIP_y / conheight);
@@ -629,20 +594,21 @@ void m_tooltip(vector pos)
                                break;
                }
        }
-       else if(menuTooltipState == 2) // re-fade in?
+       else if (menuTooltipState == 2)  // re-fade in?
+       {
                menuTooltipState = 1;
+       }
 
-       switch(menuTooltipState)
+       switch (menuTooltipState)
        {
-               case 1: // fade in
+               case 1:  // fade in
                        menuTooltipAlpha = bound(0, menuTooltipAlpha + 5 * frametime, 1);
-                       if(menuTooltipAlpha == 1)
-                               menuTooltipState = 0;
+                       if (menuTooltipAlpha == 1) menuTooltipState = 0;
                        break;
-               case 2: // fade out
-               case 3: // forced fade out
+               case 2:  // fade out
+               case 3:  // forced fade out
                        menuTooltipAlpha = bound(0, menuTooltipAlpha - 2 * frametime, 1);
-                       if(menuTooltipAlpha == 0)
+                       if (menuTooltipAlpha == 0)
                        {
                                menuTooltipState = 0;
                                menuTooltipItem = NULL;
@@ -650,7 +616,7 @@ void m_tooltip(vector pos)
                        break;
        }
 
-       if(menuTooltipItem == NULL)
+       if (menuTooltipItem == NULL)
        {
                if (menuTooltipText)
                {
@@ -661,31 +627,29 @@ void m_tooltip(vector pos)
        }
        else
        {
-               if(menu_tooltips != menu_tooltips_old)
+               if (menu_tooltips != menu_tooltips_old)
                {
-                       if (menu_tooltips != 0 && menu_tooltips_old != 0)
-                               menuTooltipItem = NULL; // reload tooltip next frame
+                       if (menu_tooltips != 0 && menu_tooltips_old != 0) menuTooltipItem = NULL; // reload tooltip next frame
                        menu_tooltips_old = menu_tooltips;
                }
-               else if(menuTooltipOrigin.x < 0) // unallocated?
+               else if (menuTooltipOrigin.x < 0)                                             // unallocated?
+               {
                        m_allocatetooltipbox(pos);
-
-               if(menuTooltipOrigin.x >= 0)
+               }
+               if (menuTooltipOrigin.x >= 0)
                {
                        // draw the tooltip!
-                       p = SKINBORDER_TOOLTIP;
+                       vector p = SKINBORDER_TOOLTIP;
                        p.x *= 1 / conwidth;
                        p.y *= 1 / conheight;
                        draw_BorderPicture(menuTooltipOrigin, SKINGFX_TOOLTIP, menuTooltipSize, '1 1 1', menuTooltipAlpha, p);
                        p = menuTooltipOrigin;
                        p.x += SKINMARGIN_TOOLTIP_x / conwidth;
                        p.y += SKINMARGIN_TOOLTIP_y / conheight;
-                       getWrappedLine_remaining = menuTooltipText;
-                       while(getWrappedLine_remaining)
+                       for (getWrappedLine_remaining = menuTooltipText; getWrappedLine_remaining; p.y += fontsize.y)
                        {
-                               s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);
+                               string s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);
                                draw_Text(p, s, fontsize, SKINCOLOR_TOOLTIP, SKINALPHA_TOOLTIP * menuTooltipAlpha, false);
-                               p.y += fontsize.y;
                        }
                }
        }
@@ -693,94 +657,90 @@ void m_tooltip(vector pos)
 
 void m_draw(float width, float height)
 {
-       float t;
-       float realFrametime;
-
        m_gamestatus();
 
        execute_next_frame();
 
        menuMouseMode = cvar("menu_mouse_absolute");
 
-       if (anim)
-               anim.tickAll(anim);
+       if (anim) anim.tickAll(anim);
 
        UpdateConWidthHeight(width, height, cvar("vid_pixelheight"));
 
-       if(!menuInitialized)
+       if (!menuInitialized)
        {
                // TODO draw an info image about this situation
                m_init_delayed();
                return;
        }
-       if(!menuNotTheFirstFrame)
+       if (!menuNotTheFirstFrame)
        {
-               menuNotTheFirstFrame = 1;
-               if(Menu_Active)
-               if(!cvar("menu_video_played"))
-               {
-                       localcmd("cd loop $menu_cdtrack; play sound/announcer/default/welcome.wav\n");
-                       menuLogoAlpha = -0.8; // no idea why, but when I start this at zero, it jumps instead of fading FIXME
-               }
+               menuNotTheFirstFrame = true;
+               if (Menu_Active && !cvar("menu_video_played"))
+        {
+            localcmd("cd loop $menu_cdtrack; play sound/announcer/default/welcome.wav\n");
+            menuLogoAlpha = -0.8;  // no idea why, but when I start this at zero, it jumps instead of fading FIXME
+        }
                // ALWAYS set this cvar; if we start but menu is not active, this means we want no background music!
                localcmd("set menu_video_played 1\n");
        }
 
-       t = gettime();
-       realFrametime = frametime = min(0.2, t - menuPrevTime);
+       float t = gettime();
+       float realFrametime = frametime = min(0.2, t - menuPrevTime);
        menuPrevTime = t;
        time += frametime;
 
        t = cvar("menu_slowmo");
-       if(t)
+       if (t)
        {
                frametime *= t;
                realFrametime *= t;
        }
        else
+       {
                t = 1;
+       }
 
-       if(Menu_Active)
+       if (Menu_Active)
        {
-               if(getmousetarget() == (menuMouseMode ? MT_CLIENT : MT_MENU) && (getkeydest() == KEY_MENU || getkeydest() == KEY_MENU_GRABBED))
-                       setkeydest(keyGrabber ? KEY_MENU_GRABBED : KEY_MENU);
-               else
-                       m_hide();
+               if (getmousetarget() == (menuMouseMode ? MT_CLIENT : MT_MENU)
+                   && (getkeydest() == KEY_MENU || getkeydest() == KEY_MENU_GRABBED))
+                       setkeydest(keyGrabber ? KEY_MENU_GRABBED : KEY_MENU);
+               else m_hide();
        }
 
-       if(cvar("cl_capturevideo"))
-               frametime = t / cvar("cl_capturevideo_fps"); // make capturevideo work smoothly
+       if (cvar("cl_capturevideo")) frametime = t / cvar("cl_capturevideo_fps");  // make capturevideo work smoothly
 
        prevMenuAlpha = menuAlpha;
-       if(Menu_Active)
+       if (Menu_Active)
        {
-               if(menuAlpha == 0 && menuLogoAlpha < 2)
+               if (menuAlpha == 0 && menuLogoAlpha < 2)
                {
-                       menuLogoAlpha = menuLogoAlpha + frametime * 2;
+                       menuLogoAlpha += 2 * frametime;
                }
                else
                {
-                       menuAlpha = min(1, menuAlpha + frametime * 5);
+                       menuAlpha = min(1, menuAlpha + 5 * frametime);
                        menuLogoAlpha = 2;
                }
        }
        else
        {
-               menuAlpha = max(0, menuAlpha - frametime * 5);
+               menuAlpha = max(0, menuAlpha - 5 * frametime);
                menuLogoAlpha = 2;
        }
 
        draw_reset_cropped();
 
-       if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
+       if (!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
        {
-               if(menuLogoAlpha > 0)
+               if (menuLogoAlpha > 0)
                {
                        draw_reset_full();
                        draw_Fill('0 0 0', '1 1 0', SKINCOLOR_BACKGROUND, 1);
                        drawBackground(SKINGFX_BACKGROUND, bound(0, menuLogoAlpha, 1), SKINALIGN_BACKGROUND, true);
                        draw_reset_cropped();
-                       if(menuAlpha <= 0 && SKINALPHA_CURSOR_INTRO > 0)
+                       if (menuAlpha <= 0 && SKINALPHA_CURSOR_INTRO > 0)
                        {
                                draw_alpha = SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1);
                                draw_drawMousePointer(menuMousePos);
@@ -788,27 +748,26 @@ void m_draw(float width, float height)
                        }
                }
        }
-       else if(SKINALPHA_BACKGROUND_INGAME)
+       else if (SKINALPHA_BACKGROUND_INGAME)
        {
-               if(menuAlpha > 0)
+               if (menuAlpha > 0)
                {
                        draw_reset_full();
-                       drawBackground(SKINGFX_BACKGROUND_INGAME, menuAlpha * SKINALPHA_BACKGROUND_INGAME, SKINALIGN_BACKGROUND_INGAME, false);
+                       drawBackground(SKINGFX_BACKGROUND_INGAME, menuAlpha * SKINALPHA_BACKGROUND_INGAME,
+                               SKINALIGN_BACKGROUND_INGAME, false);
                        draw_reset_cropped();
                }
        }
 
-       if(menuAlpha != prevMenuAlpha)
-               cvar_set("_menu_alpha", ftos(menuAlpha));
+       if (menuAlpha != prevMenuAlpha) cvar_set("_menu_alpha", ftos(menuAlpha));
 
        draw_reset_cropped();
        preMenuDraw();
        draw_reset_cropped();
 
-       if(menuAlpha <= 0)
+       if (menuAlpha <= 0)
        {
-               if(prevMenuAlpha > 0)
-                       main.initializeDialog(main, main.firstChild);
+               if (prevMenuAlpha > 0) main.initializeDialog(main, main.firstChild);
                draw_reset_cropped();
                postMenuDraw();
                return;
@@ -816,44 +775,34 @@ void m_draw(float width, float height)
 
        draw_alpha *= menuAlpha;
 
-       if(!Menu_Active)
+       if (!Menu_Active)
        {
                // do not update mouse position
                // it prevents mouse jumping to '0 0 0' when menu is fading out
        }
-       else if(menuMouseMode)
+       else if (menuMouseMode)
        {
-               vector newMouse;
-               newMouse = globalToBox(getmousepos(), draw_shift, draw_scale);
-               if(newMouse != '0 0 0')
-                       if(newMouse != menuMousePos)
-                       {
-                               menuMousePos = newMouse;
-                               if(mouseButtonsPressed)
-                                       main.mouseDrag(main, menuMousePos);
-                               else
-                                       main.mouseMove(main, menuMousePos);
-                       }
+               vector newMouse = globalToBox(getmousepos(), draw_shift, draw_scale);
+               if (newMouse != '0 0 0' && newMouse != menuMousePos)
+               {
+                       menuMousePos = newMouse;
+                       if (mouseButtonsPressed) main.mouseDrag(main, menuMousePos);
+                       else main.mouseMove(main, menuMousePos);
+               }
        }
-       else
+       else if (frametime > 0)
        {
-               if(frametime > 0)
+               vector dMouse = getmousepos() * (frametime / realFrametime);  // for capturevideo
+               if (dMouse != '0 0 0')
                {
-                       vector dMouse, minpos, maxpos;
-                       dMouse = getmousepos() * (frametime / realFrametime); // for capturevideo
-                       if(dMouse != '0 0 0')
-                       {
-                               minpos = globalToBox('0 0 0', draw_shift, draw_scale);
-                               maxpos = globalToBox(eX * (realconwidth - 1) + eY * (realconheight - 1), draw_shift, draw_scale);
-                               dMouse = globalToBoxSize(dMouse, draw_scale);
-                               menuMousePos += dMouse * cvar("menu_mouse_speed");
-                               menuMousePos.x = bound(minpos.x, menuMousePos.x, maxpos.x);
-                               menuMousePos.y = bound(minpos.y, menuMousePos.y, maxpos.y);
-                               if(mouseButtonsPressed)
-                                       main.mouseDrag(main, menuMousePos);
-                               else
-                                       main.mouseMove(main, menuMousePos);
-                       }
+                       vector minpos = globalToBox('0 0 0', draw_shift, draw_scale);
+                       vector maxpos = globalToBox(eX * (realconwidth - 1) + eY * (realconheight - 1), draw_shift, draw_scale);
+                       dMouse = globalToBoxSize(dMouse, draw_scale);
+                       menuMousePos += dMouse * cvar("menu_mouse_speed");
+                       menuMousePos.x = bound(minpos.x, menuMousePos.x, maxpos.x);
+                       menuMousePos.y = bound(minpos.y, menuMousePos.y, maxpos.y);
+                       if (mouseButtonsPressed) main.mouseDrag(main, menuMousePos);
+                       else main.mouseMove(main, menuMousePos);
                }
        }
        main.draw(main);
@@ -876,11 +825,9 @@ void m_display()
        setkeydest(KEY_MENU);
        setmousetarget((menuMouseMode ? MT_CLIENT : MT_MENU));
 
-       if(!menuInitialized)
-               return;
+       if (!menuInitialized) return;
 
-       if(mouseButtonsPressed)
-               main.mouseRelease(main, menuMousePos);
+       if (mouseButtonsPressed) main.mouseRelease(main, menuMousePos);
        mouseButtonsPressed = 0;
 
        main.focusEnter(main);
@@ -893,112 +840,94 @@ void m_hide()
        setkeydest(KEY_GAME);
        setmousetarget(MT_CLIENT);
 
-       if(!menuInitialized)
-               return;
+       if (!menuInitialized) return;
 
        main.focusLeave(main);
        main.hideNotify(main);
 }
 
-void m_toggle(float mode)
+void m_toggle(int mode)
 {
-       if(Menu_Active)
+       if (Menu_Active)
        {
-               if (mode == 1)
-                       return;
+               if (mode == 1) return;
                m_hide();
        }
        else
        {
-               if (mode == 0)
-                       return;
+               if (mode == 0) return;
                m_display();
        }
 }
 
 void Shutdown()
 {
-       entity e;
-
        m_hide();
-       for(e = NULL; (e = nextent(e)) != NULL; )
+       for (entity e = NULL; (e = nextent(e)); )
        {
-               if(e.classname != "vtbl")
-                       if(e.destroy)
-                               e.destroy(e);
+               if (e.classname == "vtbl") continue;
+               if (e.destroy) e.destroy(e);
        }
 }
 
 void m_focus_item_chain(entity outermost, entity innermost)
 {
-       if(innermost.parent != outermost)
-               m_focus_item_chain(outermost, innermost.parent);
+       if (innermost.parent != outermost) m_focus_item_chain(outermost, innermost.parent);
        innermost.parent.setFocus(innermost.parent, innermost);
 }
 
 void m_activate_window(entity wnd)
 {
-       entity par;
-       par = wnd.parent;
-       if(par)
-               m_activate_window(par);
+       entity par = wnd.parent;
+       if (par) m_activate_window(par);
 
-       if(par.instanceOfModalController)
+       if (par.instanceOfModalController)
        {
-               if(wnd.tabSelectingButton)
+               if (wnd.tabSelectingButton)
                        // tabs
                        TabButton_Click(wnd.tabSelectingButton, wnd);
                else
                        // root
                        par.initializeDialog(par, wnd);
        }
-       else if(par.instanceOfNexposee)
+       else if (par.instanceOfNexposee)
        {
                // nexposee (sorry for violating abstraction here)
                par.selectedChild = wnd;
                par.animationState = 1;
                Container_setFocus(par, NULL);
        }
-       else if(par.instanceOfContainer)
+       else if (par.instanceOfContainer)
        {
                // other containers
-               if(par.focused)
-                       par.setFocus(par, wnd);
+               if (par.focused) par.setFocus(par, wnd);
        }
 }
 
 void m_setpointerfocus(entity wnd)
 {
-       if(wnd.instanceOfContainer)
-       {
-               entity focus = wnd.preferredFocusedGrandChild(wnd);
-               if(focus)
-               {
-                       menuMousePos = focus.origin + 0.5 * focus.size;
-                       menuMousePos.x *= 1 / conwidth;
-                       menuMousePos.y *= 1 / conheight;
-                       entity par = wnd.parent;
-                       if(par.focused)
-                               par.setFocus(par, wnd);
-                       if(wnd.focused)
-                               m_focus_item_chain(wnd, focus);
-               }
-       }
+       if (!wnd.instanceOfContainer) return;
+       entity focus = wnd.preferredFocusedGrandChild(wnd);
+       if (!focus) return;
+       menuMousePos = focus.origin + 0.5 * focus.size;
+       menuMousePos.x *= 1 / conwidth;
+       menuMousePos.y *= 1 / conheight;
+       entity par = wnd.parent;
+       if (par.focused) par.setFocus(par, wnd);
+       if (wnd.focused) m_focus_item_chain(wnd, focus);
 }
 
 void m_goto(string itemname)
 {
-       entity e;
-       if(!menuInitialized)
+       if (!menuInitialized)
        {
-               if(m_goto_buffer)
-                       strunzone(m_goto_buffer);
+               if (m_goto_buffer) strunzone(m_goto_buffer);
                m_goto_buffer = strzone(itemname);
                return;
        }
-       if(itemname == "") // this can be called by GameCommand
+       if (itemname == "")  // this can be called by GameCommand
        {
-               if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED))
+               if (gamestatus & (GAME_ISSERVER | GAME_CONNECTED))
                {
                        m_hide();
                }
@@ -1010,11 +939,11 @@ void m_goto(string itemname)
        }
        else
        {
-               for(e = NULL; (e = find(e, name, itemname)); )
-                       if(e.classname != "vtbl")
-                               break;
+               entity e;
+               for (e = NULL; (e = find(e, name, itemname)); )
+                       if (e.classname != "vtbl") break;
 
-               if((e) && (!e.requiresConnection || (gamestatus & (GAME_ISSERVER | GAME_CONNECTED))))
+               if ((e) && (!e.requiresConnection || (gamestatus & (GAME_ISSERVER | GAME_CONNECTED))))
                {
                        m_hide();
                        m_activate_window(e);
@@ -1024,19 +953,17 @@ void m_goto(string itemname)
        }
 }
 
-float menuLastFocusSoundTime;
 void m_play_focus_sound()
 {
-       if(cvar("menu_sounds") > 1)
-               if(time - menuLastFocusSoundTime > 0.25)
-               {
-                       localsound(MENU_SOUND_FOCUS);
-                       menuLastFocusSoundTime = time;
-               }
+       static float menuLastFocusSoundTime;
+       if (cvar("menu_sounds") < 2) return;
+       if (time - menuLastFocusSoundTime <= 0.25) return;
+       localsound(MENU_SOUND_FOCUS);
+       menuLastFocusSoundTime = time;
 }
 
 void m_play_click_sound(string soundfile)
 {
-       if(cvar("menu_sounds"))
-               localsound(soundfile);
+       if (!cvar("menu_sounds")) return;
+       localsound(soundfile);
 }
index 6d45ca82f46a36b7f4e64f449275ec36f895a829..a4cdbc5f512bea1eba011c2dd64f30ea00b11c6f 100644 (file)
@@ -9,15 +9,11 @@
 #include "../common/constants.qh"
 #include "../common/util.qh"
 
-// constants
+const int GAME_ISSERVER     = BIT(0);
+const int GAME_CONNECTED    = BIT(1);
+const int GAME_DEVELOPER    = BIT(2);
 
-const int GAME_ISSERVER        = 1;
-const int GAME_CONNECTED       = 2;
-const int GAME_DEVELOPER       = 4;
-
-// prototypes
-
-float Menu_Active;
+bool Menu_Active;
 int gamestatus;
 
 const int S_SHIFT = 1;
@@ -35,20 +31,22 @@ void m_goto(string name);
 .string name;
 
 entity keyGrabber;
-.void(entity me, float key, float ascii) keyGrabbed;
+.void(entity this, float key, float ascii) keyGrabbed;
 
-float conwidth, conheight; // "virtual" conwidth/height values for other stuff to assume for scaling
+// "virtual" conwidth/height values for other stuff to assume for scaling
+float conwidth, conheight;
 
-float preMenuInit(); // you have to define this for pre-menu initialization. Return 0 if initialization needs to be retried a frame later, 1 if it succeeded.
-void preMenuDraw(); // this is run before the menu is drawn. You may put some stuff there that has to be done every frame.
-void postMenuDraw(); // this is run just after the menu is drawn (or not). Useful to draw something over everything else.
+/** you have to define this for pre-menu initialization. Return 0 if initialization needs to be retried a frame later, 1 if it succeeded. */
+float preMenuInit();
+/** this is run before the menu is drawn. You may put some stuff there that has to be done every frame. */
+void preMenuDraw();
+/** this is run just after the menu is drawn (or not). Useful to draw something over everything else. */
+void postMenuDraw();
 
 void m_sync();
 
 void draw_reset_cropped();
 
-// sounds
-
 const string MENU_SOUND_CLEAR   = "sound/menu/clear.wav";
 const string MENU_SOUND_CLOSE   = "sound/menu/close.wav";
 const string MENU_SOUND_EXECUTE = "sound/menu/execute.wav";
diff --git a/qcsrc/menu/mutators/events.qh b/qcsrc/menu/mutators/events.qh
new file mode 100644 (file)
index 0000000..a3dc720
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef MENU_MUTATORS_EVENTS_H
+#define MENU_MUTATORS_EVENTS_H
+
+#include "../../common/mutators/base.qh"
+
+// globals
+
+string cmd_name;
+int cmd_argc;
+string cmd_string;
+
+/**
+ * Called when a menu command is parsed
+ * NOTE: hooks MUST start with if (MUTATOR_RETURNVALUE) return false;
+ * NOTE: return true if you handled the command, return false to continue handling
+ * NOTE: THESE HOOKS MUST NEVER EVER CALL tokenize()
+ * // example:
+ * MUTATOR_HOOKFUNCTION(foo, Menu_ConsoleCommand) {
+ *     if (MUTATOR_RETURNVALUE) return false; // command was already handled
+ *     if (cmd_name == "echocvar" && cmd_argc >= 2) {
+ *         print(cvar_string(argv(1)), "\n");
+ *         return true;
+ *     }
+ *     if (cmd_name == "echostring" && cmd_argc >= 2) {
+ *         print(substring(cmd_string, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), "\n");
+ *         return true;
+ *     }
+ *     return false;
+ * }
+ */
+#define EV_Menu_ConsoleCommand(i, o) \
+       /** command name */ i(string, cmd_name) \
+       /** also, argv() can be used */ i(int, cmd_argc) \
+       /** whole command, use only if you really have to */ i(string, cmd_string) \
+       /**/
+MUTATOR_HOOKABLE(Menu_ConsoleCommand, EV_Menu_ConsoleCommand);
+#endif
diff --git a/qcsrc/menu/oo/classes.qc b/qcsrc/menu/oo/classes.qc
deleted file mode 100644 (file)
index 16a830d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef CLASSES_H
-#define CLASSES_H
-
-#include "../classes.inc"
-#define IMPLEMENTATION
-#include "../classes.inc"
-#undef IMPLEMENTATION
-
-#endif
index ae221de272b18dae865438e36afdfef9786ce0b9..5282a01888d791d9d61e47d4e9f7451fc6846282 100644 (file)
@@ -2,7 +2,7 @@
 
 #define world NULL
 
-#include "oo/classes.qc"
+#include "classes.qc"
 
 #include "draw.qc"
 #include "menu.qc"
diff --git a/qcsrc/menu/sys-post.qh b/qcsrc/menu/sys-post.qh
deleted file mode 100644 (file)
index 2b4120e..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef SYS_POST_H
-#define SYS_POST_H
-
-#pragma noref 0
-#endif
diff --git a/qcsrc/menu/sys-pre.qh b/qcsrc/menu/sys-pre.qh
deleted file mode 100644 (file)
index 333d5c6..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef SYS_PRE_H
-#define SYS_PRE_H
-
-#pragma noref 1
-#endif
index 0ac826a44064cc4752b4c828a2b9c6c119e7a6e0..63da9cd92ae56980bf6db6ba9c29925eb08ab54e 100644 (file)
@@ -60,18 +60,17 @@ bool XonoticCrosshairPicker_cellIsValid(entity me, vector cell)
 
 void XonoticCrosshairPicker_cellDraw(entity me, vector cell, vector cellPos)
 {
-       vector sz;
-       string cross = strcat("/gfx/crosshair", crosshairpicker_cellToCrosshair(me, cell));
-       sz = draw_PictureSize(cross);
+       string s = strcat("/gfx/crosshair", crosshairpicker_cellToCrosshair(me, cell));
+       vector sz = draw_PictureSize(s);
        sz = globalToBoxSize(sz, me.size);
 
        float ar = sz.x / sz.y;
        sz.x = me.realCellSize.x;
        sz.y = sz.x / ar;
-       sz = sz * 0.95;
+       sz *= 0.95;
 
        vector crosshairPos = cellPos + 0.5 * me.realCellSize;
-       draw_Picture(crosshairPos - 0.5 * sz, cross, sz, SKINCOLOR_CROSSHAIRPICKER_CROSSHAIR, SKINALPHA_CROSSHAIRPICKER_CROSSHAIR);
+       draw_Picture(crosshairPos - 0.5 * sz, s, sz, SKINCOLOR_CROSSHAIRPICKER_CROSSHAIR, SKINALPHA_CROSSHAIRPICKER_CROSSHAIR);
 
        if(cvar("crosshair_dot"))
                draw_Picture(crosshairPos - 0.5 * sz * cvar("crosshair_dot_size"), "/gfx/crosshairdot", sz * cvar("crosshair_dot_size"), SKINCOLOR_CROSSHAIRPICKER_CROSSHAIR, SKINALPHA_CROSSHAIRPICKER_CROSSHAIR);
index 57ce0c80c312e73c7826110a6075dc8a6e9b4284..3b8be8d27b0a4d57bb441136688e2411b392223b 100644 (file)
@@ -57,13 +57,13 @@ CLASS(CvarStringSource, StringSource)
     {
         string s = this.CvarStringSource_cvar;
         this.StringSource_str = s ? cvar_string(s) : string_null;
-        return super.getEntry(this, i, returns);
+        return SUPER(CvarStringSource).getEntry(this, i, returns);
     }
     METHOD(CvarStringSource, reload, int(entity this, string filter))
     {
         string s = this.CvarStringSource_cvar;
         this.StringSource_str = s ? cvar_string(s) : string_null;
-        return super.reload(this, filter);
+        return SUPER(CvarStringSource).reload(this, filter);
     }
 ENDCLASS(CvarStringSource)
 #endif
index 408cb950b43da825c4366ed3e4619713be3c0b0d..2f3cd47b02e592696c1daf4e6974b83220b19b62 100644 (file)
@@ -54,7 +54,7 @@ string WeaponArenaString()
                {
                        e = get_weaponinfo(j);
                        if(argv(i) == e.netname)
-                               s = strcat(s, " & ", e.message);
+                               s = strcat(s, " & ", e.m_name);
                }
        }
        s = sprintf(_("%s Arena"), substring(s, 3, strlen(s) - 3));
@@ -259,7 +259,7 @@ void XonoticMutatorsDialog_fill(entity me)
                if((j & 1) == 0)
                        me.TR(me);
                me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticWeaponarenaCheckBox(strzone(w.netname), strzone(w.message)));
+               me.TD(me, 1, 1.8, e = makeXonoticWeaponarenaCheckBox(strzone(w.netname), strzone(w.m_name)));
                        setDependentWeird(e, checkCompatibility_weaponarena_weapon);
                ++j;
        }
index 3c1503b29774472af5b256b37930c7736c454d81..6f68b332d3f98ad5bd9bb83c147f0ee0c2c54776 100644 (file)
@@ -7,14 +7,14 @@
 CLASS(SettingSource, DataSource)
     METHOD(SettingSource, getEntry, entity(entity this, int i, void(string name, string icon) returns))
     {
-        Lazy l = Settings[i];
+        Lazy l = Settings_from(i);
         entity it = l.m_get();
         if (returns) returns(it.title, string_null);
         return it;
     }
     METHOD(SettingSource, getEntryTooltip, entity(entity this, int i, void(string theTooltip) returns))
     {
-        Lazy l = Settings[i];
+        Lazy l = Settings_from(i);
         entity it = l.m_get();
         if (returns) returns(it.tooltip);
         return it;
@@ -94,7 +94,7 @@ CLASS(XonoticRegisteredSettingsList, XonoticListBox)
        }
        METHOD(XonoticRegisteredSettingsList, resizeNotify, void(entity this, vector relOrigin, vector relSize, vector absOrigin, vector absSize))
        {
-               super.resizeNotify(this, relOrigin, relSize, absOrigin, absSize);
+               SUPER(XonoticRegisteredSettingsList).resizeNotify(this, relOrigin, relSize, absOrigin, absSize);
 
                this.itemAbsSize = '0 0 0';
                this.realFontSize_y = this.fontSize / (this.itemAbsSize_y = (absSize.y * this.itemHeight));
@@ -103,7 +103,7 @@ CLASS(XonoticRegisteredSettingsList, XonoticListBox)
        }
        METHOD(XonoticRegisteredSettingsList, setSelected, void(entity this, int i))
        {
-               super.setSelected(this, i);
+               SUPER(XonoticRegisteredSettingsList).setSelected(this, i);
                this.onChange(this, this.onChangeEntity);
        }
     CONSTRUCTOR(XonoticRegisteredSettingsList, DataSource _source) {
@@ -147,7 +147,7 @@ CLASS(XonoticGameSettingsTab, XonoticTab)
                        topics.onChangeEntity = this;
 
                int
-               col = 0, width = 1.5;
+               col = 0, width = 1;
                this.gotoRC(this, 0, col);
                        this.TD(this, this.rows, width, topics);
 
index 5522e13c7f75f4fd81302e3af353c5f94e370a44..f04a0d23a60b39b7f6c8b060598e1bbd0ea75867 100644 (file)
@@ -25,7 +25,7 @@ entity makeXonoticGametypeList();
 
 #ifdef IMPLEMENTATION
 
-entity makeXonoticGametypeList(void)
+entity makeXonoticGametypeList()
 {
        entity me;
        me = NEW(XonoticGametypeList);
index 0b7281dbff13f3cd1e3fc25b69ef229a43da989e..66dbb835127d4ffc4812f69cda19296ba461b47d 100644 (file)
@@ -184,15 +184,10 @@ void XonoticLanguageList_getLanguages(entity me)
                        continue;
                bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_ID, argv(0));
                bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_NAME, argv(1));
-               float k = strstrofs(argv(2), "(", 0);
-               if(k > 0)
-               if(substring(argv(2), strlen(argv(2)) - 1, 1) == ")")
-               {
-                       string percent = substring(argv(2), k + 1, -2);
-                       if(percent != "100%")
-                               bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_PERCENTAGE, percent);
-               }
-               bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_NAME_LOCALIZED, (k < 0) ? argv(2) : substring(argv(2), 0, k - 1));
+               bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_NAME_LOCALIZED, argv(2));
+               string percent = argv(3);
+               if(percent && percent != "100%")
+                       bufstr_set(buf, i * LANGPARM_COUNT + LANGPARM_PERCENTAGE, percent);
                ++i;
        }
        fclose(fh);
index 2cee6162ff7a9d1d81e45677cd7bf1a1015dcc5d..3819036ad4445f8fdd99dcdc3dc9576a685e2160 100644 (file)
@@ -173,9 +173,7 @@ void RegisterSLCategories()
        #define SLIST_CATEGORY(name,enoverride,dioverride,str) \
                SET_FIELD_COUNT(name, CATEGORY_FIRST, category_ent_count) \
                CHECK_MAX_COUNT(name, MAX_CATEGORIES, category_ent_count, "SLIST_CATEGORY") \
-               cat = spawn(); \
-               categories[name - 1] = cat; \
-               cat.classname = "slist_category"; \
+               cat = categories[name - 1] = new(slist_category); \
                cat.cat_name = strzone(#name); \
                cat.cat_enoverride_string = strzone(SLIST_CATEGORY_AUTOCVAR(name)); \
                cat.cat_dioverride_string = strzone(dioverride); \
index 146075ecaedc0842e145d98988be47ecc07db524..426048002255bb4ec838055409ead3ff54be17c6 100644 (file)
@@ -277,6 +277,7 @@ string _Nex_ExtResponseSystem_UpdateToURL;
 string _Nex_ExtResponseSystem_Packs;
 float _Nex_ExtResponseSystem_PacksStep;
 
+/** engine callback */
 void URI_Get_Callback(float id, float status, string data)
 {
        if(url_URI_Get_Callback(id, status, data))
index 9e989a4662070fea39b6ae7a8934dd2f1109f00a..79ce7c5eefa7abbaca8a705961879b6503762a13 100644 (file)
@@ -28,8 +28,6 @@ float updateCompression();
 
 void UpdateNotification_URI_Get_Callback(float id, float status, string data);
 
-void URI_Get_Callback(float id, float status, string data);
-
 // game type list box stuff (does not NEED to contain all game types, other
 // types stay available via console)
 int GameType_GetID(int cnt);
index 1f2a4e19e65b2fb2caeecab9da8c2b13e6576df7..c1189dd9ba5c702214c50c0ecea30e4613f713b7 100644 (file)
@@ -88,7 +88,7 @@ string XonoticWeaponsList_toString(entity me)
        for(i = 0; i < n; ++i)
        {
                e = get_weaponinfo(stof(argv(i)));
-               s = strcat(s, e.message, ", ");
+               s = strcat(s, e.m_name, ", ");
        }
        return substring(s, 0, strlen(s) - 2);
 }
@@ -103,7 +103,7 @@ void XonoticWeaponsList_drawListBoxItem(entity me, int i, vector absSize, bool i
                draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_FOCUSED, me.focusedItemAlpha);
        }
        e = get_weaponinfo(stof(argv(i)));
-       string msg = e.message;
+       string msg = e.m_name;
        if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
                msg = strcat(msg, "*");
 
index eeb06e7a692f9f86ad283bb5a2e84731f308c152..cbda56873aaa9091b3774b298fc6641954f46b0b 100644 (file)
@@ -1,14 +1,43 @@
 #ifndef SERVER_ALL_H
 #define SERVER_ALL_H
 
-#include "autocvars.qh"
-#include "constants.qh"
-#include "defs.qh"
-#include "miscfunctions.qh"
+int maxclients;
+
+const string STR_PLAYER = "player";
+const string STR_SPECTATOR = "spectator";
+const string STR_OBSERVER = "observer";
+
+#define IS_PLAYER(v) ((v).classname == STR_PLAYER)
+#define IS_SPEC(v) ((v).classname == STR_SPECTATOR)
+#define IS_OBSERVER(v) ((v).classname == STR_OBSERVER)
+
+#define IS_CLIENT(v) (v.flags & FL_CLIENT)
+#define IS_BOT_CLIENT(v) (clienttype(v) == CLIENTTYPE_BOT)
+#define IS_REAL_CLIENT(v) (clienttype(v) == CLIENTTYPE_REAL)
+#define IS_NOT_A_CLIENT(v) (clienttype(v) == CLIENTTYPE_NOTACLIENT)
+
+#define IS_MONSTER(v) (v.flags & FL_MONSTER)
+#define IS_VEHICLE(v) (v.vehicle_flags & VHF_ISVEHICLE)
+#define IS_TURRET(v) (v.turret_flags & TUR_FLAG_ISTURRET)
 
+#define FOR_EACH_CLIENTSLOT(v) for (v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
+#define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if (IS_CLIENT(v))
+#define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if (IS_REAL_CLIENT(v))
+
+#define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if (IS_PLAYER(v))
+#define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if (IS_SPEC(v))
+#define FOR_EACH_OBSERVER(v) FOR_EACH_CLIENT(v) if (IS_OBSERVER(v))
+#define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if (IS_PLAYER(v))
+
+#define FOR_EACH_MONSTER(v) for (v = world; (v = findflags(v, flags, FL_MONSTER)) != world; )
 
 #include "../common/effects/all.qh"
 #include "../common/models/all.qh"
 #include "../common/sounds/all.qh"
 
+#include "autocvars.qh"
+#include "constants.qh"
+#include "defs.qh"
+#include "miscfunctions.qh"
+
 #endif
index 7a60823152ed2c72ee095f55e2d67192053401a1..6cd7e2395a2acd17b62a8862691e62c7d52e6298 100644 (file)
@@ -55,7 +55,6 @@ bool autocvar_bot_navigation_ignoreplayers;
 bool autocvar_bot_nofire;
 #define autocvar_bot_number cvar("bot_number")
 #define autocvar_bot_prefix cvar_string("bot_prefix")
-bool autocvar_bot_sound_monopoly;
 #define autocvar_bot_suffix cvar_string("bot_suffix")
 bool autocvar_bot_usemodelnames;
 int autocvar_bot_vs_human;
@@ -81,7 +80,6 @@ float autocvar_g_balance_armor_rot;
 float autocvar_g_balance_armor_rotlinear;
 int autocvar_g_balance_armor_rotstable;
 int autocvar_g_balance_armor_start;
-float autocvar_g_balance_cloaked_alpha;
 float autocvar_g_balance_contents_damagerate;
 float autocvar_g_balance_contents_drowndelay;
 int autocvar_g_balance_contents_playerdamage_drowning;
@@ -121,20 +119,6 @@ float autocvar_g_balance_health_rotlinear;
 float autocvar_g_balance_health_rotstable;
 float autocvar_g_balance_kill_delay;
 float autocvar_g_balance_kill_antispam;
-int autocvar_g_balance_nix_ammo_cells;
-int autocvar_g_balance_nix_ammo_plasma;
-int autocvar_g_balance_nix_ammo_fuel;
-int autocvar_g_balance_nix_ammo_nails;
-int autocvar_g_balance_nix_ammo_rockets;
-int autocvar_g_balance_nix_ammo_shells;
-int autocvar_g_balance_nix_ammoincr_cells;
-int autocvar_g_balance_nix_ammoincr_plasma;
-int autocvar_g_balance_nix_ammoincr_fuel;
-int autocvar_g_balance_nix_ammoincr_nails;
-int autocvar_g_balance_nix_ammoincr_rockets;
-int autocvar_g_balance_nix_ammoincr_shells;
-float autocvar_g_balance_nix_incrtime;
-float autocvar_g_balance_nix_roundtime;
 float autocvar_g_balance_pause_armor_rot;
 float autocvar_g_balance_pause_armor_rot_spawn;
 float autocvar_g_balance_pause_fuel_regen;
@@ -234,12 +218,7 @@ int autocvar_g_maxplayers;
 float autocvar_g_maxplayers_spectator_blocktime;
 float autocvar_g_maxpushtime;
 float autocvar_g_maxspeed;
-float autocvar_g_midair_shieldtime;
 #define autocvar_g_instagib cvar("g_instagib")
-int autocvar_g_instagib_ammo_drop;
-int autocvar_g_instagib_extralives;
-float autocvar_g_instagib_speed_highspeed;
-float autocvar_g_instagib_invis_alpha;
 bool autocvar_g_instagib_damagedbycontents = true;
 bool autocvar_g_instagib_blaster_keepdamage = false;
 bool autocvar_g_instagib_blaster_keepforce = false;
@@ -247,31 +226,17 @@ bool autocvar_g_instagib_blaster_keepforce = false;
 #define autocvar_g_mirrordamage_virtual cvar("g_mirrordamage_virtual")
 
 float autocvar_g_movement_highspeed = 1;
-int autocvar_g_multijump;
-float autocvar_g_multijump_add;
-float autocvar_g_multijump_speed;
-float autocvar_g_multijump_maxspeed;
-float autocvar_g_multijump_dodging = 1;
 string autocvar_g_mutatormsg;
 //float autocvar_g_nick_flood_penalty;
 int autocvar_g_nick_flood_penalty_red;
 int autocvar_g_nick_flood_penalty_yellow;
 //float autocvar_g_nick_flood_timeout;
-bool autocvar_g_nix_with_healtharmor;
-bool autocvar_g_nix_with_blaster;
-bool autocvar_g_nix_with_powerups;
 bool autocvar_g_nodepthtestitems;
 bool autocvar_g_nodepthtestplayers;
 bool autocvar_g_norecoil;
 float autocvar_g_items_mindist;
 float autocvar_g_items_maxdist;
-int autocvar_g_pickup_cells_max;
-int autocvar_g_pickup_plasma_max;
-int autocvar_g_pickup_fuel_max;
 int autocvar_g_pickup_items;
-int autocvar_g_pickup_nails_max;
-int autocvar_g_pickup_rockets_max;
-int autocvar_g_pickup_shells_max;
 float autocvar_g_player_alpha;
 float autocvar_g_player_brightness;
 bool autocvar_g_playerclip_collisions;
@@ -292,7 +257,6 @@ bool autocvar_g_respawn_ghosts;
 float autocvar_g_respawn_ghosts_maxtime;
 float autocvar_g_respawn_ghosts_speed;
 int autocvar_g_respawn_waves;
-bool autocvar_g_running_guns;
 bool autocvar_g_shootfromcenter;
 bool autocvar_g_shootfromeye;
 string autocvar_g_shootfromfixedorigin;
@@ -382,17 +346,7 @@ string autocvar_sv_defaultplayermodel_pink;
 string autocvar_sv_defaultplayermodel_red;
 string autocvar_sv_defaultplayermodel_yellow;
 int autocvar_sv_defaultplayerskin;
-float autocvar_sv_dodging_delay;
-float autocvar_sv_dodging_height_threshold;
-float autocvar_sv_dodging_horiz_speed;
-float autocvar_sv_dodging_horiz_speed_frozen;
-float autocvar_sv_dodging_ramp_time;
-bool autocvar_sv_dodging_sound;
-float autocvar_sv_dodging_up_speed;
-float autocvar_sv_dodging_wall_distance_threshold;
-bool autocvar_sv_dodging_wall_dodging;
 bool autocvar_sv_dodging_frozen;
-bool autocvar_sv_dodging_frozen_doubletap;
 bool autocvar_sv_doublejump;
 bool autocvar_sv_eventlog;
 bool autocvar_sv_eventlog_console;
@@ -485,25 +439,8 @@ bool autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag;
 float autocvar_g_trueaim_minrange;
 bool autocvar_g_debug_defaultsounds;
 float autocvar_g_grab_range;
-int autocvar_g_sandbox_info;
-bool autocvar_g_sandbox_readonly;
-string autocvar_g_sandbox_storage_name;
-float autocvar_g_sandbox_storage_autosave;
-bool autocvar_g_sandbox_storage_autoload;
-float autocvar_g_sandbox_editor_flood;
-int autocvar_g_sandbox_editor_maxobjects;
-int autocvar_g_sandbox_editor_free;
-float autocvar_g_sandbox_editor_distance_spawn;
-float autocvar_g_sandbox_editor_distance_edit;
-float autocvar_g_sandbox_object_scale_min;
-float autocvar_g_sandbox_object_scale_max;
-float autocvar_g_sandbox_object_material_velocity_min;
-float autocvar_g_sandbox_object_material_velocity_factor;
 int autocvar_g_max_info_autoscreenshot;
 bool autocvar_physics_ode;
-int autocvar_g_physical_items;
-float autocvar_g_physical_items_damageforcescale;
-float autocvar_g_physical_items_reset;
 float autocvar_g_monsters;
 bool autocvar_g_monsters_edit;
 bool autocvar_g_monsters_sounds;
@@ -523,23 +460,14 @@ float autocvar_g_monsters_miniboss_chance;
 float autocvar_g_monsters_miniboss_healthboost;
 float autocvar_g_monsters_drop_time;
 float autocvar_g_monsters_spawnshieldtime;
+bool autocvar_g_monsters_quake_resize = true;
 bool autocvar_g_monsters_teams;
 float autocvar_g_monsters_respawn_delay;
 bool autocvar_g_monsters_respawn;
 float autocvar_g_monsters_armor_blockpercent;
 float autocvar_g_monsters_healthbars;
 float autocvar_g_monsters_lineofsight;
-float autocvar_g_touchexplode_radius;
-float autocvar_g_touchexplode_damage;
-float autocvar_g_touchexplode_edgedamage;
-float autocvar_g_touchexplode_force;
 #define autocvar_g_bloodloss cvar("g_bloodloss")
-float autocvar_g_random_gravity_negative_chance;
-float autocvar_g_random_gravity_min;
-float autocvar_g_random_gravity_max;
-float autocvar_g_random_gravity_positive;
-float autocvar_g_random_gravity_negative;
-float autocvar_g_random_gravity_delay;
 bool autocvar_g_nades;
 bool autocvar_g_nades_override_dropweapon = true;
 vector autocvar_g_nades_throw_offset;
@@ -595,67 +523,12 @@ float autocvar_g_nades_heal_friend;
 float autocvar_g_nades_heal_foe;
 string autocvar_g_nades_pokenade_monster_type;
 float autocvar_g_nades_pokenade_monster_lifetime;
-float autocvar_g_campcheck_damage;
-float autocvar_g_campcheck_distance;
-float autocvar_g_campcheck_interval;
 bool autocvar_g_jump_grunt;
-bool autocvar_g_overkill_powerups_replace;
-float autocvar_g_overkill_superguns_respawn_time;
-bool autocvar_g_overkill_100h_anyway;
-bool autocvar_g_overkill_100a_anyway;
-bool autocvar_g_overkill_ammo_charge;
-float autocvar_g_overkill_ammo_charge_notice;
-float autocvar_g_overkill_ammo_charge_limit;
-float autocvar_g_spawn_near_teammate_distance;
-int autocvar_g_spawn_near_teammate_ignore_spawnpoint;
-float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
-float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
-int autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
-bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath;
 bool autocvar_g_physics_clientselect;
 string autocvar_g_physics_clientselect_options;
 string autocvar_g_physics_clientselect_default;
-bool  autocvar_g_buffs_effects;
-float autocvar_g_buffs_waypoint_distance;
-bool autocvar_g_buffs_randomize;
-float autocvar_g_buffs_random_lifetime;
-bool autocvar_g_buffs_random_location;
-int autocvar_g_buffs_random_location_attempts;
-int autocvar_g_buffs_spawn_count;
-bool autocvar_g_buffs_replace_powerups;
-float autocvar_g_buffs_cooldown_activate;
-float autocvar_g_buffs_cooldown_respawn;
-float autocvar_g_buffs_resistance_blockpercent;
-float autocvar_g_buffs_medic_survive_chance;
-float autocvar_g_buffs_medic_survive_health;
-float autocvar_g_buffs_medic_rot;
-float autocvar_g_buffs_medic_max;
-float autocvar_g_buffs_medic_regen;
-float autocvar_g_buffs_vengeance_damage_multiplier;
-float autocvar_g_buffs_bash_force;
-float autocvar_g_buffs_bash_force_self;
-float autocvar_g_buffs_disability_slowtime;
-float autocvar_g_buffs_disability_speed;
-float autocvar_g_buffs_disability_rate;
-float autocvar_g_buffs_disability_weaponspeed;
-float autocvar_g_buffs_speed_speed;
-float autocvar_g_buffs_speed_rate;
-float autocvar_g_buffs_speed_weaponspeed;
-float autocvar_g_buffs_speed_damage_take;
-float autocvar_g_buffs_speed_regen;
-float autocvar_g_buffs_vampire_damage_steal;
-float autocvar_g_buffs_invisible_alpha;
-float autocvar_g_buffs_flight_gravity;
-float autocvar_g_buffs_jump_height;
 bool autocvar_sv_minigames;
 bool autocvar_sv_minigames_observer;
-float autocvar_g_buffs_inferno_burntime_factor;
-float autocvar_g_buffs_inferno_burntime_min_time;
-float autocvar_g_buffs_inferno_burntime_target_damage;
-float autocvar_g_buffs_inferno_burntime_target_time;
-float autocvar_g_buffs_inferno_damagemultiplier;
-float autocvar_g_buffs_swapper_range;
-float autocvar_g_buffs_magnet_range_item;
 float autocvar_sv_player_scale;
 float autocvar_g_rm;
 float autocvar_g_rm_damage;
index 50e1d456f56e497720c5d153958518c48fac39f5..9541540298437b2a7526c326e8d5906e36b47030 100644 (file)
@@ -19,7 +19,7 @@ float findtrajectorywithleading(vector org, vector m1, vector m2, entity targ, f
        if (targ.solid < SOLID_BBOX) // SOLID_NOT and SOLID_TRIGGER
                return false; // could never hit it
        if (!tracetossent)
-               tracetossent = spawn();
+               tracetossent = new(tracetossent);
        tracetossent.owner = ignore;
        setsize(tracetossent, m1, m2);
        savesolid = targ.solid;
@@ -38,7 +38,7 @@ float findtrajectorywithleading(vector org, vector m1, vector m2, entity targ, f
        }
 
        if (!tracetossfaketarget)
-               tracetossfaketarget = spawn();
+               tracetossfaketarget = new(tracetossfaketarget);
        tracetossfaketarget.solid = savesolid;
        tracetossfaketarget.movetype = targ.movetype;
        _setmodel(tracetossfaketarget, targ.model); // no low precision
index c607de4f485988b24d9a310e34849881ed18a3f4..b125564716ae122e5a6cd4dd415e4e6d4a7e1189 100644 (file)
@@ -556,7 +556,7 @@ void autoskill(float factor)
                head.totalfrags_lastcheck = head.totalfrags;
 }
 
-void bot_calculate_stepheightvec(void)
+void bot_calculate_stepheightvec()
 {
        stepheightvec = autocvar_sv_stepheight * '0 0 1';
        jumpstepheightvec = stepheightvec +
index 2ae70728a0a78f1c47cb052cec9acb0994abdb76..12cd763e1fa2741c0498d63fc055ab3a43bf01b9 100644 (file)
@@ -114,5 +114,5 @@ void bot_serverframe();
 
 void() havocbot_setupbot;
 
-void bot_calculate_stepheightvec(void);
+void bot_calculate_stepheightvec();
 #endif
index ced6463c2ec7af55676390036fb3cbdc3030d56a..696de21dcad230f8f95a42ecd9fe49df82d5b479 100644 (file)
@@ -1045,7 +1045,7 @@ void havocbot_chooseweapon()
        // Should it do a weapon combo?
        float af, ct, combo_time, combo;
 
-       af = ATTACK_FINISHED(self);
+       af = ATTACK_FINISHED(self, 0);
        ct = autocvar_bot_ai_weapon_combo_threshold;
 
        // Bots with no skill will be 4 times more slower than "godlike" bots when doing weapon combos
index 76cda90d90f48dd98b796f31965f46ad4c017bdc..ea3a74fd54bea15d9bcac46c065f1d2a9ffee54f 100644 (file)
@@ -1059,10 +1059,11 @@ float bot_cmd_sound()
 .entity tuba_note;
 float bot_cmd_debug_assert_canfire()
 {SELFPARAM();
-       float f;
-       f = bot_cmd.bot_cmd_parm_float;
+       float f = bot_cmd.bot_cmd_parm_float;
 
-       if(self.weaponentity.state != WS_READY)
+       int slot = 0;
+       .entity weaponentity = weaponentities[slot];
+       if(self.(weaponentity).state != WS_READY)
        {
                if(f)
                {
@@ -1070,12 +1071,12 @@ float bot_cmd_debug_assert_canfire()
                        LOG_INFO("Bot ", self.netname, " using ", self.weaponname, " wants to fire, inhibited by weaponentity state\n");
                }
        }
-       else if(ATTACK_FINISHED(self) > time)
+       else if(ATTACK_FINISHED(self, slot) > time)
        {
                if(f)
                {
                        self.colormod = '8 0 8';
-                       LOG_INFO("Bot ", self.netname, " using ", self.weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(self) - time), " seconds left)\n");
+                       LOG_INFO("Bot ", self.netname, " using ", self.weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(self, slot) - time), " seconds left)\n");
                }
        }
        else if(self.tuba_note)
@@ -1091,7 +1092,7 @@ float bot_cmd_debug_assert_canfire()
                if(!f)
                {
                        self.colormod = '8 8 0';
-                       LOG_INFO("Bot ", self.netname, " using ", self.weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(self) - time), " seconds left\n");
+                       LOG_INFO("Bot ", self.netname, " using ", self.weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(self, slot) - time), " seconds left\n");
                }
        }
 
@@ -1118,9 +1119,8 @@ void bot_setcurrentcommand()
 
        if(!self.bot_cmd_current)
        {
-               self.bot_cmd_current = spawn();
-               self.bot_cmd_current.classname = "bot_cmd";
-               self.bot_cmd_current.is_bot_cmd = 1;
+               self.bot_cmd_current = new(bot_cmd);
+               self.bot_cmd_current.is_bot_cmd = true;
        }
 
        bot_cmd = self.bot_cmd_current;
index 156ad79fc256fbbfd3dbd79fb5ee711e1598fc1b..fe767b8c93384fa006a53b14321fdb86dbbca15d 100644 (file)
@@ -27,9 +27,9 @@ entity waypoint_spawn(vector m1, vector m2, float f)
                w = find(w, classname, "waypoint");
        }
 
-       w = spawn();
+       w = new(waypoint);
+       make_pure(w);
        w.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
-       w.classname = "waypoint";
        w.wpflags = f;
        setorigin(w, (m1 + m2) * 0.5);
        setsize(w, m1 - w.origin, m2 - w.origin);
index 8f34a7798b7fa90ceec7aeab4b0f3c1f74742f5d..5d6fba14fd8a2247aba7b8fd189635a2fe9f3ac2 100644 (file)
@@ -150,8 +150,7 @@ float CheatImpulse(float i)
                        // shared with regular waypoint init, so this is not a cheat by itself
                        if(!self.personal)
                        {
-                               self.personal = spawn();
-                               self.personal.classname = "personal_wp";
+                               self.personal = new(personal_wp);
                        }
                        self.personal.origin = self.origin;
                        self.personal.v_angle = self.v_angle;
@@ -338,7 +337,7 @@ float CheatCommand(float argc)
                                effectnum = _particleeffectnum(argv(1));
                                W_SetupShot(self, false, false, "", CH_WEAPON_A, 0);
                                traceline(w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, MOVE_NORMAL, self);
-                               trailparticles(self, effectnum, w_shotorg, trace_endpos);
+                               __trailparticles(self, effectnum, w_shotorg, trace_endpos);
                                DID_CHEAT();
                                break;
                        }
@@ -402,8 +401,7 @@ float CheatCommand(float argc)
                        break;
                case "dragbox_spawn": {
                        IS_CHEAT(0, argc, 0);
-                       entity e = spawn();
-                       e.classname = "dragbox_box";
+                       entity e = new(dragbox_box);
                        e.think = DragBox_Think;
                        e.nextthink = time;
                        e.solid = -1; // black
@@ -413,8 +411,7 @@ float CheatCommand(float argc)
                        else
                                e.cnt = max(0, drag_lastcnt);
 
-                       e.aiment = spawn();
-                       e.aiment.classname = "dragbox_corner_1";
+                       e.aiment = new(dragbox_corner_1);
                        e.aiment.owner = e;
                        setmodel(e.aiment, MDL_MARKER);
                        e.aiment.skin = 0;
@@ -427,8 +424,7 @@ float CheatCommand(float argc)
                                setorigin(e.aiment, trace_endpos);
                        }
 
-                       e.enemy = spawn();
-                       e.enemy.classname = "dragbox_corner_2";
+                       e.enemy = new(dragbox_corner_2);
                        e.enemy.owner = e;
                        setmodel(e.enemy, MDL_MARKER);
                        e.enemy.skin = 1;
@@ -442,13 +438,11 @@ float CheatCommand(float argc)
                        else
                                setorigin(e.enemy, e.aiment.origin + 32 * end);
 
-                       e.killindicator = spawn();
-                       e.killindicator.classname = "drag_digit";
+                       e.killindicator = new(drag_digit);
                        e.killindicator.owner = e;
                        setattachment(e.killindicator, e, "");
                        setorigin(e.killindicator, '0 0 -8');
-                       e.killindicator.killindicator = spawn();
-                       e.killindicator.killindicator.classname = "drag_digit";
+                       e.killindicator.killindicator = new(drag_digit);
                        e.killindicator.killindicator.owner = e;
                        setattachment(e.killindicator.killindicator, e, "");
                        setorigin(e.killindicator.killindicator, '0 0 8');
@@ -457,8 +451,7 @@ float CheatCommand(float argc)
                }
                case "dragpoint_spawn": {
                        IS_CHEAT(0, argc, 0);
-                       entity e = spawn();
-                       e.classname = "dragpoint";
+                       entity e = new(dragpoint);
                        e.think = DragBox_Think;
                        e.nextthink = time;
                        e.solid = 0; // nothing special
@@ -478,13 +471,11 @@ float CheatCommand(float argc)
                                move_out_of_solid(e);
                        }
 
-                       e.killindicator = spawn();
-                       e.killindicator.classname = "drag_digit";
+                       e.killindicator = new(drag_digit);
                        e.killindicator.owner = e;
                        setattachment(e.killindicator, e, "");
                        setorigin(e.killindicator, '0 0 40');
-                       e.killindicator.killindicator = spawn();
-                       e.killindicator.killindicator.classname = "drag_digit";
+                       e.killindicator.killindicator = new(drag_digit);
                        e.killindicator.killindicator.owner = e;
                        setattachment(e.killindicator.killindicator, e, "");
                        setorigin(e.killindicator.killindicator, '0 0 56');
@@ -713,9 +704,8 @@ float CheatCommand(float argc)
                        break;
                case "teleporttotarget":
                        IS_CHEAT(0, argc, 0);
-                       setself(spawn());
+                       setself(new(cheattriggerteleport));
                        setorigin(self, self.origin);
-                       self.classname = "cheattriggerteleport";
                        self.target = argv(1);
                        teleport_findtarget();
                        if(!wasfreed(self))
@@ -1025,8 +1015,9 @@ void Drag_Update(entity dragger)
        draggee.ltime = max(servertime + serverframetime, draggee.ltime); // fixes func_train breakage
 
        vector vecs = '0 0 0';
-       if(dragger.weaponentity.movedir_x > 0)
-               vecs = dragger.weaponentity.movedir;
+       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+       if(dragger.(weaponentity).movedir.x > 0)
+               vecs = dragger.(weaponentity).movedir;
 
        vector dv = v_right * -vecs_y + v_up * vecs_z;
 
index eb3dfc44e1aa12fad5259746286f08858719735e..24a63d5aab0e8823b07b5fec3eb73dba70528d7c 100644 (file)
@@ -50,8 +50,7 @@
 
 
 void send_CSQC_teamnagger() {
-       WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-       WriteByte(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
+       WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
 }
 
 bool ClientData_Send(entity this, entity to, int sf)
@@ -79,7 +78,7 @@ bool ClientData_Send(entity this, entity to, int sf)
        if(e.porto_v_angle_held)
                sf |= 8; // angles held
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
        WriteByte(MSG_ENTITY, sf);
 
        if(sf & 2)
@@ -96,9 +95,10 @@ bool ClientData_Send(entity this, entity to, int sf)
 
 void ClientData_Attach()
 {SELFPARAM();
-       Net_LinkEntity(self.clientdata = spawn(), false, 0, ClientData_Send);
-       self.clientdata.drawonlytoclient = self;
-       self.clientdata.owner = self;
+       Net_LinkEntity(this.clientdata = new(clientdata), false, 0, ClientData_Send);
+       make_pure(this.clientdata);
+       self.clientdata.drawonlytoclient = this;
+       self.clientdata.owner = this;
 }
 
 void ClientData_Detach()
@@ -175,7 +175,7 @@ void setplayermodel(entity e, string modelname)
        precache_model(modelname);
        _setmodel(e, modelname);
        player_setupanimsformodel();
-       UpdatePlayerSounds();
+       UpdatePlayerSounds(e);
 }
 
 /*
@@ -304,7 +304,10 @@ void PutObserverInServer()
        self.weaponname = "";
        self.switchingweapon = 0;
        self.weaponmodel = "";
-       self.weaponentity = world;
+       for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       {
+               self.weaponentities[slot] = NULL;
+       }
        self.exteriorweaponentity = world;
        self.killcount = FRAGS_SPECTATOR;
        self.velocity = '0 0 0';
@@ -316,6 +319,15 @@ void PutObserverInServer()
        self.event_damage = func_null;
 }
 
+int player_getspecies(entity this)
+{
+       get_model_parameters(this.model, this.skin);
+       int s = get_model_parameters_species;
+       get_model_parameters(string_null, 0);
+       if (s < 0) return SPECIES_HUMAN;
+       return s;
+}
+
 .float model_randomizer;
 void FixPlayermodel(entity player)
 {
@@ -392,8 +404,8 @@ void FixPlayermodel(entity player)
 
        if(chmdl || oldskin != player.skin) // model or skin has changed
        {
-               player.species = player_getspecies(); // update species
-               UpdatePlayerSounds(); // update skin sounds
+               player.species = player_getspecies(player); // update species
+               UpdatePlayerSounds(player); // update skin sounds
        }
 
        if(!teamplay)
@@ -532,7 +544,8 @@ void PutClientInServer()
                this.revival_time = 0;
                this.air_finished = time + 12;
 
-               entity spawnevent = spawn();
+               entity spawnevent = new(spawnevent);
+               make_pure(spawnevent);
                spawnevent.owner = this;
                Net_LinkEntity(spawnevent, false, 0.5, SpawnEvent_Send);
 
@@ -568,7 +581,10 @@ void PutClientInServer()
                        this.killcount = 0;
                }
 
-               CL_SpawnWeaponentity(this);
+               for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+               {
+                       CL_SpawnWeaponentity(this, weaponentities[slot]);
+               }
                this.alpha = default_player_alpha;
                this.colormod = '1 1 1' * autocvar_g_player_brightness;
                this.exteriorweaponentity.alpha = default_weapon_alpha;
@@ -623,34 +639,40 @@ void PutClientInServer()
 // changes and just have a console command to update this?
 bool ClientInit_SendEntity(entity this, entity to, int sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_INIT);
-       WriteByte(MSG_ENTITY, g_nexball_meter_period * 32);
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[0]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[1]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[2]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[3]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[0]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[1]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[2]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[3]));
+       WriteHeader(MSG_ENTITY, _ENT_CLIENT_INIT);
+       return = true;
+       msg_entity = to;
+       Registry_send_all();
+       int channel = MSG_ONE;
+       WriteHeader(channel, ENT_CLIENT_INIT);
+       WriteByte(channel, g_nexball_meter_period * 32);
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[0]));
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[1]));
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[2]));
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[3]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[0]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[1]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[2]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[3]));
 
        if(sv_foginterval && world.fog != "")
-               WriteString(MSG_ENTITY, world.fog);
+               WriteString(channel, world.fog);
        else
-               WriteString(MSG_ENTITY, "");
-       WriteByte(MSG_ENTITY, self.count * 255.0); // g_balance_armor_blockpercent
-       WriteCoord(MSG_ENTITY, self.bouncefactor); // g_balance_mortar_bouncefactor // WEAPONTODO
-       WriteCoord(MSG_ENTITY, self.bouncestop); // g_balance_mortar_bouncestop
-       WriteCoord(MSG_ENTITY, self.ebouncefactor); // g_balance_mortar_bouncefactor
-       WriteCoord(MSG_ENTITY, self.ebouncestop); // g_balance_mortar_bouncestop
-       WriteByte(MSG_ENTITY, WEP_CVAR(vortex, secondary)); // client has to know if it should zoom or not // WEAPONTODO
-       WriteByte(MSG_ENTITY, WEP_CVAR(rifle, secondary)); // client has to know if it should zoom or not // WEAPONTODO
-       WriteByte(MSG_ENTITY, serverflags); // client has to know if it should zoom or not
-       WriteByte(MSG_ENTITY, WEP_CVAR(minelayer, limit)); // minelayer max mines // WEAPONTODO
-       WriteByte(MSG_ENTITY, WEP_CVAR_SEC(hagar, load_max)); // hagar max loadable rockets // WEAPONTODO
-       WriteCoord(MSG_ENTITY, autocvar_g_trueaim_minrange);
-       WriteByte(MSG_ENTITY, WEP_CVAR(porto, secondary)); // WEAPONTODO
-       return true;
+               WriteString(channel, "");
+       WriteByte(channel, self.count * 255.0); // g_balance_armor_blockpercent
+       WriteCoord(channel, self.bouncefactor); // g_balance_mortar_bouncefactor // WEAPONTODO
+       WriteCoord(channel, self.bouncestop); // g_balance_mortar_bouncestop
+       WriteCoord(channel, self.ebouncefactor); // g_balance_mortar_bouncefactor
+       WriteCoord(channel, self.ebouncestop); // g_balance_mortar_bouncestop
+       WriteByte(channel, WEP_CVAR(vortex, secondary)); // client has to know if it should zoom or not // WEAPONTODO
+       WriteByte(channel, WEP_CVAR(rifle, secondary)); // client has to know if it should zoom or not // WEAPONTODO
+       WriteByte(channel, serverflags); // client has to know if it should zoom or not
+       WriteByte(channel, WEP_CVAR(minelayer, limit)); // minelayer max mines // WEAPONTODO
+       WriteByte(channel, WEP_CVAR_SEC(hagar, load_max)); // hagar max loadable rockets // WEAPONTODO
+       WriteCoord(channel, autocvar_g_trueaim_minrange);
+       WriteByte(channel, WEP_CVAR(porto, secondary)); // WEAPONTODO
+
+       MUTATOR_CALLHOOK(Ent_Init);
 }
 
 void ClientInit_CheckUpdate()
@@ -685,8 +707,9 @@ void ClientInit_CheckUpdate()
 
 void ClientInit_Spawn()
 {SELFPARAM();
-       entity e = spawn();
-       e.classname = "clientinit";
+
+       entity e = new(clientinit);
+       make_pure(e);
        e.think = ClientInit_CheckUpdate;
        Net_LinkEntity(e, false, 0, ClientInit_SendEntity);
 
@@ -698,7 +721,7 @@ void ClientInit_Spawn()
 SetNewParms
 =============
 */
-void SetNewParms (void)
+void SetNewParms ()
 {
        // initialize parms for a new player
        parm1 = -(86400 * 366);
@@ -711,7 +734,7 @@ void SetNewParms (void)
 SetChangeParms
 =============
 */
-void SetChangeParms (void)
+void SetChangeParms ()
 {SELFPARAM();
        // save parms for level change
        parm1 = self.parm_idlesince - time;
@@ -724,7 +747,7 @@ void SetChangeParms (void)
 DecodeLevelParms
 =============
 */
-void DecodeLevelParms (void)
+void DecodeLevelParms ()
 {SELFPARAM();
        // load parms
        self.parm_idlesince = parm1;
@@ -927,7 +950,7 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2
 
 }
 
-void ClientKill (void)
+void ClientKill ()
 {SELFPARAM();
        if(gameover) return;
        if(self.player_blocked) return;
@@ -975,7 +998,7 @@ ClientPreConnect
 Called once (not at each match start) when a client begins a connection to the server
 =============
 */
-void ClientPreConnect (void)
+void ClientPreConnect ()
 {SELFPARAM();
        if(autocvar_sv_eventlog)
        {
@@ -995,8 +1018,8 @@ ClientConnect
 Called when a client connects to the server
 =============
 */
-void DecodeLevelParms (void);
-void ClientConnect (void)
+void DecodeLevelParms ();
+void ClientConnect ()
 {SELFPARAM();
        float t;
 
@@ -1214,7 +1237,7 @@ Called when a client disconnects from the server
 */
 .entity chatbubbleentity;
 void ReadyCount();
-void ClientDisconnect (void)
+void ClientDisconnect ()
 {SELFPARAM();
        if(self.vehicle)
            vehicles_exit(VHEF_RELEASE);
@@ -1284,7 +1307,7 @@ void ClientDisconnect (void)
        if(self.weaponorder_byimpulse)
                strunzone(self.weaponorder_byimpulse);
 
-       ClearPlayerSounds();
+       ClearPlayerSounds(self);
 
        if(self.personal)
                remove(self.personal);
@@ -1330,7 +1353,7 @@ void UpdateChatBubble()
        // spawn a chatbubble entity if needed
        if (!self.chatbubbleentity)
        {
-               self.chatbubbleentity = spawn();
+               self.chatbubbleentity = new(chatbubbleentity);
                self.chatbubbleentity.owner = self;
                self.chatbubbleentity.exteriormodeltoclient = self;
                self.chatbubbleentity.think = ChatBubbleThink;
@@ -1362,7 +1385,7 @@ void UpdateChatBubble()
        else self.colormod = '1 1 1';
 }*/
 
-void respawn(void)
+void respawn()
 {SELFPARAM();
        if(self.alpha >= 0 && autocvar_g_respawn_ghosts)
        {
@@ -1391,7 +1414,7 @@ void play_countdown(float finished, string samp)
                                _sound (self, CH_INFO, samp, VOL_BASE, ATTEN_NORM);
 }
 
-void player_powerups (void)
+void player_powerups ()
 {SELFPARAM();
        // add a way to see what the items were BEFORE all of these checks for the mutator hook
        int items_prev = self.items;
@@ -1554,7 +1577,7 @@ float CalcRotRegen(float current, float regenstable, float regenfactor, float re
        return current;
 }
 
-void player_regen (void)
+void player_regen ()
 {SELFPARAM();
        float max_mod, regen_mod, rot_mod, limit_mod;
        max_mod = regen_mod = rot_mod = limit_mod = 1;
@@ -1625,19 +1648,20 @@ void SetZoomState(float z)
 }
 
 void GetPressedKeys()
-{SELFPARAM();
+{
+       SELFPARAM();
        MUTATOR_CALLHOOK(GetPressedKeys);
-       #define X(var,bit,flag) (flag ? var |= bit : var &= ~bit)
-       X(self.pressedkeys, KEY_FORWARD,        self.movement_x > 0);
-       X(self.pressedkeys, KEY_BACKWARD,       self.movement_x < 0);
-       X(self.pressedkeys, KEY_RIGHT,          self.movement_y > 0);
-       X(self.pressedkeys, KEY_LEFT,           self.movement_y < 0);
-
-       X(self.pressedkeys, KEY_JUMP,           PHYS_INPUT_BUTTON_JUMP(self));
-       X(self.pressedkeys, KEY_CROUCH,         PHYS_INPUT_BUTTON_CROUCH(self));
-       X(self.pressedkeys, KEY_ATCK,           PHYS_INPUT_BUTTON_ATCK(self));
-       X(self.pressedkeys, KEY_ATCK2,          PHYS_INPUT_BUTTON_ATCK2(self));
-       #undef X
+       int keys = this.pressedkeys;
+       keys = BITSET(keys, KEY_FORWARD,        this.movement.x > 0);
+       keys = BITSET(keys, KEY_BACKWARD,       this.movement.x < 0);
+       keys = BITSET(keys, KEY_RIGHT,          this.movement.y > 0);
+       keys = BITSET(keys, KEY_LEFT,           this.movement.y < 0);
+
+       keys = BITSET(keys, KEY_JUMP,           PHYS_INPUT_BUTTON_JUMP(this));
+       keys = BITSET(keys, KEY_CROUCH,         PHYS_INPUT_BUTTON_CROUCH(this));
+       keys = BITSET(keys, KEY_ATCK,           PHYS_INPUT_BUTTON_ATCK(this));
+       keys = BITSET(keys, KEY_ATCK2,          PHYS_INPUT_BUTTON_ATCK2(this));
+       this.pressedkeys = keys;
 }
 
 /*
@@ -1780,10 +1804,9 @@ bool SpectateNext()
 {SELFPARAM();
        other = find(self.enemy, classname, "player");
 
-       bool mutator_returnvalue = MUTATOR_CALLHOOK(SpectateNext, self, other);
-       other = spec_player;
-
-       if(!mutator_returnvalue && !other)
+       if (MUTATOR_CALLHOOK(SpectateNext, self, other))
+               other = spec_player;
+       else if (!other)
                other = find(other, classname, "player");
 
        if(other) { SetSpectatee(self, other); }
@@ -1804,13 +1827,14 @@ bool SpectatePrev()
        while(other && other != self.enemy)
                other = other.chain;
 
-       int mutator_returnvalue = MUTATOR_CALLHOOK(SpectatePrev, self, other, first);
-       other = spec_player;
-
-       switch(mutator_returnvalue)
+       switch (MUTATOR_CALLHOOK(SpectatePrev, self, other, first))
        {
-               case MUT_SPECPREV_FOUND: break;
-               case MUT_SPECPREV_RETURN: return true;
+               case MUT_SPECPREV_FOUND:
+                   other = spec_player;
+                   break;
+               case MUT_SPECPREV_RETURN:
+                   other = spec_player;
+                   return true;
                case MUT_SPECPREV_CONTINUE:
                default:
                {
@@ -1861,7 +1885,6 @@ void LeaveSpectatorMode()
                if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0)
                {
                        self.classname = STR_PLAYER;
-                       nades_RemoveBonus(self);
 
                        if(autocvar_g_campaign || autocvar_g_balance_teams)
                                { JoinBestTeam(self, false, true); }
@@ -1982,7 +2005,7 @@ void PrintWelcomeMessage()
        {
                if(self.BUTTON_INFO) // BUTTON_INFO hides initial MOTD
                        self.motd_actived_time = -2; // wait until BUTTON_INFO gets released
-               else if(self.motd_actived_time == -2 || IS_PLAYER(self))
+               else if(self.motd_actived_time == -2 || IS_PLAYER(self) || IS_SPEC(self))
                {
                        // instanctly hide MOTD
                        self.motd_actived_time = 0;
@@ -2129,32 +2152,6 @@ void PlayerUseKey()
        MUTATOR_CALLHOOK(PlayerUseKey);
 }
 
-float isInvisibleString(string s)
-{
-       float i, n, c;
-       s = strdecolorize(s);
-       for((i = 0), (n = strlen(s)); i < n; ++i)
-       {
-               c = str2chr(s, i);
-               switch(c)
-               {
-                       case 0:
-                       case 32: // space
-                               break;
-                       case 192: // charmap space
-                               if (!autocvar_utf8_enable)
-                                       break;
-                               return false;
-                       case 160: // space in unicode fonts
-                       case 0xE000 + 192: // utf8 charmap space
-                               if (autocvar_utf8_enable)
-                                       break;
-                       default:
-                               return false;
-               }
-       }
-       return true;
-}
 
 /*
 =============
@@ -2167,7 +2164,7 @@ Called every frame for each client before the physics are run
 void() nexball_setstatus;
 .float last_vehiclecheck;
 .int items_added;
-void PlayerPreThink (void)
+void PlayerPreThink ()
 {SELFPARAM();
        WarpZone_PlayerPhysics_FixVAngle();
 
@@ -2427,7 +2424,8 @@ void PlayerPreThink (void)
 
                // WEAPONTODO: THIS SHIT NEEDS TO GO EVENTUALLY
                // It cannot be predicted by the engine!
-               if((self.weapon == WEP_SHOCKWAVE.m_id || self.weapon == WEP_SHOTGUN.m_id) && self.weaponentity.wframe == WFRAME_FIRE2 && time < self.weapon_nextthink)
+               .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+               if((self.weapon == WEP_SHOCKWAVE.m_id || self.weapon == WEP_SHOTGUN.m_id) && self.(weaponentity).wframe == WFRAME_FIRE2 && time < self.(weaponentity).weapon_nextthink)
                        do_crouch = 0;
 
                if (do_crouch)
@@ -2555,7 +2553,7 @@ Called every frame for each client after the physics are run
 =============
 */
 .float idlekick_lasttimeleft;
-void PlayerPostThink (void)
+void PlayerPostThink ()
 {SELFPARAM();
        if(sv_maxidle > 0 && frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
        if(IS_REAL_CLIENT(self))
index 8b36e17531c6a221d70d8ca2fa088b12b29c5f00..58f1a9bd37022a67ed9ff399788706bde4c94a60 100644 (file)
@@ -54,7 +54,7 @@
  * 230 to 253: individual weapons (up to 24)
  */
 
-void ImpulseCommands (void)
+void ImpulseCommands ()
 {SELFPARAM();
        int imp;
        vector org;
@@ -145,8 +145,8 @@ void ImpulseCommands (void)
                                        break;
                        }
                }
-               else
-                       self.impulse = imp; // retry in next frame
+               //else
+                       //self.impulse = imp; // retry in next frame
        }
        else if(imp == 21)
        {
@@ -162,16 +162,16 @@ void ImpulseCommands (void)
                        m = (imp - (210 + i)); // <0 for prev, =0 for best, >0 for next
                        W_CycleWeapon(self.(cvar_cl_weaponpriorities[i]), m);
                }
-               else
-                       self.impulse = imp; // retry in next frame
+               //else
+                       //self.impulse = imp; // retry in next frame
        }
        else if(imp >= WEP_IMPULSE_BEGIN && imp <= WEP_IMPULSE_END)
        {
                if(!self.vehicle)
                if(self.deadflag == DEAD_NO)
                        W_SwitchWeapon (imp - WEP_IMPULSE_BEGIN + WEP_FIRST);
-               else
-                       self.impulse = imp; // retry in next frame
+               //else
+                       //self.impulse = imp; // retry in next frame
        }
        // deploy waypoints
        else if (imp >= 30 && imp <= 49)
index ced8119469a3964b4b48c292f9c027a3ddc88526..3a5ed9ecdfdf821398dc2f8c8a3378fc460628a8 100644 (file)
@@ -36,5 +36,5 @@
  * 230 to 253: individual weapons (up to 24)
  */
 
-void ImpulseCommands (void);
+void ImpulseCommands ();
 #endif
index 01b9ab0d3411abcfd321026a8a14c176d4a8a71e..b49488b0553701cb528de71fd1261c0326c38e65 100644 (file)
@@ -4,7 +4,6 @@
 #include "cheats.qh"
 #include "g_damage.qh"
 #include "g_subs.qh"
-#include "g_violence.qh"
 #include "miscfunctions.qh"
 #include "portals.qh"
 #include "teamplay.qh"
@@ -34,7 +33,7 @@ void Drop_Special_Items(entity player)
        MUTATOR_CALLHOOK(DropSpecialItems, player);
 }
 
-void CopyBody_Think(void)
+void CopyBody_Think()
 {SELFPARAM();
        if(self.CopyBody_nextthink && time > self.CopyBody_nextthink)
        {
@@ -52,7 +51,7 @@ void CopyBody(float keepvelocity)
 {SELFPARAM();
        if (self.effects & EF_NODRAW)
                return;
-       setself(spawn());
+       setself(new(body));
        self.enemy = this;
        self.lip = this.lip;
        self.colormap = this.colormap;
@@ -62,7 +61,6 @@ void CopyBody(float keepvelocity)
        self.angles = this.angles;
        self.v_angle = this.v_angle;
        self.avelocity = this.avelocity;
-       self.classname = "body";
        self.damageforcescale = this.damageforcescale;
        self.effects = this.effects;
        self.glowmod = this.glowmod;
@@ -125,17 +123,6 @@ void CopyBody(float keepvelocity)
        setself(this);
 }
 
-float player_getspecies()
-{SELFPARAM();
-       float s;
-       get_model_parameters(self.model, self.skin);
-       s = get_model_parameters_species;
-       get_model_parameters(string_null, 0);
-       if(s < 0)
-               return SPECIES_HUMAN;
-       return s;
-}
-
 void player_setupanimsformodel()
 {SELFPARAM();
        // load animation info
@@ -143,7 +130,7 @@ void player_setupanimsformodel()
        animdecide_setstate(self, 0, false);
 }
 
-void player_anim (void)
+void player_anim ()
 {SELFPARAM();
        int deadbits = (self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
        if(self.deadflag) {
@@ -168,11 +155,14 @@ void player_anim (void)
        animdecide_setstate(self, animbits, false);
        animdecide_setimplicitstate(self, (self.flags & FL_ONGROUND));
 
-       if (self.weaponentity)
+       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
        {
-               updateanim(self.weaponentity);
-               if (!self.weaponentity.animstate_override)
-                       setanim(self.weaponentity, self.weaponentity.anim_idle, true, false, false);
+               if (self.(weaponentity))
+               {
+                       updateanim(self.(weaponentity));
+                       if (!self.(weaponentity).animstate_override)
+                               setanim(self.(weaponentity), self.(weaponentity).anim_idle, true, false, false);
+               }
        }
 }
 
@@ -479,9 +469,18 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, int deathtyp
        self.dmg_take = self.dmg_take + take;//max(take - 10, 0);
        self.dmg_inflictor = inflictor;
 
-       float abot, vbot;
-       abot = (IS_BOT_CLIENT(attacker));
-       vbot = (IS_BOT_CLIENT(self));
+       if (self != attacker) {
+               float realdmg = damage - excess;
+               if (IS_PLAYER(attacker)) {
+                       PlayerScore_Add(attacker, SP_DMG, realdmg);
+               }
+               if (IS_PLAYER(self)) {
+                       PlayerScore_Add(self, SP_DMGTAKEN, realdmg);
+               }
+       }
+
+       bool abot = (IS_BOT_CLIENT(attacker));
+       bool vbot = (IS_BOT_CLIENT(self));
 
        valid_damage_for_weaponstats = 0;
        Weapon awep = WEP_Null;
@@ -643,17 +642,33 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, int deathtyp
                {
                        Weapon w = get_weaponinfo(j);
                        w.wr_resetplayer(w);
-                       ATTACK_FINISHED_FOR(self, j) = 0;
+                       for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+                       {
+                               ATTACK_FINISHED_FOR(self, j, slot) = 0;
+                       }
                }
        }
 }
 
-float Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol)
-// message "": do not say, just test flood control
-// return value:
-//   1 = accept
-//   0 = reject
-//  -1 = fake accept
+void MoveToTeam(entity client, int team_colour, int type)
+{
+       int lockteams_backup = lockteams;  // backup any team lock
+       lockteams = 0;  // disable locked teams
+       TeamchangeFrags(client);  // move the players frags
+       SetPlayerColors(client, team_colour - 1);  // set the players colour
+       Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, client.origin, '0 0 0');  // kill the player
+       lockteams = lockteams_backup;  // restore the team lock
+       LogTeamchange(client.playerid, client.team, type);
+}
+
+/**
+ * message "": do not say, just test flood control
+ * return value:
+ *   1 = accept
+ *   0 = reject
+ *  -1 = fake accept
+ */
+int Say(entity source, float teamsay, entity privatesay, string msgin, bool floodcontrol)
 {
        string msgstr, colorstr, cmsgstr, namestr, fullmsgstr, sourcemsgstr, fullcmsgstr, sourcecmsgstr, colorprefix;
        float flood;
@@ -945,347 +960,281 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f
        return ret;
 }
 
-float GetVoiceMessageVoiceType(string type)
+int GetVoiceMessageVoiceType(string type)
 {
-       if(type == "taunt")
-               return VOICETYPE_TAUNT;
-       if(type == "teamshoot")
-               return VOICETYPE_LASTATTACKER;
+       if (type == "taunt") return VOICETYPE_TAUNT;
+       if (type == "teamshoot") return VOICETYPE_LASTATTACKER;
        return VOICETYPE_TEAMRADIO;
 }
 
 .string GetVoiceMessageSampleField(string type)
 {
-       GetPlayerSoundSampleField_notFound = 0;
-       switch(type)
+       GetPlayerSoundSampleField_notFound = false;
+       switch (type)
        {
-#define _VOICEMSG(m) case #m: return playersound_##m;
-               ALLVOICEMSGS
-#undef _VOICEMSG
+#define X(m) case #m: return playersound_##m;
+               ALLVOICEMSGS(X)
+#undef X
        }
-       GetPlayerSoundSampleField_notFound = 1;
+       GetPlayerSoundSampleField_notFound = true;
        return playersound_taunt;
 }
 
 .string GetPlayerSoundSampleField(string type)
 {
-       GetPlayerSoundSampleField_notFound = 0;
-       switch(type)
+       GetPlayerSoundSampleField_notFound = false;
+       switch (type)
        {
-#define _VOICEMSG(m) case #m: return playersound_##m;
-               ALLPLAYERSOUNDS
-#undef _VOICEMSG
+#define X(m) case #m: return playersound_##m;
+               ALLPLAYERSOUNDS(X)
+#undef X
        }
-       GetPlayerSoundSampleField_notFound = 1;
+       GetPlayerSoundSampleField_notFound = true;
        return playersound_taunt;
 }
 
-void PrecacheGlobalSound(string samplestring)
+void PrecacheGlobalSound(string sample)
 {
-       float n, i;
-       tokenize_console(samplestring);
-       n = stof(argv(1));
-       if(n > 0)
+       int n;
        {
-               for(i = 1; i <= n; ++i)
-                       precache_sound(strcat(argv(0), ftos(i), ".wav"));
+               string s = cdr(sample);
+               if (s) n = stof(s);
+               else n = 0;
+       }
+       sample = car(sample);
+       if (n > 0)
+       {
+               for (int i = 1; i <= n; ++i)
+                       precache_sound(sprintf("%s%d.wav", sample, i));
        }
        else
        {
-               precache_sound(strcat(argv(0), ".wav"));
+               precache_sound(sprintf("%s.wav", sample));
        }
 }
 
+string allvoicesamples;
+
 void PrecachePlayerSounds(string f)
 {
        int fh = fopen(f, FILE_READ);
        if (fh < 0)
+       {
+               LOG_WARNINGF("Player sound file not found: %s\n", f);
                return;
+       }
        for (string s; (s = fgets(fh)); )
        {
                int n = tokenize_console(s);
                if (n != 3)
                {
-                       if (n != 0) LOG_TRACEF("Invalid sound info line: %s\n", s);
+                       if (n != 0) LOG_WARNINGF("Invalid sound info line: %s\n", s);
                        continue;
                }
-               PrecacheGlobalSound(strcat(argv(1), " ", argv(2)));
+               string file = argv(1);
+               string variants = argv(2);
+               PrecacheGlobalSound(strcat(file, " ", variants));
        }
        fclose(fh);
 
        if (!allvoicesamples)
        {
-#define _VOICEMSG(m) allvoicesamples = strcat(allvoicesamples, " ", #m);
-               ALLVOICEMSGS
-#undef _VOICEMSG
-               allvoicesamples = strzone(substring(allvoicesamples, 1, strlen(allvoicesamples) - 1));
+#define X(m) allvoicesamples = strcat(allvoicesamples, " ", #m);
+               ALLVOICEMSGS(X)
+#undef X
+               allvoicesamples = strzone(substring(allvoicesamples, 1, -1));
        }
 }
 
-void ClearPlayerSounds()
-{SELFPARAM();
-#define _VOICEMSG(m) if(self.playersound_##m) { strunzone(self.playersound_##m); self.playersound_##m = string_null; }
-       ALLPLAYERSOUNDS
-       ALLVOICEMSGS
-#undef _VOICEMSG
+void ClearPlayerSounds(entity this)
+{
+#define X(m) if (this.playersound_##m) { strunzone(this.playersound_##m); this.playersound_##m = string_null; }
+       ALLPLAYERSOUNDS(X)
+       ALLVOICEMSGS(X)
+#undef X
 }
 
-float LoadPlayerSounds(string f, float first)
-{SELFPARAM();
-       float fh;
-       string s;
-       var .string field;
-       fh = fopen(f, FILE_READ);
-       if(fh < 0)
+bool LoadPlayerSounds(string f, bool strict)
+{
+       SELFPARAM();
+       int fh = fopen(f, FILE_READ);
+       if (fh < 0)
        {
-               LOG_TRACE("Player sound file not found: ", f, "\n");
-               return 0;
+               if (strict) LOG_WARNINGF("Player sound file not found: %s\n", f);
+               return false;
        }
-       while((s = fgets(fh)))
+       for (string s; (s = fgets(fh)); )
        {
-               if(tokenize_console(s) != 3)
+               int n = tokenize_console(s);
+               if (n != 3)
+               {
+                       if (n != 0) LOG_WARNINGF("Invalid sound info line: %s\n", s);
                        continue;
-               field = GetPlayerSoundSampleField(argv(0));
-               if(GetPlayerSoundSampleField_notFound)
-                       field = GetVoiceMessageSampleField(argv(0));
-               if(GetPlayerSoundSampleField_notFound)
+               }
+               string key = argv(0);
+               var .string field = GetPlayerSoundSampleField(key);
+               if (GetPlayerSoundSampleField_notFound) field = GetVoiceMessageSampleField(key);
+               if (GetPlayerSoundSampleField_notFound)
+               {
+                       LOG_TRACEF("Invalid sound info field: %s\n", key);
                        continue;
-               if (self.(field))
-                       strunzone(self.(field));
-               self.(field) = strzone(strcat(argv(1), " ", argv(2)));
+               }
+               string file = argv(1);
+               string variants = argv(2);
+               if (self.(field)) strunzone(self.(field));
+               self.(field) = strzone(strcat(file, " ", variants));
        }
        fclose(fh);
-       return 1;
-}
-
-void UpdatePlayerSounds()
-{SELFPARAM();
-       if(self.modelindex == self.modelindex_for_playersound)
-       if(self.skin == self.skin_for_playersound)
-               return;
-       self.modelindex_for_playersound = self.modelindex;
-       self.skin_for_playersound = self.skin;
-       ClearPlayerSounds();
-       LoadPlayerSounds("sound/player/default.sounds", 1);
-       if(!autocvar_g_debug_defaultsounds)
-               if(!LoadPlayerSounds(get_model_datafilename(self.model, self.skin, "sounds"), 0))
-                       LoadPlayerSounds(get_model_datafilename(self.model, 0, "sounds"), 0);
+       return true;
 }
 
-void FakeGlobalSound(string sample, float chan, float voicetype)
-{SELFPARAM();
-       float n;
-       float tauntrand;
-
-       if(sample == "")
-               return;
+.int modelindex_for_playersound;
+.int skin_for_playersound;
 
-       tokenize_console(sample);
-       n = stof(argv(1));
-       if(n > 0)
-               sample = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
-       else
-               sample = strcat(argv(0), ".wav"); // randomization
+void UpdatePlayerSounds(entity this)
+{
+       if (this.modelindex == this.modelindex_for_playersound && this.skin == this.skin_for_playersound) return;
+       this.modelindex_for_playersound = this.modelindex;
+       this.skin_for_playersound = this.skin;
+       ClearPlayerSounds(this);
+       LoadPlayerSounds("sound/player/default.sounds", true);
+       if (autocvar_g_debug_defaultsounds) return;
+       if (!LoadPlayerSounds(get_model_datafilename(this.model, this.skin, "sounds"), false))
+               LoadPlayerSounds(get_model_datafilename(this.model, 0, "sounds"), true);
+}
 
-       switch(voicetype)
+void _GlobalSound(string sample, int chan, int voicetype, bool fake)
+{
+       SELFPARAM();
+       if (sample == "") return;
+       int n;
+       {
+               string s = cdr(sample);
+               if (s) n = stof(s);
+               else n = 0;
+       }
+       sample = car(sample);
+       if (n > 0) sample = sprintf("%s%d.wav", sample, floor(random() * n + 1));  // randomization
+       else sample = sprintf("%s.wav", sample);
+       switch (voicetype)
        {
                case VOICETYPE_LASTATTACKER_ONLY:
-                       break;
                case VOICETYPE_LASTATTACKER:
-                       if(self.pusher)
+               {
+                       if (!fake)
                        {
-                               msg_entity = self;
-                               if(IS_REAL_CLIENT(msg_entity))
-                                       soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTEN_NONE);
+                               if (!this.pusher) break;
+                               msg_entity = this.pusher;
+                               if (IS_REAL_CLIENT(msg_entity))
+                               {
+                                       float atten = (msg_entity.cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE;
+                                       soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten);
+                               }
                        }
+                       if (voicetype == VOICETYPE_LASTATTACKER_ONLY) break;
+                       msg_entity = this;
+                       if (IS_REAL_CLIENT(msg_entity)) soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NONE);
                        break;
+               }
                case VOICETYPE_TEAMRADIO:
-                       msg_entity = self;
-                       if(msg_entity.cvar_cl_voice_directional == 1)
-                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_MIN);
+               {
+                       #define X() \
+                               do \
+                               { \
+                                       float atten = (msg_entity.cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE; \
+                                       soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \
+                               } \
+                               while (0)
+
+                       if (fake) { msg_entity = this; X(); }
                        else
-                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
-                       break;
-               case VOICETYPE_AUTOTAUNT:
-                       if(!sv_autotaunt)
-                               break;
-                       if(!sv_taunt)
-                               break;
-                       if(autocvar_sv_gentle)
-                               break;
-                       tauntrand = random();
-                       msg_entity = self;
-                       if (tauntrand < msg_entity.cvar_cl_autotaunt)
                        {
-                               if (msg_entity.cvar_cl_voice_directional >= 1)
-                                       soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTEN_MAX));
-                               else
-                                       soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
+                               FOR_EACH_REALCLIENT(msg_entity)
+                               {
+                                       if (!teamplay || msg_entity.team == this.team) X();
+                               }
                        }
+                       #undef X
                        break;
+               }
+               case VOICETYPE_AUTOTAUNT:
                case VOICETYPE_TAUNT:
-                       if(IS_PLAYER(self))
-                               if(self.deadflag == DEAD_NO)
-                                       animdecide_setaction(self, ANIMACTION_TAUNT, true);
-                       if(!sv_taunt)
-                               break;
-                       if(autocvar_sv_gentle)
-                               break;
-                       msg_entity = self;
-                       if (msg_entity.cvar_cl_voice_directional >= 1)
-                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTEN_MAX));
+               {
+                       if (voicetype == VOICETYPE_AUTOTAUNT) if (!sv_autotaunt) { break; }else {}
+                       else if (IS_PLAYER(this) && this.deadflag == DEAD_NO) animdecide_setaction(this, ANIMACTION_TAUNT, true);
+                       if (!sv_taunt) break;
+                       if (autocvar_sv_gentle) break;
+                       float tauntrand = 0;
+                       if (voicetype == VOICETYPE_AUTOTAUNT) tauntrand = random();
+                       #define X() \
+                               do \
+                               { \
+                                       if (voicetype != VOICETYPE_AUTOTAUNT || tauntrand < msg_entity.cvar_cl_autotaunt) \
+                                       { \
+                                               float atten = (msg_entity.cvar_cl_voice_directional >= 1) \
+                                                   ? bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTEN_MAX) \
+                                                       : ATTEN_NONE; \
+                                               soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \
+                                       } \
+                               } \
+                               while (0)
+                       if (fake)
+                       {
+                               msg_entity = this;
+                               X();
+                       }
                        else
-                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
-                       break;
-               case VOICETYPE_PLAYERSOUND:
-                       msg_entity = self;
-                       soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTEN_NORM);
-                       break;
-               default:
-                       backtrace("Invalid voice type!");
-                       break;
-       }
-}
-
-void GlobalSound(string sample, float chan, float voicetype)
-{SELFPARAM();
-       float n;
-       float tauntrand;
-
-       if(sample == "")
-               return;
-
-       tokenize_console(sample);
-       n = stof(argv(1));
-       if(n > 0)
-               sample = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
-       else
-               sample = strcat(argv(0), ".wav"); // randomization
-
-       switch(voicetype)
-       {
-               case VOICETYPE_LASTATTACKER_ONLY:
-                       if(self.pusher)
                        {
-                               msg_entity = self.pusher;
-                               if(IS_REAL_CLIENT(msg_entity))
+                               FOR_EACH_REALCLIENT(msg_entity)
                                {
-                                       if(msg_entity.cvar_cl_voice_directional == 1)
-                                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_MIN);
-                                       else
-                                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
+                                       X();
                                }
                        }
+                       #undef X
                        break;
-               case VOICETYPE_LASTATTACKER:
-                       if(self.pusher)
+               }
+               case VOICETYPE_PLAYERSOUND:
+               {
+                       if (fake)
                        {
-                               msg_entity = self.pusher;
-                               if(IS_REAL_CLIENT(msg_entity))
-                               {
-                                       if(msg_entity.cvar_cl_voice_directional == 1)
-                                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_MIN);
-                                       else
-                                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
-                               }
-                               msg_entity = self;
-                               if(IS_REAL_CLIENT(msg_entity))
-                                       soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTEN_NONE);
+                               msg_entity = this;
+                               soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NORM);
                        }
-                       break;
-               case VOICETYPE_TEAMRADIO:
-                       FOR_EACH_REALCLIENT(msg_entity)
-                               if(!teamplay || msg_entity.team == self.team)
-                               {
-                                       if(msg_entity.cvar_cl_voice_directional == 1)
-                                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_MIN);
-                                       else
-                                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
-                               }
-                       break;
-               case VOICETYPE_AUTOTAUNT:
-                       if(!sv_autotaunt)
-                               break;
-                       if(!sv_taunt)
-                               break;
-                       if(autocvar_sv_gentle)
-                               break;
-                       tauntrand = random();
-                       FOR_EACH_REALCLIENT(msg_entity)
-                               if (tauntrand < msg_entity.cvar_cl_autotaunt)
-                               {
-                                       if (msg_entity.cvar_cl_voice_directional >= 1)
-                                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTEN_MAX));
-                                       else
-                                               soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
-                               }
-                       break;
-               case VOICETYPE_TAUNT:
-                       if(IS_PLAYER(self))
-                               if(self.deadflag == DEAD_NO)
-                                       animdecide_setaction(self, ANIMACTION_TAUNT, true);
-                       if(!sv_taunt)
-                               break;
-                       if(autocvar_sv_gentle)
-                               break;
-                       FOR_EACH_REALCLIENT(msg_entity)
+                       else
                        {
-                               if (msg_entity.cvar_cl_voice_directional >= 1)
-                                       soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTEN_MAX));
-                               else
-                                       soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTEN_NONE);
+                               _sound(this, chan, sample, VOL_BASE, ATTEN_NORM);
                        }
                        break;
-               case VOICETYPE_PLAYERSOUND:
-                       _sound(self, chan, sample, VOL_BASE, ATTEN_NORM);
-                       break;
+               }
                default:
+               {
                        backtrace("Invalid voice type!");
                        break;
+               }
        }
 }
 
-void PlayerSound(.string samplefield, float chan, float voicetype)
-{SELFPARAM();
-       GlobalSound(self.(samplefield), chan, voicetype);
+void PlayerSound(.string samplefield, int chan, float voicetype)
+{
+       SELFPARAM();
+       _GlobalSound(this.(samplefield), chan, voicetype, false);
 }
 
 void VoiceMessage(string type, string msg)
-{SELFPARAM();
-       float voicetype, ownteam;
-       float flood;
+{
+       SELFPARAM();
        var .string sample = GetVoiceMessageSampleField(type);
-
-       if(GetPlayerSoundSampleField_notFound)
+       if (GetPlayerSoundSampleField_notFound)
        {
-               sprint(self, strcat("Invalid voice. Use one of: ", allvoicesamples, "\n"));
+               sprint(this, sprintf("Invalid voice. Use one of: %s\n", allvoicesamples));
                return;
        }
-
-       voicetype = GetVoiceMessageVoiceType(type);
-       ownteam = (voicetype == VOICETYPE_TEAMRADIO);
-
-       flood = Say(self, ownteam, world, msg, 1);
-
-       if (IS_SPEC(self) || IS_OBSERVER(self) || flood < 0)
-               FakeGlobalSound(self.(sample), CH_VOICE, voicetype);
-       else if (flood > 0)
-               GlobalSound(self.(sample), CH_VOICE, voicetype);
-}
-
-void MoveToTeam(entity client, float team_colour, float type)
-{
-       float lockteams_backup;
-
-       lockteams_backup = lockteams;  // backup any team lock
-
-       lockteams = 0;  // disable locked teams
-
-       TeamchangeFrags(client);  // move the players frags
-       SetPlayerColors(client, team_colour - 1);  // set the players colour
-       Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, client.origin, '0 0 0');  // kill the player
-
-       lockteams = lockteams_backup;  // restore the team lock
-
-       LogTeamchange(client.playerid, client.team, type);
+       int voicetype = GetVoiceMessageVoiceType(type);
+       bool ownteam = (voicetype == VOICETYPE_TEAMRADIO);
+       int flood = Say(this, ownteam, world, msg, true);
+       bool fake;
+       if (IS_SPEC(this) || IS_OBSERVER(this) || flood < 0) fake = true;
+       else if (flood > 0) fake = false;
+       else return;
+       _GlobalSound(this.(sample), CH_VOICE, voicetype, fake);
 }
index 27d1bd0dda0afc7f395b2c0233821207603d3178..76c49d852f572c2f1138c00eb538b25f5db56204 100644 (file)
@@ -6,17 +6,15 @@
 .float istypefrag;
 
 .float CopyBody_nextthink;
-.void(void) CopyBody_think;
-void CopyBody_Think(void);
+.void() CopyBody_think;
+void CopyBody_Think();
 void CopyBody(float keepvelocity);
 
-float player_getspecies();
-
 void player_setupanimsformodel();
 
-void player_anim (void);
+void player_anim();
 
-void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+void PlayerCorpseDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
 
 // g_<gametype>_str:
 // If 0, default is used.
@@ -25,51 +23,102 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, int de
 // For consistency, negative values there are mapped to zero too.
 #define GAMETYPE_DEFAULTED_SETTING(str) \
        ((gametype_setting_tmp = cvar(strcat("g_", GetGametype(), "_" #str))), \
-        (gametype_setting_tmp < 0) ? 0 : \
-        (gametype_setting_tmp == 0 || autocvar_g_respawn_delay_forced) ? max(0, autocvar_g_##str) : \
-        gametype_setting_tmp)
-
+       (gametype_setting_tmp < 0) ? 0 \
+       : (gametype_setting_tmp == 0 || autocvar_g_respawn_delay_forced) ? max(0, autocvar_g_##str) \
+       : gametype_setting_tmp)
 
 void calculate_player_respawn_time();
 
 void ClientKill_Now_TeamChange();
 
-void PlayerDamage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
-
-.float muted; // to be used by prvm_edictset server playernumber muted 1
-float Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol);
-// message "": do not say, just test flood control
-// return value:
-//   1 = accept
-//   0 = reject
-//  -1 = fake accept
+void MoveToTeam(entity client, float team_colour, float type);
 
+void PlayerDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+
+/** to be used by `prvm_edictset server playernumber muted 1` */
+.float muted;
+int Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol);
+
+// player sounds, voice messages
+// TODO implemented fall and falling
+#define ALLPLAYERSOUNDS(X) \
+       X(death) \
+       X(drown) \
+       X(fall) \
+       X(falling) \
+       X(gasp) \
+       X(jump) \
+       X(pain100) \
+       X(pain25) \
+       X(pain50) \
+       X(pain75)
+
+#define ALLVOICEMSGS(X) \
+       X(attack) \
+       X(attackinfive) \
+       X(coverme) \
+       X(defend) \
+       X(freelance) \
+       X(incoming) \
+       X(meet) \
+       X(needhelp) \
+       X(seenflag) \
+       X(taunt) \
+       X(teamshoot)
+
+// reserved sound names for the future (some models lack sounds for them):
+// _VOICEMSG(flagcarriertakingdamage)
+// _VOICEMSG(getflag)
+// reserved sound names for the future (ALL models lack sounds for them):
+// _VOICEMSG(affirmative)
+// _VOICEMSG(attacking)
+// _VOICEMSG(defending)
+// _VOICEMSG(roaming)
+// _VOICEMSG(onmyway)
+// _VOICEMSG(droppedflag)
+// _VOICEMSG(negative)
+// _VOICEMSG(seenenemy)
+
+#define X(m) .string playersound_##m;
+ALLPLAYERSOUNDS(X)
+ALLVOICEMSGS(X)
+#undef X
+
+bool GetPlayerSoundSampleField_notFound;
 float GetVoiceMessageVoiceType(string type);
-
-string allvoicesamples;
 .string GetVoiceMessageSampleField(string type);
-
 .string GetPlayerSoundSampleField(string type);
-
 void PrecacheGlobalSound(string samplestring);
-
 void PrecachePlayerSounds(string f);
-
-void ClearPlayerSounds();
-
-float LoadPlayerSounds(string f, float first);
-
-.int modelindex_for_playersound;
-.int skin_for_playersound;
-void UpdatePlayerSounds();
-
-void FakeGlobalSound(string sample, float chan, float voicetype);
-
-void GlobalSound(string sample, float chan, float voicetype);
-
+void ClearPlayerSounds(entity this);
+float LoadPlayerSounds(string f, bool strict);
+void UpdatePlayerSounds(entity this);
+#define FakeGlobalSound(sample, chan, voicetype) _GlobalSound(sample, chan, voicetype, true)
+void _GlobalSound(string sample, float chan, float voicetype, bool fake);
+#define GlobalSound(def, chan, voicetype) _GlobalSound((def).m_globalsoundstr, chan, voicetype, false)
 void PlayerSound(.string samplefield, float chan, float voicetype);
-
 void VoiceMessage(string type, string msg);
 
-void MoveToTeam(entity client, float team_colour, float type);
+.string m_globalsoundstr;
+REGISTRY(GlobalSounds, BITS(8) - 1)
+#define GlobalSounds_from(i) _GlobalSounds_from(i, NULL)
+#define REGISTER_GLOBALSOUND(id, str) \
+       REGISTER(GlobalSounds, GS, id, m_id, new(GlobalSound)) \
+       { \
+               make_pure(this); \
+               this.m_globalsoundstr = str; \
+       }
+REGISTER_REGISTRY(GlobalSounds)
+REGISTRY_SORT(GlobalSounds, 0)
+REGISTRY_CHECK(GlobalSounds)
+PRECACHE(GlobalSounds)
+{
+       FOREACH(GlobalSounds, true, LAMBDA(PrecacheGlobalSound(it.m_globalsoundstr)));
+}
+
+REGISTER_GLOBALSOUND(STEP, "misc/footstep0 6")
+REGISTER_GLOBALSOUND(STEP_METAL, "misc/metalfootstep0 6")
+REGISTER_GLOBALSOUND(FALL, "misc/hitground 4")
+REGISTER_GLOBALSOUND(FALL_METAL, "misc/metalhitground 4")
+
 #endif
index f325dcd72c336c5f5c1ebfb86daec0802b968967..30d6291f646b034dcca0a293474d9f906d82902f 100644 (file)
 
 void BanCommand_ban(float request, float argc, string command)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argc >= 2)
+                       if (argc >= 2)
                        {
                                string ip = argv(1);
                                float reason_arg, bantime;
@@ -51,7 +51,7 @@ void BanCommand_ban(float request, float argc, string command)
 
 void BanCommand_banlist(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -72,18 +72,18 @@ void BanCommand_banlist(float request)
 
 void BanCommand_kickban(float request, float argc, string command)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argc >= 2)
+                       if (argc >= 2)
                        {
                                entity client = GetIndexedEntity(argc, 1);
                                float accepted = VerifyKickableEntity(client);
                                float reason_arg, bantime, masksize;
                                string reason;
 
-                               if(accepted > 0)
+                               if (accepted > 0)
                                {
                                        reason_arg = next_token;
 
@@ -117,18 +117,18 @@ void BanCommand_kickban(float request, float argc, string command)
        }
 }
 
-void BanCommand_mute(float request, float argc, string command) // TODO: Add a sort of mute-"ban" which allows players to be muted based on IP/cryptokey
+void BanCommand_mute(float request, float argc, string command)  // TODO: Add a sort of mute-"ban" which allows players to be muted based on IP/cryptokey
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argc >= 2)
+                       if (argc >= 2)
                        {
                                entity client = GetFilteredEntity(argv(1));
                                float accepted = VerifyClientEntity(client, true, false);
 
-                               if(accepted > 0)
+                               if (accepted > 0)
                                {
                                        client.muted = true;
                                        return;
@@ -154,39 +154,32 @@ void BanCommand_mute(float request, float argc, string command) // TODO: Add a s
 
 void BanCommand_unban(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1))
+                       if (argv(1))
                        {
                                float tmp_number = -1;
                                string tmp_string;
 
-                               if(substring(argv(1), 0, 1) == "#")
+                               if (substring(argv(1), 0, 1) == "#")
                                {
                                        tmp_string = substring(argv(1), 1, -1);
 
-                                       if(tmp_string != "") // is it all one token? like #1
-                                       {
+                                       if (tmp_string != "") // is it all one token? like #1
                                                tmp_number = stof(tmp_string);
-                                       }
-                                       else if(argc > 2) // no, it's two tokens? # 1
-                                       {
+                                       else if (argc > 2)    // no, it's two tokens? # 1
                                                tmp_number = stof(argv(2));
-                                       }
-                                       else
-                                               tmp_number = -1;
+                                       else tmp_number = -1;
                                }
-                               else // maybe it's ONLY a number?
+                               else  // maybe it's ONLY a number?
                                {
                                        tmp_number = stof(argv(1));
 
-                                       if((tmp_number == 0) && (argv(1) != "0"))
-                                               { tmp_number = -1; }
-                               }
+                                       if ((tmp_number == 0) && (argv(1) != "0")) tmp_number = -1; }
 
-                               if(tmp_number >= 0)
+                               if (tmp_number >= 0)
                                {
                                        Ban_Delete(tmp_number);
                                        return;
@@ -207,16 +200,16 @@ void BanCommand_unban(float request, float argc)
 
 void BanCommand_unmute(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argc >= 2)
+                       if (argc >= 2)
                        {
                                entity client = GetFilteredEntity(argv(1));
                                float accepted = VerifyClientEntity(client, true, false);
 
-                               if(accepted > 0)
+                               if (accepted > 0)
                                {
                                        client.muted = false;
                                        return;
@@ -244,22 +237,22 @@ void BanCommand_unmute(float request, float argc)
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
 void BanCommand_(float request)
 {
-       switch(request)
-       {
-               case CMD_REQUEST_COMMAND:
-               {
-
-                       return;
-               }
-
-               default:
-               case CMD_REQUEST_USAGE:
-               {
-                       print("\nUsage:^3 sv_cmd \n");
-                       print("  No arguments required.\n");
-                       return;
-               }
-       }
+    switch(request)
+    {
+        case CMD_REQUEST_COMMAND:
+        {
+
+            return;
+        }
+
+        default:
+        case CMD_REQUEST_USAGE:
+        {
+            print("\nUsage:^3 sv_cmd \n");
+            print("  No arguments required.\n");
+            return;
+        }
+    }
 }
 */
 
@@ -269,7 +262,7 @@ void BanCommand_(float request)
 // ==================================
 
 // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define BAN_COMMANDS(request,arguments,command) \
+#define BAN_COMMANDS(request, arguments, command) \
        BAN_COMMAND("ban", BanCommand_ban(request, arguments, command), "Ban an IP address or a range of addresses (like 1.2.3)") \
        BAN_COMMAND("banlist", BanCommand_banlist(request), "List all existing bans") \
        BAN_COMMAND("kickban", BanCommand_kickban(request, arguments, command), "Disconnect a client and ban it at the same time") \
@@ -280,46 +273,42 @@ void BanCommand_(float request)
 
 void BanCommand_macro_help()
 {
-       #define BAN_COMMAND(name,function,description) \
-               { if(strtolower(description) != "") { LOG_INFO("  ^2", name, "^7: ", description, "\n"); } }
+       #define BAN_COMMAND(name, function, description) \
+               { if (strtolower(description) != "") { LOG_INFO("  ^2", name, "^7: ", description, "\n"); } }
 
        BAN_COMMANDS(0, 0, "");
-       #undef BAN_COMMAND
-
-       return;
+#undef BAN_COMMAND
 }
 
 float BanCommand_macro_command(float argc, string command)
 {
-       #define BAN_COMMAND(name,function,description) \
-               { if(name == strtolower(argv(0))) { function; return true; } }
+       #define BAN_COMMAND(name, function, description) \
+               { if (name == strtolower(argv(0))) { function; return true; } }
 
        BAN_COMMANDS(CMD_REQUEST_COMMAND, argc, command);
-       #undef BAN_COMMAND
+#undef BAN_COMMAND
 
        return false;
 }
 
 float BanCommand_macro_usage(float argc)
 {
-       #define BAN_COMMAND(name,function,description) \
-               { if(name == strtolower(argv(1))) { function; return true; } }
+       #define BAN_COMMAND(name, function, description) \
+               { if (name == strtolower(argv(1))) { function; return true; } }
 
        BAN_COMMANDS(CMD_REQUEST_USAGE, argc, "");
-       #undef BAN_COMMAND
+#undef BAN_COMMAND
 
        return false;
 }
 
 void BanCommand_macro_write_aliases(float fh)
 {
-       #define BAN_COMMAND(name,function,description) \
-               { if(strtolower(description) != "") { CMD_Write_Alias("qc_cmd_sv", name, description); } }
+       #define BAN_COMMAND(name, function, description) \
+               { if (strtolower(description) != "") { CMD_Write_Alias("qc_cmd_sv", name, description); } }
 
        BAN_COMMANDS(0, 0, "");
-       #undef BAN_COMMAND
-
-       return;
+#undef BAN_COMMAND
 }
 
 float BanCommand(string command)
@@ -331,10 +320,8 @@ float BanCommand(string command)
        // argv:   0    - 1      - 2     - 3
        // cmd     vote - master - login - password
 
-       if(BanCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
-       {
-               return true; // handled by one of the above GenericCommand_* functions
-       }
+       if (BanCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
+               return true;                             // handled by one of the above GenericCommand_* functions
 
        return false;
 }
index 17eca95c738363e4c83c3fbe57d0762fd143111c..a330ff1b0b9e1781a4b54f3482f42e23ba0c3016 100644 (file)
@@ -6,8 +6,8 @@
 //  Last updated: December 29th, 2011
 // =====================================
 
-#define GET_BAN_ARG(v,d) if(argc > reason_arg) { if((v = stof(argv(reason_arg))) != 0) ++reason_arg; else v = d; } else { v = d; }
-#define GET_BAN_REASON(v,d) if(argc > reason_arg) v = substring(command, argv_start_index(reason_arg), strlen(command) - argv_start_index(reason_arg)); else v = d;
+#define GET_BAN_ARG(v, d) if (argc > reason_arg) { if ((v = stof(argv(reason_arg))) != 0) ++reason_arg; else v = d; } else { v = d; }
+#define GET_BAN_REASON(v, d) if (argc > reason_arg) v = substring(command, argv_start_index(reason_arg), strlen(command) - argv_start_index(reason_arg)); else v = d;
 
 void Ban_KickBanClient(entity client, float bantime, float masksize, string reason);
 void Ban_View();
index 69517738b7aa6cd2721892fdc369b101c55f054c..ac21bc62dcc61b6ff73d68350ae9cafa38699b4c 100644 (file)
@@ -35,7 +35,7 @@
 
 #include "../../lib/warpzone/common.qh"
 
-void ClientKill_TeamChange (float targetteam); // 0 = don't change, -1 = auto, -2 = spec
+void ClientKill_TeamChange(float targetteam);  // 0 = don't change, -1 = auto, -2 = spec
 
 // =========================================================
 //  Server side networked commands code, reworked by Samual
@@ -43,13 +43,14 @@ void ClientKill_TeamChange (float targetteam); // 0 = don't change, -1 = auto, -
 // =========================================================
 
 float SV_ParseClientCommand_floodcheck()
-{SELFPARAM();
-       if (!timeout_status) // not while paused
+{
+       SELFPARAM();
+       if (!timeout_status)  // not while paused
        {
-               if(time <= (self.cmd_floodtime + autocvar_sv_clientcommand_antispam_time))
+               if (time <= (self.cmd_floodtime + autocvar_sv_clientcommand_antispam_time))
                {
                        self.cmd_floodcount += 1;
-                       if(self.cmd_floodcount > autocvar_sv_clientcommand_antispam_count) { return false; } // too much spam, halt
+                       if (self.cmd_floodcount > autocvar_sv_clientcommand_antispam_count)   return false;  // too much spam, halt
                }
                else
                {
@@ -57,7 +58,7 @@ float SV_ParseClientCommand_floodcheck()
                        self.cmd_floodcount = 1;
                }
        }
-       return true; // continue, as we're not flooding yet
+       return true;  // continue, as we're not flooding yet
 }
 
 
@@ -66,12 +67,13 @@ float SV_ParseClientCommand_floodcheck()
 // =======================
 
 void ClientCommand_autoswitch(float request, float argc)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1) != "")
+                       if (argv(1) != "")
                        {
                                self.autoswitch = InterpretBoolean(argv(1));
                                sprint(self, strcat("^1autoswitch is currently turned ", (self.autoswitch ? "on" : "off"), ".\n"));
@@ -90,30 +92,31 @@ void ClientCommand_autoswitch(float request, float argc)
        }
 }
 
-void ClientCommand_clientversion(float request, float argc) // internal command, used only by code
-{SELFPARAM();
-       switch(request)
+void ClientCommand_clientversion(float request, float argc)  // internal command, used only by code
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1) != "")
+                       if (argv(1) != "")
                        {
-                               if(IS_CLIENT(self))
+                               if (IS_CLIENT(self))
                                {
                                        self.version = ((argv(1) == "$gameversion") ? 1 : stof(argv(1)));
 
-                                       if(self.version < autocvar_gameversion_min || self.version > autocvar_gameversion_max)
+                                       if (self.version < autocvar_gameversion_min || self.version > autocvar_gameversion_max)
                                        {
                                                self.version_mismatch = 1;
-                                               ClientKill_TeamChange(-2); // observe
+                                               ClientKill_TeamChange(-2);  // observe
                                        }
-                                       else if(autocvar_g_campaign || autocvar_g_balance_teams)
+                                       else if (autocvar_g_campaign || autocvar_g_balance_teams)
                                        {
-                                               //JoinBestTeam(self, false, true);
+                                               // JoinBestTeam(self, false, true);
                                        }
-                                       else if(teamplay && !autocvar_sv_spectate && !(self.team_forced > 0))
+                                       else if (teamplay && !autocvar_sv_spectate && !(self.team_forced > 0))
                                        {
-                                               self.classname = STR_OBSERVER; // really?
+                                               self.classname = STR_OBSERVER;  // really?
                                                stuffcmd(self, "menu_showteamselect\n");
                                        }
                                }
@@ -133,16 +136,16 @@ void ClientCommand_clientversion(float request, float argc) // internal command,
        }
 }
 
-void ClientCommand_mv_getpicture(float request, float argc) // internal command, used only by code
-{SELFPARAM();
-       switch(request)
+void ClientCommand_mv_getpicture(float request, float argc)  // internal command, used only by code
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1) != "")
+                       if (argv(1) != "")
                        {
-                               if(intermission_running)
-                                       MapVote_SendPicture(stof(argv(1)));
+                               if (intermission_running) MapVote_SendPicture(stof(argv(1)));
 
                                return;
                        }
@@ -160,21 +163,20 @@ void ClientCommand_mv_getpicture(float request, float argc) // internal command,
 }
 
 void ClientCommand_join(float request)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(IS_CLIENT(self))
+                       if (IS_CLIENT(self))
                        {
-                               if(!IS_PLAYER(self) && !lockteams && !gameover)
+                               if (!IS_PLAYER(self) && !lockteams && !gameover)
                                {
-                                       if(self.caplayer)
-                                               return;
-                                       if(nJoinAllowed(self))
+                                       if (self.caplayer) return;
+                                       if (nJoinAllowed(self))
                                        {
-                                               if(autocvar_g_campaign) { campaign_bots_may_start = 1; }
-
+                                               if (autocvar_g_campaign)   campaign_bots_may_start = 1;
                                                self.classname = STR_PLAYER;
                                                PlayerScore_Clear(self);
                                                Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
@@ -183,12 +185,12 @@ void ClientCommand_join(float request)
                                        }
                                        else
                                        {
-                                               //player may not join because of g_maxplayers is set
+                                               // player may not join because of g_maxplayers is set
                                                Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_PREVENT);
                                        }
                                }
                        }
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -202,26 +204,27 @@ void ClientCommand_join(float request)
 }
 
 void ClientCommand_physics(float request, float argc)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        string command = strtolower(argv(1));
 
-                       if(!autocvar_g_physics_clientselect)
+                       if (!autocvar_g_physics_clientselect)
                        {
                                sprint(self, "Client physics selection is currently disabled.\n");
                                return;
                        }
 
-                       if(command == "list" || command == "help")
+                       if (command == "list" || command == "help")
                        {
                                sprint(self, strcat("Available physics sets: \n\n", autocvar_g_physics_clientselect_options, " default\n"));
                                return;
                        }
 
-                       if(Physics_Valid(command) || command == "default")
+                       if (Physics_Valid(command) || command == "default")
                        {
                                stuffcmd(self, strcat("\nseta cl_physics ", command, "\nsendcvar cl_physics\n"));
                                sprint(self, strcat("^2Physics set successfully changed to ^3", command, "\n"));
@@ -241,21 +244,22 @@ void ClientCommand_physics(float request, float argc)
        }
 }
 
-void ClientCommand_ready(float request) // todo: anti-spam for toggling readyness
-{SELFPARAM();
-       switch(request)
+void ClientCommand_ready(float request)  // todo: anti-spam for toggling readyness
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(IS_CLIENT(self))
+                       if (IS_CLIENT(self))
                        {
-                               if(warmup_stage || autocvar_sv_ready_restart || g_race_qualifying == 2)
+                               if (warmup_stage || autocvar_sv_ready_restart || g_race_qualifying == 2)
                                {
-                                       if(!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
+                                       if (!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
                                        {
-                                               if(time < game_starttime) // game is already restarting
+                                               if (time < game_starttime) // game is already restarting
                                                        return;
-                                               if (self.ready) // toggle
+                                               if (self.ready)            // toggle
                                                {
                                                        self.ready = false;
                                                        bprint(self.netname, "^2 is ^1NOT^2 ready\n");
@@ -267,14 +271,15 @@ void ClientCommand_ready(float request) // todo: anti-spam for toggling readynes
                                                }
 
                                                // cannot reset the game while a timeout is active!
-                                               if (!timeout_status)
-                                                       ReadyCount();
-                                       } else {
+                                               if (!timeout_status) ReadyCount();
+                                       }
+                                       else
+                                       {
                                                sprint(self, "^1Game has already been restarted\n");
                                        }
                                }
                        }
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -288,13 +293,14 @@ void ClientCommand_ready(float request) // todo: anti-spam for toggling readynes
 }
 
 void ClientCommand_say(float request, float argc, string command)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argc >= 2) { Say(self, false, world, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1); }
-                       return; // never fall through to usage
+                       if (argc >= 2)   Say(self, false, world, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
+                       return;  // never fall through to usage
                }
 
                default:
@@ -308,13 +314,14 @@ void ClientCommand_say(float request, float argc, string command)
 }
 
 void ClientCommand_say_team(float request, float argc, string command)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argc >= 2) { Say(self, true, world, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1); }
-                       return; // never fall through to usage
+                       if (argc >= 2)   Say(self, true, world, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
+                       return;  // never fall through to usage
                }
 
                default:
@@ -328,45 +335,58 @@ void ClientCommand_say_team(float request, float argc, string command)
 }
 
 void ClientCommand_selectteam(float request, float argc)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1) != "")
+                       if (argv(1) != "")
                        {
-                               if(IS_CLIENT(self))
+                               if (IS_CLIENT(self))
                                {
-                                       if(teamplay)
-                                               if(self.team_forced <= 0)
+                                       if (teamplay)
+                                       {
+                                               if (self.team_forced <= 0)
+                                               {
                                                        if (!lockteams)
                                                        {
                                                                float selection;
 
-                                                               switch(argv(1))
+                                                               switch (argv(1))
                                                                {
-                                                                       case "red": selection = NUM_TEAM_1; break;
-                                                                       case "blue": selection = NUM_TEAM_2; break;
-                                                                       case "yellow": selection = NUM_TEAM_3; break;
-                                                                       case "pink": selection = NUM_TEAM_4; break;
-                                                                       case "auto": selection = (-1); break;
-
-                                                                       default: selection = 0; break;
+                                                                       case "red": selection = NUM_TEAM_1;
+                                                                               break;
+                                                                       case "blue": selection = NUM_TEAM_2;
+                                                                               break;
+                                                                       case "yellow": selection = NUM_TEAM_3;
+                                                                               break;
+                                                                       case "pink": selection = NUM_TEAM_4;
+                                                                               break;
+                                                                       case "auto": selection = (-1);
+                                                                               break;
+
+                                                                       default: selection = 0;
+                                                                               break;
                                                                }
 
-                                                               if(selection)
+                                                               if (selection)
                                                                {
-                                                                       if(self.team == selection && self.deadflag == DEAD_NO)
+                                                                       if (self.team == selection && self.deadflag == DEAD_NO)
+                                                                       {
                                                                                sprint(self, "^7You already are on that team.\n");
-                                                                       else if(self.wasplayer && autocvar_g_changeteam_banned)
+                                                                       }
+                                                                       else if (self.wasplayer && autocvar_g_changeteam_banned)
+                                                                       {
                                                                                sprint(self, "^1You cannot change team, forbidden by the server.\n");
+                                                                       }
                                                                        else
                                                                        {
-                                                                               if(autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance)
+                                                                               if (autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance)
                                                                                {
                                                                                        CheckAllowedTeams(self);
                                                                                        GetTeamCounts(self);
-                                                                                       if(!TeamSmallerEqThanTeam(Team_TeamToNumber(selection), Team_TeamToNumber(self.team), self))
+                                                                                       if (!TeamSmallerEqThanTeam(Team_TeamToNumber(selection), Team_TeamToNumber(self.team), self))
                                                                                        {
                                                                                                Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
                                                                                                return;
@@ -377,11 +397,19 @@ void ClientCommand_selectteam(float request, float argc)
                                                                }
                                                        }
                                                        else
+                                                       {
                                                                sprint(self, "^7The game has already begun, you must wait until the next map to be able to join a team.\n");
+                                                       }
+                                               }
                                                else
+                                               {
                                                        sprint(self, "^7selectteam can not be used as your team is forced\n");
+                                               }
+                                       }
                                        else
+                                       {
                                                sprint(self, "^7selectteam can only be used in teamgames\n");
+                                       }
                                }
                                return;
                        }
@@ -400,12 +428,13 @@ void ClientCommand_selectteam(float request, float argc)
 }
 
 void ClientCommand_selfstuff(float request, string command)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1) != "")
+                       if (argv(1) != "")
                        {
                                stuffcmd(self, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));
                                return;
@@ -424,17 +453,18 @@ void ClientCommand_selfstuff(float request, string command)
 }
 
 void ClientCommand_sentcvar(float request, float argc, string command)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1) != "")
+                       if (argv(1) != "")
                        {
-                               //float tokens;
+                               // float tokens;
                                string s;
 
-                               if(argc == 2) // undefined cvar: use the default value on the server then
+                               if (argc == 2)  // undefined cvar: use the default value on the server then
                                {
                                        s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
                                        tokenize_console(s);
@@ -458,22 +488,21 @@ void ClientCommand_sentcvar(float request, float argc, string command)
 }
 
 void ClientCommand_spectate(float request)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(IS_CLIENT(self))
+                       if (IS_CLIENT(self))
                        {
                                int mutator_returnvalue = MUTATOR_CALLHOOK(ClientCommand_Spectate, self);
 
-                               if(mutator_returnvalue == MUT_SPECCMD_RETURN)
-                                       return;
+                               if (mutator_returnvalue == MUT_SPECCMD_RETURN) return;
 
-                               if((IS_PLAYER(self) || mutator_returnvalue == MUT_SPECCMD_FORCE) && autocvar_sv_spectate == 1)
-                                       ClientKill_TeamChange(-2); // observe
+                               if ((IS_PLAYER(self) || mutator_returnvalue == MUT_SPECCMD_FORCE) && autocvar_sv_spectate == 1) ClientKill_TeamChange(-2); // observe
                        }
-                       return; // never fall through to usage
+                       return;                                                                                                                        // never fall through to usage
                }
 
                default:
@@ -487,12 +516,13 @@ void ClientCommand_spectate(float request)
 }
 
 void ClientCommand_suggestmap(float request, float argc)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1) != "")
+                       if (argv(1) != "")
                        {
                                sprint(self, strcat(MapVote_Suggest(argv(1)), "\n"));
                                return;
@@ -511,19 +541,20 @@ void ClientCommand_suggestmap(float request, float argc)
 }
 
 void ClientCommand_tell(float request, float argc, string command)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argc >= 3)
+                       if (argc >= 3)
                        {
                                entity tell_to = GetIndexedEntity(argc, 1);
                                float tell_accepted = VerifyClientEntity(tell_to, true, false);
 
-                               if(tell_accepted > 0) // the target is a real client
+                               if (tell_accepted > 0)   // the target is a real client
                                {
-                                       if(tell_to != self) // and we're allowed to send to them :D
+                                       if (tell_to != self) // and we're allowed to send to them :D
                                        {
                                                // workaround for argv indexes indexing ascii chars instead of utf8 chars
                                                // In this case when the player name contains utf8 chars
@@ -541,7 +572,7 @@ void ClientCommand_tell(float request, float argc, string command)
                                        }
                                        else { print_to(self, "You can't ^2tell^7 a message to yourself."); return; }
                                }
-                               else if(argv(1) == "#0")
+                               else if (argv(1) == "#0")
                                {
                                        trigger_magicear_processmessage_forallears(self, -1, world, substring(command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token)));
                                        return;
@@ -562,17 +593,16 @@ void ClientCommand_tell(float request, float argc, string command)
 }
 
 void ClientCommand_voice(float request, float argc, string command)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1) != "")
+                       if (argv(1) != "")
                        {
-                               if(argc >= 3)
-                                       VoiceMessage(argv(1), substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
-                               else
-                                       VoiceMessage(argv(1), "");
+                               if (argc >= 3) VoiceMessage(argv(1), substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
+                               else VoiceMessage(argv(1), "");
 
                                return;
                        }
@@ -594,22 +624,22 @@ void ClientCommand_voice(float request, float argc, string command)
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
 void ClientCommand_(float request)
 {
-       switch(request)
-       {
-               case CMD_REQUEST_COMMAND:
-               {
-
-                       return; // never fall through to usage
-               }
-
-               default:
-               case CMD_REQUEST_USAGE:
-               {
-                       sprint(self, "\nUsage:^3 cmd \n");
-                       sprint(self, "  No arguments required.\n");
-                       return;
-               }
-       }
+    switch(request)
+    {
+        case CMD_REQUEST_COMMAND:
+        {
+
+            return; // never fall through to usage
+        }
+
+        default:
+        case CMD_REQUEST_USAGE:
+        {
+            sprint(self, "\nUsage:^3 cmd \n");
+            sprint(self, "  No arguments required.\n");
+            return;
+        }
+    }
 }
 */
 
@@ -619,7 +649,7 @@ void ClientCommand_(float request)
 // =====================================
 
 // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define CLIENT_COMMANDS(request,arguments,command) \
+#define CLIENT_COMMANDS(request, arguments, command) \
        CLIENT_COMMAND("autoswitch", ClientCommand_autoswitch(request, arguments), "Whether or not to switch automatically when getting a better weapon") \
        CLIENT_COMMAND("clientversion", ClientCommand_clientversion(request, arguments), "Release version of the game") \
        CLIENT_COMMAND("mv_getpicture", ClientCommand_mv_getpicture(request, arguments), "Retrieve mapshot picture from the server") \
@@ -639,47 +669,44 @@ void ClientCommand_(float request)
        /* nothing */
 
 void ClientCommand_macro_help()
-{SELFPARAM();
-       #define CLIENT_COMMAND(name,function,description) \
+{
+       SELFPARAM();
+       #define CLIENT_COMMAND(name, function, description) \
                { sprint(self, "  ^2", name, "^7: ", description, "\n"); }
 
        CLIENT_COMMANDS(0, 0, "");
-       #undef CLIENT_COMMAND
-
-       return;
+#undef CLIENT_COMMAND
 }
 
 float ClientCommand_macro_command(float argc, string command)
 {
-       #define CLIENT_COMMAND(name,function,description) \
-               { if(name == strtolower(argv(0))) { function; return true; } }
+       #define CLIENT_COMMAND(name, function, description) \
+               { if (name == strtolower(argv(0))) { function; return true; } }
 
        CLIENT_COMMANDS(CMD_REQUEST_COMMAND, argc, command);
-       #undef CLIENT_COMMAND
+#undef CLIENT_COMMAND
 
        return false;
 }
 
 float ClientCommand_macro_usage(float argc)
 {
-       #define CLIENT_COMMAND(name,function,description) \
-               { if(name == strtolower(argv(1))) { function; return true; } }
+       #define CLIENT_COMMAND(name, function, description) \
+               { if (name == strtolower(argv(1))) { function; return true; } }
 
        CLIENT_COMMANDS(CMD_REQUEST_USAGE, argc, "");
-       #undef CLIENT_COMMAND
+#undef CLIENT_COMMAND
 
        return false;
 }
 
 void ClientCommand_macro_write_aliases(float fh)
 {
-       #define CLIENT_COMMAND(name,function,description) \
+       #define CLIENT_COMMAND(name, function, description) \
                { CMD_Write_Alias("qc_cmd_cmd", name, description); }
 
        CLIENT_COMMANDS(0, 0, "");
-       #undef CLIENT_COMMAND
-
-       return;
+#undef CLIENT_COMMAND
 }
 
 // ======================================
@@ -688,19 +715,18 @@ void ClientCommand_macro_write_aliases(float fh)
 // If this function exists, server game code parses clientcommand before the engine code gets it.
 
 void SV_ParseClientCommand(string command)
-{SELFPARAM();
+{
+       SELFPARAM();
        // If invalid UTF-8, don't even parse it
        string command2 = "";
        float len = strlen(command);
        float i;
        for (i = 0; i < len; ++i)
                command2 = strcat(command2, chr2str(str2chr(command, i)));
-       if (command != command2)
-               return;
+       if (command != command2) return;
 
        // if we're banned, don't even parse the command
-       if(Ban_MaybeEnforceBanOnce(self))
-               return;
+       if (Ban_MaybeEnforceBanOnce(self)) return;
 
        float argc = tokenize_console(command);
 
@@ -710,28 +736,26 @@ void SV_ParseClientCommand(string command)
        // cmd     vote - master - login - password
 
        // for floodcheck
-       switch(strtolower(argv(0)))
+       switch (strtolower(argv(0)))
        {
                // exempt commands which are not subject to floodcheck
-               case "begin": break; // handled by engine in host_cmd.c
-               case "download": break; // handled by engine in cl_parse.c
-               case "mv_getpicture": break; // handled by server in this file
-               case "pause": break; // handled by engine in host_cmd.c
-               case "prespawn": break; // handled by engine in host_cmd.c
-               case "sentcvar": break; // handled by server in this file
-               case "spawn": break; // handled by engine in host_cmd.c
+               case "begin": break;                               // handled by engine in host_cmd.c
+               case "download": break;                            // handled by engine in cl_parse.c
+               case "mv_getpicture": break;                       // handled by server in this file
+               case "pause": break;                               // handled by engine in host_cmd.c
+               case "prespawn": break;                            // handled by engine in host_cmd.c
+               case "sentcvar": break;                            // handled by server in this file
+               case "spawn": break;                               // handled by engine in host_cmd.c
 
                default:
-                       if(SV_ParseClientCommand_floodcheck())
-                               break; // "true": continue, as we're not flooding yet
-                       else
-                               return; // "false": not allowed to continue, halt // print("^1ERROR: ^7ANTISPAM CAUGHT: ", command, ".\n");
+                       if (SV_ParseClientCommand_floodcheck()) break; // "true": continue, as we're not flooding yet
+                       else return;                                   // "false": not allowed to continue, halt // print("^1ERROR: ^7ANTISPAM CAUGHT: ", command, ".\n");
        }
 
        /* NOTE: should this be disabled? It can be spammy perhaps, but hopefully it's okay for now */
-       if(argv(0) == "help")
+       if (argv(0) == "help")
        {
-               if(argc == 1)
+               if (argc == 1)
                {
                        sprint(self, "\nClient networked commands:\n");
                        ClientCommand_macro_help();
@@ -743,31 +767,33 @@ void SV_ParseClientCommand(string command)
                        sprint(self, "For help about a specific command, type cmd help COMMAND\n");
                        return;
                }
-               else if(CommonCommand_macro_usage(argc, self)) // Instead of trying to call a command, we're going to see detailed information about it
+               else if (CommonCommand_macro_usage(argc, self))  // Instead of trying to call a command, we're going to see detailed information about it
                {
                        return;
                }
-               else if(ClientCommand_macro_usage(argc)) // same, but for normal commands now
+               else if (ClientCommand_macro_usage(argc))  // same, but for normal commands now
                {
                        return;
                }
        }
-       else if(MUTATOR_CALLHOOK(SV_ParseClientCommand, strtolower(argv(0)), argc, command))
+       else if (MUTATOR_CALLHOOK(SV_ParseClientCommand, strtolower(argv(0)), argc, command))
        {
-               return; // handled by a mutator
+               return;  // handled by a mutator
        }
-       else if(CheatCommand(argc))
+       else if (CheatCommand(argc))
        {
-               return; // handled by server/cheats.qc
+               return;  // handled by server/cheats.qc
        }
-       else if(CommonCommand_macro_command(argc, self, command))
+       else if (CommonCommand_macro_command(argc, self, command))
        {
-               return; // handled by server/command/common.qc
+               return;                                          // handled by server/command/common.qc
        }
-       else if(ClientCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
+       else if (ClientCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
        {
-               return; // handled by one of the above ClientCommand_* functions
+               return;                                          // handled by one of the above ClientCommand_* functions
        }
        else
+       {
                clientcommand(self, command);
+       }
 }
index 8d804587232bb57bc1d03f6423969662a57586b8..69f0222cb7d24586da4dc6ba64a191c558a360d8 100644 (file)
 // select the proper prefix for usage and other messages
 string GetCommandPrefix(entity caller)
 {
-       if(caller)
-               return "cmd";
-       else
-               return "sv_cmd";
+       if (caller) return "cmd";
+       else return "sv_cmd";
 }
 
 // if client return player nickname, or if server return admin nickname
 string GetCallerName(entity caller)
 {
-       if(caller)
-               return caller.netname;
-       else
-               return admin_name(); //((autocvar_sv_adminnick != "") ? autocvar_sv_adminnick : autocvar_hostname);
+       if (caller) return caller.netname;
+       else return admin_name();  // ((autocvar_sv_adminnick != "") ? autocvar_sv_adminnick : autocvar_hostname);
 }
 
 // verify that the client provided is acceptable for kicking
 float VerifyKickableEntity(entity client)
 {
-       if (!IS_REAL_CLIENT(client))
-               return CLIENT_NOT_REAL;
+       if (!IS_REAL_CLIENT(client)) return CLIENT_NOT_REAL;
        return CLIENT_ACCEPTABLE;
 }
 
 // verify that the client provided is acceptable for use
 float VerifyClientEntity(entity client, float must_be_real, float must_be_bots)
 {
-       if (!IS_CLIENT(client))
-               return CLIENT_DOESNT_EXIST;
-       else if(must_be_real && !IS_REAL_CLIENT(client))
-               return CLIENT_NOT_REAL;
-       else if(must_be_bots && !IS_BOT_CLIENT(client))
-               return CLIENT_NOT_BOT;
+       if (!IS_CLIENT(client)) return CLIENT_DOESNT_EXIST;
+       else if (must_be_real && !IS_REAL_CLIENT(client)) return CLIENT_NOT_REAL;
+       else if (must_be_bots && !IS_BOT_CLIENT(client)) return CLIENT_NOT_BOT;
 
        return CLIENT_ACCEPTABLE;
 }
@@ -55,22 +47,28 @@ float VerifyClientEntity(entity client, float must_be_real, float must_be_bots)
 // if the client is not acceptable, return a string to be used for error messages
 string GetClientErrorString_color(float clienterror, string original_input, string col)
 {
-       switch(clienterror)
+       switch (clienterror)
        {
-               case CLIENT_DOESNT_EXIST: { return strcat(col, "Client '", original_input, col, "' doesn't exist"); }
-               case CLIENT_NOT_REAL: { return strcat(col, "Client '", original_input, col, "' is not real"); }
-               case CLIENT_NOT_BOT: { return strcat(col, "Client '", original_input, col, "' is not a bot"); }
-               default: { return "Incorrect usage of GetClientErrorString"; }
+               case CLIENT_DOESNT_EXIST:
+               { return strcat(col, "Client '", original_input, col, "' doesn't exist");
+               }
+               case CLIENT_NOT_REAL:
+               { return strcat(col, "Client '", original_input, col, "' is not real");
+               }
+               case CLIENT_NOT_BOT:
+               { return strcat(col, "Client '", original_input, col, "' is not a bot");
+               }
+               default:
+               { return "Incorrect usage of GetClientErrorString";
+               }
        }
 }
 
 // is this entity number even in the possible range of entities?
 float VerifyClientNumber(float tmp_number)
 {
-       if((tmp_number < 1) || (tmp_number > maxclients))
-               return false;
-       else
-               return true;
+       if ((tmp_number < 1) || (tmp_number > maxclients)) return false;
+       else return true;
 }
 
 entity GetIndexedEntity(float argc, float start_index)
@@ -83,47 +81,48 @@ entity GetIndexedEntity(float argc, float start_index)
        index = start_index;
        selection = world;
 
-       if(argc > start_index)
+       if (argc > start_index)
        {
-               if(substring(argv(index), 0, 1) == "#")
+               if (substring(argv(index), 0, 1) == "#")
                {
                        tmp_string = substring(argv(index), 1, -1);
                        ++index;
 
-                       if(tmp_string != "") // is it all one token? like #1
+                       if (tmp_string != "")  // is it all one token? like #1
                        {
                                tmp_number = stof(tmp_string);
                        }
-                       else if(argc > index) // no, it's two tokens? # 1
+                       else if (argc > index)  // no, it's two tokens? # 1
                        {
                                tmp_number = stof(argv(index));
                                ++index;
                        }
                        else
+                       {
                                tmp_number = 0;
+                       }
                }
-               else // maybe it's ONLY a number?
+               else  // maybe it's ONLY a number?
                {
                        tmp_number = stof(argv(index));
                        ++index;
                }
 
-               if(VerifyClientNumber(tmp_number))
+               if (VerifyClientNumber(tmp_number))
                {
-                       selection = edict_num(tmp_number); // yes, it was a number
+                       selection = edict_num(tmp_number);  // yes, it was a number
                }
-               else // no, maybe it's a name?
+               else  // no, maybe it's a name?
                {
                        FOR_EACH_CLIENT(tmp_player)
-                               if (strdecolorize(tmp_player.netname) == strdecolorize(argv(start_index)))
-                                       selection = tmp_player;
+                       if (strdecolorize(tmp_player.netname) == strdecolorize(argv(start_index))) selection = tmp_player;
 
                        index = (start_index + 1);
                }
        }
 
        next_token = index;
-       //print(strcat("start_index: ", ftos(start_index), ", next_token: ", ftos(next_token), ", edict: ", ftos(num_for_edict(selection)), ".\n"));
+       // print(strcat("start_index: ", ftos(start_index), ", next_token: ", ftos(next_token), ", edict: ", ftos(num_for_edict(selection)), ".\n"));
        return selection;
 }
 
@@ -133,12 +132,10 @@ entity GetFilteredEntity(string input)
        entity tmp_player, selection;
        float tmp_number;
 
-       if(substring(input, 0, 1) == "#")
-               tmp_number = stof(substring(input, 1, -1));
-       else
-               tmp_number = stof(input);
+       if (substring(input, 0, 1) == "#") tmp_number = stof(substring(input, 1, -1));
+       else tmp_number = stof(input);
 
-       if(VerifyClientNumber(tmp_number))
+       if (VerifyClientNumber(tmp_number))
        {
                selection = edict_num(tmp_number);
        }
@@ -146,8 +143,7 @@ entity GetFilteredEntity(string input)
        {
                selection = world;
                FOR_EACH_CLIENT(tmp_player)
-                       if (strdecolorize(tmp_player.netname) == strdecolorize(input))
-                               selection = tmp_player;
+               if (strdecolorize(tmp_player.netname) == strdecolorize(input)) selection = tmp_player;
        }
 
        return selection;
@@ -167,10 +163,8 @@ float GetFilteredNumber(string input)
 // switch between sprint and print depending on whether the receiver is the server or a player
 void print_to(entity to, string input)
 {
-    if(to)
-        sprint(to, strcat(input, "\n"));
-    else
-        LOG_INFO(input, "\n");
+       if (to) sprint(to, strcat(input, "\n"));
+       else LOG_INFO(input, "\n");
 }
 
 // ==========================================
@@ -179,7 +173,8 @@ void print_to(entity to, string input)
 
 // used by CommonCommand_timeout() and CommonCommand_timein() to handle game pausing and messaging and such.
 void timeout_handler_reset()
-{SELFPARAM();
+{
+       SELFPARAM();
        timeout_caller = world;
        timeout_time = 0;
        timeout_leadtime = 0;
@@ -188,24 +183,25 @@ void timeout_handler_reset()
 }
 
 void timeout_handler_think()
-{SELFPARAM();
+{
+       SELFPARAM();
        entity tmp_player;
 
-       switch(timeout_status)
+       switch (timeout_status)
        {
                case TIMEOUT_ACTIVE:
                {
-                       if(timeout_time > 0) // countdown is still going
+                       if (timeout_time > 0)  // countdown is still going
                        {
                                Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_TIMEOUT_ENDING, timeout_time);
 
-                               if(timeout_time == autocvar_sv_timeout_resumetime) // play a warning sound when only <sv_timeout_resumetime> seconds are left
+                               if (timeout_time == autocvar_sv_timeout_resumetime) // play a warning sound when only <sv_timeout_resumetime> seconds are left
                                        Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_PREPARE);
 
-                               self.nextthink = time + TIMEOUT_SLOWMO_VALUE; // think again in one second
-                               timeout_time -= 1; // decrease the time counter
+                               self.nextthink = time + TIMEOUT_SLOWMO_VALUE;       // think again in one second
+                               timeout_time -= 1;                                  // decrease the time counter
                        }
-                       else // time to end the timeout
+                       else  // time to end the timeout
                        {
                                timeout_status = TIMEOUT_INACTIVE;
 
@@ -214,7 +210,7 @@ void timeout_handler_think()
 
                                // unlock the view for players so they can move around again
                                FOR_EACH_REALPLAYER(tmp_player)
-                                       tmp_player.fixangle = false;
+                               tmp_player.fixangle = false;
 
                                timeout_handler_reset();
                        }
@@ -224,14 +220,14 @@ void timeout_handler_think()
 
                case TIMEOUT_LEADTIME:
                {
-                       if(timeout_leadtime > 0) // countdown is still going
+                       if (timeout_leadtime > 0)  // countdown is still going
                        {
                                Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_TIMEOUT_BEGINNING, timeout_leadtime);
 
                                self.nextthink = time + 1; // think again in one second
-                               timeout_leadtime -= 1; // decrease the time counter
+                               timeout_leadtime -= 1;     // decrease the time counter
                        }
-                       else // time to begin the timeout
+                       else  // time to begin the timeout
                        {
                                timeout_status = TIMEOUT_ACTIVE;
 
@@ -240,15 +236,15 @@ void timeout_handler_think()
 
                                // reset all the flood variables
                                FOR_EACH_CLIENT(tmp_player)
-                                       tmp_player.nickspamcount = tmp_player.nickspamtime = tmp_player.floodcontrol_chat =
-                                       tmp_player.floodcontrol_chatteam = tmp_player.floodcontrol_chattell =
-                                       tmp_player.floodcontrol_voice = tmp_player.floodcontrol_voiceteam = 0;
+                               tmp_player.nickspamcount = tmp_player.nickspamtime = tmp_player.floodcontrol_chat =
+                                           tmp_player.floodcontrol_chatteam = tmp_player.floodcontrol_chattell =
+                                                   tmp_player.floodcontrol_voice = tmp_player.floodcontrol_voiceteam = 0;
 
                                // copy .v_angle to .lastV_angle for every player in order to fix their view during pause (see PlayerPreThink)
                                FOR_EACH_REALPLAYER(tmp_player)
-                                       tmp_player.lastV_angle = tmp_player.v_angle;
+                               tmp_player.lastV_angle = tmp_player.v_angle;
 
-                               self.nextthink = time; // think again next frame to handle it under TIMEOUT_ACTIVE code
+                               self.nextthink = time;  // think again next frame to handle it under TIMEOUT_ACTIVE code
                        }
 
                        return;
@@ -265,19 +261,18 @@ void timeout_handler_think()
 }
 
 
-
 // ===================================================
 //  Common commands used in both sv_cmd.qc and cmd.qc
 // ===================================================
 
 void CommonCommand_cvar_changes(float request, entity caller)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        print_to(caller, cvar_changes);
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -293,12 +288,12 @@ void CommonCommand_cvar_changes(float request, entity caller)
 
 void CommonCommand_cvar_purechanges(float request, entity caller)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        print_to(caller, cvar_purechanges);
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -313,15 +308,16 @@ void CommonCommand_cvar_purechanges(float request, entity caller)
 }
 
 void CommonCommand_editmob(int request, entity caller, int argc)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(autocvar_g_campaign) { print_to(caller, "Monster editing is disabled in singleplayer"); return; }
+                       if (autocvar_g_campaign) { print_to(caller, "Monster editing is disabled in singleplayer"); return; }
                        // no checks for g_monsters here, as it may be toggled mid match which existing monsters
 
-                       if(caller)
+                       if (caller)
                        {
                                makevectors(self.v_angle);
                                WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * 100, MOVE_NORMAL, self);
@@ -331,80 +327,83 @@ void CommonCommand_editmob(int request, entity caller, int argc)
                        bool is_visible = IS_MONSTER(mon);
                        string argument = argv(2);
 
-                       switch(argv(1))
+                       switch (argv(1))
                        {
                                case "name":
                                {
-                                       if(!caller) { print_to(caller, "Only players can edit monsters"); return; }
-                                       if(!argument) { break; } // escape to usage
-                                       if(!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
-                                       if(mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
-                                       if(!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
+                                       if (!caller) { print_to(caller, "Only players can edit monsters"); return; }
+                                       if (!argument)   break;  // escape to usage
+                                       if (!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
+                                       if (mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
+                                       if (!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
 
                                        string mon_oldname = mon.monster_name;
 
                                        mon.monster_name = argument;
-                                       if(mon.sprite) { WaypointSprite_UpdateSprites(mon.sprite, WP_Monster, WP_Null, WP_Null); }
+                                       if (mon.sprite)   WaypointSprite_UpdateSprites(mon.sprite, WP_Monster, WP_Null, WP_Null);
                                        print_to(caller, sprintf("Your pet '%s' is now known as '%s'", mon_oldname, mon.monster_name));
                                        return;
                                }
                                case "spawn":
                                {
-                                       if(!caller) { print_to(caller, "Only players can spawn monsters"); return; }
-                                       if(!argv(2)) { break; } // escape to usage
+                                       if (!caller) { print_to(caller, "Only players can spawn monsters"); return; }
+                                       if (!argv(2))   break;  // escape to usage
 
                                        int moveflag, tmp_moncount = 0;
                                        string arg_lower = strtolower(argument);
-                                       moveflag = (argv(3)) ? stof(argv(3)) : 1; // follow owner if not defined
+                                       moveflag = (argv(3)) ? stof(argv(3)) : 1;  // follow owner if not defined
                                        ret_string = "Monster spawning is currently disabled by a mutator";
 
-                                       if(arg_lower == "list") { print_to(caller, monsterlist_reply); return; }
+                                       if (arg_lower == "list") { print_to(caller, monsterlist_reply); return; }
 
-                                       FOR_EACH_MONSTER(mon) { if(mon.realowner == caller) ++tmp_moncount; }
+                                       FOR_EACH_MONSTER(mon)
+                                       {
+                                               if (mon.realowner == caller) ++tmp_moncount;
+                                       }
 
-                                       if(!autocvar_g_monsters) { print_to(caller, "Monsters are disabled"); return; }
-                                       if(autocvar_g_monsters_max <= 0 || autocvar_g_monsters_max_perplayer <= 0) { print_to(caller, "Monster spawning is disabled"); return; }
-                                       if(!IS_PLAYER(caller)) { print_to(caller, "You must be playing to spawn a monster"); return; }
-                                       if(MUTATOR_CALLHOOK(AllowMobSpawning)) { print_to(caller, ret_string); return; }
-                                       if(caller.vehicle) { print_to(caller, "You can't spawn monsters while driving a vehicle"); return; }
-                                       if(caller.frozen) { print_to(caller, "You can't spawn monsters while frozen"); return; }
-                                       if(caller.deadflag != DEAD_NO) { print_to(caller, "You can't spawn monsters while dead"); return; }
-                                       if(tmp_moncount >= autocvar_g_monsters_max) { print_to(caller, "The maximum monster count has been reached"); return; }
-                                       if(tmp_moncount >= autocvar_g_monsters_max_perplayer) { print_to(caller, "You can't spawn any more monsters"); return; }
+                                       if (!autocvar_g_monsters) { print_to(caller, "Monsters are disabled"); return; }
+                                       if (autocvar_g_monsters_max <= 0 || autocvar_g_monsters_max_perplayer <= 0) { print_to(caller, "Monster spawning is disabled"); return; }
+                                       if (!IS_PLAYER(caller)) { print_to(caller, "You must be playing to spawn a monster"); return; }
+                                       if (MUTATOR_CALLHOOK(AllowMobSpawning)) { print_to(caller, ret_string); return; }
+                                       if (caller.vehicle) { print_to(caller, "You can't spawn monsters while driving a vehicle"); return; }
+                                       if (caller.frozen) { print_to(caller, "You can't spawn monsters while frozen"); return; }
+                                       if (caller.deadflag != DEAD_NO) { print_to(caller, "You can't spawn monsters while dead"); return; }
+                                       if (tmp_moncount >= autocvar_g_monsters_max) { print_to(caller, "The maximum monster count has been reached"); return; }
+                                       if (tmp_moncount >= autocvar_g_monsters_max_perplayer) { print_to(caller, "You can't spawn any more monsters"); return; }
 
                                        bool found = false;
-                                       for(int i = MON_FIRST; i <= MON_LAST; ++i)
+                                       for (int i = MON_FIRST; i <= MON_LAST; ++i)
                                        {
                                                mon = get_monsterinfo(i);
-                                               if(mon.netname == arg_lower) { found = true; break; }
+                                               if (mon.netname == arg_lower) { found = true; break; }
                                        }
 
-                                       if(!found && arg_lower != "random") { print_to(caller, "Invalid monster"); return; }
+                                       if (!found && arg_lower != "random") { print_to(caller, "Invalid monster"); return; }
 
                                        totalspawned += 1;
-                                       WarpZone_TraceBox (CENTER_OR_VIEWOFS(caller), caller.mins, caller.maxs, CENTER_OR_VIEWOFS(caller) + v_forward * 150, true, caller);
+                                       WarpZone_TraceBox(CENTER_OR_VIEWOFS(caller), caller.mins, caller.maxs, CENTER_OR_VIEWOFS(caller) + v_forward * 150, true, caller);
                                        mon = spawnmonster(arg_lower, 0, caller, caller, trace_endpos, false, false, moveflag);
                                        print_to(caller, strcat("Spawned ", mon.monster_name));
                                        return;
                                }
                                case "kill":
                                {
-                                       if(!caller) { print_to(caller, "Only players can kill monsters"); return; }
-                                       if(mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
-                                       if(!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
+                                       if (!caller) { print_to(caller, "Only players can kill monsters"); return; }
+                                       if (mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
+                                       if (!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
 
-                                       Damage (mon, world, world, mon.health + mon.max_health + 200, DEATH_KILL.m_id, mon.origin, '0 0 0');
+                                       Damage(mon, world, world, mon.health + mon.max_health + 200, DEATH_KILL.m_id, mon.origin, '0 0 0');
                                        print_to(caller, strcat("Your pet '", mon.monster_name, "' has been brutally mutilated"));
                                        return;
                                }
                                case "skin":
                                {
-                                       if(!caller) { print_to(caller, "Only players can edit monsters"); return; }
-                                       if(!argument) { break; } // escape to usage
-                                       if(!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
-                                       if(!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
-                                       if(mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
-                                       if(mon.monsterid == MON_MAGE.monsterid) { print_to(caller, "Mage skins can't be changed"); return; } // TODO
+                                       if (!caller) { print_to(caller, "Only players can edit monsters"); return; }
+                                       if (!argument)   break;  // escape to usage
+                                       if (!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
+                                       if (!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
+                                       if (mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
+                                       if (mon.monsterid == MON_MAGE.monsterid) { print_to(caller, "Mage skins can't be changed"); return; }  // TODO
 
                                        mon.skin = stof(argument);
                                        print_to(caller, strcat("Monster skin successfully changed to ", ftos(mon.skin)));
@@ -412,11 +411,11 @@ void CommonCommand_editmob(int request, entity caller, int argc)
                                }
                                case "movetarget":
                                {
-                                       if(!caller) { print_to(caller, "Only players can edit monsters"); return; }
-                                       if(!argument) { break; } // escape to usage
-                                       if(!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
-                                       if(!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
-                                       if(mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
+                                       if (!caller) { print_to(caller, "Only players can edit monsters"); return; }
+                                       if (!argument)   break;  // escape to usage
+                                       if (!autocvar_g_monsters_edit) { print_to(caller, "Monster editing is disabled"); return; }
+                                       if (!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
+                                       if (mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
 
                                        mon.monster_moveflags = stof(argument);
                                        print_to(caller, strcat("Monster move target successfully changed to ", ftos(mon.monster_moveflags)));
@@ -424,13 +423,17 @@ void CommonCommand_editmob(int request, entity caller, int argc)
                                }
                                case "butcher":
                                {
-                                       if(caller) { print_to(caller, "This command is not available to players"); return; }
-                                       if(MUTATOR_CALLHOOK(AllowMobButcher)) { LOG_INFO(ret_string, "\n"); return; }
+                                       if (caller) { print_to(caller, "This command is not available to players"); return; }
+                                       if (MUTATOR_CALLHOOK(AllowMobButcher)) { LOG_INFO(ret_string, "\n"); return; }
 
                                        int tmp_remcount = 0;
                                        entity tmp_entity;
 
-                                       FOR_EACH_MONSTER(tmp_entity) { Monster_Remove(tmp_entity); ++tmp_remcount; }
+                                       FOR_EACH_MONSTER(tmp_entity)
+                                       {
+                                               Monster_Remove(tmp_entity);
+                                               ++tmp_remcount;
+                                       }
 
                                        monsters_total = monsters_killed = totalspawned = 0;
 
@@ -455,18 +458,16 @@ void CommonCommand_editmob(int request, entity caller, int argc)
 
 void CommonCommand_info(float request, entity caller, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        string command = builtin_cvar_string(strcat("sv_info_", argv(1)));
 
-                       if(command)
-                               wordwrap_sprint(command, 1000);
-                       else
-                               print_to(caller, "ERROR: unsupported info command");
+                       if (command) wordwrap_sprint(command, 1000);
+                       else print_to(caller, "ERROR: unsupported info command");
 
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -481,12 +482,12 @@ void CommonCommand_info(float request, entity caller, float argc)
 
 void CommonCommand_ladder(float request, entity caller)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        print_to(caller, ladder_reply);
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -501,12 +502,12 @@ void CommonCommand_ladder(float request, entity caller)
 
 void CommonCommand_lsmaps(float request, entity caller)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        print_to(caller, lsmaps_reply);
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -521,12 +522,12 @@ void CommonCommand_lsmaps(float request, entity caller)
 
 void CommonCommand_printmaplist(float request, entity caller)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        print_to(caller, maplist_reply);
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -541,12 +542,12 @@ void CommonCommand_printmaplist(float request, entity caller)
 
 void CommonCommand_rankings(float request, entity caller)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        print_to(caller, rankings_reply);
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -561,15 +562,14 @@ void CommonCommand_rankings(float request, entity caller)
 
 void CommonCommand_records(float request, entity caller)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       for(int i = 0; i < 10; ++i)
-                               if(records_reply[i] != "")
-                                       print_to(caller, records_reply[i]);
+                       for (int i = 0; i < 10; ++i)
+                               if (records_reply[i] != "") print_to(caller, records_reply[i]);
 
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -584,12 +584,12 @@ void CommonCommand_records(float request, entity caller)
 
 void CommonCommand_teamstatus(float request, entity caller)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        Score_NicePrint(caller);
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -604,7 +604,7 @@ void CommonCommand_teamstatus(float request, entity caller)
 
 void CommonCommand_time(float request, entity caller)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -630,24 +630,27 @@ void CommonCommand_time(float request, entity caller)
 
 void CommonCommand_timein(float request, entity caller)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(!caller || autocvar_sv_timeout)
+                       if (!caller || autocvar_sv_timeout)
                        {
                                if (!timeout_status) { print_to(caller, "^7Error: There is no active timeout called."); }
-                               else if(caller && (caller != timeout_caller)) { print_to(caller, "^7Error: You are not allowed to stop the active timeout."); }
+                               else if (caller && (caller != timeout_caller))
+                               {
+                                       print_to(caller, "^7Error: You are not allowed to stop the active timeout.");
+                               }
 
-                               else // everything should be okay, continue aborting timeout
+                               else  // everything should be okay, continue aborting timeout
                                {
-                                       switch(timeout_status)
+                                       switch (timeout_status)
                                        {
                                                case TIMEOUT_LEADTIME:
                                                {
                                                        timeout_status = TIMEOUT_INACTIVE;
                                                        timeout_time = 0;
-                                                       timeout_handler.nextthink = time; // timeout_handler has to take care of it immediately
+                                                       timeout_handler.nextthink = time;  // timeout_handler has to take care of it immediately
                                                        bprint(strcat("^7The timeout was aborted by ", GetCallerName(caller), " !\n"));
                                                        return;
                                                }
@@ -655,18 +658,19 @@ void CommonCommand_timein(float request, entity caller)
                                                case TIMEOUT_ACTIVE:
                                                {
                                                        timeout_time = autocvar_sv_timeout_resumetime;
-                                                       timeout_handler.nextthink = time; // timeout_handler has to take care of it immediately
+                                                       timeout_handler.nextthink = time;  // timeout_handler has to take care of it immediately
                                                        bprint(strcat("^1Attention: ^7", GetCallerName(caller), " resumed the game! Prepare for battle!\n"));
                                                        return;
                                                }
 
-                                               default: LOG_TRACE("timeout status was inactive, but this code was executed anyway?"); return;
+                                               default: LOG_TRACE("timeout status was inactive, but this code was executed anyway?");
+                                                       return;
                                        }
                                }
                        }
                        else { print_to(caller, "^1Timeins are not allowed to be called, enable them with sv_timeout 1.\n"); }
 
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -679,28 +683,45 @@ void CommonCommand_timein(float request, entity caller)
        }
 }
 
-void CommonCommand_timeout(float request, entity caller) // DEAR GOD THIS COMMAND IS TERRIBLE.
+void CommonCommand_timeout(float request, entity caller)  // DEAR GOD THIS COMMAND IS TERRIBLE.
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(!caller || autocvar_sv_timeout)
+                       if (!caller || autocvar_sv_timeout)
                        {
                                float last_possible_timeout = ((autocvar_timelimit * 60) - autocvar_sv_timeout_leadtime - 1);
 
-                               if(timeout_status) { print_to(caller, "^7Error: A timeout is already active."); }
-                               else if(vote_called) { print_to(caller, "^7Error: You can not call a timeout while a vote is active."); }
-                               else if(warmup_stage && !g_warmup_allow_timeout) { print_to(caller, "^7Error: You can not call a timeout in warmup-stage."); }
-                               else if(time < game_starttime) { print_to(caller, "^7Error: You can not call a timeout while the map is being restarted."); }
-                               else if(caller && (caller.allowed_timeouts < 1)) { print_to(caller, "^7Error: You already used all your timeout calls for this map."); }
-                               else if(caller && !IS_PLAYER(caller)) { print_to(caller, "^7Error: You must be a player to call a timeout."); }
-                               else if((autocvar_timelimit) && (last_possible_timeout < time - game_starttime)) { print_to(caller, "^7Error: It is too late to call a timeout now!"); }
-
-                               else // everything should be okay, proceed with starting the timeout
+                               if (timeout_status) { print_to(caller, "^7Error: A timeout is already active."); }
+                               else if (vote_called)
                                {
-                                       if(caller) { caller.allowed_timeouts -= 1; }
+                                       print_to(caller, "^7Error: You can not call a timeout while a vote is active.");
+                               }
+                               else if (warmup_stage && !g_warmup_allow_timeout)
+                               {
+                                       print_to(caller, "^7Error: You can not call a timeout in warmup-stage.");
+                               }
+                               else if (time < game_starttime)
+                               {
+                                       print_to(caller, "^7Error: You can not call a timeout while the map is being restarted.");
+                               }
+                               else if (caller && (caller.allowed_timeouts < 1))
+                               {
+                                       print_to(caller, "^7Error: You already used all your timeout calls for this map.");
+                               }
+                               else if (caller && !IS_PLAYER(caller))
+                               {
+                                       print_to(caller, "^7Error: You must be a player to call a timeout.");
+                               }
+                               else if ((autocvar_timelimit) && (last_possible_timeout < time - game_starttime))
+                               {
+                                       print_to(caller, "^7Error: It is too late to call a timeout now!");
+                               }
 
+                               else  // everything should be okay, proceed with starting the timeout
+                               {
+                                       if (caller)   caller.allowed_timeouts -= 1;
                                        // write a bprint who started the timeout (and how many they have left)
                                        bprint(GetCallerName(caller), " ^7called a timeout", (caller ? strcat(" (", ftos(caller.allowed_timeouts), " timeout(s) left)") : ""), "!\n");
 
@@ -711,14 +732,14 @@ void CommonCommand_timeout(float request, entity caller) // DEAR GOD THIS COMMAN
 
                                        timeout_handler = spawn();
                                        timeout_handler.think = timeout_handler_think;
-                                       timeout_handler.nextthink = time; // always let the entity think asap
+                                       timeout_handler.nextthink = time;  // always let the entity think asap
 
                                        Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_TIMEOUT);
                                }
                        }
                        else { print_to(caller, "^1Timeouts are not allowed to be called, enable them with sv_timeout 1.\n"); }
 
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -733,7 +754,7 @@ void CommonCommand_timeout(float request, entity caller) // DEAR GOD THIS COMMAN
 
 void CommonCommand_who(float request, entity caller, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -753,12 +774,12 @@ void CommonCommand_who(float request, entity caller, float argc)
                        {
                                is_bot = (IS_BOT_CLIENT(tmp_player));
 
-                               if(is_bot)
+                               if (is_bot)
                                {
                                        tmp_netaddress = "null/botclient";
                                        tmp_crypto_idfp = "null/botclient";
                                }
-                               else if(privacy)
+                               else if (privacy)
                                {
                                        tmp_netaddress = "hidden";
                                        tmp_crypto_idfp = "hidden";
@@ -783,7 +804,7 @@ void CommonCommand_who(float request, entity caller, float argc)
 
                        print_to(caller, strcat("Finished listing ", ftos(total_listed_players), " client(s) out of ", ftos(maxclients), " slots."));
 
-                       return; // never fall through to usage
+                       return;  // never fall through to usage
                }
 
                default:
@@ -800,21 +821,21 @@ void CommonCommand_who(float request, entity caller, float argc)
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
 void CommonCommand_(float request, entity caller)
 {
-       switch(request)
-       {
-               case CMD_REQUEST_COMMAND:
-               {
-
-                       return; // never fall through to usage
-               }
-
-               default:
-               case CMD_REQUEST_USAGE:
-               {
-                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " "));
-                       print_to(caller, "  No arguments required.");
-                       return;
-               }
-       }
+    switch(request)
+    {
+        case CMD_REQUEST_COMMAND:
+        {
+
+            return; // never fall through to usage
+        }
+
+        default:
+        case CMD_REQUEST_USAGE:
+        {
+            print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " "));
+            print_to(caller, "  No arguments required.");
+            return;
+        }
+    }
 }
 */
index 9a011fb851b6442262feff31b6fc9bc2579655a5..2a1a2b42fd16d45008c89e2875617947f09bcd63 100644 (file)
@@ -27,15 +27,15 @@ const float TIMEOUT_ACTIVE = 2;
 const float TIMEOUT_SLOWMO_VALUE = 0.0001;
 
 // global timeout information declarations
-entity timeout_caller; // contains the entity of the player who started the last timeout
-entity timeout_handler; // responsible for centerprinting the timeout countdowns and playing sounds
-float sys_frametime; // gets initialised in worldspawn, saves the value from autocvar_sys_ticrate
-float orig_slowmo; // contains the value of autocvar_slowmo so that, after timeout finished, it isn't set to slowmo 1 necessarily
-float timeout_time; // contains the time in seconds that the active timeout has left
-float timeout_leadtime; // contains the number of seconds left of the leadtime (before the timeout starts)
-float timeout_status; // (values: 0, 1, 2) contains whether a timeout is not active (0), was called but still at leadtime (1) or is active (2)
+entity timeout_caller;   // contains the entity of the player who started the last timeout
+entity timeout_handler;  // responsible for centerprinting the timeout countdowns and playing sounds
+float sys_frametime;     // gets initialised in worldspawn, saves the value from autocvar_sys_ticrate
+float orig_slowmo;       // contains the value of autocvar_slowmo so that, after timeout finished, it isn't set to slowmo 1 necessarily
+float timeout_time;      // contains the time in seconds that the active timeout has left
+float timeout_leadtime;  // contains the number of seconds left of the leadtime (before the timeout starts)
+float timeout_status;    // (values: 0, 1, 2) contains whether a timeout is not active (0), was called but still at leadtime (1) or is active (2)
 .float allowed_timeouts; // contains the number of allowed timeouts for each player
-.vector lastV_angle; //used when pausing the game in order to force the player to keep his old view angle fixed
+.vector lastV_angle;     // used when pausing the game in order to force the player to keep his old view angle fixed
 
 // allow functions to be used in other code like g_world.qc and teamplay.qc
 void timeout_handler_think();
@@ -60,7 +60,7 @@ float VerifyClientEntity(entity client, float must_be_real, float must_be_bots);
 
 // if the client is not acceptable, return a string to be used for error messages
 string GetClientErrorString_color(float clienterror, string original_input, string col);
-#define GetClientErrorString(clienterror,original_input) GetClientErrorString_color(clienterror,original_input,"^7")
+#define GetClientErrorString(clienterror, original_input) GetClientErrorString_color(clienterror, original_input, "^7")
 
 // is this entity number even in the possible range of entities?
 float VerifyClientNumber(float tmp_number);
@@ -123,7 +123,7 @@ void CommonCommand_who(float request, entity caller, float argc);
 // ==================================
 
 // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define COMMON_COMMANDS(request,caller,arguments,command) \
+#define COMMON_COMMANDS(request, caller, arguments, command) \
        COMMON_COMMAND("cvar_changes", CommonCommand_cvar_changes(request, caller), "Prints a list of all changed server cvars") \
        COMMON_COMMAND("cvar_purechanges", CommonCommand_cvar_purechanges(request, caller), "Prints a list of all changed gameplay cvars") \
        COMMON_COMMAND("editmob", CommonCommand_editmob(request, caller, arguments), "Modifies a monster or all monsters") \
@@ -143,46 +143,42 @@ void CommonCommand_who(float request, entity caller, float argc);
 
 void CommonCommand_macro_help(entity caller)
 {
-       #define COMMON_COMMAND(name,function,description) \
+       #define COMMON_COMMAND(name, function, description) \
                { print_to(caller, strcat("  ^2", name, "^7: ", description)); }
 
        COMMON_COMMANDS(0, caller, 0, "");
-       #undef COMMON_COMMAND
-
-       return;
+#undef COMMON_COMMAND
 }
 
 float CommonCommand_macro_command(float argc, entity caller, string command)
 {
-       #define COMMON_COMMAND(name,function,description) \
-               { if(name == strtolower(argv(0))) { function; return true; } }
+       #define COMMON_COMMAND(name, function, description) \
+               { if (name == strtolower(argv(0))) { function; return true; } }
 
        COMMON_COMMANDS(CMD_REQUEST_COMMAND, caller, argc, command);
-       #undef COMMON_COMMAND
+#undef COMMON_COMMAND
 
        return false;
 }
 
 float CommonCommand_macro_usage(float argc, entity caller)
 {
-       #define COMMON_COMMAND(name,function,description) \
-               { if(name == strtolower(argv(1))) { function; return true; } }
+       #define COMMON_COMMAND(name, function, description) \
+               { if (name == strtolower(argv(1))) { function; return true; } }
 
        COMMON_COMMANDS(CMD_REQUEST_USAGE, caller, argc, "");
-       #undef COMMON_COMMAND
+#undef COMMON_COMMAND
 
        return false;
 }
 
 void CommonCommand_macro_write_aliases(float fh)
 {
-       #define COMMON_COMMAND(name,function,description) \
+       #define COMMON_COMMAND(name, function, description) \
                { CMD_Write_Alias("qc_cmd_svcmd", name, description); }
 
        COMMON_COMMANDS(0, world, 0, "");
-       #undef COMMON_COMMAND
-
-       return;
+#undef COMMON_COMMAND
 }
 
 
index fd312bff6174b840d0c808f2370d01ee5407dc46..d2233029d8eee619902f4dc55175825e687c7783 100644 (file)
@@ -21,7 +21,7 @@
 
 // See common.qc for their proper commands
 
-string getrecords(int page) // 50 records per page
+string getrecords(int page)  // 50 records per page
 {
        string s = "";
 
@@ -30,10 +30,8 @@ string getrecords(int page) // 50 records per page
 
        MapInfo_ClearTemps();
 
-       if(s == "" && page == 0)
-               return "No records are available on this server.\n";
-       else
-               return s;
+       if (s == "" && page == 0) return "No records are available on this server.\n";
+       else return s;
 }
 
 string getrankings()
@@ -48,8 +46,7 @@ string getrankings()
        {
                t = race_readTime(map, i);
 
-               if (t == 0)
-                       continue;
+               if (t == 0) continue;
 
                n = race_readName(map, i);
                p = count_ordinal(i);
@@ -58,10 +55,8 @@ string getrankings()
 
        MapInfo_ClearTemps();
 
-       if (s == "")
-               return strcat("No records are available for the map: ", map, "\n");
-       else
-               return strcat("Records for ", map, ":\n", s);
+       if (s == "") return strcat("No records are available for the map: ", map, "\n");
+       else return strcat("Records for ", map, ":\n", s);
 }
 
 string getladder()
@@ -71,23 +66,21 @@ string getladder()
 
        rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
 
-       for(k = 0; k < MapInfo_count; ++k)
+       for (k = 0; k < MapInfo_count; ++k)
        {
-               if(MapInfo_Get_ByID(k))
+               if (MapInfo_Get_ByID(k))
                {
-                       for(i = 0; i <= LADDER_CNT; ++i) // i = 0 because it is the speed award
+                       for (i = 0; i <= LADDER_CNT; ++i) // i = 0 because it is the speed award
                        {
-                               if(i == 0) // speed award
+                               if (i == 0)                   // speed award
                                {
-                                       if(stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/speed"))) == 0)
-                                               continue;
+                                       if (stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/speed"))) == 0) continue;
 
                                        myuid = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/crypto_idfp"));
                                }
-                               else // normal record, if it exists (else break)
+                               else  // normal record, if it exists (else break)
                                {
-                                       if(race_readTime(MapInfo_Map_bspname, i) == 0)
-                                               continue;
+                                       if (race_readTime(MapInfo_Map_bspname, i) == 0) continue;
 
                                        myuid = race_readUID(MapInfo_Map_bspname, i);
                                }
@@ -101,43 +94,38 @@ string getladder()
 
                                temp_s = db_get(TemporaryDB, strcat("ladder", myuid));
 
-                               if(temp_s == "")
+                               if (temp_s == "")
                                {
                                        db_put(TemporaryDB, strcat("uid", ftos(uidcnt)), myuid);
                                        ++uidcnt;
 
-                                       for(j = 0; j <= LADDER_CNT + 1; ++j)
+                                       for (j = 0; j <= LADDER_CNT + 1; ++j)
                                        {
-                                               if(j != LADDER_CNT + 1)
-                                                       temp_s = strcat(temp_s, "0 ");
-                                               else
-                                                       temp_s = strcat(temp_s, "0");
+                                               if (j != LADDER_CNT + 1) temp_s = strcat(temp_s, "0 ");
+                                               else temp_s = strcat(temp_s, "0");
                                        }
                                }
 
                                tokenize_console(temp_s);
                                s = "";
 
-                               if(i == 0) // speed award
+                               if (i == 0)                                         // speed award
                                {
-                                       for(j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
+                                       for (j = 0; j <= LADDER_CNT; ++j)               // loop over each arg in the string
                                        {
-                                               if(j == 0) // speed award
-                                                       s = strcat(s, ftos(stof(argv(j)) +1)); // add 1 to speed rec count and write
-                                               else
-                                                       s = strcat(s, " ", argv(j)); // just copy over everything else
+                                               if (j == 0)                                 // speed award
+                                                       s = strcat(s, ftos(stof(argv(j)) + 1)); // add 1 to speed rec count and write
+                                               else s = strcat(s, " ", argv(j));           // just copy over everything else
                                        }
                                }
-                               else // record
+                               else  // record
                                {
-                                       for(j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
+                                       for (j = 0; j <= LADDER_CNT; ++j)                    // loop over each arg in the string
                                        {
-                                               if(j == 0)
-                                                       s = strcat(s, argv(j)); // speed award, dont prefix with " "
-                                               else if(j == i) // wanted rec!
-                                                       s = strcat(s, " ", ftos(stof(argv(j)) +1)); // update argv(j)
-                                               else
-                                                       s = strcat(s, " ", argv(j)); // just copy over everything else
+                                               if (j == 0) s = strcat(s, argv(j));              // speed award, dont prefix with " "
+                                               else if (j == i)                                 // wanted rec!
+                                                       s = strcat(s, " ", ftos(stof(argv(j)) + 1)); // update argv(j)
+                                               else s = strcat(s, " ", argv(j));                // just copy over everything else
                                        }
                                }
 
@@ -150,33 +138,31 @@ string getladder()
                                // 5th place = floor(100 / 5) = 20 points
                                // ... etc
 
-                               if(i == 0)
-                                       s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + LADDER_FIRSTPOINT / 10)); // speed award, add LADDER_FIRSTPOINT / 10 points
-                               else
-                                       s = strcat(s, " ", ftos(stof(argv(LADDER_CNT+1)) + floor(LADDER_FIRSTPOINT / i))); // record, add LADDER_FIRSTPOINT / i points
+                               if (i == 0) s = strcat(s, " ", ftos(stof(argv(LADDER_CNT + 1)) + LADDER_FIRSTPOINT / 10)); // speed award, add LADDER_FIRSTPOINT / 10 points
+                               else s = strcat(s, " ", ftos(stof(argv(LADDER_CNT + 1)) + floor(LADDER_FIRSTPOINT / i)));  // record, add LADDER_FIRSTPOINT / i points
 
                                db_put(TemporaryDB, strcat("ladder", myuid), s);
                        }
                }
        }
 
-       for(i = 0; i <= uidcnt; ++i) // for each known uid
+       for (i = 0; i <= uidcnt; ++i)  // for each known uid
        {
                thisuid = db_get(TemporaryDB, strcat("uid", ftos(i)));
                temp_s = db_get(TemporaryDB, strcat("ladder", thisuid));
                tokenize_console(temp_s);
-               thiscnt = stof(argv(LADDER_CNT+1));
+               thiscnt = stof(argv(LADDER_CNT + 1));
 
-               if(thiscnt > top_scores[LADDER_SIZE-1])
+               if (thiscnt > top_scores[LADDER_SIZE - 1])
                {
-                       for(j = 0; j < LADDER_SIZE; ++j) // for each place in ladder
+                       for (j = 0; j < LADDER_SIZE; ++j)  // for each place in ladder
                        {
-                               if(thiscnt > top_scores[j])
+                               if (thiscnt > top_scores[j])
                                {
-                                       for(k = LADDER_SIZE-1; k >= j; --k)
+                                       for (k = LADDER_SIZE - 1; k >= j; --k)
                                        {
-                                               top_uids[k] = top_uids[k-1];
-                                               top_scores[k] = top_scores[k-1];
+                                               top_uids[k] = top_uids[k - 1];
+                                               top_scores[k] = top_scores[k - 1];
                                        }
 
                                        top_uids[j] = thisuid;
@@ -192,51 +178,47 @@ string getladder()
        s = strcat(s, "Pos ^3|");
        s = strcat(s, " ^7Total  ^3|");
 
-       for(i = 1; i <= LADDER_CNT; ++i)
-               { s = strcat(s, " ^7", count_ordinal(i), " ^3|"); }
-
+       for (i = 1; i <= LADDER_CNT; ++i)
+               s = strcat(s, " ^7", count_ordinal(i), " ^3|");
        s = strcat(s, " ^7Speed awards ^3| ^7Name");
        s = strcat(s, "\n^3----+--------");
 
-       for(i = 1; i <= min(9, LADDER_CNT); ++i)
-               { s = strcat(s, "+-----"); }
-
-       #if LADDER_CNT > 9
-       for(i = 1; i <= LADDER_CNT - 9; ++i)
-               { s = strcat(s, "+------"); }
-       #endif
+       for (i = 1; i <= min(9, LADDER_CNT); ++i)
+               s = strcat(s, "+-----");
+#if LADDER_CNT > 9
+               for (i = 1; i <= LADDER_CNT - 9; ++i)
+                       s = strcat(s, "+------");
+#endif
 
        s = strcat(s, "+--------------+--------------------\n");
 
-       for(i = 0; i < LADDER_SIZE; ++i)
+       for (i = 0; i < LADDER_SIZE; ++i)
        {
                temp_s = db_get(TemporaryDB, strcat("ladder", top_uids[i]));
                tokenize_console(temp_s);
 
-               if(argv(LADDER_CNT+1) == "") // total is 0, skip
+               if (argv(LADDER_CNT + 1) == "")                           // total is 0, skip
                        continue;
 
-               s = strcat(s, strpad(4, count_ordinal(i+1)), "^3| ^7"); // pos
-               s = strcat(s, strpad(7, argv(LADDER_CNT+1)), "^3| ^7"); // total
+               s = strcat(s, strpad(4, count_ordinal(i + 1)), "^3| ^7"); // pos
+               s = strcat(s, strpad(7, argv(LADDER_CNT + 1)), "^3| ^7"); // total
 
-               for(j = 1; j <= min(9, LADDER_CNT); ++j)
-                       { s = strcat(s, strpad(4, argv(j)), "^3| ^7"); } // 1st, 2nd, 3rd etc cnt
+               for (j = 1; j <= min(9, LADDER_CNT); ++j)
+                       s = strcat(s, strpad(4, argv(j)), "^3| ^7");          // 1st, 2nd, 3rd etc cnt
 
-               #if LADDER_CNT > 9
-               for(j = 10; j <= LADDER_CNT; ++j)
-                       { s = strcat(s, strpad(4, argv(j)), " ^3| ^7"); } // 1st, 2nd, 3rd etc cnt
-               #endif
+#if LADDER_CNT > 9
+                       for (j = 10; j <= LADDER_CNT; ++j)
+                               s = strcat(s, strpad(4, argv(j)), " ^3| ^7"); // 1st, 2nd, 3rd etc cnt
+#endif
 
-               s = strcat(s, strpad(13, argv(0)), "^3| ^7"); // speed award cnt
-               s = strcat(s, uid2name(top_uids[i]), "\n"); // name
+               s = strcat(s, strpad(13, argv(0)), "^3| ^7");         // speed award cnt
+               s = strcat(s, uid2name(top_uids[i]), "\n");           // name
        }
 
        MapInfo_ClearTemps();
 
-       if(s == "")
-               return "No ladder on this server!\n";
-       else
-               return strcat("Top ", ftos(LADDER_SIZE), " ladder rankings:\n", s);
+       if (s == "") return "No ladder on this server!\n";
+       else return strcat("Top ", ftos(LADDER_SIZE), " ladder rankings:\n", s);
 }
 
 string getmaplist()
@@ -245,12 +227,11 @@ string getmaplist()
        int i, argc;
 
        argc = tokenize_console(autocvar_g_maplist);
-       for(i = 0; i < argc; ++i)
+       for (i = 0; i < argc; ++i)
        {
-               if(MapInfo_CheckMap(argv(i)))
+               if (MapInfo_CheckMap(argv(i)))
                {
-                       if(i % 2) { col = "^2"; }
-                       else { col = "^3"; }
+                       if (i % 2) col = "^2"; else col = "^3";
                        maplist = sprintf("%s%s%s ", maplist, col, argv(i));
                }
        }
@@ -265,25 +246,23 @@ string getlsmaps()
        string lsmaps = "", col;
        float i, newmaps = 0;
 
-       for(i = 0; i < MapInfo_count; ++i)
+       for (i = 0; i < MapInfo_count; ++i)
        {
-               if((MapInfo_Get_ByID(i)) && !(MapInfo_Map_flags & MapInfo_ForbiddenFlags()))
+               if ((MapInfo_Get_ByID(i)) && !(MapInfo_Map_flags & MapInfo_ForbiddenFlags()))
                {
                        // todo: Check by play count of maps for other game types?
-                       if(
-                               (g_race && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time"))))
-                               ||
-                               (g_cts && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time"))))
-                       )
+                       if (
+                           (g_race && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time"))))
+                           ||
+                           (g_cts && !stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time"))))
+                          )
                        {
                                newmaps = true;
-                               if(i % 2) { col = "^4*"; }
-                               else { col = "^5*"; }
+                               if (i % 2) col = "^4*"; else col = "^5*";
                        }
                        else
                        {
-                               if(i % 2) { col = "^2"; }
-                               else { col = "^3"; }
+                               if (i % 2) col = "^2"; else col = "^3";
                        }
 
                        lsmaps = sprintf("%s%s%s ", lsmaps, col, MapInfo_Map_bspname);
@@ -298,10 +277,9 @@ string getmonsterlist()
 {
        string monsterlist = "", col;
 
-       for(int i = MON_FIRST; i <= MON_LAST; ++i)
+       for (int i = MON_FIRST; i <= MON_LAST; ++i)
        {
-               if(i % 2) { col = "^2"; }
-               else { col = "^3"; }
+               if (i % 2) col = "^2"; else col = "^3";
                monsterlist = sprintf("%s%s%s ", monsterlist, col, (get_monsterinfo(i)).netname);
        }
 
index 0e419fdea3ca94a327d90843bbfeb7cdfa8380e6..a0f9b21ef8fae18214da4fa6d47fa34954b1952e 100644 (file)
@@ -8,17 +8,17 @@
 
 // ladder bullshit todo
 const int LADDER_FIRSTPOINT = 100;
-#define LADDER_CNT 10 // position X still gives LADDER_FIRSTPOINT/X points
-const int LADDER_SIZE = 30;    // ladder shows the top X players
+#define LADDER_CNT 10       // position X still gives LADDER_FIRSTPOINT/X points
+const int LADDER_SIZE = 30; // ladder shows the top X players
 
 string top_uids[LADDER_SIZE];
 float top_scores[LADDER_SIZE];
 
 // allow functions to be used in other code like g_world.qc and race.qc
 string getrecords(float page);
-string getrankings(void);
-string getladder(void);
-string getmaplist(void);
-string getlsmaps(void);
-string getmonsterlist(void);
+string getrankings();
+string getladder();
+string getmaplist();
+string getlsmaps();
+string getmonsterlist();
 #endif
index 60e6bde62db74433b8ee63b3a1b79a5da22ae780..7475c5a5463185f617a1913a4ea51959d55bdd29 100644 (file)
@@ -25,14 +25,14 @@ float FullTraceFraction(vector a, vector mi, vector ma, vector b)
        float n, m;
        n = m = 0;
 
-       while(vlen(c - b) > 1)
+       while (vlen(c - b) > 1)
        {
                ++m;
 
                tracebox(c, mi, ma, b, MOVE_WORLDONLY, world);
                ++n;
 
-               if(!trace_startsolid)
+               if (!trace_startsolid)
                {
                        black += vlen(trace_endpos - c);
                        c = trace_endpos;
@@ -44,8 +44,7 @@ float FullTraceFraction(vector a, vector mi, vector ma, vector b)
                c = trace_endpos;
        }
 
-       if(n > 200)
-               LOG_TRACE("HOLY SHIT! FullTraceFraction: ", ftos(n), " total traces, ", ftos(m), " iterations\n");
+       if (n > 200) LOG_TRACE("HOLY SHIT! FullTraceFraction: ", ftos(n), " total traces, ", ftos(m), " iterations\n");
 
        return white / (black + white);
 }
@@ -74,17 +73,13 @@ float RadarMapAtPoint_LineBlock(float x, float y, float w, float h, float zmin,
        ma = '1 0 0' * w + '0 1 0' * h + dz;
        o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
 
-       if(x < world.absmin.x - w)
-               return 0;
-       if(y < world.absmin.y - h)
-               return 0;
-       if(x > world.absmax.x)
-               return 0;
-       if(y > world.absmax.y)
-               return 0;
+       if (x < world.absmin.x - w) return 0;
+       if (y < world.absmin.y - h) return 0;
+       if (x > world.absmax.x) return 0;
+       if (y > world.absmax.y) return 0;
 
        r = 0;
-       for(i = 0; i < q; ++i)
+       for (i = 0; i < q; ++i)
        {
                vector v1, v2;
                v1 = v2 = o + dz * i + mi;
@@ -95,8 +90,7 @@ float RadarMapAtPoint_LineBlock(float x, float y, float w, float h, float zmin,
                v2_y += random() * (ma.y - mi.y);
                v2_z += random() * (ma.z - mi.z);
                traceline(v1, v2, MOVE_WORLDONLY, world);
-               if(trace_startsolid || trace_fraction < 1)
-                       ++r;
+               if (trace_startsolid || trace_fraction < 1) ++r;
        }
        return r / q;
 }
@@ -114,21 +108,16 @@ float RadarMapAtPoint_Block(float x, float y, float w, float h, float zmin, floa
        ma = '1 0 0' * w + '0 1 0' * h + dz;
        o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
 
-       if(x < world.absmin.x - w)
-               return 0;
-       if(y < world.absmin.y - h)
-               return 0;
-       if(x > world.absmax.x)
-               return 0;
-       if(y > world.absmax.y)
-               return 0;
+       if (x < world.absmin.x - w) return 0;
+       if (y < world.absmin.y - h) return 0;
+       if (x > world.absmax.x) return 0;
+       if (y > world.absmax.y) return 0;
 
        r = 0;
-       for(i = 0; i < q; ++i)
+       for (i = 0; i < q; ++i)
        {
                tracebox(o + dz * i, mi, ma, o + dz * i, MOVE_WORLDONLY, world);
-               if(trace_startsolid)
-                       ++r;
+               if (trace_startsolid) ++r;
        }
        return r / q;
 }
@@ -136,7 +125,7 @@ float RadarMapAtPoint_Sample(float x, float y, float w, float h, float zmin, flo
 {
        vector a, b, mi, ma;
 
-       q *= 4; // choose q so it matches the regular algorithm in speed
+       q *= 4;  // choose q so it matches the regular algorithm in speed
 
        q = 256 * q - 1;
        // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value
@@ -149,15 +138,14 @@ float RadarMapAtPoint_Sample(float x, float y, float w, float h, float zmin, flo
        float c, i;
        c = 0;
 
-       for(i = 0; i < q; ++i)
+       for (i = 0; i < q; ++i)
        {
                vector v;
                v.x = a.x + random() * b.x;
                v.y = a.y + random() * b.y;
                v.z = a.z + random() * b.z;
                traceline(v, v, MOVE_WORLDONLY, world);
-               if(trace_startsolid)
-                       ++c;
+               if (trace_startsolid) ++c;
        }
 
        return c / q;
@@ -168,22 +156,17 @@ void sharpen_set(int x, float v)
 }
 float sharpen_getpixel(int x, int y)
 {
-       if(x < 0)
-               return 0;
-       if(x >= RADAR_WIDTH_MAX)
-               return 0;
-       if(y < 0)
-               return 0;
-       if(y > 2)
-               return 0;
+       if (x < 0) return 0;
+       if (x >= RADAR_WIDTH_MAX) return 0;
+       if (y < 0) return 0;
+       if (y > 2) return 0;
        return sharpen_buffer[x + y * RADAR_WIDTH_MAX];
 }
 float sharpen_get(float x, float a)
 {
        float sum = sharpen_getpixel(x, 1);
-       if(a == 0)
-               return sum;
-       sum *= (8 + 1/a);
+       if (a == 0) return sum;
+       sum *= (8 + 1 / a);
        sum -= sharpen_getpixel(x - 1, 0);
        sum -= sharpen_getpixel(x - 1, 1);
        sum -= sharpen_getpixel(x - 1, 2);
@@ -196,7 +179,7 @@ float sharpen_get(float x, float a)
 }
 void sharpen_shift(int w)
 {
-       for(int i = 0; i < w; ++i)
+       for (int i = 0; i < w; ++i)
        {
                sharpen_buffer[i] = sharpen_buffer[i + RADAR_WIDTH_MAX];
                sharpen_buffer[i + RADAR_WIDTH_MAX] = sharpen_buffer[i + 2 * RADAR_WIDTH_MAX];
@@ -205,7 +188,7 @@ void sharpen_shift(int w)
 }
 void sharpen_init(int w)
 {
-       for(int i = 0; i < w; ++i)
+       for (int i = 0; i < w; ++i)
        {
                sharpen_buffer[i] = 0;
                sharpen_buffer[i + RADAR_WIDTH_MAX] = 0;
@@ -214,11 +197,11 @@ void sharpen_init(int w)
 }
 void RadarMap_Next()
 {
-       if(radarmapper.count & 4)
+       if (radarmapper.count & 4)
        {
                localcmd("quit\n");
        }
-       else if(radarmapper.count & 2)
+       else if (radarmapper.count & 2)
        {
                localcmd(strcat("defer 1 \"sv_cmd radarmap --flags ", ftos(radarmapper.count), strcat(" --res ", ftos(radarmapper.size.x), " ", ftos(radarmapper.size.y), " --sharpen ", ftos(radarmapper.ltime), " --qual ", ftos(radarmapper.size.z)), "\"\n"));
                GotoNextMap(0);
@@ -227,7 +210,8 @@ void RadarMap_Next()
        radarmapper = world;
 }
 void RadarMap_Think()
-{SELFPARAM();
+{
+       SELFPARAM();
        // rough map entity
        //   cnt: current line
        //   size: pixel width/height
@@ -237,7 +221,7 @@ void RadarMap_Think()
        float i, x, l;
        string si;
 
-       if(self.frame == 0)
+       if (self.frame == 0)
        {
                // initialize
                get_mi_min_max_texcoords(1);
@@ -247,22 +231,16 @@ void RadarMap_Think()
                self.maxs_z = mi_max.z - mi_min.z;
                LOG_INFO("Picture mins/maxs: ", ftos(self.maxs.x), " and ", ftos(self.maxs.y), " should match\n");
                self.netname = strzone(strcat("gfx/", mi_shortname, "_radar.xpm"));
-               if(!(self.count & 1))
+               if (!(self.count & 1))
                {
                        self.cnt = fopen(self.netname, FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.tga"), FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.png"), FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.jpg"), FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.tga"), FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.png"), FILE_READ);
-                       if(self.cnt < 0)
-                               self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.jpg"), FILE_READ);
-                       if(self.cnt >= 0)
+                       if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.tga"), FILE_READ);
+                       if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.png"), FILE_READ);
+                       if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.jpg"), FILE_READ);
+                       if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.tga"), FILE_READ);
+                       if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.png"), FILE_READ);
+                       if (self.cnt < 0) self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.jpg"), FILE_READ);
+                       if (self.cnt >= 0)
                        {
                                fclose(self.cnt);
 
@@ -272,7 +250,7 @@ void RadarMap_Think()
                        }
                }
                self.cnt = fopen(self.netname, FILE_WRITE);
-               if(self.cnt < 0)
+               if (self.cnt < 0)
                {
                        LOG_INFO("Error writing ", self.netname, "\n");
                        remove(self);
@@ -284,47 +262,47 @@ void RadarMap_Think()
                fputs(self.cnt, "static char *RadarMap[] = {\n");
                fputs(self.cnt, "/* columns rows colors chars-per-pixel */\n");
                fputs(self.cnt, strcat("\"", ftos(self.size.x), " ", ftos(self.size.y), " 256 2\",\n"));
-               for(i = 0; i < 256; ++i)
+               for (i = 0; i < 256; ++i)
                {
-                       si = substring(doublehex, i*2, 2);
+                       si = substring(doublehex, i * 2, 2);
                        fputs(self.cnt, strcat("\"", si, " c #", si, si, si, "\",\n"));
                }
                self.frame += 1;
                self.nextthink = time;
                sharpen_init(self.size.x);
        }
-       else if(self.frame <= self.size.y)
+       else if (self.frame <= self.size.y)
        {
                // fill the sharpen buffer with this line
                sharpen_shift(self.size.x);
                i = self.count & 24;
 
-               switch(i)
+               switch (i)
                {
                        case 0:
                        default:
-                               for(x = 0; x < self.size.x; ++x)
+                               for (x = 0; x < self.size.x; ++x)
                                {
                                        l = RadarMapAtPoint_Block(self.mins.x + x * self.maxs.x, self.mins.y + (self.size.y - self.frame) * self.maxs.y, self.maxs.x, self.maxs.y, self.mins.z, self.maxs.z, self.size.z);
                                        sharpen_set(x, l);
                                }
                                break;
                        case 8:
-                               for(x = 0; x < self.size.x; ++x)
+                               for (x = 0; x < self.size.x; ++x)
                                {
                                        l = RadarMapAtPoint_Trace(self.mins.x + x * self.maxs.x, self.mins.y + (self.size.y - self.frame) * self.maxs.y, self.maxs.x, self.maxs.y, self.mins.z, self.maxs.z, self.size.z);
                                        sharpen_set(x, l);
                                }
                                break;
                        case 16:
-                               for(x = 0; x < self.size.x; ++x)
+                               for (x = 0; x < self.size.x; ++x)
                                {
                                        l = RadarMapAtPoint_Sample(self.mins.x + x * self.maxs.x, self.mins.y + (self.size.y - self.frame) * self.maxs.y, self.maxs.x, self.maxs.y, self.mins.z, self.maxs.z, self.size.z);
                                        sharpen_set(x, l);
                                }
                                break;
                        case 24:
-                               for(x = 0; x < self.size.x; ++x)
+                               for (x = 0; x < self.size.x; ++x)
                                {
                                        l = RadarMapAtPoint_LineBlock(self.mins.x + x * self.maxs.x, self.mins.y + (self.size.y - self.frame) * self.maxs.y, self.maxs.x, self.maxs.y, self.mins.z, self.maxs.z, self.size.z);
                                        sharpen_set(x, l);
@@ -333,17 +311,19 @@ void RadarMap_Think()
                }
 
                // do we have enough lines?
-               if(self.frame >= 2)
+               if (self.frame >= 2)
                {
                        // write a pixel line
                        fputs(self.cnt, "\"");
-                       for(x = 0; x < self.size.x; ++x)
+                       for (x = 0; x < self.size.x; ++x)
                        {
                                l = sharpen_get(x, self.ltime);
                                fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));
                        }
-                       if(self.frame == self.size.y)
+                       if (self.frame == self.size.y)
+                       {
                                fputs(self.cnt, "\"\n");
+                       }
                        else
                        {
                                fputs(self.cnt, "\",\n");
@@ -352,18 +332,20 @@ void RadarMap_Think()
                }
 
                // is this the last line? then write back the missing line
-               if(self.frame == self.size.y)
+               if (self.frame == self.size.y)
                {
                        sharpen_shift(self.size.x);
                        // write a pixel line
                        fputs(self.cnt, "\"");
-                       for(x = 0; x < self.size.x; ++x)
+                       for (x = 0; x < self.size.x; ++x)
                        {
                                l = sharpen_get(x, self.ltime);
                                fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));
                        }
-                       if(self.frame == self.size.y)
+                       if (self.frame == self.size.y)
+                       {
                                fputs(self.cnt, "\"\n");
+                       }
                        else
                        {
                                fputs(self.cnt, "\",\n");
@@ -388,32 +370,72 @@ float RadarMap_Make(float argc)
 {
        float i;
 
-       if(!radarmapper)
+       if (!radarmapper)
        {
-               radarmapper = spawn();
-               radarmapper.classname = "radarmapper";
+               radarmapper = new(radarmapper);
                radarmapper.think = RadarMap_Think;
                radarmapper.nextthink = time;
-               radarmapper.count = 8; // default to the --trace method, as it is faster now
+               radarmapper.count = 8;  // default to the --trace method, as it is faster now
                radarmapper.ltime = 1;
                radarmapper.size = '512 512 1';
-               for(i = 1; i < argc; ++i)
+               for (i = 1; i < argc; ++i)
                {
-                       switch(argv(i))
+                       switch (argv(i))
                        {
-                               case "--force": { radarmapper.count |= 1; break; }
-                               case "--loop": { radarmapper.count |= 2; break; }
-                               case "--quit": { radarmapper.count |= 4; break; }
-                               case "--block": { radarmapper.count &= ~24; break; }
-                               case "--trace": { radarmapper.count &= ~24; radarmapper.count |= 8; break; }
-                               case "--sample": { radarmapper.count &= ~24; radarmapper.count |= 16; break; }
-                               case "--lineblock": { radarmapper.count |= 24; break; }
-                               case "--flags": { ++i; radarmapper.count = stof(argv(i)); break; } // for the recursive call
-                               case "--sharpen": { ++i; radarmapper.ltime = stof(argv(i)); break; } // for the recursive call
-                               case "--res": // minor alias
-                               case "--resolution": { ++i; radarmapper.size_x = stof(argv(i)); ++i; radarmapper.size_y = stof(argv(i)); break; }
-                               case "--qual": // minor alias
-                               case "--quality": { ++i; radarmapper.size_z = stof(argv(i)); break; }
+                               case "--force":
+                               { radarmapper.count |= 1;
+                                 break;
+                               }
+                               case "--loop":
+                               { radarmapper.count |= 2;
+                                 break;
+                               }
+                               case "--quit":
+                               { radarmapper.count |= 4;
+                                 break;
+                               }
+                               case "--block":
+                               { radarmapper.count &= ~24;
+                                 break;
+                               }
+                               case "--trace":
+                               { radarmapper.count &= ~24;
+                                 radarmapper.count |= 8;
+                                 break;
+                               }
+                               case "--sample":
+                               { radarmapper.count &= ~24;
+                                 radarmapper.count |= 16;
+                                 break;
+                               }
+                               case "--lineblock":
+                               { radarmapper.count |= 24;
+                                 break;
+                               }
+                               case "--flags":
+                               { ++i;
+                                 radarmapper.count = stof(argv(i));
+                                 break;
+                               }  // for the recursive call
+                               case "--sharpen":
+                               { ++i;
+                                 radarmapper.ltime = stof(argv(i));
+                                 break;
+                               }  // for the recursive call
+                               case "--res":  // minor alias
+                               case "--resolution":
+                               { ++i;
+                                 radarmapper.size_x = stof(argv(i));
+                                 ++i;
+                                 radarmapper.size_y = stof(argv(i));
+                                 break;
+                               }
+                               case "--qual":  // minor alias
+                               case "--quality":
+                               { ++i;
+                                 radarmapper.size_z = stof(argv(i));
+                                 break;
+                               }
 
                                default:
                                        i = argc;
@@ -423,10 +445,10 @@ float RadarMap_Make(float argc)
                        }
                }
 
-               if(radarmapper) // after doing the arguments, see if we successfully went forward.
+               if (radarmapper)  // after doing the arguments, see if we successfully went forward.
                {
                        LOG_INFO("Radarmap entity spawned.\n");
-                       return true; // if so, don't print usage.
+                       return true;  // if so, don't print usage.
                }
        }
 
index cde2d6c45209150c5c61a4380bc09efe1a9d3f96..eec862f364f24b7c7b87ccb59cd0a194fac1100b 100644 (file)
@@ -31,7 +31,7 @@
 #include "../../common/monsters/sv_monsters.qh"
 
 
-void PutObserverInServer (void);
+void PutObserverInServer();
 
 // =====================================================
 //  Server side game commands code, reworked by Samual
@@ -40,8 +40,9 @@ void PutObserverInServer (void);
 
 //  used by GameCommand_make_mapinfo()
 void make_mapinfo_Think()
-{SELFPARAM();
-       if(MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
+{
+       SELFPARAM();
+       if (MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
        {
                LOG_INFO("Done rebuiling mapinfos.\n");
                MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
@@ -61,35 +62,29 @@ void changematchtime(float delta, float mi, float ma)
        float update;
        float lim;
 
-       if(delta == 0)
-               return;
-       if(autocvar_timelimit < 0)
-               return;
+       if (delta == 0) return;
+       if (autocvar_timelimit < 0) return;
 
-       if(mi <= 10)
-               mi = 10; // at least ten sec in the future
+       if (mi <= 10) mi = 10;  // at least ten sec in the future
        cur = time - game_starttime;
-       if(cur > 0)
-               mi += cur; // from current time!
+       if (cur > 0) mi += cur; // from current time!
 
        lim = autocvar_timelimit * 60;
 
-       if(delta > 0)
+       if (delta > 0)
        {
-               if(lim == 0)
-                       return; // cannot increase any further
-               else if(lim < ma)
-                       update = min(ma, lim + delta);
-               else // already above maximum: FAIL
+               if (lim == 0) return; // cannot increase any further
+               else if (lim < ma) update = min(ma, lim + delta);
+               else                  // already above maximum: FAIL
                        return;
        }
        else
        {
-               if(lim == 0) // infinite: try reducing to max, if we are allowed to
+               if (lim == 0)      // infinite: try reducing to max, if we are allowed to
                        update = max(mi, ma);
-               else if(lim > mi) // above minimum: decrease
+               else if (lim > mi) // above minimum: decrease
                        update = max(mi, lim + delta);
-               else // already below minimum: FAIL
+               else               // already below minimum: FAIL
                        return;
        }
 
@@ -103,7 +98,7 @@ void changematchtime(float delta, float mi, float ma)
 
 void GameCommand_adminmsg(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -118,24 +113,25 @@ void GameCommand_adminmsg(float request, float argc)
                        string successful, t;
                        successful = string_null;
 
-                       if((targets) && (admin_message))
+                       if ((targets) && (admin_message))
                        {
-                               for (;targets;)
+                               for ( ; targets; )
                                {
-                                       t = car(targets); targets = cdr(targets);
+                                       t = car(targets);
+                                       targets = cdr(targets);
 
                                        // Check to see if the player is a valid target
                                        client = GetFilteredEntity(t);
                                        accepted = VerifyClientEntity(client, true, false);
 
-                                       if(accepted <= 0)
+                                       if (accepted <= 0)
                                        {
                                                LOG_INFO("adminmsg: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".\n"));
                                                continue;
                                        }
 
                                        // send the centerprint/console print or infomessage
-                                       if(infobartime)
+                                       if (infobartime)
                                        {
                                                stuffcmd(client, sprintf("\ninfobar %f \"%s\"\n", infobartime, MakeConsoleSafe(admin_message)));
                                        }
@@ -150,10 +146,8 @@ void GameCommand_adminmsg(float request, float argc)
                                        continue;
                                }
 
-                               if(successful)
-                                       bprint("Successfully sent message '", admin_message, "' to ", successful, ".\n");
-                               else
-                                       LOG_INFO("No players given (", original_targets, ") could receive the message.\n");
+                               if (successful) bprint("Successfully sent message '", admin_message, "' to ", successful, ".\n");
+                               else LOG_INFO("No players given (", original_targets, ") could receive the message.\n");
 
                                return;
                        }
@@ -176,7 +170,7 @@ void GameCommand_adminmsg(float request, float argc)
 
 void GameCommand_allready(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -195,8 +189,9 @@ void GameCommand_allready(float request)
 }
 
 void GameCommand_allspec(float request, float argc)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -206,13 +201,12 @@ void GameCommand_allspec(float request, float argc)
 
                        FOR_EACH_REALPLAYER(client)
                        {
-                               if (client.caplayer)
-                                       client.caplayer = 0;
+                               if (client.caplayer) client.caplayer = 0;
                                WITH(entity, self, client, PutObserverInServer());
                                ++i;
                        }
-                       if(i) { bprint(strcat("Successfully forced all (", ftos(i), ") players to spectate", (reason ? strcat(" for reason: '", reason, "'") : ""), ".\n")); }
-                       else { LOG_INFO("No players found to spectate.\n"); }
+                       if (i)   bprint(strcat("Successfully forced all (", ftos(i), ") players to spectate", (reason ? strcat(" for reason: '", reason, "'") : ""), ".\n"));
+                       else   LOG_INFO("No players found to spectate.\n");
                        return;
                }
 
@@ -228,15 +222,16 @@ void GameCommand_allspec(float request, float argc)
 }
 
 void GameCommand_anticheat(float request, float argc)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        entity client = GetIndexedEntity(argc, 1);
                        float accepted = VerifyClientEntity(client, false, false);
 
-                       if(accepted > 0)
+                       if (accepted > 0)
                        {
                                WITH(entity, self, client, anticheat_report());
                                return;
@@ -260,7 +255,7 @@ void GameCommand_anticheat(float request, float argc)
 
 void GameCommand_bbox(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -271,70 +266,58 @@ void GameCommand_bbox(float request)
                        LOG_INFO("Solid bounding box size:");
 
                        tracebox('1 0 0' * world.absmin.x,
-                                                       '0 1 0' * world.absmin.y + '0 0 1' * world.absmin.z,
-                                                       '0 1 0' * world.absmax.y + '0 0 1' * world.absmax.z,
-                                                       '1 0 0' * world.absmax.x,
-                                       MOVE_WORLDONLY,
-                                       world);
-                       if(trace_startsolid)
-                               LOG_INFO(" ", ftos(world.absmin.x));
-                       else
-                               LOG_INFO(" ", ftos(trace_endpos.x));
+                               '0 1 0' * world.absmin.y + '0 0 1' * world.absmin.z,
+                               '0 1 0' * world.absmax.y + '0 0 1' * world.absmax.z,
+                               '1 0 0' * world.absmax.x,
+                               MOVE_WORLDONLY,
+                               world);
+                       if (trace_startsolid) LOG_INFO(" ", ftos(world.absmin.x));
+                       else LOG_INFO(" ", ftos(trace_endpos.x));
 
                        tracebox('0 1 0' * world.absmin.y,
-                                                       '1 0 0' * world.absmin.x + '0 0 1' * world.absmin.z,
-                                                       '1 0 0' * world.absmax.x + '0 0 1' * world.absmax.z,
-                                                       '0 1 0' * world.absmax.y,
-                                       MOVE_WORLDONLY,
-                                       world);
-                       if(trace_startsolid)
-                               LOG_INFO(" ", ftos(world.absmin.y));
-                       else
-                               LOG_INFO(" ", ftos(trace_endpos.y));
+                               '1 0 0' * world.absmin.x + '0 0 1' * world.absmin.z,
+                               '1 0 0' * world.absmax.x + '0 0 1' * world.absmax.z,
+                               '0 1 0' * world.absmax.y,
+                               MOVE_WORLDONLY,
+                               world);
+                       if (trace_startsolid) LOG_INFO(" ", ftos(world.absmin.y));
+                       else LOG_INFO(" ", ftos(trace_endpos.y));
 
                        tracebox('0 0 1' * world.absmin.z,
-                                                       '1 0 0' * world.absmin.x + '0 1 0' * world.absmin.y,
-                                                       '1 0 0' * world.absmax.x + '0 1 0' * world.absmax.y,
-                                                       '0 0 1' * world.absmax.z,
-                                       MOVE_WORLDONLY,
-                                       world);
-                       if(trace_startsolid)
-                               LOG_INFO(" ", ftos(world.absmin.z));
-                       else
-                               LOG_INFO(" ", ftos(trace_endpos.z));
+                               '1 0 0' * world.absmin.x + '0 1 0' * world.absmin.y,
+                               '1 0 0' * world.absmax.x + '0 1 0' * world.absmax.y,
+                               '0 0 1' * world.absmax.z,
+                               MOVE_WORLDONLY,
+                               world);
+                       if (trace_startsolid) LOG_INFO(" ", ftos(world.absmin.z));
+                       else LOG_INFO(" ", ftos(trace_endpos.z));
 
                        tracebox('1 0 0' * world.absmax.x,
-                                                       '0 1 0' * world.absmin.y + '0 0 1' * world.absmin.z,
-                                                       '0 1 0' * world.absmax.y + '0 0 1' * world.absmax.z,
-                                                       '1 0 0' * world.absmin.x,
-                                       MOVE_WORLDONLY,
-                                       world);
-                       if(trace_startsolid)
-                               LOG_INFO(" ", ftos(world.absmax.x));
-                       else
-                               LOG_INFO(" ", ftos(trace_endpos.x));
+                               '0 1 0' * world.absmin.y + '0 0 1' * world.absmin.z,
+                               '0 1 0' * world.absmax.y + '0 0 1' * world.absmax.z,
+                               '1 0 0' * world.absmin.x,
+                               MOVE_WORLDONLY,
+                               world);
+                       if (trace_startsolid) LOG_INFO(" ", ftos(world.absmax.x));
+                       else LOG_INFO(" ", ftos(trace_endpos.x));
 
                        tracebox('0 1 0' * world.absmax.y,
-                                                       '1 0 0' * world.absmin.x + '0 0 1' * world.absmin.z,
-                                                       '1 0 0' * world.absmax.x + '0 0 1' * world.absmax.z,
-                                                       '0 1 0' * world.absmin.y,
-                                       MOVE_WORLDONLY,
-                                       world);
-                       if(trace_startsolid)
-                               LOG_INFO(" ", ftos(world.absmax.y));
-                       else
-                               LOG_INFO(" ", ftos(trace_endpos.y));
+                               '1 0 0' * world.absmin.x + '0 0 1' * world.absmin.z,
+                               '1 0 0' * world.absmax.x + '0 0 1' * world.absmax.z,
+                               '0 1 0' * world.absmin.y,
+                               MOVE_WORLDONLY,
+                               world);
+                       if (trace_startsolid) LOG_INFO(" ", ftos(world.absmax.y));
+                       else LOG_INFO(" ", ftos(trace_endpos.y));
 
                        tracebox('0 0 1' * world.absmax.z,
-                                                       '1 0 0' * world.absmin.x + '0 1 0' * world.absmin.y,
-                                                       '1 0 0' * world.absmax.x + '0 1 0' * world.absmax.y,
-                                                       '0 0 1' * world.absmin.z,
-                                       MOVE_WORLDONLY,
-                                       world);
-                       if(trace_startsolid)
-                               LOG_INFO(" ", ftos(world.absmax.z));
-                       else
-                               LOG_INFO(" ", ftos(trace_endpos.z));
+                               '1 0 0' * world.absmin.x + '0 1 0' * world.absmin.y,
+                               '1 0 0' * world.absmax.x + '0 1 0' * world.absmax.y,
+                               '0 0 1' * world.absmin.z,
+                               MOVE_WORLDONLY,
+                               world);
+                       if (trace_startsolid) LOG_INFO(" ", ftos(world.absmax.z));
+                       else LOG_INFO(" ", ftos(trace_endpos.z));
 
                        LOG_INFO("\n");
                        return;
@@ -353,72 +336,70 @@ void GameCommand_bbox(float request)
 
 void GameCommand_bot_cmd(float request, float argc, string command)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        entity bot;
 
-                       if(argv(1) == "reset")
+                       if (argv(1) == "reset")
                        {
                                bot_resetqueues();
                                return;
                        }
-                       else if(argv(1) == "setbots")
+                       else if (argv(1) == "setbots")
                        {
                                cvar_settemp("bot_vs_human", "0");
                                cvar_settemp("minplayers", "0");
                                cvar_settemp("bot_number", "0");
                                bot_fixcount();
                                cvar_settemp("bot_number", argv(2));
-                               if(!bot_fixcount())
-                                       LOG_INFO("Sorry, could not set requested bot count\n");
+                               if (!bot_fixcount()) LOG_INFO("Sorry, could not set requested bot count\n");
                                return;
                        }
-                       else if(argv(1) == "load" && argc == 3)
+                       else if (argv(1) == "load" && argc == 3)
                        {
                                float fh, i;
                                string s;
                                fh = fopen(argv(2), FILE_READ);
-                               if(fh < 0)
+                               if (fh < 0)
                                {
                                        LOG_INFO("cannot open the file\n");
                                        return;
                                }
 
                                i = 0;
-                               while((s = fgets(fh)))
+                               while ((s = fgets(fh)))
                                {
                                        argc = tokenize_console(s);
 
-                                       if(argc >= 3 && argv(0) == "sv_cmd" && argv(1) == "bot_cmd")
+                                       if (argc >= 3 && argv(0) == "sv_cmd" && argv(1) == "bot_cmd")
                                        {
-                                               if(argv(2) == "reset")
+                                               if (argv(2) == "reset")
                                                {
                                                        bot_resetqueues();
                                                }
-                                               else if(argv(2) == "setbots")
+                                               else if (argv(2) == "setbots")
                                                {
                                                        cvar_settemp("bot_vs_human", "0");
                                                        cvar_settemp("minplayers", "0");
                                                        cvar_settemp("bot_number", "0");
                                                        bot_fixcount();
                                                        cvar_settemp("bot_number", argv(3));
-                                                       if(!bot_fixcount())
-                                                               LOG_INFO("Sorry, could not set requested bot count\n");
+                                                       if (!bot_fixcount()) LOG_INFO("Sorry, could not set requested bot count\n");
                                                }
                                                else
                                                {
                                                        // let's start at token 2 so we can skip sv_cmd bot_cmd
                                                        bot = find_bot_by_number(stof(argv(2)));
-                                                       if(bot == world)
-                                                               bot = find_bot_by_name(argv(2));
-                                                       if(bot)
-                                                               bot_queuecommand(bot, substring(s, argv_start_index(3), -1));
+                                                       if (bot == world) bot = find_bot_by_name(argv(2));
+                                                       if (bot) bot_queuecommand(bot, substring(s, argv_start_index(3), -1));
                                                }
                                        }
                                        else
+                                       {
                                                localcmd(strcat(s, "\n"));
+                                       }
 
                                        ++i;
                                }
@@ -426,27 +407,26 @@ void GameCommand_bot_cmd(float request, float argc, string command)
                                fclose(fh);
                                return;
                        }
-                       else if(argv(1) == "help")
+                       else if (argv(1) == "help")
                        {
-                               if(argv(2))
-                                       bot_cmdhelp(argv(2));
-                               else
-                                       bot_list_commands();
+                               if (argv(2)) bot_cmdhelp(argv(2));
+                               else bot_list_commands();
                                return;
                        }
-                       else if(argc >= 3) // this comes last
+                       else if (argc >= 3)  // this comes last
                        {
                                bot = find_bot_by_number(stof(argv(1)));
-                               if(bot == world)
-                                       bot = find_bot_by_name(argv(1));
-                               if(bot)
+                               if (bot == world) bot = find_bot_by_name(argv(1));
+                               if (bot)
                                {
                                        LOG_INFO(strcat("Command '", substring(command, argv_start_index(2), -1), "' sent to bot ", bot.netname, "\n"));
                                        bot_queuecommand(bot, substring(command, argv_start_index(2), -1));
                                        return;
                                }
                                else
-                                       LOG_INFO(strcat("Error: Can't find bot with the name or id '", argv(1),"' - Did you mistype the command?\n")); // don't return so that usage is shown
+                               {
+                                       LOG_INFO(strcat("Error: Can't find bot with the name or id '", argv(1), "' - Did you mistype the command?\n"));  // don't return so that usage is shown
+                               }
                        }
                }
 
@@ -466,7 +446,7 @@ void GameCommand_bot_cmd(float request, float argc, string command)
 
 void GameCommand_cointoss(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -490,25 +470,25 @@ void GameCommand_cointoss(float request, float argc)
 
 void GameCommand_database(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argc == 3)
+                       if (argc == 3)
                        {
-                               if(argv(1) == "save")
+                               if (argv(1) == "save")
                                {
                                        db_save(ServerProgsDB, argv(2));
                                        LOG_INFO(strcat("Copied serverprogs database to '", argv(2), "' in the data directory.\n"));
                                        return;
                                }
-                               else if(argv(1) == "dump")
+                               else if (argv(1) == "dump")
                                {
                                        db_dump(ServerProgsDB, argv(2));
-                                       LOG_INFO("DB dumped.\n"); // wtf does this do?
+                                       LOG_INFO("DB dumped.\n");  // wtf does this do?
                                        return;
                                }
-                               else if(argv(1) == "load")
+                               else if (argv(1) == "load")
                                {
                                        db_close(ServerProgsDB);
                                        ServerProgsDB = db_load(argv(2));
@@ -533,19 +513,19 @@ void GameCommand_database(float request, float argc)
 
 void GameCommand_defer_clear(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        entity client;
                        float accepted;
 
-                       if(argc >= 2)
+                       if (argc >= 2)
                        {
                                client = GetIndexedEntity(argc, 1);
                                accepted = VerifyClientEntity(client, true, false);
 
-                               if(accepted > 0)
+                               if (accepted > 0)
                                {
                                        stuffcmd(client, "defer clear\n");
                                        LOG_INFO("defer clear stuffed to ", client.netname, "\n");
@@ -570,7 +550,7 @@ void GameCommand_defer_clear(float request, float argc)
 
 void GameCommand_defer_clear_all(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -584,7 +564,7 @@ void GameCommand_defer_clear_all(float request)
                                GameCommand_defer_clear(CMD_REQUEST_COMMAND, argc);
                                ++i;
                        }
-                       if(i) { LOG_INFO(strcat("Successfully stuffed defer clear to all clients (", ftos(i), ")\n")); } // should a message be added if no players were found?
+                       if (i)   LOG_INFO(strcat("Successfully stuffed defer clear to all clients (", ftos(i), ")\n"));  // should a message be added if no players were found?
                        return;
                }
 
@@ -601,16 +581,14 @@ void GameCommand_defer_clear_all(float request)
 
 void GameCommand_delrec(float request, float argc)  // perhaps merge later with records and printstats and such?
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1))
+                       if (argv(1))
                        {
-                               if(argv(2))
-                                       race_deleteTime(argv(2), stof(argv(1)));
-                               else
-                                       race_deleteTime(GetMapname(), stof(argv(1)));
+                               if (argv(2)) race_deleteTime(argv(2), stof(argv(1)));
+                               else race_deleteTime(GetMapname(), stof(argv(1)));
                                return;
                        }
                }
@@ -630,7 +608,7 @@ void GameCommand_delrec(float request, float argc)  // perhaps merge later with
 
 void GameCommand_effectindexdump(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -639,54 +617,89 @@ void GameCommand_effectindexdump(float request)
 
                        d = db_create();
                        LOG_INFO("begin of effects list\n");
-                       db_put(d, "TE_GUNSHOT", "1"); LOG_INFO("effect TE_GUNSHOT is ", ftos(_particleeffectnum("TE_GUNSHOT")), "\n");
-                       db_put(d, "TE_GUNSHOTQUAD", "1"); LOG_INFO("effect TE_GUNSHOTQUAD is ", ftos(_particleeffectnum("TE_GUNSHOTQUAD")), "\n");
-                       db_put(d, "TE_SPIKE", "1"); LOG_INFO("effect TE_SPIKE is ", ftos(_particleeffectnum("TE_SPIKE")), "\n");
-                       db_put(d, "TE_SPIKEQUAD", "1"); LOG_INFO("effect TE_SPIKEQUAD is ", ftos(_particleeffectnum("TE_SPIKEQUAD")), "\n");
-                       db_put(d, "TE_SUPERSPIKE", "1"); LOG_INFO("effect TE_SUPERSPIKE is ", ftos(_particleeffectnum("TE_SUPERSPIKE")), "\n");
-                       db_put(d, "TE_SUPERSPIKEQUAD", "1"); LOG_INFO("effect TE_SUPERSPIKEQUAD is ", ftos(_particleeffectnum("TE_SUPERSPIKEQUAD")), "\n");
-                       db_put(d, "TE_WIZSPIKE", "1"); LOG_INFO("effect TE_WIZSPIKE is ", ftos(_particleeffectnum("TE_WIZSPIKE")), "\n");
-                       db_put(d, "TE_KNIGHTSPIKE", "1"); LOG_INFO("effect TE_KNIGHTSPIKE is ", ftos(_particleeffectnum("TE_KNIGHTSPIKE")), "\n");
-                       db_put(d, "TE_EXPLOSION", "1"); LOG_INFO("effect TE_EXPLOSION is ", ftos(_particleeffectnum("TE_EXPLOSION")), "\n");
-                       db_put(d, "TE_EXPLOSIONQUAD", "1"); LOG_INFO("effect TE_EXPLOSIONQUAD is ", ftos(_particleeffectnum("TE_EXPLOSIONQUAD")), "\n");
-                       db_put(d, "TE_TAREXPLOSION", "1"); LOG_INFO("effect TE_TAREXPLOSION is ", ftos(_particleeffectnum("TE_TAREXPLOSION")), "\n");
-                       db_put(d, "TE_TELEPORT", "1"); LOG_INFO("effect TE_TELEPORT is ", ftos(_particleeffectnum("TE_TELEPORT")), "\n");
-                       db_put(d, "TE_LAVASPLASH", "1"); LOG_INFO("effect TE_LAVASPLASH is ", ftos(_particleeffectnum("TE_LAVASPLASH")), "\n");
-                       db_put(d, "TE_SMALLFLASH", "1"); LOG_INFO("effect TE_SMALLFLASH is ", ftos(_particleeffectnum("TE_SMALLFLASH")), "\n");
-                       db_put(d, "TE_FLAMEJET", "1"); LOG_INFO("effect TE_FLAMEJET is ", ftos(_particleeffectnum("TE_FLAMEJET")), "\n");
-                       db_put(d, "EF_FLAME", "1"); LOG_INFO("effect EF_FLAME is ", ftos(_particleeffectnum("EF_FLAME")), "\n");
-                       db_put(d, "TE_BLOOD", "1"); LOG_INFO("effect TE_BLOOD is ", ftos(_particleeffectnum("TE_BLOOD")), "\n");
-                       db_put(d, "TE_SPARK", "1"); LOG_INFO("effect TE_SPARK is ", ftos(_particleeffectnum("TE_SPARK")), "\n");
-                       db_put(d, "TE_PLASMABURN", "1"); LOG_INFO("effect TE_PLASMABURN is ", ftos(_particleeffectnum("TE_PLASMABURN")), "\n");
-                       db_put(d, "TE_TEI_G3", "1"); LOG_INFO("effect TE_TEI_G3 is ", ftos(_particleeffectnum("TE_TEI_G3")), "\n");
-                       db_put(d, "TE_TEI_SMOKE", "1"); LOG_INFO("effect TE_TEI_SMOKE is ", ftos(_particleeffectnum("TE_TEI_SMOKE")), "\n");
-                       db_put(d, "TE_TEI_BIGEXPLOSION", "1"); LOG_INFO("effect TE_TEI_BIGEXPLOSION is ", ftos(_particleeffectnum("TE_TEI_BIGEXPLOSION")), "\n");
-                       db_put(d, "TE_TEI_PLASMAHIT", "1"); LOG_INFO("effect TE_TEI_PLASMAHIT is ", ftos(_particleeffectnum("TE_TEI_PLASMAHIT")), "\n");
-                       db_put(d, "EF_STARDUST", "1"); LOG_INFO("effect EF_STARDUST is ", ftos(_particleeffectnum("EF_STARDUST")), "\n");
-                       db_put(d, "TR_ROCKET", "1"); LOG_INFO("effect TR_ROCKET is ", ftos(_particleeffectnum("TR_ROCKET")), "\n");
-                       db_put(d, "TR_GRENADE", "1"); LOG_INFO("effect TR_GRENADE is ", ftos(_particleeffectnum("TR_GRENADE")), "\n");
-                       db_put(d, "TR_BLOOD", "1"); LOG_INFO("effect TR_BLOOD is ", ftos(_particleeffectnum("TR_BLOOD")), "\n");
-                       db_put(d, "TR_WIZSPIKE", "1"); LOG_INFO("effect TR_WIZSPIKE is ", ftos(_particleeffectnum("TR_WIZSPIKE")), "\n");
-                       db_put(d, "TR_SLIGHTBLOOD", "1"); LOG_INFO("effect TR_SLIGHTBLOOD is ", ftos(_particleeffectnum("TR_SLIGHTBLOOD")), "\n");
-                       db_put(d, "TR_KNIGHTSPIKE", "1"); LOG_INFO("effect TR_KNIGHTSPIKE is ", ftos(_particleeffectnum("TR_KNIGHTSPIKE")), "\n");
-                       db_put(d, "TR_VORESPIKE", "1"); LOG_INFO("effect TR_VORESPIKE is ", ftos(_particleeffectnum("TR_VORESPIKE")), "\n");
-                       db_put(d, "TR_NEHAHRASMOKE", "1"); LOG_INFO("effect TR_NEHAHRASMOKE is ", ftos(_particleeffectnum("TR_NEHAHRASMOKE")), "\n");
-                       db_put(d, "TR_NEXUIZPLASMA", "1"); LOG_INFO("effect TR_NEXUIZPLASMA is ", ftos(_particleeffectnum("TR_NEXUIZPLASMA")), "\n");
-                       db_put(d, "TR_GLOWTRAIL", "1"); LOG_INFO("effect TR_GLOWTRAIL is ", ftos(_particleeffectnum("TR_GLOWTRAIL")), "\n");
-                       db_put(d, "TR_SEEKER", "1"); LOG_INFO("effect TR_SEEKER is ", ftos(_particleeffectnum("TR_SEEKER")), "\n");
-                       db_put(d, "SVC_PARTICLE", "1"); LOG_INFO("effect SVC_PARTICLE is ", ftos(_particleeffectnum("SVC_PARTICLE")), "\n");
+                       db_put(d, "TE_GUNSHOT", "1");
+                       LOG_INFO("effect TE_GUNSHOT is ", ftos(_particleeffectnum("TE_GUNSHOT")), "\n");
+                       db_put(d, "TE_GUNSHOTQUAD", "1");
+                       LOG_INFO("effect TE_GUNSHOTQUAD is ", ftos(_particleeffectnum("TE_GUNSHOTQUAD")), "\n");
+                       db_put(d, "TE_SPIKE", "1");
+                       LOG_INFO("effect TE_SPIKE is ", ftos(_particleeffectnum("TE_SPIKE")), "\n");
+                       db_put(d, "TE_SPIKEQUAD", "1");
+                       LOG_INFO("effect TE_SPIKEQUAD is ", ftos(_particleeffectnum("TE_SPIKEQUAD")), "\n");
+                       db_put(d, "TE_SUPERSPIKE", "1");
+                       LOG_INFO("effect TE_SUPERSPIKE is ", ftos(_particleeffectnum("TE_SUPERSPIKE")), "\n");
+                       db_put(d, "TE_SUPERSPIKEQUAD", "1");
+                       LOG_INFO("effect TE_SUPERSPIKEQUAD is ", ftos(_particleeffectnum("TE_SUPERSPIKEQUAD")), "\n");
+                       db_put(d, "TE_WIZSPIKE", "1");
+                       LOG_INFO("effect TE_WIZSPIKE is ", ftos(_particleeffectnum("TE_WIZSPIKE")), "\n");
+                       db_put(d, "TE_KNIGHTSPIKE", "1");
+                       LOG_INFO("effect TE_KNIGHTSPIKE is ", ftos(_particleeffectnum("TE_KNIGHTSPIKE")), "\n");
+                       db_put(d, "TE_EXPLOSION", "1");
+                       LOG_INFO("effect TE_EXPLOSION is ", ftos(_particleeffectnum("TE_EXPLOSION")), "\n");
+                       db_put(d, "TE_EXPLOSIONQUAD", "1");
+                       LOG_INFO("effect TE_EXPLOSIONQUAD is ", ftos(_particleeffectnum("TE_EXPLOSIONQUAD")), "\n");
+                       db_put(d, "TE_TAREXPLOSION", "1");
+                       LOG_INFO("effect TE_TAREXPLOSION is ", ftos(_particleeffectnum("TE_TAREXPLOSION")), "\n");
+                       db_put(d, "TE_TELEPORT", "1");
+                       LOG_INFO("effect TE_TELEPORT is ", ftos(_particleeffectnum("TE_TELEPORT")), "\n");
+                       db_put(d, "TE_LAVASPLASH", "1");
+                       LOG_INFO("effect TE_LAVASPLASH is ", ftos(_particleeffectnum("TE_LAVASPLASH")), "\n");
+                       db_put(d, "TE_SMALLFLASH", "1");
+                       LOG_INFO("effect TE_SMALLFLASH is ", ftos(_particleeffectnum("TE_SMALLFLASH")), "\n");
+                       db_put(d, "TE_FLAMEJET", "1");
+                       LOG_INFO("effect TE_FLAMEJET is ", ftos(_particleeffectnum("TE_FLAMEJET")), "\n");
+                       db_put(d, "EF_FLAME", "1");
+                       LOG_INFO("effect EF_FLAME is ", ftos(_particleeffectnum("EF_FLAME")), "\n");
+                       db_put(d, "TE_BLOOD", "1");
+                       LOG_INFO("effect TE_BLOOD is ", ftos(_particleeffectnum("TE_BLOOD")), "\n");
+                       db_put(d, "TE_SPARK", "1");
+                       LOG_INFO("effect TE_SPARK is ", ftos(_particleeffectnum("TE_SPARK")), "\n");
+                       db_put(d, "TE_PLASMABURN", "1");
+                       LOG_INFO("effect TE_PLASMABURN is ", ftos(_particleeffectnum("TE_PLASMABURN")), "\n");
+                       db_put(d, "TE_TEI_G3", "1");
+                       LOG_INFO("effect TE_TEI_G3 is ", ftos(_particleeffectnum("TE_TEI_G3")), "\n");
+                       db_put(d, "TE_TEI_SMOKE", "1");
+                       LOG_INFO("effect TE_TEI_SMOKE is ", ftos(_particleeffectnum("TE_TEI_SMOKE")), "\n");
+                       db_put(d, "TE_TEI_BIGEXPLOSION", "1");
+                       LOG_INFO("effect TE_TEI_BIGEXPLOSION is ", ftos(_particleeffectnum("TE_TEI_BIGEXPLOSION")), "\n");
+                       db_put(d, "TE_TEI_PLASMAHIT", "1");
+                       LOG_INFO("effect TE_TEI_PLASMAHIT is ", ftos(_particleeffectnum("TE_TEI_PLASMAHIT")), "\n");
+                       db_put(d, "EF_STARDUST", "1");
+                       LOG_INFO("effect EF_STARDUST is ", ftos(_particleeffectnum("EF_STARDUST")), "\n");
+                       db_put(d, "TR_ROCKET", "1");
+                       LOG_INFO("effect TR_ROCKET is ", ftos(_particleeffectnum("TR_ROCKET")), "\n");
+                       db_put(d, "TR_GRENADE", "1");
+                       LOG_INFO("effect TR_GRENADE is ", ftos(_particleeffectnum("TR_GRENADE")), "\n");
+                       db_put(d, "TR_BLOOD", "1");
+                       LOG_INFO("effect TR_BLOOD is ", ftos(_particleeffectnum("TR_BLOOD")), "\n");
+                       db_put(d, "TR_WIZSPIKE", "1");
+                       LOG_INFO("effect TR_WIZSPIKE is ", ftos(_particleeffectnum("TR_WIZSPIKE")), "\n");
+                       db_put(d, "TR_SLIGHTBLOOD", "1");
+                       LOG_INFO("effect TR_SLIGHTBLOOD is ", ftos(_particleeffectnum("TR_SLIGHTBLOOD")), "\n");
+                       db_put(d, "TR_KNIGHTSPIKE", "1");
+                       LOG_INFO("effect TR_KNIGHTSPIKE is ", ftos(_particleeffectnum("TR_KNIGHTSPIKE")), "\n");
+                       db_put(d, "TR_VORESPIKE", "1");
+                       LOG_INFO("effect TR_VORESPIKE is ", ftos(_particleeffectnum("TR_VORESPIKE")), "\n");
+                       db_put(d, "TR_NEHAHRASMOKE", "1");
+                       LOG_INFO("effect TR_NEHAHRASMOKE is ", ftos(_particleeffectnum("TR_NEHAHRASMOKE")), "\n");
+                       db_put(d, "TR_NEXUIZPLASMA", "1");
+                       LOG_INFO("effect TR_NEXUIZPLASMA is ", ftos(_particleeffectnum("TR_NEXUIZPLASMA")), "\n");
+                       db_put(d, "TR_GLOWTRAIL", "1");
+                       LOG_INFO("effect TR_GLOWTRAIL is ", ftos(_particleeffectnum("TR_GLOWTRAIL")), "\n");
+                       db_put(d, "TR_SEEKER", "1");
+                       LOG_INFO("effect TR_SEEKER is ", ftos(_particleeffectnum("TR_SEEKER")), "\n");
+                       db_put(d, "SVC_PARTICLE", "1");
+                       LOG_INFO("effect SVC_PARTICLE is ", ftos(_particleeffectnum("SVC_PARTICLE")), "\n");
 
                        fh = fopen("effectinfo.txt", FILE_READ);
-                       while((s = fgets(fh)))
+                       while ((s = fgets(fh)))
                        {
                                tokenize_console(s);
-                               if(argv(0) == "effect")
+                               if (argv(0) == "effect")
                                {
-                                       if(db_get(d, argv(1)) != "1")
+                                       if (db_get(d, argv(1)) != "1")
                                        {
                                                int i = _particleeffectnum(argv(1));
-                                               if(i >= 0)
-                                                       LOG_INFO("effect ", argv(1), " is ", ftos(i), "\n");
+                                               if (i >= 0) LOG_INFO("effect ", argv(1), " is ", ftos(i), "\n");
                                                db_put(d, argv(1), "1");
                                        }
                                }
@@ -709,7 +722,7 @@ void GameCommand_effectindexdump(float request)
 
 void GameCommand_extendmatchtime(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -730,13 +743,13 @@ void GameCommand_extendmatchtime(float request)
 
 void GameCommand_find(float request, float argc)  // is this even needed? We have prvm_edicts command and such ANYWAY
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        entity client;
 
-                       for(client = world; (client = find(client, classname, argv(1))); )
+                       for (client = world; (client = find(client, classname, argv(1))); )
                                LOG_INFO(etos(client), "\n");
 
                        return;
@@ -755,23 +768,23 @@ void GameCommand_find(float request, float argc)  // is this even needed? We hav
 
 void GameCommand_gametype(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1) != "")
+                       if (argv(1) != "")
                        {
                                string s = argv(1);
                                float t = MapInfo_Type_FromString(s), tsave = MapInfo_CurrentGametype();
 
-                               if(t)
+                               if (t)
                                {
                                        MapInfo_SwitchGameType(t);
                                        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
-                                       if(MapInfo_count > 0)
+                                       if (MapInfo_count > 0)
                                        {
                                                // update lsmaps in case the gametype changed, this way people can easily list maps for it
-                                               if(lsmaps_reply != "") { strunzone(lsmaps_reply); }
+                                               if (lsmaps_reply != "")   strunzone(lsmaps_reply);
                                                lsmaps_reply = strzone(getlsmaps());
                                                bprint("Game type successfully switched to ", s, "\n");
                                        }
@@ -783,7 +796,9 @@ void GameCommand_gametype(float request, float argc)
                                        }
                                }
                                else
+                               {
                                        bprint("Game type switch to ", s, " failed: this type does not exist!\n");
+                               }
 
                                return;
                        }
@@ -803,7 +818,7 @@ void GameCommand_gametype(float request, float argc)
 
 void GameCommand_gettaginfo(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -811,22 +826,23 @@ void GameCommand_gettaginfo(float request, float argc)
                        float i;
                        vector v;
 
-                       if(argc >= 4)
+                       if (argc >= 4)
                        {
                                tmp_entity = spawn();
-                               if(argv(1) == "w")
-                                       _setmodel(tmp_entity, (nextent(world)).weaponentity.model);
+                               if (argv(1) == "w")
+                               {
+                                       .entity weaponentity = weaponentities[0];
+                                       _setmodel(tmp_entity, (nextent(world)).(weaponentity).model);
+                               }
                                else
                                {
                                        precache_model(argv(1));
                                        _setmodel(tmp_entity, argv(1));
                                }
                                tmp_entity.frame = stof(argv(2));
-                               if(substring(argv(3), 0, 1) == "#")
-                                       i = stof(substring(argv(3), 1, -1));
-                               else
-                                       i = gettagindex(tmp_entity, argv(3));
-                               if(i)
+                               if (substring(argv(3), 0, 1) == "#") i = stof(substring(argv(3), 1, -1));
+                               else i = gettagindex(tmp_entity, argv(3));
+                               if (i)
                                {
                                        v = gettaginfo(tmp_entity, i);
                                        LOG_INFO("model ", tmp_entity.model, " frame ", ftos(tmp_entity.frame), " tag ", gettaginfo_name);
@@ -836,14 +852,16 @@ void GameCommand_gettaginfo(float request, float argc)
                                        LOG_INFO(" forward = ", ftos(gettaginfo_forward.x), " ", ftos(gettaginfo_forward.y), " ", ftos(gettaginfo_forward.z), "\n");
                                        LOG_INFO(" right = ", ftos(gettaginfo_right.x), " ", ftos(gettaginfo_right.y), " ", ftos(gettaginfo_right.z), "\n");
                                        LOG_INFO(" up = ", ftos(gettaginfo_up.x), " ", ftos(gettaginfo_up.y), " ", ftos(gettaginfo_up.z), "\n");
-                                       if(argc >= 6)
+                                       if (argc >= 6)
                                        {
                                                v.y = -v.y;
                                                localcmd(strcat(argv(4), vtos(v), argv(5), "\n"));
                                        }
                                }
                                else
+                               {
                                        LOG_INFO("bone not found\n");
+                               }
 
                                remove(tmp_entity);
                                return;
@@ -863,17 +881,20 @@ void GameCommand_gettaginfo(float request, float argc)
 
 void GameCommand_animbench(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        entity tmp_entity;
 
-                       if(argc >= 4)
+                       if (argc >= 4)
                        {
                                tmp_entity = spawn();
-                               if(argv(1) == "w")
-                                       _setmodel(tmp_entity, (nextent(world)).weaponentity.model);
+                               if (argv(1) == "w")
+                               {
+                                       .entity weaponentity = weaponentities[0];
+                                       _setmodel(tmp_entity, (nextent(world)).(weaponentity).model);
+                               }
                                else
                                {
                                        precache_model(argv(1));
@@ -886,7 +907,7 @@ void GameCommand_animbench(float request, float argc)
                                float t2 = 0;
                                float n = 0;
 
-                               while(t1 + t2 < 1)
+                               while (t1 + t2 < 1)
                                {
                                        tmp_entity.frame = f1;
                                        t0 = gettime(GETTIME_HIRES);
@@ -919,11 +940,11 @@ void GameCommand_animbench(float request, float argc)
 
 void GameCommand_gotomap(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(1))
+                       if (argv(1))
                        {
                                LOG_INFO(GotoMap(argv(1)), "\n");
                                return;
@@ -944,11 +965,11 @@ void GameCommand_gotomap(float request, float argc)
 
 void GameCommand_lockteams(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(teamplay)
+                       if (teamplay)
                        {
                                lockteams = 1;
                                bprint("^1The teams are now locked.\n");
@@ -973,14 +994,13 @@ void GameCommand_lockteams(float request)
 
 void GameCommand_make_mapinfo(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        entity tmp_entity;
 
-                       tmp_entity = spawn();
-                       tmp_entity.classname = "make_mapinfo";
+                       tmp_entity = new(make_mapinfo);
                        tmp_entity.think = make_mapinfo_Think;
                        tmp_entity.nextthink = time;
                        MapInfo_Enumerate();
@@ -999,8 +1019,9 @@ void GameCommand_make_mapinfo(float request)
 }
 
 void GameCommand_moveplayer(float request, float argc)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -1015,29 +1036,29 @@ void GameCommand_moveplayer(float request, float argc)
                        successful = string_null;
 
                        // lets see if the target(s) even actually exist.
-                       if((targets) && (destination))
+                       if ((targets) && (destination))
                        {
-                               for (;targets;)
+                               for ( ; targets; )
                                {
-                                       t = car(targets); targets = cdr(targets);
+                                       t = car(targets);
+                                       targets = cdr(targets);
 
                                        // Check to see if the player is a valid target
                                        client = GetFilteredEntity(t);
                                        accepted = VerifyClientEntity(client, false, false);
 
-                                       if(accepted <= 0)
+                                       if (accepted <= 0)
                                        {
                                                LOG_INFO("moveplayer: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".\n"));
                                                continue;
                                        }
 
                                        // Where are we putting this player?
-                                       if(destination == "spec" || destination == "spectator")
+                                       if (destination == "spec" || destination == "spectator")
                                        {
-                                               if(!IS_SPEC(client) && !IS_OBSERVER(client))
+                                               if (!IS_SPEC(client) && !IS_OBSERVER(client))
                                                {
-                                                       if (client.caplayer)
-                                                               client.caplayer = 0;
+                                                       if (client.caplayer) client.caplayer = 0;
                                                        WITH(entity, self, client, PutObserverInServer());
 
                                                        successful = strcat(successful, (successful ? ", " : ""), client.netname);
@@ -1050,9 +1071,9 @@ void GameCommand_moveplayer(float request, float argc)
                                        }
                                        else
                                        {
-                                               if(!IS_SPEC(client) && !IS_OBSERVER(client))
+                                               if (!IS_SPEC(client) && !IS_OBSERVER(client))
                                                {
-                                                       if(teamplay)
+                                                       if (teamplay)
                                                        {
                                                                // set up
                                                                float team_id;
@@ -1061,13 +1082,13 @@ void GameCommand_moveplayer(float request, float argc)
 
                                                                // find the team to move the player to
                                                                team_id = Team_ColorToTeam(destination);
-                                                               if(team_id == client.team) // already on the destination team
+                                                               if (team_id == client.team)  // already on the destination team
                                                                {
                                                                        // keep the forcing undone
                                                                        LOG_INFO("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") is already on the ", Team_ColoredFullName(client.team), (targets ? "^7, skipping to next player.\n" : "^7.\n"));
                                                                        continue;
                                                                }
-                                                               else if(team_id == 0)  // auto team
+                                                               else if (team_id == 0)  // auto team
                                                                {
                                                                        CheckAllowedTeams(client);
                                                                        team_id = Team_NumberToTeam(FindSmallestTeam(client, false));
@@ -1079,14 +1100,15 @@ void GameCommand_moveplayer(float request, float argc)
                                                                client.team_forced = save;
 
                                                                // Check to see if the destination team is even available
-                                                               switch(team_id)
+                                                               switch (team_id)
                                                                {
-                                                                       case NUM_TEAM_1: if(c1 == -1) { LOG_INFO("Sorry, can't move player to red team if it doesn't exist.\n"); return; } break;
-                                                                       case NUM_TEAM_2: if(c2 == -1) { LOG_INFO("Sorry, can't move player to blue team if it doesn't exist.\n"); return; } break;
-                                                                       case NUM_TEAM_3: if(c3 == -1) { LOG_INFO("Sorry, can't move player to yellow team if it doesn't exist.\n"); return; } break;
-                                                                       case NUM_TEAM_4: if(c4 == -1) { LOG_INFO("Sorry, can't move player to pink team if it doesn't exist.\n"); return; } break;
+                                                                       case NUM_TEAM_1: if (c1 == -1) { LOG_INFO("Sorry, can't move player to red team if it doesn't exist.\n"); return; } break;
+                                                                       case NUM_TEAM_2: if (c2 == -1) { LOG_INFO("Sorry, can't move player to blue team if it doesn't exist.\n"); return; } break;
+                                                                       case NUM_TEAM_3: if (c3 == -1) { LOG_INFO("Sorry, can't move player to yellow team if it doesn't exist.\n"); return; } break;
+                                                                       case NUM_TEAM_4: if (c4 == -1) { LOG_INFO("Sorry, can't move player to pink team if it doesn't exist.\n"); return; } break;
 
-                                                                       default: LOG_INFO("Sorry, can't move player here if team ", destination, " doesn't exist.\n"); return;
+                                                                       default: LOG_INFO("Sorry, can't move player here if team ", destination, " doesn't exist.\n");
+                                                                               return;
                                                                }
 
                                                                // If so, lets continue and finally move the player
@@ -1104,18 +1126,16 @@ void GameCommand_moveplayer(float request, float argc)
                                                }
                                                else
                                                {
-                                                       LOG_INFO("Can't change teams if the player isn't in the game.\n"); // well technically we could, but should we allow that? :P
+                                                       LOG_INFO("Can't change teams if the player isn't in the game.\n");  // well technically we could, but should we allow that? :P
                                                        return;
                                                }
                                        }
                                }
 
-                               if(successful)
-                                       bprint("Successfully moved players ", successful, " to destination ", destination, ".\n");
-                               else
-                                       LOG_INFO("No players given (", original_targets, ") are able to move.\n");
+                               if (successful) bprint("Successfully moved players ", successful, " to destination ", destination, ".\n");
+                               else LOG_INFO("No players given (", original_targets, ") are able to move.\n");
 
-                               return; // still correct parameters so return to avoid usage print
+                               return;  // still correct parameters so return to avoid usage print
                        }
                }
 
@@ -1137,19 +1157,21 @@ void GameCommand_moveplayer(float request, float argc)
 
 void GameCommand_nospectators(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        blockSpectators = 1;
                        entity plr;
-                       FOR_EACH_REALCLIENT(plr) //give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
+                       FOR_EACH_REALCLIENT(plr)  // give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
                        {
-                               if(IS_SPEC(plr) || IS_OBSERVER(plr))
-                               if(!plr.caplayer)
+                               if (IS_SPEC(plr) || IS_OBSERVER(plr))
                                {
-                                       plr.spectatortime = time;
-                                       Send_Notification(NOTIF_ONE_ONLY, plr, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
+                                       if (!plr.caplayer)
+                                       {
+                                               plr.spectatortime = time;
+                                               Send_Notification(NOTIF_ONE_ONLY, plr, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
+                                       }
                                }
                        }
                        bprint(strcat("^7All spectators will be automatically kicked when not joining the game after ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds!\n"));
@@ -1167,24 +1189,25 @@ void GameCommand_nospectators(float request)
 }
 
 void GameCommand_playerdemo(float request, float argc)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argv(2) && argv(3))
+                       if (argv(2) && argv(3))
                        {
                                entity client;
                                float i, n, accepted;
 
-                               switch(argv(1))
+                               switch (argv(1))
                                {
                                        case "read":
                                        {
                                                client = GetIndexedEntity(argc, 2);
                                                accepted = VerifyClientEntity(client, false, true);
 
-                                               if(accepted <= 0)
+                                               if (accepted <= 0)
                                                {
                                                        LOG_INFO("playerdemo: read: ", GetClientErrorString(accepted, argv(2)), ".\n");
                                                        return;
@@ -1199,7 +1222,7 @@ void GameCommand_playerdemo(float request, float argc)
                                                client = GetIndexedEntity(argc, 2);
                                                accepted = VerifyClientEntity(client, false, false);
 
-                                               if(accepted <= 0)
+                                               if (accepted <= 0)
                                                {
                                                        LOG_INFO("playerdemo: write: ", GetClientErrorString(accepted, argv(2)), ".\n");
                                                        return;
@@ -1215,9 +1238,9 @@ void GameCommand_playerdemo(float request, float argc)
                                                cvar_set("bot_number", ftos(n));
 
                                                localcmd("wait; wait; wait\n");
-                                               for(i = 0; i < n; ++i) { localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", argv(2), ftos(i+1), "\n"); }
-
-                                               localcmd("sv_cmd playerdemo write 1 ", ftos(n+1), "\n");
+                                               for (i = 0; i < n; ++i)
+                                                       localcmd("sv_cmd playerdemo read ", ftos(i + 2), " ", argv(2), ftos(i + 1), "\n");
+                                               localcmd("sv_cmd playerdemo write 1 ", ftos(n + 1), "\n");
                                                return;
                                        }
 
@@ -1227,7 +1250,8 @@ void GameCommand_playerdemo(float request, float argc)
                                                cvar_set("bot_number", ftos(n));
 
                                                localcmd("wait; wait; wait\n");
-                                               for(i = 0; i < n; ++i) { localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", argv(2), ftos(i+1), "\n"); }
+                                               for (i = 0; i < n; ++i)
+                                                       localcmd("sv_cmd playerdemo read ", ftos(i + 2), " ", argv(2), ftos(i + 1), "\n");
                                                return;
                                        }
                                }
@@ -1247,7 +1271,7 @@ void GameCommand_playerdemo(float request, float argc)
 
 void GameCommand_printstats(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -1268,12 +1292,11 @@ void GameCommand_printstats(float request)
 
 void GameCommand_radarmap(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(RadarMap_Make(argc))
-                               return;
+                       if (RadarMap_Make(argc)) return;
                }
 
                default:
@@ -1291,11 +1314,11 @@ void GameCommand_radarmap(float request, float argc)
 
 void GameCommand_reducematchtime(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       changematchtime(autocvar_timelimit_decrement *-60, autocvar_timelimit_min * 60, autocvar_timelimit_max * 60);
+                       changematchtime(autocvar_timelimit_decrement * -60, autocvar_timelimit_min * 60, autocvar_timelimit_max * 60);
                        return;
                }
 
@@ -1312,11 +1335,11 @@ void GameCommand_reducematchtime(float request)
 
 void GameCommand_setbots(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(argc >= 2)
+                       if (argc >= 2)
                        {
                                cvar_settemp("minplayers", "0");
                                cvar_settemp("bot_number", argv(1));
@@ -1338,12 +1361,13 @@ void GameCommand_setbots(float request, float argc)
 }
 
 void GameCommand_shuffleteams(float request)
-{SELFPARAM();
-       switch(request)
+{
+       SELFPARAM();
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(teamplay)
+                       if (teamplay)
                        {
                                entity tmp_player;
                                int i;
@@ -1353,29 +1377,29 @@ void GameCommand_shuffleteams(float request)
                                t_players = 0;
                                t_teams = 0;
                                FOR_EACH_CLIENT(tmp_player)
-                               if(IS_PLAYER(tmp_player) || tmp_player.caplayer)
+                               if (IS_PLAYER(tmp_player) || tmp_player.caplayer)
                                {
                                        CheckAllowedTeams(tmp_player);
 
-                                       if(c1 >= 0) t_teams = max(1, t_teams);
-                                       if(c2 >= 0) t_teams = max(2, t_teams);
-                                       if(c3 >= 0) t_teams = max(3, t_teams);
-                                       if(c4 >= 0) t_teams = max(4, t_teams);
+                                       if (c1 >= 0) t_teams = max(1, t_teams);
+                                       if (c2 >= 0) t_teams = max(2, t_teams);
+                                       if (c3 >= 0) t_teams = max(3, t_teams);
+                                       if (c4 >= 0) t_teams = max(4, t_teams);
 
                                        ++t_players;
                                }
 
                                // build a list of the players in a random order
                                FOR_EACH_CLIENT(tmp_player)
-                               if(IS_PLAYER(tmp_player) || tmp_player.caplayer)
+                               if (IS_PLAYER(tmp_player) || tmp_player.caplayer)
                                {
-                                       for (;;)
+                                       for ( ; ; )
                                        {
                                                i = bound(1, floor(random() * maxclients) + 1, maxclients);
 
-                                               if(shuffleteams_players[i])
+                                               if (shuffleteams_players[i])
                                                {
-                                                       continue; // a player is already assigned to this slot
+                                                       continue;  // a player is already assigned to this slot
                                                }
                                                else
                                                {
@@ -1399,21 +1423,18 @@ void GameCommand_shuffleteams(float request)
                                        {
                                                if (!(shuffleteams_teams[i] >= x))
                                                {
-                                                       if (!(shuffleteams_players[z]))
-                                                               continue; // not a player, move on to next random slot
+                                                       if (!(shuffleteams_players[z])) continue;  // not a player, move on to next random slot
 
-                                                       if(VerifyClientNumber(shuffleteams_players[z]))
-                                                               setself(edict_num(shuffleteams_players[z]));
+                                                       if (VerifyClientNumber(shuffleteams_players[z])) setself(edict_num(shuffleteams_players[z]));
 
-                                                       if(self.team != team_color)
-                                                               MoveToTeam(self, team_color, 6);
+                                                       if (self.team != team_color) MoveToTeam(self, team_color, 6);
 
                                                        shuffleteams_players[z] = 0;
                                                        shuffleteams_teams[i] = shuffleteams_teams[i] + 1;
                                                }
                                                else
                                                {
-                                                       break; // move on to next team
+                                                       break;  // move on to next team
                                                }
                                        }
                                }
@@ -1421,10 +1442,10 @@ void GameCommand_shuffleteams(float request)
                                bprint("Successfully shuffled the players around randomly.\n");
 
                                // clear the buffers now
-                               for (i=0; i<SHUFFLETEAMS_MAX_PLAYERS; ++i)
+                               for (i = 0; i < SHUFFLETEAMS_MAX_PLAYERS; ++i)
                                        shuffleteams_players[i] = 0;
 
-                               for (i=0; i<SHUFFLETEAMS_MAX_TEAMS; ++i)
+                               for (i = 0; i < SHUFFLETEAMS_MAX_TEAMS; ++i)
                                        shuffleteams_teams[i] = 0;
                        }
                        else
@@ -1452,51 +1473,53 @@ void GameCommand_stuffto(float request, float argc)
        // Because of this, it is disabled by default and must be enabled by the server owner when doing compilation. That way,
        // we can be certain they understand the risks of it... So to enable, compile server with -DSTUFFTO_ENABLED argument.
 
-       #ifdef STUFFTO_ENABLED
+#ifdef STUFFTO_ENABLED
        #message "stuffto command enabled"
-       switch(request)
-       {
-               case CMD_REQUEST_COMMAND:
+               switch (request)
                {
-                       if(argv(2))
+                       case CMD_REQUEST_COMMAND:
                        {
-                               entity client = GetIndexedEntity(argc, 1);
-                               float accepted = VerifyClientEntity(client, true, false);
-
-                               if(accepted > 0)
+                               if (argv(2))
                                {
-                                       stuffcmd(client, strcat("\n", argv(next_token), "\n"));
-                                       LOG_INFO(strcat("Command: \"", argv(next_token), "\" sent to ", GetCallerName(client), " (", argv(1) ,").\n"));
+                                       entity client = GetIndexedEntity(argc, 1);
+                                       float accepted = VerifyClientEntity(client, true, false);
+
+                                       if (accepted > 0)
+                                       {
+                                               stuffcmd(client, strcat("\n", argv(next_token), "\n"));
+                                               LOG_INFO(strcat("Command: \"", argv(next_token), "\" sent to ", GetCallerName(client), " (", argv(1), ").\n"));
+                                       }
+                                       else
+                                       {
+                                               LOG_INFO("stuffto: ", GetClientErrorString(accepted, argv(1)), ".\n");
+                                       }
+
+                                       return;
                                }
-                               else
-                                       LOG_INFO("stuffto: ", GetClientErrorString(accepted, argv(1)), ".\n");
+                       }
 
+                       default:
+                               LOG_INFO("Incorrect parameters for ^2stuffto^7\n");
+                       case CMD_REQUEST_USAGE:
+                       {
+                               LOG_INFO("\nUsage:^3 sv_cmd stuffto client \"command\"\n");
+                               LOG_INFO("  'client' is the entity number or name of the player,\n");
+                               LOG_INFO("  and 'command' is the command to be sent to that player.\n");
                                return;
                        }
                }
-
-               default:
-                       LOG_INFO("Incorrect parameters for ^2stuffto^7\n");
-               case CMD_REQUEST_USAGE:
+#else
+               if (request)
                {
-                       LOG_INFO("\nUsage:^3 sv_cmd stuffto client \"command\"\n");
-                       LOG_INFO("  'client' is the entity number or name of the player,\n");
-                       LOG_INFO("  and 'command' is the command to be sent to that player.\n");
+                       LOG_INFO("stuffto command is not enabled on this server.\n");
                        return;
                }
-       }
-       #else
-       if(request)
-       {
-               LOG_INFO("stuffto command is not enabled on this server.\n");
-               return;
-       }
-       #endif
+#endif
 }
 
 void GameCommand_trace(float request, float argc)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
@@ -1504,14 +1527,14 @@ void GameCommand_trace(float request, float argc)
                        vector org, delta, start, end, p, q, q0, pos, vv, dv;
                        float i, f, safe, unsafe, dq, dqf;
 
-                       switch(argv(1))
+                       switch (argv(1))
                        {
                                case "debug":
                                {
                                        float hitcount = 0;
                                        LOG_INFO("TEST CASE. If this returns the runaway loop counter error, possibly everything is oaky.\n");
                                        float worst_endpos_bug = 0;
-                                       for (;;)
+                                       for ( ; ; )
                                        {
                                                org = world.mins;
                                                delta = world.maxs - world.mins;
@@ -1528,32 +1551,30 @@ void GameCommand_trace(float request, float argc)
                                                end = stov(vtos(end));
 
                                                tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);
-                                               if(!trace_startsolid && trace_fraction < 1)
+                                               if (!trace_startsolid && trace_fraction < 1)
                                                {
                                                        p = trace_endpos;
                                                        tracebox(p, PL_MIN, PL_MAX, p, MOVE_NOMONSTERS, world);
-                                                       if(trace_startsolid)
+                                                       if (trace_startsolid)
                                                        {
-                                                               rint(42); // do an engine breakpoint on VM_rint so you can get the trace that errnoeously returns startsolid
+                                                               rint(42);  // do an engine breakpoint on VM_rint so you can get the trace that errnoeously returns startsolid
                                                                tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);
 
                                                                // how much do we need to back off?
                                                                safe = 1;
                                                                unsafe = 0;
-                                                               for (;;)
+                                                               for ( ; ; )
                                                                {
                                                                        pos = p * (1 - (safe + unsafe) * 0.5) + start * ((safe + unsafe) * 0.5);
                                                                        tracebox(pos, PL_MIN, PL_MAX, pos, MOVE_NOMONSTERS, world);
-                                                                       if(trace_startsolid)
+                                                                       if (trace_startsolid)
                                                                        {
-                                                                               if((safe + unsafe) * 0.5 == unsafe)
-                                                                                       break;
+                                                                               if ((safe + unsafe) * 0.5 == unsafe) break;
                                                                                unsafe = (safe + unsafe) * 0.5;
                                                                        }
                                                                        else
                                                                        {
-                                                                               if((safe + unsafe) * 0.5 == safe)
-                                                                                       break;
+                                                                               if ((safe + unsafe) * 0.5 == safe) break;
                                                                                safe = (safe + unsafe) * 0.5;
                                                                        }
                                                                }
@@ -1562,38 +1583,31 @@ void GameCommand_trace(float request, float argc)
                                                                LOG_INFO("unsafe distance to back off: ", ftos(unsafe * vlen(p - start)), "qu\n");
 
                                                                tracebox(p, PL_MIN + '0.1 0.1 0.1', PL_MAX - '0.1 0.1 0.1', p, MOVE_NOMONSTERS, world);
-                                                               if(trace_startsolid)
-                                                                       LOG_INFO("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
-                                                               else
-                                                                       LOG_INFO("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
-                                                               if (++hitcount >= 10)
-                                                                       break;
+                                                               if (trace_startsolid) LOG_INFO("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
+                                                               else LOG_INFO("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
+                                                               if (++hitcount >= 10) break;
                                                        }
                                                        else
                                                        {
                                                                q0 = p;
                                                                dq = 0;
                                                                dqf = 1;
-                                                               for (;;)
+                                                               for ( ; ; )
                                                                {
                                                                        q = p + normalize(end - p) * (dq + dqf);
-                                                                       if(q == q0)
-                                                                               break;
+                                                                       if (q == q0) break;
                                                                        tracebox(p, PL_MIN, PL_MAX, q, MOVE_NOMONSTERS, world);
-                                                                       if(trace_startsolid)
-                                                                               error("THIS ONE cannot happen");
-                                                                       if(trace_fraction > 0)
-                                                                               dq += dqf * trace_fraction;
+                                                                       if (trace_startsolid) error("THIS ONE cannot happen");
+                                                                       if (trace_fraction > 0) dq += dqf * trace_fraction;
                                                                        dqf *= 0.5;
                                                                        q0 = q;
                                                                }
-                                                               if(dq > worst_endpos_bug)
+                                                               if (dq > worst_endpos_bug)
                                                                {
                                                                        worst_endpos_bug = dq;
                                                                        LOG_INFO("trace_endpos still before solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");
                                                                        LOG_INFO("could go ", ftos(dq), " units further to ", vtos(q), "\n");
-                                                                       if (++hitcount >= 10)
-                                                                               break;
+                                                                       if (++hitcount >= 10) break;
                                                                }
                                                        }
                                                }
@@ -1606,26 +1620,26 @@ void GameCommand_trace(float request, float argc)
                                        e = nextent(world);
                                        tracebox(e.origin + '0 0 32', e.mins, e.maxs, e.origin + '0 0 -1024', MOVE_NORMAL, e);
                                        vv = trace_endpos;
-                                       if(trace_fraction == 1)
+                                       if (trace_fraction == 1)
                                        {
                                                LOG_INFO("not above ground, aborting\n");
                                                return;
                                        }
                                        f = 0;
-                                       for(i = 0; i < 100000; ++i)
+                                       for (i = 0; i < 100000; ++i)
                                        {
                                                dv = randomvec();
-                                               if(dv.z > 0)
-                                                       dv = -1 * dv;
+                                               if (dv.z > 0) dv = -1 * dv;
                                                tracebox(vv, e.mins, e.maxs, vv + dv, MOVE_NORMAL, e);
-                                               if(trace_startsolid)
-                                                       LOG_INFO("bug 1\n");
-                                               if(trace_fraction == 1)
-                                               if(dv.z < f)
+                                               if (trace_startsolid) LOG_INFO("bug 1\n");
+                                               if (trace_fraction == 1)
                                                {
-                                                       LOG_INFO("bug 2: ", ftos(dv.x), " ", ftos(dv.y), " ", ftos(dv.z));
-                                                       LOG_INFO(" (", ftos(asin(dv.z / vlen(dv)) * 180 / M_PI), " degrees)\n");
-                                                       f = dv.z;
+                                                       if (dv.z < f)
+                                                       {
+                                                               LOG_INFO("bug 2: ", ftos(dv.x), " ", ftos(dv.y), " ", ftos(dv.z));
+                                                               LOG_INFO(" (", ftos(asin(dv.z / vlen(dv)) * 180 / M_PI), " degrees)\n");
+                                                               f = dv.z;
+                                                       }
                                                }
                                        }
                                        LOG_INFO("highest possible dist: ", ftos(f), "\n");
@@ -1634,31 +1648,29 @@ void GameCommand_trace(float request, float argc)
 
                                case "walk":
                                {
-                                       if(argc == 4)
+                                       if (argc == 4)
                                        {
                                                e = nextent(world);
-                                               if(tracewalk(e, stov(argv(2)), e.mins, e.maxs, stov(argv(3)), MOVE_NORMAL))
-                                                       LOG_INFO("can walk\n");
-                                               else
-                                                       LOG_INFO("cannot walk\n");
+                                               if (tracewalk(e, stov(argv(2)), e.mins, e.maxs, stov(argv(3)), MOVE_NORMAL)) LOG_INFO("can walk\n");
+                                               else LOG_INFO("cannot walk\n");
                                                return;
                                        }
                                }
 
                                case "showline":
                                {
-                                       if(argc == 4)
+                                       if (argc == 4)
                                        {
                                                vv = stov(argv(2));
                                                dv = stov(argv(3));
                                                traceline(vv, dv, MOVE_NORMAL, world);
-                                               trailparticles(world, particleeffectnum(EFFECT_TR_NEXUIZPLASMA), vv, trace_endpos);
-                                               trailparticles(world, particleeffectnum(EFFECT_TR_CRYLINKPLASMA), trace_endpos, dv);
+                                               __trailparticles(world, particleeffectnum(EFFECT_TR_NEXUIZPLASMA), vv, trace_endpos);
+                                               __trailparticles(world, particleeffectnum(EFFECT_TR_CRYLINKPLASMA), trace_endpos, dv);
                                                return;
                                        }
                                }
 
-                               // no default case, just go straight to invalid
+                                       // no default case, just go straight to invalid
                        }
                }
 
@@ -1676,11 +1688,11 @@ void GameCommand_trace(float request, float argc)
 
 void GameCommand_unlockteams(float request)
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(teamplay)
+                       if (teamplay)
                        {
                                lockteams = 0;
                                bprint("^1The teams are now unlocked.\n");
@@ -1709,9 +1721,9 @@ void GameCommand_warp(float request, float argc)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(autocvar_g_campaign)
+                       if (autocvar_g_campaign)
                        {
-                               if(argc >= 2)
+                               if (argc >= 2)
                                {
                                        CampaignLevelWarp(stof(argv(1)));
                                        LOG_INFO("Successfully warped to campaign level ", stof(argv(1)), ".\n");
@@ -1723,7 +1735,9 @@ void GameCommand_warp(float request, float argc)
                                }
                        }
                        else
+                       {
                                LOG_INFO("Not in campaign, can't level warp\n");
+                       }
                        return;
                }
 
@@ -1742,22 +1756,22 @@ void GameCommand_warp(float request, float argc)
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
 void GameCommand_(float request)
 {
-       switch(request)
-       {
-               case CMD_REQUEST_COMMAND:
-               {
-
-                       return;
-               }
-
-               default:
-               case CMD_REQUEST_USAGE:
-               {
-                       print("\nUsage:^3 sv_cmd \n");
-                       print("  No arguments required.\n");
-                       return;
-               }
-       }
+    switch(request)
+    {
+        case CMD_REQUEST_COMMAND:
+        {
+
+            return;
+        }
+
+        default:
+        case CMD_REQUEST_USAGE:
+        {
+            print("\nUsage:^3 sv_cmd \n");
+            print("  No arguments required.\n");
+            return;
+        }
+    }
 }
 */
 
@@ -1767,7 +1781,7 @@ void GameCommand_(float request)
 // ==================================
 
 // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define SERVER_COMMANDS(request,arguments,command) \
+#define SERVER_COMMANDS(request, arguments, command) \
        SERVER_COMMAND("adminmsg", GameCommand_adminmsg(request, arguments), "Send an admin message to a client directly") \
        SERVER_COMMAND("allready", GameCommand_allready(request), "Restart the server and reset the players") \
        SERVER_COMMAND("allspec", GameCommand_allspec(request, arguments), "Force all players to spectate") \
@@ -1804,46 +1818,42 @@ void GameCommand_(float request)
 
 void GameCommand_macro_help()
 {
-       #define SERVER_COMMAND(name,function,description) \
+       #define SERVER_COMMAND(name, function, description) \
                { LOG_INFO("  ^2", name, "^7: ", description, "\n"); }
 
        SERVER_COMMANDS(0, 0, "");
-       #undef SERVER_COMMAND
-
-       return;
+#undef SERVER_COMMAND
 }
 
 float GameCommand_macro_command(float argc, string command)
 {
-       #define SERVER_COMMAND(name,function,description) \
-               { if(name == strtolower(argv(0))) { function; return true; } }
+       #define SERVER_COMMAND(name, function, description) \
+               { if (name == strtolower(argv(0))) { function; return true; } }
 
        SERVER_COMMANDS(CMD_REQUEST_COMMAND, argc, command);
-       #undef SERVER_COMMAND
+#undef SERVER_COMMAND
 
        return false;
 }
 
 float GameCommand_macro_usage(float argc)
 {
-       #define SERVER_COMMAND(name,function,description) \
-               { if(name == strtolower(argv(1))) { function; return true; } }
+       #define SERVER_COMMAND(name, function, description) \
+               { if (name == strtolower(argv(1))) { function; return true; } }
 
        SERVER_COMMANDS(CMD_REQUEST_USAGE, argc, "");
-       #undef SERVER_COMMAND
+#undef SERVER_COMMAND
 
        return false;
 }
 
 void GameCommand_macro_write_aliases(float fh)
 {
-       #define SERVER_COMMAND(name,function,description) \
+       #define SERVER_COMMAND(name, function, description) \
                { CMD_Write_Alias("qc_cmd_sv", name, description); }
 
        SERVER_COMMANDS(0, 0, "");
-       #undef SERVER_COMMAND
-
-       return;
+#undef SERVER_COMMAND
 }
 
 
@@ -1861,9 +1871,9 @@ void GameCommand(string command)
        // argv:   0    - 1      - 2     - 3
        // cmd     vote - master - login - password
 
-       if(strtolower(argv(0)) == "help")
+       if (strtolower(argv(0)) == "help")
        {
-               if(argc == 1)
+               if (argc == 1)
                {
                        LOG_INFO("\nServer console commands:\n");
                        GameCommand_macro_help();
@@ -1882,46 +1892,44 @@ void GameCommand(string command)
 
                        return;
                }
-               else if(BanCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
+               else if (BanCommand_macro_usage(argc))  // Instead of trying to call a command, we're going to see detailed information about it
                {
                        return;
                }
-               else if(CommonCommand_macro_usage(argc, world)) // same here, but for common commands instead
+               else if (CommonCommand_macro_usage(argc, world))  // same here, but for common commands instead
                {
                        return;
                }
-               else if(GenericCommand_macro_usage(argc)) // same here, but for generic commands instead
+               else if (GenericCommand_macro_usage(argc))  // same here, but for generic commands instead
                {
                        return;
                }
-               else if(GameCommand_macro_usage(argc)) // finally try for normal commands too
+               else if (GameCommand_macro_usage(argc))  // finally try for normal commands too
                {
                        return;
                }
        }
-       else if(MUTATOR_CALLHOOK(SV_ParseServerCommand, strtolower(argv(0)), argc, command))
+       else if (MUTATOR_CALLHOOK(SV_ParseServerCommand, strtolower(argv(0)), argc, command))
        {
-               return; // handled by a mutator
+               return;  // handled by a mutator
        }
-       else if(BanCommand(command))
+       else if (BanCommand(command))
        {
-               return; // handled by server/command/ipban.qc
+               return;  // handled by server/command/ipban.qc
        }
-       else if(CommonCommand_macro_command(argc, world, command))
+       else if (CommonCommand_macro_command(argc, world, command))
        {
-               return; // handled by server/command/common.qc
+               return;  // handled by server/command/common.qc
        }
-       else if(GenericCommand(command))
+       else if (GenericCommand(command))
        {
-               return; // handled by common/command/generic.qc
+               return;                                        // handled by common/command/generic.qc
        }
-       else if(GameCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
+       else if (GameCommand_macro_command(argc, command)) // continue as usual and scan for normal commands
        {
-               return; // handled by one of the above GameCommand_* functions
+               return;                                        // handled by one of the above GameCommand_* functions
        }
 
        // nothing above caught the command, must be invalid
        LOG_INFO(((command != "") ? strcat("Unknown server command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try sv_cmd help.\n");
-
-       return;
 }
index 0cc520c2e402e21d6bed78e35a94365b9a6033ab..8fa66dac47567fe28f92a42505fbdeebff80d646 100644 (file)
@@ -13,7 +13,7 @@ void race_deleteTime(string map, float pos);
 const float SHUFFLETEAMS_MAX_PLAYERS = 255;
 const float SHUFFLETEAMS_MAX_TEAMS = 4;
 float shuffleteams_players[SHUFFLETEAMS_MAX_PLAYERS]; // maximum of 255 player slots
-float shuffleteams_teams[SHUFFLETEAMS_MAX_TEAMS]; // maximum of 4 teams
+float shuffleteams_teams[SHUFFLETEAMS_MAX_TEAMS];     // maximum of 4 teams
 
 // used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
 void GameCommand_macro_write_aliases(float fh);
index da9be11ff69c9ed53f4abc0505393532b4e6f028..81d5136f9648949b18e8b7866059ea977eff7a2e 100644 (file)
@@ -27,7 +27,7 @@ bool Nagger_SendEntity(entity this, entity to, float sendflags)
 {
        int nags, i, f, b;
        entity e;
-       WriteByte(MSG_ENTITY, ENT_CLIENT_NAGGER);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_NAGGER);
 
        // bits:
        //   1 = ready
@@ -40,33 +40,28 @@ bool Nagger_SendEntity(entity this, entity to, float sendflags)
        // 128 = vote string
 
        nags = 0;
-       if(readycount)
+       if (readycount)
        {
                nags |= BIT(0);
-               if(to.ready == 0)
-                       nags |= BIT(1);
+               if (to.ready == 0) nags |= BIT(1);
        }
-       if(vote_called)
+       if (vote_called)
        {
                nags |= BIT(2);
-               if(to.vote_selection == 0)
-                       nags |= BIT(3);
+               if (to.vote_selection == 0) nags |= BIT(3);
        }
-       if(warmup_stage)
-               nags |= BIT(4);
+       if (warmup_stage) nags |= BIT(4);
 
-       if(sendflags & BIT(6))
-               nags |= BIT(6);
+       if (sendflags & BIT(6)) nags |= BIT(6);
 
-       if(sendflags & BIT(7))
-               nags |= BIT(7);
+       if (sendflags & BIT(7)) nags |= BIT(7);
 
-       if(!(nags & 4)) // no vote called? send no string
+       if (!(nags & 4))  // no vote called? send no string
                nags &= ~(BIT(6) | BIT(7));
 
        WriteByte(MSG_ENTITY, nags);
 
-       if(nags & BIT(6))
+       if (nags & BIT(6))
        {
                WriteByte(MSG_ENTITY, vote_accept_count);
                WriteByte(MSG_ENTITY, vote_reject_count);
@@ -74,16 +69,14 @@ bool Nagger_SendEntity(entity this, entity to, float sendflags)
                WriteChar(MSG_ENTITY, to.vote_selection);
        }
 
-       if(nags & BIT(7))
-               WriteString(MSG_ENTITY, vote_called_display);
+       if (nags & BIT(7)) WriteString(MSG_ENTITY, vote_called_display);
 
-       if(nags & 1)
+       if (nags & 1)
        {
-               for(i = 1; i <= maxclients; i += 8)
+               for (i = 1; i <= maxclients; i += 8)
                {
-                       for(f = 0, e = edict_num(i), b = 1; b < 256; b *= 2, e = nextent(e))
-                               if(!IS_REAL_CLIENT(e) || e.ready)
-                                       f |= b;
+                       for (f = 0, e = edict_num(i), b = 1; b < 256; b *= 2, e = nextent(e))
+                               if (!IS_REAL_CLIENT(e) || e.ready) f |= b;
                        WriteByte(MSG_ENTITY, f);
                }
        }
@@ -93,32 +86,29 @@ bool Nagger_SendEntity(entity this, entity to, float sendflags)
 
 void Nagger_Init()
 {
-       Net_LinkEntity(nagger = spawn(), false, 0, Nagger_SendEntity);
+       Net_LinkEntity(nagger = new(nagger), false, 0, Nagger_SendEntity);
+       make_pure(nagger);
 }
 
 void Nagger_VoteChanged()
 {
-       if(nagger)
-               nagger.SendFlags |= BIT(7);
+       if (nagger) nagger.SendFlags |= BIT(7);
 }
 
 void Nagger_VoteCountChanged()
 {
-       if(nagger)
-               nagger.SendFlags |= BIT(6);
+       if (nagger) nagger.SendFlags |= BIT(6);
 }
 
 void Nagger_ReadyCounted()
 {
-       if(nagger)
-               nagger.SendFlags |= BIT(0);
+       if (nagger) nagger.SendFlags |= BIT(0);
 }
 
 // If the vote_caller is still here, return their name, otherwise vote_caller_name
 string OriginalCallerName()
 {
-       if (IS_REAL_CLIENT(vote_caller))
-               return vote_caller.netname;
+       if (IS_REAL_CLIENT(vote_caller)) return vote_caller.netname;
        return vote_caller_name;
 }
 
@@ -130,9 +120,12 @@ void VoteReset()
 {
        entity tmp_player;
 
-       FOR_EACH_CLIENT(tmp_player) { tmp_player.vote_selection = 0; }
+       FOR_EACH_CLIENT(tmp_player)
+       {
+               tmp_player.vote_selection = 0;
+       }
 
-       if(vote_called)
+       if (vote_called)
        {
                strunzone(vote_called_command);
                strunzone(vote_called_display);
@@ -156,11 +149,9 @@ void VoteReset()
 void VoteStop(entity stopper)
 {
        bprint("\{1}^2* ^3", GetCallerName(stopper), "^2 stopped ^3", OriginalCallerName(), "^2's vote\n");
-       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid))); }
-
+       if (autocvar_sv_eventlog)   GameLogEcho(strcat(":vote:vstop:", ftos(stopper.playerid)));
        // Don't force them to wait for next vote, this way they can e.g. correct their vote.
-       if((vote_caller) && (stopper == vote_caller)) { vote_caller.vote_waittime = time + autocvar_sv_vote_stop; }
-
+       if ((vote_caller) && (stopper == vote_caller))   vote_caller.vote_waittime = time + autocvar_sv_vote_stop;
        VoteReset();
 }
 
@@ -168,12 +159,10 @@ void VoteAccept()
 {
        bprint("\{1}^2* ^3", OriginalCallerName(), "^2's vote for ^1", vote_called_display, "^2 was accepted\n");
 
-       if((vote_called == VOTE_MASTER) && vote_caller)
-               vote_caller.vote_master = 1;
-       else
-               localcmd(strcat(vote_called_command, "\n"));
+       if ((vote_called == VOTE_MASTER) && vote_caller) vote_caller.vote_master = 1;
+       else localcmd(strcat(vote_called_command, "\n"));
 
-       if(vote_caller) { vote_caller.vote_waittime = 0; } // people like your votes, you don't need to wait to vote again
+       if (vote_caller)   vote_caller.vote_waittime = 0;  // people like your votes, you don't need to wait to vote again
 
        VoteReset();
        Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_ACCEPT);
@@ -202,7 +191,7 @@ void VoteSpam(float notvoters, float mincount, string result)
                strcat(", ^1", ftos(vote_abstain_count), "^2 didn't care"),
                strcat(", ^1", ftos(notvoters), strcat("^2 didn't ", ((mincount >= 0) ? "" : "have to "), "vote\n"))));
 
-       if(autocvar_sv_eventlog)
+       if (autocvar_sv_eventlog)
        {
                GameLogEcho(strcat(
                        strcat(":vote:v", result, ":", ftos(vote_accept_count)),
@@ -219,8 +208,8 @@ void VoteCount(float first_count)
        vote_accept_count = vote_reject_count = vote_abstain_count = 0;
 
        float spectators_allowed = ((autocvar_sv_vote_nospectators != 2)
-                               || ((autocvar_sv_vote_nospectators == 1) && (warmup_stage || gameover))
-                               || (autocvar_sv_vote_nospectators == 0));
+           || ((autocvar_sv_vote_nospectators == 1) && (warmup_stage || gameover))
+           || (autocvar_sv_vote_nospectators == 0));
 
        float vote_player_count = 0, notvoters = 0;
        float vote_real_player_count = 0, vote_real_accept_count = 0;
@@ -236,28 +225,36 @@ void VoteCount(float first_count)
        FOR_EACH_REALCLIENT(tmp_player)
        {
                ++vote_player_count;
-               if(IS_PLAYER(tmp_player)) { ++vote_real_player_count; }
-
-               switch(tmp_player.vote_selection)
+               if (IS_PLAYER(tmp_player))   ++vote_real_player_count;
+               switch (tmp_player.vote_selection)
                {
-                       case VOTE_SELECT_REJECT: { ++vote_reject_count; { if(IS_PLAYER(tmp_player)) ++vote_real_reject_count; } break; }
-                       case VOTE_SELECT_ACCEPT: { ++vote_accept_count; { if(IS_PLAYER(tmp_player)) ++vote_real_accept_count; } break; }
-                       case VOTE_SELECT_ABSTAIN: { ++vote_abstain_count; { if(IS_PLAYER(tmp_player)) ++vote_real_abstain_count; } break; }
+                       case VOTE_SELECT_REJECT:
+                       { ++vote_reject_count;
+                         { if (IS_PLAYER(tmp_player)) ++vote_real_reject_count; } break;
+                       }
+                       case VOTE_SELECT_ACCEPT:
+                       { ++vote_accept_count;
+                         { if (IS_PLAYER(tmp_player)) ++vote_real_accept_count; } break;
+                       }
+                       case VOTE_SELECT_ABSTAIN:
+                       { ++vote_abstain_count;
+                         { if (IS_PLAYER(tmp_player)) ++vote_real_abstain_count; } break;
+                       }
                        default: break;
                }
        }
 
        // Check to see if there are enough players on the server to allow master voting... otherwise, vote master could be used for evil.
-       if((vote_called == VOTE_MASTER) && autocvar_sv_vote_master_playerlimit > vote_player_count)
+       if ((vote_called == VOTE_MASTER) && autocvar_sv_vote_master_playerlimit > vote_player_count)
        {
-               if(vote_caller) { vote_caller.vote_waittime = 0; }
+               if (vote_caller)   vote_caller.vote_waittime = 0;
                print_to(vote_caller, "^1There are not enough players on this server to allow you to become vote master.");
                VoteReset();
                return;
        }
 
        // if spectators aren't allowed to vote and there are players in a match, then only count the players in the vote and ignore spectators.
-       if(!spectators_allowed && (vote_real_player_count > 0))
+       if (!spectators_allowed && (vote_real_player_count > 0))
        {
                vote_accept_count = vote_real_accept_count;
                vote_reject_count = vote_real_reject_count;
@@ -277,43 +274,43 @@ void VoteCount(float first_count)
        vote_needed_of_voted = floor((vote_accept_count + vote_reject_count) * vote_factor_of_voted) + 1;
 
        // are there any players at all on the server? it could be an admin vote
-       if(vote_player_count == 0 && first_count)
+       if (vote_player_count == 0 && first_count)
        {
-               VoteSpam(0, -1, "yes"); // no players at all, just accept it
+               VoteSpam(0, -1, "yes");  // no players at all, just accept it
                VoteAccept();
                return;
        }
 
        // since there ARE players, finally calculate the result of the vote
-       if(vote_accept_count >= vote_needed_overall)
+       if (vote_accept_count >= vote_needed_overall)
        {
-               VoteSpam(notvoters, -1, "yes"); // there is enough acceptions to pass the vote
+               VoteSpam(notvoters, -1, "yes");  // there is enough acceptions to pass the vote
                VoteAccept();
                return;
        }
 
-       if(vote_reject_count > vote_player_count - vote_abstain_count - vote_needed_overall)
+       if (vote_reject_count > vote_player_count - vote_abstain_count - vote_needed_overall)
        {
-               VoteSpam(notvoters, -1, "no"); // there is enough rejections to deny the vote
+               VoteSpam(notvoters, -1, "no");  // there is enough rejections to deny the vote
                VoteReject();
                return;
        }
 
        // there is not enough votes in either direction, now lets just calculate what the voters have said
-       if(time > vote_endtime)
+       if (time > vote_endtime)
        {
                final_needed_votes = vote_needed_overall;
 
-               if(autocvar_sv_vote_majority_factor_of_voted)
+               if (autocvar_sv_vote_majority_factor_of_voted)
                {
-                       if(vote_accept_count >= vote_needed_of_voted)
+                       if (vote_accept_count >= vote_needed_of_voted)
                        {
                                VoteSpam(notvoters, min(vote_needed_overall, vote_needed_of_voted), "yes");
                                VoteAccept();
                                return;
                        }
 
-                       if(vote_accept_count + vote_reject_count > 0)
+                       if (vote_accept_count + vote_reject_count > 0)
                        {
                                VoteSpam(notvoters, min(vote_needed_overall, vote_needed_of_voted), "no");
                                VoteReject();
@@ -331,13 +328,11 @@ void VoteCount(float first_count)
 
 void VoteThink()
 {
-       if(vote_endtime > 0) // a vote was called
-       if(time > vote_endtime) // time is up
+       if (vote_endtime > 0)        // a vote was called
        {
-               VoteCount(false);
+               if (time > vote_endtime) // time is up
+                       VoteCount(false);
        }
-
-       return;
 }
 
 
@@ -347,39 +342,39 @@ void VoteThink()
 
 // Resets the state of all clients, items, weapons, waypoints, ... of the map.
 void reset_map(float dorespawn)
-{SELFPARAM();
+{
+       SELFPARAM();
 
-       if(time <= game_starttime && round_handler_IsActive())
+       if (time <= game_starttime && round_handler_IsActive())
                round_handler_Reset(game_starttime);
 
        MUTATOR_CALLHOOK(reset_map_global);
 
-       for(entity e = world; (e = nextent(e)); )
+       for (entity e = world; (e = nextent(e)); )
        {
                setself(e);
-               if(IS_NOT_A_CLIENT(self))
+               if (IS_NOT_A_CLIENT(self))
                {
-                       if(self.reset)
+                       if (self.reset)
                        {
                                self.reset();
                                continue;
                        }
 
-                       if(self.team_saved)
-                               self.team = self.team_saved;
+                       if (self.team_saved) self.team = self.team_saved;
 
-                       if(self.flags & FL_PROJECTILE) // remove any projectiles left
+                       if (self.flags & FL_PROJECTILE)  // remove any projectiles left
                                remove(self);
                }
        }
 
        // Waypoints and assault start come LAST
-       for(entity e = world; (e = nextent(e)); )
+       for (entity e = world; (e = nextent(e)); )
        {
                setself(e);
-               if(IS_NOT_A_CLIENT(self))
+               if (IS_NOT_A_CLIENT(self))
                {
-                       if(self.reset2)
+                       if (self.reset2)
                        {
                                self.reset2();
                                continue;
@@ -389,51 +384,52 @@ void reset_map(float dorespawn)
 
        entity e;
        FOR_EACH_PLAYER(e)
-       if(e.frozen)
-       {
-               WITH(entity, self, e, Unfreeze(self));
-       }
+       if (e.frozen) WITH(entity, self, e, Unfreeze(self));
 
        // Moving the player reset code here since the player-reset depends
        // on spawnpoint entities which have to be reset first --blub
-       if(dorespawn)
-       if(!MUTATOR_CALLHOOK(reset_map_players))
-       FOR_EACH_CLIENT(e) // reset all players
+       if (dorespawn)
        {
-               setself(e);
-               /*
-               only reset players if a restart countdown is active
-               this can either be due to cvar sv_ready_restart_after_countdown having set
-               restart_mapalreadyrestarted to 1 after the countdown ended or when
-               sv_ready_restart_after_countdown is not used and countdown is still running
-               */
-               if (restart_mapalreadyrestarted || (time < game_starttime))
+               if (!MUTATOR_CALLHOOK(reset_map_players))
                {
-                       //NEW: changed behaviour so that it prevents that previous spectators/observers suddenly spawn as players
-                       if (IS_PLAYER(self)) {
-                               //PlayerScore_Clear(self);
-                               self.killcount = 0;
-                               //stop the player from moving so that he stands still once he gets respawned
-                               self.velocity = '0 0 0';
-                               self.avelocity = '0 0 0';
-                               self.movement = '0 0 0';
-                               PutClientInServer();
+                       FOR_EACH_CLIENT(e)  // reset all players
+                       {
+                               setself(e);
+                               /*
+                               only reset players if a restart countdown is active
+                               this can either be due to cvar sv_ready_restart_after_countdown having set
+                               restart_mapalreadyrestarted to 1 after the countdown ended or when
+                               sv_ready_restart_after_countdown is not used and countdown is still running
+                               */
+                               if (restart_mapalreadyrestarted || (time < game_starttime))
+                               {
+                                       // NEW: changed behaviour so that it prevents that previous spectators/observers suddenly spawn as players
+                                       if (IS_PLAYER(self))
+                                       {
+                                               // PlayerScore_Clear(self);
+                                               self.killcount = 0;
+                                               // stop the player from moving so that he stands still once he gets respawned
+                                               self.velocity = '0 0 0';
+                                               self.avelocity = '0 0 0';
+                                               self.movement = '0 0 0';
+                                               PutClientInServer();
+                                       }
+                               }
                        }
+
+                       setself(this);
                }
        }
-
-       setself(this);
 }
 
 // Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set)
 void ReadyRestart_think()
-{SELFPARAM();
+{
+       SELFPARAM();
        restart_mapalreadyrestarted = 1;
        reset_map(true);
        Score_ClearAll();
        remove(self);
-
-       return;
 }
 
 // Forces a restart of the game without actually reloading the map // this is a mess...
@@ -446,8 +442,7 @@ void ReadyRestart_force()
        VoteReset();
 
        // clear overtime, we have to decrease timelimit to its original value again.
-       if (checkrules_overtimesadded > 0 && g_race_qualifying != 2) { cvar_set("timelimit", ftos(autocvar_timelimit - (checkrules_overtimesadded * autocvar_timelimit_overtime))); }
-
+       if (checkrules_overtimesadded > 0 && g_race_qualifying != 2)   cvar_set("timelimit", ftos(autocvar_timelimit - (checkrules_overtimesadded * autocvar_timelimit_overtime)));
        checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0;
 
        readyrestart_happened = 1;
@@ -464,22 +459,25 @@ void ReadyRestart_force()
        restart_mapalreadyrestarted = 0; // reset this var, needed when cvar sv_ready_restart_repeatable is in use
 
        // disable the warmup global for the server
-       warmup_stage = 0; // once the game is restarted the game is in match stage
+       warmup_stage = 0;                // once the game is restarted the game is in match stage
 
        // reset the .ready status of all players (also spectators)
-       FOR_EACH_REALCLIENT(tmp_player) { tmp_player.ready = 0; }
+       FOR_EACH_REALCLIENT(tmp_player)
+       {
+               tmp_player.ready = 0;
+       }
        readycount = 0;
-       Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
+       Nagger_ReadyCounted();  // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
 
        // lock teams with lockonrestart
-       if(autocvar_teamplay_lockonrestart && teamplay)
+       if (autocvar_teamplay_lockonrestart && teamplay)
        {
                lockteams = 1;
                bprint("^1The teams are now locked.\n");
        }
 
-       //initiate the restart-countdown-announcer entity
-       if(autocvar_sv_ready_restart_after_countdown)
+       // initiate the restart-countdown-announcer entity
+       if (autocvar_sv_ready_restart_after_countdown)
        {
                restart_timer = spawn();
                restart_timer.think = ReadyRestart_think;
@@ -487,29 +485,26 @@ void ReadyRestart_force()
        }
 
        // after a restart every players number of allowed timeouts gets reset, too
-       if(autocvar_sv_timeout) { FOR_EACH_REALPLAYER(tmp_player) { tmp_player.allowed_timeouts = autocvar_sv_timeout_number; } }
-
-       //reset map immediately if this cvar is not set
-       if (!autocvar_sv_ready_restart_after_countdown) { reset_map(true); }
-
-       if(autocvar_sv_eventlog) { GameLogEcho(":restart"); }
-}
+       if (autocvar_sv_timeout)
+       {
+               FOR_EACH_REALPLAYER(tmp_player)
+               {
+                       tmp_player.allowed_timeouts = autocvar_sv_timeout_number;
+               }
+               // reset map immediately if this cvar is not set
+               if (!autocvar_sv_ready_restart_after_countdown)   reset_map(true); }
+       if (autocvar_sv_eventlog)   GameLogEcho(":restart"); }
 
 void ReadyRestart()
 {
        // no assault support yet...
-       if(g_assault | gameover | intermission_running | race_completing)
-               localcmd("restart\n");
-       else
-               localcmd("\nsv_hook_gamerestart\n");
+       if (g_assault | gameover | intermission_running | race_completing) localcmd("restart\n");
+       else localcmd("\nsv_hook_gamerestart\n");
 
        // Reset ALL scores, but only do that at the beginning of the countdown if sv_ready_restart_after_countdown is off!
        // Otherwise scores could be manipulated during the countdown.
-       if (!autocvar_sv_ready_restart_after_countdown) { Score_ClearAll(); }
-
+       if (!autocvar_sv_ready_restart_after_countdown)   Score_ClearAll();
        ReadyRestart_force();
-
-       return;
 }
 
 // Count the players who are ready and determine whether or not to restart the match
@@ -521,11 +516,10 @@ void ReadyCount()
 
        FOR_EACH_REALCLIENT(tmp_player)
        {
-               if(IS_PLAYER(tmp_player) || tmp_player.caplayer == 1)
+               if (IS_PLAYER(tmp_player) || tmp_player.caplayer == 1)
                {
                        ++t_players;
-                       if(tmp_player.ready) { ++t_ready; }
-               }
+                       if (tmp_player.ready)   ++t_ready; }
        }
 
        readycount = t_ready;
@@ -535,12 +529,7 @@ void ReadyCount()
        ready_needed_factor = bound(0.5, cvar("g_warmup_majority_factor"), 0.999);
        ready_needed_count = floor(t_players * ready_needed_factor) + 1;
 
-       if(readycount >= ready_needed_count)
-       {
-               ReadyRestart();
-       }
-
-       return;
+       if (readycount >= ready_needed_count) ReadyRestart();
 }
 
 
@@ -552,12 +541,9 @@ float Votecommand_check_assignment(entity caller, float assignment)
 {
        float from_server = (!caller);
 
-       if((assignment == VC_ASGNMNT_BOTH)
-               || ((!from_server && assignment == VC_ASGNMNT_CLIENTONLY)
-               || (from_server && assignment == VC_ASGNMNT_SERVERONLY)))
-       {
-               return true;
-       }
+       if ((assignment == VC_ASGNMNT_BOTH)
+           || ((!from_server && assignment == VC_ASGNMNT_CLIENTONLY)
+           || (from_server && assignment == VC_ASGNMNT_SERVERONLY))) return true;
 
        return false;
 }
@@ -566,21 +552,18 @@ string VoteCommand_extractcommand(string input, float startpos, float argc)
 {
        string output;
 
-       if((argc - 1) < startpos)
-               output = "";
-       else
-               output = substring(input, argv_start_index(startpos), argv_end_index(-1) - argv_start_index(startpos));
+       if ((argc - 1) < startpos) output = "";
+       else output = substring(input, argv_start_index(startpos), argv_end_index(-1) - argv_start_index(startpos));
 
        return output;
 }
 
 float VoteCommand_checknasty(string vote_command)
 {
-       if((strstrofs(vote_command, ";", 0) >= 0)
-               || (strstrofs(vote_command, "\n", 0) >= 0)
-               || (strstrofs(vote_command, "\r", 0) >= 0)
-               || (strstrofs(vote_command, "$", 0) >= 0))
-               return false;
+       if ((strstrofs(vote_command, ";", 0) >= 0)
+           || (strstrofs(vote_command, "\n", 0) >= 0)
+           || (strstrofs(vote_command, "\r", 0) >= 0)
+           || (strstrofs(vote_command, "$", 0) >= 0)) return false;
 
        return true;
 }
@@ -589,8 +572,7 @@ float VoteCommand_checkinlist(string vote_command, string list)
 {
        string l = strcat(" ", list, " ");
 
-       if(strstrofs(l, strcat(" ", vote_command, " "), 0) >= 0)
-               return true;
+       if (strstrofs(l, strcat(" ", vote_command, " "), 0) >= 0) return true;
 
        return false;
 }
@@ -605,16 +587,16 @@ string ValidateMap(string validated_map, entity caller)
                return string_null;
        }
 
-       if(!autocvar_sv_vote_override_mostrecent && caller)
+       if (!autocvar_sv_vote_override_mostrecent && caller)
        {
-               if(Map_IsRecent(validated_map))
+               if (Map_IsRecent(validated_map))
                {
                        print_to(caller, "This server does not allow for recent maps to be played again. Please be patient for some rounds.");
                        return string_null;
                }
        }
 
-       if(!MapInfo_CheckMap(validated_map))
+       if (!MapInfo_CheckMap(validated_map))
        {
                print_to(caller, strcat("^1Invalid mapname, \"^3", validated_map, "^1\" does not support the current game mode."));
                return string_null;
@@ -627,14 +609,13 @@ float VoteCommand_checkargs(float startpos, float argc)
 {
        float p, q, check, minargs;
        string cvarname = strcat("sv_vote_command_restriction_", argv(startpos));
-       string cmdrestriction = cvar_string(cvarname); // note: this warns on undefined cvar. We want that.
+       string cmdrestriction = cvar_string(cvarname);  // note: this warns on undefined cvar. We want that.
        string charlist, arg;
        float checkmate;
 
-       if(cmdrestriction == "")
-               return true;
+       if (cmdrestriction == "") return true;
 
-       ++startpos; // skip command name
+       ++startpos;  // skip command name
 
        // check minimum arg count
 
@@ -643,49 +624,45 @@ float VoteCommand_checkargs(float startpos, float argc)
        // ...
 
        minargs = stof(cmdrestriction);
-       if(argc - startpos < minargs)
-               return false;
+       if (argc - startpos < minargs) return false;
 
-       p = strstrofs(cmdrestriction, ";", 0); // find first semicolon
+       p = strstrofs(cmdrestriction, ";", 0);  // find first semicolon
 
-       for (;;)
+       for ( ; ; )
        {
                // we know that at any time, startpos <= argc - minargs
                // so this means: argc-minargs >= startpos >= argc, thus
                // argc-minargs >= argc, thus minargs <= 0, thus all minargs
                // have been seen already
 
-               if(startpos >= argc) // all args checked? GOOD
+               if (startpos >= argc) // all args checked? GOOD
                        break;
 
-               if(p < 0) // no more args? FAIL
+               if (p < 0)            // no more args? FAIL
                {
                        // exception: exactly minargs left, this one included
-                       if(argc - startpos == minargs)
-                               break;
+                       if (argc - startpos == minargs) break;
 
                        // otherwise fail
                        return false;
                }
 
                // cut to next semicolon
-               q = strstrofs(cmdrestriction, ";", p+1); // find next semicolon
-               if(q < 0)
-                       charlist = substring(cmdrestriction, p+1, -1);
-               else
-                       charlist = substring(cmdrestriction, p+1, q - (p+1));
+               q = strstrofs(cmdrestriction, ";", p + 1);  // find next semicolon
+               if (q < 0) charlist = substring(cmdrestriction, p + 1, -1);
+               else charlist = substring(cmdrestriction, p + 1, q - (p + 1));
 
                // in case we ever want to allow semicolons in VoteCommand_checknasty
                // charlist = strreplace("^^", ";", charlist);
 
-               if(charlist != "")
+               if (charlist != "")
                {
                        // verify the arg only contains allowed chars
                        arg = argv(startpos);
                        checkmate = strlen(arg);
-                       for(check = 0; check < checkmate; ++check)
-                               if(strstrofs(charlist, substring(arg, check, 1), 0) < 0)
-                                       return false; // not allowed character
+                       for (check = 0; check < checkmate; ++check)
+                               if (strstrofs(charlist, substring(arg, check, 1), 0) < 0) return false;
+                       // not allowed character
                        // all characters are allowed. FINE.
                }
 
@@ -704,40 +681,35 @@ float VoteCommand_parse(entity caller, string vote_command, string vote_list, fl
        first_command = argv(startpos);
 
        /*printf("VoteCommand_parse(): Command: '%s', Length: %f.\n",
-               substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)),
-               strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)))
+           substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)),
+           strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos)))
        );*/
 
-       if(
-               (autocvar_sv_vote_limit > 0)
-               &&
-               (strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos))) > autocvar_sv_vote_limit)
-       )
-               return false;
+       if (
+           (autocvar_sv_vote_limit > 0)
+           &&
+           (strlen(substring(vote_command, argv_start_index(startpos), strlen(vote_command) - argv_start_index(startpos))) > autocvar_sv_vote_limit)
+          )   return false;
 
-       if (!VoteCommand_checkinlist(first_command, vote_list))
-               return false;
+       if (!VoteCommand_checkinlist(first_command, vote_list)) return false;
 
-       if (!VoteCommand_checkargs(startpos, argc))
-               return false;
+       if (!VoteCommand_checkargs(startpos, argc)) return false;
 
-       switch(first_command) // now go through and parse the proper commands to adjust as needed.
+       switch (first_command) // now go through and parse the proper commands to adjust as needed.
        {
                case "kick":
-               case "kickban": // catch all kick/kickban commands
+               case "kickban":    // catch all kick/kickban commands
                {
                        entity victim = GetIndexedEntity(argc, (startpos + 1));
                        float accepted = VerifyClientEntity(victim, true, false);
 
-                       if(accepted > 0)
+                       if (accepted > 0)
                        {
                                string reason = ((argc > next_token) ? substring(vote_command, argv_start_index(next_token), strlen(vote_command) - argv_start_index(next_token)) : "No reason provided");
                                string command_arguments;
 
-                               if(first_command == "kickban")
-                                       command_arguments = strcat(ftos(autocvar_g_ban_default_bantime), " ", ftos(autocvar_g_ban_default_masksize), " ~");
-                               else
-                                       command_arguments = reason;
+                               if (first_command == "kickban") command_arguments = strcat(ftos(autocvar_g_ban_default_bantime), " ", ftos(autocvar_g_ban_default_masksize), " ~");
+                               else command_arguments = reason;
 
                                vote_parsed_command = strcat(first_command, " # ", ftos(num_for_edict(victim)), " ", command_arguments);
                                vote_parsed_display = strcat("^1", vote_command, " (^7", victim.netname, "^1): ", reason);
@@ -749,10 +721,10 @@ float VoteCommand_parse(entity caller, string vote_command, string vote_list, fl
 
                case "map":
                case "chmap":
-               case "gotomap": // re-direct all map selection commands to gotomap
+               case "gotomap":  // re-direct all map selection commands to gotomap
                {
                        vote_command = ValidateMap(argv(startpos + 1), caller);
-                       if (!vote_command) { return false; }
+                       if (!vote_command)   return false;
                        vote_parsed_command = strcat("gotomap ", vote_command);
                        vote_parsed_display = strzone(strcat("^1", vote_parsed_command));
 
@@ -776,22 +748,24 @@ float VoteCommand_parse(entity caller, string vote_command, string vote_list, fl
 //  Command Sub-Functions
 // =======================
 
-void VoteCommand_abstain(float request, entity caller) // CLIENT ONLY
+void VoteCommand_abstain(float request, entity caller)  // CLIENT ONLY
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        if (!vote_called) { print_to(caller, "^1No vote called."); }
-                       else if(caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
+                       else if (caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change)
+                       {
+                               print_to(caller, "^1You have already voted.");
+                       }
 
-                       else // everything went okay, continue changing vote
+                       else  // everything went okay, continue changing vote
                        {
                                print_to(caller, "^1You abstained from your vote.");
                                caller.vote_selection = VOTE_SELECT_ABSTAIN;
                                msg_entity = caller;
-                               if(!autocvar_sv_vote_singlecount) { VoteCount(false); }
-                       }
+                               if (!autocvar_sv_vote_singlecount)   VoteCount(false); }
 
                        return;
                }
@@ -806,54 +780,81 @@ void VoteCommand_abstain(float request, entity caller) // CLIENT ONLY
        }
 }
 
-void VoteCommand_call(float request, entity caller, float argc, string vote_command) // BOTH
+void VoteCommand_call(float request, entity caller, float argc, string vote_command)  // BOTH
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        float spectators_allowed = ((autocvar_sv_vote_nospectators != 2)
-                               || ((autocvar_sv_vote_nospectators == 1) && warmup_stage)
-                               || (autocvar_sv_vote_nospectators == 0));
+                           || ((autocvar_sv_vote_nospectators == 1) && warmup_stage)
+                           || (autocvar_sv_vote_nospectators == 0));
 
                        float tmp_playercount = 0;
                        entity tmp_player;
 
                        vote_command = VoteCommand_extractcommand(vote_command, 2, argc);
 
-                       if(!autocvar_sv_vote_call && caller) { print_to(caller, "^1Vote calling is not allowed."); }
-                       else if(!autocvar_sv_vote_gamestart && time < game_starttime) { print_to(caller, "^1Vote calling is not allowed before the match has started."); }
-                       else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
-                       else if(!spectators_allowed && (caller && !IS_PLAYER(caller))) { print_to(caller, "^1Only players can call a vote."); }
-                       else if(caller && !IS_CLIENT(caller)) { print_to(caller, "^1Only connected clients can vote."); }
-                       else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
-                       else if(caller && (time < caller.vote_waittime)) { print_to(caller, strcat("^1You have to wait ^2", ftos(ceil(caller.vote_waittime - time)), "^1 seconds before you can again call a vote.")); }
-                       else if (!VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
-                       else if (!VoteCommand_parse(caller, vote_command, autocvar_sv_vote_commands, 2, argc)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
-
-                       else // everything went okay, continue with calling the vote
+                       if (!autocvar_sv_vote_call && caller) { print_to(caller, "^1Vote calling is not allowed."); }
+                       else if (!autocvar_sv_vote_gamestart && time < game_starttime)
                        {
-                               vote_caller = caller; // remember who called the vote
+                               print_to(caller, "^1Vote calling is not allowed before the match has started.");
+                       }
+                       else if (vote_called)
+                       {
+                               print_to(caller, "^1There is already a vote called.");
+                       }
+                       else if (!spectators_allowed && (caller && !IS_PLAYER(caller)))
+                       {
+                               print_to(caller, "^1Only players can call a vote.");
+                       }
+                       else if (caller && !IS_CLIENT(caller))
+                       {
+                               print_to(caller, "^1Only connected clients can vote.");
+                       }
+                       else if (timeout_status)
+                       {
+                               print_to(caller, "^1You can not call a vote while a timeout is active.");
+                       }
+                       else if (caller && (time < caller.vote_waittime))
+                       {
+                               print_to(caller, strcat("^1You have to wait ^2", ftos(ceil(caller.vote_waittime - time)), "^1 seconds before you can again call a vote."));
+                       }
+                       else if (!VoteCommand_checknasty(vote_command))
+                       {
+                               print_to(caller, "^1Syntax error in command, see 'vhelp' for more info.");
+                       }
+                       else if (!VoteCommand_parse(caller, vote_command, autocvar_sv_vote_commands, 2, argc))
+                       {
+                               print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info.");
+                       }
+
+                       else  // everything went okay, continue with calling the vote
+                       {
+                               vote_caller = caller;  // remember who called the vote
                                vote_caller_name = strzone(GetCallerName(vote_caller));
                                vote_called = VOTE_NORMAL;
                                vote_called_command = strzone(vote_parsed_command);
                                vote_called_display = strzone(vote_parsed_display);
                                vote_endtime = time + autocvar_sv_vote_timeout;
 
-                               if(caller)
+                               if (caller)
                                {
                                        caller.vote_selection = VOTE_SELECT_ACCEPT;
                                        caller.vote_waittime = time + autocvar_sv_vote_wait;
                                        msg_entity = caller;
                                }
 
-                               FOR_EACH_REALCLIENT(tmp_player) { ++tmp_playercount; }
-                               if(tmp_playercount > 1) { Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_CALL); } // don't announce a "vote now" sound if player is alone
+                               FOR_EACH_REALCLIENT(tmp_player)
+                               {
+                                       ++tmp_playercount;
+                               }
+                               if (tmp_playercount > 1)   Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_CALL);  // don't announce a "vote now" sound if player is alone
 
                                bprint("\{1}^2* ^3", OriginalCallerName(), "^2 calls a vote for ", vote_called_display, "\n");
-                               if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
+                               if (autocvar_sv_eventlog)   GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display));
                                Nagger_VoteChanged();
-                               VoteCount(true); // needed if you are the only one
+                               VoteCount(true);  // needed if you are the only one
                        }
 
                        return;
@@ -871,64 +872,83 @@ void VoteCommand_call(float request, entity caller, float argc, string vote_comm
        }
 }
 
-void VoteCommand_master(float request, entity caller, float argc, string vote_command) // CLIENT ONLY
+void VoteCommand_master(float request, entity caller, float argc, string vote_command)  // CLIENT ONLY
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(autocvar_sv_vote_master)
+                       if (autocvar_sv_vote_master)
                        {
-                               switch(strtolower(argv(2)))
+                               switch (strtolower(argv(2)))
                                {
                                        case "do":
                                        {
                                                vote_command = VoteCommand_extractcommand(vote_command, 3, argc);
 
                                                if (!caller.vote_master) { print_to(caller, "^1You do not have vote master privelages."); }
-                                               else if (!VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
-                                               else if (!VoteCommand_parse(caller, vote_command, strcat(autocvar_sv_vote_commands, " ", autocvar_sv_vote_master_commands), 3, argc)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
+                                               else if (!VoteCommand_checknasty(vote_command))
+                                               {
+                                                       print_to(caller, "^1Syntax error in command, see 'vhelp' for more info.");
+                                               }
+                                               else if (!VoteCommand_parse(caller, vote_command, strcat(autocvar_sv_vote_commands, " ", autocvar_sv_vote_master_commands), 3, argc))
+                                               {
+                                                       print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info.");
+                                               }
 
-                                               else // everything went okay, proceed with command
+                                               else  // everything went okay, proceed with command
                                                {
                                                        localcmd(strcat(vote_parsed_command, "\n"));
                                                        print_to(caller, strcat("Executing command '", vote_parsed_display, "' on server."));
                                                        bprint("\{1}^2* ^3", GetCallerName(caller), "^2 used their ^3master^2 status to do \"^2", vote_parsed_display, "^2\".\n");
-                                                       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vdo:", ftos(caller.playerid), ":", vote_parsed_display)); }
-                                               }
+                                                       if (autocvar_sv_eventlog)   GameLogEcho(strcat(":vote:vdo:", ftos(caller.playerid), ":", vote_parsed_display)); }
 
                                                return;
                                        }
 
                                        case "login":
                                        {
-                                               if(autocvar_sv_vote_master_password == "") { print_to(caller, "^1Login to vote master is not allowed."); }
-                                               else if(caller.vote_master) { print_to(caller, "^1You are already logged in as vote master."); }
-                                               else if(autocvar_sv_vote_master_password != argv(3)) { print_to(caller, strcat("Rejected vote master login from ", GetCallerName(caller))); }
+                                               if (autocvar_sv_vote_master_password == "") { print_to(caller, "^1Login to vote master is not allowed."); }
+                                               else if (caller.vote_master)
+                                               {
+                                                       print_to(caller, "^1You are already logged in as vote master.");
+                                               }
+                                               else if (autocvar_sv_vote_master_password != argv(3))
+                                               {
+                                                       print_to(caller, strcat("Rejected vote master login from ", GetCallerName(caller)));
+                                               }
 
-                                               else // everything went okay, proceed with giving this player master privilages
+                                               else  // everything went okay, proceed with giving this player master privilages
                                                {
                                                        caller.vote_master = true;
                                                        print_to(caller, strcat("Accepted vote master login from ", GetCallerName(caller)));
                                                        bprint("\{1}^2* ^3", GetCallerName(caller), "^2 logged in as ^3master^2\n");
-                                                       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vlogin:", ftos(caller.playerid))); }
-                                               }
+                                                       if (autocvar_sv_eventlog)   GameLogEcho(strcat(":vote:vlogin:", ftos(caller.playerid))); }
 
                                                return;
                                        }
 
-                                       default: // calling a vote for master
+                                       default:  // calling a vote for master
                                        {
                                                float spectators_allowed = ((autocvar_sv_vote_nospectators != 2)
-                                                       || ((autocvar_sv_vote_nospectators == 1) && warmup_stage)
-                                                       || (autocvar_sv_vote_nospectators == 0));
+                                                   || ((autocvar_sv_vote_nospectators == 1) && warmup_stage)
+                                                   || (autocvar_sv_vote_nospectators == 0));
 
                                                if (!autocvar_sv_vote_master_callable) { print_to(caller, "^1Vote to become vote master is not allowed."); }
-                                               else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
-                                               else if(!spectators_allowed && (caller && !IS_PLAYER(caller))) { print_to(caller, "^1Only players can call a vote."); }
-                                               else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
+                                               else if (vote_called)
+                                               {
+                                                       print_to(caller, "^1There is already a vote called.");
+                                               }
+                                               else if (!spectators_allowed && (caller && !IS_PLAYER(caller)))
+                                               {
+                                                       print_to(caller, "^1Only players can call a vote.");
+                                               }
+                                               else if (timeout_status)
+                                               {
+                                                       print_to(caller, "^1You can not call a vote while a timeout is active.");
+                                               }
 
-                                               else // everything went okay, continue with creating vote
+                                               else  // everything went okay, continue with creating vote
                                                {
                                                        vote_caller = caller;
                                                        vote_caller_name = strzone(GetCallerName(vote_caller));
@@ -941,9 +961,9 @@ void VoteCommand_master(float request, entity caller, float argc, string vote_co
                                                        caller.vote_waittime = time + autocvar_sv_vote_wait;
 
                                                        bprint("\{1}^2* ^3", OriginalCallerName(), "^2 calls a vote to become ^3master^2.\n");
-                                                       if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
+                                                       if (autocvar_sv_eventlog)   GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display));
                                                        Nagger_VoteChanged();
-                                                       VoteCount(true); // needed if you are the only one
+                                                       VoteCount(true);  // needed if you are the only one
                                                }
 
                                                return;
@@ -966,23 +986,28 @@ void VoteCommand_master(float request, entity caller, float argc, string vote_co
        }
 }
 
-void VoteCommand_no(float request, entity caller) // CLIENT ONLY
+void VoteCommand_no(float request, entity caller)  // CLIENT ONLY
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        if (!vote_called) { print_to(caller, "^1No vote called."); }
-                       else if(caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
-                       else if(((caller == vote_caller) || caller.vote_master) && autocvar_sv_vote_no_stops_vote) { VoteStop(caller); }
+                       else if (caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change)
+                       {
+                               print_to(caller, "^1You have already voted.");
+                       }
+                       else if (((caller == vote_caller) || caller.vote_master) && autocvar_sv_vote_no_stops_vote)
+                       {
+                               VoteStop(caller);
+                       }
 
-                       else // everything went okay, continue changing vote
+                       else  // everything went okay, continue changing vote
                        {
                                print_to(caller, "^1You rejected the vote.");
                                caller.vote_selection = VOTE_SELECT_REJECT;
                                msg_entity = caller;
-                               if(!autocvar_sv_vote_singlecount) { VoteCount(false); }
-                       }
+                               if (!autocvar_sv_vote_singlecount)   VoteCount(false); }
 
                        return;
                }
@@ -997,16 +1022,14 @@ void VoteCommand_no(float request, entity caller) // CLIENT ONLY
        }
 }
 
-void VoteCommand_status(float request, entity caller) // BOTH
+void VoteCommand_status(float request, entity caller)  // BOTH
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(vote_called)
-                               print_to(caller, strcat("^7Vote for ", vote_called_display, "^7 called by ^7", OriginalCallerName(), "^7."));
-                       else
-                               print_to(caller, "^1No vote called.");
+                       if (vote_called) print_to(caller, strcat("^7Vote for ", vote_called_display, "^7 called by ^7", OriginalCallerName(), "^7."));
+                       else print_to(caller, "^1No vote called.");
 
                        return;
                }
@@ -1021,16 +1044,15 @@ void VoteCommand_status(float request, entity caller) // BOTH
        }
 }
 
-void VoteCommand_stop(float request, entity caller) // BOTH
+void VoteCommand_stop(float request, entity caller)  // BOTH
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if (!vote_called) { print_to(caller, "^1No vote called."); }
-                       else if((caller == vote_caller) || !caller || caller.vote_master) { VoteStop(caller); }
-                       else { print_to(caller, "^1You are not allowed to stop that vote."); }
-
+                       if (!vote_called)   print_to(caller, "^1No vote called.");
+                       else if ((caller == vote_caller) || !caller || caller.vote_master)   VoteStop(caller);
+                       else   print_to(caller, "^1You are not allowed to stop that vote.");
                        return;
                }
 
@@ -1044,22 +1066,24 @@ void VoteCommand_stop(float request, entity caller) // BOTH
        }
 }
 
-void VoteCommand_yes(float request, entity caller) // CLIENT ONLY
+void VoteCommand_yes(float request, entity caller)  // CLIENT ONLY
 {
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
                        if (!vote_called) { print_to(caller, "^1No vote called."); }
-                       else if(caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change) { print_to(caller, "^1You have already voted."); }
+                       else if (caller.vote_selection != VOTE_SELECT_NULL && !autocvar_sv_vote_change)
+                       {
+                               print_to(caller, "^1You have already voted.");
+                       }
 
-                       else // everything went okay, continue changing vote
+                       else  // everything went okay, continue changing vote
                        {
                                print_to(caller, "^1You accepted the vote.");
                                caller.vote_selection = VOTE_SELECT_ACCEPT;
                                msg_entity = caller;
-                               if(!autocvar_sv_vote_singlecount) { VoteCount(false); }
-                       }
+                               if (!autocvar_sv_vote_singlecount)   VoteCount(false); }
 
                        return;
                }
@@ -1078,22 +1102,22 @@ void VoteCommand_yes(float request, entity caller) // CLIENT ONLY
 ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
 void VoteCommand_(float request)
 {
-       switch(request)
-       {
-               case CMD_REQUEST_COMMAND:
-               {
-
-                       return;
-               }
-
-               default:
-               case CMD_REQUEST_USAGE:
-               {
-                       print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote ");
-                       print_to(caller, "  No arguments required.");
-                       return;
-               }
-       }
+    switch(request)
+    {
+        case CMD_REQUEST_COMMAND:
+        {
+
+            return;
+        }
+
+        default:
+        case CMD_REQUEST_USAGE:
+        {
+            print_to(caller, strcat("\nUsage:^3 ", GetCommandPrefix(caller), " vote ");
+            print_to(caller, "  No arguments required.");
+            return;
+        }
+    }
 }
 */
 
@@ -1103,7 +1127,7 @@ void VoteCommand_(float request)
 // ================================
 
 // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define VOTE_COMMANDS(request,caller,arguments,command) \
+#define VOTE_COMMANDS(request, caller, arguments, command) \
        VOTE_COMMAND("abstain", VoteCommand_abstain(request, caller), "Abstain your vote in current vote", VC_ASGNMNT_CLIENTONLY) \
        VOTE_COMMAND("call", VoteCommand_call(request, caller, arguments, command), "Create a new vote for players to decide on", VC_ASGNMNT_BOTH) \
        VOTE_COMMAND("help", VoteCommand_macro_help(caller, arguments), "Shows this information", VC_ASGNMNT_BOTH) \
@@ -1118,38 +1142,36 @@ void VoteCommand_macro_help(entity caller, float argc)
 {
        string command_origin = GetCommandPrefix(caller);
 
-       if(argc == 2 || argv(2) == "help") // help display listing all commands
+       if (argc == 2 || argv(2) == "help")  // help display listing all commands
        {
                print_to(caller, "\nVoting commands:\n");
-               #define VOTE_COMMAND(name,function,description,assignment) \
-                       { if(Votecommand_check_assignment(caller, assignment)) { print_to(caller, strcat("  ^2", name, "^7: ", description)); } }
+               #define VOTE_COMMAND(name, function, description, assignment) \
+                       { if (Votecommand_check_assignment(caller, assignment)) { print_to(caller, strcat("  ^2", name, "^7: ", description)); } }
 
                VOTE_COMMANDS(0, caller, 0, "");
-               #undef VOTE_COMMAND
+#undef VOTE_COMMAND
 
                print_to(caller, strcat("\nUsage:^3 ", command_origin, " vote COMMAND...^7, where possible commands are listed above.\n"));
                print_to(caller, strcat("For help about a specific command, type ", command_origin, " vote help COMMAND"));
                print_to(caller, strcat("\n^7You can call a vote for or execute these commands: ^3", autocvar_sv_vote_commands, "^7 and maybe further ^3arguments^7"));
        }
-       else // usage for individual command
+       else  // usage for individual command
        {
-               #define VOTE_COMMAND(name,function,description,assignment) \
-                       { if(Votecommand_check_assignment(caller, assignment)) { if(name == strtolower(argv(2))) { function; return; } } }
+               #define VOTE_COMMAND(name, function, description, assignment) \
+                       { if (Votecommand_check_assignment(caller, assignment)) { if (name == strtolower(argv(2))) { function; return; } } }
 
                VOTE_COMMANDS(CMD_REQUEST_USAGE, caller, argc, "");
-               #undef VOTE_COMMAND
+#undef VOTE_COMMAND
        }
-
-       return;
 }
 
 float VoteCommand_macro_command(entity caller, float argc, string vote_command)
 {
-       #define VOTE_COMMAND(name,function,description,assignment) \
-               { if(Votecommand_check_assignment(caller, assignment)) { if(name == strtolower(argv(1))) { function; return true; } } }
+       #define VOTE_COMMAND(name, function, description, assignment) \
+               { if (Votecommand_check_assignment(caller, assignment)) { if (name == strtolower(argv(1))) { function; return true; } } }
 
        VOTE_COMMANDS(CMD_REQUEST_COMMAND, caller, argc, vote_command);
-       #undef VOTE_COMMAND
+#undef VOTE_COMMAND
 
        return false;
 }
@@ -1166,12 +1188,11 @@ void VoteCommand(float request, entity caller, float argc, string vote_command)
        // argv:   0    - 1      - 2     - 3
        // cmd     vote - master - login - password
 
-       switch(request)
+       switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
-                       if(VoteCommand_macro_command(caller, argc, vote_command))
-                               return;
+                       if (VoteCommand_macro_command(caller, argc, vote_command)) return;
                }
 
                default:
index f80785e2a12f8c4935654a8e1853141fb4c5653a..98b000e75d3c6f624e48f88acbef9b16dee36ea0 100644 (file)
@@ -23,17 +23,17 @@ const float VOTE_NORMAL = 1;
 const float VOTE_MASTER = 2;
 
 // global vote information declarations
-entity vote_caller; // original caller of the current vote
-string vote_caller_name; // name of the vote caller
-float vote_called; // stores status of current vote (See VOTE_*)
-float vote_endtime; // time when the vote is finished
-float vote_accept_count; // total amount of players who accept the vote (counted by VoteCount() function)
-float vote_reject_count; // same as above, but rejected
-float vote_abstain_count; // same as above, but abstained
-float vote_needed_overall; // total amount of players NEEDED for a vote to pass (based on sv_vote_majority_factor)
-.float vote_master; // flag for if the player has vote master privelages
-.float vote_waittime; // flag for how long the player must wait before they can vote again
-.float vote_selection; // flag for which vote selection the player has made (See VOTE_SELECT_*)
+entity vote_caller;         // original caller of the current vote
+string vote_caller_name;    // name of the vote caller
+float vote_called;          // stores status of current vote (See VOTE_*)
+float vote_endtime;         // time when the vote is finished
+float vote_accept_count;    // total amount of players who accept the vote (counted by VoteCount() function)
+float vote_reject_count;    // same as above, but rejected
+float vote_abstain_count;   // same as above, but abstained
+float vote_needed_overall;  // total amount of players NEEDED for a vote to pass (based on sv_vote_majority_factor)
+.float vote_master;         // flag for if the player has vote master privelages
+.float vote_waittime;       // flag for how long the player must wait before they can vote again
+.float vote_selection;      // flag for which vote selection the player has made (See VOTE_SELECT_*)
 string vote_called_command; // command sent by client
 string vote_called_display; // visual string of command sent by client
 string vote_parsed_command; // command which is fixed after being parsed
@@ -47,10 +47,10 @@ void VoteCommand(float request, entity caller, float argc, string vote_command);
 // warmup and nagger stuff
 const float RESTART_COUNTDOWN = 10;
 entity nagger;
-float readycount; // amount of players who are ready
-float readyrestart_happened; // keeps track of whether a restart has already happened
+float readycount;                  // amount of players who are ready
+float readyrestart_happened;       // keeps track of whether a restart has already happened
 float restart_mapalreadyrestarted; // bool, indicates whether reset_map() was already executed
-.float ready; // flag for if a player is ready
+.float ready;                      // flag for if a player is ready
 void reset_map(float dorespawn);
 void ReadyCount();
 void ReadyRestart_force();
index 6de55189f1408c220cbba92b0368e61f6bf8890c..c1ea1c6c61dcab81aa2df27e52f5b10377605d4e 100644 (file)
@@ -4,13 +4,11 @@
 const int FL_WEAPON = BIT(13);
 const int FL_POWERUP = BIT(14);
 const int FL_PROJECTILE = BIT(15);
-const int FL_TOSSED = BIT(BIT(4));
+const int FL_TOSSED = BIT(16);
 const int FL_NO_WEAPON_STAY = BIT(17);
 const int FL_SPAWNING = BIT(18);
 const int FL_PICKUPITEMS = BIT(19);
 
-const int SVC_SOUND = 6;
-const int SVC_STOPSOUND = 16;
 const int SVC_SETVIEW = 5;
 
 const int RESPAWN_FORCE = 1;
@@ -18,8 +16,6 @@ const int RESPAWN_SILENT = 2;
 
 #define EFMASK_CHEAP (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NODRAW | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT)
 
-const int MSG_ENTITY = 5; // csqc
-
 const int NUM_PLAYERSKINS_TEAMPLAY = 3;
 
 const int ASSAULT_VALUE_INACTIVE = 1000;
diff --git a/qcsrc/server/controlpoint.qc b/qcsrc/server/controlpoint.qc
deleted file mode 100644 (file)
index ceeb4f1..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#include "controlpoint.qh"
-
-#include "command/common.qh"
-
-.bool iscaptured;
-
-bool cpicon_send(entity this, entity to, int sf)
-{
-       WriteByte(MSG_ENTITY, ENT_CLIENT_CONTROLPOINT_ICON);
-       WriteByte(MSG_ENTITY, sf);
-       if(sf & CPSF_SETUP)
-       {
-               WriteCoord(MSG_ENTITY, self.origin_x);
-               WriteCoord(MSG_ENTITY, self.origin_y);
-               WriteCoord(MSG_ENTITY, self.origin_z);
-
-               WriteByte(MSG_ENTITY, self.health);
-               WriteByte(MSG_ENTITY, self.max_health);
-               WriteByte(MSG_ENTITY, self.count);
-               WriteByte(MSG_ENTITY, self.team);
-               WriteByte(MSG_ENTITY, self.owner.iscaptured);
-       }
-
-       if(sf & CPSF_STATUS)
-       {
-               WriteByte(MSG_ENTITY, self.team);
-
-               if(self.health <= 0)
-                       WriteByte(MSG_ENTITY, 0);
-               else
-                       WriteByte(MSG_ENTITY, ceil((self.health / self.max_health) * 255));
-       }
-
-       return true;
-}
-
-void onslaught_controlpoint_icon_link(entity e, void() spawnproc)
-{
-       Net_LinkEntity(e, true, 0, cpicon_send);
-       e.think         = spawnproc;
-       e.nextthink     = time * sys_frametime;
-}
diff --git a/qcsrc/server/controlpoint.qh b/qcsrc/server/controlpoint.qh
deleted file mode 100644 (file)
index d76f0ea..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef CONTROLPOINT_H
-#define CONTROLPOINT_H
-
-const vector CPICON_MIN = '-32 -32 -9';
-const vector CPICON_MAX = '32 32 25';
-
-const int CPSF_STATUS = 4;
-const int CPSF_SETUP = 8;
-
-#endif
diff --git a/qcsrc/server/csqceffects.qc b/qcsrc/server/csqceffects.qc
deleted file mode 100644 (file)
index a26fa97..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include "../common/constants.qh"
-#endif
-
-void te_csqc_lightningarc(vector from,vector to)
-{
-       WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-       WriteByte(MSG_BROADCAST, TE_CSQC_ARC);
-
-       WriteCoord(MSG_BROADCAST, from.x);
-       WriteCoord(MSG_BROADCAST, from.y);
-       WriteCoord(MSG_BROADCAST, from.z);
-       WriteCoord(MSG_BROADCAST, to.x);
-       WriteCoord(MSG_BROADCAST, to.y);
-       WriteCoord(MSG_BROADCAST, to.z);
-}
-
diff --git a/qcsrc/server/csqceffects.qh b/qcsrc/server/csqceffects.qh
deleted file mode 100644 (file)
index 9fd0c38..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef CSQCEFFECTS_H
-#define CSQCEFFECTS_H
-void te_csqc_lightningarc(vector from,vector to);
-#endif
index 4f790014934e7f6186e2810b43171b929623b69e..094eb453192a6e7b48ce2204d39ea18acdc150d9 100644 (file)
@@ -2,8 +2,9 @@
 #define SERVER_DEFS_H
 
 #include "../common/weapons/all.qh"
+#include "../common/stats.qh"
 
-#define INDEPENDENT_ATTACK_FINISHED
+#define INDEPENDENT_ATTACK_FINISHED 1
 
 #define BUTTON_ATCK       button0
 #define BUTTON_JUMP       button2
 
 // Globals
 
-float g_cloaked, g_footsteps, g_grappling_hook, g_instagib;
+float g_footsteps, g_grappling_hook, g_instagib;
 float g_warmup_limit;
 float g_warmup_allguns;
 float g_warmup_allow_timeout;
 float warmup_stage;
-float g_pickup_respawntime_weapon;
-float g_pickup_respawntime_superweapon;
-float g_pickup_respawntime_ammo;
-float g_pickup_respawntime_short;
-float g_pickup_respawntime_medium;
-float g_pickup_respawntime_long;
-float g_pickup_respawntime_powerup;
-float g_pickup_respawntimejitter_weapon;
-float g_pickup_respawntimejitter_superweapon;
-float g_pickup_respawntimejitter_ammo;
-float g_pickup_respawntimejitter_short;
-float g_pickup_respawntimejitter_medium;
-float g_pickup_respawntimejitter_long;
-float g_pickup_respawntimejitter_powerup;
+PROPERTY(float, g_pickup_respawntime_weapon)
+PROPERTY(float, g_pickup_respawntime_superweapon)
+PROPERTY(float, g_pickup_respawntime_ammo)
+PROPERTY(float, g_pickup_respawntime_short)
+PROPERTY(float, g_pickup_respawntime_medium)
+PROPERTY(float, g_pickup_respawntime_long)
+PROPERTY(float, g_pickup_respawntime_powerup)
+PROPERTY(float, g_pickup_respawntimejitter_weapon)
+PROPERTY(float, g_pickup_respawntimejitter_superweapon)
+PROPERTY(float, g_pickup_respawntimejitter_ammo)
+PROPERTY(float, g_pickup_respawntimejitter_short)
+PROPERTY(float, g_pickup_respawntimejitter_medium)
+PROPERTY(float, g_pickup_respawntimejitter_long)
+PROPERTY(float, g_pickup_respawntimejitter_powerup)
 float g_jetpack;
 
 float sv_clones;
@@ -53,8 +54,6 @@ void UpdateFrags(entity player, float f);
 
 float team1_score, team2_score, team3_score, team4_score;
 
-float maxclients;
-
 // flag set on worldspawn so that the code knows if it is dedicated or not
 float server_is_dedicated;
 
@@ -76,8 +75,8 @@ float server_is_dedicated;
 .float pain_frame;                     //"
 .float  crouch;        // Crouching or not?
 
-.float strength_finished;
-.float invincible_finished;
+.float strength_finished = _STAT(STRENGTH_FINISHED);
+.float invincible_finished = _STAT(INVINCIBLE_FINISHED);
 .float superweapons_finished;
 
 .float cnt; // used in too many places
@@ -148,26 +147,26 @@ const float MAX_DAMAGEEXTRARADIUS = 16;
 // string overrides entity
 .string item_pickupsound;
 .entity item_pickupsound_ent;
+.entity item_model_ent;
 
 // definitions for weaponsystem
 // more WEAPONTODO: move these to their proper files
-.entity weaponentity;
 .entity exteriorweaponentity;
 .vector weaponentity_glowmod;
 
 //.int weapon; // current weapon
-.int switchweapon; // weapon requested to switch to
+.int switchweapon = _STAT(SWITCHWEAPON);
 .int switchingweapon; // weapon currently being switched to (is copied from switchweapon once switch is possible)
 .string weaponname; // name of .weapon
 
 // WEAPONTODO
 .float autoswitch;
 float client_hasweapon(entity cl, float wpn, float andammo, float complain);
-void w_clear(Weapon thiswep, entity actor, bool fire1, bool fire2);
-void w_ready(Weapon thiswep, entity actor, bool fire1, bool fire2);
+void w_clear(Weapon thiswep, entity actor, .entity weaponentity, int fire);
+void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire);
 // VorteX: standalone think for weapons, so normal think on weaponentity can be reserved by weaponflashes (which needs update even player dies)
 .float weapon_nextthink;
-.void(Weapon thiswep, entity actor, bool fire1, bool fire2) weapon_think;
+.void(Weapon thiswep, entity actor, .entity weaponentity, int fire) weapon_think;
 
 
 // weapon states (self.weaponentity.state)
@@ -180,7 +179,7 @@ const int WS_READY                  = 4; // idle frame
 // there is 2 weapon tics that can run in one server frame
 const int W_TICSPERFRAME = 2;
 
-void weapon_defaultspawnfunc(float wpn);
+void weapon_defaultspawnfunc(entity this, Weapon e);
 
 float gameover;
 float intermission_running;
@@ -261,14 +260,14 @@ WepSet weaponsInMap;
 
 float bot_waypoints_for_items;
 
-.float attack_finished_for[Weapons_MAX];
-.float attack_finished_single;
-#ifdef INDEPENDENT_ATTACK_FINISHED
-#define ATTACK_FINISHED_FOR(ent,w) ((ent).(attack_finished_for[(w) - WEP_FIRST]))
+.float attack_finished_for[Weapons_MAX * MAX_WEAPONSLOTS];
+.float attack_finished_single[MAX_WEAPONSLOTS];
+#if INDEPENDENT_ATTACK_FINISHED
+#define ATTACK_FINISHED_FOR(ent, w, slot) ((ent).(attack_finished_for[((w) - WEP_FIRST) * MAX_WEAPONSLOTS + (slot)]))
 #else
-#define ATTACK_FINISHED_FOR(ent,w) ((ent).attack_finished_single)
+#define ATTACK_FINISHED_FOR(ent, w, slot) ((ent).attack_finished_single[slot])
 #endif
-#define ATTACK_FINISHED(ent) ATTACK_FINISHED_FOR(ent,(ent).weapon)
+#define ATTACK_FINISHED(ent, slot) ATTACK_FINISHED_FOR(ent, (ent).weapon, slot)
 
 // assault game mode: Which team is attacking in this round?
 float assault_attacker_team;
@@ -302,57 +301,6 @@ float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end)
 
 float next_pingtime;
 
-// player sounds, voice messages
-// TODO implemented fall and falling
-#define ALLPLAYERSOUNDS \
-               _VOICEMSG(death) \
-               _VOICEMSG(drown) \
-               _VOICEMSG(fall) \
-               _VOICEMSG(falling) \
-               _VOICEMSG(gasp) \
-               _VOICEMSG(jump) \
-               _VOICEMSG(pain100) \
-               _VOICEMSG(pain25) \
-               _VOICEMSG(pain50) \
-               _VOICEMSG(pain75)
-
-#define ALLVOICEMSGS \
-               _VOICEMSG(attack) \
-               _VOICEMSG(attackinfive) \
-               _VOICEMSG(coverme) \
-               _VOICEMSG(defend) \
-               _VOICEMSG(freelance) \
-               _VOICEMSG(incoming) \
-               _VOICEMSG(meet) \
-               _VOICEMSG(needhelp) \
-               _VOICEMSG(seenflag) \
-               _VOICEMSG(taunt) \
-               _VOICEMSG(teamshoot)
-
-#define _VOICEMSG(m) .string playersound_##m;
-ALLPLAYERSOUNDS
-ALLVOICEMSGS
-#undef _VOICEMSG
-
-// reserved sound names for the future (some models lack sounds for them):
-//             _VOICEMSG(flagcarriertakingdamage) \
-//             _VOICEMSG(getflag) \
-// reserved sound names for the future (ALL models lack sounds for them):
-//             _VOICEMSG(affirmative) \
-//             _VOICEMSG(attacking) \
-//             _VOICEMSG(defending) \
-//             _VOICEMSG(roaming) \
-//             _VOICEMSG(onmyway) \
-//             _VOICEMSG(droppedflag) \
-//             _VOICEMSG(negative) \
-//             _VOICEMSG(seenenemy) \
-//      /**/
-
-string globalsound_fall;
-string globalsound_metalfall;
-string globalsound_step;
-string globalsound_metalstep;
-
 const float VOICETYPE_PLAYERSOUND = 10;
 const float VOICETYPE_TEAMRADIO = 11;
 const float VOICETYPE_LASTATTACKER = 12;
@@ -360,17 +308,6 @@ const float VOICETYPE_LASTATTACKER_ONLY = 13;
 const float VOICETYPE_AUTOTAUNT = 14;
 const float VOICETYPE_TAUNT = 15;
 
-void PrecachePlayerSounds(string f);
-void PrecacheGlobalSound(string samplestring);
-void UpdatePlayerSounds();
-void ClearPlayerSounds();
-void PlayerSound(.string samplefield, float channel, float voicetype);
-void GlobalSound(string samplestring, float channel, float voicetype);
-void FakeGlobalSound(string samplestring, float channel, float voicetype);
-void VoiceMessage(string type, string message);
-float GetPlayerSoundSampleField_notFound;
-.string GetVoiceMessageSampleField(string type);
-
 // autotaunt system
 .float cvar_cl_autotaunt;
 .float cvar_cl_voice_directional;
@@ -396,7 +333,7 @@ float cvar_purechanges_count;
 
 float game_starttime; //point in time when the countdown to game start is over
 float round_starttime; //point in time when the countdown to round start is over
-.float stat_game_starttime;
+.float stat_game_starttime = _STAT(GAMESTARTTIME);
 .float stat_round_starttime;
 
 void W_Porto_Remove (entity p);
index cf275c0f89aa1b8eb49dd4ec55af3d238fe528b9..9c98e7d99f2ed32ccf7dc631f204bd6ebf3bcfe8 100644 (file)
@@ -19,7 +19,7 @@ float entcs_customize()
 
 bool entcs_send(entity this, entity to, int sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_ENTCS);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_ENTCS);
        WriteByte(MSG_ENTITY, sf);
        if(sf & BIT(0))
                WriteByte(MSG_ENTITY, num_for_edict(self.owner) - 1);
@@ -68,6 +68,7 @@ void entcs_think()
 entity attach_entcs(entity e)
 {
        entity ent = e.entcs = new(entcs_sender);
+       make_pure(ent);
        ent.owner = e;
        ent.think = entcs_think;
        ent.nextthink = time;
index 802eabd7fd7219d12b8eea680b1985e3eddfec2b..147c03ca26e60a4a1d64eea44fae528544ca74a6 100644 (file)
@@ -12,7 +12,6 @@
 #include "weapons/accuracy.qh"
 #include "weapons/csqcprojectile.qh"
 #include "weapons/selection.qh"
-#include "../common/buffs/all.qh"
 #include "../common/constants.qh"
 #include "../common/deathtypes/all.qh"
 #include "../common/notifications.qh"
 #include "../lib/csqcmodel/sv_model.qh"
 #include "../lib/warpzone/common.qh"
 
-bool Damage_DamageInfo_SendEntity(entity this, entity to, int sf)
-{
-       WriteByte(MSG_ENTITY, ENT_CLIENT_DAMAGEINFO);
-       WriteShort(MSG_ENTITY, self.projectiledeathtype);
-       WriteCoord(MSG_ENTITY, floor(self.origin.x));
-       WriteCoord(MSG_ENTITY, floor(self.origin.y));
-       WriteCoord(MSG_ENTITY, floor(self.origin.z));
-       WriteByte(MSG_ENTITY, bound(1, self.dmg, 255));
-       WriteByte(MSG_ENTITY, bound(0, self.dmg_radius, 255));
-       WriteByte(MSG_ENTITY, bound(1, self.dmg_edge, 255));
-       WriteShort(MSG_ENTITY, self.oldorigin.x);
-       WriteByte(MSG_ENTITY, self.species);
-       return true;
-}
-
-void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, int deathtype, float bloodtype, entity dmgowner)
-{
-       // TODO maybe call this from non-edgedamage too?
-       // TODO maybe make the client do the particle effects for the weapons and the impact sounds using this info?
-
-       entity e;
-
-       if(!sound_allowed(MSG_BROADCAST, dmgowner))
-               deathtype |= 0x8000;
-
-       e = spawn();
-       setorigin(e, org);
-       e.projectiledeathtype = deathtype;
-       e.dmg = coredamage;
-       e.dmg_edge = edgedamage;
-       e.dmg_radius = rad;
-       e.dmg_force = vlen(force);
-       e.velocity = force;
-       e.oldorigin_x = compressShortVector(e.velocity);
-       e.species = bloodtype;
-
-       Net_LinkEntity(e, false, 0.2, Damage_DamageInfo_SendEntity);
-}
-
 void UpdateFrags(entity player, float f)
 {
        PlayerTeamScore_AddScore(player, f);
@@ -114,8 +74,7 @@ void GiveFrags (entity attacker, entity targ, float f, int deathtype)
                {
                        if(!GiveFrags_randomweapons)
                        {
-                               GiveFrags_randomweapons = spawn();
-                               GiveFrags_randomweapons.classname = "GiveFrags_randomweapons";
+                               GiveFrags_randomweapons = new(GiveFrags_randomweapons);
                        }
 
                        if(warmup_stage)
@@ -204,7 +163,7 @@ void Obituary_SpecialDeath(
 {
        if(DEATH_ISSPECIAL(deathtype))
        {
-               entity deathent = Deathtypes[deathtype - DT_FIRST];
+               entity deathent = Deathtypes_from(deathtype - DT_FIRST);
                if (!deathent) { backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n"); return; }
 
                if(murder)
@@ -302,6 +261,8 @@ float Obituary_WeaponDeath(
        return false;
 }
 
+.int buffs; // TODO: remove
+
 void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
 {
        // Sanity check
@@ -563,10 +524,8 @@ void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypo
        targ.revive_speed = freeze_time;
        self.bot_attack = false;
 
-       entity ice, head;
-       ice = spawn();
+       entity ice = new(ice);
        ice.owner = targ;
-       ice.classname = "ice";
        ice.scale = targ.scale;
        ice.think = Ice_Think;
        ice.nextthink = time;
@@ -582,6 +541,7 @@ void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypo
 
        RemoveGrapplingHook(targ);
 
+       entity head;
        FOR_EACH_PLAYER(head)
        if(head.hook.aiment == targ)
                RemoveGrapplingHook(head);
@@ -889,9 +849,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
                vector farce = damage_explosion_calcpush(self.damageforcescale * force, self.velocity, autocvar_g_balance_damagepush_speedfactor);
                if(self.movetype == MOVETYPE_PHYSICS)
                {
-                       entity farcent;
-                       farcent = spawn();
-                       farcent.classname = "farce";
+                       entity farcent = new(farce);
                        farcent.enemy = self;
                        farcent.movedir = farce * 10;
                        if(self.mass)
@@ -1140,8 +1098,7 @@ float Fire_AddDamage(entity e, entity o, float d, float t, float dt)
                if(!e.fire_burner)
                {
                        // print("adding a fire burner to ", e.classname, "\n");
-                       e.fire_burner = spawn();
-                       e.fire_burner.classname = "fireburner";
+                       e.fire_burner = new(fireburner);
                        e.fire_burner.think = fireburner_think;
                        e.fire_burner.nextthink = time;
                        e.fire_burner.owner = e;
index f95115a2ca465a8f8fbe01679da18eed973229a6..99bd819495bd9949394e05f2cc34c95e4d361b8e 100644 (file)
@@ -80,7 +80,7 @@ void RemoveGrapplingHook(entity pl)
        //pl.disableclientprediction = false;
 }
 
-void GrapplingHookReset(void)
+void GrapplingHookReset()
 {SELFPARAM();
        if(self.realowner.hook == self)
                RemoveGrapplingHook(self.owner);
@@ -106,7 +106,7 @@ void GrapplingHook_Stop()
 .vector hook_start, hook_end;
 bool GrapplingHookSend(entity this, entity to, int sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_HOOK);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_HOOK);
        sf = sf & 0x7F;
        if(sound_allowed(MSG_BROADCAST, self.realowner))
                sf |= 0x80;
@@ -299,7 +299,7 @@ void GrapplingHookThink()
        }
 }
 
-void GrapplingHookTouch (void)
+void GrapplingHookTouch ()
 {SELFPARAM();
        if(other.movetype == MOVETYPE_FOLLOW)
                return;
@@ -339,7 +339,7 @@ void GrapplingHook_Damage (entity inflictor, entity attacker, float damage, int
        }
 }
 
-void FireGrapplingHook (void)
+void FireGrapplingHook ()
 {SELFPARAM();
        entity missile;
        vector org;
index f9f4083e3475786fc617e77e08941bef1bf5055d..46ebe5ed89476348bc9411ba75c207153389d2b0 100644 (file)
@@ -15,7 +15,7 @@ class(BGMScript) .float bgmscriptrelease;
 
 .float modelscale;
 
-void g_model_setcolormaptoactivator (void)
+void g_model_setcolormaptoactivator ()
 {SELFPARAM();
        if(teamplay)
        {
@@ -29,13 +29,13 @@ void g_model_setcolormaptoactivator (void)
        self.colormap |= BIT(10); // RENDER_COLORMAPPED
 }
 
-void g_clientmodel_setcolormaptoactivator (void)
+void g_clientmodel_setcolormaptoactivator ()
 {SELFPARAM();
        g_model_setcolormaptoactivator();
        self.SendFlags |= (BIT(3) | BIT(0));
 }
 
-void g_clientmodel_use(void)
+void g_clientmodel_use()
 {SELFPARAM();
        if (self.antiwall_flag == 1)
        {
@@ -90,23 +90,23 @@ bool g_clientmodel_genericsendentity(entity this, entity to, int sf)
        if(self.lodmodelindex1)
                sf |= 0x80;
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_WALL);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_WALL);
        WriteByte(MSG_ENTITY, sf);
 
-       if(sf & 1)
+       if(sf & BIT(0))
        {
                if(sf & 0x40)
                        WriteShort(MSG_ENTITY, self.colormap);
        }
 
-       if(sf & 2)
+       if(sf & BIT(1))
        {
                WriteCoord(MSG_ENTITY, self.origin.x);
                WriteCoord(MSG_ENTITY, self.origin.y);
                WriteCoord(MSG_ENTITY, self.origin.z);
        }
 
-       if(sf & 4)
+       if(sf & BIT(2))
        {
                if(sf & 0x10)
                {
@@ -116,7 +116,7 @@ bool g_clientmodel_genericsendentity(entity this, entity to, int sf)
                }
        }
 
-       if(sf & 8)
+       if(sf & BIT(3))
        {
                if(sf & 0x80)
                {
index 41bac7a43f9d896b20ea0639e059092d6b635596..f2e3da898645ddfb755f0bd852e7a077988efa94 100644 (file)
@@ -62,7 +62,7 @@ main
 unused but required by the engine
 ==================
 */
-void main (void)
+void main ()
 {
 
 }
index c9d1264c07721897a7b84b9665b8cb6d98749fcf..a50885a7fe45f34208b8c7eea2f57d3382cfa10e 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef G_SUBS_H
 #define G_SUBS_H
 
-void SUB_NullThink(void);
+void SUB_NullThink();
 
 void()  SUB_CalcMoveDone;
 void() SUB_CalcAngleMoveDone;
@@ -21,7 +21,7 @@ SUB_Remove
 Remove self
 ==================
 */
-void SUB_Remove (void);
+void SUB_Remove ();
 
 /*
 ==================
@@ -31,7 +31,7 @@ Applies some friction to self
 ==================
 */
 .float friction;
-void SUB_Friction (void);
+void SUB_Friction ();
 
 /*
 ==================
@@ -42,7 +42,7 @@ Makes client invisible or removes non-client
 */
 void SUB_VanishOrRemove (entity ent);
 
-void SUB_SetFade_Think (void);
+void SUB_SetFade_Think ();
 
 /*
 ==================
@@ -61,10 +61,10 @@ calculate self.velocity and self.nextthink to reach dest from
 self.origin traveling at speed
 ===============
 */
-void SUB_CalcMoveDone (void);
+void SUB_CalcMoveDone ();
 
 .float platmovetype_turn;
-void SUB_CalcMove_controller_think (void);
+void SUB_CalcMove_controller_think ();
 
 void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector dest);
 
@@ -86,7 +86,7 @@ self.angles rotating
 The calling function should make sure self.think is valid
 ===============
 */
-void SUB_CalcAngleMoveDone (void);
+void SUB_CalcAngleMoveDone ();
 
 // FIXME: I fixed this function only for rotation around the main axes
 void SUB_CalcAngleMove (vector destangle, float tspeedtype, float tspeed, void() func);
@@ -100,7 +100,7 @@ main
 unused but required by the engine
 ==================
 */
-void main (void);
+void main ();
 
 // Misc
 
@@ -135,15 +135,6 @@ Ripped from DPMod
 */
 vector findbetterlocation (vector org, float mindist);
 
-/*
-==================
-crandom
-
-Returns a random number between -1.0 and 1.0
-==================
-*/
-float crandom (void);
-
 /*
 ==================
 Angc used for animations
diff --git a/qcsrc/server/g_violence.qc b/qcsrc/server/g_violence.qc
deleted file mode 100644 (file)
index b016acd..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "g_violence.qh"
-
-.int state;
-
-bool Violence_GibSplash_SendEntity(entity this, entity to, int sf)
-{
-       WriteByte(MSG_ENTITY, ENT_CLIENT_GIBSPLASH);
-       WriteByte(MSG_ENTITY, self.state); // actually type
-       WriteByte(MSG_ENTITY, bound(1, self.cnt * 16, 255)); // gibbage amount multiplier
-       WriteShort(MSG_ENTITY, floor(self.origin.x / 4)); // not using a coord here, as gibs don't need this accuracy
-       WriteShort(MSG_ENTITY, floor(self.origin.y / 4)); // not using a coord here, as gibs don't need this accuracy
-       WriteShort(MSG_ENTITY, floor(self.origin.z / 4)); // not using a coord here, as gibs don't need this accuracy
-       WriteShort(MSG_ENTITY, self.oldorigin.x); // acrually compressed velocity
-       return true;
-}
-
-// TODO maybe convert this to a TE?
-void Violence_GibSplash_At(vector org, vector dir, float type, float amount, entity gibowner, entity attacker)
-{SELFPARAM();
-       if(g_cts) // no gibs in CTS
-               return;
-
-       entity e;
-
-       e = spawn();
-       e.classname = "gibsplash";
-       e.cnt = amount;
-       e.state = type; // should stay smaller than 15
-       if(!sound_allowed(MSG_BROADCAST, gibowner) || !sound_allowed(MSG_BROADCAST, attacker))
-               e.state |= 0x40; // "silence" bit
-       e.state |= 8 * self.species; // gib type, ranges from 0 to 15
-
-       // if this is a copied dead body, send the num of its player instead
-       // TODO: remove this field, read from model txt files
-       if(self.classname == "body")
-               e.team = num_for_edict(self.enemy);
-       else
-               e.team = num_for_edict(self);
-
-       setorigin(e, org);
-       e.velocity = dir;
-
-       e.oldorigin_x = compressShortVector(e.velocity);
-
-       Net_LinkEntity(e, false, 0.2, Violence_GibSplash_SendEntity);
-}
-
-void Violence_GibSplash(entity source, float type, float amount, entity attacker)
-{
-       Violence_GibSplash_At(source.origin + source.view_ofs, source.velocity, type, amount, source, attacker);
-}
diff --git a/qcsrc/server/g_violence.qh b/qcsrc/server/g_violence.qh
deleted file mode 100644 (file)
index 6a33ac4..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef G_VIOLENCE_H
-#define G_VIOLENCE_H
-
-bool Violence_GibSplash_SendEntity(entity this, entity to, int sf);
-
-// TODO maybe convert this to a TE?
-void Violence_GibSplash_At(vector org, vector dir, float type, float amount, entity gibowner, entity attacker);
-
-void Violence_GibSplash(entity source, float type, float amount, entity attacker);
-#endif
index c706a1bdd5ad4288a89d81930af3ee97a743354b..85f1ce163bc72edaf028cc1c9d153c833b8ace03 100644 (file)
@@ -18,7 +18,6 @@
 #include "scores.qh"
 #include "teamplay.qh"
 #include "weapons/weaponstats.qh"
-#include "../common/buffs/all.qh"
 #include "../common/constants.qh"
 #include "../common/deathtypes/all.qh"
 #include "../common/mapinfo.qh"
@@ -54,8 +53,7 @@ void PingPLReport_Think()
        e = edict_num(self.cnt + 1);
        if(IS_REAL_CLIENT(e))
        {
-               WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-               WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
+               WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
                WriteByte(MSG_BROADCAST, self.cnt);
                WriteShort(MSG_BROADCAST, max(1, e.ping));
                WriteByte(MSG_BROADCAST, ceil(e.ping_packetloss * 255));
@@ -72,8 +70,7 @@ void PingPLReport_Think()
        }
        else
        {
-               WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-               WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
+               WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
                WriteByte(MSG_BROADCAST, self.cnt);
                WriteShort(MSG_BROADCAST, 0);
                WriteByte(MSG_BROADCAST, 0);
@@ -83,8 +80,8 @@ void PingPLReport_Think()
 }
 void PingPLReport_Spawn()
 {
-       pingplreport = spawn();
-       pingplreport.classname = "pingplreport";
+       pingplreport = new(pingplreport);
+       make_pure(pingplreport);
        pingplreport.think = PingPLReport_Think;
        pingplreport.nextthink = time;
 }
@@ -98,17 +95,7 @@ void ShuffleMaplist();
 
 void SetDefaultAlpha()
 {
-       if(autocvar_g_running_guns)
-       {
-               default_player_alpha = -1;
-               default_weapon_alpha = +1;
-       }
-       else if(g_cloaked)
-       {
-               default_player_alpha = autocvar_g_balance_cloaked_alpha;
-               default_weapon_alpha = default_player_alpha;
-       }
-       else
+       if (!MUTATOR_CALLHOOK(SetDefaultAlpha))
        {
                default_player_alpha = autocvar_g_player_alpha;
                if(default_player_alpha == 0)
@@ -515,7 +502,7 @@ void detect_maptype()
 entity randomseed;
 bool RandomSeed_Send(entity this, entity to, int sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
        WriteShort(MSG_ENTITY, self.cnt);
        return true;
 }
@@ -528,7 +515,8 @@ void RandomSeed_Think()
 }
 void RandomSeed_Spawn()
 {SELFPARAM();
-       randomseed = spawn();
+       randomseed = new(randomseed);
+       make_pure(randomseed);
        randomseed.think = RandomSeed_Think;
        Net_LinkEntity(randomseed, false, 0, RandomSeed_Send);
 
@@ -546,19 +534,18 @@ spawnfunc(__init_dedicated_server)
 
        remove = remove_unsafely;
 
-       entity e;
-       e = spawn();
+       entity e = spawn();
        e.think = GotoFirstMap;
        e.nextthink = time; // this is usually 1 at this point
 
-       e = spawn();
-       e.classname = "info_player_deathmatch"; // safeguard against player joining
+       e = new(info_player_deathmatch);  // safeguard against player joining
 
        self.classname = "worldspawn"; // safeguard against various stuff ;)
 
        // needs to be done so early because of the constants they create
        static_init();
        static_init_late();
+       static_init_precache();
 
        MapInfo_Enumerate();
        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
@@ -658,6 +645,7 @@ spawnfunc(worldspawn)
 
        InitGameplayMode();
        static_init_late();
+       static_init_precache();
        readlevelcvars();
        GrappleHookInit();
 
@@ -768,15 +756,11 @@ spawnfunc(worldspawn)
 
        WepSet_AddStat();
        WepSet_AddStat_InMap();
-       addstat(STAT_SWITCHWEAPON, AS_INT, switchweapon);
        addstat(STAT_SWITCHINGWEAPON, AS_INT, switchingweapon);
-       addstat(STAT_GAMESTARTTIME, AS_FLOAT, stat_game_starttime);
        addstat(STAT_ROUNDSTARTTIME, AS_FLOAT, stat_round_starttime);
        addstat(STAT_ALLOW_OLDVORTEXBEAM, AS_INT, stat_allow_oldvortexbeam);
        Nagger_Init();
 
-       addstat(STAT_STRENGTH_FINISHED, AS_FLOAT, strength_finished);
-       addstat(STAT_INVINCIBLE_FINISHED, AS_FLOAT, invincible_finished);
        addstat(STAT_SUPERWEAPONS_FINISHED, AS_FLOAT, superweapons_finished);
        addstat(STAT_PRESSED_KEYS, AS_FLOAT, pressedkeys);
        addstat(STAT_FUEL, AS_INT, ammo_fuel);
@@ -796,8 +780,6 @@ spawnfunc(worldspawn)
 
        addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
 
-       addstat(STAT_ARC_HEAT, AS_FLOAT, arc_heat_percent);
-
        // freeze attacks
        addstat(STAT_FROZEN, AS_INT, frozen);
        addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, revive_progress);
@@ -1476,7 +1458,6 @@ void DumpStats(float final)
 
 void FixIntermissionClient(entity e)
 {
-       string s;
        if(!e.autoscreenshot) // initial call
        {
                e.autoscreenshot = time + 0.8;  // used for autoscreenshot
@@ -1485,18 +1466,24 @@ void FixIntermissionClient(entity e)
                e.solid = SOLID_NOT;
                e.movetype = MOVETYPE_NONE;
                e.takedamage = DAMAGE_NO;
-               if(e.weaponentity)
+               for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
-                       e.weaponentity.effects = EF_NODRAW;
-                       if (e.weaponentity.weaponentity)
-                               e.weaponentity.weaponentity.effects = EF_NODRAW;
+                   .entity weaponentity = weaponentities[slot];
+                       if(e.(weaponentity))
+                       {
+                               e.(weaponentity).effects = EF_NODRAW;
+                               if (e.(weaponentity).(weaponentity))
+                                       e.(weaponentity).(weaponentity).effects = EF_NODRAW;
+                       }
                }
                if(IS_REAL_CLIENT(e))
                {
                        stuffcmd(e, "\nscr_printspeed 1000000\n");
-                       s = autocvar_sv_intermission_cdtrack;
-                       if(s != "")
-                               stuffcmd(e, strcat("\ncd loop ", s, "\n"));
+                       string list = autocvar_sv_intermission_cdtrack;
+                       for(string it; (it = car(list)); list = cdr(list))
+                               RandomSelection_Add(world, 0, it, 1, 1);
+                       if(RandomSelection_chosen_string && RandomSelection_chosen_string != "")
+                               stuffcmd(e, strcat("\ncd loop ", RandomSelection_chosen_string, "\n"));
                        msg_entity = e;
                        WriteByte(MSG_ONE, SVC_INTERMISSION);
                }
@@ -1657,7 +1644,7 @@ void AddWinners(.float field, float value)
 }
 
 // clear the .winning flags
-void ClearWinners(void)
+void ClearWinners()
 {
        entity head;
        FOR_EACH_PLAYER(head)
diff --git a/qcsrc/server/generator.qc b/qcsrc/server/generator.qc
deleted file mode 100644 (file)
index 2a1c0b2..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "generator.qh"
-
-bool generator_send(entity this, entity to, int sf)
-{
-       WriteByte(MSG_ENTITY, ENT_CLIENT_GENERATOR);
-       WriteByte(MSG_ENTITY, sf);
-       if(sf & GSF_SETUP)
-       {
-               WriteCoord(MSG_ENTITY, self.origin_x);
-               WriteCoord(MSG_ENTITY, self.origin_y);
-               WriteCoord(MSG_ENTITY, self.origin_z);
-
-               WriteByte(MSG_ENTITY, self.health);
-               WriteByte(MSG_ENTITY, self.max_health);
-               WriteByte(MSG_ENTITY, self.count);
-               WriteByte(MSG_ENTITY, self.team);
-       }
-
-       if(sf & GSF_STATUS)
-       {
-               WriteByte(MSG_ENTITY, self.team);
-
-               if(self.health <= 0)
-                       WriteByte(MSG_ENTITY, 0);
-               else
-                       WriteByte(MSG_ENTITY, ceil((self.health / self.max_health) * 255));
-       }
-
-       return true;
-}
-
-void generator_link(void() spawnproc)
-{SELFPARAM();
-       Net_LinkEntity(self, true, 0, generator_send);
-       self.think              = spawnproc;
-       self.nextthink  = time;
-}
diff --git a/qcsrc/server/generator.qh b/qcsrc/server/generator.qh
deleted file mode 100644 (file)
index 003c2b1..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef GENERATOR_H
-#define GENERATOR_H
-const vector GENERATOR_MIN = '-52 -52 -14';
-const vector GENERATOR_MAX = '52 52 75';
-
-const int GSF_STATUS = 4;
-const int GSF_SETUP = 8;
-
-bool generator_send(entity this, entity to, int sf);
-#endif
index a60970d21af00b73d7d9fe72891ec2c60649cdca..7463fefbeafe827a9515660477849fb7030087f1 100644 (file)
@@ -318,9 +318,7 @@ void Ban_LoadBans()
                }
        }
 
-       entity e;
-       e = spawn();
-       e.classname = "bansyncer";
+       entity e = new(bansyncer);
        e.think = OnlineBanList_Think;
        e.nextthink = time + 1;
 }
index 5ab3c8df22626eceb373246a94621684bb2e3ea7..d1e1f32e429e53bb7c3a1d534860d00896e6ecdd 100644 (file)
@@ -239,7 +239,7 @@ spawnfunc(item_key)
                self.message = strzone(strcat("You've picked up the ", self.netname, "!"));
 
        if (self.noise == "")
-               self.noise = SND(ITEMPICKUP);
+               self.noise = strzone(SND(ITEMPICKUP));
 
        // save the name for later
        item_keys_names[lowestbit(self.itemkeys)] = self.netname;
index 5a9f7e0765c85e5a66e6d4ada2da8048b02fd597..ed17d86e8e2a26ddc97cf47bde011cbc65649766 100644 (file)
@@ -264,8 +264,7 @@ void MapVote_Init()
 void MapVote_SendPicture(float id)
 {SELFPARAM();
        msg_entity = self;
-       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-       WriteByte(MSG_ONE, TE_CSQC_PICTURE);
+       WriteHeader(MSG_ONE, TE_CSQC_PICTURE);
        WriteByte(MSG_ONE, id);
        WritePicture(MSG_ONE, strcat(mapvote_screenshot_dirs[mapvote_maps_screenshot_dir[id]], "/", mapvote_maps[id]), 3072);
 }
@@ -349,7 +348,7 @@ bool MapVote_SendEntity(entity this, entity to, int sf)
        if(sf & 1)
                sf &= ~2; // if we send 1, we don't need to also send 2
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_MAPVOTE);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_MAPVOTE);
        WriteByte(MSG_ENTITY, sf);
 
        if(sf & 1)
index 3a4680ebb94366867b11d1c9c11829e055302eec..d12a903778571195c13999e904daa605330ba24d 100644 (file)
@@ -52,7 +52,7 @@ void WarpZone_crosshair_trace(entity pl)
 }
 
 
-string admin_name(void)
+string admin_name()
 {
        if(autocvar_sv_adminnick != "")
                return autocvar_sv_adminnick;
@@ -60,40 +60,6 @@ string admin_name(void)
                return "SERVER ADMIN";
 }
 
-void DistributeEvenly_Init(float amount, float totalweight)
-{
-    if (DistributeEvenly_amount)
-    {
-        LOG_TRACE("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
-        LOG_TRACE(ftos(DistributeEvenly_totalweight), " left!)\n");
-    }
-    if (totalweight == 0)
-        DistributeEvenly_amount = 0;
-    else
-        DistributeEvenly_amount = amount;
-    DistributeEvenly_totalweight = totalweight;
-}
-float DistributeEvenly_Get(float weight)
-{
-    float f;
-    if (weight <= 0)
-        return 0;
-    f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
-    DistributeEvenly_totalweight -= weight;
-    DistributeEvenly_amount -= f;
-    return f;
-}
-float DistributeEvenly_GetRandomized(float weight)
-{
-    float f;
-    if (weight <= 0)
-        return 0;
-    f = floor(random() + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
-    DistributeEvenly_totalweight -= weight;
-    DistributeEvenly_amount -= f;
-    return f;
-}
-
 
 void GameLogEcho(string s)
 {
@@ -296,7 +262,7 @@ string formatmessage(string msg)
                        case "l": replacement = NearestLocation(self.origin); break;
                        case "y": replacement = NearestLocation(cursor); break;
                        case "d": replacement = NearestLocation(self.death_origin); break;
-                       case "w": replacement = WEP_NAME((!self.weapon) ? (!self.switchweapon ? self.cnt : self.switchweapon) : self.weapon); break;
+                       case "w": replacement = WEP_NAME(((!self.weapon) ? (!self.switchweapon ? self.cnt : self.switchweapon) : self.weapon)); break;
                        case "W": replacement = ammoitems; break;
                        case "x": replacement = ((cursor_ent.netname == "" || !cursor_ent) ? "nothing" : cursor_ent.netname); break;
                        case "s": replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1')); break;
@@ -446,11 +412,6 @@ void GetCvars(float f)
        GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
        GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
        GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
-       GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
-       GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
-
-       self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
-       self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
 
        GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
        GetCvars_handleFloat(s, f, cvar_cl_allow_uid2name, "cl_allow_uid2name");
@@ -601,7 +562,7 @@ void readplayerstartcvars()
                                if (e.netname == s)
                                {
                                        g_weaponarena_weapons |= WepSet_FromWeapon(j);
-                                       g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
+                                       g_weaponarena_list = strcat(g_weaponarena_list, e.m_name, " & ");
                                        break;
                                }
                        }
@@ -742,183 +703,6 @@ void readplayerstartcvars()
        warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
 }
 
-float sound_allowed(float destin, entity e)
-{
-    // sounds from world may always pass
-    for (;;)
-    {
-        if (e.classname == "body")
-            e = e.enemy;
-       else if (e.realowner && e.realowner != e)
-            e = e.realowner;
-       else if (e.owner && e.owner != e)
-            e = e.owner;
-        else
-            break;
-    }
-    // sounds to self may always pass
-    if (destin == MSG_ONE)
-        if (e == msg_entity)
-            return true;
-    // sounds by players can be removed
-    if (autocvar_bot_sound_monopoly)
-        if (IS_REAL_CLIENT(e))
-            return false;
-    // anything else may pass
-    return true;
-}
-
-void soundtoat(float _dest, entity e, vector o, float chan, string samp, float vol, float attenu)
-{
-    float entno, idx;
-
-    if (!sound_allowed(_dest, e))
-        return;
-
-    entno = num_for_edict(e);
-    idx = precache_sound_index(samp);
-
-    int sflags;
-    sflags = 0;
-
-    attenu = floor(attenu * 64);
-    vol = floor(vol * 255);
-
-    if (vol != 255)
-        sflags |= SND_VOLUME;
-    if (attenu != 64)
-        sflags |= SND_ATTENUATION;
-    if (entno >= 8192 || chan < 0 || chan > 7)
-        sflags |= SND_LARGEENTITY;
-    if (idx >= 256)
-        sflags |= SND_LARGESOUND;
-
-    WriteByte(_dest, SVC_SOUND);
-    WriteByte(_dest, sflags);
-    if (sflags & SND_VOLUME)
-        WriteByte(_dest, vol);
-    if (sflags & SND_ATTENUATION)
-        WriteByte(_dest, attenu);
-    if (sflags & SND_LARGEENTITY)
-    {
-        WriteShort(_dest, entno);
-        WriteByte(_dest, chan);
-    }
-    else
-    {
-        WriteShort(_dest, entno * 8 + chan);
-    }
-    if (sflags & SND_LARGESOUND)
-        WriteShort(_dest, idx);
-    else
-        WriteByte(_dest, idx);
-
-    WriteCoord(_dest, o.x);
-    WriteCoord(_dest, o.y);
-    WriteCoord(_dest, o.z);
-}
-void soundto(float _dest, entity e, float chan, string samp, float vol, float _atten)
-{
-    vector o;
-
-    if (!sound_allowed(_dest, e))
-        return;
-
-    o = e.origin + 0.5 * (e.mins + e.maxs);
-    soundtoat(_dest, e, o, chan, samp, vol, _atten);
-}
-void soundat(entity e, vector o, float chan, string samp, float vol, float _atten)
-{
-    soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, _atten);
-}
-void stopsoundto(float _dest, entity e, float chan)
-{
-    float entno;
-
-    if (!sound_allowed(_dest, e))
-        return;
-
-    entno = num_for_edict(e);
-
-    if (entno >= 8192 || chan < 0 || chan > 7)
-    {
-        float idx, sflags;
-        idx = precache_sound_index(SND(Null));
-        sflags = SND_LARGEENTITY;
-        if (idx >= 256)
-            sflags |= SND_LARGESOUND;
-        WriteByte(_dest, SVC_SOUND);
-        WriteByte(_dest, sflags);
-        WriteShort(_dest, entno);
-        WriteByte(_dest, chan);
-        if (sflags & SND_LARGESOUND)
-            WriteShort(_dest, idx);
-        else
-            WriteByte(_dest, idx);
-        WriteCoord(_dest, e.origin.x);
-        WriteCoord(_dest, e.origin.y);
-        WriteCoord(_dest, e.origin.z);
-    }
-    else
-    {
-        WriteByte(_dest, SVC_STOPSOUND);
-        WriteShort(_dest, entno * 8 + chan);
-    }
-}
-void stopsound(entity e, float chan)
-{
-    if (!sound_allowed(MSG_BROADCAST, e))
-        return;
-
-    stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
-    stopsoundto(MSG_ALL, e, chan); // in case of packet loss
-}
-
-void play2(entity e, string filename)
-{
-    //stuffcmd(e, strcat("play2 ", filename, "\n"));
-    msg_entity = e;
-    soundtoat(MSG_ONE, world, '0 0 0', CH_INFO, filename, VOL_BASE, ATTEN_NONE);
-}
-
-// use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
-.float spamtime;
-float spamsound(entity e, float chan, string samp, float vol, float _atten)
-{
-    if (!sound_allowed(MSG_BROADCAST, e))
-        return false;
-
-    if (time > e.spamtime)
-    {
-        e.spamtime = time;
-        _sound(e, chan, samp, vol, _atten);
-        return true;
-    }
-    return false;
-}
-
-void play2team(float t, string filename)
-{
-    entity head;
-
-    if (autocvar_bot_sound_monopoly)
-        return;
-
-    FOR_EACH_REALPLAYER(head)
-    {
-        if (head.team == t)
-            play2(head, filename);
-    }
-}
-
-void play2all(string samp)
-{
-    if (autocvar_bot_sound_monopoly)
-        return;
-
-    _sound(world, CH_INFO, samp, VOL_BASE, ATTEN_NONE);
-}
-
 void PrecachePlayerSounds(string f);
 void precache_playermodel(string m)
 {
@@ -1003,16 +787,6 @@ void precache()
                precache_playermodels(autocvar_sv_defaultplayermodel);
     }
 
-    if (g_footsteps)
-    {
-        PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
-        PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
-    }
-
-    // gore and miscellaneous sounds
-    PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
-    PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
-
 #if 0
     // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
 
@@ -1087,7 +861,7 @@ void remove_safely(entity e)
     builtin_remove(e);
 }
 
-void InitializeEntity(entity e, void(void) func, float order)
+void InitializeEntity(entity e, void() func, float order)
 {
     entity prev, cur;
 
@@ -1163,7 +937,7 @@ bool EliminatedPlayers_SendEntity(entity this, entity to, float sendflags)
 {
        float i, f, b;
        entity e;
-       WriteByte(MSG_ENTITY, ENT_CLIENT_ELIMINATEDPLAYERS);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_ELIMINATEDPLAYERS);
        WriteByte(MSG_ENTITY, sendflags);
 
        if(sendflags & 1)
@@ -1346,7 +1120,7 @@ float WarpZone_Projectile_Touch_ImpactFilter_Callback()
        return false;
 }
 
-
+/** engine callback */
 void URI_Get_Callback(float id, float status, string data)
 {
        if(url_URI_Get_Callback(id, status, data))
@@ -1603,151 +1377,6 @@ vector gettaginfo_relative(entity e, float tag)
     return gettaginfo(gettaginfo_relative_ent, tag);
 }
 
-.float scale2;
-
-bool modeleffect_SendEntity(entity this, entity to, int sf)
-{
-       float f;
-       WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
-
-       f = 0;
-       if(self.velocity != '0 0 0')
-               f |= 1;
-       if(self.angles != '0 0 0')
-               f |= 2;
-       if(self.avelocity != '0 0 0')
-               f |= 4;
-
-       WriteByte(MSG_ENTITY, f);
-       WriteShort(MSG_ENTITY, self.modelindex);
-       WriteByte(MSG_ENTITY, self.skin);
-       WriteByte(MSG_ENTITY, self.frame);
-       WriteCoord(MSG_ENTITY, self.origin.x);
-       WriteCoord(MSG_ENTITY, self.origin.y);
-       WriteCoord(MSG_ENTITY, self.origin.z);
-       if(f & 1)
-       {
-               WriteCoord(MSG_ENTITY, self.velocity.x);
-               WriteCoord(MSG_ENTITY, self.velocity.y);
-               WriteCoord(MSG_ENTITY, self.velocity.z);
-       }
-       if(f & 2)
-       {
-               WriteCoord(MSG_ENTITY, self.angles.x);
-               WriteCoord(MSG_ENTITY, self.angles.y);
-               WriteCoord(MSG_ENTITY, self.angles.z);
-       }
-       if(f & 4)
-       {
-               WriteCoord(MSG_ENTITY, self.avelocity.x);
-               WriteCoord(MSG_ENTITY, self.avelocity.y);
-               WriteCoord(MSG_ENTITY, self.avelocity.z);
-       }
-       WriteShort(MSG_ENTITY, self.scale * 256.0);
-       WriteShort(MSG_ENTITY, self.scale2 * 256.0);
-       WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
-       WriteByte(MSG_ENTITY, self.fade_time * 100.0);
-       WriteByte(MSG_ENTITY, self.alpha * 255.0);
-
-       return true;
-}
-
-void modeleffect_spawn(string m, float s, float f, vector o, vector v, vector ang, vector angv, float s0, float s2, float a, float t1, float t2)
-{
-       entity e;
-       float sz;
-       e = spawn();
-       e.classname = "modeleffect";
-       _setmodel(e, m);
-       e.frame = f;
-       setorigin(e, o);
-       e.velocity = v;
-       e.angles = ang;
-       e.avelocity = angv;
-       e.alpha = a;
-       e.teleport_time = t1;
-       e.fade_time = t2;
-       e.skin = s;
-       if(s0 >= 0)
-               e.scale = s0 / max6(-e.mins.x, -e.mins.y, -e.mins.z, e.maxs.x, e.maxs.y, e.maxs.z);
-       else
-               e.scale = -s0;
-       if(s2 >= 0)
-               e.scale2 = s2 / max6(-e.mins.x, -e.mins.y, -e.mins.z, e.maxs.x, e.maxs.y, e.maxs.z);
-       else
-               e.scale2 = -s2;
-       sz = max(e.scale, e.scale2);
-       setsize(e, e.mins * sz, e.maxs * sz);
-       Net_LinkEntity(e, false, 0.1, modeleffect_SendEntity);
-}
-
-void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
-{
-       return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
-}
-
-float randombit(float bits)
-{
-       if(!(bits & (bits-1))) // this ONLY holds for powers of two!
-               return bits;
-
-       float n, f, b, r;
-
-       r = random();
-       b = 0;
-       n = 0;
-
-       for(f = 1; f <= bits; f *= 2)
-       {
-               if(bits & f)
-               {
-                       ++n;
-                       r *= n;
-                       if(r <= 1)
-                               b = f;
-                       else
-                               r = (r - 1) / (n - 1);
-               }
-       }
-
-       return b;
-}
-
-float randombits(float bits, float k, float error_return)
-{
-       float r;
-       r = 0;
-       while(k > 0 && bits != r)
-       {
-               r += randombit(bits - r);
-               --k;
-       }
-       if(error_return)
-               if(k > 0)
-                       return -1; // all
-       return r;
-}
-
-void randombit_test(float bits, float iter)
-{
-       while(iter > 0)
-       {
-               LOG_INFO(ftos(randombit(bits)), "\n");
-               --iter;
-       }
-}
-
-float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
-{
-       if(halflifedist > 0)
-               return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
-       else if(halflifedist < 0)
-               return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
-       else
-               return 1;
-}
-
-
 .string aiment_classname;
 .float aiment_deadflag;
 void SetMovetypeFollow(entity ent, entity e)
index 3ca3ea67306edc931bfa1206ea2a586cfaa24235..4193ff29add7c5bd7fd357c9862a3faaa85d0ef3 100644 (file)
@@ -33,19 +33,12 @@ float cvar_normal(string n)
 entity eliminatedPlayers;
 void EliminatedPlayers_Init(float(entity) isEliminated_func);
 
-string admin_name(void);
+string admin_name();
 
 void write_recordmarker(entity pl, float tstart, float dt);
 
 void play2all(string samp);
 
-void DistributeEvenly_Init(float amount, float totalweight);
-float DistributeEvenly_Get(float weight);
-
-void modeleffect_spawn(string m, float s, float f, vector o, vector v, vector ang, vector angv, float s0, float s2, float a, float t1, float t2);
-
-void shockwave_spawn(string m, vector org, float sz, float t1, float t2);
-
 void play2team(float t, string filename);
 
 void GetCvars_handleFloat(string thisname, float f, .float field, string name);
@@ -62,10 +55,7 @@ void InitializeEntitiesRun();
 
 void stopsoundto(float _dest, entity e, float chan);
 void soundtoat(float _dest, entity e, vector o, float chan, string samp, float vol, float _atten);
-float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d);
 
-float DistributeEvenly_amount;
-float DistributeEvenly_totalweight;
 void objerror(string s);
 void droptofloor();
 void() SUB_Remove;
@@ -134,32 +124,6 @@ void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomo
 
 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
 
-const string STR_PLAYER = "player";
-const string STR_SPECTATOR = "spectator";
-const string STR_OBSERVER = "observer";
-
-#define IS_PLAYER(v)                   ((v).classname == STR_PLAYER)
-#define IS_SPEC(v)                             ((v).classname == STR_SPECTATOR)
-#define IS_OBSERVER(v)                         ((v).classname == STR_OBSERVER)
-#define IS_CLIENT(v)                   (v.flags & FL_CLIENT)
-#define IS_BOT_CLIENT(v)               (clienttype(v) == CLIENTTYPE_BOT)
-#define IS_REAL_CLIENT(v)              (clienttype(v) == CLIENTTYPE_REAL)
-#define IS_NOT_A_CLIENT(v)             (clienttype(v) == CLIENTTYPE_NOTACLIENT)
-
-#define IS_MONSTER(v)                  (v.flags & FL_MONSTER)
-#define IS_VEHICLE(v)                  (v.vehicle_flags & VHF_ISVEHICLE)
-#define IS_TURRET(v)                   (v.turret_flags & TUR_FLAG_ISTURRET)
-
-#define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
-#define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(IS_CLIENT(v))
-#define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(IS_REAL_CLIENT(v))
-
-#define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(IS_PLAYER(v))
-#define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if (!IS_PLAYER(v)) // Samual: shouldn't this be IS_SPEC(v)? and rather create a separate macro to include observers too
-#define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(IS_PLAYER(v))
-
-#define FOR_EACH_MONSTER(v) for(v = world; (v = findflags(v, flags, FL_MONSTER)) != world; )
-
 #define CENTER_OR_VIEWOFS(ent) (ent.origin + (IS_PLAYER(ent) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5)))
 
 // copies a string to a tempstring (so one can strunzone it)
@@ -297,7 +261,7 @@ float sv_autotaunt;
 float sv_taunt;
 
 string GetGametype(); // g_world.qc
-void readlevelcvars(void)
+void readlevelcvars()
 {
        if(cvar("sv_allow_fullbright"))
                serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
@@ -322,7 +286,6 @@ void readlevelcvars(void)
 
        sv_clones = cvar("sv_clones");
        sv_foginterval = cvar("sv_foginterval");
-       g_cloaked = cvar("g_cloaked");
        g_footsteps = cvar("g_footsteps");
        g_jetpack = cvar("g_jetpack");
        sv_maxidle = cvar("sv_maxidle");
@@ -419,17 +382,6 @@ void readlevelcvars(void)
 
 //#NO AUTOCVARS END
 
-
-// Sound functions
-//string precache_sound (string s) = #19;
-// hack
-float precache_sound_index (string s) = #19;
-
-const float SND_VOLUME = BIT(0);
-const float SND_ATTENUATION = BIT(1);
-const float SND_LARGEENTITY = BIT(3);
-const float SND_LARGESOUND = BIT(4);
-
 const float INITPRIO_FIRST                             = 0;
 const float INITPRIO_GAMETYPE                  = 0;
 const float INITPRIO_GAMETYPE_FALLBACK         = 1;
@@ -439,7 +391,7 @@ const float INITPRIO_SETLOCATION            = 90;
 const float INITPRIO_LINKDOORS                         = 91;
 const float INITPRIO_LAST                              = 99;
 
-.void(void) initialize_entity;
+.void() initialize_entity;
 .float initialize_entity_order;
 .entity initialize_entity_next;
 entity initialize_entity_first;
@@ -449,7 +401,7 @@ entity initialize_entity_first;
 
 
 float sound_allowed(float dest, entity e);
-void InitializeEntity(entity e, void(void) func, float order);
-void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer);
+void InitializeEntity(entity e, void() func, float order);
+void SetCustomizer(entity e, float() customizer, void() uncustomizer);
 
 #endif
index d1cd583b15503dffb5b5b1242325341d16f37217..1a80b440947a48ca55ec7d839ba1ec3853167ca5 100644 (file)
@@ -9,34 +9,5 @@
 #include "mutator/gamemode_keepaway.qc"
 #include "mutator/gamemode_keyhunt.qc"
 #include "mutator/gamemode_lms.qc"
-#include "mutator/gamemode_onslaught.qc"
 #include "mutator/gamemode_race.qc"
 #include "mutator/gamemode_tdm.qc"
-
-#include "mutator/mutator_bloodloss.qc"
-#include "mutator/mutator_breakablehook.qc"
-#include "mutator/mutator_buffs.qc"
-#include "mutator/mutator_campcheck.qc"
-#include "mutator/mutator_dodging.qc"
-#include "mutator/mutator_hook.qc"
-#include "mutator/mutator_invincibleproj.qc"
-#include "mutator/mutator_melee_only.qc"
-#include "mutator/mutator_midair.qc"
-#include "mutator/mutator_multijump.qc"
-#include "mutator/mutator_nades.qc"
-#include "mutator/mutator_new_toys.qc"
-#include "mutator/mutator_nix.qc"
-#include "mutator/mutator_overkill.qc"
-#include "mutator/mutator_physical_items.qc"
-#include "mutator/mutator_pinata.qc"
-#include "mutator/mutator_random_gravity.qc"
-#include "mutator/mutator_rocketflying.qc"
-#include "mutator/mutator_rocketminsta.qc"
-#include "mutator/mutator_spawn_near_teammate.qc"
-#include "mutator/mutator_superspec.qc"
-#include "mutator/mutator_touchexplode.qc"
-#include "mutator/mutator_vampirehook.qc"
-#include "mutator/mutator_vampire.qc"
-#include "mutator/mutator_weaponarena_random.qc"
-
-#include "mutator/sandbox.qc"
index 542763fd28dcff1965b2cec466244f48c473e832..3520953ba5cf6c2858f85385db2ec07037da25c9 100644 (file)
@@ -9,8 +9,6 @@
     #include "../../common/stats.qh"
     #include "../../common/teams.qh"
     #include "../../common/util.qh"
-    #include "../../common/nades/all.qh"
-    #include "../../common/buffs/all.qh"
     #include "../../common/command/markup.qh"
     #include "../../common/command/rpn.qh"
     #include "../../common/command/generic.qh"
index 2d9e75b94efc96b392939c5ee57e35d3618566b1..4795aab28dcb5dcf7fca777e3758c4e61670f5ee 100644 (file)
@@ -153,6 +153,9 @@ MUTATOR_HOOKABLE(ForbidThrowCurrentWeapon, EV_NO_ARGS);
 /** returns true if dropping the current weapon shall not be allowed at any time including death */
 MUTATOR_HOOKABLE(ForbidDropCurrentWeapon, EV_NO_ARGS);
 
+/**  */
+MUTATOR_HOOKABLE(SetDefaultAlpha, EV_NO_ARGS);
+
 /** allows changing attack rate */
 #define EV_WeaponRateFactor(i, o) \
     /**/ i(float, weapon_rate) \
@@ -182,7 +185,10 @@ MUTATOR_HOOKABLE(CustomizeWaypoint, EV_CustomizeWaypoint);
  * checks if the current item may be spawned (self.items and self.weapons may be read and written to, as well as the ammo_ fields)
  * return error to request removal
  */
-MUTATOR_HOOKABLE(FilterItem, EV_NO_ARGS);
+#define EV_FilterItem(i, o) \
+    /** the current item */ i(entity, __self) \
+    /**/
+MUTATOR_HOOKABLE(FilterItem, EV_FilterItem);
 
 /** return error to request removal */
 #define EV_TurretSpawn(i, o) \
@@ -334,15 +340,31 @@ MUTATOR_HOOKABLE(PlayerDamage_Calculate, EV_PlayerDamage_Calculate);
  * Called when a player is damaged
  */
 #define EV_PlayerDamaged(i, o) \
-    /** attacker */ i(entity, mutator_argv_entity_0) \
-    /** target */ i(entity, mutator_argv_entity_1) \
-    /** health */ i(int, mutator_argv_int_0) \
-    /** armor */ i(int, mutator_argv_int_1) \
-    /** location */ i(vector, mutator_argv_vector_0) \
-    /** deathtype */ i(int, mutator_argv_int_2) \
+    /** attacker  */ i(entity, MUTATOR_ARGV_0_entity) \
+    /** target    */ i(entity, MUTATOR_ARGV_1_entity) \
+    /** health    */ i(int,    MUTATOR_ARGV_0_int) \
+    /** armor     */ i(int,    MUTATOR_ARGV_1_int) \
+    /** location  */ i(vector, MUTATOR_ARGV_0_vector) \
+    /** deathtype */ i(int,    MUTATOR_ARGV_2_int) \
     /**/
 MUTATOR_HOOKABLE(PlayerDamaged, EV_PlayerDamaged);
 
+/**
+ * Called by W_DecreaseAmmo
+ */
+#define EV_W_DecreaseAmmo(i, o) \
+    /** actor */ i(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(W_DecreaseAmmo, EV_W_DecreaseAmmo);
+
+/**
+ * Called by W_Reload
+ */
+#define EV_W_Reload(i, o) \
+    /** actor */ i(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(W_Reload, EV_W_Reload);
+
 /** called at the end of player_powerups() in cl_client.qc, used for manipulating the values which are set by powerup items. */
 #define EV_PlayerPowerups(i, o) \
     /**/ i(entity, __self) \
@@ -811,4 +833,23 @@ MUTATOR_HOOKABLE(TurretValidateTarget, EV_TurretValidateTarget);
     /**/ i(entity, __self) \
     /**/
 MUTATOR_HOOKABLE(TurretThink, EV_TurretThink);
+
+MUTATOR_HOOKABLE(Ent_Init, EV_NO_ARGS);
+
+/** */
+#define EV_PrepareExplosionByDamage(i, o) \
+    /**/ i(entity, __self) \
+    /**/ i(entity, frag_attacker) \
+    /**/
+MUTATOR_HOOKABLE(PrepareExplosionByDamage, EV_PrepareExplosionByDamage);
+
+/** called when a monster model is about to be set, allows custom paths etc. */
+#define EV_MonsterModel(i, o) \
+    /**/ i(string, monster_model) \
+    /**/ i(string, monster_model_output) \
+    /**/ o(string, monster_model_output) \
+    /**/
+string monster_model;
+string monster_model_output;
+MUTATOR_HOOKABLE(MonsterModel, EV_MonsterModel);
 #endif
index b9621cdadaf1822535d7a3f6d3a4c7e8f091b5fb..725569bfff6469745c55a56ffcce910131287071 100644 (file)
@@ -9,17 +9,17 @@ void ca_Initialize();
 
 REGISTER_MUTATOR(ca, false)
 {
-       ActivateTeamplay();
-       SetLimits(autocvar_g_ca_point_limit, autocvar_g_ca_point_leadlimit, -1, -1);
-
-       if (autocvar_g_ca_team_spawns)
-               have_team_spawns = -1; // request team spawns
-
        MUTATOR_ONADD
        {
                if (time > 1) // game loads at time 1
                        error("This is a game type and it cannot be added at runtime.");
                ca_Initialize();
+
+               ActivateTeamplay();
+               SetLimits(autocvar_g_ca_point_limit, autocvar_g_ca_point_leadlimit, -1, -1);
+
+               if (autocvar_g_ca_team_spawns)
+                       have_team_spawns = -1; // request team spawns
        }
 
        MUTATOR_ONREMOVE
index 73e992c95b0d54c862dbd61dd9037a7564ad70d0..d16b1687781fa52df21050715e0c510283348e5c 100644 (file)
@@ -6,15 +6,15 @@ void ctf_Initialize();
 
 REGISTER_MUTATOR(ctf, false)
 {
-       ActivateTeamplay();
-       SetLimits(autocvar_capturelimit_override, -1, autocvar_captureleadlimit_override, -1);
-       have_team_spawns = -1; // request team spawns
-
        MUTATOR_ONADD
        {
                if (time > 1) // game loads at time 1
                        error("This is a game type and it cannot be added at runtime.");
                ctf_Initialize();
+
+               ActivateTeamplay();
+               SetLimits(autocvar_capturelimit_override, autocvar_captureleadlimit_override, -1, -1);
+               have_team_spawns = -1; // request team spawns
        }
 
        MUTATOR_ONROLLBACK_OR_REMOVE
@@ -47,9 +47,14 @@ const int SP_CTF_DROPS = 7;
 const int SP_CTF_FCKILLS = 8;
 const int SP_CTF_RETURNS = 9;
 
+CLASS(Flag, Pickup)
+    ATTRIB(Flag, m_mins, vector, PL_MIN_CONST + '0 0 -13')
+    ATTRIB(Flag, m_maxs, vector, PL_MAX_CONST + '0 0 -13')
+ENDCLASS(Flag)
+Flag CTF_FLAG; STATIC_INIT(Flag) { CTF_FLAG = NEW(Flag); }
+void ctf_FlagTouch() { SELFPARAM(); ITEM_HANDLE(Pickup, CTF_FLAG, this, other); }
+
 // flag constants // for most of these, there is just one question to be asked: WHYYYYY?
-#define FLAG_MIN (PL_MIN_CONST + '0 0 -13')
-#define FLAG_MAX (PL_MAX_CONST + '0 0 -13')
 
 const float FLAG_SCALE = 0.6;
 
@@ -125,6 +130,8 @@ const int RETURN_DAMAGE = 3;
 const int RETURN_SPEEDRUN = 4;
 const int RETURN_NEEDKILL = 5;
 
+void ctf_Handle_Throw(entity player, entity receiver, float droptype);
+
 // flag properties
 #define ctf_spawnorigin dropped_origin
 bool ctf_stalemate; // indicates that a stalemate is active
@@ -467,13 +474,12 @@ void ctf_CaptureShield_Touch()
 
 void ctf_CaptureShield_Spawn(entity flag)
 {SELFPARAM();
-       entity shield = spawn();
+       entity shield = new(ctf_captureshield);
 
        shield.enemy = self;
        shield.team = self.team;
        shield.touch = ctf_CaptureShield_Touch;
        shield.customizeentityforclient = ctf_CaptureShield_Customize;
-       shield.classname = "ctf_captureshield";
        shield.effects = EF_ADDITIVE;
        shield.movetype = MOVETYPE_NOCLIP;
        shield.solid = SOLID_TRIGGER;
@@ -672,6 +678,10 @@ void ctf_Handle_Throw(entity player, entity receiver, int droptype)
        ctf_CaptureShield_Update(player, 0); // shield player from picking up flag
 }
 
+void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
+{
+       return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
+}
 
 // ==============
 // Event Handlers
@@ -930,7 +940,7 @@ bool ctf_Stalemate_Customize()
        return true;
 }
 
-void ctf_CheckStalemate(void)
+void ctf_CheckStalemate()
 {
        // declarations
        int stale_flags = 0, stale_red_flags = 0, stale_blue_flags = 0, stale_yellow_flags = 0, stale_pink_flags = 0, stale_neutral_flags = 0;
@@ -1033,11 +1043,11 @@ void ctf_FlagThink()
                        ctf_CaptureShield_Update(tmp_entity, 1); // release shield only
 
        // sanity checks
-       if(self.mins != FLAG_MIN || self.maxs != FLAG_MAX) { // reset the flag boundaries in case it got squished
+       if(self.mins != CTF_FLAG.m_mins || self.maxs != CTF_FLAG.m_maxs) { // reset the flag boundaries in case it got squished
                LOG_TRACE("wtf the flag got squashed?\n");
-               tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self);
+               tracebox(self.origin, CTF_FLAG.m_mins, CTF_FLAG.m_maxs, self.origin, MOVE_NOMONSTERS, self);
                if(!trace_startsolid || self.noalign) // can we resize it without getting stuck?
-                       setsize(self, FLAG_MIN, FLAG_MAX); }
+                       setsize(self, CTF_FLAG.m_mins, CTF_FLAG.m_maxs); }
 
        switch(self.ctf_status) // reset flag angles in case warpzones adjust it
        {
@@ -1168,26 +1178,27 @@ void ctf_FlagThink()
        }
 }
 
-void ctf_FlagTouch()
-{SELFPARAM();
+METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
+{
+       return = false;
        if(gameover) { return; }
        if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
 
-       entity toucher = other, tmp_entity;
-       bool is_not_monster = (!IS_MONSTER(toucher)), num_perteam = 0;
+       bool is_not_monster = (!IS_MONSTER(toucher));
 
        // automatically kill the flag and return it if it touched lava/slime/nodrop surfaces
        if(ITEM_TOUCH_NEEDKILL())
        {
                if(!autocvar_g_ctf_flag_return_damage_delay)
                {
-                       self.health = 0;
-                       ctf_CheckFlagReturn(self, RETURN_NEEDKILL);
+                       flag.health = 0;
+                       ctf_CheckFlagReturn(flag, RETURN_NEEDKILL);
                }
-               if(!self.ctf_flagdamaged) { return; }
+               if(!flag.ctf_flagdamaged) { return; }
        }
 
-       FOR_EACH_PLAYER(tmp_entity) if(SAME_TEAM(toucher, tmp_entity)) { ++num_perteam; }
+       int num_perteam = 0;
+       entity tmp_entity; FOR_EACH_PLAYER(tmp_entity) if(SAME_TEAM(toucher, tmp_entity)) { ++num_perteam; }
 
        // special touch behaviors
        if(toucher.frozen) { return; }
@@ -1205,40 +1216,40 @@ void ctf_FlagTouch()
        }
        else if (!IS_PLAYER(toucher)) // The flag just touched an object, most likely the world
        {
-               if(time > self.wait) // if we haven't in a while, play a sound/effect
+               if(time > flag.wait) // if we haven't in a while, play a sound/effect
                {
-                       Send_Effect_(self.toucheffect, self.origin, '0 0 0', 1);
-                       _sound(self, CH_TRIGGER, self.snd_flag_touch, VOL_BASE, ATTEN_NORM);
-                       self.wait = time + FLAG_TOUCHRATE;
+                       Send_Effect_(flag.toucheffect, flag.origin, '0 0 0', 1);
+                       _sound(flag, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
+                       flag.wait = time + FLAG_TOUCHRATE;
                }
                return;
        }
        else if(toucher.deadflag != DEAD_NO) { return; }
 
-       switch(self.ctf_status)
+       switch(flag.ctf_status)
        {
                case FLAG_BASE:
                {
                        if(ctf_oneflag)
                        {
-                               if(CTF_SAMETEAM(toucher, self) && (toucher.flagcarried) && !toucher.flagcarried.team && is_not_monster)
-                                       ctf_Handle_Capture(self, toucher, CAPTURE_NORMAL); // toucher just captured the neutral flag to enemy base
-                               else if(!self.team && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
-                                       ctf_Handle_Pickup(self, toucher, PICKUP_BASE); // toucher just stole the neutral flag
+                               if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && !toucher.flagcarried.team && is_not_monster)
+                                       ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the neutral flag to enemy base
+                               else if(!flag.team && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
+                                       ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the neutral flag
                        }
-                       else if(CTF_SAMETEAM(toucher, self) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, self) && is_not_monster)
-                               ctf_Handle_Capture(self, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
-                       else if(CTF_DIFFTEAM(toucher, self) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
-                               ctf_Handle_Pickup(self, toucher, PICKUP_BASE); // toucher just stole the enemies flag
+                       else if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, flag) && is_not_monster)
+                               ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
+                       else if(CTF_DIFFTEAM(toucher, flag) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
+                               ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the enemies flag
                        break;
                }
 
                case FLAG_DROPPED:
                {
-                       if(CTF_SAMETEAM(toucher, self) && (autocvar_g_ctf_flag_return || num_perteam <= 1) && self.team) // automatically return if there's only 1 player on the team
-                               ctf_Handle_Return(self, toucher); // toucher just returned his own flag
-                       else if(is_not_monster && (!toucher.flagcarried) && ((toucher != self.ctf_dropper) || (time > self.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
-                               ctf_Handle_Pickup(self, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
+                       if(CTF_SAMETEAM(toucher, flag) && (autocvar_g_ctf_flag_return || num_perteam <= 1) && flag.team) // automatically return if there's only 1 player on the team
+                               ctf_Handle_Return(flag, toucher); // toucher just returned his own flag
+                       else if(is_not_monster && (!toucher.flagcarried) && ((toucher != flag.ctf_dropper) || (time > flag.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
+                               ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
                        break;
                }
 
@@ -1250,12 +1261,12 @@ void ctf_FlagTouch()
 
                case FLAG_PASSING:
                {
-                       if((IS_PLAYER(toucher)) && (toucher.deadflag == DEAD_NO) && (toucher != self.pass_sender))
+                       if((IS_PLAYER(toucher)) && (toucher.deadflag == DEAD_NO) && (toucher != flag.pass_sender))
                        {
-                               if(DIFF_TEAM(toucher, self.pass_sender))
-                                       ctf_Handle_Return(self, toucher);
+                               if(DIFF_TEAM(toucher, flag.pass_sender))
+                                       ctf_Handle_Return(flag, toucher);
                                else
-                                       ctf_Handle_Retrieve(self, toucher);
+                                       ctf_Handle_Retrieve(flag, toucher);
                        }
                        break;
                }
@@ -1323,7 +1334,7 @@ void ctf_Reset()
        ctf_RespawnFlag(self);
 }
 
-void ctf_DelayedFlagSetup(void) // called after a flag is placed on a map by ctf_FlagSetup()
+void ctf_DelayedFlagSetup() // called after a flag is placed on a map by ctf_FlagSetup()
 {SELFPARAM();
        // bot waypoints
        waypoint_spawnforitem_force(self, self.origin);
@@ -1349,12 +1360,6 @@ void ctf_DelayedFlagSetup(void) // called after a flag is placed on a map by ctf
        ctf_CaptureShield_Spawn(self);
 }
 
-void set_flag_string(entity flag, .string field, string value, string teamname)
-{
-       if(flag.(field) == "")
-               flag.(field) = strzone(sprintf(value,teamname));
-}
-
 void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
 {SELFPARAM();
        // declarations
@@ -1395,20 +1400,20 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e
        if(!flag.scale)                         { flag.scale = FLAG_SCALE; }
        if(flag.skin == 0)                      { flag.skin = cvar(sprintf("g_ctf_flag_%s_skin", teamname)); }
        if(flag.model == "")            { flag.model = cvar_string(sprintf("g_ctf_flag_%s_model", teamname)); }
-       set_flag_string(flag, toucheffect,      "%sflag_touch", teamname);
-       set_flag_string(flag, passeffect,       "%s_pass",              teamname);
-       set_flag_string(flag, capeffect,        "%s_cap",               teamname);
+       if (flag.toucheffect == "") { flag.toucheffect = EFFECT_FLAG_TOUCH(teamnumber).eent_eff_name; }
+       if (flag.passeffect == "")      { flag.passeffect = EFFECT_PASS(teamnumber).eent_eff_name; }
+       if (flag.capeffect == "")       { flag.capeffect = EFFECT_CAP(teamnumber).eent_eff_name; }
 
        // sounds
-       flag.snd_flag_taken = SND(CTF_TAKEN(teamnumber));
-       flag.snd_flag_returned = SND(CTF_RETURNED(teamnumber));
-       flag.snd_flag_capture = SND(CTF_CAPTURE(teamnumber));
-       flag.snd_flag_dropped = SND(CTF_DROPPED(teamnumber));
-       if (flag.snd_flag_respawn == "") flag.snd_flag_respawn = SND(CTF_RESPAWN); // if there is ever a team-based sound for this, update the code to match.
+       flag.snd_flag_taken = strzone(SND(CTF_TAKEN(teamnumber)));
+       flag.snd_flag_returned = strzone(SND(CTF_RETURNED(teamnumber)));
+       flag.snd_flag_capture = strzone(SND(CTF_CAPTURE(teamnumber)));
+       flag.snd_flag_dropped = strzone(SND(CTF_DROPPED(teamnumber)));
+       if (flag.snd_flag_respawn == "") flag.snd_flag_respawn = strzone(SND(CTF_RESPAWN)); // if there is ever a team-based sound for this, update the code to match.
        precache_sound(flag.snd_flag_respawn);
-       if (flag.snd_flag_touch == "") flag.snd_flag_touch = SND(CTF_TOUCH); // again has no team-based sound
+       if (flag.snd_flag_touch == "") flag.snd_flag_touch = strzone(SND(CTF_TOUCH)); // again has no team-based sound
        precache_sound(flag.snd_flag_touch);
-       if (flag.snd_flag_pass == "") flag.snd_flag_pass = SND(CTF_PASS); // same story here
+       if (flag.snd_flag_pass == "") flag.snd_flag_pass = strzone(SND(CTF_PASS)); // same story here
        precache_sound(flag.snd_flag_pass);
 
        // precache
@@ -1416,7 +1421,7 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e
 
        // appearence
        _setmodel(flag, flag.model); // precision set below
-       setsize(flag, FLAG_MIN, FLAG_MAX);
+       setsize(flag, CTF_FLAG.m_mins, CTF_FLAG.m_maxs);
        setorigin(flag, (flag.origin + FLAG_SPAWN_OFFSET));
 
        if(autocvar_g_ctf_flag_glowtrails)
index 982da6ea3e6307699aead50e51b4fafe666ec05a..c256d1b974b6d79e9a8ceb57d0198b5364c12e03 100644 (file)
@@ -7,15 +7,15 @@ void cts_Initialize();
 
 REGISTER_MUTATOR(cts, false)
 {
-       g_race_qualifying = true;
-       independent_players = 1;
-       SetLimits(0, 0, 0, -1);
-
        MUTATOR_ONADD
        {
                if (time > 1) // game loads at time 1
                        error("This is a game type and it cannot be added at runtime.");
                cts_Initialize();
+
+               g_race_qualifying = true;
+               independent_players = 1;
+               SetLimits(0, 0, 0, -1);
        }
 
        MUTATOR_ONROLLBACK_OR_REMOVE
@@ -380,13 +380,6 @@ MUTATOR_HOOKFUNCTION(cts, ForbidPlayerScore_Clear)
        return true; // in CTS, you don't lose score by observing
 }
 
-MUTATOR_HOOKFUNCTION(cts, SetModname)
-{
-       g_cloaked = 1; // always enable cloak in CTS
-
-       return false;
-}
-
 MUTATOR_HOOKFUNCTION(cts, GetRecords)
 {
        for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
index 5ebd7c6b6e65b477ac711cb21fb1c54dc93adca5..d05bc18bd2125fc0de1eadc9c52c3fbd133af0f2 100644 (file)
@@ -18,7 +18,7 @@ REGISTER_MUTATOR(dm, false)
 
        MUTATOR_ONREMOVE
        {
-               print("This is a game type and it cannot be removed at runtime.");
+               error("This is a game type and it cannot be removed at runtime.");
                return -1;
        }
 
index 5195177dfcb1b493093e7ad385b590158c2f02ad..8c5d5159d5383e5763bd7cb818ff8359c6e31c9e 100644 (file)
@@ -10,19 +10,19 @@ void dom_Initialize();
 
 REGISTER_MUTATOR(dom, false)
 {
-       int fraglimit_override = autocvar_g_domination_point_limit;
-       if (autocvar_g_domination_roundbased && autocvar_g_domination_roundbased_point_limit)
-               fraglimit_override = autocvar_g_domination_roundbased_point_limit;
-
-       ActivateTeamplay();
-       SetLimits(fraglimit_override, autocvar_g_domination_point_leadlimit, -1, -1);
-       have_team_spawns = -1; // request team spawns
-
        MUTATOR_ONADD
        {
                if (time > 1) // game loads at time 1
                        error("This is a game type and it cannot be added at runtime.");
                dom_Initialize();
+
+               int fraglimit_override = autocvar_g_domination_point_limit;
+               if (autocvar_g_domination_roundbased && autocvar_g_domination_roundbased_point_limit)
+                       fraglimit_override = autocvar_g_domination_roundbased_point_limit;
+
+               ActivateTeamplay();
+               SetLimits(fraglimit_override, autocvar_g_domination_point_leadlimit, -1, -1);
+               have_team_spawns = -1; // request team spawns
        }
 
        MUTATOR_ONREMOVE
index c392c4be58dc40675a157cd6868ef12a053a7f95..29ae0066848980f495ffb70b8a2bbce775230e5b 100644 (file)
@@ -8,17 +8,17 @@ void freezetag_Initialize();
 
 REGISTER_MUTATOR(ft, false)
 {
-       ActivateTeamplay();
-       SetLimits(autocvar_g_freezetag_point_limit, autocvar_g_freezetag_point_leadlimit, -1, -1);
-
-       if (autocvar_g_freezetag_team_spawns)
-               have_team_spawns = -1; // request team spawns
-
        MUTATOR_ONADD
        {
                if (time > 1) // game loads at time 1
                        error("This is a game type and it cannot be added at runtime.");
                freezetag_Initialize();
+
+               ActivateTeamplay();
+               SetLimits(autocvar_g_freezetag_point_limit, autocvar_g_freezetag_point_leadlimit, -1, -1);
+
+               if (autocvar_g_freezetag_team_spawns)
+                       have_team_spawns = -1; // request team spawns
        }
 
        MUTATOR_ONROLLBACK_OR_REMOVE
@@ -44,15 +44,16 @@ const float ICE_MIN_ALPHA = 0.1;
 float freezetag_teams;
 
 .float reviving; // temp var
-#endif
 
+float autocvar_g_freezetag_revive_extra_size;
+float autocvar_g_freezetag_revive_speed;
+bool autocvar_g_freezetag_revive_nade;
+float autocvar_g_freezetag_revive_nade_health;
+
+#endif
 #ifdef IMPLEMENTATION
 
 float autocvar_g_freezetag_frozen_maxtime;
-bool autocvar_g_freezetag_revive_nade;
-float autocvar_g_freezetag_revive_nade_health;
-float autocvar_g_freezetag_revive_extra_size;
-float autocvar_g_freezetag_revive_speed;
 float autocvar_g_freezetag_revive_clearspeed;
 float autocvar_g_freezetag_round_timelimit;
 int autocvar_g_freezetag_teams;
index f52afb9e2fcbcf73ee87e75ae945d17bae23577f..1fa986483bd4ed9d31678bb6a3867f2a2fa4b916 100644 (file)
@@ -9,14 +9,6 @@ void invasion_Initialize();
 
 REGISTER_MUTATOR(inv, false)
 {
-       SetLimits(autocvar_g_invasion_point_limit, -1, -1, -1);
-       if (autocvar_g_invasion_teams >= 2)
-       {
-               ActivateTeamplay();
-               if (autocvar_g_invasion_team_spawns)
-                       have_team_spawns = -1; // request team spawns
-       }
-
        MUTATOR_ONADD
        {
                if (time > 1) // game loads at time 1
@@ -25,6 +17,14 @@ REGISTER_MUTATOR(inv, false)
                invasion_Initialize();
 
                cvar_settemp("g_monsters", "1");
+
+               SetLimits(autocvar_g_invasion_point_limit, -1, -1, -1);
+               if (autocvar_g_invasion_teams >= 2)
+               {
+                       ActivateTeamplay();
+                       if (autocvar_g_invasion_team_spawns)
+                               have_team_spawns = -1; // request team spawns
+               }
        }
 
        MUTATOR_ONROLLBACK_OR_REMOVE
index 8961e6bf0027398d159f1d3b266b8d19ee0934dd..ea14243709cfc1b433e3a159c053e5801dc992af 100644 (file)
@@ -462,13 +462,11 @@ MUTATOR_HOOKFUNCTION(ka, DropSpecialItems)
 
 void ka_SpawnBall() // loads various values for the ball, runs only once at start of match
 {
-       entity e;
-       e = spawn();
+       entity e = new(keepawayball);
        e.model = "models/orbs/orbblue.md3";
        precache_model(e.model);
        _setmodel(e, e.model);
        setsize(e, '-16 -16 -20', '16 16 20'); // 20 20 20 was too big, player is only 16 16 24... gotta cheat with the Z (20) axis so that the particle isn't cut off
-       e.classname = "keepawayball";
        e.damageforcescale = autocvar_g_keepawayball_damageforcescale;
        e.takedamage = DAMAGE_YES;
        e.solid = SOLID_TRIGGER;
index 5982cf2085436442543488477e823925958eeb52..8d4240e29aa3478b35dbfdfc6b0e0e95179dc1d6 100644 (file)
@@ -8,16 +8,16 @@ void kh_Initialize();
 
 REGISTER_MUTATOR(kh, false)
 {
-       ActivateTeamplay();
-       SetLimits(autocvar_g_keyhunt_point_limit, autocvar_g_keyhunt_point_leadlimit, -1, -1);
-       if (autocvar_g_keyhunt_team_spawns)
-               have_team_spawns = -1; // request team spawns
-
        MUTATOR_ONADD
        {
                if (time > 1) // game loads at time 1
                        error("This is a game type and it cannot be added at runtime.");
                kh_Initialize();
+
+               ActivateTeamplay();
+               SetLimits(autocvar_g_keyhunt_point_limit, autocvar_g_keyhunt_point_leadlimit, -1, -1);
+               if (autocvar_g_keyhunt_team_spawns)
+                       have_team_spawns = -1; // request team spawns
        }
 
        MUTATOR_ONROLLBACK_OR_REMOVE
@@ -45,7 +45,7 @@ float kh_tracking_enabled;
 .entity kh_next;
 float kh_Key_AllOwnedByWhichTeam();
 
-typedef void(void) kh_Think_t;
+typedef void() kh_Think_t;
 void kh_StartRound();
 void kh_Controller_SetThink(float t, kh_Think_t func);
 
@@ -102,7 +102,7 @@ float kh_no_radar_circles;
 //     bits  5- 9: team of key 2, or 0 for no such key, or 30 for dropped, or 31 for self
 //     bits 10-14: team of key 3, or 0 for no such key, or 30 for dropped, or 31 for self
 //     bits 15-19: team of key 4, or 0 for no such key, or 30 for dropped, or 31 for self
-.float kh_state;
+.float kh_state = _STAT(KH_KEYS);
 .float siren_time;  //  time delay the siren
 //.float stuff_time;  //  time delay to stuffcmd a cvar
 
@@ -800,17 +800,16 @@ void key_reset()
 }
 
 const string STR_ITEM_KH_KEY = "item_kh_key";
-void kh_Key_Spawn(entity initial_owner, float angle, float i)  // runs every time a new flag is created, ie after all the keys have been collected
+void kh_Key_Spawn(entity initial_owner, float _angle, float i)  // runs every time a new flag is created, ie after all the keys have been collected
 {
-       entity key;
-       key = spawn();
+       entity key = spawn();
        key.count = i;
        key.classname = STR_ITEM_KH_KEY;
        key.touch = kh_Key_Touch;
        key.think = kh_Key_Think;
        key.nextthink = time;
        key.items = IT_KEY1 | IT_KEY2;
-       key.cnt = angle;
+       key.cnt = _angle;
        key.angles = '0 360 0' * random();
        key.event_damage = kh_Key_Damage;
        key.takedamage = DAMAGE_YES;
@@ -1096,8 +1095,6 @@ void kh_Initialize()  // sets up th KH environment
        kh_controller.model = "";
        kh_controller.modelindex = 0;
 
-       addstat(STAT_KH_KEYS, AS_INT, kh_state);
-
        kh_ScoreRules(kh_teams);
 }
 
index f2ee672dad4026b425160afb8e3771f7fd93c100..9fa7f4739715b39269c9b4e600ee8ce6705a0d69 100644 (file)
@@ -6,13 +6,13 @@ void lms_Initialize();
 
 REGISTER_MUTATOR(lms, false)
 {
-       SetLimits(((!autocvar_g_lms_lives_override) ? -1 : autocvar_g_lms_lives_override), 0, -1, -1);
-
        MUTATOR_ONADD
        {
                if (time > 1) // game loads at time 1
                        error("This is a game type and it cannot be added at runtime.");
                lms_Initialize();
+
+               SetLimits(((!autocvar_g_lms_lives_override) ? -1 : autocvar_g_lms_lives_override), 0, -1, -1);
        }
 
        MUTATOR_ONROLLBACK_OR_REMOVE
diff --git a/qcsrc/server/mutators/mutator/gamemode_onslaught.qc b/qcsrc/server/mutators/mutator/gamemode_onslaught.qc
deleted file mode 100644 (file)
index 51ddcad..0000000
+++ /dev/null
@@ -1,2326 +0,0 @@
-#ifndef GAMEMODE_ONSLAUGHT_H
-#define GAMEMODE_ONSLAUGHT_H
-
-float autocvar_g_onslaught_point_limit;
-void ons_Initialize();
-
-REGISTER_MUTATOR(ons, false)
-{
-       ActivateTeamplay();
-       SetLimits(autocvar_g_onslaught_point_limit, -1, -1, -1);
-       have_team_spawns = -1; // request team spawns
-
-       MUTATOR_ONADD
-       {
-               if (time > 1) // game loads at time 1
-                       error("This is a game type and it cannot be added at runtime.");
-               ons_Initialize();
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // we actually cannot roll back ons_Initialize here
-               // BUT: we don't need to! If this gets called, adding always
-               // succeeds.
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This is a game type and it cannot be removed at runtime.");
-               return -1;
-       }
-
-       return false;
-}
-
-#ifdef SVQC
-
-.entity ons_toucher; // player who touched the control point
-
-// control point / generator constants
-const float ONS_CP_THINKRATE = 0.2;
-const float GEN_THINKRATE = 1;
-#define CPGEN_SPAWN_OFFSET ('0 0 1' * (PL_MAX_CONST.z - 13))
-const vector CPGEN_WAYPOINT_OFFSET = ('0 0 128');
-const vector CPICON_OFFSET = ('0 0 96');
-
-// list of generators on the map
-entity ons_worldgeneratorlist;
-.entity ons_worldgeneratornext;
-.entity ons_stalegeneratornext;
-
-// list of control points on the map
-entity ons_worldcplist;
-.entity ons_worldcpnext;
-.entity ons_stalecpnext;
-
-// list of links on the map
-entity ons_worldlinklist;
-.entity ons_worldlinknext;
-.entity ons_stalelinknext;
-
-// definitions
-.entity sprite;
-.string target2;
-.int iscaptured;
-.int islinked;
-.int isshielded;
-.float lasthealth;
-.int lastteam;
-.int lastshielded;
-.int lastcaptured;
-
-.bool waslinked;
-
-bool ons_stalemate;
-
-.float teleport_antispam;
-
-.bool ons_roundlost;
-
-// waypoint sprites
-.entity bot_basewaypoint; // generator waypointsprite
-
-.bool isgenneighbor[17];
-.bool iscpneighbor[17];
-float ons_notification_time[17];
-
-.float ons_overtime_damagedelay;
-
-.vector ons_deathloc;
-
-.entity ons_spawn_by;
-
-// declarations for functions used outside gamemode_onslaught.qc
-void ons_Generator_UpdateSprite(entity e);
-void ons_ControlPoint_UpdateSprite(entity e);
-bool ons_ControlPoint_Attackable(entity cp, int teamnumber);
-
-// CaptureShield: Prevent capturing or destroying control point/generator if it is not available yet
-float ons_captureshield_force; // push force of the shield
-
-// bot player logic
-const int HAVOCBOT_ONS_ROLE_NONE               = 0;
-const int HAVOCBOT_ONS_ROLE_DEFENSE    = 2;
-const int HAVOCBOT_ONS_ROLE_ASSISTANT  = 4;
-const int HAVOCBOT_ONS_ROLE_OFFENSE    = 8;
-
-.entity havocbot_ons_target;
-
-.int havocbot_role_flags;
-.float havocbot_attack_time;
-
-void havocbot_role_ons_defense();
-void havocbot_role_ons_offense();
-void havocbot_role_ons_assistant();
-
-void havocbot_ons_reset_role(entity bot);
-void havocbot_goalrating_items(float ratingscale, vector org, float sradius);
-void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradius);
-
-// score rule declarations
-const int ST_ONS_CAPS = 1;
-const int SP_ONS_CAPS = 4;
-const int SP_ONS_TAKES = 6;
-
-#endif
-#endif
-
-#ifdef IMPLEMENTATION
-
-#include "../../controlpoint.qh"
-#include "../../generator.qh"
-
-bool g_onslaught;
-
-float autocvar_g_onslaught_debug;
-float autocvar_g_onslaught_teleport_wait;
-bool autocvar_g_onslaught_spawn_at_controlpoints;
-bool autocvar_g_onslaught_spawn_at_generator;
-float autocvar_g_onslaught_cp_proxydecap;
-float autocvar_g_onslaught_cp_proxydecap_distance = 512;
-float autocvar_g_onslaught_cp_proxydecap_dps = 100;
-float autocvar_g_onslaught_spawn_at_controlpoints_chance = 0.5;
-float autocvar_g_onslaught_spawn_at_controlpoints_random;
-float autocvar_g_onslaught_spawn_at_generator_chance;
-float autocvar_g_onslaught_spawn_at_generator_random;
-float autocvar_g_onslaught_cp_buildhealth;
-float autocvar_g_onslaught_cp_buildtime;
-float autocvar_g_onslaught_cp_health;
-float autocvar_g_onslaught_cp_regen;
-float autocvar_g_onslaught_gen_health;
-float autocvar_g_onslaught_shield_force = 100;
-float autocvar_g_onslaught_allow_vehicle_touch;
-float autocvar_g_onslaught_round_timelimit;
-float autocvar_g_onslaught_warmup;
-float autocvar_g_onslaught_teleport_radius;
-float autocvar_g_onslaught_spawn_choose;
-float autocvar_g_onslaught_click_radius;
-
-void FixSize(entity e);
-
-// =======================
-// CaptureShield Functions
-// =======================
-
-bool ons_CaptureShield_Customize()
-{SELFPARAM();
-       entity e = WaypointSprite_getviewentity(other);
-
-       if(!self.enemy.isshielded && (ons_ControlPoint_Attackable(self.enemy, e.team) > 0 || self.enemy.classname != "onslaught_controlpoint")) { return false; }
-       if(SAME_TEAM(self, e)) { return false; }
-
-       return true;
-}
-
-void ons_CaptureShield_Touch()
-{SELFPARAM();
-       if(!self.enemy.isshielded && (ons_ControlPoint_Attackable(self.enemy, other.team) > 0 || self.enemy.classname != "onslaught_controlpoint")) { return; }
-       if(!IS_PLAYER(other)) { return; }
-       if(SAME_TEAM(other, self)) { return; }
-
-       vector mymid = (self.absmin + self.absmax) * 0.5;
-       vector othermid = (other.absmin + other.absmax) * 0.5;
-
-       Damage(other, self, self, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(othermid - mymid) * ons_captureshield_force);
-
-       if(IS_REAL_CLIENT(other))
-       {
-               play2(other, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
-
-               if(self.enemy.classname == "onslaught_generator")
-                       Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_GENERATOR_SHIELDED);
-               else
-                       Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_CONTROLPOINT_SHIELDED);
-       }
-}
-
-void ons_CaptureShield_Reset()
-{SELFPARAM();
-       self.colormap = self.enemy.colormap;
-       self.team = self.enemy.team;
-}
-
-void ons_CaptureShield_Spawn(entity generator, bool is_generator)
-{
-       entity shield = spawn();
-
-       shield.enemy = generator;
-       shield.team = generator.team;
-       shield.colormap = generator.colormap;
-       shield.reset = ons_CaptureShield_Reset;
-       shield.touch = ons_CaptureShield_Touch;
-       shield.customizeentityforclient = ons_CaptureShield_Customize;
-       shield.classname = "ons_captureshield";
-       shield.effects = EF_ADDITIVE;
-       shield.movetype = MOVETYPE_NOCLIP;
-       shield.solid = SOLID_TRIGGER;
-       shield.avelocity = '7 0 11';
-       shield.scale = 1;
-       shield.model = ((is_generator) ? "models/onslaught/generator_shield.md3" : "models/onslaught/controlpoint_shield.md3");
-
-       precache_model(shield.model);
-       setorigin(shield, generator.origin);
-       _setmodel(shield, shield.model);
-       setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
-}
-
-
-// ==========
-// Junk Pile
-// ==========
-
-void ons_debug(string input)
-{
-       switch(autocvar_g_onslaught_debug)
-       {
-               case 1: LOG_TRACE(input); break;
-               case 2: LOG_INFO(input); break;
-       }
-}
-
-void setmodel_fixsize(entity e, Model m)
-{
-       setmodel(e, m);
-       FixSize(e);
-}
-
-void onslaught_updatelinks()
-{
-       entity l;
-       // first check if the game has ended
-       ons_debug("--- updatelinks ---\n");
-       // mark generators as being shielded and networked
-       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
-       {
-               if (l.iscaptured)
-                       ons_debug(strcat(etos(l), " (generator) belongs to team ", ftos(l.team), "\n"));
-               else
-                       ons_debug(strcat(etos(l), " (generator) is destroyed\n"));
-               l.islinked = l.iscaptured;
-               l.isshielded = l.iscaptured;
-               l.sprite.SendFlags |= 16;
-       }
-       // mark points as shielded and not networked
-       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
-       {
-               l.islinked = false;
-               l.isshielded = true;
-               int i;
-               for(i = 0; i < 17; ++i) { l.isgenneighbor[i] = false; l.iscpneighbor[i] = false; }
-               ons_debug(strcat(etos(l), " (point) belongs to team ", ftos(l.team), "\n"));
-               l.sprite.SendFlags |= 16;
-       }
-       // flow power outward from the generators through the network
-       bool stop = false;
-       while (!stop)
-       {
-               stop = true;
-               for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
-               {
-                       // if both points are captured by the same team, and only one of
-                       // them is powered, mark the other one as powered as well
-                       if (l.enemy.iscaptured && l.goalentity.iscaptured)
-                               if (l.enemy.islinked != l.goalentity.islinked)
-                                       if(SAME_TEAM(l.enemy, l.goalentity))
-                                       {
-                                               if (!l.goalentity.islinked)
-                                               {
-                                                       stop = false;
-                                                       l.goalentity.islinked = true;
-                                                       ons_debug(strcat(etos(l), " (link) is marking ", etos(l.goalentity), " (point) because its team matches ", etos(l.enemy), " (point)\n"));
-                                               }
-                                               else if (!l.enemy.islinked)
-                                               {
-                                                       stop = false;
-                                                       l.enemy.islinked = true;
-                                                       ons_debug(strcat(etos(l), " (link) is marking ", etos(l.enemy), " (point) because its team matches ", etos(l.goalentity), " (point)\n"));
-                                               }
-                                       }
-               }
-       }
-       // now that we know which points are powered we can mark their neighbors
-       // as unshielded if team differs
-       for(l = ons_worldlinklist; l; l = l.ons_worldlinknext)
-       {
-               if (l.goalentity.islinked)
-               {
-                       if(DIFF_TEAM(l.goalentity, l.enemy))
-                       {
-                               ons_debug(strcat(etos(l), " (link) is unshielding ", etos(l.enemy), " (point) because its team does not match ", etos(l.goalentity), " (point)\n"));
-                               l.enemy.isshielded = false;
-                       }
-                       if(l.goalentity.classname == "onslaught_generator")
-                               l.enemy.isgenneighbor[l.goalentity.team] = true;
-                       else
-                               l.enemy.iscpneighbor[l.goalentity.team] = true;
-               }
-               if (l.enemy.islinked)
-               {
-                       if(DIFF_TEAM(l.goalentity, l.enemy))
-                       {
-                               ons_debug(strcat(etos(l), " (link) is unshielding ", etos(l.goalentity), " (point) because its team does not match ", etos(l.enemy), " (point)\n"));
-                               l.goalentity.isshielded = false;
-                       }
-                       if(l.enemy.classname == "onslaught_generator")
-                               l.goalentity.isgenneighbor[l.enemy.team] = true;
-                       else
-                               l.goalentity.iscpneighbor[l.enemy.team] = true;
-               }
-       }
-       // now update the generators
-       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
-       {
-               if (l.isshielded)
-               {
-                       ons_debug(strcat(etos(l), " (generator) is shielded\n"));
-                       l.takedamage = DAMAGE_NO;
-                       l.bot_attack = false;
-               }
-               else
-               {
-                       ons_debug(strcat(etos(l), " (generator) is not shielded\n"));
-                       l.takedamage = DAMAGE_AIM;
-                       l.bot_attack = true;
-               }
-
-               ons_Generator_UpdateSprite(l);
-       }
-       // now update the takedamage and alpha variables on control point icons
-       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
-       {
-               if (l.isshielded)
-               {
-                       ons_debug(strcat(etos(l), " (point) is shielded\n"));
-                       if (l.goalentity)
-                       {
-                               l.goalentity.takedamage = DAMAGE_NO;
-                               l.goalentity.bot_attack = false;
-                       }
-               }
-               else
-               {
-                       ons_debug(strcat(etos(l), " (point) is not shielded\n"));
-                       if (l.goalentity)
-                       {
-                               l.goalentity.takedamage = DAMAGE_AIM;
-                               l.goalentity.bot_attack = true;
-                       }
-               }
-               ons_ControlPoint_UpdateSprite(l);
-       }
-       l = findchain(classname, "ons_captureshield");
-       while(l)
-       {
-               l.team = l.enemy.team;
-               l.colormap = l.enemy.colormap;
-               l = l.chain;
-       }
-}
-
-
-// ===================
-// Main Link Functions
-// ===================
-
-bool ons_Link_Send(entity this, entity to, int sendflags)
-{
-       WriteByte(MSG_ENTITY, ENT_CLIENT_RADARLINK);
-       WriteByte(MSG_ENTITY, sendflags);
-       if(sendflags & 1)
-       {
-               WriteCoord(MSG_ENTITY, self.goalentity.origin_x);
-               WriteCoord(MSG_ENTITY, self.goalentity.origin_y);
-               WriteCoord(MSG_ENTITY, self.goalentity.origin_z);
-       }
-       if(sendflags & 2)
-       {
-               WriteCoord(MSG_ENTITY, self.enemy.origin_x);
-               WriteCoord(MSG_ENTITY, self.enemy.origin_y);
-               WriteCoord(MSG_ENTITY, self.enemy.origin_z);
-       }
-       if(sendflags & 4)
-       {
-               WriteByte(MSG_ENTITY, self.clientcolors); // which is goalentity's color + enemy's color * 16
-       }
-       return true;
-}
-
-void ons_Link_CheckUpdate()
-{SELFPARAM();
-       // TODO check if the two sides have moved (currently they won't move anyway)
-       float cc = 0, cc1 = 0, cc2 = 0;
-
-       if(self.goalentity.islinked || self.goalentity.iscaptured) { cc1 = (self.goalentity.team - 1) * 0x01; }
-       if(self.enemy.islinked || self.enemy.iscaptured) { cc2 = (self.enemy.team - 1) * 0x10; }
-
-       cc = cc1 + cc2;
-
-       if(cc != self.clientcolors)
-       {
-               self.clientcolors = cc;
-               self.SendFlags |= 4;
-       }
-
-       self.nextthink = time;
-}
-
-void ons_DelayedLinkSetup()
-{SELFPARAM();
-       self.goalentity = find(world, targetname, self.target);
-       self.enemy = find(world, targetname, self.target2);
-       if(!self.goalentity) { objerror("can not find target\n"); }
-       if(!self.enemy) { objerror("can not find target2\n"); }
-
-       ons_debug(strcat(etos(self.goalentity), " linked with ", etos(self.enemy), "\n"));
-       self.SendFlags |= 3;
-       self.think = ons_Link_CheckUpdate;
-       self.nextthink = time;
-}
-
-
-// =============================
-// Main Control Point Functions
-// =============================
-
-int ons_ControlPoint_CanBeLinked(entity cp, int teamnumber)
-{
-       if(cp.isgenneighbor[teamnumber]) { return 2; }
-       if(cp.iscpneighbor[teamnumber]) { return 1; }
-
-       return 0;
-}
-
-int ons_ControlPoint_Attackable(entity cp, int teamnumber)
-       // -2: SAME TEAM, attackable by enemy!
-       // -1: SAME TEAM!
-       // 0: off limits
-       // 1: attack it
-       // 2: touch it
-       // 3: attack it (HIGH PRIO)
-       // 4: touch it (HIGH PRIO)
-{
-       int a;
-
-       if(cp.isshielded)
-       {
-               return 0;
-       }
-       else if(cp.goalentity)
-       {
-               // if there's already an icon built, nothing happens
-               if(cp.team == teamnumber)
-               {
-                       a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
-                       if(a) // attackable by enemy?
-                               return -2; // EMERGENCY!
-                       return -1;
-               }
-               // we know it can be linked, so no need to check
-               // but...
-               a = ons_ControlPoint_CanBeLinked(cp, teamnumber);
-               if(a == 2) // near our generator?
-                       return 3; // EMERGENCY!
-               return 1;
-       }
-       else
-       {
-               // free point
-               if(ons_ControlPoint_CanBeLinked(cp, teamnumber))
-               {
-                       a = ons_ControlPoint_CanBeLinked(cp, teamnumber); // why was this here NUM_TEAM_1 + NUM_TEAM_2 - t
-                       if(a == 2)
-                               return 4; // GET THIS ONE NOW!
-                       else
-                               return 2; // TOUCH ME
-               }
-       }
-       return 0;
-}
-
-void ons_ControlPoint_Icon_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
-       if(damage <= 0) { return; }
-
-       if (self.owner.isshielded)
-       {
-               // this is protected by a shield, so ignore the damage
-               if (time > self.pain_finished)
-                       if (IS_PLAYER(attacker))
-                       {
-                               play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
-                               self.pain_finished = time + 1;
-                               attacker.typehitsound += 1; // play both sounds (shield is way too quiet)
-                       }
-
-               return;
-       }
-
-       if(IS_PLAYER(attacker))
-       if(time - ons_notification_time[self.team] > 10)
-       {
-               play2team(self.team, SND(ONS_CONTROLPOINT_UNDERATTACK));
-               ons_notification_time[self.team] = time;
-       }
-
-       self.health = self.health - damage;
-       if(self.owner.iscaptured)
-               WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
-       else
-               WaypointSprite_UpdateBuildFinished(self.owner.sprite, time + (self.max_health - self.health) / (self.count / ONS_CP_THINKRATE));
-       self.pain_finished = time + 1;
-       // particles on every hit
-       pointparticles(particleeffectnum(EFFECT_SPARKS), hitloc, force*-1, 1);
-       //sound on every hit
-       if (random() < 0.5)
-               sound(self, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE+0.3, ATTEN_NORM);
-       else
-               sound(self, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE+0.3, ATTEN_NORM);
-
-       if (self.health < 0)
-       {
-               sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
-               pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), self.origin, '0 0 0', 1);
-               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_CPDESTROYED_), self.owner.message, attacker.netname);
-
-               PlayerScore_Add(attacker, SP_ONS_TAKES, 1);
-               PlayerScore_Add(attacker, SP_SCORE, 10);
-
-               self.owner.goalentity = world;
-               self.owner.islinked = false;
-               self.owner.iscaptured = false;
-               self.owner.team = 0;
-               self.owner.colormap = 1024;
-
-               WaypointSprite_UpdateMaxHealth(self.owner.sprite, 0);
-
-               onslaught_updatelinks();
-
-               // Use targets now (somebody make sure this is in the right place..)
-               setself(self.owner);
-               activator = self;
-               SUB_UseTargets ();
-               setself(this);
-
-               self.owner.waslinked = self.owner.islinked;
-               if(self.owner.model != "models/onslaught/controlpoint_pad.md3")
-                       setmodel_fixsize(self.owner, MDL_ONS_CP_PAD1);
-               //setsize(self, '-32 -32 0', '32 32 8');
-
-               remove(self);
-       }
-
-       self.SendFlags |= CPSF_STATUS;
-}
-
-void ons_ControlPoint_Icon_Think()
-{SELFPARAM();
-       self.nextthink = time + ONS_CP_THINKRATE;
-
-       if(autocvar_g_onslaught_cp_proxydecap)
-       {
-        int _enemy_count = 0;
-        int _friendly_count = 0;
-        float _dist;
-        entity _player;
-
-        FOR_EACH_PLAYER(_player)
-        {
-            if(!_player.deadflag)
-            {
-                _dist = vlen(_player.origin - self.origin);
-                if(_dist < autocvar_g_onslaught_cp_proxydecap_distance)
-                {
-                                       if(SAME_TEAM(_player, self))
-                        ++_friendly_count;
-                    else
-                        ++_enemy_count;
-                }
-            }
-        }
-
-        _friendly_count = _friendly_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
-        _enemy_count = _enemy_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
-
-        self.health = bound(0, self.health + (_friendly_count - _enemy_count), self.max_health);
-               self.SendFlags |= CPSF_STATUS;
-        if(self.health <= 0)
-        {
-            ons_ControlPoint_Icon_Damage(self, self, 1, 0, self.origin, '0 0 0');
-            return;
-        }
-    }
-
-       if (time > self.pain_finished + 5)
-       {
-               if(self.health < self.max_health)
-               {
-                       self.health = self.health + self.count;
-                       if (self.health >= self.max_health)
-                               self.health = self.max_health;
-                       WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
-               }
-       }
-
-       if(self.owner.islinked != self.owner.waslinked)
-       {
-               // unteam the spawnpoint if needed
-               int t = self.owner.team;
-               if(!self.owner.islinked)
-                       self.owner.team = 0;
-
-               setself(self.owner);
-               activator = self;
-               SUB_UseTargets ();
-               setself(this);
-
-               self.owner.team = t;
-
-               self.owner.waslinked = self.owner.islinked;
-       }
-
-       // damaged fx
-       if(random() < 0.6 - self.health / self.max_health)
-       {
-               Send_Effect(EFFECT_ELECTRIC_SPARKS, self.origin + randompos('-10 -10 -20', '10 10 20'), '0 0 0', 1);
-
-               if(random() > 0.8)
-                       sound(self, CH_PAIN, SND_ONS_SPARK1, VOL_BASE, ATTEN_NORM);
-               else if (random() > 0.5)
-                       sound(self, CH_PAIN, SND_ONS_SPARK2, VOL_BASE, ATTEN_NORM);
-       }
-}
-
-void ons_ControlPoint_Icon_BuildThink()
-{SELFPARAM();
-       int a;
-
-       self.nextthink = time + ONS_CP_THINKRATE;
-
-       // only do this if there is power
-       a = ons_ControlPoint_CanBeLinked(self.owner, self.owner.team);
-       if(!a)
-               return;
-
-       self.health = self.health + self.count;
-
-       self.SendFlags |= CPSF_STATUS;
-
-       if (self.health >= self.max_health)
-       {
-               self.health = self.max_health;
-               self.count = autocvar_g_onslaught_cp_regen * ONS_CP_THINKRATE; // slow repair rate from now on
-               self.think = ons_ControlPoint_Icon_Think;
-               sound(self, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILT, VOL_BASE, ATTEN_NORM);
-               self.owner.iscaptured = true;
-               self.solid = SOLID_BBOX;
-
-               Send_Effect(EFFECT_CAP(self.owner.team), self.owner.origin, '0 0 0', 1);
-
-               WaypointSprite_UpdateMaxHealth(self.owner.sprite, self.max_health);
-               WaypointSprite_UpdateHealth(self.owner.sprite, self.health);
-
-               if(IS_PLAYER(self.owner.ons_toucher))
-               {
-                       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ONSLAUGHT_CAPTURE, self.owner.ons_toucher.netname, self.owner.message);
-                       Send_Notification(NOTIF_ALL_EXCEPT, self.owner.ons_toucher, MSG_CENTER, APP_TEAM_ENT_4(self.owner.ons_toucher, CENTER_ONS_CAPTURE_), self.owner.message);
-                       Send_Notification(NOTIF_ONE, self.owner.ons_toucher, MSG_CENTER, CENTER_ONS_CAPTURE, self.owner.message);
-                       PlayerScore_Add(self.owner.ons_toucher, SP_ONS_CAPS, 1);
-                       PlayerTeamScore_AddScore(self.owner.ons_toucher, 10);
-               }
-
-               self.owner.ons_toucher = world;
-
-               onslaught_updatelinks();
-
-               // Use targets now (somebody make sure this is in the right place..)
-               setself(self.owner);
-               activator = self;
-               SUB_UseTargets ();
-               setself(this);
-
-               self.SendFlags |= CPSF_SETUP;
-       }
-       if(self.owner.model != MDL_ONS_CP_PAD2.model_str())
-               setmodel_fixsize(self.owner, MDL_ONS_CP_PAD2);
-
-       if(random() < 0.9 - self.health / self.max_health)
-               Send_Effect(EFFECT_RAGE, self.origin + 10 * randomvec(), '0 0 -1', 1);
-}
-
-void onslaught_controlpoint_icon_link(entity e, void() spawnproc);
-
-void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
-{
-       entity e = spawn();
-
-       setsize(e, CPICON_MIN, CPICON_MAX);
-       setorigin(e, cp.origin + CPICON_OFFSET);
-
-       e.classname = "onslaught_controlpoint_icon";
-       e.owner = cp;
-       e.max_health = autocvar_g_onslaught_cp_health;
-       e.health = autocvar_g_onslaught_cp_buildhealth;
-       e.solid = SOLID_NOT;
-       e.takedamage = DAMAGE_AIM;
-       e.bot_attack = true;
-       e.event_damage = ons_ControlPoint_Icon_Damage;
-       e.team = player.team;
-       e.colormap = 1024 + (e.team - 1) * 17;
-       e.count = (e.max_health - e.health) * ONS_CP_THINKRATE / autocvar_g_onslaught_cp_buildtime; // how long it takes to build
-
-       sound(e, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILD, VOL_BASE, ATTEN_NORM);
-
-       cp.goalentity = e;
-       cp.team = e.team;
-       cp.colormap = e.colormap;
-
-       Send_Effect(EFFECT_FLAG_TOUCH(player.team), e.origin, '0 0 0', 1);
-
-       WaypointSprite_UpdateBuildFinished(cp.sprite, time + (e.max_health - e.health) / (e.count / ONS_CP_THINKRATE));
-       WaypointSprite_UpdateRule(cp.sprite,cp.team,SPRITERULE_TEAMPLAY);
-       cp.sprite.SendFlags |= 16;
-
-       onslaught_controlpoint_icon_link(e, ons_ControlPoint_Icon_BuildThink);
-}
-
-entity ons_ControlPoint_Waypoint(entity e)
-{
-       if(e.team)
-       {
-               int a = ons_ControlPoint_Attackable(e, e.team);
-
-               if(a == -2) { return WP_OnsCPDefend; } // defend now
-               if(a == -1 || a == 1 || a == 2) { return WP_OnsCP; } // touch
-               if(a == 3 || a == 4) { return WP_OnsCPAttack; } // attack
-       }
-       else
-               return WP_OnsCP;
-
-       return WP_Null;
-}
-
-void ons_ControlPoint_UpdateSprite(entity e)
-{
-       entity s1 = ons_ControlPoint_Waypoint(e);
-       WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
-
-       bool sh;
-       sh = !(ons_ControlPoint_CanBeLinked(e, NUM_TEAM_1) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_2) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_3) || ons_ControlPoint_CanBeLinked(e, NUM_TEAM_4));
-
-       if(e.lastteam != e.team + 2 || e.lastshielded != sh || e.iscaptured != e.lastcaptured)
-       {
-               if(e.iscaptured) // don't mess up build bars!
-               {
-                       if(sh)
-                       {
-                               WaypointSprite_UpdateMaxHealth(e.sprite, 0);
-                       }
-                       else
-                       {
-                               WaypointSprite_UpdateMaxHealth(e.sprite, e.goalentity.max_health);
-                               WaypointSprite_UpdateHealth(e.sprite, e.goalentity.health);
-                       }
-               }
-               if(e.lastshielded)
-               {
-                       if(e.team)
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, 0.5 * colormapPaletteColor(e.team - 1, false));
-                       else
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.5 0.5 0.5');
-               }
-               else
-               {
-                       if(e.team)
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, colormapPaletteColor(e.team - 1, false));
-                       else
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.75 0.75 0.75');
-               }
-               WaypointSprite_Ping(e.sprite);
-
-               e.lastteam = e.team + 2;
-               e.lastshielded = sh;
-               e.lastcaptured = e.iscaptured;
-       }
-}
-
-void ons_ControlPoint_Touch()
-{SELFPARAM();
-       entity toucher = other;
-       int attackable;
-
-       if(IS_VEHICLE(toucher) && toucher.owner)
-       if(autocvar_g_onslaught_allow_vehicle_touch)
-               toucher = toucher.owner;
-       else
-               return;
-
-       if(!IS_PLAYER(toucher)) { return; }
-       if(toucher.frozen) { return; }
-       if(toucher.deadflag != DEAD_NO) { return; }
-
-       if ( SAME_TEAM(self,toucher) )
-       if ( self.iscaptured )
-       {
-               if(time <= toucher.teleport_antispam)
-                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT_ANTISPAM, rint(toucher.teleport_antispam - time));
-               else
-                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_ONS_TELEPORT);
-       }
-
-       attackable = ons_ControlPoint_Attackable(self, toucher.team);
-       if(attackable != 2 && attackable != 4)
-               return;
-       // we've verified that this player has a legitimate claim to this point,
-       // so start building the captured point icon (which only captures this
-       // point if it successfully builds without being destroyed first)
-       ons_ControlPoint_Icon_Spawn(self, toucher);
-
-       self.ons_toucher = toucher;
-
-       onslaught_updatelinks();
-}
-
-void ons_ControlPoint_Think()
-{SELFPARAM();
-       self.nextthink = time + ONS_CP_THINKRATE;
-       CSQCMODEL_AUTOUPDATE(self);
-}
-
-void ons_ControlPoint_Reset()
-{SELFPARAM();
-       if(self.goalentity)
-               remove(self.goalentity);
-
-       self.goalentity = world;
-       self.team = 0;
-       self.colormap = 1024;
-       self.iscaptured = false;
-       self.islinked = false;
-       self.isshielded = true;
-       self.think = ons_ControlPoint_Think;
-       self.ons_toucher = world;
-       self.nextthink = time + ONS_CP_THINKRATE;
-       setmodel_fixsize(self, MDL_ONS_CP_PAD1);
-
-       WaypointSprite_UpdateMaxHealth(self.sprite, 0);
-       WaypointSprite_UpdateRule(self.sprite,self.team,SPRITERULE_TEAMPLAY);
-
-       onslaught_updatelinks();
-
-       activator = self;
-       SUB_UseTargets(); // to reset the structures, playerspawns etc.
-
-       CSQCMODEL_AUTOUPDATE(self);
-}
-
-void ons_DelayedControlPoint_Setup(void)
-{SELFPARAM();
-       onslaught_updatelinks();
-
-       // captureshield setup
-       ons_CaptureShield_Spawn(self, false);
-
-       CSQCMODEL_AUTOINIT(self);
-}
-
-void ons_ControlPoint_Setup(entity cp)
-{SELFPARAM();
-       // declarations
-       setself(cp); // for later usage with droptofloor()
-
-       // main setup
-       cp.ons_worldcpnext = ons_worldcplist; // link control point into ons_worldcplist
-       ons_worldcplist = cp;
-
-       cp.netname = "Control point";
-       cp.team = 0;
-       cp.solid = SOLID_BBOX;
-       cp.movetype = MOVETYPE_NONE;
-       cp.touch = ons_ControlPoint_Touch;
-       cp.think = ons_ControlPoint_Think;
-       cp.nextthink = time + ONS_CP_THINKRATE;
-       cp.reset = ons_ControlPoint_Reset;
-       cp.colormap = 1024;
-       cp.iscaptured = false;
-       cp.islinked = false;
-       cp.isshielded = true;
-
-       if(cp.message == "") { cp.message = "a"; }
-
-       // appearence
-       setmodel_fixsize(cp, MDL_ONS_CP_PAD1);
-
-       // control point placement
-       if((cp.spawnflags & 1) || cp.noalign) // don't drop to floor, just stay at fixed location
-       {
-               cp.noalign = true;
-               cp.movetype = MOVETYPE_NONE;
-       }
-       else // drop to floor, automatically find a platform and set that as spawn origin
-       {
-               setorigin(cp, cp.origin + '0 0 20');
-               cp.noalign = false;
-               setself(cp);
-               droptofloor();
-               cp.movetype = MOVETYPE_TOSS;
-       }
-
-       // waypointsprites
-       WaypointSprite_SpawnFixed(WP_Null, self.origin + CPGEN_WAYPOINT_OFFSET, self, sprite, RADARICON_NONE);
-       WaypointSprite_UpdateRule(self.sprite, self.team, SPRITERULE_TEAMPLAY);
-
-       InitializeEntity(cp, ons_DelayedControlPoint_Setup, INITPRIO_SETLOCATION);
-}
-
-
-// =========================
-// Main Generator Functions
-// =========================
-
-entity ons_Generator_Waypoint(entity e)
-{
-       if (e.isshielded)
-               return WP_OnsGenShielded;
-       return WP_OnsGen;
-}
-
-void ons_Generator_UpdateSprite(entity e)
-{
-       entity s1 = ons_Generator_Waypoint(e);
-       WaypointSprite_UpdateSprites(e.sprite, s1, s1, s1);
-
-       if(e.lastteam != e.team + 2 || e.lastshielded != e.isshielded)
-       {
-               e.lastteam = e.team + 2;
-               e.lastshielded = e.isshielded;
-               if(e.lastshielded)
-               {
-                       if(e.team)
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, 0.5 * colormapPaletteColor(e.team - 1, false));
-                       else
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.5 0.5 0.5');
-               }
-               else
-               {
-                       if(e.team)
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, colormapPaletteColor(e.team - 1, false));
-                       else
-                               WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.75 0.75 0.75');
-               }
-               WaypointSprite_Ping(e.sprite);
-       }
-}
-
-void ons_GeneratorDamage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
-       if(damage <= 0) { return; }
-       if(warmup_stage || gameover) { return; }
-       if(!round_handler_IsRoundStarted()) { return; }
-
-       if (attacker != self)
-       {
-               if (self.isshielded)
-               {
-                       // this is protected by a shield, so ignore the damage
-                       if (time > self.pain_finished)
-                               if (IS_PLAYER(attacker))
-                               {
-                                       play2(attacker, SND(ONS_DAMAGEBLOCKEDBYSHIELD));
-                                       attacker.typehitsound += 1;
-                                       self.pain_finished = time + 1;
-                               }
-                       return;
-               }
-               if (time > self.pain_finished)
-               {
-                       self.pain_finished = time + 10;
-                       entity head;
-                       FOR_EACH_REALPLAYER(head) if(SAME_TEAM(head, self)) { Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_GENERATOR_UNDERATTACK); }
-                       play2team(self.team, SND(ONS_GENERATOR_UNDERATTACK));
-               }
-       }
-       self.health = self.health - damage;
-       WaypointSprite_UpdateHealth(self.sprite, self.health);
-       // choose an animation frame based on health
-       self.frame = 10 * bound(0, (1 - self.health / self.max_health), 1);
-       // see if the generator is still functional, or dying
-       if (self.health > 0)
-       {
-               self.lasthealth = self.health;
-       }
-       else
-       {
-               if (attacker == self)
-                       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_GENDESTROYED_OVERTIME_));
-               else
-               {
-                       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(self.team, INFO_ONSLAUGHT_GENDESTROYED_));
-                       PlayerScore_Add(attacker, SP_SCORE, 100);
-               }
-               self.iscaptured = false;
-               self.islinked = false;
-               self.isshielded = false;
-               self.takedamage = DAMAGE_NO; // can't be hurt anymore
-               self.event_damage = func_null; // won't do anything if hurt
-               self.count = 0; // reset counter
-               self.think = func_null;
-               self.nextthink = 0;
-               //self.think(); // do the first explosion now
-
-               WaypointSprite_UpdateMaxHealth(self.sprite, 0);
-               WaypointSprite_Ping(self.sprite);
-               //WaypointSprite_Kill(self.sprite); // can't do this yet, code too poor
-
-               onslaught_updatelinks();
-       }
-
-       // Throw some flaming gibs on damage, more damage = more chance for gib
-       if(random() < damage/220)
-       {
-               sound(self, CH_TRIGGER, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-       }
-       else
-       {
-               // particles on every hit
-               Send_Effect(EFFECT_SPARKS, hitloc, force * -1, 1);
-
-               //sound on every hit
-               if (random() < 0.5)
-                       sound(self, CH_TRIGGER, SND_ONS_HIT1, VOL_BASE, ATTEN_NORM);
-               else
-                       sound(self, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE, ATTEN_NORM);
-       }
-
-       self.SendFlags |= GSF_STATUS;
-}
-
-void ons_GeneratorThink()
-{SELFPARAM();
-       entity e;
-       self.nextthink = time + GEN_THINKRATE;
-       if (!gameover)
-       {
-        if(!self.isshielded && self.wait < time)
-        {
-            self.wait = time + 5;
-            FOR_EACH_REALPLAYER(e)
-            {
-                               if(SAME_TEAM(e, self))
-                               {
-                                       Send_Notification(NOTIF_ONE, e, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM);
-                    soundto(MSG_ONE, e, CHAN_AUTO, SND(KH_ALARM), VOL_BASE, ATTEN_NONE);    // FIXME: unique sound?
-                }
-                               else
-                                       Send_Notification(NOTIF_ONE, e, MSG_CENTER, APP_TEAM_NUM_4(self.team, CENTER_ONS_NOTSHIELDED_));
-            }
-        }
-       }
-}
-
-void ons_GeneratorReset()
-{SELFPARAM();
-       self.team = self.team_saved;
-       self.lasthealth = self.max_health = self.health = autocvar_g_onslaught_gen_health;
-       self.takedamage = DAMAGE_AIM;
-       self.bot_attack = true;
-       self.iscaptured = true;
-       self.islinked = true;
-       self.isshielded = true;
-       self.event_damage = ons_GeneratorDamage;
-       self.think = ons_GeneratorThink;
-       self.nextthink = time + GEN_THINKRATE;
-
-       Net_LinkEntity(self, false, 0, generator_send);
-
-       self.SendFlags = GSF_SETUP; // just incase
-       self.SendFlags |= GSF_STATUS;
-
-       WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
-       WaypointSprite_UpdateHealth(self.sprite, self.health);
-       WaypointSprite_UpdateRule(self.sprite,self.team,SPRITERULE_TEAMPLAY);
-
-       onslaught_updatelinks();
-}
-
-void ons_DelayedGeneratorSetup()
-{SELFPARAM();
-       // bot waypoints
-       waypoint_spawnforitem_force(self, self.origin);
-       self.nearestwaypointtimeout = 0; // activate waypointing again
-       self.bot_basewaypoint = self.nearestwaypoint;
-
-       // captureshield setup
-       ons_CaptureShield_Spawn(self, true);
-
-       onslaught_updatelinks();
-
-       Net_LinkEntity(self, false, 0, generator_send);
-}
-
-
-void onslaught_generator_touch()
-{SELFPARAM();
-       if ( IS_PLAYER(other) )
-       if ( SAME_TEAM(self,other) )
-       if ( self.iscaptured )
-       {
-               Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_ONS_TELEPORT);
-       }
-}
-
-void ons_GeneratorSetup(entity gen) // called when spawning a generator entity on the map as a spawnfunc
-{SELFPARAM();
-       // declarations
-       int teamnumber = gen.team;
-       setself(gen); // for later usage with droptofloor()
-
-       // main setup
-       gen.ons_worldgeneratornext = ons_worldgeneratorlist; // link generator into ons_worldgeneratorlist
-       ons_worldgeneratorlist = gen;
-
-       gen.netname = sprintf("%s generator", Team_ColoredFullName(teamnumber));
-       gen.classname = "onslaught_generator";
-       gen.solid = SOLID_BBOX;
-       gen.team_saved = teamnumber;
-       gen.movetype = MOVETYPE_NONE;
-       gen.lasthealth = gen.max_health = gen.health = autocvar_g_onslaught_gen_health;
-       gen.takedamage = DAMAGE_AIM;
-       gen.bot_attack = true;
-       gen.event_damage = ons_GeneratorDamage;
-       gen.reset = ons_GeneratorReset;
-       gen.think = ons_GeneratorThink;
-       gen.nextthink = time + GEN_THINKRATE;
-       gen.iscaptured = true;
-       gen.islinked = true;
-       gen.isshielded = true;
-       gen.touch = onslaught_generator_touch;
-
-       // appearence
-       // model handled by CSQC
-       setsize(gen, GENERATOR_MIN, GENERATOR_MAX);
-       setorigin(gen, (gen.origin + CPGEN_SPAWN_OFFSET));
-       gen.colormap = 1024 + (teamnumber - 1) * 17;
-
-       // generator placement
-       setself(gen);
-       droptofloor();
-
-       // waypointsprites
-       WaypointSprite_SpawnFixed(WP_Null, self.origin + CPGEN_WAYPOINT_OFFSET, self, sprite, RADARICON_NONE);
-       WaypointSprite_UpdateRule(self.sprite, self.team, SPRITERULE_TEAMPLAY);
-       WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
-       WaypointSprite_UpdateHealth(self.sprite, self.health);
-
-       InitializeEntity(gen, ons_DelayedGeneratorSetup, INITPRIO_SETLOCATION);
-}
-
-
-// ===============
-//  Round Handler
-// ===============
-
-int total_generators;
-void Onslaught_count_generators()
-{
-       entity e;
-       total_generators = redowned = blueowned = yellowowned = pinkowned = 0;
-       for(e = ons_worldgeneratorlist; e; e = e.ons_worldgeneratornext)
-       {
-               ++total_generators;
-               redowned += (e.team == NUM_TEAM_1 && e.health > 0);
-               blueowned += (e.team == NUM_TEAM_2 && e.health > 0);
-               yellowowned += (e.team == NUM_TEAM_3 && e.health > 0);
-               pinkowned += (e.team == NUM_TEAM_4 && e.health > 0);
-       }
-}
-
-int Onslaught_GetWinnerTeam()
-{
-       int winner_team = 0;
-       if(redowned > 0)
-               winner_team = NUM_TEAM_1;
-       if(blueowned > 0)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_2;
-       }
-       if(yellowowned > 0)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_3;
-       }
-       if(pinkowned > 0)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_4;
-       }
-       if(winner_team)
-               return winner_team;
-       return -1; // no generators left?
-}
-
-#define ONS_OWNED_GENERATORS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
-#define ONS_OWNED_GENERATORS_OK() (ONS_OWNED_GENERATORS() > 1)
-bool Onslaught_CheckWinner()
-{
-       entity e;
-
-       if ((autocvar_timelimit && time > game_starttime + autocvar_timelimit * 60) || (round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0))
-       {
-               ons_stalemate = true;
-
-               if (!wpforenemy_announced)
-               {
-                       Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT);
-                       sound(world, CH_INFO, SND_ONS_GENERATOR_DECAY, VOL_BASE, ATTEN_NONE);
-
-                       wpforenemy_announced = true;
-               }
-
-               entity tmp_entity; // temporary entity
-               float d;
-               for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext) if(time >= tmp_entity.ons_overtime_damagedelay)
-               {
-                       // tmp_entity.max_health / 300 gives 5 minutes of overtime.
-                       // control points reduce the overtime duration.
-                       d = 1;
-                       for(e = ons_worldcplist; e; e = e.ons_worldcpnext)
-                       {
-                               if(DIFF_TEAM(e, tmp_entity))
-                               if(e.islinked)
-                                       d = d + 1;
-                       }
-
-                       if(autocvar_g_campaign && autocvar__campaign_testrun)
-                               d = d * tmp_entity.max_health;
-                       else
-                               d = d * tmp_entity.max_health / max(30, 60 * autocvar_timelimit_suddendeath);
-
-                       Damage(tmp_entity, tmp_entity, tmp_entity, d, DEATH_HURTTRIGGER.m_id, tmp_entity.origin, '0 0 0');
-
-                       tmp_entity.sprite.SendFlags |= 16;
-
-                       tmp_entity.ons_overtime_damagedelay = time + 1;
-               }
-       }
-       else { wpforenemy_announced = false; ons_stalemate = false; }
-
-       Onslaught_count_generators();
-
-       if(ONS_OWNED_GENERATORS_OK())
-               return 0;
-
-       int winner_team = Onslaught_GetWinnerTeam();
-
-       if(winner_team > 0)
-       {
-               Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM_4(winner_team, CENTER_ROUND_TEAM_WIN_));
-               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(winner_team, INFO_ROUND_TEAM_WIN_));
-               TeamScore_AddToTeam(winner_team, ST_ONS_CAPS, +1);
-       }
-       else if(winner_team == -1)
-       {
-               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED);
-               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED);
-       }
-
-       ons_stalemate = false;
-
-       play2all(SND(CTF_CAPTURE(winner_team)));
-
-       round_handler_Init(7, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
-
-       FOR_EACH_PLAYER(e)
-       {
-               e.ons_roundlost = true;
-               e.player_blocked = true;
-
-               nades_Clear(e);
-       }
-
-       return 1;
-}
-
-bool Onslaught_CheckPlayers()
-{
-       return 1;
-}
-
-void Onslaught_RoundStart()
-{
-       entity tmp_entity;
-       FOR_EACH_PLAYER(tmp_entity) { tmp_entity.player_blocked = false; }
-
-       for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
-               tmp_entity.sprite.SendFlags |= 16;
-
-       for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
-               tmp_entity.sprite.SendFlags |= 16;
-}
-
-
-// ================
-// Bot player logic
-// ================
-
-// NOTE: LEGACY CODE, needs to be re-written!
-
-void havocbot_goalrating_ons_offenseitems(float ratingscale, vector org, float sradius)
-{SELFPARAM();
-       entity head;
-       float t, c;
-       int i;
-       bool needarmor = false, needweapons = false;
-
-       // Needs armor/health?
-       if(self.health<100)
-               needarmor = true;
-
-       // Needs weapons?
-       c = 0;
-       for(i = WEP_FIRST; i <= WEP_LAST ; ++i)
-       {
-               // Find weapon
-               if(self.weapons & WepSet_FromWeapon(i))
-               if(++c>=4)
-                       break;
-       }
-
-       if(c<4)
-               needweapons = true;
-
-       if(!needweapons && !needarmor)
-               return;
-
-       ons_debug(strcat(self.netname, " needs weapons ", ftos(needweapons) , "\n"));
-       ons_debug(strcat(self.netname, " needs armor ", ftos(needarmor) , "\n"));
-
-       // See what is around
-       head = findchainfloat(bot_pickup, true);
-       while (head)
-       {
-               // gather health and armor only
-               if (head.solid)
-               if ( ((head.health || head.armorvalue) && needarmor) || (head.weapons && needweapons ) )
-               if (vlen(head.origin - org) < sradius)
-               {
-                       t = head.bot_pickupevalfunc(self, head);
-                       if (t > 0)
-                               navigation_routerating(head, t * ratingscale, 500);
-               }
-               head = head.chain;
-       }
-}
-
-void havocbot_role_ons_setrole(entity bot, int role)
-{
-       ons_debug(strcat(bot.netname," switched to "));
-       switch(role)
-       {
-               case HAVOCBOT_ONS_ROLE_DEFENSE:
-                       ons_debug("defense");
-                       bot.havocbot_role = havocbot_role_ons_defense;
-                       bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
-                       bot.havocbot_role_timeout = 0;
-                       break;
-               case HAVOCBOT_ONS_ROLE_ASSISTANT:
-                       ons_debug("assistant");
-                       bot.havocbot_role = havocbot_role_ons_assistant;
-                       bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
-                       bot.havocbot_role_timeout = 0;
-                       break;
-               case HAVOCBOT_ONS_ROLE_OFFENSE:
-                       ons_debug("offense");
-                       bot.havocbot_role = havocbot_role_ons_offense;
-                       bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
-                       bot.havocbot_role_timeout = 0;
-                       break;
-       }
-       ons_debug("\n");
-}
-
-int havocbot_ons_teamcount(entity bot, int role)
-{SELFPARAM();
-       int c = 0;
-       entity head;
-
-       FOR_EACH_PLAYER(head)
-       if(SAME_TEAM(head, self))
-       if(head.havocbot_role_flags & role)
-               ++c;
-
-       return c;
-}
-
-void havocbot_goalrating_ons_controlpoints_attack(float ratingscale)
-{SELFPARAM();
-       entity cp, cp1, cp2, best, pl, wp;
-       float radius, bestvalue;
-       int c;
-       bool found;
-
-       // Filter control points
-       for(cp2 = ons_worldcplist; cp2; cp2 = cp2.ons_worldcpnext)
-       {
-               cp2.wpcost = c = 0;
-               cp2.wpconsidered = false;
-
-               if(cp2.isshielded)
-                       continue;
-
-               // Ignore owned controlpoints
-               if(!(cp2.isgenneighbor[self.team] || cp2.iscpneighbor[self.team]))
-                       continue;
-
-               // Count team mates interested in this control point
-               // (easier and cleaner than keeping counters per cp and teams)
-               FOR_EACH_PLAYER(pl)
-               if(SAME_TEAM(pl, self))
-               if(pl.havocbot_role_flags & HAVOCBOT_ONS_ROLE_OFFENSE)
-               if(pl.havocbot_ons_target==cp2)
-                       ++c;
-
-               // NOTE: probably decrease the cost of attackable control points
-               cp2.wpcost = c;
-               cp2.wpconsidered = true;
-       }
-
-       // We'll consider only the best case
-       bestvalue = 99999999999;
-       cp = world;
-       for(cp1 = ons_worldcplist; cp1; cp1 = cp1.ons_worldcpnext)
-       {
-               if (!cp1.wpconsidered)
-                       continue;
-
-               if(cp1.wpcost<bestvalue)
-               {
-                       bestvalue = cp1.wpcost;
-                       cp = cp1;
-                       self.havocbot_ons_target = cp1;
-               }
-       }
-
-       if (!cp)
-               return;
-
-       ons_debug(strcat(self.netname, " chose cp ranked ", ftos(bestvalue), "\n"));
-
-       if(cp.goalentity)
-       {
-               // Should be attacked
-               // Rate waypoints near it
-               found = false;
-               best = world;
-               bestvalue = 99999999999;
-               for(radius=0; radius<1000 && !found; radius+=500)
-               {
-                       for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
-                       {
-                               if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
-                               if(wp.classname=="waypoint")
-                               if(checkpvs(wp.origin,cp))
-                               {
-                                       found = true;
-                                       if(wp.cnt<bestvalue)
-                                       {
-                                               best = wp;
-                                               bestvalue = wp.cnt;
-                                       }
-                               }
-                       }
-               }
-
-               if(best)
-               {
-                       navigation_routerating(best, ratingscale, 10000);
-                       best.cnt += 1;
-
-                       self.havocbot_attack_time = 0;
-                       if(checkpvs(self.view_ofs,cp))
-                       if(checkpvs(self.view_ofs,best))
-                               self.havocbot_attack_time = time + 2;
-               }
-               else
-               {
-                       navigation_routerating(cp, ratingscale, 10000);
-               }
-               ons_debug(strcat(self.netname, " found an attackable controlpoint at ", vtos(cp.origin) ,"\n"));
-       }
-       else
-       {
-               // Should be touched
-               ons_debug(strcat(self.netname, " found a touchable controlpoint at ", vtos(cp.origin) ,"\n"));
-               found = false;
-
-               // Look for auto generated waypoint
-               if (!bot_waypoints_for_items)
-               for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
-               {
-                       if(wp.classname=="waypoint")
-                       {
-                               navigation_routerating(wp, ratingscale, 10000);
-                               found = true;
-                       }
-               }
-
-               // Nothing found, rate the controlpoint itself
-               if (!found)
-                       navigation_routerating(cp, ratingscale, 10000);
-       }
-}
-
-bool havocbot_goalrating_ons_generator_attack(float ratingscale)
-{SELFPARAM();
-       entity g, wp, bestwp;
-       bool found;
-       int best;
-
-       for(g = ons_worldgeneratorlist; g; g = g.ons_worldgeneratornext)
-       {
-               if(SAME_TEAM(g, self) || g.isshielded)
-                       continue;
-
-               // Should be attacked
-               // Rate waypoints near it
-               found = false;
-               bestwp = world;
-               best = 99999999999;
-
-               for(wp=findradius(g.origin,400); wp; wp=wp.chain)
-               {
-                       if(wp.classname=="waypoint")
-                       if(checkpvs(wp.origin,g))
-                       {
-                               found = true;
-                               if(wp.cnt<best)
-                               {
-                                       bestwp = wp;
-                                       best = wp.cnt;
-                               }
-                       }
-               }
-
-               if(bestwp)
-               {
-                       ons_debug("waypoints found around generator\n");
-                       navigation_routerating(bestwp, ratingscale, 10000);
-                       bestwp.cnt += 1;
-
-                       self.havocbot_attack_time = 0;
-                       if(checkpvs(self.view_ofs,g))
-                       if(checkpvs(self.view_ofs,bestwp))
-                               self.havocbot_attack_time = time + 5;
-
-                       return true;
-               }
-               else
-               {
-                       ons_debug("generator found without waypoints around\n");
-                       // if there aren't waypoints near the generator go straight to it
-                       navigation_routerating(g, ratingscale, 10000);
-                       self.havocbot_attack_time = 0;
-                       return true;
-               }
-       }
-       return false;
-}
-
-void havocbot_role_ons_offense()
-{SELFPARAM();
-       if(self.deadflag != DEAD_NO)
-       {
-               self.havocbot_attack_time = 0;
-               havocbot_ons_reset_role(self);
-               return;
-       }
-
-       // Set the role timeout if necessary
-       if (!self.havocbot_role_timeout)
-               self.havocbot_role_timeout = time + 120;
-
-       if (time > self.havocbot_role_timeout)
-       {
-               havocbot_ons_reset_role(self);
-               return;
-       }
-
-       if(self.havocbot_attack_time>time)
-               return;
-
-       if (self.bot_strategytime < time)
-       {
-               navigation_goalrating_start();
-               havocbot_goalrating_enemyplayers(20000, self.origin, 650);
-               if(!havocbot_goalrating_ons_generator_attack(20000))
-                       havocbot_goalrating_ons_controlpoints_attack(20000);
-               havocbot_goalrating_ons_offenseitems(10000, self.origin, 10000);
-               navigation_goalrating_end();
-
-               self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
-       }
-}
-
-void havocbot_role_ons_assistant()
-{SELFPARAM();
-       havocbot_ons_reset_role(self);
-}
-
-void havocbot_role_ons_defense()
-{SELFPARAM();
-       havocbot_ons_reset_role(self);
-}
-
-void havocbot_ons_reset_role(entity bot)
-{SELFPARAM();
-       entity head;
-       int c = 0;
-
-       if(self.deadflag != DEAD_NO)
-               return;
-
-       bot.havocbot_ons_target = world;
-
-       // TODO: Defend control points or generator if necessary
-
-       // if there is only me on the team switch to offense
-       c = 0;
-       FOR_EACH_PLAYER(head)
-       if(SAME_TEAM(head, self))
-               ++c;
-
-       if(c==1)
-       {
-               havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
-               return;
-       }
-
-       havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
-}
-
-
-/*
- * Find control point or generator owned by the same team self which is nearest to pos
- * if max_dist is positive, only control points within this range will be considered
- */
-entity ons_Nearest_ControlPoint(vector pos, float max_dist)
-{SELFPARAM();
-       entity tmp_entity, closest_target = world;
-       tmp_entity = findchain(classname, "onslaught_controlpoint");
-       while(tmp_entity)
-       {
-               if(SAME_TEAM(tmp_entity, self))
-               if(tmp_entity.iscaptured)
-               if(max_dist <= 0 || vlen(tmp_entity.origin - pos) <= max_dist)
-               if(vlen(tmp_entity.origin - pos) <= vlen(closest_target.origin - pos) || closest_target == world)
-                       closest_target = tmp_entity;
-               tmp_entity = tmp_entity.chain;
-       }
-       tmp_entity = findchain(classname, "onslaught_generator");
-       while(tmp_entity)
-       {
-               if(SAME_TEAM(tmp_entity, self))
-               if(max_dist <= 0 || vlen(tmp_entity.origin - pos) < max_dist)
-               if(vlen(tmp_entity.origin - pos) <= vlen(closest_target.origin - pos) || closest_target == world)
-                       closest_target = tmp_entity;
-               tmp_entity = tmp_entity.chain;
-       }
-
-       return closest_target;
-}
-
-/*
- * Find control point or generator owned by the same team self which is nearest to pos
- * if max_dist is positive, only control points within this range will be considered
- * This function only check distances on the XY plane, disregarding Z
- */
-entity ons_Nearest_ControlPoint_2D(vector pos, float max_dist)
-{SELFPARAM();
-       entity tmp_entity, closest_target = world;
-       vector delta;
-       float smallest_distance = 0, distance;
-
-       tmp_entity = findchain(classname, "onslaught_controlpoint");
-       while(tmp_entity)
-       {
-               delta = tmp_entity.origin - pos;
-               delta_z = 0;
-               distance = vlen(delta);
-
-               if(SAME_TEAM(tmp_entity, self))
-               if(tmp_entity.iscaptured)
-               if(max_dist <= 0 || distance <= max_dist)
-               if(closest_target == world || distance <= smallest_distance )
-               {
-                       closest_target = tmp_entity;
-                       smallest_distance = distance;
-               }
-
-               tmp_entity = tmp_entity.chain;
-       }
-       tmp_entity = findchain(classname, "onslaught_generator");
-       while(tmp_entity)
-       {
-               delta = tmp_entity.origin - pos;
-               delta_z = 0;
-               distance = vlen(delta);
-
-               if(SAME_TEAM(tmp_entity, self))
-               if(max_dist <= 0 || distance <= max_dist)
-               if(closest_target == world || distance <= smallest_distance )
-               {
-                       closest_target = tmp_entity;
-                       smallest_distance = distance;
-               }
-
-               tmp_entity = tmp_entity.chain;
-       }
-
-       return closest_target;
-}
-/**
- * find the number of control points and generators in the same team as self
- */
-int ons_Count_SelfControlPoints()
-{SELFPARAM();
-       entity tmp_entity;
-       tmp_entity = findchain(classname, "onslaught_controlpoint");
-       int n = 0;
-       while(tmp_entity)
-       {
-               if(SAME_TEAM(tmp_entity, self))
-               if(tmp_entity.iscaptured)
-                       n++;
-               tmp_entity = tmp_entity.chain;
-       }
-       tmp_entity = findchain(classname, "onslaught_generator");
-       while(tmp_entity)
-       {
-               if(SAME_TEAM(tmp_entity, self))
-                       n++;
-               tmp_entity = tmp_entity.chain;
-       }
-       return n;
-}
-
-/**
- * Teleport player to a random position near tele_target
- * if tele_effects is true, teleport sound+particles are created
- * return false on failure
- */
-bool ons_Teleport(entity player, entity tele_target, float range, bool tele_effects)
-{
-       if ( !tele_target )
-               return false;
-
-       int i;
-       vector loc;
-       float theta;
-       // narrow the range for each iteration to increase chances that a spawnpoint
-       // can be found even if there's little room around the control point
-       float iteration_scale = 1;
-       for(i = 0; i < 16; ++i)
-       {
-               iteration_scale -= i / 16;
-               theta = random() * 2 * M_PI;
-               loc_y = sin(theta);
-               loc_x = cos(theta);
-               loc_z = 0;
-               loc *= random() * range * iteration_scale;
-
-               loc += tele_target.origin + '0 0 128' * iteration_scale;
-
-               tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, player);
-               if(trace_fraction == 1.0 && !trace_startsolid)
-               {
-                       traceline(tele_target.origin, loc, MOVE_NOMONSTERS, tele_target); // double check to make sure we're not spawning outside the world
-                       if(trace_fraction == 1.0 && !trace_startsolid)
-                       {
-                               if ( tele_effects )
-                               {
-                                       Send_Effect(EFFECT_TELEPORT, player.origin, '0 0 0', 1);
-                                       sound (player, CH_TRIGGER, SND_TELEPORT, VOL_BASE, ATTEN_NORM);
-                               }
-                               setorigin(player, loc);
-                               player.angles = '0 1 0' * ( theta * RAD2DEG + 180 );
-                               makevectors(player.angles);
-                               player.fixangle = true;
-                               player.teleport_antispam = time + autocvar_g_onslaught_teleport_wait;
-
-                               if ( tele_effects )
-                                       Send_Effect(EFFECT_TELEPORT, player.origin + v_forward * 32, '0 0 0', 1);
-                               return true;
-                       }
-               }
-       }
-
-       return false;
-}
-
-// ==============
-// Hook Functions
-// ==============
-
-MUTATOR_HOOKFUNCTION(ons, reset_map_global)
-{SELFPARAM();
-       entity e;
-       FOR_EACH_PLAYER(e)
-       {
-               e.ons_roundlost = false;
-               e.ons_deathloc = '0 0 0';
-               WITH(entity, self, e, PutClientInServer());
-       }
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, ClientDisconnect)
-{SELFPARAM();
-       self.ons_deathloc = '0 0 0';
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, MakePlayerObserver)
-{SELFPARAM();
-       self.ons_deathloc = '0 0 0';
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayerSpawn)
-{SELFPARAM();
-       if(!round_handler_IsRoundStarted())
-       {
-               self.player_blocked = true;
-               return false;
-       }
-
-       entity l;
-       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
-       {
-               l.sprite.SendFlags |= 16;
-       }
-       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
-       {
-               l.sprite.SendFlags |= 16;
-       }
-
-       if(ons_stalemate) { Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_OVERTIME_CONTROLPOINT); }
-
-       if ( autocvar_g_onslaught_spawn_choose )
-       if ( self.ons_spawn_by )
-       if ( ons_Teleport(self,self.ons_spawn_by,autocvar_g_onslaught_teleport_radius,false) )
-       {
-               self.ons_spawn_by = world;
-               return false;
-       }
-
-       if(autocvar_g_onslaught_spawn_at_controlpoints)
-       if(random() <= autocvar_g_onslaught_spawn_at_controlpoints_chance)
-       {
-               float random_target = autocvar_g_onslaught_spawn_at_controlpoints_random;
-               entity tmp_entity, closest_target = world;
-               vector spawn_loc = self.ons_deathloc;
-
-               // new joining player or round reset, don't bother checking
-               if(spawn_loc == '0 0 0') { return false; }
-
-               if(random_target) { RandomSelection_Init(); }
-
-               for(tmp_entity = ons_worldcplist; tmp_entity; tmp_entity = tmp_entity.ons_worldcpnext)
-               {
-                       if(SAME_TEAM(tmp_entity, self))
-                       if(random_target)
-                               RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
-                       else if(vlen(tmp_entity.origin - spawn_loc) <= vlen(closest_target.origin - spawn_loc) || closest_target == world)
-                               closest_target = tmp_entity;
-               }
-
-               if(random_target) { closest_target = RandomSelection_chosen_ent; }
-
-               if(closest_target)
-               {
-                       float i;
-                       vector loc;
-                       float iteration_scale = 1;
-                       for(i = 0; i < 10; ++i)
-                       {
-                               iteration_scale -= i / 10;
-                               loc = closest_target.origin + '0 0 96' * iteration_scale;
-                               loc += ('0 1 0' * random()) * 128 * iteration_scale;
-                               tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, self);
-                               if(trace_fraction == 1.0 && !trace_startsolid)
-                               {
-                                       traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the world
-                                       if(trace_fraction == 1.0 && !trace_startsolid)
-                                       {
-                                               setorigin(self, loc);
-                                               self.angles = normalize(loc - closest_target.origin) * RAD2DEG;
-                                               return false;
-                                       }
-                               }
-                       }
-               }
-       }
-
-       if(autocvar_g_onslaught_spawn_at_generator)
-       if(random() <= autocvar_g_onslaught_spawn_at_generator_chance)
-       {
-               float random_target = autocvar_g_onslaught_spawn_at_generator_random;
-               entity tmp_entity, closest_target = world;
-               vector spawn_loc = self.ons_deathloc;
-
-               // new joining player or round reset, don't bother checking
-               if(spawn_loc == '0 0 0') { return false; }
-
-               if(random_target) { RandomSelection_Init(); }
-
-               for(tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
-               {
-                       if(random_target)
-                               RandomSelection_Add(tmp_entity, 0, string_null, 1, 1);
-                       else
-                       {
-                               if(SAME_TEAM(tmp_entity, self))
-                               if(vlen(tmp_entity.origin - spawn_loc) <= vlen(closest_target.origin - spawn_loc) || closest_target == world)
-                                       closest_target = tmp_entity;
-                       }
-               }
-
-               if(random_target) { closest_target = RandomSelection_chosen_ent; }
-
-               if(closest_target)
-               {
-                       float i;
-                       vector loc;
-                       float iteration_scale = 1;
-                       for(i = 0; i < 10; ++i)
-                       {
-                               iteration_scale -= i / 10;
-                               loc = closest_target.origin + '0 0 128' * iteration_scale;
-                               loc += ('0 1 0' * random()) * 256 * iteration_scale;
-                               tracebox(loc, PL_MIN, PL_MAX, loc, MOVE_NORMAL, self);
-                               if(trace_fraction == 1.0 && !trace_startsolid)
-                               {
-                                       traceline(closest_target.origin, loc, MOVE_NOMONSTERS, closest_target); // double check to make sure we're not spawning outside the world
-                                       if(trace_fraction == 1.0 && !trace_startsolid)
-                                       {
-                                               setorigin(self, loc);
-                                               self.angles = normalize(loc - closest_target.origin) * RAD2DEG;
-                                               return false;
-                                       }
-                               }
-                       }
-               }
-       }
-
-    return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayerDies)
-{SELFPARAM();
-       frag_target.ons_deathloc = frag_target.origin;
-       entity l;
-       for(l = ons_worldgeneratorlist; l; l = l.ons_worldgeneratornext)
-       {
-               l.sprite.SendFlags |= 16;
-       }
-       for(l = ons_worldcplist; l; l = l.ons_worldcpnext)
-       {
-               l.sprite.SendFlags |= 16;
-       }
-
-       if ( autocvar_g_onslaught_spawn_choose )
-       if ( ons_Count_SelfControlPoints() > 1 )
-               stuffcmd(self, "qc_cmd_cl hud clickradar\n");
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, MonsterMove)
-{SELFPARAM();
-       entity e = find(world, targetname, self.target);
-       if (e != world)
-               self.team = e.team;
-
-       return false;
-}
-
-void ons_MonsterSpawn_Delayed()
-{SELFPARAM();
-       entity e, own = self.owner;
-
-       if(!own) { remove(self); return; }
-
-       if(own.targetname)
-       {
-               e = find(world, target, own.targetname);
-               if(e != world)
-               {
-                       own.team = e.team;
-
-                       activator = e;
-                       own.use();
-               }
-       }
-
-       remove(self);
-}
-
-MUTATOR_HOOKFUNCTION(ons, MonsterSpawn)
-{SELFPARAM();
-       entity e = spawn();
-       e.owner = self;
-       InitializeEntity(e, ons_MonsterSpawn_Delayed, INITPRIO_FINDTARGET);
-
-       return false;
-}
-
-void ons_TurretSpawn_Delayed()
-{SELFPARAM();
-       entity e, own = self.owner;
-
-       if(!own) { remove(self); return; }
-
-       if(own.targetname)
-       {
-               e = find(world, target, own.targetname);
-               if(e != world)
-               {
-                       own.team = e.team;
-                       own.active = ACTIVE_NOT;
-
-                       activator = e;
-                       own.use();
-               }
-       }
-
-       remove(self);
-}
-
-MUTATOR_HOOKFUNCTION(ons, TurretSpawn)
-{SELFPARAM();
-       entity e = spawn();
-       e.owner = self;
-       InitializeEntity(e, ons_TurretSpawn_Delayed, INITPRIO_FINDTARGET);
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, HavocBot_ChooseRole)
-{SELFPARAM();
-       havocbot_ons_reset_role(self);
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ons, GetTeamCount)
-{
-       // onslaught is special
-       for(entity tmp_entity = ons_worldgeneratorlist; tmp_entity; tmp_entity = tmp_entity.ons_worldgeneratornext)
-       {
-               switch(tmp_entity.team)
-               {
-                       case NUM_TEAM_1: c1 = 0; break;
-                       case NUM_TEAM_2: c2 = 0; break;
-                       case NUM_TEAM_3: c3 = 0; break;
-                       case NUM_TEAM_4: c4 = 0; break;
-               }
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ons, SpectateCopy)
-{SELFPARAM();
-       self.ons_roundlost = other.ons_roundlost; // make spectators see it too
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, SV_ParseClientCommand)
-{SELFPARAM();
-       if(MUTATOR_RETURNVALUE) // command was already handled?
-               return false;
-
-       if ( cmd_name == "ons_spawn" )
-       {
-               vector pos = self.origin;
-               if(cmd_argc > 1)
-                       pos_x = stof(argv(1));
-               if(cmd_argc > 2)
-                       pos_y = stof(argv(2));
-               if(cmd_argc > 3)
-                       pos_z = stof(argv(3));
-
-               if ( IS_PLAYER(self) )
-               {
-                       if ( !self.frozen )
-                       {
-                               entity source_point = ons_Nearest_ControlPoint(self.origin, autocvar_g_onslaught_teleport_radius);
-
-                               if ( !source_point && self.health > 0 )
-                               {
-                                       sprint(self, "\nYou need to be next to a control point\n");
-                                       return 1;
-                               }
-
-
-                               entity closest_target = ons_Nearest_ControlPoint_2D(pos, autocvar_g_onslaught_click_radius);
-
-                               if ( closest_target == world )
-                               {
-                                       sprint(self, "\nNo control point found\n");
-                                       return 1;
-                               }
-
-                               if ( self.health <= 0 )
-                               {
-                                       self.ons_spawn_by = closest_target;
-                                       self.respawn_flags = self.respawn_flags | RESPAWN_FORCE;
-                               }
-                               else
-                               {
-                                       if ( source_point == closest_target )
-                                       {
-                                               sprint(self, "\nTeleporting to the same point\n");
-                                               return 1;
-                                       }
-
-                                       if ( !ons_Teleport(self,closest_target,autocvar_g_onslaught_teleport_radius,true) )
-                                               sprint(self, "\nUnable to teleport there\n");
-                               }
-
-                               return 1;
-                       }
-
-                       sprint(self, "\nNo teleportation for you\n");
-               }
-
-               return 1;
-       }
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayerUseKey)
-{SELFPARAM();
-       if(MUTATOR_RETURNVALUE || gameover) { return false; }
-
-       if((time > self.teleport_antispam) && (self.deadflag == DEAD_NO) && !self.vehicle)
-       {
-               entity source_point = ons_Nearest_ControlPoint(self.origin, autocvar_g_onslaught_teleport_radius);
-               if ( source_point )
-               {
-                       stuffcmd(self, "qc_cmd_cl hud clickradar\n");
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, PlayHitsound)
-{
-       return (frag_victim.classname == "onslaught_generator" && !frag_victim.isshielded)
-               || (frag_victim.classname == "onslaught_controlpoint_icon" && !frag_victim.owner.isshielded);
-}
-
-MUTATOR_HOOKFUNCTION(ons, SendWaypoint)
-{
-       if(wp_sendflags & 16)
-       {
-               if(self.owner.classname == "onslaught_controlpoint")
-               {
-                       entity wp_owner = self.owner;
-                       entity e = WaypointSprite_getviewentity(wp_sendto);
-                       if(SAME_TEAM(e, wp_owner) && wp_owner.goalentity.health >= wp_owner.goalentity.max_health) { wp_flag |= 2; }
-                       if(!ons_ControlPoint_Attackable(wp_owner, e.team)) { wp_flag |= 2; }
-               }
-               if(self.owner.classname == "onslaught_generator")
-               {
-                       entity wp_owner = self.owner;
-                       if(wp_owner.isshielded && wp_owner.health >= wp_owner.max_health) { wp_flag |= 2; }
-                       if(wp_owner.health <= 0) { wp_flag |= 2; }
-               }
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, TurretValidateTarget)
-{
-       if(substring(turret_target.classname, 0, 10) == "onslaught_") // don't attack onslaught targets, that's the player's job!
-       {
-               ret_float = -3;
-               return true;
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ons, TurretThink)
-{
-       // ONS uses somewhat backwards linking.
-       if(self.target)
-       {
-               entity e = find(world, targetname, self.target);
-               if (e != world)
-                       self.team = e.team;
-       }
-
-       if(self.team != self.tur_head.team)
-               turret_respawn();
-
-       return false;
-}
-
-
-// ==========
-// Spawnfuncs
-// ==========
-
-/*QUAKED spawnfunc_onslaught_link (0 .5 .8) (-16 -16 -16) (16 16 16)
-  Link between control points.
-
-  This entity targets two different spawnfunc_onslaught_controlpoint or spawnfunc_onslaught_generator entities, and suppresses shielding on both if they are owned by different teams.
-
-keys:
-"target" - first control point.
-"target2" - second control point.
- */
-spawnfunc(onslaught_link)
-{
-       if(!g_onslaught) { remove(self); return; }
-
-       if (self.target == "" || self.target2 == "")
-               objerror("target and target2 must be set\n");
-
-       self.ons_worldlinknext = ons_worldlinklist; // link into ons_worldlinklist
-       ons_worldlinklist = self;
-
-       InitializeEntity(self, ons_DelayedLinkSetup, INITPRIO_FINDTARGET);
-       Net_LinkEntity(self, false, 0, ons_Link_Send);
-}
-
-/*QUAKED spawnfunc_onslaught_controlpoint (0 .5 .8) (-32 -32 0) (32 32 128)
-  Control point. Be sure to give this enough clearance so that the shootable part has room to exist
-
-  This should link to an spawnfunc_onslaught_controlpoint entity or spawnfunc_onslaught_generator entity.
-
-keys:
-"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
-"target" - target any entities that are tied to this control point, such as vehicles and buildable structure entities.
-"message" - name of this control point (should reflect the location in the map, such as "center bridge", "north tower", etc)
- */
-
-spawnfunc(onslaught_controlpoint)
-{
-       if(!g_onslaught) { remove(self); return; }
-
-       ons_ControlPoint_Setup(self);
-}
-
-/*QUAKED spawnfunc_onslaught_generator (0 .5 .8) (-32 -32 -24) (32 32 64)
-  Base generator.
-
-  spawnfunc_onslaught_link entities can target this.
-
-keys:
-"team" - team that owns this generator (5 = red, 14 = blue, etc), MUST BE SET.
-"targetname" - name that spawnfunc_onslaught_link entities will use to target this.
- */
-spawnfunc(onslaught_generator)
-{
-       if(!g_onslaught) { remove(self); return; }
-       if(!self.team) { objerror("team must be set"); }
-
-       ons_GeneratorSetup(self);
-}
-
-// scoreboard setup
-void ons_ScoreRules()
-{
-       CheckAllowedTeams(world);
-       ScoreRules_basics(((c4>=0) ? 4 : (c3>=0) ? 3 : 2), SFL_SORT_PRIO_PRIMARY, 0, true);
-       ScoreInfo_SetLabel_TeamScore  (ST_ONS_CAPS,     "destroyed", SFL_SORT_PRIO_PRIMARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_ONS_CAPS,     "caps",      SFL_SORT_PRIO_SECONDARY);
-       ScoreInfo_SetLabel_PlayerScore(SP_ONS_TAKES,    "takes",     0);
-       ScoreRules_basics_end();
-}
-
-void ons_DelayedInit() // Do this check with a delay so we can wait for teams to be set up
-{
-       ons_ScoreRules();
-
-       round_handler_Spawn(Onslaught_CheckPlayers, Onslaught_CheckWinner, Onslaught_RoundStart);
-       round_handler_Init(5, autocvar_g_onslaught_warmup, autocvar_g_onslaught_round_timelimit);
-}
-
-void ons_Initialize()
-{
-       g_onslaught = true;
-       ons_captureshield_force = autocvar_g_onslaught_shield_force;
-
-       addstat(STAT_ROUNDLOST, AS_INT, ons_roundlost);
-
-       InitializeEntity(world, ons_DelayedInit, INITPRIO_GAMETYPE);
-}
-
-#endif
index 229242f8b3cca30c17feb55aaafdf0f08ac249c5..4fbafe03535a21da375d031d38aa3c8f37817021 100644 (file)
@@ -6,13 +6,13 @@ void race_Initialize();
 
 REGISTER_MUTATOR(rc, false)
 {
-       rc_SetLimits();
-
        MUTATOR_ONADD
        {
                if (time > 1) // game loads at time 1
                        error("This is a game type and it cannot be added at runtime.");
                race_Initialize();
+
+               rc_SetLimits();
        }
 
        MUTATOR_ONROLLBACK_OR_REMOVE
index 49ec0acc9f5e3dd90be9013a671ba107f93cc827..42415a495e7140dbab08c4e9a47c925f51be4022 100644 (file)
@@ -8,16 +8,16 @@ void tdm_DelayedInit();
 
 REGISTER_MUTATOR(tdm, false)
 {
-       ActivateTeamplay();
-       SetLimits(autocvar_g_tdm_point_limit, autocvar_g_tdm_point_leadlimit, -1, -1);
-       if (autocvar_g_tdm_team_spawns)
-               have_team_spawns = -1; // request team spawns
-
        MUTATOR_ONADD
        {
                if (time > 1) // game loads at time 1
                        error("This is a game type and it cannot be added at runtime.");
                InitializeEntity(world, tdm_DelayedInit, INITPRIO_GAMETYPE);
+
+               ActivateTeamplay();
+               SetLimits(autocvar_g_tdm_point_limit, autocvar_g_tdm_point_leadlimit, -1, -1);
+               if (autocvar_g_tdm_team_spawns)
+                       have_team_spawns = -1; // request team spawns
        }
 
        MUTATOR_ONROLLBACK_OR_REMOVE
diff --git a/qcsrc/server/mutators/mutator/mutator_bloodloss.qc b/qcsrc/server/mutators/mutator/mutator_bloodloss.qc
deleted file mode 100644 (file)
index ca37166..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(bloodloss, cvar("g_bloodloss"));
-
-.float bloodloss_timer;
-
-MUTATOR_HOOKFUNCTION(bloodloss, PlayerPreThink)
-{SELFPARAM();
-       if(IS_PLAYER(self))
-       if(self.health <= autocvar_g_bloodloss && self.deadflag == DEAD_NO)
-       {
-               self.BUTTON_CROUCH = true;
-
-               if(time >= self.bloodloss_timer)
-               {
-                       if(self.vehicle)
-                               vehicles_exit(VHEF_RELEASE);
-                       if(self.event_damage)
-                               self.event_damage(self, self, 1, DEATH_ROT.m_id, self.origin, '0 0 0');
-                       self.bloodloss_timer = time + 0.5 + random() * 0.5;
-               }
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(bloodloss, PlayerJump)
-{SELFPARAM();
-       if(self.health <= autocvar_g_bloodloss)
-               return true;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":bloodloss");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(bloodloss, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Blood loss");
-       return false;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_breakablehook.qc b/qcsrc/server/mutators/mutator/mutator_breakablehook.qc
deleted file mode 100644 (file)
index cb9463b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifdef IMPLEMENTATION
-#include "../../../common/deathtypes/all.qh"
-#include "../../g_hook.qh"
-
-REGISTER_MUTATOR(breakablehook, cvar("g_breakablehook"));
-
-bool autocvar_g_breakablehook; // allow toggling mid match?
-bool autocvar_g_breakablehook_owner;
-
-MUTATOR_HOOKFUNCTION(breakablehook, PlayerDamage_Calculate)
-{
-       if(frag_target.classname == "grapplinghook")
-       {
-               if((!autocvar_g_breakablehook)
-               || (!autocvar_g_breakablehook_owner && frag_attacker == frag_target.realowner)
-                       ) { frag_damage = 0; }
-
-               // hurt the owner of the hook
-               if(DIFF_TEAM(frag_attacker, frag_target.realowner))
-               {
-                       Damage (frag_target.realowner, frag_attacker, frag_attacker, 5, WEP_HOOK.m_id | HITTYPE_SPLASH, frag_target.realowner.origin, '0 0 0');
-                       RemoveGrapplingHook(frag_target.realowner);
-                       return false; // dead
-               }
-       }
-
-       return false;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_buffs.qc b/qcsrc/server/mutators/mutator/mutator_buffs.qc
deleted file mode 100644 (file)
index 4f0758f..0000000
+++ /dev/null
@@ -1,1000 +0,0 @@
-#ifndef MUTATOR_BUFFS_H
-#define MUTATOR_BUFFS_H
-
-// ammo
-.float buff_ammo_prev_infitems;
-.int buff_ammo_prev_clipload;
-// invisible
-.float buff_invisible_prev_alpha;
-// flight
-.float buff_flight_prev_gravity;
-// disability
-.float buff_disability_time;
-.float buff_disability_effect_time;
-// common buff variables
-.float buff_effect_delay;
-
-// buff definitions
-.float buff_active;
-.float buff_activetime;
-.float buff_activetime_updated;
-.entity buff_waypoint;
-.int oldbuffs; // for updating effects
-.entity buff_model; // controls effects (TODO: make csqc)
-
-const vector BUFF_MIN = ('-16 -16 -20');
-const vector BUFF_MAX = ('16 16 20');
-
-// client side options
-.float cvar_cl_buffs_autoreplace;
-#endif
-
-#ifdef IMPLEMENTATION
-
-#include "../../../common/triggers/target/music.qh"
-#include "../../../common/gamemodes/all.qh"
-#include "../../../common/buffs/all.qh"
-
-.float buff_time;
-void buffs_DelayedInit();
-
-REGISTER_MUTATOR(buffs, cvar("g_buffs"))
-{
-       MUTATOR_ONADD
-       {
-               addstat(STAT_BUFFS, AS_INT, buffs);
-               addstat(STAT_BUFF_TIME, AS_FLOAT, buff_time);
-
-               InitializeEntity(world, buffs_DelayedInit, INITPRIO_FINDTARGET);
-       }
-}
-
-entity buff_FirstFromFlags(int _buffs)
-{
-       if (flags)
-       {
-               FOREACH(Buffs, it.m_itemid & _buffs, LAMBDA(return it));
-       }
-       return BUFF_Null;
-}
-
-bool buffs_BuffModel_Customize()
-{SELFPARAM();
-       entity player, myowner;
-       bool same_team;
-
-       player = WaypointSprite_getviewentity(other);
-       myowner = self.owner;
-       same_team = (SAME_TEAM(player, myowner) || SAME_TEAM(player, myowner));
-
-       if(myowner.alpha <= 0.5 && !same_team && myowner.alpha != 0)
-               return false;
-
-       if(MUTATOR_CALLHOOK(BuffModel_Customize, self, player))
-               return false;
-
-       if(player == myowner || (IS_SPEC(other) && other.enemy == myowner))
-       {
-               // somewhat hide the model, but keep the glow
-               self.effects = 0;
-               self.alpha = -1;
-       }
-       else
-       {
-               self.effects = EF_FULLBRIGHT | EF_LOWPRECISION;
-               self.alpha = 1;
-       }
-       return true;
-}
-
-void buffs_BuffModel_Spawn(entity player)
-{
-       player.buff_model = spawn();
-       setmodel(player.buff_model, MDL_BUFF);
-       setsize(player.buff_model, '0 0 -40', '0 0 40');
-       setattachment(player.buff_model, player, "");
-       setorigin(player.buff_model, '0 0 1' * (player.buff_model.maxs.z * 1));
-       player.buff_model.owner = player;
-       player.buff_model.scale = 0.7;
-       player.buff_model.pflags = PFLAGS_FULLDYNAMIC;
-       player.buff_model.light_lev = 200;
-       player.buff_model.customizeentityforclient = buffs_BuffModel_Customize;
-}
-
-vector buff_GlowColor(entity buff)
-{
-       //if(buff.team) { return Team_ColorRGB(buff.team); }
-       return buff.m_color;
-}
-
-void buff_Effect(entity player, string eff)
-{SELFPARAM();
-       if(!autocvar_g_buffs_effects) { return; }
-
-       if(time >= self.buff_effect_delay)
-       {
-               Send_Effect_(eff, player.origin + ((player.mins + player.maxs) * 0.5), '0 0 0', 1);
-               self.buff_effect_delay = time + 0.05; // prevent spam
-       }
-}
-
-// buff item
-float buff_Waypoint_visible_for_player(entity plr)
-{SELFPARAM();
-       if(!self.owner.buff_active && !self.owner.buff_activetime)
-               return false;
-
-       if (plr.buffs)
-       {
-               return plr.cvar_cl_buffs_autoreplace == false || plr.buffs != self.owner.buffs;
-       }
-
-       return WaypointSprite_visible_for_player(plr);
-}
-
-void buff_Waypoint_Spawn(entity e)
-{
-       entity buff = buff_FirstFromFlags(e.buffs);
-       entity wp = WaypointSprite_Spawn(WP_Buff, 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, world, e.team, e, buff_waypoint, true, RADARICON_Buff);
-       wp.wp_extra = buff.m_id;
-       WaypointSprite_UpdateTeamRadar(e.buff_waypoint, RADARICON_Buff, e.glowmod);
-       e.buff_waypoint.waypointsprite_visible_for_player = buff_Waypoint_visible_for_player;
-}
-
-void buff_SetCooldown(float cd)
-{SELFPARAM();
-       cd = max(0, cd);
-
-       if(!self.buff_waypoint)
-               buff_Waypoint_Spawn(self);
-
-       WaypointSprite_UpdateBuildFinished(self.buff_waypoint, time + cd);
-       self.buff_activetime = cd;
-       self.buff_active = !cd;
-}
-
-void buff_Respawn(entity ent)
-{SELFPARAM();
-       if(gameover) { return; }
-
-       vector oldbufforigin = ent.origin;
-
-       if(!MoveToRandomMapLocation(ent, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, ((autocvar_g_buffs_random_location_attempts > 0) ? autocvar_g_buffs_random_location_attempts : 10), 1024, 256))
-       {
-               entity spot = SelectSpawnPoint(true);
-               setorigin(ent, ((spot.origin + '0 0 200') + (randomvec() * 300)));
-               ent.angles = spot.angles;
-       }
-
-       tracebox(ent.origin, ent.mins * 1.5, self.maxs * 1.5, ent.origin, MOVE_NOMONSTERS, ent);
-
-       setorigin(ent, trace_endpos); // attempt to unstick
-
-       ent.movetype = MOVETYPE_TOSS;
-
-       makevectors(ent.angles);
-       ent.velocity = '0 0 200';
-       ent.angles = '0 0 0';
-       if(autocvar_g_buffs_random_lifetime > 0)
-               ent.lifetime = time + autocvar_g_buffs_random_lifetime;
-
-       Send_Effect(EFFECT_ELECTRO_COMBO, oldbufforigin + ((ent.mins + ent.maxs) * 0.5), '0 0 0', 1);
-       Send_Effect(EFFECT_ELECTRO_COMBO, CENTER_OR_VIEWOFS(ent), '0 0 0', 1);
-
-       WaypointSprite_Ping(ent.buff_waypoint);
-
-       sound(ent, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
-}
-
-void buff_Touch()
-{SELFPARAM();
-       if(gameover) { return; }
-
-       if(ITEM_TOUCH_NEEDKILL())
-       {
-               buff_Respawn(self);
-               return;
-       }
-
-       if((self.team && DIFF_TEAM(other, self))
-       || (other.frozen)
-       || (other.vehicle)
-       || (!self.buff_active)
-       )
-       {
-               // can't touch this
-               return;
-       }
-
-       if(MUTATOR_CALLHOOK(BuffTouch, self, other))
-               return;
-
-       if(!IS_PLAYER(other))
-               return; // incase mutator changed other
-
-       if (other.buffs)
-       {
-               if (other.cvar_cl_buffs_autoreplace && other.buffs != self.buffs)
-               {
-                       int buffid = buff_FirstFromFlags(other.buffs).m_id;
-                       //Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_DROP, other.buffs);
-                       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ITEM_BUFF_LOST, other.netname, buffid);
-
-                       other.buffs = 0;
-                       //sound(other, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
-               }
-               else { return; } // do nothing
-       }
-
-       self.owner = other;
-       self.buff_active = false;
-       self.lifetime = 0;
-       int buffid = buff_FirstFromFlags(self.buffs).m_id;
-       Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_BUFF_GOT, buffid);
-       Send_Notification(NOTIF_ALL_EXCEPT, other, MSG_INFO, INFO_ITEM_BUFF, other.netname, buffid);
-
-       Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
-       sound(other, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
-       other.buffs |= (self.buffs);
-}
-
-float buff_Available(entity buff)
-{
-       if (buff == BUFF_Null)
-               return false;
-       if (buff == BUFF_AMMO && ((start_items & IT_UNLIMITED_WEAPON_AMMO) || (start_items & IT_UNLIMITED_AMMO) || (cvar("g_melee_only"))))
-               return false;
-       if (buff == BUFF_VAMPIRE && cvar("g_vampire"))
-               return false;
-       return cvar(strcat("g_buffs_", buff.m_name));
-}
-
-.int buff_seencount;
-
-void buff_NewType(entity ent, float cb)
-{
-       RandomSelection_Init();
-       FOREACH(Buffs, buff_Available(it), LAMBDA(
-               it.buff_seencount += 1;
-               // if it's already been chosen, give it a lower priority
-               RandomSelection_Add(world, it.m_itemid, string_null, 1, max(0.2, 1 / it.buff_seencount));
-       ));
-       ent.buffs = RandomSelection_chosen_float;
-}
-
-void buff_Think()
-{SELFPARAM();
-       if(self.buffs != self.oldbuffs)
-       {
-               entity buff = buff_FirstFromFlags(self.buffs);
-               self.color = buff.m_color;
-               self.glowmod = buff_GlowColor(buff);
-               self.skin = buff.m_skin;
-
-               setmodel(self, MDL_BUFF);
-
-               if(self.buff_waypoint)
-               {
-                       //WaypointSprite_Disown(self.buff_waypoint, 1);
-                       WaypointSprite_Kill(self.buff_waypoint);
-                       buff_Waypoint_Spawn(self);
-                       if(self.buff_activetime)
-                               WaypointSprite_UpdateBuildFinished(self.buff_waypoint, time + self.buff_activetime - frametime);
-               }
-
-               self.oldbuffs = self.buffs;
-       }
-
-       if(!gameover)
-       if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
-       if(!self.buff_activetime_updated)
-       {
-               buff_SetCooldown(self.buff_activetime);
-               self.buff_activetime_updated = true;
-       }
-
-       if(!self.buff_active && !self.buff_activetime)
-       if(!self.owner || self.owner.frozen || self.owner.deadflag != DEAD_NO || !self.owner.iscreature || !(self.owner.buffs & self.buffs))
-       {
-               buff_SetCooldown(autocvar_g_buffs_cooldown_respawn + frametime);
-               self.owner = world;
-               if(autocvar_g_buffs_randomize)
-                       buff_NewType(self, self.buffs);
-
-               if(autocvar_g_buffs_random_location || (self.spawnflags & 64))
-                       buff_Respawn(self);
-       }
-
-       if(self.buff_activetime)
-       if(!gameover)
-       if((round_handler_IsActive() && !round_handler_IsRoundStarted()) || time >= game_starttime)
-       {
-               self.buff_activetime = max(0, self.buff_activetime - frametime);
-
-               if(!self.buff_activetime)
-               {
-                       self.buff_active = true;
-                       sound(self, CH_TRIGGER, SND_STRENGTH_RESPAWN, VOL_BASE, ATTN_NORM);
-                       Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
-               }
-       }
-
-       if(self.buff_active)
-       {
-               if(self.team && !self.buff_waypoint)
-                       buff_Waypoint_Spawn(self);
-
-               if(self.lifetime)
-               if(time >= self.lifetime)
-                       buff_Respawn(self);
-       }
-
-       self.nextthink = time;
-       //self.angles_y = time * 110.1;
-}
-
-void buff_Waypoint_Reset()
-{SELFPARAM();
-       WaypointSprite_Kill(self.buff_waypoint);
-
-       if(self.buff_activetime) { buff_Waypoint_Spawn(self); }
-}
-
-void buff_Reset()
-{SELFPARAM();
-       if(autocvar_g_buffs_randomize)
-               buff_NewType(self, self.buffs);
-       self.owner = world;
-       buff_SetCooldown(autocvar_g_buffs_cooldown_activate);
-       buff_Waypoint_Reset();
-       self.buff_activetime_updated = false;
-
-       if(autocvar_g_buffs_random_location || (self.spawnflags & 64))
-               buff_Respawn(self);
-}
-
-float buff_Customize()
-{SELFPARAM();
-       entity player = WaypointSprite_getviewentity(other);
-       if(!self.buff_active || (self.team && DIFF_TEAM(player, self)))
-       {
-               self.alpha = 0.3;
-               if(self.effects & EF_FULLBRIGHT) { self.effects &= ~(EF_FULLBRIGHT); }
-               self.pflags = 0;
-       }
-       else
-       {
-               self.alpha = 1;
-               if(!(self.effects & EF_FULLBRIGHT)) { self.effects |= EF_FULLBRIGHT; }
-               self.light_lev = 220 + 36 * sin(time);
-               self.pflags = PFLAGS_FULLDYNAMIC;
-       }
-       return true;
-}
-
-void buff_Init(entity ent)
-{SELFPARAM();
-       if(!cvar("g_buffs")) { remove(ent); return; }
-
-       if(!teamplay && ent.team) { ent.team = 0; }
-
-       entity buff = buff_FirstFromFlags(self.buffs);
-
-       setself(ent);
-       if(!self.buffs || buff_Available(buff))
-               buff_NewType(self, 0);
-
-       self.classname = "item_buff";
-       self.solid = SOLID_TRIGGER;
-       self.flags = FL_ITEM;
-       self.think = buff_Think;
-       self.touch = buff_Touch;
-       self.reset = buff_Reset;
-       self.nextthink = time + 0.1;
-       self.gravity = 1;
-       self.movetype = MOVETYPE_TOSS;
-       self.scale = 1;
-       self.skin = buff.m_skin;
-       self.effects = EF_FULLBRIGHT | EF_STARDUST | EF_NOSHADOW;
-       self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
-       self.customizeentityforclient = buff_Customize;
-       //self.gravity = 100;
-       self.color = buff.m_color;
-       self.glowmod = buff_GlowColor(self);
-       buff_SetCooldown(autocvar_g_buffs_cooldown_activate + game_starttime);
-       self.buff_active = !self.buff_activetime;
-       self.pflags = PFLAGS_FULLDYNAMIC;
-
-       if(self.spawnflags & 1)
-               self.noalign = true;
-
-       if(self.noalign)
-               self.movetype = MOVETYPE_NONE; // reset by random location
-
-       setmodel(self, MDL_BUFF);
-       setsize(self, BUFF_MIN, BUFF_MAX);
-
-       if(cvar("g_buffs_random_location") || (self.spawnflags & 64))
-               buff_Respawn(self);
-
-       setself(this);
-}
-
-void buff_Init_Compat(entity ent, entity replacement)
-{
-       if (ent.spawnflags & 2)
-               ent.team = NUM_TEAM_1;
-       else if (ent.spawnflags & 4)
-               ent.team = NUM_TEAM_2;
-
-       ent.buffs = replacement.m_itemid;
-
-       buff_Init(ent);
-}
-
-void buff_SpawnReplacement(entity ent, entity old)
-{
-       setorigin(ent, old.origin);
-       ent.angles = old.angles;
-       ent.noalign = (old.noalign || (old.spawnflags & 1));
-
-       buff_Init(ent);
-}
-
-void buff_Vengeance_DelayedDamage()
-{SELFPARAM();
-       if(self.enemy)
-               Damage(self.enemy, self.owner, self.owner, self.dmg, DEATH_BUFF.m_id, self.enemy.origin, '0 0 0');
-
-       remove(self);
-       return;
-}
-
-float buff_Inferno_CalculateTime(float x, float offset_x, float offset_y, float intersect_x, float intersect_y, float base)
-{
-       return offset_y + (intersect_y - offset_y) * logn(((x - offset_x) * ((base - 1) / intersect_x)) + 1, base);
-}
-
-// mutator hooks
-MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_SplitHealthArmor)
-{
-       if(frag_deathtype == DEATH_BUFF.m_id) { return false; }
-
-       if(frag_target.buffs & BUFF_RESISTANCE.m_itemid)
-       {
-               vector v = healtharmor_applydamage(50, autocvar_g_buffs_resistance_blockpercent, frag_deathtype, frag_damage);
-               damage_take = v.x;
-               damage_save = v.y;
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_Calculate)
-{
-       if(frag_deathtype == DEATH_BUFF.m_id) { return false; }
-
-       if(frag_target.buffs & BUFF_SPEED.m_itemid)
-       if(frag_target != frag_attacker)
-               frag_damage *= autocvar_g_buffs_speed_damage_take;
-
-       if(frag_target.buffs & BUFF_MEDIC.m_itemid)
-       if((frag_target.health - frag_damage) <= 0)
-       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
-       if(frag_attacker)
-       if(random() <= autocvar_g_buffs_medic_survive_chance)
-               frag_damage = max(5, frag_target.health - autocvar_g_buffs_medic_survive_health);
-
-       if(frag_target.buffs & BUFF_JUMP.m_itemid)
-       if(frag_deathtype == DEATH_FALL.m_id)
-               frag_damage = 0;
-
-       if(frag_target.buffs & BUFF_VENGEANCE.m_itemid)
-       if(frag_attacker)
-       if(frag_attacker != frag_target)
-       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
-       {
-               entity dmgent = spawn();
-
-               dmgent.dmg = frag_damage * autocvar_g_buffs_vengeance_damage_multiplier;
-               dmgent.enemy = frag_attacker;
-               dmgent.owner = frag_target;
-               dmgent.think = buff_Vengeance_DelayedDamage;
-               dmgent.nextthink = time + 0.1;
-       }
-
-       if(frag_target.buffs & BUFF_BASH.m_itemid)
-       if(frag_attacker != frag_target)
-       if(vlen(frag_force))
-               frag_force = '0 0 0';
-
-       if(frag_attacker.buffs & BUFF_BASH.m_itemid)
-       if(vlen(frag_force))
-       if(frag_attacker == frag_target)
-               frag_force *= autocvar_g_buffs_bash_force_self;
-       else
-               frag_force *= autocvar_g_buffs_bash_force;
-
-       if(frag_attacker.buffs & BUFF_DISABILITY.m_itemid)
-       if(frag_target != frag_attacker)
-               frag_target.buff_disability_time = time + autocvar_g_buffs_disability_slowtime;
-
-       if(frag_attacker.buffs & BUFF_MEDIC.m_itemid)
-       if(DEATH_WEAPONOF(frag_deathtype) != WEP_ARC)
-       if(SAME_TEAM(frag_attacker, frag_target))
-       if(frag_attacker != frag_target)
-       {
-               frag_target.health = min(g_pickup_healthmega_max, frag_target.health + frag_damage);
-               frag_damage = 0;
-       }
-
-       if(frag_attacker.buffs & BUFF_INFERNO.m_itemid)
-       if(frag_target != frag_attacker) {
-               float time = buff_Inferno_CalculateTime(
-                       frag_damage,
-                       0,
-                       autocvar_g_buffs_inferno_burntime_min_time,
-                       autocvar_g_buffs_inferno_burntime_target_damage,
-                       autocvar_g_buffs_inferno_burntime_target_time,
-                       autocvar_g_buffs_inferno_burntime_factor
-               );
-               Fire_AddDamage(frag_target, frag_attacker, (frag_damage * autocvar_g_buffs_inferno_damagemultiplier) * time, time, DEATH_BUFF.m_id);
-       }
-
-       // this... is ridiculous (TODO: fix!)
-       if(frag_attacker.buffs & BUFF_VAMPIRE.m_itemid)
-       if(!frag_target.vehicle)
-       if(DEATH_WEAPONOF(frag_deathtype) != WEP_ARC)
-       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
-       if(frag_target.deadflag == DEAD_NO)
-       if(IS_PLAYER(frag_target) || IS_MONSTER(frag_target))
-       if(frag_attacker != frag_target)
-       if(!frag_target.frozen)
-       if(frag_target.takedamage)
-       if(DIFF_TEAM(frag_attacker, frag_target))
-       {
-               frag_attacker.health = bound(0, frag_attacker.health + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.health), g_pickup_healthsmall_max);
-               if(frag_target.armorvalue)
-                       frag_attacker.armorvalue = bound(0, frag_attacker.armorvalue + bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal, frag_target.armorvalue), g_pickup_armorsmall_max);
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs,PlayerSpawn)
-{SELFPARAM();
-       self.buffs = 0;
-       // reset timers here to prevent them continuing after re-spawn
-       self.buff_disability_time = 0;
-       self.buff_disability_effect_time = 0;
-       return false;
-}
-
-.float stat_sv_maxspeed;
-.float stat_sv_airspeedlimit_nonqw;
-.float stat_sv_jumpvelocity;
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics)
-{SELFPARAM();
-       if(self.buffs & BUFF_SPEED.m_itemid)
-       {
-               self.stat_sv_maxspeed *= autocvar_g_buffs_speed_speed;
-               self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_speed_speed;
-       }
-
-       if(time < self.buff_disability_time)
-       {
-               self.stat_sv_maxspeed *= autocvar_g_buffs_disability_speed;
-               self.stat_sv_airspeedlimit_nonqw *= autocvar_g_buffs_disability_speed;
-       }
-
-       if(self.buffs & BUFF_JUMP.m_itemid)
-       {
-               // automatically reset, no need to worry
-               self.stat_sv_jumpvelocity = autocvar_g_buffs_jump_height;
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerJump)
-{SELFPARAM();
-       if(self.buffs & BUFF_JUMP.m_itemid)
-               player_jumpheight = autocvar_g_buffs_jump_height;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, MonsterMove)
-{SELFPARAM();
-       if(time < self.buff_disability_time)
-       {
-               monster_speed_walk *= autocvar_g_buffs_disability_speed;
-               monster_speed_run *= autocvar_g_buffs_disability_speed;
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerDies)
-{SELFPARAM();
-       if(self.buffs)
-       {
-               int buffid = buff_FirstFromFlags(self.buffs).m_id;
-               Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
-               self.buffs = 0;
-
-               if(self.buff_model)
-               {
-                       remove(self.buff_model);
-                       self.buff_model = world;
-               }
-       }
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerUseKey, CBC_ORDER_FIRST)
-{SELFPARAM();
-       if(MUTATOR_RETURNVALUE || gameover) { return false; }
-       if(self.buffs)
-       {
-               int buffid = buff_FirstFromFlags(self.buffs).m_id;
-               Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_BUFF_DROP, buffid);
-               Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
-
-               self.buffs = 0;
-               sound(self, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
-               return true;
-       }
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon)
-{SELFPARAM();
-       if(MUTATOR_RETURNVALUE || gameover) { return false; }
-
-       if(self.buffs & BUFF_SWAPPER.m_itemid)
-       {
-               float best_distance = autocvar_g_buffs_swapper_range;
-               entity closest = world;
-               entity player;
-               FOR_EACH_PLAYER(player)
-               if(DIFF_TEAM(self, player))
-               if(player.deadflag == DEAD_NO && !player.frozen && !player.vehicle)
-               if(vlen(self.origin - player.origin) <= best_distance)
-               {
-                       best_distance = vlen(self.origin - player.origin);
-                       closest = player;
-               }
-
-               if(closest)
-               {
-                       vector my_org, my_vel, my_ang, their_org, their_vel, their_ang;
-
-                       my_org = self.origin;
-                       my_vel = self.velocity;
-                       my_ang = self.angles;
-                       their_org = closest.origin;
-                       their_vel = closest.velocity;
-                       their_ang = closest.angles;
-
-                       Drop_Special_Items(closest);
-
-                       MUTATOR_CALLHOOK(PortalTeleport, self); // initiate flag dropper
-
-                       setorigin(self, their_org);
-                       setorigin(closest, my_org);
-
-                       closest.velocity = my_vel;
-                       closest.angles = my_ang;
-                       closest.fixangle = true;
-                       closest.oldorigin = my_org;
-                       closest.oldvelocity = my_vel;
-                       self.velocity = their_vel;
-                       self.angles = their_ang;
-                       self.fixangle = true;
-                       self.oldorigin = their_org;
-                       self.oldvelocity = their_vel;
-
-                       // set pusher so self gets the kill if they fall into void
-                       closest.pusher = self;
-                       closest.pushltime = time + autocvar_g_maxpushtime;
-                       closest.istypefrag = closest.BUTTON_CHAT;
-
-                       Send_Effect(EFFECT_ELECTRO_COMBO, their_org, '0 0 0', 1);
-                       Send_Effect(EFFECT_ELECTRO_COMBO, my_org, '0 0 0', 1);
-
-                       sound(self, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
-                       sound(closest, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
-
-                       // TODO: add a counter to handle how many times one can teleport, and a delay to prevent spam
-                       self.buffs = 0;
-                       return true;
-               }
-       }
-       return false;
-}
-
-bool buffs_RemovePlayer(entity player)
-{
-       if(player.buff_model)
-       {
-               remove(player.buff_model);
-               player.buff_model = world;
-       }
-
-       // also reset timers here to prevent them continuing after spectating
-       player.buff_disability_time = 0;
-       player.buff_disability_effect_time = 0;
-
-       return false;
-}
-MUTATOR_HOOKFUNCTION(buffs, MakePlayerObserver) { return buffs_RemovePlayer(self); }
-MUTATOR_HOOKFUNCTION(buffs, ClientDisconnect) { return buffs_RemovePlayer(self); }
-
-MUTATOR_HOOKFUNCTION(buffs, CustomizeWaypoint)
-{SELFPARAM();
-       entity e = WaypointSprite_getviewentity(other);
-
-       // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
-       // but only apply this to real players, not to spectators
-       if((self.owner.flags & FL_CLIENT) && (self.owner.buffs & BUFF_INVISIBLE.m_itemid) && (e == other))
-       if(DIFF_TEAM(self.owner, e))
-               return true;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, OnEntityPreSpawn, CBC_ORDER_LAST)
-{SELFPARAM();
-       if(autocvar_g_buffs_replace_powerups)
-       switch(self.classname)
-       {
-               case "item_strength":
-               case "item_invincible":
-               {
-                       entity e = spawn();
-                       buff_SpawnReplacement(e, self);
-                       return true;
-               }
-       }
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, WeaponRateFactor)
-{SELFPARAM();
-       if(self.buffs & BUFF_SPEED.m_itemid)
-               weapon_rate *= autocvar_g_buffs_speed_rate;
-
-       if(time < self.buff_disability_time)
-               weapon_rate *= autocvar_g_buffs_disability_rate;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, WeaponSpeedFactor)
-{SELFPARAM();
-       if(self.buffs & BUFF_SPEED.m_itemid)
-               ret_float *= autocvar_g_buffs_speed_weaponspeed;
-
-       if(time < self.buff_disability_time)
-               ret_float *= autocvar_g_buffs_disability_weaponspeed;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
-{SELFPARAM();
-       if(gameover || self.deadflag != DEAD_NO) { return false; }
-
-       if(time < self.buff_disability_time)
-       if(time >= self.buff_disability_effect_time)
-       {
-               Send_Effect(EFFECT_SMOKING, self.origin + ((self.mins + self.maxs) * 0.5), '0 0 0', 1);
-               self.buff_disability_effect_time = time + 0.5;
-       }
-
-       // handle buff lost status
-       // 1: notify everyone else
-       // 2: notify carrier as well
-       int buff_lost = 0;
-
-       if(self.buff_time)
-       if(time >= self.buff_time)
-               buff_lost = 2;
-
-       if(self.frozen) { buff_lost = 1; }
-
-       if(buff_lost)
-       {
-               if(self.buffs)
-               {
-                       int buffid = buff_FirstFromFlags(self.buffs).m_id;
-                       Send_Notification(NOTIF_ALL_EXCEPT, self, MSG_INFO, INFO_ITEM_BUFF_LOST, self.netname, buffid);
-                       if(buff_lost >= 2)
-                       {
-                               Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_BUFF_DROP, buffid); // TODO: special timeout message?
-                               sound(self, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
-                       }
-                       self.buffs = 0;
-               }
-       }
-
-       if(self.buffs & BUFF_MAGNET.m_itemid)
-       {
-               vector pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_item;
-               for(other = world; (other = findflags(other, flags, FL_ITEM)); )
-               if(boxesoverlap(self.absmin - pickup_size, self.absmax + pickup_size, other.absmin, other.absmax))
-               {
-                       setself(other);
-                       other = this;
-                       if(self.touch)
-                               self.touch();
-                       other = self;
-                       setself(this);
-               }
-       }
-
-       if(self.buffs & BUFF_AMMO.m_itemid)
-       if(self.clip_size)
-               self.clip_load = self.(weapon_load[self.switchweapon]) = self.clip_size;
-
-       if((self.buffs & BUFF_INVISIBLE.m_itemid) && (self.oldbuffs & BUFF_INVISIBLE.m_itemid))
-       if(self.alpha != autocvar_g_buffs_invisible_alpha)
-               self.alpha = autocvar_g_buffs_invisible_alpha; // powerups reset alpha, so we must enforce this (TODO)
-
-#define BUFF_ONADD(b) if ( (self.buffs & (b).m_itemid) && !(self.oldbuffs & (b).m_itemid))
-#define BUFF_ONREM(b) if (!(self.buffs & (b).m_itemid) &&  (self.oldbuffs & (b).m_itemid))
-
-       if(self.buffs != self.oldbuffs)
-       {
-               entity buff = buff_FirstFromFlags(self.buffs);
-               float bufftime = buff != BUFF_Null ? buff.m_time(buff) : 0;
-               self.buff_time = (bufftime) ? time + bufftime : 0;
-
-               BUFF_ONADD(BUFF_AMMO)
-               {
-                       self.buff_ammo_prev_infitems = (self.items & IT_UNLIMITED_WEAPON_AMMO);
-                       self.items |= IT_UNLIMITED_WEAPON_AMMO;
-
-                       if(self.clip_load)
-                               self.buff_ammo_prev_clipload = self.clip_load;
-                       self.clip_load = self.(weapon_load[self.switchweapon]) = self.clip_size;
-               }
-
-               BUFF_ONREM(BUFF_AMMO)
-               {
-                       if(self.buff_ammo_prev_infitems)
-                               self.items |= IT_UNLIMITED_WEAPON_AMMO;
-                       else
-                               self.items &= ~IT_UNLIMITED_WEAPON_AMMO;
-
-                       if(self.buff_ammo_prev_clipload)
-                               self.clip_load = self.buff_ammo_prev_clipload;
-               }
-
-               BUFF_ONADD(BUFF_INVISIBLE)
-               {
-                       if(time < self.strength_finished && g_instagib)
-                               self.alpha = autocvar_g_instagib_invis_alpha;
-                       else
-                               self.alpha = self.buff_invisible_prev_alpha;
-                       self.alpha = autocvar_g_buffs_invisible_alpha;
-               }
-
-               BUFF_ONREM(BUFF_INVISIBLE)
-                       self.alpha = self.buff_invisible_prev_alpha;
-
-               BUFF_ONADD(BUFF_FLIGHT)
-               {
-                       self.buff_flight_prev_gravity = self.gravity;
-                       self.gravity = autocvar_g_buffs_flight_gravity;
-               }
-
-               BUFF_ONREM(BUFF_FLIGHT)
-                       self.gravity = self.buff_flight_prev_gravity;
-
-               self.oldbuffs = self.buffs;
-               if(self.buffs)
-               {
-                       if(!self.buff_model)
-                               buffs_BuffModel_Spawn(self);
-
-                       self.buff_model.color = buff.m_color;
-                       self.buff_model.glowmod = buff_GlowColor(self.buff_model);
-                       self.buff_model.skin = buff.m_skin;
-
-                       self.effects |= EF_NOSHADOW;
-               }
-               else
-               {
-                       remove(self.buff_model);
-                       self.buff_model = world;
-
-                       self.effects &= ~(EF_NOSHADOW);
-               }
-       }
-
-       if(self.buff_model)
-       {
-               self.buff_model.effects = self.effects;
-               self.buff_model.effects |= EF_LOWPRECISION;
-               self.buff_model.effects = self.buff_model.effects & EFMASK_CHEAP; // eat performance
-
-               self.buff_model.alpha = self.alpha;
-       }
-
-#undef BUFF_ONADD
-#undef BUFF_ONREM
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, SpectateCopy)
-{SELFPARAM();
-       self.buffs = other.buffs;
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, VehicleEnter)
-{
-       vh_vehicle.buffs = vh_player.buffs;
-       vh_player.buffs = 0;
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, VehicleExit)
-{
-       vh_player.buffs = vh_vehicle.buffs;
-       vh_vehicle.buffs = 0;
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, PlayerRegen)
-{SELFPARAM();
-       if(self.buffs & BUFF_MEDIC.m_itemid)
-       {
-               regen_mod_rot = autocvar_g_buffs_medic_rot;
-               regen_mod_limit = regen_mod_max = autocvar_g_buffs_medic_max;
-               regen_mod_regen = autocvar_g_buffs_medic_regen;
-       }
-
-       if(self.buffs & BUFF_SPEED.m_itemid)
-               regen_mod_regen = autocvar_g_buffs_speed_regen;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, GetCvars)
-{
-       GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_buffs_autoreplace, "cl_buffs_autoreplace");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":Buffs");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(buffs, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Buffs");
-       return false;
-}
-
-void buffs_DelayedInit()
-{
-       if(autocvar_g_buffs_spawn_count > 0)
-       if(find(world, classname, "item_buff") == world)
-       {
-               float i;
-               for(i = 0; i < autocvar_g_buffs_spawn_count; ++i)
-               {
-                       entity e = spawn();
-                       e.spawnflags |= 64; // always randomize
-                       e.velocity = randomvec() * 250; // this gets reset anyway if random location works
-                       buff_Init(e);
-               }
-       }
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_campcheck.qc b/qcsrc/server/mutators/mutator/mutator_campcheck.qc
deleted file mode 100644 (file)
index be5bfce..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(campcheck, cvar("g_campcheck"));
-
-.float campcheck_nextcheck;
-.float campcheck_traveled_distance;
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerDies)
-{SELFPARAM();
-       Kill_Notification(NOTIF_ONE, self, MSG_CENTER_CPID, CPID_CAMPCHECK);
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerDamage_Calculate)
-{
-       if(IS_PLAYER(frag_target))
-       if(IS_PLAYER(frag_attacker))
-       if(frag_attacker != frag_target)
-       {
-               frag_target.campcheck_traveled_distance = autocvar_g_campcheck_distance;
-               frag_attacker.campcheck_traveled_distance = autocvar_g_campcheck_distance;
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerPreThink)
-{SELFPARAM();
-       if(!gameover)
-       if(!warmup_stage) // don't consider it camping during warmup?
-       if(time >= game_starttime)
-       if(IS_PLAYER(self))
-       if(IS_REAL_CLIENT(self)) // bots may camp, but that's no reason to constantly kill them
-       if(self.deadflag == DEAD_NO)
-       if(!self.frozen)
-       if(!self.BUTTON_CHAT)
-       if(autocvar_g_campcheck_interval)
-       {
-               vector dist;
-
-               // calculate player movement (in 2 dimensions only, so jumping on one spot doesn't count as movement)
-               dist = self.prevorigin - self.origin;
-               dist.z = 0;
-               self.campcheck_traveled_distance += fabs(vlen(dist));
-
-               if((autocvar_g_campaign && !campaign_bots_may_start) || (time < game_starttime) || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
-               {
-                       self.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
-                       self.campcheck_traveled_distance = 0;
-               }
-
-               if(time > self.campcheck_nextcheck)
-               {
-                       if(self.campcheck_traveled_distance < autocvar_g_campcheck_distance)
-                       {
-                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_CAMPCHECK);
-                               if(self.vehicle)
-                                       Damage(self.vehicle, self, self, autocvar_g_campcheck_damage * 2, DEATH_CAMP.m_id, self.vehicle.origin, '0 0 0');
-                               else
-                                       Damage(self, self, self, bound(0, autocvar_g_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP.m_id, self.origin, '0 0 0');
-                       }
-                       self.campcheck_nextcheck = time + autocvar_g_campcheck_interval;
-                       self.campcheck_traveled_distance = 0;
-               }
-
-               return false;
-       }
-
-       self.campcheck_nextcheck = time + autocvar_g_campcheck_interval; // one of the above checks failed, so keep the timer up to date
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, PlayerSpawn)
-{SELFPARAM();
-       self.campcheck_nextcheck = time + autocvar_g_campcheck_interval * 2;
-       self.campcheck_traveled_distance = 0;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(campcheck, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":CampCheck");
-       return false;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_dodging.qc b/qcsrc/server/mutators/mutator/mutator_dodging.qc
deleted file mode 100644 (file)
index 85b9fea..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-#ifdef IMPLEMENTATION
-
-#ifdef CSQC
-       #define PHYS_DODGING_FRAMETIME                          (1 / (frametime <= 0 ? 60 : frametime))
-       #define PHYS_DODGING                                            getstati(STAT_DODGING)
-       #define PHYS_DODGING_DELAY                                      getstatf(STAT_DODGING_DELAY)
-       #define PHYS_DODGING_TIMEOUT(s)                         getstatf(STAT_DODGING_TIMEOUT)
-       #define PHYS_DODGING_HORIZ_SPEED_FROZEN         getstatf(STAT_DODGING_HORIZ_SPEED_FROZEN)
-       #define PHYS_DODGING_FROZEN_NODOUBLETAP         getstati(STAT_DODGING_FROZEN_NO_DOUBLETAP)
-       #define PHYS_DODGING_HORIZ_SPEED                        getstatf(STAT_DODGING_HORIZ_SPEED)
-       #define PHYS_DODGING_PRESSED_KEYS(s)            s.pressedkeys
-       #define PHYS_DODGING_HEIGHT_THRESHOLD           getstatf(STAT_DODGING_HEIGHT_THRESHOLD)
-       #define PHYS_DODGING_DISTANCE_THRESHOLD         getstatf(STAT_DODGING_DISTANCE_THRESHOLD)
-       #define PHYS_DODGING_RAMP_TIME                          getstatf(STAT_DODGING_RAMP_TIME)
-       #define PHYS_DODGING_UP_SPEED                           getstatf(STAT_DODGING_UP_SPEED)
-       #define PHYS_DODGING_WALL                                       getstatf(STAT_DODGING_WALL)
-#elif defined(SVQC)
-       #define PHYS_DODGING_FRAMETIME                          sys_frametime
-       #define PHYS_DODGING                                            g_dodging
-       #define PHYS_DODGING_DELAY                                      autocvar_sv_dodging_delay
-       #define PHYS_DODGING_TIMEOUT(s)                         s.cvar_cl_dodging_timeout
-       #define PHYS_DODGING_HORIZ_SPEED_FROZEN         autocvar_sv_dodging_horiz_speed_frozen
-       #define PHYS_DODGING_FROZEN_NODOUBLETAP         autocvar_sv_dodging_frozen_doubletap
-       #define PHYS_DODGING_HORIZ_SPEED                        autocvar_sv_dodging_horiz_speed
-       #define PHYS_DODGING_PRESSED_KEYS(s)            s.pressedkeys
-       #define PHYS_DODGING_HEIGHT_THRESHOLD           autocvar_sv_dodging_height_threshold
-       #define PHYS_DODGING_DISTANCE_THRESHOLD         autocvar_sv_dodging_wall_distance_threshold
-       #define PHYS_DODGING_RAMP_TIME                          autocvar_sv_dodging_ramp_time
-       #define PHYS_DODGING_UP_SPEED                           autocvar_sv_dodging_up_speed
-       #define PHYS_DODGING_WALL                                       autocvar_sv_dodging_wall_dodging
-#endif
-
-#ifdef SVQC
-
-float g_dodging;
-
-// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
-.float dodging_action;
-
-// the jump part of the dodge cannot be ramped
-.float dodging_single_action;
-
-#include "../../../common/animdecide.qh"
-#include "../../../common/physics.qh"
-
-.float cvar_cl_dodging_timeout;
-
-.float stat_dodging;
-.float stat_dodging_delay;
-.float stat_dodging_horiz_speed_frozen;
-.float stat_dodging_frozen_nodoubletap;
-.float stat_dodging_frozen;
-.float stat_dodging_horiz_speed;
-.float stat_dodging_height_threshold;
-.float stat_dodging_distance_threshold;
-.float stat_dodging_ramp_time;
-.float stat_dodging_up_speed;
-.float stat_dodging_wall;
-
-REGISTER_MUTATOR(dodging, cvar("g_dodging"))
-{
-       // this just turns on the cvar.
-       MUTATOR_ONADD
-       {
-               g_dodging = cvar("g_dodging");
-               addstat(STAT_DODGING, AS_INT, stat_dodging);
-               addstat(STAT_DODGING_DELAY, AS_FLOAT, stat_dodging_delay);
-               addstat(STAT_DODGING_TIMEOUT, AS_FLOAT, cvar_cl_dodging_timeout); // we stat this, so it is updated on the client when updated on server (otherwise, chaos)
-               addstat(STAT_DODGING_FROZEN_NO_DOUBLETAP, AS_INT, stat_dodging_frozen_nodoubletap);
-               addstat(STAT_DODGING_HORIZ_SPEED_FROZEN, AS_FLOAT, stat_dodging_horiz_speed_frozen);
-               addstat(STAT_DODGING_FROZEN, AS_INT, stat_dodging_frozen);
-               addstat(STAT_DODGING_HORIZ_SPEED, AS_FLOAT, stat_dodging_horiz_speed);
-               addstat(STAT_DODGING_HEIGHT_THRESHOLD, AS_FLOAT, stat_dodging_height_threshold);
-               addstat(STAT_DODGING_DISTANCE_THRESHOLD, AS_FLOAT, stat_dodging_distance_threshold);
-               addstat(STAT_DODGING_RAMP_TIME, AS_FLOAT, stat_dodging_ramp_time);
-               addstat(STAT_DODGING_UP_SPEED, AS_FLOAT, stat_dodging_up_speed);
-               addstat(STAT_DODGING_WALL, AS_FLOAT, stat_dodging_wall);
-       }
-
-       // this just turns off the cvar.
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               g_dodging = 0;
-       }
-
-       return false;
-}
-
-#endif
-
-// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
-.float dodging_action;
-
-// the jump part of the dodge cannot be ramped
-.float dodging_single_action;
-
-
-// these are used to store the last key press time for each of the keys..
-.float last_FORWARD_KEY_time;
-.float last_BACKWARD_KEY_time;
-.float last_LEFT_KEY_time;
-.float last_RIGHT_KEY_time;
-
-// these store the movement direction at the time of the dodge action happening.
-.vector dodging_direction;
-
-// this indicates the last time a dodge was executed. used to check if another one is allowed
-// and to ramp up the dodge acceleration in the physics hook.
-.float last_dodging_time;
-
-// This is the velocity gain to be added over the ramp time.
-// It will decrease from frame to frame during dodging_action = 1
-// until it's 0.
-.float dodging_velocity_gain;
-
-#ifdef CSQC
-.int pressedkeys;
-
-#elif defined(SVQC)
-
-void dodging_UpdateStats()
-{SELFPARAM();
-       self.stat_dodging = PHYS_DODGING;
-       self.stat_dodging_delay = PHYS_DODGING_DELAY;
-       self.stat_dodging_horiz_speed_frozen = PHYS_DODGING_HORIZ_SPEED_FROZEN;
-       self.stat_dodging_frozen = PHYS_DODGING_FROZEN;
-       self.stat_dodging_frozen_nodoubletap = PHYS_DODGING_FROZEN_NODOUBLETAP;
-       self.stat_dodging_height_threshold = PHYS_DODGING_HEIGHT_THRESHOLD;
-       self.stat_dodging_distance_threshold = PHYS_DODGING_DISTANCE_THRESHOLD;
-       self.stat_dodging_ramp_time = PHYS_DODGING_RAMP_TIME;
-       self.stat_dodging_up_speed = PHYS_DODGING_UP_SPEED;
-       self.stat_dodging_wall = PHYS_DODGING_WALL;
-}
-
-#endif
-
-// returns 1 if the player is close to a wall
-bool check_close_to_wall(float threshold)
-{SELFPARAM();
-       if (PHYS_DODGING_WALL == 0) { return false; }
-
-       #define X(OFFSET)                                                                                                                               \
-       tracebox(self.origin, self.mins, self.maxs, self.origin + OFFSET, true, self);  \
-       if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)                \
-               return true;
-       X(1000*v_right);
-       X(-1000*v_right);
-       X(1000*v_forward);
-       X(-1000*v_forward);
-       #undef X
-
-       return false;
-}
-
-bool check_close_to_ground(float threshold)
-{SELFPARAM();
-       return IS_ONGROUND(self) ? true : false;
-}
-
-float PM_dodging_checkpressedkeys()
-{SELFPARAM();
-       if(!PHYS_DODGING)
-               return false;
-
-       float frozen_dodging = (PHYS_FROZEN(self) && PHYS_DODGING_FROZEN);
-       float frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
-
-       // first check if the last dodge is far enough back in time so we can dodge again
-       if ((time - self.last_dodging_time) < PHYS_DODGING_DELAY)
-               return false;
-
-       makevectors(self.angles);
-
-       if (check_close_to_ground(PHYS_DODGING_HEIGHT_THRESHOLD) != 1
-               && check_close_to_wall(PHYS_DODGING_DISTANCE_THRESHOLD) != 1)
-               return true;
-
-       float tap_direction_x = 0;
-       float tap_direction_y = 0;
-       float dodge_detected = 0;
-
-       #define X(COND,BTN,RESULT)                                                                                                                      \
-       if (self.movement_##COND)                                                                                               \
-               /* is this a state change? */                                                                                                   \
-               if(!(PHYS_DODGING_PRESSED_KEYS(self) & KEY_##BTN) || frozen_no_doubletap) {             \
-                               tap_direction_##RESULT;                                                                                                 \
-                               if ((time - self.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(self))   \
-                                       dodge_detected = 1;                                                                                                     \
-                               self.last_##BTN##_KEY_time = time;                                                                              \
-               }
-       X(x < 0, BACKWARD,      x--);
-       X(x > 0, FORWARD,       x++);
-       X(y < 0, LEFT,          y--);
-       X(y > 0, RIGHT,         y++);
-       #undef X
-
-       if (dodge_detected == 1)
-       {
-               self.last_dodging_time = time;
-
-               self.dodging_action = 1;
-               self.dodging_single_action = 1;
-
-               self.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED;
-
-               self.dodging_direction_x = tap_direction_x;
-               self.dodging_direction_y = tap_direction_y;
-
-               // normalize the dodging_direction vector.. (unlike UT99) XD
-               float length = self.dodging_direction_x * self.dodging_direction_x
-                                       + self.dodging_direction_y * self.dodging_direction_y;
-               length = sqrt(length);
-
-               self.dodging_direction_x = self.dodging_direction_x * 1.0 / length;
-               self.dodging_direction_y = self.dodging_direction_y * 1.0 / length;
-               return true;
-       }
-       return false;
-}
-
-void PM_dodging()
-{SELFPARAM();
-       if (!PHYS_DODGING)
-               return;
-
-#ifdef SVQC
-       dodging_UpdateStats();
-#endif
-
-    if (PHYS_DEAD(self))
-        return;
-
-       // when swimming, no dodging allowed..
-       if (self.waterlevel >= WATERLEVEL_SWIMMING)
-       {
-               self.dodging_action = 0;
-               self.dodging_direction_x = 0;
-               self.dodging_direction_y = 0;
-               return;
-       }
-
-       // make sure v_up, v_right and v_forward are sane
-       makevectors(self.angles);
-
-       // if we have e.g. 0.5 sec ramptime and a frametime of 0.25, then the ramp code
-       // will be called ramp_time/frametime times = 2 times. so, we need to
-       // add 0.5 * the total speed each frame until the dodge action is done..
-       float common_factor = PHYS_DODGING_FRAMETIME / PHYS_DODGING_RAMP_TIME;
-
-       // if ramp time is smaller than frametime we get problems ;D
-       common_factor = min(common_factor, 1);
-
-       float horiz_speed = PHYS_FROZEN(self) ? PHYS_DODGING_HORIZ_SPEED_FROZEN : PHYS_DODGING_HORIZ_SPEED;
-       float new_velocity_gain = self.dodging_velocity_gain - (common_factor * horiz_speed);
-       new_velocity_gain = max(0, new_velocity_gain);
-
-       float velocity_difference = self.dodging_velocity_gain - new_velocity_gain;
-
-       // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
-       if (self.dodging_action == 1)
-       {
-               //disable jump key during dodge accel phase
-               if(self.movement_z > 0) { self.movement_z = 0; }
-
-               self.velocity += ((self.dodging_direction_y * velocity_difference) * v_right)
-                                       + ((self.dodging_direction_x * velocity_difference) * v_forward);
-
-               self.dodging_velocity_gain = self.dodging_velocity_gain - velocity_difference;
-       }
-
-       // the up part of the dodge is a single shot action
-       if (self.dodging_single_action == 1)
-       {
-               UNSET_ONGROUND(self);
-
-               self.velocity += PHYS_DODGING_UP_SPEED * v_up;
-
-#ifdef SVQC
-               if (autocvar_sv_dodging_sound)
-                       PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
-
-               animdecide_setaction(self, ANIMACTION_JUMP, true);
-#endif
-
-               self.dodging_single_action = 0;
-       }
-
-       // are we done with the dodging ramp yet?
-       if((self.dodging_action == 1) && ((time - self.last_dodging_time) > PHYS_DODGING_RAMP_TIME))
-       {
-               // reset state so next dodge can be done correctly
-               self.dodging_action = 0;
-               self.dodging_direction_x = 0;
-               self.dodging_direction_y = 0;
-       }
-}
-
-#ifdef SVQC
-
-MUTATOR_HOOKFUNCTION(dodging, GetCvars)
-{
-       GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_dodging_timeout, "cl_dodging_timeout");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(dodging, PlayerPhysics)
-{
-       // print("dodging_PlayerPhysics\n");
-       PM_dodging();
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(dodging, GetPressedKeys)
-{
-       PM_dodging_checkpressedkeys();
-
-       return false;
-}
-
-#endif
-
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_hook.qc b/qcsrc/server/mutators/mutator/mutator_hook.qc
deleted file mode 100644 (file)
index b298e7b..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifdef IMPLEMENTATION
-AUTOCVAR(g_grappling_hook, bool, false, _("let players spawn with the grappling hook which allows them to pull themselves up"));
-#ifdef SVQC
-REGISTER_MUTATOR(hook, autocvar_g_grappling_hook) {
-    MUTATOR_ONADD {
-        g_grappling_hook = true;
-        WEP_HOOK.ammo_factor = 0;
-    }
-    MUTATOR_ONROLLBACK_OR_REMOVE {
-        g_grappling_hook = false;
-        WEP_HOOK.ammo_factor = 1;
-    }
-}
-
-MUTATOR_HOOKFUNCTION(hook, BuildMutatorsString)
-{
-    ret_string = strcat(ret_string, ":grappling_hook");
-}
-
-MUTATOR_HOOKFUNCTION(hook, BuildMutatorsPrettyString)
-{
-    ret_string = strcat(ret_string, ", Hook");
-}
-
-MUTATOR_HOOKFUNCTION(hook, BuildGameplayTipsString)
-{
-    ret_string = strcat(ret_string, "\n\n^3grappling hook^8 is enabled, press 'e' to use it\n");
-}
-
-MUTATOR_HOOKFUNCTION(hook, PlayerSpawn)
-{
-    SELFPARAM();
-    self.offhand = OFFHAND_HOOK;
-}
-
-MUTATOR_HOOKFUNCTION(hook, FilterItem)
-{
-    return self.weapon == WEP_HOOK.m_id;
-}
-
-#endif
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_invincibleproj.qc b/qcsrc/server/mutators/mutator/mutator_invincibleproj.qc
deleted file mode 100644 (file)
index 5a781a8..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(invincibleprojectiles, cvar("g_invincible_projectiles"));
-
-MUTATOR_HOOKFUNCTION(invincibleprojectiles, EditProjectile)
-{
-       if(other.health)
-       {
-               // disable health which in effect disables damage calculations
-               other.health = 0;
-       }
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":InvincibleProjectiles");
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(invincibleprojectiles, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Invincible Projectiles");
-       return 0;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_melee_only.qc b/qcsrc/server/mutators/mutator/mutator_melee_only.qc
deleted file mode 100644 (file)
index 5b03f46..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(melee_only, cvar("g_melee_only") && !cvar("g_instagib") && !g_nexball);
-
-MUTATOR_HOOKFUNCTION(melee_only, SetStartItems)
-{
-       start_ammo_shells = warmup_start_ammo_shells = 0;
-       start_weapons = warmup_start_weapons = WEPSET(SHOTGUN);
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, ForbidThrowCurrentWeapon)
-{
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, FilterItem)
-{SELFPARAM();
-       switch (self.items)
-       {
-               case ITEM_HealthSmall.m_itemid:
-               case ITEM_ArmorSmall.m_itemid:
-                       return false;
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":MeleeOnly");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(melee_only, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Melee Only Arena");
-       return false;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_midair.qc b/qcsrc/server/mutators/mutator/mutator_midair.qc
deleted file mode 100644 (file)
index bf34283..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(midair, cvar("g_midair"));
-
-.float midair_shieldtime;
-
-MUTATOR_HOOKFUNCTION(midair, PlayerDamage_Calculate)
-{SELFPARAM();
-       if(IS_PLAYER(frag_attacker))
-       if(IS_PLAYER(frag_target))
-       if(time < self.midair_shieldtime)
-               frag_damage = false;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(midair, PlayerPowerups)
-{SELFPARAM();
-       if(time >= game_starttime)
-       if(self.flags & FL_ONGROUND)
-       {
-               self.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
-               self.midair_shieldtime = max(self.midair_shieldtime, time + autocvar_g_midair_shieldtime);
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(midair, PlayerSpawn)
-{SELFPARAM();
-       if(IS_BOT_CLIENT(self))
-               self.bot_moveskill = 0; // disable bunnyhopping
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(midair, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":midair");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(midair, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Midair");
-       return false;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_multijump.qc b/qcsrc/server/mutators/mutator/mutator_multijump.qc
deleted file mode 100644 (file)
index f01a801..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-#ifdef IMPLEMENTATION
-#ifdef SVQC
-       #include "../../antilag.qh"
-#endif
-#include "../../../common/physics.qh"
-
-.int multijump_count;
-.bool multijump_ready;
-.bool cvar_cl_multijump;
-
-#ifdef CSQC
-
-#define PHYS_MULTIJUMP                                 getstati(STAT_MULTIJUMP)
-#define PHYS_MULTIJUMP_SPEED           getstatf(STAT_MULTIJUMP_SPEED)
-#define PHYS_MULTIJUMP_ADD                     getstati(STAT_MULTIJUMP_ADD)
-#define PHYS_MULTIJUMP_MAXSPEED        getstatf(STAT_MULTIJUMP_MAXSPEED)
-#define PHYS_MULTIJUMP_DODGING                 getstati(STAT_MULTIJUMP_DODGING)
-
-#elif defined(SVQC)
-
-#define PHYS_MULTIJUMP                                 autocvar_g_multijump
-#define PHYS_MULTIJUMP_SPEED           autocvar_g_multijump_speed
-#define PHYS_MULTIJUMP_ADD                     autocvar_g_multijump_add
-#define PHYS_MULTIJUMP_MAXSPEED        autocvar_g_multijump_maxspeed
-#define PHYS_MULTIJUMP_DODGING                 autocvar_g_multijump_dodging
-
-
-.float stat_multijump;
-.float stat_multijump_speed;
-.float stat_multijump_add;
-.float stat_multijump_maxspeed;
-.float stat_multijump_dodging;
-
-void multijump_UpdateStats()
-{SELFPARAM();
-       self.stat_multijump = PHYS_MULTIJUMP;
-       self.stat_multijump_speed = PHYS_MULTIJUMP_SPEED;
-       self.stat_multijump_add = PHYS_MULTIJUMP_ADD;
-       self.stat_multijump_maxspeed = PHYS_MULTIJUMP_MAXSPEED;
-       self.stat_multijump_dodging = PHYS_MULTIJUMP_DODGING;
-}
-
-void multijump_AddStats()
-{
-       addstat(STAT_MULTIJUMP, AS_INT, stat_multijump);
-       addstat(STAT_MULTIJUMP_SPEED, AS_FLOAT, stat_multijump_speed);
-       addstat(STAT_MULTIJUMP_ADD, AS_INT, stat_multijump_add);
-       addstat(STAT_MULTIJUMP_MAXSPEED, AS_FLOAT, stat_multijump_maxspeed);
-       addstat(STAT_MULTIJUMP_DODGING, AS_INT, stat_multijump_dodging);
-}
-
-#endif
-
-void PM_multijump()
-{SELFPARAM();
-       if(!PHYS_MULTIJUMP) { return; }
-
-       if(IS_ONGROUND(self))
-       {
-               self.multijump_count = 0;
-       }
-}
-
-bool PM_multijump_checkjump()
-{SELFPARAM();
-       if(!PHYS_MULTIJUMP) { return false; }
-
-#ifdef SVQC
-       bool client_multijump = self.cvar_cl_multijump;
-#elif defined(CSQC)
-       bool client_multijump = cvar("cl_multijump");
-
-       if(cvar("cl_multijump") > 1)
-               return false; // nope
-#endif
-
-       if (!IS_JUMP_HELD(self) && !IS_ONGROUND(self) && client_multijump) // jump button pressed this frame and we are in midair
-               self.multijump_ready = true;  // this is necessary to check that we released the jump button and pressed it again
-       else
-               self.multijump_ready = false;
-
-       int phys_multijump = PHYS_MULTIJUMP;
-
-#ifdef CSQC
-       phys_multijump = (PHYS_MULTIJUMP) ? -1 : 0;
-#endif
-
-       if(!player_multijump && self.multijump_ready && (self.multijump_count < phys_multijump || phys_multijump == -1) && self.velocity_z > PHYS_MULTIJUMP_SPEED && (!PHYS_MULTIJUMP_MAXSPEED || vlen(self.velocity) <= PHYS_MULTIJUMP_MAXSPEED))
-       {
-               if (PHYS_MULTIJUMP)
-               {
-                       if (!PHYS_MULTIJUMP_ADD) // in this case we make the z velocity == jumpvelocity
-                       {
-                               if (self.velocity_z < PHYS_JUMPVELOCITY)
-                               {
-                                       player_multijump = true;
-                                       self.velocity_z = 0;
-                               }
-                       }
-                       else
-                               player_multijump = true;
-
-                       if(player_multijump)
-                       {
-                               if(PHYS_MULTIJUMP_DODGING)
-                               if(self.movement_x != 0 || self.movement_y != 0) // don't remove all speed if player isnt pressing any movement keys
-                               {
-                                       float curspeed;
-                                       vector wishvel, wishdir;
-
-/*#ifdef SVQC
-                                       curspeed = max(
-                                               vlen(vec2(self.velocity)), // current xy speed
-                                               vlen(vec2(antilag_takebackavgvelocity(self, max(self.lastteleporttime + sys_frametime, time - 0.25), time))) // average xy topspeed over the last 0.25 secs
-                                       );
-#elif defined(CSQC)*/
-                                       curspeed = vlen(vec2(self.velocity));
-//#endif
-
-                                       makevectors(self.v_angle_y * '0 1 0');
-                                       wishvel = v_forward * self.movement_x + v_right * self.movement_y;
-                                       wishdir = normalize(wishvel);
-
-                                       self.velocity_x = wishdir_x * curspeed; // allow "dodging" at a multijump
-                                       self.velocity_y = wishdir_y * curspeed;
-                                       // keep velocity_z unchanged!
-                               }
-                               if (PHYS_MULTIJUMP > 0)
-                               {
-                                       self.multijump_count += 1;
-                               }
-                       }
-               }
-               self.multijump_ready = false; // require releasing and pressing the jump button again for the next jump
-       }
-
-       return false;
-}
-
-#ifdef SVQC
-REGISTER_MUTATOR(multijump, cvar("g_multijump"))
-{
-       MUTATOR_ONADD
-       {
-               multijump_AddStats();
-       }
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(multijump, PlayerPhysics)
-{
-       multijump_UpdateStats();
-       PM_multijump();
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(multijump, PlayerJump)
-{
-       return PM_multijump_checkjump();
-}
-
-MUTATOR_HOOKFUNCTION(multijump, GetCvars)
-{
-       GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_multijump, "cl_multijump");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":multijump");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Multi jump");
-       return false;
-}
-
-#endif
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_nades.qc b/qcsrc/server/mutators/mutator/mutator_nades.qc
deleted file mode 100644 (file)
index d9fd1c8..0000000
+++ /dev/null
@@ -1,1233 +0,0 @@
-#ifndef MUTATOR_NADES_H
-#define MUTATOR_NADES_H
-
-.entity nade;
-.entity fake_nade;
-.float nade_timer;
-.float nade_refire;
-.float bonus_nades;
-.float nade_special_time;
-.float bonus_nade_score;
-.float nade_type;
-.string pokenade_type;
-.entity nade_damage_target;
-.float cvar_cl_nade_type;
-.string cvar_cl_pokenade_type;
-.float toss_time;
-.float stat_healing_orb;
-.float stat_healing_orb_alpha;
-.float nade_show_particles;
-
-// Remove nades that are being thrown
-void(entity player) nades_Clear;
-
-// Give a bonus grenade to a player
-void(entity player, float score) nades_GiveBonus;
-// Remove all bonus nades from a player
-void(entity player) nades_RemoveBonus;
-
-#endif
-#ifdef IMPLEMENTATION
-
-#include "../../../common/nades/all.qh"
-#include "../../../common/gamemodes/all.qh"
-#include "../../../common/monsters/spawn.qh"
-#include "../../../common/monsters/sv_monsters.qh"
-#include "../../g_subs.qh"
-
-REGISTER_MUTATOR(nades, cvar("g_nades"))
-{
-       MUTATOR_ONADD
-       {
-               addstat(STAT_NADE_TIMER, AS_FLOAT, nade_timer);
-               addstat(STAT_NADE_BONUS, AS_FLOAT, bonus_nades);
-               addstat(STAT_NADE_BONUS_TYPE, AS_INT, nade_type);
-               addstat(STAT_NADE_BONUS_SCORE, AS_FLOAT, bonus_nade_score);
-               addstat(STAT_HEALING_ORB, AS_FLOAT, stat_healing_orb);
-               addstat(STAT_HEALING_ORB_ALPHA, AS_FLOAT, stat_healing_orb_alpha);
-       }
-
-       return false;
-}
-
-.float nade_time_primed;
-
-.entity nade_spawnloc;
-
-void nade_timer_think()
-{SELFPARAM();
-       self.skin = 8 - (self.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10);
-       self.nextthink = time;
-       if(!self.owner || wasfreed(self.owner))
-               remove(self);
-}
-
-void nade_burn_spawn(entity _nade)
-{
-       CSQCProjectile(_nade, true, Nades[_nade.nade_type].m_projectile[true], true);
-}
-
-void nade_spawn(entity _nade)
-{
-       entity timer = spawn();
-       setmodel(timer, MDL_NADE_TIMER);
-       setattachment(timer, _nade, "");
-       timer.classname = "nade_timer";
-       timer.colormap = _nade.colormap;
-       timer.glowmod = _nade.glowmod;
-       timer.think = nade_timer_think;
-       timer.nextthink = time;
-       timer.wait = _nade.wait;
-       timer.owner = _nade;
-       timer.skin = 10;
-
-       _nade.effects |= EF_LOWPRECISION;
-
-       CSQCProjectile(_nade, true, Nades[_nade.nade_type].m_projectile[false], true);
-}
-
-void napalm_damage(float dist, float damage, float edgedamage, float burntime)
-{SELFPARAM();
-       entity e;
-       float d;
-       vector p;
-
-       if ( damage < 0 )
-               return;
-
-       RandomSelection_Init();
-       for(e = WarpZone_FindRadius(self.origin, dist, true); e; e = e.chain)
-               if(e.takedamage == DAMAGE_AIM)
-               if(self.realowner != e || autocvar_g_nades_napalm_selfdamage)
-               if(!IS_PLAYER(e) || !self.realowner || DIFF_TEAM(e, self))
-               if(!e.frozen)
-               {
-                       p = e.origin;
-                       p.x += e.mins.x + random() * (e.maxs.x - e.mins.x);
-                       p.y += e.mins.y + random() * (e.maxs.y - e.mins.y);
-                       p.z += e.mins.z + random() * (e.maxs.z - e.mins.z);
-                       d = vlen(WarpZone_UnTransformOrigin(e, self.origin) - p);
-                       if(d < dist)
-                       {
-                               e.fireball_impactvec = p;
-                               RandomSelection_Add(e, 0, string_null, 1 / (1 + d), !Fire_IsBurning(e));
-                       }
-               }
-       if(RandomSelection_chosen_ent)
-       {
-               d = vlen(WarpZone_UnTransformOrigin(RandomSelection_chosen_ent, self.origin) - RandomSelection_chosen_ent.fireball_impactvec);
-               d = damage + (edgedamage - damage) * (d / dist);
-               Fire_AddDamage(RandomSelection_chosen_ent, self.realowner, d * burntime, burntime, self.projectiledeathtype | HITTYPE_BOUNCE);
-               //trailparticles(self, particleeffectnum(EFFECT_FIREBALL_LASER), self.origin, RandomSelection_chosen_ent.fireball_impactvec);
-               Send_Effect(EFFECT_FIREBALL_LASER, self.origin, RandomSelection_chosen_ent.fireball_impactvec - self.origin, 1);
-       }
-}
-
-
-void napalm_ball_think()
-{SELFPARAM();
-       if(round_handler_IsActive())
-       if(!round_handler_IsRoundStarted())
-       {
-               remove(self);
-               return;
-       }
-
-       if(time > self.pushltime)
-       {
-               remove(self);
-               return;
-       }
-
-       vector midpoint = ((self.absmin + self.absmax) * 0.5);
-       if(pointcontents(midpoint) == CONTENT_WATER)
-       {
-               self.velocity = self.velocity * 0.5;
-
-               if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
-                       { self.velocity_z = 200; }
-       }
-
-       self.angles = vectoangles(self.velocity);
-
-       napalm_damage(autocvar_g_nades_napalm_ball_radius,autocvar_g_nades_napalm_ball_damage,
-                                 autocvar_g_nades_napalm_ball_damage,autocvar_g_nades_napalm_burntime);
-
-       self.nextthink = time + 0.1;
-}
-
-
-void nade_napalm_ball()
-{SELFPARAM();
-       entity proj;
-       vector kick;
-
-       spamsound(self, CH_SHOTS, SND(FIREBALL_FIRE), VOL_BASE, ATTEN_NORM);
-
-       proj = spawn ();
-       proj.owner = self.owner;
-       proj.realowner = self.realowner;
-       proj.team = self.owner.team;
-       proj.classname = "grenade";
-       proj.bot_dodge = true;
-       proj.bot_dodgerating = autocvar_g_nades_napalm_ball_damage;
-       proj.movetype = MOVETYPE_BOUNCE;
-       proj.projectiledeathtype = DEATH_NADE_NAPALM.m_id;
-       PROJECTILE_MAKETRIGGER(proj);
-       setmodel(proj, MDL_Null);
-       proj.scale = 1;//0.5;
-       setsize(proj, '-4 -4 -4', '4 4 4');
-       setorigin(proj, self.origin);
-       proj.think = napalm_ball_think;
-       proj.nextthink = time;
-       proj.damageforcescale = autocvar_g_nades_napalm_ball_damageforcescale;
-       proj.effects = EF_LOWPRECISION | EF_FLAME;
-
-       kick.x =(random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread;
-       kick.y = (random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread;
-       kick.z = (random()/2+0.5) * autocvar_g_nades_napalm_ball_spread;
-       proj.velocity = kick;
-
-       proj.pushltime = time + autocvar_g_nades_napalm_ball_lifetime;
-
-       proj.angles = vectoangles(proj.velocity);
-       proj.flags = FL_PROJECTILE;
-       proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC;
-
-       //CSQCProjectile(proj, true, PROJECTILE_NAPALM_FIRE, true);
-}
-
-
-void napalm_fountain_think()
-{SELFPARAM();
-
-       if(round_handler_IsActive())
-       if(!round_handler_IsRoundStarted())
-       {
-               remove(self);
-               return;
-       }
-
-       if(time >= self.ltime)
-       {
-               remove(self);
-               return;
-       }
-
-       vector midpoint = ((self.absmin + self.absmax) * 0.5);
-       if(pointcontents(midpoint) == CONTENT_WATER)
-       {
-               self.velocity = self.velocity * 0.5;
-
-               if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
-                       { self.velocity_z = 200; }
-
-               UpdateCSQCProjectile(self);
-       }
-
-       napalm_damage(autocvar_g_nades_napalm_fountain_radius, autocvar_g_nades_napalm_fountain_damage,
-               autocvar_g_nades_napalm_fountain_edgedamage, autocvar_g_nades_napalm_burntime);
-
-       self.nextthink = time + 0.1;
-       if(time >= self.nade_special_time)
-       {
-               self.nade_special_time = time + autocvar_g_nades_napalm_fountain_delay;
-               nade_napalm_ball();
-       }
-}
-
-void nade_napalm_boom()
-{SELFPARAM();
-       entity fountain;
-       int c;
-       for (c = 0; c < autocvar_g_nades_napalm_ball_count; c++)
-               nade_napalm_ball();
-
-
-       fountain = spawn();
-       fountain.owner = self.owner;
-       fountain.realowner = self.realowner;
-       fountain.origin = self.origin;
-       setorigin(fountain, fountain.origin);
-       fountain.think = napalm_fountain_think;
-       fountain.nextthink = time;
-       fountain.ltime = time + autocvar_g_nades_napalm_fountain_lifetime;
-       fountain.pushltime = fountain.ltime;
-       fountain.team = self.team;
-       fountain.movetype = MOVETYPE_TOSS;
-       fountain.projectiledeathtype = DEATH_NADE_NAPALM.m_id;
-       fountain.bot_dodge = true;
-       fountain.bot_dodgerating = autocvar_g_nades_napalm_fountain_damage;
-       fountain.nade_special_time = time;
-       setsize(fountain, '-16 -16 -16', '16 16 16');
-       CSQCProjectile(fountain, true, PROJECTILE_NAPALM_FOUNTAIN, true);
-}
-
-void nade_ice_freeze(entity freezefield, entity frost_target, float freeze_time)
-{
-       frost_target.frozen_by = freezefield.realowner;
-       Send_Effect(EFFECT_ELECTRO_IMPACT, frost_target.origin, '0 0 0', 1);
-       Freeze(frost_target, 1/freeze_time, 3, false);
-
-       Drop_Special_Items(frost_target);
-}
-
-void nade_ice_think()
-{SELFPARAM();
-
-       if(round_handler_IsActive())
-       if(!round_handler_IsRoundStarted())
-       {
-               remove(self);
-               return;
-       }
-
-       if(time >= self.ltime)
-       {
-               if ( autocvar_g_nades_ice_explode )
-               {
-                       entity expef = EFFECT_NADE_EXPLODE(self.realowner.team);
-                       Send_Effect(expef, self.origin + '0 0 1', '0 0 0', 1);
-                       sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-
-                       RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
-                               autocvar_g_nades_nade_radius, self, world, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
-                       Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
-                               autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
-               }
-               remove(self);
-               return;
-       }
-
-
-       self.nextthink = time+0.1;
-
-       // gaussian
-       float randomr;
-       randomr = random();
-       randomr = exp(-5*randomr*randomr)*autocvar_g_nades_nade_radius;
-       float randomw;
-       randomw = random()*M_PI*2;
-       vector randomp;
-       randomp.x = randomr*cos(randomw);
-       randomp.y = randomr*sin(randomw);
-       randomp.z = 1;
-       Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, self.origin + randomp, '0 0 0', 1);
-
-       if(time >= self.nade_special_time)
-       {
-               self.nade_special_time = time+0.7;
-
-               Send_Effect(EFFECT_ELECTRO_IMPACT, self.origin, '0 0 0', 1);
-               Send_Effect(EFFECT_ICEFIELD, self.origin, '0 0 0', 1);
-       }
-
-
-       float current_freeze_time = self.ltime - time - 0.1;
-
-       entity e;
-       for(e = findradius(self.origin, autocvar_g_nades_nade_radius); e; e = e.chain)
-       if(e != self)
-       if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(e, self.realowner) || e == self.realowner))
-       if(e.takedamage && e.deadflag == DEAD_NO)
-       if(e.health > 0)
-       if(!e.revival_time || ((time - e.revival_time) >= 1.5))
-       if(!e.frozen)
-       if(current_freeze_time > 0)
-               nade_ice_freeze(self, e, current_freeze_time);
-}
-
-void nade_ice_boom()
-{SELFPARAM();
-       entity fountain;
-       fountain = spawn();
-       fountain.owner = self.owner;
-       fountain.realowner = self.realowner;
-       fountain.origin = self.origin;
-       setorigin(fountain, fountain.origin);
-       fountain.think = nade_ice_think;
-       fountain.nextthink = time;
-       fountain.ltime = time + autocvar_g_nades_ice_freeze_time;
-       fountain.pushltime = fountain.wait = fountain.ltime;
-       fountain.team = self.team;
-       fountain.movetype = MOVETYPE_TOSS;
-       fountain.projectiledeathtype = DEATH_NADE_ICE.m_id;
-       fountain.bot_dodge = false;
-       setsize(fountain, '-16 -16 -16', '16 16 16');
-       fountain.nade_special_time = time+0.3;
-       fountain.angles = self.angles;
-
-       if ( autocvar_g_nades_ice_explode )
-       {
-               setmodel(fountain, MDL_PROJECTILE_GRENADE);
-               entity timer = spawn();
-               setmodel(timer, MDL_NADE_TIMER);
-               setattachment(timer, fountain, "");
-               timer.classname = "nade_timer";
-               timer.colormap = self.colormap;
-               timer.glowmod = self.glowmod;
-               timer.think = nade_timer_think;
-               timer.nextthink = time;
-               timer.wait = fountain.ltime;
-               timer.owner = fountain;
-               timer.skin = 10;
-       }
-       else
-               setmodel(fountain, MDL_Null);
-}
-
-void nade_translocate_boom()
-{SELFPARAM();
-       if(self.realowner.vehicle)
-               return;
-
-       vector locout = self.origin + '0 0 1' * (1 - self.realowner.mins.z - 24);
-       tracebox(locout, self.realowner.mins, self.realowner.maxs, locout, MOVE_NOMONSTERS, self.realowner);
-       locout = trace_endpos;
-
-       makevectors(self.realowner.angles);
-
-       MUTATOR_CALLHOOK(PortalTeleport, self.realowner);
-
-       TeleportPlayer(self, self.realowner, locout, self.realowner.angles, v_forward * vlen(self.realowner.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
-}
-
-void nade_spawn_boom()
-{SELFPARAM();
-       entity spawnloc = spawn();
-       setorigin(spawnloc, self.origin);
-       setsize(spawnloc, self.realowner.mins, self.realowner.maxs);
-       spawnloc.movetype = MOVETYPE_NONE;
-       spawnloc.solid = SOLID_NOT;
-       spawnloc.drawonlytoclient = self.realowner;
-       spawnloc.effects = EF_STARDUST;
-       spawnloc.cnt = autocvar_g_nades_spawn_count;
-
-       if(self.realowner.nade_spawnloc)
-       {
-               remove(self.realowner.nade_spawnloc);
-               self.realowner.nade_spawnloc = world;
-       }
-
-       self.realowner.nade_spawnloc = spawnloc;
-}
-
-void nade_heal_think()
-{SELFPARAM();
-       if(time >= self.ltime)
-       {
-               remove(self);
-               return;
-       }
-
-       self.nextthink = time;
-
-       if(time >= self.nade_special_time)
-       {
-               self.nade_special_time = time+0.25;
-               self.nade_show_particles = 1;
-       }
-       else
-               self.nade_show_particles = 0;
-}
-
-void nade_heal_touch()
-{SELFPARAM();
-       float maxhealth;
-       float health_factor;
-       if(IS_PLAYER(other) || IS_MONSTER(other))
-       if(other.deadflag == DEAD_NO)
-       if(!other.frozen)
-       {
-               health_factor = autocvar_g_nades_heal_rate*frametime/2;
-               if ( other != self.realowner )
-               {
-                       if ( SAME_TEAM(other,self) )
-                               health_factor *= autocvar_g_nades_heal_friend;
-                       else
-                               health_factor *= autocvar_g_nades_heal_foe;
-               }
-               if ( health_factor > 0 )
-               {
-                       maxhealth = (IS_MONSTER(other)) ? other.max_health : g_pickup_healthmega_max;
-                       if ( other.health < maxhealth )
-                       {
-                               if ( self.nade_show_particles )
-                                       Send_Effect(EFFECT_HEALING, other.origin, '0 0 0', 1);
-                               other.health = min(other.health+health_factor, maxhealth);
-                       }
-                       other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
-               }
-               else if ( health_factor < 0 )
-               {
-                       Damage(other,self,self.realowner,-health_factor,DEATH_NADE_HEAL.m_id,other.origin,'0 0 0');
-               }
-
-       }
-
-       if ( IS_REAL_CLIENT(other) || IS_VEHICLE(other) )
-       {
-               entity show_red = (IS_VEHICLE(other)) ? other.owner : other;
-               show_red.stat_healing_orb = time+0.1;
-               show_red.stat_healing_orb_alpha = 0.75 * (self.ltime - time) / self.healer_lifetime;
-       }
-}
-
-void nade_heal_boom()
-{SELFPARAM();
-       entity healer;
-       healer = spawn();
-       healer.owner = self.owner;
-       healer.realowner = self.realowner;
-       setorigin(healer, self.origin);
-       healer.healer_lifetime = autocvar_g_nades_heal_time; // save the cvar
-       healer.ltime = time + healer.healer_lifetime;
-       healer.team = self.realowner.team;
-       healer.bot_dodge = false;
-       healer.solid = SOLID_TRIGGER;
-       healer.touch = nade_heal_touch;
-
-       setmodel(healer, MDL_NADE_HEAL);
-       healer.healer_radius = autocvar_g_nades_nade_radius;
-       vector size = '1 1 1' * healer.healer_radius / 2;
-       setsize(healer,-size,size);
-
-       Net_LinkEntity(healer, true, 0, healer_send);
-
-       healer.think = nade_heal_think;
-       healer.nextthink = time;
-       healer.SendFlags |= 1;
-}
-
-void nade_monster_boom()
-{SELFPARAM();
-       entity e = spawnmonster(self.pokenade_type, 0, self.realowner, self.realowner, self.origin, false, false, 1);
-
-       if(autocvar_g_nades_pokenade_monster_lifetime > 0)
-               e.monster_lifetime = time + autocvar_g_nades_pokenade_monster_lifetime;
-       e.monster_skill = MONSTER_SKILL_INSANE;
-}
-
-void nade_boom()
-{SELFPARAM();
-       entity expef = NULL;
-       bool nade_blast = true;
-
-       switch ( Nades[self.nade_type] )
-       {
-               case NADE_TYPE_NAPALM:
-                       nade_blast = autocvar_g_nades_napalm_blast;
-                       expef = EFFECT_EXPLOSION_MEDIUM;
-                       break;
-               case NADE_TYPE_ICE:
-                       nade_blast = false;
-                       expef = EFFECT_ELECTRO_COMBO; // hookbomb_explode electro_combo bigplasma_impact
-                       break;
-               case NADE_TYPE_TRANSLOCATE:
-                       nade_blast = false;
-                       break;
-               case NADE_TYPE_MONSTER:
-               case NADE_TYPE_SPAWN:
-                       nade_blast = false;
-                       switch(self.realowner.team)
-                       {
-                               case NUM_TEAM_1: expef = EFFECT_SPAWN_RED; break;
-                               case NUM_TEAM_2: expef = EFFECT_SPAWN_BLUE; break;
-                               case NUM_TEAM_3: expef = EFFECT_SPAWN_YELLOW; break;
-                               case NUM_TEAM_4: expef = EFFECT_SPAWN_PINK; break;
-                               default: expef = EFFECT_SPAWN_NEUTRAL; break;
-                       }
-                       break;
-               case NADE_TYPE_HEAL:
-                       nade_blast = false;
-                       expef = EFFECT_SPAWN_RED;
-                       break;
-
-               default:
-               case NADE_TYPE_NORMAL:
-                       expef = EFFECT_NADE_EXPLODE(self.realowner.team);
-                       break;
-       }
-
-       if(expef)
-               Send_Effect(expef, findbetterlocation(self.origin, 8), '0 0 0', 1);
-
-       sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM);
-       sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
-
-       self.event_damage = func_null; // prevent somehow calling damage in the next call
-
-       if(nade_blast)
-       {
-               RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
-                                autocvar_g_nades_nade_radius, self, world, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy);
-               Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self);
-       }
-
-       if(self.takedamage)
-       switch ( Nades[self.nade_type] )
-       {
-               case NADE_TYPE_NAPALM: nade_napalm_boom(); break;
-               case NADE_TYPE_ICE: nade_ice_boom(); break;
-               case NADE_TYPE_TRANSLOCATE: nade_translocate_boom(); break;
-               case NADE_TYPE_SPAWN: nade_spawn_boom(); break;
-               case NADE_TYPE_HEAL: nade_heal_boom(); break;
-               case NADE_TYPE_MONSTER: nade_monster_boom(); break;
-       }
-
-       entity head;
-       for(head = world; (head = find(head, classname, "grapplinghook")); )
-       if(head.aiment == self)
-               RemoveGrapplingHook(head.realowner);
-
-       remove(self);
-}
-
-void nade_touch()
-{SELFPARAM();
-       /*float is_weapclip = 0;
-       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW)
-       if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID))
-       if (!(trace_dphitcontents & DPCONTENTS_OPAQUE))
-               is_weapclip = 1;*/
-       if(ITEM_TOUCH_NEEDKILL()) // || is_weapclip)
-       {
-               entity head;
-               for(head = world; (head = find(head, classname, "grapplinghook")); )
-               if(head.aiment == self)
-                       RemoveGrapplingHook(head.realowner);
-               remove(self);
-               return;
-       }
-
-       PROJECTILE_TOUCH;
-
-       //setsize(self, '-2 -2 -2', '2 2 2');
-       //UpdateCSQCProjectile(self);
-       if(self.health == self.max_health)
-       {
-               spamsound(self, CH_SHOTS, SND(GRENADE_BOUNCE_RANDOM()), VOL_BASE, ATTEN_NORM);
-               return;
-       }
-
-       self.enemy = other;
-       nade_boom();
-}
-
-void nade_beep()
-{SELFPARAM();
-       sound(self, CH_SHOTS_SINGLE, SND_NADE_BEEP, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
-       self.think = nade_boom;
-       self.nextthink = max(self.wait, time);
-}
-
-void nade_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
-       if(ITEM_DAMAGE_NEEDKILL(deathtype))
-       {
-               self.takedamage = DAMAGE_NO;
-               nade_boom();
-               return;
-       }
-
-       if(self.nade_type == NADE_TYPE_TRANSLOCATE.m_id || self.nade_type == NADE_TYPE_SPAWN.m_id)
-               return;
-
-       if(DEATH_ISWEAPON(deathtype, WEP_BLASTER))
-       {
-               force *= 1.5;
-               damage = 0;
-       }
-
-       if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER) && (deathtype & HITTYPE_SECONDARY))
-       {
-               force *= 0.5; // too much
-               frag_damage = 0;
-       }
-
-       if(DEATH_ISWEAPON(deathtype, WEP_VORTEX) || DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
-       {
-               force *= 6;
-               damage = self.max_health * 0.55;
-       }
-
-       if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN) || DEATH_ISWEAPON(deathtype, WEP_HMG))
-               damage = self.max_health * 0.1;
-
-       if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE) || DEATH_ISWEAPON(deathtype, WEP_SHOTGUN)) // WEAPONTODO
-       if(deathtype & HITTYPE_SECONDARY)
-       {
-               damage = self.max_health * 0.1;
-               force *= 10;
-       }
-       else
-               damage = self.max_health * 1.15;
-
-       self.velocity += force;
-       UpdateCSQCProjectile(self);
-
-       if(damage <= 0 || ((self.flags & FL_ONGROUND) && IS_PLAYER(attacker)))
-               return;
-
-       if(self.health == self.max_health)
-       {
-               sound(self, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
-               self.nextthink = max(time + autocvar_g_nades_nade_lifetime, time);
-               self.think = nade_beep;
-       }
-
-       self.health -= damage;
-
-       if ( self.nade_type != NADE_TYPE_HEAL.m_id || IS_PLAYER(attacker) )
-               self.realowner = attacker;
-
-       if(self.health <= 0)
-               W_PrepareExplosionByDamage(attacker, nade_boom);
-       else
-               nade_burn_spawn(self);
-}
-
-void toss_nade(entity e, vector _velocity, float _time)
-{SELFPARAM();
-       if(e.nade == world)
-               return;
-
-       entity _nade = e.nade;
-       e.nade = world;
-
-       remove(e.fake_nade);
-       e.fake_nade = world;
-
-       makevectors(e.v_angle);
-
-       W_SetupShot(e, false, false, "", CH_WEAPON_A, 0);
-
-       Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_NADES);
-
-       vector offset = (v_forward * autocvar_g_nades_throw_offset.x)
-                                 + (v_right * autocvar_g_nades_throw_offset.y)
-                                 + (v_up * autocvar_g_nades_throw_offset.z);
-       if(autocvar_g_nades_throw_offset == '0 0 0')
-               offset = '0 0 0';
-
-       setorigin(_nade, w_shotorg + offset + (v_right * 25) * -1);
-       //setmodel(_nade, MDL_PROJECTILE_NADE);
-       //setattachment(_nade, world, "");
-       PROJECTILE_MAKETRIGGER(_nade);
-       setsize(_nade, '-16 -16 -16', '16 16 16');
-       _nade.movetype = MOVETYPE_BOUNCE;
-
-       tracebox(_nade.origin, _nade.mins, _nade.maxs, _nade.origin, false, _nade);
-       if (trace_startsolid)
-               setorigin(_nade, e.origin);
-
-       if(self.v_angle.x >= 70 && self.v_angle.x <= 110 && self.BUTTON_CROUCH)
-               _nade.velocity = '0 0 100';
-       else if(autocvar_g_nades_nade_newton_style == 1)
-               _nade.velocity = e.velocity + _velocity;
-       else if(autocvar_g_nades_nade_newton_style == 2)
-               _nade.velocity = _velocity;
-       else
-               _nade.velocity = W_CalculateProjectileVelocity(e.velocity, _velocity, true);
-
-       _nade.touch = nade_touch;
-       _nade.health = autocvar_g_nades_nade_health;
-       _nade.max_health = _nade.health;
-       _nade.takedamage = DAMAGE_AIM;
-       _nade.event_damage = nade_damage;
-       _nade.customizeentityforclient = func_null;
-       _nade.exteriormodeltoclient = world;
-       _nade.traileffectnum = 0;
-       _nade.teleportable = true;
-       _nade.pushable = true;
-       _nade.gravity = 1;
-       _nade.missile_flags = MIF_SPLASH | MIF_ARC;
-       _nade.damagedbycontents = true;
-       _nade.angles = vectoangles(_nade.velocity);
-       _nade.flags = FL_PROJECTILE;
-       _nade.projectiledeathtype = DEATH_NADE.m_id;
-       _nade.toss_time = time;
-       _nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX);
-
-       if(_nade.nade_type == NADE_TYPE_TRANSLOCATE.m_id || _nade.nade_type == NADE_TYPE_SPAWN.m_id)
-               _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
-       else
-               _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
-
-       nade_spawn(_nade);
-
-       if(_time)
-       {
-               _nade.think = nade_boom;
-               _nade.nextthink = _time;
-       }
-
-       e.nade_refire = time + autocvar_g_nades_nade_refire;
-       e.nade_timer = 0;
-}
-
-void nades_GiveBonus(entity player, float score)
-{
-       if (autocvar_g_nades)
-       if (autocvar_g_nades_bonus)
-       if (IS_REAL_CLIENT(player))
-       if (IS_PLAYER(player) && player.bonus_nades < autocvar_g_nades_bonus_max)
-       if (player.frozen == 0)
-       if (player.deadflag == DEAD_NO)
-       {
-               if ( player.bonus_nade_score < 1 )
-                       player.bonus_nade_score += score/autocvar_g_nades_bonus_score_max;
-
-               if ( player.bonus_nade_score >= 1 )
-               {
-                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_NADE_BONUS);
-                       play2(player, SND(KH_ALARM));
-                       player.bonus_nades++;
-                       player.bonus_nade_score -= 1;
-               }
-       }
-}
-
-void nades_RemoveBonus(entity player)
-{
-       player.bonus_nades = player.bonus_nade_score = 0;
-}
-
-float nade_customize()
-{SELFPARAM();
-       //if(IS_SPEC(other)) { return false; }
-       if(other == self.realowner || (IS_SPEC(other) && other.enemy == self.realowner))
-       {
-               // somewhat hide the model, but keep the glow
-               //self.effects = 0;
-               if(self.traileffectnum)
-                       self.traileffectnum = 0;
-               self.alpha = -1;
-       }
-       else
-       {
-               //self.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
-               if(!self.traileffectnum)
-                       self.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades[self.nade_type].m_projectile[false], self.team).eent_eff_name);
-               self.alpha = 1;
-       }
-
-       return true;
-}
-
-void nade_prime()
-{SELFPARAM();
-       if(autocvar_g_nades_bonus_only)
-       if(!self.bonus_nades)
-               return; // only allow bonus nades
-
-       if(self.nade)
-               remove(self.nade);
-
-       if(self.fake_nade)
-               remove(self.fake_nade);
-
-       entity n = spawn(), fn = spawn();
-
-       n.classname = "nade";
-       fn.classname = "fake_nade";
-
-       if(self.items & ITEM_Strength.m_itemid && autocvar_g_nades_bonus_onstrength)
-               n.nade_type = self.nade_type;
-       else if (self.bonus_nades >= 1)
-       {
-               n.nade_type = self.nade_type;
-               n.pokenade_type = self.pokenade_type;
-               self.bonus_nades -= 1;
-       }
-       else
-       {
-               n.nade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_nade_type : autocvar_g_nades_nade_type);
-               n.pokenade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_pokenade_type : autocvar_g_nades_pokenade_monster_type);
-       }
-
-       n.nade_type = bound(1, n.nade_type, Nades_COUNT);
-
-       setmodel(n, MDL_PROJECTILE_NADE);
-       //setattachment(n, self, "bip01 l hand");
-       n.exteriormodeltoclient = self;
-       n.customizeentityforclient = nade_customize;
-       n.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades[n.nade_type].m_projectile[false], self.team).eent_eff_name);
-       n.colormod = Nades[n.nade_type].m_color;
-       n.realowner = self;
-       n.colormap = self.colormap;
-       n.glowmod = self.glowmod;
-       n.wait = time + autocvar_g_nades_nade_lifetime;
-       n.nade_time_primed = time;
-       n.think = nade_beep;
-       n.nextthink = max(n.wait - 3, time);
-       n.projectiledeathtype = DEATH_NADE.m_id;
-
-       setmodel(fn, MDL_NADE_VIEW);
-       setattachment(fn, self.weaponentity, "");
-       fn.realowner = fn.owner = self;
-       fn.colormod = Nades[n.nade_type].m_color;
-       fn.colormap = self.colormap;
-       fn.glowmod = self.glowmod;
-       fn.think = SUB_Remove;
-       fn.nextthink = n.wait;
-
-       self.nade = n;
-       self.fake_nade = fn;
-}
-
-float CanThrowNade()
-{SELFPARAM();
-       if(self.vehicle)
-               return false;
-
-       if(gameover)
-               return false;
-
-       if(self.deadflag != DEAD_NO)
-               return false;
-
-       if (!autocvar_g_nades)
-               return false; // allow turning them off mid match
-
-       if(forbidWeaponUse(self))
-               return false;
-
-       if (!IS_PLAYER(self))
-               return false;
-
-       return true;
-}
-
-.bool nade_altbutton;
-
-void nades_CheckThrow()
-{SELFPARAM();
-       if(!CanThrowNade())
-               return;
-
-       entity held_nade = self.nade;
-       if (!held_nade)
-       {
-               self.nade_altbutton = true;
-               if(time > self.nade_refire)
-               {
-                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_NADE_THROW);
-                       nade_prime();
-                       self.nade_refire = time + autocvar_g_nades_nade_refire;
-               }
-       }
-       else
-       {
-               self.nade_altbutton = false;
-               if (time >= held_nade.nade_time_primed + 1) {
-                       makevectors(self.v_angle);
-                       float _force = time - held_nade.nade_time_primed;
-                       _force /= autocvar_g_nades_nade_lifetime;
-                       _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));
-                       toss_nade(self, (v_forward * 0.75 + v_up * 0.2 + v_right * 0.05) * _force, 0);
-               }
-       }
-}
-
-void nades_Clear(entity player)
-{
-       if(player.nade)
-               remove(player.nade);
-       if(player.fake_nade)
-               remove(player.fake_nade);
-
-       player.nade = player.fake_nade = world;
-       player.nade_timer = 0;
-}
-
-MUTATOR_HOOKFUNCTION(nades, VehicleEnter)
-{
-       if(vh_player.nade)
-               toss_nade(vh_player, '0 0 100', max(vh_player.nade.wait, time + 0.05));
-
-       return false;
-}
-
-CLASS(NadeOffhand, OffhandWeapon)
-    METHOD(NadeOffhand, offhand_think, void(NadeOffhand this, entity player, bool key_pressed))
-    {
-       entity held_nade = player.nade;
-               if (held_nade)
-               {
-                       player.nade_timer = bound(0, (time - held_nade.nade_time_primed) / autocvar_g_nades_nade_lifetime, 1);
-                       // LOG_TRACEF("%d %d\n", player.nade_timer, time - held_nade.nade_time_primed);
-                       makevectors(player.angles);
-                       held_nade.velocity = player.velocity;
-                       setorigin(held_nade, player.origin + player.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0);
-                       held_nade.angles_y = player.angles.y;
-
-                       if (time + 0.1 >= held_nade.wait)
-                               toss_nade(player, '0 0 0', time + 0.05);
-               }
-
-        if (!CanThrowNade()) return;
-        if (!(time > player.nade_refire)) return;
-               if (key_pressed) {
-                       if (!held_nade) {
-                               nade_prime();
-                               held_nade = player.nade;
-                       }
-               } else if (time >= held_nade.nade_time_primed + 1) {
-                       if (held_nade) {
-                               makevectors(player.v_angle);
-                               float _force = time - held_nade.nade_time_primed;
-                               _force /= autocvar_g_nades_nade_lifetime;
-                               _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));
-                               toss_nade(player, (v_forward * 0.7 + v_up * 0.2 + v_right * 0.1) * _force, 0);
-                       }
-               }
-    }
-ENDCLASS(NadeOffhand)
-NadeOffhand OFFHAND_NADE; STATIC_INIT(OFFHAND_NADE) { OFFHAND_NADE = NEW(NadeOffhand); }
-
-MUTATOR_HOOKFUNCTION(nades, ForbidThrowCurrentWeapon, CBC_ORDER_LAST)
-{
-       if (self.offhand != OFFHAND_NADE || (self.weapons & WEPSET(HOOK)) || autocvar_g_nades_override_dropweapon) {
-               nades_CheckThrow();
-               return true;
-       }
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
-{SELFPARAM();
-       if (!IS_PLAYER(self)) { return false; }
-
-       if (self.nade && (self.offhand != OFFHAND_NADE || (self.weapons & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, self, self.nade_altbutton);
-
-       if(IS_PLAYER(self))
-       {
-               if ( autocvar_g_nades_bonus && autocvar_g_nades )
-               {
-                       entity key;
-                       float key_count = 0;
-                       FOR_EACH_KH_KEY(key) if(key.owner == self) { ++key_count; }
-
-                       float time_score;
-                       if(self.flagcarried || self.ballcarried) // this player is important
-                               time_score = autocvar_g_nades_bonus_score_time_flagcarrier;
-                       else
-                               time_score = autocvar_g_nades_bonus_score_time;
-
-                       if(key_count)
-                               time_score = autocvar_g_nades_bonus_score_time_flagcarrier * key_count; // multiply by the number of keys the player is holding
-
-                       if(autocvar_g_nades_bonus_client_select)
-                       {
-                               self.nade_type = self.cvar_cl_nade_type;
-                               self.pokenade_type = self.cvar_cl_pokenade_type;
-                       }
-                       else
-                       {
-                               self.nade_type = autocvar_g_nades_bonus_type;
-                               self.pokenade_type = autocvar_g_nades_pokenade_monster_type;
-                       }
-
-                       self.nade_type = bound(1, self.nade_type, Nades_COUNT);
-
-                       if(self.bonus_nade_score >= 0 && autocvar_g_nades_bonus_score_max)
-                               nades_GiveBonus(self, time_score / autocvar_g_nades_bonus_score_max);
-               }
-               else
-               {
-                       self.bonus_nades = self.bonus_nade_score = 0;
-               }
-       }
-
-       float n = 0;
-       entity o = world;
-       if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
-               n = -1;
-       else
-       {
-               vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
-               n = 0;
-               FOR_EACH_PLAYER(other) if(self != other)
-               {
-                       if(other.deadflag == DEAD_NO)
-                       if(other.frozen == 0)
-                       if(SAME_TEAM(other, self))
-                       if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
-                       {
-                               if(!o)
-                                       o = other;
-                               if(self.frozen == 1)
-                                       other.reviving = true;
-                               ++n;
-                       }
-               }
-       }
-
-       if(n && self.frozen == 3) // OK, there is at least one teammate reviving us
-       {
-               self.revive_progress = bound(0, self.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
-               self.health = max(1, self.revive_progress * start_health);
-
-               if(self.revive_progress >= 1)
-               {
-                       Unfreeze(self);
-
-                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
-                       Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, self.netname);
-               }
-
-               FOR_EACH_PLAYER(other) if(other.reviving)
-               {
-                       other.revive_progress = self.revive_progress;
-                       other.reviving = false;
-               }
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, PlayerSpawn)
-{SELFPARAM();
-       if(autocvar_g_nades_spawn)
-               self.nade_refire = time + autocvar_g_spawnshieldtime;
-       else
-               self.nade_refire  = time + autocvar_g_nades_nade_refire;
-
-       if(autocvar_g_nades_bonus_client_select)
-               self.nade_type = self.cvar_cl_nade_type;
-
-       self.nade_timer = 0;
-
-       if (!self.offhand) self.offhand = OFFHAND_NADE;
-
-       if(self.nade_spawnloc)
-       {
-               setorigin(self, self.nade_spawnloc.origin);
-               self.nade_spawnloc.cnt -= 1;
-
-               if(self.nade_spawnloc.cnt <= 0)
-               {
-                       remove(self.nade_spawnloc);
-                       self.nade_spawnloc = world;
-               }
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, PlayerDies, CBC_ORDER_LAST)
-{
-       if(frag_target.nade)
-       if(!frag_target.frozen || !autocvar_g_freezetag_revive_nade)
-               toss_nade(frag_target, '0 0 100', max(frag_target.nade.wait, time + 0.05));
-
-       float killcount_bonus = ((frag_attacker.killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * frag_attacker.killcount, autocvar_g_nades_bonus_score_medium) : autocvar_g_nades_bonus_score_minor);
-
-       if(IS_PLAYER(frag_attacker))
-       {
-               if (SAME_TEAM(frag_attacker, frag_target) || frag_attacker == frag_target)
-                       nades_RemoveBonus(frag_attacker);
-               else if(frag_target.flagcarried)
-                       nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_medium);
-               else if(autocvar_g_nades_bonus_score_spree && frag_attacker.killcount > 1)
-               {
-                       #define SPREE_ITEM(counta,countb,center,normal,gentle) \
-                               case counta: { nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_spree); break; }
-                       switch(frag_attacker.killcount)
-                       {
-                               KILL_SPREE_LIST
-                               default: nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor); break;
-                       }
-                       #undef SPREE_ITEM
-               }
-               else
-                       nades_GiveBonus(frag_attacker, killcount_bonus);
-       }
-
-       nades_RemoveBonus(frag_target);
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, PlayerDamage_Calculate)
-{
-       if(frag_target.frozen)
-       if(autocvar_g_freezetag_revive_nade)
-       if(frag_attacker == frag_target)
-       if(frag_deathtype == DEATH_NADE.m_id)
-       if(time - frag_inflictor.toss_time <= 0.1)
-       {
-               Unfreeze(frag_target);
-               frag_target.health = autocvar_g_freezetag_revive_nade_health;
-               Send_Effect(EFFECT_ICEORGLASS, frag_target.origin, '0 0 0', 3);
-               frag_damage = 0;
-               frag_force = '0 0 0';
-               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED_NADE, frag_target.netname);
-               Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF);
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, MonsterDies)
-{SELFPARAM();
-       if(IS_PLAYER(frag_attacker))
-       if(DIFF_TEAM(frag_attacker, self))
-       if(!(self.spawnflags & MONSTERFLAG_SPAWNED))
-               nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor);
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, DropSpecialItems)
-{
-       if(frag_target.nade)
-               toss_nade(frag_target, '0 0 0', time + 0.05);
-
-       return false;
-}
-
-bool nades_RemovePlayer()
-{SELFPARAM();
-       nades_Clear(self);
-       nades_RemoveBonus(self);
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, MakePlayerObserver) { nades_RemovePlayer(); }
-MUTATOR_HOOKFUNCTION(nades, ClientDisconnect) { nades_RemovePlayer(); }
-MUTATOR_HOOKFUNCTION(nades, reset_map_global) { nades_RemovePlayer(); }
-
-MUTATOR_HOOKFUNCTION(nades, SpectateCopy)
-{SELFPARAM();
-       self.nade_timer = other.nade_timer;
-       self.nade_type = other.nade_type;
-       self.pokenade_type = other.pokenade_type;
-       self.bonus_nades = other.bonus_nades;
-       self.bonus_nade_score = other.bonus_nade_score;
-       self.stat_healing_orb = other.stat_healing_orb;
-       self.stat_healing_orb_alpha = other.stat_healing_orb_alpha;
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, GetCvars)
-{
-       GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_nade_type, "cl_nade_type");
-       GetCvars_handleString(get_cvars_s, get_cvars_f, cvar_cl_pokenade_type, "cl_pokenade_type");
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":Nades");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(nades, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Nades");
-       return false;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_new_toys.qc b/qcsrc/server/mutators/mutator/mutator_new_toys.qc
deleted file mode 100644 (file)
index 78904ff..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-#ifdef IMPLEMENTATION
-/*
-
-CORE    laser   vortex     lg      rl      cry     gl      elec    hagar   fireb   hook
-                                                                       vaporizer  porto
-                                                                       tuba
-
-NEW             rifle   hlac    minel                           seeker
-IDEAS                                   OPEN    flak    OPEN            FUN FUN FUN FUN
-
-
-
-How this mutator works:
- =======================
-
-When a gun tries to spawn, this mutator is called. It will provide alternate
-weaponreplace lists.
-
-Entity:
-
-{
-"classname" "weapon_vortex"
-"new_toys" "rifle"
-}
--> This will spawn as Rifle in this mutator ONLY, and as Vortex otherwise.
-
-{
-"classname" "weapon_vortext"
-"new_toys" "vortex rifle"
-}
--> This will spawn as either Vortex or Rifle in this mutator ONLY, and as Vortex otherwise.
-
-{
-"classname" "weapon_vortex"
-"new_toys" "vortex"
-}
--> This is always a Vortex.
-
-If the map specifies no "new_toys" argument
-
-There will be two default replacements selectable: "replace all" and "replace random".
-In "replace all" mode, e.g. Vortex will have the default replacement "rifle".
-In "replace random" mode, Vortex will have the default replacement "vortex rifle".
-
-This mutator's replacements run BEFORE regular weaponreplace!
-
-The New Toys guns do NOT get a spawn function, so they can only ever be spawned
-when this mutator is active.
-
-Likewise, warmup, give all, give ALL and impulse 99 will not give them unless
-this mutator is active.
-
-Outside this mutator, they still can be spawned by:
-- setting their start weapon cvar to 1
-- give weaponname
-- weaponreplace
-- weaponarena (but all and most weapons arena again won't include them)
-
-This mutator performs the default replacements on the DEFAULTS of the
-start weapon selection.
-
-These weapons appear in the menu's priority list, BUT get a suffix
-"(Mutator weapon)".
-
-Picking up a "new toys" weapon will not play standard weapon pickup sound, but
-roflsound "New toys, new toys!" sound.
-
-*/
-
-bool nt_IsNewToy(int w);
-
-REGISTER_MUTATOR(nt, cvar("g_new_toys") && !cvar("g_instagib") && !cvar("g_overkill"))
-{
-       MUTATOR_ONADD
-       {
-               if(time > 1) // game loads at time 1
-                       error("This cannot be added at runtime\n");
-
-               // mark the guns as ok to use by e.g. impulse 99
-               for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
-                       if(nt_IsNewToy(i))
-                               get_weaponinfo(i).spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
-                       if(nt_IsNewToy(i))
-                               get_weaponinfo(i).spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This cannot be removed at runtime\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-.string new_toys;
-
-float autocvar_g_new_toys_autoreplace;
-bool autocvar_g_new_toys_use_pickupsound = true;
-const float NT_AUTOREPLACE_NEVER = 0;
-const float NT_AUTOREPLACE_ALWAYS = 1;
-const float NT_AUTOREPLACE_RANDOM = 2;
-
-MUTATOR_HOOKFUNCTION(nt, SetModname)
-{
-       modname = "NewToys";
-       return 0;
-}
-
-bool nt_IsNewToy(int w)
-{
-       switch(w)
-       {
-               case WEP_SEEKER.m_id:
-               case WEP_MINE_LAYER.m_id:
-               case WEP_HLAC.m_id:
-               case WEP_RIFLE.m_id:
-               case WEP_SHOCKWAVE.m_id:
-                       return true;
-               default:
-                       return false;
-       }
-}
-
-string nt_GetFullReplacement(string w)
-{
-       switch(w)
-       {
-               case "hagar": return "seeker";
-               case "devastator": return "minelayer";
-               case "machinegun": return "hlac";
-               case "vortex": return "rifle";
-               //case "shotgun": return "shockwave";
-               default: return string_null;
-       }
-}
-
-string nt_GetReplacement(string w, float m)
-{
-       if(m == NT_AUTOREPLACE_NEVER)
-               return w;
-       string s = nt_GetFullReplacement(w);
-       if (!s)
-               return w;
-       if(m == NT_AUTOREPLACE_RANDOM)
-               s = strcat(w, " ", s);
-       return s;
-}
-
-MUTATOR_HOOKFUNCTION(nt, SetStartItems)
-{
-       // rearrange start_weapon_default
-       // apply those bits that are set by start_weapon_defaultmask
-       // same for warmup
-
-       float i, j, k, n;
-
-       WepSet newdefault;
-       WepSet warmup_newdefault;
-
-       newdefault = '0 0 0';
-       warmup_newdefault = '0 0 0';
-
-       for(i = WEP_FIRST; i <= WEP_LAST; ++i)
-       {
-               entity e = get_weaponinfo(i);
-               if(!e.weapon)
-                       continue;
-
-               n = tokenize_console(nt_GetReplacement(e.netname, autocvar_g_new_toys_autoreplace));
-
-               for(j = 0; j < n; ++j)
-                       for(k = WEP_FIRST; k <= WEP_LAST; ++k)
-                               if(get_weaponinfo(k).netname == argv(j))
-                               {
-                                       if(start_weapons & WepSet_FromWeapon(i))
-                                               newdefault |= WepSet_FromWeapon(k);
-                                       if(warmup_start_weapons & WepSet_FromWeapon(i))
-                                               warmup_newdefault |= WepSet_FromWeapon(k);
-                               }
-       }
-
-       newdefault &= start_weapons_defaultmask;
-       start_weapons &= ~start_weapons_defaultmask;
-       start_weapons |= newdefault;
-
-       warmup_newdefault &= warmup_start_weapons_defaultmask;
-       warmup_start_weapons &= ~warmup_start_weapons_defaultmask;
-       warmup_start_weapons |= warmup_newdefault;
-
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nt, SetWeaponreplace)
-{SELFPARAM();
-       // otherwise, we do replace
-       if(self.new_toys)
-       {
-               // map defined replacement:
-               ret_string = self.new_toys;
-       }
-       else
-       {
-               // auto replacement:
-               ret_string = nt_GetReplacement(other.netname, autocvar_g_new_toys_autoreplace);
-       }
-
-       // apply regular weaponreplace
-       ret_string = W_Apply_Weaponreplace(ret_string);
-
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nt, FilterItem)
-{SELFPARAM();
-       if(nt_IsNewToy(self.weapon) && autocvar_g_new_toys_use_pickupsound) {
-               self.item_pickupsound = string_null;
-               self.item_pickupsound_ent = SND_WEAPONPICKUP_NEW_TOYS;
-       }
-       return 0;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_nix.qc b/qcsrc/server/mutators/mutator/mutator_nix.qc
deleted file mode 100644 (file)
index 259547a..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-#ifdef IMPLEMENTATION
-float g_nix_with_blaster;
-// WEAPONTODO
-int nix_weapon;
-float nix_nextchange;
-float nix_nextweapon;
-.float nix_lastchange_id;
-.float nix_lastinfotime;
-.float nix_nextincr;
-
-bool NIX_CanChooseWeapon(int wpn);
-
-REGISTER_MUTATOR(nix, cvar("g_nix") && !cvar("g_instagib") && !cvar("g_overkill"))
-{
-       MUTATOR_ONADD
-       {
-               g_nix_with_blaster = autocvar_g_nix_with_blaster;
-
-               nix_nextchange = 0;
-               nix_nextweapon = 0;
-
-               for (int i = WEP_FIRST; i <= WEP_LAST; ++i)
-                       if (NIX_CanChooseWeapon(i)) {
-                               Weapon w = get_weaponinfo(i);
-                               w.wr_init(w);
-                       }
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // nothing to roll back
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
-               entity e;
-               FOR_EACH_PLAYER(e) if(e.deadflag == DEAD_NO)
-               {
-                       e.ammo_cells = start_ammo_cells;
-                       e.ammo_plasma = start_ammo_plasma;
-                       e.ammo_shells = start_ammo_shells;
-                       e.ammo_nails = start_ammo_nails;
-                       e.ammo_rockets = start_ammo_rockets;
-                       e.ammo_fuel = start_ammo_fuel;
-                       e.weapons = start_weapons;
-                       if(!client_hasweapon(e, e.weapon, true, false))
-                               e.switchweapon = w_getbestweapon(self);
-               }
-       }
-
-       return 0;
-}
-
-bool NIX_CanChooseWeapon(int wpn)
-{
-       entity e = get_weaponinfo(wpn);
-       if(!e.weapon) // skip dummies
-               return false;
-       if(g_weaponarena)
-       {
-               if(!(g_weaponarena_weapons & WepSet_FromWeapon(wpn)))
-                       return false;
-       }
-       else
-       {
-               if(wpn == WEP_BLASTER.m_id && g_nix_with_blaster)
-                       return false;
-               if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
-                       return false;
-               if (!(e.spawnflags & WEP_FLAG_NORMAL))
-                       return false;
-       }
-       return true;
-}
-void NIX_ChooseNextWeapon()
-{
-       float j;
-       RandomSelection_Init();
-       for(j = WEP_FIRST; j <= WEP_LAST; ++j)
-               if(NIX_CanChooseWeapon(j))
-                       RandomSelection_Add(world, j, string_null, 1, (j != nix_weapon));
-       nix_nextweapon = RandomSelection_chosen_float;
-}
-
-void NIX_GiveCurrentWeapon()
-{SELFPARAM();
-       float dt;
-
-       if(!nix_nextweapon)
-               NIX_ChooseNextWeapon();
-
-       dt = ceil(nix_nextchange - time);
-
-       if(dt <= 0)
-       {
-               nix_weapon = nix_nextweapon;
-               nix_nextweapon = 0;
-               if (!nix_nextchange) // no round played yet?
-                       nix_nextchange = time; // start the first round now!
-               else
-                       nix_nextchange = time + autocvar_g_balance_nix_roundtime;
-               // Weapon w = get_weaponinfo(nix_weapon);
-               // w.wr_init(w); // forget it, too slow
-       }
-
-       // get weapon info
-       entity e = get_weaponinfo(nix_weapon);
-
-       if(nix_nextchange != self.nix_lastchange_id) // this shall only be called once per round!
-       {
-               self.ammo_shells = self.ammo_nails = self.ammo_rockets = self.ammo_cells = self.ammo_plasma = self.ammo_fuel = 0;
-
-               if(self.items & IT_UNLIMITED_WEAPON_AMMO)
-               {
-                       switch(e.ammo_field)
-                       {
-                               case ammo_shells:  self.ammo_shells  = autocvar_g_pickup_shells_max;  break;
-                               case ammo_nails:   self.ammo_nails   = autocvar_g_pickup_nails_max;   break;
-                               case ammo_rockets: self.ammo_rockets = autocvar_g_pickup_rockets_max; break;
-                               case ammo_cells:   self.ammo_cells   = autocvar_g_pickup_cells_max;   break;
-                               case ammo_plasma:  self.ammo_plasma  = autocvar_g_pickup_plasma_max;   break;
-                               case ammo_fuel:    self.ammo_fuel    = autocvar_g_pickup_fuel_max;    break;
-                       }
-               }
-               else
-               {
-                       switch(e.ammo_field)
-                       {
-                               case ammo_shells:  self.ammo_shells  = autocvar_g_balance_nix_ammo_shells;  break;
-                               case ammo_nails:   self.ammo_nails   = autocvar_g_balance_nix_ammo_nails;   break;
-                               case ammo_rockets: self.ammo_rockets = autocvar_g_balance_nix_ammo_rockets; break;
-                               case ammo_cells:   self.ammo_cells   = autocvar_g_balance_nix_ammo_cells;   break;
-                               case ammo_plasma:  self.ammo_plasma  = autocvar_g_balance_nix_ammo_plasma;   break;
-                               case ammo_fuel:    self.ammo_fuel    = autocvar_g_balance_nix_ammo_fuel;    break;
-                       }
-               }
-
-               self.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
-               if(dt >= 1 && dt <= 5)
-                       self.nix_lastinfotime = -42;
-               else
-                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
-
-               Weapon w = get_weaponinfo(nix_weapon);
-               w.wr_resetplayer(w);
-
-               // all weapons must be fully loaded when we spawn
-               if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
-                       self.(weapon_load[nix_weapon]) = e.reloading_ammo;
-
-               // vortex too
-               if(WEP_CVAR(vortex, charge))
-               {
-                       if(WEP_CVAR_SEC(vortex, chargepool))
-                               self.vortex_chargepool_ammo = 1;
-                       self.vortex_charge = WEP_CVAR(vortex, charge_start);
-               }
-
-               // set last change info
-               self.nix_lastchange_id = nix_nextchange;
-       }
-       if(self.nix_lastinfotime != dt)
-       {
-               self.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
-               if(dt >= 1 && dt <= 5)
-                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
-       }
-
-       if(!(self.items & IT_UNLIMITED_WEAPON_AMMO) && time > self.nix_nextincr)
-       {
-               switch(e.ammo_field)
-               {
-                       case ammo_shells:  self.ammo_shells  += autocvar_g_balance_nix_ammoincr_shells;  break;
-                       case ammo_nails:   self.ammo_nails   += autocvar_g_balance_nix_ammoincr_nails;   break;
-                       case ammo_rockets: self.ammo_rockets += autocvar_g_balance_nix_ammoincr_rockets; break;
-                       case ammo_cells:   self.ammo_cells   += autocvar_g_balance_nix_ammoincr_cells;   break;
-                       case ammo_plasma:  self.ammo_plasma  += autocvar_g_balance_nix_ammoincr_plasma;   break;
-                       case ammo_fuel:    self.ammo_fuel    += autocvar_g_balance_nix_ammoincr_fuel;    break;
-               }
-
-               self.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
-       }
-
-       self.weapons = '0 0 0';
-       if(g_nix_with_blaster)
-               self.weapons |= WEPSET(BLASTER);
-       self.weapons |= WepSet_FromWeapon(nix_weapon);
-
-       if(self.switchweapon != nix_weapon)
-               if(!client_hasweapon(self, self.switchweapon, true, false))
-                       if(client_hasweapon(self, nix_weapon, true, false))
-                               W_SwitchWeapon(nix_weapon);
-}
-
-MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
-{
-       return 1; // no throwing in NIX
-}
-
-MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":NIX");
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", NIX");
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nix, FilterItem)
-{SELFPARAM();
-       switch (self.items)
-       {
-               case ITEM_HealthSmall.m_itemid:
-               case ITEM_HealthMedium.m_itemid:
-               case ITEM_HealthLarge.m_itemid:
-               case ITEM_HealthMega.m_itemid:
-               case ITEM_ArmorSmall.m_itemid:
-               case ITEM_ArmorMedium.m_itemid:
-               case ITEM_ArmorLarge.m_itemid:
-               case ITEM_ArmorMega.m_itemid:
-                       if (autocvar_g_nix_with_healtharmor)
-                               return 0;
-                       break;
-               case ITEM_Strength.m_itemid:
-               case ITEM_Shield.m_itemid:
-                       if (autocvar_g_nix_with_powerups)
-                               return 0;
-                       break;
-       }
-
-       return 1; // delete all other items
-}
-
-MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
-{SELFPARAM();
-       if(self.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
-               return 1;
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
-{SELFPARAM();
-       if(!intermission_running)
-       if(self.deadflag == DEAD_NO)
-       if(IS_PLAYER(self))
-               NIX_GiveCurrentWeapon();
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
-{SELFPARAM();
-       self.nix_lastchange_id = -1;
-       NIX_GiveCurrentWeapon(); // overrides the weapons you got when spawning
-       self.items |= IT_UNLIMITED_SUPERWEAPONS;
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nix, SetModname, CBC_ORDER_LAST)
-{
-       modname = "NIX";
-       return 0;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_overkill.qc b/qcsrc/server/mutators/mutator/mutator_overkill.qc
deleted file mode 100644 (file)
index ea5adbf..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-#ifdef IMPLEMENTATION
-.vector ok_deathloc;
-.float ok_spawnsys_timer;
-.float ok_lastwep;
-.float ok_item;
-
-.float ok_notice_time;
-.float ammo_charge[Weapons_MAX];
-.float ok_use_ammocharge;
-.float ok_ammo_charge;
-
-.float ok_pauseregen_finished;
-
-void(entity ent, float wep) ok_DecreaseCharge;
-
-void ok_Initialize();
-
-REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
-{
-       MUTATOR_ONADD
-       {
-               ok_Initialize();
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-               WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-       }
-
-       return false;
-}
-
-void W_Blaster_Attack(entity, float, float, float, float, float, float, float, float, float, float);
-spawnfunc(weapon_hmg);
-spawnfunc(weapon_rpc);
-
-void ok_DecreaseCharge(entity ent, int wep)
-{
-       if(!ent.ok_use_ammocharge) return;
-
-       entity wepent = get_weaponinfo(wep);
-
-       if(wepent.weapon == 0)
-               return; // dummy
-
-       ent.ammo_charge[wep] -= max(0, cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
-}
-
-void ok_IncreaseCharge(entity ent, int wep)
-{
-       entity wepent = get_weaponinfo(wep);
-
-       if(wepent.weapon == 0)
-               return; // dummy
-
-       if(ent.ok_use_ammocharge)
-       if(!ent.BUTTON_ATCK) // not while attacking?
-               ent.ammo_charge[wep] = min(autocvar_g_overkill_ammo_charge_limit, ent.ammo_charge[wep] + cvar(sprintf("g_overkill_ammo_charge_rate_%s", wepent.netname)) * frametime / W_TICSPERFRAME);
-}
-
-float ok_CheckWeaponCharge(entity ent, int wep)
-{
-       if(!ent.ok_use_ammocharge) return true;
-
-       entity wepent = get_weaponinfo(wep);
-
-       if(wepent.weapon == 0)
-               return 0; // dummy
-
-       return (ent.ammo_charge[wep] >= cvar(sprintf("g_overkill_ammo_decharge_%s", wepent.netname)));
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDamage_Calculate, CBC_ORDER_LAST)
-{
-       if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target))
-       if(DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
-       {
-               frag_damage = 0;
-
-               if(frag_attacker != frag_target)
-               if(frag_target.health > 0)
-               if(frag_target.frozen == 0)
-               if(frag_target.deadflag == DEAD_NO)
-               {
-                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE);
-                       frag_force = '0 0 0';
-               }
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDamage_SplitHealthArmor)
-{SELFPARAM();
-       if(damage_take)
-               self.ok_pauseregen_finished = max(self.ok_pauseregen_finished, time + 2);
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerDies)
-{SELFPARAM();
-       entity targ = ((frag_attacker) ? frag_attacker : frag_target);
-
-       if(IS_MONSTER(self))
-       {
-               remove(other); // remove default item
-               other = world;
-       }
-
-       setself(spawn());
-       self.ok_item = true;
-       self.noalign = true;
-       self.pickup_anyway = true;
-       spawnfunc_item_armor_small(this);
-       self.movetype = MOVETYPE_TOSS;
-       self.gravity = 1;
-       self.reset = SUB_Remove;
-       setorigin(self, frag_target.origin + '0 0 32');
-       self.velocity = '0 0 200' + normalize(targ.origin - self.origin) * 500;
-       self.classname = "droppedweapon"; // hax
-       SUB_SetFade(self, time + 5, 1);
-       setself(this);
-
-       self.ok_lastwep = self.switchweapon;
-
-       return false;
-}
-MUTATOR_HOOKFUNCTION(ok, MonsterDropItem) { ok_PlayerDies(); }
-
-MUTATOR_HOOKFUNCTION(ok, PlayerRegen)
-{SELFPARAM();
-       // overkill's values are different, so use custom regen
-       if(!self.frozen)
-       {
-               self.armorvalue = CalcRotRegen(self.armorvalue, autocvar_g_balance_armor_regenstable, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, 1 * frametime * (time > self.ok_pauseregen_finished), 0, 0, 1, 1 * frametime * (time > self.pauserotarmor_finished), autocvar_g_balance_armor_limit);
-               self.health = CalcRotRegen(self.health, autocvar_g_balance_health_regenstable, 0, 100, 1 * frametime * (time > self.ok_pauseregen_finished), 200, 0, autocvar_g_balance_health_rotlinear, 1 * frametime * (time > self.pauserothealth_finished), autocvar_g_balance_health_limit);
-
-               float minf, maxf, limitf;
-
-               maxf = autocvar_g_balance_fuel_rotstable;
-               minf = autocvar_g_balance_fuel_regenstable;
-               limitf = autocvar_g_balance_fuel_limit;
-
-               self.ammo_fuel = CalcRotRegen(self.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > self.pauseregen_finished) * ((self.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > self.pauserotfuel_finished), limitf);
-       }
-       return true; // return true anyway, as frozen uses no regen
-}
-
-MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
-{
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
-{SELFPARAM();
-       if(intermission_running || gameover)
-               return false;
-
-       if(self.deadflag != DEAD_NO || !IS_PLAYER(self) || self.frozen)
-               return false;
-
-       if(self.ok_lastwep)
-       {
-               self.switchweapon = self.ok_lastwep;
-               self.ok_lastwep = 0;
-       }
-
-       ok_IncreaseCharge(self, self.weapon);
-
-       if(self.BUTTON_ATCK2)
-       if(!forbidWeaponUse(self) || self.weapon_blocked) // allow if weapon is blocked
-       if(time >= self.jump_interval)
-       {
-               self.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor();
-               makevectors(self.v_angle);
-
-               int oldwep = self.weapon;
-               self.weapon = WEP_BLASTER.m_id;
-               W_Blaster_Attack(
-                       self,
-                       WEP_BLASTER.m_id | HITTYPE_SECONDARY,
-                       WEP_CVAR_SEC(vaporizer, shotangle),
-                       WEP_CVAR_SEC(vaporizer, damage),
-                       WEP_CVAR_SEC(vaporizer, edgedamage),
-                       WEP_CVAR_SEC(vaporizer, radius),
-                       WEP_CVAR_SEC(vaporizer, force),
-                       WEP_CVAR_SEC(vaporizer, speed),
-                       WEP_CVAR_SEC(vaporizer, spread),
-                       WEP_CVAR_SEC(vaporizer, delay),
-                       WEP_CVAR_SEC(vaporizer, lifetime)
-               );
-               self.weapon = oldwep;
-       }
-
-       self.weapon_blocked = false;
-
-       self.ok_ammo_charge = self.ammo_charge[self.weapon];
-
-       if(self.ok_use_ammocharge)
-       if(!ok_CheckWeaponCharge(self, self.weapon))
-       {
-               if(autocvar_g_overkill_ammo_charge_notice && time > self.ok_notice_time && self.BUTTON_ATCK && IS_REAL_CLIENT(self) && self.weapon == self.switchweapon)
-               {
-                       //Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_OVERKILL_CHARGE);
-                       self.ok_notice_time = time + 2;
-                       play2(self, SND(DRYFIRE));
-               }
-               Weapon wpn = get_weaponinfo(self.weapon);
-               if(self.weaponentity.state != WS_CLEAR)
-                       w_ready(wpn, self, self.BUTTON_ATCK, self.BUTTON_ATCK2);
-
-               self.weapon_blocked = true;
-       }
-
-       self.BUTTON_ATCK2 = 0;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, PlayerSpawn)
-{SELFPARAM();
-       if(autocvar_g_overkill_ammo_charge)
-       {
-               for(int i = WEP_FIRST; i <= WEP_LAST; ++i)
-                       self.ammo_charge[i] = autocvar_g_overkill_ammo_charge_limit;
-
-               self.ok_use_ammocharge = 1;
-               self.ok_notice_time = time;
-       }
-       else
-               self.ok_use_ammocharge = 0;
-
-       self.ok_pauseregen_finished = time + 2;
-
-       return false;
-}
-
-void _spawnfunc_weapon_hmg() { SELFPARAM(); spawnfunc_weapon_hmg(this); }
-void _spawnfunc_weapon_rpc() { SELFPARAM(); spawnfunc_weapon_rpc(this); }
-
-MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
-{SELFPARAM();
-       if(autocvar_g_powerups)
-       if(autocvar_g_overkill_powerups_replace)
-       {
-               if(self.classname == "item_strength")
-               {
-                       entity wep = spawn();
-                       setorigin(wep, self.origin);
-                       setmodel(wep, MDL_OK_HMG);
-                       wep.classname = "weapon_hmg";
-                       wep.ok_item = true;
-                       wep.noalign = self.noalign;
-                       wep.cnt = self.cnt;
-                       wep.team = self.team;
-                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
-                       wep.pickup_anyway = true;
-                       wep.think = _spawnfunc_weapon_hmg;
-                       wep.nextthink = time + 0.1;
-                       return true;
-               }
-
-               if(self.classname == "item_invincible")
-               {
-                       entity wep = spawn();
-                       setorigin(wep, self.origin);
-                       setmodel(wep, MDL_OK_RPC);
-                       wep.classname = "weapon_rpc";
-                       wep.ok_item = true;
-                       wep.noalign = self.noalign;
-                       wep.cnt = self.cnt;
-                       wep.team = self.team;
-                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
-                       wep.pickup_anyway = true;
-                       wep.think = _spawnfunc_weapon_rpc;
-                       wep.nextthink = time + 0.1;
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, FilterItem)
-{SELFPARAM();
-       if(self.ok_item)
-               return false;
-
-       switch(self.items)
-       {
-               case ITEM_HealthMega.m_itemid: return !(autocvar_g_overkill_100h_anyway);
-               case ITEM_ArmorMega.m_itemid: return !(autocvar_g_overkill_100a_anyway);
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ok, SpectateCopy)
-{SELFPARAM();
-       self.ammo_charge[self.weapon] = other.ammo_charge[other.weapon];
-       self.ok_use_ammocharge = other.ok_use_ammocharge;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, SetStartItems)
-{
-       WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
-
-       if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
-       if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
-
-       start_items |= IT_UNLIMITED_WEAPON_AMMO;
-       start_weapons = warmup_start_weapons = ok_start_items;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":OK");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Overkill");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ok, SetModname)
-{
-       modname = "Overkill";
-       return true;
-}
-
-void ok_SetCvars()
-{
-       // hack to force overkill playermodels
-       cvar_settemp("sv_defaultcharacter", "1");
-       cvar_settemp("sv_defaultplayermodel", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
-       cvar_settemp("sv_defaultplayermodel_red", "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm");
-       cvar_settemp("sv_defaultplayermodel_blue", "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm");
-}
-
-void ok_Initialize()
-{
-       ok_SetCvars();
-
-       precache_all_playermodels("models/ok_player/*.dpm");
-
-       addstat(STAT_OK_AMMO_CHARGE, AS_FLOAT, ok_use_ammocharge);
-       addstat(STAT_OK_AMMO_CHARGEPOOL, AS_FLOAT, ok_ammo_charge);
-
-       WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-       WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-
-       WEP_SHOTGUN.mdl = "ok_shotgun";
-       WEP_MACHINEGUN.mdl = "ok_mg";
-       WEP_VORTEX.mdl = "ok_sniper";
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_physical_items.qc b/qcsrc/server/mutators/mutator/mutator_physical_items.qc
deleted file mode 100644 (file)
index 58a01ca..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(physical_items, cvar("g_physical_items"))
-{
-       // check if we have a physics engine
-       MUTATOR_ONADD
-       {
-               if (!(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")))
-               {
-                       LOG_TRACE("Warning: Physical items are enabled but no physics engine can be used. Reverting to old items.\n");
-                       return -1;
-               }
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // nothing to roll back
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               LOG_INFO("This cannot be removed at runtime\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-.vector spawn_origin, spawn_angles;
-
-void physical_item_think()
-{SELFPARAM();
-       self.nextthink = time;
-
-       self.alpha = self.owner.alpha; // apply fading and ghosting
-
-       if(!self.cnt) // map item, not dropped
-       {
-               // copy ghost item properties
-               self.colormap = self.owner.colormap;
-               self.colormod = self.owner.colormod;
-               self.glowmod = self.owner.glowmod;
-
-               // if the item is not spawned, make sure the invisible / ghost item returns to its origin and stays there
-               if(autocvar_g_physical_items_reset)
-               {
-                       if(self.owner.wait > time) // awaiting respawn
-                       {
-                               setorigin(self, self.spawn_origin);
-                               self.angles = self.spawn_angles;
-                               self.solid = SOLID_NOT;
-                               self.alpha = -1;
-                               self.movetype = MOVETYPE_NONE;
-                       }
-                       else
-                       {
-                               self.alpha = 1;
-                               self.solid = SOLID_CORPSE;
-                               self.movetype = MOVETYPE_PHYSICS;
-                       }
-               }
-       }
-
-       if(!self.owner.modelindex)
-               remove(self); // the real item is gone, remove this
-}
-
-void physical_item_touch()
-{SELFPARAM();
-       if(!self.cnt) // not for dropped items
-       if (ITEM_TOUCH_NEEDKILL())
-       {
-               setorigin(self, self.spawn_origin);
-               self.angles = self.spawn_angles;
-       }
-}
-
-void physical_item_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
-{SELFPARAM();
-       if(!self.cnt) // not for dropped items
-       if(ITEM_DAMAGE_NEEDKILL(deathtype))
-       {
-               setorigin(self, self.spawn_origin);
-               self.angles = self.spawn_angles;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(physical_items, Item_Spawn)
-{SELFPARAM();
-       if(self.owner == world && autocvar_g_physical_items <= 1)
-               return false;
-       if (self.spawnflags & 1) // floating item
-               return false;
-
-       // The actual item can't be physical and trigger at the same time, so make it invisible and use a second entity for physics.
-       // Ugly hack, but unless SOLID_TRIGGER is gotten to work with MOVETYPE_PHYSICS in the engine it can't be fixed.
-       entity wep;
-       wep = spawn();
-       _setmodel(wep, self.model);
-       setsize(wep, self.mins, self.maxs);
-       setorigin(wep, self.origin);
-       wep.angles = self.angles;
-       wep.velocity = self.velocity;
-
-       wep.owner = self;
-       wep.solid = SOLID_CORPSE;
-       wep.movetype = MOVETYPE_PHYSICS;
-       wep.takedamage = DAMAGE_AIM;
-       wep.effects |= EF_NOMODELFLAGS; // disable the spinning
-       wep.colormap = self.owner.colormap;
-       wep.glowmod = self.owner.glowmod;
-       wep.damageforcescale = autocvar_g_physical_items_damageforcescale;
-       wep.dphitcontentsmask = self.dphitcontentsmask;
-       wep.cnt = (self.owner != world);
-
-       wep.think = physical_item_think;
-       wep.nextthink = time;
-       wep.touch = physical_item_touch;
-       wep.event_damage = physical_item_damage;
-
-       if(!wep.cnt)
-       {
-               // fix the spawn origin
-               setorigin(wep, wep.origin + '0 0 1');
-               entity oldself;
-               oldself = self;
-               WITH(entity, self, wep, builtin_droptofloor());
-       }
-
-       wep.spawn_origin = wep.origin;
-       wep.spawn_angles = self.angles;
-
-       self.effects |= EF_NODRAW; // hide the original weapon
-       self.movetype = MOVETYPE_FOLLOW;
-       self.aiment = wep; // attach the original weapon
-       self.SendEntity = func_null;
-
-       return false;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_pinata.qc b/qcsrc/server/mutators/mutator/mutator_pinata.qc
deleted file mode 100644 (file)
index a806b29..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(pinata, cvar("g_pinata") && !cvar("g_instagib") && !cvar("g_overkill"));
-
-MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
-{SELFPARAM();
-       for(int j = WEP_FIRST; j <= WEP_LAST; ++j)
-       if(self.weapons & WepSet_FromWeapon(j))
-       if(self.switchweapon != j)
-       if(W_IsWeaponThrowable(j))
-               W_ThrowNewWeapon(self, j, false, self.origin + (self.mins + self.maxs) * 0.5, randomvec() * 175 + '0 0 325');
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":Pinata");
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(pinata, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Piñata");
-       return false;
-}
-
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_random_gravity.qc b/qcsrc/server/mutators/mutator/mutator_random_gravity.qc
deleted file mode 100644 (file)
index 1b17c9f..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifdef IMPLEMENTATION
-// Random Gravity
-//
-// Mutator by Mario
-// Inspired by Player 2
-
-REGISTER_MUTATOR(random_gravity, cvar("g_random_gravity"))
-{
-       MUTATOR_ONADD
-       {
-               cvar_settemp("sv_gravity", cvar_string("sv_gravity")); // settemp current gravity so it's restored on match end
-       }
-
-       return false;
-}
-
-float gravity_delay;
-
-MUTATOR_HOOKFUNCTION(random_gravity, SV_StartFrame)
-{
-       if(gameover || !cvar("g_random_gravity")) return false;
-       if(time < gravity_delay) return false;
-       if(time < game_starttime) return false;
-       if(round_handler_IsActive() && !round_handler_IsRoundStarted()) return false;
-
-    if(random() >= autocvar_g_random_gravity_negative_chance)
-        cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() - random() * -autocvar_g_random_gravity_negative, autocvar_g_random_gravity_max)));
-    else
-        cvar_set("sv_gravity", ftos(bound(autocvar_g_random_gravity_min, random() * autocvar_g_random_gravity_positive, autocvar_g_random_gravity_max)));
-
-       gravity_delay = time + autocvar_g_random_gravity_delay;
-
-       LOG_TRACE("Gravity is now: ", ftos(autocvar_sv_gravity), "\n");
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":RandomGravity");
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(random_gravity, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Random gravity");
-       return 0;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_rocketflying.qc b/qcsrc/server/mutators/mutator/mutator_rocketflying.qc
deleted file mode 100644 (file)
index f23d991..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(rocketflying, cvar("g_rocket_flying"));
-
-MUTATOR_HOOKFUNCTION(rocketflying, EditProjectile)
-{
-       if(other.classname == "rocket" || other.classname == "mine")
-       {
-               // kill detonate delay of rockets
-               other.spawnshieldtime = time;
-       }
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":RocketFlying");
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(rocketflying, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Rocket Flying");
-       return 0;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_rocketminsta.qc b/qcsrc/server/mutators/mutator/mutator_rocketminsta.qc
deleted file mode 100644 (file)
index f8a1709..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifdef IMPLEMENTATION
-#include "../../../common/deathtypes/all.qh"
-#include "../../round_handler.qh"
-
-REGISTER_MUTATOR(rm, cvar("g_instagib"));
-
-MUTATOR_HOOKFUNCTION(rm, PlayerDamage_Calculate)
-{
-       // we do it this way, so rm can be toggled during the match
-       if(!autocvar_g_rm) { return false; }
-
-       if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR))
-       if(frag_attacker == frag_target || frag_target.classname == "nade")
-               frag_damage = 0;
-
-       if(autocvar_g_rm_laser)
-       if(DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
-       if(frag_attacker == frag_target || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
-               frag_damage = 0;
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(rm, PlayerDies)
-{
-       // we do it this way, so rm can be toggled during the match
-       if(!autocvar_g_rm) { return false; }
-
-       if(DEATH_ISWEAPON(frag_deathtype, WEP_DEVASTATOR) || DEATH_ISWEAPON(frag_deathtype, WEP_ELECTRO))
-               frag_damage = 1000; // always gib if it was a vaporizer death
-
-       return false;
-}
-
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_spawn_near_teammate.qc b/qcsrc/server/mutators/mutator/mutator_spawn_near_teammate.qc
deleted file mode 100644 (file)
index 24147b2..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(spawn_near_teammate, cvar("g_spawn_near_teammate") && teamplay);
-
-.entity msnt_lookat;
-
-.float msnt_timer;
-.vector msnt_deathloc;
-
-.float cvar_cl_spawn_near_teammate;
-
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, Spawn_Score)
-{SELFPARAM();
-       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && self.cvar_cl_spawn_near_teammate))
-               return 0;
-
-       entity p;
-
-       spawn_spot.msnt_lookat = world;
-
-       if(!teamplay)
-               return 0;
-
-       RandomSelection_Init();
-       FOR_EACH_PLAYER(p) if(p != self) if(p.team == self.team) if(!p.deadflag)
-       {
-               float l = vlen(spawn_spot.origin - p.origin);
-               if(l > autocvar_g_spawn_near_teammate_distance)
-                       continue;
-               if(l < 48)
-                       continue;
-               if(!checkpvs(spawn_spot.origin, p))
-                       continue;
-               RandomSelection_Add(p, 0, string_null, 1, 1);
-       }
-
-       if(RandomSelection_chosen_ent)
-       {
-               spawn_spot.msnt_lookat = RandomSelection_chosen_ent;
-               spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_FOUND;
-       }
-       else if(self.team == spawn_spot.team)
-               spawn_score.x += SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM; // prefer same team, if we can't find a spawn near teammate
-
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
-{SELFPARAM();
-       // Note: when entering this, fixangle is already set.
-       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint == 1 || (autocvar_g_spawn_near_teammate_ignore_spawnpoint == 2 && self.cvar_cl_spawn_near_teammate))
-       {
-               if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death)
-                       self.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
-
-               entity team_mate, best_mate = world;
-               vector best_spot = '0 0 0';
-               float pc = 0, best_dist = 0, dist = 0;
-               FOR_EACH_PLAYER(team_mate)
-               {
-                       if((autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health >= 0 && team_mate.health >= autocvar_g_balance_health_regenstable) || autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health == 0)
-                       if(team_mate.deadflag == DEAD_NO)
-                       if(team_mate.msnt_timer < time)
-                       if(SAME_TEAM(self, team_mate))
-                       if(time > team_mate.spawnshieldtime) // spawn shielding
-                       if(team_mate.frozen == 0)
-                       if(team_mate != self)
-                       {
-                               tracebox(team_mate.origin, PL_MIN, PL_MAX, team_mate.origin - '0 0 100', MOVE_WORLDONLY, team_mate);
-                               if(trace_fraction != 1.0)
-                               if(!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
-                               {
-                                       pc = pointcontents(trace_endpos + '0 0 1');
-                                       if(pc == CONTENT_EMPTY)
-                                       {
-                                               if(vlen(team_mate.velocity) > 5)
-                                                       fixedmakevectors(vectoangles(team_mate.velocity));
-                                               else
-                                                       fixedmakevectors(team_mate.angles);
-
-                                               for(pc = 0; pc != 5; ++pc) // test 5 diffrent spots close to mate
-                                               {
-                                                       switch(pc)
-                                                       {
-                                                               case 0:
-                                                                       tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin + v_right * 128, MOVE_NORMAL, team_mate);
-                                                                       break;
-                                                               case 1:
-                                                                       tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_right * 128 , MOVE_NORMAL, team_mate);
-                                                                       break;
-                                                               case 2:
-                                                                       tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin + v_right * 64 - v_forward * 64, MOVE_NORMAL, team_mate);
-                                                                       break;
-                                                               case 3:
-                                                                       tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_right * 64 - v_forward * 64, MOVE_NORMAL, team_mate);
-                                                                       break;
-                                                               case 4:
-                                                                       tracebox(team_mate.origin , PL_MIN, PL_MAX, team_mate.origin - v_forward * 128, MOVE_NORMAL, team_mate);
-                                                                       break;
-                                                       }
-
-                                                       if(trace_fraction == 1.0)
-                                                       {
-                                                               traceline(trace_endpos + '0 0 4', trace_endpos - '0 0 100', MOVE_NORMAL, team_mate);
-                                                               if(trace_fraction != 1.0)
-                                                               {
-                                                                       if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
-                                                                       {
-                                                                               dist = vlen(trace_endpos - self.msnt_deathloc);
-                                                                               if(dist < best_dist || best_dist == 0)
-                                                                               {
-                                                                                       best_dist = dist;
-                                                                                       best_spot = trace_endpos;
-                                                                                       best_mate = team_mate;
-                                                                               }
-                                                                       }
-                                                                       else
-                                                                       {
-                                                                               setorigin(self, trace_endpos);
-                                                                               self.angles = team_mate.angles;
-                                                                               self.angles_z = 0; // never spawn tilted even if the spot says to
-                                                                               team_mate.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
-                                                                               return 0;
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-
-               if(autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath)
-               if(best_dist)
-               {
-                       setorigin(self, best_spot);
-                       self.angles = best_mate.angles;
-                       self.angles_z = 0; // never spawn tilted even if the spot says to
-                       best_mate.msnt_timer = time + autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
-               }
-       }
-       else if(spawn_spot.msnt_lookat)
-       {
-               self.angles = vectoangles(spawn_spot.msnt_lookat.origin - self.origin);
-               self.angles_x = -self.angles.x;
-               self.angles_z = 0; // never spawn tilted even if the spot says to
-               /*
-               sprint(self, "You should be looking at ", spawn_spot.msnt_lookat.netname, "^7.\n");
-               sprint(self, "distance: ", vtos(spawn_spot.msnt_lookat.origin - self.origin), "\n");
-               sprint(self, "angles: ", vtos(self.angles), "\n");
-               */
-       }
-
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerDies)
-{SELFPARAM();
-       self.msnt_deathloc = self.origin;
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(spawn_near_teammate, GetCvars)
-{
-       GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_spawn_near_teammate, "cl_spawn_near_teammate");
-       return false;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_superspec.qc b/qcsrc/server/mutators/mutator/mutator_superspec.qc
deleted file mode 100644 (file)
index 416df75..0000000
+++ /dev/null
@@ -1,480 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(superspec, cvar("g_superspectate"));
-
-#define _SSMAGIX "SUPERSPEC_OPTIONSFILE_V1"
-#define _ISLOCAL ((edict_num(1) == self) ? true : false)
-
-const float ASF_STRENGTH               = BIT(0);
-const float ASF_SHIELD                         = BIT(1);
-const float ASF_MEGA_AR                = BIT(2);
-const float ASF_MEGA_HP                = BIT(3);
-const float ASF_FLAG_GRAB              = BIT(4);
-const float ASF_OBSERVER_ONLY  = BIT(5);
-const float ASF_SHOWWHAT               = BIT(6);
-const float ASF_SSIM                   = BIT(7);
-const float ASF_FOLLOWKILLER   = BIT(8);
-const float ASF_ALL                    = 0xFFFFFF;
-.float autospec_flags;
-
-const float SSF_SILENT = 1;
-const float SSF_VERBOSE = 2;
-const float SSF_ITEMMSG = 4;
-.float superspec_flags;
-
-.string superspec_itemfilter; //"classname1 classname2 ..."
-
-bool superspec_Spectate(entity _player)
-{SELFPARAM();
-       if(Spectate(_player) == 1)
-               self.classname = STR_SPECTATOR;
-
-       return true;
-}
-
-void superspec_save_client_conf()
-{SELFPARAM();
-       string fn = "superspec-local.options";
-       float fh;
-
-       if (!_ISLOCAL)
-       {
-               if(self.crypto_idfp == "")
-                       return;
-
-               fn = sprintf("superspec-%s.options", uri_escape(self.crypto_idfp));
-       }
-
-       fh = fopen(fn, FILE_WRITE);
-       if(fh < 0)
-       {
-               LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for writing.\n");
-       }
-       else
-       {
-               fputs(fh, _SSMAGIX);
-               fputs(fh, "\n");
-               fputs(fh, ftos(self.autospec_flags));
-               fputs(fh, "\n");
-               fputs(fh, ftos(self.superspec_flags));
-               fputs(fh, "\n");
-               fputs(fh, self.superspec_itemfilter);
-               fputs(fh, "\n");
-               fclose(fh);
-       }
-}
-
-void superspec_msg(string _center_title, string _con_title, entity _to, string _msg, float _spamlevel)
-{
-       sprint(_to, strcat(_con_title, _msg));
-
-       if(_to.superspec_flags & SSF_SILENT)
-               return;
-
-       if(_spamlevel > 1)
-               if (!(_to.superspec_flags & SSF_VERBOSE))
-                       return;
-
-       centerprint(_to, strcat(_center_title, _msg));
-}
-
-float superspec_filteritem(entity _for, entity _item)
-{
-       float i;
-
-       if(_for.superspec_itemfilter == "")
-               return true;
-
-       if(_for.superspec_itemfilter == "")
-               return true;
-
-       float l = tokenize_console(_for.superspec_itemfilter);
-       for(i = 0; i < l; ++i)
-       {
-               if(argv(i) == _item.classname)
-                       return true;
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, ItemTouch)
-{SELFPARAM();
-       entity _item = self;
-
-       entity e;
-       FOR_EACH_SPEC(e)
-       {
-               setself(e);
-               if(self.superspec_flags & SSF_ITEMMSG)
-                       if(superspec_filteritem(self, _item))
-                       {
-                               if(self.superspec_flags & SSF_VERBOSE)
-                                       superspec_msg("", "", self, sprintf("Player %s^7 just picked up ^3%s\n", other.netname, _item.netname), 1);
-                               else
-                                       superspec_msg("", "", self, sprintf("Player %s^7 just picked up ^3%s\n^8(%s^8)\n", other.netname, _item.netname, _item.classname), 1);
-                               if((self.autospec_flags & ASF_SSIM) && self.enemy != other)
-                               {
-                                       superspec_Spectate(other);
-
-                                       setself(this);
-                                       return MUT_ITEMTOUCH_CONTINUE;
-                               }
-                       }
-
-               if((self.autospec_flags & ASF_SHIELD && _item.invincible_finished) ||
-                       (self.autospec_flags & ASF_STRENGTH && _item.strength_finished) ||
-                       (self.autospec_flags & ASF_MEGA_AR && _item.itemdef == ITEM_ArmorMega) ||
-                       (self.autospec_flags & ASF_MEGA_HP && _item.itemdef == ITEM_HealthMega) ||
-                       (self.autospec_flags & ASF_FLAG_GRAB && _item.classname == "item_flag_team"))
-               {
-
-                       if((self.enemy != other) || IS_OBSERVER(self))
-                       {
-                               if(self.autospec_flags & ASF_OBSERVER_ONLY && !IS_OBSERVER(self))
-                               {
-                                       if(self.superspec_flags & SSF_VERBOSE)
-                                               superspec_msg("", "", self, sprintf("^8Ignored that ^7%s^8 grabbed %s^8 since the observer_only option is ON\n", other.netname, _item.netname), 2);
-                               }
-                               else
-                               {
-                                       if(self.autospec_flags & ASF_SHOWWHAT)
-                                               superspec_msg("", "", self, sprintf("^7Following %s^7 due to picking up %s\n", other.netname, _item.netname), 2);
-
-                                       superspec_Spectate(other);
-                               }
-                       }
-               }
-       }
-
-       setself(this);
-
-       return MUT_ITEMTOUCH_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, SV_ParseClientCommand)
-{SELFPARAM();
-#define OPTIONINFO(flag,var,test,text,long,short) \
-    var = strcat(var, ((flag & test) ? "^2[ON]  ^7" : "^1[OFF] ^7")); \
-    var = strcat(var, text," ^7(^3 ", long, "^7 | ^3", short, " ^7)\n")
-
-       if(MUTATOR_RETURNVALUE) // command was already handled?
-               return false;
-
-       if(IS_PLAYER(self))
-               return false;
-
-       if(cmd_name == "superspec_itemfilter")
-       {
-               if(argv(1) == "help")
-               {
-                       string _aspeco;
-                       _aspeco = "^7 superspec_itemfilter ^3\"item_classname1 item_classname2\"^7 only show thise items when ^2superspec ^3item_message^7 is on\n";
-                       _aspeco = strcat(_aspeco, "^3 clear^7 Remove the filter (show all pickups)\n");
-                       _aspeco = strcat(_aspeco, "^3 show ^7 Display current filter\n");
-                       superspec_msg("^3superspec_itemfilter help:\n\n\n", "\n^3superspec_itemfilter help:\n", self, _aspeco, 1);
-               }
-               else if(argv(1) == "clear")
-               {
-                       if(self.superspec_itemfilter != "")
-                               strunzone(self.superspec_itemfilter);
-
-                       self.superspec_itemfilter = "";
-               }
-               else if(argv(1) == "show" || argv(1) == "")
-               {
-                       if(self.superspec_itemfilter == "")
-                       {
-                               superspec_msg("^3superspec_itemfilter^7 is ^1not^7 set", "\n^3superspec_itemfilter^7 is ^1not^7 set\n", self, "", 1);
-                               return true;
-                       }
-                       float i;
-                       float l = tokenize_console(self.superspec_itemfilter);
-                       string _msg = "";
-                       for(i = 0; i < l; ++i)
-                               _msg = strcat(_msg, "^3#", ftos(i), " ^7", argv(i), "\n");
-                               //_msg = sprintf("^3#%d^7 %s\n%s", i, _msg, argv(i));
-
-                       _msg = strcat(_msg,"\n");
-
-                       superspec_msg("^3superspec_itemfilter is:\n\n\n", "\n^3superspec_itemfilter is:\n", self, _msg, 1);
-               }
-               else
-               {
-                       if(self.superspec_itemfilter != "")
-                               strunzone(self.superspec_itemfilter);
-
-                       self.superspec_itemfilter = strzone(argv(1));
-               }
-
-               return true;
-       }
-
-       if(cmd_name == "superspec")
-       {
-               string _aspeco;
-
-               if(cmd_argc > 1)
-               {
-                       float i, _bits = 0, _start = 1;
-                       if(argv(1) == "help")
-                       {
-                               _aspeco = "use cmd superspec [option] [on|off] to set options\n\n";
-                               _aspeco = strcat(_aspeco, "^3 silent ^7(short^5 si^7) supresses ALL messages from superspectate.\n");
-                               _aspeco = strcat(_aspeco, "^3 verbose ^7(short^5 ve^7) makes superspectate print some additional information.\n");
-                               _aspeco = strcat(_aspeco, "^3 item_message ^7(short^5 im^7) makes superspectate print items that were picked up.\n");
-                               _aspeco = strcat(_aspeco, "^7    Use cmd superspec_itemfilter \"item_class1 item_class2\" to set up a filter of what to show with ^3item_message.\n");
-                               superspec_msg("^2Available Super Spectate ^3options:\n\n\n", "\n^2Available Super Spectate ^3options:\n", self, _aspeco, 1);
-                               return true;
-                       }
-
-                       if(argv(1) == "clear")
-                       {
-                               self.superspec_flags = 0;
-                               _start = 2;
-                       }
-
-                       for(i = _start; i < cmd_argc; ++i)
-                       {
-                               if(argv(i) == "on" || argv(i) == "1")
-                               {
-                                       self.superspec_flags |= _bits;
-                                       _bits = 0;
-                               }
-                               else if(argv(i) == "off" || argv(i) == "0")
-                               {
-                                       if(_start == 1)
-                                               self.superspec_flags &= ~_bits;
-
-                                       _bits = 0;
-                               }
-                               else
-                               {
-                                       if((argv(i) == "silent") || (argv(i) == "si")) _bits |= SSF_SILENT ;
-                                       if((argv(i) == "verbose") || (argv(i) == "ve")) _bits |= SSF_VERBOSE;
-                                       if((argv(i) == "item_message") || (argv(i) == "im")) _bits |= SSF_ITEMMSG;
-                               }
-                       }
-               }
-
-               _aspeco = "";
-               OPTIONINFO(self.superspec_flags, _aspeco, SSF_SILENT, "Silent", "silent", "si");
-               OPTIONINFO(self.superspec_flags, _aspeco, SSF_VERBOSE, "Verbose", "verbose", "ve");
-               OPTIONINFO(self.superspec_flags, _aspeco, SSF_ITEMMSG, "Item pickup messages", "item_message", "im");
-
-               superspec_msg("^3Current Super Spectate options are:\n\n\n\n\n", "\n^3Current Super Spectate options are:\n", self, _aspeco, 1);
-
-               return true;
-       }
-
-/////////////////////
-
-       if(cmd_name == "autospec")
-       {
-               string _aspeco;
-               if(cmd_argc > 1)
-               {
-                       if(argv(1) == "help")
-                       {
-                               _aspeco = "use cmd autospec [option] [on|off] to set options\n\n";
-                               _aspeco = strcat(_aspeco, "^3 strength ^7(short^5 st^7) for automatic spectate on strength powerup\n");
-                               _aspeco = strcat(_aspeco, "^3 shield ^7(short^5 sh^7) for automatic spectate on shield powerup\n");
-                               _aspeco = strcat(_aspeco, "^3 mega_health ^7(short^5 mh^7) for automatic spectate on mega health\n");
-                               _aspeco = strcat(_aspeco, "^3 mega_armor ^7(short^5 ma^7) for automatic spectate on mega armor\n");
-                               _aspeco = strcat(_aspeco, "^3 flag_grab ^7(short^5 fg^7) for automatic spectate on CTF flag grab\n");
-                               _aspeco = strcat(_aspeco, "^3 observer_only ^7(short^5 oo^7) for automatic spectate only if in observer mode\n");
-                               _aspeco = strcat(_aspeco, "^3 show_what ^7(short^5 sw^7) to display what event triggered autospectate\n");
-                               _aspeco = strcat(_aspeco, "^3 item_msg ^7(short^5 im^7) to autospec when item_message in superspectate is triggered\n");
-                               _aspeco = strcat(_aspeco, "^3 followkiller ^7(short ^5fk^7) to autospec the killer/off\n");
-                               _aspeco = strcat(_aspeco, "^3 all ^7(short ^5aa^7) to turn everything on/off\n");
-                               superspec_msg("^2Available Auto Spectate ^3options:\n\n\n", "\n^2Available Auto Spectate ^3options:\n", self, _aspeco, 1);
-                               return true;
-                       }
-
-                       float i, _bits = 0, _start = 1;
-                       if(argv(1) == "clear")
-                       {
-                               self.autospec_flags = 0;
-                               _start = 2;
-                       }
-
-                       for(i = _start; i < cmd_argc; ++i)
-                       {
-                               if(argv(i) == "on" || argv(i) == "1")
-                               {
-                                       self.autospec_flags |= _bits;
-                                       _bits = 0;
-                               }
-                               else if(argv(i) == "off" || argv(i) == "0")
-                               {
-                                       if(_start == 1)
-                                               self.autospec_flags &= ~_bits;
-
-                                       _bits = 0;
-                               }
-                               else
-                               {
-                                       if((argv(i) == "strength") || (argv(i) == "st")) _bits |= ASF_STRENGTH;
-                                       if((argv(i) == "shield") || (argv(i) == "sh")) _bits |= ASF_SHIELD;
-                                       if((argv(i) == "mega_health") || (argv(i) == "mh")) _bits |= ASF_MEGA_HP;
-                                       if((argv(i) == "mega_armor") || (argv(i) == "ma")) _bits |= ASF_MEGA_AR;
-                                       if((argv(i) == "flag_grab") || (argv(i) == "fg")) _bits |= ASF_FLAG_GRAB;
-                                       if((argv(i) == "observer_only") || (argv(i) == "oo")) _bits |= ASF_OBSERVER_ONLY;
-                                       if((argv(i) == "show_what") || (argv(i) == "sw")) _bits |= ASF_SHOWWHAT;
-                                       if((argv(i) == "item_msg") || (argv(i) == "im")) _bits |= ASF_SSIM;
-                                       if((argv(i) == "followkiller") || (argv(i) == "fk")) _bits |= ASF_FOLLOWKILLER;
-                                       if((argv(i) == "all") || (argv(i) == "aa")) _bits |= ASF_ALL;
-                               }
-                       }
-               }
-
-               _aspeco = "";
-               OPTIONINFO(self.autospec_flags, _aspeco, ASF_STRENGTH, "Strength", "strength", "st");
-               OPTIONINFO(self.autospec_flags, _aspeco, ASF_SHIELD, "Shield", "shield", "sh");
-               OPTIONINFO(self.autospec_flags, _aspeco, ASF_MEGA_HP, "Mega Health", "mega_health", "mh");
-               OPTIONINFO(self.autospec_flags, _aspeco, ASF_MEGA_AR, "Mega Armor", "mega_armor", "ma");
-               OPTIONINFO(self.autospec_flags, _aspeco, ASF_FLAG_GRAB, "Flag grab", "flag_grab","fg");
-               OPTIONINFO(self.autospec_flags, _aspeco, ASF_OBSERVER_ONLY, "Only switch if observer", "observer_only", "oo");
-               OPTIONINFO(self.autospec_flags, _aspeco, ASF_SHOWWHAT, "Show what item triggered spectate", "show_what", "sw");
-               OPTIONINFO(self.autospec_flags, _aspeco, ASF_SSIM, "Switch on superspec item message", "item_msg", "im");
-               OPTIONINFO(self.autospec_flags, _aspeco, ASF_FOLLOWKILLER, "Followkiller", "followkiller", "fk");
-
-               superspec_msg("^3Current auto spectate options are:\n\n\n\n\n", "\n^3Current auto spectate options are:\n", self, _aspeco, 1);
-               return true;
-       }
-
-       if(cmd_name == "followpowerup")
-       {
-               entity _player;
-               FOR_EACH_PLAYER(_player)
-               {
-                       if(_player.strength_finished > time || _player.invincible_finished > time)
-                               return superspec_Spectate(_player);
-               }
-
-               superspec_msg("", "", self, "No active powerup\n", 1);
-               return true;
-       }
-
-       if(cmd_name == "followstrength")
-       {
-               entity _player;
-               FOR_EACH_PLAYER(_player)
-               {
-                       if(_player.strength_finished > time)
-                               return superspec_Spectate(_player);
-               }
-
-               superspec_msg("", "", self, "No active Strength\n", 1);
-               return true;
-       }
-
-       if(cmd_name == "followshield")
-       {
-               entity _player;
-               FOR_EACH_PLAYER(_player)
-               {
-                       if(_player.invincible_finished > time)
-                               return superspec_Spectate(_player);
-               }
-
-               superspec_msg("", "", self, "No active Shield\n", 1);
-               return true;
-       }
-
-       return false;
-#undef OPTIONINFO
-}
-
-MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":SS");
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Super Spectators");
-       return 0;
-}
-
-void superspec_hello()
-{SELFPARAM();
-       if(self.enemy.crypto_idfp == "")
-               Send_Notification(NOTIF_ONE_ONLY, self.enemy, MSG_INFO, INFO_SUPERSPEC_MISSING_UID);
-
-       remove(self);
-}
-
-MUTATOR_HOOKFUNCTION(superspec, ClientConnect)
-{SELFPARAM();
-       if(!IS_REAL_CLIENT(self))
-               return false;
-
-       string fn = "superspec-local.options";
-       float fh;
-
-       self.superspec_flags = SSF_VERBOSE;
-       self.superspec_itemfilter = "";
-
-       entity _hello = spawn();
-       _hello.enemy = self;
-       _hello.think = superspec_hello;
-       _hello.nextthink = time + 5;
-
-       if (!_ISLOCAL)
-       {
-               if(self.crypto_idfp == "")
-                       return false;
-
-               fn = sprintf("superspec-%s.options", uri_escape(self.crypto_idfp));
-       }
-
-       fh = fopen(fn, FILE_READ);
-       if(fh < 0)
-       {
-               LOG_TRACE("^1ERROR: ^7 superspec can not open ", fn, " for reading.\n");
-       }
-       else
-       {
-               string _magic = fgets(fh);
-               if(_magic != _SSMAGIX)
-               {
-                       LOG_TRACE("^1ERROR^7 While reading superspec options file: unknown magic\n");
-               }
-               else
-               {
-                       self.autospec_flags = stof(fgets(fh));
-                       self.superspec_flags = stof(fgets(fh));
-                       self.superspec_itemfilter = strzone(fgets(fh));
-               }
-               fclose(fh);
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, PlayerDies)
-{SELFPARAM();
-       entity e;
-       FOR_EACH_SPEC(e)
-       {
-               setself(e);
-               if(self.autospec_flags & ASF_FOLLOWKILLER && IS_PLAYER(frag_attacker) && self.enemy == this)
-               {
-                       if(self.autospec_flags & ASF_SHOWWHAT)
-                               superspec_msg("", "", self, sprintf("^7Following %s^7 due to followkiller\n", frag_attacker.netname), 2);
-
-                       superspec_Spectate(frag_attacker);
-               }
-       }
-
-       setself(this);
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(superspec, ClientDisconnect)
-{
-       superspec_save_client_conf();
-       return false;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_touchexplode.qc b/qcsrc/server/mutators/mutator/mutator_touchexplode.qc
deleted file mode 100644 (file)
index 29d9a2c..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(touchexplode, cvar("g_touchexplode"));
-
-.float touchexplode_time;
-
-void PlayerTouchExplode(entity p1, entity p2)
-{SELFPARAM();
-       vector org = (p1.origin + p2.origin) * 0.5;
-       org.z += (p1.mins.z + p2.mins.z) * 0.5;
-
-       sound(self, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
-       Send_Effect(EFFECT_EXPLOSION_SMALL, org, '0 0 0', 1);
-
-       entity e = spawn();
-       setorigin(e, org);
-       RadiusDamage(e, world, autocvar_g_touchexplode_damage, autocvar_g_touchexplode_edgedamage, autocvar_g_touchexplode_radius, world, world, autocvar_g_touchexplode_force, DEATH_TOUCHEXPLODE.m_id, world);
-       remove(e);
-}
-
-MUTATOR_HOOKFUNCTION(touchexplode, PlayerPreThink)
-{SELFPARAM();
-       if(time > self.touchexplode_time)
-       if(!gameover)
-       if(!self.frozen)
-       if(IS_PLAYER(self))
-       if(self.deadflag == DEAD_NO)
-       if (!IS_INDEPENDENT_PLAYER(self))
-       FOR_EACH_PLAYER(other) if(self != other)
-       {
-               if(time > other.touchexplode_time)
-               if(!other.frozen)
-               if(other.deadflag == DEAD_NO)
-               if (!IS_INDEPENDENT_PLAYER(other))
-               if(boxesoverlap(self.absmin, self.absmax, other.absmin, other.absmax))
-               {
-                       PlayerTouchExplode(self, other);
-                       self.touchexplode_time = other.touchexplode_time = time + 0.2;
-               }
-       }
-
-       return false;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_vampire.qc b/qcsrc/server/mutators/mutator/mutator_vampire.qc
deleted file mode 100644 (file)
index 315da7d..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(vampire, cvar("g_vampire") && !cvar("g_instagib"));
-
-MUTATOR_HOOKFUNCTION(vampire, PlayerDamage_SplitHealthArmor)
-{
-       if(time >= frag_target.spawnshieldtime)
-       if(frag_target != frag_attacker)
-       if(frag_target.deadflag == DEAD_NO)
-       {
-               frag_attacker.health += bound(0, damage_take, frag_target.health);
-               frag_attacker.health = bound(0, frag_attacker.health, autocvar_g_balance_health_limit);
-       }
-
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsString)
-{
-       ret_string = strcat(ret_string, ":Vampire");
-       return 0;
-}
-
-MUTATOR_HOOKFUNCTION(vampire, BuildMutatorsPrettyString)
-{
-       ret_string = strcat(ret_string, ", Vampire");
-       return 0;
-}
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_vampirehook.qc b/qcsrc/server/mutators/mutator/mutator_vampirehook.qc
deleted file mode 100644 (file)
index f669f6a..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifdef IMPLEMENTATION
-REGISTER_MUTATOR(vh, cvar("g_vampirehook"));
-
-bool autocvar_g_vampirehook_teamheal;
-float autocvar_g_vampirehook_damage;
-float autocvar_g_vampirehook_damagerate;
-float autocvar_g_vampirehook_health_steal;
-
-.float last_dmg;
-
-MUTATOR_HOOKFUNCTION(vh, GrappleHookThink)
-{SELFPARAM();
-       entity dmgent = ((SAME_TEAM(self.owner, self.aiment) && autocvar_g_vampirehook_teamheal) ? self.owner : self.aiment);
-
-       if(IS_PLAYER(self.aiment))
-       if(self.last_dmg < time)
-       if(!self.aiment.frozen)
-       if(time >= game_starttime)
-       if(DIFF_TEAM(self.owner, self.aiment) || autocvar_g_vampirehook_teamheal)
-       if(self.aiment.health > 0)
-       if(autocvar_g_vampirehook_damage)
-       {
-               self.last_dmg = time + autocvar_g_vampirehook_damagerate;
-               self.owner.damage_dealt += autocvar_g_vampirehook_damage;
-               Damage(dmgent, self, self.owner, autocvar_g_vampirehook_damage, WEP_HOOK.m_id, self.origin, '0 0 0');
-               if(SAME_TEAM(self.owner, self.aiment))
-                       self.aiment.health = min(self.aiment.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
-               else
-                       self.owner.health = min(self.owner.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
-
-               if(dmgent == self.owner)
-                       dmgent.health -= autocvar_g_vampirehook_damage; // FIXME: friendly fire?!
-       }
-
-       return false;
-}
-
-#endif
diff --git a/qcsrc/server/mutators/mutator/mutator_weaponarena_random.qc b/qcsrc/server/mutators/mutator/mutator_weaponarena_random.qc
deleted file mode 100644 (file)
index 5c82100..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifdef IMPLEMENTATION
-// WEAPONTODO: rename the cvars
-REGISTER_MUTATOR(weaponarena_random, true);
-
-MUTATOR_HOOKFUNCTION(weaponarena_random, PlayerSpawn) {
-    SELFPARAM();
-    if (!g_weaponarena_random) return;
-    if (g_weaponarena_random_with_blaster) this.weapons &= ~WEPSET(BLASTER);
-    W_RandomWeapons(this, g_weaponarena_random);
-    if (g_weaponarena_random_with_blaster) this.weapons |= WEPSET(BLASTER);
-}
-
-#endif
diff --git a/qcsrc/server/mutators/mutator/sandbox.qc b/qcsrc/server/mutators/mutator/sandbox.qc
deleted file mode 100644 (file)
index dbee6a1..0000000
+++ /dev/null
@@ -1,828 +0,0 @@
-#ifdef IMPLEMENTATION
-float autosave_time;
-void sandbox_Database_Load();
-
-REGISTER_MUTATOR(sandbox, cvar("g_sandbox"))
-{
-       MUTATOR_ONADD
-       {
-               autosave_time = time + autocvar_g_sandbox_storage_autosave; // don't save the first server frame
-               if(autocvar_g_sandbox_storage_autoload)
-                       sandbox_Database_Load();
-       }
-
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               // nothing to roll back
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               // nothing to remove
-       }
-
-       return false;
-}
-
-const float MAX_STORAGE_ATTACHMENTS = 16;
-float object_count;
-.float object_flood;
-.entity object_attach;
-.string material;
-
-.float touch_timer;
-void sandbox_ObjectFunction_Touch()
-{SELFPARAM();
-       // apply material impact effects
-
-       if(!self.material)
-               return;
-       if(self.touch_timer > time)
-               return; // don't execute each frame
-       self.touch_timer = time + 0.1;
-
-       // make particle count and sound volume depend on impact speed
-       float intensity;
-       intensity = vlen(self.velocity) + vlen(other.velocity);
-       if(intensity) // avoid divisions by 0
-               intensity /= 2; // average the two velocities
-       if (!(intensity >= autocvar_g_sandbox_object_material_velocity_min))
-               return; // impact not strong enough to do anything
-       // now offset intensity and apply it to the effects
-       intensity -= autocvar_g_sandbox_object_material_velocity_min; // start from minimum velocity, not actual velocity
-       intensity = bound(0, intensity * autocvar_g_sandbox_object_material_velocity_factor, 1);
-
-       _sound(self, CH_TRIGGER, strcat("object/impact_", self.material, "_", ftos(ceil(random() * 5)) , ".wav"), VOL_BASE * intensity, ATTEN_NORM);
-       Send_Effect_(strcat("impact_", self.material), self.origin, '0 0 0', ceil(intensity * 10)); // allow a count from 1 to 10
-}
-
-void sandbox_ObjectFunction_Think()
-{SELFPARAM();
-       entity e;
-
-       // decide if and how this object can be grabbed
-       if(autocvar_g_sandbox_readonly)
-               self.grab = 0; // no grabbing
-       else if(autocvar_g_sandbox_editor_free < 2 && self.crypto_idfp)
-               self.grab = 1; // owner only
-       else
-               self.grab = 3; // anyone
-
-       // Object owner is stored via player UID, but we also need the owner as an entity (if the player is available on the server).
-       // Therefore, scan for all players, and update the owner as long as the player is present. We must always do this,
-       // since if the owning player disconnects, the object's owner should also be reset.
-       FOR_EACH_REALPLAYER(e) // bots can't have objects
-       {
-               if(self.crypto_idfp == e.crypto_idfp)
-               {
-                       self.realowner = e;
-                       break;
-               }
-               self.realowner = world;
-       }
-
-       self.nextthink = time;
-
-       CSQCMODEL_AUTOUPDATE(self);
-}
-
-.float old_solid, old_movetype;
-entity sandbox_ObjectEdit_Get(float permissions)
-{SELFPARAM();
-       // Returns the traced entity if the player can edit it, and world if not.
-       // If permissions if false, the object is returned regardless of editing rights.
-       // Attached objects are SOLID_NOT and do not get traced.
-
-       crosshair_trace_plusvisibletriggers(self);
-       if(vlen(self.origin - trace_ent.origin) > autocvar_g_sandbox_editor_distance_edit)
-               return world; // out of trace range
-       if(trace_ent.classname != "object")
-               return world; // entity is not an object
-       if(!permissions)
-               return trace_ent; // don't check permissions, anyone can edit this object
-       if(trace_ent.crypto_idfp == "")
-               return trace_ent; // the player who spawned this object did not have an UID, so anyone can edit it
-       if (!(trace_ent.realowner != self && autocvar_g_sandbox_editor_free < 2))
-               return trace_ent; // object does not belong to the player, and players can only edit their own objects on this server
-       return world;
-}
-
-void sandbox_ObjectEdit_Scale(entity e, float f)
-{
-       e.scale = f;
-       if(e.scale)
-       {
-               e.scale = bound(autocvar_g_sandbox_object_scale_min, e.scale, autocvar_g_sandbox_object_scale_max);
-               _setmodel(e, e.model); // reset mins and maxs based on mesh
-               setsize(e, e.mins * e.scale, e.maxs * e.scale); // adapt bounding box size to model size
-       }
-}
-
-void sandbox_ObjectAttach_Remove(entity e);
-void sandbox_ObjectAttach_Set(entity e, entity parent, string s)
-{
-       // attaches e to parent on string s
-
-       // we can't attach to an attachment, for obvious reasons
-       sandbox_ObjectAttach_Remove(e);
-
-       e.old_solid = e.solid; // persist solidity
-       e.old_movetype = e.movetype; // persist physics
-       e.movetype = MOVETYPE_FOLLOW;
-       e.solid = SOLID_NOT;
-       e.takedamage = DAMAGE_NO;
-
-       setattachment(e, parent, s);
-       e.owner = parent;
-}
-
-void sandbox_ObjectAttach_Remove(entity e)
-{
-       // detaches any object attached to e
-
-       entity head;
-       for(head = world; (head = find(head, classname, "object")); )
-       {
-               if(head.owner == e)
-               {
-                       vector org;
-                       org = gettaginfo(head, 0);
-                       setattachment(head, world, "");
-                       head.owner = world;
-
-                       // objects change origin and angles when detached, so apply previous position
-                       setorigin(head, org);
-                       head.angles = e.angles; // don't allow detached objects to spin or roll
-
-                       head.solid = head.old_solid; // restore persisted solidity
-                       head.movetype = head.old_movetype; // restore persisted physics
-                       head.takedamage = DAMAGE_AIM;
-               }
-       }
-}
-
-entity sandbox_ObjectSpawn(float database)
-{SELFPARAM();
-       // spawn a new object with default properties
-
-       entity e = spawn();
-       e.classname = "object";
-       e.takedamage = DAMAGE_AIM;
-       e.damageforcescale = 1;
-       e.solid = SOLID_BBOX; // SOLID_BSP would be best, but can lag the server badly
-       e.movetype = MOVETYPE_TOSS;
-       e.frame = 0;
-       e.skin = 0;
-       e.material = string_null;
-       e.touch = sandbox_ObjectFunction_Touch;
-       e.think = sandbox_ObjectFunction_Think;
-       e.nextthink = time;
-       //e.effects |= EF_SELECTABLE; // don't do this all the time, maybe just when editing objects?
-
-       if(!database)
-       {
-               // set the object's owner via player UID
-               // if the player does not have an UID, the owner cannot be stored and his objects may be edited by anyone
-               if(self.crypto_idfp != "")
-                       e.crypto_idfp = strzone(self.crypto_idfp);
-               else
-                       print_to(self, "^1SANDBOX - WARNING: ^7You spawned an object, but lack a player UID. ^1Your objects are not secured and can be edited by any player!");
-
-               // set public object information
-               e.netname = strzone(self.netname); // name of the owner
-               e.message = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // creation time
-               e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S")); // last editing time
-
-               // set origin and direction based on player position and view angle
-               makevectors(self.v_angle);
-               WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * autocvar_g_sandbox_editor_distance_spawn, MOVE_NORMAL, self);
-               setorigin(e, trace_endpos);
-               e.angles_y = self.v_angle.y;
-       }
-
-       WITH(entity, self, e, CSQCMODEL_AUTOINIT(e));
-
-       object_count += 1;
-       return e;
-}
-
-void sandbox_ObjectRemove(entity e)
-{
-       sandbox_ObjectAttach_Remove(e); // detach child objects
-
-       // if the object being removed has been selected for attachment by a player, unset it
-       entity head;
-       FOR_EACH_REALPLAYER(head) // bots can't have objects
-       {
-               if(head.object_attach == e)
-                       head.object_attach = world;
-       }
-
-       if(e.material)  {       strunzone(e.material);  e.material = string_null;       }
-       if(e.crypto_idfp)       {       strunzone(e.crypto_idfp);       e.crypto_idfp = string_null;    }
-       if(e.netname)   {       strunzone(e.netname);   e.netname = string_null;        }
-       if(e.message)   {       strunzone(e.message);   e.message = string_null;        }
-       if(e.message2)  {       strunzone(e.message2);  e.message2 = string_null;       }
-       remove(e);
-       e = world;
-
-       object_count -= 1;
-}
-
-string port_string[MAX_STORAGE_ATTACHMENTS]; // fteqcc crashes if this isn't defined as a global
-
-string sandbox_ObjectPort_Save(entity e, float database)
-{
-       // save object properties, and return them as a string
-       float i = 0;
-       string s;
-       entity head;
-
-       for(head = world; (head = find(head, classname, "object")); )
-       {
-               // the main object needs to be first in the array [0] with attached objects following
-               float slot, physics, solidity;
-               if(head == e) // this is the main object, place it first
-               {
-                       slot = 0;
-                       solidity = head.solid; // applied solidity is normal solidity for children
-                       physics = head.movetype; // applied physics are normal physics for parents
-               }
-               else if(head.owner == e) // child object, list them in order
-               {
-                       i += 1; // children start from 1
-                       slot = i;
-                       solidity = head.old_solid; // persisted solidity is normal solidity for children
-                       physics = head.old_movetype; // persisted physics are normal physics for children
-                       gettaginfo(head.owner, head.tag_index); // get the name of the tag our object is attached to, used further below
-               }
-               else
-                       continue;
-
-               // ---------------- OBJECT PROPERTY STORAGE: SAVE ----------------
-               if(slot)
-               {
-                       // properties stored only for child objects
-                       if(gettaginfo_name)     port_string[slot] = strcat(port_string[slot], "\"", gettaginfo_name, "\" ");    else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
-               }
-               else
-               {
-                       // properties stored only for parent objects
-                       if(database)
-                       {
-                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.origin), " ");
-                               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.angles), " ");
-                       }
-               }
-               // properties stored for all objects
-               port_string[slot] = strcat(port_string[slot], "\"", head.model, "\" ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.skin), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.alpha), " ");
-               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.colormod), " ");
-               port_string[slot] = strcat(port_string[slot], sprintf("\"%.9v\"", head.glowmod), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.frame), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.scale), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(solidity), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(physics), " ");
-               port_string[slot] = strcat(port_string[slot], ftos(head.damageforcescale), " ");
-               if(head.material)       port_string[slot] = strcat(port_string[slot], "\"", head.material, "\" ");      else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
-               if(database)
-               {
-                       // properties stored only for the database
-                       if(head.crypto_idfp)    port_string[slot] = strcat(port_string[slot], "\"", head.crypto_idfp, "\" ");   else    port_string[slot] = strcat(port_string[slot], "\"\" "); // none
-                       port_string[slot] = strcat(port_string[slot], "\"", e.netname, "\" ");
-                       port_string[slot] = strcat(port_string[slot], "\"", e.message, "\" ");
-                       port_string[slot] = strcat(port_string[slot], "\"", e.message2, "\" ");
-               }
-       }
-
-       // now apply the array to a simple string, with the ; symbol separating objects
-       s = "";
-       for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
-       {
-               if(port_string[i])
-                       s = strcat(s, port_string[i], "; ");
-               port_string[i] = string_null; // fully clear the string
-       }
-
-       return s;
-}
-
-entity sandbox_ObjectPort_Load(string s, float database)
-{
-       // load object properties, and spawn a new object with them
-       float n, i;
-       entity e = world, parent = world;
-
-       // separate objects between the ; symbols
-       n = tokenizebyseparator(s, "; ");
-       for(i = 0; i < n; ++i)
-               port_string[i] = argv(i);
-
-       // now separate and apply the properties of each object
-       for(i = 0; i < n; ++i)
-       {
-               float argv_num;
-               string tagname = string_null;
-               argv_num = 0;
-               tokenize_console(port_string[i]);
-               e = sandbox_ObjectSpawn(database);
-
-               // ---------------- OBJECT PROPERTY STORAGE: LOAD ----------------
-               if(i)
-               {
-                       // properties stored only for child objects
-                       if(argv(argv_num) != "")        tagname = argv(argv_num);       else tagname = string_null;     ++argv_num;
-               }
-               else
-               {
-                       // properties stored only for parent objects
-                       if(database)
-                       {
-                               setorigin(e, stov(argv(argv_num)));     ++argv_num;
-                               e.angles = stov(argv(argv_num));        ++argv_num;
-                       }
-                       parent = e; // mark parent objects as such
-               }
-               // properties stored for all objects
-               _setmodel(e, argv(argv_num));   ++argv_num;
-               e.skin = stof(argv(argv_num));  ++argv_num;
-               e.alpha = stof(argv(argv_num)); ++argv_num;
-               e.colormod = stov(argv(argv_num));      ++argv_num;
-               e.glowmod = stov(argv(argv_num));       ++argv_num;
-               e.frame = stof(argv(argv_num)); ++argv_num;
-               sandbox_ObjectEdit_Scale(e, stof(argv(argv_num)));      ++argv_num;
-               e.solid = e.old_solid = stof(argv(argv_num));   ++argv_num;
-               e.movetype = e.old_movetype = stof(argv(argv_num));     ++argv_num;
-               e.damageforcescale = stof(argv(argv_num));      ++argv_num;
-               if(e.material)  strunzone(e.material);  if(argv(argv_num) != "")        e.material = strzone(argv(argv_num));   else    e.material = string_null;       ++argv_num;
-               if(database)
-               {
-                       // properties stored only for the database
-                       if(e.crypto_idfp)       strunzone(e.crypto_idfp);       if(argv(argv_num) != "")        e.crypto_idfp = strzone(argv(argv_num));        else    e.crypto_idfp = string_null;    ++argv_num;
-                       if(e.netname)   strunzone(e.netname);   e.netname = strzone(argv(argv_num));    ++argv_num;
-                       if(e.message)   strunzone(e.message);   e.message = strzone(argv(argv_num));    ++argv_num;
-                       if(e.message2)  strunzone(e.message2);  e.message2 = strzone(argv(argv_num));   ++argv_num;
-               }
-
-               // attach last
-               if(i)
-                       sandbox_ObjectAttach_Set(e, parent, tagname);
-       }
-
-       for(i = 0; i <= MAX_STORAGE_ATTACHMENTS; ++i)
-               port_string[i] = string_null; // fully clear the string
-
-       return e;
-}
-
-void sandbox_Database_Save()
-{
-       // saves all objects to the database file
-       entity head;
-       string file_name;
-       float file_get;
-
-       file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
-       file_get = fopen(file_name, FILE_WRITE);
-       fputs(file_get, strcat("// sandbox storage \"", autocvar_g_sandbox_storage_name, "\" for map \"", GetMapname(), "\" last updated ", strftime(true, "%d-%m-%Y %H:%M:%S")));
-       fputs(file_get, strcat(" containing ", ftos(object_count), " objects\n"));
-
-       for(head = world; (head = find(head, classname, "object")); )
-       {
-               // attached objects are persisted separately, ignore them here
-               if(head.owner != world)
-                       continue;
-
-               // use a line of text for each object, listing all properties
-               fputs(file_get, strcat(sandbox_ObjectPort_Save(head, true), "\n"));
-       }
-       fclose(file_get);
-}
-
-void sandbox_Database_Load()
-{
-       // loads all objects from the database file
-       string file_read, file_name;
-       float file_get, i;
-
-       file_name = strcat("sandbox/storage_", autocvar_g_sandbox_storage_name, "_", GetMapname(), ".txt");
-       file_get = fopen(file_name, FILE_READ);
-       if(file_get < 0)
-       {
-               if(autocvar_g_sandbox_info > 0)
-                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7could not find storage file ^3", file_name, "^7, no objects were loaded\n"));
-       }
-       else
-       {
-               for (;;)
-               {
-                       file_read = fgets(file_get);
-                       if(file_read == "")
-                               break;
-                       if(substring(file_read, 0, 2) == "//")
-                               continue;
-                       if(substring(file_read, 0, 1) == "#")
-                               continue;
-
-                       entity e;
-                       e = sandbox_ObjectPort_Load(file_read, true);
-
-                       if(e.material)
-                       {
-                               // since objects are being loaded for the first time, precache material sounds for each
-                               for (i = 1; i <= 5; i++) // 5 sounds in total
-                                       precache_sound(strcat("object/impact_", e.material, "_", ftos(i), ".wav"));
-                       }
-               }
-               if(autocvar_g_sandbox_info > 0)
-                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7successfully loaded storage file ^3", file_name, "\n"));
-       }
-       fclose(file_get);
-}
-
-MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
-{SELFPARAM();
-       if(MUTATOR_RETURNVALUE) // command was already handled?
-               return false;
-       if(cmd_name == "g_sandbox")
-       {
-               if(autocvar_g_sandbox_readonly)
-               {
-                       print_to(self, "^2SANDBOX - INFO: ^7Sandbox mode is active, but in read-only mode. Sandbox commands cannot be used");
-                       return true;
-               }
-               if(cmd_argc < 2)
-               {
-                       print_to(self, "^2SANDBOX - INFO: ^7Sandbox mode is active. For usage information, type 'sandbox help'");
-                       return true;
-               }
-
-               switch(argv(1))
-               {
-                       entity e;
-                       float i;
-                       string s;
-
-                       // ---------------- COMMAND: HELP ----------------
-                       case "help":
-                               print_to(self, "You can use the following sandbox commands:");
-                               print_to(self, "^7\"^2object_spawn ^3models/foo/bar.md3^7\" spawns a new object in front of the player, and gives it the specified model");
-                               print_to(self, "^7\"^2object_remove^7\" removes the object the player is looking at. Players can only remove their own objects");
-                               print_to(self, "^7\"^2object_duplicate ^3value^7\" duplicates the object, if the player has copying rights over the original");
-                               print_to(self, "^3copy value ^7- copies the properties of the object to the specified client cvar");
-                               print_to(self, "^3paste value ^7- spawns an object with the given properties. Properties or cvars must be specified as follows; eg1: \"0 1 2 ...\", eg2: \"$cl_cvar\"");
-                               print_to(self, "^7\"^2object_attach ^3property value^7\" attaches one object to another. Players can only attach their own objects");
-                               print_to(self, "^3get ^7- selects the object you are facing as the object to be attached");
-                               print_to(self, "^3set value ^7- attaches the previously selected object to the object you are facing, on the specified bone");
-                               print_to(self, "^3remove ^7- detaches all objects from the object you are facing");
-                               print_to(self, "^7\"^2object_edit ^3property value^7\" edits the given property of the object. Players can only edit their own objects");
-                               print_to(self, "^3skin value ^7- changes the skin of the object");
-                               print_to(self, "^3alpha value ^7- sets object transparency");
-                               print_to(self, "^3colormod \"value_x value_y value_z\" ^7- main object color");
-                               print_to(self, "^3glowmod \"value_x value_y value_z\" ^7- glow object color");
-                               print_to(self, "^3frame value ^7- object animation frame, for self-animated models");
-                               print_to(self, "^3scale value ^7- changes object scale. 0.5 is half size and 2 is double size");
-                               print_to(self, "^3solidity value ^7- object collisions, 0 = non-solid, 1 = solid");
-                               print_to(self, "^3physics value ^7- object physics, 0 = static, 1 = movable, 2 = physical");
-                               print_to(self, "^3force value ^7- amount of force applied to objects that are shot");
-                               print_to(self, "^3material value ^7- sets the material of the object. Default materials are: metal, stone, wood, flesh");
-                               print_to(self, "^7\"^2object_claim^7\" sets the player as the owner of the object, if he has the right to edit it");
-                               print_to(self, "^7\"^2object_info ^3value^7\" shows public information about the object");
-                               print_to(self, "^3object ^7- prints general information about the object, such as owner and creation / editing date");
-                               print_to(self, "^3mesh ^7- prints information about the object's mesh, including skeletal bones");
-                               print_to(self, "^3attachments ^7- prints information about the object's attachments");
-                               print_to(self, "^7The ^1drag object ^7key can be used to grab and carry objects. Players can only grab their own objects");
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, SPAWN ----------------
-                       case "object_spawn":
-                               if(time < self.object_flood)
-                               {
-                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(self.object_flood - time), " ^7seconds beofore spawning another object"));
-                                       return true;
-                               }
-                               self.object_flood = time + autocvar_g_sandbox_editor_flood;
-                               if(object_count >= autocvar_g_sandbox_editor_maxobjects)
-                               {
-                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
-                                       return true;
-                               }
-                               if(cmd_argc < 3)
-                               {
-                                       print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object without specifying a model. Please specify the path to your model file after the 'object_spawn' command");
-                                       return true;
-                               }
-                               if (!(fexists(argv(2))))
-                               {
-                                       print_to(self, "^1SANDBOX - WARNING: ^7Attempted to spawn an object with a non-existent model. Make sure the path to your model file is correct");
-                                       return true;
-                               }
-
-                               e = sandbox_ObjectSpawn(false);
-                               _setmodel(e, argv(2));
-
-                               if(autocvar_g_sandbox_info > 0)
-                                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " spawned an object at origin ^3", vtos(e.origin), "\n"));
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, REMOVE ----------------
-                       case "object_remove":
-                               e = sandbox_ObjectEdit_Get(true);
-                               if(e != world)
-                               {
-                                       if(autocvar_g_sandbox_info > 0)
-                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " removed an object at origin ^3", vtos(e.origin), "\n"));
-                                       sandbox_ObjectRemove(e);
-                                       return true;
-                               }
-
-                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be removed. Make sure you are facing an object that you have edit rights over");
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, DUPLICATE ----------------
-                       case "object_duplicate":
-                               switch(argv(2))
-                               {
-                                       case "copy":
-                                               // copies customizable properties of the selected object to the clipboard cvar
-                                               e = sandbox_ObjectEdit_Get(autocvar_g_sandbox_editor_free); // can we copy objects we can't edit?
-                                               if(e != world)
-                                               {
-                                                       s = sandbox_ObjectPort_Save(e, false);
-                                                       s = strreplace("\"", "\\\"", s);
-                                                       stuffcmd(self, strcat("set ", argv(3), " \"", s, "\""));
-
-                                                       print_to(self, "^2SANDBOX - INFO: ^7Object copied to clipboard");
-                                                       return true;
-                                               }
-                                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be copied. Make sure you are facing an object that you have copy rights over");
-                                               return true;
-
-                                       case "paste":
-                                               // spawns a new object using the properties in the player's clipboard cvar
-                                               if(time < self.object_flood)
-                                               {
-                                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Flood protection active. Please wait ^3", ftos(self.object_flood - time), " ^7seconds beofore spawning another object"));
-                                                       return true;
-                                               }
-                                               self.object_flood = time + autocvar_g_sandbox_editor_flood;
-                                               if(argv(3) == "") // no object in clipboard
-                                               {
-                                                       print_to(self, "^1SANDBOX - WARNING: ^7No object in clipboard. You must copy an object before you can paste it");
-                                                       return true;
-                                               }
-                                               if(object_count >= autocvar_g_sandbox_editor_maxobjects)
-                                               {
-                                                       print_to(self, strcat("^1SANDBOX - WARNING: ^7Cannot spawn any more objects. Up to ^3", ftos(autocvar_g_sandbox_editor_maxobjects), " ^7objects may exist at a time"));
-                                                       return true;
-                                               }
-                                               e = sandbox_ObjectPort_Load(argv(3), false);
-
-                                               print_to(self, "^2SANDBOX - INFO: ^7Object pasted successfully");
-                                               if(autocvar_g_sandbox_info > 0)
-                                                       LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " pasted an object at origin ^3", vtos(e.origin), "\n"));
-                                               return true;
-                               }
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, ATTACH ----------------
-                       case "object_attach":
-                               switch(argv(2))
-                               {
-                                       case "get":
-                                               // select e as the object as meant to be attached
-                                               e = sandbox_ObjectEdit_Get(true);
-                                               if(e != world)
-                                               {
-                                                       self.object_attach = e;
-                                                       print_to(self, "^2SANDBOX - INFO: ^7Object selected for attachment");
-                                                       return true;
-                                               }
-                                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be selected for attachment. Make sure you are facing an object that you have edit rights over");
-                                               return true;
-                                       case "set":
-                                               if(self.object_attach == world)
-                                               {
-                                                       print_to(self, "^1SANDBOX - WARNING: ^7No object selected for attachment. Please select an object to be attached first.");
-                                                       return true;
-                                               }
-
-                                               // attaches the previously selected object to e
-                                               e = sandbox_ObjectEdit_Get(true);
-                                               if(e != world)
-                                               {
-                                                       sandbox_ObjectAttach_Set(self.object_attach, e, argv(3));
-                                                       self.object_attach = world; // object was attached, no longer keep it scheduled for attachment
-                                                       print_to(self, "^2SANDBOX - INFO: ^7Object attached successfully");
-                                                       if(autocvar_g_sandbox_info > 1)
-                                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " attached objects at origin ^3", vtos(e.origin), "\n"));
-                                                       return true;
-                                               }
-                                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be attached to the parent. Make sure you are facing an object that you have edit rights over");
-                                               return true;
-                                       case "remove":
-                                               // removes e if it was attached
-                                               e = sandbox_ObjectEdit_Get(true);
-                                               if(e != world)
-                                               {
-                                                       sandbox_ObjectAttach_Remove(e);
-                                                       print_to(self, "^2SANDBOX - INFO: ^7Child objects detached successfully");
-                                                       if(autocvar_g_sandbox_info > 1)
-                                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " detached objects at origin ^3", vtos(e.origin), "\n"));
-                                                       return true;
-                                               }
-                                               print_to(self, "^1SANDBOX - WARNING: ^7Child objects could not be detached. Make sure you are facing an object that you have edit rights over");
-                                               return true;
-                               }
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, EDIT ----------------
-                       case "object_edit":
-                               if(argv(2) == "")
-                               {
-                                       print_to(self, "^1SANDBOX - WARNING: ^7Too few parameters. You must specify a property to edit");
-                                       return true;
-                               }
-
-                               e = sandbox_ObjectEdit_Get(true);
-                               if(e != world)
-                               {
-                                       switch(argv(2))
-                                       {
-                                               case "skin":
-                                                       e.skin = stof(argv(3));
-                                                       break;
-                                               case "alpha":
-                                                       e.alpha = stof(argv(3));
-                                                       break;
-                                               case "color_main":
-                                                       e.colormod = stov(argv(3));
-                                                       break;
-                                               case "color_glow":
-                                                       e.glowmod = stov(argv(3));
-                                                       break;
-                                               case "frame":
-                                                       e.frame = stof(argv(3));
-                                                       break;
-                                               case "scale":
-                                                       sandbox_ObjectEdit_Scale(e, stof(argv(3)));
-                                                       break;
-                                               case "solidity":
-                                                       switch(argv(3))
-                                                       {
-                                                               case "0": // non-solid
-                                                                       e.solid = SOLID_TRIGGER;
-                                                                       break;
-                                                               case "1": // solid
-                                                                       e.solid = SOLID_BBOX;
-                                                                       break;
-                                                               default:
-                                                                       break;
-                                                       }
-                                               case "physics":
-                                                       switch(argv(3))
-                                                       {
-                                                               case "0": // static
-                                                                       e.movetype = MOVETYPE_NONE;
-                                                                       break;
-                                                               case "1": // movable
-                                                                       e.movetype = MOVETYPE_TOSS;
-                                                                       break;
-                                                               case "2": // physical
-                                                                       e.movetype = MOVETYPE_PHYSICS;
-                                                                       break;
-                                                               default:
-                                                                       break;
-                                                       }
-                                                       break;
-                                               case "force":
-                                                       e.damageforcescale = stof(argv(3));
-                                                       break;
-                                               case "material":
-                                                       if(e.material)  strunzone(e.material);
-                                                       if(argv(3))
-                                                       {
-                                                               for (i = 1; i <= 5; i++) // precache material sounds, 5 in total
-                                                                       precache_sound(strcat("object/impact_", argv(3), "_", ftos(i), ".wav"));
-                                                               e.material = strzone(argv(3));
-                                                       }
-                                                       else
-                                                               e.material = string_null; // no material
-                                                       break;
-                                               default:
-                                                       print_to(self, "^1SANDBOX - WARNING: ^7Invalid object property. For usage information, type 'sandbox help'");
-                                                       return true;
-                                       }
-
-                                       // update last editing time
-                                       if(e.message2)  strunzone(e.message2);
-                                       e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S"));
-
-                                       if(autocvar_g_sandbox_info > 1)
-                                               LOG_INFO(strcat("^3SANDBOX - SERVER: ^7", self.netname, " edited property ^3", argv(2), " ^7of an object at origin ^3", vtos(e.origin), "\n"));
-                                       return true;
-                               }
-
-                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be edited. Make sure you are facing an object that you have edit rights over");
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, CLAIM ----------------
-                       case "object_claim":
-                               // if the player can edit an object but is not its owner, this can be used to claim that object
-                               if(self.crypto_idfp == "")
-                               {
-                                       print_to(self, "^1SANDBOX - WARNING: ^7You do not have a player UID, and cannot claim objects");
-                                       return true;
-                               }
-                               e = sandbox_ObjectEdit_Get(true);
-                               if(e != world)
-                               {
-                                       // update the owner's name
-                                       // Do this before checking if you're already the owner and skipping if such, so we
-                                       // also update the player's nickname if he changed it (but has the same player UID)
-                                       if(e.netname != self.netname)
-                                       {
-                                               if(e.netname)   strunzone(e.netname);
-                                               e.netname = strzone(self.netname);
-                                               print_to(self, "^2SANDBOX - INFO: ^7Object owner name updated");
-                                       }
-
-                                       if(e.crypto_idfp == self.crypto_idfp)
-                                       {
-                                               print_to(self, "^2SANDBOX - INFO: ^7Object is already yours, nothing to claim");
-                                               return true;
-                                       }
-
-                                       if(e.crypto_idfp)       strunzone(e.crypto_idfp);
-                                       e.crypto_idfp = strzone(self.crypto_idfp);
-
-                                       print_to(self, "^2SANDBOX - INFO: ^7Object claimed successfully");
-                               }
-                               print_to(self, "^1SANDBOX - WARNING: ^7Object could not be claimed. Make sure you are facing an object that you have edit rights over");
-                               return true;
-
-                       // ---------------- COMMAND: OBJECT, INFO ----------------
-                       case "object_info":
-                               // prints public information about the object to the player
-                               e = sandbox_ObjectEdit_Get(false);
-                               if(e != world)
-                               {
-                                       switch(argv(2))
-                                       {
-                                               case "object":
-                                                       print_to(self, strcat("^2SANDBOX - INFO: ^7Object is owned by \"^7", e.netname, "^7\", created \"^3", e.message, "^7\", last edited \"^3", e.message2, "^7\""));
-                                                       return true;
-                                               case "mesh":
-                                                       s = "";
-                                                       FOR_EACH_TAG(e)
-                                                               s = strcat(s, "^7\"^5", gettaginfo_name, "^7\", ");
-                                                       print_to(self, strcat("^2SANDBOX - INFO: ^7Object mesh is \"^3", e.model, "^7\" at animation frame ^3", ftos(e.frame), " ^7containing the following tags: ", s));
-                                                       return true;
-                                               case "attachments":
-                                                       // this should show the same info as 'mesh' but for attachments
-                                                       s = "";
-                                                       entity head;
-                                                       i = 0;
-                                                       for(head = world; (head = find(head, classname, "object")); )
-                                                       {
-                                                               if(head.owner == e)
-                                                               {
-                                                                       ++i; // start from 1
-                                                                       gettaginfo(e, head.tag_index);
-                                                                       s = strcat(s, "^1attachment ", ftos(i), "^7 has mesh \"^3", head.model, "^7\" at animation frame ^3", ftos(head.frame));
-                                                                       s = strcat(s, "^7 and is attached to bone \"^5", gettaginfo_name, "^7\", ");
-                                                               }
-                                                       }
-                                                       if(i) // object contains attachments
-                                                               print_to(self, strcat("^2SANDBOX - INFO: ^7Object contains the following ^1", ftos(i), "^7 attachment(s): ", s));
-                                                       else
-                                                               print_to(self, "^2SANDBOX - INFO: ^7Object contains no attachments");
-                                                       return true;
-                                       }
-                               }
-                               print_to(self, "^1SANDBOX - WARNING: ^7No information could be found. Make sure you are facing an object");
-                               return true;
-
-                       // ---------------- COMMAND: DEFAULT ----------------
-                       default:
-                               print_to(self, "Invalid command. For usage information, type 'sandbox help'");
-                               return true;
-               }
-       }
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(sandbox, SV_StartFrame)
-{
-       if(!autocvar_g_sandbox_storage_autosave)
-               return false;
-       if(time < autosave_time)
-               return false;
-       autosave_time = time + autocvar_g_sandbox_storage_autosave;
-
-       sandbox_Database_Save();
-
-       return true;
-}
-#endif
index 800f0335ef85ea3305b6ec1f60ccfb824ac67540..9a199bd62697031f402a995912663823d375956a 100644 (file)
@@ -471,9 +471,8 @@ entity pathlib_astar(vector from,vector to)
     {
         LOG_TRACE("AStar: Goal found on first node!\n");
 
-        open           = spawn();
+        open           = new(path_end);
         open.owner     = open;
-        open.classname = "path_end";
         setorigin(open,path.origin);
 
         pathlib_cleanup();
index 9b1d7194f9555587bb42fcda6e0d01d589c168fc..18600463741fc20bb88e1fd5baf07b7a9ddb47bc 100644 (file)
@@ -624,8 +624,7 @@ entity Portal_Spawn(entity own, vector org, vector ang)
        if(!CheckWireframeBox(own, org - 48 * v_right - 48 * v_up + 16 * v_forward, 96 * v_right, 96 * v_up, 96 * v_forward))
                return world;
 
-       portal = spawn();
-       portal.classname = "portal";
+       portal = new(portal);
        portal.aiment = own;
        setorigin(portal, org);
        portal.mangle = ang;
index ab94c42bdd4d6215daef510455181d1ac5a8116f..08a9d4d22b14f1ff50540d4f2e64ee7862f03f40 100644 (file)
@@ -1,6 +1,8 @@
 #include "../lib/_all.inc"
 #include "_all.qh"
 
+#include "../common/effects/qc/all.qc"
+
 #include "anticheat.qc"
 #include "antilag.qc"
 #include "campaign.qc"
 #include "cl_client.qc"
 #include "cl_impulse.qc"
 #include "cl_player.qc"
-#include "controlpoint.qc"
-#include "csqceffects.qc"
 #include "ent_cs.qc"
 #include "g_damage.qc"
 #include "g_hook.qc"
 // #include "g_lights.qc" // TODO: was never used
 #include "g_models.qc"
 #include "g_subs.qc"
-#include "g_violence.qc"
 #include "g_world.qc"
-#include "generator.qc"
 #include "ipban.qc"
 #include "item_key.qc"
 #include "mapvoting.qc"
@@ -43,8 +41,6 @@
 
 #include "command/all.qc"
 
-#include "mutators/all.qc"
-
 #include "pathlib/_all.inc"
 
 #include "weapons/accuracy.qc"
 #include "../common/campaign_setup.qc"
 #include "../common/effects/effectinfo.qc"
 #include "../common/mapinfo.qc"
-#include "../common/monsters/spawn.qc"
-#include "../common/monsters/sv_monsters.qc"
 #include "../common/minigames/minigames.qc"
 #include "../common/minigames/sv_minigames.qc"
+#include "../common/monsters/spawn.qc"
+#include "../common/monsters/sv_monsters.qc"
 #include "../common/movetypes/include.qc"
 #include "../common/net_notice.qc"
 #include "../common/notifications.qc"
 #include "../common/physics.qc"
 #include "../common/playerstats.qc"
-#include "../common/viewloc.qc"
 #include "../common/triggers/include.qc"
 #include "../common/util.qc"
+#include "../common/viewloc.qc"
 
 #include "../common/deathtypes/all.qc"
-#include "../common/buffs/all.qc"
 #include "../common/effects/all.qc"
 #include "../common/gamemodes/all.qc"
 #include "../common/items/all.qc"
 #include "../common/monsters/all.qc"
-#include "../common/mutators/all.qc"
-#include "../common/nades/all.qc"
 #include "../common/turrets/all.qc"
 #include "../common/vehicles/all.qc"
 #include "../common/weapons/all.qc"
+#include "../common/mutators/all.qc"
+#include "mutators/all.qc"
 
 #include "../common/turrets/sv_turrets.qc"
 #include "../common/turrets/config.qc"
index fe7606a39ba1ebba3dbe87b009a8ded4669289b5..3d6e9e85e80eacdfd3bf2371af6dcdcbf46a5afb 100644 (file)
@@ -165,8 +165,7 @@ void race_SendNextCheckpoint(entity e, float spec) // qualifying only
        if(!spec)
                msg_entity = e;
        WRITESPECTATABLE_MSG_ONE({
-               WriteByte(MSG_ONE, SVC_TEMPENTITY);
-               WriteByte(MSG_ONE, TE_CSQC_RACE);
+               WriteHeader(MSG_ONE, TE_CSQC_RACE);
                if(spec)
                {
                        WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_NEXT_SPEC_QUALIFYING);
@@ -184,8 +183,7 @@ void race_SendNextCheckpoint(entity e, float spec) // qualifying only
 void race_send_recordtime(float msg)
 {
        // send the server best time
-       WriteByte(msg, SVC_TEMPENTITY);
-       WriteByte(msg, TE_CSQC_RACE);
+       WriteHeader(msg, TE_CSQC_RACE);
        WriteByte(msg, RACE_NET_SERVER_RECORD);
        WriteInt24_t(msg, race_readTime(GetMapname(), 1));
 }
@@ -194,8 +192,7 @@ void race_send_recordtime(float msg)
 void race_send_speedaward(float msg)
 {
        // send the best speed of the round
-       WriteByte(msg, SVC_TEMPENTITY);
-       WriteByte(msg, TE_CSQC_RACE);
+       WriteHeader(msg, TE_CSQC_RACE);
        WriteByte(msg, RACE_NET_SPEED_AWARD);
        WriteInt24_t(msg, floor(speedaward_speed+0.5));
        WriteString(msg, speedaward_holder);
@@ -204,8 +201,7 @@ void race_send_speedaward(float msg)
 void race_send_speedaward_alltimebest(float msg)
 {
        // send the best speed
-       WriteByte(msg, SVC_TEMPENTITY);
-       WriteByte(msg, TE_CSQC_RACE);
+       WriteHeader(msg, TE_CSQC_RACE);
        WriteByte(msg, RACE_NET_SPEED_AWARD_BEST);
        WriteInt24_t(msg, floor(speedaward_alltimebest+0.5));
        WriteString(msg, speedaward_alltimebest_holder);
@@ -213,8 +209,7 @@ void race_send_speedaward_alltimebest(float msg)
 
 void race_SendRankings(float pos, float prevpos, float del, float msg)
 {
-       WriteByte(msg, SVC_TEMPENTITY);
-       WriteByte(msg, TE_CSQC_RACE);
+       WriteHeader(msg, TE_CSQC_RACE);
        WriteByte(msg, RACE_NET_SERVER_RANKINGS);
        WriteShort(msg, pos);
        WriteShort(msg, prevpos);
@@ -235,8 +230,7 @@ void race_SendStatus(float id, entity e)
                msg = MSG_ALL;
        msg_entity = e;
        WRITESPECTATABLE_MSG_ONE_VARNAME(dummy3, {
-               WriteByte(msg, SVC_TEMPENTITY);
-               WriteByte(msg, TE_CSQC_RACE);
+               WriteHeader(msg, TE_CSQC_RACE);
                WriteByte(msg, RACE_NET_SERVER_STATUS);
                WriteShort(msg, id);
                WriteString(msg, e.netname);
@@ -447,8 +441,7 @@ void race_SendTime(entity e, float cp, float t, float tvalid)
                        if(g_race_qualifying)
                        {
                                WRITESPECTATABLE_MSG_ONE_VARNAME(dummy1, {
-                                       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                                       WriteByte(MSG_ONE, TE_CSQC_RACE);
+                                       WriteHeader(MSG_ONE, TE_CSQC_RACE);
                                        WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_QUALIFYING);
                                        WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
                                        WriteInt24_t(MSG_ONE, t); // time to that intermediate
@@ -476,8 +469,7 @@ void race_SendTime(entity e, float cp, float t, float tvalid)
                {
                        msg_entity = e;
                        WRITESPECTATABLE_MSG_ONE_VARNAME(dummy2, {
-                               WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                               WriteByte(MSG_ONE, TE_CSQC_RACE);
+                               WriteHeader(MSG_ONE, TE_CSQC_RACE);
                                WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE);
                                WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
                                if(e == oth)
@@ -503,8 +495,7 @@ void race_SendTime(entity e, float cp, float t, float tvalid)
                {
                        msg_entity = oth;
                        WRITESPECTATABLE_MSG_ONE_VARNAME(dummy3, {
-                               WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                               WriteByte(MSG_ONE, TE_CSQC_RACE);
+                               WriteHeader(MSG_ONE, TE_CSQC_RACE);
                                WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT);
                                WriteByte(MSG_ONE, race_CheckpointNetworkID(cp)); // checkpoint the player now is at
                                if(e == oth)
@@ -537,8 +528,7 @@ void race_ClearTime(entity e)
 
        msg_entity = e;
        WRITESPECTATABLE_MSG_ONE({
-               WriteByte(MSG_ONE, SVC_TEMPENTITY);
-               WriteByte(MSG_ONE, TE_CSQC_RACE);
+               WriteHeader(MSG_ONE, TE_CSQC_RACE);
                WriteByte(MSG_ONE, RACE_NET_CHECKPOINT_CLEAR); // next
        });
 }
@@ -1100,8 +1090,7 @@ void race_ImposePenaltyTime(entity pl, float penalty, string reason)
                {
                        msg_entity = pl;
                        WRITESPECTATABLE_MSG_ONE({
-                               WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                               WriteByte(MSG_ONE, TE_CSQC_RACE);
+                               WriteHeader(MSG_ONE, TE_CSQC_RACE);
                                WriteByte(MSG_ONE, RACE_NET_PENALTY_QUALIFYING);
                                WriteShort(MSG_ONE, TIME_ENCODE(penalty));
                                WriteString(MSG_ONE, reason);
@@ -1115,8 +1104,7 @@ void race_ImposePenaltyTime(entity pl, float penalty, string reason)
                {
                        msg_entity = pl;
                        WRITESPECTATABLE_MSG_ONE_VARNAME(dummy, {
-                               WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                               WriteByte(MSG_ONE, TE_CSQC_RACE);
+                               WriteHeader(MSG_ONE, TE_CSQC_RACE);
                                WriteByte(MSG_ONE, RACE_NET_PENALTY_RACE);
                                WriteShort(MSG_ONE, TIME_ENCODE(penalty));
                                WriteString(MSG_ONE, reason);
index e6a1334f88426fec87ff6b2a95ae312391dcfd24..8fb1a787be1904edee99e5e3bd93831fb7f7194d 100644 (file)
 #include "../common/util.qh"
 
 void round_handler_Think()
-{SELFPARAM();
-       float f;
+{
+       SELFPARAM();
 
-       if(time < game_starttime)
+       if (time < game_starttime)
        {
                round_handler_Reset(game_starttime);
                return;
        }
 
-       if(gameover)
+       if (gameover)
        {
                round_handler_Reset(0);
                round_handler_Remove();
                return;
        }
 
-       if(self.wait)
+       if (this.wait)
        {
-               self.wait = false;
-               self.cnt = self.count + 1; // init countdown
-               round_starttime = time + self.count;
+               this.wait = false;
+               this.cnt = this.count + 1;  // init countdown
+               round_starttime = time + this.count;
                reset_map(true);
        }
 
-       if(self.cnt > 0) // countdown running
+       if (this.cnt > 0)  // countdown running
        {
-               if(self.canRoundStart())
+               if (this.canRoundStart())
                {
-                       if(self.cnt == self.count + 1)
-                               round_starttime = time + self.count;
-                       f = self.cnt - 1;
-                       if(f == 0)
+                       if (this.cnt == this.count + 1) round_starttime = time + this.count;
+                       int f = this.cnt - 1;
+                       if (f == 0)
                        {
-                               self.cnt = 0;
-                               self.round_endtime = (self.round_timelimit) ? time + self.round_timelimit : 0;
-                               self.nextthink = time;
-                               if(self.roundStart)
-                                       self.roundStart();
+                               this.cnt = 0;
+                               this.round_endtime = (this.round_timelimit) ? time + this.round_timelimit : 0;
+                               this.nextthink = time;
+                               if (this.roundStart) this.roundStart();
                                return;
                        }
-                       self.cnt = self.cnt - 1;
+                       this.cnt = this.cnt - 1;
                }
                else
                {
                        round_handler_Reset(0);
                }
-               self.nextthink = time + 1; // canRoundStart every second
+               this.nextthink = time + 1;  // canRoundStart every second
        }
        else
        {
-               if(self.canRoundEnd())
+               if (this.canRoundEnd())
                {
                        // schedule a new round
-                       self.wait = true;
-                       self.nextthink = time + self.delay;
+                       this.wait = true;
+                       this.nextthink = time + this.delay;
                }
                else
                {
-                       self.nextthink = time; // canRoundEnd every frame
+                       this.nextthink = time;  // canRoundEnd every frame
                }
        }
 }
 
 void round_handler_Init(float the_delay, float the_count, float the_round_timelimit)
 {
-       round_handler.delay = (the_delay > 0) ? the_delay : 0;
-       round_handler.count = fabs(floor(the_count));
-       round_handler.cnt = round_handler.count + 1;
-       round_handler.round_timelimit = (the_round_timelimit > 0) ? the_round_timelimit : 0;
+       entity this = round_handler;
+       this.delay = (the_delay > 0) ? the_delay : 0;
+       this.count = fabs(floor(the_count));
+       this.cnt = this.count + 1;
+       this.round_timelimit = (the_round_timelimit > 0) ? the_round_timelimit : 0;
 }
 
 // NOTE: this is only needed because if round_handler spawns at time 1
 // gamestarttime isn't initialized yet
 void round_handler_FirstThink()
 {
-       round_starttime = max(time, game_starttime) + round_handler.count;
-       round_handler.think = round_handler_Think;
-       round_handler.nextthink = max(time, game_starttime);
+       SELFPARAM();
+       round_starttime = max(time, game_starttime) + this.count;
+       this.think = round_handler_Think;
+       this.nextthink = max(time, game_starttime);
 }
 
 void round_handler_Spawn(float() canRoundStart_func, float() canRoundEnd_func, void() roundStart_func)
 {
-       if(round_handler)
+       if (round_handler)
        {
                backtrace("Can't spawn round_handler again!");
                return;
        }
-       round_handler = spawn();
-       round_handler.classname = "round_handler";
+       entity this = round_handler = new(round_handler);
 
-       round_handler.think = round_handler_FirstThink;
-       round_handler.canRoundStart = canRoundStart_func;
-       round_handler.canRoundEnd = canRoundEnd_func;
-       round_handler.roundStart = roundStart_func;
-       round_handler.wait = false;
+       this.think = round_handler_FirstThink;
+       this.canRoundStart = canRoundStart_func;
+       this.canRoundEnd = canRoundEnd_func;
+       this.roundStart = roundStart_func;
+       this.wait = false;
        round_handler_Init(5, 5, 180);
-       round_handler.nextthink = time;
+       this.nextthink = time;
 }
 
 void round_handler_Reset(float next_think)
 {
-       round_handler.wait = false;
-       if(round_handler.count)
-       if(round_handler.cnt < round_handler.count + 1)
-               round_handler.cnt = round_handler.count + 1;
-       round_handler.nextthink = next_think;
-       round_starttime = (next_think) ? (next_think + round_handler.count) : -1;
+       entity this = round_handler;
+       this.wait = false;
+       if (this.count)
+               if (this.cnt < this.count + 1) this.cnt = this.count + 1;
+       this.nextthink = next_think;
+       round_starttime = (next_think) ? (next_think + this.count) : -1;
 }
 
 void round_handler_Remove()
@@ -118,4 +117,3 @@ void round_handler_Remove()
        remove(round_handler);
        round_handler = world;
 }
-
index 678baec958aa26d313a297959947fde5cbd5cac3..2eca07bc94843d8e8a9c75bebe3067e9e2febe62 100644 (file)
@@ -58,7 +58,7 @@ bool TeamScore_SendEntity(entity this, entity to, float sendflags)
 {
        float i, p, longflags;
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_TEAMSCORES);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TEAMSCORES);
        WriteByte(MSG_ENTITY, self.team - 1);
 
        longflags = 0;
@@ -87,9 +87,8 @@ bool TeamScore_SendEntity(entity this, entity to, float sendflags)
 
 void TeamScore_Spawn(float t, string name)
 {
-       entity ts;
-       ts = spawn();
-       ts.classname = "csqc_score_team";
+       entity ts = new(csqc_score_team);
+       make_pure(ts);
        ts.netname = name; // not used yet, FIXME
        ts.team = t;
        Net_LinkEntity(ts, false, 0, TeamScore_SendEntity);
@@ -188,7 +187,7 @@ void ScoreInfo_SetLabel_TeamScore(float i, string label, float scoreflags)
 bool ScoreInfo_SendEntity(entity this, entity to, int sf)
 {
        float i;
-       WriteByte(MSG_ENTITY, ENT_CLIENT_SCORES_INFO);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_SCORES_INFO);
        WriteInt24_t(MSG_ENTITY, MapInfo_LoadedGametype);
        for(i = 0; i < MAX_SCORE; ++i)
        {
@@ -211,8 +210,8 @@ void ScoreInfo_Init(float teams)
        }
        else
        {
-               scores_initialized = spawn();
-               scores_initialized.classname = "ent_client_scoreinfo";
+               scores_initialized = new(ent_client_scoreinfo);
+               make_pure(scores_initialized);
                Net_LinkEntity(scores_initialized, false, 0, ScoreInfo_SendEntity);
        }
        if(teams >= 1)
@@ -233,7 +232,7 @@ bool PlayerScore_SendEntity(entity this, entity to, float sendflags)
 {
        float i, p, longflags;
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_SCORES);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_SCORES);
        WriteByte(MSG_ENTITY, num_for_edict(self.owner));
 
        longflags = 0;
@@ -316,10 +315,10 @@ void Score_ClearAll()
 
 void PlayerScore_Attach(entity player)
 {
-       entity sk;
        if(player.scorekeeper)
                error("player already has a scorekeeper");
-       sk = spawn();
+       entity sk = new(scorekeeper);
+       make_pure(sk);
        sk.owner = player;
        Net_LinkEntity(sk, false, 0, PlayerScore_SendEntity);
        player.scorekeeper = sk;
@@ -530,6 +529,7 @@ void WinningConditionHelper()
 
        FOR_EACH_CLIENT(p)
        {
+               string s = "";
                if(fullstatus)
                {
                        s = GetPlayerScoreString(p, 1);
@@ -927,7 +927,7 @@ void PlayerScore_PlayerStats(entity p)
                                PS_GR_P_ADDVAL(s.owner, strcat(PLAYERSTATS_SCOREBOARD, scores_label[i]), s.(scores[i]));
 }
 
-void PlayerScore_TeamStats(void)
+void PlayerScore_TeamStats()
 {
        entity sk;
        float t, i;
index 07d7267910cc7391e3e79deccdd4a1416289b4ec..2071b0c3211e7a6db05a7d59081c0360d7a594b1 100644 (file)
@@ -31,6 +31,9 @@ void ScoreRules_basics(float teams, float sprio, float stprio, float score_enabl
 
        if(score_enabled)
                ScoreInfo_SetLabel_PlayerScore(SP_SCORE,        "score",     sprio);
+               
+       ScoreInfo_SetLabel_PlayerScore(SP_DMG, "damage", 0);
+       ScoreInfo_SetLabel_PlayerScore(SP_DMGTAKEN, "damagetaken", SFL_LOWER_IS_BETTER);
 }
 void ScoreRules_basics_end()
 {
index a1abfa58fc2f02e926d6e0de50c264b8aa4fa08c..36b08008e8b7dedfa643c1b931a60187c18a7e82 100644 (file)
@@ -12,7 +12,7 @@
 
 bool SpawnPoint_Send(entity this, entity to, int sf)
 {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_SPAWNPOINT);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_SPAWNPOINT);
 
        WriteByte(MSG_ENTITY, self.team);
        WriteShort(MSG_ENTITY, self.origin.x);
@@ -26,7 +26,7 @@ bool SpawnEvent_Send(entity this, entity to, int sf)
 {
        float send;
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_SPAWNEVENT);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_SPAWNEVENT);
 
        if(autocvar_g_spawn_alloweffects)
        {
@@ -117,9 +117,7 @@ void relocate_spawnpoint()
     {
         // show where spawnpoints point at too
         makevectors(self.angles);
-        entity e;
-        e = spawn();
-        e.classname = "info_player_foo";
+        entity e = new(info_player_foo);
         setorigin(e, self.origin + v_forward * 24);
         setsize(e, '-8 -8 -8', '8 8 8');
         e.solid = SOLID_TRIGGER;
index 4941b5521b7122b5ef534f7371e011291eb827a4..beaab08a4d5823f7cab36dd313d103f9068fd146 100644 (file)
@@ -547,16 +547,13 @@ MODEL(FLOCKER, "models/turrets/rocket.md3");
 
 void spawn_flocker()
 {SELFPARAM();
-    entity flocker;
-
-    flocker = spawn ();
+    entity flocker = new(flocker);
 
     setorigin(flocker, self.origin + '0 0 32');
     setmodel (flocker, MDL_FLOCKER);
     setsize (flocker, '-3 -3 -3', '3 3 3');
 
     flocker.flock_id   = self.flock_id;
-    flocker.classname  = "flocker";
     flocker.owner      = self;
     flocker.think      = flocker_think;
     flocker.nextthink  = time + random() * 5;
@@ -649,12 +646,11 @@ spawnfunc(flockerspawn)
     self.think     = flockerspawn_think;
     self.nextthink = time + 0.25;
 
-    self.enemy = spawn();
+    self.enemy = new(FLock Hunter);
 
     setmodel(self.enemy, MDL_FLOCKER);
     setorigin(self.enemy,self.origin + '0 0 768' + (randomvec() * 128));
 
-    self.enemy.classname = "FLock Hunter";
     self.enemy.scale     = 3;
     self.enemy.effects   = EF_LOWPRECISION;
     self.enemy.movetype  = MOVETYPE_BOUNCEMISSILE;
index 1ffcb60c58980fe86599dab4000ccb77d745f83e..0d5fa234f974ebe6bbdd10c7fc2cb35e36d2c9c4 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "../common/constants.qh"
 #include "../common/deathtypes/all.qh"
+#include "../common/debug.qh"
 #include "../common/mapinfo.qh"
 #include "../common/util.qh"
 
@@ -27,7 +28,7 @@
 .float lastground;
 .int state;
 
-void CreatureFrame (void)
+void CreatureFrame ()
 {SELFPARAM();
        float dm;
 
@@ -158,9 +159,9 @@ void CreatureFrame (void)
                                        if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS))
                                        {
                                                if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)
-                                                       GlobalSound(globalsound_metalstep, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+                                                       GlobalSound(GS_STEP_METAL, CH_PLAYER, VOICETYPE_PLAYERSOUND);
                                                else
-                                                       GlobalSound(globalsound_step, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+                                                       GlobalSound(GS_STEP, CH_PLAYER, VOICETYPE_PLAYERSOUND);
                                        }
                                }
                        }
@@ -422,7 +423,7 @@ void SV_OnEntityPreSpawnFunction()
        }
 }
 
-void WarpZone_PostInitialize_Callback(void)
+void WarpZone_PostInitialize_Callback()
 {
        // create waypoint links for warpzones
        entity e;
index cb76f97f9a9a730cd9f750a3889a68d388ead5e4..f295777db791f581cc15e5a10ecdd4eb79cdea3b 100644 (file)
@@ -26,6 +26,8 @@
     #include "../lib/warpzone/util_server.qh"
 #endif
 
+REGISTER_NET_LINKED(ENT_CLIENT_ITEM)
+
 #ifdef CSQC
 void ItemDraw(entity self)
 {
@@ -94,8 +96,8 @@ void Item_PreDraw()
                self.drawmask = MASK_NORMAL;
 }
 
-void ItemRead(float _IsNew)
-{SELFPARAM();
+NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
+{
     int sf = ReadByte();
 
     if(sf & ISF_LOCATION)
@@ -240,6 +242,7 @@ void ItemRead(float _IsNew)
         if(self.ItemStatus & ITS_ANIMATE2)
             self.move_avelocity = '0 -90 0';
     }
+    return true;
 }
 
 #endif
@@ -252,7 +255,7 @@ bool ItemSend(entity this, entity to, int sf)
        else
                sf &= ~ISF_DROP;
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_ITEM);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_ITEM);
        WriteByte(MSG_ENTITY, sf);
 
        //WriteByte(MSG_ENTITY, self.cnt);
@@ -272,7 +275,8 @@ bool ItemSend(entity this, entity to, int sf)
 
        if(sf & ISF_SIZE)
        {
-               WriteByte(MSG_ENTITY, ((self.flags & FL_POWERUP) || self.health || self.armorvalue));
+               Pickup p = this.itemdef;
+               WriteByte(MSG_ENTITY, p.instanceOfPowerup || p.instanceOfHealth || p.instanceOfArmor);
        }
 
        if(sf & ISF_STATUS)
@@ -308,9 +312,9 @@ void ItemUpdate(entity item)
        item.SendFlags |= ISF_LOCATION;
 }
 
-float have_pickup_item(void)
-{SELFPARAM();
-       if(self.flags & FL_POWERUP)
+bool have_pickup_item(entity this)
+{
+       if(this.itemdef.instanceOfPowerup)
        {
                if(autocvar_g_powerups > 0)
                        return true;
@@ -324,7 +328,7 @@ float have_pickup_item(void)
                if(autocvar_g_pickup_items == 0)
                        return false;
                if(g_weaponarena)
-                       if(self.weapons || (self.items & IT_AMMO)) // no item or ammo pickups in weaponarena
+                       if(this.weapons || (this.items & IT_AMMO)) // no item or ammo pickups in weaponarena
                                return false;
        }
        return true;
@@ -377,7 +381,12 @@ void Item_Show (entity e, float mode)
                e.spawnshieldtime = 1;
                e.ItemStatus &= ~ITS_AVAILABLE;
        }
-       else if((e.flags & FL_WEAPON) && !(e.flags & FL_NO_WEAPON_STAY) && g_weapon_stay)
+       else {
+       entity def = e.itemdef;
+       bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.weapons & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
+               || e.team // weapon stay isn't supported for teamed weapons
+               ;
+       if(def.instanceOfWeaponPickup && !nostay && g_weapon_stay)
        {
                // make the item translucent and not touchable
                e.model = e.mdl;
@@ -394,7 +403,7 @@ void Item_Show (entity e, float mode)
                e.glowmod = e.colormod;
                e.spawnshieldtime = 1;
                e.ItemStatus &= ~ITS_AVAILABLE;
-       }
+       }}
 
        if (e.items & ITEM_Strength.m_itemid || e.items & ITEM_Shield.m_itemid)
                e.ItemStatus |= ITS_POWERUP;
@@ -430,7 +439,7 @@ float Item_ItemsTime_UpdateTime(entity e, float t);
 void Item_ItemsTime_SetTime(entity e, float t);
 void Item_ItemsTime_SetTimesForAllPlayers();
 
-void Item_Respawn (void)
+void Item_Respawn ()
 {SELFPARAM();
        Item_Show(self, 1);
        // this is ugly...
@@ -456,7 +465,7 @@ void Item_Respawn (void)
        Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
 }
 
-void Item_RespawnCountdown (void)
+void Item_RespawnCountdown ()
 {SELFPARAM();
        if(self.count >= ITEM_RESPAWN_TICKS)
        {
@@ -639,7 +648,7 @@ float Item_GiveTo(entity item, entity player)
        pickedup |= Item_GiveAmmoTo(item, player, health, item.max_health, ITEM_MODE_HEALTH);
        pickedup |= Item_GiveAmmoTo(item, player, armorvalue, item.max_armorvalue, ITEM_MODE_ARMOR);
 
-       if (item.flags & FL_WEAPON)
+       if (item.itemdef.instanceOfWeaponPickup)
        {
                WepSet it;
                it = item.weapons;
@@ -690,7 +699,7 @@ float Item_GiveTo(entity item, entity player)
                return 0;
 
        // crude hack to enforce switching weapons
-       if(g_cts && (item.flags & FL_WEAPON))
+       if(g_cts && item.itemdef.instanceOfWeaponPickup)
        {
                W_SwitchWeapon_Force(player, item.weapon);
                return 1;
@@ -703,16 +712,16 @@ float Item_GiveTo(entity item, entity player)
        return 1;
 }
 
-void Item_Touch (void)
-{SELFPARAM();
-       entity e, head;
+void Item_Touch()
+{
+       SELFPARAM();
 
        // remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
-       if(self.classname == "droppedweapon")
+       if (this.classname == "droppedweapon")
        {
                if (ITEM_TOUCH_NEEDKILL())
                {
-                       remove(self);
+                       remove(this);
                        return;
                }
        }
@@ -720,33 +729,33 @@ void Item_Touch (void)
        if(!(other.flags & FL_PICKUPITEMS)
        || other.frozen
        || other.deadflag
-       || (self.solid != SOLID_TRIGGER)
-       || (self.owner == other)
-       || (time < self.item_spawnshieldtime)
-       ) { return;}
+       || (this.solid != SOLID_TRIGGER)
+       || (this.owner == other)
+       || (time < this.item_spawnshieldtime)
+       ) { return; }
 
-       switch(MUTATOR_CALLHOOK(ItemTouch, self, other))
+       switch (MUTATOR_CALLHOOK(ItemTouch, this, other))
        {
                case MUT_ITEMTOUCH_RETURN: { return; }
                case MUT_ITEMTOUCH_PICKUP: { goto pickup; }
        }
 
-       if (self.classname == "droppedweapon")
+       if (this.classname == "droppedweapon")
        {
-               self.strength_finished = max(0, self.strength_finished - time);
-               self.invincible_finished = max(0, self.invincible_finished - time);
-               self.superweapons_finished = max(0, self.superweapons_finished - time);
+               this.strength_finished = max(0, this.strength_finished - time);
+               this.invincible_finished = max(0, this.invincible_finished - time);
+               this.superweapons_finished = max(0, this.superweapons_finished - time);
        }
-       entity it = self.itemdef;
-       bool gave = (it && it.instanceOfPickup) ? ITEM_HANDLE(Pickup, it, self, other) : Item_GiveTo(self, other);
+       entity it = this.itemdef;
+       bool gave = ITEM_HANDLE(Pickup, it, this, other);
        if (!gave)
        {
-               if (self.classname == "droppedweapon")
+               if (this.classname == "droppedweapon")
                {
                        // undo what we did above
-                       self.strength_finished += time;
-                       self.invincible_finished += time;
-                       self.superweapons_finished += time;
+                       this.strength_finished += time;
+                       this.invincible_finished += time;
+                       this.superweapons_finished += time;
                }
                return;
        }
@@ -755,17 +764,18 @@ void Item_Touch (void)
 
        other.last_pickup = time;
 
-       Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
-       _sound (other, CH_TRIGGER, (self.item_pickupsound ? self.item_pickupsound : self.item_pickupsound_ent.sound_str()), VOL_BASE, ATTEN_NORM);
+       Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
+       _sound (other, CH_TRIGGER, (this.item_pickupsound ? this.item_pickupsound : Sound_fixpath(this.item_pickupsound_ent)), VOL_BASE, ATTEN_NORM);
 
-       if (self.classname == "droppedweapon")
-               remove (self);
-       else if (self.spawnshieldtime)
+       if (this.classname == "droppedweapon")
+               remove (this);
+       else if (this.spawnshieldtime)
        {
-               if(self.team)
+               entity e;
+               if(this.team)
                {
                        RandomSelection_Init();
-                       for(head = world; (head = findfloat(head, team, self.team)); )
+                       for(entity head = world; (head = findfloat(head, team, this.team)); )
                        {
                                if(head.flags & FL_ITEM)
                                if(head.classname != "item_flag_team" && head.classname != "item_key_team")
@@ -778,28 +788,29 @@ void Item_Touch (void)
 
                }
                else
-                       e = self;
+                       e = this;
                Item_ScheduleRespawn(e);
        }
 }
 
-void Item_Reset()
-{SELFPARAM();
-       Item_Show(self, !self.state);
-       setorigin (self, self.origin);
+void Item_Reset(entity this)
+{
+       Item_Show(this, !this.state);
+       setorigin(this, this.origin);
 
-       if(self.classname != "droppedweapon")
+       if (this.classname != "droppedweapon")
        {
-               self.think = Item_Think;
-               self.nextthink = time;
+               this.think = Item_Think;
+               this.nextthink = time;
 
-               if(self.waypointsprite_attached)
-                       WaypointSprite_Kill(self.waypointsprite_attached);
+               if (this.waypointsprite_attached)
+                       WaypointSprite_Kill(this.waypointsprite_attached);
 
-               if((self.flags & FL_POWERUP) || (self.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
-                       Item_ScheduleInitialRespawn(self);
+               if (this.itemdef.instanceOfPowerup || (this.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
+                       Item_ScheduleInitialRespawn(this);
        }
 }
+void Item_Reset_self() { SELFPARAM(); Item_Reset(this); }
 
 void Item_FindTeam()
 {SELFPARAM();
@@ -831,13 +842,13 @@ void Item_FindTeam()
                        head.effects &= ~EF_NODRAW;
                }
 
-               Item_Reset();
+               Item_Reset(self);
        }
 }
 
 // Savage: used for item garbage-collection
 // TODO: perhaps nice special effect?
-void RemoveItem(void)
+void RemoveItem()
 {SELFPARAM();
        if(wasfreed(self) || !self) { return; }
        Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
@@ -971,238 +982,219 @@ void Item_Damage(entity inflictor, entity attacker, float damage, int deathtype,
                RemoveItem();
 }
 
-void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, float defaultrespawntimejitter, string itemname, float itemid, float weaponid, float itemflags, float(entity player, entity item) pickupevalfunc, float pickupbasevalue)
-{SELFPARAM();
-       startitem_failed = false;
-
-       if(self.model == "")
-               self.model = itemmodel;
+void _StartItem(entity this, entity def, float defaultrespawntime, float defaultrespawntimejitter)
+{
+       string itemname = def.m_name;
+       Model itemmodel = def.m_model;
+    Sound pickupsound = def.m_sound;
+       float(entity player, entity item) pickupevalfunc = def.m_pickupevalfunc;
+       float pickupbasevalue = def.m_botvalue;
+       int itemflags = def.m_itemflags;
 
-       if(self.model == "")
-    {
-        error(strcat("^1Tried to spawn ", itemname, " with no model!\n"));
-        return;
-    }
+       startitem_failed = false;
 
-       if(self.item_pickupsound == "")
-               self.item_pickupsound = pickupsound;
+       this.item_model_ent = itemmodel;
+    this.item_pickupsound_ent = pickupsound;
 
-       if(!self.respawntime) // both need to be set
+       if(!this.respawntime) // both need to be set
        {
-               self.respawntime = defaultrespawntime;
-               self.respawntimejitter = defaultrespawntimejitter;
+               this.respawntime = defaultrespawntime;
+               this.respawntimejitter = defaultrespawntimejitter;
        }
 
-       self.items = itemid;
-       self.weapon = weaponid;
+       int itemid = def.m_itemid;
+       this.items = itemid;
+       int weaponid = def.instanceOfWeaponPickup ? def.m_weapon.m_id : 0;
+       this.weapon = weaponid;
 
-       if(!self.fade_end)
+       if(!this.fade_end)
        {
-               self.fade_start = autocvar_g_items_mindist;
-               self.fade_end = autocvar_g_items_maxdist;
+               this.fade_start = autocvar_g_items_mindist;
+               this.fade_end = autocvar_g_items_maxdist;
        }
 
        if(weaponid)
-               self.weapons = WepSet_FromWeapon(weaponid);
+               this.weapons = WepSet_FromWeapon(weaponid);
 
-       self.flags = FL_ITEM | itemflags;
+       this.flags = FL_ITEM | itemflags;
 
-       if(MUTATOR_CALLHOOK(FilterItem)) // error means we do not want the item
+       if(MUTATOR_CALLHOOK(FilterItem, this)) // error means we do not want the item
        {
                startitem_failed = true;
-               remove(self);
+               remove(this);
                return;
        }
 
        // is it a dropped weapon?
-       if (self.classname == "droppedweapon")
+       if (this.classname == "droppedweapon")
        {
-               self.reset = SUB_Remove;
+               this.reset = SUB_Remove;
                // it's a dropped weapon
-               self.movetype = MOVETYPE_TOSS;
+               this.movetype = MOVETYPE_TOSS;
 
                // Savage: remove thrown items after a certain period of time ("garbage collection")
-               self.think = RemoveItem;
-               self.nextthink = time + 20;
+               this.think = RemoveItem;
+               this.nextthink = time + 20;
 
-               self.takedamage = DAMAGE_YES;
-               self.event_damage = Item_Damage;
+               this.takedamage = DAMAGE_YES;
+               this.event_damage = Item_Damage;
 
-               if(self.strength_finished || self.invincible_finished || self.superweapons_finished)
-               /*
-               if(self.items == 0)
-               if(!(self.weapons & ~WEPSET_SUPERWEAPONS)) // only superweapons
-               if(self.ammo_nails == 0)
-               if(self.ammo_cells == 0)
-               if(self.ammo_rockets == 0)
-               if(self.ammo_shells == 0)
-               if(self.ammo_fuel == 0)
-               if(self.health == 0)
-               if(self.armorvalue == 0)
-               */
+               if(this.strength_finished || this.invincible_finished || this.superweapons_finished)
                {
                        // if item is worthless after a timer, have it expire then
-                       self.nextthink = max(self.strength_finished, self.invincible_finished, self.superweapons_finished);
+                       this.nextthink = max(this.strength_finished, this.invincible_finished, this.superweapons_finished);
                }
 
                // don't drop if in a NODROP zone (such as lava)
-               traceline(self.origin, self.origin, MOVE_NORMAL, self);
+               traceline(this.origin, this.origin, MOVE_NORMAL, this);
                if (trace_dpstartcontents & DPCONTENTS_NODROP)
                {
                        startitem_failed = true;
-                       remove(self);
+                       remove(this);
                        return;
                }
        }
        else
        {
-               if(!have_pickup_item())
+               if(!have_pickup_item(this))
                {
                        startitem_failed = true;
-                       remove (self);
+                       remove (this);
                        return;
                }
 
-               if(self.angles != '0 0 0')
-                       self.SendFlags |= ISF_ANGLES;
+               if(this.angles != '0 0 0')
+                       this.SendFlags |= ISF_ANGLES;
 
-               self.reset = Item_Reset;
+               this.reset = Item_Reset_self;
                // it's a level item
-               if(self.spawnflags & 1)
-                       self.noalign = 1;
-               if (self.noalign > 0)
-                       self.movetype = MOVETYPE_NONE;
+               if(this.spawnflags & 1)
+                       this.noalign = 1;
+               if (this.noalign > 0)
+                       this.movetype = MOVETYPE_NONE;
                else
-                       self.movetype = MOVETYPE_TOSS;
+                       this.movetype = MOVETYPE_TOSS;
                // do item filtering according to game mode and other things
-               if (self.noalign <= 0)
+               if (this.noalign <= 0)
                {
                        // first nudge it off the floor a little bit to avoid math errors
-                       setorigin(self, self.origin + '0 0 1');
+                       setorigin(this, this.origin + '0 0 1');
                        // set item size before we spawn a spawnfunc_waypoint
-                       if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
-                               setsize (self, '-16 -16 0', '16 16 48');
-                       else
-                               setsize (self, '-16 -16 0', '16 16 32');
-                       self.SendFlags |= ISF_SIZE;
+                       setsize(this, def.m_mins, def.m_maxs);
+                       this.SendFlags |= ISF_SIZE;
                        // note droptofloor returns false if stuck/or would fall too far
-                       if(!self.noalign)
-                               droptofloor();
-                       waypoint_spawnforitem(self);
+                       if (!this.noalign)
+                               WITH(entity, self, this, droptofloor());
+                       waypoint_spawnforitem(this);
                }
 
                /*
                 * can't do it that way, as it would break maps
                 * TODO make a target_give like entity another way, that perhaps has
                 * the weapon name in a key
-               if(self.targetname)
+               if(this.targetname)
                {
                        // target_give not yet supported; maybe later
-                       print("removed targeted ", self.classname, "\n");
+                       print("removed targeted ", this.classname, "\n");
                        startitem_failed = true;
-                       remove (self);
+                       remove (this);
                        return;
                }
                */
 
                if(autocvar_spawn_debug >= 2)
                {
-                       entity otheritem;
-                       for(otheritem = findradius(self.origin, 3); otheritem; otheritem = otheritem.chain)
+                       for(entity otheritem = findradius(this.origin, 3); otheritem; otheritem = otheritem.chain)
                        {
                            // why not flags & fl_item?
                                if(otheritem.is_item)
                                {
-                                       LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(self.origin));
+                                       LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(this.origin));
                                        LOG_TRACE(" vs ", otheritem.netname, vtos(otheritem.origin), "\n");
                                        error("Mapper sucks.");
                                }
                        }
-                       self.is_item = true;
+                       this.is_item = true;
                }
 
                weaponsInMap |= WepSet_FromWeapon(weaponid);
 
-               precache_model (self.model);
-               precache_sound (self.item_pickupsound);
+               precache_model(this.model);
+               precache_sound(this.item_pickupsound);
 
-               if((itemflags & (FL_POWERUP | FL_WEAPON)) || (itemid & (IT_HEALTH | IT_ARMOR | IT_KEY1 | IT_KEY2)))
-                       self.target = "###item###"; // for finding the nearest item using find()
+               if (   def.instanceOfPowerup
+                       || def.instanceOfWeaponPickup
+                       || (def.instanceOfHealth && def != ITEM_HealthSmall)
+                       || (def.instanceOfArmor && def != ITEM_ArmorSmall)
+                       || (itemid & (IT_KEY1 | IT_KEY2))
+               ) this.target = "###item###"; // for finding the nearest item using find()
 
-               Item_ItemsTime_SetTime(self, 0);
+               Item_ItemsTime_SetTime(this, 0);
        }
 
-       self.bot_pickup = true;
-       self.bot_pickupevalfunc = pickupevalfunc;
-       self.bot_pickupbasevalue = pickupbasevalue;
-       self.mdl = self.model;
-       self.netname = itemname;
-       self.touch = Item_Touch;
-       setmodel(self, MDL_Null); // precision set below
-       //self.effects |= EF_LOWPRECISION;
-
-       if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
-       {
-               self.pos1 = '-16 -16 0';
-               self.pos2 = '16 16 48';
-       }
-       else
-       {
-               self.pos1 = '-16 -16 0';
-               self.pos2 = '16 16 32';
-       }
-       setsize (self, self.pos1, self.pos2);
+       this.bot_pickup = true;
+       this.bot_pickupevalfunc = pickupevalfunc;
+       this.bot_pickupbasevalue = pickupbasevalue;
+       this.mdl = this.model ? this.model : strzone(this.item_model_ent.model_str());
+       this.netname = itemname;
+       this.touch = Item_Touch;
+       setmodel(this, MDL_Null); // precision set below
+       //this.effects |= EF_LOWPRECISION;
 
-       self.SendFlags |= ISF_SIZE;
+       setsize (this, this.pos1 =  def.m_mins, this.pos2 = def.m_maxs);
 
-       if(!(self.spawnflags & 1024))
-       {
-               if(itemflags & FL_POWERUP)
-                       self.ItemStatus |= ITS_ANIMATE1;
+       this.SendFlags |= ISF_SIZE;
 
-               if(self.armorvalue || self.health)
-                       self.ItemStatus |= ITS_ANIMATE2;
+       if (!(this.spawnflags & 1024)) {
+               if(def.instanceOfPowerup)
+                       this.ItemStatus |= ITS_ANIMATE1;
+       
+               if(this.armorvalue || this.health)
+                       this.ItemStatus |= ITS_ANIMATE2;
        }
 
-       if(itemflags & FL_WEAPON)
+       if(def.instanceOfWeaponPickup)
        {
-               if (self.classname != "droppedweapon") // if dropped, colormap is already set up nicely
-                       self.colormap = 1024; // color shirt=0 pants=0 grey
+               if (this.classname != "droppedweapon") // if dropped, colormap is already set up nicely
+                       this.colormap = 1024; // color shirt=0 pants=0 grey
                else
-                       self.gravity = 1;
-
-               if(!(self.spawnflags & 1024))
-                       self.ItemStatus |= ITS_ANIMATE1;
-               self.ItemStatus |= ISF_COLORMAP;
+                       this.gravity = 1;
+               if (!(this.spawnflags & 1024))
+                       this.ItemStatus |= ITS_ANIMATE1;
+               this.ItemStatus |= ISF_COLORMAP;
        }
 
-       self.state = 0;
-       if(self.team) // broken, no idea why.
+       this.state = 0;
+       if(this.team) // broken, no idea why.
        {
-               if(!self.cnt)
-                       self.cnt = 1; // item probability weight
+               if(!this.cnt)
+                       this.cnt = 1; // item probability weight
 
-               self.effects |= EF_NODRAW; // marker for item team search
-               InitializeEntity(self, Item_FindTeam, INITPRIO_FINDTARGET);
+               this.effects |= EF_NODRAW; // marker for item team search
+               InitializeEntity(this, Item_FindTeam, INITPRIO_FINDTARGET);
        }
        else
-               Item_Reset();
+               Item_Reset(this);
 
-       Net_LinkEntity(self, !((itemflags & FL_POWERUP) || self.health || self.armorvalue), 0, ItemSend);
+       Net_LinkEntity(this, !(def.instanceOfPowerup || def.instanceOfHealth || def.instanceOfArmor), 0, ItemSend);
 
        // call this hook after everything else has been done
-       if(MUTATOR_CALLHOOK(Item_Spawn, self))
+       if (MUTATOR_CALLHOOK(Item_Spawn, this))
        {
                startitem_failed = true;
-               remove(self);
+               remove(this);
                return;
        }
 }
 
-void StartItemA (entity a)
-{SELFPARAM();
-    self.itemdef = a;
-    StartItem(strzone(a.m_model.model_str()), a.m_sound, a.m_respawntime(), a.m_respawntimejitter(), a.m_name, a.m_itemid, 0, a.m_itemflags, a.m_pickupevalfunc, a.m_botvalue);
+void StartItem(entity this, GameItem def)
+{
+    _StartItem(
+       this,
+       this.itemdef = def,
+       def.m_respawntime(), // defaultrespawntime
+       def.m_respawntimejitter() // defaultrespawntimejitter
+       );
 }
 
 spawnfunc(item_rockets)
@@ -1211,7 +1203,7 @@ spawnfunc(item_rockets)
                self.ammo_rockets = g_pickup_rockets;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-    StartItemA (ITEM_Rockets);
+    StartItem(this, ITEM_Rockets);
 }
 
 spawnfunc(item_bullets)
@@ -1230,7 +1222,7 @@ spawnfunc(item_bullets)
                self.ammo_nails = g_pickup_nails;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-    StartItemA (ITEM_Bullets);
+    StartItem(this, ITEM_Bullets);
 }
 
 spawnfunc(item_cells)
@@ -1239,7 +1231,7 @@ spawnfunc(item_cells)
                self.ammo_cells = g_pickup_cells;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-       StartItemA (ITEM_Cells);
+       StartItem(this, ITEM_Cells);
 }
 
 spawnfunc(item_plasma)
@@ -1248,7 +1240,7 @@ spawnfunc(item_plasma)
                self.ammo_plasma = g_pickup_plasma;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-       StartItemA (ITEM_Plasma);
+       StartItem(this, ITEM_Plasma);
 }
 
 spawnfunc(item_shells)
@@ -1267,7 +1259,7 @@ spawnfunc(item_shells)
                self.ammo_shells = g_pickup_shells;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-       StartItemA (ITEM_Shells);
+       StartItem(this, ITEM_Shells);
 }
 
 spawnfunc(item_armor_small)
@@ -1278,7 +1270,7 @@ spawnfunc(item_armor_small)
                self.max_armorvalue = g_pickup_armorsmall_max;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_armorsmall_anyway;
-       StartItemA (ITEM_ArmorSmall);
+       StartItem(this, ITEM_ArmorSmall);
 }
 
 spawnfunc(item_armor_medium)
@@ -1289,7 +1281,7 @@ spawnfunc(item_armor_medium)
                self.max_armorvalue = g_pickup_armormedium_max;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_armormedium_anyway;
-       StartItemA (ITEM_ArmorMedium);
+       StartItem(this, ITEM_ArmorMedium);
 }
 
 spawnfunc(item_armor_big)
@@ -1300,7 +1292,7 @@ spawnfunc(item_armor_big)
                self.max_armorvalue = g_pickup_armorbig_max;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_armorbig_anyway;
-       StartItemA (ITEM_ArmorLarge);
+       StartItem(this, ITEM_ArmorLarge);
 }
 
 spawnfunc(item_armor_large)
@@ -1311,7 +1303,7 @@ spawnfunc(item_armor_large)
                self.max_armorvalue = g_pickup_armorlarge_max;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_armorlarge_anyway;
-       StartItemA (ITEM_ArmorMega);
+       StartItem(this, ITEM_ArmorMega);
 }
 
 spawnfunc(item_health_small)
@@ -1322,7 +1314,7 @@ spawnfunc(item_health_small)
                self.health = g_pickup_healthsmall;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_healthsmall_anyway;
-       StartItemA (ITEM_HealthSmall);
+       StartItem(this, ITEM_HealthSmall);
 }
 
 spawnfunc(item_health_medium)
@@ -1333,7 +1325,7 @@ spawnfunc(item_health_medium)
                self.health = g_pickup_healthmedium;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_healthmedium_anyway;
-    StartItemA (ITEM_HealthMedium);
+    StartItem(this, ITEM_HealthMedium);
 }
 
 spawnfunc(item_health_large)
@@ -1344,7 +1336,7 @@ spawnfunc(item_health_large)
                self.health = g_pickup_healthlarge;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_healthlarge_anyway;
-       StartItemA (ITEM_HealthLarge);
+       StartItem(this, ITEM_HealthLarge);
 }
 
 spawnfunc(item_health_mega)
@@ -1355,7 +1347,7 @@ spawnfunc(item_health_mega)
         self.health = g_pickup_healthmega;
     if(!self.pickup_anyway)
         self.pickup_anyway = g_pickup_healthmega_anyway;
-    StartItemA (ITEM_HealthMega);
+    StartItem(this, ITEM_HealthMega);
 }
 
 // support old misnamed entities
@@ -1369,14 +1361,14 @@ spawnfunc(item_strength)
 {
                if(!self.strength_finished)
                        self.strength_finished = autocvar_g_balance_powerup_strength_time;
-               StartItemA (ITEM_Strength);
+               StartItem(this, ITEM_Strength);
 }
 
 spawnfunc(item_invincible)
 {
                if(!self.invincible_finished)
                        self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
-               StartItemA (ITEM_Shield);
+               StartItem(this, ITEM_Shield);
 }
 
 // compatibility:
@@ -1533,7 +1525,7 @@ spawnfunc(item_fuel)
                self.ammo_fuel = g_pickup_fuel;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-       StartItemA (ITEM_JetpackFuel);
+       StartItem(this, ITEM_JetpackFuel);
 }
 
 spawnfunc(item_fuel_regen)
@@ -1543,7 +1535,7 @@ spawnfunc(item_fuel_regen)
                spawnfunc_item_fuel(this);
                return;
        }
-       StartItemA (ITEM_JetpackRegen);
+       StartItem(this, ITEM_JetpackRegen);
 }
 
 spawnfunc(item_jetpack)
@@ -1555,7 +1547,7 @@ spawnfunc(item_jetpack)
                spawnfunc_item_fuel(this);
                return;
        }
-       StartItemA (ITEM_Jetpack);
+       StartItem(this, ITEM_Jetpack);
 }
 
 float GiveWeapon(entity e, float wpn, float op, float val)
@@ -1588,62 +1580,6 @@ float GiveWeapon(entity e, float wpn, float op, float val)
        return (v0 != v1);
 }
 
-float GiveBit(entity e, .float fld, float bit, float op, float val)
-{
-       float v0, v1;
-       v0 = (e.(fld) & bit);
-       switch(op)
-       {
-               case OP_SET:
-                       if(val > 0)
-                               e.(fld) |= bit;
-                       else
-                               e.(fld) &= ~bit;
-                       break;
-               case OP_MIN:
-               case OP_PLUS:
-                       if(val > 0)
-                               e.(fld) |= bit;
-                       break;
-               case OP_MAX:
-                       if(val <= 0)
-                               e.(fld) &= ~bit;
-                       break;
-               case OP_MINUS:
-                       if(val > 0)
-                               e.(fld) &= ~bit;
-                       break;
-       }
-       v1 = (e.(fld) & bit);
-       return (v0 != v1);
-}
-
-float GiveValue(entity e, .float fld, float op, float val)
-{
-       float v0, v1;
-       v0 = e.(fld);
-       switch(op)
-       {
-               case OP_SET:
-                       e.(fld) = val;
-                       break;
-               case OP_MIN:
-                       e.(fld) = max(e.(fld), val); // min 100 cells = at least 100 cells
-                       break;
-               case OP_MAX:
-                       e.(fld) = min(e.(fld), val);
-                       break;
-               case OP_PLUS:
-                       e.(fld) += val;
-                       break;
-               case OP_MINUS:
-                       e.(fld) -= val;
-                       break;
-       }
-       v1 = e.(fld);
-       return (v0 != v1);
-}
-
 void GiveSound(entity e, float v0, float v1, float t, string snd_incr, string snd_decr)
 {
        if(v1 == v0)
index 45b5f9e9c32f9df0352b661a5bf1fea92ee2b03e..718944952c291571dea3257a0114ab84d43463c9 100644 (file)
@@ -25,7 +25,7 @@ const int ISF_SIZE                            = BIT(7);
 .float fade_end;
 
 #ifdef SVQC
-void StartItemA (entity a);
+void StartItem(entity this, entity a);
 #endif
 
 #ifdef CSQC
@@ -45,8 +45,6 @@ string autocvar_cl_simpleitems_postfix = "_simple";
 void ItemDraw(entity this);
 void ItemDrawSimple(entity this);
 
-void ItemRead(float _IsNew);
-
 #endif
 #ifdef SVQC
 spawnfunc(item_strength);
@@ -60,7 +58,7 @@ float autocvar_sv_simple_items;
 bool ItemSend(entity this, entity to, int sf);
 
 
-float have_pickup_item(void);
+bool have_pickup_item(entity this);
 
 const float ITEM_RESPAWN_TICKS = 10;
 
@@ -74,9 +72,9 @@ const float ITEM_RESPAWN_TICKS = 10;
 
 void Item_Show (entity e, float mode);
 
-void Item_Respawn (void);
+void Item_Respawn ();
 
-void Item_RespawnCountdown (void);
+void Item_RespawnCountdown ();
 void Item_ScheduleRespawnIn(entity e, float t);
 
 void Item_ScheduleRespawn(entity e);
@@ -90,9 +88,9 @@ float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax
 
 float Item_GiveTo(entity item, entity player);
 
-void Item_Touch (void);
+void Item_Touch();
 
-void Item_Reset();
+void Item_Reset(entity this);
 
 void Item_FindTeam();
 // Savage: used for item garbage-collection
@@ -112,16 +110,10 @@ float commodity_pickupevalfunc(entity player, entity item);
 
 .float is_item;
 .entity itemdef;
-void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, float defaultrespawntimejitter, string itemname, float itemid, float weaponid, float itemflags, float(entity player, entity item) pickupevalfunc, float pickupbasevalue);
-
+void _StartItem(entity this, entity def, float defaultrespawntime, float defaultrespawntimejitter);
 
-void target_items_use (void);
 
-const float OP_SET = 0;
-const float OP_MIN = 1;
-const float OP_MAX = 2;
-const float OP_PLUS = 3;
-const float OP_MINUS = 4;
+void target_items_use ();
 
 float GiveWeapon(entity e, float wpn, float op, float val);
 
index 94663fc36534a93502fc0f6816a2d13da945417d..82646da26a01dfca79a42192c9adc9d2f77d5f06 100644 (file)
@@ -1,6 +1,5 @@
 
 #include "../common/weapons/all.qh"
-#include "../common/buffs/all.qh"
 
 spawnfunc(weapon_crylink);
 spawnfunc(weapon_electro);
@@ -155,10 +154,7 @@ spawnfunc(target_give)
 
 spawnfunc(item_flight)
 {
-       if(!cvar("g_buffs") || !cvar("g_buffs_flight"))
-               spawnfunc_item_jetpack(this);
-       else
-               buff_Init_Compat(self, BUFF_FLIGHT);
+       spawnfunc_item_jetpack(this);
 }
 
 .float notteam;
index 2f2bf545455a60af2b6a1c4185bd25ce43bda98f..deb6032ce207a32b980a06804608cbd4303ad173 100644 (file)
@@ -114,7 +114,7 @@ string GetClientVersionMessage()
        return versionmsg;
 }
 
-string getwelcomemessage(void)
+string getwelcomemessage()
 {
        string s, modifications, motd;
 
@@ -132,8 +132,6 @@ string getwelcomemessage(void)
                modifications = strcat(modifications, ", No start weapons");
        if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
                modifications = strcat(modifications, ", Low gravity");
-       if(g_cloaked && !g_cts)
-               modifications = strcat(modifications, ", Cloaked");
        if(g_weapon_stay && !g_cts)
                modifications = strcat(modifications, ", Weapons stay");
        if(g_jetpack)
@@ -654,7 +652,7 @@ void SV_ChangeTeam(float _color)
 
        // since this is an engine function, and gamecode doesn't have any calls earlier than this, do the connecting message here
        if(!IS_CLIENT(self))
-               Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_CONNECTING, self.netname);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_CONNECTING, self.netname);
 
        SetPlayerTeam(self, dteam, steam, !IS_CLIENT(self));
 
index b934993235d4c130ad9b24ad55081922acabdd39..6b3bdf0f2a1e517f4e93d03209abd227dae16c18 100644 (file)
@@ -27,7 +27,7 @@ void InitGameplayMode();
 
 string GetClientVersionMessage();
 
-string getwelcomemessage(void);
+string getwelcomemessage();
 
 void SetPlayerColors(entity pl, float _color);
 
index 7d1633f7f34124e6de945eb2fd17657c3b47daec..211ef8cec090682aeaf040286f54018f8ff27376 100644 (file)
@@ -6,43 +6,32 @@
 #include "../../common/util.qh"
 #include "../../common/weapons/all.qh"
 
-float accuracy_byte(float n, float d)
+int accuracy_byte(float n, float d)
 {
-       //printf("accuracy: %d / %d\n", n, d);
-       if(n <= 0)
-               return 0;
-       if(n > d)
-               return 255;
+       if (n <= 0) return 0;
+       if (n > d) return 255;
        return 1 + rint(n * 100.0 / d);
 }
 
 bool accuracy_send(entity this, entity to, int sf)
 {
-       int w, f;
-       entity a;
-       WriteByte(MSG_ENTITY, ENT_CLIENT_ACCURACY);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_ACCURACY);
 
-       a = self.owner;
-       if(IS_SPEC(a))
-               a = a.enemy;
+       entity a = this.owner;
+       if (IS_SPEC(a)) a = a.enemy;
        a = a.accuracy;
 
-       if(to != a.owner)
-               if (!(self.owner.cvar_cl_accuracy_data_share && autocvar_sv_accuracy_data_share))
+       if (to != a.owner)
+               if (!autocvar_sv_accuracy_data_share && !a.owner.cvar_cl_accuracy_data_share)
                        sf = 0;
        // note: zero sendflags can never be sent... so we can use that to say that we send no accuracy!
        WriteInt24_t(MSG_ENTITY, sf);
-       if(sf == 0)
-               return true;
+       if (sf == 0) return true;
        // note: we know that client and server agree about SendFlags...
-       for(w = 0, f = 1; w <= WEP_LAST - WEP_FIRST; ++w)
-       {
-               if(sf & f)
-                       WriteByte(MSG_ENTITY, accuracy_byte(self.(accuracy_hit[w]), self.(accuracy_fired[w])));
-               if(f == 0x800000)
-                       f = 1;
-               else
-                       f *= 2;
+       int f = 1;
+       for (int w = 0; w <= WEP_LAST - WEP_FIRST; ++w) {
+               if (sf & f) WriteByte(MSG_ENTITY, accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w]));
+               f = (f == 0x800000) ? 1 : f * 2;
        }
        return true;
 }
@@ -50,11 +39,11 @@ bool accuracy_send(entity this, entity to, int sf)
 // init/free
 void accuracy_init(entity e)
 {
-       e.accuracy = spawn();
-       e.accuracy.owner = e;
-       e.accuracy.classname = "accuracy";
-       e.accuracy.drawonlytoclient = e;
-       Net_LinkEntity(e.accuracy, false, 0, accuracy_send);
+       entity a = e.accuracy = new(accuracy);
+       make_pure(a);
+       a.owner = e;
+       a.drawonlytoclient = e;
+       Net_LinkEntity(a, false, 0, accuracy_send);
 }
 
 void accuracy_free(entity e)
@@ -72,60 +61,53 @@ void accuracy_resend(entity e)
 .float hit_time;
 .float fired_time;
 
-void accuracy_add(entity e, int w, float fired, float hit)
+void accuracy_add(entity this, int w, int fired, int hit)
 {
-       entity a;
-       float b;
-       if(IS_INDEPENDENT_PLAYER(e))
-               return;
-       a = e.accuracy;
-       if(!a || !(hit || fired))
-               return;
+       if (IS_INDEPENDENT_PLAYER(this)) return;
+       entity a = this.accuracy;
+       if (!a) return;
+       if (!hit && !fired) return;
        w -= WEP_FIRST;
-       b = accuracy_byte(a.(accuracy_hit[w]), a.(accuracy_fired[w]));
-       if(hit)
-               a.(accuracy_hit[w]) += hit;
-       if(fired)
-               a.(accuracy_fired[w]) += fired;
-
-    if(hit && a.hit_time != time) // only run this once per frame
-    {
-        a.(accuracy_cnt_hit[w]) += 1;
+       int b = accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w]);
+       if (hit)    a.accuracy_hit  [w] += hit;
+       if (fired)  a.accuracy_fired[w] += fired;
+
+    if (hit && a.hit_time != time) { // only run this once per frame
+        a.accuracy_cnt_hit[w] += 1;
         a.hit_time = time;
     }
 
-    if(fired && a.fired_time != time) // only run this once per frame
-    {
-        a.(accuracy_cnt_fired[w]) += 1;
+    if (fired && a.fired_time != time) { // only run this once per frame
+        a.accuracy_cnt_fired[w] += 1;
         a.fired_time = time;
     }
 
-       if(b == accuracy_byte(a.(accuracy_hit[w]), a.(accuracy_fired[w])))
-               return;
-       w = pow(2, w % 24);
-       a.SendFlags |= w;
-       FOR_EACH_CLIENT(a)
-               if(IS_SPEC(a))
-                       if(a.enemy == e)
-                               a.SendFlags |= w;
+       if (b == accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w])) return; // no change
+       int sf = 1 << (w % 24);
+       a.SendFlags |= sf;
+       entity e; FOR_EACH_CLIENT(e) if (IS_SPEC(e)) if (e.enemy == this) {
+               e.accuracy.SendFlags |= sf;
+       }
 }
 
-float accuracy_isgooddamage(entity attacker, entity targ)
+bool accuracy_isgooddamage(entity attacker, entity targ)
 {
-       float mutator_check = MUTATOR_CALLHOOK(AccuracyTargetValid, attacker, targ);
-
-       if(!warmup_stage)
-       if(targ.deadflag == DEAD_NO)
-       if(!targ.frozen)
-       if(mutator_check == MUT_ACCADD_INVALID || (mutator_check == MUT_ACCADD_VALID && IS_CLIENT(targ)))
-       if(DIFF_TEAM(attacker, targ))
-               return true;
-       return false;
+       int mutator_check = MUTATOR_CALLHOOK(AccuracyTargetValid, attacker, targ);
+
+       if (warmup_stage) return false;
+       if (targ.deadflag != DEAD_NO) return false;
+       if (targ.frozen) return false;
+       if (SAME_TEAM(attacker, targ)) return false;
+
+       if (mutator_check == MUT_ACCADD_INVALID) return true;
+
+       if (mutator_check != MUT_ACCADD_VALID) return false;
+       if (!IS_CLIENT(targ)) return false;
+
+       return true;
 }
 
-float accuracy_canbegooddamage(entity attacker)
+bool accuracy_canbegooddamage(entity attacker)
 {
-       if(!warmup_stage)
-               return true;
-       return false;
+       return !warmup_stage;
 }
index e8d22d98b19db76ac1f14935aee31b2f3ce2c96d..33c1fbf3924aacf3a71cab0a3cf4acf2de6033b5 100644 (file)
@@ -1,8 +1,10 @@
 #ifndef ACCURACY_H
 #define ACCURACY_H
 
-.float cvar_cl_accuracy_data_share;
-.float cvar_cl_accuracy_data_receive;
+.bool cvar_cl_accuracy_data_share;
+REPLICATE(cvar_cl_accuracy_data_share, bool, "cl_accuracy_data_share");
+.bool cvar_cl_accuracy_data_receive;
+REPLICATE(cvar_cl_accuracy_data_receive, bool, "cl_accuracy_data_receive");
 
 .entity accuracy;
 .float accuracy_frags[Weapons_MAX];
@@ -24,6 +26,6 @@ void accuracy_resend(entity e);
 void accuracy_add(entity e, float w, float fired, float hit);
 
 // helper
-float accuracy_isgooddamage(entity attacker, entity targ);
-float accuracy_canbegooddamage(entity attacker);
+bool accuracy_isgooddamage(entity attacker, entity targ);
+bool accuracy_canbegooddamage(entity attacker);
 #endif
index 5a5e30bf79c11c92cd217c5e006bf0d399a92c73..ef3d185c03e64f63ba6ab6474b66cb054bbc3789 100644 (file)
@@ -89,6 +89,8 @@ void W_PrepareExplosionByDamage(entity attacker, void() explode)
                self.realowner = attacker;
        }
 
+       MUTATOR_CALLHOOK(PrepareExplosionByDamage, self, attacker);
+
        // do not explode NOW but in the NEXT FRAME!
        // because recursive calls to RadiusDamage are not allowed
        self.nextthink = time;
index 1e254b804e13e2b2c28bc73db985d237ba733a79..dfee551368a4863a3718d60d7ca7fa090a0db19c 100644 (file)
@@ -34,7 +34,7 @@ bool CSQCProjectile_SendEntity(entity this, entity to, int sf)
        if(self.gravity != 0)
                sf |= 0x10;
 
-       WriteByte(MSG_ENTITY, ENT_CLIENT_PROJECTILE);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_PROJECTILE);
        WriteByte(MSG_ENTITY, sf);
 
        if(sf & 1)
index b7eb2fe097e0e169d3cf6a1f9177c0292701dc6c..cfa68dc99e38673b99c2a9863565f5d3e47b306c 100644 (file)
@@ -12,8 +12,7 @@
 void Send_WeaponComplain(entity e, float wpn, float type)
 {
        msg_entity = e;
-       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-       WriteByte(MSG_ONE, TE_CSQC_WEAPONCOMPLAIN);
+       WriteHeader(MSG_ONE, TE_CSQC_WEAPONCOMPLAIN);
        WriteByte(MSG_ONE, wpn);
        WriteByte(MSG_ONE, type);
 }
@@ -308,7 +307,7 @@ void W_PreviousWeapon(float list)
 }
 
 // previously used if exists and has ammo, (second) best otherwise
-void W_LastWeapon(void)
+void W_LastWeapon()
 {SELFPARAM();
        if(client_hasweapon(self, self.cnt, true, false))
                W_SwitchWeapon(self.cnt);
index 69f644c70a0f1e65dde06150f69d03996a762be7..d51addd7d9ab729b5d9517982f038bb09bd0dee9 100644 (file)
@@ -29,5 +29,5 @@ void W_NextWeapon(float list);
 void W_PreviousWeapon(float list);
 
 // previously used if exists and has ammo, (second) best otherwise
-void W_LastWeapon(void);
+void W_LastWeapon();
 #endif
index 995154509c11243d148f0f0c90f7aef0287d8892..244f6a5e6d768bfcc8d47ce357836f45cf805bac 100644 (file)
@@ -33,81 +33,75 @@ string W_Apply_Weaponreplace(string in)
        return substring(out, 1, -1);
 }
 
-void weapon_defaultspawnfunc(float wpn)
-{SELFPARAM();
-       entity e;
-       float t;
-       string s;
-       float i, j;
-       int f;
-
-       if(self.classname != "droppedweapon" && self.classname != "replacedweapon")
+void weapon_defaultspawnfunc(entity this, Weapon e)
+{
+       int wpn = e.m_id;
+       if (this.classname != "droppedweapon" && this.classname != "replacedweapon")
        {
-               e = get_weaponinfo(wpn);
-
-               if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
+               if (e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
                {
                        objerror("Attempted to spawn a mutator-blocked weapon rejected");
                        startitem_failed = true;
                        return;
                }
 
-               s = W_Apply_Weaponreplace(e.netname);
-               MUTATOR_CALLHOOK(SetWeaponreplace, self, e, s);
+               string s = W_Apply_Weaponreplace(e.netname);
+               MUTATOR_CALLHOOK(SetWeaponreplace, this, e, s);
                s = ret_string;
-               if(s == "")
+               if (s == "")
                {
-                       remove(self);
+                       remove(this);
                        startitem_failed = true;
                        return;
                }
-               t = tokenize_console(s);
-               if(t >= 2)
+               int t = tokenize_console(s);
+               if (t >= 2)
                {
-                       self.team = --internalteam;
-                       for(i = 1; i < t; ++i)
+                       this.team = --internalteam;
+                       for (int i = 1; i < t; ++i)
                        {
                                s = argv(i);
-                               for(j = WEP_FIRST; j <= WEP_LAST; ++j)
+                               int j;
+                               for (j = WEP_FIRST; j <= WEP_LAST; ++j)
                                {
                                        e = get_weaponinfo(j);
-                                       if(e.netname == s)
+                                       if (e.netname == s)
                                        {
-                                               setself(spawn());
-                                               copyentity(this, self);
-                                               self.classname = "replacedweapon";
-                                               weapon_defaultspawnfunc(j);
+                                               entity replacement = spawn();
+                                               copyentity(this, replacement);
+                                               replacement.classname = "replacedweapon";
+                                               weapon_defaultspawnfunc(replacement, e);
                                                break;
                                        }
                                }
-                               if(j > WEP_LAST)
+                               if (j > WEP_LAST)
                                {
                                        LOG_INFO("The weapon replace list for ", this.classname, " contains an unknown weapon ", s, ". Skipped.\n");
                                }
                        }
-                       setself(this);
                }
-               if(t >= 1) // always the case!
+               if (t >= 1) // always the case!
                {
                        s = argv(0);
                        wpn = 0;
-                       for(j = WEP_FIRST; j <= WEP_LAST; ++j)
+                       int j;
+                       for (j = WEP_FIRST; j <= WEP_LAST; ++j)
                        {
                                e = get_weaponinfo(j);
-                               if(e.netname == s)
+                               if (e.netname == s)
                                {
                                        wpn = j;
                                        break;
                                }
                        }
-                       if(j > WEP_LAST)
+                       if (j > WEP_LAST)
                        {
-                               LOG_INFO("The weapon replace list for ", self.classname, " contains an unknown weapon ", s, ". Skipped.\n");
+                               LOG_INFO("The weapon replace list for ", this.classname, " contains an unknown weapon ", s, ". Skipped.\n");
                        }
                }
-               if(wpn == 0)
+               if (wpn == 0)
                {
-                       remove(self);
+                       remove(this);
                        startitem_failed = true;
                        return;
                }
@@ -115,73 +109,67 @@ void weapon_defaultspawnfunc(float wpn)
 
        e = get_weaponinfo(wpn);
 
-       if(!self.respawntime)
+       if (!this.respawntime)
        {
-               if(e.weapons & WEPSET_SUPERWEAPONS)
+               if (e.weapons & WEPSET_SUPERWEAPONS)
                {
-                       self.respawntime = g_pickup_respawntime_superweapon;
-                       self.respawntimejitter = g_pickup_respawntimejitter_superweapon;
+                       this.respawntime = g_pickup_respawntime_superweapon;
+                       this.respawntimejitter = g_pickup_respawntimejitter_superweapon;
                }
                else
                {
-                       self.respawntime = g_pickup_respawntime_weapon;
-                       self.respawntimejitter = g_pickup_respawntimejitter_weapon;
+                       this.respawntime = g_pickup_respawntime_weapon;
+                       this.respawntimejitter = g_pickup_respawntimejitter_weapon;
                }
        }
 
-       if(e.weapons & WEPSET_SUPERWEAPONS)
-               if(!self.superweapons_finished)
-                       self.superweapons_finished = autocvar_g_balance_superweapons_time;
+       if (e.weapons & WEPSET_SUPERWEAPONS)
+               if (!this.superweapons_finished)
+                       this.superweapons_finished = autocvar_g_balance_superweapons_time;
 
        // if we don't already have ammo, give us some ammo
-       if(!self.(e.ammo_field))
+       if (!this.(e.ammo_field))
        {
-               switch(e.ammo_field)
+               switch (e.ammo_field)
                {
-                       case ammo_shells:  self.ammo_shells  = cvar("g_pickup_shells_weapon");  break;
-                       case ammo_nails:   self.ammo_nails   = cvar("g_pickup_nails_weapon");   break;
-                       case ammo_rockets: self.ammo_rockets = cvar("g_pickup_rockets_weapon"); break;
-                       case ammo_cells:   self.ammo_cells   = cvar("g_pickup_cells_weapon");   break;
-                       case ammo_plasma:  self.ammo_plasma  = cvar("g_pickup_plasma_weapon");  break;
-                       case ammo_fuel:    self.ammo_fuel    = cvar("g_pickup_fuel_weapon");    break;
+                       case ammo_shells:  this.ammo_shells  = cvar("g_pickup_shells_weapon");  break;
+                       case ammo_nails:   this.ammo_nails   = cvar("g_pickup_nails_weapon");   break;
+                       case ammo_rockets: this.ammo_rockets = cvar("g_pickup_rockets_weapon"); break;
+                       case ammo_cells:   this.ammo_cells   = cvar("g_pickup_cells_weapon");   break;
+                       case ammo_plasma:  this.ammo_plasma  = cvar("g_pickup_plasma_weapon");  break;
+                       case ammo_fuel:    this.ammo_fuel    = cvar("g_pickup_fuel_weapon");    break;
                }
        }
 
        #if 0 // WEAPONTODO
-       if(e.items)
+       if (e.items)
        {
-               for(i = 0, j = 1; i < 24; ++i, j *= 2)
+               for (int i = 0, j = 1; i < 24; ++i, j <<= 1)
                {
-                       if(e.items & j)
+                       if (e.items & j)
                        {
                                ammotype = Item_CounterField(j);
-                               if(!self.ammotype)
-                                       self.ammotype = cvar(strcat("g_pickup_", Item_CounterFieldName(j), "_weapon"));
+                               if (!this.ammotype)
+                                       this.ammotype = cvar(strcat("g_pickup_", Item_CounterFieldName(j), "_weapon"));
                        }
                }
        }
        #endif
 
        // pickup anyway
-       if(g_pickup_weapons_anyway)
-               self.pickup_anyway = true;
-
-       f = FL_WEAPON;
-
-       // no weapon-stay on superweapons
-       if(e.weapons & WEPSET_SUPERWEAPONS)
-               f |= FL_NO_WEAPON_STAY;
-
-       // weapon stay isn't supported for teamed weapons
-       if(self.team)
-               f |= FL_NO_WEAPON_STAY;
-
-       StartItem(strzone(e.m_model.model_str()), string_null, self.respawntime, self.respawntimejitter, e.message, 0, e.weapon, f, weapon_pickupevalfunc, e.bot_pickupbasevalue);
-       self.item_pickupsound_ent = SND_WEAPONPICKUP;
+       if (g_pickup_weapons_anyway)
+               this.pickup_anyway = true;
+
+       GameItem def = e.m_pickup;
+       _StartItem(
+               this,
+               this.itemdef = def,
+               this.respawntime, // defaultrespawntime
+               this.respawntimejitter // defaultrespawntimejitter
+       );
        #if 0 // WEAPONTODO
-       if (self.modelindex) { // don't precache if self was removed
-               Weapon w = get_weaponinfo(e.weapon);
-               w.wr_init(w);
+       if (this.modelindex) { // don't precache if this was removed
+               e.wr_init(e);
        }
        #endif
 }
index e9cfad94eb31e83bf5713f624aebfd582d5bbe9e..fd66a8e87b97c94a4a17ba7f33805692eea0054c 100644 (file)
@@ -3,5 +3,5 @@
 
 string W_Apply_Weaponreplace(string in);
 
-void weapon_defaultspawnfunc(float wpn);
+void weapon_defaultspawnfunc(entity this, Weapon e);
 #endif
index 9e1b3e4dc987de6c4de6472a454e9e73006b2c00..ef98f69d382e6068cfb50f141ec3bde958fce5ad 100644 (file)
@@ -34,12 +34,12 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
 {SELFPARAM();
        float thisammo, i;
        string s;
-       var .int ammotype = (get_weaponinfo(wpn)).ammo_field;
+       Weapon info = get_weaponinfo(wpn);
+       var .int ammotype = info.ammo_field;
 
-       entity wep = spawn();
+       entity wep = new(droppedweapon);
 
        setorigin(wep, org);
-       wep.classname = "droppedweapon";
        wep.velocity = velo;
        wep.owner = wep.enemy = own;
        wep.flags |= FL_TOSSED;
@@ -75,7 +75,7 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
                }
        }
 
-       WITH(entity, self, wep, weapon_defaultspawnfunc(wpn));
+       weapon_defaultspawnfunc(wep, info);
        if(startitem_failed)
                return string_null;
        wep.glowmod = own.weaponentity_glowmod;
@@ -171,7 +171,8 @@ void W_ThrowWeapon(vector velo, vector delta, float doreduce)
                return;
        if(!autocvar_g_weapon_throwable)
                return;
-       if(self.weaponentity.state != WS_READY)
+       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+       if(self.(weaponentity).state != WS_READY)
                return;
        if(!W_IsWeaponThrowable(w))
                return;
index 4c9e0e34cf02ce30a1524cdaa7452e72acffaba2..ea0faa845b3ad6974ae040e656286ec3a12a004f 100644 (file)
@@ -55,8 +55,10 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, vector s_forward, vector m
 
        W_HitPlotAnalysis(ent, v_forward, v_right, v_up);
 
-       if(ent.weaponentity.movedir.x > 0)
-               vecs = ent.weaponentity.movedir;
+       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+       vector md = ent.(weaponentity).movedir;
+       if(md.x > 0)
+               vecs = md;
        else
                vecs = '0 0 0';
 
@@ -357,11 +359,11 @@ void fireBullet(vector start, vector dir, float spread, float max_solid_penetrat
        float total_damage = 0;
 
        if(tracereffects & EF_RED)
-               fireBullet_trace_callback_eff = particleeffectnum(EFFECT_RIFLE);
+               fireBullet_trace_callback_eff = EFFECT_RIFLE;
        else if(tracereffects & EF_BLUE)
-               fireBullet_trace_callback_eff = particleeffectnum(EFFECT_RIFLE_WEAK);
+               fireBullet_trace_callback_eff = EFFECT_RIFLE_WEAK;
        else
-               fireBullet_trace_callback_eff = particleeffectnum(EFFECT_BULLET);
+               fireBullet_trace_callback_eff = EFFECT_BULLET;
 
        float lag = ANTILAG_LATENCY(self);
        if(lag < 0.001)
index b2ab7d08222d64b81be935e746e31fab99844766..c4f63835c359f07b9fb8f2ea932c2f89179ebe9c 100644 (file)
@@ -52,7 +52,7 @@ void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float p
 .vector railgunforce;
 void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype);
 
-float fireBullet_trace_callback_eff;
+entity fireBullet_trace_callback_eff;
 entity fireBullet_last_hit;
 void fireBullet_trace_callback(vector start, vector hit, vector end);
 void fireBullet(vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, int tracereffects);
index 7fa14508688cc50ba50803fbd22e87d98b0a67b4..3ea45ad46814ca7dfcc306288048b41cded229fb 100644 (file)
 
 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float algn)
 {
-       switch(algn)
+       switch (algn)
        {
                default: case 3: break; // right alignment
-               case 4: vecs.y = -vecs.y; break; // left
-               case 1: case 2: vecs.y = 0; vecs.z -= 2; break; // center
+               case 4: vecs.y = -vecs.y;
+                       break;              // left
+               case 1: case 2: vecs.y = 0;
+                       vecs.z -= 2;
+                       break;              // center
        }
 
        return vecs;
@@ -30,25 +33,31 @@ vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn
 {
        string s;
 
-       if(visual)
+       if (visual)
+       {
                vecs = shotorg_adjustfromclient(vecs, y_is_right, algn);
-       else if(autocvar_g_shootfromeye)
+       }
+       else if (autocvar_g_shootfromeye)
+       {
                vecs.y = vecs.z = 0;
-       else if(autocvar_g_shootfromcenter)
+       }
+       else if (autocvar_g_shootfromcenter)
        {
                vecs.y = 0;
                vecs.z -= 2;
        }
-       else if((s = autocvar_g_shootfromfixedorigin) != "")
+       else if ((s = autocvar_g_shootfromfixedorigin) != "")
        {
                vector v = stov(s);
-               if(y_is_right) { v.y = -v.y; }
-               if(v.x != 0) { vecs.x = v.x; }
+               if (y_is_right) v.y = -v.y;
+               if (v.x != 0) vecs.x = v.x;
                vecs.y = v.y;
                vecs.z = v.z;
        }
-       else // just do the same as top
+       else  // just do the same as top
+       {
                vecs = shotorg_adjustfromclient(vecs, y_is_right, algn);
+       }
 
        return vecs;
 }
@@ -83,14 +92,14 @@ float W_WeaponSpeedFactor()
 }
 
 
-void weapon_thinkf(entity actor, float fr, float t, void(Weapon thiswep, entity actor, bool fire1, bool fire2) func);
+void weapon_thinkf(entity actor, .entity weaponentity, float fr, float t, void(Weapon thiswep, entity actor,
+    .entity weaponentity, int fire) func);
 
-float CL_Weaponentity_CustomizeEntityForClient()
-{SELFPARAM();
-       self.viewmodelforclient = self.owner;
-       if(IS_SPEC(other))
-               if(other.enemy == self.owner)
-                       self.viewmodelforclient = other;
+bool CL_Weaponentity_CustomizeEntityForClient()
+{
+       SELFPARAM();
+       this.viewmodelforclient = this.owner;
+       if (IS_SPEC(other) && other.enemy == this.owner) this.viewmodelforclient = other;
        return true;
 }
 
@@ -137,395 +146,385 @@ float CL_Weaponentity_CustomizeEntityForClient()
  */
 
 // writes:
-//   self.origin, self.angles
-//   self.weaponentity
-//   self.movedir, self.view_ofs
+//   this.origin, this.angles
+//   this.weaponentity
+//   this.movedir, this.view_ofs
 //   attachment stuff
 //   anim stuff
 // to free:
 //   call again with ""
 //   remove the ent
-void CL_WeaponEntity_SetModel(string name)
-{SELFPARAM();
-       float v_shot_idx;
+void CL_WeaponEntity_SetModel(entity this, .entity weaponentity, string name)
+{
        if (name != "")
        {
                // if there is a child entity, hide it until we're sure we use it
-               if (self.weaponentity)
-                       self.weaponentity.model = "";
-               _setmodel(self, W_Model(strcat("v_", name, ".md3")));
-               v_shot_idx = gettagindex(self, "shot"); // used later
-               if(!v_shot_idx)
-                       v_shot_idx = gettagindex(self, "tag_shot");
-
-               _setmodel(self, W_Model(strcat("h_", name, ".iqm")));
+               if (this.(weaponentity)) this.(weaponentity).model = "";
+               _setmodel(this, W_Model(strcat("v_", name, ".md3")));
+               int v_shot_idx = gettagindex(this, "shot");  // used later
+               if (!v_shot_idx) v_shot_idx = gettagindex(this, "tag_shot");
+
+               _setmodel(this, W_Model(strcat("h_", name, ".iqm")));
                // preset some defaults that work great for renamed zym files (which don't need an animinfo)
-               self.anim_fire1  = animfixfps(self, '0 1 0.01', '0 0 0');
-               self.anim_fire2  = animfixfps(self, '1 1 0.01', '0 0 0');
-               self.anim_idle   = animfixfps(self, '2 1 0.01', '0 0 0');
-               self.anim_reload = animfixfps(self, '3 1 0.01', '0 0 0');
+               this.anim_fire1  = animfixfps(this, '0 1 0.01', '0 0 0');
+               this.anim_fire2  = animfixfps(this, '1 1 0.01', '0 0 0');
+               this.anim_idle   = animfixfps(this, '2 1 0.01', '0 0 0');
+               this.anim_reload = animfixfps(this, '3 1 0.01', '0 0 0');
 
                // if we have a "weapon" tag, let's attach the v_ model to it ("invisible hand" style model)
                // if we don't, this is a "real" animated model
-               if(gettagindex(self, "weapon"))
+               if (gettagindex(this, "weapon"))
                {
-                       if (!self.weaponentity)
-                               self.weaponentity = spawn();
-                       _setmodel(self.weaponentity, W_Model(strcat("v_", name, ".md3")));
-                       setattachment(self.weaponentity, self, "weapon");
+                       if (!this.(weaponentity)) this.(weaponentity) = new(weaponentity);
+                       _setmodel(this.(weaponentity), W_Model(strcat("v_", name, ".md3")));
+                       setattachment(this.(weaponentity), this, "weapon");
                }
-               else if(gettagindex(self, "tag_weapon"))
+               else if (gettagindex(this, "tag_weapon"))
                {
-                       if (!self.weaponentity)
-                               self.weaponentity = spawn();
-                       _setmodel(self.weaponentity, W_Model(strcat("v_", name, ".md3")));
-                       setattachment(self.weaponentity, self, "tag_weapon");
+                       if (!this.(weaponentity)) this.(weaponentity) = new(weaponentity);
+                       _setmodel(this.(weaponentity), W_Model(strcat("v_", name, ".md3")));
+                       setattachment(this.(weaponentity), this, "tag_weapon");
                }
                else
                {
-                       if(self.weaponentity)
-                               remove(self.weaponentity);
-                       self.weaponentity = world;
+                       if (this.(weaponentity)) remove(this.(weaponentity));
+                       this.(weaponentity) = NULL;
                }
 
-               setorigin(self,'0 0 0');
-               self.angles = '0 0 0';
-               self.frame = 0;
-               self.viewmodelforclient = world;
+               setorigin(this, '0 0 0');
+               this.angles = '0 0 0';
+               this.frame = 0;
+               this.viewmodelforclient = NULL;
 
                float idx;
 
-               if(v_shot_idx) // v_ model attached to invisible h_ model
+               if (v_shot_idx)  // v_ model attached to invisible h_ model
                {
-                       self.movedir = gettaginfo(self.weaponentity, v_shot_idx);
+                       this.movedir = gettaginfo(this.(weaponentity), v_shot_idx);
                }
                else
                {
-                       idx = gettagindex(self, "shot");
-                       if(!idx)
-                               idx = gettagindex(self, "tag_shot");
-                       if(idx)
-                               self.movedir = gettaginfo(self, idx);
+                       idx = gettagindex(this, "shot");
+                       if (!idx) idx = gettagindex(this, "tag_shot");
+                       if (idx)
+                       {
+                               this.movedir = gettaginfo(this, idx);
+                       }
                        else
                        {
-                               LOG_INFO("WARNING: weapon model ", self.model, " does not support the 'shot' tag, will display shots TOTALLY wrong\n");
-                               self.movedir = '0 0 0';
+                               LOG_INFO("WARNING: weapon model ", this.model,
+                                       " does not support the 'shot' tag, will display shots TOTALLY wrong\n");
+                               this.movedir = '0 0 0';
                        }
                }
 
-               if(self.weaponentity) // v_ model attached to invisible h_ model
+               if (this.(weaponentity))  // v_ model attached to invisible h_ model
                {
-                       idx = gettagindex(self.weaponentity, "shell");
-                       if(!idx)
-                               idx = gettagindex(self.weaponentity, "tag_shell");
-                       if(idx)
-                               self.spawnorigin = gettaginfo(self.weaponentity, idx);
+                       idx = gettagindex(this.(weaponentity), "shell");
+                       if (!idx) idx = gettagindex(this.(weaponentity), "tag_shell");
+                       if (idx) this.spawnorigin = gettaginfo(this.(weaponentity), idx);
                }
                else
+               {
                        idx = 0;
-               if(!idx)
+               }
+               if (!idx)
                {
-                       idx = gettagindex(self, "shell");
-                       if(!idx)
-                               idx = gettagindex(self, "tag_shell");
-                       if(idx)
-                               self.spawnorigin = gettaginfo(self, idx);
+                       idx = gettagindex(this, "shell");
+                       if (!idx) idx = gettagindex(this, "tag_shell");
+                       if (idx)
+                       {
+                               this.spawnorigin = gettaginfo(this, idx);
+                       }
                        else
                        {
-                               LOG_INFO("WARNING: weapon model ", self.model, " does not support the 'shell' tag, will display casings wrong\n");
-                               self.spawnorigin = self.movedir;
+                               LOG_INFO("WARNING: weapon model ", this.model,
+                                       " does not support the 'shell' tag, will display casings wrong\n");
+                               this.spawnorigin = this.movedir;
                        }
                }
 
-               if(v_shot_idx)
+               if (v_shot_idx)
                {
-                       self.oldorigin = '0 0 0'; // use regular attachment
+                       this.oldorigin = '0 0 0';  // use regular attachment
                }
                else
                {
-                       if(self.weaponentity)
+                       if (this.(weaponentity))
                        {
-                               idx = gettagindex(self, "weapon");
-                               if(!idx)
-                                       idx = gettagindex(self, "tag_weapon");
+                               idx = gettagindex(this, "weapon");
+                               if (!idx) idx = gettagindex(this, "tag_weapon");
                        }
                        else
                        {
-                               idx = gettagindex(self, "handle");
-                               if(!idx)
-                                       idx = gettagindex(self, "tag_handle");
+                               idx = gettagindex(this, "handle");
+                               if (!idx) idx = gettagindex(this, "tag_handle");
                        }
-                       if(idx)
+                       if (idx)
                        {
-                               self.oldorigin = self.movedir - gettaginfo(self, idx);
+                               this.oldorigin = this.movedir - gettaginfo(this, idx);
                        }
                        else
                        {
-                               LOG_INFO("WARNING: weapon model ", self.model, " does not support the 'handle' tag and neither does the v_ model support the 'shot' tag, will display muzzle flashes TOTALLY wrong\n");
-                               self.oldorigin = '0 0 0'; // there is no way to recover from this
+                               LOG_INFO("WARNING: weapon model ", this.model,
+                                       " does not support the 'handle' tag and neither does the v_ model support the 'shot' tag, will display muzzle flashes TOTALLY wrong\n");
+                               this.oldorigin = '0 0 0';  // there is no way to recover from this
                        }
                }
 
-               self.viewmodelforclient = self.owner;
+               this.viewmodelforclient = this.owner;
        }
        else
        {
-               self.model = "";
-               if(self.weaponentity)
-                       remove(self.weaponentity);
-               self.weaponentity = world;
-               self.movedir = '0 0 0';
-               self.spawnorigin = '0 0 0';
-               self.oldorigin = '0 0 0';
-               self.anim_fire1  = '0 1 0.01';
-               self.anim_fire2  = '0 1 0.01';
-               self.anim_idle   = '0 1 0.01';
-               self.anim_reload = '0 1 0.01';
+               this.model = "";
+               if (this.(weaponentity)) remove(this.(weaponentity));
+               this.(weaponentity) = NULL;
+               this.movedir = '0 0 0';
+               this.spawnorigin = '0 0 0';
+               this.oldorigin = '0 0 0';
+               this.anim_fire1  = '0 1 0.01';
+               this.anim_fire2  = '0 1 0.01';
+               this.anim_idle   = '0 1 0.01';
+               this.anim_reload = '0 1 0.01';
        }
 
-       self.view_ofs = '0 0 0';
+       this.view_ofs = '0 0 0';
 
-       if(self.movedir.x >= 0)
+       if (this.movedir.x >= 0)
        {
-               vector v0;
-               v0 = self.movedir;
-               self.movedir = shotorg_adjust(v0, false, false, self.owner.cvar_cl_gunalign);
-               self.view_ofs = shotorg_adjust(v0, false, true, self.owner.cvar_cl_gunalign) - v0;
+               vector v0 = this.movedir;
+               this.movedir = shotorg_adjust(v0, false, false, this.owner.cvar_cl_gunalign);
+               this.view_ofs = shotorg_adjust(v0, false, true, this.owner.cvar_cl_gunalign) - v0;
        }
-       self.owner.stat_shotorg = compressShotOrigin(self.movedir);
-       self.movedir = decompressShotOrigin(self.owner.stat_shotorg); // make them match perfectly
+       this.owner.stat_shotorg = compressShotOrigin(this.movedir);
+       this.movedir = decompressShotOrigin(this.owner.stat_shotorg); // make them match perfectly
 
-       self.spawnorigin += self.view_ofs; // offset the casings origin by the same amount
+       this.spawnorigin += this.view_ofs;                            // offset the casings origin by the same amount
 
        // check if an instant weapon switch occurred
-       setorigin(self, self.view_ofs);
+       setorigin(this, this.view_ofs);
        // reset animstate now
-       self.wframe = WFRAME_IDLE;
-       setanim(self, self.anim_idle, true, false, true);
+       this.wframe = WFRAME_IDLE;
+       setanim(this, this.anim_idle, true, false, true);
 }
 
 vector CL_Weapon_GetShotOrg(float wpn)
-{SELFPARAM();
-       entity wi = get_weaponinfo(wpn);
-       setself(spawn());
-       CL_WeaponEntity_SetModel(wi.mdl);
-       vector ret = self.movedir;
-       CL_WeaponEntity_SetModel("");
-       remove(self);
-       setself(this);
+{
+       entity wi = Weapons_from(wpn);
+       entity e = spawn();
+       .entity weaponentity = weaponentities[0];
+       CL_WeaponEntity_SetModel(e, weaponentity, wi.mdl);
+       vector ret = e.movedir;
+       CL_WeaponEntity_SetModel(e, weaponentity, "");
+       remove(e);
        return ret;
 }
 
+..entity weaponentity_fld;
+
 void CL_Weaponentity_Think()
-{SELFPARAM();
-       int tb;
-       self.nextthink = time;
-       if (intermission_running)
-               self.frame = self.anim_idle.x;
-       if (self.owner.weaponentity != self)
+{
+       SELFPARAM();
+       this.nextthink = time;
+       if (intermission_running) this.frame = this.anim_idle.x;
+       .entity weaponentity = this.weaponentity_fld;
+       if (this.owner.(weaponentity) != this)
        {
-               if (self.weaponentity)
-                       remove(self.weaponentity);
-               remove(self);
+               if (this.(weaponentity)) remove(this.(weaponentity));
+               remove(this);
                return;
        }
-       if (self.owner.deadflag != DEAD_NO)
+       if (this.owner.deadflag != DEAD_NO)
        {
-               self.model = "";
-               if (self.weaponentity)
-                       self.weaponentity.model = "";
+               this.model = "";
+               if (this.(weaponentity)) this.(weaponentity).model = "";
                return;
        }
-       if (self.weaponname != self.owner.weaponname || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag)
+       if (this.weaponname != this.owner.weaponname || this.dmg != this.owner.modelindex
+           || this.deadflag != this.owner.deadflag)
        {
-               self.weaponname = self.owner.weaponname;
-               self.dmg = self.owner.modelindex;
-               self.deadflag = self.owner.deadflag;
+               this.weaponname = this.owner.weaponname;
+               this.dmg = this.owner.modelindex;
+               this.deadflag = this.owner.deadflag;
 
-               CL_WeaponEntity_SetModel(self.owner.weaponname);
+               CL_WeaponEntity_SetModel(this, weaponentity, this.owner.weaponname);
        }
 
-       tb = (self.effects & (EF_TELEPORT_BIT | EF_RESTARTANIM_BIT));
-       self.effects = self.owner.effects & EFMASK_CHEAP;
-       self.effects &= ~EF_LOWPRECISION;
-       self.effects &= ~EF_FULLBRIGHT; // can mask team color, so get rid of it
-       self.effects &= ~EF_TELEPORT_BIT;
-       self.effects &= ~EF_RESTARTANIM_BIT;
-       self.effects |= tb;
-
-       if(self.owner.alpha == default_player_alpha)
-               self.alpha = default_weapon_alpha;
-       else if(self.owner.alpha != 0)
-               self.alpha = self.owner.alpha;
-       else
-               self.alpha = 1;
-
-       self.glowmod = self.owner.weaponentity_glowmod;
-       self.colormap = self.owner.colormap;
-       if (self.weaponentity)
+       int tb = (this.effects & (EF_TELEPORT_BIT | EF_RESTARTANIM_BIT));
+       this.effects = this.owner.effects & EFMASK_CHEAP;
+       this.effects &= ~EF_LOWPRECISION;
+       this.effects &= ~EF_FULLBRIGHT;  // can mask team color, so get rid of it
+       this.effects &= ~EF_TELEPORT_BIT;
+       this.effects &= ~EF_RESTARTANIM_BIT;
+       this.effects |= tb;
+       if (weaponentity != weaponentities[0]) this.effects |= EF_NODRAW;
+
+       if (this.owner.alpha == default_player_alpha) this.alpha = default_weapon_alpha;
+       else if (this.owner.alpha != 0) this.alpha = this.owner.alpha;
+       else this.alpha = 1;
+
+       this.glowmod = this.owner.weaponentity_glowmod;
+       this.colormap = this.owner.colormap;
+       if (this.(weaponentity))
        {
-               self.weaponentity.effects = self.effects;
-               self.weaponentity.alpha = self.alpha;
-               self.weaponentity.colormap = self.colormap;
-               self.weaponentity.glowmod = self.glowmod;
+               this.(weaponentity).effects = this.effects;
+               this.(weaponentity).alpha = this.alpha;
+               this.(weaponentity).colormap = this.colormap;
+               this.(weaponentity).glowmod = this.glowmod;
        }
 
-       self.angles = '0 0 0';
+       this.angles = '0 0 0';
 
-       float f = (self.owner.weapon_nextthink - time);
-       if (self.state == WS_RAISE && !intermission_running)
+       float f = this.weapon_nextthink - time;
+       if (this.state == WS_RAISE && !intermission_running)
        {
-               entity newwep = get_weaponinfo(self.owner.switchweapon);
+               entity newwep = Weapons_from(this.owner.switchweapon);
                f = f * g_weaponratefactor / max(f, newwep.switchdelay_raise);
-               self.angles_x = -90 * f * f;
+               this.angles_x = -90 * f * f;
        }
-       else if (self.state == WS_DROP && !intermission_running)
+       else if (this.state == WS_DROP && !intermission_running)
        {
-               entity oldwep = get_weaponinfo(self.owner.weapon);
+               entity oldwep = Weapons_from(this.owner.weapon);
                f = 1 - f * g_weaponratefactor / max(f, oldwep.switchdelay_drop);
-               self.angles_x = -90 * f * f;
+               this.angles_x = -90 * f * f;
        }
-       else if (self.state == WS_CLEAR)
+       else if (this.state == WS_CLEAR)
        {
                f = 1;
-               self.angles_x = -90 * f * f;
+               this.angles_x = -90 * f * f;
        }
 }
 
 void CL_ExteriorWeaponentity_Think()
-{SELFPARAM();
-       float tag_found;
-       self.nextthink = time;
-       if (self.owner.exteriorweaponentity != self)
+{
+       SELFPARAM();
+       this.nextthink = time;
+       if (this.owner.exteriorweaponentity != this)
        {
-               remove(self);
+               remove(this);
                return;
        }
-       if (self.owner.deadflag != DEAD_NO)
+       if (this.owner.deadflag != DEAD_NO)
        {
-               self.model = "";
+               this.model = "";
                return;
        }
-       if (self.weaponname != self.owner.weaponname || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag)
+       if (this.weaponname != this.owner.weaponname || this.dmg != this.owner.modelindex
+           || this.deadflag != this.owner.deadflag)
        {
-               self.weaponname = self.owner.weaponname;
-               self.dmg = self.owner.modelindex;
-               self.deadflag = self.owner.deadflag;
-               if (self.owner.weaponname != "")
-                       _setmodel(self, W_Model(strcat("v_", self.owner.weaponname, ".md3")));
-               else
-                       self.model = "";
-
-               if((tag_found = gettagindex(self.owner, "tag_weapon")))
+               this.weaponname = this.owner.weaponname;
+               this.dmg = this.owner.modelindex;
+               this.deadflag = this.owner.deadflag;
+               if (this.owner.weaponname != "") _setmodel(this, W_Model(strcat("v_", this.owner.weaponname, ".md3")));
+               else this.model = "";
+
+               int tag_found;
+               if ((tag_found = gettagindex(this.owner, "tag_weapon")))
                {
-                       self.tag_index = tag_found;
-                       self.tag_entity = self.owner;
+                       this.tag_index = tag_found;
+                       this.tag_entity = this.owner;
                }
                else
-                       setattachment(self, self.owner, "bip01 r hand");
+               {
+                       setattachment(this, this.owner, "bip01 r hand");
+               }
        }
-       self.effects = self.owner.effects;
-       self.effects |= EF_LOWPRECISION;
-       self.effects = self.effects & EFMASK_CHEAP; // eat performance
-       if(self.owner.alpha == default_player_alpha)
-               self.alpha = default_weapon_alpha;
-       else if(self.owner.alpha != 0)
-               self.alpha = self.owner.alpha;
-       else
-               self.alpha = 1;
+       this.effects = this.owner.effects;
+       this.effects |= EF_LOWPRECISION;
+       this.effects = this.effects & EFMASK_CHEAP;  // eat performance
+       if (this.owner.alpha == default_player_alpha) this.alpha = default_weapon_alpha;
+       else if (this.owner.alpha != 0) this.alpha = this.owner.alpha;
+       else this.alpha = 1;
 
-       self.glowmod = self.owner.weaponentity_glowmod;
-       self.colormap = self.owner.colormap;
+       this.glowmod = this.owner.weaponentity_glowmod;
+       this.colormap = this.owner.colormap;
 
-       CSQCMODEL_AUTOUPDATE(self);
+       CSQCMODEL_AUTOUPDATE(this);
 }
 
 // spawning weaponentity for client
-void CL_SpawnWeaponentity(entity e)
+void CL_SpawnWeaponentity(entity e, .entity weaponentity)
 {
-       entity view = e.weaponentity = spawn();
-       view.classname = "weaponentity";
+       entity view = e.(weaponentity) = new(weaponentity);
+       make_pure(view);
        view.solid = SOLID_NOT;
        view.owner = e;
-       setmodel(view, MDL_Null); // precision set when changed
+       setmodel(view, MDL_Null);  // precision set when changed
        setorigin(view, '0 0 0');
        view.angles = '0 0 0';
        view.viewmodelforclient = e;
        view.flags = 0;
+       view.weaponentity_fld = weaponentity;
        view.think = CL_Weaponentity_Think;
        view.customizeentityforclient = CL_Weaponentity_CustomizeEntityForClient;
        view.nextthink = time;
 
-       entity exterior = e.exteriorweaponentity = spawn();
-       exterior.classname = "exteriorweaponentity";
-       exterior.solid = SOLID_NOT;
-       exterior.exteriorweaponentity = exterior;
-       exterior.owner = e;
-       setorigin(exterior, '0 0 0');
-       exterior.angles = '0 0 0';
-       exterior.think = CL_ExteriorWeaponentity_Think;
-       exterior.nextthink = time;
-
-       CSQCMODEL_AUTOINIT(exterior);
+       if (weaponentity == weaponentities[0])
+       {
+               entity exterior = e.exteriorweaponentity = new(exteriorweaponentity);
+               make_pure(exterior);
+               exterior.solid = SOLID_NOT;
+               exterior.exteriorweaponentity = exterior;
+               exterior.owner = e;
+               setorigin(exterior, '0 0 0');
+               exterior.angles = '0 0 0';
+               exterior.think = CL_ExteriorWeaponentity_Think;
+               exterior.nextthink = time;
+
+               CSQCMODEL_AUTOINIT(exterior);
+       }
 }
 
 // Weapon subs
-void w_clear(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void w_clear(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        if (actor.weapon != -1)
        {
                actor.weapon = 0;
                actor.switchingweapon = 0;
        }
-       if (actor.weaponentity)
+       entity this = actor.(weaponentity);
+       if (this)
        {
-               actor.weaponentity.state = WS_CLEAR;
-               actor.weaponentity.effects = 0;
+               this.state = WS_CLEAR;
+               this.effects = 0;
        }
 }
 
-void w_ready(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
-       if (actor.weaponentity)
-               actor.weaponentity.state = WS_READY;
-       weapon_thinkf(actor, WFRAME_IDLE, 1000000, w_ready);
+       entity this = actor.(weaponentity);
+       if (this) this.state = WS_READY;
+       weapon_thinkf(actor, weaponentity, WFRAME_IDLE, 1000000, w_ready);
 }
 
 .float prevdryfire;
 .float prevwarntime;
-bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, float secondary)
+bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, bool secondary)
 {
        if ((actor.items & IT_UNLIMITED_WEAPON_AMMO)) return true;
        bool ammo = false;
-       if (secondary) {
-               WITH(entity, self, actor, ammo = thiswep.wr_checkammo2(thiswep));
-       } else {
-               WITH(entity, self, actor, ammo = thiswep.wr_checkammo1(thiswep));
-       }
+       if (secondary) WITH(entity, self, actor, ammo = thiswep.wr_checkammo2(thiswep));
+       else WITH(entity, self, actor, ammo = thiswep.wr_checkammo1(thiswep));
        if (ammo) return true;
        // always keep the Mine Layer if we placed mines, so that we can detonate them
-       entity mine;
-       if(actor.weapon == WEP_MINE_LAYER.m_id)
-       for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == actor)
-               return false;
+       if (thiswep == WEP_MINE_LAYER)
+               for (entity mine; (mine = find(mine, classname, "mine")); )
+                       if (mine.owner == actor) return false;
 
-       if(actor.weapon == WEP_SHOTGUN.m_id)
-       if(!secondary && WEP_CVAR(shotgun, secondary) == 1)
-               return false; // no clicking, just allow
+       if (thiswep == WEP_SHOTGUN)
+               if (!secondary && WEP_CVAR(shotgun, secondary) == 1) return false;             // no clicking, just allow
 
-       if(actor.weapon == actor.switchweapon && time - actor.prevdryfire > 1) // only play once BEFORE starting to switch weapons
+       if (thiswep == Weapons_from(actor.switchweapon) && time - actor.prevdryfire > 1) // only play once BEFORE starting to switch weapons
        {
-               sound (actor, CH_WEAPON_A, SND_DRYFIRE, VOL_BASE, ATTEN_NORM);
+               sound(actor, CH_WEAPON_A, SND_DRYFIRE, VOL_BASE, ATTEN_NORM);
                actor.prevdryfire = time;
        }
 
        // check if the other firing mode has enough ammo
        bool ammo_other = false;
-       if (secondary) {
-               WITH(entity, self, actor, ammo = thiswep.wr_checkammo1(thiswep));
-       } else {
-               WITH(entity, self, actor, ammo = thiswep.wr_checkammo2(thiswep));
-       }
+       if (secondary) WITH(entity, self, actor, ammo_other = thiswep.wr_checkammo1(thiswep));
+       else WITH(entity, self, actor, ammo_other = thiswep.wr_checkammo2(thiswep));
        if (ammo_other)
        {
                if (time - actor.prevwarntime > 1)
@@ -535,277 +534,283 @@ bool weapon_prepareattack_checkammo(Weapon thiswep, entity actor, float secondar
                                actor,
                                MSG_MULTI,
                                ITEM_WEAPON_PRIMORSEC,
-                               actor.weapon,
+                               thiswep.m_id,
                                secondary,
                                (1 - secondary)
-                       );
+                                        );
                }
                actor.prevwarntime = time;
        }
-       else // this weapon is totally unable to fire, switch to another one
+       else  // this weapon is totally unable to fire, switch to another one
        {
                W_SwitchToOtherWeapon(actor);
        }
 
        return false;
 }
+
 .float race_penalty;
-bool weapon_prepareattack_check(Weapon thiswep, entity actor, bool secondary, float attacktime)
+bool weapon_prepareattack_check(Weapon thiswep, entity actor, .entity weaponentity, bool secondary, float attacktime)
 {
-       if(!weapon_prepareattack_checkammo(thiswep, actor, secondary))
-               return false;
+       if (!weapon_prepareattack_checkammo(thiswep, actor, secondary)) return false;
 
-       //if sv_ready_restart_after_countdown is set, don't allow the player to shoot
-       //if all players readied up and the countdown is running
-       if(time < game_starttime || time < actor.race_penalty) {
-               return false;
-       }
+       // if sv_ready_restart_after_countdown is set, don't allow the player to shoot
+       // if all players readied up and the countdown is running
+       if (time < game_starttime || time < actor.race_penalty) return false;
 
-       if (timeout_status == TIMEOUT_ACTIVE) //don't allow the player to shoot while game is paused
+       if (timeout_status == TIMEOUT_ACTIVE)  // don't allow the player to shoot while game is paused
                return false;
 
        // do not even think about shooting if switching
-       if(actor.switchweapon != actor.weapon)
-               return false;
+       if (actor.switchweapon != actor.weapon) return false;
 
-       if(attacktime >= 0)
+       if (attacktime >= 0)
        {
+               int slot = weaponslot(weaponentity);
                // don't fire if previous attack is not finished
-               if (ATTACK_FINISHED(actor) > time + actor.weapon_frametime * 0.5)
-                       return false;
+               if (ATTACK_FINISHED(actor, slot) > time + actor.weapon_frametime * 0.5) return false;
+               entity this = actor.(weaponentity);
                // don't fire while changing weapon
-               if (actor.weaponentity.state != WS_READY)
-                       return false;
+               if (this.state != WS_READY) return false;
        }
        return true;
 }
-void weapon_prepareattack_do(entity actor, bool secondary, float attacktime)
+
+void weapon_prepareattack_do(entity actor, .entity weaponentity, bool secondary, float attacktime)
 {
-       actor.weaponentity.state = WS_INUSE;
+       entity this = actor.(weaponentity);
+       this.state = WS_INUSE;
 
-       actor.spawnshieldtime = min(actor.spawnshieldtime, time); // kill spawn shield when you fire
+       actor.spawnshieldtime = min(actor.spawnshieldtime, time);  // kill spawn shield when you fire
 
        // if the weapon hasn't been firing continuously, reset the timer
-       if(attacktime >= 0)
+       if (attacktime >= 0)
        {
-               if (ATTACK_FINISHED(actor) < time - actor.weapon_frametime * 1.5)
+               int slot = weaponslot(weaponentity);
+               if (ATTACK_FINISHED(actor, slot) < time - actor.weapon_frametime * 1.5)
                {
-                       ATTACK_FINISHED(actor) = time;
-                       //dprint("resetting attack finished to ", ftos(time), "\n");
+                       ATTACK_FINISHED(actor, slot) = time;
+                       // dprint("resetting attack finished to ", ftos(time), "\n");
                }
-               ATTACK_FINISHED(actor) = ATTACK_FINISHED(actor) + attacktime * W_WeaponRateFactor();
+               ATTACK_FINISHED(actor, slot) = ATTACK_FINISHED(actor, slot) + attacktime * W_WeaponRateFactor();
        }
        actor.bulletcounter += 1;
-       //dprint("attack finished ", ftos(ATTACK_FINISHED(actor)), "\n");
+       // dprint("attack finished ", ftos(ATTACK_FINISHED(actor, slot)), "\n");
 }
-bool weapon_prepareattack(Weapon thiswep, entity actor, bool secondary, float attacktime)
+
+bool weapon_prepareattack(Weapon thiswep, entity actor, .entity weaponentity, bool secondary, float attacktime)
 {
-       if (weapon_prepareattack_check(thiswep, actor, secondary, attacktime)) {
-               weapon_prepareattack_do(actor, secondary, attacktime);
+       if (weapon_prepareattack_check(thiswep, actor, weaponentity, secondary, attacktime))
+       {
+               weapon_prepareattack_do(actor, weaponentity, secondary, attacktime);
                return true;
        }
        return false;
 }
 
-void weapon_thinkf(entity actor, float fr, float t, void(Weapon thiswep, entity actor, bool fire1, bool fire2) func)
+void weapon_thinkf(entity actor, .entity weaponentity, float fr, float t, void(Weapon thiswep, entity actor,
+       .entity weaponentity, int fire) func)
 {
-       vector a;
-       vector of, or, ou;
-       float restartanim;
-
-       if(fr == WFRAME_DONTCHANGE)
+       entity this = actor.(weaponentity);
+       bool restartanim;
+       if (fr == WFRAME_DONTCHANGE)
        {
-               fr = actor.weaponentity.wframe;
+               fr = this.wframe;
                restartanim = false;
        }
        else if (fr == WFRAME_IDLE)
+       {
                restartanim = false;
+       }
        else
+       {
                restartanim = true;
+       }
 
-       of = v_forward;
-       or = v_right;
-       ou = v_up;
+       vector of = v_forward;
+       vector or = v_right;
+       vector ou = v_up;
 
-       if (actor.weaponentity)
+       if (this)
        {
-               actor.weaponentity.wframe = fr;
-               a = '0 0 0';
-               if (fr == WFRAME_IDLE)
-                       a = actor.weaponentity.anim_idle;
-               else if (fr == WFRAME_FIRE1)
-                       a = actor.weaponentity.anim_fire1;
-               else if (fr == WFRAME_FIRE2)
-                       a = actor.weaponentity.anim_fire2;
-               else // if (fr == WFRAME_RELOAD)
-                       a = actor.weaponentity.anim_reload;
+               this.wframe = fr;
+               vector a = '0 0 0';
+               if (fr == WFRAME_IDLE) a = this.anim_idle;
+               else if (fr == WFRAME_FIRE1) a = this.anim_fire1;
+               else if (fr == WFRAME_FIRE2) a = this.anim_fire2;
+               else  // if (fr == WFRAME_RELOAD)
+                       a = this.anim_reload;
                a.z *= g_weaponratefactor;
-               setanim(actor.weaponentity, a, restartanim == false, restartanim, restartanim);
+               setanim(this, a, restartanim == false, restartanim, restartanim);
        }
 
        v_forward = of;
        v_right = or;
        v_up = ou;
 
-       if(actor.weapon_think == w_ready && func != w_ready && actor.weaponentity.state == WS_RAISE)
-       {
-               backtrace("Tried to override initial weapon think function - should this really happen?");
-       }
+       if (this.weapon_think == w_ready && func != w_ready && this.state == WS_RAISE) backtrace(
+                       "Tried to override initial weapon think function - should this really happen?");
 
        t *= W_WeaponRateFactor();
 
        // VorteX: haste can be added here
-       if (actor.weapon_think == w_ready)
+       if (this.weapon_think == w_ready)
        {
-               actor.weapon_nextthink = time;
-               //dprint("started firing at ", ftos(time), "\n");
+               this.weapon_nextthink = time;
+               // dprint("started firing at ", ftos(time), "\n");
        }
-       if (actor.weapon_nextthink < time - actor.weapon_frametime * 1.5 || actor.weapon_nextthink > time + actor.weapon_frametime * 1.5)
+       if (this.weapon_nextthink < time - actor.weapon_frametime * 1.5
+           || this.weapon_nextthink > time + actor.weapon_frametime * 1.5)
        {
-               actor.weapon_nextthink = time;
-               //dprint("reset weapon animation timer at ", ftos(time), "\n");
+               this.weapon_nextthink = time;
+               // dprint("reset weapon animation timer at ", ftos(time), "\n");
        }
-       actor.weapon_nextthink = actor.weapon_nextthink + t;
-       actor.weapon_think = func;
-       //dprint("next ", ftos(actor.weapon_nextthink), "\n");
+       this.weapon_nextthink = this.weapon_nextthink + t;
+       this.weapon_think = func;
+       // dprint("next ", ftos(this.weapon_nextthink), "\n");
 
-       if((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t)
+       if ((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t)
        {
-               if((actor.weapon == WEP_SHOCKWAVE.m_id || actor.weapon == WEP_SHOTGUN.m_id) && fr == WFRAME_FIRE2)
-                       animdecide_setaction(actor, ANIMACTION_MELEE, restartanim);
-               else
-                       animdecide_setaction(actor, ANIMACTION_SHOOT, restartanim);
+               if ((actor.weapon == WEP_SHOCKWAVE.m_id || actor.weapon == WEP_SHOTGUN.m_id)
+                   && fr == WFRAME_FIRE2) animdecide_setaction(actor, ANIMACTION_MELEE, restartanim);
+               else animdecide_setaction(actor, ANIMACTION_SHOOT, restartanim);
        }
        else
        {
-               if(actor.anim_upper_action == ANIMACTION_SHOOT || actor.anim_upper_action == ANIMACTION_MELEE)
-                       actor.anim_upper_action = 0;
+               if (actor.anim_upper_action == ANIMACTION_SHOOT
+                   || actor.anim_upper_action == ANIMACTION_MELEE) actor.anim_upper_action = 0;
        }
 }
 
-float forbidWeaponUse(entity player)
+bool forbidWeaponUse(entity player)
 {
-       if(time < game_starttime && !autocvar_sv_ready_restart_after_countdown)
-               return 1;
-       if(round_handler_IsActive() && !round_handler_IsRoundStarted())
-               return 1;
-       if(player.player_blocked)
-               return 1;
-       if(player.frozen)
-               return 1;
-       if(player.weapon_blocked)
-               return 1;
-       return 0;
+       if (time < game_starttime && !autocvar_sv_ready_restart_after_countdown) return true;
+       if (round_handler_IsActive() && !round_handler_IsRoundStarted()) return true;
+       if (player.player_blocked) return true;
+       if (player.frozen) return true;
+       if (player.weapon_blocked) return true;
+       return false;
 }
 
 .bool hook_switchweapon;
 
 void W_WeaponFrame(entity actor)
 {
-       vector fo, ri, up;
+       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+       entity this = actor.(weaponentity);
+       if (frametime) actor.weapon_frametime = frametime;
 
-       if (frametime)
-               actor.weapon_frametime = frametime;
+       if (!this || actor.health < 1) return; // Dead player can't use weapons and injure impulse commands
 
-       if (!actor.weaponentity || actor.health < 1)
-               return; // Dead player can't use weapons and injure impulse commands
 
-       if(forbidWeaponUse(actor))
-       if(actor.weaponentity.state != WS_CLEAR)
+       if (forbidWeaponUse(actor))
        {
-               Weapon wpn = get_weaponinfo(actor.weapon);
-               w_ready(wpn, actor, actor.BUTTON_ATCK, actor.BUTTON_ATCK2);
-               return;
+               if (actor.(weaponentity).state != WS_CLEAR)
+               {
+                       Weapon wpn = Weapons_from(actor.weapon);
+                       w_ready(wpn, actor, weaponentity, (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0));
+                       return;
+               }
        }
 
-       if(!actor.switchweapon)
+       if (actor.switchweapon == 0)
        {
                actor.weapon = 0;
                actor.switchingweapon = 0;
-               actor.weaponentity.state = WS_CLEAR;
+               this.state = WS_CLEAR;
                actor.weaponname = "";
-               //actor.items &= ~IT_AMMO;
+               // actor.items &= ~IT_AMMO;
                return;
        }
 
        makevectors(actor.v_angle);
-       fo = v_forward; // save them in case the weapon think functions change it
-       ri = v_right;
-       up = v_up;
+       vector fo = v_forward;  // save them in case the weapon think functions change it
+       vector ri = v_right;
+       vector up = v_up;
 
        // Change weapon
        if (actor.weapon != actor.switchweapon)
        {
-               if (actor.weaponentity.state == WS_CLEAR)
+               switch (this.state)
                {
-                       // end switching!
-                       actor.switchingweapon = actor.switchweapon;
-                       entity newwep = get_weaponinfo(actor.switchweapon);
-
-                       // the two weapon entities will notice this has changed and update their models
-                       actor.weapon = actor.switchweapon;
-                       actor.weaponname = newwep.mdl;
-                       actor.bulletcounter = 0;
-                       actor.ammo_field = newwep.ammo_field;
-                       Weapon w = get_weaponinfo(actor.switchweapon);
-                       w.wr_setup(w);
-                       actor.weaponentity.state = WS_RAISE;
-
-                       // set our clip load to the load of the weapon we switched to, if it's reloadable
-                       if(newwep.spawnflags & WEP_FLAG_RELOADABLE && newwep.reloading_ammo) // prevent accessing undefined cvars
+                       default:
+                               LOG_WARNINGF("unhandled weaponentity (%i) state for player (%i): %d\n", this, actor, this.state);
+                               break;
+                       case WS_INUSE:
+                       case WS_RAISE:
+                               break;
+                       case WS_CLEAR:
                        {
-                               actor.clip_load = actor.(weapon_load[actor.switchweapon]);
-                               actor.clip_size = newwep.reloading_ammo;
-                       }
-                       else
-                               actor.clip_load = actor.clip_size = 0;
-
-                       weapon_thinkf(actor, WFRAME_IDLE, newwep.switchdelay_raise, w_ready);
-               }
-               else if (actor.weaponentity.state == WS_DROP)
-               {
-                       // in dropping phase we can switch at any time
-                       actor.switchingweapon = actor.switchweapon;
-               }
-               else if (actor.weaponentity.state == WS_READY)
-               {
-                       // start switching!
-                       actor.switchingweapon = actor.switchweapon;
-                       entity oldwep = get_weaponinfo(actor.weapon);
+                               // end switching!
+                               actor.switchingweapon = actor.switchweapon;
+                               entity newwep = Weapons_from(actor.switchweapon);
+
+                               // the two weapon entities will notice this has changed and update their models
+                               actor.weapon = actor.switchweapon;
+                               actor.weaponname = newwep.mdl;
+                               actor.bulletcounter = 0;
+                               actor.ammo_field = newwep.ammo_field;
+                               newwep.wr_setup(newwep);
+                               this.state = WS_RAISE;
+
+                               // set our clip load to the load of the weapon we switched to, if it's reloadable
+                               if ((newwep.spawnflags & WEP_FLAG_RELOADABLE) && newwep.reloading_ammo)  // prevent accessing undefined cvars
+                               {
+                                       actor.clip_load = actor.(weapon_load[actor.switchweapon]);
+                                       actor.clip_size = newwep.reloading_ammo;
+                               }
+                               else
+                               {
+                                       actor.clip_load = actor.clip_size = 0;
+                               }
 
-                       // set up weapon switch think in the future, and start drop anim
-                       #ifndef INDEPENDENT_ATTACK_FINISHED
-                       if(ATTACK_FINISHED(actor) <= time + actor.weapon_frametime * 0.5)
+                               weapon_thinkf(actor, weaponentity, WFRAME_IDLE, newwep.switchdelay_raise, w_ready);
+                               break;
+                       }
+                       case WS_DROP:
                        {
-                       #endif
-                               sound(actor, CH_WEAPON_SINGLE, SND_WEAPON_SWITCH, VOL_BASE, ATTN_NORM);
-                               actor.weaponentity.state = WS_DROP;
-                               weapon_thinkf(actor, WFRAME_DONTCHANGE, oldwep.switchdelay_drop, w_clear);
-                       #ifndef INDEPENDENT_ATTACK_FINISHED
+                               // in dropping phase we can switch at any time
+                               actor.switchingweapon = actor.switchweapon;
+                               break;
+                       }
+                       case WS_READY:
+                       {
+                               // start switching!
+                               actor.switchingweapon = actor.switchweapon;
+                               entity oldwep = Weapons_from(actor.weapon);
+
+                               // set up weapon switch think in the future, and start drop anim
+                               if (
+#if INDEPENDENT_ATTACK_FINISHED
+                                           true
+#else
+                                           ATTACK_FINISHED(actor, slot) <= time + actor.weapon_frametime * 0.5
+#endif
+                                  )
+                               {
+                                       sound(actor, CH_WEAPON_SINGLE, SND_WEAPON_SWITCH, VOL_BASE, ATTN_NORM);
+                                       this.state = WS_DROP;
+                                       weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, oldwep.switchdelay_drop, w_clear);
+                               }
+                               break;
                        }
-                       #endif
                }
        }
 
        // LordHavoc: network timing test code
-       //if (actor.button0)
-       //      print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor)), " >= ", ftos(actor.weapon_nextthink), "\n");
+       // if (actor.button0)
+       //      print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor, slot)), " >= ", ftos(this.weapon_nextthink), "\n");
 
-       float w;
-       w = actor.weapon;
+       int w = actor.weapon;
 
        // call the think code which may fire the weapon
        // and do so multiple times to resolve framerate dependency issues if the
        // server framerate is very low and the weapon fire rate very high
-       float c;
-       c = 0;
-       while (c < W_TICSPERFRAME)
+       for (int c = 0; c < W_TICSPERFRAME; ++c)
        {
-               c = c + 1;
-               if(w && !(actor.weapons & WepSet_FromWeapon(w)))
+               if (w && !(actor.weapons & WepSet_FromWeapon(w)))
                {
-                       if(actor.weapon == actor.switchweapon)
-                               W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
+                       if (actor.weapon == actor.switchweapon) W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
                        w = 0;
                }
 
@@ -816,100 +821,104 @@ void W_WeaponFrame(entity actor)
                bool block_weapon = false;
                {
                        bool key_pressed = actor.BUTTON_HOOK && !actor.vehicle;
-               Weapon off = actor.offhand;
-               if (off && !(actor.weapons & WEPSET(HOOK))) {
-                       if (off.offhand_think) off.offhand_think(off, actor, key_pressed);
-               } else {
-                       if (key_pressed && actor.switchweapon != WEP_HOOK.m_id && !actor.hook_switchweapon) {
-                                       W_SwitchWeapon(WEP_HOOK.m_id);
-                               }
+                       Weapon off = actor.offhand;
+                       if (off && !(actor.weapons & WEPSET(HOOK)))
+                       {
+                               if (off.offhand_think) off.offhand_think(off, actor, key_pressed);
+                       }
+                       else
+                       {
+                               if (key_pressed && actor.switchweapon != WEP_HOOK.m_id && !actor.hook_switchweapon) W_SwitchWeapon(
+                                               WEP_HOOK.m_id);
                                actor.hook_switchweapon = key_pressed;
                                Weapon h = WEP_HOOK;
                                block_weapon = (actor.weapon == h.m_id && (actor.BUTTON_ATCK || key_pressed));
-                               h.wr_think(h, actor, block_weapon, false);
-               }
-        }
+                               h.wr_think(h, actor, weaponentity, block_weapon ? 1 : 0);
+                       }
+               }
+
+               v_forward = fo;
+               v_right = ri;
+               v_up = up;
 
                if (!block_weapon)
-               if (w) {
-                       Weapon e = get_weaponinfo(actor.weapon);
-                       e.wr_think(e, actor, actor.BUTTON_ATCK, actor.BUTTON_ATCK2);
-               } else {
-                       Weapon w = get_weaponinfo(actor.weapon);
-                       w.wr_gonethink(w);
+               {
+                       if (w)
+                       {
+                               Weapon e = Weapons_from(actor.weapon);
+                               e.wr_think(e, actor, weaponentity, (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0));
+                       }
+                       else
+                       {
+                               Weapon w = Weapons_from(actor.weapon);
+                               w.wr_gonethink(w);
+                       }
                }
 
-               if (time + actor.weapon_frametime * 0.5 >= actor.weapon_nextthink)
+               if (time + actor.weapon_frametime * 0.5 >= this.weapon_nextthink)
                {
-                       if(actor.weapon_think)
+                       if (this.weapon_think)
                        {
                                v_forward = fo;
                                v_right = ri;
                                v_up = up;
-                               Weapon wpn = get_weaponinfo(actor.weapon);
-                               actor.weapon_think(wpn, actor, actor.BUTTON_ATCK, actor.BUTTON_ATCK2);
+                               Weapon wpn = Weapons_from(actor.weapon);
+                               this.weapon_think(wpn, actor, weaponentity,
+                                       (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0));
                        }
                        else
+                       {
                                bprint("\{1}^1ERROR: undefined weapon think function for ", actor.netname, "\n");
+                       }
                }
        }
 }
 
 void W_AttachToShotorg(entity actor, entity flash, vector offset)
 {
-       entity xflash;
+       .entity weaponentity = weaponentities[0];
        flash.owner = actor;
        flash.angles_z = random() * 360;
 
-       if(gettagindex(actor.weaponentity, "shot"))
-               setattachment(flash, actor.weaponentity, "shot");
-       else
-               setattachment(flash, actor.weaponentity, "tag_shot");
+       entity this = actor.(weaponentity);
+       if (gettagindex(this, "shot")) setattachment(flash, this, "shot");
+       else setattachment(flash, this, "tag_shot");
        setorigin(flash, offset);
 
-       xflash = spawn();
+       entity xflash = spawn();
        copyentity(flash, xflash);
 
        flash.viewmodelforclient = actor;
 
-       if(actor.weaponentity.oldorigin.x > 0)
+       if (this.oldorigin.x > 0)
        {
                setattachment(xflash, actor.exteriorweaponentity, "");
-               setorigin(xflash, actor.weaponentity.oldorigin + offset);
+               setorigin(xflash, this.oldorigin + offset);
        }
        else
        {
-               if(gettagindex(actor.exteriorweaponentity, "shot"))
-                       setattachment(xflash, actor.exteriorweaponentity, "shot");
-               else
-                       setattachment(xflash, actor.exteriorweaponentity, "tag_shot");
+               if (gettagindex(actor.exteriorweaponentity, "shot")) setattachment(xflash, actor.exteriorweaponentity, "shot");
+               else setattachment(xflash, actor.exteriorweaponentity, "tag_shot");
                setorigin(xflash, offset);
        }
 }
 
 void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use)
 {
+       if (MUTATOR_CALLHOOK(W_DecreaseAmmo, actor)) return;
 
-       if(cvar("g_overkill"))
-       if(actor.ok_use_ammocharge)
-       {
-               ok_DecreaseCharge(actor, actor.weapon);
-               return; // TODO
-       }
-
-       if((actor.items & IT_UNLIMITED_WEAPON_AMMO) && !wep.reloading_ammo)
-               return;
+       if ((actor.items & IT_UNLIMITED_WEAPON_AMMO) && !wep.reloading_ammo) return;
 
        // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
-       if(wep.reloading_ammo)
+       if (wep.reloading_ammo)
        {
                actor.clip_load -= ammo_use;
                actor.(weapon_load[actor.weapon]) = actor.clip_load;
        }
-       else if(wep.ammo_field != ammo_none)
+       else if (wep.ammo_field != ammo_none)
        {
                actor.(wep.ammo_field) -= ammo_use;
-               if(actor.(wep.ammo_field) < 0)
+               if (actor.(wep.ammo_field) < 0)
                {
                        backtrace(sprintf(
                                "W_DecreaseAmmo(%.2f): '%s' subtracted too much %s from '%s', resulting with '%.2f' left... "
@@ -919,7 +928,7 @@ void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use)
                                GetAmmoPicture(wep.ammo_field),
                                actor.netname,
                                actor.(wep.ammo_field)
-                       ));
+                                            ));
                }
        }
 }
@@ -930,21 +939,23 @@ void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use)
 .float reload_complain;
 .string reload_sound;
 
-void W_ReloadedAndReady(Weapon thiswep, entity actor, bool fire1, bool fire2)
+void W_ReloadedAndReady(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        // finish the reloading process, and do the ammo transfer
 
-       actor.clip_load = actor.old_clip_load; // restore the ammo counter, in case we still had ammo in the weapon before reloading
+       actor.clip_load = actor.old_clip_load;  // restore the ammo counter, in case we still had ammo in the weapon before reloading
 
        // if the gun uses no ammo, max out weapon load, else decrease ammo as we increase weapon load
-       if(!actor.reload_ammo_min || actor.items & IT_UNLIMITED_WEAPON_AMMO || actor.ammo_field == ammo_none)
+       if (!actor.reload_ammo_min || actor.items & IT_UNLIMITED_WEAPON_AMMO || actor.ammo_field == ammo_none)
+       {
                actor.clip_load = actor.reload_ammo_amount;
+       }
        else
        {
                // make sure we don't add more ammo than we have
                float load = min(actor.reload_ammo_amount - actor.clip_load, actor.(actor.ammo_field));
-        actor.clip_load += load;
-        actor.(actor.ammo_field) -= load;
+               actor.clip_load += load;
+               actor.(actor.ammo_field) -= load;
        }
        actor.(weapon_load[actor.weapon]) = actor.clip_load;
 
@@ -952,21 +963,19 @@ void W_ReloadedAndReady(Weapon thiswep, entity actor, bool fire1, bool fire2)
        // then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there,
        // so your weapon is disabled for a few seconds without reason
 
-       //ATTACK_FINISHED(actor) -= actor.reload_time - 1;
+       // ATTACK_FINISHED(actor, slot) -= actor.reload_time - 1;
 
-       Weapon wpn = get_weaponinfo(actor.weapon);
-       w_ready(wpn, actor, actor.BUTTON_ATCK, actor.BUTTON_ATCK2);
+       Weapon wpn = Weapons_from(actor.weapon);
+       w_ready(wpn, actor, weaponentity, (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0));
 }
 
 void W_Reload(entity actor, float sent_ammo_min, string sent_sound)
 {
+       .entity weaponentity = weaponentities[0];
        // set global values to work with
-       entity e;
-       e = get_weaponinfo(actor.weapon);
+       entity e = Weapons_from(actor.weapon);
 
-       if(cvar("g_overkill"))
-       if(actor.ok_use_ammocharge)
-               return; // TODO
+       if (MUTATOR_CALLHOOK(W_Reload, actor)) return;
 
        actor.reload_ammo_min = sent_ammo_min;
        actor.reload_ammo_amount = e.reloading_ammo;
@@ -976,46 +985,49 @@ void W_Reload(entity actor, float sent_ammo_min, string sent_sound)
        // don't reload weapons that don't have the RELOADABLE flag
        if (!(e.spawnflags & WEP_FLAG_RELOADABLE))
        {
-               LOG_TRACE("Warning: Attempted to reload a weapon that does not have the WEP_FLAG_RELOADABLE flag. Fix your code!\n");
+               LOG_TRACE(
+                       "Warning: Attempted to reload a weapon that does not have the WEP_FLAG_RELOADABLE flag. Fix your code!\n");
                return;
        }
 
        // return if reloading is disabled for this weapon
-       if(!actor.reload_ammo_amount)
-               return;
+       if (!actor.reload_ammo_amount) return;
 
        // our weapon is fully loaded, no need to reload
-       if (actor.clip_load >= actor.reload_ammo_amount)
-               return;
+       if (actor.clip_load >= actor.reload_ammo_amount) return;
 
        // no ammo, so nothing to load
-       if(actor.ammo_field != ammo_none)
-       if(!actor.(actor.ammo_field) && actor.reload_ammo_min)
-       if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+       if (actor.ammo_field != ammo_none)
        {
-               if(IS_REAL_CLIENT(actor) && actor.reload_complain < time)
+               if (!actor.(actor.ammo_field) && actor.reload_ammo_min)
                {
-                       play2(actor, SND(UNAVAILABLE));
-                       sprint(actor, strcat("You don't have enough ammo to reload the ^2", WEP_NAME(actor.weapon), "\n"));
-                       actor.reload_complain = time + 1;
-               }
-               // switch away if the amount of ammo is not enough to keep using this weapon
-               Weapon w = get_weaponinfo(actor.weapon);
-               if (!(w.wr_checkammo1(w) + w.wr_checkammo2(w)))
-               {
-                       actor.clip_load = -1; // reload later
-                       W_SwitchToOtherWeapon(actor);
+                       if (!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+                       {
+                               if (IS_REAL_CLIENT(actor) && actor.reload_complain < time)
+                               {
+                                       play2(actor, SND(UNAVAILABLE));
+                                       sprint(actor, strcat("You don't have enough ammo to reload the ^2", WEP_NAME(actor.weapon), "\n"));
+                                       actor.reload_complain = time + 1;
+                               }
+                               // switch away if the amount of ammo is not enough to keep using this weapon
+                               Weapon w = Weapons_from(actor.weapon);
+                               if (!(w.wr_checkammo1(w) + w.wr_checkammo2(w)))
+                               {
+                                       actor.clip_load = -1;  // reload later
+                                       W_SwitchToOtherWeapon(actor);
+                               }
+                               return;
+                       }
                }
-               return;
        }
 
-       if (actor.weaponentity)
+       entity this = actor.(weaponentity);
+       if (this)
        {
-               if (actor.weaponentity.wframe == WFRAME_RELOAD)
-                       return;
+               if (this.wframe == WFRAME_RELOAD) return;
 
                // allow switching away while reloading, but this will cause a new reload!
-               actor.weaponentity.state = WS_READY;
+               this.state = WS_READY;
        }
 
        // now begin the reloading process
@@ -1026,21 +1038,18 @@ void W_Reload(entity actor, float sent_ammo_min, string sent_sound)
        // then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there,
        // so your weapon is disabled for a few seconds without reason
 
-       //ATTACK_FINISHED(actor) = max(time, ATTACK_FINISHED(actor)) + actor.reload_time + 1;
+       // ATTACK_FINISHED(actor, slot) = max(time, ATTACK_FINISHED(actor, slot)) + actor.reload_time + 1;
 
-       weapon_thinkf(actor, WFRAME_RELOAD, actor.reload_time, W_ReloadedAndReady);
+       weapon_thinkf(actor, weaponentity, WFRAME_RELOAD, actor.reload_time, W_ReloadedAndReady);
 
-       if(actor.clip_load < 0)
-               actor.clip_load = 0;
+       if (actor.clip_load < 0) actor.clip_load = 0;
        actor.old_clip_load = actor.clip_load;
        actor.clip_load = actor.(weapon_load[actor.weapon]) = -1;
 }
 
 void W_DropEvent(.void(Weapon) event, entity player, float weapon_type, entity weapon_item)
-{SELFPARAM();
-       setself(player);
+{
+       Weapon w = Weapons_from(weapon_type);
        weapon_dropevent_item = weapon_item;
-       Weapon w = get_weaponinfo(weapon_type);
-       w.event(w);
-       setself(this);
+       WITH(entity, self, player, w.event(w));
 }
index 86d31119568c33f7518bfbb7cc01c176f1acc8a5..97e6c72b4be3698caee7cfca657bf4fd4858c4f2 100644 (file)
@@ -18,7 +18,7 @@ vector shotorg_adjust(vector vecs, bool y_is_right, bool visual, int algn);
 
 vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn);
 
-void CL_SpawnWeaponentity(entity e);
+void CL_SpawnWeaponentity(entity e, .entity weaponentity);
 
 vector CL_Weapon_GetShotOrg(float wpn);
 
@@ -38,12 +38,12 @@ float W_WeaponRateFactor();
 
 float W_WeaponSpeedFactor();
 
-bool weapon_prepareattack(Weapon thiswep, entity actor, bool secondary, float attacktime);
+bool weapon_prepareattack(Weapon thiswep, entity actor, .entity weaponentity, bool secondary, float attacktime);
 
-bool weapon_prepareattack_check(Weapon thiswep, entity actor, float secondary, float attacktime);
+bool weapon_prepareattack_check(Weapon thiswep, entity actor, .entity weaponentity, float secondary, float attacktime);
 
-void weapon_prepareattack_do(entity actor, float secondary, float attacktime);
+void weapon_prepareattack_do(entity actor, .entity weaponentity, float secondary, float attacktime);
 
-void weapon_thinkf(entity actor, float fr, float t, void(Weapon thiswep, entity actor, bool fire1, bool fire2) func);
+void weapon_thinkf(entity actor, .entity weaponentity, float fr, float t, void(Weapon thiswep, entity actor, .entity weaponentity, int fire) func);
 
 #endif
index 4709cdc2dfe21586582fb6245eb0e0d12a901592..b09403f9545fa44e5d246bfab479be9815f535b2 100644 (file)
@@ -1016,23 +1016,23 @@ align_oc_decl_colon                      = false    # false/true #ignore
 #
 
 # Whether to collapse empty blocks between '{' and '}'
-nl_collapse_empty_body                   = false    # false/true
+nl_collapse_empty_body                   = true     # false/true
 
 # Don't split one-line braced assignments - 'foo_t f = { 1, 2 };'
 # WARNING: Code doesn't seem to use this feature - delete from the config?
-nl_assign_leave_one_liners               = false    # false/true
+nl_assign_leave_one_liners               = true     # false/true
 
 # Don't split one-line braced statements inside a class xx { } body
 # WARNING: Code doesn't seem to use this feature - delete from the config?
-nl_class_leave_one_liners                = false    # false/true
+nl_class_leave_one_liners                = true     # false/true
 
 # Don't split one-line enums: 'enum foo { BAR = 15 };'
 # WARNING: Code doesn't seem to use this feature - delete from the config?
-nl_enum_leave_one_liners                 = false    # false/true
+nl_enum_leave_one_liners                 = true     # false/true
 
 # Don't split one-line get or set functions
 # WARNING: Code doesn't seem to use this feature - delete from the config?
-nl_getset_leave_one_liners               = false    # false/true
+nl_getset_leave_one_liners               = true     # false/true
 
 # Don't split one-line function definitions - 'int foo() { return 0; }'
 nl_func_leave_one_liners                 = true     # false/true
@@ -1200,7 +1200,7 @@ nl_switch_brace                          = add      # ignore/add/remove/force
 nl_multi_line_cond                       = false    # false/true
 
 # Force a newline in a define after the macro name for multi-line defines.
-nl_multi_line_define                     = false    # false/true
+nl_multi_line_define                     = true     # false/true
 
 # Whether to put a newline before 'case' statement
 nl_before_case                           = false    # false/true
@@ -1307,7 +1307,7 @@ nl_fdef_brace                            = add      # ignore/add/remove/force
 nl_return_expr                           = remove   # ignore/add/remove/force
 
 # Whether to put a newline after semicolons, except in 'for' statements
-nl_after_semicolon                       = false    # false/true
+nl_after_semicolon                       = true     # false/true
 
 # Whether to put a newline after brace open.
 # This also adds a newline before the matching brace close.
@@ -1340,7 +1340,7 @@ nl_after_vbrace_close                    = false    # false/true
 nl_brace_struct_var                      = remove   # ignore/add/remove/force
 
 # Whether to alter newlines in '#define' macros
-nl_define_macro                          = false    # false/true
+nl_define_macro                          = true     # false/true
 
 # Whether to not put blanks after '#ifxx', '#elxx', or before '#endif'
 nl_squeeze_ifdef                         = false    # false/true
@@ -1390,7 +1390,7 @@ nl_class_colon                           = ignore   # ignore/add/remove/force
 
 # Change simple unbraced if statements into a one-liner
 # 'if(b)\n i++;' => 'if(b) i++;'
-nl_create_if_one_liner                   = false    # false/true
+nl_create_if_one_liner                   = true     # false/true
 
 # Change simple unbraced for statements into a one-liner
 # 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);'
@@ -1436,7 +1436,7 @@ pos_class_colon                          = ignore   # ignore/join/lead/lead_brea
 #
 
 # Try to limit code width to N number of columns
-code_width                               = 0        # number
+code_width                               = 120      # number
 
 # Whether to fully split long 'for' statements at semi-colons
 # WARNING: Code doesn't seem to use this feature - delete from the config?
@@ -1636,7 +1636,7 @@ mod_sort_using                           = false    # false/true
 
 # If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C]
 # This is generally a bad idea, as it may break your code.
-mod_sort_include                         = false    # false/true
+mod_sort_include                         = false     # false/true
 
 # If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace.
 # WARNING: Code doesn't seem to use this feature - delete from the config?
@@ -1645,7 +1645,7 @@ mod_move_case_break                      = false    # false/true
 # Will add or remove the braces around a fully braced case statement.
 # Will only remove the braces if there are no variable declarations in the block.
 # NOTE: is 78 worse than ignore
-mod_case_brace                           = remove   # ignore/add/remove/force
+mod_case_brace                           = add      # ignore/add/remove/force
 
 # If TRUE, it will remove a void 'return;' that appears as the last statement in a function.
 mod_remove_empty_return                  = true     # false/true #force
@@ -1696,7 +1696,7 @@ cmt_cpp_to_c                             = false    # false/true
 
 # Whether to put a star on subsequent comment lines
 # WARNING: Code doesn't seem to use this feature - delete from the config?
-cmt_star_cont                            = false    # false/true
+cmt_star_cont                            = true     # false/true
 
 # The number of spaces to insert at the start of subsequent comment lines
 # WARNING: Code doesn't seem to use this feature - delete from the config?
@@ -1748,14 +1748,14 @@ cmt_insert_before_preproc                = false    # false/true
 
 # Control indent of preprocessors inside #if blocks at brace level 0
 # WARNING: Indifferent... please decide manually.
-pp_indent                                = ignore   # ignore/add/remove/force
+pp_indent                                = force    # ignore/add/remove/force
 
 # Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false)
 pp_indent_at_level                       = false    # false/true
 
 # If pp_indent_at_level=false, specifies the number of columns to indent per level. Default=1.
 # WARNING: Code doesn't seem to use this feature - delete from the config?
-pp_indent_count                          = 0        # number
+pp_indent_count                          = 4        # number
 
 # Add or remove space after # based on pp_level of #if blocks
 # NOTE: is 28 worse than ignore
@@ -1771,14 +1771,14 @@ pp_indent_region                         = 0        # number
 
 # Whether to indent the code between #region and #endregion
 # WARNING: Code doesn't seem to use this feature - delete from the config?
-pp_region_indent_code                    = false    # false/true
+pp_region_indent_code                    = true    # false/true
 
 # If pp_indent_at_level=true, sets the indent for #if, #else, and #endif when not at file-level
 # WARNING: Code doesn't seem to use this feature - delete from the config?
-pp_indent_if                             = 0        # number
+pp_indent_if                             = 4        # number
 
 # Control whether to indent the code between #if, #else and #endif when not at file-level
-pp_if_indent_code                        = false    # false/true
+pp_if_indent_code                        = true    # false/true
 
 # Whether to indent '#define' at the brace level (true) or from column 1 (false)
 pp_define_at_level                       = true     # false/true
@@ -1788,11 +1788,15 @@ pp_define_at_level                       = true     # false/true
 # type myfoo1 myfoo2
 
 type void
+type bool
+type int
 type float
 type vector
 type entity
 type string
 type .void
+type .bool
+type .int
 type .float
 type .vector
 type .entity
@@ -1809,7 +1813,7 @@ type .string
 # You can assign any keyword to any type with the set option.
 # set func_call_user _ N_
 
-# menu QC OO
+# QC OO
 macro-open CLASS
 macro-else EXTENDS
 macro-close ENDCLASS
index 2df39aa3a83c904623621483762ca4722a1f4415..b36953e366231db2192a145697470e6fa5d016a4 100755 (executable)
@@ -3,7 +3,7 @@ fix_function_types() {
        #  void(void) func;
        # ) wrong and removes the space between type and variable. Fix this by
        # a simple sed on ")letter" which should normally not occur.
-       sed -e 's/)\([A-Za-z0-9]\)/) \1/g' "$@"
+       sed -e 's/)\([A-Za-z_]\)/) \1/g' "$@"
 }
 
 if [ -z "$UNCRUSTIFY_CONFIG" ]; then
@@ -16,7 +16,7 @@ case "$#" in
                fix_function_types
                ;;
        *)
-               uncrustify --replace --no-backup -c "$UNCRUSTIFY_CONFIG" "$@" &&\
+               uncrustify --replace --no-backup -c "$UNCRUSTIFY_CONFIG" "$@" ;\
                fix_function_types -i "$@"
                ;;
 esac
diff --git a/quickmenu_example.txt b/quickmenu_example.txt
new file mode 100644 (file)
index 0000000..6f97e28
--- /dev/null
@@ -0,0 +1,36 @@
+// This quickmenu example file can be loaded by setting
+// hud_panel_quickmenu_file quickmenu_example.txt
+// and executing "quickmenu file"
+// For more options see "quickmenu help"
+
+"Chat"
+       "nice one" "say :-) / nice one"
+       "good game" "say good game"
+       "hi / good luck" "say hi / good luck and have fun"
+"Chat"
+
+"Settings"
+       // nested submenu
+       "Sound settings"
+               "Hit sound" "toggle cl_hitsound"
+               "Chat sound" "toggle cl_chatsound"
+       "Sound settings"
+
+       // A toggle command displays a checkbox showing the current cvar's state
+       "enable 3rd person view" "toggle chase_active"
+       // it's possible to invert the meaning of the checkbox by inverting the
+       // parameters of toggle from the implicit 1 0 to 0 1
+       "disable 3rd person view" "toggle chase_active 0 1"
+"Settings"
+
+"screenshot" "wait; screenshot"
+
+// Commands that accept a player's name as parameter (%s), followed by one of
+// these special keywords:
+//   ALLPLAYERS_BUT_ME
+//   ALLPLAYERS
+//   OWNTEAMPLAYERS_BUT_ME
+//   OWNTEAMPLAYERS
+//   ENEMYTEAMPLAYERS
+// lets you pick a player's name from a list:
+"private chat with:" "commandmode tell \"%s\"" ALLPLAYERS_BUT_ME