TickHook: Fix crash when TickHook isn't set.
[gemrb.git] / gemrb / core / CharAnimations.cpp
blob979094834ac0d02d8a6c5bab37e45b0292830984
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "CharAnimations.h"
23 #include "win32def.h"
25 #include "Game.h"
26 #include "GameData.h"
27 #include "ImageMgr.h"
28 #include "Interface.h"
29 #include "Map.h"
30 #include "Palette.h"
31 #include "Video.h"
33 static int AvatarsCount = 0;
34 static AvatarStruct *AvatarTable = NULL;
35 static const ieByte SixteenToNine[16]={0,1,2,3,4,5,6,7,8,7,6,5,4,3,2,1};
36 static const ieByte SixteenToFive[16]={0,0,1,1,2,2,3,3,4,4,3,3,2,2,1,1};
38 static const int zOrder_Mirror16[16][4] = {
39 { 0, 3, 2, 1 },
40 { 0, 3, 2, 1 },
41 { 0, 3, 1, 2 },
42 { 0, 3, 1, 2 },
43 { 1, 0, 3, 2 },
44 { 1, 0, 3, 2 },
45 { 1, 0, 3, 2 },
46 { 1, 0, 3, 2 },
47 { 1, 0, 3, 2 },
48 { 1, 0, 3, 2 },
49 { 1, 0, 3, 2 },
50 { 1, 0, 3, 2 },
51 { 1, 0, 3, 2 },
52 { 0, 3, 1, 2 },
53 { 0, 3, 1, 2 },
54 { 0, 3, 2, 1 }
57 static const int zOrder_8[8][4] = {
58 { 0, 3, 2, 1 },
59 { 0, 3, 1, 2 },
60 { 1, 0, 3, 2 },
61 { 1, 0, 3, 2 },
62 { 1, 0, 3, 2 },
63 { 2, 0, 3, 1 },
64 { 2, 0, 3, 1 },
65 { 2, 0, 3, 1 }
68 struct EquipResRefData {
69 char Suffix[9];
70 unsigned char Cycle;
74 void CharAnimations::ReleaseMemory()
76 if (AvatarTable) {
77 free(AvatarTable);
78 AvatarTable=NULL;
82 int CharAnimations::GetAvatarsCount()
84 return AvatarsCount;
87 AvatarStruct *CharAnimations::GetAvatarStruct(int RowNum)
89 return AvatarTable+RowNum;
92 unsigned int CharAnimations::GetAnimationID() const
94 if (AvatarsRowNum==~0u) return 0;
95 return AvatarTable[AvatarsRowNum].AnimID;
98 int CharAnimations::GetCircleSize() const
100 if (AvatarsRowNum==~0u) return -1;
101 return AvatarTable[AvatarsRowNum].CircleSize;
103 int CharAnimations::NoPalette() const
105 if (AvatarsRowNum==~0u) return -1;
106 return AvatarTable[AvatarsRowNum].PaletteType;
109 int CharAnimations::GetAnimType() const
111 if (AvatarsRowNum==~0u) return -1;
112 return AvatarTable[AvatarsRowNum].AnimationType;
115 int CharAnimations::GetSize() const
117 if (AvatarsRowNum==~0u) return 0;
118 return AvatarTable[AvatarsRowNum].Size;
121 int CharAnimations::GetBloodColor() const
123 if(AvatarsRowNum==~0u) return 0;
124 return AvatarTable[AvatarsRowNum].BloodColor;
127 static ieResRef EmptySound={0};
129 const ieResRef &CharAnimations::GetWalkSound() const
131 if(AvatarsRowNum==~0u) return EmptySound;
132 return AvatarTable[AvatarsRowNum].WalkSound;
135 int CharAnimations::GetWalkSoundCount() const
137 if(AvatarsRowNum==~0u) return 0;
138 return AvatarTable[AvatarsRowNum].WalkSoundCount;
141 int CharAnimations::GetActorPartCount() const
143 if (AvatarsRowNum==~0u) return -1;
144 switch (AvatarTable[AvatarsRowNum].AnimationType) {
145 case IE_ANI_NINE_FRAMES: //dragon animations
146 return 9;
147 case IE_ANI_FOUR_FRAMES: //wyvern animations
148 return 4;
149 case IE_ANI_PST_GHOST: //special pst anims
150 if (AvatarTable[AvatarsRowNum].Prefixes[1][0]=='*') {
151 return 1;
153 if (AvatarTable[AvatarsRowNum].Prefixes[2][0]=='*') {
154 return 2;
156 if (AvatarTable[AvatarsRowNum].Prefixes[3][0]=='*') {
157 return 3;
159 return 4;
160 default:
161 return 1;
165 int CharAnimations::GetTotalPartCount() const
167 if (AvatarsRowNum==~0u) return -1;
168 switch (AvatarTable[AvatarsRowNum].AnimationType) {
169 case IE_ANI_FOUR_FILES:
170 case IE_ANI_FOUR_FILES_2:
171 return GetActorPartCount() + 1; // only weapon
172 case IE_ANI_CODE_MIRROR:
173 return GetActorPartCount() + 3; // equipment
174 case IE_ANI_TWENTYTWO:
175 return GetActorPartCount() + 3; // equipment
176 default:
177 return GetActorPartCount();
181 void CharAnimations::SetArmourLevel(int ArmourLevel)
183 if (AvatarsRowNum==~0u) return;
184 //ignore ArmourLevel for the static pst anims (all sprites are displayed)
185 if (AvatarTable[AvatarsRowNum].AnimationType == IE_ANI_PST_GHOST) {
186 ArmourLevel = 0;
188 strncpy( ResRef, AvatarTable[AvatarsRowNum].Prefixes[ArmourLevel], 8 );
189 ResRef[8]=0;
190 DropAnims();
193 //RangedType could be weird, reducing its value to 0,1,2
194 void CharAnimations::SetRangedType(int rt)
196 if ((unsigned int) rt<2) {
197 RangedType=(ieByte) rt;
198 } else {
199 RangedType=2;
203 void CharAnimations::SetWeaponType(int wt)
205 if (wt != WeaponType) {
206 WeaponType = wt;
207 DropAnims();
211 void CharAnimations::SetHelmetRef(const char* ref)
213 HelmetRef[0] = ref[0];
214 HelmetRef[1] = ref[1];
216 // TODO: Only drop helmet anims?
217 // Note: this doesn't happen "often", so this isn't a performance
218 // bottleneck. (wjp)
219 DropAnims();
220 gamedata->FreePalette(palette[PAL_HELMET], 0);
221 gamedata->FreePalette(modifiedPalette[PAL_HELMET], 0);
224 void CharAnimations::SetWeaponRef(const char* ref)
226 WeaponRef[0] = ref[0];
227 WeaponRef[1] = ref[1];
229 // TODO: Only drop weapon anims?
230 DropAnims();
231 gamedata->FreePalette(palette[PAL_WEAPON], 0);
232 gamedata->FreePalette(modifiedPalette[PAL_WEAPON], 0);
235 void CharAnimations::SetOffhandRef(const char* ref)
237 OffhandRef[0] = ref[0];
238 OffhandRef[1] = ref[1];
240 // TODO: Only drop shield/offhand anims?
241 DropAnims();
242 gamedata->FreePalette(palette[PAL_OFFHAND], 0);
243 gamedata->FreePalette(modifiedPalette[PAL_OFFHAND], 0);
246 void CharAnimations::LockPalette(const ieDword *gradients)
248 if (lockPalette) return;
249 //cannot lock colors for PST animations
250 if (GetAnimType() >= IE_ANI_PST_ANIMATION_1)
252 return;
254 //force initialisation of animation
255 SetColors( gradients );
256 GetAnimation(0,0);
257 if (palette[PAL_MAIN]) {
258 lockPalette=true;
262 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
263 static const char *StancePrefix[]={"3","2","5","5","4","4","2","2","5","4","1","3","3","3","4","1","4","4","4"};
264 static const char *CyclePrefix[]= {"0","0","1","1","1","1","0","0","1","1","0","1","1","1","1","1","1","1","1"};
265 static const unsigned int CycleOffset[] = {0, 0, 0, 0, 0, 9, 0, 0, 0, 18, 0, 0, 9, 18, 0, 0, 0, 0, 0};
267 void CharAnimations::SetColors(const ieDword *arg)
269 Colors = arg;
270 SetupColors(PAL_MAIN);
271 SetupColors(PAL_WEAPON);
272 SetupColors(PAL_OFFHAND);
273 SetupColors(PAL_HELMET);
276 void CharAnimations::SetupColors(PaletteType type)
278 Palette* pal = palette[(int)type];
280 if (!pal) {
281 return;
284 if (!Colors) {
285 return;
288 if (GetAnimType() >= IE_ANI_PST_ANIMATION_1) {
289 // Only do main palette
290 if (type != PAL_MAIN) {
291 return;
293 // TODO: handle equipment colour glows
295 // Colors[6] is the COLORCOUNT stat in PST.
296 // It tells how many customisable color slots we have.
297 // The color slots start from the end of the palette and go
298 // backwards. There are 6 available slots with a size of 32 each.
299 // Actually, the slots seem to be written in the cre file
300 // but we ignore them, i'm not sure this is correct
301 int colorcount = Colors[6];
302 int size = 32;
303 //the color count shouldn't be more than 6!
304 if (colorcount>6) colorcount=6;
305 int dest = 256-colorcount*size;
306 bool needmod = false;
307 if (GlobalColorMod.type != RGBModifier::NONE) {
308 needmod = true;
310 if ((colorcount == 0) && (needmod==false) ) {
311 gamedata->FreePalette(palette[PAL_MAIN], PaletteResRef);
312 PaletteResRef[0]=0;
313 return;
315 for (int i = 0; i < colorcount; i++) {
316 core->GetPalette( Colors[i]&255, size,
317 &palette[PAL_MAIN]->col[dest] );
318 dest +=size;
321 if (needmod) {
322 if (!modifiedPalette[PAL_MAIN])
323 modifiedPalette[PAL_MAIN] = new Palette();
324 modifiedPalette[PAL_MAIN]->SetupGlobalRGBModification(palette[PAL_MAIN], GlobalColorMod);
325 } else {
326 gamedata->FreePalette(modifiedPalette[PAL_MAIN], 0);
328 return;
331 int PType = NoPalette();
332 if ( PType && (type == PAL_MAIN) ) {
333 bool needmod = false;
334 if (GlobalColorMod.type != RGBModifier::NONE) {
335 needmod = true;
337 if (!needmod && PaletteResRef[0]) {
338 gamedata->FreePalette(palette[PAL_MAIN], PaletteResRef);
340 PaletteResRef[0]=0;
341 //handling special palettes like MBER_BL (black bear)
342 if (PType!=1) {
343 if (GetAnimType()==IE_ANI_NINE_FRAMES) {
344 snprintf(PaletteResRef,9,"%.4s_%-.2s%s",ResRef, (char *) &PType, StancePrefix[StanceID]);
345 } else {
346 snprintf(PaletteResRef,9,"%.4s_%-.2s",ResRef, (char *) &PType);
348 strlwr(PaletteResRef);
349 Palette *tmppal = gamedata->GetPalette(PaletteResRef);
350 if (tmppal) {
351 palette[PAL_MAIN] = tmppal;
352 } else {
353 PaletteResRef[0]=0;
356 if (needmod) {
357 if (!modifiedPalette[PAL_MAIN])
358 modifiedPalette[PAL_MAIN] = new Palette();
359 modifiedPalette[PAL_MAIN]->SetupGlobalRGBModification(palette[PAL_MAIN], GlobalColorMod);
360 } else {
361 gamedata->FreePalette(modifiedPalette[PAL_MAIN], 0);
363 return;
366 pal->SetupPaperdollColours(Colors, (int)type);
367 if (lockPalette) {
368 return;
371 int i;
372 bool needmod = false;
373 if (GlobalColorMod.type != RGBModifier::NONE) {
374 needmod = true;
375 } else {
376 for (i = 0; i < 7; ++i) {
377 if (ColorMods[i+8*((int)type)].type != RGBModifier::NONE)
378 needmod = true;
383 if (needmod) {
384 if (!modifiedPalette[(int)type])
385 modifiedPalette[(int)type] = new Palette();
387 if (GlobalColorMod.type != RGBModifier::NONE) {
388 modifiedPalette[(int)type]->SetupGlobalRGBModification(palette[(int)type], GlobalColorMod);
389 } else {
390 modifiedPalette[(int)type]->SetupRGBModification(palette[(int)type],ColorMods, (int)type);
392 } else {
393 gamedata->FreePalette(modifiedPalette[(int)type], 0);
398 Palette* CharAnimations::GetPartPalette(int part)
400 int actorPartCount = GetActorPartCount();
401 PaletteType type = PAL_MAIN;
403 if (part == actorPartCount) type = PAL_WEAPON;
404 if (part == actorPartCount+1) type = PAL_OFFHAND;
405 if (part == actorPartCount+2) type = PAL_HELMET;
407 if (modifiedPalette[(int)type])
408 return modifiedPalette[(int)type];
410 return palette[(int)type];
413 static int compare_avatars(const void *a, const void *b)
415 unsigned int aa = ((AvatarStruct *)a)->AnimID;
416 unsigned int bb = ((AvatarStruct *)b)->AnimID;
417 return (int) (aa-bb);
420 void CharAnimations::InitAvatarsTable()
422 AutoTable Avatars("avatars");
423 if (!Avatars) {
424 printMessage("CharAnimations", "A critical animation file is missing!\n", LIGHT_RED);
425 abort();
427 AvatarTable = (AvatarStruct *) calloc ( AvatarsCount = Avatars->GetRowCount(), sizeof(AvatarStruct) );
428 int i=AvatarsCount;
429 DataFileMgr *resdata = core->GetResDataINI();
430 while(i--) {
431 AvatarTable[i].AnimID=(unsigned int) strtol(Avatars->GetRowName(i),NULL,0 );
432 strnlwrcpy(AvatarTable[i].Prefixes[0],Avatars->QueryField(i,AV_PREFIX1),8);
433 strnlwrcpy(AvatarTable[i].Prefixes[1],Avatars->QueryField(i,AV_PREFIX2),8);
434 strnlwrcpy(AvatarTable[i].Prefixes[2],Avatars->QueryField(i,AV_PREFIX3),8);
435 strnlwrcpy(AvatarTable[i].Prefixes[3],Avatars->QueryField(i,AV_PREFIX4),8);
436 AvatarTable[i].AnimationType=(ieByte) atoi(Avatars->QueryField(i,AV_ANIMTYPE) );
437 AvatarTable[i].CircleSize=(ieByte) atoi(Avatars->QueryField(i,AV_CIRCLESIZE) );
438 const char *tmp = Avatars->QueryField(i,AV_USE_PALETTE);
439 //QueryField will always return a zero terminated string
440 //so tmp[0] must exist
441 if ( isalpha (tmp[0]) ) {
442 //this is a hack, we store 2 letters on an integer
443 //it was allocated with calloc, so don't bother erasing it
444 strncpy( (char *) &AvatarTable[i].PaletteType, tmp, 3);
446 else {
447 AvatarTable[i].PaletteType=atoi(Avatars->QueryField(i,AV_USE_PALETTE) );
449 char size = Avatars->QueryField(i,AV_SIZE)[0];
450 if (size == '*') {
451 size = 0;
453 AvatarTable[i].Size = size;
455 AvatarTable[i].WalkScale = 0;
456 AvatarTable[i].RunScale = 0;
457 AvatarTable[i].Bestiary = -1;
459 if (resdata) {
460 char section[12];
461 snprintf(section,10,"%d", i);
463 if (!resdata->GetKeysCount(section)) continue;
465 float walkscale = resdata->GetKeyAsFloat(section, "walkscale", 0.0f);
466 if (walkscale != 0.0f) AvatarTable[i].WalkScale = (int)(1000.0f / walkscale);
467 float runscale = resdata->GetKeyAsFloat(section, "runscale", 0.0f);
468 if (runscale != 0.0f) AvatarTable[i].RunScale = (int)(1000.0f / runscale);
469 AvatarTable[i].Bestiary = resdata->GetKeyAsInt(section, "bestiary", -1);
472 qsort(AvatarTable, AvatarsCount, sizeof(AvatarStruct), compare_avatars);
475 AutoTable blood("bloodclr");
476 if (blood) {
477 int rows = blood->GetRowCount();
478 for(int i=0;i<rows;i++) {
479 unsigned long value = 0;
480 unsigned long rmin = 0;
481 unsigned long rmax = 0xffff;
483 valid_number(blood->QueryField(i,0), (long &)value);
484 valid_number(blood->QueryField(i,1), (long &)rmin);
485 valid_number(blood->QueryField(i,2), (long &)rmax);
486 if (value>255 || rmin>0xffff || rmax>0xffff) {
487 printMessage("CharAnimations", "bloodclr entry:", LIGHT_RED);
488 printf("%02x %04x-%04x ", (unsigned int) value, (unsigned int) rmin, (unsigned int) rmax);
489 printStatus("Invalid value!", LIGHT_RED);
490 continue;
492 for(int j=0;j<AvatarsCount;j++) {
493 if (rmax<AvatarTable[j].AnimID) break;
494 if (rmin>AvatarTable[j].AnimID) continue;
495 AvatarTable[j].BloodColor = value;
500 AutoTable walk("walksnd");
501 if (walk) {
502 int rows = walk->GetRowCount();
503 for(int i=0;i<rows;i++) {
504 ieResRef value;
505 unsigned long rmin = 0;
506 unsigned long rmax = 0xffff;
507 unsigned int range = 0;
509 strnuprcpy(value, walk->QueryField(i,0), 8);
510 valid_number(walk->QueryField(i,1), (long &)rmin);
511 valid_number(walk->QueryField(i,2), (long &)rmax);
512 valid_number(walk->QueryField(i,3), (long &)range);
513 if (value[0]=='*') {
514 value[0]=0;
515 range = 0;
517 for(int j=0;j<AvatarsCount;j++) {
518 if (rmax<AvatarTable[j].AnimID) break;
519 if (rmin>AvatarTable[j].AnimID) continue;
520 memcpy(AvatarTable[j].WalkSound, value, sizeof(ieResRef) );
521 AvatarTable[j].WalkSoundCount = range;
527 CharAnimations::CharAnimations(unsigned int AnimID, ieDword ArmourLevel)
529 Colors = NULL;
530 int i,j;
531 for (i = 0; i < 4; ++i) {
532 modifiedPalette[i] = NULL;
533 palette[i] = NULL;
535 nextStanceID = 0;
536 StanceID = 0;
537 autoSwitchOnEnd = false;
538 lockPalette = false;
539 if (!AvatarsCount) {
540 InitAvatarsTable();
543 for (i = 0; i < MAX_ANIMS; i++) {
544 for (j = 0; j < MAX_ORIENT; j++) {
545 Anims[i][j] = NULL;
548 ArmorType = 0;
549 RangedType = 0;
550 WeaponType = 0;
551 PaletteResRef[0] = 0;
552 WeaponRef[0] = 0;
553 HelmetRef[0] = 0;
554 OffhandRef[0] = 0;
555 for (i = 0; i < 32; ++i) {
556 ColorMods[i].type = RGBModifier::NONE;
557 ColorMods[i].speed = 0;
558 // make initial phase depend on location to make the pulse appear
559 // less even
560 ColorMods[i].phase = 5*i;
562 GlobalColorMod.type = RGBModifier::NONE;
563 GlobalColorMod.speed = 0;
564 GlobalColorMod.phase = 0;
565 lastModUpdate = 0;
567 AvatarsRowNum=AvatarsCount;
568 if (core->HasFeature(GF_ONE_BYTE_ANIMID) ) {
569 ieDword tmp = AnimID&0xf000;
570 if (tmp==0x6000 || tmp==0xe000) {
571 AnimID&=0xff;
575 while (AvatarsRowNum--) {
576 if (AvatarTable[AvatarsRowNum].AnimID<=AnimID) {
577 SetArmourLevel( ArmourLevel );
578 return;
581 ResRef[0]=0;
582 printMessage("CharAnimations", " ", LIGHT_RED);
583 printf("Invalid or nonexistent avatar entry:%04X\n", AnimID);
586 //we have to drop them when armourlevel changes
587 void CharAnimations::DropAnims()
589 Animation** tmppoi;
590 int partCount = GetTotalPartCount();
591 for (int StanceID = 0; StanceID < MAX_ANIMS; StanceID++) {
592 for (int i = 0; i < MAX_ORIENT; i++) {
593 if (Anims[StanceID][i]) {
594 tmppoi = Anims[StanceID][i];
595 for (int j = 0; j < partCount; j++)
596 delete Anims[StanceID][i][j];
597 delete[] tmppoi;
599 // anims can only be duplicated at the Animation** level
600 for (int IDb=StanceID;IDb < MAX_ANIMS; IDb++) {
601 for (int i2 = 0; i2<MAX_ORIENT; i2++) {
602 if (Anims[IDb][i2] == tmppoi) {
603 Anims[IDb][i2] = 0;
612 CharAnimations::~CharAnimations(void)
614 DropAnims();
615 gamedata->FreePalette(palette[PAL_MAIN], PaletteResRef);
616 int i;
617 for (i = 1; i < 4; ++i)
618 gamedata->FreePalette(palette[i], 0);
619 for (i = 0; i < 4; ++i)
620 gamedata->FreePalette(modifiedPalette[i], 0);
623 This is a simple Idea of how the animation are coded
625 There are the following animation types:
627 IE_ANI_CODE_MIRROR: The code automatically mirrors the needed frames
628 (as in the example above)
630 These Animations are stores using the following template:
631 [NAME][ARMORTYPE][ACTIONCODE]
633 Each BAM File contains only 9 Orientations, the missing 7 Animations
634 are created by Horizontally Mirroring the 1-7 Orientations.
636 IE_ANI_CODE_MIRROR_2: another mirroring type with more animations
637 [NAME]g[1,11-15,2,21-26]
639 IE_ANI_CODE_MIRROR_3: Almost identical to IE_ANI_CODE_MIRROR_2, but with fewer cycles in g26
641 IE_ANI_ONE_FILE: The whole animation is in one file, no mirroring needed.
642 Each animation group is 16 Cycles.
644 IE_ANI_TWO_FILES: The whole animation is in 2 files. The East and West part are in 2 BAM Files.
645 Example:
646 ACHKg1
647 ACHKg1E
649 Each BAM File contains many animation groups, each animation group
650 stores 5 Orientations, the missing 3 are stored in East BAM Files.
653 IE_ANI_FOUR_FILES: The Animation is coded in Four Files. Probably it is an old Two File animation with
654 additional frames added in a second time.
656 IE_ANI_FOUR_FILES_2: Like IE_ANI_FOUR_FILES but with only 16 cycles per frame.
658 IE_ANI_TWENTYTWO: This Animation Type stores the Animation in the following format
659 [NAME][ACTIONCODE][/E]
660 ACTIONCODE=A1-6, CA, SX, SA (sling is A1)
661 The g1 file contains several animation states. See MHR
662 Probably it could use A7-9 files too, bringing the file numbers to 28.
663 This is the original bg1 format.
665 IE_ANI_SIX_FILES: The layout for these files is:
666 [NAME][g1-3][/E]
667 Each state contains 16 Orientations, but the last 6 are stored in the East file.
668 g1 contains only the walking animation.
669 G2 contains stand, ready, get hit, die and twitch.
670 g3 contains 3 attacks.
672 IE_ANI_SIX_FILES_2: Similar to SIX_FILES, but the orientation numbers are reduced like in FOUR_FILES. Only one animation uses it: MOGR
674 IE_ANI_TWO_FILES_2: Animations using this type are stored using the following template:
675 [NAME]g1[/E]
676 Each state contains 8 Orientations, but the second 4 are stored in the East file.
677 From the standard animations, only AHRS and ACOW belong to this type.
679 IE_ANI_TWO_FILES_3: Animations using this type are stored using the following template:
680 [NAME][ACTIONTYPE][/E]
682 Example:
683 MBFI*
684 MBFI*E
686 Each BAM File contains one animation group, each animation group
687 stores 5 Orientations though the files contain all 8 Cycles, the missing 3 are stored in East BAM Files in Cycle: Stance*8+ (5,6,7).
688 This is the standard IWD animation, but BG2 also has it.
689 See MMR
691 IE_ANI_TWO_FILES_3B: Animations using this type are stored using the following template:
692 [NAME][ACTIONTYPE][/E]
694 Example:
695 MBFI*
696 MBFI*E
698 This is a cut down version of IE_ANI_TWO_FILES_3. A2, CA and SP suffixes are missing.
699 This is the standard IWD animation, but BG2 also has it.
700 See MOR2
702 IE_ANI_FOUR_FRAMES: These animations are large, four bams make a frame.
705 IE_ANI_NINE_FRAMES: These animations are huge, nine bams make a frame.
708 IE_ANI_FRAGMENT: These animations are used for projectile graphics.
709 A single file contains 5 cycles (code mirror for east animation)
711 IE_ANI_PST_ANIMATION_1:
712 IE_ANI_PST_ANIMATION_2:
713 IE_ANI_PST_ANIMATION_3:
714 Planescape: Torment Animations are stored in a different
715 way than the other games. This format uses the following template:
716 [C/D][ACTIONTYPE][NAME][B]
718 Example:
719 CAT1MRTB
721 Each Animation stores 5 Orientations, which are automatically mirrored
722 to form an 8 Orientation Animation. PST Animations have a different Palette
723 format. This Animation Type handles the PST Palette format too.
725 NOTE: Walking/Running animations store 9 Orientations.
726 The second variation is missing the resting stance (STD) and the transitions.
727 These creatures are always in combat stance (don't rest).
728 Animation_3 is without STC (combat stance), they are always standing
730 IE_ANI_PST_STAND: This is a modified PST animation, it contains only a
731 Standing image for every orientations, it follows the
732 [C/D]STD[NAME][B] standard.
734 IE_ANI_PST_GHOST: This is a special static animation with no standard
735 All armourlevels are drawn simultaneously. There is no orientation or stance.
738 WEST PART | EAST PART
740 NW NNW N NNE NE
741 NW 006 007 008 009 010 NE
742 WNW 005 | 011 ENE
743 W 004 xxx 012 E
744 WSW 003 | 013 ESE
745 SW 002 001 000 015 014 SE
746 SW SSW S SSE SE
752 Animation** CharAnimations::GetAnimation(unsigned char Stance, unsigned char Orient)
754 if (StanceID>=MAX_ANIMS) {
755 printf("Illegal stance ID\n");
756 abort();
759 //for paletted dragon animations, we need the stance id
760 StanceID = nextStanceID = Stance;
761 int AnimType = GetAnimType();
763 //alter stance here if it is missing and you know a substitute
764 //probably we should feed this result back to the actor?
765 switch (AnimType) {
766 case -1: //invalid animation
767 return NULL;
769 case IE_ANI_PST_STAND:
770 StanceID=IE_ANI_AWAKE;
771 break;
772 case IE_ANI_PST_GHOST:
773 StanceID=IE_ANI_AWAKE;
774 Orient=0;
775 break;
776 case IE_ANI_PST_ANIMATION_3: //stc->std
777 if (StanceID==IE_ANI_READY) {
778 StanceID=IE_ANI_AWAKE;
780 break;
781 case IE_ANI_PST_ANIMATION_2: //std->stc
782 if (StanceID==IE_ANI_AWAKE) {
783 StanceID=IE_ANI_READY;
785 break;
787 //pst animations don't have separate animation for sleep/die
788 if (AnimType >= IE_ANI_PST_ANIMATION_1) {
789 if (StanceID==IE_ANI_DIE) {
790 StanceID=IE_ANI_TWITCH;
794 //TODO: Implement Auto Resource Loading
795 //setting up the sequencing of animation cycles
796 autoSwitchOnEnd = false;
797 switch (StanceID) {
798 case IE_ANI_DAMAGE:
799 nextStanceID = IE_ANI_READY;
800 autoSwitchOnEnd = true;
801 break;
802 case IE_ANI_SLEEP: //going to sleep
803 nextStanceID = IE_ANI_TWITCH;
804 autoSwitchOnEnd = true;
805 break;
806 case IE_ANI_TWITCH: //dead, sleeping
807 autoSwitchOnEnd = false;
808 break;
809 case IE_ANI_DIE: //going to die
810 nextStanceID = IE_ANI_TWITCH;
811 autoSwitchOnEnd = true;
812 break;
813 case IE_ANI_WALK:
814 case IE_ANI_RUN:
815 case IE_ANI_CAST: // looping
816 case IE_ANI_READY:
817 break;
818 case IE_ANI_AWAKE:
819 break;
820 case IE_ANI_EMERGE:
821 case IE_ANI_GET_UP:
822 case IE_ANI_HEAD_TURN:
823 case IE_ANI_PST_START:
824 nextStanceID = IE_ANI_AWAKE;
825 autoSwitchOnEnd = true;
826 break;
827 case IE_ANI_CONJURE: //ending
828 case IE_ANI_SHOOT:
829 case IE_ANI_ATTACK:
830 case IE_ANI_ATTACK_JAB:
831 case IE_ANI_ATTACK_SLASH:
832 case IE_ANI_ATTACK_BACKSLASH:
833 nextStanceID = IE_ANI_READY;
834 autoSwitchOnEnd = true;
835 break;
836 default:
837 printf ("Invalid Stance: %d\n", StanceID);
838 break;
840 Animation** anims = Anims[StanceID][Orient];
842 if (anims) {
843 return anims;
846 int partCount = GetTotalPartCount();
847 int actorPartCount = GetActorPartCount();
848 if (partCount < 0) return 0;
849 anims = new Animation*[partCount];
851 EquipResRefData* equipdat = 0;
852 for (int part = 0; part < partCount; ++part)
854 anims[part] = 0;
856 //newresref is based on the prefix (ResRef) and various
857 // other things.
858 //this is longer than expected so it won't overflow
859 char NewResRef[12];
860 unsigned char Cycle = 0;
861 if (part < actorPartCount) {
862 // Character animation parts
864 if (equipdat) delete equipdat;
866 //we need this long for special anims
867 strncpy( NewResRef, ResRef, 8 );
868 GetAnimResRef( StanceID, Orient, NewResRef, Cycle, part, equipdat);
869 } else {
870 // Equipment animation parts
872 anims[part] = 0;
873 if (GetSize() == 0) continue;
875 if (part == actorPartCount) {
876 if (WeaponRef[0] == 0) continue;
877 // weapon
878 GetEquipmentResRef(WeaponRef,false,NewResRef,Cycle,equipdat);
879 } else if (part == actorPartCount+1) {
880 if (OffhandRef[0] == 0) continue;
881 if (WeaponType == IE_ANI_WEAPON_2H) continue;
882 // off-hand
883 if (WeaponType == IE_ANI_WEAPON_1H) {
884 GetEquipmentResRef(OffhandRef,false,NewResRef,Cycle,
885 equipdat);
886 } else { // IE_ANI_WEAPON_2W
887 GetEquipmentResRef(OffhandRef,true,NewResRef,Cycle,
888 equipdat);
890 } else if (part == actorPartCount+2) {
891 if (HelmetRef[0] == 0) continue;
892 // helmet
893 GetEquipmentResRef(HelmetRef,false,NewResRef,Cycle,equipdat);
896 NewResRef[8]=0; //cutting right to size
898 AnimationFactory* af = ( AnimationFactory* )
899 gamedata->GetFactoryResource( NewResRef,
900 IE_BAM_CLASS_ID, IE_NORMAL );
902 if (!af) {
903 if (part < actorPartCount) {
904 char warnbuf[200];
905 snprintf(warnbuf, 200,
906 "Couldn't create animationfactory: %s (%04x)\n", NewResRef, GetAnimationID());
907 printMessage("CharAnimations",warnbuf,LIGHT_RED);
908 for (int i = 0; i < part; ++i)
909 delete anims[i];
910 delete[] anims;
911 delete equipdat;
912 return 0;
913 } else {
914 // not fatal if animation for equipment is missing
915 continue;
919 Animation* a = af->GetCycle( Cycle );
920 anims[part] = a;
922 if (!a) {
923 if (part < actorPartCount) {
924 char warnbuf[200];
925 snprintf(warnbuf, 200,
926 "Couldn't load animation: %s, cycle %d\n",
927 NewResRef, Cycle);
928 printMessage("CharAnimations",warnbuf,LIGHT_RED);
929 for (int i = 0; i < part; ++i)
930 delete anims[i];
931 delete[] anims;
932 delete equipdat;
933 return 0;
934 } else {
935 // not fatal if animation for equipment is missing
936 continue;
940 if (part < actorPartCount) {
941 //if you need to revert this change, consider true paletted
942 //animations which need a GlobalColorMod (mgir for example)
944 //if (!palette[PAL_MAIN] && ((GlobalColorMod.type!=RGBModifier::NONE) || (NoPalette()!=1)) ) {
945 if(!palette[PAL_MAIN]) {
946 // This is the first time we're loading an Animation.
947 // We copy the palette of its first frame into our own palette
948 palette[PAL_MAIN] = a->GetFrame(0)->GetPalette()->Copy();
949 // ...and setup the colours properly
950 SetupColors(PAL_MAIN);
952 } else if (part == actorPartCount) {
953 if (!palette[PAL_WEAPON]) {
954 palette[PAL_WEAPON] = a->GetFrame(0)->GetPalette()->Copy();
955 SetupColors(PAL_WEAPON);
957 } else if (part == actorPartCount+1) {
958 if (!palette[PAL_OFFHAND]) {
959 palette[PAL_OFFHAND] = a->GetFrame(0)->GetPalette()->Copy();
960 SetupColors(PAL_OFFHAND);
962 } else if (part == actorPartCount+2) {
963 if (!palette[PAL_HELMET]) {
964 palette[PAL_HELMET] = a->GetFrame(0)->GetPalette()->Copy();
965 SetupColors(PAL_HELMET);
969 //animation is affected by game flags
970 a->gameAnimation = true;
971 a->SetPos( 0 );
973 //setting up the sequencing of animation cycles
974 switch (StanceID) {
975 case IE_ANI_DAMAGE:
976 case IE_ANI_SLEEP:
977 case IE_ANI_TWITCH:
978 case IE_ANI_DIE:
979 case IE_ANI_PST_START:
980 case IE_ANI_HEAD_TURN:
981 case IE_ANI_CONJURE:
982 case IE_ANI_SHOOT:
983 case IE_ANI_ATTACK:
984 case IE_ANI_ATTACK_JAB:
985 case IE_ANI_ATTACK_SLASH:
986 case IE_ANI_ATTACK_BACKSLASH:
987 a->Flags |= A_ANI_PLAYONCE;
988 break;
989 case IE_ANI_EMERGE:
990 case IE_ANI_GET_UP:
991 a->playReversed = true;
992 a->Flags |= A_ANI_PLAYONCE;
993 break;
995 switch (GetAnimType()) {
996 case IE_ANI_NINE_FRAMES: //dragon animations
997 case IE_ANI_FOUR_FRAMES: //wyvern animations
998 case IE_ANI_BIRD:
999 case IE_ANI_CODE_MIRROR:
1000 case IE_ANI_CODE_MIRROR_2: //9 orientations
1001 case IE_ANI_CODE_MIRROR_3:
1002 case IE_ANI_PST_ANIMATION_3: //no stc just std
1003 case IE_ANI_PST_ANIMATION_2: //no std just stc
1004 case IE_ANI_PST_ANIMATION_1:
1005 case IE_ANI_FRAGMENT:
1006 if (Orient > 8) {
1007 a->MirrorAnimation( );
1009 break;
1010 default:
1011 break;
1014 // make animarea of part 0 encompass the animarea of the other parts
1015 if (part > 0)
1016 anims[0]->AddAnimArea(a);
1020 switch (GetAnimType()) {
1021 case IE_ANI_NINE_FRAMES: //dragon animations
1022 case IE_ANI_FOUR_FRAMES: //wyvern animations
1023 case IE_ANI_BIRD:
1024 case IE_ANI_CODE_MIRROR:
1025 case IE_ANI_SIX_FILES: //16 anims some are stored elsewhere
1026 case IE_ANI_ONE_FILE: //16 orientations
1027 case IE_ANI_CODE_MIRROR_2: //9 orientations
1028 case IE_ANI_CODE_MIRROR_3:
1029 Anims[StanceID][Orient] = anims;
1030 break;
1031 case IE_ANI_TWO_FILES:
1032 case IE_ANI_TWENTYTWO:
1033 case IE_ANI_TWO_FILES_2:
1034 case IE_ANI_TWO_FILES_3:
1035 case IE_ANI_TWO_FILES_3B:
1036 case IE_ANI_FOUR_FILES:
1037 case IE_ANI_FOUR_FILES_2:
1038 case IE_ANI_SIX_FILES_2:
1039 case IE_ANI_FRAGMENT:
1040 Orient&=~1;
1041 Anims[StanceID][Orient] = anims;
1042 Anims[StanceID][Orient + 1] = anims;
1043 break;
1045 case IE_ANI_PST_ANIMATION_3: //no stc just std
1046 case IE_ANI_PST_ANIMATION_2: //no std just stc
1047 case IE_ANI_PST_ANIMATION_1:
1048 switch (StanceID) {
1049 case IE_ANI_WALK:
1050 case IE_ANI_RUN:
1051 case IE_ANI_PST_START:
1052 Anims[StanceID][Orient] = anims;
1053 break;
1054 default:
1055 Orient &=~1;
1056 Anims[StanceID][Orient] = anims;
1057 Anims[StanceID][Orient + 1] = anims;
1058 break;
1060 break;
1062 case IE_ANI_PST_STAND:
1063 Orient &=~1;
1064 Anims[StanceID][Orient] = anims;
1065 Anims[StanceID][Orient+1] = anims;
1066 break;
1067 case IE_ANI_PST_GHOST:
1068 Orient = 0;
1069 StanceID = IE_ANI_AWAKE;
1070 Anims[StanceID][0] = anims;
1071 break;
1072 default:
1073 printMessage("CharAnimations","Unknown animation type\n",LIGHT_RED);
1074 abort();
1076 delete equipdat;
1078 return Anims[StanceID][Orient];
1081 static const int one_file[19]={2, 1, 0, 0, 2, 3, 0, 1, 0, 4, 1, 0, 0, 0, 3, 1, 4, 4, 4};
1083 void CharAnimations::GetAnimResRef(unsigned char StanceID,
1084 unsigned char Orient,
1085 char* NewResRef, unsigned char& Cycle,
1086 int Part, EquipResRefData*& EquipData)
1088 char tmp[256];
1089 EquipData = 0;
1090 Orient &= 15;
1091 switch (GetAnimType()) {
1092 case IE_ANI_FOUR_FRAMES:
1093 AddFFSuffix( NewResRef, StanceID, Cycle, Orient, Part );
1094 break;
1096 case IE_ANI_NINE_FRAMES:
1097 AddNFSuffix( NewResRef, StanceID, Cycle, Orient, Part );
1098 break;
1100 case IE_ANI_CODE_MIRROR:
1101 AddVHRSuffix( NewResRef, StanceID, Cycle, Orient, EquipData );
1102 break;
1104 case IE_ANI_BIRD:
1105 Cycle = (ieByte) ((StanceID&1) * 9 + SixteenToNine[Orient]);
1106 break;
1108 case IE_ANI_FRAGMENT:
1109 Cycle = SixteenToFive[Orient];
1110 break;
1112 case IE_ANI_ONE_FILE:
1113 Cycle = (ieByte) (one_file[StanceID] * 16 + Orient);
1114 break;
1116 case IE_ANI_SIX_FILES:
1117 AddSixSuffix( NewResRef, StanceID, Cycle, Orient );
1118 break;
1120 case IE_ANI_TWENTYTWO: //5+3 animations
1121 AddMHRSuffix( NewResRef, StanceID, Cycle, Orient, EquipData );
1122 break;
1124 case IE_ANI_TWO_FILES_2: //4+4 animations
1125 AddLR2Suffix( NewResRef, StanceID, Cycle, Orient );
1126 break;
1128 case IE_ANI_TWO_FILES_3: //IWD style anims
1129 AddMMRSuffix( NewResRef, StanceID, Cycle, Orient );
1130 break;
1132 case IE_ANI_TWO_FILES_3B: //IWD style anims
1133 AddMMR2Suffix( NewResRef, StanceID, Cycle, Orient );
1134 break;
1136 case IE_ANI_TWO_FILES:
1137 AddTwoFileSuffix(NewResRef, StanceID, Cycle, Orient );
1138 break;
1140 case IE_ANI_FOUR_FILES:
1141 AddLRSuffix( NewResRef, StanceID, Cycle, Orient, EquipData );
1142 break;
1144 case IE_ANI_FOUR_FILES_2:
1145 AddLRSuffix2( NewResRef, StanceID, Cycle, Orient, EquipData );
1146 break;
1148 case IE_ANI_SIX_FILES_2: //MOGR (variant of FOUR_FILES)
1149 AddLR3Suffix( NewResRef, StanceID, Cycle, Orient );
1150 break;
1152 case IE_ANI_CODE_MIRROR_2: //9 orientations
1153 AddVHR2Suffix( NewResRef, StanceID, Cycle, Orient );
1154 break;
1156 case IE_ANI_CODE_MIRROR_3: // like IE_ANI_CODE_MIRROR_2 but with fewer cycles in g26
1157 AddVHR3Suffix( NewResRef, StanceID, Cycle, Orient );
1158 break;
1160 case IE_ANI_PST_ANIMATION_1:
1161 case IE_ANI_PST_ANIMATION_2:
1162 case IE_ANI_PST_ANIMATION_3:
1163 AddPSTSuffix( NewResRef, StanceID, Cycle, Orient );
1164 break;
1166 case IE_ANI_PST_STAND:
1167 sprintf(NewResRef,"%cSTD%4s",ResRef[0], ResRef+1);
1168 Cycle = (ieByte) SixteenToFive[Orient];
1169 break;
1170 case IE_ANI_PST_GHOST: // pst static animations
1171 //still doesn't handle the second cycle of the golem anim
1172 Cycle = 0;
1173 strnlwrcpy(NewResRef, AvatarTable[AvatarsRowNum].Prefixes[Part], 8);
1174 break;
1175 default:
1176 sprintf (tmp,"Unknown animation type in avatars.2da row: %d\n", AvatarsRowNum);
1177 printMessage ("CharAnimations",tmp, LIGHT_RED);
1178 abort();
1182 void CharAnimations::GetEquipmentResRef(const char* equipRef, bool offhand,
1183 char* ResRef, unsigned char& Cycle, EquipResRefData* equip)
1185 switch (GetAnimType()) {
1186 case IE_ANI_FOUR_FILES:
1187 case IE_ANI_FOUR_FILES_2:
1188 GetLREquipmentRef( ResRef, Cycle, equipRef, offhand, equip );
1189 break;
1190 case IE_ANI_CODE_MIRROR:
1191 GetVHREquipmentRef( ResRef, Cycle, equipRef, offhand, equip );
1192 break;
1193 case IE_ANI_TWENTYTWO:
1194 GetMHREquipmentRef( ResRef, Cycle, equipRef, offhand, equip );
1195 break;
1196 default:
1197 printMessage ("CharAnimations", "Unsupported animation type for equipment animation.\n", LIGHT_RED);
1198 abort();
1199 break;
1203 const int* CharAnimations::GetZOrder(unsigned char Orient)
1205 switch (GetAnimType()) {
1206 case IE_ANI_CODE_MIRROR:
1207 return zOrder_Mirror16[Orient];
1208 case IE_ANI_TWENTYTWO:
1209 return zOrder_8[Orient/2];
1210 case IE_ANI_FOUR_FILES:
1211 return 0; // FIXME
1212 default:
1213 return 0;
1218 void CharAnimations::AddPSTSuffix(char* ResRef, unsigned char StanceID,
1219 unsigned char& Cycle, unsigned char Orient)
1221 const char *Prefix;
1223 switch (StanceID) {
1224 case IE_ANI_ATTACK:
1225 case IE_ANI_ATTACK_SLASH:
1226 case IE_ANI_ATTACK_JAB:
1227 case IE_ANI_ATTACK_BACKSLASH:
1228 Cycle=SixteenToFive[Orient];
1229 Prefix="at1"; break;
1230 case IE_ANI_DAMAGE:
1231 Cycle=SixteenToFive[Orient];
1232 Prefix="hit"; break;
1233 case IE_ANI_GET_UP:
1234 case IE_ANI_EMERGE:
1235 Cycle=SixteenToFive[Orient];
1236 Prefix="gup"; break;
1237 case IE_ANI_AWAKE:
1238 Cycle=SixteenToFive[Orient];
1239 Prefix="std"; break;
1240 case IE_ANI_READY:
1241 Cycle=SixteenToFive[Orient];
1242 Prefix="stc"; break;
1243 case IE_ANI_DIE:
1244 case IE_ANI_SLEEP:
1245 case IE_ANI_TWITCH:
1246 Cycle=SixteenToFive[Orient];
1247 Prefix="dfb"; break;
1248 case IE_ANI_RUN:
1249 Cycle=SixteenToNine[Orient];
1250 Prefix="run"; break;
1251 case IE_ANI_WALK:
1252 Cycle=SixteenToNine[Orient];
1253 Prefix="wlk"; break;
1254 case IE_ANI_HEAD_TURN:
1255 Cycle=SixteenToFive[Orient];
1256 if (rand()&1) {
1257 Prefix="sf2";
1258 sprintf(ResRef,"%c%3s%4s",this->ResRef[0], Prefix, this->ResRef+1);
1259 if (gamedata->Exists(ResRef, IE_BAM_CLASS_ID) ) {
1260 return;
1263 Prefix="sf1";
1264 sprintf(ResRef,"%c%3s%4s",this->ResRef[0], Prefix, this->ResRef+1);
1265 if (gamedata->Exists(ResRef, IE_BAM_CLASS_ID) ) {
1266 return;
1268 Prefix = "stc";
1269 break;
1270 case IE_ANI_PST_START:
1271 Cycle=0;
1272 Prefix="ms1"; break;
1273 default: //just in case
1274 Cycle=SixteenToFive[Orient];
1275 Prefix="stc"; break;
1277 sprintf(ResRef,"%c%3s%4s",this->ResRef[0], Prefix, this->ResRef+1);
1280 void CharAnimations::AddVHR2Suffix(char* ResRef, unsigned char StanceID,
1281 unsigned char& Cycle, unsigned char Orient)
1283 Cycle=SixteenToNine[Orient];
1285 switch (StanceID) {
1286 case IE_ANI_ATTACK: //temporarily
1287 case IE_ANI_ATTACK_BACKSLASH:
1288 strcat( ResRef, "g21" );
1289 break;
1291 case IE_ANI_ATTACK_SLASH:
1292 strcat( ResRef, "g2" );
1293 break;
1295 case IE_ANI_ATTACK_JAB:
1296 strcat( ResRef, "g26" );
1297 Cycle+=45;
1298 break;
1300 case IE_ANI_CAST: //looping
1301 strcat( ResRef, "g25" );
1302 Cycle+=45;
1303 break;
1305 case IE_ANI_CONJURE://ending
1306 strcat( ResRef, "g26" );
1307 Cycle+=54;
1308 break;
1310 case IE_ANI_SHOOT:
1311 strcat( ResRef, "g24" );
1312 Cycle+=27;
1313 break;
1315 case IE_ANI_HEAD_TURN:
1316 case IE_ANI_AWAKE:
1317 strcat( ResRef, "g12" );
1318 Cycle+=18;
1319 break;
1321 case IE_ANI_SLEEP:
1322 strcat( ResRef, "g15" );
1323 Cycle+=45;
1324 break;
1326 case IE_ANI_TWITCH:
1327 strcat( ResRef, "g14" );
1328 Cycle+=45;
1329 break;
1331 case IE_ANI_DIE:
1332 case IE_ANI_EMERGE:
1333 case IE_ANI_GET_UP:
1334 case IE_ANI_PST_START:
1335 strcat( ResRef, "g14" );
1336 Cycle+=36;
1337 break;
1339 case IE_ANI_DAMAGE:
1340 strcat( ResRef, "g13" );
1341 Cycle+=27;
1342 break;
1344 case IE_ANI_READY:
1345 strcat( ResRef, "g1" );
1346 Cycle+=9;
1347 break;
1349 case IE_ANI_WALK:
1350 strcat( ResRef, "g11" );
1351 break;
1352 default:
1353 printf("VHR2 Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1354 abort();
1355 break;
1359 void CharAnimations::AddVHR3Suffix(char* ResRef, unsigned char StanceID,
1360 unsigned char& Cycle, unsigned char Orient)
1362 Cycle=SixteenToNine[Orient];
1364 switch (StanceID) {
1365 case IE_ANI_ATTACK: //temporarily
1366 case IE_ANI_ATTACK_BACKSLASH:
1367 strcat( ResRef, "g21" );
1368 break;
1370 case IE_ANI_ATTACK_SLASH:
1371 strcat( ResRef, "g2" );
1372 break;
1374 case IE_ANI_ATTACK_JAB:
1375 strcat( ResRef, "g26" );
1376 Cycle+=18;
1377 break;
1379 case IE_ANI_CAST: //looping
1380 strcat( ResRef, "g25" );
1381 Cycle+=45;
1382 break;
1384 case IE_ANI_CONJURE://ending
1385 strcat( ResRef, "g26" );
1386 Cycle+=36;
1387 break;
1389 case IE_ANI_SHOOT:
1390 strcat( ResRef, "g24" );
1391 Cycle+=27;
1392 break;
1394 case IE_ANI_HEAD_TURN:
1395 case IE_ANI_AWAKE:
1396 strcat( ResRef, "g12" );
1397 Cycle+=18;
1398 break;
1400 case IE_ANI_SLEEP:
1401 strcat( ResRef, "g15" );
1402 Cycle+=45;
1403 break;
1405 case IE_ANI_TWITCH:
1406 strcat( ResRef, "g14" );
1407 Cycle+=45;
1408 break;
1410 case IE_ANI_DIE:
1411 case IE_ANI_EMERGE:
1412 case IE_ANI_GET_UP:
1413 case IE_ANI_PST_START:
1414 strcat( ResRef, "g14" );
1415 Cycle+=36;
1416 break;
1418 case IE_ANI_DAMAGE:
1419 strcat( ResRef, "g13" );
1420 Cycle+=27;
1421 break;
1423 case IE_ANI_READY:
1424 strcat( ResRef, "g1" );
1425 Cycle+=9;
1426 break;
1428 case IE_ANI_WALK:
1429 strcat( ResRef, "g11" );
1430 break;
1431 default:
1432 printf("VHR3 Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1433 abort();
1434 break;
1438 // Note: almost like SixSuffix
1439 void CharAnimations::AddFFSuffix(char* ResRef, unsigned char StanceID,
1440 unsigned char& Cycle, unsigned char Orient, int Part)
1442 Cycle=SixteenToNine[Orient];
1443 switch (StanceID) {
1444 case IE_ANI_WALK:
1445 strcat( ResRef, "g1" );
1446 break;
1448 case IE_ANI_ATTACK:
1449 case IE_ANI_ATTACK_SLASH:
1450 strcat( ResRef, "g3" );
1451 break;
1453 case IE_ANI_ATTACK_BACKSLASH:
1454 strcat( ResRef, "g3" );
1455 Cycle += 16;
1456 break;
1458 case IE_ANI_ATTACK_JAB:
1459 case IE_ANI_CAST:
1460 case IE_ANI_CONJURE:
1461 strcat( ResRef, "g3" );
1462 Cycle += 32;
1463 break;
1465 case IE_ANI_HEAD_TURN: //could be wrong
1466 case IE_ANI_AWAKE:
1467 strcat( ResRef, "g2" );
1468 break;
1470 case IE_ANI_READY:
1471 strcat( ResRef, "g2" );
1472 Cycle += 16;
1473 break;
1475 case IE_ANI_DAMAGE:
1476 strcat( ResRef, "g2" );
1477 Cycle += 32;
1478 break;
1480 case IE_ANI_DIE:
1481 case IE_ANI_GET_UP:
1482 case IE_ANI_EMERGE:
1483 case IE_ANI_PST_START:
1484 strcat( ResRef, "g2" );
1485 Cycle += 48;
1486 break;
1488 case IE_ANI_TWITCH:
1489 strcat( ResRef, "g2" );
1490 Cycle += 64;
1491 break;
1493 default:
1494 printf("Four frames Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1495 abort();
1496 break;
1499 ResRef[6]=(char) (Part+'1');
1500 ResRef[7]=0;
1503 void CharAnimations::AddNFSuffix(char* ResRef, unsigned char StanceID,
1504 unsigned char& Cycle, unsigned char Orient, int Part)
1506 char prefix[10];
1508 Cycle = SixteenToNine[Orient];
1509 snprintf(prefix, 9, "%s%s%d%s%d", ResRef, StancePrefix[StanceID], Part+1,
1510 CyclePrefix[StanceID], Cycle);
1511 strnlwrcpy(ResRef,prefix,8);
1512 Cycle=(ieByte) (Cycle+CycleOffset[StanceID]);
1515 //Attack
1516 //h1, h2, w2
1517 //static const char *SlashPrefix[]={"a1","a4","a7"};
1518 //static const char *BackPrefix[]={"a2","a5","a8"};
1519 //static const char *JabPrefix[]={"a3","a6","a9"};
1520 static const char *SlashPrefix[]={"a1","a2","a7"};
1521 static const char *BackPrefix[]={"a3","a4","a8"};
1522 static const char *JabPrefix[]={"a5","a6","a9"};
1523 static const char *RangedPrefix[]={"sa","sx","ss"};
1524 static const char *RangedPrefixOld[]={"sa","sx","a1"};
1526 void CharAnimations::AddVHRSuffix(char* ResRef, unsigned char StanceID,
1527 unsigned char& Cycle, unsigned char Orient, EquipResRefData*& EquipData)
1529 Cycle = SixteenToNine[Orient];
1530 EquipData = new EquipResRefData;
1531 EquipData->Suffix[0] = 0;
1532 switch (StanceID) {
1533 case IE_ANI_ATTACK:
1534 case IE_ANI_ATTACK_SLASH:
1535 strcat( ResRef, SlashPrefix[WeaponType] );
1536 strcpy( EquipData->Suffix, SlashPrefix[WeaponType] );
1537 break;
1539 case IE_ANI_ATTACK_BACKSLASH:
1540 strcat( ResRef, BackPrefix[WeaponType] );
1541 strcpy( EquipData->Suffix, BackPrefix[WeaponType] );
1542 break;
1544 case IE_ANI_ATTACK_JAB:
1545 strcat( ResRef, JabPrefix[WeaponType] );
1546 strcpy( EquipData->Suffix, JabPrefix[WeaponType] );
1547 break;
1549 case IE_ANI_AWAKE:
1550 strcat( ResRef, "g17" );
1551 strcpy( EquipData->Suffix, "g1" );
1552 Cycle += 63;
1553 break;
1555 case IE_ANI_CAST: //looping
1556 strcat( ResRef, "ca" );
1557 strcpy( EquipData->Suffix, "ca" );
1558 break;
1560 case IE_ANI_CONJURE: //ending
1561 strcat( ResRef, "ca" );
1562 strcpy( EquipData->Suffix, "ca" );
1563 Cycle += 9;
1564 break;
1566 case IE_ANI_DAMAGE:
1567 strcat( ResRef, "g14" );
1568 strcpy( EquipData->Suffix, "g1" );
1569 Cycle += 36;
1570 break;
1572 case IE_ANI_DIE:
1573 strcat( ResRef, "g15" );
1574 strcpy( EquipData->Suffix, "g1" );
1575 Cycle += 45;
1576 break;
1577 //I cannot find an emerge animation...
1578 //Maybe is Die reversed
1579 case IE_ANI_GET_UP:
1580 case IE_ANI_EMERGE:
1581 case IE_ANI_PST_START:
1582 strcat( ResRef, "g19" );
1583 strcpy( EquipData->Suffix, "g1" );
1584 Cycle += 81;
1585 break;
1587 case IE_ANI_HEAD_TURN:
1588 if (rand()&1) {
1589 strcat( ResRef, "g12" );
1590 Cycle += 18;
1591 } else {
1592 strcat( ResRef, "g18" );
1593 Cycle += 72;
1595 strcpy( EquipData->Suffix, "g1" );
1596 break;
1598 //Unknown... maybe only a transparency effect apply
1599 case IE_ANI_HIDE:
1600 break;
1602 case IE_ANI_READY:
1603 if ( WeaponType == IE_ANI_WEAPON_2H ) {
1604 strcat( ResRef, "g13" );
1605 Cycle += 27;
1606 } else {
1607 strcat( ResRef, "g1" );
1608 Cycle += 9;
1610 strcpy( EquipData->Suffix, "g1" );
1611 break;
1612 //This depends on the ranged weapon equipped
1613 case IE_ANI_SHOOT:
1614 strcat( ResRef, RangedPrefix[RangedType] );
1615 strcpy( EquipData->Suffix, RangedPrefix[RangedType] );
1616 break;
1618 case IE_ANI_SLEEP:
1619 strcat( ResRef, "g16" );
1620 strcpy( EquipData->Suffix, "g1" );
1621 Cycle += 54;
1622 break;
1624 case IE_ANI_TWITCH:
1625 strcat( ResRef, "g16" );
1626 strcpy( EquipData->Suffix, "g1" );
1627 Cycle += 54;
1628 break;
1630 case IE_ANI_WALK:
1631 strcat( ResRef, "g11" );
1632 strcpy( EquipData->Suffix, "g1" );
1633 break;
1635 default:
1636 printf("VHR Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1637 abort();
1638 break;
1640 EquipData->Cycle = Cycle;
1643 void CharAnimations::GetVHREquipmentRef(char* ResRef, unsigned char& Cycle,
1644 const char* equipRef, bool offhand,
1645 EquipResRefData* equip)
1647 Cycle = equip->Cycle;
1648 if (offhand) {
1649 sprintf( ResRef, "wq%c%c%co%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix );
1650 } else {
1651 sprintf( ResRef, "wq%c%c%c%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix );
1655 void CharAnimations::AddSixSuffix(char* ResRef, unsigned char StanceID,
1656 unsigned char& Cycle, unsigned char Orient)
1658 switch (StanceID) {
1659 case IE_ANI_WALK:
1660 strcat( ResRef, "g1" );
1661 Cycle = Orient;
1662 break;
1664 case IE_ANI_ATTACK:
1665 case IE_ANI_ATTACK_SLASH:
1666 strcat( ResRef, "g3" );
1667 Cycle = Orient;
1668 break;
1670 case IE_ANI_ATTACK_BACKSLASH:
1671 strcat( ResRef, "g3" );
1672 Cycle = 16 + Orient;
1673 break;
1675 case IE_ANI_ATTACK_JAB:
1676 strcat( ResRef, "g3" );
1677 Cycle = 32 + Orient;
1678 break;
1680 case IE_ANI_HEAD_TURN: //could be wrong
1681 case IE_ANI_AWAKE:
1682 strcat( ResRef, "g2" );
1683 Cycle = 0 + Orient;
1684 break;
1686 case IE_ANI_READY:
1687 strcat( ResRef, "g2" );
1688 Cycle = 16 + Orient;
1689 break;
1691 case IE_ANI_DAMAGE:
1692 strcat( ResRef, "g2" );
1693 Cycle = 32 + Orient;
1694 break;
1696 case IE_ANI_DIE:
1697 case IE_ANI_GET_UP:
1698 case IE_ANI_EMERGE:
1699 case IE_ANI_PST_START:
1700 strcat( ResRef, "g2" );
1701 Cycle = 48 + Orient;
1702 break;
1704 case IE_ANI_TWITCH:
1705 strcat( ResRef, "g2" );
1706 Cycle = 64 + Orient;
1707 break;
1709 default:
1710 printf("Six Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1711 abort();
1712 break;
1715 if (Orient>9) {
1716 strcat( ResRef, "e" );
1720 void CharAnimations::AddLR2Suffix(char* ResRef, unsigned char StanceID,
1721 unsigned char& Cycle, unsigned char Orient)
1723 Orient /= 2;
1725 switch (StanceID) {
1726 case IE_ANI_READY:
1727 case IE_ANI_CAST: //looping
1728 case IE_ANI_CONJURE://ending
1729 case IE_ANI_HIDE:
1730 case IE_ANI_WALK:
1731 case IE_ANI_AWAKE:
1732 Cycle = 0 + Orient;
1733 break;
1735 case IE_ANI_SHOOT:
1736 case IE_ANI_ATTACK:
1737 case IE_ANI_ATTACK_SLASH:
1738 case IE_ANI_ATTACK_BACKSLASH:
1739 case IE_ANI_ATTACK_JAB:
1740 case IE_ANI_HEAD_TURN:
1741 Cycle = 8 + Orient;
1742 break;
1744 case IE_ANI_DIE:
1745 case IE_ANI_GET_UP:
1746 case IE_ANI_EMERGE:
1747 case IE_ANI_PST_START:
1748 Cycle = 24 + Orient;
1749 break;
1751 case IE_ANI_DAMAGE:
1752 Cycle = 16 + Orient;
1753 break;
1755 case IE_ANI_SLEEP:
1756 case IE_ANI_TWITCH:
1757 Cycle = 32 + Orient;
1758 break;
1759 default:
1760 printf("LR2 Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1761 abort();
1762 break;
1764 if (Orient>=4) {
1765 strcat( ResRef, "g1e" );
1766 } else {
1767 strcat( ResRef, "g1" );
1771 void CharAnimations::AddMHRSuffix(char* ResRef, unsigned char StanceID,
1772 unsigned char& Cycle, unsigned char Orient, EquipResRefData*& EquipData)
1774 Orient /= 2;
1775 EquipData = new EquipResRefData;
1776 EquipData->Suffix[0] = 0;
1778 switch (StanceID) {
1779 case IE_ANI_ATTACK:
1780 case IE_ANI_ATTACK_SLASH:
1781 strcat (ResRef, SlashPrefix[WeaponType]);
1782 strcpy( EquipData->Suffix, SlashPrefix[WeaponType] );
1783 Cycle = Orient;
1784 break;
1786 case IE_ANI_ATTACK_BACKSLASH:
1787 strcat (ResRef, BackPrefix[WeaponType]);
1788 strcpy( EquipData->Suffix, BackPrefix[WeaponType] );
1789 Cycle = Orient;
1790 break;
1792 case IE_ANI_ATTACK_JAB:
1793 strcat (ResRef, JabPrefix[WeaponType]);
1794 strcpy( EquipData->Suffix, JabPrefix[WeaponType] );
1795 Cycle = Orient;
1796 break;
1798 case IE_ANI_READY:
1799 strcat( ResRef, "g1" );
1800 strcpy( EquipData->Suffix, "g1" );
1801 if ( WeaponType == IE_ANI_WEAPON_2W ) {
1802 Cycle = 24 + Orient;
1803 } else {
1804 Cycle = 8 + Orient;
1806 break;
1808 case IE_ANI_CAST://looping
1809 strcat( ResRef, "ca" );
1810 strcpy( EquipData->Suffix, "ca" );
1811 Cycle = 8 + Orient;
1812 break;
1814 case IE_ANI_CONJURE://ending
1815 strcat( ResRef, "ca" );
1816 strcpy( EquipData->Suffix, "ca" );
1817 Cycle = Orient;
1818 break;
1820 case IE_ANI_DAMAGE:
1821 strcat( ResRef, "g1" );
1822 strcpy( EquipData->Suffix, "g1" );
1823 Cycle = 40 + Orient;
1824 break;
1826 case IE_ANI_DIE:
1827 case IE_ANI_GET_UP:
1828 case IE_ANI_PST_START:
1829 strcat( ResRef, "g1" );
1830 strcpy( EquipData->Suffix, "g1" );
1831 Cycle = 48 + Orient;
1832 break;
1834 //I cannot find an emerge animation...
1835 //Maybe is Die reversed
1836 case IE_ANI_EMERGE:
1837 strcat( ResRef, "g1" );
1838 strcpy( EquipData->Suffix, "g1" );
1839 Cycle = 48 + Orient;
1840 break;
1842 case IE_ANI_HEAD_TURN:
1843 strcat( ResRef, "g1" );
1844 strcpy( EquipData->Suffix, "g1" );
1845 Cycle = 32 + Orient;
1846 break;
1848 //Unknown... maybe only a transparency effect apply
1849 case IE_ANI_HIDE:
1850 break;
1852 case IE_ANI_AWAKE:
1853 strcat( ResRef, "g1" );
1854 strcpy( EquipData->Suffix, "g1" );
1855 Cycle = 16 + Orient;
1856 break;
1858 //This depends on the ranged weapon equipped
1859 case IE_ANI_SHOOT:
1860 strcat (ResRef, RangedPrefixOld[RangedType]);
1861 strcpy( EquipData->Suffix, RangedPrefixOld[RangedType] );
1862 Cycle = Orient;
1863 break;
1865 case IE_ANI_SLEEP:
1866 strcat( ResRef, "g1" );
1867 strcpy( EquipData->Suffix, "g1" );
1868 Cycle = 64 + Orient;
1869 break;
1871 case IE_ANI_TWITCH:
1872 strcat( ResRef, "g1" );
1873 strcpy( EquipData->Suffix, "g1" );
1874 Cycle = 56 + Orient;
1875 break;
1877 case IE_ANI_WALK:
1878 strcat( ResRef, "g1" );
1879 strcpy( EquipData->Suffix, "g1" );
1880 Cycle = Orient;
1881 break;
1882 default:
1883 printf("MHR Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1884 abort();
1885 break;
1887 if (Orient>=5) {
1888 strcat( ResRef, "e" );
1889 strcat( EquipData->Suffix, "e" );
1891 EquipData->Cycle = Cycle;
1894 void CharAnimations::GetMHREquipmentRef(char* ResRef, unsigned char& Cycle,
1895 const char* equipRef, bool offhand,
1896 EquipResRefData* equip)
1898 Cycle = equip->Cycle;
1899 if (offhand) {
1900 //i think there is no offhand stuff for bg1, lets use the bg2 equivalent here?
1901 sprintf( ResRef, "wq%c%c%co%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix );
1902 } else {
1903 sprintf( ResRef, "wp%c%c%c%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix );
1907 void CharAnimations::AddTwoFileSuffix( char* ResRef, unsigned char StanceID,
1908 unsigned char& Cycle, unsigned char Orient)
1910 switch(StanceID) {
1911 case IE_ANI_HEAD_TURN:
1912 Cycle = 16 + Orient / 2;
1913 break;
1914 case IE_ANI_DAMAGE:
1915 Cycle = 24 + Orient / 2;
1916 break;
1917 case IE_ANI_SLEEP:
1918 case IE_ANI_TWITCH:
1919 Cycle = 40 + Orient / 2;
1920 break;
1921 case IE_ANI_GET_UP:
1922 case IE_ANI_EMERGE:
1923 case IE_ANI_DIE:
1924 case IE_ANI_PST_START:
1925 Cycle = 32 + Orient / 2;
1926 break;
1927 case IE_ANI_WALK:
1928 Cycle = Orient / 2;
1929 break;
1930 default:
1931 Cycle = 8 + Orient / 2;
1932 break;
1934 strcat( ResRef, "g1" );
1935 if (Orient > 9) {
1936 strcat( ResRef, "e" );
1940 void CharAnimations::AddLRSuffix2( char* ResRef, unsigned char StanceID,
1941 unsigned char& Cycle, unsigned char Orient, EquipResRefData *&EquipData)
1943 EquipData = new EquipResRefData;
1944 EquipData->Suffix[0] = 0;
1945 switch (StanceID) {
1946 case IE_ANI_ATTACK:
1947 case IE_ANI_ATTACK_BACKSLASH:
1948 case IE_ANI_ATTACK_SLASH:
1949 case IE_ANI_ATTACK_JAB:
1950 strcat( ResRef, "g2" );
1951 strcpy( EquipData->Suffix, "g2" );
1952 Cycle = Orient / 2;
1953 break;
1954 case IE_ANI_CAST:
1955 case IE_ANI_CONJURE:
1956 case IE_ANI_SHOOT:
1957 strcat( ResRef, "g2" );
1958 strcpy( EquipData->Suffix, "g2" );
1959 Cycle = 8 + Orient / 2;
1960 break;
1961 case IE_ANI_WALK:
1962 strcat( ResRef, "g1" );
1963 strcpy( EquipData->Suffix, "g1" );
1964 Cycle = Orient / 2;
1965 break;
1966 case IE_ANI_READY:
1967 strcat( ResRef, "g1" );
1968 strcpy( EquipData->Suffix, "g1" );
1969 Cycle = 8 + Orient / 2;
1970 break;
1971 case IE_ANI_HEAD_TURN: //could be wrong
1972 case IE_ANI_AWAKE:
1973 strcat( ResRef, "g1" );
1974 strcpy( EquipData->Suffix, "g1" );
1975 Cycle = 16 + Orient / 2;
1976 break;
1977 case IE_ANI_DAMAGE:
1978 strcat( ResRef, "g1" );
1979 strcpy( EquipData->Suffix, "g1" );
1980 Cycle = 24 + Orient / 2;
1981 break;
1982 case IE_ANI_GET_UP:
1983 case IE_ANI_EMERGE:
1984 case IE_ANI_PST_START:
1985 case IE_ANI_DIE:
1986 strcat( ResRef, "g1" );
1987 strcpy( EquipData->Suffix, "g1" );
1988 Cycle = 32 + Orient / 2;
1989 break;
1990 case IE_ANI_SLEEP:
1991 case IE_ANI_TWITCH:
1992 strcat( ResRef, "g1" );
1993 strcpy( EquipData->Suffix, "g1" );
1994 Cycle = 40 + Orient / 2;
1995 break;
1996 default:
1997 printf("LRSuffix2 Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1998 abort();
1999 break;
2001 if (Orient > 9) {
2002 strcat( ResRef, "e" );
2003 strcat( EquipData->Suffix, "e");
2005 EquipData->Cycle = Cycle;
2008 void CharAnimations::AddLRSuffix( char* ResRef, unsigned char StanceID,
2009 unsigned char& Cycle, unsigned char Orient, EquipResRefData *&EquipData)
2011 EquipData = new EquipResRefData;
2012 EquipData->Suffix[0] = 0;
2013 switch (StanceID) {
2014 case IE_ANI_ATTACK:
2015 case IE_ANI_ATTACK_BACKSLASH:
2016 strcat( ResRef, "g2" );
2017 strcpy( EquipData->Suffix, "g2" );
2018 Cycle = Orient / 2;
2019 break;
2020 case IE_ANI_ATTACK_SLASH:
2021 strcat( ResRef, "g2" );
2022 strcpy( EquipData->Suffix, "g2" );
2023 Cycle = 8 + Orient / 2;
2024 break;
2025 case IE_ANI_ATTACK_JAB:
2026 strcat( ResRef, "g2" );
2027 strcpy( EquipData->Suffix, "g2" );
2028 Cycle = 16 + Orient / 2;
2029 break;
2030 case IE_ANI_CAST:
2031 case IE_ANI_CONJURE:
2032 case IE_ANI_SHOOT:
2033 //these animations are missing
2034 strcat( ResRef, "g2" );
2035 strcpy( EquipData->Suffix, "g2" );
2036 Cycle = Orient / 2;
2037 break;
2038 case IE_ANI_WALK:
2039 strcat( ResRef, "g1" );
2040 strcpy( EquipData->Suffix, "g1" );
2041 Cycle = Orient / 2;
2042 break;
2043 case IE_ANI_READY:
2044 strcat( ResRef, "g1" );
2045 strcpy( EquipData->Suffix, "g1" );
2046 Cycle = 8 + Orient / 2;
2047 break;
2048 case IE_ANI_HEAD_TURN: //could be wrong
2049 case IE_ANI_AWAKE:
2050 strcat( ResRef, "g1" );
2051 strcpy( EquipData->Suffix, "g1" );
2052 Cycle = 16 + Orient / 2;
2053 break;
2054 case IE_ANI_DAMAGE:
2055 strcat( ResRef, "g1" );
2056 strcpy( EquipData->Suffix, "g1" );
2057 Cycle = 24 + Orient / 2;
2058 break;
2059 case IE_ANI_GET_UP:
2060 case IE_ANI_EMERGE:
2061 case IE_ANI_PST_START:
2062 case IE_ANI_DIE:
2063 strcat( ResRef, "g1" );
2064 strcpy( EquipData->Suffix, "g1" );
2065 Cycle = 32 + Orient / 2;
2066 break;
2067 case IE_ANI_TWITCH:
2068 case IE_ANI_SLEEP:
2069 strcat( ResRef, "g1" );
2070 strcpy( EquipData->Suffix, "g1" );
2071 Cycle = 40 + Orient / 2;
2072 break;
2073 default:
2074 printf("LR Animation: unhandled stance: %s %d\n", ResRef, StanceID);
2075 abort();
2076 break;
2078 if (Orient > 9) {
2079 strcat( ResRef, "e" );
2080 strcat( EquipData->Suffix, "e");
2082 EquipData->Cycle = Cycle;
2085 void CharAnimations::GetLREquipmentRef(char* ResRef, unsigned char& Cycle,
2086 const char* equipRef, bool /*offhand*/,
2087 EquipResRefData* equip)
2089 Cycle = equip->Cycle;
2090 //hackhackhack
2091 sprintf( ResRef, "%4s%c%s", this->ResRef, equipRef[0], equip->Suffix );
2094 //Only for the ogre animation (MOGR)
2095 void CharAnimations::AddLR3Suffix( char* ResRef, unsigned char StanceID,
2096 unsigned char& Cycle, unsigned char Orient)
2098 switch (StanceID) {
2099 case IE_ANI_ATTACK:
2100 case IE_ANI_ATTACK_BACKSLASH:
2101 strcat( ResRef, "g2" );
2102 Cycle = Orient / 2;
2103 break;
2104 case IE_ANI_ATTACK_SLASH:
2105 strcat( ResRef, "g2" );
2106 Cycle = 8 + Orient / 2;
2107 break;
2108 case IE_ANI_ATTACK_JAB:
2109 strcat( ResRef, "g2" );
2110 Cycle = 8 + Orient / 2; //there is no third attack animation
2111 break;
2112 case IE_ANI_CAST:
2113 case IE_ANI_CONJURE:
2114 case IE_ANI_SHOOT:
2115 strcat( ResRef, "g3" );
2116 Cycle = Orient / 2;
2117 break;
2118 case IE_ANI_WALK:
2119 strcat( ResRef, "g1" );
2120 Cycle = 16 + Orient / 2;
2121 break;
2122 case IE_ANI_READY:
2123 strcat( ResRef, "g1" );
2124 Cycle = 8 + Orient / 2;
2125 break;
2126 case IE_ANI_HEAD_TURN: //could be wrong
2127 case IE_ANI_AWAKE:
2128 strcat( ResRef, "g1" );
2129 Cycle = Orient / 2;
2130 break;
2131 case IE_ANI_DAMAGE:
2132 strcat( ResRef, "g3" );
2133 Cycle = 8 + Orient / 2;
2134 break;
2135 case IE_ANI_DIE:
2136 case IE_ANI_GET_UP:
2137 case IE_ANI_EMERGE:
2138 case IE_ANI_PST_START:
2139 case IE_ANI_SLEEP:
2140 strcat( ResRef, "g3" );
2141 Cycle = 16 + Orient / 2;
2142 break;
2143 case IE_ANI_TWITCH:
2144 strcat( ResRef, "g3" );
2145 Cycle = 24 + Orient / 2;
2146 break;
2147 default:
2148 printf("LR3 Animation: unhandled stance: %s %d\n", ResRef, StanceID);
2149 abort();
2150 break;
2152 if (Orient > 9) {
2153 strcat( ResRef, "e" );
2157 void CharAnimations::AddMMR2Suffix(char* ResRef, unsigned char StanceID,
2158 unsigned char& Cycle, unsigned char Orient)
2160 switch (StanceID) {
2161 case IE_ANI_ATTACK:
2162 case IE_ANI_ATTACK_SLASH:
2163 case IE_ANI_ATTACK_BACKSLASH:
2164 case IE_ANI_ATTACK_JAB:
2165 case IE_ANI_CONJURE:
2166 case IE_ANI_CAST:
2167 strcat( ResRef, "a1" );
2168 Cycle = ( Orient / 2 );
2169 break;
2171 case IE_ANI_SHOOT:
2172 strcat( ResRef, "a4" );
2173 Cycle = ( Orient / 2 );
2174 break;
2176 case IE_ANI_AWAKE:
2177 case IE_ANI_READY:
2178 strcat( ResRef, "sd" );
2179 Cycle = ( Orient / 2 );
2180 break;
2182 case IE_ANI_HEAD_TURN:
2183 strcat( ResRef, "sc" );
2184 Cycle = ( Orient / 2 );
2185 break;
2187 case IE_ANI_DAMAGE:
2188 strcat( ResRef, "gh" );
2189 Cycle = ( Orient / 2 );
2190 break;
2192 case IE_ANI_DIE:
2193 strcat( ResRef, "de" );
2194 Cycle = ( Orient / 2 );
2195 break;
2197 case IE_ANI_GET_UP:
2198 case IE_ANI_EMERGE:
2199 case IE_ANI_PST_START:
2200 strcat( ResRef, "gu" );
2201 Cycle = ( Orient / 2 );
2202 break;
2204 //Unknown... maybe only a transparency effect apply
2205 case IE_ANI_HIDE:
2206 break;
2208 case IE_ANI_SLEEP:
2209 strcat( ResRef, "sl" );
2210 Cycle = ( Orient / 2 );
2211 break;
2213 case IE_ANI_TWITCH:
2214 strcat( ResRef, "tw" );
2215 Cycle = ( Orient / 2 );
2216 break;
2218 case IE_ANI_WALK:
2219 strcat( ResRef, "wk" );
2220 Cycle = ( Orient / 2 );
2221 break;
2222 default:
2223 printf("MMR Animation: unhandled stance: %s %d\n", ResRef, StanceID);
2224 abort();
2225 break;
2227 if (Orient > 9) {
2228 strcat( ResRef, "e" );
2232 void CharAnimations::AddMMRSuffix(char* ResRef, unsigned char StanceID,
2233 unsigned char& Cycle, unsigned char Orient)
2235 switch (StanceID) {
2236 case IE_ANI_ATTACK:
2237 case IE_ANI_ATTACK_SLASH:
2238 case IE_ANI_ATTACK_BACKSLASH:
2239 strcat( ResRef, "a1" );
2240 Cycle = ( Orient / 2 );
2241 break;
2243 case IE_ANI_SHOOT:
2244 strcat( ResRef, "a4" );
2245 Cycle = ( Orient / 2 );
2246 break;
2248 case IE_ANI_ATTACK_JAB:
2249 strcat( ResRef, "a2" );
2250 Cycle = ( Orient / 2 );
2251 break;
2253 case IE_ANI_AWAKE:
2254 case IE_ANI_READY:
2255 strcat( ResRef, "sd" );
2256 Cycle = ( Orient / 2 );
2257 break;
2259 case IE_ANI_CONJURE:
2260 strcat( ResRef, "ca" );
2261 Cycle = ( Orient / 2 );
2262 break;
2264 case IE_ANI_CAST:
2265 strcat( ResRef, "sp" );
2266 Cycle = ( Orient / 2 );
2267 break;
2269 case IE_ANI_HEAD_TURN:
2270 strcat( ResRef, "sc" );
2271 Cycle = ( Orient / 2 );
2272 break;
2274 case IE_ANI_DAMAGE:
2275 strcat( ResRef, "gh" );
2276 Cycle = ( Orient / 2 );
2277 break;
2279 case IE_ANI_DIE:
2280 strcat( ResRef, "de" );
2281 Cycle = ( Orient / 2 );
2282 break;
2284 case IE_ANI_GET_UP:
2285 case IE_ANI_EMERGE:
2286 case IE_ANI_PST_START:
2287 strcat( ResRef, "gu" );
2288 Cycle = ( Orient / 2 );
2289 break;
2291 //Unknown... maybe only a transparency effect apply
2292 case IE_ANI_HIDE:
2293 break;
2295 case IE_ANI_SLEEP:
2296 strcat( ResRef, "sl" );
2297 Cycle = ( Orient / 2 );
2298 break;
2300 case IE_ANI_TWITCH:
2301 strcat( ResRef, "tw" );
2302 Cycle = ( Orient / 2 );
2303 break;
2305 case IE_ANI_WALK:
2306 strcat( ResRef, "wk" );
2307 Cycle = ( Orient / 2 );
2308 break;
2309 default:
2310 printf("MMR Animation: unhandled stance: %s %d\n", ResRef, StanceID);
2311 abort();
2312 break;
2314 if (Orient > 9) {
2315 strcat( ResRef, "e" );
2319 void CharAnimations::PulseRGBModifiers()
2321 unsigned long time = core->GetGame()->Ticks;
2323 if (time - lastModUpdate <= 40)
2324 return;
2326 if (time - lastModUpdate > 400) lastModUpdate = time - 40;
2328 int inc = (time - lastModUpdate)/40;
2329 bool change[4] = { false, false, false, false };
2330 if (GlobalColorMod.type != RGBModifier::NONE &&
2331 GlobalColorMod.speed > 0)
2333 GlobalColorMod.phase += inc;
2334 change[0] = change[1] = change[2] = change[3] = true;
2336 // reset if done
2337 if (GlobalColorMod.phase > 2*GlobalColorMod.speed) {
2338 GlobalColorMod.type = RGBModifier::NONE;
2339 GlobalColorMod.phase = 0;
2340 GlobalColorMod.speed = 0;
2344 for (int i = 0; i < 32; ++i) {
2345 if (ColorMods[i].type != RGBModifier::NONE &&
2346 ColorMods[i].speed > 0)
2348 ColorMods[i].phase += inc;
2349 change[i>>3] = true;
2353 if (change[0]) SetupColors(PAL_MAIN);
2354 if (change[1]) SetupColors(PAL_WEAPON);
2355 if (change[2]) SetupColors(PAL_OFFHAND);
2356 if (change[3]) SetupColors(PAL_HELMET);
2358 lastModUpdate += inc*40;