]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Rewrite monster attacks as a single function & rename knight to bruiser
authorMario <mario.mario@y7mail.com>
Sat, 27 Apr 2013 20:12:59 +0000 (06:12 +1000)
committerMario <mario.mario@y7mail.com>
Sat, 27 Apr 2013 20:12:59 +0000 (06:12 +1000)
25 files changed:
monsters.cfg
qcsrc/client/monsters.qc
qcsrc/common/deathtypes.qh
qcsrc/common/notifications.qh
qcsrc/server/monsters/lib/defs.qh
qcsrc/server/monsters/lib/monsters.qc
qcsrc/server/monsters/lib/monsters_early.qh
qcsrc/server/monsters/lib/spawn.qc
qcsrc/server/monsters/monster/bruiser.qc [new file with mode: 0644]
qcsrc/server/monsters/monster/demon.qc
qcsrc/server/monsters/monster/dog.qc
qcsrc/server/monsters/monster/fish.qc
qcsrc/server/monsters/monster/hknight.qc
qcsrc/server/monsters/monster/knight.qc [deleted file]
qcsrc/server/monsters/monster/ogre.qc
qcsrc/server/monsters/monster/shalrath.qc
qcsrc/server/monsters/monster/shambler.qc
qcsrc/server/monsters/monster/slime.qc
qcsrc/server/monsters/monster/soldier.qc
qcsrc/server/monsters/monster/spider.qc
qcsrc/server/monsters/monster/wizard.qc
qcsrc/server/monsters/monster/zombie.qc
qcsrc/server/monsters/monsters.qh
qcsrc/server/mutators/gamemode_towerdefense.qc
qcsrc/server/mutators/gamemode_towerdefense.qh

index ad9e36703a15b74f9444a0b67a9156183ea6ab83..4b6611276d056adf42f26f615a7137cb2fc2fbc3 100644 (file)
@@ -25,7 +25,7 @@ set g_monsters_skill_normal 4 "Monster normal skill level (used for skill based
 set g_monsters_skill_hard 5 "Monster hard skill level (used for skill based functions)"
 set g_monsters_skill_insane 7 "Monster insane skill level (used for skill based functions)"
 set g_monsters_skill_nightmare 10 "Monster nightmare skill level (used for skill based functions)"
-set g_monsters_spawn_list "ogre demon shambler knight marine scrag dog slime hellknight fish mage zombie spider" "monsters not listed here will spawn as knights"
+set g_monsters_spawn_list "ogre demon shambler bruiser marine scrag dog slime hellknight fish mage zombie spider" "monsters not listed here will spawn as bruisers"
 
 // Ogre
 set g_monster_ogre 1 "Enable Ogres"
@@ -65,15 +65,15 @@ set g_monster_shambler_drop_size large "Size of the item Shamblers drop. Possibl
 set g_monster_shambler_speed_walk 100 "Shambler walk speed"
 set g_monster_shambler_speed_run 150 "Shambler run speed"
 
-// Knight
-set g_monster_knight 1 "Enable Knights"
-set g_monster_knight_health 75 "Knight Health"
-set g_monster_knight_drop armor "Knight drops this item on death"
-set g_monster_knight_drop_size medium "Size of the item Knights drop. Possible values are: small, medium, large"
-set g_monster_knight_melee_damage 20 "Knight melee attack damage"
-set g_monster_knight_melee_side_damage 10 "Knight melee attack side damage"
-set g_monster_knight_speed_walk 40 "Knight walk speed"
-set g_monster_knight_speed_run 70 "Knight run speed"
+// Bruiser
+set g_monster_bruiser 1 "Enable Bruisers"
+set g_monster_bruiser_health 75 "Bruiser Health"
+set g_monster_bruiser_drop armor "Bruiser drops this item on death"
+set g_monster_bruiser_drop_size medium "Size of the item Bruisers drop. Possible values are: small, medium, large"
+set g_monster_bruiser_melee_damage 20 "Bruiser melee attack damage"
+set g_monster_bruiser_melee_side_damage 10 "Bruiser melee attack side damage"
+set g_monster_bruiser_speed_walk 40 "Bruiser walk speed"
+set g_monster_bruiser_speed_run 70 "Bruiser run speed"
 
 // Grunt
 set g_monster_soldier 1 "Enable Grunts"
index e8b8d990fe24aa0d17e7c1ce617e69266dab51fd..68ff59610ee33cf3ac5e4c1e1bb2b5e9d7771cd2 100644 (file)
@@ -34,9 +34,9 @@ void monster_precache(float _mid)
                        precache_model(SHAMBLER_MODEL);
                        break;
                }
-               case MONSTER_KNIGHT:
+               case MONSTER_BRUISER:
                {
-                       precache_model(KNIGHT_MODEL);
+                       precache_model(BRUISER_MODEL);
                        break;
                }
                case MONSTER_MARINE:
@@ -135,12 +135,12 @@ void monster_mid2info(float _mid)
                        if(self) self.scale = 1.3;
                        break;
                }
-               case MONSTER_KNIGHT:
+               case MONSTER_BRUISER:
                {
-                       mid2info_model = KNIGHT_MODEL;
-                       mid2info_name = "Knight";
-                       mid2info_min = KNIGHT_MIN;
-                       mid2info_max = KNIGHT_MAX;
+                       mid2info_model = BRUISER_MODEL;
+                       mid2info_name = "Bruiser";
+                       mid2info_min = BRUISER_MIN;
+                       mid2info_max = BRUISER_MAX;
                        if(self) self.scale = 1.3;
                        break;
                }
index 81a53e7f1bd386576a609099452b7e772a5cd89a..506cb9cac85ff730e533822d11d73f85d258147e 100644 (file)
@@ -24,7 +24,7 @@
        DEATHTYPE(DEATH_MONSTER_HKNIGHT_INFERNO,DEATH_SELF_MON_HKNIGHT_INFERNO,         NO_MSG,                                            NORMAL_POS) \
        DEATHTYPE(DEATH_MONSTER_HKNIGHT_MELEE,  DEATH_SELF_MON_HKNIGHT_MELEE,           NO_MSG,                                            NORMAL_POS) \
        DEATHTYPE(DEATH_MONSTER_HKNIGHT_SPIKE,  DEATH_SELF_MON_HKNIGHT_SPIKE,           NO_MSG,                                            NORMAL_POS) \
-       DEATHTYPE(DEATH_MONSTER_KNIGHT,                 DEATH_SELF_MON_KNIGHT,                          NO_MSG,                                            NORMAL_POS) \
+       DEATHTYPE(DEATH_MONSTER_BRUISER,                DEATH_SELF_MON_BRUISER,                         NO_MSG,                                            NORMAL_POS) \
        DEATHTYPE(DEATH_MONSTER_OGRE_CHAINSAW,  DEATH_SELF_MON_OGRE_CHAINSAW,           NO_MSG,                                            NORMAL_POS) \
        DEATHTYPE(DEATH_MONSTER_OGRE_GRENADE,   DEATH_SELF_MON_OGRE_GRENADE,            NO_MSG,                                            NORMAL_POS) \
        DEATHTYPE(DEATH_MONSTER_OGRE_UZI,               DEATH_SELF_MON_OGRE_UZI,                        NO_MSG,                                            NORMAL_POS) \
index d081e1e65913abafcb2bbcd1fa79e793d2e63bf0..9e0d60f5198fc603429aa0c18d51c74c07c42e85 100644 (file)
@@ -296,7 +296,7 @@ void Send_Notification_WOVA(
        MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_HKNIGHT_INFERNO, 2, 1, "s1 s2loc spree_lost", "s1",               "notify_death",                 _("^BG%s^K1 was burned to death by a Hell-Knight%s%s\n"), "") \
        MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_HKNIGHT_MELEE,   2, 1, "s1 s2loc spree_lost", "s1",               "notify_death",                 _("^BG%s^K1 was slain by a Hell-Knight%s%s\n"), "") \
        MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_HKNIGHT_SPIKE,   2, 1, "s1 s2loc spree_lost", "s1",               "notify_death",                 _("^BG%s^K1 was cursed by a Hell-Knight%s%s\n"), "") \
-       MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_KNIGHT,              2, 1, "s1 s2loc spree_lost", "s1",           "notify_death",                 _("^BG%s^K1 was sliced up by a Knight%s%s\n"), "") \
+       MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_BRUISER,             2, 1, "s1 s2loc spree_lost", "s1",           "notify_death",                 _("^BG%s^K1 was beaten in a fistfight by a Bruiser%s%s\n"), "") \
        MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_OGRE_CHAINSAW,   2, 1, "s1 s2loc spree_lost", "s1",               "notify_death",                 _("^BG%s^K1 was cut down by an Ogre%s%s\n"), "") \
        MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_OGRE_GRENADE,    2, 1, "s1 s2loc spree_lost", "s1",               "notify_death",                 _("^BG%s^K1 almost dodged the Ogre grenade%s%s\n"), "") \
        MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_OGRE_UZI,            2, 1, "s1 s2loc spree_lost", "s1",           "notify_death",                 _("^BG%s^K1 was nailed by an Ogre%s%s\n"), "") \
@@ -652,7 +652,7 @@ void Send_Notification_WOVA(
        MSG_MULTI_NOTIF(1, DEATH_SELF_MON_HKNIGHT_INFERNO,               NO_MSG,        INFO_DEATH_SELF_MON_HKNIGHT_INFERNO,       CENTER_DEATH_SELF_MONSTER) \
        MSG_MULTI_NOTIF(1, DEATH_SELF_MON_HKNIGHT_MELEE,                 NO_MSG,        INFO_DEATH_SELF_MON_HKNIGHT_MELEE,                 CENTER_DEATH_SELF_MONSTER) \
        MSG_MULTI_NOTIF(1, DEATH_SELF_MON_HKNIGHT_SPIKE,                 NO_MSG,        INFO_DEATH_SELF_MON_HKNIGHT_SPIKE,                 CENTER_DEATH_SELF_MONSTER) \
-       MSG_MULTI_NOTIF(1, DEATH_SELF_MON_KNIGHT,                                NO_MSG,        INFO_DEATH_SELF_MON_KNIGHT,                                CENTER_DEATH_SELF_MONSTER) \
+       MSG_MULTI_NOTIF(1, DEATH_SELF_MON_BRUISER,                               NO_MSG,        INFO_DEATH_SELF_MON_BRUISER,                       CENTER_DEATH_SELF_MONSTER) \
        MSG_MULTI_NOTIF(1, DEATH_SELF_MON_OGRE_CHAINSAW,                 NO_MSG,        INFO_DEATH_SELF_MON_OGRE_CHAINSAW,                 CENTER_DEATH_SELF_MONSTER) \
        MSG_MULTI_NOTIF(1, DEATH_SELF_MON_OGRE_GRENADE,                  NO_MSG,        INFO_DEATH_SELF_MON_OGRE_GRENADE,                  CENTER_DEATH_SELF_MONSTER) \
        MSG_MULTI_NOTIF(1, DEATH_SELF_MON_OGRE_UZI,                              NO_MSG,        INFO_DEATH_SELF_MON_OGRE_UZI,                      CENTER_DEATH_SELF_MONSTER) \
index fbeadc6342257ac7256c03976a9e45b7c3be1e52..4169c0d911824bcda2b0ecf2a6938d91122a9a80 100644 (file)
@@ -1,7 +1,9 @@
-.float()       attack_melee;
-.float()       attack_ranged;
 .float()       checkattack;
 
+.float(float attack_type) monster_attackfunc;
+const float MONSTER_ATTACK_MELEE       = 1;
+const float MONSTER_ATTACK_RANGED      = 2;
+
 .float candrop;
 
 .float spawn_time; // stop monster from moving around right after spawning
index 181aa8d8da433d16ea7c7b6d671c911ef2508544..ad292447805fcc61d7e28eb8c09d6d52744f383a 100644 (file)
@@ -372,23 +372,21 @@ float GenericCheckAttack ()
        if (time < self.attack_finished_single)
                return FALSE;
                
-       if(self.attack_melee)
+       if not(self.monster_attackfunc)
+               return FALSE; // doesn't have an attack function?!
+               
        if(vlen(self.enemy.origin - self.origin) <= 100)
        {
                monster_sound(self.msound_attack_melee, 0, FALSE); // no delay for attack sounds
-               self.attack_melee(); // don't wait for nextthink - too slow
-               return TRUE;
+               if(self.monster_attackfunc(MONSTER_ATTACK_MELEE))
+                       return TRUE;
        }
-       
-       // monster doesn't have a ranged attack function, so stop here
-       if not(self.attack_ranged)
-               return FALSE;
 
        // see if any entities are in the way of the shot
        if not(findtrajectorywithleading(self.origin, '0 0 0', '0 0 0', self.enemy, 800, 0, 2.5, 0, self))
                return FALSE;
 
-       if(self.attack_ranged())
+       if(self.monster_attackfunc(MONSTER_ATTACK_RANGED))
        {
                monster_sound(self.msound_attack_ranged, 0, FALSE); // no delay for attack sounds
                return TRUE;
@@ -1003,6 +1001,7 @@ float monster_initialize(string  net_name, float mon_id,
        self.touch                              = MonsterTouch;
        self.use                                = monster_use;
        self.solid                              = SOLID_BBOX;
+       self.checkattack                = GenericCheckAttack;
        self.scale                              = 1;
        self.movetype                   = MOVETYPE_WALK;
        self.delay                              = -1; // used in attack delay code
index 0c0cdfcd0d669825d5146ae4a6dbd5c649df6779..b0d3fb9326f368025e4034a3b3fe33cdf00cc17c 100644 (file)
@@ -26,7 +26,7 @@ float MONSTER_ZOMBIE          = 2;
 float MONSTER_OGRE                     = 3;
 float MONSTER_DEMON            = 4;
 float MONSTER_SHAMBLER                 = 5;
-float MONSTER_KNIGHT           = 6;
+float MONSTER_BRUISER          = 6;
 float MONSTER_MARINE           = 7;
 float MONSTER_SCRAG            = 8;
 float MONSTER_DOG                      = 9;
index 40c2b7f6c99769dcd77d32747c18b124f3faa81a..2912f0ad7ebdd90abc41ab44f45131f313225efa 100644 (file)
@@ -26,7 +26,7 @@ entity spawnmonster (string monster, entity spawnedby, entity own, vector orig,
        setorigin(e, orig);
        
        if not(spawnmonster_checkinlist(monster, autocvar_g_monsters_spawn_list))
-               monster = "knight";
+               monster = "bruiser";
        
        e.realowner = spawnedby;
        
diff --git a/qcsrc/server/monsters/monster/bruiser.qc b/qcsrc/server/monsters/monster/bruiser.qc
new file mode 100644 (file)
index 0000000..bf29837
--- /dev/null
@@ -0,0 +1,109 @@
+// size
+const vector BRUISER_MIN = '-20 -20 -31';
+const vector BRUISER_MAX = '20 20 53';
+
+// model
+string BRUISER_MODEL = "models/monsters/knight.mdl";
+
+#ifdef SVQC
+// cvars
+float autocvar_g_monster_bruiser;
+float autocvar_g_monster_bruiser_health;
+float autocvar_g_monster_bruiser_melee_damage;
+float autocvar_g_monster_bruiser_speed_walk;
+float autocvar_g_monster_bruiser_speed_run;
+
+// animations
+const float bruiser_anim_stand                 = 0;
+const float bruiser_anim_run           = 1;
+const float bruiser_anim_runattack     = 2;
+const float bruiser_anim_pain1                 = 3;
+const float bruiser_anim_pain2                 = 4;
+const float bruiser_anim_attack        = 5;
+const float bruiser_anim_walk          = 6;
+const float bruiser_anim_kneel                 = 7;
+const float bruiser_anim_standing      = 8;
+const float bruiser_anim_death1        = 9;
+const float bruiser_anim_death2        = 10;
+
+void bruiser_think ()
+{
+       self.think = bruiser_think;
+       self.nextthink = time + self.ticrate;
+       
+       monster_move(autocvar_g_monster_bruiser_speed_run, autocvar_g_monster_bruiser_speed_walk, 50, bruiser_anim_run, bruiser_anim_walk, bruiser_anim_stand);
+}
+
+float bruiser_attack(float attack_type)
+{
+       switch(attack_type)
+       {
+               case MONSTER_ATTACK_MELEE:
+               {
+                       float len = vlen(self.velocity);
+                       monsters_setframe((len < 50) ? bruiser_anim_attack : bruiser_anim_runattack);
+                       self.attack_finished_single = time + 1.25;
+                       
+                       monster_melee(self.enemy, autocvar_g_monster_bruiser_melee_damage, 0.3, DEATH_MONSTER_BRUISER, FALSE);
+                       
+                       return TRUE;
+               }
+               case MONSTER_ATTACK_RANGED:
+       }
+       
+       return FALSE;
+}
+
+void bruiser_die ()
+{
+       Monster_CheckDropCvars ("bruiser");
+       
+       self.think = monster_dead_think;
+       self.nextthink = time + self.ticrate;
+       self.ltime = time + 5;
+       monsters_setframe((random() > 0.5) ? bruiser_anim_death1 : bruiser_anim_death2);
+       
+       monster_hook_death(); // for post-death mods
+}
+
+void bruiser_spawn ()
+{
+       if not(self.health)
+               self.health = autocvar_g_monster_bruiser_health;
+
+       self.damageforcescale   = 0.003;
+       self.classname                  = "monster_bruiser";
+       self.monster_attackfunc = bruiser_attack;
+       self.nextthink                  = time + random() * 0.5 + 0.1;
+       self.think                              = bruiser_think;
+       
+       monsters_setframe(bruiser_anim_stand);
+       
+       monster_setupsounds("bruiser");
+       
+       monster_hook_spawn(); // for post-spawn mods
+}
+
+void spawnfunc_monster_bruiser ()
+{      
+       if not(autocvar_g_monster_bruiser) { remove(self); return; }
+       
+       self.monster_spawnfunc = spawnfunc_monster_bruiser;
+       
+       if(Monster_CheckAppearFlags(self))
+               return;
+       
+       self.scale = 1.3;
+       
+       if not (monster_initialize(
+                        "Bruiser", MONSTER_BRUISER,
+                        BRUISER_MIN, BRUISER_MAX,
+                        FALSE,
+                        bruiser_die, bruiser_spawn))
+       {
+               remove(self);
+               return;
+       }
+}
+
+#endif // SVQC
index 634bdfc1bb55ced254392edace55911976ad3a13..28e97b6c43e4575bc9a98889df75b444ddf3ed7d 100644 (file)
@@ -31,16 +31,6 @@ void demon_think ()
        monster_move(autocvar_g_monster_demon_speed_run, autocvar_g_monster_demon_speed_walk, 100, demon_anim_run, demon_anim_walk, demon_anim_stand);
 }
 
-float demon_attack_melee ()
-{
-       monsters_setframe(demon_anim_attack);
-       self.attack_finished_single = time + 1;
-       
-       monster_melee(self.enemy, autocvar_g_monster_demon_damage, 0.3, DEATH_MONSTER_FIEND, TRUE);
-       
-       return TRUE;
-}
-
 void Demon_JumpTouch ()
 {
        if (self.health <= 0)
@@ -59,12 +49,26 @@ void Demon_JumpTouch ()
                self.touch = MonsterTouch;
 }
 
-float demon_jump ()
+float demon_attack(float attack_type)
 {
-       makevectors(self.angles);
-       if(monster_leap(demon_anim_leap, Demon_JumpTouch, v_forward * 700 + '0 0 300', 0.8))
-               return TRUE;
-               
+       switch(attack_type)
+       {
+               case MONSTER_ATTACK_MELEE:
+               {
+                       monsters_setframe(demon_anim_attack);
+                       self.attack_finished_single = time + 1;
+                       monster_melee(self.enemy, autocvar_g_monster_demon_damage, 0.3, DEATH_MONSTER_FIEND, TRUE);
+                       
+                       return TRUE;
+               }
+               case MONSTER_ATTACK_RANGED:
+               {
+                       makevectors(self.angles);
+                       if(monster_leap(demon_anim_leap, Demon_JumpTouch, v_forward * 700 + '0 0 300', 0.8))
+                               return TRUE;
+               }
+       }
+       
        return FALSE;
 }
 
@@ -87,9 +91,7 @@ void demon_spawn ()
 
        self.damageforcescale   = 0;
        self.classname                  = "monster_demon";
-       self.checkattack                = GenericCheckAttack;
-       self.attack_melee               = demon_attack_melee;
-       self.attack_ranged              = demon_jump;
+       self.monster_attackfunc = demon_attack;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = demon_think;
        
index 99288ae8c075bc24e6e25e46f3f733d0ff461ee2..0846b7b64fb5aabbd7f9a7a0b3054d3874ee6b1e 100644 (file)
@@ -22,6 +22,14 @@ const float dog_anim_attack  = 3;
 const float dog_anim_die       = 4;
 const float dog_anim_pain      = 5;
 
+void dog_think ()
+{
+       self.think = dog_think;
+       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_JumpTouch ()
 {
        if (self.health <= 0)
@@ -37,30 +45,26 @@ void Dog_JumpTouch ()
                self.touch = MonsterTouch;
 }
 
-void dog_think ()
-{
-       self.think = dog_think;
-       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);
-}
-
-float dog_attack ()
+float cerberus_attack(float attack_type)
 {
-       monsters_setframe(dog_anim_attack);
-       self.attack_finished_single = time + 0.7;
-
-       monster_melee(self.enemy, autocvar_g_monster_dog_bite_damage, 0.2, DEATH_MONSTER_DOG_BITE, TRUE);
+       switch(attack_type)
+       {
+               case MONSTER_ATTACK_MELEE:
+               {
+                       monsters_setframe(dog_anim_attack);
+                       self.attack_finished_single = time + 0.7;
+                       monster_melee(self.enemy, autocvar_g_monster_dog_bite_damage, 0.2, DEATH_MONSTER_DOG_BITE, TRUE);
+                       
+                       return TRUE;
+               }
+               case MONSTER_ATTACK_RANGED:
+               {
+                       makevectors(self.angles);
+                       if(monster_leap(dog_anim_attack, Dog_JumpTouch, v_forward * 300 + '0 0 200', 0.8))
+                               return TRUE;
+               }
+       }
        
-       return TRUE;
-}
-
-float dog_jump ()
-{
-       makevectors(self.angles);
-       if(monster_leap(dog_anim_attack, Dog_JumpTouch, v_forward * 300 + '0 0 200', 0.8))
-               return TRUE;
-               
        return FALSE;
 }
 
@@ -83,9 +87,7 @@ void dog_spawn ()
 
        self.damageforcescale   = 0;
        self.classname                  = "monster_dog";
-       self.attack_melee               = dog_attack;
-       self.attack_ranged              = dog_jump;
-       self.checkattack                = GenericCheckAttack;
+       self.monster_attackfunc = cerberus_attack;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = dog_think;
        
index 4d490745a08942d06b4df63cf3647ab681669d64..1f19da0d1707632541884623d36bf724fe81f5c7 100644 (file)
@@ -27,14 +27,22 @@ void fish_think ()
        monster_move(autocvar_g_monster_fish_speed_run, autocvar_g_monster_fish_speed_walk, 10, fish_anim_swim, fish_anim_swim, fish_anim_swim);
 }
 
-float fish_attack ()
+float fish_attack(float attack_type)
 {
-       monsters_setframe(fish_anim_attack);
-       self.attack_finished_single = time + 0.5;
-
-       monster_melee(self.enemy, autocvar_g_monster_fish_damage, 0.1, DEATH_MONSTER_FISH, FALSE);
+       switch(attack_type)
+       {
+               case MONSTER_ATTACK_MELEE:
+               {
+                       monsters_setframe(fish_anim_attack);
+                       self.attack_finished_single = time + 0.5;
+                       monster_melee(self.enemy, autocvar_g_monster_fish_damage, 0.1, DEATH_MONSTER_FISH, FALSE);
+                       
+                       return TRUE;
+               }
+               case MONSTER_ATTACK_RANGED:
+       }
        
-       return TRUE;
+       return FALSE;
 }
 
 void fish_die ()
@@ -56,8 +64,7 @@ void fish_spawn ()
 
        self.damageforcescale   = 0.5;
        self.classname                  = "monster_fish";
-       self.checkattack                = GenericCheckAttack;
-       self.attack_melee               = fish_attack;
+       self.monster_attackfunc = fish_attack;
        self.flags                         |= FL_SWIM;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = fish_think;
index f16cb159310724be9c76183969ef46e98c5d5d58..1de3ba525a2a226fc71983ca6fd00789f86e770c 100644 (file)
@@ -45,6 +45,14 @@ const float hellknight_anim_smash    = 11;
 const float hellknight_anim_wattack = 12;
 const float hellknight_anim_magic3     = 13;
 
+void hellknight_think()
+{
+       self.think = hellknight_think;
+       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);
+}
+
 void hknight_spike_think()
 {
        if(self)
@@ -118,70 +126,6 @@ void hknight_infernowarning ()
        hknight_inferno();
 }
 
-float() hknight_magic;
-float hknight_checkmagic ()
-{
-       local vector v1 = '0 0 0', v2 = '0 0 0';
-       local float dot = 0;
-
-       // use magic to kill zombies as they heal too fast for sword
-       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)
-               {
-                       hknight_magic();
-                       return TRUE;
-               }
-       }
-
-       if (random() < 0.25)
-               return FALSE; // 25% of the time it won't do anything
-       v1 = normalize(self.enemy.velocity);
-       v2 = normalize(self.enemy.origin - self.origin);
-       dot = v1 * v2;
-       if (dot >= 0.7) // moving away
-       if (vlen(self.enemy.velocity) >= 150) // walking/running away
-               return hknight_magic();
-       return FALSE;
-}
-
-void() hellknight_charge;
-void CheckForCharge ()
-{
-       // check for mad charge
-       if (time < self.attack_finished_single)
-               return;
-       if (fabs(self.origin_z - self.enemy.origin_z) > 20)
-               return;         // too much height change
-       if (vlen (self.origin - self.enemy.origin) < 80)
-               return;         // use regular attack
-       if (hknight_checkmagic())
-               return; // chose magic
-
-       // charge
-       hellknight_charge();
-}
-
-void CheckContinueCharge ()
-{
-       if(hknight_checkmagic())
-               return; // chose magic
-       if(time >= self.attack_finished_single)
-       {
-               hellknight_think();
-               return;         // done charging
-       }
-}
-
-void hellknight_think ()
-{
-       self.think = hellknight_think;
-       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);
-}
-
 .float hknight_cycles;
 void hellknight_magic ()
 {
@@ -269,65 +213,7 @@ void hellknight_magic3 ()
        self.delay = time + 0.4;
 }
 
-void hellknight_charge ()
-{
-       monsters_setframe(hellknight_anim_charge1);
-       self.attack_finished_single = time + 0.5;
-       
-       hknight_checkmagic();
-       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
-       hknight_checkmagic();
-}
-
-void hellknight_charge2 ()
-{
-       monsters_setframe(hellknight_anim_charge2);
-       self.attack_finished_single = time + 0.5;
-       
-       CheckContinueCharge ();
-       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
-}
-
-void hellknight_slice ()
-{
-       monsters_setframe(hellknight_anim_slice);
-       self.attack_finished_single = time + 0.7;
-       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, FALSE);
-}
-
-void hellknight_smash ()
-{
-       monsters_setframe(hellknight_anim_smash);
-       self.attack_finished_single = time + 0.7;
-       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
-}
-
-void hellknight_weapon_attack ()
-{
-       monsters_setframe(hellknight_anim_wattack);
-       self.attack_finished_single = time + 0.7;
-       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
-}
-
-float hknight_type;
-float hknight_melee ()
-{
-       hknight_type += 1;
-
-       if (hknight_type == 1)
-               hellknight_slice();
-       else if (hknight_type == 2)
-               hellknight_smash();
-       else
-       {
-               hellknight_weapon_attack();
-               hknight_type = 0;
-       }
-       
-       return TRUE;
-}
-
-float hknight_magic ()
+float hknight_magic()
 {
        if not(self.flags & FL_ONGROUND)
                return FALSE;
@@ -386,10 +272,39 @@ float hknight_magic ()
                        }
                        return FALSE;
                }
-               default:
-                       return FALSE;
        }
-       // never get here
+       
+       return FALSE;
+}
+
+float knight_attack(float attack_type)
+{
+       switch(attack_type)
+       {
+               case MONSTER_ATTACK_MELEE:
+               {
+                       float anim;
+                       if(random() < 0.3)
+                               anim = hellknight_anim_slice;
+                       else if(random() < 0.6)
+                               anim = hellknight_anim_smash;
+                       else
+                               anim = hellknight_anim_wattack;
+                       
+                       monsters_setframe(anim);
+                       self.attack_finished_single = time + 0.7;
+                       monster_melee(self.enemy, autocvar_g_monster_hellknight_melee_damage, 0.3, DEATH_MONSTER_HKNIGHT_MELEE, TRUE);
+                       
+                       return TRUE;
+               }
+               case MONSTER_ATTACK_RANGED:
+               {
+                       if(hknight_magic())
+                               return TRUE;
+               }
+       }
+       
+       return FALSE;
 }
 
 void hellknight_die ()
@@ -419,9 +334,7 @@ void hellknight_spawn ()
 
        self.damageforcescale   = 0.003;
        self.classname                  = "monster_hellknight";
-       self.checkattack                = GenericCheckAttack;
-       self.attack_melee               = hknight_melee;
-       self.attack_ranged              = hknight_magic;
+       self.monster_attackfunc = knight_attack;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = hellknight_think;
        
diff --git a/qcsrc/server/monsters/monster/knight.qc b/qcsrc/server/monsters/monster/knight.qc
deleted file mode 100644 (file)
index 7822620..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-// size
-const vector KNIGHT_MIN = '-20 -20 -31';
-const vector KNIGHT_MAX = '20 20 53';
-
-// model
-string KNIGHT_MODEL = "models/monsters/knight.mdl";
-
-#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_speed_walk;
-float autocvar_g_monster_knight_speed_run;
-
-// animations
-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 + 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);
-}
-
-float knight_attack ()
-{
-       float len = vlen(self.velocity);
-
-       monsters_setframe((len < 50) ? knight_anim_attack : knight_anim_runattack);
-       
-       self.attack_finished_single = time + 1.25;
-       
-       monster_melee(self.enemy, autocvar_g_monster_knight_melee_damage, 0.3, DEATH_MONSTER_KNIGHT, FALSE);
-       
-       return TRUE;
-}
-
-void knight_die ()
-{
-       Monster_CheckDropCvars ("knight");
-       
-       self.think = monster_dead_think;
-       self.nextthink = time + self.ticrate;
-       self.ltime = time + 5;
-       monsters_setframe((random() > 0.5) ? knight_anim_death1 : knight_anim_death2);
-       
-       monster_hook_death(); // for post-death mods
-}
-
-void knight_spawn ()
-{
-       if not(self.health)
-               self.health = autocvar_g_monster_knight_health;
-
-       self.damageforcescale   = 0.003;
-       self.classname                  = "monster_knight";
-       self.checkattack                = GenericCheckAttack;
-       self.attack_melee               = knight_attack;
-       self.nextthink                  = time + random() * 0.5 + 0.1;
-       self.think                              = knight_think;
-       
-       monsters_setframe(knight_anim_stand);
-       
-       monster_setupsounds("knight");
-       
-       monster_hook_spawn(); // for post-spawn mods
-}
-
-void spawnfunc_monster_knight ()
-{      
-       if not(autocvar_g_monster_knight) { remove(self); return; }
-       
-       self.monster_spawnfunc = spawnfunc_monster_knight;
-       
-       if(Monster_CheckAppearFlags(self))
-               return;
-       
-       self.scale = 1.3;
-       
-       if not (monster_initialize(
-                        "Knight", MONSTER_KNIGHT,
-                        KNIGHT_MIN, KNIGHT_MAX,
-                        FALSE,
-                        knight_die, knight_spawn))
-       {
-               remove(self);
-               return;
-       }
-}
-
-#endif // SVQC
index 7b051a96d4848e7261c090a68cb211277385f357..238526ba11dc001aa84d38ad14587c5f9f7ec600 100644 (file)
@@ -41,9 +41,6 @@ void ogre_think()
 void ogre_swing()
 {
        self.ogre_cycles += 1;
-       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;
        self.delay = time + 0.2;
        self.monster_delayedattack = ogre_swing;
@@ -78,14 +75,6 @@ void ogre_uzi_fire()
        self.monster_delayedattack = ogre_uzi_fire;
 }
 
-void ogre_uzi()
-{
-       monsters_setframe(ogre_anim_pain);
-       self.attack_finished_single = time + 0.8;
-       self.delay = time + 0.1;
-       self.monster_delayedattack = ogre_uzi_fire;
-}
-
 void ogre_grenade_explode()
 {
        pointparticles(particleeffectnum("grenade_explode"), self.origin, '0 0 0', 1);
@@ -137,8 +126,6 @@ void ogre_grenade_think()
 void ogre_gl()
 {
        entity gren;
-       
-       monster_makevectors(self.enemy);
 
        W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", CH_WEAPON_A, autocvar_g_monster_ogre_attack_grenade_damage);
        w_shotdir = v_forward; // no TrueAim for grenades please
@@ -172,32 +159,44 @@ void ogre_gl()
        gren.flags = FL_PROJECTILE;
 
        CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE, TRUE);
-       
-       
-       monsters_setframe(ogre_anim_pain);
-       self.attack_finished_single = time + 1.2;
 }
 
-float ogre_missile()
+float ogre_attack(float attack_type)
 {
-       self.ogre_cycles = 0;
-       if (random() <= autocvar_g_monster_ogre_attack_uzi_chance)
-       {
-               ogre_uzi();
-               return TRUE;
-       }
-       else
+       switch(attack_type)
        {
-               ogre_gl();
-               return TRUE;
+               case MONSTER_ATTACK_MELEE:
+               {
+                       self.ogre_cycles = 0;
+                       monsters_setframe(ogre_anim_swing);
+                       self.attack_finished_single = time + 1.3;
+                       ogre_swing();
+                       
+                       return TRUE;
+               }
+               case MONSTER_ATTACK_RANGED:
+               {
+                       self.ogre_cycles = 0;
+                       if(random() <= autocvar_g_monster_ogre_attack_uzi_chance)
+                       {
+                               monsters_setframe(ogre_anim_pain);
+                               self.attack_finished_single = time + 0.8;
+                               self.delay = time + 0.1;
+                               self.monster_delayedattack = ogre_uzi_fire;
+                       }
+                       else
+                       {
+                               monster_makevectors(self.enemy);
+                               ogre_gl();
+                               monsters_setframe(ogre_anim_pain);
+                               self.attack_finished_single = time + 1.2;
+                       }
+                       
+                       return TRUE;
+               }
        }
-}
-
-float ogre_melee()
-{
-       self.ogre_cycles = 0;
-       ogre_swing();
-       return TRUE;
+       
+       return FALSE;
 }
 
 void ogre_die()
@@ -219,9 +218,7 @@ void ogre_spawn()
 
        self.damageforcescale   = 0.003;
        self.classname                  = "monster_ogre";
-       self.checkattack                = GenericCheckAttack;
-       self.attack_melee               = ogre_melee;
-       self.attack_ranged              = ogre_missile;
+       self.monster_attackfunc = ogre_attack;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = ogre_think;
        self.weapon                             = WEP_GRENADE_LAUNCHER;
index 44f52acdd646ac06221a1debf6c4a4304a747c8c..fbbccc9d156051244e47cbb26c22e59265a5520c 100644 (file)
@@ -39,7 +39,6 @@ const float shalrath_anim_death       = 4;
 const float shalrath_anim_run          = 5;
 
 void() ShalMissile;
-float() shal_missile;
 void() shalrath_heal;
 void() shalrath_shield;
 void() shalrath_shield_die;
@@ -94,14 +93,6 @@ void shalrath_think()
        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()
-{
-       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;
-}
-
 void shalrathattack_melee()
 {
        monster_melee(self.enemy, autocvar_g_monster_shalrath_attack_melee_damage, 0.3, DEATH_MONSTER_MAGE, TRUE);
@@ -110,16 +101,6 @@ void shalrathattack_melee()
        self.monster_delayedattack = func_null;
 }
 
-float shalrath_attack_melee()
-{
-       self.monster_delayedattack = shalrathattack_melee;
-       self.delay = time + 0.2;
-       monsters_setframe(shalrath_anim_attack);
-       self.attack_finished_single = time + autocvar_g_monster_shalrath_attack_melee_delay;
-       
-       return TRUE;
-}
-
 void shalrath_grenade_explode()
 {
        pointparticles(particleeffectnum("explosion_small"), self.origin, '0 0 0', 1);
@@ -171,19 +152,6 @@ void shalrath_throw_itemgrenade()
        self.attack_finished_single = time + 1.5;
 }
 
-float shal_missile()
-{
-       if(random() < autocvar_g_monster_shalrath_attack_grenade_chance / 100)
-       {
-               shalrath_throw_itemgrenade();
-               return TRUE;
-       }
-       
-       shalrath_attack();
-       
-       return TRUE;
-}
-
 void ShalHome()
 {
        local vector dir = '0 0 0', vtemp = self.enemy.origin + '0 0 10';
@@ -278,13 +246,15 @@ float ShalrathCheckAttack()
        
        if(time < self.attack_finished_single)
                return FALSE;
+               
+       if not(self.monster_attackfunc)
+               return FALSE; // no attack function?!
        
        if (vlen(self.enemy.origin - self.origin) <= 120)
-       {       // melee attack
-               if (self.attack_melee)
+       {
+               if(self.monster_attackfunc(MONSTER_ATTACK_MELEE))
                {
                        monster_sound(self.msound_attack_melee, 0, FALSE); // no delay for attack sounds
-                       self.attack_melee();
                        return TRUE;
                }
        }
@@ -301,7 +271,7 @@ float ShalrathCheckAttack()
        //if (trace_inopen && trace_inwater)
        //      return FALSE; // sight line crossed contents
 
-       if (self.attack_ranged())
+       if (self.monster_attackfunc(MONSTER_ATTACK_RANGED))
                return TRUE;
 
        return FALSE;
@@ -388,6 +358,39 @@ void shalrath_shield()
        self.armorvalue = autocvar_g_monster_shalrath_shield_blockpercent / 100;
 }
 
+float mage_attack(float attack_type)
+{
+       switch(attack_type)
+       {
+               case MONSTER_ATTACK_MELEE:
+               {
+                       self.monster_delayedattack = shalrathattack_melee;
+                       self.delay = time + 0.2;
+                       monsters_setframe(shalrath_anim_attack);
+                       self.attack_finished_single = time + autocvar_g_monster_shalrath_attack_melee_delay;
+                       
+                       return TRUE;
+               }
+               case MONSTER_ATTACK_RANGED:
+               {
+                       if(random() < autocvar_g_monster_shalrath_attack_grenade_chance / 100)
+                       {
+                               shalrath_throw_itemgrenade();
+                               return TRUE;
+                       }
+       
+                       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;
+                       
+                       return TRUE;
+               }
+       }
+       
+       return FALSE;
+}
+
 void shalrath_die()
 {
        Monster_CheckDropCvars ("shalrath");
@@ -408,8 +411,7 @@ void shalrath_spawn()
        self.damageforcescale   = 0.003;
        self.classname                  = "monster_shalrath";
        self.checkattack                = ShalrathCheckAttack;
-       self.attack_ranged              = shal_missile;
-       self.attack_melee               = shalrath_attack_melee;
+       self.monster_attackfunc = mage_attack;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = shalrath_think;
        
index f139d72a259b9dbed44aea9777bf2d05e5a64c75..2ec7f6d6f6c8d63da33934abd85bc7b83a7451bb 100644 (file)
@@ -79,20 +79,6 @@ void shambler_swing_right ()
        }
 }
 
-float sham_melee ()
-{
-       local float chance = random();
-
-       if (chance > 0.6)
-               shambler_delayedsmash();
-       else if (chance > 0.3)
-               shambler_swing_right ();
-       else
-               shambler_swing_left ();
-               
-       return TRUE;
-}
-
 void CastLightning ()
 {
        self.monster_delayedattack = func_null;
@@ -117,18 +103,35 @@ void CastLightning ()
        WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3"), org, v);
 }
 
-void shambler_magic ()
+float shambler_attack(float attack_type)
 {
-       monsters_setframe(shambler_anim_magic);
-       self.attack_finished_single = time + 1.1;
-       self.monster_delayedattack = CastLightning;
-       self.delay = time + 0.6;
-}
+       switch(attack_type)
+       {
+               case MONSTER_ATTACK_MELEE:
+               {
+                       float chance = random();
+
+                       if(chance > 0.6)
+                               shambler_delayedsmash();
+                       else if(chance > 0.3)
+                               shambler_swing_right();
+                       else
+                               shambler_swing_left();
+                       
+                       return TRUE;
+               }
+               case MONSTER_ATTACK_RANGED:
+               {
+                       monsters_setframe(shambler_anim_magic);
+                       self.attack_finished_single = time + 1.1;
+                       self.monster_delayedattack = CastLightning;
+                       self.delay = time + 0.6;
+                       
+                       return TRUE;
+               }
+       }
        
-float sham_lightning ()
-{
-       shambler_magic();
-       return TRUE;
+       return FALSE;
 }
 
 void shambler_die ()
@@ -150,9 +153,7 @@ void shambler_spawn ()
 
        self.damageforcescale   = 0.003;
        self.classname                  = "monster_shambler";
-       self.attack_melee               = sham_melee;
-       self.checkattack                = GenericCheckAttack;
-       self.attack_ranged              = sham_lightning;
+       self.monster_attackfunc = shambler_attack;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = shambler_think;
        self.weapon                             = WEP_NEX;
index 57821556a99a702ab3ffa436aa970bc3cfe71246..dd8fdae30d298eda84f2699a18243fc3c91f30c7 100644 (file)
@@ -49,11 +49,18 @@ void slime_touch_jump()
        }
 }
 
-float slime_attack()
+float slime_attack(float attack_type)
 {
-       makevectors(self.angles);
-       if(monster_leap(slime_anim_jump, slime_touch_jump, v_forward * 600 + '0 0 200', 0.5))
-               return TRUE;
+       switch(attack_type)
+       {
+               case MONSTER_ATTACK_MELEE:
+               case MONSTER_ATTACK_RANGED:
+               {
+                       makevectors(self.angles);
+                       if(monster_leap(slime_anim_jump, slime_touch_jump, v_forward * 600 + '0 0 200', 0.5))
+                               return TRUE;
+               }
+       }
        
        return FALSE;
 }
@@ -102,9 +109,7 @@ void slime_spawn()
        
        self.damageforcescale   = 0.003;
        self.classname                  = "monster_slime";
-       self.checkattack                = GenericCheckAttack;
-       self.attack_ranged              = slime_attack;
-       self.attack_melee               = self.attack_ranged;
+       self.monster_attackfunc = slime_attack;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = slime_think;
        
index 4a85f8492b095451e29c121b436a8f85ac7325ea..dfe7de8255b3b4b2f6b4aa5ab3985981e2994841 100644 (file)
@@ -237,61 +237,71 @@ void soldier_laser_fire()
        CSQCProjectile(missile, TRUE, PROJECTILE_LASER, TRUE);
 }
 
-float soldier_attack()
+float marine_attack(float attack_type)
 {
-       monsters_setframe(soldier_anim_shoot);
-       
-       monster_makevectors(self.enemy);
-       
-       if(self.currentammo <= 0)
+       switch(attack_type)
        {
-               soldier_reload();
-               return FALSE;
-       }
-       
-       self.grunt_cycles = 0;
-       
-       switch(self.weapon)
-       {
-               case WEP_ROCKET_LAUNCHER:
-               {
-                       self.currentammo -= 1;
-                       self.attack_finished_single = time + 0.8;
-                       soldier_rocket_fire();
-                       return TRUE;
-               }
-               case WEP_SHOTGUN:
-               {
-                       self.currentammo -= 1;
-                       self.attack_finished_single = time + 0.8;
-                       soldier_shotgun_fire();
-                       return TRUE;
-               }
-               case WEP_UZI:
+               case MONSTER_ATTACK_MELEE:
                {
+                       monsters_setframe(soldier_anim_shoot);
                        self.attack_finished_single = time + 0.8;
-                       self.delay = time + 0.1;
-                       self.monster_delayedattack = soldier_uzi_fire;
+                       monster_melee(self.enemy, autocvar_g_monster_soldier_melee_damage, 0.3, DEATH_MONSTER_MARINE_SLAP, TRUE);
+                       
                        return TRUE;
                }
-               case WEP_LASER:
+               case MONSTER_ATTACK_RANGED:
                {
-                       self.attack_finished_single = time + 0.8;
-                       soldier_laser_fire();
-                       return TRUE;
+                       if(self.currentammo <= 0)
+                       {
+                               soldier_reload();
+                               
+                               return FALSE;
+                       }
+                       
+                       monsters_setframe(soldier_anim_shoot);
+                       monster_makevectors(self.enemy);
+                       self.grunt_cycles = 0;
+       
+                       switch(self.weapon)
+                       {
+                               case WEP_ROCKET_LAUNCHER:
+                               {
+                                       self.currentammo -= 1;
+                                       self.attack_finished_single = time + 0.8;
+                                       soldier_rocket_fire();
+                                       
+                                       return TRUE;
+                               }
+                               case WEP_SHOTGUN:
+                               {
+                                       self.currentammo -= 1;
+                                       self.attack_finished_single = time + 0.8;
+                                       soldier_shotgun_fire();
+                                       
+                                       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;
+                                       soldier_laser_fire();
+                                       
+                                       return TRUE;
+                               }
+                       }
+                       
+                       return FALSE;
                }
-               default:
-                       return FALSE; // no weapon?
        }
-}
-
-float soldier_melee ()
-{
-       monsters_setframe(soldier_anim_shoot);
-       self.attack_finished_single = time + 0.8;
-       monster_melee(self.enemy, autocvar_g_monster_soldier_melee_damage, 0.3, DEATH_MONSTER_MARINE_SLAP, TRUE);
        
-       return TRUE;
+       return FALSE;
 }
 
 void soldier_die()
@@ -313,9 +323,7 @@ void soldier_spawn ()
 
        self.damageforcescale   = 0.003;
        self.classname                  = "monster_soldier";
-       self.checkattack                = GenericCheckAttack;
-       self.attack_melee               = soldier_melee;
-       self.attack_ranged              = soldier_attack;
+       self.monster_attackfunc = marine_attack;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = soldier_think;
        self.currentammo                = 3;
index 3867894bf396c9ab5e1f58bf7d723dd5aa822d78..4487ba72672f9de5e98b6f7f79d38d2ab21f5362 100644 (file)
@@ -28,15 +28,12 @@ const float spider_anim_attack2             = 3;
 const float SPIDER_TYPE_ICE            = 0;
 const float SPIDER_TYPE_FIRE   = 1;
 
-float spider_attack_standing()
-{      
-       monster_melee(self.enemy, autocvar_g_monster_spider_attack_stand_damage, 0.3, DEATH_MONSTER_SPIDER, TRUE);
-       
-       monsters_setframe((random() > 0.5) ? spider_anim_attack : spider_anim_attack2);
-
-       self.attack_finished_single = time + autocvar_g_monster_spider_attack_stand_delay;
+void spider_think()
+{
+       self.think = spider_think;
+       self.nextthink = time + self.ticrate;
        
-       return TRUE;
+       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);
 }
 
 void spider_web_explode ()
@@ -130,38 +127,36 @@ void spider_shootweb(float ptype)
        proj.bouncestop = 0.05;
        proj.missile_flags = MIF_SPLASH | MIF_ARC;
 
-       CSQCProjectile(proj, TRUE, p, FALSE); // no culling, it has sound
+       CSQCProjectile(proj, TRUE, p, TRUE);
 }
 
-void spider_attack_leap()
+float spider_attack(float attack_type)
 {
-       vector angles_face = vectoangles(self.enemy.origin - self.origin);
-
-       // 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;
-       
-       monster_makevectors(self.enemy);
-       
-       spider_shootweb(self.spider_type);
-}
-
-float spider_attack_ranged()
-{
-       if(self.enemy.frozen)
-               return FALSE;
-               
-       spider_attack_leap();
-       return TRUE;
-}
-
-void spider_think()
-{
-       self.think = spider_think;
-       self.nextthink = time + self.ticrate;
+       switch(attack_type)
+       {
+               case MONSTER_ATTACK_MELEE:
+               {
+                       monster_melee(self.enemy, autocvar_g_monster_spider_attack_stand_damage, 0.3, DEATH_MONSTER_SPIDER, TRUE);
+                       monsters_setframe((random() > 0.5) ? spider_anim_attack : spider_anim_attack2);
+                       self.attack_finished_single = time + autocvar_g_monster_spider_attack_stand_delay;
+                       
+                       return TRUE;
+               }
+               case MONSTER_ATTACK_RANGED:
+               {
+                       if(self.enemy.frozen)
+                               return FALSE;
+                       
+                       monsters_setframe(spider_anim_attack2);
+                       self.attack_finished_single = time + autocvar_g_monster_spider_attack_leap_delay;
+                       monster_makevectors(self.enemy);
+                       spider_shootweb(self.spider_type);
+                       
+                       return TRUE;
+               }
+       }
        
-       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);
+       return FALSE;
 }
 
 void spider_die ()
@@ -184,9 +179,7 @@ void spider_spawn()
        
        self.classname                  = "monster_spider";
        self.nextthink                  = time + random() * 0.5 + 0.1;
-       self.checkattack                = GenericCheckAttack;
-       self.attack_melee               = spider_attack_standing;
-       self.attack_ranged              = spider_attack_ranged;
+       self.monster_attackfunc = spider_attack;
        self.think                              = spider_think;
        
        monsters_setframe(spider_anim_idle);
index 04880534cef28cc5a944a4cb23a8256248580c6b..03813dd142a5102f4a465a4db2bf08a17a2fcc1d 100644 (file)
@@ -23,6 +23,14 @@ const float wizard_anim_magic        = 2;
 const float wizard_anim_pain   = 3;
 const float wizard_anim_death  = 4;
 
+void wizard_think ()
+{
+       self.think = wizard_think;
+       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);
+}
+
 void Wiz_FastExplode()
 {
        self.event_damage = func_null;
@@ -84,17 +92,20 @@ void Wiz_StartFast ()
        CSQCProjectile(missile, TRUE, PROJECTILE_CRYLINK, TRUE);
 }
 
-void wizard_think ()
+float wyvern_attack(float attack_type)
 {
-       self.think = wizard_think;
-       self.nextthink = time + self.ticrate;
+       switch(attack_type)
+       {
+               case MONSTER_ATTACK_MELEE:
+               case MONSTER_ATTACK_RANGED:
+               {
+                       Wiz_StartFast();
+                       
+                       return TRUE;
+               }
+       }
        
-       monster_move(autocvar_g_monster_wizard_speed_run, autocvar_g_monster_wizard_speed_walk, 300, wizard_anim_fly, wizard_anim_hover, wizard_anim_hover);
-}
-
-void wizard_fastattack ()
-{
-       Wiz_StartFast();
+       return FALSE;
 }
 
 void wizard_die ()
@@ -113,20 +124,13 @@ void wizard_die ()
        monster_hook_death(); // for post-death mods
 }
 
-float Wiz_Missile ()
-{
-       wizard_fastattack();
-       return TRUE;
-}
-
 void wizard_spawn ()
 {
        if not(self.health)
                self.health = autocvar_g_monster_wizard_health;
        
        self.classname                  = "monster_wizard";
-       self.checkattack                = GenericCheckAttack;
-       self.attack_ranged              = Wiz_Missile;
+       self.monster_attackfunc = wyvern_attack;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.movetype                   = MOVETYPE_FLY; // TODO: make it fly up/down
        self.flags                         |= FL_FLY;
index d9c45d9ff7fef2166a3bc93330c0e384d70491fe..a1d0b539530c7277619a9afb91e823cf10ebb0fc 100644 (file)
@@ -52,24 +52,12 @@ const float zombie_anim_runforwardleft              = 28;
 const float zombie_anim_runforwardright                = 29;
 const float zombie_anim_spawn                          = 30;
 
-float zombie_attack_standing()
+void zombie_think()
 {
-       float rand = random(), chosen_anim;
-               
-       if (rand < 0.33)
-               chosen_anim = zombie_anim_attackstanding1;
-       else if (rand < 0.66)
-               chosen_anim = zombie_anim_attackstanding2;
-       else
-               chosen_anim = zombie_anim_attackstanding3;
-               
-       monsters_setframe(chosen_anim);
+       self.think = zombie_think;
+       self.nextthink = time + self.ticrate;
 
-       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);
-       
-       return TRUE;
+       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_attack_leap_touch ()
@@ -79,7 +67,7 @@ void zombie_attack_leap_touch ()
                
        vector angles_face;
 
-       if (monster_isvalidtarget(other, self))
+       if(other.takedamage)
        {
                angles_face = vectoangles(self.moveto - self.origin);
                angles_face = normalize(angles_face) * autocvar_g_monster_zombie_attack_leap_force;
@@ -87,25 +75,42 @@ void zombie_attack_leap_touch ()
                self.touch = MonsterTouch; // instantly turn it off to stop damage spam
        }
 
-       if(self.flags & FL_ONGROUND)
+       if (trace_dphitcontents)
                self.touch = MonsterTouch;
 }
 
-float zombie_attack_ranged()
+float zombie_attack(float attack_type)
 {
-       makevectors(self.angles);
-       if(monster_leap(zombie_anim_attackleap, zombie_attack_leap_touch, v_forward * autocvar_g_monster_zombie_attack_leap_speed + '0 0 200', autocvar_g_monster_zombie_attack_leap_delay))
-               return TRUE;
+       switch(attack_type)
+       {
+               case MONSTER_ATTACK_MELEE:
+               {
+                       float rand = random(), chosen_anim;
                
-       return FALSE;
-}
-
-void zombie_think()
-{
-       self.think = zombie_think;
-       self.nextthink = time + self.ticrate;
+                       if(rand < 0.33)
+                               chosen_anim = zombie_anim_attackstanding1;
+                       else if(rand < 0.66)
+                               chosen_anim = zombie_anim_attackstanding2;
+                       else
+                               chosen_anim = zombie_anim_attackstanding3;
+                               
+                       monsters_setframe(chosen_anim);
 
-       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);
+                       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);
+                       
+                       return TRUE;
+               }
+               case MONSTER_ATTACK_RANGED:
+               {
+                       makevectors(self.angles);
+                       if(monster_leap(zombie_anim_attackleap, zombie_attack_leap_touch, v_forward * autocvar_g_monster_zombie_attack_leap_speed + '0 0 200', autocvar_g_monster_zombie_attack_leap_delay))
+                               return TRUE;
+               }
+       }
+       
+       return FALSE;
 }
 
 void zombie_die ()
@@ -129,9 +134,7 @@ void zombie_spawn()
        self.spawn_time                 = time + 2.1;
        self.nextthink                  = time + random() * 0.5 + 0.1;
        self.think                              = zombie_think;
-       self.checkattack                = GenericCheckAttack;
-       self.attack_melee               = zombie_attack_standing;
-       self.attack_ranged              = zombie_attack_ranged;
+       self.monster_attackfunc = zombie_attack;
        self.respawntime                = 0.1;
        self.spawnflags            |= MONSTER_RESPAWN_DEATHPOINT; // always enabled for zombie
        
index d1ff2db38c7205c9aad855a672e2d04ed04222ba..0d5c260a3647cd7ef7347e390bce6c35fa52b02b 100644 (file)
@@ -9,7 +9,7 @@
 #include "monster/ogre.qc"
 #include "monster/demon.qc"
 #include "monster/shambler.qc"
-#include "monster/knight.qc"
+#include "monster/bruiser.qc"
 #include "monster/soldier.qc"
 #include "monster/wizard.qc"
 #include "monster/dog.qc"
index dcc79b82ce51852fe813a1b83e8666d5066d916d..bd43d421882c4a8264c948f06994c46b20de4f63 100644 (file)
@@ -379,7 +379,7 @@ float Monster_GetStrength(float mnster)
        switch(mnster)
        {
                default:
-               case MONSTER_KNIGHT:
+               case MONSTER_BRUISER:
                case MONSTER_MARINE:
                case MONSTER_ZOMBIE:
                case MONSTER_SPIDER:
@@ -406,7 +406,7 @@ string monster_type2string(float mnster)
                case MONSTER_OGRE: return "ogre";
                case MONSTER_DEMON: return "demon";
                case MONSTER_SHAMBLER: return "shambler";
-               case MONSTER_KNIGHT: return "knight";
+               case MONSTER_BRUISER: return "bruiser";
                case MONSTER_MARINE: return "marine";
                case MONSTER_SCRAG: return "scrag";
                case MONSTER_DOG: return "dog";
@@ -424,7 +424,7 @@ float Monster_GetType(float mnster)
        switch(mnster)
        {
                default:
-               case MONSTER_KNIGHT:
+               case MONSTER_BRUISER:
                case MONSTER_MARINE:
                case MONSTER_ZOMBIE:
                case MONSTER_SPIDER:
@@ -455,7 +455,7 @@ float RandomMonster()
        if(n_spiders) RandomSelection_Add(world, MONSTER_SPIDER, "", 1, 1);
        if(n_ogres) RandomSelection_Add(world, MONSTER_OGRE, "", 1, 1);
        if(n_dogs) RandomSelection_Add(world, MONSTER_DOG, "", 1, 1);
-       if(n_knights) RandomSelection_Add(world, MONSTER_KNIGHT, "", 1, 1);
+       if(n_bruisers) RandomSelection_Add(world, MONSTER_BRUISER, "", 1, 1);
        if(n_shamblers) RandomSelection_Add(world, MONSTER_SHAMBLER, "", 0.2, 0.2);
        if(n_slimes) RandomSelection_Add(world, MONSTER_SLIME, "", 0.2, 0.2);
        if(n_wizards && flyspawns_count) RandomSelection_Add(world, MONSTER_SCRAG, "", 1, 1);
@@ -505,7 +505,7 @@ void queue_monsters(float maxmonsters)
        n_demons        = DistributeEvenly_Get(1);
        n_ogres         = DistributeEvenly_Get(1);
        n_dogs          = DistributeEvenly_Get(1);
-       n_knights   = DistributeEvenly_Get(1);
+       n_bruisers  = DistributeEvenly_Get(1);
        n_shalraths = DistributeEvenly_Get(1);
        n_soldiers  = DistributeEvenly_Get(1);
        n_hknights  = DistributeEvenly_Get(1);
@@ -842,7 +842,7 @@ MUTATOR_HOOKFUNCTION(td_MonsterSpawn)
                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_BRUISER: n_bruisers -= 1; break;
                case MONSTER_MARINE: n_soldiers -= 1; break;
                case MONSTER_SCRAG: n_wizards -= 1; break;
                case MONSTER_DOG: n_dogs -= 1; break;
index dd78d14ccb20d6719e93cdf714db1528c92df277..35847d182dfed593862bccd70927ed947777065d 100644 (file)
@@ -1,6 +1,6 @@
 // Counters
 float monster_count, totalmonsters;
-float n_knights, n_dogs, n_ogres, n_shamblers, n_wizards, n_shalraths, n_soldiers, n_hknights, n_demons, n_zombies, n_slimes, n_fish, n_spiders;
+float n_bruisers, n_dogs, n_ogres, n_shamblers, n_wizards, n_shalraths, n_soldiers, n_hknights, n_demons, n_zombies, n_slimes, n_fish, n_spiders;
 float current_monsters;
 float waterspawns_count, flyspawns_count;
 float wave_count, max_waves;