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