From: Mario Date: Tue, 22 Jan 2013 10:02:56 +0000 (+1100) Subject: Monsters! X-Git-Tag: xonotic-v0.8.0~241^2^2~583 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=a9b5deb6fe07db043c93c734186fb09394105f9a;p=xonotic%2Fxonotic-data.pk3dir.git Monsters! --- diff --git a/balanceXonotic.cfg b/balanceXonotic.cfg index 871b9a390..6e65eced5 100644 --- a/balanceXonotic.cfg +++ b/balanceXonotic.cfg @@ -15,6 +15,7 @@ set g_start_weapon_porto -1 "0 = never provide the weapon, 1 = always provide th set g_start_weapon_hook -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default" set g_start_weapon_tuba -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default" set g_start_weapon_fireball -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default" +set g_start_weapon_incubator -1 "0 = never provide the weapon, 1 = always provide the weapon, -1 = game mode default" set g_balance_health_start 100 set g_balance_armor_start 0 set g_start_ammo_shells 15 diff --git a/commands.cfg b/commands.cfg index 44fa671bd..091cf49ee 100644 --- a/commands.cfg +++ b/commands.cfg @@ -152,6 +152,7 @@ alias reportcvar "qc_cmd_cmd reportcvar ${* ?}" // Old sy alias selectteam "qc_cmd_cmd selectteam ${* ?}" // Attempt to choose a team to join into alias selfstuff "qc_cmd_cmd selfstuff ${* ?}" // Stuffcmd a command to your own client alias sentcvar "qc_cmd_cmd sentcvar ${* ?}" // New system for sending a client cvar to the server +alias spawnmob "qc_cmd_cmd mobspawn ${* ?}" // Spawn a monster infront of the player alias spectate "qc_cmd_cmd spectate ${* ?}" // Become an observer alias suggestmap "qc_cmd_cmd suggestmap ${* ?}" // Suggest a map to the mapvote at match end //alias tell "qc_cmd_cmd tell ${* ?}" // Send a message directly to a player @@ -170,6 +171,9 @@ alias spec "spectate" // mutator aliases alias sandbox "cmd g_sandbox ${* ?}" +alias spawnturret "cmd turretspawn ${* ?}" +alias debugmonsters "cmd debugmonsters ${* ?}" +alias upgradeturret "cmd buffturret ${* ?}" // ============================================================ @@ -181,6 +185,7 @@ alias allspec "qc_cmd_sv allspec ${* ?}" // Force alias anticheat "qc_cmd_sv anticheat ${* ?}" // Create an anticheat report for a client alias bbox "qc_cmd_sv bbox ${* ?}" // Print detailed information about world size alias bot_cmd "qc_cmd_sv bot_cmd ${* ?}" // Control and send commands to bots +alias butcher "qc_cmd_sv butcher ${* ?}" // Remove all monsters on the map alias cointoss "qc_cmd_sv cointoss ${* ?}" // Flip a virtual coin and give random result alias database "qc_cmd_sv database ${* ?}" // Extra controls of the serverprogs database alias defer_clear "qc_cmd_sv defer_clear ${* ?}" // Clear all queued defer commands for a specific client diff --git a/defaultXonotic.cfg b/defaultXonotic.cfg index 1ad85c8bd..fc397ca7a 100644 --- a/defaultXonotic.cfg +++ b/defaultXonotic.cfg @@ -1388,6 +1388,7 @@ set g_weaponreplace_minstanex "" set g_weaponreplace_hook "" set g_weaponreplace_tuba "" set g_weaponreplace_fireball "" +set g_weaponreplace_incubator "" set sv_q3acompat_machineshotgunswap 0 "shorthand for swapping uzi and shotgun (for Q3A map compatibility in mapinfo files)" set g_movement_highspeed 1 "movement speed modification factor (only changes movement when above maxspeed)" @@ -1546,6 +1547,8 @@ exec turrets.cfg exec vehicles.cfg exec crosshairs.cfg exec gamemodes.cfg +exec monsters.cfg +exec za.cfg // load console command aliases and settings exec commands.cfg diff --git a/gamemodes.cfg b/gamemodes.cfg index 6cff7e5a4..94926ebaa 100644 --- a/gamemodes.cfg +++ b/gamemodes.cfg @@ -38,6 +38,7 @@ alias cl_hook_gamestart_nb alias cl_hook_gamestart_cts alias cl_hook_gamestart_ka alias cl_hook_gamestart_ft +alias cl_hook_gamestart_td alias cl_hook_gameend alias cl_hook_activeweapon @@ -60,6 +61,7 @@ alias sv_hook_gamestart_nb alias sv_hook_gamestart_cts alias sv_hook_gamestart_ka alias sv_hook_gamestart_ft +alias sv_hook_gamestart_td alias sv_hook_gamerestart alias sv_hook_gameend @@ -141,6 +143,9 @@ set g_cts_weapon_stay 2 set g_ft_respawn_waves 0 set g_ft_respawn_delay 0 set g_ft_weapon_stay 0 +set g_td_respawn_waves 0 +set g_td_respawn_delay 0 +set g_td_weapon_stay 0 // ======= @@ -472,3 +477,30 @@ set g_balance_rune_speed_highspeed 1.5 set g_balance_curse_slow_highspeed 0.6 set g_balance_rune_speed_combo_highspeed 0.9 +// =============== +// tower defense +// =============== +set g_td 0 "Tower Defense: protect the generator/s from waves of monsters" +set g_td_force_settings 0 "if enabled, don't use map settings (monster count, start wave etc.)" +set g_td_start_wave 1 +set g_td_generator_health 700 +set g_td_generator_damaged_points 20 "player loses this many points if the generator was damaged during the wave" +set g_td_current_monsters 10 "maximum monsters that can be spawned simultaneously" +set g_td_miniboss_min_monsters 5 "monster count to start spawning minibosses at" +set g_td_monster_count 10 +set g_td_monster_count_increment 5 +set g_td_hardcore 0 "if enabled, players can't respawn during combat phase" +set g_td_buildphase_time 20 +set g_td_generator_dontend 0 "don't change maps when a generator is destroyed (only if there is more than 1 generator)" +set g_td_pvp 0 +set g_td_monsters_skill_start 1 +set g_td_monsters_skill_increment 0.1 +set g_td_monster_spawn_protection_radius 300 +set g_td_max_waves 8 +set g_td_kill_points 5 +set g_td_turretkill_points 3 +set g_td_turret_max 4 +set g_td_turret_plasma_cost 50 +set g_td_turret_mlrs_cost 80 +set g_td_turret_walker_cost 100 +set g_td_tower_buff_cost 70 diff --git a/models/monsters/demon.mdl b/models/monsters/demon.mdl new file mode 100644 index 000000000..d2a566b5b Binary files /dev/null and b/models/monsters/demon.mdl differ diff --git a/models/monsters/demon.mdl.framegroups b/models/monsters/demon.mdl.framegroups new file mode 100644 index 000000000..b87a0876f --- /dev/null +++ b/models/monsters/demon.mdl.framegroups @@ -0,0 +1 @@ +1 12 10 1 // demon stand 14 7 10 1 // demon walk 22 5 10 1 // demon run 28 11 10 0 // demon leap 40 5 10 0 // demon pain 46 8 10 0 // demon death 55 14 10 1 // demon melee \ No newline at end of file diff --git a/models/monsters/demon.txt b/models/monsters/demon.txt new file mode 100644 index 000000000..fa603367e --- /dev/null +++ b/models/monsters/demon.txt @@ -0,0 +1,25 @@ +Fiendish Deamon Doll model + +Copyright (C) 2003 Ulrich Gablraith + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +History: + +7-5-04 + +The model was given to Mapes so he could port it into OpenQuartz by permission. + +Greg Mapes \ No newline at end of file diff --git a/models/monsters/dog.dpm b/models/monsters/dog.dpm new file mode 100644 index 000000000..e2201581b Binary files /dev/null and b/models/monsters/dog.dpm differ diff --git a/models/monsters/dog.dpm.framegroups b/models/monsters/dog.dpm.framegroups new file mode 100644 index 000000000..9ace1c472 --- /dev/null +++ b/models/monsters/dog.dpm.framegroups @@ -0,0 +1,11 @@ +/* +Generated framegroups file for dog +Used by DarkPlaces to simulate frame groups in DPM models. +*/ + +1 25 60 1 // dog idle +26 37 60 1 // dog walk +63 37 120 1 // dog run +100 50 60 1 // dog attack +150 42 60 0 // dog die +192 25 60 1 // dog pain diff --git a/models/monsters/dog.txt b/models/monsters/dog.txt new file mode 100644 index 000000000..4cd5ddeb9 --- /dev/null +++ b/models/monsters/dog.txt @@ -0,0 +1 @@ +This cerberus model is GPL 2.0 compatible (http://opengameart.org/content/animated-cerberus). \ No newline at end of file diff --git a/models/monsters/enforcer.mdl b/models/monsters/enforcer.mdl new file mode 100644 index 000000000..b52fe4f65 Binary files /dev/null and b/models/monsters/enforcer.mdl differ diff --git a/models/monsters/enforcer.mdl.framegroups b/models/monsters/enforcer.mdl.framegroups new file mode 100644 index 000000000..b767b2bf8 --- /dev/null +++ b/models/monsters/enforcer.mdl.framegroups @@ -0,0 +1 @@ +1 6 10 1 // enforcer stand 8 15 10 1 // enforcer walk 24 7 10 1 // enforcer run 32 9 10 1 // enforcer attack 42 13 10 0 // enforcer death1 56 10 10 0 // enforcer death2 67 3 10 0 // enforcer pain1 71 4 10 0 // enforcer pain2 76 7 10 0 // enforcer pain3 84 18 10 0 // enforcer pain4 \ No newline at end of file diff --git a/models/monsters/enforcer.txt b/models/monsters/enforcer.txt new file mode 100644 index 000000000..6a85459a2 --- /dev/null +++ b/models/monsters/enforcer.txt @@ -0,0 +1,28 @@ +Enforcer + +Copyright (C) 2004 Greg Mapes + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +7-7-04 +First Release: + +Greg Mapes + +7-11-04 + +The gun was a bit long and stuck through a lot of walls and other surfaces when it died, so it got revised. + +Greg Mapes diff --git a/models/monsters/fish.mdl b/models/monsters/fish.mdl new file mode 100644 index 000000000..e1db999bb Binary files /dev/null and b/models/monsters/fish.mdl differ diff --git a/models/monsters/fish.mdl.framegroups b/models/monsters/fish.mdl.framegroups new file mode 100644 index 000000000..bf18b81a6 --- /dev/null +++ b/models/monsters/fish.mdl.framegroups @@ -0,0 +1 @@ +1 17 10 1 // fish attack 19 19 10 0 // fish death 41 16 10 1 // fish swim 59 8 10 0 // fish pain \ No newline at end of file diff --git a/models/monsters/gpl.txt b/models/monsters/gpl.txt new file mode 100644 index 000000000..6bf61e7d5 --- /dev/null +++ b/models/monsters/gpl.txt @@ -0,0 +1 @@ +All the models in this folder (except zombie.dpm) were copied from the GPL project OpenQuartz 2 (http://www.quakewiki.net/openquartz-2). \ No newline at end of file diff --git a/models/monsters/hknight.mdl b/models/monsters/hknight.mdl new file mode 100644 index 000000000..a0cd4d7c7 Binary files /dev/null and b/models/monsters/hknight.mdl differ diff --git a/models/monsters/hknight.mdl.framegroups b/models/monsters/hknight.mdl.framegroups new file mode 100644 index 000000000..cc16b3089 --- /dev/null +++ b/models/monsters/hknight.mdl.framegroups @@ -0,0 +1 @@ +1 8 10 1 // hellknight stand 10 19 10 1 // hellknight walk 30 7 10 1 // hellknight run 38 4 10 0 // hellknight pain 43 11 10 0 // hellknight death1 55 8 10 0 // hellknight death2 64 15 10 0 // hellknight charge1 80 13 10 0 // hellknight magic1 94 12 10 0 // hellknight magic2 107 5 10 0 // hellknight charge2 113 9 10 1 // hellknight slice 123 9 10 1 // hellknight smash 133 21 10 1 // hellknight weapon attack 155 10 10 0 //hellknight magic3 \ No newline at end of file diff --git a/models/monsters/hknight.txt b/models/monsters/hknight.txt new file mode 100644 index 000000000..1dffdb709 --- /dev/null +++ b/models/monsters/hknight.txt @@ -0,0 +1,25 @@ +Hooded model + +Copyright (C) 2003 Ulrich Gablraith + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +History: + +7-5-04 + +The model was given to Mapes so he could port it into OpenQuartz by permission. + +Greg Mapes \ No newline at end of file diff --git a/models/monsters/knight.mdl b/models/monsters/knight.mdl new file mode 100644 index 000000000..36ebd6199 Binary files /dev/null and b/models/monsters/knight.mdl differ diff --git a/models/monsters/knight.mdl.framegroups b/models/monsters/knight.mdl.framegroups new file mode 100644 index 000000000..c4acc5e04 --- /dev/null +++ b/models/monsters/knight.mdl.framegroups @@ -0,0 +1 @@ +1 8 10 1 // knight stand 10 7 10 1 // knight run 18 10 10 1 // knight run attack 29 2 10 0 // knight pain1 32 10 10 0 // knight pain2 43 9 10 1 // knight attack 53 13 10 1 // knight walk 67 4 10 0 // knight kneel 72 4 10 1 // knight standing 77 9 10 0 // knight death1 88 10 10 0 // knight death2 \ No newline at end of file diff --git a/models/monsters/knight.txt b/models/monsters/knight.txt new file mode 100644 index 000000000..59cec6c97 --- /dev/null +++ b/models/monsters/knight.txt @@ -0,0 +1,25 @@ +Knight model + +Copyright (C) 2004 Ulrich Gablraith + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +History: + +7-5-04 + +The model was given to Mapes so he could port it into OpenQuartz by permission. + +Greg Mapes \ No newline at end of file diff --git a/models/monsters/monsters.txt b/models/monsters/monsters.txt new file mode 100644 index 000000000..9e55cb84e --- /dev/null +++ b/models/monsters/monsters.txt @@ -0,0 +1,31 @@ +Monsters -Phantom Knight, Magical Knight, Master Knight, Knight, Jack-o-Lantern, + -Doll Fiend. + +Copyright (C) 2004 Ulrich Galbraith + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Ulrich Galbraith +ugalbrai@krl.org + + +7-22-04 + +First release + +I had to give some of them proper animation and proper connecting models so they would work. + +-Mapes \ No newline at end of file diff --git a/models/monsters/ogre.mdl b/models/monsters/ogre.mdl new file mode 100644 index 000000000..a0cd4d7c7 Binary files /dev/null and b/models/monsters/ogre.mdl differ diff --git a/models/monsters/ogre.mdl.framegroups b/models/monsters/ogre.mdl.framegroups new file mode 100644 index 000000000..0d6938607 --- /dev/null +++ b/models/monsters/ogre.mdl.framegroups @@ -0,0 +1 @@ +1 8 10 1 // ogre stand 10 15 10 1 // ogre walk 26 7 10 1 // ogre run 34 13 10 1 // ogre swing 48 13 10 1 // ogre smash 62 5 10 1 // ogre shoot 68 4 10 0 // ogre pain1 73 2 10 0 // ogre pain2 76 5 10 0 // ogre pain3 82 15 10 0 // ogre pain4 98 14 10 0 // ogre pain5 113 13 10 0 // ogre death1 127 9 10 0 // ogre death2 137 10 10 0 // ogre pull \ No newline at end of file diff --git a/models/monsters/shalrath.mdl b/models/monsters/shalrath.mdl new file mode 100644 index 000000000..bfa4ec291 Binary files /dev/null and b/models/monsters/shalrath.mdl differ diff --git a/models/monsters/shalrath.mdl.framegroups b/models/monsters/shalrath.mdl.framegroups new file mode 100644 index 000000000..35108f53c --- /dev/null +++ b/models/monsters/shalrath.mdl.framegroups @@ -0,0 +1 @@ +1 10 10 1 // shalrath attack 12 4 10 0 // shalrath pain 18 5 10 0 // shalrath death 26 12 10 1 // shalrath walk \ No newline at end of file diff --git a/models/monsters/shambler.mdl b/models/monsters/shambler.mdl new file mode 100644 index 000000000..2e23dfa90 Binary files /dev/null and b/models/monsters/shambler.mdl differ diff --git a/models/monsters/shambler.mdl.framegroups b/models/monsters/shambler.mdl.framegroups new file mode 100644 index 000000000..b003d568d --- /dev/null +++ b/models/monsters/shambler.mdl.framegroups @@ -0,0 +1 @@ +1 16 10 1 // shambler stand 18 11 10 1 // shambler walk 31 5 10 1 // shambler run 37 11 10 1 // shambler smash 49 8 10 1 // shambler swing right 58 8 10 1 // shambler swing left 67 11 10 1 // shambler magic 79 5 10 0 // shambler pain 85 10 10 0 // shambler death \ No newline at end of file diff --git a/models/monsters/soldier.mdl b/models/monsters/soldier.mdl new file mode 100644 index 000000000..a0cd4d7c7 Binary files /dev/null and b/models/monsters/soldier.mdl differ diff --git a/models/monsters/soldier.mdl.framegroups b/models/monsters/soldier.mdl.framegroups new file mode 100644 index 000000000..0d6938607 --- /dev/null +++ b/models/monsters/soldier.mdl.framegroups @@ -0,0 +1 @@ +1 8 10 1 // ogre stand 10 15 10 1 // ogre walk 26 7 10 1 // ogre run 34 13 10 1 // ogre swing 48 13 10 1 // ogre smash 62 5 10 1 // ogre shoot 68 4 10 0 // ogre pain1 73 2 10 0 // ogre pain2 76 5 10 0 // ogre pain3 82 15 10 0 // ogre pain4 98 14 10 0 // ogre pain5 113 13 10 0 // ogre death1 127 9 10 0 // ogre death2 137 10 10 0 // ogre pull \ No newline at end of file diff --git a/models/monsters/spider.dpm b/models/monsters/spider.dpm new file mode 100644 index 000000000..d0bc9ce5f Binary files /dev/null and b/models/monsters/spider.dpm differ diff --git a/models/monsters/spider.dpm.framegroups b/models/monsters/spider.dpm.framegroups new file mode 100644 index 000000000..039a7c3ca --- /dev/null +++ b/models/monsters/spider.dpm.framegroups @@ -0,0 +1,9 @@ +/* +Generated framegroups file for spider +Used by DarkPlaces to simulate frame groups in DPM models. +*/ + +1 60 60 1 // spider idle +61 41 120 1 // spider walk +102 24 60 1 // spider attack +125 10 60 1 // spider attack2 \ No newline at end of file diff --git a/models/monsters/spider.txt b/models/monsters/spider.txt new file mode 100644 index 000000000..7d7cdafa2 --- /dev/null +++ b/models/monsters/spider.txt @@ -0,0 +1 @@ +This spider model is GPL 2.0 compatible (http://opengameart.org/content/low-poly-spider-glest). \ No newline at end of file diff --git a/models/monsters/tarbaby.mdl b/models/monsters/tarbaby.mdl new file mode 100644 index 000000000..db8c318f3 Binary files /dev/null and b/models/monsters/tarbaby.mdl differ diff --git a/models/monsters/tarbaby.mdl.framegroups b/models/monsters/tarbaby.mdl.framegroups new file mode 100644 index 000000000..7271df49f --- /dev/null +++ b/models/monsters/tarbaby.mdl.framegroups @@ -0,0 +1 @@ +1 24 10 1 // tarbaby walk 26 24 10 1 // tarbaby run 51 5 10 0 // tarbaby jump 57 3 10 1 // tarbaby fly 61 1 10 0 // tarbaby explode \ No newline at end of file diff --git a/models/monsters/wizard.mdl b/models/monsters/wizard.mdl new file mode 100644 index 000000000..b130ba031 Binary files /dev/null and b/models/monsters/wizard.mdl differ diff --git a/models/monsters/wizard.mdl.framegroups b/models/monsters/wizard.mdl.framegroups new file mode 100644 index 000000000..c51109aac --- /dev/null +++ b/models/monsters/wizard.mdl.framegroups @@ -0,0 +1 @@ +1 14 10 1 // wizard hover 16 13 10 1 // wizard fly 30 12 10 1 // wizard magic attack 43 3 10 0 // wizard pain 47 7 10 0 // wizard death \ No newline at end of file diff --git a/models/monsters/wizard.txt b/models/monsters/wizard.txt new file mode 100644 index 000000000..3b00ddefe --- /dev/null +++ b/models/monsters/wizard.txt @@ -0,0 +1,31 @@ +pterascragg model + +Copyright (C) 2000 Dylan "lithiumbat" Sartain + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +History: + +7-11-00 + +First release +build time: about 2 hrs spread over three days +model was made as a replacement for the scragg or wizard. + +7-13-00 + +Seth Galbraith (sgalbrai@krl.org): +Lowered death frame to lie on the ground +Created head gib model diff --git a/models/monsters/zombie.dpm_0.skin b/models/monsters/zombie.dpm_0.skin new file mode 100644 index 000000000..19ad7a727 --- /dev/null +++ b/models/monsters/zombie.dpm_0.skin @@ -0,0 +1,2 @@ +bloodyskull,bloodyskull +meat,meat \ No newline at end of file diff --git a/models/monsters/zombie.dpm_1.skin b/models/monsters/zombie.dpm_1.skin new file mode 100644 index 000000000..1561520d7 --- /dev/null +++ b/models/monsters/zombie.dpm_1.skin @@ -0,0 +1,2 @@ +bloodyskull,bloodyskull_alien +meat,meat_alien \ No newline at end of file diff --git a/models/monsters/zombie.dpm_2.skin b/models/monsters/zombie.dpm_2.skin new file mode 100644 index 000000000..e00379eff --- /dev/null +++ b/models/monsters/zombie.dpm_2.skin @@ -0,0 +1,2 @@ +bloodyskull,bloodyskull_robot +meat,meat_robot \ No newline at end of file diff --git a/monsters.cfg b/monsters.cfg new file mode 100644 index 000000000..5a9007bab --- /dev/null +++ b/monsters.cfg @@ -0,0 +1,210 @@ +// Misc +set g_monsters 1 "Enable monsters (master switch)" +set g_monsters_skill 1 "Monster skill (affecting some of their attributes). 1 - easy, 2 - medium, 3 - hard, 4 - insane, 5 - nightmare" +set g_monsters_miniboss_chance 5 +set g_monsters_miniboss_healthboost 100 +set g_monsters_forcedrop "" "Force all monsters to drop this item on death. Possible values are: health, armor, ammo" +set g_monsters_drop_size medium "Size of the item monsters drop. Possible health/amor values are: small, medium, large. Possible ammo values are: shells, bullets, cells, rockets" +set g_monsters_owners 1 "Monsters will not attack their owners if set to 1" +set g_monsters_teams 1 +set g_monster_spawnshieldtime 2 "Monsters will not take damage for this amount of seconds" +set g_monsters_typefrag 1 +set g_monsters_healthbars 1 "Show health bars above monsters" +set g_monsters_giants_only 0 +set g_monsters_nogiants 1 +set g_monsters_respawn 1 "Enable monster respawning" +set g_monsters_respawn_delay 20 "Monsters respawn in this amount of seconds" +set g_monsters_score_kill 1 "Get this many points for killing a naturally spawned monster" +set g_monsters_max 20 "Global maximum player-spawned monsters" +set g_monsters_max_perplayer 3 "Maximum monsters per-player" +set g_monsters_skill_easy 2 "Monster easy skill level (used for skill based functions)" +set g_monsters_skill_normal 4 "Monster normal skill level (used for skill based functions)" +set g_monsters_skill_hard 5 "Monster hard skill level (used for skill based functions)" +set g_monsters_skill_insane 7 "Monster insane skill level (used for skill based functions)" +set g_monsters_skill_nightmare 10 "Monster nightmare skill level (used for skill based functions)" + +// Enforcer +set g_monster_enforcer 1 "Enable Enforcers" +set g_monster_enforcer_health 80 "Enforcer health" +set g_monster_enforcer_drop armor "Enforcer drops this item on death" +set g_monster_enforcer_drop_size large "Size of the item Enforcers drop. Possible values are: small, medium, large" +set g_monster_enforcer_speed_walk 75 "Enforcer walk speed" +set g_monster_enforcer_speed_run 100 "Enforcer run speed" +set g_monster_enforcer_attack_uzi_bullets 3 "Number of machine gun bullets Enforcer fires" + +// Ogre +set g_monster_ogre 1 "Enable Ogres" +set g_monster_ogre_health 200 "Ogre health" +set g_monster_ogre_chainsaw_damage 15 "Ogre chainsaw damage (hits multiple times)" +set g_monster_ogre_drop ammo "Ogre drops this item on death" +set g_monster_ogre_drop_size bullets "Size of the item Ogres drop. Possible values are: small, medium, large" +set g_monster_ogre_speed_walk 100 "Ogre walk speed" +set g_monster_ogre_speed_run 150 "Ogre run speed" +set g_monster_ogre_attack_uzi_bullets 3 "Number of machine gun bullets Ogre fires" + +// Fiend +set g_monster_demon 1 "Enable Fiends" +set g_monster_demon_health 300 "Fiend health" +set g_monster_demon_attack_jump_damage 40 "Fiend jump attack damage" +set g_monster_demon_damage 20 "Fiend melee attack damage" +set g_monster_demon_drop health "Fiend drops this item on death" +set g_monster_demon_drop_size medium "Size of the item Fiends drop. Possible values are: small, medium, large" +set g_monster_demon_speed_walk 150 "Fiend walk speed" +set g_monster_demon_speed_run 300 "Fiend run speed" + +// Shambler +set g_monster_shambler 1 "Enable Shamblers" +set g_monster_shambler_health 600 "Shambler health" +set g_monster_shambler_damage 50 "Shambler melee attack damage" +set g_monster_shambler_attack_lightning_damage 20 "Shambler lightning attack damage per frame" +set g_monster_shambler_attack_claw_damage 30 "Shambler claw attack damage" +set g_monster_shambler_drop health "Shambler drops this item on death" +set g_monster_shambler_drop_size large "Size of the item Shamblers drop. Possible values are: small, medium, large" +set g_monster_shambler_speed_walk 100 "Shambler walk speed" +set g_monster_shambler_speed_run 150 "Shambler run speed" + +// Knight +set g_monster_knight 1 "Enable Knights" +set g_monster_knight_health 75 "Knight Health" +set g_monster_knight_drop armor "Knight drops this item on death" +set g_monster_knight_drop_size medium "Size of the item Knights drop. Possible values are: small, medium, large" +set g_monster_knight_melee_damage 20 "Knight melee attack damage" +set g_monster_knight_melee_side_damage 10 "Knight melee attack side damage" +set g_monster_knight_speed_walk 40 "Knight walk speed" +set g_monster_knight_speed_run 70 "Knight run speed" + +// Grunt +set g_monster_soldier 1 "Enable Grunts" +set g_monster_soldier_health 100 "Grunt Health" +set g_monster_soldier_drop ammo "Grunt drops this item on death" +set g_monster_soldier_drop_size shells "Size of the item Grunts drop. Possible values are: small, medium, large" +set g_monster_soldier_melee_damage 20 "Grunt melee attack damage" +set g_monster_soldier_speed_walk 30 "Grunt walk speed" +set g_monster_soldier_speed_run 50 "Grunt run speed" +set g_monster_soldier_ammo 5 "Grunt weapon ammo" +set g_monster_soldier_weapon_laser_chance 6 "Chance of Grunt weapon being laser" +set g_monster_soldier_weapon_shotgun_chance 8 "Chance of Grunt weapon being shotgun" +set g_monster_soldier_weapon_machinegun_chance 4 "Chance of Grunt weapon being machine gun" +set g_monster_soldier_weapon_rocketlauncher_chance 2 "Chance of Grunt weapon being rocket launcher" +set g_monster_soldier_attack_uzi_bullets 3 "Number of machine gun bullets Grunt fires" + +// Scrag +set g_monster_wizard 1 "Enable Scrags" +set g_monster_wizard_health 80 "Scrag health" +set g_monster_wizard_drop ammo "Scrag drops this item on death" +set g_monster_wizard_drop_size cells "Size of the item Scrags drop. Possible values are: small, medium, large" +set g_monster_wizard_speed_walk 40 "Scrag walk speed" +set g_monster_wizard_speed_run 70 "Scrag run speed" +set g_monster_wizard_spike_damage 15 "Scrag spike damage" +set g_monster_wizard_spike_damage 7 "Scrag spike edge damage" +set g_monster_wizard_spike_radius 20 "Scrag spike damage radius" +set g_monster_wizard_spike_speed 400 "Scrag spike speed" + +// Rottweiler +set g_monster_dog 1 "Enable Rottweilers" +set g_monster_dog_health 25 "Rottweiler health" +set g_monster_dog_bite_damage 15 "Rottweiler bite attack damage" +set g_monster_dog_attack_jump_damage 30 "Rottweiler jump attack damage" +set g_monster_dog_drop health "Rottweiler drops this item on death" +set g_monster_dog_drop_size small "Size of the item Rottweilers drop. Possible values are: small, medium, large" +set g_monster_dog_speed_walk 60 "Rottweiler walk speed" +set g_monster_dog_speed_run 120 "Rottweiler run speed" + +// Spawn +set g_monster_tarbaby 1 "Enable Spawns" +set g_monster_tarbaby_health 80 "Spawn health" +set g_monster_tarbaby_drop ammo "Spawn drops this item when it explodes" +set g_monster_tarbaby_drop_size rockets "Size of the item Spawns drop. Possible values are: small, medium, large" +set g_monster_tarbaby_speed_walk 20 "Spawn walk speed" +set g_monster_tarbaby_speed_run 30 "Spawn run speed" + +// Hell-Knight +set g_monster_hellknight 1 "Enable Hell-Knights" +set g_monster_hellknight_health 250 "Hell-Knight health" +set g_monster_hellknight_drop armor "Hell-Knight drops this item on death" +set g_monster_hellknight_drop_size medium "Size of the item Hell-Knights drop. Possible values are: small, medium, large" +set g_monster_hellknight_inferno_damage 40 "Hell-Knight inferno damage" +set g_monster_hellknight_inferno_chance 0.4 "Hell-Knight inferno attack chance" +set g_monster_hellknight_inferno_damagetime 3 "How long the inferno should burn the player" +set g_monster_hellknight_fireball_damage 30 "Hell-Knight fireball projectile damage" +set g_monster_hellknight_fireball_edgedamage 10 "Hell-Knight fireball indirect hit damage" +set g_monster_hellknight_fireball_force 50 "Hell-Knight fireball projectile push force" +set g_monster_hellknight_fireball_radius 70 "Hell-Knight fireball projectile damage radius" +set g_monster_hellknight_fireball_speed 600 "Hell-Knight fireball projectile speed" +set g_monster_hellknight_fireball_spread 0 "Hell-Knight fireball projectile spread" +set g_monster_hellknight_fireball_chance 0.3 "Chance for Hell-Knight to throw a fireball" +set g_monster_hellknight_jump_chance 0.2 "Chance for Hell-Knight to jump at the player (always 1 if enemy is further than _dist)" +set g_monster_hellknight_jump_damage 25 "Hell-Knight jump attack damage" +set g_monster_hellknight_jump_dist 500 "Hell-Knight will prioritise jumping if the enemy is this far away" +set g_monster_hellknight_melee_damage 20 "Hell-Knight melee attack damage" +set g_monster_hellknight_spike_damage 5 "Hell-Knight spike projectile damage" +set g_monster_hellknight_spike_edgedamage 5 "Hell-Knight spike projectile indirect hit damage" +set g_monster_hellknight_spike_radius 20 "Hell-Knight spike projectile damage radius" +set g_monster_hellknight_spike_force 5 "Hell-Knight spike projectile force" +set g_monster_hellknight_spike_chance 0.5 "Hell-Knight spike attack chance" +set g_monster_hellknight_speed_walk 75 "Hell-Knight walk speed" +set g_monster_hellknight_speed_run 150 "Hell-Knight run speed" + +// Rotfish +set g_monster_fish 1 "Enable Rotfish" +set g_monster_fish_health 25 "Rotfish health" +set g_monster_fish_damage 10 "Rotfish bite attack damage" +set g_monster_fish_drop health "Rotfish drops this item on death" +set g_monster_fish_drop_size small "Size of the item Rotfish drop. Possible values are: small, medium, large" +set g_monster_fish_speed_walk 40 "Rotfish walk speed" +set g_monster_fish_speed_run 70 "Rotfish run speed" + +// Vore +set g_monster_shalrath 1 "Enable Vores" +set g_monster_shalrath_health 400 "Vore health" +set g_monster_shalrath_damage 30 "Vore magic attack damage" +set g_monster_shalrath_drop health "Vore drops this item on death" +set g_monster_shalrath_drop_size medium "Size of the item Vores drop. Possible values are: small, medium, large" +set g_monster_shalrath_speed 50 "Vore move speed" + +// Spawner +set g_monster_spawner 1 "Enable Monster Spawner" +set g_monster_spawner_health 100 "Spawner health" +set g_monster_spawner_target_recheck_delay 1 "Spawner enemy check delay" +set g_monster_spawner_target_range 600 "Spawner maximum enemy distance" +set g_monster_spawner_spawn_range 600 "Spawn monsters while enemy is within this range" +set g_monster_spawner_maxmobs 4 "Maximum number of spawned monsters" +set g_monster_spawner_forcespawn 0 "Force spawner to spawn this type of monster" + +// Zombie +set g_monster_zombie 1 "Enable Zombies" +set g_monster_zombie_attack_leap_damage 45 "Damage when zombie performs an attack leap" +set g_monster_zombie_attack_leap_delay 1.5 "Delay after zombie attack leap" +set g_monster_zombie_attack_leap_force 55 "Force of zombie attack leap" +set g_monster_zombie_attack_leap_range 96 "Range of zombie attack leap" +set g_monster_zombie_attack_leap_speed 500 "The speed of a zombie attack leap" +set g_monster_zombie_attack_stand_damage 35 "Damage when zombie hits from a standing position" +set g_monster_zombie_attack_stand_delay 1.2 "Delay after a zombie hits from a standing position" +set g_monster_zombie_attack_stand_range 48 "Range of a zombie standing position attack" +set g_monster_zombie_health 200 "Zombie health" +set g_monster_zombie_idle_timer 1 "Minimum time a zombie can stay idle" +set g_monster_zombie_speed_walk 150 "Zombie walk speed" +set g_monster_zombie_speed_run 400 "Zombie run speed" +set g_monster_zombie_stopspeed 100 "Speed at which zombie stops" +set g_monster_zombie_target_recheck_delay 5 How much time should a zombie run afer an enemy before checking if it's still in range" +set g_monster_zombie_target_range 1200 How far the zombie can see an enemy" +set g_monster_zombie_drop health "Zombie drops this item on death" +set g_monster_zombie_drop_size large "Size of the item zombies drop. Possible values are: small, medium, large" + +// Spider +set g_monster_spider 1 "Enable Spiders" +set g_monster_spider_attack_type 0 "Spider attack type (0 = ice, 1 = fire, ...)" +set g_monster_spider_attack_leap_delay 1.5 "Delay after spider attack leap" +set g_monster_spider_attack_leap_range 96 "Range of spider attack leap" +set g_monster_spider_attack_stand_damage 35 "Damage when spider hits from a standing position" +set g_monster_spider_attack_stand_delay 1.2 "Delay after a spider hits from a standing position" +set g_monster_spider_attack_stand_range 48 "Range of a spider standing position attack" +set g_monster_spider_health 200 "Spider health" +set g_monster_spider_idle_timer_min 1 "Minimum time a spider can stay idle" +set g_monster_spider_speed_walk 150 "Spider walk speed" +set g_monster_spider_speed_run 400 "Spider run speed" +set g_monster_spider_stopspeed 100 Speed at which spider stops" +set g_monster_spider_target_recheck_delay 5 How much time should a spider run afer an enemy before checking if it's still in range" +set g_monster_spider_target_range 1200 How far the spider can see an enemy" +set g_monster_spider_drop health "Spider drops this item on death" +set g_monster_spider_drop_size large "Size of the item spiders drop. Possible values are: small, medium, large" \ No newline at end of file diff --git a/qcsrc/client/hud.qc b/qcsrc/client/hud.qc index cc870794b..987da3bfc 100644 --- a/qcsrc/client/hud.qc +++ b/qcsrc/client/hud.qc @@ -1978,7 +1978,74 @@ void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) // s } } } - } else if (type == DEATH_CUSTOM) { + } else if(DEATH_ISMONSTER(type)) { + HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC); + if(alsoprint) + { + if(gentle) + print (sprintf(_("^1%s^1 hit a monster, and the monster hit back\n"), s1)); + else + { + switch(type) + { + case DEATH_MONSTER_DEMON_MELEE: + print (sprintf(_("^1%s^1 was eviscerated by a Fiend \n"), s1)); + break; + case DEATH_MONSTER_DEMON_JUMP: + print (sprintf(_("^1%s^1 didn't see the Fiend pouncing at them \n"), s1)); + break; + case DEATH_MONSTER_SHAMBLER_MELEE: + print (sprintf(_("^1%s^1 was smashed by a Shambler \n"), s1)); + break; + case DEATH_MONSTER_SHAMBLER_CLAW: + print (sprintf(_("^1%s^1's insides were ripped out by a Shambler \n"), s1)); + break; + case DEATH_MONSTER_SHAMBLER_LIGHTNING: + print (sprintf(_("^1%s^1 was zapped to death by a Shambler \n"), s1)); + break; + case DEATH_MONSTER_SOLDIER_NAIL: + print (sprintf(_("^1%s^1 was riddled full of holes by a Soldier \n"), s1)); + break; + case DEATH_MONSTER_ENFORCER_NAIL: + print (sprintf(_("^1%s^1 was riddled full of holes by an Enforcer \n"), s1)); + break; + case DEATH_MONSTER_DOG_BITE: + print (sprintf(_("^1%s^1 was mauled by a Rottweiler \n"), s1)); + break; + case DEATH_MONSTER_DOG_JUMP: + print (sprintf(_("^1%s^1 didn't see the pouncing Rottweiler \n"), s1)); + break; + case DEATH_MONSTER_TARBABY_BLOWUP: + print (sprintf(_("^1%s^1 was slimed by a Spawn \n"), s1)); + break; + case DEATH_MONSTER_FISH_BITE: + print (sprintf(_("^1%s^1 was fed to the Rotfish \n"), s1)); + break; + case DEATH_MONSTER_HELLFISH_BITE: + print (sprintf(_("^1%s^1 was eaten alive by a Hellfish \n"), s1)); + break; + case DEATH_MONSTER_SHALRATH_MELEE: + print (sprintf(_("^1%s^1 was exploded by a Vore \n"), s1)); + break; + case DEATH_MONSTER_OGRE_CHAINSAW: + print (sprintf(_("^1%s^1 was destroyed by an Ogre \n"), s1)); + break; + case DEATH_MONSTER_OGRE_NAIL: + print (sprintf(_("^1%s^1 was riddled full of holes by an Ogre \n"), s1)); + break; + case DEATH_MONSTER_ZOMBIE: + print (sprintf(_("^1%s^1's brains were eaten by a Zombie \n"), s1)); + break; + case DEATH_MONSTER_HELLKNIGHT_FIREBALL: + print (sprintf(_("^1%s^1 was exploded by a Hell-Knight's fireball \n"), s1)); + case DEATH_MONSTER_MELEE: + print (sprintf(_("^1%s^1 was killed by a monster \n"), s1)); + break; + } + } + } + } + else if (type == DEATH_CUSTOM) { HUD_KillNotify_Push(s1, "", 0, DEATH_CUSTOM); if(alsoprint) print("^1", sprintf(s2, strcat(s1, "^1")), "\n"); diff --git a/qcsrc/client/scoreboard.qc b/qcsrc/client/scoreboard.qc index af982ad46..134987fe8 100644 --- a/qcsrc/client/scoreboard.qc +++ b/qcsrc/client/scoreboard.qc @@ -1083,15 +1083,30 @@ vector HUD_DrawKeyValue(vector pos, string key, string value) { vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) { float stat_secrets_found, stat_secrets_total; - float rows; + float stat_current_wave, stat_totalwaves; + float stat_monsters_killed, stat_monsters_total; + float rows = 0; string val; + + // get tower defense stats + stat_current_wave = getstatf(STAT_CURRENT_WAVE); + stat_totalwaves = getstatf(STAT_TOTALWAVES); + + // get monster stats + stat_monsters_killed = getstatf(STAT_MONSTERS_KILLED); + stat_monsters_total = getstatf(STAT_MONSTERS_TOTAL); // get secrets stats stat_secrets_found = getstatf(STAT_SECRETS_FOUND); stat_secrets_total = getstatf(STAT_SECRETS_TOTAL); // get number of rows - rows = (stat_secrets_total ? 1 : 0); + if(stat_secrets_total) + rows += 1; + if(stat_totalwaves) + rows += 1; + if(stat_monsters_total) + rows += 1; // if no rows, return if not(rows) @@ -1111,10 +1126,27 @@ vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) { else drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, scoreboard_alpha_bg, DRAWFLAG_NORMAL); drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL); + + // draw waves + if(stat_totalwaves) + { + val = sprintf("%d/%d", stat_current_wave, stat_totalwaves); + pos = HUD_DrawKeyValue(pos, _("Current wave:"), val); + } + + // draw monsters + if(stat_monsters_total) + { + val = sprintf("%d/%d", stat_monsters_killed, stat_monsters_total); + pos = HUD_DrawKeyValue(pos, _("Monsters killed:"), val); + } // draw secrets - val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total); - pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val); + if(stat_secrets_total) + { + val = sprintf("%d/%d", stat_secrets_found, stat_secrets_total); + pos = HUD_DrawKeyValue(pos, _("Secrets found:"), val); + } // update position pos_y += 1.25 * hud_fontsize_y; diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index 75f5a0bde..133da188e 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -181,6 +181,12 @@ const float STAT_SECRETS_FOUND = 71; const float STAT_RESPAWN_TIME = 72; +const float STAT_CURRENT_WAVE = 73; +const float STAT_TOTALWAVES = 74; + +const float STAT_MONSTERS_TOTAL = 75; +const float STAT_MONSTERS_KILLED = 76; + // mod stats (1xx) const float STAT_REDALIVE = 100; const float STAT_BLUEALIVE = 101; @@ -427,6 +433,28 @@ float DEATH_TURRET_PHASER = 10511; float DEATH_TURRET_TESLA = 10512; float DEATH_TURRET_LAST = 10512; +// Monster death types +float DEATH_MONSTER = 10513; +float DEATH_MONSTER_DEMON_MELEE = 10514; +float DEATH_MONSTER_DEMON_JUMP = 10515; +float DEATH_MONSTER_SHAMBLER_MELEE = 10516; +float DEATH_MONSTER_SHAMBLER_CLAW = 10517; +float DEATH_MONSTER_SHAMBLER_LIGHTNING = 10518; +float DEATH_MONSTER_SOLDIER_NAIL = 10519; +float DEATH_MONSTER_ENFORCER_NAIL = 10520; +float DEATH_MONSTER_DOG_BITE = 10521; +float DEATH_MONSTER_DOG_JUMP = 10522; +float DEATH_MONSTER_TARBABY_BLOWUP = 10523; +float DEATH_MONSTER_FISH_BITE = 10524; +float DEATH_MONSTER_HELLFISH_BITE = 10525; +float DEATH_MONSTER_SHALRATH_MELEE = 10526; +float DEATH_MONSTER_OGRE_CHAINSAW = 10527; +float DEATH_MONSTER_OGRE_NAIL = 10528; +float DEATH_MONSTER_MELEE = 10529; +float DEATH_MONSTER_ZOMBIE = 10530; +float DEATH_MONSTER_HELLKNIGHT_FIREBALL = 10531; +float DEATH_MONSTER_LAST = 10532; + float DEATH_WEAPONMASK = 0xFF; float DEATH_HITTYPEMASK = 0x1F00; // which is WAY below 10000 used for normal deaths float HITTYPE_SECONDARY = 0x100; @@ -442,6 +470,7 @@ float HITTYPE_RESERVED = 0x1000; // unused yet #define DEATH_ISWEAPON(t,w) (!DEATH_ISSPECIAL(t) && DEATH_WEAPONOFWEAPONDEATH(t) == (w)) #define DEATH_WEAPONOF(t) (DEATH_ISSPECIAL(t) ? 0 : DEATH_WEAPONOFWEAPONDEATH(t)) #define WEP_VALID(w) ((w) >= WEP_FIRST && (w) <= WEP_LAST) +#define DEATH_ISMONSTER(t) ((t) >= DEATH_MONSTER && (t) <= DEATH_MONSTER_LAST) #define FRAGS_PLAYER 0 #define FRAGS_SPECTATOR -666 diff --git a/qcsrc/common/mapinfo.qc b/qcsrc/common/mapinfo.qc index f7ced4205..606df668f 100644 --- a/qcsrc/common/mapinfo.qc +++ b/qcsrc/common/mapinfo.qc @@ -315,6 +315,8 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF; else if(v == "runematch_spawn_point") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RUNEMATCH; + else if(v == "td_generator") + MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_TD; else if(v == "target_assault_roundend") MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ASSAULT; else if(v == "onslaught_generator") diff --git a/qcsrc/common/mapinfo.qh b/qcsrc/common/mapinfo.qh index bd67f67a8..253c7750b 100644 --- a/qcsrc/common/mapinfo.qh +++ b/qcsrc/common/mapinfo.qh @@ -39,6 +39,9 @@ REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,"timelimit=20 pointlimit=30 REGISTER_GAMETYPE(_("Last Man Standing"),lms,g_lms,LMS,"timelimit=20 lives=9 leadlimit=0") #define g_lms IS_GAMETYPE(LMS) +REGISTER_GAMETYPE(_("Tower Defense"),td,g_td,TD,"timelimit=20 pointlimit=10 leadlimit=0") +#define g_td IS_GAMETYPE(TD) + REGISTER_GAMETYPE(_("Arena"),arena,g_arena,ARENA,"timelimit=20 pointlimit=10 leadlimit=0") #define g_arena IS_GAMETYPE(ARENA) diff --git a/qcsrc/server/accuracy.qc b/qcsrc/server/accuracy.qc index 9271e03d0..f7a01d572 100644 --- a/qcsrc/server/accuracy.qc +++ b/qcsrc/server/accuracy.qc @@ -111,6 +111,7 @@ float accuracy_isgooddamage(entity attacker, entity targ) { if(!inWarmupStage) if(targ.flags & FL_CLIENT) + if(!(attacker.flags & FL_MONSTER)) // no accuracy for monsters if(targ.deadflag == DEAD_NO) if(IsDifferentTeam(attacker, targ)) return TRUE; diff --git a/qcsrc/server/autocvars.qh b/qcsrc/server/autocvars.qh index 433261d45..564c76b15 100644 --- a/qcsrc/server/autocvars.qh +++ b/qcsrc/server/autocvars.qh @@ -1275,3 +1275,47 @@ float autocvar_g_sandbox_object_material_velocity_min; float autocvar_g_sandbox_object_material_velocity_factor; float autocvar_g_max_info_autoscreenshot; float autocvar_physics_ode; +float autocvar_g_td_start_wave; +float autocvar_g_td_hardcore; +float autocvar_g_td_generator_health; +float autocvar_g_td_current_monsters; +float autocvar_g_td_generator_damaged_points; +float autocvar_g_td_monster_count; +float autocvar_g_td_monster_count_increment; +float autocvar_g_td_buildphase_time; +float autocvar_g_td_pvp; +float autocvar_g_td_max_waves; +float autocvar_g_td_kill_points; +float autocvar_g_td_turretkill_points; +float autocvar_g_td_generator_dontend; +float autocvar_g_td_force_settings; +float autocvar_g_td_turret_max; +float autocvar_g_td_turret_plasma_cost; +float autocvar_g_td_turret_mlrs_cost; +float autocvar_g_td_turret_walker_cost; +float autocvar_g_td_tower_buff_cost; +float autocvar_g_td_monsters_skill_start; +float autocvar_g_td_monsters_skill_increment; +float autocvar_g_td_monster_spawn_protection_radius; +float autocvar_g_za_monster_count; +float autocvar_g_monsters; +float autocvar_g_monsters_max; +float autocvar_g_monsters_max_perplayer; +float autocvar_g_monsters_giants_only; +float autocvar_g_monsters_typefrag; +float autocvar_g_monsters_owners; +float autocvar_g_monsters_miniboss_chance; +float autocvar_g_monsters_miniboss_healthboost; +string autocvar_g_monsters_forcedrop; +string autocvar_g_monsters_drop_type; +string autocvar_g_monsters_drop_size; +float autocvar_g_monsters_teams; +float autocvar_g_monsters_healthbars; +float autocvar_g_monsters_respawn_delay; +float autocvar_g_monsters_respawn; +float autocvar_g_monsters_nogiants; +float autocvar_g_monsters_skill_easy; +float autocvar_g_monsters_skill_normal; +float autocvar_g_monsters_skill_hard; +float autocvar_g_monsters_skill_insane; +float autocvar_g_monsters_skill_nightmare; diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 165460eeb..e5dc5e5d4 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -843,6 +843,7 @@ void PutClientInServer (void) self.event_damage = PlayerDamage; self.bot_attack = TRUE; + self.monster_attack = TRUE; self.statdraintime = time + 5; self.BUTTON_ATCK = self.BUTTON_JUMP = self.BUTTON_ATCK2 = 0; @@ -897,6 +898,8 @@ void PutClientInServer (void) self.target = s; activator = world; self = oldself; + + Unfreeze(self); spawn_spot = spot; MUTATOR_CALLHOOK(PlayerSpawn); @@ -2369,6 +2372,9 @@ float nJoinAllowed(entity ignore) { if(autocvar_g_forced_team_otherwise == "spectator") return 0; } + + if(MUTATOR_CALLHOOK(PlayerCanJoin)) + return 0; if(self.team_forced < 0) return 0; // forced spectators can never join @@ -2622,6 +2628,15 @@ void PlayerPreThink (void) return; #endif + if(self.frozen) + { + self.revive_progress = bound(0, self.revive_progress + frametime * self.revive_speed, 1); + self.health = max(1, self.revive_progress * autocvar_g_balance_health_start); + + if(self.revive_progress >= 1) + Unfreeze(self); + } + MUTATOR_CALLHOOK(PlayerPreThink); if(!self.cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button @@ -2786,7 +2801,7 @@ void PlayerPreThink (void) self.prevorigin = self.origin; if (!self.vehicle) - if (((self.BUTTON_CROUCH && !self.hook.state) || self.health <= g_bloodloss) && self.animstate_startframe != self.anim_melee_x && !self.freezetag_frozen) // prevent crouching if using melee attack + if (((self.BUTTON_CROUCH && !self.hook.state) || self.health <= g_bloodloss) && self.animstate_startframe != self.anim_melee_x && !self.freezetag_frozen && !self.frozen) // prevent crouching if using melee attack { if (!self.crouch) { @@ -2853,6 +2868,9 @@ void PlayerPreThink (void) // secret status secrets_setstatus(); + // monsters status + monsters_setstatus(); + self.dmg_team = max(0, self.dmg_team - autocvar_g_teamdamage_resetspeed * frametime); //self.angles_y=self.v_angle_y + 90; // temp diff --git a/qcsrc/server/cl_physics.qc b/qcsrc/server/cl_physics.qc index 3e2268d89..8efecbadb 100644 --- a/qcsrc/server/cl_physics.qc +++ b/qcsrc/server/cl_physics.qc @@ -23,7 +23,7 @@ When you press the jump key */ void PlayerJump (void) { - if(self.freezetag_frozen) + if(self.freezetag_frozen || self.frozen) return; // no jumping in freezetag when frozen float mjumpheight; @@ -872,6 +872,12 @@ void SV_PlayerPhysics() self.disableclientprediction = 0; if(time < self.ladder_time) self.disableclientprediction = 1; + + if(self.frozen) + { + self.movement = '0 0 0'; + self.disableclientprediction = 1; + } MUTATOR_CALLHOOK(PlayerPhysics); @@ -1074,7 +1080,7 @@ void SV_PlayerPhysics() PM_Accelerate(wishdir, wishspeed, wishspeed, autocvar_sv_accelerate*maxspd_mod, 1, 0, 0, 0); } } - else if ((self.items & IT_JETPACK) && self.BUTTON_HOOK && (!autocvar_g_jetpack_fuel || self.ammo_fuel >= 0.01 || self.items & IT_UNLIMITED_WEAPON_AMMO) && !self.freezetag_frozen) + else if ((self.items & IT_JETPACK) && self.BUTTON_HOOK && (!autocvar_g_jetpack_fuel || self.ammo_fuel >= 0.01 || self.items & IT_UNLIMITED_WEAPON_AMMO) && !self.freezetag_frozen && !self.frozen) { //makevectors(self.v_angle_y * '0 1 0'); makevectors(self.v_angle); diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 6945fe722..2d028c17c 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -273,7 +273,7 @@ void player_anim (void) if (!self.animstate_override) { - if (self.freezetag_frozen) + if (self.freezetag_frozen || self.frozen) setanim(self, self.anim_idle, TRUE, FALSE, FALSE); else if (!(self.flags & FL_ONGROUND) || self.BUTTON_JUMP) { diff --git a/qcsrc/server/cl_weapons.qc b/qcsrc/server/cl_weapons.qc index 236c0923f..835c39a94 100644 --- a/qcsrc/server/cl_weapons.qc +++ b/qcsrc/server/cl_weapons.qc @@ -343,6 +343,8 @@ void W_ThrowWeapon(vector velo, vector delta, float doreduce) w = self.weapon; if (w == 0) return; // just in case + if(self.frozen) + return; if(MUTATOR_CALLHOOK(ForbidThrowCurrentWeapon)) return; if(!autocvar_g_weapon_throwable) @@ -377,7 +379,7 @@ void W_WeaponFrame() if(((arena_roundbased || g_ca || g_freezetag) && time < warmup) || ((time < game_starttime) && !autocvar_sv_ready_restart_after_countdown)) return; - if(self.freezetag_frozen == 1) + if(self.freezetag_frozen == 1 || self.frozen == 1) return; if (!self.weaponentity || self.health < 1) diff --git a/qcsrc/server/cl_weaponsystem.qc b/qcsrc/server/cl_weaponsystem.qc index 8f510edff..0d8d46a6c 100644 --- a/qcsrc/server/cl_weaponsystem.qc +++ b/qcsrc/server/cl_weaponsystem.qc @@ -103,7 +103,7 @@ void W_HitPlotAnalysis(entity player, vector screenforward, vector screenright, vector org; float lag; - if(player.hitplotfh >= 0) + if(player.hitplotfh >= 0 && !(player.flags & FL_MONSTER)) { lag = ANTILAG_LATENCY(player); if(lag < 0.001) @@ -1092,6 +1092,8 @@ vector W_CalculateProjectileVelocity(vector pvelocity, vector mvelocity, float f void W_AttachToShotorg(entity flash, vector offset) { + if(self.flags & FL_MONSTER) + return; // no flash for monsters entity xflash; flash.owner = self; flash.angles_z = random() * 360; @@ -1355,6 +1357,9 @@ void W_SetupProjectileVelocity(entity missile, float pSpeed, float spread) void W_DecreaseAmmo(.float ammo_type, float ammo_use, float ammo_reload) { + if(self.flags & FL_MONSTER) // no ammo for monsters... yet + return; + if((self.items & IT_UNLIMITED_WEAPON_AMMO) && !ammo_reload) return; diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc index 530646afd..007514983 100644 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@ -182,6 +182,66 @@ void ClientCommand_join(float request) } } +void ClientCommand_mobspawn(float request, float argc) +{ + switch(request) + { + case CMD_REQUEST_COMMAND: + { + entity e; + string tospawn, mname, s; + float spawncount = 0, moveflag, max_global, max_perplayer, i; + + max_global = autocvar_g_monsters_max; + max_perplayer = autocvar_g_monsters_max_perplayer; + moveflag = (argv(3) ? stof(argv(3)) : 1); // follow owner if not defined + spawncount = ((argv(2)) ? stof(argv(2)) : 1); + tospawn = argv(1); + mname = argv(4); + s = ((spawncount == 1) ? "" : "s"); + + if(tospawn == "list") + { + sprint(self, "Available monsters:\n"); + sprint(self, strcat(monsterlist(), "\n")); + return; + } + + if(self.classname != STR_PLAYER) { sprint(self, "You can't spawn monsters while spectating.\n"); return; } + else if(self.deadflag) { sprint(self, "You can't spawn monsters while dead.\n"); return; } + else if(self.monstercount > max_perplayer) { sprint(self, "You have spawned too many monsters, kill some before trying to spawn any more.\n"); return; } + else if(totalspawned > max_global) { sprint(self, "The global maximum monster count has been reached, kill some before trying to spawn any more.\n"); return; } + else if(spawncount == 0) { sprint(self, "No monsters to spawn.\n"); return; } + + makevectors(self.v_angle); + WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * 100, MOVE_NORMAL, self); + + for(i = 0; i < spawncount; i++) + { + self.monstercount++; + if(self.monstercount > max_perplayer) break; // FIXME: check for these properly + e = spawnmonster(tospawn, self, self, trace_endpos, FALSE, moveflag); + if(e == world) { self.monstercount -= 1; break; } // take back the 1 that was lost + if(mname != "") e.netname = mname; + totalspawned++; + } + + sprint(self, sprintf("Spawned %d %s%s\n", spawncount, tospawn, s)); + + return; + } + + default: + sprint(self, "Incorrect parameters for ^2mobspawn^7\n"); + case CMD_REQUEST_USAGE: + { + sprint(self, "\nUsage:^3 cmd mobspawn monster\n"); + sprint(self, " See 'cmd mobspawn list' for available arguments.\n"); + return; + } + } +} + void ClientCommand_ready(float request) // todo: anti-spam for toggling readyness { switch(request) @@ -560,6 +620,7 @@ void ClientCommand_(float request) 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") \ CLIENT_COMMAND("join", ClientCommand_join(request), "Become a player in the game") \ + CLIENT_COMMAND("mobspawn", ClientCommand_mobspawn(request, arguments), "Spawn monsters infront of yourself") \ CLIENT_COMMAND("ready", ClientCommand_ready(request), "Qualify as ready to end warmup stage (or restart server if allowed)") \ CLIENT_COMMAND("say", ClientCommand_say(request, arguments, command), "Print a message to chat to all players") \ CLIENT_COMMAND("say_team", ClientCommand_say_team(request, arguments, command), "Print a message to chat to all team mates") \ diff --git a/qcsrc/server/command/cmd.qh b/qcsrc/server/command/cmd.qh index e64cbc267..120bf3e02 100644 --- a/qcsrc/server/command/cmd.qh +++ b/qcsrc/server/command/cmd.qh @@ -8,7 +8,10 @@ .float lms_spectate_warning; .float checkfail; +// number of monsters spawned with mobspawn command +float totalspawned; + string MapVote_Suggest(string m); // used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file -void ClientCommand_macro_write_aliases(float fh); \ No newline at end of file +void ClientCommand_macro_write_aliases(float fh); diff --git a/qcsrc/server/command/sv_cmd.qc b/qcsrc/server/command/sv_cmd.qc index 0710ddfa8..382c7de61 100644 --- a/qcsrc/server/command/sv_cmd.qc +++ b/qcsrc/server/command/sv_cmd.qc @@ -139,6 +139,43 @@ void GameCommand_adminmsg(float request, float argc) } } +void GameCommand_butcher(float request) +{ + switch(request) + { + case CMD_REQUEST_COMMAND: + { + float removed_count = 0; + totalspawned = 0; + entity montokill = world; + FOR_EACH_MONSTER(montokill) + { + if(montokill.sprite) + WaypointSprite_Kill(montokill.sprite); + + if(montokill.realowner.flags & FL_CLIENT) + montokill.realowner.monstercount -= 1; + + remove(montokill); + removed_count += 1; + } + if(removed_count <= 0) + print("No monsters to kill\n"); + else + print(strcat("Killed ", ftos(removed_count), " monster", ((removed_count == 1) ? "\n" : "s\n"))); + return; // never fall through to usage + } + + default: + case CMD_REQUEST_USAGE: + { + print("\nUsage:^3 sv_cmd butcher\n"); + print(" No arguments required.\n"); + return; + } + } +} + void GameCommand_allready(float request) { switch(request) @@ -1727,6 +1764,7 @@ void GameCommand_(float request) // Common commands have double indentation to separate them a bit. #define SERVER_COMMANDS(request,arguments,command) \ SERVER_COMMAND("adminmsg", GameCommand_adminmsg(request, arguments), "Send an admin message to a client directly") \ + SERVER_COMMAND("butcher", GameCommand_butcher(request), "Instantly removes all monsters on the map") \ 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") \ SERVER_COMMAND("anticheat", GameCommand_anticheat(request, arguments), "Create an anticheat report for a client") \ diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index f77725413..c2cc06dad 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -584,6 +584,7 @@ float client_cefc_accumulatortime; #endif ..float current_ammo; +.float currentegg; .float weapon_load[WEP_MAXCOUNT]; .float ammo_none; // used by the reloading system, must always be 0 @@ -644,6 +645,10 @@ float serverflags; .float freezetag_frozen; .float freezetag_revive_progress; +.float frozen; // for freeze attacks +.float revive_progress; +.float revive_speed; // NOTE: multiplier (anything above 1 is instaheal) + .entity muzzle_flash; .float misc_bulletcounter; // replaces uzi & hlac bullet counter. @@ -674,3 +679,19 @@ string modname; #define MISSILE_IS_CONFUSABLE(m) ((m.missile_flags & MIF_GUIDED_CONFUSABLE) ? TRUE : FALSE) #define MISSILE_IS_GUIDED(m) ((m.missile_flags & MIF_GUIDED_ALL) ? TRUE : FALSE) #define MISSILE_IS_TRACKING(m) ((m.missile_flags & MIF_GUIDED_TRACKING) ? TRUE : FALSE) + +.string spawnmob; +.float monster_attack; + +float monster_skill; +float spawncode_first_load; // used to tell the player the monster database is loading (TODO: fix this?) + +.entity monster_owner; // new monster owner entity, fixes non-solid monsters +.float monstercount; // per player monster count + +.float stat_monsters_killed; // stats +.float stat_monsters_total; +float monsters_total; +float monsters_killed; +void monsters_setstatus(); // monsters.qc +string monsterlist(); diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index a3eeefb73..c55c40a66 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -529,6 +529,67 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype) } } +void Ice_Think() +{ + if(self.owner.health < 1) + { + remove(self); + return; + } + setorigin(self, self.owner.origin - '0 0 16'); + self.nextthink = time; +} + +void Freeze (entity targ, float freeze_time) +{ + float monster = (targ.flags & FL_MONSTER); + float player = (targ.flags & FL_CLIENT); + + if(!player && !monster) // only specified entities can be freezed + return; + + if(targ.frozen || targ.freezetag_frozen) + return; + + targ.frozen = 1; + targ.revive_progress = 0; + targ.health = 1; + targ.revive_speed = freeze_time; + + entity ice; + ice = spawn(); + ice.owner = targ; + ice.classname = "ice"; + ice.scale = targ.scale; + ice.think = Ice_Think; + ice.nextthink = time; + ice.frame = floor(random() * 21); // ice model has 20 different looking frames + setmodel(ice, "models/ice/ice.md3"); + + entity oldself; + oldself = self; + self = ice; + Ice_Think(); + self = oldself; + + RemoveGrapplingHook(targ); +} + +void Unfreeze (entity targ) +{ + targ.frozen = 0; + targ.revive_progress = 0; + targ.health = ((targ.classname == STR_PLAYER) ? autocvar_g_balance_health_start : targ.max_health); + + // remove the ice block + entity ice; + for(ice = world; (ice = find(ice, classname, "ice")); ) if(ice.owner == targ) + { + remove(ice); + break; + } +} + // these are updated by each Damage call for use in button triggering and such entity damage_targ; entity damage_inflictor; @@ -715,6 +776,12 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float mirrorforce *= g_weaponforcefactor; } + if(targ.frozen && attacker.classname != "monster_spider") + { + damage = 0; + force *= 0.2; + } + // should this be changed at all? If so, in what way? frag_attacker = attacker; frag_target = targ; @@ -823,7 +890,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float else victim = targ; - if(victim.classname == "player" || victim.turrcaps_flags & TFL_TURRCAPS_ISTURRET) + if(victim.classname == "player" || victim.turrcaps_flags & TFL_TURRCAPS_ISTURRET || victim.flags & FL_MONSTER) { if(IsDifferentTeam(victim, attacker)) { @@ -1347,7 +1414,7 @@ void Fire_ApplyDamage(entity e) e.fire_endtime = 0; // ice stops fire - if(e.freezetag_frozen) + if(e.freezetag_frozen || e.frozen) e.fire_endtime = 0; t = min(frametime, e.fire_endtime - time); diff --git a/qcsrc/server/g_hook.qc b/qcsrc/server/g_hook.qc index f7af47d92..ad1da10f7 100644 --- a/qcsrc/server/g_hook.qc +++ b/qcsrc/server/g_hook.qc @@ -302,7 +302,7 @@ void FireGrapplingHook (void) if((arena_roundbased && time < warmup) || (time < game_starttime)) return; - if(self.freezetag_frozen) + if(self.freezetag_frozen || self.frozen) return; if(self.vehicle) diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index 8d8c0328e..bacdce417 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -264,6 +264,7 @@ void cvar_changes_init() BADCVAR("g_freezetag"); BADCVAR("g_keepaway"); BADCVAR("g_keyhunt"); + BADCVAR("g_td"); BADCVAR("g_keyhunt_teams"); BADCVAR("g_keyhunt_teams"); BADCVAR("g_lms"); @@ -820,6 +821,16 @@ void spawnfunc_worldspawn (void) addstat(STAT_FROZEN, AS_INT, freezetag_frozen); addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress); } + + if(g_td) + { + addstat(STAT_CURRENT_WAVE, AS_FLOAT, stat_current_wave); + addstat(STAT_TOTALWAVES, AS_FLOAT, stat_totalwaves); + } + + // freeze attacks + addstat(STAT_FROZEN, AS_INT, frozen); + addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, revive_progress); // g_movementspeed hack addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw); @@ -830,6 +841,10 @@ void spawnfunc_worldspawn (void) // secrets addstat(STAT_SECRETS_TOTAL, AS_FLOAT, stat_secrets_total); addstat(STAT_SECRETS_FOUND, AS_FLOAT, stat_secrets_found); + + // monsters + addstat(STAT_MONSTERS_TOTAL, AS_FLOAT, stat_monsters_total); + addstat(STAT_MONSTERS_KILLED, AS_FLOAT, stat_monsters_killed); // misc addstat(STAT_RESPAWN_TIME, AS_FLOAT, stat_respawn_time); @@ -942,6 +957,8 @@ void spawnfunc_worldspawn (void) // weird mutators that deserve to count as mod if(autocvar_g_minstagib) modname = "MinstaGib"; + if(autocvar_g_monsters) + modname = "Monsters"; // extra mutators that deserve to count as mod MUTATOR_CALLHOOK(SetModname); // weird game types that deserve to count as mod @@ -2119,6 +2136,36 @@ float WinningCondition_RanOutOfSpawns() return WINNING_NO; } +// TD winning condition: +// game terminates if there are no generators (or 1 dies if td_dontend is TRUE) +float gensurvived; +float WinningCondition_TowerDefense() +{ + WinningConditionHelper(); // set worldstatus + + if(inWarmupStage) + return WINNING_NO; + + // first check if the game has ended + if(gendestroyed == TRUE) // FALSE means either generator hasen't spawned yet, or mapper didn't add one + if(td_gencount < 1 || !td_dont_end) + { + ClearWinners(); + dprint("Everyone lost, ending game.\n"); + return WINNING_YES; + } + + if(gensurvived) + { + ClearWinners(); + SetWinners(winning, 4); + return WINNING_YES; + } + + // Two or more teams remain + return WINNING_NO; +} + /* ============ CheckRules_World @@ -2274,6 +2321,10 @@ void CheckRules_World() { checkrules_status = WinningCondition_Onslaught(); // TODO remove this? } + else if(g_td) + { + checkrules_status = WinningCondition_TowerDefense(); // TODO make these mutator hooks? + } else { checkrules_status = WinningCondition_Scores(fraglimit, leadlimit); diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index efb735406..4a226c786 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -90,6 +90,7 @@ string STR_OBSERVER = "observer"; #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL) #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; ) #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL) +#define FOR_EACH_MONSTER(v) for(v = world; (v = findflags(v, flags, FL_MONSTER)) != world; ) #else #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(v.flags & FL_CLIENT) @@ -97,6 +98,7 @@ string STR_OBSERVER = "observer"; #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER) #define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if(v.classname != STR_PLAYER) #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER) +#define FOR_EACH_MONSTER(v) for(v = world; (v = findflags(v, flags, FL_MONSTER)) != world; ) #endif #define CENTER_OR_VIEWOFS(ent) (ent.origin + ((ent.classname == STR_PLAYER) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5))) @@ -1115,6 +1117,8 @@ string GetGametype(); // g_world.qc void readlevelcvars(void) { g_minstagib = cvar("g_minstagib"); + + monster_skill = cvar("g_monsters_skill"); // load ALL the mutators if(cvar("g_dodging")) @@ -1140,6 +1144,9 @@ void readlevelcvars(void) // is this a mutator? is this a mode? if(cvar("g_sandbox")) MUTATOR_ADD(sandbox); + + if(cvar("g_za")) + MUTATOR_ADD(mutator_zombie_apocalypse); if(cvar("sv_allow_fullbright")) serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT; diff --git a/qcsrc/server/movelib.qc b/qcsrc/server/movelib.qc index 9b9f7fde0..633b07609 100644 --- a/qcsrc/server/movelib.qc +++ b/qcsrc/server/movelib.qc @@ -102,6 +102,19 @@ void movelib_move(vector force,float max_velocity,float drag,float theMass,float self.velocity = normalize(self.velocity) * (mspeed - 50);//* max_velocity; } +void movelib_move_simple_gravity(vector newdir,float velo,float blendrate) +{ + float z_speed = self.velocity_z; + self.movelib_lastupdate = time; + self.velocity = self.velocity * (1 - blendrate) + (newdir * blendrate) * velo; + self.velocity_z = z_speed; +} + +void movelib_jump_simple(float power){ + self.velocity_z=power; + self.movelib_lastupdate = time; +} + /* .float mass; .float side_friction; diff --git a/qcsrc/server/mutators/base.qh b/qcsrc/server/mutators/base.qh index 1b6cea8fc..da9d0f36c 100644 --- a/qcsrc/server/mutators/base.qh +++ b/qcsrc/server/mutators/base.qh @@ -50,6 +50,10 @@ MUTATOR_HOOKABLE(PlayerSpawn); MUTATOR_HOOKABLE(ClientDisconnect); // called when a player disconnects + +MUTATOR_HOOKABLE(PlayerCanJoin); + // called when a player tries to join + // if this returns TRUE, the player cannot join MUTATOR_HOOKABLE(PlayerDies); // called when a player dies to e.g. remove stuff he was carrying. @@ -103,6 +107,12 @@ MUTATOR_HOOKABLE(TurretSpawn); // return error to request removal // INPUT: self - turret +MUTATOR_HOOKABLE(TurretValidateTarget); + // return target score + // INPUT: + entity turret_target; + entity turret; + MUTATOR_HOOKABLE(OnEntityPreSpawn); // return error to prevent entity spawn, or modify the entity @@ -127,6 +137,33 @@ MUTATOR_HOOKABLE(EditProjectile); // INPUT: entity self; entity other; + +MUTATOR_HOOKABLE(MonsterSpawn); + // called when a monster spawns + +MUTATOR_HOOKABLE(MonsterDies); + // called when a monster dies + // INPUT: + entity frag_attacker; + +MUTATOR_HOOKABLE(MonsterDropItem); + // called when a monster is dropping loot + // INPUT, OUTPUT: + string monster_dropitem; + string monster_dropsize; + +MUTATOR_HOOKABLE(MonsterMove); + // called when a monster moves + // INPUT: + float monster_speed_run; + float monster_speed_walk; + entity monster_target; + +MUTATOR_HOOKABLE(MonsterFindTarget); + // called when a monster looks for another target + +MUTATOR_HOOKABLE(MonsterCheckBossFlag); + // called to change a random monster to a miniboss MUTATOR_HOOKABLE(PlayerDamage_SplitHealthArmor); // called when a player gets damaged to e.g. remove stuff he was carrying. diff --git a/qcsrc/server/mutators/mutators.qh b/qcsrc/server/mutators/mutators.qh index 2ac6094d3..b1cd9469e 100644 --- a/qcsrc/server/mutators/mutators.qh +++ b/qcsrc/server/mutators/mutators.qh @@ -4,6 +4,7 @@ MUTATOR_DECLARATION(gamemode_keepaway); MUTATOR_DECLARATION(gamemode_ctf); MUTATOR_DECLARATION(gamemode_nexball); MUTATOR_DECLARATION(gamemode_onslaught); +MUTATOR_DECLARATION(gamemode_td); MUTATOR_DECLARATION(mutator_dodging); MUTATOR_DECLARATION(mutator_invincibleprojectiles); @@ -13,5 +14,6 @@ MUTATOR_DECLARATION(mutator_rocketflying); MUTATOR_DECLARATION(mutator_spawn_near_teammate); MUTATOR_DECLARATION(mutator_vampire); MUTATOR_DECLARATION(mutator_superspec); +MUTATOR_DECLARATION(mutator_zombie_apocalypse); MUTATOR_DECLARATION(sandbox); diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index 028519372..7b30b2eba 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -34,6 +34,7 @@ mutators/gamemode_keyhunt.qh // TODO fix this mutators/gamemode_keepaway.qh mutators/gamemode_nexball.qh mutators/mutator_dodging.qh +mutators/gamemode_td.qh //// tZork Turrets //// tturrets/include/turrets_early.qh @@ -206,6 +207,8 @@ playerstats.qc ../common/explosion_equation.qc +monsters/monsters.qh + mutators/base.qc mutators/gamemode_ctf.qc mutators/gamemode_freezetag.qc @@ -213,6 +216,7 @@ mutators/gamemode_keyhunt.qc mutators/gamemode_keepaway.qc mutators/gamemode_nexball.qc mutators/gamemode_onslaught.qc +mutators/gamemode_td.qc mutators/mutator_invincibleproj.qc mutators/mutator_new_toys.qc mutators/mutator_nix.qc @@ -222,6 +226,7 @@ mutators/mutator_vampire.qc mutators/mutator_spawn_near_teammate.qc mutators/sandbox.qc mutators/mutator_superspec.qc +mutators/mutator_zombie_apocalypse.qc ../warpzonelib/anglestransform.qc ../warpzonelib/mathlib.qc diff --git a/qcsrc/server/sv_main.qc b/qcsrc/server/sv_main.qc index c91c1ac18..579afd544 100644 --- a/qcsrc/server/sv_main.qc +++ b/qcsrc/server/sv_main.qc @@ -10,6 +10,7 @@ void CreatureFrame (void) float vehic = (self.vehicle_flags & VHF_ISVEHICLE); float projectile = (self.flags & FL_PROJECTILE); + float monster = (self.flags & FL_MONSTER); if (self.watertype <= CONTENT_WATER && self.waterlevel > 0) // workaround a retarded bug made by id software :P (yes, it's that old of a bug) { @@ -19,7 +20,7 @@ void CreatureFrame (void) self.dmgtime = 0; } - if(!vehic && !projectile) // vehicles and projectiles don't drown + if(!vehic && !projectile && !monster) // vehicles, monsters and projectiles don't drown { if (self.waterlevel != WATERLEVEL_SUBMERGED) { diff --git a/qcsrc/server/teamplay.qc b/qcsrc/server/teamplay.qc index b8f2f3ac8..4df34ee60 100644 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@ -146,6 +146,13 @@ void InitGameplayMode() MUTATOR_ADD(gamemode_ctf); have_team_spawns = -1; // request team spawns } + + if(g_td) + { + fraglimit_override = 0; // no limits in TD - it's a survival mode + leadlimit_override = 0; + MUTATOR_ADD(gamemode_td); + } if(g_runematch) { diff --git a/qcsrc/server/tturrets/system/system_damage.qc b/qcsrc/server/tturrets/system/system_damage.qc index 971d65cca..4ac34eb63 100644 --- a/qcsrc/server/tturrets/system/system_damage.qc +++ b/qcsrc/server/tturrets/system/system_damage.qc @@ -64,6 +64,7 @@ void turret_stdproc_respawn() self.tur_head.avelocity = self.avelocity; self.tur_head.angles = self.idle_aim; self.health = self.tur_health; + self.max_health = self.tur_health; self.enemy = world; self.volly_counter = self.shot_volly; @@ -125,6 +126,9 @@ void turret_stdproc_damage (entity inflictor, entity attacker, float damage, flo self.takedamage = DAMAGE_NO; self.nextthink = time; self.think = turret_stdproc_die; + + if(self.realowner) + self.realowner.turret_cnt -= 1; } self.SendFlags |= TNSF_STATUS; diff --git a/qcsrc/server/tturrets/system/system_main.qc b/qcsrc/server/tturrets/system/system_main.qc index dd58b3cee..8907bc41b 100644 --- a/qcsrc/server/tturrets/system/system_main.qc +++ b/qcsrc/server/tturrets/system/system_main.qc @@ -571,6 +571,13 @@ float turret_stdproc_firecheck() float turret_validate_target(entity e_turret, entity e_target, float validate_flags) { vector v_tmp; + + turret_target = e_target; + turret = e_turret; + if(MUTATOR_CALLHOOK(TurretValidateTarget)) + return 1; + e_target = turret_target; + e_turret = turret; //if(!validate_flags & TFL_TARGETSELECT_NOBUILTIN) // return -0.5; @@ -1107,6 +1114,9 @@ float turret_stdproc_init (string cvar_base_name, string base, string head, floa if not (self.health) self.health = 1000; self.tur_health = max(1, self.health); + self.max_health = self.tur_health; + self.bot_attack = TRUE; + self.monster_attack = TRUE; if not (self.turrcaps_flags) self.turrcaps_flags = TFL_TURRCAPS_RADIUSDMG | TFL_TURRCAPS_MEDPROJ | TFL_TURRCAPS_PLAYERKILL; @@ -1339,7 +1349,6 @@ float turret_stdproc_init (string cvar_base_name, string base, string head, floa self.turret_score_target = turret_stdproc_targetscore_generic; self.use = turret_stdproc_use; - self.bot_attack = TRUE; ++turret_count; self.nextthink = time + 1; diff --git a/qcsrc/server/tturrets/system/system_scoreprocs.qc b/qcsrc/server/tturrets/system/system_scoreprocs.qc index c542dab40..16ecbce5e 100644 --- a/qcsrc/server/tturrets/system/system_scoreprocs.qc +++ b/qcsrc/server/tturrets/system/system_scoreprocs.qc @@ -44,7 +44,10 @@ float turret_stdproc_targetscore_generic(entity _turret, entity _target) if ((_turret.target_select_missilebias > 0) && (_target.flags & FL_PROJECTILE)) m_score = 1; - if ((_turret.target_select_playerbias > 0) && (_target.flags & FL_CLIENT)) + if ((_turret.target_select_playerbias > 0) && (_target.flags & FL_CLIENT) && !g_td) + p_score = 1; + + if(g_td && _target.flags & FL_MONSTER) p_score = 1; d_score = max(d_score, 0); diff --git a/qcsrc/server/tturrets/units/unit_fusionreactor.qc b/qcsrc/server/tturrets/units/unit_fusionreactor.qc index 8118b8f23..de8509b3e 100644 --- a/qcsrc/server/tturrets/units/unit_fusionreactor.qc +++ b/qcsrc/server/tturrets/units/unit_fusionreactor.qc @@ -7,6 +7,11 @@ void turret_fusionreactor_fire() vector fl_org; self.enemy.ammo = min(self.enemy.ammo + self.shot_dmg,self.enemy.ammo_max); + if(g_td) // auto repair? + { + self.enemy.health = min(self.enemy.health + self.shot_dmg,self.enemy.max_health); + self.enemy.tur_health = min(self.enemy.tur_health + self.shot_dmg,self.enemy.max_health); + } fl_org = 0.5 * (self.enemy.absmin + self.enemy.absmax); te_smallflash(fl_org); } @@ -38,15 +43,27 @@ float turret_fusionreactor_firecheck() return 0; if (self.ammo < self.shot_dmg) - return 0; + return 0; + + if (vlen(self.enemy.origin - self.origin) > self.target_range) + return 0; + if(g_td) + { + if(self.realowner != self.enemy.realowner) + return 0; + + if(self.enemy.turrcaps_flags & TFL_TURRCAPS_AMMOSOURCE) + return 0; + + if(self.enemy.health >= self.enemy.max_health) + return 0; + } + if (self.enemy.ammo >= self.enemy.ammo_max) return 0; - if (vlen(self.enemy.origin - self.origin) > self.target_range) - return 0; - - if(self.team != self.enemy.team) + if(teamplay && self.team != self.enemy.team) return 0; if not (self.enemy.ammo_flags & TFL_AMMO_ENERGY) diff --git a/qcsrc/server/tturrets/units/unit_walker.qc b/qcsrc/server/tturrets/units/unit_walker.qc index 041c16929..ebdd0a133 100644 --- a/qcsrc/server/tturrets/units/unit_walker.qc +++ b/qcsrc/server/tturrets/units/unit_walker.qc @@ -107,7 +107,7 @@ void walker_rocket_think() m_speed = vlen(self.velocity); // Enemy dead? just keep on the current heading then. - if (self.enemy == world || self.enemy.deadflag != DEAD_NO) + if (self.enemy == world || self.enemy.deadflag != DEAD_NO || (g_td && !(self.enemy.flags & FL_MONSTER || self.enemy.classname == "td_generator")) || self.enemy.classname == "td_generator") self.enemy = world; if (self.enemy) diff --git a/qcsrc/server/w_all.qc b/qcsrc/server/w_all.qc index ac4ef47ed..f8240dcc6 100644 --- a/qcsrc/server/w_all.qc +++ b/qcsrc/server/w_all.qc @@ -19,3 +19,4 @@ #include "w_rifle.qc" #include "w_fireball.qc" #include "w_seeker.qc" +#include "w_incubator.qc" diff --git a/qcsrc/server/w_electro.qc b/qcsrc/server/w_electro.qc index ad1fbf0fd..f59e3b3eb 100644 --- a/qcsrc/server/w_electro.qc +++ b/qcsrc/server/w_electro.qc @@ -253,7 +253,7 @@ void lgbeam_think() return; } - if (owner_player.weaponentity.state != WS_INUSE || !lgbeam_checkammo() || owner_player.deadflag != DEAD_NO || !owner_player.BUTTON_ATCK || owner_player.freezetag_frozen) + if (owner_player.weaponentity.state != WS_INUSE || !lgbeam_checkammo() || owner_player.deadflag != DEAD_NO || !owner_player.BUTTON_ATCK || owner_player.freezetag_frozen || owner_player.frozen) { if(self == owner_player.lgbeam) owner_player.lgbeam = world; diff --git a/textures/bloodyskull_pants.jpg b/textures/bloodyskull_pants.jpg new file mode 100644 index 000000000..e0083ac02 Binary files /dev/null and b/textures/bloodyskull_pants.jpg differ diff --git a/textures/cerberus/cerberus_text.png b/textures/cerberus/cerberus_text.png new file mode 100644 index 000000000..3ac7c0547 Binary files /dev/null and b/textures/cerberus/cerberus_text.png differ diff --git a/textures/cerberus/cerberus_text_pants.png b/textures/cerberus/cerberus_text_pants.png new file mode 100644 index 000000000..d109711e4 Binary files /dev/null and b/textures/cerberus/cerberus_text_pants.png differ diff --git a/textures/meat_pants.tga b/textures/meat_pants.tga new file mode 100644 index 000000000..1568b0956 Binary files /dev/null and b/textures/meat_pants.tga differ diff --git a/textures/spider/spidertex.tga b/textures/spider/spidertex.tga new file mode 100644 index 000000000..e9f8df1e9 Binary files /dev/null and b/textures/spider/spidertex.tga differ diff --git a/za.cfg b/za.cfg new file mode 100644 index 000000000..1e6682e82 --- /dev/null +++ b/za.cfg @@ -0,0 +1,2 @@ +set g_za 0 "Enable zombie apocalypse mutator" +set g_za_monster_count 20 \ No newline at end of file