Control: Change controls to use new callback infrastrucure.
[gemrb.git] / gemrb / core / CharAnimations.cpp
blob158e49b4a08fb2494de06b4c988eefc952293835
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 char CharAnimations::GetSize() const
117 if (AvatarsRowNum==~0u) return 0;
118 return AvatarTable[AvatarsRowNum].Size;
121 int CharAnimations::GetActorPartCount() const
123 if (AvatarsRowNum==~0u) return -1;
124 switch (AvatarTable[AvatarsRowNum].AnimationType) {
125 case IE_ANI_NINE_FRAMES: //dragon animations
126 return 9;
127 case IE_ANI_FOUR_FRAMES: //wyvern animations
128 return 4;
129 case IE_ANI_PST_GHOST: //special pst anims
130 if (AvatarTable[AvatarsRowNum].Prefixes[1][0]=='*') {
131 return 1;
133 if (AvatarTable[AvatarsRowNum].Prefixes[2][0]=='*') {
134 return 2;
136 if (AvatarTable[AvatarsRowNum].Prefixes[3][0]=='*') {
137 return 3;
139 return 4;
140 default:
141 return 1;
145 int CharAnimations::GetTotalPartCount() const
147 if (AvatarsRowNum==~0u) return -1;
148 switch (AvatarTable[AvatarsRowNum].AnimationType) {
149 case IE_ANI_FOUR_FILES:
150 case IE_ANI_FOUR_FILES_2:
151 return GetActorPartCount() + 1; // only weapon
152 case IE_ANI_CODE_MIRROR:
153 return GetActorPartCount() + 3; // equipment
154 case IE_ANI_TWENTYTWO:
155 return GetActorPartCount() + 3; // equipment
156 default:
157 return GetActorPartCount();
161 void CharAnimations::SetArmourLevel(int ArmourLevel)
163 if (AvatarsRowNum==~0u) return;
164 //ignore ArmourLevel for the static pst anims (all sprites are displayed)
165 if (AvatarTable[AvatarsRowNum].AnimationType == IE_ANI_PST_GHOST) {
166 ArmourLevel = 0;
168 strncpy( ResRef, AvatarTable[AvatarsRowNum].Prefixes[ArmourLevel], 8 );
169 ResRef[8]=0;
170 DropAnims();
173 //RangedType could be weird, reducing its value to 0,1,2
174 void CharAnimations::SetRangedType(int rt)
176 if ((unsigned int) rt<2) {
177 RangedType=(ieByte) rt;
178 } else {
179 RangedType=2;
183 void CharAnimations::SetWeaponType(int wt)
185 if (wt != WeaponType) {
186 WeaponType = wt;
187 DropAnims();
191 void CharAnimations::SetHelmetRef(const char* ref)
193 HelmetRef[0] = ref[0];
194 HelmetRef[1] = ref[1];
196 // TODO: Only drop helmet anims?
197 // Note: this doesn't happen "often", so this isn't a performance
198 // bottleneck. (wjp)
199 DropAnims();
200 gamedata->FreePalette(palette[PAL_HELMET], 0);
201 gamedata->FreePalette(modifiedPalette[PAL_HELMET], 0);
204 void CharAnimations::SetWeaponRef(const char* ref)
206 WeaponRef[0] = ref[0];
207 WeaponRef[1] = ref[1];
209 // TODO: Only drop weapon anims?
210 DropAnims();
211 gamedata->FreePalette(palette[PAL_WEAPON], 0);
212 gamedata->FreePalette(modifiedPalette[PAL_WEAPON], 0);
215 void CharAnimations::SetOffhandRef(const char* ref)
217 OffhandRef[0] = ref[0];
218 OffhandRef[1] = ref[1];
220 // TODO: Only drop shield/offhand anims?
221 DropAnims();
222 gamedata->FreePalette(palette[PAL_OFFHAND], 0);
223 gamedata->FreePalette(modifiedPalette[PAL_OFFHAND], 0);
226 void CharAnimations::LockPalette(const ieDword *gradients)
228 if (lockPalette) return;
229 //cannot lock colors for PST animations
230 if (GetAnimType() >= IE_ANI_PST_ANIMATION_1)
232 return;
234 //force initialisation of animation
235 SetColors( gradients );
236 GetAnimation(0,0);
237 if (palette[PAL_MAIN]) {
238 lockPalette=true;
242 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
243 static const char *StancePrefix[]={"3","2","5","5","4","4","2","2","5","4","1","3","3","3","4","1","4","4","4"};
244 static const char *CyclePrefix[]= {"0","0","1","1","1","1","0","0","1","1","0","1","1","1","1","1","1","1","1"};
245 static const unsigned int CycleOffset[] = {0, 0, 0, 0, 0, 9, 0, 0, 0, 18, 0, 0, 9, 18, 0, 0, 0, 0, 0};
247 void CharAnimations::SetColors(const ieDword *arg)
249 Colors = arg;
250 SetupColors(PAL_MAIN);
251 SetupColors(PAL_WEAPON);
252 SetupColors(PAL_OFFHAND);
253 SetupColors(PAL_HELMET);
256 void CharAnimations::SetupColors(PaletteType type)
258 Palette* pal = palette[(int)type];
260 if (!pal) {
261 return;
264 if (!Colors) {
265 return;
268 if (GetAnimType() >= IE_ANI_PST_ANIMATION_1) {
269 // Only do main palette
270 if (type != PAL_MAIN) {
271 return;
273 // TODO: handle equipment colour glows
275 // Colors[6] is the COLORCOUNT stat in PST.
276 // It tells how many customisable color slots we have.
277 // The color slots start from the end of the palette and go
278 // backwards. There are 6 available slots with a size of 32 each.
279 // Actually, the slots seem to be written in the cre file
280 // but we ignore them, i'm not sure this is correct
281 int colorcount = Colors[6];
282 int size = 32;
283 //the color count shouldn't be more than 6!
284 if (colorcount>6) colorcount=6;
285 int dest = 256-colorcount*size;
286 bool needmod = false;
287 if (GlobalColorMod.type != RGBModifier::NONE) {
288 needmod = true;
290 if ((colorcount == 0) && (needmod==false) ) {
291 gamedata->FreePalette(palette[PAL_MAIN], PaletteResRef);
292 PaletteResRef[0]=0;
293 return;
295 for (int i = 0; i < colorcount; i++) {
296 core->GetPalette( Colors[i]&255, size,
297 &palette[PAL_MAIN]->col[dest] );
298 dest +=size;
301 if (needmod) {
302 if (!modifiedPalette[PAL_MAIN])
303 modifiedPalette[PAL_MAIN] = new Palette();
304 modifiedPalette[PAL_MAIN]->SetupGlobalRGBModification(palette[PAL_MAIN], GlobalColorMod);
305 } else {
306 gamedata->FreePalette(modifiedPalette[PAL_MAIN], 0);
308 return;
311 int PType = NoPalette();
312 if ( PType && (type == PAL_MAIN) ) {
313 bool needmod = false;
314 if (GlobalColorMod.type != RGBModifier::NONE) {
315 needmod = true;
317 if (!needmod && PaletteResRef[0]) {
318 gamedata->FreePalette(palette[PAL_MAIN], PaletteResRef);
320 PaletteResRef[0]=0;
321 //handling special palettes like MBER_BL (black bear)
322 if (PType!=1) {
323 if (GetAnimType()==IE_ANI_NINE_FRAMES) {
324 snprintf(PaletteResRef,9,"%.4s_%-.2s%s",ResRef, (char *) &PType, StancePrefix[StanceID]);
325 } else {
326 snprintf(PaletteResRef,9,"%.4s_%-.2s",ResRef, (char *) &PType);
328 strlwr(PaletteResRef);
329 Palette *tmppal = gamedata->GetPalette(PaletteResRef);
330 if (tmppal) {
331 palette[PAL_MAIN] = tmppal;
332 } else {
333 PaletteResRef[0]=0;
336 if (needmod) {
337 if (!modifiedPalette[PAL_MAIN])
338 modifiedPalette[PAL_MAIN] = new Palette();
339 modifiedPalette[PAL_MAIN]->SetupGlobalRGBModification(palette[PAL_MAIN], GlobalColorMod);
340 } else {
341 gamedata->FreePalette(modifiedPalette[PAL_MAIN], 0);
343 return;
346 pal->SetupPaperdollColours(Colors, (int)type);
347 if (lockPalette) {
348 return;
351 int i;
352 bool needmod = false;
353 if (GlobalColorMod.type != RGBModifier::NONE) {
354 needmod = true;
355 } else {
356 for (i = 0; i < 7; ++i) {
357 if (ColorMods[i+8*((int)type)].type != RGBModifier::NONE)
358 needmod = true;
363 if (needmod) {
364 if (!modifiedPalette[(int)type])
365 modifiedPalette[(int)type] = new Palette();
367 if (GlobalColorMod.type != RGBModifier::NONE) {
368 modifiedPalette[(int)type]->SetupGlobalRGBModification(palette[(int)type], GlobalColorMod);
369 } else {
370 modifiedPalette[(int)type]->SetupRGBModification(palette[(int)type],ColorMods, (int)type);
372 } else {
373 gamedata->FreePalette(modifiedPalette[(int)type], 0);
378 Palette* CharAnimations::GetPartPalette(int part)
380 int actorPartCount = GetActorPartCount();
381 PaletteType type = PAL_MAIN;
383 if (part == actorPartCount) type = PAL_WEAPON;
384 if (part == actorPartCount+1) type = PAL_OFFHAND;
385 if (part == actorPartCount+2) type = PAL_HELMET;
387 if (modifiedPalette[(int)type])
388 return modifiedPalette[(int)type];
390 return palette[(int)type];
393 static int compare_avatars(const void *a, const void *b)
395 unsigned int aa = ((AvatarStruct *)a)->AnimID;
396 unsigned int bb = ((AvatarStruct *)b)->AnimID;
398 if (aa>bb) return 1;
399 if (aa<bb) return -1;
400 return 0;
402 return (int) (aa-bb);
405 void CharAnimations::InitAvatarsTable()
407 AutoTable Avatars("avatars");
408 if (!Avatars) {
409 printMessage("CharAnimations", "A critical animation file is missing!\n", LIGHT_RED);
410 abort();
412 AvatarTable = (AvatarStruct *) calloc ( AvatarsCount = Avatars->GetRowCount(), sizeof(AvatarStruct) );
413 int i=AvatarsCount;
414 DataFileMgr *resdata = core->GetResDataINI();
415 while(i--) {
416 AvatarTable[i].AnimID=(unsigned int) strtol(Avatars->GetRowName(i),NULL,0 );
417 strnlwrcpy(AvatarTable[i].Prefixes[0],Avatars->QueryField(i,AV_PREFIX1),8);
418 strnlwrcpy(AvatarTable[i].Prefixes[1],Avatars->QueryField(i,AV_PREFIX2),8);
419 strnlwrcpy(AvatarTable[i].Prefixes[2],Avatars->QueryField(i,AV_PREFIX3),8);
420 strnlwrcpy(AvatarTable[i].Prefixes[3],Avatars->QueryField(i,AV_PREFIX4),8);
421 AvatarTable[i].AnimationType=(ieByte) atoi(Avatars->QueryField(i,AV_ANIMTYPE) );
422 AvatarTable[i].CircleSize=(ieByte) atoi(Avatars->QueryField(i,AV_CIRCLESIZE) );
423 const char *tmp = Avatars->QueryField(i,AV_USE_PALETTE);
424 //QueryField will always return a zero terminated string
425 //so tmp[0] must exist
426 if ( isalpha (tmp[0]) ) {
427 //this is a hack, we store 2 letters on an integer
428 //it was allocated with calloc, so don't bother erasing it
429 strncpy( (char *) &AvatarTable[i].PaletteType, tmp, 3);
431 else {
432 AvatarTable[i].PaletteType=atoi(Avatars->QueryField(i,AV_USE_PALETTE) );
434 AvatarTable[i].Size=Avatars->QueryField(i,AV_SIZE)[0];
436 AvatarTable[i].WalkScale = 0;
437 AvatarTable[i].RunScale = 0;
438 AvatarTable[i].Bestiary = -1;
440 if (resdata) {
441 char section[12];
442 snprintf(section,10,"%d", i);
444 if (!resdata->GetKeysCount(section)) continue;
446 float walkscale = resdata->GetKeyAsFloat(section, "walkscale", 0.0f);
447 if (walkscale != 0.0f) AvatarTable[i].WalkScale = (int)(1000.0f / walkscale);
448 float runscale = resdata->GetKeyAsFloat(section, "runscale", 0.0f);
449 if (runscale != 0.0f) AvatarTable[i].RunScale = (int)(1000.0f / runscale);
450 AvatarTable[i].Bestiary = resdata->GetKeyAsInt(section, "bestiary", -1);
453 qsort(AvatarTable, AvatarsCount, sizeof(AvatarStruct), compare_avatars);
456 CharAnimations::CharAnimations(unsigned int AnimID, ieDword ArmourLevel)
458 Colors = NULL;
459 int i,j;
460 for (i = 0; i < 4; ++i) {
461 modifiedPalette[i] = NULL;
462 palette[i] = NULL;
464 nextStanceID = 0;
465 StanceID = 0;
466 autoSwitchOnEnd = false;
467 lockPalette = false;
468 if (!AvatarsCount) {
469 InitAvatarsTable();
472 for (i = 0; i < MAX_ANIMS; i++) {
473 for (j = 0; j < MAX_ORIENT; j++) {
474 Anims[i][j] = NULL;
477 ArmorType = 0;
478 RangedType = 0;
479 WeaponType = 0;
480 PaletteResRef[0] = 0;
481 WeaponRef[0] = 0;
482 HelmetRef[0] = 0;
483 OffhandRef[0] = 0;
484 for (i = 0; i < 32; ++i) {
485 ColorMods[i].type = RGBModifier::NONE;
486 ColorMods[i].speed = 0;
487 // make initial phase depend on location to make the pulse appear
488 // less even
489 ColorMods[i].phase = 5*i;
491 GlobalColorMod.type = RGBModifier::NONE;
492 GlobalColorMod.speed = 0;
493 GlobalColorMod.phase = 0;
494 lastModUpdate = 0;
497 AvatarsRowNum=AvatarsCount;
498 if (core->HasFeature(GF_ONE_BYTE_ANIMID) ) {
499 ieDword tmp = AnimID&0xf000;
500 if (tmp==0x6000 || tmp==0xe000) {
501 AnimID&=0xff;
505 while (AvatarsRowNum--) {
506 if (AvatarTable[AvatarsRowNum].AnimID<=AnimID) {
507 SetArmourLevel( ArmourLevel );
508 return;
511 ResRef[0]=0;
512 printMessage("CharAnimations", " ", LIGHT_RED);
513 printf("Invalid or nonexistent avatar entry:%04X\n", AnimID);
516 //we have to drop them when armourlevel changes
517 void CharAnimations::DropAnims()
519 Animation** tmppoi;
520 int partCount = GetTotalPartCount();
521 for (int StanceID = 0; StanceID < MAX_ANIMS; StanceID++) {
522 for (int i = 0; i < MAX_ORIENT; i++) {
523 if (Anims[StanceID][i]) {
524 tmppoi = Anims[StanceID][i];
525 for (int j = 0; j < partCount; j++)
526 delete Anims[StanceID][i][j];
527 delete[] tmppoi;
529 // anims can only be duplicated at the Animation** level
530 for (int IDb=StanceID;IDb < MAX_ANIMS; IDb++) {
531 for (int i2 = 0; i2<MAX_ORIENT; i2++) {
532 if (Anims[IDb][i2] == tmppoi) {
533 Anims[IDb][i2] = 0;
542 CharAnimations::~CharAnimations(void)
544 DropAnims();
545 gamedata->FreePalette(palette[PAL_MAIN], PaletteResRef);
546 int i;
547 for (i = 1; i < 4; ++i)
548 gamedata->FreePalette(palette[i], 0);
549 for (i = 0; i < 4; ++i)
550 gamedata->FreePalette(modifiedPalette[i], 0);
553 This is a simple Idea of how the animation are coded
555 There are the following animation types:
557 IE_ANI_CODE_MIRROR: The code automatically mirrors the needed frames
558 (as in the example above)
560 These Animations are stores using the following template:
561 [NAME][ARMORTYPE][ACTIONCODE]
563 Each BAM File contains only 9 Orientations, the missing 7 Animations
564 are created by Horizontally Mirroring the 1-7 Orientations.
566 IE_ANI_CODE_MIRROR_2: another mirroring type with more animations
567 [NAME]g[1,11-15,2,21-26]
569 IE_ANI_CODE_MIRROR_3: Almost identical to IE_ANI_CODE_MIRROR_2, but with fewer cycles in g26
571 IE_ANI_ONE_FILE: The whole animation is in one file, no mirroring needed.
572 Each animation group is 16 Cycles.
574 IE_ANI_TWO_FILES: The whole animation is in 2 files. The East and West part are in 2 BAM Files.
575 Example:
576 ACHKg1
577 ACHKg1E
579 Each BAM File contains many animation groups, each animation group
580 stores 5 Orientations, the missing 3 are stored in East BAM Files.
583 IE_ANI_FOUR_FILES: The Animation is coded in Four Files. Probably it is an old Two File animation with
584 additional frames added in a second time.
586 IE_ANI_FOUR_FILES_2: Like IE_ANI_FOUR_FILES but with only 16 cycles per frame.
588 IE_ANI_TWENTYTWO: This Animation Type stores the Animation in the following format
589 [NAME][ACTIONCODE][/E]
590 ACTIONCODE=A1-6, CA, SX, SA (sling is A1)
591 The g1 file contains several animation states. See MHR
592 Probably it could use A7-9 files too, bringing the file numbers to 28.
593 This is the original bg1 format.
595 IE_ANI_SIX_FILES: The layout for these files is:
596 [NAME][g1-3][/E]
597 Each state contains 16 Orientations, but the last 6 are stored in the East file.
598 g1 contains only the walking animation.
599 G2 contains stand, ready, get hit, die and twitch.
600 g3 contains 3 attacks.
602 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
604 IE_ANI_TWO_FILES_2: Animations using this type are stored using the following template:
605 [NAME]g1[/E]
606 Each state contains 8 Orientations, but the second 4 are stored in the East file.
607 From the standard animations, only AHRS and ACOW belong to this type.
609 IE_ANI_TWO_FILES_3: Animations using this type are stored using the following template:
610 [NAME][ACTIONTYPE][/E]
612 Example:
613 MBFI*
614 MBFI*E
616 Each BAM File contains one animation group, each animation group
617 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).
618 This is the standard IWD animation, but BG2 also has it.
619 See MMR
621 IE_ANI_TWO_FILES_3B: Animations using this type are stored using the following template:
622 [NAME][ACTIONTYPE][/E]
624 Example:
625 MBFI*
626 MBFI*E
628 This is a cut down version of IE_ANI_TWO_FILES_3. A2, CA and SP suffixes are missing.
629 This is the standard IWD animation, but BG2 also has it.
630 See MOR2
632 IE_ANI_FOUR_FRAMES: These animations are large, four bams make a frame.
635 IE_ANI_NINE_FRAMES: These animations are huge, nine bams make a frame.
638 IE_ANI_FRAGMENT: These animations are used for projectile graphics.
639 A single file contains 5 cycles (code mirror for east animation)
641 IE_ANI_PST_ANIMATION_1:
642 IE_ANI_PST_ANIMATION_2:
643 IE_ANI_PST_ANIMATION_3:
644 Planescape: Torment Animations are stored in a different
645 way than the other games. This format uses the following template:
646 [C/D][ACTIONTYPE][NAME][B]
648 Example:
649 CAT1MRTB
651 Each Animation stores 5 Orientations, which are automatically mirrored
652 to form an 8 Orientation Animation. PST Animations have a different Palette
653 format. This Animation Type handles the PST Palette format too.
655 NOTE: Walking/Running animations store 9 Orientations.
656 The second variation is missing the resting stance (STD) and the transitions.
657 These creatures are always in combat stance (don't rest).
658 Animation_3 is without STC (combat stance), they are always standing
660 IE_ANI_PST_STAND: This is a modified PST animation, it contains only a
661 Standing image for every orientations, it follows the
662 [C/D]STD[NAME][B] standard.
664 IE_ANI_PST_GHOST: This is a special static animation with no standard
665 All armourlevels are drawn simultaneously. There is no orientation or stance.
668 WEST PART | EAST PART
670 NW NNW N NNE NE
671 NW 006 007 008 009 010 NE
672 WNW 005 | 011 ENE
673 W 004 xxx 012 E
674 WSW 003 | 013 ESE
675 SW 002 001 000 015 014 SE
676 SW SSW S SSE SE
682 Animation** CharAnimations::GetAnimation(unsigned char Stance, unsigned char Orient)
684 if (StanceID>=MAX_ANIMS) {
685 printf("Illegal stance ID\n");
686 abort();
689 //for paletted dragon animations, we need the stance id
690 StanceID = nextStanceID = Stance;
691 int AnimType = GetAnimType();
693 //alter stance here if it is missing and you know a substitute
694 //probably we should feed this result back to the actor?
695 switch (AnimType) {
696 case -1: //invalid animation
697 return NULL;
699 case IE_ANI_PST_STAND:
700 StanceID=IE_ANI_AWAKE;
701 break;
702 case IE_ANI_PST_GHOST:
703 StanceID=IE_ANI_AWAKE;
704 Orient=0;
705 break;
706 case IE_ANI_PST_ANIMATION_3: //stc->std
707 if (StanceID==IE_ANI_READY) {
708 StanceID=IE_ANI_AWAKE;
710 break;
711 case IE_ANI_PST_ANIMATION_2: //std->stc
712 if (StanceID==IE_ANI_AWAKE) {
713 StanceID=IE_ANI_READY;
715 break;
717 //pst animations don't have separate animation for sleep/die
718 if (AnimType >= IE_ANI_PST_ANIMATION_1) {
719 if (StanceID==IE_ANI_DIE) {
720 StanceID=IE_ANI_TWITCH;
724 //TODO: Implement Auto Resource Loading
725 //setting up the sequencing of animation cycles
726 autoSwitchOnEnd = false;
727 switch (StanceID) {
728 case IE_ANI_DAMAGE:
729 nextStanceID = IE_ANI_READY;
730 autoSwitchOnEnd = true;
731 break;
732 case IE_ANI_SLEEP: //going to sleep
733 nextStanceID = IE_ANI_TWITCH;
734 autoSwitchOnEnd = true;
735 break;
736 case IE_ANI_TWITCH: //dead, sleeping
737 autoSwitchOnEnd = false;
738 break;
739 case IE_ANI_DIE: //going to die
740 nextStanceID = IE_ANI_TWITCH;
741 autoSwitchOnEnd = true;
742 break;
743 case IE_ANI_WALK:
744 case IE_ANI_RUN:
745 case IE_ANI_CAST: // looping
746 case IE_ANI_READY:
747 break;
748 case IE_ANI_AWAKE:
749 break;
750 case IE_ANI_EMERGE:
751 case IE_ANI_GET_UP:
752 case IE_ANI_HEAD_TURN:
753 case IE_ANI_PST_START:
754 nextStanceID = IE_ANI_AWAKE;
755 autoSwitchOnEnd = true;
756 break;
757 case IE_ANI_CONJURE: //ending
758 case IE_ANI_SHOOT:
759 case IE_ANI_ATTACK:
760 case IE_ANI_ATTACK_JAB:
761 case IE_ANI_ATTACK_SLASH:
762 case IE_ANI_ATTACK_BACKSLASH:
763 nextStanceID = IE_ANI_READY;
764 autoSwitchOnEnd = true;
765 break;
766 default:
767 printf ("Invalid Stance: %d\n", StanceID);
768 break;
770 Animation** anims = Anims[StanceID][Orient];
772 if (anims) {
773 return anims;
776 int partCount = GetTotalPartCount();
777 int actorPartCount = GetActorPartCount();
778 if (partCount < 0) return 0;
779 anims = new Animation*[partCount];
781 EquipResRefData* equipdat = 0;
782 for (int part = 0; part < partCount; ++part)
784 anims[part] = 0;
786 //newresref is based on the prefix (ResRef) and various
787 // other things.
788 //this is longer than expected so it won't overflow
789 char NewResRef[12];
790 unsigned char Cycle = 0;
791 if (part < actorPartCount) {
792 // Character animation parts
794 if (equipdat) delete equipdat;
796 //we need this long for special anims
797 strncpy( NewResRef, ResRef, 8 );
798 GetAnimResRef( StanceID, Orient, NewResRef, Cycle, part, equipdat);
799 } else {
800 // Equipment animation parts
802 anims[part] = 0;
803 if (GetSize() == '*' || GetSize() == 0) continue;
805 if (part == actorPartCount) {
806 if (WeaponRef[0] == 0) continue;
807 // weapon
808 GetEquipmentResRef(WeaponRef,false,NewResRef,Cycle,equipdat);
809 } else if (part == actorPartCount+1) {
810 if (OffhandRef[0] == 0) continue;
811 if (WeaponType == IE_ANI_WEAPON_2H) continue;
812 // off-hand
813 if (WeaponType == IE_ANI_WEAPON_1H) {
814 GetEquipmentResRef(OffhandRef,false,NewResRef,Cycle,
815 equipdat);
816 } else { // IE_ANI_WEAPON_2W
817 GetEquipmentResRef(OffhandRef,true,NewResRef,Cycle,
818 equipdat);
820 } else if (part == actorPartCount+2) {
821 if (HelmetRef[0] == 0) continue;
822 // helmet
823 GetEquipmentResRef(HelmetRef,false,NewResRef,Cycle,equipdat);
826 NewResRef[8]=0; //cutting right to size
828 AnimationFactory* af = ( AnimationFactory* )
829 gamedata->GetFactoryResource( NewResRef,
830 IE_BAM_CLASS_ID, IE_NORMAL );
832 if (!af) {
833 if (part < actorPartCount) {
834 char warnbuf[200];
835 snprintf(warnbuf, 200,
836 "Couldn't create animationfactory: %s (%04x)\n", NewResRef, GetAnimationID());
837 printMessage("CharAnimations",warnbuf,LIGHT_RED);
838 for (int i = 0; i < part; ++i)
839 delete anims[i];
840 delete[] anims;
841 delete equipdat;
842 return 0;
843 } else {
844 // not fatal if animation for equipment is missing
845 continue;
849 Animation* a = af->GetCycle( Cycle );
850 anims[part] = a;
852 if (!a) {
853 if (part < actorPartCount) {
854 char warnbuf[200];
855 snprintf(warnbuf, 200,
856 "Couldn't load animation: %s, cycle %d\n",
857 NewResRef, Cycle);
858 printMessage("CharAnimations",warnbuf,LIGHT_RED);
859 for (int i = 0; i < part; ++i)
860 delete anims[i];
861 delete[] anims;
862 delete equipdat;
863 return 0;
864 } else {
865 // not fatal if animation for equipment is missing
866 continue;
870 if (part < actorPartCount) {
871 //if you need to revert this change, consider true paletted
872 //animations which need a GlobalColorMod (mgir for example)
874 //if (!palette[PAL_MAIN] && ((GlobalColorMod.type!=RGBModifier::NONE) || (NoPalette()!=1)) ) {
875 if(!palette[PAL_MAIN]) {
876 // This is the first time we're loading an Animation.
877 // We copy the palette of its first frame into our own palette
878 palette[PAL_MAIN] = a->GetFrame(0)->GetPalette()->Copy();
879 // ...and setup the colours properly
880 SetupColors(PAL_MAIN);
882 } else if (part == actorPartCount) {
883 if (!palette[PAL_WEAPON]) {
884 palette[PAL_WEAPON] = a->GetFrame(0)->GetPalette()->Copy();
885 SetupColors(PAL_WEAPON);
887 } else if (part == actorPartCount+1) {
888 if (!palette[PAL_OFFHAND]) {
889 palette[PAL_OFFHAND] = a->GetFrame(0)->GetPalette()->Copy();
890 SetupColors(PAL_OFFHAND);
892 } else if (part == actorPartCount+2) {
893 if (!palette[PAL_HELMET]) {
894 palette[PAL_HELMET] = a->GetFrame(0)->GetPalette()->Copy();
895 SetupColors(PAL_HELMET);
899 //animation is affected by game flags
900 a->gameAnimation = true;
901 a->SetPos( 0 );
903 //setting up the sequencing of animation cycles
904 switch (StanceID) {
905 case IE_ANI_DAMAGE:
906 case IE_ANI_SLEEP:
907 case IE_ANI_TWITCH:
908 case IE_ANI_DIE:
909 case IE_ANI_PST_START:
910 case IE_ANI_HEAD_TURN:
911 case IE_ANI_CONJURE:
912 case IE_ANI_SHOOT:
913 case IE_ANI_ATTACK:
914 case IE_ANI_ATTACK_JAB:
915 case IE_ANI_ATTACK_SLASH:
916 case IE_ANI_ATTACK_BACKSLASH:
917 a->Flags |= A_ANI_PLAYONCE;
918 break;
919 case IE_ANI_EMERGE:
920 case IE_ANI_GET_UP:
921 a->playReversed = true;
922 a->Flags |= A_ANI_PLAYONCE;
923 break;
925 switch (GetAnimType()) {
926 case IE_ANI_NINE_FRAMES: //dragon animations
927 case IE_ANI_FOUR_FRAMES: //wyvern animations
928 case IE_ANI_BIRD:
929 case IE_ANI_CODE_MIRROR:
930 case IE_ANI_CODE_MIRROR_2: //9 orientations
931 case IE_ANI_CODE_MIRROR_3:
932 case IE_ANI_PST_ANIMATION_3: //no stc just std
933 case IE_ANI_PST_ANIMATION_2: //no std just stc
934 case IE_ANI_PST_ANIMATION_1:
935 case IE_ANI_FRAGMENT:
936 if (Orient > 8) {
937 a->MirrorAnimation( );
939 break;
940 default:
941 break;
944 // make animarea of part 0 encompass the animarea of the other parts
945 if (part > 0)
946 anims[0]->AddAnimArea(a);
950 switch (GetAnimType()) {
951 case IE_ANI_NINE_FRAMES: //dragon animations
952 case IE_ANI_FOUR_FRAMES: //wyvern animations
953 case IE_ANI_BIRD:
954 case IE_ANI_CODE_MIRROR:
955 case IE_ANI_SIX_FILES: //16 anims some are stored elsewhere
956 case IE_ANI_ONE_FILE: //16 orientations
957 case IE_ANI_CODE_MIRROR_2: //9 orientations
958 case IE_ANI_CODE_MIRROR_3:
959 Anims[StanceID][Orient] = anims;
960 break;
961 case IE_ANI_TWO_FILES:
962 case IE_ANI_TWENTYTWO:
963 case IE_ANI_TWO_FILES_2:
964 case IE_ANI_TWO_FILES_3:
965 case IE_ANI_TWO_FILES_3B:
966 case IE_ANI_FOUR_FILES:
967 case IE_ANI_FOUR_FILES_2:
968 case IE_ANI_SIX_FILES_2:
969 case IE_ANI_FRAGMENT:
970 Orient&=~1;
971 Anims[StanceID][Orient] = anims;
972 Anims[StanceID][Orient + 1] = anims;
973 break;
975 case IE_ANI_PST_ANIMATION_3: //no stc just std
976 case IE_ANI_PST_ANIMATION_2: //no std just stc
977 case IE_ANI_PST_ANIMATION_1:
978 switch (StanceID) {
979 case IE_ANI_WALK:
980 case IE_ANI_RUN:
981 case IE_ANI_PST_START:
982 Anims[StanceID][Orient] = anims;
983 break;
984 default:
985 Orient &=~1;
986 Anims[StanceID][Orient] = anims;
987 Anims[StanceID][Orient + 1] = anims;
988 break;
990 break;
992 case IE_ANI_PST_STAND:
993 Orient &=~1;
994 Anims[StanceID][Orient] = anims;
995 Anims[StanceID][Orient+1] = anims;
996 break;
997 case IE_ANI_PST_GHOST:
998 Orient = 0;
999 StanceID = IE_ANI_AWAKE;
1000 Anims[StanceID][0] = anims;
1001 break;
1002 default:
1003 printMessage("CharAnimations","Unknown animation type\n",LIGHT_RED);
1004 abort();
1006 delete equipdat;
1008 return Anims[StanceID][Orient];
1011 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};
1013 void CharAnimations::GetAnimResRef(unsigned char StanceID,
1014 unsigned char Orient,
1015 char* NewResRef, unsigned char& Cycle,
1016 int Part, EquipResRefData*& EquipData)
1018 char tmp[256];
1019 EquipData = 0;
1020 Orient &= 15;
1021 switch (GetAnimType()) {
1022 case IE_ANI_FOUR_FRAMES:
1023 AddFFSuffix( NewResRef, StanceID, Cycle, Orient, Part );
1024 break;
1026 case IE_ANI_NINE_FRAMES:
1027 AddNFSuffix( NewResRef, StanceID, Cycle, Orient, Part );
1028 break;
1030 case IE_ANI_CODE_MIRROR:
1031 AddVHRSuffix( NewResRef, StanceID, Cycle, Orient, EquipData );
1032 break;
1034 case IE_ANI_BIRD:
1035 Cycle = (ieByte) ((StanceID&1) * 9 + SixteenToNine[Orient]);
1036 break;
1038 case IE_ANI_FRAGMENT:
1039 Cycle = SixteenToFive[Orient];
1040 break;
1042 case IE_ANI_ONE_FILE:
1043 Cycle = (ieByte) (one_file[StanceID] * 16 + Orient);
1044 break;
1046 case IE_ANI_SIX_FILES:
1047 AddSixSuffix( NewResRef, StanceID, Cycle, Orient );
1048 break;
1050 case IE_ANI_TWENTYTWO: //5+3 animations
1051 AddMHRSuffix( NewResRef, StanceID, Cycle, Orient, EquipData );
1052 break;
1054 case IE_ANI_TWO_FILES_2: //4+4 animations
1055 AddLR2Suffix( NewResRef, StanceID, Cycle, Orient );
1056 break;
1058 case IE_ANI_TWO_FILES_3: //IWD style anims
1059 AddMMRSuffix( NewResRef, StanceID, Cycle, Orient );
1060 break;
1062 case IE_ANI_TWO_FILES_3B: //IWD style anims
1063 AddMMR2Suffix( NewResRef, StanceID, Cycle, Orient );
1064 break;
1066 case IE_ANI_TWO_FILES:
1067 AddTwoFileSuffix(NewResRef, StanceID, Cycle, Orient );
1068 break;
1070 case IE_ANI_FOUR_FILES:
1071 AddLRSuffix( NewResRef, StanceID, Cycle, Orient, EquipData );
1072 break;
1074 case IE_ANI_FOUR_FILES_2:
1075 AddLRSuffix2( NewResRef, StanceID, Cycle, Orient, EquipData );
1076 break;
1078 case IE_ANI_SIX_FILES_2: //MOGR (variant of FOUR_FILES)
1079 AddLR3Suffix( NewResRef, StanceID, Cycle, Orient );
1080 break;
1082 case IE_ANI_CODE_MIRROR_2: //9 orientations
1083 AddVHR2Suffix( NewResRef, StanceID, Cycle, Orient );
1084 break;
1086 case IE_ANI_CODE_MIRROR_3: // like IE_ANI_CODE_MIRROR_2 but with fewer cycles in g26
1087 AddVHR3Suffix( NewResRef, StanceID, Cycle, Orient );
1088 break;
1090 case IE_ANI_PST_ANIMATION_1:
1091 case IE_ANI_PST_ANIMATION_2:
1092 case IE_ANI_PST_ANIMATION_3:
1093 AddPSTSuffix( NewResRef, StanceID, Cycle, Orient );
1094 break;
1096 case IE_ANI_PST_STAND:
1097 sprintf(NewResRef,"%cSTD%4s",ResRef[0], ResRef+1);
1098 Cycle = (ieByte) SixteenToFive[Orient];
1099 break;
1100 case IE_ANI_PST_GHOST: // pst static animations
1101 //still doesn't handle the second cycle of the golem anim
1102 Cycle = 0;
1103 strnlwrcpy(NewResRef, AvatarTable[AvatarsRowNum].Prefixes[Part], 8);
1104 break;
1105 default:
1106 sprintf (tmp,"Unknown animation type in avatars.2da row: %d\n", AvatarsRowNum);
1107 printMessage ("CharAnimations",tmp, LIGHT_RED);
1108 abort();
1112 void CharAnimations::GetEquipmentResRef(const char* equipRef, bool offhand,
1113 char* ResRef, unsigned char& Cycle, EquipResRefData* equip)
1115 switch (GetAnimType()) {
1116 case IE_ANI_FOUR_FILES:
1117 case IE_ANI_FOUR_FILES_2:
1118 GetLREquipmentRef( ResRef, Cycle, equipRef, offhand, equip );
1119 break;
1120 case IE_ANI_CODE_MIRROR:
1121 GetVHREquipmentRef( ResRef, Cycle, equipRef, offhand, equip );
1122 break;
1123 case IE_ANI_TWENTYTWO:
1124 GetMHREquipmentRef( ResRef, Cycle, equipRef, offhand, equip );
1125 break;
1126 default:
1127 printMessage ("CharAnimations", "Unsupported animation type for equipment animation.\n", LIGHT_RED);
1128 abort();
1129 break;
1133 const int* CharAnimations::GetZOrder(unsigned char Orient)
1135 switch (GetAnimType()) {
1136 case IE_ANI_CODE_MIRROR:
1137 return zOrder_Mirror16[Orient];
1138 case IE_ANI_TWENTYTWO:
1139 return zOrder_8[Orient/2];
1140 case IE_ANI_FOUR_FILES:
1141 return 0; // FIXME
1142 default:
1143 return 0;
1148 void CharAnimations::AddPSTSuffix(char* ResRef, unsigned char StanceID,
1149 unsigned char& Cycle, unsigned char Orient)
1151 const char *Prefix;
1153 switch (StanceID) {
1154 case IE_ANI_ATTACK:
1155 case IE_ANI_ATTACK_SLASH:
1156 case IE_ANI_ATTACK_JAB:
1157 case IE_ANI_ATTACK_BACKSLASH:
1158 Cycle=SixteenToFive[Orient];
1159 Prefix="at1"; break;
1160 case IE_ANI_DAMAGE:
1161 Cycle=SixteenToFive[Orient];
1162 Prefix="hit"; break;
1163 case IE_ANI_GET_UP:
1164 case IE_ANI_EMERGE:
1165 Cycle=SixteenToFive[Orient];
1166 Prefix="gup"; break;
1167 case IE_ANI_AWAKE:
1168 Cycle=SixteenToFive[Orient];
1169 Prefix="std"; break;
1170 case IE_ANI_READY:
1171 Cycle=SixteenToFive[Orient];
1172 Prefix="stc"; break;
1173 case IE_ANI_DIE:
1174 case IE_ANI_SLEEP:
1175 case IE_ANI_TWITCH:
1176 Cycle=SixteenToFive[Orient];
1177 Prefix="dfb"; break;
1178 case IE_ANI_RUN:
1179 Cycle=SixteenToNine[Orient];
1180 Prefix="run"; break;
1181 case IE_ANI_WALK:
1182 Cycle=SixteenToNine[Orient];
1183 Prefix="wlk"; break;
1184 case IE_ANI_HEAD_TURN:
1185 Cycle=SixteenToFive[Orient];
1186 if (rand()&1) {
1187 Prefix="sf2";
1188 sprintf(ResRef,"%c%3s%4s",this->ResRef[0], Prefix, this->ResRef+1);
1189 if (gamedata->Exists(ResRef, IE_BAM_CLASS_ID) ) {
1190 return;
1193 Prefix="sf1";
1194 sprintf(ResRef,"%c%3s%4s",this->ResRef[0], Prefix, this->ResRef+1);
1195 if (gamedata->Exists(ResRef, IE_BAM_CLASS_ID) ) {
1196 return;
1198 Prefix = "stc";
1199 break;
1200 case IE_ANI_PST_START:
1201 Cycle=0;
1202 Prefix="ms1"; break;
1203 default: //just in case
1204 Cycle=SixteenToFive[Orient];
1205 Prefix="stc"; break;
1207 sprintf(ResRef,"%c%3s%4s",this->ResRef[0], Prefix, this->ResRef+1);
1210 void CharAnimations::AddVHR2Suffix(char* ResRef, unsigned char StanceID,
1211 unsigned char& Cycle, unsigned char Orient)
1213 Cycle=SixteenToNine[Orient];
1215 switch (StanceID) {
1216 case IE_ANI_ATTACK: //temporarily
1217 case IE_ANI_ATTACK_BACKSLASH:
1218 strcat( ResRef, "g21" );
1219 break;
1221 case IE_ANI_ATTACK_SLASH:
1222 strcat( ResRef, "g2" );
1223 break;
1225 case IE_ANI_ATTACK_JAB:
1226 strcat( ResRef, "g26" );
1227 Cycle+=45;
1228 break;
1230 case IE_ANI_CAST: //looping
1231 strcat( ResRef, "g25" );
1232 Cycle+=45;
1233 break;
1235 case IE_ANI_CONJURE://ending
1236 strcat( ResRef, "g26" );
1237 Cycle+=54;
1238 break;
1240 case IE_ANI_SHOOT:
1241 strcat( ResRef, "g24" );
1242 Cycle+=27;
1243 break;
1245 case IE_ANI_HEAD_TURN:
1246 case IE_ANI_AWAKE:
1247 strcat( ResRef, "g12" );
1248 Cycle+=18;
1249 break;
1251 case IE_ANI_SLEEP:
1252 strcat( ResRef, "g15" );
1253 Cycle+=45;
1254 break;
1256 case IE_ANI_TWITCH:
1257 strcat( ResRef, "g14" );
1258 Cycle+=45;
1259 break;
1261 case IE_ANI_DIE:
1262 case IE_ANI_EMERGE:
1263 case IE_ANI_GET_UP:
1264 case IE_ANI_PST_START:
1265 strcat( ResRef, "g14" );
1266 Cycle+=36;
1267 break;
1269 case IE_ANI_DAMAGE:
1270 strcat( ResRef, "g13" );
1271 Cycle+=27;
1272 break;
1274 case IE_ANI_READY:
1275 strcat( ResRef, "g1" );
1276 Cycle+=9;
1277 break;
1279 case IE_ANI_WALK:
1280 strcat( ResRef, "g11" );
1281 break;
1282 default:
1283 printf("VHR2 Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1284 abort();
1285 break;
1289 void CharAnimations::AddVHR3Suffix(char* ResRef, unsigned char StanceID,
1290 unsigned char& Cycle, unsigned char Orient)
1292 Cycle=SixteenToNine[Orient];
1294 switch (StanceID) {
1295 case IE_ANI_ATTACK: //temporarily
1296 case IE_ANI_ATTACK_BACKSLASH:
1297 strcat( ResRef, "g21" );
1298 break;
1300 case IE_ANI_ATTACK_SLASH:
1301 strcat( ResRef, "g2" );
1302 break;
1304 case IE_ANI_ATTACK_JAB:
1305 strcat( ResRef, "g26" );
1306 Cycle+=18;
1307 break;
1309 case IE_ANI_CAST: //looping
1310 strcat( ResRef, "g25" );
1311 Cycle+=45;
1312 break;
1314 case IE_ANI_CONJURE://ending
1315 strcat( ResRef, "g26" );
1316 Cycle+=36;
1317 break;
1319 case IE_ANI_SHOOT:
1320 strcat( ResRef, "g24" );
1321 Cycle+=27;
1322 break;
1324 case IE_ANI_HEAD_TURN:
1325 case IE_ANI_AWAKE:
1326 strcat( ResRef, "g12" );
1327 Cycle+=18;
1328 break;
1330 case IE_ANI_SLEEP:
1331 strcat( ResRef, "g15" );
1332 Cycle+=45;
1333 break;
1335 case IE_ANI_TWITCH:
1336 strcat( ResRef, "g14" );
1337 Cycle+=45;
1338 break;
1340 case IE_ANI_DIE:
1341 case IE_ANI_EMERGE:
1342 case IE_ANI_GET_UP:
1343 case IE_ANI_PST_START:
1344 strcat( ResRef, "g14" );
1345 Cycle+=36;
1346 break;
1348 case IE_ANI_DAMAGE:
1349 strcat( ResRef, "g13" );
1350 Cycle+=27;
1351 break;
1353 case IE_ANI_READY:
1354 strcat( ResRef, "g1" );
1355 Cycle+=9;
1356 break;
1358 case IE_ANI_WALK:
1359 strcat( ResRef, "g11" );
1360 break;
1361 default:
1362 printf("VHR3 Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1363 abort();
1364 break;
1368 // Note: almost like SixSuffix
1369 void CharAnimations::AddFFSuffix(char* ResRef, unsigned char StanceID,
1370 unsigned char& Cycle, unsigned char Orient, int Part)
1372 Cycle=SixteenToNine[Orient];
1373 switch (StanceID) {
1374 case IE_ANI_WALK:
1375 strcat( ResRef, "g1" );
1376 break;
1378 case IE_ANI_ATTACK:
1379 case IE_ANI_ATTACK_SLASH:
1380 strcat( ResRef, "g3" );
1381 break;
1383 case IE_ANI_ATTACK_BACKSLASH:
1384 strcat( ResRef, "g3" );
1385 Cycle += 16;
1386 break;
1388 case IE_ANI_ATTACK_JAB:
1389 case IE_ANI_CAST:
1390 case IE_ANI_CONJURE:
1391 strcat( ResRef, "g3" );
1392 Cycle += 32;
1393 break;
1395 case IE_ANI_HEAD_TURN: //could be wrong
1396 case IE_ANI_AWAKE:
1397 strcat( ResRef, "g2" );
1398 break;
1400 case IE_ANI_READY:
1401 strcat( ResRef, "g2" );
1402 Cycle += 16;
1403 break;
1405 case IE_ANI_DAMAGE:
1406 strcat( ResRef, "g2" );
1407 Cycle += 32;
1408 break;
1410 case IE_ANI_DIE:
1411 case IE_ANI_GET_UP:
1412 case IE_ANI_EMERGE:
1413 case IE_ANI_PST_START:
1414 strcat( ResRef, "g2" );
1415 Cycle += 48;
1416 break;
1418 case IE_ANI_TWITCH:
1419 strcat( ResRef, "g2" );
1420 Cycle += 64;
1421 break;
1423 default:
1424 printf("Four frames Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1425 abort();
1426 break;
1429 ResRef[6]=(char) (Part+'1');
1430 ResRef[7]=0;
1433 void CharAnimations::AddNFSuffix(char* ResRef, unsigned char StanceID,
1434 unsigned char& Cycle, unsigned char Orient, int Part)
1436 char prefix[10];
1438 Cycle = SixteenToNine[Orient];
1439 snprintf(prefix, 9, "%s%s%d%s%d", ResRef, StancePrefix[StanceID], Part+1,
1440 CyclePrefix[StanceID], Cycle);
1441 strnlwrcpy(ResRef,prefix,8);
1442 Cycle=(ieByte) (Cycle+CycleOffset[StanceID]);
1445 //Attack
1446 //h1, h2, w2
1447 static const char *SlashPrefix[]={"a1","a4","a7"};
1448 static const char *BackPrefix[]={"a2","a5","a8"};
1449 static const char *JabPrefix[]={"a3","a6","a9"};
1450 static const char *RangedPrefix[]={"sa","sx","ss"};
1451 static const char *RangedPrefixOld[]={"sa","sx","a1"};
1453 void CharAnimations::AddVHRSuffix(char* ResRef, unsigned char StanceID,
1454 unsigned char& Cycle, unsigned char Orient, EquipResRefData*& EquipData)
1456 Cycle = SixteenToNine[Orient];
1457 EquipData = new EquipResRefData;
1458 EquipData->Suffix[0] = 0;
1459 switch (StanceID) {
1460 case IE_ANI_ATTACK:
1461 case IE_ANI_ATTACK_SLASH:
1462 strcat( ResRef, SlashPrefix[WeaponType] );
1463 strcpy( EquipData->Suffix, SlashPrefix[WeaponType] );
1464 break;
1466 case IE_ANI_ATTACK_BACKSLASH:
1467 strcat( ResRef, BackPrefix[WeaponType] );
1468 strcpy( EquipData->Suffix, BackPrefix[WeaponType] );
1469 break;
1471 case IE_ANI_ATTACK_JAB:
1472 strcat( ResRef, JabPrefix[WeaponType] );
1473 strcpy( EquipData->Suffix, JabPrefix[WeaponType] );
1474 break;
1476 case IE_ANI_AWAKE:
1477 strcat( ResRef, "g17" );
1478 strcpy( EquipData->Suffix, "g1" );
1479 Cycle += 63;
1480 break;
1482 case IE_ANI_CAST: //looping
1483 strcat( ResRef, "ca" );
1484 strcpy( EquipData->Suffix, "ca" );
1485 break;
1487 case IE_ANI_CONJURE: //ending
1488 strcat( ResRef, "ca" );
1489 strcpy( EquipData->Suffix, "ca" );
1490 Cycle += 9;
1491 break;
1493 case IE_ANI_DAMAGE:
1494 strcat( ResRef, "g14" );
1495 strcpy( EquipData->Suffix, "g1" );
1496 Cycle += 36;
1497 break;
1499 case IE_ANI_DIE:
1500 strcat( ResRef, "g15" );
1501 strcpy( EquipData->Suffix, "g1" );
1502 Cycle += 45;
1503 break;
1504 //I cannot find an emerge animation...
1505 //Maybe is Die reversed
1506 case IE_ANI_GET_UP:
1507 case IE_ANI_EMERGE:
1508 case IE_ANI_PST_START:
1509 strcat( ResRef, "g19" );
1510 strcpy( EquipData->Suffix, "g1" );
1511 Cycle += 81;
1512 break;
1514 case IE_ANI_HEAD_TURN:
1515 if (rand()&1) {
1516 strcat( ResRef, "g12" );
1517 Cycle += 18;
1518 } else {
1519 strcat( ResRef, "g18" );
1520 Cycle += 72;
1522 strcpy( EquipData->Suffix, "g1" );
1523 break;
1525 //Unknown... maybe only a transparency effect apply
1526 case IE_ANI_HIDE:
1527 break;
1529 case IE_ANI_READY:
1530 if ( WeaponType == IE_ANI_WEAPON_2H ) {
1531 strcat( ResRef, "g13" );
1532 Cycle += 27;
1533 } else {
1534 strcat( ResRef, "g1" );
1535 Cycle += 9;
1537 strcpy( EquipData->Suffix, "g1" );
1538 break;
1539 //This depends on the ranged weapon equipped
1540 case IE_ANI_SHOOT:
1541 strcat( ResRef, RangedPrefix[RangedType] );
1542 strcpy( EquipData->Suffix, RangedPrefix[RangedType] );
1543 break;
1545 case IE_ANI_SLEEP:
1546 strcat( ResRef, "g16" );
1547 strcpy( EquipData->Suffix, "g1" );
1548 Cycle += 54;
1549 break;
1551 case IE_ANI_TWITCH:
1552 strcat( ResRef, "g16" );
1553 strcpy( EquipData->Suffix, "g1" );
1554 Cycle += 54;
1555 break;
1557 case IE_ANI_WALK:
1558 strcat( ResRef, "g11" );
1559 strcpy( EquipData->Suffix, "g1" );
1560 break;
1562 default:
1563 printf("VHR Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1564 abort();
1565 break;
1567 EquipData->Cycle = Cycle;
1570 void CharAnimations::GetVHREquipmentRef(char* ResRef, unsigned char& Cycle,
1571 const char* equipRef, bool offhand,
1572 EquipResRefData* equip)
1574 Cycle = equip->Cycle;
1575 if (offhand) {
1576 sprintf( ResRef, "wq%c%c%co%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix );
1577 } else {
1578 sprintf( ResRef, "wq%c%c%c%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix );
1582 void CharAnimations::AddSixSuffix(char* ResRef, unsigned char StanceID,
1583 unsigned char& Cycle, unsigned char Orient)
1585 switch (StanceID) {
1586 case IE_ANI_WALK:
1587 strcat( ResRef, "g1" );
1588 Cycle = Orient;
1589 break;
1591 case IE_ANI_ATTACK:
1592 case IE_ANI_ATTACK_SLASH:
1593 strcat( ResRef, "g3" );
1594 Cycle = Orient;
1595 break;
1597 case IE_ANI_ATTACK_BACKSLASH:
1598 strcat( ResRef, "g3" );
1599 Cycle = 16 + Orient;
1600 break;
1602 case IE_ANI_ATTACK_JAB:
1603 strcat( ResRef, "g3" );
1604 Cycle = 32 + Orient;
1605 break;
1607 case IE_ANI_HEAD_TURN: //could be wrong
1608 case IE_ANI_AWAKE:
1609 strcat( ResRef, "g2" );
1610 Cycle = 0 + Orient;
1611 break;
1613 case IE_ANI_READY:
1614 strcat( ResRef, "g2" );
1615 Cycle = 16 + Orient;
1616 break;
1618 case IE_ANI_DAMAGE:
1619 strcat( ResRef, "g2" );
1620 Cycle = 32 + Orient;
1621 break;
1623 case IE_ANI_DIE:
1624 case IE_ANI_GET_UP:
1625 case IE_ANI_EMERGE:
1626 case IE_ANI_PST_START:
1627 strcat( ResRef, "g2" );
1628 Cycle = 48 + Orient;
1629 break;
1631 case IE_ANI_TWITCH:
1632 strcat( ResRef, "g2" );
1633 Cycle = 64 + Orient;
1634 break;
1636 default:
1637 printf("Six Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1638 abort();
1639 break;
1642 if (Orient>9) {
1643 strcat( ResRef, "e" );
1647 void CharAnimations::AddLR2Suffix(char* ResRef, unsigned char StanceID,
1648 unsigned char& Cycle, unsigned char Orient)
1650 Orient /= 2;
1652 switch (StanceID) {
1653 case IE_ANI_READY:
1654 case IE_ANI_CAST: //looping
1655 case IE_ANI_CONJURE://ending
1656 case IE_ANI_HIDE:
1657 case IE_ANI_WALK:
1658 case IE_ANI_AWAKE:
1659 Cycle = 0 + Orient;
1660 break;
1662 case IE_ANI_SHOOT:
1663 case IE_ANI_ATTACK:
1664 case IE_ANI_ATTACK_SLASH:
1665 case IE_ANI_ATTACK_BACKSLASH:
1666 case IE_ANI_ATTACK_JAB:
1667 case IE_ANI_HEAD_TURN:
1668 Cycle = 8 + Orient;
1669 break;
1671 case IE_ANI_DIE:
1672 case IE_ANI_GET_UP:
1673 case IE_ANI_EMERGE:
1674 case IE_ANI_PST_START:
1675 Cycle = 24 + Orient;
1676 break;
1678 case IE_ANI_DAMAGE:
1679 Cycle = 16 + Orient;
1680 break;
1682 case IE_ANI_SLEEP:
1683 case IE_ANI_TWITCH:
1684 Cycle = 32 + Orient;
1685 break;
1686 default:
1687 printf("LR2 Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1688 abort();
1689 break;
1691 if (Orient>=4) {
1692 strcat( ResRef, "g1e" );
1693 } else {
1694 strcat( ResRef, "g1" );
1698 void CharAnimations::AddMHRSuffix(char* ResRef, unsigned char StanceID,
1699 unsigned char& Cycle, unsigned char Orient, EquipResRefData*& EquipData)
1701 Orient /= 2;
1702 EquipData = new EquipResRefData;
1703 EquipData->Suffix[0] = 0;
1705 switch (StanceID) {
1706 case IE_ANI_ATTACK:
1707 case IE_ANI_ATTACK_SLASH:
1708 strcat (ResRef, SlashPrefix[WeaponType]);
1709 strcpy( EquipData->Suffix, SlashPrefix[WeaponType] );
1710 Cycle = Orient;
1711 break;
1713 case IE_ANI_ATTACK_BACKSLASH:
1714 strcat (ResRef, BackPrefix[WeaponType]);
1715 strcpy( EquipData->Suffix, BackPrefix[WeaponType] );
1716 Cycle = Orient;
1717 break;
1719 case IE_ANI_ATTACK_JAB:
1720 strcat (ResRef, JabPrefix[WeaponType]);
1721 strcpy( EquipData->Suffix, JabPrefix[WeaponType] );
1722 Cycle = Orient;
1723 break;
1725 case IE_ANI_READY:
1726 strcat( ResRef, "g1" );
1727 strcpy( EquipData->Suffix, "g1" );
1728 if ( WeaponType == IE_ANI_WEAPON_2W ) {
1729 Cycle = 24 + Orient;
1730 } else {
1731 Cycle = 8 + Orient;
1733 break;
1735 case IE_ANI_CAST://looping
1736 strcat( ResRef, "ca" );
1737 strcpy( EquipData->Suffix, "ca" );
1738 Cycle = 8 + Orient;
1739 break;
1741 case IE_ANI_CONJURE://ending
1742 strcat( ResRef, "ca" );
1743 strcpy( EquipData->Suffix, "ca" );
1744 Cycle = Orient;
1745 break;
1747 case IE_ANI_DAMAGE:
1748 strcat( ResRef, "g1" );
1749 strcpy( EquipData->Suffix, "g1" );
1750 Cycle = 40 + Orient;
1751 break;
1753 case IE_ANI_DIE:
1754 case IE_ANI_GET_UP:
1755 case IE_ANI_PST_START:
1756 strcat( ResRef, "g1" );
1757 strcpy( EquipData->Suffix, "g1" );
1758 Cycle = 48 + Orient;
1759 break;
1761 //I cannot find an emerge animation...
1762 //Maybe is Die reversed
1763 case IE_ANI_EMERGE:
1764 strcat( ResRef, "g1" );
1765 strcpy( EquipData->Suffix, "g1" );
1766 Cycle = 48 + Orient;
1767 break;
1769 case IE_ANI_HEAD_TURN:
1770 strcat( ResRef, "g1" );
1771 strcpy( EquipData->Suffix, "g1" );
1772 Cycle = 32 + Orient;
1773 break;
1775 //Unknown... maybe only a transparency effect apply
1776 case IE_ANI_HIDE:
1777 break;
1779 case IE_ANI_AWAKE:
1780 strcat( ResRef, "g1" );
1781 strcpy( EquipData->Suffix, "g1" );
1782 Cycle = 16 + Orient;
1783 break;
1785 //This depends on the ranged weapon equipped
1786 case IE_ANI_SHOOT:
1787 strcat (ResRef, RangedPrefixOld[RangedType]);
1788 strcpy( EquipData->Suffix, RangedPrefixOld[RangedType] );
1789 Cycle = Orient;
1790 break;
1792 case IE_ANI_SLEEP:
1793 strcat( ResRef, "g1" );
1794 strcpy( EquipData->Suffix, "g1" );
1795 Cycle = 64 + Orient;
1796 break;
1798 case IE_ANI_TWITCH:
1799 strcat( ResRef, "g1" );
1800 strcpy( EquipData->Suffix, "g1" );
1801 Cycle = 56 + Orient;
1802 break;
1804 case IE_ANI_WALK:
1805 strcat( ResRef, "g1" );
1806 strcpy( EquipData->Suffix, "g1" );
1807 Cycle = Orient;
1808 break;
1809 default:
1810 printf("MHR Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1811 abort();
1812 break;
1814 if (Orient>=5) {
1815 strcat( ResRef, "e" );
1816 strcat( EquipData->Suffix, "e" );
1818 EquipData->Cycle = Cycle;
1821 void CharAnimations::GetMHREquipmentRef(char* ResRef, unsigned char& Cycle,
1822 const char* equipRef, bool offhand,
1823 EquipResRefData* equip)
1825 Cycle = equip->Cycle;
1826 if (offhand) {
1827 //i think there is no offhand stuff for bg1, lets use the bg2 equivalent here?
1828 sprintf( ResRef, "wq%c%c%co%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix );
1829 } else {
1830 sprintf( ResRef, "wp%c%c%c%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix );
1834 void CharAnimations::AddTwoFileSuffix( char* ResRef, unsigned char StanceID,
1835 unsigned char& Cycle, unsigned char Orient)
1837 switch(StanceID) {
1838 case IE_ANI_HEAD_TURN:
1839 Cycle = 16 + Orient / 2;
1840 break;
1841 case IE_ANI_DAMAGE:
1842 Cycle = 24 + Orient / 2;
1843 break;
1844 case IE_ANI_SLEEP:
1845 case IE_ANI_TWITCH:
1846 Cycle = 40 + Orient / 2;
1847 break;
1848 case IE_ANI_GET_UP:
1849 case IE_ANI_EMERGE:
1850 case IE_ANI_DIE:
1851 case IE_ANI_PST_START:
1852 Cycle = 32 + Orient / 2;
1853 break;
1854 case IE_ANI_WALK:
1855 Cycle = Orient / 2;
1856 break;
1857 default:
1858 Cycle = 8 + Orient / 2;
1859 break;
1861 strcat( ResRef, "g1" );
1862 if (Orient > 9) {
1863 strcat( ResRef, "e" );
1867 void CharAnimations::AddLRSuffix2( char* ResRef, unsigned char StanceID,
1868 unsigned char& Cycle, unsigned char Orient, EquipResRefData *&EquipData)
1870 EquipData = new EquipResRefData;
1871 EquipData->Suffix[0] = 0;
1872 switch (StanceID) {
1873 case IE_ANI_ATTACK:
1874 case IE_ANI_ATTACK_BACKSLASH:
1875 case IE_ANI_ATTACK_SLASH:
1876 case IE_ANI_ATTACK_JAB:
1877 strcat( ResRef, "g2" );
1878 strcpy( EquipData->Suffix, "g2" );
1879 Cycle = Orient / 2;
1880 break;
1881 case IE_ANI_CAST:
1882 case IE_ANI_CONJURE:
1883 case IE_ANI_SHOOT:
1884 strcat( ResRef, "g2" );
1885 strcpy( EquipData->Suffix, "g2" );
1886 Cycle = 8 + Orient / 2;
1887 break;
1888 case IE_ANI_WALK:
1889 strcat( ResRef, "g1" );
1890 strcpy( EquipData->Suffix, "g1" );
1891 Cycle = Orient / 2;
1892 break;
1893 case IE_ANI_READY:
1894 strcat( ResRef, "g1" );
1895 strcpy( EquipData->Suffix, "g1" );
1896 Cycle = 8 + Orient / 2;
1897 break;
1898 case IE_ANI_HEAD_TURN: //could be wrong
1899 case IE_ANI_AWAKE:
1900 strcat( ResRef, "g1" );
1901 strcpy( EquipData->Suffix, "g1" );
1902 Cycle = 16 + Orient / 2;
1903 break;
1904 case IE_ANI_DAMAGE:
1905 strcat( ResRef, "g1" );
1906 strcpy( EquipData->Suffix, "g1" );
1907 Cycle = 24 + Orient / 2;
1908 break;
1909 case IE_ANI_GET_UP:
1910 case IE_ANI_EMERGE:
1911 case IE_ANI_PST_START:
1912 case IE_ANI_DIE:
1913 strcat( ResRef, "g1" );
1914 strcpy( EquipData->Suffix, "g1" );
1915 Cycle = 32 + Orient / 2;
1916 break;
1917 case IE_ANI_TWITCH:
1918 strcat( ResRef, "g1" );
1919 strcpy( EquipData->Suffix, "g1" );
1920 Cycle = 40 + Orient / 2;
1921 break;
1922 default:
1923 printf("LRSuffix2 Animation: unhandled stance: %s %d\n", ResRef, StanceID);
1924 abort();
1925 break;
1927 if (Orient > 9) {
1928 strcat( ResRef, "e" );
1929 strcat( EquipData->Suffix, "e");
1931 EquipData->Cycle = Cycle;
1934 void CharAnimations::AddLRSuffix( char* ResRef, unsigned char StanceID,
1935 unsigned char& Cycle, unsigned char Orient, EquipResRefData *&EquipData)
1937 EquipData = new EquipResRefData;
1938 EquipData->Suffix[0] = 0;
1939 switch (StanceID) {
1940 case IE_ANI_ATTACK:
1941 case IE_ANI_ATTACK_BACKSLASH:
1942 strcat( ResRef, "g2" );
1943 strcpy( EquipData->Suffix, "g2" );
1944 Cycle = Orient / 2;
1945 break;
1946 case IE_ANI_ATTACK_SLASH:
1947 strcat( ResRef, "g2" );
1948 strcpy( EquipData->Suffix, "g2" );
1949 Cycle = 8 + Orient / 2;
1950 break;
1951 case IE_ANI_ATTACK_JAB:
1952 strcat( ResRef, "g2" );
1953 strcpy( EquipData->Suffix, "g2" );
1954 Cycle = 16 + Orient / 2;
1955 break;
1956 case IE_ANI_CAST:
1957 case IE_ANI_CONJURE:
1958 case IE_ANI_SHOOT:
1959 //these animations are missing
1960 strcat( ResRef, "g2" );
1961 strcpy( EquipData->Suffix, "g2" );
1962 Cycle = Orient / 2;
1963 break;
1964 case IE_ANI_WALK:
1965 strcat( ResRef, "g1" );
1966 strcpy( EquipData->Suffix, "g1" );
1967 Cycle = Orient / 2;
1968 break;
1969 case IE_ANI_READY:
1970 strcat( ResRef, "g1" );
1971 strcpy( EquipData->Suffix, "g1" );
1972 Cycle = 8 + Orient / 2;
1973 break;
1974 case IE_ANI_HEAD_TURN: //could be wrong
1975 case IE_ANI_AWAKE:
1976 strcat( ResRef, "g1" );
1977 strcpy( EquipData->Suffix, "g1" );
1978 Cycle = 16 + Orient / 2;
1979 break;
1980 case IE_ANI_DAMAGE:
1981 strcat( ResRef, "g1" );
1982 strcpy( EquipData->Suffix, "g1" );
1983 Cycle = 24 + Orient / 2;
1984 break;
1985 case IE_ANI_GET_UP:
1986 case IE_ANI_EMERGE:
1987 case IE_ANI_PST_START:
1988 case IE_ANI_DIE:
1989 strcat( ResRef, "g1" );
1990 strcpy( EquipData->Suffix, "g1" );
1991 Cycle = 32 + Orient / 2;
1992 break;
1993 case IE_ANI_TWITCH:
1994 case IE_ANI_SLEEP:
1995 strcat( ResRef, "g1" );
1996 strcpy( EquipData->Suffix, "g1" );
1997 Cycle = 40 + Orient / 2;
1998 break;
1999 default:
2000 printf("LR Animation: unhandled stance: %s %d\n", ResRef, StanceID);
2001 abort();
2002 break;
2004 if (Orient > 9) {
2005 strcat( ResRef, "e" );
2006 strcat( EquipData->Suffix, "e");
2008 EquipData->Cycle = Cycle;
2011 void CharAnimations::GetLREquipmentRef(char* ResRef, unsigned char& Cycle,
2012 const char* equipRef, bool /*offhand*/,
2013 EquipResRefData* equip)
2015 Cycle = equip->Cycle;
2016 //hackhackhack
2017 sprintf( ResRef, "%4s%c%s", this->ResRef, equipRef[0], equip->Suffix );
2018 printf("LREquipment resref: %s\n", ResRef);
2021 //Only for the ogre animation (MOGR)
2022 void CharAnimations::AddLR3Suffix( char* ResRef, unsigned char StanceID,
2023 unsigned char& Cycle, unsigned char Orient)
2025 switch (StanceID) {
2026 case IE_ANI_ATTACK:
2027 case IE_ANI_ATTACK_BACKSLASH:
2028 strcat( ResRef, "g2" );
2029 Cycle = Orient / 2;
2030 break;
2031 case IE_ANI_ATTACK_SLASH:
2032 strcat( ResRef, "g2" );
2033 Cycle = 8 + Orient / 2;
2034 break;
2035 case IE_ANI_ATTACK_JAB:
2036 strcat( ResRef, "g2" );
2037 Cycle = 8 + Orient / 2; //there is no third attack animation
2038 break;
2039 case IE_ANI_CAST:
2040 case IE_ANI_CONJURE:
2041 case IE_ANI_SHOOT:
2042 strcat( ResRef, "g3" );
2043 Cycle = Orient / 2;
2044 break;
2045 case IE_ANI_WALK:
2046 strcat( ResRef, "g1" );
2047 Cycle = 16 + Orient / 2;
2048 break;
2049 case IE_ANI_READY:
2050 strcat( ResRef, "g1" );
2051 Cycle = 8 + Orient / 2;
2052 break;
2053 case IE_ANI_HEAD_TURN: //could be wrong
2054 case IE_ANI_AWAKE:
2055 strcat( ResRef, "g1" );
2056 Cycle = Orient / 2;
2057 break;
2058 case IE_ANI_DAMAGE:
2059 strcat( ResRef, "g3" );
2060 Cycle = 8 + Orient / 2;
2061 break;
2062 case IE_ANI_DIE:
2063 case IE_ANI_GET_UP:
2064 case IE_ANI_EMERGE:
2065 case IE_ANI_PST_START:
2066 case IE_ANI_SLEEP:
2067 strcat( ResRef, "g3" );
2068 Cycle = 16 + Orient / 2;
2069 break;
2070 case IE_ANI_TWITCH:
2071 strcat( ResRef, "g3" );
2072 Cycle = 24 + Orient / 2;
2073 break;
2074 default:
2075 printf("LR3 Animation: unhandled stance: %s %d\n", ResRef, StanceID);
2076 abort();
2077 break;
2079 if (Orient > 9) {
2080 strcat( ResRef, "e" );
2084 void CharAnimations::AddMMR2Suffix(char* ResRef, unsigned char StanceID,
2085 unsigned char& Cycle, unsigned char Orient)
2087 switch (StanceID) {
2088 case IE_ANI_ATTACK:
2089 case IE_ANI_ATTACK_SLASH:
2090 case IE_ANI_ATTACK_BACKSLASH:
2091 case IE_ANI_ATTACK_JAB:
2092 case IE_ANI_CONJURE:
2093 case IE_ANI_CAST:
2094 strcat( ResRef, "a1" );
2095 Cycle = ( Orient / 2 );
2096 break;
2098 case IE_ANI_SHOOT:
2099 strcat( ResRef, "a4" );
2100 Cycle = ( Orient / 2 );
2101 break;
2103 case IE_ANI_AWAKE:
2104 case IE_ANI_READY:
2105 strcat( ResRef, "sd" );
2106 Cycle = ( Orient / 2 );
2107 break;
2109 case IE_ANI_HEAD_TURN:
2110 strcat( ResRef, "sc" );
2111 Cycle = ( Orient / 2 );
2112 break;
2114 case IE_ANI_DAMAGE:
2115 strcat( ResRef, "gh" );
2116 Cycle = ( Orient / 2 );
2117 break;
2119 case IE_ANI_DIE:
2120 strcat( ResRef, "de" );
2121 Cycle = ( Orient / 2 );
2122 break;
2124 case IE_ANI_GET_UP:
2125 case IE_ANI_EMERGE:
2126 case IE_ANI_PST_START:
2127 strcat( ResRef, "gu" );
2128 Cycle = ( Orient / 2 );
2129 break;
2131 //Unknown... maybe only a transparency effect apply
2132 case IE_ANI_HIDE:
2133 break;
2135 case IE_ANI_SLEEP:
2136 strcat( ResRef, "sl" );
2137 Cycle = ( Orient / 2 );
2138 break;
2140 case IE_ANI_TWITCH:
2141 strcat( ResRef, "tw" );
2142 Cycle = ( Orient / 2 );
2143 break;
2145 case IE_ANI_WALK:
2146 strcat( ResRef, "wk" );
2147 Cycle = ( Orient / 2 );
2148 break;
2149 default:
2150 printf("MMR Animation: unhandled stance: %s %d\n", ResRef, StanceID);
2151 abort();
2152 break;
2154 if (Orient > 9) {
2155 strcat( ResRef, "e" );
2159 void CharAnimations::AddMMRSuffix(char* ResRef, unsigned char StanceID,
2160 unsigned char& Cycle, unsigned char Orient)
2162 switch (StanceID) {
2163 case IE_ANI_ATTACK:
2164 case IE_ANI_ATTACK_SLASH:
2165 case IE_ANI_ATTACK_BACKSLASH:
2166 strcat( ResRef, "a1" );
2167 Cycle = ( Orient / 2 );
2168 break;
2170 case IE_ANI_SHOOT:
2171 strcat( ResRef, "a4" );
2172 Cycle = ( Orient / 2 );
2173 break;
2175 case IE_ANI_ATTACK_JAB:
2176 strcat( ResRef, "a2" );
2177 Cycle = ( Orient / 2 );
2178 break;
2180 case IE_ANI_AWAKE:
2181 case IE_ANI_READY:
2182 strcat( ResRef, "sd" );
2183 Cycle = ( Orient / 2 );
2184 break;
2186 case IE_ANI_CONJURE:
2187 strcat( ResRef, "ca" );
2188 Cycle = ( Orient / 2 );
2189 break;
2191 case IE_ANI_CAST:
2192 strcat( ResRef, "sp" );
2193 Cycle = ( Orient / 2 );
2194 break;
2196 case IE_ANI_HEAD_TURN:
2197 strcat( ResRef, "sc" );
2198 Cycle = ( Orient / 2 );
2199 break;
2201 case IE_ANI_DAMAGE:
2202 strcat( ResRef, "gh" );
2203 Cycle = ( Orient / 2 );
2204 break;
2206 case IE_ANI_DIE:
2207 strcat( ResRef, "de" );
2208 Cycle = ( Orient / 2 );
2209 break;
2211 case IE_ANI_GET_UP:
2212 case IE_ANI_EMERGE:
2213 case IE_ANI_PST_START:
2214 strcat( ResRef, "gu" );
2215 Cycle = ( Orient / 2 );
2216 break;
2218 //Unknown... maybe only a transparency effect apply
2219 case IE_ANI_HIDE:
2220 break;
2222 case IE_ANI_SLEEP:
2223 strcat( ResRef, "sl" );
2224 Cycle = ( Orient / 2 );
2225 break;
2227 case IE_ANI_TWITCH:
2228 strcat( ResRef, "tw" );
2229 Cycle = ( Orient / 2 );
2230 break;
2232 case IE_ANI_WALK:
2233 strcat( ResRef, "wk" );
2234 Cycle = ( Orient / 2 );
2235 break;
2236 default:
2237 printf("MMR Animation: unhandled stance: %s %d\n", ResRef, StanceID);
2238 abort();
2239 break;
2241 if (Orient > 9) {
2242 strcat( ResRef, "e" );
2246 void CharAnimations::PulseRGBModifiers()
2248 unsigned long time = core->GetGame()->Ticks;
2250 if (time - lastModUpdate <= 40)
2251 return;
2253 if (time - lastModUpdate > 400) lastModUpdate = time - 40;
2255 int inc = (time - lastModUpdate)/40;
2256 bool change[4] = { false, false, false, false };
2257 if (GlobalColorMod.type != RGBModifier::NONE &&
2258 GlobalColorMod.speed > 0)
2260 GlobalColorMod.phase += inc;
2261 change[0] = change[1] = change[2] = change[3] = true;
2263 // reset if done
2264 if (GlobalColorMod.phase > 2*GlobalColorMod.speed) {
2265 GlobalColorMod.type = RGBModifier::NONE;
2266 GlobalColorMod.phase = 0;
2267 GlobalColorMod.speed = 0;
2271 for (int i = 0; i < 32; ++i) {
2272 if (ColorMods[i].type != RGBModifier::NONE &&
2273 ColorMods[i].speed > 0)
2275 ColorMods[i].phase += inc;
2276 change[i>>3] = true;
2280 if (change[0]) SetupColors(PAL_MAIN);
2281 if (change[1]) SetupColors(PAL_WEAPON);
2282 if (change[2]) SetupColors(PAL_OFFHAND);
2283 if (change[3]) SetupColors(PAL_HELMET);
2285 lastModUpdate += inc*40;