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/// @file char.inl
23/// @note You will routinely include "char.inl" in all *.inl files or *.c/*.cpp files, instead of "char.h"
24
25#include "char.h"
26
27/// @note include "profile.inl" here.
28///  Do not include "char.inl" in "profile.inl", otherwise there is a bootstrapping problem.
29#include "profile.inl"
30#include "enchant.inl"
31#include "particle.inl"
32
33#include "egoboo_math.inl"
34
35//--------------------------------------------------------------------------------------------
36// FORWARD DECLARARIONS
37//--------------------------------------------------------------------------------------------
38// cap_t accessor functions
39static INLINE bool_t cap_is_type_idsz( const CAP_REF icap, IDSZ test_idsz );
40static INLINE bool_t cap_has_idsz( const CAP_REF icap, IDSZ idsz );
41
42//--------------------------------------------------------------------------------------------
43// team_t accessor functions
44static INLINE CHR_REF  team_get_ileader( const TEAM_REF iteam );
45static INLINE chr_t  * team_get_pleader( const TEAM_REF iteam );
46
47static INLINE bool_t team_hates_team( const TEAM_REF ipredator_team, const TEAM_REF iprey_team );
48
49//--------------------------------------------------------------------------------------------
50// chr_t accessor functions
51static INLINE PRO_REF  chr_get_ipro( const CHR_REF ichr );
52static INLINE CAP_REF  chr_get_icap( const CHR_REF ichr );
53static INLINE EVE_REF  chr_get_ieve( const CHR_REF ichr );
54static INLINE PIP_REF  chr_get_ipip( const CHR_REF ichr, int ipip );
55static INLINE TEAM_REF chr_get_iteam( const CHR_REF ichr );
56static INLINE TEAM_REF chr_get_iteam_base( const CHR_REF ichr );
57
58static INLINE pro_t * chr_get_ppro( const CHR_REF ichr );
59static INLINE cap_t * chr_get_pcap( const CHR_REF ichr );
60static INLINE eve_t * chr_get_peve( const CHR_REF ichr );
61static INLINE pip_t * chr_get_ppip( const CHR_REF ichr, int ipip );
62
63static INLINE Mix_Chunk      * chr_get_chunk_ptr( chr_t * pchr, int index );
64static INLINE Mix_Chunk      * chr_get_chunk( const CHR_REF ichr, int index );
65static INLINE team_t         * chr_get_pteam( const CHR_REF ichr );
66static INLINE team_t         * chr_get_pteam_base( const CHR_REF ichr );
67static INLINE ai_state_t     * chr_get_pai( const CHR_REF ichr );
68static INLINE chr_instance_t * chr_get_pinstance( const CHR_REF ichr );
69
70static INLINE IDSZ chr_get_idsz( const CHR_REF ichr, int type );
71
72static INLINE void chr_update_size( chr_t * pchr );
73static INLINE void chr_init_size( chr_t * pchr, cap_t * pcap );
74static INLINE void chr_set_size( chr_t * pchr, float size );
75static INLINE void chr_set_width( chr_t * pchr, float width );
76static INLINE void chr_set_shadow( chr_t * pchr, float width );
77static INLINE void chr_set_height( chr_t * pchr, float height );
78static INLINE void chr_set_fat( chr_t * pchr, float fat );
79
80static INLINE bool_t chr_has_idsz( const CHR_REF ichr, IDSZ idsz );
81static INLINE bool_t chr_is_type_idsz( const CHR_REF ichr, IDSZ idsz );
82static INLINE bool_t chr_has_vulnie( const CHR_REF item, const PRO_REF weapon_profile );
83
84static INLINE bool_t chr_getMatUp( chr_t *pchr, fvec3_base_t vec );
85static INLINE bool_t chr_getMatRight( chr_t *pchr, fvec3_base_t vec );
86static INLINE bool_t chr_getMatForward( chr_t *pchr, fvec3_base_t vec );
87static INLINE bool_t chr_getMatTranslate( chr_t *pchr, fvec3_base_t vec );
88
89static INLINE float   * chr_get_pos_v( chr_t * pchr );
90static INLINE fvec3_t   chr_get_pos( chr_t * pchr );
91
92//--------------------------------------------------------------------------------------------
93// IMPLEMENTATION
94//--------------------------------------------------------------------------------------------
95static INLINE bool_t cap_is_type_idsz( const CAP_REF icap, IDSZ test_idsz )
96{
97    /// @details BB@> check IDSZ_PARENT and IDSZ_TYPE to see if the test_idsz matches. If we are not
98    ///     picky (i.e. IDSZ_NONE == test_idsz), then it matches any valid item.
99
100    cap_t * pcap;
101
102    if ( !LOADED_CAP( icap ) ) return bfalse;
103    pcap = CapStack.lst + icap;
104
105    if ( IDSZ_NONE == test_idsz ) return btrue;
106    if ( test_idsz == pcap->idsz[IDSZ_TYPE  ] ) return btrue;
107    if ( test_idsz == pcap->idsz[IDSZ_PARENT] ) return btrue;
108
109    return bfalse;
110}
111
112//--------------------------------------------------------------------------------------------
113static INLINE bool_t cap_has_idsz( const CAP_REF icap, IDSZ idsz )
114{
115    /// @detalis BB@> does idsz match any of the stored values in pcap->idsz[]?
116    ///               Matches anything if not picky (idsz == IDSZ_NONE)
117
118    int     cnt;
119    cap_t * pcap;
120    bool_t  retval;
121
122    if ( !LOADED_CAP( icap ) ) return bfalse;
123    pcap = CapStack.lst + icap;
124
125    if ( IDSZ_NONE == idsz ) return btrue;
126
127    retval = bfalse;
128    for ( cnt = 0; cnt < IDSZ_COUNT; cnt++ )
129    {
130        if ( pcap->idsz[cnt] == idsz )
131        {
132            retval = btrue;
133            break;
134        }
135    }
136
137    return retval;
138}
139
140//--------------------------------------------------------------------------------------------
141//--------------------------------------------------------------------------------------------
142static INLINE CHR_REF team_get_ileader( const TEAM_REF iteam )
143{
144    CHR_REF ichr;
145
146    if ( iteam >= TEAM_MAX ) return ( CHR_REF )MAX_CHR;
147
148    ichr = TeamStack.lst[iteam].leader;
149    if ( !DEFINED_CHR( ichr ) ) return ( CHR_REF )MAX_CHR;
150
151    return ichr;
152}
153
154//--------------------------------------------------------------------------------------------
155static INLINE chr_t  * team_get_pleader( const TEAM_REF iteam )
156{
157    CHR_REF ichr;
158
159    if ( iteam >= TEAM_MAX ) return NULL;
160
161    ichr = TeamStack.lst[iteam].leader;
162    if ( !DEFINED_CHR( ichr ) ) return NULL;
163
164    return ChrList.lst + ichr;
165}
166
167//--------------------------------------------------------------------------------------------
168static INLINE bool_t team_hates_team( const TEAM_REF ipredator_team, const TEAM_REF iprey_team )
169{
170    /// @details BB@> a wrapper function for access to the hatesteam data
171
172    if ( ipredator_team >= TEAM_MAX || iprey_team >= TEAM_MAX ) return bfalse;
173
174    return TeamStack.lst[ipredator_team].hatesteam[ REF_TO_INT( iprey_team )];
175}
176
177//--------------------------------------------------------------------------------------------
178//--------------------------------------------------------------------------------------------
179static INLINE PRO_REF chr_get_ipro( const CHR_REF ichr )
180{
181    chr_t * pchr;
182
183    if ( !DEFINED_CHR( ichr ) ) return ( PRO_REF )MAX_PROFILE;
184    pchr = ChrList.lst + ichr;
185
186    if ( !LOADED_PRO( pchr->profile_ref ) ) return ( PRO_REF )MAX_PROFILE;
187
188    return pchr->profile_ref;
189}
190
191//--------------------------------------------------------------------------------------------
192static INLINE CAP_REF chr_get_icap( const CHR_REF ichr )
193{
194    chr_t * pchr;
195
196    if ( !DEFINED_CHR( ichr ) ) return ( CAP_REF )MAX_CAP;
197    pchr = ChrList.lst + ichr;
198
199    return pro_get_icap( pchr->profile_ref );
200}
201
202//--------------------------------------------------------------------------------------------
203static INLINE EVE_REF chr_get_ieve( const CHR_REF ichr )
204{
205    chr_t * pchr;
206
207    if ( !DEFINED_CHR( ichr ) ) return ( EVE_REF )MAX_EVE;
208    pchr = ChrList.lst + ichr;
209
210    return pro_get_ieve( pchr->profile_ref );
211}
212
213//--------------------------------------------------------------------------------------------
214static INLINE PIP_REF chr_get_ipip( const CHR_REF ichr, int ipip )
215{
216    chr_t * pchr;
217
218    if ( !DEFINED_CHR( ichr ) ) return ( PIP_REF )MAX_PIP;
219    pchr = ChrList.lst + ichr;
220
221    return pro_get_ipip( pchr->profile_ref, ipip );
222}
223
224//--------------------------------------------------------------------------------------------
225static INLINE TEAM_REF chr_get_iteam( const CHR_REF ichr )
226{
227    chr_t * pchr;
228    int iteam;
229
230    if ( !DEFINED_CHR( ichr ) ) return ( TEAM_REF )TEAM_DAMAGE;
231    pchr = ChrList.lst + ichr;
232
233    iteam = REF_TO_INT( pchr->team );
234    iteam = CLIP( iteam, 0, TEAM_MAX );
235
236    return ( TEAM_REF )iteam;
237}
238
239//--------------------------------------------------------------------------------------------
240static INLINE TEAM_REF chr_get_iteam_base( const CHR_REF ichr )
241{
242    chr_t * pchr;
243    int iteam;
244
245    if ( !DEFINED_CHR( ichr ) ) return ( TEAM_REF )TEAM_MAX;
246    pchr = ChrList.lst + ichr;
247
248    iteam = REF_TO_INT( pchr->baseteam );
249    iteam = CLIP( iteam, 0, TEAM_MAX );
250
251    return ( TEAM_REF )iteam;
252}
253
254//--------------------------------------------------------------------------------------------
255static INLINE pro_t * chr_get_ppro( const CHR_REF ichr )
256{
257    chr_t * pchr;
258
259    if ( !DEFINED_CHR( ichr ) ) return NULL;
260    pchr = ChrList.lst + ichr;
261
262    if ( !LOADED_PRO( pchr->profile_ref ) ) return NULL;
263
264    return ProList.lst + pchr->profile_ref;
265}
266
267//--------------------------------------------------------------------------------------------
268static INLINE cap_t * chr_get_pcap( const CHR_REF ichr )
269{
270    chr_t * pchr;
271
272    if ( !DEFINED_CHR( ichr ) ) return NULL;
273    pchr = ChrList.lst + ichr;
274
275    return pro_get_pcap( pchr->profile_ref );
276}
277
278//--------------------------------------------------------------------------------------------
279static INLINE eve_t * chr_get_peve( const CHR_REF ichr )
280{
281    chr_t * pchr;
282
283    if ( !DEFINED_CHR( ichr ) ) return NULL;
284    pchr = ChrList.lst + ichr;
285
286    return pro_get_peve( pchr->profile_ref );
287}
288
289//--------------------------------------------------------------------------------------------
290static INLINE pip_t * chr_get_ppip( const CHR_REF ichr, int ipip )
291{
292    chr_t * pchr;
293
294    if ( !DEFINED_CHR( ichr ) ) return NULL;
295    pchr = ChrList.lst + ichr;
296
297    return pro_get_ppip( pchr->profile_ref, ipip );
298}
299
300//--------------------------------------------------------------------------------------------
301static INLINE Mix_Chunk * chr_get_chunk( const CHR_REF ichr, int index )
302{
303    chr_t * pchr;
304
305    if ( !DEFINED_CHR( ichr ) ) return NULL;
306    pchr = ChrList.lst + ichr;
307
308    return pro_get_chunk( pchr->profile_ref, index );
309}
310
311//--------------------------------------------------------------------------------------------
312static INLINE Mix_Chunk * chr_get_chunk_ptr( chr_t * pchr, int index )
313{
314    if ( !DEFINED_PCHR( pchr ) ) return NULL;
315
316    return pro_get_chunk( pchr->profile_ref, index );
317}
318
319//--------------------------------------------------------------------------------------------
320static INLINE team_t * chr_get_pteam( const CHR_REF ichr )
321{
322    chr_t * pchr;
323
324    if ( !DEFINED_CHR( ichr ) ) return NULL;
325    pchr = ChrList.lst + ichr;
326
327    if ( pchr->team < 0 && pchr->team >= TEAM_MAX ) return NULL;
328
329    return TeamStack.lst + pchr->team;
330}
331
332//--------------------------------------------------------------------------------------------
333static INLINE team_t * chr_get_pteam_base( const CHR_REF ichr )
334{
335    chr_t * pchr;
336
337    if ( !DEFINED_CHR( ichr ) ) return NULL;
338    pchr = ChrList.lst + ichr;
339
340    if ( pchr->baseteam < 0 || pchr->baseteam >= TEAM_MAX ) return NULL;
341
342    return TeamStack.lst + pchr->baseteam;
343}
344
345//--------------------------------------------------------------------------------------------
346static INLINE ai_state_t * chr_get_pai( const CHR_REF ichr )
347{
348    chr_t * pchr;
349
350    if ( !DEFINED_CHR( ichr ) ) return NULL;
351    pchr = ChrList.lst + ichr;
352
353    return &( pchr->ai );
354}
355
356//--------------------------------------------------------------------------------------------
357static INLINE chr_instance_t * chr_get_pinstance( const CHR_REF ichr )
358{
359    chr_t * pchr;
360
361    if ( !DEFINED_CHR( ichr ) ) return NULL;
362    pchr = ChrList.lst + ichr;
363
364    return &( pchr->inst );
365}
366
367//--------------------------------------------------------------------------------------------
368static INLINE IDSZ chr_get_idsz( const CHR_REF ichr, int type )
369{
370    cap_t * pcap;
371
372    if ( type >= IDSZ_COUNT ) return IDSZ_NONE;
373
374    pcap = chr_get_pcap( ichr );
375    if ( NULL == pcap ) return IDSZ_NONE;
376
377    return pcap->idsz[type];
378}
379
380//--------------------------------------------------------------------------------------------
381static INLINE bool_t chr_has_idsz( const CHR_REF ichr, IDSZ idsz )
382{
383    /// @detalis BB@> a wrapper for cap_has_idsz
384
385    CAP_REF icap = chr_get_icap( ichr );
386
387    return cap_has_idsz( icap, idsz );
388}
389
390//--------------------------------------------------------------------------------------------
391static INLINE bool_t chr_is_type_idsz( const CHR_REF item, IDSZ test_idsz )
392{
393    /// @details BB@> check IDSZ_PARENT and IDSZ_TYPE to see if the test_idsz matches. If we are not
394    ///     picky (i.e. IDSZ_NONE == test_idsz), then it matches any valid item.
395
396    CAP_REF icap;
397
398    icap = chr_get_icap( item );
399
400    return cap_is_type_idsz( icap, test_idsz );
401}
402
403//--------------------------------------------------------------------------------------------
404static INLINE bool_t chr_has_vulnie( const CHR_REF item, const PRO_REF test_profile )
405{
406    /// @detalis BB@> is item vulnerable to the type in profile test_profile?
407
408    IDSZ vulnie;
409
410    if ( !INGAME_CHR( item ) ) return bfalse;
411    vulnie = chr_get_idsz( item, IDSZ_VULNERABILITY );
412
413    // not vulnerable if there is no specific weakness
414    if ( IDSZ_NONE == vulnie ) return bfalse;
415
416    // check vs. every IDSZ that could have something to do with attacking
417    if ( vulnie == pro_get_idsz( test_profile, IDSZ_TYPE ) ) return btrue;
418    if ( vulnie == pro_get_idsz( test_profile, IDSZ_PARENT ) ) return btrue;
419
420    return bfalse;
421}
422
423//--------------------------------------------------------------------------------------------
424static INLINE bool_t chr_getMatUp( chr_t *pchr, fvec3_base_t vup )
425{
426    /// @details BB@> MAKE SURE the value it calculated relative to a valid matrix
427
428    bool_t rv;
429
430    if ( !ALLOCATED_PCHR( pchr ) ) return bfalse;
431
432    if ( NULL == vup ) return bfalse;
433
434    if ( !chr_matrix_valid( pchr ) )
435    {
436        chr_update_matrix( pchr, btrue );
437    }
438
439    rv = bfalse;
440    if ( chr_matrix_valid( pchr ) )
441    {
442        rv = mat_getChrUp( pchr->inst.matrix.v, vup );
443    }
444
445    if ( !rv )
446    {
447        // assume default Up is +z
448        vup[kZ] = 1.0f;
449        vup[kX] = vup[kY] = 0.0f;
450    }
451
452    return btrue;
453}
454
455//--------------------------------------------------------------------------------------------
456static INLINE bool_t chr_getMatRight( chr_t *pchr, fvec3_base_t vright )
457{
458    /// @details BB@> MAKE SURE the value it calculated relative to a valid matrix
459
460    bool_t rv;
461
462    if ( !ALLOCATED_PCHR( pchr ) ) return bfalse;
463
464    if ( NULL == vright ) return bfalse;
465
466    if ( !chr_matrix_valid( pchr ) )
467    {
468        chr_update_matrix( pchr, btrue );
469    }
470
471    rv = bfalse;
472    if ( chr_matrix_valid( pchr ) )
473    {
474        rv = mat_getChrRight( pchr->inst.matrix.v, vright );
475    }
476
477    if ( !rv )
478    {
479        // assume default Right is +y
480        vright[kY] = 1.0f;
481        vright[kX] = vright[kZ] = 0.0f;
482    }
483
484    return btrue;
485}
486
487//--------------------------------------------------------------------------------------------
488static INLINE bool_t chr_getMatForward( chr_t *pchr, fvec3_base_t vfwd )
489{
490    /// @details BB@> MAKE SURE the value it calculated relative to a valid matrix
491
492    bool_t rv;
493
494    if ( !ALLOCATED_PCHR( pchr ) ) return bfalse;
495
496    if ( NULL == vfwd ) return bfalse;
497
498    if ( !chr_matrix_valid( pchr ) )
499    {
500        chr_update_matrix( pchr, btrue );
501    }
502
503    rv = bfalse;
504    if ( chr_matrix_valid( pchr ) )
505    {
506        rv = mat_getChrForward( pchr->inst.matrix.v, vfwd );
507    }
508
509    if ( !rv )
510    {
511        // assume default Forward is +x
512        vfwd[kX] = 1.0f;
513        vfwd[kY] = vfwd[kZ] = 0.0f;
514    }
515
516    return btrue;
517}
518
519//--------------------------------------------------------------------------------------------
520static INLINE bool_t chr_getMatTranslate( chr_t *pchr, fvec3_base_t vtrans )
521{
522    /// @details BB@> MAKE SURE the value it calculated relative to a valid matrix
523
524    bool_t rv;
525
526    if ( !ALLOCATED_PCHR( pchr ) ) return bfalse;
527
528    if ( NULL == vtrans ) return bfalse;
529
530    if ( !chr_matrix_valid( pchr ) )
531    {
532        chr_update_matrix( pchr, btrue );
533    }
534
535    rv = bfalse;
536    if ( chr_matrix_valid( pchr ) )
537    {
538        rv = mat_getTranslate( pchr->inst.matrix.v, vtrans );
539    }
540
541    if ( !rv )
542    {
543        fvec3_base_copy( vtrans, chr_get_pos_v( pchr ) );
544    }
545
546    return btrue;
547}
548
549//--------------------------------------------------------------------------------------------
550//--------------------------------------------------------------------------------------------
551static INLINE void chr_update_size( chr_t * pchr )
552{
553    /// @details BB@> Convert the base size values to the size values that are used in the game
554
555    if ( !ALLOCATED_PCHR( pchr ) ) return;
556
557    pchr->shadow_size   = pchr->shadow_size_save   * pchr->fat;
558    pchr->bump.size     = pchr->bump_save.size     * pchr->fat;
559    pchr->bump.size_big = pchr->bump_save.size_big * pchr->fat;
560    pchr->bump.height   = pchr->bump_save.height   * pchr->fat;
561
562    chr_update_collision_size( pchr, btrue );
563}
564
565//--------------------------------------------------------------------------------------------
566static INLINE void chr_init_size( chr_t * pchr, cap_t * pcap )
567{
568    /// @details BB@> initalize the character size info
569
570    if ( !ALLOCATED_PCHR( pchr ) ) return;
571
572    if ( NULL == pcap || !pcap->loaded ) return;
573
574    pchr->fat_stt           = pcap->size;
575    pchr->shadow_size_stt   = pcap->shadow_size;
576    pchr->bump_stt.size     = pcap->bump_size;
577    pchr->bump_stt.size_big = pcap->bump_sizebig;
578    pchr->bump_stt.height   = pcap->bump_height;
579
580    pchr->fat                = pchr->fat_stt;
581    pchr->shadow_size_save   = pchr->shadow_size_stt;
582    pchr->bump_save.size     = pchr->bump_stt.size;
583    pchr->bump_save.size_big = pchr->bump_stt.size_big;
584    pchr->bump_save.height   = pchr->bump_stt.height;
585
586    chr_update_size( pchr );
587}
588
589//--------------------------------------------------------------------------------------------
590static INLINE void chr_set_size( chr_t * pchr, float size )
591{
592    /// @details BB@> scale the entire character so that the size matches the given value
593
594    float ratio;
595
596    if ( !DEFINED_PCHR( pchr ) ) return;
597
598    ratio = size / pchr->bump.size;
599
600    pchr->shadow_size_save  *= ratio;
601    pchr->bump_save.size    *= ratio;
602    pchr->bump_save.size_big *= ratio;
603    pchr->bump_save.height  *= ratio;
604
605    chr_update_size( pchr );
606}
607
608//--------------------------------------------------------------------------------------------
609static INLINE void chr_set_width( chr_t * pchr, float width )
610{
611    /// @details BB@> update the base character "width". This also modifies the shadow size
612
613    float ratio;
614
615    if ( !DEFINED_PCHR( pchr ) ) return;
616
617    ratio = width / pchr->bump_stt.size;
618    ratio = ABS( ratio );
619
620    pchr->shadow_size_stt   *= ratio;
621    pchr->bump_stt.size     *= ratio;
622    pchr->bump_stt.size_big *= ratio;
623
624    chr_update_size( pchr );
625}
626
627//--------------------------------------------------------------------------------------------
628static INLINE void chr_set_shadow( chr_t * pchr, float width )
629{
630    /// @details BB@> update the base shadow size
631
632    if ( !DEFINED_PCHR( pchr ) ) return;
633
634    pchr->shadow_size_save = width;
635
636    chr_update_size( pchr );
637}
638
639//--------------------------------------------------------------------------------------------
640static INLINE void chr_set_fat( chr_t * pchr, float fat )
641{
642    /// @details BB@> update all the character size info by specifying the fat value
643
644    if ( !DEFINED_PCHR( pchr ) ) return;
645
646    pchr->fat = fat;
647
648    chr_update_size( pchr );
649}
650
651//--------------------------------------------------------------------------------------------
652static INLINE void chr_set_height( chr_t * pchr, float height )
653{
654    /// @details BB@> update the base character height
655
656    if ( !DEFINED_PCHR( pchr ) ) return;
657
658    if ( height < 0 ) height = 0;
659
660    pchr->bump_save.height = height;
661
662    chr_update_size( pchr );
663}
664
665//--------------------------------------------------------------------------------------------
666static INLINE float * chr_get_pos_v( chr_t * pchr )
667{
668    static fvec3_t vtmp = ZERO_VECT3;
669
670    if ( !ALLOCATED_PCHR( pchr ) ) return vtmp.v;
671
672    return pchr->pos.v;
673}
674
675//--------------------------------------------------------------------------------------------
676static INLINE fvec3_t chr_get_pos( chr_t * pchr )
677{
678    fvec3_t vtmp = ZERO_VECT3;
679
680    if ( !ALLOCATED_PCHR( pchr ) ) return vtmp;
681
682    return pchr->pos;
683}
684
685//--------------------------------------------------------------------------------------------
686//--------------------------------------------------------------------------------------------
687
688#define _char_inl