]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Add an infection mode to zombie apocalypse, which allows playing as monsters
authorMario <zacjardine@y7mail.com>
Sun, 26 Apr 2015 18:19:08 +0000 (04:19 +1000)
committerMario <zacjardine@y7mail.com>
Sun, 26 Apr 2015 18:19:08 +0000 (04:19 +1000)
31 files changed:
qcsrc/Makefile
qcsrc/client/csqcmodel_hooks.qc
qcsrc/client/main.qc
qcsrc/client/view.qc
qcsrc/common/animdecide.qc
qcsrc/common/animdecide.qh
qcsrc/common/minigames/minigame/all.qh
qcsrc/common/minigames/minigame/c4.qc
qcsrc/common/monsters/all.qh
qcsrc/common/monsters/monster/afrit.qc
qcsrc/common/monsters/monster/creeper.qc
qcsrc/common/monsters/monster/demon.qc
qcsrc/common/monsters/monster/enforcer.qc
qcsrc/common/monsters/monster/goomba.qc
qcsrc/common/monsters/monster/mage.qc
qcsrc/common/monsters/monster/ogre.qc
qcsrc/common/monsters/monster/rotfish.qc
qcsrc/common/monsters/monster/rottweiler.qc
qcsrc/common/monsters/monster/scrag.qc
qcsrc/common/monsters/monster/shambler.qc
qcsrc/common/monsters/monster/spawn.qc
qcsrc/common/monsters/monster/spider.qc
qcsrc/common/monsters/monster/vore.qc
qcsrc/common/monsters/monster/wyvern.qc
qcsrc/common/monsters/monster/zombie.qc
qcsrc/common/monsters/monsters.qh
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/monsters/sv_monsters.qh
qcsrc/server/autocvars.qh
qcsrc/server/cl_client.qc
qcsrc/server/mutators/mutator_zombie_apocalypse.qc

index b7594c76e3769167189cb1e2f472f665afa51404..04d8d85f04a065f2c9c6b7292bf47c446f1dc50a 100644 (file)
@@ -13,6 +13,7 @@ QCCFLAGS ?= \
        -std=gmqcc \
        -O3 -flno \
        -DSTUFFTO_ENABLED \
+       -DMONSTERS_EXTRA \
        -Werror -fno-bail-on-werror -Wall \
        -fftepp -fftepp-predefs -Wcpp -futf8 \
        $(QCCFLAGS_WTFS) \
index e63c7d68b725d72f9634255aee2457cf538d21d0..2022634393a89b41e778776d2611f3cd7f331826 100644 (file)
@@ -681,8 +681,12 @@ void CSQCModel_Hook_PreDraw(bool isplayer)
 
        if(self.isplayermodel) // this checks if it's a player MODEL!
        {
-               CSQCPlayer_ModelAppearance_Apply(self.entnum == player_localnum + 1);
-               CSQCPlayer_LOD_Apply();
+               if(isplayer)
+               {
+                       CSQCPlayer_ModelAppearance_Apply(self.entnum == player_localnum + 1);
+                       CSQCPlayer_LOD_Apply();
+               }
+
                if(!isplayer)
                {
                        skeleton_loadinfo(self);
@@ -780,7 +784,7 @@ void CSQCModel_Hook_PreUpdate(bool isnew, bool isplayer, bool islocalplayer)
 void CSQCModel_Hook_PostUpdate(bool isnew, bool isplayer, bool islocalplayer)
 {
        // is it a player model? (shared state)
-       self.isplayermodel = (substring(self.model, 0, 14) == "models/player/" || substring(self.model, 0, 17) == "models/ok_player/");
+       self.isplayermodel = (substring(self.model, 0, 14) == "models/player/" || substring(self.model, 0, 17) == "models/ok_player/" || substring(self.model, 0, 16) == "models/monsters/");
 
        // save values set by server
        if(self.isplayermodel)
index 3398066e82b6fcd79931ec56681976059b684c83..8cd2acd7f41ad0df8b1d6d7a08a7b074b97540f9 100644 (file)
@@ -211,6 +211,7 @@ void CSQC_Init(void)
 
        // needs to be done so early because of the constants they create
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
+       CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
        CALL_ACCUMULATED_FUNCTION(RegisterTurrets);
        CALL_ACCUMULATED_FUNCTION(RegisterVehicles);
        CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
index c72a3dd14b5904f03b253fdce7c2130476218fe2..66228f441a61c0fcaf2f8f096b1ba48829d1f4f1 100644 (file)
@@ -475,7 +475,7 @@ vector liquidcolor_prev;
 
 float eventchase_current_distance;
 float eventchase_running;
-float WantEventchase()
+bool WantEventchase()
 {
        if(autocvar_cl_orthoview)
                return false;
@@ -487,6 +487,8 @@ float WantEventchase()
        {
                if(hud != HUD_NORMAL && (autocvar_cl_eventchase_vehicle || spectatee_status > 0))
                        return true;
+               if(substring(self.model, 0, 16) == "models/monsters/")
+                       return true;
                if(autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(WepSet_GetFromStat() & WepSet_FromWeapon(WEP_PORTO)))
                        return true;
                if(autocvar_cl_eventchase_death && (getstati(STAT_HEALTH) <= 0))
index d5e8617d93159fd20da7cc3b7a21adbd21089ec0..20e0c17a0776536430b9079b49af4738ee7e6392 100644 (file)
     #include "../server/defs.qh"
 #endif
 
-// player animation data for this model
-// each vector is as follows:
-// _x = startframe
-// _y = numframes
-// _z = framerate
-.vector anim_die1; // player dies
-.vector anim_die2; // player dies differently
-.vector anim_draw; // player pulls out a weapon
-.vector anim_duckwalk; // player walking while crouching
-.vector anim_duckjump; // player jumping from a crouch
-.vector anim_duckidle; // player idling while crouching
-.vector anim_idle; // player standing
-.vector anim_jump; // player jump
-.vector anim_pain1; // player flinches from pain
-.vector anim_pain2; // player flinches from pain, differently
-.vector anim_shoot; // player shoots
-.vector anim_taunt; // player taunts others (FIXME: no code references this)
-.vector anim_run; // player running forward
-.vector anim_runbackwards; // player running backward
-.vector anim_strafeleft; // player shuffling left quickly
-.vector anim_straferight; // player shuffling right quickly
-.vector anim_forwardright; // player running forward and right
-.vector anim_forwardleft; // player running forward and left
-.vector anim_backright; // player running backward and right
-.vector anim_backleft; // player running back and left
-.vector anim_melee; // player doing the melee action
-.vector anim_duck; // player doing the melee action
-.vector anim_duckwalkbackwards;
-.vector anim_duckwalkstrafeleft;
-.vector anim_duckwalkstraferight;
-.vector anim_duckwalkforwardright;
-.vector anim_duckwalkforwardleft;
-.vector anim_duckwalkbackright;
-.vector anim_duckwalkbackleft;
-.float animdecide_modelindex;
+bool monsters_animoverride(entity e)
+{
+       int monster_id = 0;
+       for(int i = MON_FIRST; i <= MON_LAST; ++i)
+       {
+               entity mon = get_monsterinfo(i);
+
+               //if(substring(e.model, 0, strlen(mon.model) - 4) == substring(mon.model, 0, strlen(mon.model) - 4))
+               if(e.model == mon.model)
+               {
+                       monster_id = i;
+                       break;
+               }
+       }
+
+       if(!monster_id) { return false; }
+
+       MON_ACTION(monster_id, MR_ANIM);
+
+       vector none = '0 0 0';
+       e.anim_duckwalk = e.anim_walk;
+       e.anim_duckjump = animfixfps(e, '5 1 10', none);
+       e.anim_duckidle = e.anim_idle;
+       e.anim_jump = animfixfps(e, '8 1 10', none);
+       e.anim_taunt = animfixfps(e, '12 1 0.33', none);
+       e.anim_runbackwards = e.anim_run;
+       e.anim_strafeleft = e.anim_run;
+       e.anim_straferight = e.anim_run;
+       e.anim_forwardright = e.anim_run;
+       e.anim_forwardleft = e.anim_run;
+       e.anim_backright = e.anim_run;
+       e.anim_backleft  = e.anim_run;
+       e.anim_duckwalkbackwards = e.anim_walk;
+       e.anim_duckwalkstrafeleft = e.anim_walk;
+       e.anim_duckwalkstraferight = e.anim_walk;
+       e.anim_duckwalkforwardright = e.anim_walk;
+       e.anim_duckwalkforwardleft = e.anim_walk;
+       e.anim_duckwalkbackright = e.anim_walk;
+       e.anim_duckwalkbackleft  = e.anim_walk;
+
+       // these anims ought to stay until stopped explicitly by weaponsystem
+       e.anim_shoot_z = 0.001;
+       e.anim_melee_z = 0.001;
+
+       return true;
+}
 
 void animdecide_load_if_needed(entity e)
 {
@@ -52,6 +63,12 @@ void animdecide_load_if_needed(entity e)
                return;
        e.animdecide_modelindex = e.modelindex;
 
+       if(substring(e.model, 0, 16) == "models/monsters/")
+       {
+               if(monsters_animoverride(e))
+                       return;
+       }
+
        vector none = '0 0 0';
        e.anim_die1 = animfixfps(e, '0 1 0.5', none); // 2 seconds
        e.anim_die2 = animfixfps(e, '1 1 0.5', none); // 2 seconds
index 5d441ef80f7cd34ca46505ef3958c9bfe7c620da..585fb1e67a43960fd11daab7a7c050d98b71db86 100644 (file)
@@ -24,6 +24,42 @@ void animdecide_setframes(entity e, bool support_blending, .int fld_frame, .int
 .float anim_upper_implicit_action;
 .float anim_upper_implicit_time;
 
+// player animation data for this model
+// each vector is as follows:
+// _x = startframe
+// _y = numframes
+// _z = framerate
+.vector anim_die1; // player dies
+.vector anim_die2; // player dies differently
+.vector anim_draw; // player pulls out a weapon
+.vector anim_duckwalk; // player walking while crouching
+.vector anim_duckjump; // player jumping from a crouch
+.vector anim_duckidle; // player idling while crouching
+.vector anim_idle; // player standing
+.vector anim_jump; // player jump
+.vector anim_pain1; // player flinches from pain
+.vector anim_pain2; // player flinches from pain, differently
+.vector anim_shoot; // player shoots
+.vector anim_taunt; // player taunts others (FIXME: no code references this)
+.vector anim_run; // player running forward
+.vector anim_runbackwards; // player running backward
+.vector anim_strafeleft; // player shuffling left quickly
+.vector anim_straferight; // player shuffling right quickly
+.vector anim_forwardright; // player running forward and right
+.vector anim_forwardleft; // player running forward and left
+.vector anim_backright; // player running backward and right
+.vector anim_backleft; // player running back and left
+.vector anim_melee; // player doing the melee action
+.vector anim_duck; // player doing the melee action
+.vector anim_duckwalkbackwards;
+.vector anim_duckwalkstrafeleft;
+.vector anim_duckwalkstraferight;
+.vector anim_duckwalkforwardright;
+.vector anim_duckwalkforwardleft;
+.vector anim_duckwalkbackright;
+.vector anim_duckwalkbackleft;
+.float animdecide_modelindex;
+
 // explicit anim states (networked)
 void animdecide_setstate(entity e, int newstate, float restart);
 const int ANIMSTATE_DEAD1 = 1; // base frames: die1
index 2505b142be14580942a76ce0d5915fce261159b2..f6c850107981f23e060d89461520d0e3488ecdc2 100644 (file)
@@ -63,7 +63,7 @@ that .owner is set to the minigame session entity and .minigame_autoclean is tru
 
 #include "nmm.qc"
 #include "ttt.qc"
-//#include "c4.qc"
+#include "c4.qc"
 #include "pong.qc"
 
 /**
@@ -76,10 +76,9 @@ that .owner is set to the minigame session entity and .minigame_autoclean is tru
        MINIGAME(nmm, "Nine Men's Morris") \
        MINIGAME(ttt, "Tic Tac Toe") \
        MINIGAME(pong, "Pong") \
+       MINIGAME(c4,  "Connect Four") \
        /*empty line*/
 
-//MINIGAME(c4,  "Connect Four") \
-
 /**
  * Set up automatic entity read/write functionality
  * To ensure that everything is handled automatically, spawn on the server using msle_spawn
index 6e38afeb66d5a2875c484d8c4d8150584544e6dc..c4e06006f8367c6ae668fa0ad473747544fb4ebb 100644 (file)
@@ -8,6 +8,16 @@ const float C4_TURN_TEAM1 = 0x0001;
 const float C4_TURN_TEAM2 = 0x0002;
 const float C4_TURN_TEAM  = 0x000f; // turn team mask
 
+const int C4_LET_CNT = 7;
+const int C4_NUM_CNT = 6;
+const int C4_WIN_CNT = 4;
+
+const int C4_MAX_TILES = 42;
+
+const int C4_TILE_SIZE = 8;
+
+const int C4_TEAMS = 2;
+
 // send flags
 const float C4_SF_PLAYERSCORE  = MINIG_SF_CUSTOM;   // send minigame_player scores (won matches)
 
@@ -35,7 +45,7 @@ bool c4_winning_piece(entity piece)
        entity left = piece;
        entity topleft = piece;
        entity botleft = piece;
-       for(i = number; i < 6; ++i)
+       for(i = number; i < C4_NUM_CNT; ++i)
        {
                entity p = c4_find_piece(piece.owner,minigame_tile_buildname(letter, i));
                if(p.team == piece.team)
@@ -59,7 +69,7 @@ bool c4_winning_piece(entity piece)
                        botleft = p;
                else break;
        }
-       for(i = letter, j = number; i >= 0, j < 6; --i, ++j)
+       for(i = letter, j = number; i >= 0, j < C4_NUM_CNT; --i, ++j)
        {
                entity p = c4_find_piece(piece.owner,minigame_tile_buildname(i, j));
                if(p.team == piece.team)
@@ -76,43 +86,43 @@ bool c4_winning_piece(entity piece)
                else break;
        }
 
-       if(found >= 4)
+       if(found >= C4_WIN_CNT)
                return true;
 
        // right
        found = 0;
-       for(i = minigame_tile_letter(left.netname); i < 7; ++i)
+       for(i = minigame_tile_letter(left.netname); i < C4_LET_CNT; ++i)
        {
                if(c4_find_piece(piece.owner,minigame_tile_buildname(i, number)).team == piece.team)
                        ++found;
                else break;
        }
 
-       if(found >= 4)
+       if(found >= C4_WIN_CNT)
                return true;
 
        // diagright down
        found = 0;
-       for(i = minigame_tile_letter(topleft.netname), j = minigame_tile_number(topleft.netname); i < 7, j >= 0; ++i, --j)
+       for(i = minigame_tile_letter(topleft.netname), j = minigame_tile_number(topleft.netname); i < C4_LET_CNT, j >= 0; ++i, --j)
        {
                if(c4_find_piece(piece.owner,minigame_tile_buildname(i, j)).team == piece.team)
                        ++found;
                else break;
        }
 
-       if(found >= 4)
+       if(found >= C4_WIN_CNT)
                return true;
 
        // diagright up
        found = 0;
-       for(i = minigame_tile_letter(botleft.netname), j = minigame_tile_number(botleft.netname); i < 7, j < 6; ++i, ++j)
+       for(i = minigame_tile_letter(botleft.netname), j = minigame_tile_number(botleft.netname); i < C4_LET_CNT, j < C4_NUM_CNT; ++i, ++j)
        {
                if(c4_find_piece(piece.owner,minigame_tile_buildname(i, j)).team == piece.team)
                        ++found;
                else break;
        }
 
-       if(found >= 4)
+       if(found >= C4_WIN_CNT)
                return true;
        
        return false;
@@ -125,7 +135,7 @@ float c4_valid_tile(string tile)
                return 0;
        float number = minigame_tile_number(tile);
        float letter = minigame_tile_letter(tile);
-       return 0 <= number && number < 6 && 0 <= letter && letter < 7;
+       return 0 <= number && number < C4_NUM_CNT && 0 <= letter && letter < C4_LET_CNT;
 }
 
 // make a move
@@ -143,14 +153,14 @@ void c4_move(entity minigame, entity player, string pos )
                        minigame_server_sendflags(piece,MINIG_SF_ALL);
                        minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
                        minigame.c4_npieces++;
-                       minigame.c4_nexteam = minigame_next_team(player.team,2);
+                       minigame.c4_nexteam = minigame_next_team(player.team,C4_TEAMS);
                        if ( c4_winning_piece(piece) )
                        {
                                player.minigame_flags++;
                                minigame_server_sendflags(player, C4_SF_PLAYERSCORE);
                                minigame.minigame_flags = C4_TURN_WIN | player.team;
                        }
-                       else if ( minigame.c4_npieces >= 21 )
+                       else if ( minigame.c4_npieces >= C4_MAX_TILES )
                                minigame.minigame_flags = C4_TURN_DRAW;
                        else
                                minigame.minigame_flags = C4_TURN_PLACE | minigame.c4_nexteam;
@@ -186,7 +196,7 @@ void c4_next_match(entity minigame, entity player)
 
 
 // required function, handle server side events
-float minigame_event_c4(entity minigame, string event, ...)
+float c4_server_event(entity minigame, string event, ...)
 {
        switch(event)
        {
@@ -211,11 +221,11 @@ float minigame_event_c4(entity minigame, string event, ...)
                        float pl_num = minigame_count_players(minigame);
 
                        // Don't allow more than 2 players
-                       if(pl_num >= 2) { return false; }
+                       if(pl_num >= C4_TEAMS) { return false; }
 
                        // Get the right team
                        if(minigame.minigame_players)
-                               return minigame_next_team(minigame.minigame_players.team, 2);
+                               return minigame_next_team(minigame.minigame_players.team, C4_TEAMS);
 
                        // Team 1 by default
                        return 1;
@@ -258,7 +268,7 @@ vector c4_boardsize;// HUD board size
 .float c4_checkwin; // Used to optimize checks to display a win
 
 // Required function, draw the game board
-void minigame_hud_board_c4(vector pos, vector mySize)
+void c4_hud_board(vector pos, vector mySize)
 {
        minigame_hud_fitsqare(pos, mySize);
        c4_boardpos = pos;
@@ -266,13 +276,13 @@ void minigame_hud_board_c4(vector pos, vector mySize)
        
        minigame_hud_simpleboard(pos,mySize,minigame_texture("c4/board"));
 
-       vector tile_size = minigame_hud_denormalize_size(('1 0 0' / 6) + ('0 1 0' / 6),pos,mySize);
+       vector tile_size = minigame_hud_denormalize_size('1 1 0' / C4_TILE_SIZE,pos,mySize);
        vector tile_pos;
 
        if ( (active_minigame.minigame_flags & C4_TURN_TEAM) == minigame_self.team )
        if ( c4_valid_tile(c4_curr_pos) )
        {
-               tile_pos = minigame_tile_pos(c4_curr_pos,6,7);
+               tile_pos = minigame_tile_pos(c4_curr_pos,C4_NUM_CNT,C4_LET_CNT);
                tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
                minigame_drawpic_centered( tile_pos,  
                                minigame_texture(strcat("c4/piece",ftos(minigame_self.team))),
@@ -284,7 +294,7 @@ void minigame_hud_board_c4(vector pos, vector mySize)
        {
                if ( e.classname == "minigame_board_piece" )
                {
-                       tile_pos = minigame_tile_pos(e.netname,6,7);
+                       tile_pos = minigame_tile_pos(e.netname,C4_NUM_CNT,C4_LET_CNT);
                        tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
                        
                        if ( active_minigame.minigame_flags & C4_TURN_WIN )
@@ -310,7 +320,7 @@ void minigame_hud_board_c4(vector pos, vector mySize)
 
 
 // Required function, draw the game status panel
-void minigame_hud_status_c4(vector pos, vector mySize)
+void c4_hud_status(vector pos, vector mySize)
 {
        HUD_Panel_DrawBg(1);
        vector ts;
@@ -335,7 +345,7 @@ void minigame_hud_status_c4(vector pos, vector mySize)
                        if ( e.team == 2 )
                                mypos_y  += player_fontsize_y + ts_y;
                        minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
-                               (e.minigame_playerslot ? GetPlayerName(e.minigame_playerslot-1) : _("AI")),
+                               GetPlayerName(e.minigame_playerslot-1),
                                player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
                        
                        mypos_y += player_fontsize_y;
@@ -402,7 +412,7 @@ string c4_get_lowest_tile(entity minigame, string s)
 {
        int i;
        int end = 0;
-       for(i = 6; i >= 0; --i)
+       for(i = C4_NUM_CNT; i >= 0; --i)
        {
                if(c4_find_piece(minigame,minigame_tile_buildname(minigame_tile_letter(s), i - 1)).team)
                {
@@ -414,7 +424,7 @@ string c4_get_lowest_tile(entity minigame, string s)
 }
 
 // Required function, handle client events
-float minigame_event_c4(entity minigame, string event, ...)
+float c4_client_event(entity minigame, string event, ...)
 {
        switch(event)
        {
@@ -435,14 +445,14 @@ float minigame_event_c4(entity minigame, string event, ...)
                                                if ( ! c4_curr_pos )
                                                        c4_set_curr_pos(c4_get_lowest_tile(minigame, "a3"));
                                                else
-                                                       c4_set_curr_pos(c4_get_lowest_tile(minigame, minigame_relative_tile(c4_curr_pos,1,0,6,7)));
+                                                       c4_set_curr_pos(c4_get_lowest_tile(minigame, minigame_relative_tile(c4_curr_pos,1,0,C4_NUM_CNT,C4_LET_CNT)));
                                                return true;
                                        case K_LEFTARROW:
                                        case K_KP_LEFTARROW:
                                                if ( ! c4_curr_pos )
                                                        c4_set_curr_pos(c4_get_lowest_tile(minigame, "c3"));
                                                else
-                                                       c4_set_curr_pos(c4_get_lowest_tile(minigame, minigame_relative_tile(c4_curr_pos,-1,0,6,7)));
+                                                       c4_set_curr_pos(c4_get_lowest_tile(minigame, minigame_relative_tile(c4_curr_pos,-1,0,C4_NUM_CNT,C4_LET_CNT)));
                                                return true;
                                        /*case K_UPARROW:
                                        case K_KP_UPARROW:
@@ -483,7 +493,7 @@ float minigame_event_c4(entity minigame, string event, ...)
                        vector mouse_pos = minigame_hud_normalize(mousepos,c4_boardpos,c4_boardsize);
                        if ( minigame.minigame_flags == (C4_TURN_PLACE|minigame_self.team) )
                        {
-                               c4_set_curr_pos(c4_get_lowest_tile(minigame, minigame_tile_name(mouse_pos,6,7)));
+                               c4_set_curr_pos(c4_get_lowest_tile(minigame, minigame_tile_name(mouse_pos,C4_NUM_CNT,C4_LET_CNT)));
                        }
                        if ( ! c4_valid_tile(c4_curr_pos) )
                                c4_set_curr_pos("");
index 2228dbbecd313f1481599fb3431287993126cc09..4a7592d9454039d5a28485b8a82f815bbe1e31fc 100644 (file)
@@ -6,6 +6,9 @@
 #include "sv_monsters.qh"
 #endif
 
+#include "../animdecide.qh"
+vector animfixfps(entity e, vector a, vector b);
+
 #include "monster/zombie.qc"
 #include "monster/spider.qc"
 #include "monster/mage.qc"
index 48bce9e2efb77c70891ad5913f15d0a56398a512..46cff984723167603b4064ec8ea367519a2a5e37 100644 (file)
@@ -106,11 +106,13 @@ float M_Afrit_Attack(float attack_type)
 }
 
 void spawnfunc_monster_afrit() { Monster_Spawn(MON_AFRIT); }
+#endif // SVQC
 
-float M_Afrit(float req)
+bool M_Afrit(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        if(self.target_range < 0)
@@ -159,6 +161,7 @@ float M_Afrit(float req)
                        self.superweapons_finished = time + 20;
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -173,6 +176,7 @@ float M_Afrit(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_afrit_health);
@@ -196,10 +200,10 @@ float M_Afrit(float req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index a2cb40ac5e278ef5217f47530c526462fc129cd1..8aad493159259c34f9a7809d3a97850b3ddc5ac3 100644 (file)
@@ -73,11 +73,13 @@ bool M_Creeper_Attack(int attack_type)
 }
 
 void spawnfunc_monster_creeper() { Monster_Spawn(MON_CREEPER); }
+#endif // SVQC
 
-float M_Creeper(float req)
+bool M_Creeper(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        if(self.creeper_primed)
@@ -95,6 +97,7 @@ float M_Creeper(float req)
                        setanim(self, self.anim_die1, false, true, true);
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -105,6 +108,7 @@ float M_Creeper(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_creeper_health);
@@ -124,10 +128,10 @@ float M_Creeper(float req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index 105bfa4fb1f7a8c106ef91f4d7a7c3e5017d4604..1b3aad794816c2d6c1414843cd1ac6c6f44cae24 100644 (file)
@@ -79,11 +79,13 @@ float M_Demon_Attack(float attack_type)
 void spawnfunc_monster_demon() { Monster_Spawn(MON_DEMON); }
 void spawnfunc_monster_demon1() { spawnfunc_monster_demon(); }
 void spawnfunc_monster_animus() { spawnfunc_monster_demon(); }
+#endif // SVQC
 
-float M_Demon(float req)
+bool M_Demon(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        return true;
@@ -99,6 +101,7 @@ float M_Demon(float req)
                        setanim(self, self.anim_die1, false, true, true);
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -112,6 +115,7 @@ float M_Demon(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_demon_health);
@@ -128,10 +132,10 @@ float M_Demon(float req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index 3560f9366d884325faf1b3b0606fd5d37d769077..b431800fab2967a0cee31ab0c112dc2eed74ff63 100644 (file)
@@ -122,11 +122,13 @@ float M_Enforcer_Attack(float attack_type)
 }
 
 void spawnfunc_monster_enforcer() { Monster_Spawn(MON_ENFORCER); }
+#endif // SVQC
 
-float M_Enforcer(float req)
+bool M_Enforcer(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        return true;
@@ -150,6 +152,7 @@ float M_Enforcer(float req)
                        setanim(self, ((random() > 0.5) ? self.anim_die1 : self.anim_die2), false, true, true);
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -166,6 +169,7 @@ float M_Enforcer(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_enforcer_health);
@@ -185,10 +189,10 @@ float M_Enforcer(float req)
                        precache_sound(W_Sound("lasergun_fire"));
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index 8844534674c9e3f5c37c87345fd49634b130471d..7dd75f4b125bd7695c92463a766ce58534ad5f72 100644 (file)
@@ -2,7 +2,7 @@
 REGISTER_MONSTER(
 /* MON_##id   */ GOOMBA,
 /* functions  */ M_Goomba, M_Goomba_Attack,
-/* spawnflags */ MON_FLAG_MELEE,
+/* spawnflags */ MON_FLAG_MELEE | MON_FLAG_CRUSH,
 /* mins,maxs  */ '-18 -18 -20', '18 18 20',
 /* model      */ "goomba.md3",
 /* netname    */ "goomba",
@@ -54,11 +54,13 @@ bool M_Goomba_Attack(int attack_type)
 }
 
 void spawnfunc_monster_goomba() { Monster_Spawn(MON_GOOMBA); }
+#endif // SVQC
 
 bool M_Goomba(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        Monster_Move_2D(self.speed, autocvar_g_monster_goomba_allow_jumpoff);
@@ -89,10 +91,10 @@ bool M_Goomba(int req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index b1ec4e6af7acd86afcdf00fe4a5b59474b5015ba..a6f6608e357d134d0a9dec573655959c277ba6ba 100644 (file)
@@ -345,15 +345,17 @@ void spawnfunc_monster_mage() { Monster_Spawn(MON_MAGE); }
 // compatibility with old spawns
 void spawnfunc_monster_shalrath() { spawnfunc_monster_mage(); }
 #endif
+#endif // SVQC
 
-float M_Mage(float req)
+bool M_Mage(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        entity head;
-                       float need_help = false;
+                       bool need_help = false;
 
                        for(head = world; (head = findfloat(head, iscreature, true)); )
                        if(head != self)
@@ -389,6 +391,7 @@ float M_Mage(float req)
                        setanim(self, self.anim_die1, false, true, true);
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -401,6 +404,7 @@ float M_Mage(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_mage_health);
@@ -419,10 +423,10 @@ float M_Mage(float req)
                        precache_sound (W_Sound("tagexp1"));
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index cbcd985249567141bb0928be8332617283dd508c..d038e1070b62b37d7a7d7eab3c700bd1b4827bf0 100644 (file)
@@ -314,11 +314,13 @@ float M_Ogre_Attack(float attack_type)
 }
 
 void spawnfunc_monster_ogre() { Monster_Spawn(MON_OGRE); }
+#endif // SVQC
 
-float M_Ogre(float req)
+bool M_Ogre(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        return true;
@@ -343,6 +345,7 @@ float M_Ogre(float req)
                        setanim(self, ((random() > 0.5) ? self.anim_die1 : self.anim_die2), false, true, true);
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -363,6 +366,7 @@ float M_Ogre(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_ogre_health);
@@ -383,10 +387,10 @@ float M_Ogre(float req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index fc8d3022c85bdf735c9176935f4774e502e40fcd..61aea862fd8dd7f962ff9a26e8a890f624f427bc 100644 (file)
@@ -48,11 +48,13 @@ float M_Rotfish_Attack(float attack_type)
 
 void spawnfunc_monster_rotfish() { Monster_Spawn(MON_ROTFISH); }
 void spawnfunc_monster_fish() { spawnfunc_monster_rotfish(); }
+#endif // SVQC
 
-float M_Rotfish(float req)
+bool M_Rotfish(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        return true;
@@ -68,6 +70,7 @@ float M_Rotfish(float req)
                        setanim(self, self.anim_die1, false, true, true);
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -80,6 +83,7 @@ float M_Rotfish(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_rotfish_health);
@@ -97,10 +101,10 @@ float M_Rotfish(float req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index 4149357de0a34b73a2bd89b559c33244c0c4c3b9..b81cb5fc392c77580c8a8f347f85cf2be1284dc4 100644 (file)
@@ -50,11 +50,13 @@ float M_Rottweiler_Attack(float attack_type)
 }
 
 void spawnfunc_monster_rottweiler() { Monster_Spawn(MON_ROTTWEILER); }
+#endif // SVQC
 
-float M_Rottweiler(float req)
+bool M_Rottweiler(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        return true;
@@ -73,6 +75,7 @@ float M_Rottweiler(float req)
                        setanim(self, ((random() > 0.5) ? self.anim_die1 : self.anim_die2), false, true, true);
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -88,6 +91,7 @@ float M_Rottweiler(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_rottweiler_health);
@@ -104,10 +108,10 @@ float M_Rottweiler(float req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index cc6c6dde2764fc98e1b5891280930728f2d4c023..0247e1bc1e9e865193ef4032f99985c3608394b1 100644 (file)
@@ -110,11 +110,13 @@ void spawnfunc_monster_scrag() { Monster_Spawn(MON_SCRAG); }
 // compatibility with old spawns
 void spawnfunc_monster_wizard() { spawnfunc_monster_scrag(); }
 void spawnfunc_monster_wyvern() { spawnfunc_monster_scrag(); }
+#endif // SVQC
 
-float M_Scrag(float req)
+bool M_Scrag(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        return true;
@@ -133,6 +135,7 @@ float M_Scrag(float req)
                        self.velocity_z = 100 + 100 * random();
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -145,6 +148,7 @@ float M_Scrag(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_scrag_health);
@@ -161,10 +165,10 @@ float M_Scrag(float req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index 8557c705d75c3547848ce5d4d1f374d067f95fcf..fcff1722ed21a188f8448b0e006795a987d4f344 100644 (file)
@@ -209,11 +209,13 @@ float M_Shambler_Attack(float attack_type)
 }
 
 void spawnfunc_monster_shambler() { Monster_Spawn(MON_SHAMBLER); }
+#endif // SVQC
 
-float M_Shambler(float req)
+bool M_Shambler(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        return true;
@@ -229,6 +231,7 @@ float M_Shambler(float req)
                        setanim(self, self.anim_die1, false, true, true);
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -244,6 +247,7 @@ float M_Shambler(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_shambler_health);
@@ -266,10 +270,10 @@ float M_Shambler(float req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index 2ef2c2e0897fe4d6164c54ca5268a21c03e1a554..4f2cbc5990f4b2787df094f6439871007c5ddb62 100644 (file)
@@ -84,11 +84,13 @@ float M_Spawn_Attack(float attack_type)
 }
 
 void spawnfunc_monster_spawn() { Monster_Spawn(MON_SPAWN); }
+#endif // SVQC
 
-float M_Spawn(float req)
+bool M_Spawn(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        // prevent standard code from breaking everything
@@ -109,6 +111,7 @@ float M_Spawn(float req)
                        defer(0.05, M_Spawn_Attack_Explode); // simply defer to prevent recursion
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -120,6 +123,7 @@ float M_Spawn(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_spawn_health);
@@ -137,10 +141,10 @@ float M_Spawn(float req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index 3f8e5b62b3021fe4033534947cc3bd983d6f9cad..0c77ad81327e280712544daa5199edefaa2092b4 100644 (file)
@@ -122,11 +122,13 @@ float M_Spider_Attack(float attack_type)
 }
 
 void spawnfunc_monster_spider() { Monster_Spawn(MON_SPIDER); }
+#endif // SVQC
 
-float M_Spider(float req)
+bool M_Spider(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        return true;
@@ -141,6 +143,7 @@ float M_Spider(float req)
                        self.angles_x = 180;
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -152,6 +155,7 @@ float M_Spider(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_spider_health);
@@ -169,10 +173,10 @@ float M_Spider(float req)
                        precache_sound (W_Sound("electro_fire2"));
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index 0c6b478edf32bc5fccc417bd70d80a868a7adf70..11e74aef5434da95789dd1452c3c5ca0219f3759 100644 (file)
@@ -183,11 +183,13 @@ void spawnfunc_monster_vore() { Monster_Spawn(MON_VORE); }
 
 // compatibility with old spawns
 void spawnfunc_monster_shalrath() { spawnfunc_monster_vore(); }
+#endif // SVQC
 
-float M_Vore(float req)
+int M_Vore(bool req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        return true;
@@ -203,6 +205,7 @@ float M_Vore(float req)
                        setanim(self, self.anim_die1, false, true, true);
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -215,6 +218,7 @@ float M_Vore(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_vore_health);
@@ -234,10 +238,10 @@ float M_Vore(float req)
                        precache_sound (W_Sound("tagexp1"));
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index d931a5b2e07b59832d0432ce77f22c5ec6693e24..3e300b99991fd07b76d8ad56c0e57544404ef534 100644 (file)
@@ -104,11 +104,13 @@ void spawnfunc_monster_wyvern() { Monster_Spawn(MON_WYVERN); }
 // compatibility with old spawns
 void spawnfunc_monster_wizard() { spawnfunc_monster_wyvern(); }
 #endif // extra monsters include original wizard
+#endif // SVQC
 
-float M_Wyvern(float req)
+bool M_Wyvern(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        return true;
@@ -127,6 +129,7 @@ float M_Wyvern(float req)
                        self.velocity_z = 100 + 100 * random();
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -139,6 +142,7 @@ float M_Wyvern(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_wyvern_health);
@@ -155,10 +159,10 @@ float M_Wyvern(float req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index 966dc99a5df5e8be3e26dc0ab1cad4a3cec0b8f5..23a9d258ab571b92a6983cb97e4151570a62d9d1 100644 (file)
@@ -134,11 +134,13 @@ float M_Zombie_Attack(float attack_type)
 }
 
 void spawnfunc_monster_zombie() { Monster_Spawn(MON_ZOMBIE); }
+#endif // SVQC
 
-float M_Zombie(float req)
+bool M_Zombie(int req)
 {
        switch(req)
        {
+               #ifdef SVQC
                case MR_THINK:
                {
                        if(time >= self.spawn_time)
@@ -158,6 +160,7 @@ float M_Zombie(float req)
                        setanim(self, ((random() > 0.5) ? self.anim_die1 : self.anim_die2), false, true, true);
                        return true;
                }
+               #endif
                case MR_ANIM:
                {
                        vector none = '0 0 0';
@@ -178,6 +181,7 @@ float M_Zombie(float req)
 
                        return true;
                }
+               #ifdef SVQC
                case MR_SETUP:
                {
                        if(!self.health) self.health = (autocvar_g_monster_zombie_health);
@@ -204,10 +208,10 @@ float M_Zombie(float req)
                {
                        return true;
                }
+               #endif
        }
 
        return true;
 }
 
-#endif // SVQC
 #endif // REGISTER_MONSTER
index 33068648ec88ad9581bf894f1f511bf4d6147048..649020f982cd0aa89c910febbe8ea82e5274df97 100644 (file)
@@ -21,6 +21,7 @@ const int MON_FLAG_SUPERMONSTER = 256; // incredibly powerful monster
 const int MON_FLAG_RANGED = 512; // monster shoots projectiles
 const int MON_FLAG_MELEE = 1024;
 const int MON_FLAG_RIDE = 2048; // monster can be mounted
+const int MON_FLAG_CRUSH = 4096; // monster can be stomped
 
 // entity properties of monsterinfo
 .float monsterid; // MON_...
@@ -33,6 +34,18 @@ const int MON_FLAG_RIDE = 2048; // monster can be mounted
 .int spawnflags;
 .vector mins, maxs; // monster hitbox size
 
+// animations
+.vector anim_blockend;
+.vector anim_blockstart;
+.vector anim_melee1;
+.vector anim_melee2;
+.vector anim_melee3;
+.vector anim_pain3;
+.vector anim_pain4;
+.vector anim_pain5;
+.vector anim_walk;
+.vector anim_spawn;
+
 // other useful macros
 #define MON_ACTION(monstertype,mrequest) (get_monsterinfo(monstertype)).monster_func(mrequest)
 
@@ -63,12 +76,9 @@ int MON_LAST;
                register_monster(id,func,attackfunc,monsterflags,min_s,max_s,modelname,shortname,mname); \
        } \
        ACCUMULATE_FUNCTION(RegisterMonsters, RegisterMonsters_##id)
-#ifdef SVQC
+#ifndef MENUQC
 #define REGISTER_MONSTER(id,func,attackfunc,monsterflags,min_s,max_s,modelname,shortname,mname) \
        REGISTER_MONSTER_2(MON_##id,func,attackfunc,monsterflags,min_s,max_s,modelname,shortname,mname)
-#elif defined(CSQC)
-       #define REGISTER_MONSTER(id,func,attackfunc,monsterflags,min_s,max_s,modelname,shortname,mname) \
-       REGISTER_MONSTER_2(MON_##id,m_null,m_null,monsterflags,min_s,max_s,modelname,shortname,mname)
 #else
 #define REGISTER_MONSTER(id,func,attackfunc,monsterflags,min_s,max_s,modelname,shortname,mname) \
        REGISTER_MONSTER_2(MON_##id,m_null,m_null,monsterflags,min_s,max_s,modelname,shortname,mname)
index 7d21678b4b3d6e1c94d1012d97db86f8d822c3bb..f58c2634246d357415468720cb5279d33ecccf23 100644 (file)
@@ -65,11 +65,14 @@ void monster_dropitem()
 
 void monster_makevectors(entity e)
 {
-       vector v;
+       if(IS_MONSTER(self))
+       {
+               vector v;
 
-       v = e.origin + (e.mins + e.maxs) * 0.5;
-       self.v_angle = vectoangles(v - (self.origin + self.view_ofs));
-       self.v_angle_x = -self.v_angle_x;
+               v = e.origin + (e.mins + e.maxs) * 0.5;
+               self.v_angle = vectoangles(v - (self.origin + self.view_ofs));
+               self.v_angle_x = -self.v_angle_x;
+       }
 
        makevectors(self.v_angle);
 }
@@ -358,11 +361,11 @@ void Monster_Sound(.string samplefield, float sound_delay, float delaytoo, float
 
 float Monster_Attack_Melee(entity targ, float damg, vector anim, float er, float animtime, int deathtype, float dostop)
 {
-       if(dostop) { self.state = MONSTER_ATTACK_MELEE; }
+       if(dostop && IS_MONSTER(self)) { self.state = MONSTER_ATTACK_MELEE; }
 
-       setanim(self, anim, true, true, true);
+       setanim(self, anim, false, true, false);
 
-       if(self.animstate_endtime > time)
+       if(self.animstate_endtime > time && IS_MONSTER(self))
                self.attack_finished_single = self.anim_finished = self.animstate_endtime;
        else
                self.attack_finished_single = self.anim_finished = time + animtime;
@@ -379,7 +382,7 @@ float Monster_Attack_Melee(entity targ, float damg, vector anim, float er, float
 
 float Monster_Attack_Leap_Check(vector vel)
 {
-       if(self.state)
+       if(self.state && IS_MONSTER(self))
                return false; // already attacking
        if(!(self.flags & FL_ONGROUND))
                return false; // not on the ground
@@ -404,14 +407,15 @@ bool Monster_Attack_Leap(vector anm, void() touchfunc, vector vel, float animtim
        if(!Monster_Attack_Leap_Check(vel))
                return false;
 
-       setanim(self, anm, true, true, true);
+       setanim(self, anm, false, true, false);
 
-       if(self.animstate_endtime > time)
+       if(self.animstate_endtime > time && IS_MONSTER(self))
                self.attack_finished_single = self.anim_finished = self.animstate_endtime;
        else
                self.attack_finished_single = self.anim_finished = time + animtime;
 
-       self.state = MONSTER_ATTACK_RANGED;
+       if(IS_MONSTER(self))
+               self.state = MONSTER_ATTACK_RANGED;
        self.touch = touchfunc;
        self.origin_z += 1;
        self.velocity = vel;
index d5f04b765871c0d324a01579d90c1e3d803a58b4..d1d224363d314dc52e59199c3f794c7e34b60830 100644 (file)
@@ -29,17 +29,6 @@ int monsters_killed;
 .int oldskin;
 .string mdl_dead; // dead model for goombas
 
-.vector anim_blockend;
-.vector anim_blockstart;
-.vector anim_melee1;
-.vector anim_melee2;
-.vector anim_melee3;
-.vector anim_pain3;
-.vector anim_pain4;
-.vector anim_pain5;
-.vector anim_walk;
-.vector anim_spawn;
-
 #define MONSTER_SKILLMOD(mon) (0.5 + mon.monster_skill * ((1.2 - 0.3) / 10))
 
 // other properties
index afa682de90006f7082872e052f0844e9a8656e8c..0f3357c16a193a171633808678f729ceb11f8bd7 100644 (file)
@@ -929,6 +929,7 @@ bool autocvar_g_jump_grunt;
 bool autocvar_g_overkill_powerups_replace;
 bool autocvar_g_za;
 int autocvar_g_za_max_monsters;
+bool autocvar_g_za_infect;
 string autocvar_g_za_spawnmonster;
 float autocvar_g_za_spawn_delay;
 float autocvar_g_overkill_superguns_respawn_time;
index 4b1c8c4ff4a08037fd73b7ecce1c296c560fb9d5..41b8e179226383cfe65888ba7b083d76ea518510 100644 (file)
@@ -182,6 +182,7 @@ string CheckPlayerModel(string plyermodel) {
        if(substring(plyermodel,-4,4) != ".dpm")
        if(substring(plyermodel,-4,4) != ".iqm")
        if(substring(plyermodel,-4,4) != ".md3")
+       if(substring(plyermodel,-4,4) != ".mdl")
        if(substring(plyermodel,-4,4) != ".psk")
                return FallbackPlayerModel;
        // forbid the LOD models
@@ -488,13 +489,17 @@ void PlayerTouch (void)
        if(other == world)
                return;
 
-       if(!autocvar_g_player_crush && !IS_MONSTER(other))
+       bool and_monster = IS_MONSTER(other);
+       if(and_monster && !((get_monsterinfo(other.monsterid)).spawnflags & MON_FLAG_CRUSH))
+               and_monster = false;
+
+       if(!autocvar_g_player_crush && !and_monster)
                return;
 
        if(!IS_PLAYER(self))
                return;
 
-       if(!IS_PLAYER(other) && !IS_MONSTER(other))
+       if(!IS_PLAYER(other) && !and_monster)
                return;
 
        if(self.deadflag != DEAD_NO || other.deadflag != DEAD_NO)
index bd771b277d75853a1120d53ebca6ca79876662df..4f4c442e12a5e4afa7b5a77b57837ac38ed5f86f 100644 (file)
@@ -13,6 +13,125 @@ void za_SpawnMonster()
        e.nextthink = time + 0.1;
 }
 
+.vector za_viewofs;
+
+void za_SetEnemy(entity player)
+{
+       entity head;
+       entity closest_targ = world;
+       FOR_EACH_PLAYER(head) if(head != player)
+       if(vlen(head.origin - player.origin) < autocvar_g_monsters_target_range)
+       if(!closest_targ || vlen(closest_targ.origin - player.origin) > vlen(head.origin - player.origin))
+               closest_targ = head;
+
+       if(!closest_targ)
+       {
+               FOR_EACH_MONSTER(head)
+               if(vlen(head.origin - player.origin) < autocvar_g_monsters_target_range)
+               if(!closest_targ || vlen(closest_targ.origin - player.origin) > vlen(head.origin - player.origin))
+                       closest_targ = head;
+       }
+
+       if(closest_targ)
+               player.enemy = closest_targ;
+}
+
+MUTATOR_HOOKFUNCTION(za_FixPlayermodel)
+{
+       if(self.monsterid)
+               ret_string = (get_monsterinfo(self.monsterid)).model;
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(za_PlayerPhysics)
+{
+       if(!self.monsterid) { return false; }
+
+       entity mon = get_monsterinfo(self.monsterid);
+
+       self.weapons = '0 0 0';
+       self.switchweapon = 0;
+       self.stat_pl_min = mon.mins;
+       self.stat_pl_max = mon.maxs;
+       self.stat_pl_crouch_min = mon.mins;
+       self.stat_pl_crouch_max = mon.maxs;
+       self.stat_pl_crouch_view_ofs = self.za_viewofs;
+       self.stat_pl_view_ofs = self.za_viewofs;
+       self.stat_sv_jumpvelocity = 0;
+
+       self.stat_sv_maxspeed = self.speed2;
+       self.stat_sv_maxairspeed = self.speed2;
+       self.BUTTON_CROUCH = false;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(za_PlayerThink)
+{
+       if(!self.monsterid || time < self.attack_finished_single) { return false; }
+
+       MON_ACTION(self.monsterid, MR_THINK);
+
+       if(self.BUTTON_ATCK)
+       if(self.monster_attackfunc)
+       {
+               za_SetEnemy(self);
+               if(self.monster_attackfunc(MONSTER_ATTACK_MELEE))
+                       animdecide_setaction(self, ANIMACTION_MELEE, false);
+       }
+
+       if(self.BUTTON_ATCK2)
+       if(self.monster_attackfunc)
+       {
+               za_SetEnemy(self);
+               if(self.monster_attackfunc(MONSTER_ATTACK_RANGED))
+                       animdecide_setaction(self, ANIMACTION_SHOOT, false);
+       }
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(za_ItemTouch)
+{
+       if(other.monsterid)
+               return MUT_ITEMTOUCH_RETURN;
+
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(za_PlayerDies)
+{
+       if(!autocvar_g_za_infect) { return false; }
+
+       if(!IS_MONSTER(frag_attacker))
+       {
+               self.monsterid = 0;
+               return false;
+       }
+
+       entity mon = get_monsterinfo(frag_attacker.monsterid);
+
+       self.monsterid = frag_attacker.monsterid;
+       self.health = frag_attacker.max_health;
+       self.weapons = '0 0 0';
+       self.switchweapon = 0;
+       self.stat_pl_min = mon.mins;
+       self.stat_pl_max = mon.maxs;
+       self.stat_pl_crouch_min = mon.mins;
+       self.stat_pl_crouch_max = mon.maxs;
+       self.monster_attack = false;
+       self.speed = frag_attacker.speed;
+       self.speed2 = frag_attacker.speed2;
+       self.stopspeed = frag_attacker.stopspeed;
+       self.view_ofs = self.za_viewofs = frag_attacker.view_ofs;
+       self.attack_range = ((frag_attacker.attack_range) ? frag_attacker.attack_range : 150);
+       //self.attack_range = frag_attacker.attack_range;
+       self.monster_attackfunc = mon.monster_attackfunc;
+       setsize(self, frag_attacker.mins, frag_attacker.maxs);
+
+       return false;
+}
+
 MUTATOR_HOOKFUNCTION(za_StartFrame)
 {
        if(time < za_spawn_delay || autocvar_g_za_max_monsters <= 0 || !autocvar_g_za)
@@ -37,6 +156,11 @@ MUTATOR_HOOKFUNCTION(za_StartFrame)
 
 MUTATOR_DEFINITION(mutator_zombie_apocalypse)
 {
+       MUTATOR_HOOK(FixPlayermodel, za_FixPlayermodel, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerPhysics, za_PlayerPhysics, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerPreThink, za_PlayerThink, CBC_ORDER_ANY);
+       MUTATOR_HOOK(ItemTouch, za_ItemTouch, CBC_ORDER_ANY);
+       MUTATOR_HOOK(PlayerDies, za_PlayerDies, CBC_ORDER_ANY);
        MUTATOR_HOOK(SV_StartFrame, za_StartFrame, CBC_ORDER_ANY);
 
        MUTATOR_ONADD