]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Big load of updates (attempted CSQC monsters)
authorMario <mario.mario@y7mail.com>
Sat, 13 Apr 2013 07:01:21 +0000 (17:01 +1000)
committerMario <mario.mario@y7mail.com>
Sat, 13 Apr 2013 07:01:21 +0000 (17:01 +1000)
51 files changed:
commands.cfg
gamemodes.cfg
models/monsters/hknight.mdl.framegroups
models/monsters/mage.dpm
models/monsters/ogre.dpm
models/monsters/zombie.dpm.framegroups
models/monsters/zombie.dpm_3.skin [new file with mode: 0644]
monsters.cfg
qcsrc/client/Main.qc
qcsrc/client/autocvars.qh
qcsrc/client/monsters.qc [new file with mode: 0644]
qcsrc/client/monsters.qh [new file with mode: 0644]
qcsrc/client/progs.src
qcsrc/common/constants.qh
qcsrc/common/notifications.qh
qcsrc/server/autocvars.qh
qcsrc/server/command/cmd.qc
qcsrc/server/command/sv_cmd.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/monsters/lib/defs.qh
qcsrc/server/monsters/lib/monsters.qc
qcsrc/server/monsters/lib/monsters_early.qh [new file with mode: 0644]
qcsrc/server/monsters/lib/spawn.qc
qcsrc/server/monsters/monster/demon.qc
qcsrc/server/monsters/monster/dog.qc
qcsrc/server/monsters/monster/enforcer.qc
qcsrc/server/monsters/monster/fish.qc
qcsrc/server/monsters/monster/hknight.qc
qcsrc/server/monsters/monster/knight.qc
qcsrc/server/monsters/monster/ogre.qc
qcsrc/server/monsters/monster/shalrath.qc
qcsrc/server/monsters/monster/shambler.qc
qcsrc/server/monsters/monster/soldier.qc
qcsrc/server/monsters/monster/spawner.qc [deleted file]
qcsrc/server/monsters/monster/spider.qc
qcsrc/server/monsters/monster/tarbaby.qc
qcsrc/server/monsters/monster/wizard.qc
qcsrc/server/monsters/monster/zombie.qc
qcsrc/server/monsters/monsters.qh
qcsrc/server/mutators/gamemode_ctf.qc
qcsrc/server/mutators/gamemode_towerdefense.qc
qcsrc/server/mutators/mutator_zombie_apocalypse.qc
qcsrc/server/progs.src
qcsrc/server/vehicles/vehicles.qc
scripts/cerberus.shader [deleted file]
scripts/mage.shader [deleted file]
scripts/monsters.shader [new file with mode: 0644]
scripts/ogre.shader [deleted file]
scripts/shaderlist.txt
scripts/spider.shader [deleted file]

index a01ffc9c69084dae30932315f090359fc954d1c2..0fd85a569ea4ac98cd7cce84fd01d7e9425310c6 100644 (file)
@@ -105,6 +105,7 @@ alias menu_showhudoptions "menu_cmd directpanelhudmenu ${* ?}"
 alias menu_showsandboxtools "menu_cmd directmenu SandboxTools"
 alias menu_showquitdialog "menu_cmd directmenu Quit"
 alias menu_showtdtools "menu_cmd directmenu TowerDefense"
+alias menu_showmonstertools "menu_cmd directmenu MonsterTools"
 
 // command executed before loading a map by the menu
 // makes sure maxplayers is at least minplayers or bot_number + 1
@@ -181,7 +182,6 @@ alias spec "spectate"
 // mutator aliases
 alias sandbox "cmd g_sandbox ${* ?}"
 alias spawnturret "cmd turretspawn ${* ?}"
-alias debugmonsters "cmd debugmonsters ${* ?}"
 alias upgradeturret "cmd buffturret ${* ?}"
 alias rmturret "cmd turretremove ${* ?}"
 alias repairturret "cmd repairturret ${* ?}"
index d9705ad9663c522a308a502b8341912a2ae0d882..5519ce51530c4caaa97dae77bc68cd9c683aaee1 100644 (file)
@@ -224,6 +224,7 @@ set g_ctf_pass_timelimit 2 "how long a flag can stay trying to pass before it gi
 set g_ctf_pass_velocity 750 "how fast or far a player can pass the flag"
 set g_ctf_allow_vehicle_touch 0 "allow flags to be picked up/captured/returned without even leaving the vehicle"
 set g_ctf_allow_vehicle_carry 1 "allow players to hold flags inside a vehicle"
+set g_ctf_allow_monster_touch 1 "allow flags to be returned by monsters"
 
 set g_ctf_shield_max_ratio 0   "shield at most this percentage of a team from the enemy flag (try: 0.4 for 40%)"
 set g_ctf_shield_min_negscore 20       "shield the player from the flag if he's got this negative amount of points or less"
@@ -452,8 +453,8 @@ set g_td_turret_flac_cost 40
 set g_td_turret_upgrade_cost 100
 set g_td_turret_repair_cost 20
 set g_td_barricade_damage 10
-set g_td_monsters_speed_walk 75
-set g_td_monsters_speed_run 110
+set g_td_monsters_speed_walk 110
+set g_td_monsters_speed_run 150
 set g_td_monsters_spawn_delay 3
 
 // ====================
index cc16b3089dcd2d2aeee615dd323b1fce1ff23cba..c495edd8a57ba5f7ada683a39d0c013866001671 100644 (file)
@@ -1 +1 @@
-1 8 10 1 // hellknight stand\r10 19 10 1 // hellknight walk\r30 7 10 1 // hellknight run\r38 4 10 0 // hellknight pain\r43 11 10 0 // hellknight death1\r55 8 10 0 // hellknight death2\r64 15 10 0 // hellknight charge1\r80 13 10 0 // hellknight magic1\r94 12 10 0 // hellknight magic2\r107 5 10 0 // hellknight charge2\r113 9 10 1 // hellknight slice\r123 9 10 1 // hellknight smash\r133 21 10 1 // hellknight weapon attack\r155 10 10 0 //hellknight magic3
\ No newline at end of file
+1 8 10 1 // hellknight stand\r10 19 10 1 // hellknight walk\r30 7 10 1 // hellknight run\r38 4 10 0 // hellknight pain\r43 11 10 0 // hellknight death1\r55 8 10 0 // hellknight death2\r64 15 10 1 // hellknight charge1\r80 13 10 1 // hellknight magic1\r94 12 10 1 // hellknight magic2\r107 5 10 1 // hellknight charge2\r113 9 10 1 // hellknight slice\r123 9 10 1 // hellknight smash\r133 21 10 1 // hellknight weapon attack\r155 10 10 1 //hellknight magic3
\ No newline at end of file
index 3686b74af7e991ad71145d54248e145588b2cbfc..2e50fb5ca6e9fc149005b1258acea666696ac558 100644 (file)
Binary files a/models/monsters/mage.dpm and b/models/monsters/mage.dpm differ
index 0f9b30ebae9657315507ade30dee3e5d123993c3..c38482dcf8dc7d7c207bd61d33340d8eb67c8709 100644 (file)
Binary files a/models/monsters/ogre.dpm and b/models/monsters/ogre.dpm differ
index 3d56cdb2f452d770d5896be4e177e9c5355c80f1..3d38a2864cc49b0f3a9f34be0bc73c6da21ef617 100644 (file)
@@ -1,4 +1,4 @@
-1 56 30 0      // zombie attackleap         1
+1 56 30 1      // zombie attackleap         1
 57 41 60 1     // zombie attackrun1         2
 98 41 60 1     // zombie attackrun2         3
 139 41 60 1    // zombie attackrun3         4
diff --git a/models/monsters/zombie.dpm_3.skin b/models/monsters/zombie.dpm_3.skin
new file mode 100644 (file)
index 0000000..ad7e545
--- /dev/null
@@ -0,0 +1,2 @@
+bloodyskull,cleanskull
+meat,meat
\ No newline at end of file
index 78ca83fce0eb03fecdf6171a4f96e9cdc80cfb7f..88772499c6d857259a1e884076c4cc1511c8f32d 100644 (file)
@@ -168,6 +168,11 @@ set g_monster_shalrath_attack_spike_radius 60 "Vore homing spike explosion radiu
 set g_monster_shalrath_attack_spike_delay 2 "Delay between Vore homing spike attacks"
 set g_monster_shalrath_attack_melee_damage 30 "Vore magic attack damage"
 set g_monster_shalrath_attack_melee_delay 0.7 "Delay between Vore melee attacks"
+set g_monster_shalrath_heal_self 50 "Amount of health Vore will regenerate every attack when its low on health"
+set g_monster_shalrath_heal_friends 15 "Amount of health Vore will regenerate nearby friends"
+set g_monster_shalrath_heal_minhealth 250 "Health limit below which Vore will try to heal itself"
+set g_monster_shalrath_heal_range 200 "Maximum healing distance"
+set g_monster_shalrath_heal_delay 1.5 "Delay between healing bursts"
 
 // Spawner
 set g_monster_spawner 1 "Enable Monster Spawner"
index 173a93194bcacf0a17d676f88ced5ee5eed1bab6..630e34fe22c08137c6bc5290d102919e57b6afb2 100644 (file)
@@ -779,6 +779,7 @@ void CSQC_Ent_Update(float bIsNewEntity)
                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_MONSTER: ent_monster(); 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;
index 150efb1708ca705054fd00d2c30bbb20d6c18091..2d2515ad7429ed3c83e66bbe9f1d0f645e5f54b2 100644 (file)
@@ -163,6 +163,7 @@ float autocvar_g_waypointsprite_spam;
 float autocvar_g_waypointsprite_timealphaexponent;
 var float autocvar_g_waypointsprite_turrets = TRUE;
 var float autocvar_g_waypointsprite_turrets_maxdist = 5000;
+var float autocvar_g_waypointsprite_monsters_maxdist = 5000;
 
 var float autocvar_hud_cursormode = TRUE;
 float autocvar_hud_colorflash_alpha;
diff --git a/qcsrc/client/monsters.qc b/qcsrc/client/monsters.qc
new file mode 100644 (file)
index 0000000..8fc8438
--- /dev/null
@@ -0,0 +1,360 @@
+string mid2info_model;
+string mid2info_name;
+vector mid2info_min;
+vector mid2info_max;
+
+float monster_precached[MONSTER_LAST];
+void monster_mid2info(float _mid);
+
+void monster_precache(float _mid)
+{    
+    monster_mid2info(_mid);
+    if(turret_is_precache[_mid])
+        return;
+
+    switch(_mid)
+    {
+        case MONSTER_ZOMBIE:
+               {
+                       precache_model(ZOMBIE_MODEL);
+                       break;
+               }
+               case MONSTER_OGRE:
+               {
+                       precache_model(OGRE_MODEL);
+                       break;
+               }
+               case MONSTER_DEMON:
+               {
+                       precache_model(DEMON_MODEL);
+                       break;
+               }
+               case MONSTER_SHAMBLER:
+               {
+                       precache_model(SHAMBLER_MODEL);
+                       break;
+               }
+               case MONSTER_KNIGHT:
+               {
+                       precache_model(KNIGHT_MODEL);
+                       break;
+               }
+               case MONSTER_MARINE:
+               {
+                       precache_model(SOLDIER_MODEL);
+                       break;
+               }
+               case MONSTER_SCRAG:
+               {
+                       precache_model(WIZARD_MODEL);
+                       break;
+               }
+               case MONSTER_DOG:
+               {
+                       precache_model(DOG_MODEL);
+                       break;
+               }
+               case MONSTER_TARBABY:
+               {
+                       precache_model(TARBABY_MODEL);
+                       break;
+               }
+               case MONSTER_HELLKNIGHT:
+               {
+                       precache_model(HELLKNIGHT_MODEL);
+                       break;
+               }
+               case MONSTER_FISH:
+               {
+                       precache_model(FISH_MODEL);
+                       break;
+               }
+               case MONSTER_MAGE:
+               {
+                       precache_model(SHALRATH_MODEL);
+                       break;
+               }
+               case MONSTER_ENFORCER:
+               {
+                       precache_model(ENFORCER_MODEL);
+                       break;
+               }
+               case MONSTER_SPIDER:
+               {
+                       precache_model(SPIDER_MODEL);
+
+                       break;
+               }
+    }    
+    monster_precached[_mid] = TRUE;
+}
+
+void monster_mid2info(float _mid)
+{
+       switch(_mid)
+       {
+               case MONSTER_ZOMBIE:
+               {
+                       mid2info_model = ZOMBIE_MODEL;
+                       mid2info_name = "Zombie";
+                       mid2info_min = ZOMBIE_MIN;
+                       mid2info_max = ZOMBIE_MAX;
+                       break;
+               }
+               case MONSTER_OGRE:
+               {
+                       mid2info_model = OGRE_MODEL;
+                       mid2info_name = "Ogre";
+                       mid2info_min = OGRE_MIN;
+                       mid2info_max = OGRE_MAX;
+                       break;
+               }
+               case MONSTER_DEMON:
+               {
+                       mid2info_model = DEMON_MODEL;
+                       mid2info_name = "Fiend";
+                       mid2info_min = DEMON_MIN;
+                       mid2info_max = DEMON_MAX;
+                       break;
+               }
+               case MONSTER_SHAMBLER:
+               {
+                       mid2info_model = SHAMBLER_MODEL;
+                       mid2info_name = "Shambler";
+                       mid2info_min = SHAMBLER_MIN;
+                       mid2info_max = SHAMBLER_MAX;
+                       break;
+               }
+               case MONSTER_KNIGHT:
+               {
+                       mid2info_model = KNIGHT_MODEL;
+                       mid2info_name = "Knight";
+                       mid2info_min = KNIGHT_MIN;
+                       mid2info_max = KNIGHT_MAX;
+                       break;
+               }
+               case MONSTER_MARINE:
+               {
+                       mid2info_model = SOLDIER_MODEL;
+                       mid2info_name = "Marine";
+                       mid2info_min = SOLDIER_MIN;
+                       mid2info_max = SOLDIER_MAX;
+                       break;
+               }
+               case MONSTER_SCRAG:
+               {
+                       mid2info_model = WIZARD_MODEL;
+                       mid2info_name = "Scrag";
+                       mid2info_min = WIZARD_MIN;
+                       mid2info_max = WIZARD_MAX;
+                       break;
+               }
+               case MONSTER_DOG:
+               {
+                       mid2info_model = DOG_MODEL;
+                       mid2info_name = "Cerberus";
+                       mid2info_min = DOG_MIN;
+                       mid2info_max = DOG_MAX;
+                       break;
+               }
+               case MONSTER_TARBABY:
+               {
+                       mid2info_model = TARBABY_MODEL;
+                       mid2info_name = "Spawn";
+                       mid2info_min = TARBABY_MIN;
+                       mid2info_max = TARBABY_MAX;
+                       break;
+               }
+               case MONSTER_HELLKNIGHT:
+               {
+                       mid2info_model = HELLKNIGHT_MODEL;
+                       mid2info_name = "Hell-Knight";
+                       mid2info_min = HELLKNIGHT_MIN;
+                       mid2info_max = HELLKNIGHT_MAX;
+                       break;
+               }
+               case MONSTER_FISH:
+               {
+                       mid2info_model = FISH_MODEL;
+                       mid2info_name = "Rotfish";
+                       mid2info_min = FISH_MIN;
+                       mid2info_max = FISH_MAX;
+                       break;
+               }
+               case MONSTER_MAGE:
+               {
+                       mid2info_model = SHALRATH_MODEL;
+                       mid2info_name = "Mage";
+                       mid2info_min = SHALRATH_MIN;
+                       mid2info_max = SHALRATH_MAX;
+                       break;
+               }
+               case MONSTER_ENFORCER:
+               {
+                       mid2info_model = ENFORCER_MODEL;
+                       mid2info_name = "Enforcer";
+                       mid2info_min = ENFORCER_MIN;
+                       mid2info_max = ENFORCER_MAX;
+                       break;
+               }
+               case MONSTER_SPIDER:
+               {
+                       mid2info_model = SPIDER_MODEL;
+                       mid2info_name = "Spider";
+                       mid2info_min = SPIDER_MIN;
+                       mid2info_max = SPIDER_MAX;
+                       break;
+               }
+               default:
+               {
+                       dprint("WARNING: Unknown monster in CSQC\n");
+                       break;
+               }
+       }       
+}
+
+.vector glowmod;
+void monster_changeteam()
+{      
+       switch(self.team - 1)
+       {
+               case NUM_TEAM_1: // Red
+               {
+                       self.glowmod = '2 0 0';
+                       self.teamradar_color = '1 0 0';
+                       break;
+               }
+               case NUM_TEAM_2: // Blue
+               {
+                       self.glowmod = '0 0 2';
+                       self.teamradar_color = '0 0 1';
+                       break;
+               }
+               case NUM_TEAM_3: // Yellow
+               {
+                       self.glowmod = '1 1 0';
+                       self.teamradar_color = '1 1 0';
+                       break;
+               }
+               case NUM_TEAM_4: // Pink
+               {
+                       self.glowmod = '1 0 1';
+                       self.teamradar_color = '1 0 1';
+                       break;
+               }
+       }
+       
+       if(self.team)
+               self.colormap = 1024 + (self.team - 1) * 17;
+       
+}
+
+void monster_construct()
+{      
+       monster_mid2info(self.monsterid);
+       self.netname = mid2info_name;
+
+       setorigin(self, self.origin);
+       setmodel(self, mid2info_model);
+       setsize(self, mid2info_min, mid2info_max);
+       
+       self.move_movetype      = MOVETYPE_BOUNCE;
+       self.health                     = 255;
+       self.solid                      = SOLID_BBOX;
+       self.movetype           = MOVETYPE_BOUNCE; 
+       self.move_origin        = self.origin;
+       self.move_time          = time;
+       self.drawmask           = MASK_NORMAL;  
+       self.alpha                      = 1;
+}
+
+void ent_monster()
+{
+       float sf;
+       sf = ReadByte();
+
+       if(sf & MSF_SETUP)
+       {               
+               self.monsterid = ReadByte();
+                               
+               self.origin_x = ReadCoord();
+               self.origin_y = ReadCoord();
+               self.origin_z = ReadCoord();
+               setorigin(self, self.origin);
+               
+               self.angles_x = ReadAngle();
+               self.angles_y = ReadAngle();
+               
+               self.scale = ReadByte();
+               self.skin = ReadByte();
+               
+               monster_precache(self.monsterid);
+               monster_construct();
+               self.colormap = 1024;
+               self.glowmod = '0 1 1'; 
+       }
+       
+       if(sf & MSF_SIZE)
+       {
+               self.scale = ReadByte();
+               self.mins_x = ReadCoord();
+               self.mins_y = ReadCoord();
+               self.mins_z = ReadCoord();
+               
+               self.maxs_x = ReadCoord();
+               self.maxs_y = ReadCoord();
+               self.maxs_z = ReadCoord();
+
+               setsize(self, self.mins, self.maxs);
+       }
+       
+       if(sf & MSF_ANG)
+       {
+               self.move_angles_x = ReadShort();
+               self.move_angles_y = ReadShort();
+               self.angles = self.move_angles;
+       }
+       
+       if(sf & MSF_MOVE)
+       {
+               self.origin_x = ReadShort();
+               self.origin_y = ReadShort();
+               self.origin_z = ReadShort();
+               setorigin(self, self.origin);
+               
+               self.velocity_x = ReadShort();
+               self.velocity_y = ReadShort();
+               self.velocity_z = ReadShort();
+               
+               self.move_angles_y = ReadShort();
+                       
+               self.move_time   = time;
+               self.move_velocity = self.velocity;
+               self.move_origin   = self.origin;
+       }
+               
+       if(sf & MSF_ANIM)
+       {
+               self.frame1time = ReadCoord();
+               self.frame        = ReadByte();
+       }
+
+       if(sf & MSF_STATUS)
+       {
+               float _tmp;
+               _tmp = ReadByte();
+               if(_tmp != self.team)
+               {                       
+                       self.team = _tmp;                               
+                       monster_changeteam();
+               }
+               
+               _tmp = ReadByte();
+               
+               if(_tmp == 0 && self.health != 0)
+               if(self.monsterid == MONSTER_SPIDER)
+                       self.angles += '180 0 0';
+
+               self.health = _tmp;
+       }
+}
diff --git a/qcsrc/client/monsters.qh b/qcsrc/client/monsters.qh
new file mode 100644 (file)
index 0000000..aa6fb41
--- /dev/null
@@ -0,0 +1 @@
+void ent_monster();
index 3b8aa1bace9adc8970b782b4388416bda44dadc5..29e1143f69d3a41f6da52acd12c9165fa9fa2c3f 100644 (file)
@@ -46,6 +46,8 @@ bgmscript.qh
 noise.qh
 tturrets.qh
 ../server/tturrets/include/turrets_early.qh
+monsters.qh
+../server/monsters/lib/monsters_early.qh
 ../server/movelib.qc
 main.qh
 vehicles/vehicles.qh
@@ -117,6 +119,9 @@ command/cl_cmd.qc
 ../warpzonelib/client.qc
 tturrets.qc
 
+../server/monsters/monsters.qh
+monsters.qc
+
 player_skeleton.qc
 ../common/animdecide.qc
 
index 6b362fed97614407ca395292065406b7dc128f41..fd894be1f3fe0002ed1ee8658844d10cc26ec6bd 100644 (file)
@@ -101,6 +101,7 @@ const float ENT_CLIENT_NOTIFICATION = 36;
 const float ENT_CLIENT_TURRET = 40;
 const float ENT_CLIENT_AUXILIARYXHAIR = 50;
 const float ENT_CLIENT_VEHICLE = 60;
+const float ENT_CLIENT_MONSTER = 70;
 
 const float SPRITERULE_DEFAULT = 0;
 const float SPRITERULE_TEAMPLAY = 1;
index a32cc2b426c58e67f7b38776fbd70744d62a40f7..f594ee76c91e4df78d41173ea28c4f3017878d83 100644 (file)
@@ -336,11 +336,12 @@ void Send_Notification_WOVA(
        MSG_INFO_NOTIF(1, INFO_TD_NOFUEL,                          0, 0, "", "",                            "",                     _("^K1You don't have enough fuel to spawn that turret\n"), "") \
        MSG_INFO_NOTIF(1, INFO_TD_NOFUEL_REPAIR,                   0, 1, "f1", "",                          "",                         _("^K1You need %s fuel to repair this turret\n"), "") \
        MSG_INFO_NOTIF(1, INFO_TD_NOFUEL_UPGRADE,              0, 1, "f1", "",                          "",                     _("^K1You need %s fuel to increase this turret's power\n"), "") \
-       MSG_INFO_NOTIF(1, INFO_TD_PHASE_BUILD,                     0, 3, "f1 f2 f3", "",                    "",                     _("^BGWave %s^BG build phase... Next monsters: ^F2%s^BG, wave starts in ^F2%s seconds\n"), "") \
+       MSG_INFO_NOTIF(1, INFO_TD_PHASE_BUILD,                     0, 3, "f1 f2 f3", "",                    "",                     _("^BGWave ^F2%s^BG build phase... Next monsters: ^F2%s^BG, wave starts in ^F2%s seconds\n"), "") \
        MSG_INFO_NOTIF(1, INFO_TD_PHASE_COMBAT,                    0, 0, "", "",                            "",                     _("^K1Combat phase!\n"), "") \
        MSG_INFO_NOTIF(1, INFO_TD_REMOVE,                          0, 0, "", "",                            "",                     _("^BGTurret removed\n"), "") \
        MSG_INFO_NOTIF(1, INFO_TD_REPAIR,                          0, 0, "", "",                            "",                     _("^F1Turret repaired by 100 health points!\n"), "") \
        MSG_INFO_NOTIF(1, INFO_TD_SPAWN,                                   0, 0, "", "",                            "",                     _("^BGYou spawned a turret\n"), "") \
+       MSG_INFO_NOTIF(1, INFO_TD_TURRETS_DISABLED,            0, 0, "", "",                            "",                     _("^BGTurrets are disabled on this map\n"), "") \
        MSG_INFO_NOTIF(1, INFO_TD_UPGRADE,                         0, 0, "", "",                            "",                     _("^F1Turret power increased by 20 percent!\n"), "") \
        MSG_INFO_NOTIF(1, INFO_TD_VICTORY,                         1, 0, "s1", "",                          "",                     _("^F1%s^F1 victory!\n"), "") \
        MSG_INFO_NOTIF(2, INFO_VERSION_BETA,                   2, 0, "s1 s2", "",                       "",                     _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s (beta)^BG, you have ^F2Xonotic %s\n"), "") \
index 7c9177436b433bf19206973a1ce0a3bdc3e2cc1a..03cdc954b563a1a647c397035cb792b9604249e6 100644 (file)
@@ -730,6 +730,7 @@ float autocvar_g_chat_teamcolors;
 float autocvar_g_chat_tellprivacy;
 float autocvar_g_ctf_allow_vehicle_carry;
 float autocvar_g_ctf_allow_vehicle_touch;
+float autocvar_g_ctf_allow_monster_touch;
 float autocvar_g_ctf_throw;
 float autocvar_g_ctf_throw_angle_max;
 float autocvar_g_ctf_throw_angle_min;
index 6f22c5083058bcabae917e3b89824f92b4014b7b..37292d56a4e168c382dae69cc33472f3d7d554d7 100644 (file)
@@ -235,7 +235,7 @@ void ClientCommand_mobkill(float request)
                                        return;
                                }
                                sprint(self, strcat("Your pet '", trace_ent.netname, "' has been brutally mutilated.\n"));
-                               Damage (trace_ent, world, world, trace_ent.health + trace_ent.max_health, DEATH_KILL, trace_ent.origin, '0 0 0');
+                               Damage (trace_ent, world, world, trace_ent.health + trace_ent.max_health + 200, DEATH_KILL, trace_ent.origin, '0 0 0');
                                return;
                        }
                        else
@@ -276,8 +276,9 @@ void ClientCommand_mobspawn(float request, float argc)
                                return;
                        }
                        
-                       if(!IS_PLAYER(self)) { sprint(self, "You can't spawn monsters while spectating.\n"); }
-                       else if not(autocvar_g_monsters) { sprint(self, "Monsters aren't enabled.\n"); }
+                       if(autocvar_g_monsters_max <= 0 || autocvar_g_monsters_max_perplayer <= 0) { sprint(self, "Monster spawning is disabled.\n"); }
+                       else if(!IS_PLAYER(self)) { sprint(self, "You can't spawn monsters while spectating.\n"); }
+                       else if not(autocvar_g_monsters) { Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_MONSTERS_DISABLED); }
                        else if(self.vehicle) { sprint(self, "You can't spawn monsters while driving a vehicle.\n"); }
                        else if(g_td) { sprint(self, "You can't spawn monsters in Tower Defense mode.\n"); }
                        else if(self.deadflag) { sprint(self, "You can't spawn monsters while dead.\n"); }
index 2a967151d199ddeb516731976b708bb60b1cd988..f3264a40c2b36d4457bf773278f886cf2c76f770 100644 (file)
@@ -164,6 +164,9 @@ void GameCommand_butcher(float request)
                        FOR_EACH_PLAYER(head)
                                head.monstercount = 0;
                                
+                       monsters_total = 0; // reset stats?
+                       monsters_killed = 0;
+                               
                        totalspawned = 0;
                        
                        if(removed_count <= 0)
index 39a8af1fd61eb309fa56359fa69e17c756982410..d88da22fc0dd82e4708b98f609868d9cb2a3cef2 100644 (file)
@@ -627,19 +627,3 @@ 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
-.float monster_moveflags; // checks where to move when not attacking
index a667590666539eebb447b26984582f264744be11..7196c7e18974b5783fca91bdfb25fc4c52b50b51 100644 (file)
@@ -815,7 +815,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float
                        mirrorforce *= g_weaponforcefactor;
                }
                
-               if(targ.frozen && attacker.classname != "monster_spider")
+               if(targ.frozen && attacker.monsterid != MONSTER_SPIDER)
                {
                        damage = 0;
                        force *= 0.2;
index 422885af47e1cb806e2b378da98576ce8a66f05b..ca25bb982245761dd6a7704d73452d65f52816f5 100644 (file)
@@ -6,7 +6,11 @@
 
 .float candrop;
 
-.float spawner_monstercount;
+.string oldmessage;
+
+.float respawnflags;
+const float MONSTER_RESPAWN_SPAWNPOINT = 0; // re-spawn at original spawn point
+const float MONSTER_RESPAWN_DEATHPOINT = 1; // re-spawn where we died
 
 .float monster_respawned; // used to make sure we're not recounting respawned monster stats
 
@@ -45,4 +49,5 @@ const float MONSTER_MOVE_SPAWNLOC = 3; // monster will move to its spawn locatio
 const float MONSTER_MOVE_NOMOVE = 4; // monster simply stands still
 const float MONSTER_MOVE_ENEMY = 5; // used only as a movestate
 
-float MONSTER_STATE_ATTACK_LEAP = 1; // the start of something big?
+const float MONSTER_STATE_ATTACK_LEAP = 1;
+const float MONSTER_STATE_ATTACK_MELEE = 2;
index 889aeb4fc8ecfe1be91fe123bcdf8101e86a8aa0..c335d800441ca68118922dff842b85f6c03642c6 100644 (file)
@@ -79,6 +79,16 @@ void Monster_DropItem (string itype, string itemsize)
        e.nextthink = time + 0.1;
 }
 
+void monsters_setframe(float _frame)
+{
+       if(self.frame == _frame)
+               return;
+               
+       self.anim_start_time = time;
+       self.frame = _frame;
+       self.SendFlags |= MSF_ANIM;
+}
+
 float monster_isvalidtarget (entity targ, entity ent)
 {
        if(!targ || !ent)
@@ -172,21 +182,30 @@ void monster_precachesounds(entity e)
        precache_sound(e.msound_pain);
 }
 
-void monster_melee (entity targ, float damg, float er, float deathtype)
+void monster_melee (entity targ, float damg, float er, float deathtype, float dostop)
 {
-       float bigdmg = 0, rdmg = damg * random();
+       float bigdmg, dot, rdmg = damg * random();
 
        if (self.health <= 0)
                return;
        if (targ == world)
                return;
-
-       if (vlen(self.origin - targ.origin) > er * self.scale)
-               return;
                
+       if(dostop)
+       {
+               self.velocity_x = 0;
+               self.velocity_y = 0;
+               self.state = MONSTER_STATE_ATTACK_MELEE;
+               self.SendFlags |= MSF_MOVE;
+       }
+
+       makevectors (self.angles);
+       dot = normalize (targ.origin - self.origin) * v_forward;
+       
        bigdmg = rdmg * self.scale;
        
-       Damage(targ, self, self, bigdmg * monster_skill, deathtype, targ.origin, normalize(targ.origin - self.origin));
+       if(dot > er)
+               Damage(targ, self, self, bigdmg * monster_skill, deathtype, targ.origin, normalize(targ.origin - self.origin));
 }
 
 void Monster_CheckDropCvars (string mon)
@@ -214,11 +233,13 @@ void Monster_CheckDropCvars (string mon)
                Monster_DropItem("armor", "medium");
 }
 
-void ScaleMonster (float scle)
+void ScaleMonster (float scle, vector min_s, vector max_s)
 {
        // this should prevent monster from falling through floor when scale changes
        self.scale = scle;
+       setsize(self, min_s * scle, max_s * scle);
        setorigin(self, self.origin + ('0 0 30' * scle));
+       self.SendFlags |= MSF_SIZE | MSF_MOVE;
 }
 
 void Monster_CheckMinibossFlag ()
@@ -226,15 +247,19 @@ void Monster_CheckMinibossFlag ()
        if(MUTATOR_CALLHOOK(MonsterCheckBossFlag))
                return;
                
+       if(self.spawnflags & MONSTERFLAG_GIANT)
+               return; // 1 size modifier at a time
+               
        float r = random() * 4, chance = random() * 100;
 
        // g_monsters_miniboss_chance cvar or spawnflags 64 causes a monster to be a miniboss
        if ((self.spawnflags & MONSTERFLAG_MINIBOSS) || (chance < autocvar_g_monsters_miniboss_chance))
        {
                self.health += autocvar_g_monsters_miniboss_healthboost;
-               ScaleMonster(1.5);
+               ScaleMonster(1.5, self.mins, self.maxs);
                self.flags |= MONSTERFLAG_MINIBOSS;
-               self.weapon = WEP_NEX;
+               if not(self.weapon)
+                       self.weapon = WEP_NEX;
                
                if (r < 2 || self.team == NUM_TEAM_2)
                {
@@ -249,11 +274,8 @@ void Monster_CheckMinibossFlag ()
                else
                        self.effects |= (EF_FULLBRIGHT | EF_RED | EF_BLUE);
                
-               if(teamplay)
-               if(self.team)
-                       return;
-                       
-               self.colormod = randomvec() * 4;
+               if not(self.team)
+                       self.colormod = randomvec();
        }
 }
 
@@ -277,9 +299,14 @@ void Monster_Fade ()
        if(Monster_CanRespawn(self))
        {
                self.monster_respawned = TRUE;
-               setmodel(self, "");
+               self.netname = ""; // needed to fix sprite (TODO: fix!)
                self.think = self.monster_spawnfunc;
                self.nextthink = time + self.respawntime;
+               if(self.respawnflags & MONSTER_RESPAWN_DEATHPOINT)
+               {
+                       self.pos1 = self.origin;
+                       self.pos2 = self.angles;
+               }
                setorigin(self, self.pos1);
                self.angles = self.pos2;
                self.health = self.max_health; // TODO: check if resetting to max_health is wise here
@@ -292,7 +319,16 @@ void Monster_Fade ()
 
 float Monster_CanJump (vector vel)
 {
-       local vector old = self.velocity;
+       if(self.state)
+               return FALSE; // already attacking
+       if not(self.flags & FL_ONGROUND)
+               return FALSE; // not on the ground
+       if(self.health <= 0)
+               return FALSE; // called when dead?
+       if(time < self.attack_finished_single)
+               return FALSE; // still attacking
+
+       vector old = self.velocity;
        
        self.velocity = vel;
        tracetoss(self, self);
@@ -305,20 +341,15 @@ float Monster_CanJump (vector vel)
 
 float monster_leap (float anm, void() touchfunc, vector vel, float anim_finished)
 {
-       if not(self.flags & FL_ONGROUND)
-               return FALSE;
-       if(self.health < 1)
-               return FALSE; // called when dead?
-       if not(Monster_CanJump(vel))
+       if(!Monster_CanJump(vel))
                return FALSE;
                
-       self.frame = anm;
+       monsters_setframe(anm);
        self.state = MONSTER_STATE_ATTACK_LEAP;
        self.touch = touchfunc;
        self.origin_z += 1;
        self.velocity = vel;
-       if (self.flags & FL_ONGROUND)
-               self.flags -= FL_ONGROUND;
+       self.flags &~= FL_ONGROUND;
                
        self.attack_finished_single = time + anim_finished;
        
@@ -394,17 +425,20 @@ float trace_path(vector from, vector to)
        return ((trace1 < trace_fraction) ? trace1 : trace_fraction);
 }
 
+.float last_trace;
 vector monster_pickmovetarget(entity targ)
 {
        // enemy is always preferred target
        if(self.enemy)
        {
                self.monster_movestate = MONSTER_MOVE_ENEMY;
+               self.last_trace = time + 0.1;
                return self.enemy.origin;
        }
        if(targ)
        {
                self.monster_movestate = MONSTER_MOVE_WANDER;
+               self.last_trace = time + 0.5;
                return targ.origin;
        }
        
@@ -413,12 +447,14 @@ vector monster_pickmovetarget(entity targ)
                case MONSTER_MOVE_OWNER:
                {
                        self.monster_movestate = MONSTER_MOVE_OWNER;
+                       self.last_trace = time + 0.3;
                        if(self.monster_owner && self.monster_owner.classname != "monster_swarm")
                                return self.monster_owner.origin;
                }
                case MONSTER_MOVE_WANDER:
                {
                        self.monster_movestate = MONSTER_MOVE_WANDER;
+                       self.last_trace = time + 2;
                                
                        self.angles_y = random() * 500;
                        makevectors(self.angles);
@@ -427,18 +463,19 @@ vector monster_pickmovetarget(entity targ)
                case MONSTER_MOVE_SPAWNLOC:
                {
                        self.monster_movestate = MONSTER_MOVE_SPAWNLOC;
+                       self.last_trace = time + 2;
                        return self.pos1;
                }
                default:
                case MONSTER_MOVE_NOMOVE:
                {
                        self.monster_movestate = MONSTER_MOVE_NOMOVE;
+                       self.last_trace = time + 2;
                        return self.origin;
                }
        }
 }
 
-.float last_trace;
 void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_run, float manim_walk, float manim_idle)
 {
        if(self.target)
@@ -500,7 +537,7 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
        if(gameover || time < game_starttime)
        {
                runspeed = walkspeed = 0;
-               self.frame = manim_idle;
+               monsters_setframe(manim_idle);
                movelib_beak_simple(stopspeed);
                return;
        }
@@ -527,15 +564,13 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
                if(self.enemy)
                        monster_sound(self.msound_sight, 0, FALSE);
        }
+       
+       if(self.state == MONSTER_STATE_ATTACK_MELEE && time >= self.attack_finished_single)
+               self.state = 0;
                
-       if(time >= self.last_trace)
-       {
-               if(self.monster_movestate == MONSTER_MOVE_WANDER && self.goalentity.classname != "td_waypoint")
-                       self.last_trace = time + 2;
-               else
-                       self.last_trace = time + 0.5;
+       if(self.state != MONSTER_STATE_ATTACK_MELEE) // don't move if set
+       if(time >= self.last_trace || self.enemy) // update enemy instantly
                self.moveto = monster_pickmovetarget(targ);
-       }
 
        if not(self.enemy)
                monster_sound(self.msound_idle, 5, TRUE);
@@ -543,7 +578,12 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
        vector angles_face = vectoangles(self.moveto - self.origin);
        vector owner_face = vectoangles(self.monster_owner.origin - self.origin);
        vector enemy_face = vectoangles(self.enemy.origin - self.origin);
-       self.angles_y = angles_face_y;
+       
+       if(self.state != MONSTER_STATE_ATTACK_LEAP)
+       {
+               self.angles_y = angles_face_y;
+               self.v_angle = self.angles;
+       }
        
        if(self.state == MONSTER_STATE_ATTACK_LEAP && (self.flags & FL_ONGROUND))
        {
@@ -561,15 +601,15 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
        if(self.flags & FL_ONGROUND)
                movelib_jump_simple(100);
 
-       if(vlen(self.origin - self.moveto) > 64)
+       if(vlen(self.origin - self.moveto) > 64 * self.scale)
        {
-               if(self.flags & FL_FLY)
+               if(self.flags & FL_FLY || self.flags & FL_SWIM)
                        movelib_move_simple(v_forward, ((self.enemy) ? runspeed : walkspeed), 0.6);
                else
                        movelib_move_simple_gravity(v_forward, ((self.enemy) ? runspeed : walkspeed), 0.6);
                if(time > self.pain_finished)
                if(time > self.attack_finished_single)
-                       self.frame = ((self.enemy) ? manim_run : manim_walk);
+                       monsters_setframe((self.enemy) ? manim_run : manim_walk);
        }
        else
        {
@@ -578,7 +618,7 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
                if(time > self.pain_finished)
                if (vlen(self.velocity) <= 30)
                {
-                       self.frame = manim_idle;
+                       monsters_setframe(manim_idle);
                        if(self.enemy)
                                self.angles_y = enemy_face_y;
                        else
@@ -588,6 +628,10 @@ void monster_move(float runspeed, float walkspeed, float stopspeed, float manim_
                
        if(self.enemy && self.checkattack)
                self.checkattack();
+               
+       self.SendFlags |= MSF_ANG;
+       if(vlen(self.velocity) > 0)
+               self.SendFlags |= MSF_MOVE;
 }
 
 void monsters_setstatus()
@@ -596,13 +640,133 @@ void monsters_setstatus()
        self.stat_monsters_killed = monsters_killed;
 }
 
-void Monster_Appear ()
+void Monster_Appear()
 {
        self.enemy = activator;
        self.spawnflags &~= MONSTERFLAG_APPEAR;
        self.monster_spawnfunc();
 }
 
+float Monster_CheckAppearFlags(entity ent)
+{
+       if not(ent.spawnflags & MONSTERFLAG_APPEAR)
+               return FALSE;
+       
+       ent.think = func_null;
+       ent.nextthink = -1;
+       ent.use = Monster_Appear;
+       ent.flags = FL_MONSTER; // set so this monster can get butchered
+       
+       return TRUE;
+}
+
+void monsters_reset()
+{
+       setorigin(self, self.pos1);
+       self.angles = self.pos2;
+       
+       self.health = self.max_health;
+       self.velocity = '0 0 0';
+       self.enemy = world;
+       self.goalentity = world;
+       self.attack_finished_single = 0;
+       self.moveto = self.origin;
+       
+       WaypointSprite_UpdateHealth(self.sprite, self.health);
+}
+
+float monster_send(entity to, float sf)
+{
+       WriteByte(MSG_ENTITY, ENT_CLIENT_MONSTER);    
+       WriteByte(MSG_ENTITY, sf);
+       if(sf & MSF_SETUP)
+       {
+           WriteByte(MSG_ENTITY, self.monsterid);
+           
+           WriteCoord(MSG_ENTITY, self.origin_x);
+           WriteCoord(MSG_ENTITY, self.origin_y);
+           WriteCoord(MSG_ENTITY, self.origin_z);
+           
+           WriteAngle(MSG_ENTITY, self.angles_x);
+           WriteAngle(MSG_ENTITY, self.angles_y);
+               
+               WriteByte(MSG_ENTITY, self.scale);
+               WriteByte(MSG_ENTITY, self.skin);
+    }
+       
+       if(sf & MSF_SIZE)
+       {
+               WriteByte(MSG_ENTITY, self.scale);
+               
+               WriteCoord(MSG_ENTITY, self.mins_x);
+           WriteCoord(MSG_ENTITY, self.mins_y);
+           WriteCoord(MSG_ENTITY, self.mins_z);
+               
+               WriteCoord(MSG_ENTITY, self.maxs_x);
+           WriteCoord(MSG_ENTITY, self.maxs_y);
+           WriteCoord(MSG_ENTITY, self.maxs_z);
+       }
+    
+    if(sf & MSF_ANG)
+    {
+        WriteShort(MSG_ENTITY, rint(self.angles_x));
+        WriteShort(MSG_ENTITY, rint(self.angles_y));
+    }
+    
+    if(sf & MSF_MOVE)
+    {
+        WriteShort(MSG_ENTITY, rint(self.origin_x));
+        WriteShort(MSG_ENTITY, rint(self.origin_y));
+        WriteShort(MSG_ENTITY, rint(self.origin_z));
+
+        WriteShort(MSG_ENTITY, rint(self.velocity_x));
+        WriteShort(MSG_ENTITY, rint(self.velocity_y));
+        WriteShort(MSG_ENTITY, rint(self.velocity_z));        
+        
+        WriteShort(MSG_ENTITY, rint(self.angles_y));        
+    }
+    
+    if(sf & MSF_ANIM)
+    {
+        WriteCoord(MSG_ENTITY, self.anim_start_time);
+        WriteByte(MSG_ENTITY, self.frame);
+    }
+    
+    if(sf & MSF_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 monster_link(void() spawnproc)
+{
+    Net_LinkEntity(self, TRUE, 0, monster_send);
+    self.think      = spawnproc;
+    self.nextthink  = time;
+}
+
+void monsters_corpse_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+{
+       self.health -= damage;
+               
+       Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker);
+               
+       if(self.health <= -100) // 100 health until gone?
+       {
+               Violence_GibSplash(self, 1, 0.5, attacker);
+               
+               self.think = SUB_Remove;
+               self.nextthink = time + 0.1;
+       }
+}
+
 void monsters_damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
 {
        if(self.frozen && deathtype != DEATH_KILL)
@@ -615,7 +779,8 @@ void monsters_damage (entity inflictor, entity attacker, float damage, float dea
        if(monster_isvalidtarget(attacker, self))
                self.enemy = attacker;
                
-       damage *= self.armorvalue;
+       if(deathtype != DEATH_KILL)
+               damage *= self.armorvalue;
                
        self.health -= damage;
        
@@ -660,14 +825,23 @@ void monsters_damage (entity inflictor, entity attacker, float damage, float dea
                frag_attacker = attacker;
                frag_target = self;
                MUTATOR_CALLHOOK(MonsterDies);
+               
+               if(self.health <= -100) // check if we're already gibbed
+               {
+                       Violence_GibSplash(self, 1, 0.5, attacker);
+               
+                       self.think = SUB_Remove;
+                       self.nextthink = time + 0.1;
+               }
        }
+       
+       self.SendFlags |= MSF_STATUS;
 }
 
 // used to hook into monster post death functions without a mutator
 void monster_hook_death()
 {
-       if(self.sprite)
-        WaypointSprite_Kill(self.sprite);
+       WaypointSprite_Kill(self.sprite);
                
        if(self.weaponentity)
        {
@@ -683,26 +857,31 @@ void monster_hook_death()
        if(self.candrop && self.weapon)
                W_ThrowNewWeapon(self, self.weapon, 0, self.origin, randomvec() * 150 + '0 0 325');     
                
-       if(self.realowner.classname == "monster_spawner")
-               self.realowner.spawner_monstercount -= 1;
-               
        if(IS_CLIENT(self.realowner))
                self.realowner.monstercount -= 1;
                
+       self.event_damage       = monsters_corpse_damage;
+       self.solid                      = SOLID_CORPSE;
+       self.takedamage         = DAMAGE_AIM;
+       self.enemy                      = world;
+       self.movetype           = MOVETYPE_TOSS;
+               
        totalspawned -= 1;
 }
 
 // used to hook into monster post spawn functions without a mutator
 void monster_hook_spawn()
 {
-       Monster_CheckMinibossFlag();
+       if not(self.monster_respawned)
+               Monster_CheckMinibossFlag();
 
        self.max_health = self.health;
        self.pain_finished = self.nextthink;
+       self.anim_start_time = time;
 
        monster_precachesounds(self);
        
-       if(teamplay && self.team)
+       if(self.team)
        {
                //self.colormod = Team_ColorRGB(self.team);
                //self.glowmod = self.colormod;
@@ -725,17 +904,21 @@ void monster_hook_spawn()
                
        if(autocvar_g_monsters_healthbars)
        {
-               WaypointSprite_Spawn(self.netname, 0, 600, self, '0 0 1' * self.sprite_height, world, 0, self, sprite, FALSE, RADARICON_DANGER, ((self.team) ? Team_ColorRGB(self.team) : '1 0 0'));    
+               WaypointSprite_Spawn(self.message, 0, 600, self, '0 0 1' * self.sprite_height, world, 0, self, sprite, FALSE, RADARICON_DANGER, ((self.team) ? Team_ColorRGB(self.team) : '1 0 0'));    
                WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
                WaypointSprite_UpdateHealth(self.sprite, self.health);
        }
        
+       self.message = self.oldmessage;
+       
        monster_sound(self.msound_spawn, 0, FALSE);
 
        MUTATOR_CALLHOOK(MonsterSpawn);
+       
+       self.SendFlags = MSF_SETUP;
 }
 
-float monster_initialize(string  net_name,
+float monster_initialize(string  net_name, float mon_id,
                                                 string  bodymodel,
                                                 vector  min_s,
                                                 vector  max_s,
@@ -753,35 +936,36 @@ float monster_initialize(string  net_name,
        if(monster_skill == autocvar_g_monsters_skill_insane && (self.spawnflags & MONSTERSKILL_NOTINSANE)) { return FALSE; }
        if(monster_skill >= autocvar_g_monsters_skill_nightmare && (self.spawnflags & MONSTERSKILL_NOTNIGHTMARE)) { return FALSE; }
 
-       if(self.model == "")
+       if(self.model == "" || self.model == "null")
        if(bodymodel == "")
                error("monsters: missing bodymodel!");
 
        if(self.netname == "")
        {
                if(net_name != "" && IS_PLAYER(self.realowner))
-                       net_name = strzone(strdecolorize(sprintf("%s's %s", self.realowner.netname, net_name)));
+                       net_name = strzone(sprintf("%s^7's %s", self.realowner.netname, net_name));
                self.netname = ((net_name == "") ? self.classname : net_name);
+               self.oldmessage = self.message;
+               self.message = strzone(strdecolorize(self.netname));
        }
        
+       if(autocvar_g_monsters_giants_only)
+               self.spawnflags |= MONSTERFLAG_GIANT;
+       
        if not(self.scale)
                self.scale = 1;
-       
-       if(self.spawnflags & MONSTERFLAG_GIANT && !autocvar_g_monsters_nogiants)
-               ScaleMonster(5);
-       else
-               ScaleMonster(self.scale);
                
-       min_s *= self.scale;
-       max_s *= self.scale;
-
+       if(self.spawnflags & MONSTERFLAG_GIANT && !autocvar_g_monsters_nogiants)
+               self.scale = 5;
+       
+       
        if(self.team && !teamplay)
                self.team = 0;
 
        self.flags = FL_MONSTER;
        
-       if(self.model != "")
-               bodymodel = self.model;
+       if(self.model && self.model != "null")
+               bodymodel = self.model; // TODO: find out why monsters can become invisible
                
        if not(self.spawnflags & MONSTERFLAG_SPAWNED) // naturally spawned monster
        if not(self.monster_respawned)
@@ -790,14 +974,14 @@ float monster_initialize(string  net_name,
        precache_model(bodymodel);
 
        setmodel(self, bodymodel);
-       
-       setsize(self, min_s, max_s);
+       ScaleMonster(self.scale, min_s, max_s);
 
        self.takedamage                 = DAMAGE_AIM;
        self.bot_attack                 = TRUE;
        self.iscreature                 = TRUE;
        self.teleportable               = TRUE;
        self.damagedbycontents  = TRUE;
+       self.monsterid                  = mon_id;
        self.damageforcescale   = 0.003;
        self.monster_die                = dieproc;
        self.event_damage               = monsters_damage;
@@ -807,17 +991,19 @@ float monster_initialize(string  net_name,
        self.movetype                   = MOVETYPE_WALK;
        self.delay                              = -1; // used in attack delay code
        monsters_spawned           += 1;
-       self.think                              = spawnproc;
-       self.nextthink                  = time;
        self.enemy                              = world;
        self.velocity                   = '0 0 0';
        self.moveto                             = self.origin;
-       self.pos1                               = self.origin;
        self.pos2                               = self.angles;
+       self.reset                              = monsters_reset;
        self.candrop                    = TRUE;
+       self.view_ofs                   = '0 0 1' * self.maxs_z;
+       
+       if not(self.ticrate)
+               self.ticrate = 0.05;
        
        if not(self.armorvalue)
-               self.armorvalue = 1;
+               self.armorvalue = 1; // multiplier
        
        if not(self.target_range)
                self.target_range = autocvar_g_monsters_target_range;
@@ -837,9 +1023,13 @@ float monster_initialize(string  net_name,
        if not(nodrop)
        {
                setorigin(self, self.origin);
-               tracebox(self.origin + '0 0 100', min_s, max_s, self.origin - '0 0 10000', MOVE_WORLDONLY, self);
+               tracebox(self.origin + '0 0 100', self.mins, self.maxs, self.origin - '0 0 10000', MOVE_WORLDONLY, self);
                setorigin(self, trace_endpos);
        }
+       
+       self.pos1 = self.origin;
+       
+       monster_link(spawnproc);
 
        return TRUE;
 }
diff --git a/qcsrc/server/monsters/lib/monsters_early.qh b/qcsrc/server/monsters/lib/monsters_early.qh
new file mode 100644 (file)
index 0000000..5a2f2b7
--- /dev/null
@@ -0,0 +1,52 @@
+// for definitions used outside the monsters folder
+
+#ifdef SVQC
+.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
+.float monster_moveflags; // checks where to move when not attacking
+#endif // SVQC
+
+#ifndef MENUQC
+.float monsterid;
+// Monster IDs
+float MONSTER_FIRST            = 1;
+float MONSTER_ZOMBIE           = 2;
+float MONSTER_OGRE                     = 3;
+float MONSTER_DEMON            = 4;
+float MONSTER_SHAMBLER                 = 5;
+float MONSTER_KNIGHT           = 6;
+float MONSTER_MARINE           = 7;
+float MONSTER_SCRAG            = 8;
+float MONSTER_DOG                      = 9;
+float MONSTER_TARBABY          = 10;
+float MONSTER_HELLKNIGHT       = 11;
+float MONSTER_FISH                     = 12;
+float MONSTER_MAGE                     = 13;
+float MONSTER_ENFORCER                 = 14;
+float MONSTER_SPIDER           = 15;
+float MONSTER_LAST                     = 16;
+
+float MSF_UPDATE       = 2;
+float MSF_STATUS       = 4;
+float MSF_SETUP        = 8;
+float MSF_ANG          = 16;
+float MSF_MOVE         = 32;
+.float anim_start_time;
+float MSF_ANIM         = 64;
+float MSF_SIZE            = 128;
+
+float MSF_FULL_UPDATE  = 16777215;
+
+#endif // CSQC/SVQC
\ No newline at end of file
index 87704d80f2524ff202d07031d7286ff308299b29..40c2b7f6c99769dcd77d32747c18b124f3faa81a 100644 (file)
@@ -10,14 +10,6 @@ float spawnmonster_checkinlist(string monster, string list)
 
 entity spawnmonster (string monster, entity spawnedby, entity own, vector orig, float respwn, float moveflag)
 {
-       if not(autocvar_g_monsters)
-       {
-               if(IS_CLIENT(spawnedby))
-                       Send_Notification(NOTIF_ONE, spawnedby, MSG_INFO, INFO_MONSTERS_DISABLED);
-                       
-               return world;
-       }
-       
        if(!spawncode_first_load)
        {
                initialize_field_db();
@@ -43,24 +35,21 @@ entity spawnmonster (string monster, entity spawnedby, entity own, vector orig,
        
        if (spawnedby.classname == "monster_swarm")
                e.monster_owner = own;  
-       else if(IS_CLIENT(spawnedby))
+       else if(IS_PLAYER(spawnedby))
        {
                if(teamplay && autocvar_g_monsters_teams)
                        e.team = spawnedby.team; // colors handled in spawn code
                        
-               if(teamplay)
+               if(e.team)
                        e.colormap = 1024;
                else
                        e.colormap = spawnedby.colormap;
                        
                if(autocvar_g_monsters_owners)
-                       e.monster_owner = own; // using owner makes the monster non-solid for its master
+                       e.monster_owner = own; // using .owner makes the monster non-solid for its master
                        
                e.angles = spawnedby.angles;
        }
-       
-       if(autocvar_g_monsters_giants_only)
-               e.spawnflags |= MONSTERFLAG_GIANT;
                
        monster = strcat("$ spawnfunc_monster_", monster);
                
index 55d189a4fb7b7585fa2aecb5a7ce5a9bde814294..3e52b8cc21a93d7bd10670d88c60bd7bca9df634 100644 (file)
@@ -1,3 +1,14 @@
+#ifndef MENUQC
+// size
+const vector DEMON_MIN = '-32 -32 -24';
+const vector DEMON_MAX = '32 32 24';
+
+// model
+string DEMON_MODEL = "models/monsters/demon.mdl";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_demon;
 float autocvar_g_monster_demon_health;
@@ -6,35 +17,29 @@ float autocvar_g_monster_demon_damage;
 float autocvar_g_monster_demon_speed_walk;
 float autocvar_g_monster_demon_speed_run;
 
-// size
-const vector DEMON_MIN = '-32 -32 -24';
-const vector DEMON_MAX = '32 32 24';
-
-// animation
-#define demon_anim_stand  0
-#define demon_anim_walk   1
-#define demon_anim_run 2
-#define demon_anim_leap   3
-#define demon_anim_pain   4
-#define demon_anim_death  5
-#define demon_anim_attack 6
+// animations
+const float demon_anim_stand   = 0;
+const float demon_anim_walk            = 1;
+const float demon_anim_run             = 2;
+const float demon_anim_leap            = 3;
+const float demon_anim_pain            = 4;
+const float demon_anim_death   = 5;
+const float demon_anim_attack  = 6;
 
 void demon_think ()
 {
        self.think = demon_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        monster_move(autocvar_g_monster_demon_speed_run, autocvar_g_monster_demon_speed_walk, 100, demon_anim_run, demon_anim_walk, demon_anim_stand);
 }
 
 void demon_attack_melee ()
 {
-       float bigdmg = autocvar_g_monster_demon_damage * self.scale;
-       
-       self.frame = demon_anim_attack;
+       monsters_setframe(demon_anim_attack);
        self.attack_finished_single = time + 1;
        
-       monster_melee(self.enemy, bigdmg * monster_skill, 120, DEATH_MONSTER_FIEND);
+       monster_melee(self.enemy, autocvar_g_monster_demon_damage, 0.3, DEATH_MONSTER_FIEND, TRUE);
 }
 
 void Demon_JumpTouch ()
@@ -70,14 +75,9 @@ void demon_die ()
 {
        Monster_CheckDropCvars ("demon");
        
-       self.frame                      = demon_anim_death;
-       self.think                      = Monster_Fade; 
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.movetype           = MOVETYPE_TOSS;
-       self.enemy                      = world;
-       self.nextthink          = time + 3;
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe(demon_anim_death);
        
        monster_hook_death(); // for post-death mods
 }
@@ -93,33 +93,28 @@ void demon_spawn ()
        self.attack_melee               = demon_attack_melee;
        self.attack_ranged              = demon_jump;
        self.nextthink                  = time + random() * 0.5 + 0.1;
-       self.frame                              = demon_anim_stand;
        self.think                              = demon_think;
        self.sprite_height              = 30;
        
+       monsters_setframe(demon_anim_stand);
+       
        monster_hook_spawn(); // for post-spawn mods
 }
 
-/* QUAKED monster_demon (1 0 0) (-32 -32 -24) (32 32 64) Ambush */
 void spawnfunc_monster_demon ()
 {      
        if not(autocvar_g_monster_demon) { remove(self); return; }
        
        self.monster_spawnfunc = spawnfunc_monster_demon;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        self.scale = 1.3;
        
        if not (monster_initialize(
-                        "Fiend",
-                        "models/monsters/demon.mdl",
+                        "Fiend", MONSTER_DEMON,
+                        DEMON_MODEL,
                         DEMON_MIN, DEMON_MAX,
                         FALSE,
                         demon_die, demon_spawn))
@@ -131,3 +126,5 @@ void spawnfunc_monster_demon ()
 
 // Compatibility with old spawns
 void spawnfunc_monster_demon1 () { spawnfunc_monster_demon(); }
+
+#endif // SVQC
index 686ad510fa62f94223e06849d55a0b5f4ef7742c..0095a905b4dbe4c722c61e0973c682b91c56e30d 100644 (file)
@@ -1,7 +1,14 @@
+#ifndef MENUQC
 // size
 const vector DOG_MAX = '16 16 12';
 const vector DOG_MIN = '-16 -16 -24';
 
+// model
+string DOG_MODEL = "models/monsters/dog.dpm";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_dog;
 float autocvar_g_monster_dog_health;
@@ -11,12 +18,12 @@ float autocvar_g_monster_dog_speed_walk;
 float autocvar_g_monster_dog_speed_run;
 
 // animations
-#define dog_anim_idle          0
-#define dog_anim_walk          1
-#define dog_anim_run           2
-#define dog_anim_attack        3
-#define dog_anim_die           4
-#define dog_anim_pain          5
+const float dog_anim_idle      = 0;
+const float dog_anim_walk      = 1;
+const float dog_anim_run       = 2;
+const float dog_anim_attack    = 3;
+const float dog_anim_die       = 4;
+const float dog_anim_pain      = 5;
 
 void Dog_JumpTouch ()
 {
@@ -37,19 +44,17 @@ void Dog_JumpTouch ()
 void dog_think ()
 {
        self.think = dog_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        monster_move(autocvar_g_monster_dog_speed_run, autocvar_g_monster_dog_speed_walk, 50, dog_anim_run, dog_anim_walk, dog_anim_idle);
 }
 
 void dog_attack ()
 {
-       float bigdmg = autocvar_g_monster_dog_bite_damage * self.scale;
-       
-       self.frame = dog_anim_attack;
+       monsters_setframe(dog_anim_attack);
        self.attack_finished_single = time + 0.7;
 
-       monster_melee(self.enemy, bigdmg * monster_skill, 100, DEATH_MONSTER_DOG_BITE);
+       monster_melee(self.enemy, autocvar_g_monster_dog_bite_damage, 0.2, DEATH_MONSTER_DOG_BITE, TRUE);
 }
 
 float dog_jump ()
@@ -65,14 +70,9 @@ void dog_die ()
 {
        Monster_CheckDropCvars ("dog");
        
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.nextthink          = time + 2.1;
-       self.think                      = Monster_Fade;
-       self.movetype           = MOVETYPE_TOSS;
-       self.frame                      = dog_anim_die;
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe(dog_anim_die);
        
        monster_hook_death(); // for post-death mods
 }
@@ -89,8 +89,8 @@ void dog_spawn ()
        self.checkattack                = GenericCheckAttack;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = dog_think;
-       self.frame                              = dog_anim_idle;
        self.sprite_height              = 20;
+       monsters_setframe(dog_anim_idle);
        
        monster_hook_spawn(); // for post-spawn mods
 }
@@ -101,17 +101,12 @@ void spawnfunc_monster_dog ()
        
        self.monster_spawnfunc = spawnfunc_monster_dog;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        if not (monster_initialize(
-                        "Cerberus",
-                        "models/monsters/dog.dpm",
+                        "Cerberus", MONSTER_DOG,
+                        DOG_MODEL,
                         DOG_MIN, DOG_MAX,
                         FALSE,
                         dog_die, dog_spawn))
@@ -120,3 +115,5 @@ void spawnfunc_monster_dog ()
                return;
        }
 }
+
+#endif // SVQC
index d52fdd0467079dec142c01b701a466cdaa5db164..88af41902c3bef7c08e0422efcd2fa397ba3fd06 100644 (file)
@@ -1,7 +1,14 @@
+#ifndef MENUQC
 // size
 const vector ENFORCER_MIN = '-32 -32 0';
 const vector ENFORCER_MAX = '32 32 64';
 
+// model
+string ENFORCER_MODEL = "models/turrets/ewheel-base2.md3";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_enforcer;
 float autocvar_g_monster_enforcer_health;
@@ -10,16 +17,16 @@ float autocvar_g_monster_enforcer_speed_run;
 float autocvar_g_monster_enforcer_attack_uzi_bullets;
 
 // animations
-#define enforcer_anim_stop             0
-#define enforcer_anim_walk             1
-#define enforcer_anim_run              2
-#define enforcer_anim_walkback         3
-#define enforcer_anim_runback  4
+const float enforcer_anim_stop                 = 0;
+const float enforcer_anim_walk                 = 1;
+const float enforcer_anim_run          = 2;
+const float enforcer_anim_walkback     = 3;
+const float enforcer_anim_runback      = 4;
 
 void enforcer_think ()
 {
        self.think = enforcer_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        if(self.delay != -1)
                self.nextthink = self.delay;
@@ -27,30 +34,6 @@ void enforcer_think ()
        monster_move(autocvar_g_monster_enforcer_speed_run, autocvar_g_monster_enforcer_speed_walk, 100, enforcer_anim_run, enforcer_anim_walk, enforcer_anim_stop);
 }
 
-void enforcer_laser ()
-{
-       self.attack_finished_single = time + 0.8;
-       W_Laser_Attack(0);
-}
-
-float enf_missile_laser ()
-{
-       enforcer_laser();
-       return TRUE;
-}
-
-void enforcer_shotgun ()
-{
-       self.attack_finished_single = time + 0.8;
-       W_Shotgun_Attack();
-}
-
-float enf_missile_shotgun ()
-{
-       enforcer_shotgun();
-       return TRUE;
-}
-
 .float enf_cycles;
 void enforcer_uzi_fire ()
 {
@@ -67,56 +50,56 @@ void enforcer_uzi_fire ()
        self.monster_delayedattack = enforcer_uzi_fire;
 }
 
-void enforcer_uzi ()
-{
-       self.attack_finished_single = time + 0.8;
-       self.delay = time + 0.1;
-       self.monster_delayedattack = enforcer_uzi_fire;
-}
-
-float enf_missile_uzi ()
-{
-       self.enf_cycles = 0;
-       enforcer_uzi();
-       return TRUE;
-}
-
-void enforcer_rl ()
-{
-       self.attack_finished_single = time + 0.8;
-       W_Rocket_Attack();
-}
-
-float enf_missile_rocket ()
-{
-       enforcer_rl();
-       return TRUE;
-}
-
-void enforcer_electro ()
-{
-       self.attack_finished_single = time + 0.8;
-       W_Electro_Attack();
-}
-
-float enf_missile_plasma ()
+float enforcer_attack()
 {
-       enforcer_electro();
-       return TRUE;
+       makevectors(self.angles);
+       switch(self.weapon)
+       {
+               case WEP_ROCKET_LAUNCHER:
+               {
+                       self.attack_finished_single = time + 0.8;
+                       W_Rocket_Attack();
+                       return TRUE;
+               }
+               case WEP_ELECTRO:
+               {
+                       self.attack_finished_single = time + 0.8;
+                       W_Electro_Attack();
+                       return TRUE;
+               }
+               case WEP_SHOTGUN:
+               {
+                       self.attack_finished_single = time + 0.8;
+                       W_Shotgun_Attack();
+                       return TRUE;
+               }
+               case WEP_UZI:
+               {
+                       self.enf_cycles = 0;
+                       self.attack_finished_single = time + 0.8;
+                       self.delay = time + 0.1;
+                       self.monster_delayedattack = enforcer_uzi_fire;
+                       return TRUE;
+               }
+               case WEP_LASER:
+               {
+                       self.attack_finished_single = time + 0.8;
+                       W_Laser_Attack(0);
+               }
+               default:
+                       return FALSE; // no weapon?
+       }
+       
+       // never gets here
 }
 
 void enforcer_die ()
 {
        Monster_CheckDropCvars ("enforcer");
        
-       self.solid                      = SOLID_NOT;
-       self.movetype           = MOVETYPE_TOSS;
-       self.think                      = Monster_Fade;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.nextthink          = time + 2.1;
-       self.frame                      = enforcer_anim_stop;
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe(enforcer_anim_stop);
                
        monster_hook_death(); // for post-death mods
 }
@@ -133,6 +116,8 @@ void enforcer_spawn ()
        self.think                              = enforcer_think;
        self.items                              = (IT_SHELLS | IT_ROCKETS | IT_NAILS | IT_CELLS);
        self.sprite_height              = 45;
+       self.attack_ranged              = enforcer_attack;
+       self.view_ofs              *= 0.5;
        
        self.weaponentity = spawn();
        self.weaponentity.owner = self;
@@ -143,32 +128,14 @@ void enforcer_spawn ()
        setmodel(self.weaponentity, "models/turrets/ewheel-gun1.md3");
        setattachment(self.weaponentity, self, "tag_head");
        
-       local float r = random();
-       if (r < 0.20)
-       {
-               self.attack_ranged = enf_missile_rocket;
-               self.weapon = WEP_ROCKET_LAUNCHER;
-       }
-       else if (r < 0.40)
-       {
-               self.attack_ranged = enf_missile_plasma;
-               self.weapon = WEP_ELECTRO;
-       }
-       else if (r < 0.60)
-       {
-               self.attack_ranged = enf_missile_shotgun;
-               self.weapon = WEP_SHOTGUN;
-       }
-       else if (r < 0.80)
-       {
-               self.attack_ranged = enf_missile_uzi;
-               self.weapon = WEP_UZI;
-       }
-       else
-       {
-               self.attack_ranged = enf_missile_laser;
-               self.weapon = WEP_LASER;
-       }
+       RandomSelection_Init();
+       RandomSelection_Add(world, WEP_ROCKET_LAUNCHER, "", 1, 1);
+       RandomSelection_Add(world, WEP_ELECTRO, "", 1, 1);
+       RandomSelection_Add(world, WEP_SHOTGUN, "", 1, 1);
+       RandomSelection_Add(world, WEP_UZI, "", 1, 1);
+       RandomSelection_Add(world, WEP_LASER, "", 1, 1);
+       
+       self.weapon = RandomSelection_chosen_float;
                
        monster_hook_spawn(); // for post-spawn mods
 }
@@ -179,17 +146,12 @@ void spawnfunc_monster_enforcer ()
        
        self.monster_spawnfunc = spawnfunc_monster_enforcer;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        if not (monster_initialize(
-                        "Enforcer",
-                        "models/turrets/ewheel-base2.md3",
+                        "Enforcer", MONSTER_ENFORCER,
+                        ENFORCER_MODEL,
                         ENFORCER_MIN, ENFORCER_MAX,
                         FALSE,
                         enforcer_die, enforcer_spawn))
@@ -198,3 +160,5 @@ void spawnfunc_monster_enforcer ()
                return;
        }
 }
+
+#endif // SVQC
index 31e74c6916c4aa0776812e589ef35c30a3f6d46f..677a496f883ff3d5bea8a1f5397598af2c9d4330 100644 (file)
@@ -1,7 +1,14 @@
+#ifndef MENUQC
 // size
 const vector FISH_MIN = '-16 -16 -24';
 const vector FISH_MAX = '16 16 16';
 
+// model
+string FISH_MODEL = "models/monsters/fish.mdl";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_fish;
 float autocvar_g_monster_fish_health;
@@ -10,40 +17,34 @@ float autocvar_g_monster_fish_speed_walk;
 float autocvar_g_monster_fish_speed_run;
 
 // animations
-#define fish_anim_attack 0
-#define fish_anim_death  1
-#define fish_anim_swim   2
-#define fish_anim_pain   3
+const float fish_anim_attack = 0;
+const float fish_anim_death  = 1;
+const float fish_anim_swim   = 2;
+const float fish_anim_pain   = 3;
 
 void fish_think ()
 {
        self.think = fish_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        monster_move(autocvar_g_monster_fish_speed_run, autocvar_g_monster_fish_speed_walk, 10, fish_anim_swim, fish_anim_swim, fish_anim_swim);
 }
 
 void fish_attack ()
 {
-       float bigdmg = autocvar_g_monster_fish_damage * self.scale;
-       
-       self.frame = fish_anim_attack;
+       monsters_setframe(fish_anim_attack);
        self.attack_finished_single = time + 0.5;
 
-       monster_melee(self.enemy, bigdmg * monster_skill, 60, DEATH_MONSTER_FISH);
+       monster_melee(self.enemy, autocvar_g_monster_fish_damage, 0.1, DEATH_MONSTER_FISH, FALSE);
 }
 
 void fish_die ()
 {
        Monster_CheckDropCvars ("fish");
        
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.frame                      = fish_anim_death;
-       self.think                      = Monster_Fade;
-       self.nextthink          = time + 2.1;
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe(fish_anim_death);
        
        monster_hook_death(); // for post-death mods
 }
@@ -71,19 +72,14 @@ void spawnfunc_monster_fish ()
        
        self.monster_spawnfunc = spawnfunc_monster_fish;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        self.scale = 1.3;
        
        if not (monster_initialize(
-                        "Rotfish",
-                        "models/monsters/fish.mdl",
+                        "Rotfish", MONSTER_FISH,
+                        FISH_MODEL,
                         FISH_MIN, FISH_MAX,
                         TRUE,
                         fish_die, fish_spawn))
@@ -92,3 +88,5 @@ void spawnfunc_monster_fish ()
                return;
        }
 }
+
+#endif // SVQC
index 22333f1aef58f6283bb1e17af7a2d4add07061f6..fca42d953a88da9e4a7c535aaf9b39b4abd6010f 100644 (file)
@@ -1,7 +1,14 @@
+#ifndef MENUQC
 // size
 const vector HELLKNIGHT_MIN = '-16 -16 -24';
 const vector HELLKNIGHT_MAX = '16 16 32';
 
+// model
+string HELLKNIGHT_MODEL = "models/monsters/hknight.mdl";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_hellknight;
 float autocvar_g_monster_hellknight_health;
@@ -26,20 +33,20 @@ float autocvar_g_monster_hellknight_jump_damage;
 float autocvar_g_monster_hellknight_jump_dist;
 
 // animations
-#define hellknight_anim_stand  0
-#define hellknight_anim_walk   1
-#define hellknight_anim_run    2
-#define hellknight_anim_pain   3
-#define hellknight_anim_death1         4
-#define hellknight_anim_death2         5
-#define hellknight_anim_charge1 6
-#define hellknight_anim_magic1         7
-#define hellknight_anim_magic2         8
-#define hellknight_anim_charge2 9
-#define hellknight_anim_slice  10
-#define hellknight_anim_smash  11
-#define hellknight_anim_wattack 12
-#define hellknight_anim_magic3         13
+const float hellknight_anim_stand      = 0;
+const float hellknight_anim_walk       = 1;
+const float hellknight_anim_run        = 2;
+const float hellknight_anim_pain       = 3;
+const float hellknight_anim_death1     = 4;
+const float hellknight_anim_death2     = 5;
+const float hellknight_anim_charge1 = 6;
+const float hellknight_anim_magic1     = 7;
+const float hellknight_anim_magic2     = 8;
+const float hellknight_anim_charge2 = 9;
+const float hellknight_anim_slice      = 10;
+const float hellknight_anim_smash      = 11;
+const float hellknight_anim_wattack = 12;
+const float hellknight_anim_magic3     = 13;
 
 void hknight_spike_think()
 {
@@ -120,7 +127,7 @@ float hknight_checkmagic ()
        local float dot = 0;
 
        // use magic to kill zombies as they heal too fast for sword
-       if (self.enemy.classname == "monster_zombie")
+       if (self.enemy.monsterid == MONSTER_ZOMBIE)
        {
                traceline((self.absmin + self.absmax) * 0.5, (self.enemy.absmin + self.enemy.absmax) * 0.5, FALSE, self);
                if (trace_ent == self.enemy)
@@ -172,7 +179,7 @@ void CheckContinueCharge ()
 void hellknight_think ()
 {
        self.think = hellknight_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        monster_move(autocvar_g_monster_hellknight_speed_run, autocvar_g_monster_hellknight_speed_walk, 100, hellknight_anim_run, hellknight_anim_walk, hellknight_anim_stand);
 }
@@ -185,7 +192,7 @@ void hellknight_magic ()
        
        if(self.hknight_cycles >= 5)
        {
-               self.frame = hellknight_anim_magic1;
+               monsters_setframe(hellknight_anim_magic1);
                self.attack_finished_single = time + 0.7;
                hknight_infernowarning();
                self.think = hellknight_think;
@@ -247,7 +254,7 @@ void hellknight_fireball ()
 
 void hellknight_magic2 ()
 {
-       self.frame = hellknight_anim_magic2;
+       monsters_setframe(hellknight_anim_magic2);
        self.attack_finished_single = time + 1.2;
        self.delay = time + 0.4;
        self.monster_delayedattack = hellknight_fireball;
@@ -265,7 +272,7 @@ void hellknight_spikes ()
 
 void hellknight_magic3 ()
 {
-       self.frame = hellknight_anim_magic3;
+       monsters_setframe(hellknight_anim_magic3);
        self.attack_finished_single = time + 1;
        self.think = hellknight_spikes;
        self.nextthink = time + 0.4;
@@ -273,42 +280,42 @@ void hellknight_magic3 ()
 
 void hellknight_charge ()
 {
-       self.frame = hellknight_anim_charge1;
+       monsters_setframe(hellknight_anim_charge1);
        self.attack_finished_single = time + 0.5;
        
        hknight_checkmagic();
-       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 70, DEATH_MONSTER_HKNIGHT_MELEE);
+       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
        hknight_checkmagic();
 }
 
 void hellknight_charge2 ()
 {
-       self.frame = hellknight_anim_charge2;
+       monsters_setframe(hellknight_anim_charge2);
        self.attack_finished_single = time + 0.5;
        
        CheckContinueCharge ();
-       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 70, DEATH_MONSTER_HKNIGHT_MELEE);
+       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
 }
 
 void hellknight_slice ()
 {
-       self.frame = hellknight_anim_slice;
+       monsters_setframe(hellknight_anim_slice);
        self.attack_finished_single = time + 0.7;
-       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 70, DEATH_MONSTER_HKNIGHT_MELEE);
+       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
 }
 
 void hellknight_smash ()
 {
-       self.frame = hellknight_anim_smash;
+       monsters_setframe(hellknight_anim_smash);
        self.attack_finished_single = time + 0.7;
-       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 70, DEATH_MONSTER_HKNIGHT_MELEE);
+       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
 }
 
 void hellknight_weapon_attack ()
 {
-       self.frame = hellknight_anim_wattack;
+       monsters_setframe(hellknight_anim_wattack);
        self.attack_finished_single = time + 0.7;
-       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 70, DEATH_MONSTER_HKNIGHT_MELEE);
+       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
 }
 
 float hknight_type;
@@ -340,7 +347,7 @@ float hknight_magic ()
                
        self.hknight_cycles = 0;
 
-       if (self.enemy.classname == "monster_zombie")
+       if (self.enemy.monsterid == MONSTER_ZOMBIE)
        {
                // always use fireball to kill zombies
                hellknight_magic2();
@@ -397,13 +404,9 @@ void hellknight_die ()
        float chance = random();
        Monster_CheckDropCvars ("hellknight");
        
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.movetype           = MOVETYPE_TOSS;
-       self.think                      = Monster_Fade;
-       self.nextthink          = time + 2.1;
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe((random() > 0.5) ? hellknight_anim_death1 : hellknight_anim_death2);
        
        if(chance < 0.10 || self.flags & MONSTERFLAG_MINIBOSS)
        if(self.candrop)
@@ -411,11 +414,6 @@ void hellknight_die ()
                self.superweapons_finished = time + autocvar_g_balance_superweapons_time + 5; // give the player a few seconds to find the weapon
                self.weapon = WEP_FIREBALL;
        }
-       
-       if (random() > 0.5)
-               self.frame = hellknight_anim_death1;
-       else
-               self.frame = hellknight_anim_death2;
                
        monster_hook_death(); // for post-death mods
 }
@@ -433,7 +431,8 @@ void hellknight_spawn ()
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = hellknight_think;
        self.sprite_height              = 30;
-       self.frame                              = hellknight_anim_stand;
+       
+       monsters_setframe(hellknight_anim_stand);
        
        monster_hook_spawn(); // for post-spawn mods
 }
@@ -444,19 +443,14 @@ void spawnfunc_monster_hell_knight ()
        
        self.monster_spawnfunc = spawnfunc_monster_hell_knight;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        self.scale = 1.3;
        
        if not (monster_initialize(
-                        "Hell-knight",
-                        "models/monsters/hknight.mdl",
+                        "Hell-knight", MONSTER_HELLKNIGHT,
+                        HELLKNIGHT_MODEL,
                         HELLKNIGHT_MIN, HELLKNIGHT_MAX,
                         FALSE,
                         hellknight_die, hellknight_spawn))
@@ -470,3 +464,5 @@ void spawnfunc_monster_hell_knight ()
 
 // compatibility with old spawns
 void spawnfunc_monster_hellknight () { spawnfunc_monster_hell_knight(); }
+
+#endif // SVQC
index 35ded60ddd21e5370a13b9327108280f34df0eab..17ade040af4bc595d00a1f669cc86d065c0bfddd 100644 (file)
@@ -1,58 +1,62 @@
+#ifndef MENUQC
 // size
 const vector KNIGHT_MIN = '-16 -16 -24';
 const vector KNIGHT_MAX = '16 16 32';
-       
+
+// model
+string KNIGHT_MODEL = "models/monsters/knight.mdl";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_knight;
 float autocvar_g_monster_knight_health;
-float autocvar_g_monster_knight_melee_damage;
+//float autocvar_g_monster_knight_melee_damage;
 float autocvar_g_monster_knight_speed_walk;
 float autocvar_g_monster_knight_speed_run;
 
 // animations
-#define knight_anim_stand              0
-#define knight_anim_run                1
-#define knight_anim_runattack  2
-#define knight_anim_pain1              3
-#define knight_anim_pain2              4
-#define knight_anim_attack             5
-#define knight_anim_walk               6
-#define knight_anim_kneel              7
-#define knight_anim_standing   8
-#define knight_anim_death1             9
-#define knight_anim_death2             10
+const float knight_anim_stand          = 0;
+const float knight_anim_run            = 1;
+const float knight_anim_runattack      = 2;
+const float knight_anim_pain1          = 3;
+const float knight_anim_pain2          = 4;
+const float knight_anim_attack                 = 5;
+const float knight_anim_walk           = 6;
+const float knight_anim_kneel          = 7;
+const float knight_anim_standing       = 8;
+const float knight_anim_death1                 = 9;
+const float knight_anim_death2                 = 10;
 
 void knight_think ()
 {
        self.think = knight_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        monster_move(autocvar_g_monster_knight_speed_run, autocvar_g_monster_knight_speed_walk, 50, knight_anim_run, knight_anim_walk, knight_anim_stand);
 }
 
 void knight_attack ()
 {
-       local float len = vlen(self.velocity);
+       float len = vlen(self.velocity);
+       
+       W_Shotgun_Attack2();
 
-       self.frame = ((len < 50) ? knight_anim_attack : knight_anim_runattack);
+       monsters_setframe((len < 50) ? knight_anim_attack : knight_anim_runattack);
        
-       self.attack_finished_single = time + 0.9;
+       self.attack_finished_single = time + 1.25;
        
-       monster_melee(self.enemy, autocvar_g_monster_knight_melee_damage, 80, DEATH_MONSTER_KNIGHT);
+       //monster_melee(self.enemy, autocvar_g_monster_knight_melee_damage, 0.3, DEATH_MONSTER_KNIGHT);
 }
 
 void knight_die ()
 {
        Monster_CheckDropCvars ("knight");
-               
-       self.frame                      = ((random() > 0.5) ? knight_anim_death1 : knight_anim_death2);
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.think                      = Monster_Fade;
-       self.movetype           = MOVETYPE_TOSS;
-       self.nextthink          = time + 2.1;
+       
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe((random() > 0.5) ? knight_anim_death1 : knight_anim_death2);
        
        monster_hook_death(); // for post-death mods
 }
@@ -69,7 +73,9 @@ void knight_spawn ()
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = knight_think;
        self.sprite_height              = 30;
-       self.frame                              = knight_anim_stand;
+       self.view_ofs              *= 0.5;
+       
+       monsters_setframe(knight_anim_stand);
        
        monster_hook_spawn(); // for post-spawn mods
 }
@@ -80,19 +86,14 @@ void spawnfunc_monster_knight ()
        
        self.monster_spawnfunc = spawnfunc_monster_knight;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        self.scale = 1.3;
        
        if not (monster_initialize(
-                        "Knight",
-                        "models/monsters/knight.mdl",
+                        "Knight", MONSTER_KNIGHT,
+                        KNIGHT_MODEL,
                         KNIGHT_MIN, KNIGHT_MAX,
                         FALSE,
                         knight_die, knight_spawn))
@@ -101,3 +102,5 @@ void spawnfunc_monster_knight ()
                return;
        }
 }
+
+#endif // SVQC
index 6cbb2d3712edff0b1bb66a53e58e92f6663ad496..653fcb619dec1643a83d261b778d4c3287379760 100644 (file)
@@ -1,7 +1,14 @@
+#ifndef MENUQC
 // size
-const vector OGRE_MIN = '-32 -32 -24';
-const vector OGRE_MAX = '32 32 32';
+const vector OGRE_MIN = '-36 -36 -20';
+const vector OGRE_MAX = '36 36 50';
+
+// model
+string OGRE_MODEL = "models/monsters/ogre.dpm";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_ogre;
 float autocvar_g_monster_ogre_health;
@@ -11,12 +18,12 @@ float autocvar_g_monster_ogre_speed_run;
 float autocvar_g_monster_ogre_attack_uzi_bullets;
 
 // animations
-#define ogre_anim_idle                 0
-#define ogre_anim_walk                 1
-#define ogre_anim_run          2
-#define ogre_anim_pain                 3
-#define ogre_anim_swing        4
-#define ogre_anim_die          5
+const float ogre_anim_idle             = 0;
+const float ogre_anim_walk             = 1;
+const float ogre_anim_run              = 2;
+const float ogre_anim_pain             = 3;
+const float ogre_anim_swing    = 4;
+const float ogre_anim_die              = 5;
 
 void chainsaw (float side)
 {
@@ -32,7 +39,7 @@ void chainsaw (float side)
 void ogre_think ()
 {
        self.think = ogre_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        if(self.delay != -1)
                self.nextthink = self.delay;
@@ -44,7 +51,7 @@ void ogre_think ()
 void ogre_swing ()
 {
        self.ogre_cycles += 1;
-       self.frame = ogre_anim_swing;
+       monsters_setframe(ogre_anim_swing);
        if(self.ogre_cycles == 1)
                self.attack_finished_single = time + 1.3;
        self.angles_y = self.angles_y + random()* 25;
@@ -79,7 +86,7 @@ void ogre_uzi_fire ()
 
 void ogre_uzi ()
 {
-       self.frame = ogre_anim_pain;
+       monsters_setframe(ogre_anim_pain);
        self.attack_finished_single = time + 0.8;
        self.delay = time + 0.1;
        self.monster_delayedattack = ogre_uzi_fire;
@@ -88,7 +95,7 @@ void ogre_uzi ()
 void ogre_gl ()
 {
        W_Grenade_Attack2();
-       self.frame = ogre_anim_pain;
+       monsters_setframe(ogre_anim_pain);
        self.attack_finished_single = time + 0.8;
 }
 
@@ -117,14 +124,9 @@ void ogre_die()
 {
        Monster_CheckDropCvars ("ogre");
        
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.nextthink          = time + 2.1;
-       self.movetype           = MOVETYPE_TOSS;
-       self.think                      = Monster_Fade;
-       self.frame                      = ogre_anim_die;
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe(ogre_anim_die);
                
        monster_hook_death(); // for post-death mods
 }
@@ -138,13 +140,14 @@ void ogre_spawn ()
        self.classname                  = "monster_ogre";
        self.checkattack                = GenericCheckAttack;
        self.attack_melee               = ogre_melee;
-       self.frame                              = ogre_anim_idle;
        self.attack_ranged              = ogre_missile;
        self.nextthink                  = time + 0.1;
        self.think                              = ogre_think;
-       self.sprite_height              = 50;
+       self.sprite_height              = 65;
        self.weapon                             = WEP_GRENADE_LAUNCHER;
        
+       monsters_setframe(ogre_anim_idle);
+       
        monster_hook_spawn(); // for post-spawn mods
 }
 
@@ -154,19 +157,12 @@ void spawnfunc_monster_ogre ()
        
        self.monster_spawnfunc = spawnfunc_monster_ogre;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
-       
-       self.scale = 1.3;
        
        if not (monster_initialize(
-                        "Ogre",
-                        "models/monsters/ogre.dpm",
+                        "Ogre", MONSTER_OGRE,
+                        OGRE_MODEL,
                         OGRE_MIN, OGRE_MAX,
                         FALSE,
                         ogre_die, ogre_spawn))
@@ -177,3 +173,5 @@ void spawnfunc_monster_ogre ()
        
        weapon_action(WEP_GRENADE_LAUNCHER, WR_PRECACHE);
 }
+
+#endif // SVQC
index 6dcfb61726e2ee557db34c0749c8dfc0c8256d57..40d30979e1a043885851b0996c027e7e0e236308 100644 (file)
@@ -1,7 +1,14 @@
+#ifndef MENUQC
 // size
-const vector SHALRATH_MIN = '-32 -32 -24';
-const vector SHALRATH_MAX = '32 32 32';
+const vector SHALRATH_MIN = '-36 -36 -24';
+const vector SHALRATH_MAX = '36 36 50';
 
+// model
+string SHALRATH_MODEL = "models/monsters/mage.dpm";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_shalrath;
 float autocvar_g_monster_shalrath_health;
@@ -11,31 +18,56 @@ float autocvar_g_monster_shalrath_attack_spike_radius;
 float autocvar_g_monster_shalrath_attack_spike_delay;
 float autocvar_g_monster_shalrath_attack_melee_damage;
 float autocvar_g_monster_shalrath_attack_melee_delay;
+float autocvar_g_monster_shalrath_heal_self;
+float autocvar_g_monster_shalrath_heal_friends;
+float autocvar_g_monster_shalrath_heal_minhealth;
+float autocvar_g_monster_shalrath_heal_range;
+float autocvar_g_monster_shalrath_heal_delay;
 
 // animations
-#define shalrath_anim_idle             0
-#define shalrath_anim_walk             1
-#define shalrath_anim_attack   2
-#define shalrath_anim_pain             3
-#define shalrath_anim_death    4
-#define shalrath_anim_run              5
+const float shalrath_anim_idle         = 0;
+const float shalrath_anim_walk                 = 1;
+const float shalrath_anim_attack       = 2;
+const float shalrath_anim_pain                 = 3;
+const float shalrath_anim_death        = 4;
+const float shalrath_anim_run          = 5;
 
 void() ShalMissile;
+float() shal_missile;
+void() shalrath_heal;
 
 void shalrath_think ()
 {
+       entity head;
+       float friend_needshelp = FALSE;
+       
+       FOR_EACH_PLAYER(head)
+       {
+               if(vlen(head.origin - self.origin) < autocvar_g_monster_shalrath_heal_range * self.scale)
+               if((!g_minstagib && head.health < autocvar_g_balance_health_regenstable) || (g_minstagib && head.ammo_cells < start_ammo_cells))
+               {
+                       friend_needshelp = TRUE;
+                       break; // found 1 player near us who is low on health
+               }
+       }
+       
        self.think = shalrath_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        if(self.delay != -1)
                self.nextthink = self.delay;
+               
+       if(self.health < autocvar_g_monster_shalrath_heal_minhealth || friend_needshelp)
+       if(time >= self.attack_finished_single)
+       if(random() < 0.5)
+               shalrath_heal();
        
        monster_move(autocvar_g_monster_shalrath_speed, autocvar_g_monster_shalrath_speed, 50, shalrath_anim_walk, shalrath_anim_run, shalrath_anim_idle);
 }
 
 void shalrath_attack ()
 {
-       self.frame = shalrath_anim_attack;
+       monsters_setframe(shalrath_anim_attack);
        self.delay = time + 0.2;
        self.attack_finished_single = time + autocvar_g_monster_shalrath_attack_spike_delay;
        self.monster_delayedattack = ShalMissile;
@@ -43,18 +75,14 @@ void shalrath_attack ()
 
 void shalrathattack_melee ()
 {
-       float bigdmg = 0, rdmg = autocvar_g_monster_shalrath_attack_melee_damage * random();
-
-       bigdmg = rdmg * self.scale;
-
-       monster_melee(self.enemy, bigdmg * monster_skill, 120, DEATH_MONSTER_MAGE);
+       monster_melee(self.enemy, autocvar_g_monster_shalrath_attack_melee_damage, 0.3, DEATH_MONSTER_MAGE, TRUE);
 }
 
 void shalrath_attack_melee ()
 {
        self.monster_delayedattack = shalrathattack_melee;
        self.delay = time + 0.2;
-       self.frame = shalrath_anim_attack;
+       monsters_setframe(shalrath_anim_attack);
        self.attack_finished_single = time + autocvar_g_monster_shalrath_attack_melee_delay;
 }
 
@@ -136,10 +164,9 @@ void ShalMissile ()
 
 float ShalrathCheckAttack ()
 {
-       local vector spot1 = '0 0 0', spot2 = '0 0 0';
-       local entity targ = self.enemy;
+       vector spot1 = '0 0 0', spot2 = '0 0 0';
 
-       if (self.health <= 0 || targ == world || targ.health < 1)
+       if (self.health <= 0 || self.enemy == world || self.enemy.health < 1)
                return FALSE;
        
        if(self.monster_delayedattack && self.delay != -1)
@@ -167,35 +194,66 @@ float ShalrathCheckAttack ()
 
 // see if any entities are in the way of the shot
        spot1 = self.origin + self.view_ofs;
-       spot2 = targ.origin + targ.view_ofs;
+       spot2 = self.enemy.origin + self.enemy.view_ofs;
 
        traceline (spot1, spot2, FALSE, self);
 
-       if (trace_ent != targ && trace_fraction < 1)
+       if (trace_ent != self.enemy && trace_fraction < 1)
                return FALSE; // don't have a clear shot
 
        //if (trace_inopen && trace_inwater)
        //      return FALSE; // sight line crossed contents
 
-       if (random() < 0.2)
        if (self.attack_ranged())
                return TRUE;
 
        return FALSE;
 }
 
+void shalrath_heal()
+{
+       entity head;
+       if(self.health < self.max_health) // only show our effect if we are healing ourself too
+               pointparticles(particleeffectnum("healing_fx"), self.origin, '0 0 0', 1);
+       self.health = bound(0, self.health + autocvar_g_monster_shalrath_heal_self, self.max_health);
+       WaypointSprite_UpdateHealth(self.sprite, self.health);
+       monsters_setframe(shalrath_anim_attack);
+       self.attack_finished_single = time + autocvar_g_monster_shalrath_heal_delay;
+       
+       for(head = world; (head = findfloat(head, monster_attack, TRUE)); )
+       {
+               if(head.health > 0)
+               if not(head.frozen || head.freezetag_frozen)
+               if(vlen(head.origin - self.origin) < autocvar_g_monster_shalrath_heal_range * self.scale)
+               if not(IsDifferentTeam(head, self))
+               {
+                       if(IS_PLAYER(head))
+                       {
+                               if(head.ammo_cells < start_ammo_cells || head.health < g_pickup_healthmedium_max)
+                                       pointparticles(particleeffectnum(((g_minstagib) ? "ammoregen_fx" : "healing_fx")), head.origin, '0 0 0', 1);
+                               if(g_minstagib)
+                                       head.ammo_cells = bound(0, head.ammo_cells + 1, start_ammo_cells);
+                               else
+                                       head.health = bound(0, head.health + autocvar_g_monster_shalrath_heal_friends, g_pickup_healthmedium_max);
+                       }
+                       else
+                       {
+                               if(head.health < head.max_health)
+                                       pointparticles(particleeffectnum("healing_fx"), head.origin, '0 0 0', 1);
+                               head.health = bound(0, head.health + autocvar_g_monster_shalrath_heal_friends, head.max_health);
+                               WaypointSprite_UpdateHealth(head.sprite, head.health);
+                       }
+               }
+       }
+}
+
 void shalrath_die ()
 {
        Monster_CheckDropCvars ("shalrath");
        
-       self.think                      = Monster_Fade;
-       self.frame                      = shalrath_anim_death;
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.nextthink          = time + 2.1;   
-       self.movetype           = MOVETYPE_TOSS;
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe(shalrath_anim_death);
        
        monster_hook_death(); // for post-death mods
 }
@@ -212,8 +270,9 @@ void shalrath_spawn ()
        self.attack_melee               = shalrath_attack_melee;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = shalrath_think;
-       self.frame                              = shalrath_anim_walk;
-       self.sprite_height              = 40;
+       self.sprite_height              = 65;
+       
+       monsters_setframe(shalrath_anim_walk);
        
        monster_hook_spawn(); // for post-spawn mods
 }
@@ -224,20 +283,12 @@ void spawnfunc_monster_shalrath ()
        
        self.monster_spawnfunc = spawnfunc_monster_shalrath;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
-               
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
-       
-       self.scale = 1.3;
        
        if not (monster_initialize(
-                        "Mage",
-                        "models/monsters/mage.dpm",
+                        "Mage", MONSTER_MAGE,
+                        SHALRATH_MODEL,
                         SHALRATH_MIN, SHALRATH_MAX,
                         FALSE,
                         shalrath_die, shalrath_spawn))
@@ -249,3 +300,5 @@ void spawnfunc_monster_shalrath ()
 
 // compatibility with old spawns
 void spawnfunc_monster_vore () { spawnfunc_monster_shalrath(); }
+
+#endif // SVQC
index de1ff35d2b7c9bd1d8c8cd0909b665d6e0d088da..afa983d226bae365c11f1d488dfebba260353c9a 100644 (file)
@@ -1,7 +1,14 @@
+#ifndef MENUQC
 // size
 const vector SHAMBLER_MIN = '-32 -32 -24';
 const vector SHAMBLER_MAX = '32 32 64';
 
+// model
+string SHAMBLER_MODEL = "models/monsters/shambler.mdl";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_shambler;
 float autocvar_g_monster_shambler_health;
@@ -12,20 +19,20 @@ float autocvar_g_monster_shambler_speed_walk;
 float autocvar_g_monster_shambler_speed_run;
 
 // animations
-#define shambler_anim_stand    0
-#define shambler_anim_walk             1
-#define shambler_anim_run              2
-#define shambler_anim_smash    3
-#define shambler_anim_swingr   4
-#define shambler_anim_swingl   5
-#define shambler_anim_magic    6
-#define shambler_anim_pain             7
-#define shambler_anim_death    8
+const float shambler_anim_stand        = 0;
+const float shambler_anim_walk                 = 1;
+const float shambler_anim_run          = 2;
+const float shambler_anim_smash        = 3;
+const float shambler_anim_swingr       = 4;
+const float shambler_anim_swingl       = 5;
+const float shambler_anim_magic        = 6;
+const float shambler_anim_pain                 = 7;
+const float shambler_anim_death        = 8;
 
 void shambler_think ()
 {
        self.think = shambler_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        monster_move(autocvar_g_monster_shambler_speed_run, autocvar_g_monster_shambler_speed_walk, 300, shambler_anim_run, shambler_anim_walk, shambler_anim_stand);
 }
@@ -49,22 +56,20 @@ void shambler_smash ()
 
 void shambler_delayedsmash ()
 {
-       self.frame = shambler_anim_smash;
+       monsters_setframe(shambler_anim_smash);
        self.think = shambler_smash;
        self.nextthink = time + 0.7;
 }
 
 void ShamClaw (float side)
 {
-       float bigdmg = autocvar_g_monster_shambler_attack_claw_damage * self.scale;
-       
-       monster_melee(self.enemy, bigdmg * monster_skill, 100, DEATH_MONSTER_SHAMBLER_CLAW);
+       monster_melee(self.enemy, autocvar_g_monster_shambler_attack_claw_damage, 0.3, DEATH_MONSTER_SHAMBLER_CLAW, TRUE);
 }
 
 void() shambler_swing_right;
 void shambler_swing_left ()
 {
-       self.frame = shambler_anim_swingl;
+       monsters_setframe(shambler_anim_swingl);
        ShamClaw(250);
        self.attack_finished_single = time + 0.8;
        self.nextthink = self.attack_finished_single;
@@ -75,7 +80,7 @@ void shambler_swing_left ()
 
 void shambler_swing_right ()
 {
-       self.frame = shambler_anim_swingr;
+       monsters_setframe(shambler_anim_swingr);
        ShamClaw(-250);
        self.attack_finished_single = time + 0.8;
        self.nextthink = self.attack_finished_single;
@@ -98,9 +103,9 @@ void sham_melee ()
 
 void CastLightning ()
 {
-       self.nextthink = time + 0.4;
-       self.think = shambler_think;
-       
+       self.monster_delayedattack = func_null;
+       self.delay = -1;
+
        local vector org = '0 0 0', dir = '0 0 0';
        vector v = '0 0 0';
 
@@ -122,10 +127,10 @@ void CastLightning ()
 
 void shambler_magic ()
 {
-       self.frame = shambler_anim_magic;
+       monsters_setframe(shambler_anim_magic);
        self.attack_finished_single = time + 1.1;
-       self.nextthink = time + 0.6;
-       self.think = CastLightning;
+       self.monster_delayedattack = CastLightning;
+       self.delay = time + 0.6;
 }
        
 float sham_lightning ()
@@ -138,14 +143,9 @@ void shambler_die ()
 {
        Monster_CheckDropCvars ("shambler");
        
-       self.think                      = Monster_Fade;
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.nextthink          = time + 2.1;
-       self.frame                      = shambler_anim_death;
-       self.movetype           = MOVETYPE_TOSS;
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe(shambler_anim_death);
        
        monster_hook_death(); // for post-death mods
 }
@@ -161,11 +161,12 @@ void shambler_spawn ()
        self.checkattack                = GenericCheckAttack;
        self.attack_ranged              = sham_lightning;
        self.nextthink                  = time + random() * 0.5 + 0.1;
-       self.frame                              = shambler_anim_stand;
        self.think                              = shambler_think;
        self.sprite_height              = 70;
        self.weapon                             = WEP_NEX;
        
+       monsters_setframe(shambler_anim_stand);
+       
        monster_hook_spawn(); // for post-spawn mods
 }
 
@@ -175,19 +176,14 @@ void spawnfunc_monster_shambler ()
        
        self.monster_spawnfunc = spawnfunc_monster_shambler;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        self.scale = 1.3;
        
        if not (monster_initialize(
-                        "Shambler",
-                        "models/monsters/shambler.mdl",
+                        "Shambler", MONSTER_SHAMBLER,
+                        SHAMBLER_MODEL,
                         SHAMBLER_MIN, SHAMBLER_MAX,
                         FALSE,
                         shambler_die, shambler_spawn))
@@ -201,3 +197,5 @@ void spawnfunc_monster_shambler ()
        
        precache_sound ("weapons/lgbeam_fire.wav");
 }
+
+#endif // SVQC
index 480410f611a96f82217b4b4fdcb9079ed62178e3..11c3663b1d3054a3177784f6d1954ca8013ec838 100644 (file)
@@ -1,7 +1,14 @@
+#ifndef MENUQC
 // size
 const vector SOLDIER_MIN = '-16 -16 -30';
 const vector SOLDIER_MAX = '16 16 32';
 
+// model
+string SOLDIER_MODEL = "models/monsters/soldier.zym";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_soldier;
 float autocvar_g_monster_soldier_health;
@@ -16,45 +23,34 @@ float autocvar_g_monster_soldier_weapon_rocketlauncher_chance;
 float autocvar_g_monster_soldier_attack_uzi_bullets;
 
 // animations
-#define soldier_anim_die1                      0
-#define soldier_anim_die2                      1
-#define soldier_anim_draw                      2
-#define soldier_anim_duck                      3
-#define soldier_anim_duckwalk          4
-#define soldier_anim_duckjump          5
-#define soldier_anim_duckidle          6
-#define soldier_anim_idle                      7
-#define soldier_anim_jump                      8
-#define soldier_anim_pain1                     9
-#define soldier_anim_pain2                     10
-#define soldier_anim_shoot                     11
-#define soldier_anim_taunt                     12
-#define soldier_anim_run                       13
-#define soldier_anim_runbackwards      14
-#define soldier_anim_strafeleft        15
-#define soldier_anim_straferight       16
-#define soldier_anim_dead1                     17
-#define soldier_anim_dead2                     18
-#define soldier_anim_forwardright      19
-#define soldier_anim_forwardleft       20
-#define soldier_anim_backright                 21
-#define soldier_anim_backleft          22
-
-//#define soldier_anim_stand   0
-//#define soldier_anim_death1 1
-//#define soldier_anim_death2 2
-//#define soldier_anim_reload 3
-//#define soldier_anim_pain1   4
-//#define soldier_anim_pain2   5
-//#define soldier_anim_pain3   6
-//#define soldier_anim_run     7
-//#define soldier_anim_shoot   8
-//#define soldier_anim_prowl   9
+const float soldier_anim_die1                  = 0;
+const float soldier_anim_die2                  = 1;
+const float soldier_anim_draw                  = 2;
+const float soldier_anim_duck                  = 3;
+const float soldier_anim_duckwalk              = 4;
+const float soldier_anim_duckjump              = 5;
+const float soldier_anim_duckidle              = 6;
+const float soldier_anim_idle                  = 7;
+const float soldier_anim_jump                  = 8;
+const float soldier_anim_pain1                         = 9;
+const float soldier_anim_pain2                         = 10;
+const float soldier_anim_shoot                         = 11;
+const float soldier_anim_taunt                         = 12;
+const float soldier_anim_run                   = 13;
+const float soldier_anim_runbackwards  = 14;
+const float soldier_anim_strafeleft    = 15;
+const float soldier_anim_straferight   = 16;
+const float soldier_anim_dead1                         = 17;
+const float soldier_anim_dead2                         = 18;
+const float soldier_anim_forwardright  = 19;
+const float soldier_anim_forwardleft   = 20;
+const float soldier_anim_backright             = 21;
+const float soldier_anim_backleft              = 22;
 
 void soldier_think ()
 {
        self.think = soldier_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        if(self.delay != -1)
                self.nextthink = self.delay;
@@ -67,101 +63,23 @@ void soldier_think ()
 
 void soldier_reload ()
 {
-       self.frame = soldier_anim_draw;
+       self.monster_delayedattack = func_null; // out of ammo, don't keep attacking
+       self.delay = -1;
+       monsters_setframe(soldier_anim_draw);
        self.attack_finished_single = time + 2;
        self.currentammo = autocvar_g_monster_soldier_ammo;
        sound (self, CH_SHOTS, "weapons/reload.wav", VOL_BASE, ATTN_LARGE);
 }
 
-float SoldierCheckAttack ()
-{
-       local vector spot1 = '0 0 0', spot2 = '0 0 0';
-       local entity targ = self.enemy;
-       local float chance = 0;
-
-       if (self.health <= 0 || targ.health < 1 || targ == world)
-               return FALSE;
-
-       // see if any entities are in the way of the shot
-       spot1 = self.origin + self.view_ofs;
-       spot2 = targ.origin + targ.view_ofs;
-
-       traceline (spot1, spot2, FALSE, self);
-
-       if (trace_ent != targ)
-               return FALSE; // don't have a clear shot
-
-       if (trace_inwater)
-       if (trace_inopen)
-               return FALSE; // sight line crossed contents
-               
-       if(self.monster_delayedattack && self.delay != -1)
-       {
-               if(time < self.delay)
-                       return FALSE;
-                       
-               self.monster_delayedattack();
-       }
-
-       // missile attack
-       if (time < self.attack_finished_single)
-               return FALSE;
-
-       if (vlen(self.enemy.origin - self.origin) >= 2000)
-               return FALSE;
-
-       if (vlen(self.enemy.origin - self.origin) <= 120)
-               chance = 0.9;
-       else if (vlen(self.enemy.origin - self.origin) <= 500)
-               chance = 0.6; // was 0.4
-       else if (vlen(self.enemy.origin - self.origin) <= 1000)
-               chance = 0.3; // was 0.05
-       else
-               chance = 0;
-
-       if (chance > 0)
-       if (chance > random())
-               return FALSE;
-               
-       if(self.currentammo <= 0 && vlen(self.enemy.origin - self.origin) <= 120)
-       {
-               monster_sound(self.msound_attack_melee, 0, FALSE); // no delay for attack sounds
-               self.attack_melee();
-               return TRUE;
-       }
-       
-       if(self.currentammo <= 0)
-       {
-               soldier_reload();
-               return FALSE;
-       }
-
-       if (self.attack_ranged())
-               return TRUE;
-
-       return FALSE;
-}
-
-void soldier_laser ()
-{
-       self.frame = soldier_anim_shoot;
-       self.attack_finished_single = time + 0.8;
-       W_Laser_Attack(0);
-}
-
-float soldier_missile_laser ()
-{
-       // FIXME: check if it would hit
-       soldier_laser();
-       return TRUE;
-}
-
 .float grunt_cycles;
 void soldier_uzi_fire ()
 {
        self.currentammo -= 1;
        if(self.currentammo <= 0)
+       {
+               soldier_reload();
                return;
+       }
                
        self.grunt_cycles += 1;
        
@@ -176,85 +94,67 @@ void soldier_uzi_fire ()
        self.monster_delayedattack = soldier_uzi_fire;
 }
 
-void soldier_uzi ()
+float soldier_attack()
 {
+       monsters_setframe(soldier_anim_shoot);
+       makevectors(self.angles);
+       
        if(self.currentammo <= 0)
-               return;
-               
-       self.frame = soldier_anim_shoot;
-       self.attack_finished_single = time + 0.8;
-       self.delay = time + 0.1;
-       self.monster_delayedattack = soldier_uzi_fire;
-}
-
-float soldier_missile_uzi ()
-{
-       self.grunt_cycles = 0;
-       // FIXME: check if it would hit
-       soldier_uzi();
-       return TRUE;
-}
-
-void soldier_shotgun ()
-{
-       self.currentammo -= 1;
-       if(self.currentammo <= 0)
-               return;
-               
-       self.frame = soldier_anim_shoot;
-       self.attack_finished_single = time + 0.8;
-       W_Shotgun_Attack();
-}
-
-float soldier_missile_shotgun ()
-{
-       // FIXME: check if it would hit
+       {
+               soldier_reload();
+               return FALSE;
+       }
+       
        self.grunt_cycles = 0;
-       soldier_shotgun();
-       return TRUE;
-}
-
-void soldier_rl ()
-{
-       self.currentammo -= 1;
-       if(self.currentammo <= 0)
-               return;
-               
-       self.frame = soldier_anim_shoot;
-       self.attack_finished_single = time + 0.8;
-       W_Rocket_Attack();
-}
-
-float soldier_missile_rl ()
-{
-       // FIXME: check if it would hit
-       soldier_rl();
-       return TRUE;
+       
+       switch(self.weapon)
+       {
+               case WEP_ROCKET_LAUNCHER:
+               {
+                       self.currentammo -= 1;
+                       self.attack_finished_single = time + 0.8;
+                       W_Rocket_Attack();
+                       return TRUE;
+               }
+               case WEP_SHOTGUN:
+               {
+                       self.currentammo -= 1;
+                       self.attack_finished_single = time + 0.8;
+                       W_Shotgun_Attack();
+                       return TRUE;
+               }
+               case WEP_UZI:
+               {
+                       self.attack_finished_single = time + 0.8;
+                       self.delay = time + 0.1;
+                       self.monster_delayedattack = soldier_uzi_fire;
+                       return TRUE;
+               }
+               case WEP_LASER:
+               {
+                       self.attack_finished_single = time + 0.8;
+                       W_Laser_Attack(0);
+                       return TRUE;
+               }
+               default:
+                       return FALSE; // no weapon?
+       }
 }
 
-void soldier_bash ()
+void soldier_melee ()
 {
-       self.frame = soldier_anim_shoot;
+       monsters_setframe(soldier_anim_shoot);
        self.attack_finished_single = time + 0.8;
-       monster_melee(self.enemy, autocvar_g_monster_soldier_melee_damage, 70, DEATH_MONSTER_MARINE_SLAP);
+       monster_melee(self.enemy, autocvar_g_monster_soldier_melee_damage, 0.3, DEATH_MONSTER_MARINE_SLAP, TRUE);
 }
 
 void soldier_die()
 {
        Monster_CheckDropCvars ("soldier");
        
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.movetype           = MOVETYPE_TOSS;
-       self.think                      = Monster_Fade;
-       self.nextthink          = time + 2.1;
-
-       if (random() < 0.5)
-               self.frame = soldier_anim_die1;
-       else
-               self.frame = soldier_anim_die2;
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe((random() > 0.5) ? soldier_anim_die1 : soldier_anim_die2);
                
        monster_hook_death(); // for post-death mods
 }
@@ -266,14 +166,17 @@ void soldier_spawn ()
 
        self.damageforcescale   = 0.003;
        self.classname                  = "monster_soldier";
-       self.checkattack                = SoldierCheckAttack;
-       self.attack_melee               = soldier_bash;
-       self.frame                              = soldier_anim_draw;
+       self.checkattack                = GenericCheckAttack;
+       self.attack_melee               = soldier_melee;
+       self.attack_ranged              = soldier_attack;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = soldier_think;
+       self.currentammo                = 3;
        self.sprite_height              = 45;
        self.items                              = (IT_SHELLS | IT_ROCKETS | IT_NAILS);
        
+       monsters_setframe(soldier_anim_draw);
+       
        RandomSelection_Init();
        RandomSelection_Add(world, WEP_LASER, string_null, autocvar_g_monster_soldier_weapon_laser_chance, 1);
        RandomSelection_Add(world, WEP_SHOTGUN, string_null, autocvar_g_monster_soldier_weapon_shotgun_chance, 1);
@@ -288,34 +191,8 @@ void soldier_spawn ()
        setmodel(self.weaponentity, "models/weapons/v_seeker.md3");
        setattachment(self.weaponentity, self, "bip01 r hand");
        
-       if (RandomSelection_chosen_float == WEP_ROCKET_LAUNCHER)
-       {
-               self.weapon = WEP_ROCKET_LAUNCHER;
-               self.currentammo = self.ammo_rockets;
-               self.armorvalue = 0.9;
-               self.attack_ranged = soldier_missile_rl;
-       }
-       else if (RandomSelection_chosen_float == WEP_UZI)
-       {
-               self.weapon = WEP_UZI;
-               self.currentammo = self.ammo_nails;
-               self.armorvalue = 0.5;
-               self.attack_ranged = soldier_missile_uzi;
-       }
-       else if (RandomSelection_chosen_float == WEP_SHOTGUN)
-       {
-               self.weapon = WEP_SHOTGUN;
-               self.currentammo = self.ammo_shells;
-               self.armorvalue = 0.7;
-               self.attack_ranged = soldier_missile_shotgun;
-       }
-       else
-       {
-               self.weapon = WEP_LASER;
-               self.armorvalue = 0.6;
-               self.currentammo = self.ammo_none;
-               self.attack_ranged = soldier_missile_laser;
-       }
+       self.armorvalue = bound(0.5, random(), 1);
+       self.weapon = RandomSelection_chosen_float;
 
        monster_hook_spawn(); // for post-spawn mods
 }
@@ -326,17 +203,12 @@ void spawnfunc_monster_soldier ()
        
        self.monster_spawnfunc = spawnfunc_monster_soldier;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        if not (monster_initialize(
-                        "Grunt",
-                        "models/monsters/soldier.zym",
+                        "Grunt", MONSTER_MARINE,
+                        SOLDIER_MODEL,
                         SOLDIER_MIN, SOLDIER_MAX,
                         FALSE,
                         soldier_die, soldier_spawn))
@@ -349,7 +221,10 @@ void spawnfunc_monster_soldier ()
        precache_sound ("weapons/uzi_fire.wav");
        precache_sound ("weapons/laser_fire.wav");
        precache_sound ("weapons/reload.wav");
+       precache_model ("models/weapons/v_seeker.md3");
 }
 
 // compatibility with old spawns
 void spawnfunc_monster_army () { spawnfunc_monster_soldier(); }
+
+#endif // SVQC
diff --git a/qcsrc/server/monsters/monster/spawner.qc b/qcsrc/server/monsters/monster/spawner.qc
deleted file mode 100644 (file)
index 1e984f5..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-// size
-const vector SPAWNER_MIN = '-35 -35 -10';
-const vector SPAWNER_MAX = '35 35 70';
-
-// cvars
-float autocvar_g_monster_spawner;
-float autocvar_g_monster_spawner_health;
-float autocvar_g_monster_spawner_maxmobs;
-string autocvar_g_monster_spawner_forcespawn;
-
-void spawnmonsters ()
-{
-       if(self.spawner_monstercount >= autocvar_g_monster_spawner_maxmobs || self.frozen)
-               return;
-               
-       vector p1, p2, p3, p4, chosenposi;
-       float r = random();
-       string type = self.spawnmob;
-       entity e;
-       
-       self.spawner_monstercount += 1;
-               
-       if(autocvar_g_monster_spawner_forcespawn)
-               type = autocvar_g_monster_spawner_forcespawn;
-               
-       if(type == "" || type == "spawner") // spawner spawning spawners?!
-               type = "knight";
-       
-       p1 = self.origin - '0 70 -50' * self.scale;
-       p2 = self.origin + '0 70 50' * self.scale;
-       p3 = self.origin - '70 0 -50' * self.scale;
-       p4 = self.origin + '70 0 -50' * self.scale;
-          
-       if (r < 0.20)
-               chosenposi = p1;
-       else if (r < 0.50)
-               chosenposi = p2;
-       else if (r < 0.80)
-               chosenposi = p3;
-       else
-               chosenposi = p4;
-
-       e = spawnmonster(type, self, self, chosenposi, FALSE, MONSTER_MOVE_WANDER);
-       
-       e.team = self.team;
-       e.candrop = FALSE;
-       
-       if(self.spawnflags & MONSTERFLAG_GIANT)
-               e.spawnflags = MONSTERFLAG_GIANT;
-               
-       if(self.flags & MONSTERFLAG_MINIBOSS)
-               e.spawnflags = MONSTERFLAG_MINIBOSS;
-}
-
-void spawner_die () 
-{
-       setmodel(self, "");
-       pointparticles(particleeffectnum(((self.scale > 3) ? "explosion_big" : "explosion_medium")), self.origin, '0 0 0', 1);
-       sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
-       
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.think                      = Monster_Fade;
-       self.nextthink          = time + 1;
-       
-       monster_hook_death(); // for post-death mods
-}
-
-void spawner_think() 
-{
-       self.think = spawner_think;
-       
-       if(self.spawner_monstercount >= autocvar_g_monster_spawner_maxmobs)
-               self.nextthink = time + 15;
-
-       if (self.spawner_monstercount <= autocvar_g_monster_spawner_maxmobs)
-               spawnmonsters();
-
-       self.nextthink = time + 1;
-
-       if(self.spawner_monstercount <= autocvar_g_monster_spawner_maxmobs)
-               self.nextthink = time + 0.1;
-}
-
-void spawner_spawn() 
-{
-       if not(self.health)
-               self.health = autocvar_g_monster_spawner_health * self.scale;
-       
-       self.classname                  = "monster_spawner";
-       self.nextthink                  = time + 0.2;
-       self.velocity                   = '0 0 0';
-       self.think                              = spawner_think;
-       self.touch                              = func_null;    
-       self.sprite_height      = 80;
-       
-       self.spawner_monstercount = 0;
-       
-       self.movetype = MOVETYPE_NONE;
-       
-       monster_hook_spawn(); // for post-spawn mods
-}
-
-/*QUAKED monster_spawner (1 0 0) (-18 -18 -25) (18 18 47)
----------NOTES----------
-Spawns monsters when a player is nearby
--------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
-modeldisabled="models/containers/crate01.md3"
-*/
-void spawnfunc_monster_spawner() 
-{
-       if not(autocvar_g_monster_spawner) { remove(self); return; }
-       
-       self.monster_spawnfunc = spawnfunc_monster_spawner;
-       
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
-               return;
-       }
-       
-       self.scale = 0.8;
-       
-       if not (monster_initialize(
-                        "Monster spawner",
-                        "models/containers/crate01.md3",
-                        SPAWNER_MIN, SPAWNER_MAX,
-                        FALSE,
-                        spawner_die, spawner_spawn))
-       {
-               remove(self);
-               return;
-       }
-
-       precache_sound("weapons/rocket_impact.wav");
-}
index 4bb0eb59949a9e0e3e111a07481ae3c5f12e3872..63da385fcad6319b62d62e0a3756b7ce15984615 100644 (file)
@@ -1,3 +1,14 @@
+#ifndef MENUQC
+// size
+const vector SPIDER_MIN = '-18 -18 -25';
+const vector SPIDER_MAX = '18 18 30';
+
+// model
+string SPIDER_MODEL = "models/monsters/spider.dpm";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_spider;
 float autocvar_g_monster_spider_stopspeed;
@@ -9,43 +20,16 @@ float autocvar_g_monster_spider_speed_walk;
 float autocvar_g_monster_spider_speed_run;
 float autocvar_g_monster_spider_attack_type;
 
-// spider animations
-#define spider_anim_idle                       0
-#define spider_anim_walk                       1
-#define spider_anim_attack                     2
-#define spider_anim_attack2                    3
-
-const vector SPIDER_MIN                                 = '-18 -18 -25';
-const vector SPIDER_MAX                                 = '18 18 30';
+// animations
+const float spider_anim_idle           = 0;
+const float spider_anim_walk           = 1;
+const float spider_anim_attack         = 2;
+const float spider_anim_attack2                = 3;
 
 .float spider_type; // used to switch between fire & ice attacks
 const float SPIDER_TYPE_ICE            = 0;
 const float SPIDER_TYPE_FIRE   = 1;
 
-void spider_spawn();
-void spawnfunc_monster_spider();
-void spider_think();
-
-void spider_die ()
-{
-       Monster_CheckDropCvars ("spider");
-       
-       self.angles += '180 0 0';
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.movetype           = MOVETYPE_TOSS;
-       self.think                      = Monster_Fade;
-       self.nextthink          = time + 2.1;
-       self.frame                      = spider_anim_attack;
-       
-       monster_hook_death(); // for post-death mods
-}
-
-/**
- * Performe a standing attack on self.enemy.
- */
 void spider_attack_standing()
 {
        float dot = 0, bigdmg = autocvar_g_monster_spider_attack_stand_damage * self.scale;
@@ -57,11 +41,8 @@ void spider_attack_standing()
        dot = normalize (self.enemy.origin - self.origin) * v_forward;
        if(dot > 0.3)
                Damage(self.enemy, self, self, bigdmg * monster_skill, DEATH_MONSTER_SPIDER, self.origin, '0 0 0');
-               
-       if(random() < 0.50)
-               self.frame = spider_anim_attack;
-       else
-               self.frame = spider_anim_attack2;
+       
+       monsters_setframe((random() > 0.5) ? spider_anim_attack : spider_anim_attack2);
 
        self.attack_finished_single = time + autocvar_g_monster_spider_attack_stand_delay;
 }
@@ -132,8 +113,8 @@ void spider_attack_leap()
 {
        vector angles_face = vectoangles(self.enemy.origin - self.origin);
 
-       // face the enemy       
-       self.frame = spider_anim_attack2;
+       // face the enemy
+       monsters_setframe(spider_anim_attack2);
        self.angles_y = angles_face_y ;
        self.attack_finished_single = time + autocvar_g_monster_spider_attack_leap_delay;
        
@@ -161,14 +142,23 @@ float spider_attack_ranged()
 void spider_think()
 {
        self.think = spider_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        monster_move(autocvar_g_monster_spider_speed_run, autocvar_g_monster_spider_speed_walk, autocvar_g_monster_spider_stopspeed, spider_anim_walk, spider_anim_walk, spider_anim_idle);
 }
 
-/**
- * Spawn the spider.
- */
+void spider_die ()
+{
+       Monster_CheckDropCvars ("spider");
+       
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe(spider_anim_attack);
+       self.angles += '180 0 0';
+       
+       monster_hook_death(); // for post-death mods
+}
+
 void spider_spawn() 
 {
        if not(self.health)
@@ -176,45 +166,32 @@ void spider_spawn()
        
        self.classname                  = "monster_spider";
        self.nextthink                  = time + random() * 0.5 + 0.1;
-       self.frame                              = spider_anim_idle;
        self.checkattack                = GenericCheckAttack;
        self.attack_melee               = spider_attack_standing;
        self.attack_ranged              = spider_attack_ranged;
        self.think                              = spider_think;
        self.sprite_height      = 40;
        
+       monsters_setframe(spider_anim_idle);
+       
+       if not(self.spider_type)
+               self.spider_type = autocvar_g_monster_spider_attack_type;
+       
        monster_hook_spawn(); // for post-spawn mods
 }
 
-/*QUAKED monster_spider (1 0 0) (-18 -18 -25) (18 18 47)
-Spider, 60 health points.
--------- KEYS --------
--------- SPAWNFLAGS --------
-MONSTERFLAG_APPEAR: monster will spawn when triggered.
----------NOTES----------
--------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
-modeldisabled="models/monsters/spider.dpm"
-*/
 void spawnfunc_monster_spider() 
 {
        if not(autocvar_g_monster_spider) { remove(self); return; }
        
        self.monster_spawnfunc = spawnfunc_monster_spider;
-       self.classname = "monster_spider";
-       if(!self.spider_type)
-               self.spider_type = autocvar_g_monster_spider_attack_type;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        if not (monster_initialize(
-                        "Spider",
-                        "models/monsters/spider.dpm",
+                        "Spider", MONSTER_SPIDER,
+                        SPIDER_MODEL,
                         SPIDER_MIN, SPIDER_MAX,
                         FALSE,
                         spider_die, spider_spawn))
@@ -223,3 +200,5 @@ void spawnfunc_monster_spider()
                return;
        }
 }
+
+#endif // SVQC
index 81160578908b81e5591d1460c2256ba2390aeafc..4acbf3775b8748dcb7839a930e59b9c90db087ff 100644 (file)
@@ -1,7 +1,14 @@
+#ifndef MENUQC
 // size
 const vector TARBABY_MIN = '-16 -16 -24';
 const vector TARBABY_MAX = '16 16 16';
 
+// model
+string TARBABY_MODEL = "models/monsters/tarbaby.mdl";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_tarbaby;
 float autocvar_g_monster_tarbaby_health;
@@ -9,31 +16,29 @@ float autocvar_g_monster_tarbaby_speed_walk;
 float autocvar_g_monster_tarbaby_speed_run;
 
 // animations
-#define tarbaby_anim_walk              0
-#define tarbaby_anim_run               1
-#define tarbaby_anim_jump              2
-#define tarbaby_anim_fly               3
-#define tarbaby_anim_explode   4
+const float tarbaby_anim_walk          = 0;
+const float tarbaby_anim_run           = 1;
+const float tarbaby_anim_jump          = 2;
+const float tarbaby_anim_fly           = 3;
+const float tarbaby_anim_explode       = 4;
 
 void tarbaby_think ()
 {
        self.think = tarbaby_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        monster_move(autocvar_g_monster_tarbaby_speed_run, autocvar_g_monster_tarbaby_speed_walk, 20, tarbaby_anim_run, tarbaby_anim_walk, tarbaby_anim_walk);
 }
 
 void Tar_JumpTouch ()
 {
-       // dunno why this would be called when dead, but to be safe
-       if (self.health <= 0)
-               return;
-               
-       if (other.takedamage)
-       if (vlen(self.velocity) > 200)
+       if(self.health > 0)
+       if(other.health > 0)
+       if(other.takedamage)
+       if(vlen(self.velocity) > 200)
        {
                // make the monster die
-               self.event_damage(self, self, self.health + self.max_health, DEATH_MONSTER_TARBABY, self.origin, '0 0 0');
+               self.event_damage(self, self, self.health + self.max_health + 200, DEATH_MONSTER_TARBABY, self.origin, '0 0 0');
                        
                return;
        }
@@ -53,10 +58,7 @@ void tarbaby_jump ()
 {
        if not(self.flags & FL_ONGROUND)
                return;
-       self.frame = tarbaby_anim_jump;
-       // dunno why this would be called when dead, but to be safe
-       if (self.health <= 0)
-               return;
+       monsters_setframe(tarbaby_anim_jump);
        self.movetype = MOVETYPE_BOUNCE;
        self.touch = Tar_JumpTouch;
        makevectors (self.angles);
@@ -96,13 +98,11 @@ void tarbaby_explode()
 
 void tarbaby_die ()
 {
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
+       self.think                      = tarbaby_explode;
+       self.nextthink          = time + 0.1;
        self.event_damage   = func_null;
        self.movetype           = MOVETYPE_NONE;
        self.enemy                      = world;
-       self.think                      = tarbaby_explode;
-       self.nextthink          = time + 0.1;
 }
 
 void tarbaby_spawn ()
@@ -118,7 +118,8 @@ void tarbaby_spawn ()
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = tarbaby_think;
        self.sprite_height              = 20;
-       self.frame                              = tarbaby_anim_walk;
+       
+       monsters_setframe(tarbaby_anim_walk);
        
        monster_hook_spawn(); // for post-spawn mods
 }
@@ -129,19 +130,14 @@ void spawnfunc_monster_tarbaby ()
        
        self.monster_spawnfunc = spawnfunc_monster_tarbaby;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        self.scale = 1.3;
        
        if not (monster_initialize(
-                        "Spawn",
-                        "models/monsters/tarbaby.mdl",
+                        "Spawn", MONSTER_TARBABY,
+                        TARBABY_MODEL,
                         TARBABY_MIN, TARBABY_MAX,
                         FALSE,
                         tarbaby_die, tarbaby_spawn))
@@ -155,3 +151,5 @@ void spawnfunc_monster_tarbaby ()
 
 // compatibility with old spawns
 void spawnfunc_monster_spawn () { spawnfunc_monster_tarbaby(); }
+
+#endif // SVQC
index 97842688a38b981865e1c6ad369d1003270d8396..58c0fe0ed2689c121df181388f8c378fd35c6d6d 100644 (file)
@@ -1,7 +1,14 @@
+#ifndef MENUQC
 // size
-const vector WIZARD_MIN = '-16 -16 -24';
-const vector WIZARD_MAX = '16 16 24';
+const vector WIZARD_MIN = '-16 -16 -45';
+const vector WIZARD_MAX = '16 16 16';
 
+// model
+string WIZARD_MODEL = "models/monsters/wizard.mdl";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_wizard;
 float autocvar_g_monster_wizard_health;
@@ -13,11 +20,11 @@ float autocvar_g_monster_wizard_spike_radius;
 float autocvar_g_monster_wizard_spike_speed;
 
 // animations
-#define wizard_anim_hover      0
-#define wizard_anim_fly        1
-#define wizard_anim_magic      2
-#define wizard_anim_pain       3
-#define wizard_anim_death      4
+const float wizard_anim_hover  = 0;
+const float wizard_anim_fly    = 1;
+const float wizard_anim_magic  = 2;
+const float wizard_anim_pain   = 3;
+const float wizard_anim_death  = 4;
 
 void Wiz_FastExplode()
 {
@@ -95,7 +102,7 @@ void Wiz_StartFast ()
 void wizard_think ()
 {
        self.think = wizard_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
        
        monster_move(autocvar_g_monster_wizard_speed_run, autocvar_g_monster_wizard_speed_walk, 300, wizard_anim_fly, wizard_anim_hover, wizard_anim_hover);
 }
@@ -110,17 +117,13 @@ void wizard_die ()
        Monster_CheckDropCvars ("wizard");
        
        self.think                      = Monster_Fade;
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.movetype           = MOVETYPE_TOSS;
+       self.nextthink          = time + 5;
        self.flags                      = FL_ONGROUND;
-       self.nextthink          = time + 2.1;
-       self.velocity_x         = -200 + 400*random();
-       self.velocity_y         = -200 + 400*random();
-       self.velocity_z         = 100 + 100*random();
-       self.frame                      = wizard_anim_death;
+       self.velocity_x         = -200 + 400 * random();
+       self.velocity_y         = -200 + 400 * random();
+       self.velocity_z         = 100 + 100 * random();
+       
+       monsters_setframe(wizard_anim_death);
        
        monster_hook_death(); // for post-death mods
 }
@@ -154,19 +157,14 @@ void spawnfunc_monster_wizard ()
        
        self.monster_spawnfunc = spawnfunc_monster_wizard;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        self.scale = 1.3;
        
        if not (monster_initialize(
-                        "Scrag",
-                        "models/monsters/wizard.mdl",
+                        "Scrag", MONSTER_SCRAG,
+                        WIZARD_MODEL,
                         WIZARD_MIN, WIZARD_MAX,
                         TRUE,
                         wizard_die, wizard_spawn))
@@ -181,3 +179,5 @@ void spawnfunc_monster_wizard ()
 
 // compatibility with old spawns
 void spawnfunc_monster_scrag () { spawnfunc_monster_wizard(); }
+
+#endif // SVQC
index 8a5131ad7ce441c255395363810f79922fd5722f..225ede8a405dfa38559f45bee69797f6956e91bd 100644 (file)
@@ -1,9 +1,14 @@
-/**
- * Special purpose fields:
- * .delay - time at which to check if zombie's enemy is still in range
- * .enemy - enemy of this zombie
- */
+#ifndef MENUQC
+// size
+const vector ZOMBIE_MIN = '-18 -18 -25';
+const vector ZOMBIE_MAX = '18 18 47';
+
+// model
+string ZOMBIE_MODEL = "models/monsters/zombie.dpm";
+
+#endif
+
+#ifdef SVQC
 // cvars
 float autocvar_g_monster_zombie;
 float autocvar_g_monster_zombie_stopspeed;
@@ -17,125 +22,75 @@ float autocvar_g_monster_zombie_health;
 float autocvar_g_monster_zombie_speed_walk;
 float autocvar_g_monster_zombie_speed_run;
 
-// zombie animations
-#define zombie_anim_attackleap                 0
-#define zombie_anim_attackrun1                 1
-#define zombie_anim_attackrun2                 2
-#define zombie_anim_attackrun3                 3
-#define zombie_anim_attackstanding1            4
-#define zombie_anim_attackstanding2            5
-#define zombie_anim_attackstanding3            6
-#define zombie_anim_blockend                   7
-#define zombie_anim_blockstart                 8
-#define zombie_anim_deathback1                 9
-#define zombie_anim_deathback2                 10
-#define zombie_anim_deathback3                 11
-#define zombie_anim_deathfront1                        12
-#define zombie_anim_deathfront2                        13
-#define zombie_anim_deathfront3                        14
-#define zombie_anim_deathleft1                 15
-#define zombie_anim_deathleft2                 16
-#define zombie_anim_deathright1                        17
-#define zombie_anim_deathright2                        18
-#define zombie_anim_idle                               19
-#define zombie_anim_painback1                  20
-#define zombie_anim_painback2                  21
-#define zombie_anim_painfront1                 22
-#define zombie_anim_painfront2                 23
-#define zombie_anim_runbackwards               24
-#define zombie_anim_runbackwardsleft           25
-#define zombie_anim_runbackwardsright          26
-#define zombie_anim_runforward                 27
-#define zombie_anim_runforwardleft             28
-#define zombie_anim_runforwardright            29
-#define zombie_anim_spawn                              30
-
-const vector ZOMBIE_MIN                                 = '-18 -18 -25';
-const vector ZOMBIE_MAX                                 = '18 18 47';
-
-void zombie_spawn();
-void spawnfunc_monster_zombie();
-void zombie_think();
-
-void zombie_die ()
-{
-       Monster_CheckDropCvars ("zombie");
-       
-       self.solid                      = SOLID_NOT;
-       self.takedamage         = DAMAGE_NO;
-       self.event_damage   = func_null;
-       self.enemy                      = world;
-       self.movetype           = MOVETYPE_TOSS;
-       self.think                      = Monster_Fade;
-       self.nextthink          = time + 2.1;
-       
-       if (random() > 0.5)
-               self.frame = zombie_anim_deathback1;
-       else
-               self.frame = zombie_anim_deathfront1;
-               
-       monster_hook_death(); // for post-death mods
-}
+// animations
+const float zombie_anim_attackleap                     = 0;
+const float zombie_anim_attackrun1                     = 1;
+const float zombie_anim_attackrun2                     = 2;
+const float zombie_anim_attackrun3                     = 3;
+const float zombie_anim_attackstanding1                = 4;
+const float zombie_anim_attackstanding2                = 5;
+const float zombie_anim_attackstanding3                = 6;
+const float zombie_anim_blockend                       = 7;
+const float zombie_anim_blockstart                     = 8;
+const float zombie_anim_deathback1                     = 9;
+const float zombie_anim_deathback2                     = 10;
+const float zombie_anim_deathback3                     = 11;
+const float zombie_anim_deathfront1                    = 12;
+const float zombie_anim_deathfront2                    = 13;
+const float zombie_anim_deathfront3                    = 14;
+const float zombie_anim_deathleft1                     = 15;
+const float zombie_anim_deathleft2                     = 16;
+const float zombie_anim_deathright1                    = 17;
+const float zombie_anim_deathright2                    = 18;
+const float zombie_anim_idle                           = 19;
+const float zombie_anim_painback1                      = 20;
+const float zombie_anim_painback2                      = 21;
+const float zombie_anim_painfront1                     = 22;
+const float zombie_anim_painfront2                     = 23;
+const float zombie_anim_runbackwards           = 24;
+const float zombie_anim_runbackwardsleft       = 25;
+const float zombie_anim_runbackwardsright      = 26;
+const float zombie_anim_runforward                     = 27;
+const float zombie_anim_runforwardleft         = 28;
+const float zombie_anim_runforwardright                = 29;
+const float zombie_anim_spawn                          = 30;
 
 void zombie_attack_standing()
 {
-       float rand = random(), dot = 0, bigdmg = 0;
-
-       self.velocity_x = 0;
-       self.velocity_y = 0;
-       
-       if(self.monster_owner == self.enemy)
-       {
-               self.enemy = world;
-               return;
-       }
-       
-       bigdmg = autocvar_g_monster_zombie_attack_stand_damage * self.scale;
-
-       //print("zombie attacks!\n");
-       makevectors (self.angles);
-       dot = normalize (self.enemy.origin - self.origin) * v_forward;
-       if(dot > 0.3)
-       {
-               Damage(self.enemy, self, self, bigdmg * monster_skill, DEATH_MONSTER_ZOMBIE_MELEE, self.origin, '0 0 0');
-       }
-       
-       if(self.enemy.health < 1)
-               self.enemy = world;
+       float rand = random(), chosen_anim;
                
        if (rand < 0.33)
-               self.frame = zombie_anim_attackstanding1;
+               chosen_anim = zombie_anim_attackstanding1;
        else if (rand < 0.66)
-               self.frame = zombie_anim_attackstanding2;
+               chosen_anim = zombie_anim_attackstanding2;
        else
-               self.frame = zombie_anim_attackstanding3;
+               chosen_anim = zombie_anim_attackstanding3;
+               
+       monsters_setframe(chosen_anim);
 
-       self.nextthink = time + autocvar_g_monster_zombie_attack_stand_delay;
-       self.attack_finished_single = self.nextthink;
+       self.attack_finished_single = time + autocvar_g_monster_zombie_attack_stand_delay;
+       
+       monster_melee(self.enemy, autocvar_g_monster_zombie_attack_stand_damage, 0.3, DEATH_MONSTER_ZOMBIE_MELEE, TRUE);
 }
 
-void zombie_attack_leap_touch()
+void zombie_attack_leap_touch ()
 {
-       vector angles_face;
-       float bigdmg = autocvar_g_monster_zombie_attack_leap_damage * self.scale;
-       
-       if (other.deadflag != DEAD_NO)
+       if (self.health <= 0)
                return;
                
-       if (self.monster_owner == other)
-               return;
-       
-       if (other.takedamage == DAMAGE_NO)
-               return;
-               
-       //void Damage (entity targ, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
-       traceline(self.origin, other.origin, FALSE, self);
+       vector angles_face;
+       float bigdmg = autocvar_g_monster_zombie_attack_leap_damage * self.scale;
 
-       angles_face = vectoangles(self.moveto - self.origin);
-       angles_face = normalize(angles_face) * autocvar_g_monster_zombie_attack_leap_force;
-       Damage(other, self, self, bigdmg * monster_skill, DEATH_MONSTER_ZOMBIE_JUMP, trace_endpos, angles_face);        
-               
-       self.touch = MonsterTouch;
+       if (monster_isvalidtarget(other, self))
+       {
+               angles_face = vectoangles(self.moveto - self.origin);
+               angles_face = normalize(angles_face) * autocvar_g_monster_zombie_attack_leap_force;
+               Damage(other, self, self, bigdmg * monster_skill, DEATH_MONSTER_ZOMBIE_JUMP, other.origin, angles_face);
+               self.touch = MonsterTouch; // instantly turn it off to stop damage spam
+       }
+
+       if(self.flags & FL_ONGROUND)
+               self.touch = MonsterTouch;
 }
 
 float zombie_attack_ranged()
@@ -150,11 +105,22 @@ float zombie_attack_ranged()
 void zombie_think()
 {
        self.think = zombie_think;
-       self.nextthink = time + 0.1;
+       self.nextthink = time + self.ticrate;
 
        monster_move(autocvar_g_monster_zombie_speed_run, autocvar_g_monster_zombie_speed_walk, autocvar_g_monster_zombie_stopspeed, zombie_anim_runforward, zombie_anim_runforward, zombie_anim_idle);
 }
 
+void zombie_die ()
+{
+       Monster_CheckDropCvars ("zombie");
+       
+       self.think = Monster_Fade;
+       self.nextthink = time + 5;
+       monsters_setframe((random() > 0.5) ? zombie_anim_deathback1 : zombie_anim_deathfront1);
+               
+       monster_hook_death(); // for post-death mods
+}
+
 void zombie_spawn() 
 {
        if not(self.health)
@@ -162,13 +128,18 @@ void zombie_spawn()
        
        self.classname                  = "monster_zombie";
        self.nextthink                  = time + 2.1;
-       self.frame                              = zombie_anim_spawn;
        self.think                              = zombie_think;
        self.sprite_height      = 50;
        self.checkattack                = GenericCheckAttack;
        self.attack_melee               = zombie_attack_standing;
        self.attack_ranged              = zombie_attack_ranged;
-       self.skin                               = rint(random() * 4);
+       self.respawntime                = 0.1;
+       self.respawnflags               = MONSTER_RESPAWN_DEATHPOINT;
+       
+       monsters_setframe(zombie_anim_spawn);
+       
+       if not(self.monster_respawned)
+               self.skin = rint(random() * 4);
        
        // some sounds
        if(self.msound_idle == "") self.msound_idle = "monsters/zombie_idle.wav";
@@ -181,33 +152,18 @@ void zombie_spawn()
        monster_hook_spawn(); // for post-spawn mods
 }
 
-/*QUAKED monster_zombie (1 0 0) (-18 -18 -25) (18 18 47)
-Zombie, 60 health points.
--------- KEYS --------
--------- SPAWNFLAGS --------
-MONSTERFLAG_APPEAR: monster will spawn when triggered.
----------NOTES----------
-Original Quake 1 zombie entity used a smaller box ('-16 -16 -24', '16 16 32').
--------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
-modeldisabled="models/monsters/zombie.dpm"
-*/
 void spawnfunc_monster_zombie() 
 {
        if not(autocvar_g_monster_zombie) { remove(self); return; }
        
        self.monster_spawnfunc = spawnfunc_monster_zombie;
        
-       if(self.spawnflags & MONSTERFLAG_APPEAR)
-       {
-               self.think = func_null;
-               self.nextthink = -1;
-               self.use = Monster_Appear;
+       if(Monster_CheckAppearFlags(self))
                return;
-       }
        
        if not (monster_initialize(
-                        "Zombie",
-                        "models/monsters/zombie.dpm",
+                        "Zombie", MONSTER_ZOMBIE,
+                        ZOMBIE_MODEL,
                         ZOMBIE_MIN, ZOMBIE_MAX,
                         FALSE,
                         zombie_die, zombie_spawn))
@@ -216,3 +172,5 @@ void spawnfunc_monster_zombie()
                return;
        }
 }
+
+#endif //SVQC
index a9695490b874d858367c31a47cb3246e401a003f..c43a999d026a76a4981ac2c65e581cc48936ff78 100644 (file)
@@ -1,9 +1,11 @@
 // Lib
+#ifdef SVQC
 #include "lib/defs.qh"
 #include "lib/monsters.qc"
+#include "lib/spawn.qc"
+#endif
 
 // Monsters
-#include "lib/spawn.qc"
 #include "monster/ogre.qc"
 #include "monster/demon.qc"
 #include "monster/shambler.qc"
@@ -18,4 +20,3 @@
 #include "monster/enforcer.qc"
 #include "monster/zombie.qc"
 #include "monster/spider.qc"
-#include "monster/spawner.qc"
index 8f0bc931efd540c587ea0f1ea5f3371fb04bdd0d..f578c5f73d274d07b7ce90dcd25cc9ae90d5d1fd 100644 (file)
@@ -451,14 +451,19 @@ void ctf_Handle_Capture(entity flag, entity toucher, float capturetype)
 void ctf_Handle_Return(entity flag, entity player)
 {
        // messages and sounds
-       Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_RETURN_));
+       if(player.classname == "player")
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_RETURN_));
+               
        Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_RETURN_), player.netname);
        sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTN_NONE);
        ctf_EventLog("return", flag.team, player);
 
        // scoring
-       PlayerTeamScore_AddScore(player, autocvar_g_ctf_score_return); // reward for return
-       PlayerScore_Add(player, SP_CTF_RETURNS, 1); // add to count of returns
+       if(player.classname == "player")
+       {
+               PlayerTeamScore_AddScore(player, autocvar_g_ctf_score_return); // reward for return
+               PlayerScore_Add(player, SP_CTF_RETURNS, 1); // add to count of returns
+       }
 
        TeamScore_AddToTeam(flag.team, ST_SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the team who was last carrying it
        
@@ -825,6 +830,11 @@ void ctf_FlagTouch()
                else
                        return; // do nothing
        }
+       else if(toucher.flags & FL_MONSTER)
+       {
+               if not(autocvar_g_ctf_allow_monster_touch)
+                       return; // do nothing
+       }
        else if(toucher.classname != "player") // 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
@@ -841,9 +851,9 @@ void ctf_FlagTouch()
        {       
                case FLAG_BASE:
                {
-                       if(!IsDifferentTeam(toucher, self) && (toucher.flagcarried) && IsDifferentTeam(toucher.flagcarried, self))
+                       if(!IsDifferentTeam(toucher, self) && (toucher.flagcarried) && IsDifferentTeam(toucher.flagcarried, self) && !(toucher.flags & FL_MONSTER))
                                ctf_Handle_Capture(self, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
-                       else if(IsDifferentTeam(toucher, self) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time))
+                       else if(IsDifferentTeam(toucher, self) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && !(toucher.flags & FL_MONSTER))
                                ctf_Handle_Pickup(self, toucher, PICKUP_BASE); // toucher just stole the enemies flag
                        break;
                }
@@ -852,7 +862,7 @@ void ctf_FlagTouch()
                {
                        if(!IsDifferentTeam(toucher, self))
                                ctf_Handle_Return(self, toucher); // toucher just returned his own flag
-                       else if((!toucher.flagcarried) && ((toucher != self.ctf_dropper) || (time > self.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
+                       else if(!(toucher.flags & FL_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
                        break;
                }
index d971d9e59b5175ca2698d098a8440d3e57123030..1f8a9c33ab9008513c1e14ec1764f6e238f038fa 100644 (file)
@@ -25,17 +25,18 @@ void spawnfunc_td_controller()
        self.classname = "td_controller";
                
        gensurvived = FALSE;
-       td_dont_end = ((self.dontend) ? self.dontend : autocvar_g_td_generator_dontend);                
-       max_waves = ((self.maxwaves) ? self.maxwaves : autocvar_g_td_max_waves);        
-       totalmonsters = ((self.monstercount) ? self.monstercount : autocvar_g_td_monster_count);
-       wave_count = ((self.startwave) ? self.startwave : autocvar_g_td_start_wave);
-       max_turrets = ((self.maxturrets) ? self.maxturrets : autocvar_g_td_turret_max);
-       build_time = ((self.buildtime) ? self.buildtime : autocvar_g_td_buildphase_time);
-       m_speed_walk = ((self.mspeed_walk) ? self.mspeed_walk : autocvar_g_td_monsters_speed_walk);
-       m_speed_run = ((self.mspeed_run) ? self.mspeed_run : autocvar_g_td_monsters_speed_run);
-       spawn_delay = ((self.spawndelay) ? self.spawndelay : autocvar_g_td_monsters_spawn_delay);
-       max_current = ((self.maxcurrent) ? self.maxcurrent : autocvar_g_td_current_monsters);
-       ignore_turrets = ((self.ignoreturrets) ? self.ignoreturrets : autocvar_g_td_monsters_ignore_turrets);
+       
+       td_dont_end = ((self.dontend == 0) ? autocvar_g_td_generator_dontend : self.dontend);
+       max_waves = ((self.maxwaves == 0) ? autocvar_g_td_max_waves : self.maxwaves);
+       totalmonsters = ((self.monstercount == 0) ? autocvar_g_td_monster_count : self.monstercount);
+       wave_count = ((self.startwave == 0) ? autocvar_g_td_start_wave : self.startwave);
+       max_turrets = ((self.maxturrets == 0) ? autocvar_g_td_turret_max : self.maxturrets);
+       build_time = ((self.buildtime == 0) ? autocvar_g_td_buildphase_time : self.buildtime);
+       m_speed_walk = ((self.mspeed_walk == 0) ? autocvar_g_td_monsters_speed_walk : self.mspeed_walk);
+       m_speed_run = ((self.mspeed_run == 0) ? autocvar_g_td_monsters_speed_run : self.mspeed_run);
+       spawn_delay = ((self.spawndelay == 0) ? autocvar_g_td_monsters_spawn_delay : self.spawndelay);
+       max_current = ((self.maxcurrent == 0) ? autocvar_g_td_current_monsters : self.maxcurrent);
+       ignore_turrets = ((self.ignoreturrets == 0) ? autocvar_g_td_monsters_ignore_turrets : self.ignoreturrets);
        
        if(autocvar_g_td_monsters_skill_start)
                monster_skill = autocvar_g_td_monsters_skill_start;
@@ -273,6 +274,7 @@ void spawnturret(entity spawnedby, entity own, string turet, vector orig)
        self.angles_y = spawnedby.v_angle_y;
        spawnedby.turret_cnt += 1;
        self.colormap = spawnedby.colormap;
+       self.colormod = '1 1 1';
        
        switch(turet)
        {
@@ -565,7 +567,7 @@ void build_phase()
        if(totalmonsters < 1) totalmonsters = ((autocvar_g_td_monster_count > 0) ? autocvar_g_td_monster_count : 10);
        if(wave_count < 1) wave_count = 1;
        
-       Send_Notification(NOTIF_ALL, world, MSG_MULTI, MULTI_TD_PHASE_BUILD, wave_count, totalmonsters, autocvar_g_td_buildphase_time);
+       Send_Notification(NOTIF_ALL, world, MSG_MULTI, MULTI_TD_PHASE_BUILD, wave_count, totalmonsters, build_time);
     
     FOR_EACH_MONSTER(head)
     {
@@ -752,7 +754,7 @@ MUTATOR_HOOKFUNCTION(td_MonsterMove)
        }
        
        if not(self.enemy) // don't change targets while attacking
-       if((vlen(self.goalentity.origin - self.origin) <= 100 && self.goalentity.classname == "td_waypoint") || (vlen(self.goalentity.origin - self.origin) <= 200 && self.flags & FL_FLY && self.goalentity.classname == "td_waypoint"))
+       if((vlen(self.goalentity.origin - self.origin) <= 100 && self.goalentity.classname == "td_waypoint") || (vlen(self.goalentity.origin - self.origin) <= 200 && (self.flags & FL_FLY) && self.goalentity.classname == "td_waypoint"))
        {
                if(self.goalentity.target2)
                {
@@ -791,27 +793,30 @@ MUTATOR_HOOKFUNCTION(td_MonsterSpawn)
        
        self.drop_size = self.health * 0.05;
        
+       self.target_range = 600;
+       
        if(self.drop_size < 1) self.drop_size = 1;
        
        self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_BODY;
        
        self.origin += '0 0 25'; // hopefully this fixes monsters falling through the floor
        
-       switch(self.classname)
+       switch(self.monsterid)
        {
-               case "monster_knight": n_knights -= 1; break;
-               case "monster_dog": n_dogs -= 1; break;
-               case "monster_ogre": n_ogres -= 1; break;
-               case "monster_shambler": n_shamblers -= 1; AnnounceSpawn("Shambler"); break;
-               case "monster_wizard": n_wizards -= 1; break;
-               case "monster_shalrath": n_shalraths -= 1; break;
-               case "monster_soldier": n_soldiers -= 1; break;
-               case "monster_hellknight": n_hknights -= 1; break;
-               case "monster_enforcer": n_enforcers -= 1; break;
-               case "monster_demon": n_demons -= 1; break;
-               case "monster_zombie": n_zombies -= 1; break;
-               case "monster_spider": n_spiders -= 1; break;
-               case "monster_tarbaby": n_tarbabies -= 1; break;
+               case MONSTER_ZOMBIE: n_zombies -= 1; break;
+               case MONSTER_OGRE: n_ogres -= 1; break;
+               case MONSTER_DEMON: n_demons -= 1; break;
+               case MONSTER_SHAMBLER: n_shamblers -= 1; break;
+               case MONSTER_KNIGHT: n_knights -= 1; break;
+               case MONSTER_MARINE: n_soldiers -= 1; break;
+               case MONSTER_SCRAG: n_wizards -= 1; break;
+               case MONSTER_DOG: n_dogs -= 1; break;
+               case MONSTER_TARBABY: n_tarbabies -= 1; break;
+               case MONSTER_HELLKNIGHT: n_hknights -= 1; break;
+               case MONSTER_FISH: n_fish -= 1; break;
+               case MONSTER_MAGE: n_shalraths -= 1; break;
+               case MONSTER_ENFORCER: n_enforcers -= 1; break;
+               case MONSTER_SPIDER: n_spiders -= 1; break;
        }
        
        return TRUE;
@@ -831,7 +836,7 @@ MUTATOR_HOOKFUNCTION(td_MonsterDies)
                PlayerScore_Add(frag_attacker, SP_TD_SCORE, autocvar_g_td_kill_points);
                PlayerScore_Add(frag_attacker, SP_TD_KILLS, 1);
        }
-       else if(IS_PLAYER(frag_attacker.realowner))
+       else if(IS_PLAYER(frag_attacker.realowner) && frag_attacker.turrcaps_flags & TFL_TURRCAPS_ISTURRET)
        {
                PlayerScore_Add(frag_attacker.realowner, SP_TD_SCORE, autocvar_g_td_turretkill_points);
                PlayerScore_Add(frag_attacker.realowner, SP_TD_TURKILLS, 1);
@@ -930,6 +935,11 @@ MUTATOR_HOOKFUNCTION(td_PlayerCommand)
                        Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_CANTSPAWN);
                        return TRUE;
                }
+               if(max_turrets <= 0)
+               {
+                       Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_TURRETS_DISABLED);
+                       return TRUE;
+               }
                if(self.turret_cnt >= max_turrets)
                {
                        Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_MAXTURRETS, max_turrets);
index 3f84465a0afab231c8bc6dba7e7970e05bd9dadd..cf511ea9241f8144886175b74faf802446c7e335 100644 (file)
@@ -34,9 +34,8 @@ void zombie_spawn_somewhere ()
        
        if(MoveToRandomMapLocation(self, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
        {
-               mon = spawnmonster("zombie", self, self, self.origin, TRUE, 2);
+               mon = spawnmonster("zombie", self, self, self.origin, TRUE, 2); // double tap needed
                tracebox(mon.origin, mon.mins, mon.maxs, mon.origin, MOVE_NOMONSTERS, mon);
-               mon.spawnflags |= MONSTERFLAG_NORESPAWN;
 
                if(trace_startsolid)
                {
@@ -60,7 +59,7 @@ void za_roundwon()
        
        numzoms = autocvar_g_za_monster_count;
        
-       monsters_total = numzoms;
+       monsters_total += numzoms;
        totalzombies = numzoms;
        
        self.think = spawn_zombies;
@@ -71,7 +70,7 @@ void spawn_zombies ()
 {
        self.nextthink = time + 1;
        
-       if(totalzombies < 1)
+       if(totalzombies <= 0)
        {
                self.think = za_roundwon;
                self.nextthink = time;
@@ -101,9 +100,9 @@ void za_init ()
        
        roundcnt = 1;
        
-    numzoms = autocvar_g_za_monster_count * roundcnt;
+    numzoms = autocvar_g_za_monster_count;
        
-       monsters_total = numzoms;
+       monsters_total += numzoms;
        totalzombies = numzoms;
        
     e = spawn();
@@ -113,6 +112,9 @@ void za_init ()
 
 MUTATOR_HOOKFUNCTION(za_ZombieDies)
 {
+       if(self.monster_respawned)
+               return FALSE; // don't count zombies that respawned
+               
        if(frag_attacker.classname == "player")
                PlayerScore_Add(frag_attacker, SP_SCORE, 1);
        
index 166f3a823a45fd14b8f283f4364c3f19df8faf51..ba0555a2901b410e797c1e85c3150fe99862ca0b 100644 (file)
@@ -48,6 +48,8 @@ mutators/gamemode_rts.qh
 tturrets/include/turrets_early.qh
 vehicles/vehicles_def.qh
 
+monsters/lib/monsters_early.qh
+
 campaign.qh
 ../common/campaign_common.qh
 ../common/mapinfo.qh
index bad37d30f4ecd7759e842b2b2a2db793304c95fe..ee230c94dc3d176c69ddf8aba19f8a01293efc2c 100644 (file)
@@ -633,6 +633,7 @@ void vehicles_enter()
 
     self.team                 = self.owner.team;
     self.flags               -= FL_NOTARGET;
+       self.monster_attack               = TRUE;
     
     if (clienttype(other) == CLIENTTYPE_REAL)
     {
@@ -811,6 +812,7 @@ void vehicles_exit(float eject)
     sound (_vehicle, CH_TRIGGER_SINGLE, "misc/null.wav", 1, ATTN_NORM);
     _vehicle.vehicle_hudmodel.viewmodelforclient = _vehicle;   
     _vehicle.phase = time + 1;
+       _vehicle.monster_attack = FALSE;
     
     _vehicle.vehicle_exit(eject);
     
@@ -1258,7 +1260,6 @@ float vehicle_initialize(string  net_name,
     self.tur_head.owner     = self;
     self.takedamage         = DAMAGE_AIM;
     self.bot_attack         = TRUE;
-       self.monster_attack             = TRUE;
     self.iscreature         = TRUE;
     self.teleportable       = FALSE; // no teleporting for vehicles, too buggy
     self.damagedbycontents     = TRUE;
diff --git a/scripts/cerberus.shader b/scripts/cerberus.shader
deleted file mode 100644 (file)
index 8253191..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-textures/cerberus/cerberus_text
-{
-       cull none
-
-       {
-               map textures/cerberus
-       }
-}
diff --git a/scripts/mage.shader b/scripts/mage.shader
deleted file mode 100644 (file)
index 7a235c1..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-mage
-{
-       cull none
-
-       {
-               map textures/mage
-       }
-}
diff --git a/scripts/monsters.shader b/scripts/monsters.shader
new file mode 100644 (file)
index 0000000..dbab45d
--- /dev/null
@@ -0,0 +1,32 @@
+textures/spider/spidertex
+{
+       cull none
+
+       {
+               map textures/spidertex
+       }
+}
+textures/cerberus/cerberus_text
+{
+       cull none
+
+       {
+               map textures/cerberus
+       }
+}
+textures/berzerker_texture
+{
+       cull none
+
+       {
+               map textures/ogre
+       }
+}
+mage
+{
+       cull none
+
+       {
+               map textures/mage
+       }
+}
diff --git a/scripts/ogre.shader b/scripts/ogre.shader
deleted file mode 100644 (file)
index 195e5f1..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-textures/berzerker_texture
-{
-       cull none
-
-       {
-               map textures/ogre
-       }
-}
index b779627c5215ac4be419e7c1f8a576f274184962..8082c886fdc7e67dbfc6767e028ac49ed2113475 100644 (file)
@@ -14,8 +14,5 @@ tree
 tuba
 turrets
 weapons
-mage
 barricade
-spider
-cerberus
-ogre
+monsters
diff --git a/scripts/spider.shader b/scripts/spider.shader
deleted file mode 100644 (file)
index b84c374..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-textures/spider/spidertex
-{
-       cull none
-
-       {
-               map textures/spidertex
-       }
-}