1#pragma once
2
3//********************************************************************************************
4//*
5//*    This file is part of Egoboo.
6//*
7//*    Egoboo is free software: you can redistribute it and/or modify it
8//*    under the terms of the GNU General Public License as published by
9//*    the Free Software Foundation, either version 3 of the License, or
10//*    (at your option) any later version.
11//*
12//*    Egoboo is distributed in the hope that it will be useful, but
13//*    WITHOUT ANY WARRANTY; without even the implied warranty of
14//*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15//*    General Public License for more details.
16//*
17//*    You should have received a copy of the GNU General Public License
18//*    along with Egoboo.  If not, see <http://www.gnu.org/licenses/>.
19//*
20//********************************************************************************************
21
22#include "PrtList.h"
23
24#include "char.inl"
25
26//--------------------------------------------------------------------------------------------
27// FORWARD DECLARATION
28//--------------------------------------------------------------------------------------------
29
30static INLINE PIP_REF  prt_get_ipip( const PRT_REF particle );
31static INLINE pip_t  * prt_get_ppip( const PRT_REF particle );
32static INLINE CHR_REF  prt_get_iowner( const PRT_REF iprt, int depth );
33static INLINE bool_t   prt_set_size( prt_t *, int size );
34static INLINE float    prt_get_scale( prt_t * pprt );
35
36static INLINE prt_bundle_t * prt_bundle_ctor( prt_bundle_t * pbundle );
37static INLINE prt_bundle_t * prt_bundle_validate( prt_bundle_t * pbundle );
38static INLINE prt_bundle_t * prt_bundle_set( prt_bundle_t * pbundle, prt_t * pprt );
39
40static INLINE float * prt_get_pos_v( prt_t * pprt );
41static INLINE fvec3_t prt_get_pos( prt_t * pprt );
42
43//--------------------------------------------------------------------------------------------
44// IMPLEMENTATION
45//--------------------------------------------------------------------------------------------
46static INLINE PIP_REF prt_get_ipip( const PRT_REF iprt )
47{
48    prt_t * pprt;
49
50    if ( !DEFINED_PRT( iprt ) ) return ( PIP_REF )MAX_PIP;
51    pprt = PrtList.lst + iprt;
52
53    if ( !LOADED_PIP( pprt->pip_ref ) ) return ( PIP_REF )MAX_PIP;
54
55    return pprt->pip_ref;
56}
57
58//--------------------------------------------------------------------------------------------
59static INLINE pip_t * prt_get_ppip( const PRT_REF iprt )
60{
61    prt_t * pprt;
62
63    if ( !DEFINED_PRT( iprt ) ) return NULL;
64    pprt = PrtList.lst + iprt;
65
66    if ( !LOADED_PIP( pprt->pip_ref ) ) return NULL;
67
68    return PipStack.lst + pprt->pip_ref;
69}
70
71//--------------------------------------------------------------------------------------------
72static INLINE bool_t prt_set_size( prt_t * pprt, int size )
73{
74    pip_t *ppip;
75
76    if ( !DEFINED_PPRT( pprt ) ) return bfalse;
77
78    if ( !LOADED_PIP( pprt->pip_ref ) ) return bfalse;
79    ppip = PipStack.lst + pprt->pip_ref;
80
81    // set the graphical size
82    pprt->size = size;
83
84    // set the bumper size, if available
85    if ( 0 == pprt->bump_size_stt )
86    {
87        // make the particle non-interacting if the initial bumper size was 0
88        pprt->bump_real.size   = 0;
89        pprt->bump_padded.size = 0;
90    }
91    else
92    {
93        float real_size  =     FP8_TO_FLOAT( size ) * prt_get_scale( pprt );
94
95        if ( 0.0f == pprt->bump_real.size || 0.0f == size )
96        {
97            // just set the size, assuming a spherical particle
98            pprt->bump_real.size     = real_size;
99            pprt->bump_real.size_big = real_size * SQRT_TWO;
100            pprt->bump_real.height   = real_size;
101        }
102        else
103        {
104            float mag = real_size / pprt->bump_real.size;
105
106            // resize all dimensions equally
107            pprt->bump_real.size     *= mag;
108            pprt->bump_real.size_big *= mag;
109            pprt->bump_real.height   *= mag;
110        }
111
112        // make sure that the virtual bumper size is at least as big as what is in the pip file
113        pprt->bump_padded.size     = MAX( pprt->bump_real.size,     ppip->bump_size );
114        pprt->bump_padded.size_big = MAX( pprt->bump_real.size_big, ppip->bump_size * SQRT_TWO );
115        pprt->bump_padded.height   = MAX( pprt->bump_real.height,   ppip->bump_height );
116    }
117
118    // set the real size of the particle
119    oct_bb_set_bumper( &( pprt->prt_min_cv ), pprt->bump_real );
120
121    // use the padded bumper to figure out the chr_max_cv
122    oct_bb_set_bumper( &( pprt->prt_max_cv ), pprt->bump_padded );
123
124    return btrue;
125}
126
127//--------------------------------------------------------------------------------------------
128static INLINE CHR_REF prt_get_iowner( const PRT_REF iprt, int depth )
129{
130    /// BB@> A helper function for determining the owner of a paricle
131    ///
132    ///      @details There could be a possibility that a particle exists that was spawned by
133    ///      another particle, but has lost contact with its original spawner. For instance
134    ///      If an explosion particle bounces off of something with MISSILE_DEFLECT or
135    ///      MISSILE_REFLECT, which subsequently dies before the particle...
136    ///
137    ///      That is actually pretty far fetched, but at some point it might make sense to
138    ///      spawn particles just keeping track of the spawner (whether particle or character)
139    ///      and working backward to any potential owner using this function. ;)
140    ///
141    ///      @note this function should be completely trivial for anything other than
142    ///       namage particles created by an explosion
143
144    CHR_REF iowner = ( CHR_REF )MAX_CHR;
145
146    prt_t * pprt;
147
148    // be careful because this can be recursive
149    if ( depth > ( int )maxparticles - ( int )PrtList.free_count ) return ( CHR_REF )MAX_CHR;
150
151    if ( !DEFINED_PRT( iprt ) ) return ( CHR_REF )MAX_CHR;
152    pprt = PrtList.lst + iprt;
153
154    if ( DEFINED_CHR( pprt->owner_ref ) )
155    {
156        iowner = pprt->owner_ref;
157    }
158    else
159    {
160        // make a check for a stupid looping structure...
161        // cannot be sure you could never get a loop, though
162
163        if ( !ALLOCATED_PRT( pprt->parent_ref ) )
164        {
165            // make sure that a non valid parent_ref is marked as non-valid
166            pprt->parent_ref = MAX_PRT;
167            pprt->parent_guid = 0xFFFFFFFF;
168        }
169        else
170        {
171            // if a particle has been poofed, and another particle lives at that address,
172            // it is possible that the pprt->parent_ref points to a valid particle that is
173            // not the parent. Depending on how scrambled the list gets, there could actually
174            // be looping structures. I have actually seen this, so don't laugh :)
175
176            if ( PrtList.lst[pprt->parent_ref].obj_base.guid == pprt->parent_guid )
177            {
178                if ( iprt != pprt->parent_ref )
179                {
180                    iowner = prt_get_iowner( pprt->parent_ref, depth + 1 );
181                }
182            }
183            else
184            {
185                // the parent particle doesn't exist anymore
186                // fix the reference
187                pprt->parent_ref = MAX_PRT;
188                pprt->parent_guid = 0xFFFFFFFF;
189            }
190        }
191    }
192
193    return iowner;
194}
195
196//--------------------------------------------------------------------------------------------
197static INLINE float prt_get_scale( prt_t * pprt )
198{
199    /// @details BB@> get the scale factor between the "graphical size" of the particle and the actual
200    ///               display size
201
202    float scale = 0.25f;
203
204    if ( !DEFINED_PPRT( pprt ) ) return scale;
205
206    // set some particle dependent properties
207    switch ( pprt->type )
208    {
209        case SPRITE_SOLID: scale *= 0.9384f; break;
210        case SPRITE_ALPHA: scale *= 0.9353f; break;
211        case SPRITE_LIGHT: scale *= 1.5912f; break;
212    }
213
214    return scale;
215}
216
217//--------------------------------------------------------------------------------------------
218//--------------------------------------------------------------------------------------------
219static INLINE prt_bundle_t * prt_bundle_ctor( prt_bundle_t * pbundle )
220{
221    if ( NULL == pbundle ) return NULL;
222
223    pbundle->prt_ref = ( PRT_REF ) MAX_PRT;
224    pbundle->prt_ptr = NULL;
225
226    pbundle->pip_ref = ( PIP_REF ) MAX_PIP;
227    pbundle->pip_ptr = NULL;
228
229    return pbundle;
230}
231
232//--------------------------------------------------------------------------------------------
233static INLINE prt_bundle_t * prt_bundle_validate( prt_bundle_t * pbundle )
234{
235    if ( NULL == pbundle ) return NULL;
236
237    if ( ALLOCATED_PRT( pbundle->prt_ref ) )
238    {
239        pbundle->prt_ptr = PrtList.lst + pbundle->prt_ref;
240    }
241    else if ( NULL != pbundle->prt_ptr )
242    {
243        pbundle->prt_ref = GET_REF_PPRT( pbundle->prt_ptr );
244    }
245    else
246    {
247        pbundle->prt_ref = MAX_PRT;
248        pbundle->prt_ptr = NULL;
249    }
250
251    if ( !LOADED_PIP( pbundle->pip_ref ) && NULL != pbundle->prt_ptr )
252    {
253        pbundle->pip_ref = pbundle->prt_ptr->pip_ref;
254    }
255
256    if ( LOADED_PIP( pbundle->pip_ref ) )
257    {
258        pbundle->pip_ptr = PipStack.lst + pbundle->pip_ref;
259    }
260    else
261    {
262        pbundle->pip_ref = ( PIP_REF ) MAX_PIP;
263        pbundle->pip_ptr = NULL;
264    }
265
266    return pbundle;
267}
268
269//--------------------------------------------------------------------------------------------
270static INLINE prt_bundle_t * prt_bundle_set( prt_bundle_t * pbundle, prt_t * pprt )
271{
272    if ( NULL == pbundle ) return NULL;
273
274    // blank out old data
275    pbundle = prt_bundle_ctor( pbundle );
276
277    if ( NULL == pbundle || NULL == pprt ) return pbundle;
278
279    // set the particle pointer
280    pbundle->prt_ptr = pprt;
281
282    // validate the particle data
283    pbundle = prt_bundle_validate( pbundle );
284
285    return pbundle;
286}
287
288//--------------------------------------------------------------------------------------------
289fvec3_t prt_get_pos( prt_t * pprt )
290{
291    fvec3_t vtmp = ZERO_VECT3;
292
293    if ( !ALLOCATED_PPRT( pprt ) ) return vtmp;
294
295    return pprt->pos;
296}
297
298//--------------------------------------------------------------------------------------------
299float * prt_get_pos_v( prt_t * pprt )
300{
301    static fvec3_t vtmp = ZERO_VECT3;
302
303    if ( !ALLOCATED_PPRT( pprt ) ) return vtmp.v;
304
305    return pprt->pos.v;
306}
307
308//--------------------------------------------------------------------------------------------
309//--------------------------------------------------------------------------------------------
310
311#define _particle_inl