1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: p_fab.c 1511 2020-04-04 08:50:49Z wesleyjohnson $
5 //
6 // Copyright (C) 1998-2000 by DooM Legacy Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 //
19 // $Log: p_fab.c,v $
20 // Revision 1.5  2000/10/21 08:43:30  bpereira
21 // Revision 1.4  2000/07/01 09:23:49  bpereira
22 // Revision 1.3  2000/04/24 20:24:38  bpereira
23 // Revision 1.2  2000/02/27 00:42:10  hurdler
24 // Revision 1.1.1.1  2000/02/22 20:32:32  hurdler
25 // Initial import into CVS (v1.29 pr3)
26 //
27 //
28 // DESCRIPTION:
29 //      some new action routines, separated from the original doom
30 //      sources, so that you can include it or remove it easy.
31 //
32 //-----------------------------------------------------------------------------
33 
34 
35 #include "doomincl.h"
36 #include "g_game.h"
37 #include "p_local.h"
38 #include "r_state.h"
39 #include "p_fab.h"
40 #include "m_random.h"
41 #include "dehacked.h"
42   // flags_valid_deh
43 #include "info.h"
44   // MT_xxx
45 #include "r_data.h"
46   // TRANSLU_xxx
47 
48 
49 #ifdef DOORDELAY_CONTROL
50 // [WDJ] 1/15/2009 support control of door and event delay
51 // see p_doors.c
52 extern  int  adj_ticks_per_sec;
53 
54 CV_PossibleValue_t doordelay_cons_t[]={{0,"0.9x Fast"}, {1,"Normal"}, {2,"1.2x Slow"}, {3,"1.6x Slow"}, {4,"2x Slow"}, {5,"3x Slow"}, {0,NULL}};
55 int  doordelay_table[6] = { 32, 35, 42, 56, 70, 105 };  // 35 is normal
56 
DoorDelay_OnChange(void)57 void DoorDelay_OnChange( void )
58 {
59    adj_ticks_per_sec = doordelay_table[ cv_doordelay.value ];
60 }
61 
62 consvar_t cv_doordelay = {"doordelay","1",CV_NETVAR|CV_CALL|CV_SAVE,doordelay_cons_t,DoorDelay_OnChange};
63 
64 #endif
65 
66 
67 // [WDJ] 2/3/2011  Insta-death by voodoo doll, subverted.
68 CV_PossibleValue_t instadeath_cons_t[]={{0,"Die"}, {1,"Damage"}, {2,"Zap"}, {0,NULL}};
69 consvar_t cv_instadeath = {"instadeath", "0", CV_SAVE|CV_NETVAR, instadeath_cons_t, NULL};
70 
71 voodoo_mode_e  voodoo_mode;
72 
73 // [WDJ] 2/7/2011  Voodoo doll behavior
VoodooMode_OnChange(void)74 void VoodooMode_OnChange( void )
75 {
76    // config file saves cv_voodoo_mode but changes to voodoo_mode do not get saved.
77    voodoo_mode = (voodoo_mode_e) cv_voodoo_mode.EV;
78 }
79 
80 CV_PossibleValue_t voodoo_mode_cons_t[]={{0,"Vanilla"}, {1,"Multispawn"}, {2,"Target"}, {3, "Auto"}, {0,NULL}};
81 consvar_t cv_voodoo_mode = {"voodoo_mode", "3", CV_CALL|CV_SAVE|CV_NETVAR, voodoo_mode_cons_t, VoodooMode_OnChange};
82 
83 
84 // Translucency
85 
86 void Translucency_OnChange(void);
87 
88 // Auto exists mostly as the best conversion of previous Off/On.
89 CV_PossibleValue_t translucency_cons_t[]={{0,"Off"}, {1,"Auto"}, {2,"Boom"}, {3, "Legacy"}, {4, "All"}, {0,NULL}};
90 consvar_t cv_translucency  = {"translucency" ,"1",CV_CALL|CV_SAVE, translucency_cons_t, Translucency_OnChange};
91 
92 
93 //
94 // Action routine, for the ROCKET thing.
95 // This one adds trails of smoke to the rocket.
96 // The action pointer of the S_ROCKET state must point here to take effect.
97 // This routine is based on the Revenant Fireball Tracer code A_Tracer()
98 //
A_SmokeTrailer(mobj_t * actor)99 void A_SmokeTrailer (mobj_t* actor)
100 {
101     mobj_t*     th;
102 
103     if (gametic % (4 * NEWTICRATERATIO))
104         return;
105 
106     // spawn a puff of smoke behind the rocket
107     if( (EV_legacy < 125)  // rocket trails spawnpuff from v1.11 to v1.24
108         && (EV_legacy >= 111) ) // skull trails since v1.25
109         P_SpawnPuff (actor->x, actor->y, actor->z);
110 
111     // add the smoke behind the rocket
112     th = P_SpawnMobj (actor->x-actor->momx,
113                       actor->y-actor->momy,
114                       actor->z, MT_SMOK);
115 
116     th->momz = FRACUNIT;
117 
118     // Legacy use of P_Random, enabled by EV_legacy.
119     // Do not use extra P_Random during Doom and Boom demos.
120     // [WDJ] Legacy cannot interact with smoke, but the thought of some obscure
121     // interaction in the future makes me continue to use P_Random.
122     th->tics -= (EV_legacy ? PP_Random(pL_smoketrail) : N_Random() ) & 3;
123     if (th->tics < 1)
124         th->tics = 1;
125 }
126 
127 
128 // [WDJ] Table of translucent objects
129 enum { TRF_MT = 0xFFF, TRF_ext = 0x1000, TRF_noflag = 0x8000 };
130 
131 typedef struct {
132     uint16_t     flag_mt;  // MT type to check MF_TRANSLUCENT, + TRF_
133     uint16_t     first_state, last_state;  // statenum_t
134     byte         translu_sel;   // translucent_e, no Boom ext
135 } PACKED_ATTR  translucent_state_item_t;
136 // [WDJ] Table costs 500 more bytes than the inline calls when not packed !!
137 
138 static translucent_state_item_t  translucent_state_table[] =
139 {
140     //revenant fireball, MT_TRACER, extension effect
141     {MT_TRACER|TRF_ext, S_TRACER,    S_TRACER2,   TRANSLU_fire},
142     {MT_TRACER|TRF_ext, S_TRACEEXP1, S_TRACEEXP3, TRANSLU_med},
143 
144     //rev. fireball. smoke trail, MT_SMOKE
145     {MT_SMOKE, S_SMOKE1, S_SMOKE5, TRANSLU_med},
146 
147     //imp fireball, MT_TROOPSHOT
148     {MT_TROOPSHOT, S_TBALL1,  S_TBALL2,  TRANSLU_fire},
149     {MT_TROOPSHOT, S_TBALLX1, S_TBALLX3, TRANSLU_med},
150 
151     //archvile attack, MT_FIRE
152     {MT_FIRE, S_FIRE1, S_FIRE30, TRANSLU_fire},
153 
154     //bfg ball, MT_BFG
155     {MT_BFG, S_BFGSHOT,  S_BFGSHOT2, TRANSLU_fire},
156     {MT_BFG, S_BFGLAND,  S_BFGLAND3, TRANSLU_med},
157     {MT_BFG, S_BFGLAND4, S_BFGLAND6, TRANSLU_more},
158     {MT_BFG, S_BFGEXP,   0         , TRANSLU_med},
159     {MT_BFG, S_BFGEXP2,  S_BFGEXP4 , TRANSLU_more},
160 
161     //plasma bullet, MT_PLASMA
162     {MT_PLASMA, S_PLASBALL, S_PLASBALL2, TRANSLU_fire},
163     {MT_PLASMA, S_PLASEXP,  S_PLASEXP2,  TRANSLU_med},
164     {MT_PLASMA, S_PLASEXP3, S_PLASEXP5,  TRANSLU_more},
165 
166     //bullet puff, MT_PUFF
167     {MT_PUFF, S_PUFF1, S_PUFF4, TRANSLU_more},
168 
169     //teleport fog, MT_TFOG
170     {MT_TFOG, S_TFOG,  S_TFOG5,  TRANSLU_med},
171     {MT_TFOG, S_TFOG6, S_TFOG10, TRANSLU_more},
172 
173     //respawn item fog, MT_IFOG
174     {MT_IFOG, S_IFOG, S_IFOG5, TRANSLU_med},
175 
176     //soulsphere, MT_MISC12
177     {MT_MISC12, S_SOUL, S_SOUL6, TRANSLU_med},
178     //invulnerability, MT_INV
179     {MT_INV, S_PINV, S_PINV4, TRANSLU_med},
180     //blur artifact, MT_INS
181     {MT_INS, S_PINS, S_PINS4, TRANSLU_med},
182     //megasphere, MT_MEGA
183     {MT_MEGA, S_MEGA, S_MEGA4, TRANSLU_med},
184 
185     // MT_MISC42, no flags extension effect
186     {TRF_noflag, S_GREENTORCH, S_REDTORCH4, TRANSLU_fx1}, // blue torch
187     // MT_MISC45, no flags extension effect
188     {TRF_noflag, S_GTORCHSHRT, S_RTORCHSHRT4, TRANSLU_fx1}, // short blue torch
189 
190     // flaming barrel !!, MT_MISC77, no flags extension effect
191     {TRF_noflag, S_BBAR1, S_BBAR3, TRANSLU_fx1},
192 
193     //lost soul, MT_SKULL, extension effect
194     {MT_SKULL|TRF_ext, S_SKULL_STND, S_SKULL_DIE6, TRANSLU_fx1},
195     //baron shot, MT_BRUISERSHOT
196     {MT_BRUISERSHOT, S_BRBALL1,  S_BRBALL2,  TRANSLU_fire},
197     {MT_BRUISERSHOT, S_BRBALLX1, S_BRBALLX3, TRANSLU_med},
198     //demon spawnfire, MT_SPAWNFIRE
199     {MT_SPAWNFIRE, S_SPAWNFIRE1, S_SPAWNFIRE3, TRANSLU_fire},
200     {MT_SPAWNFIRE, S_SPAWNFIRE4, S_SPAWNFIRE8, TRANSLU_med},
201     //caco fireball, MT_HEADSHOT
202     {MT_HEADSHOT, S_RBALL1,  S_RBALL2,  TRANSLU_fire},
203     {MT_HEADSHOT, S_RBALLX1, S_RBALLX3, TRANSLU_med},
204 
205     //arachno shot, MT_ARACHPLAZ
206     {MT_ARACHPLAZ, S_ARACH_PLAZ, S_ARACH_PLAZ2, TRANSLU_fire},
207     {MT_ARACHPLAZ, S_ARACH_PLEX, S_ARACH_PLEX2, TRANSLU_med},
208     {MT_ARACHPLAZ, S_ARACH_PLEX3,S_ARACH_PLEX4, TRANSLU_more},
209     {MT_ARACHPLAZ, S_ARACH_PLEX5,            0, TRANSLU_hi},
210 
211     //blood puffs!, MT_BLOOD
212     //{TRF_noflag, S_BLOOD1   ,            0, TRANSLU_med},
213     //{TRF_noflag, S_BLOOD2   , S_BLOOD3    , TRANSLU_more},
214 
215     //eye in symbol, MT_MISC38, no flags extension effect
216     {TRF_noflag, S_EVILEYE, S_EVILEYE4, TRANSLU_med},
217 
218     //mancubus fireball, MT_FATSHOT
219     {MT_FATSHOT, S_FATSHOT1,  S_FATSHOT2,  TRANSLU_fire},
220     {MT_FATSHOT, S_FATSHOTX1, S_FATSHOTX3, TRANSLU_med},
221 
222     // rockets explosion, MT_ROCKET, no flags extension effect
223     {TRF_noflag, S_EXPLODE1, S_EXPLODE2, TRANSLU_fire},
224     {TRF_noflag, S_EXPLODE3,          0, TRANSLU_med},
225 
226     //Fab: lava/slime damage smoke test, MT_SMOK, no flags extension effect
227     {TRF_noflag, S_SMOK1,   S_SMOK5,   TRANSLU_med},
228     {TRF_noflag, S_SPLASH1, S_SPLASH3, TRANSLU_more},
229 
230     {TRF_noflag, S_NULL, S_NULL, TRANSLU_more}  // term
231 };
232 
233 typedef enum {
234    TE_off, TE_boom, TE_ext, TE_all
235 } translucent_enable_e;
236 
237 static translucent_enable_e  translucent_enable = TE_all;
238 
239 //  hack the translucency in the states for a set of standard doom sprites
240 //
P_SetTranslucencies(void)241 void P_SetTranslucencies (void)
242 {
243     translucent_state_item_t * tip;
244     state_t * laststate;
245     state_t * state;
246     boolean  tr_enable;
247 
248     for(tip=&translucent_state_table[0]; tip->first_state != S_NULL; tip++)
249     {
250         tr_enable = false;  // default
251         switch( translucent_enable )
252         {
253          case TE_off:  // reset translucent
254             break;
255          case TE_all:  // independent of info MF_TRANSLUCENT
256             tr_enable = true;
257             break;
258          case TE_boom: // ignore DoomLegacy extensions
259             if(tip->flag_mt & TRF_ext)  break;  // legacy extension
260             // continue to TE_ext to test flag
261          case TE_ext:  // all flag, including DoomLegacy extensions
262             if(tip->flag_mt == TRF_noflag)  // does not check MF_TRANSLUCENT
263             {
264                 tr_enable = true;
265             }
266             else
267             {
268                 // check info flag MF_TRANSLUCENT, maybe modified by BEX
269                 register int mobjindex = tip->flag_mt & TRF_MT;
270                 if( mobjindex < NUMMOBJTYPES
271                     &&  mobjinfo[mobjindex].flags & MF_TRANSLUCENT )
272                     tr_enable = true;
273             }
274             break;
275         }
276         // change the info state tables for the object
277         laststate = &states[tip->last_state];
278         for( state = &states[tip->first_state]; state <= laststate; state++ )
279         {
280             state->frame &= ~FF_TRANSMASK;  // clear previous translucent
281             if( tr_enable )
282                 state->frame |= (tip->translu_sel<<FF_TRANSSHIFT);
283         }
284     }
285 }
286 
287 // Auto -> TE_ext, extensions checked
288 byte translucency_en_table[] =
289 { TE_off, TE_ext, TE_boom, TE_ext, TE_all };
290 
Translucency_OnChange(void)291 void Translucency_OnChange(void)
292 {
293     // [WDJ] Translucent control
294     // TE_boom has fewer transparent items.
295     // TE_all (as before) unless DEH has set flags.
296     translucent_enable = translucency_en_table[ cv_translucency.value ];
297     if( cv_translucency.value != 1 )  // not auto
298     {
299         if( flags_valid_deh
300            && ((translucent_enable == TE_off) || (translucent_enable == TE_all) ) )
301             GenPrintf( EMSG_hud, "DEH set translucency overridden by controls.\n" );
302     }
303     P_SetTranslucencies();
304 }
305 
306 
307 
308 
309 // =======================================================================
310 //                    FUNKY DEATHMATCH COMMANDS
311 // =======================================================================
312 
313 void BloodTime_OnChange (void);
314 
315 CV_PossibleValue_t bloodtime_cons_t[]={{1,"MIN"},{3600,"MAX"},{0,NULL}};
316 // how much tics to last for the last (third) frame of blood (S_BLOODx)
317 consvar_t cv_bloodtime = {"bloodtime","20",CV_NETVAR|CV_VALUE|CV_CALL|CV_SAVE,bloodtime_cons_t,BloodTime_OnChange};
318 
319 // Called when var. 'bloodtime' is changed : set the blood states duration
320 //
BloodTime_OnChange(void)321 void BloodTime_OnChange (void)
322 {
323     // CV_VALUE
324     states[S_BLOOD1].tics = 8;
325     states[S_BLOOD2].tics = 8;
326     states[S_BLOOD3].tics = (cv_bloodtime.value*TICRATE) - 16;
327 
328     CONS_Printf ("blood lasts for %d seconds\n", cv_bloodtime.value);
329 }
330 
331 
332 // [WDJ] All misc init
D_Register_MiscCommands(void)333 void D_Register_MiscCommands (void)
334 {
335     // add commands for deathmatch rules and style (like more blood) :)
336     CV_RegisterVar (&cv_solidcorpse);                 //p_enemy
337 
338     CV_RegisterVar (&cv_bloodtime);
339 
340     // BP:not realy in deathmatch but is just here
341     CV_RegisterVar (&cv_translucency);
342 #ifdef DOORDELAY_CONTROL
343     // [WDJ] 1/15/2009 support control of door and event delay
344     // see p_doors.c
345     CV_RegisterVar (&cv_doordelay);
346 #endif
347     // [WDJ] 2/7/2011 Voodoo
348     CV_RegisterVar (&cv_instadeath);
349     CV_RegisterVar (&cv_voodoo_mode);
350     // for p_enemy
351     CV_RegisterVar (&cv_monbehavior);
352     CV_RegisterVar (&cv_monsterfriction);
353     CV_RegisterVar (&cv_monster_remember);
354     CV_RegisterVar (&cv_monstergravity);
355     CV_RegisterVar (&cv_doorstuck);
356     CV_RegisterVar (&cv_pickupflash);
357     CV_RegisterVar (&cv_weapon_recoil);
358     CV_RegisterVar (&cv_zerotags);
359     // MBF
360     CV_RegisterVar (&cv_mbf_falloff);
361     CV_RegisterVar (&cv_mbf_monster_avoid_hazard);
362     CV_RegisterVar (&cv_mbf_monster_backing);
363     CV_RegisterVar (&cv_mbf_dropoff);
364     CV_RegisterVar (&cv_mbf_pursuit);
365 #ifdef DOGS
366     CV_RegisterVar (&cv_mbf_dogs);
367     CV_RegisterVar (&cv_mbf_dog_jumping);
368 #endif
369     CV_RegisterVar (&cv_mbf_distfriend);
370     CV_RegisterVar (&cv_mbf_staylift);
371     CV_RegisterVar (&cv_mbf_help_friend);
372     CV_RegisterVar (&cv_mbf_monkeys);
373 }
374 
DemoAdapt_p_fab(void)375 void  DemoAdapt_p_fab(void)  // local enables of p_fab
376 {
377     if( ! demoplayback )
378     {
379         // restore player settings
380 #ifdef DOORDELAY_CONTROL
381         DoorDelay_OnChange();
382 #endif
383         // cv_instadeath not covered here
384         VoodooMode_OnChange();
385     }
386 }
387 
388 
389 // [WDJ] State ext storage.
390 state_ext_t *  state_ext = NULL;
391 static unsigned int  num_state_ext_alloc = 0;
392 static unsigned int  num_state_ext_used = 0;
393 
394 
P_state_ext(state_t * state)395 state_ext_t *  P_state_ext( state_t * state )
396 {
397     return  &state_ext[ state->state_ext_id ];
398 }
399 
400 #define STATE_EXT_INC  64
401 // Give it an state_ext.
P_create_state_ext(state_t * state)402 state_ext_t *  P_create_state_ext( state_t * state )
403 {
404     if( state->state_ext_id == 0 )
405     {
406         // does not already have one
407         if( num_state_ext_used >= num_state_ext_alloc )
408         {
409             // Grow the ext states
410             int reqnum = num_state_ext_alloc + STATE_EXT_INC;
411             state_ext_t * ns = (state_ext_t*)
412                  realloc( state_ext, reqnum * sizeof(state_ext_t) );
413             if( ns == NULL )
414             {
415                 I_SoftError( "Realloc of states failed\n" );
416                 return &state_ext[0];
417             }
418             state_ext = ns;
419             memset( &ns[num_state_ext_alloc], 0, STATE_EXT_INC * sizeof(state_ext_t));
420             num_state_ext_alloc = reqnum;
421         }
422         state->state_ext_id = num_state_ext_used++;
423     }
424 
425     return  &state_ext[ state->state_ext_id ];
426 }
427 
428 // Clear and init the state_ext.
P_clear_state_ext(void)429 void  P_clear_state_ext( void )
430 {
431     state_t * s;
432 
433     if( state_ext && (num_state_ext_alloc > 256) )
434     {
435         free( state_ext );
436         state_ext = NULL;
437     }
438 
439     if( state_ext == NULL )
440     {
441         num_state_ext_used = 1;  // 0 is always dummy
442         num_state_ext_alloc = 64;
443         state_ext = (state_ext_t*) malloc( num_state_ext_alloc * sizeof(state_ext_t) );
444         memset( state_ext, 0, num_state_ext_alloc * sizeof(state_ext_t));
445     }
446 
447     // Init all states to dummy.
448     for( s = states; s < &states[NUMSTATES]; s++ )
449        s->state_ext_id = 0;
450 }
451