1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
3 *
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.
8
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.
13
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.
17 *
18 *
19 */
20
21 #include "CharAnimations.h"
22
23 #include "AnimationFactory.h"
24 #include "DataFileMgr.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 "RNG.h"
32
33 namespace GemRB {
34
35 static int AvatarsCount = 0;
36 static AvatarStruct *AvatarTable = NULL;
37 static const ieByte SixteenToNine[16]={0,1,2,3,4,5,6,7,8,7,6,5,4,3,2,1};
38 static const ieByte SixteenToFive[16]={0,0,1,1,2,2,3,3,4,4,3,3,2,2,1,1};
39
40 static const int zOrder_TwoPiece[2] = { 1, 0 };
41
42 static const int zOrder_Mirror16[16][4] = {
43 { 0, 3, 2, 1 },
44 { 0, 3, 2, 1 },
45 { 0, 3, 1, 2 },
46 { 0, 3, 1, 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 { 1, 0, 3, 2 },
53 { 1, 0, 3, 2 },
54 { 1, 0, 3, 2 },
55 { 1, 0, 3, 2 },
56 { 0, 3, 1, 2 },
57 { 0, 3, 1, 2 },
58 { 0, 3, 2, 1 }
59 };
60
61 static const int zOrder_8[8][4] = {
62 { 0, 3, 2, 1 },
63 { 0, 3, 1, 2 },
64 { 1, 0, 3, 2 },
65 { 1, 2, 0, 3 },
66 { 1, 2, 0, 3 },
67 { 2, 0, 3, 1 },
68 { 2, 0, 3, 1 },
69 { 2, 0, 3, 1 }
70 };
71
72 struct EquipResRefData {
73 char Suffix[9];
74 unsigned char Cycle;
75 };
76
ReleaseMemory()77 void CharAnimations::ReleaseMemory()
78 {
79 if (AvatarTable) {
80 free(AvatarTable);
81 AvatarTable=NULL;
82 }
83 }
84
GetAvatarsCount()85 int CharAnimations::GetAvatarsCount()
86 {
87 return AvatarsCount;
88 }
89
GetAvatarStruct(int RowNum)90 AvatarStruct *CharAnimations::GetAvatarStruct(int RowNum)
91 {
92 return AvatarTable+RowNum;
93 }
94
GetAnimationID() const95 unsigned int CharAnimations::GetAnimationID() const
96 {
97 if (AvatarsRowNum==~0u) return 0;
98 return AvatarTable[AvatarsRowNum].AnimID;
99 }
100
GetCircleSize() const101 int CharAnimations::GetCircleSize() const
102 {
103 if (AvatarsRowNum==~0u) return -1;
104 return AvatarTable[AvatarsRowNum].CircleSize;
105 }
NoPalette() const106 int CharAnimations::NoPalette() const
107 {
108 if (AvatarsRowNum==~0u) return -1;
109 return AvatarTable[AvatarsRowNum].PaletteType;
110 }
111
GetAnimType() const112 int CharAnimations::GetAnimType() const
113 {
114 if (AvatarsRowNum==~0u) return -1;
115 return AvatarTable[AvatarsRowNum].AnimationType;
116 }
117
GetSize() const118 int CharAnimations::GetSize() const
119 {
120 if (AvatarsRowNum==~0u) return 0;
121 return AvatarTable[AvatarsRowNum].Size;
122 }
123
GetBloodColor() const124 int CharAnimations::GetBloodColor() const
125 {
126 if(AvatarsRowNum==~0u) return 0;
127 return AvatarTable[AvatarsRowNum].BloodColor;
128 }
129
GetFlags() const130 unsigned int CharAnimations::GetFlags() const
131 {
132 if(AvatarsRowNum==~0u) return 0;
133 return AvatarTable[AvatarsRowNum].Flags;
134 }
135
MaybeOverrideStance(unsigned char stance) const136 unsigned char CharAnimations::MaybeOverrideStance(unsigned char stance) const
137 {
138 if(AvatarsRowNum==~0u) return stance;
139 return AvatarTable[AvatarsRowNum].StanceOverride[stance];
140 }
141 /*
142 * For some actors (Arundel, FFG, fire giants) a new stance requires a
143 * different palette to use. Presumably, this is relevant for PAL_MAIN only.
144 */
MaybeUpdateMainPalette(Animation ** anims)145 void CharAnimations::MaybeUpdateMainPalette(Animation **anims) {
146 if (previousStanceID != StanceID) {
147 // Test if the palette in question is actually different to the one loaded.
148 if (*PartPalettes[PAL_MAIN] != *(anims[0]->GetFrame(0)->GetPalette())) {
149 gamedata->FreePalette(PartPalettes[PAL_MAIN], PaletteResRef[PAL_MAIN]);
150 PaletteResRef[PAL_MAIN][0] = 0;
151
152 PartPalettes[PAL_MAIN] = anims[0]->GetFrame(0)->GetPalette()->Copy();
153 SetupColors(PAL_MAIN);
154 }
155 }
156 }
157
158 static ieResRef EmptySound={0};
159
GetWalkSound() const160 const ieResRef &CharAnimations::GetWalkSound() const
161 {
162 if(AvatarsRowNum==~0u) return EmptySound;
163 return AvatarTable[AvatarsRowNum].WalkSound;
164 }
165
GetWalkSoundCount() const166 int CharAnimations::GetWalkSoundCount() const
167 {
168 if(AvatarsRowNum==~0u) return 0;
169 return AvatarTable[AvatarsRowNum].WalkSoundCount;
170 }
171
GetActorPartCount() const172 int CharAnimations::GetActorPartCount() const
173 {
174 if (AvatarsRowNum==~0u) return -1;
175 switch (AvatarTable[AvatarsRowNum].AnimationType) {
176 case IE_ANI_NINE_FRAMES: //dragon animations
177 return 9;
178 case IE_ANI_FOUR_FRAMES: //wyvern animations
179 case IE_ANI_FOUR_FRAMES_2: //demogorgon animations
180 return 4;
181 case IE_ANI_TWO_PIECE: //ankheg animations
182 return 2;
183 case IE_ANI_PST_GHOST: //special pst anims
184 if (AvatarTable[AvatarsRowNum].Prefixes[1][0]=='*') {
185 return 1;
186 }
187 if (AvatarTable[AvatarsRowNum].Prefixes[2][0]=='*') {
188 return 2;
189 }
190 if (AvatarTable[AvatarsRowNum].Prefixes[3][0]=='*') {
191 return 3;
192 }
193 return 4;
194 default:
195 return 1;
196 }
197 }
198
GetTotalPartCount() const199 int CharAnimations::GetTotalPartCount() const
200 {
201 if (AvatarsRowNum==~0u) return -1;
202 switch (AvatarTable[AvatarsRowNum].AnimationType) {
203 case IE_ANI_FOUR_FILES:
204 case IE_ANI_FOUR_FILES_2:
205 return GetActorPartCount() + 1; // only weapon
206 case IE_ANI_CODE_MIRROR:
207 return GetActorPartCount() + 3; // equipment
208 case IE_ANI_TWENTYTWO:
209 return GetActorPartCount() + 3; // equipment
210 default:
211 return GetActorPartCount();
212 }
213 }
214
GetArmourLevel(int ArmourLevel) const215 const ieResRef& CharAnimations::GetArmourLevel(int ArmourLevel) const
216 {
217 //ignore ArmourLevel for the static pst anims (all sprites are displayed)
218 if (AvatarTable[AvatarsRowNum].AnimationType == IE_ANI_PST_GHOST) {
219 ArmourLevel = 0;
220 }
221 return AvatarTable[AvatarsRowNum].Prefixes[ArmourLevel];
222 }
223
SetArmourLevel(int ArmourLevel)224 void CharAnimations::SetArmourLevel(int ArmourLevel)
225 {
226 if (AvatarsRowNum==~0u) return;
227 //ignore ArmourLevel for the static pst anims (all sprites are displayed)
228 if (AvatarTable[AvatarsRowNum].AnimationType == IE_ANI_PST_GHOST) {
229 ArmourLevel = 0;
230 }
231 CopyResRef( ResRef, AvatarTable[AvatarsRowNum].Prefixes[ArmourLevel] );
232 DropAnims();
233 }
234
235 //RangedType could be weird, reducing its value to 0,1,2
SetRangedType(int rt)236 void CharAnimations::SetRangedType(int rt)
237 {
238 if ((unsigned int) rt<2) {
239 RangedType=(ieByte) rt;
240 } else {
241 RangedType=2;
242 }
243 }
244
SetWeaponType(int wt)245 void CharAnimations::SetWeaponType(int wt)
246 {
247 if (wt != WeaponType) {
248 WeaponType = wt;
249 DropAnims();
250 }
251 }
252
SetHelmetRef(const char * ref)253 void CharAnimations::SetHelmetRef(const char* ref)
254 {
255 strlcpy(HelmetRef, ref, sizeof(HelmetRef)+1);
256
257 // Only drop helmet anims?
258 // Note: this doesn't happen "often", so this isn't a performance
259 // bottleneck. (wjp)
260 DropAnims();
261 gamedata->FreePalette(PartPalettes[PAL_HELMET], 0);
262 gamedata->FreePalette(ModPartPalettes[PAL_HELMET], 0);
263 }
264
SetWeaponRef(const char * ref)265 void CharAnimations::SetWeaponRef(const char* ref)
266 {
267 WeaponRef[0] = ref[0];
268 WeaponRef[1] = ref[1];
269
270 // TODO: Only drop weapon anims?
271 DropAnims();
272 gamedata->FreePalette(PartPalettes[PAL_WEAPON], 0);
273 gamedata->FreePalette(ModPartPalettes[PAL_WEAPON], 0);
274 }
275
SetOffhandRef(const char * ref)276 void CharAnimations::SetOffhandRef(const char* ref)
277 {
278 OffhandRef[0] = ref[0];
279 OffhandRef[1] = ref[1];
280
281 // TODO: Only drop shield/offhand anims?
282 DropAnims();
283 gamedata->FreePalette(PartPalettes[PAL_OFFHAND], 0);
284 gamedata->FreePalette(ModPartPalettes[PAL_OFFHAND], 0);
285 }
286
LockPalette(const ieDword * gradients)287 void CharAnimations::LockPalette(const ieDword *gradients)
288 {
289 if (lockPalette) return;
290 //cannot lock colors for PST animations
291 if (GetAnimType() >= IE_ANI_PST_ANIMATION_1)
292 {
293 return;
294 }
295 //force initialisation of animation
296 SetColors( gradients );
297 GetAnimation(0,0);
298 if (PartPalettes[PAL_MAIN]) {
299 lockPalette=true;
300 }
301 }
302
303 // NOTE: change if MAX_ANIMS is increased
304 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
305 static const char StancePrefix[] = {'3','2','5','5','4','4','2','2','5','4','1','3','3','3','4','1','4','4','4'};
306 static const char CyclePrefix[] = {'0','0','1','1','1','1','0','0','1','1','0','0','0','0','1','1','1','1','1'};
307 static const unsigned int CycleOffset[] = { 0, 0, 0, 0, 0, 9, 0, 0, 0, 18, 0, 0, 9, 18, 0, 0, 0, 0, 0 };
308
309 #define NINE_FRAMES_PALETTE(stance) ((PaletteType) (StancePrefix[stance] - '1'))
310
SetColors(const ieDword * arg)311 void CharAnimations::SetColors(const ieDword *arg)
312 {
313 Colors = arg;
314 SetupColors(PAL_MAIN);
315 SetupColors(PAL_MAIN_2);
316 SetupColors(PAL_MAIN_3);
317 SetupColors(PAL_MAIN_4);
318 SetupColors(PAL_MAIN_5);
319 SetupColors(PAL_WEAPON);
320 SetupColors(PAL_OFFHAND);
321 SetupColors(PAL_HELMET);
322 }
323
CheckColorMod()324 void CharAnimations::CheckColorMod()
325 {
326 if (!GlobalColorMod.locked) {
327 if (GlobalColorMod.type != RGBModifier::NONE) {
328 GlobalColorMod.type = RGBModifier::NONE;
329 GlobalColorMod.speed = 0;
330 for (int i = 0; i < PAL_MAX; ++i) {
331 change[i] = true;
332 }
333 }
334 }
335 unsigned int location;
336
337 for (location = 0; location < PAL_MAX * 8; ++location) {
338 if (!ColorMods[location].phase) {
339 if (ColorMods[location].type != RGBModifier::NONE) {
340 ColorMods[location].type = RGBModifier::NONE;
341 ColorMods[location].speed = 0;
342 change[location>>3]=true;
343 }
344 }
345 }
346 //this is set by sanctuary and stoneskin (override global colors)
347 lockPalette = false;
348 }
349
SetupColors(PaletteType type)350 void CharAnimations::SetupColors(PaletteType type)
351 {
352 PaletteHolder pal = PartPalettes[type];
353
354 if (!pal) {
355 return;
356 }
357
358 if (!Colors) {
359 return;
360 }
361
362 int PType = NoPalette();
363
364 if (GetAnimType() >= IE_ANI_PST_ANIMATION_1) {
365 // Only do main palette
366 if (type != PAL_MAIN) {
367 return;
368 }
369 // TODO: handle equipment colour glows
370
371 // Colors[6] is the COLORCOUNT stat in PST.
372 // It tells how many customisable color slots we have.
373 // The color slots start from the end of the palette and go
374 // backwards. There are 6 available slots with a size of 32 each.
375 // Actually, the slots seem to be written in the cre file
376 // but we ignore them, i'm not sure this is correct
377 int colorcount = Colors[6];
378 constexpr int size = 32;
379 //the color count shouldn't be more than 6!
380 if (colorcount>6) colorcount=6;
381 int dest = 256-colorcount*size;
382 bool needmod = false;
383 if (GlobalColorMod.type != RGBModifier::NONE) {
384 needmod = true;
385 }
386 //don't drop the palette, it disables rgb pulse effects
387 //also don't bail out, we need to free the modified palette later
388 //so this entire block is needless
389 /*
390 if ((colorcount == 0) && (needmod==false) ) {
391 gamedata->FreePalette(palette[PAL_MAIN], PaletteResRef);
392 PaletteResRef[0]=0;
393 return;
394 }
395 */
396 for (int i = 0; i < colorcount; i++) {
397 const auto& pal32 = core->GetPalette32(Colors[i]);
398 PartPalettes[PAL_MAIN]->CopyColorRange(&pal32[0], &pal32[32], dest);
399 dest +=size;
400 }
401
402 if (needmod) {
403 if (!ModPartPalettes[PAL_MAIN])
404 ModPartPalettes[PAL_MAIN] = new Palette();
405 ModPartPalettes[PAL_MAIN]->SetupGlobalRGBModification(PartPalettes[PAL_MAIN], GlobalColorMod);
406 } else {
407 gamedata->FreePalette(ModPartPalettes[PAL_MAIN], 0);
408 }
409 } else if (PType && (type <= PAL_MAIN_5)) {
410 //handling special palettes like MBER_BL (black bear)
411 if (PType!=1) {
412 ieResRef oldResRef;
413 CopyResRef(oldResRef, PaletteResRef[type]);
414 if (GetAnimType()==IE_ANI_NINE_FRAMES) {
415 snprintf(PaletteResRef[type],9,"%.4s_%-.2s%c",ResRef, (char *) &PType, '1'+type);
416 } else {
417 if (!stricmp(ResRef, "MFIE")) { // hack for magic golems
418 snprintf(PaletteResRef[type],9,"%.4s%-.2sB", ResRef, (char *) &PType);
419 } else {
420 snprintf(PaletteResRef[type],9,"%.4s_%-.2s", ResRef, (char *) &PType);
421 }
422 }
423 strlwr(PaletteResRef[type]);
424 PaletteHolder tmppal = gamedata->GetPalette(PaletteResRef[type]);
425 if (tmppal) {
426 gamedata->FreePalette(PartPalettes[type], oldResRef);
427 PartPalettes[type] = tmppal;
428 } else {
429 PaletteResRef[type][0]=0;
430 }
431 }
432 bool needmod = GlobalColorMod.type != RGBModifier::NONE;
433 if (needmod) {
434 if (!ModPartPalettes[type])
435 ModPartPalettes[type] = new Palette();
436 ModPartPalettes[type]->SetupGlobalRGBModification(PartPalettes[type], GlobalColorMod);
437 } else {
438 gamedata->FreePalette(ModPartPalettes[type], 0);
439 }
440 } else {
441 pal->SetupPaperdollColours(Colors, type);
442 if (lockPalette) {
443 return;
444 }
445
446 bool needmod = false;
447 if (GlobalColorMod.type != RGBModifier::NONE) {
448 needmod = true;
449 } else {
450 // TODO: should that -1 really be there??
451 for (size_t i = 0; i < PAL_MAX - 1; ++i) {
452 if (ColorMods[i+8*type].type != RGBModifier::NONE)
453 needmod = true;
454 }
455 }
456
457 if (needmod) {
458 if (!ModPartPalettes[type])
459 ModPartPalettes[type] = new Palette();
460
461 if (GlobalColorMod.type != RGBModifier::NONE) {
462 ModPartPalettes[type]->SetupGlobalRGBModification(PartPalettes[type], GlobalColorMod);
463 } else {
464 ModPartPalettes[type]->SetupRGBModification(PartPalettes[type],ColorMods, type);
465 }
466 } else {
467 gamedata->FreePalette(ModPartPalettes[type], 0);
468 }
469 }
470 }
471
GetPartPalette(int part)472 PaletteHolder CharAnimations::GetPartPalette(int part)
473 {
474 int actorPartCount = GetActorPartCount();
475 PaletteType type = PAL_MAIN;
476 if (GetAnimType() == IE_ANI_NINE_FRAMES) {
477 //these animations use several palettes
478 type = NINE_FRAMES_PALETTE(StanceID);
479 }
480 else if (GetAnimType() == IE_ANI_FOUR_FRAMES_2) return NULL;
481 // always use unmodified BAM palette for the supporting part
482 else if (GetAnimType() == IE_ANI_TWO_PIECE && part == 1) return NULL;
483 else if (part == actorPartCount) type = PAL_WEAPON;
484 else if (part == actorPartCount+1) type = PAL_OFFHAND;
485 else if (part == actorPartCount+2) type = PAL_HELMET;
486
487 if (ModPartPalettes[type])
488 return ModPartPalettes[type];
489
490 return PartPalettes[type];
491 }
492
GetShadowPalette() const493 PaletteHolder CharAnimations::GetShadowPalette() const {
494 return shadowPalette;
495 }
496
compare_avatars(const void * a,const void * b)497 static inline int compare_avatars(const void *a, const void *b)
498 {
499 return (int) (((const AvatarStruct *)a)->AnimID - ((const AvatarStruct *)b)->AnimID);
500 }
501
InitAvatarsTable()502 void CharAnimations::InitAvatarsTable()
503 {
504 AutoTable Avatars("avatars");
505 if (!Avatars) {
506 error("CharAnimations", "A critical animation file is missing!\n");
507 }
508 AvatarTable = (AvatarStruct *) calloc ( AvatarsCount = Avatars->GetRowCount(), sizeof(AvatarStruct) );
509 int i=AvatarsCount;
510 DataFileMgr *resdata = core->GetResDataINI();
511 while(i--) {
512 AvatarTable[i].AnimID=(unsigned int) strtol(Avatars->GetRowName(i),NULL,0 );
513 strnlwrcpy(AvatarTable[i].Prefixes[0],Avatars->QueryField(i,AV_PREFIX1),8);
514 strnlwrcpy(AvatarTable[i].Prefixes[1],Avatars->QueryField(i,AV_PREFIX2),8);
515 strnlwrcpy(AvatarTable[i].Prefixes[2],Avatars->QueryField(i,AV_PREFIX3),8);
516 strnlwrcpy(AvatarTable[i].Prefixes[3],Avatars->QueryField(i,AV_PREFIX4),8);
517 AvatarTable[i].AnimationType=(ieByte) atoi(Avatars->QueryField(i,AV_ANIMTYPE) );
518 AvatarTable[i].CircleSize=(ieByte) atoi(Avatars->QueryField(i,AV_CIRCLESIZE) );
519 const char *tmp = Avatars->QueryField(i,AV_USE_PALETTE);
520 //QueryField will always return a zero terminated string
521 //so tmp[0] must exist
522 if ( isalpha (tmp[0]) ) {
523 //this is a hack, we store 2 letters on an integer
524 //it was allocated with calloc, so don't bother erasing it
525 strncpy( (char *) &AvatarTable[i].PaletteType, tmp, 3);
526 }
527 else {
528 AvatarTable[i].PaletteType=atoi(Avatars->QueryField(i,AV_USE_PALETTE) );
529 }
530 char size = Avatars->QueryField(i,AV_SIZE)[0];
531 if (size == '*') {
532 size = 0;
533 }
534 AvatarTable[i].Size = size;
535
536 AvatarTable[i].WalkScale = 0;
537 AvatarTable[i].RunScale = 0;
538 AvatarTable[i].Bestiary = -1;
539
540 for (int j = 0; j < MAX_ANIMS; j++)
541 AvatarTable[i].StanceOverride[j] = j;
542
543 if (resdata) {
544 char section[12];
545 snprintf(section, 10, "%d", i%100000); // the mod is just to silent warnings, since we know i is small enough
546
547 if (!resdata->GetKeysCount(section)) continue;
548
549 float walkscale = resdata->GetKeyAsFloat(section, "walkscale", 0.0f);
550 if (walkscale != 0.0f) AvatarTable[i].WalkScale = (int)(1000.0f / walkscale);
551 float runscale = resdata->GetKeyAsFloat(section, "runscale", 0.0f);
552 if (runscale != 0.0f) AvatarTable[i].RunScale = (int)(1000.0f / runscale);
553 AvatarTable[i].Bestiary = resdata->GetKeyAsInt(section, "bestiary", -1);
554 }
555 }
556 qsort(AvatarTable, AvatarsCount, sizeof(AvatarStruct), compare_avatars);
557
558
559 AutoTable blood("bloodclr");
560 if (blood) {
561 int rows = blood->GetRowCount();
562 for(int i=0;i<rows;i++) {
563 unsigned long value = 0;
564 unsigned long flags = 0;
565 unsigned long rmin = 0;
566 unsigned long rmax = 0xffff;
567
568 valid_number(blood->QueryField(i,0), (long &)value);
569 valid_number(blood->QueryField(i,1), (long &)rmin);
570 valid_number(blood->QueryField(i,2), (long &)rmax);
571 valid_number(blood->QueryField(i,3), (long &)flags);
572 if (value>255 || rmin>rmax || rmax>0xffff) {
573 Log(ERROR, "CharAnimations", "Invalid bloodclr entry: %02x %04x-%04x ",
574 (unsigned int) value, (unsigned int) rmin, (unsigned int) rmax);
575 continue;
576 }
577 for(int j=0;j<AvatarsCount;j++) {
578 if (rmax<AvatarTable[j].AnimID) break;
579 if (rmin>AvatarTable[j].AnimID) continue;
580 AvatarTable[j].BloodColor = (char) value;
581 AvatarTable[j].Flags = (unsigned int) flags;
582 }
583 }
584 }
585
586 AutoTable walk("walksnd");
587 if (walk) {
588 int rows = walk->GetRowCount();
589 for(int i=0;i<rows;i++) {
590 ieResRef value;
591 unsigned long rmin = 0;
592 unsigned long rmax = 0xffff;
593 unsigned long range = 0;
594
595 strnuprcpy(value, walk->QueryField(i,0), 8);
596 valid_number(walk->QueryField(i,1), (long &)rmin);
597 valid_number(walk->QueryField(i,2), (long &)rmax);
598 valid_number(walk->QueryField(i,3), (long &)range);
599 if (value[0]=='*') {
600 value[0]=0;
601 range = 0;
602 }
603 if (range>255 || rmin>rmax || rmax>0xffff) {
604 Log(ERROR, "CharAnimations", "Invalid walksnd entry: %02x %04x-%04x ",
605 (unsigned int) range, (unsigned int) rmin, (unsigned int) rmax);
606 continue;
607 }
608 for(int j=0;j<AvatarsCount;j++) {
609 if (rmax<AvatarTable[j].AnimID) break;
610 if (rmin>AvatarTable[j].AnimID) continue;
611 memcpy(AvatarTable[j].WalkSound, value, sizeof(ieResRef) );
612 AvatarTable[j].WalkSoundCount = (unsigned int) range;
613 }
614 }
615 }
616
617 AutoTable stances("stances", true);
618 if (stances) {
619 int rows = stances->GetRowCount();
620 for (int i = 0; i < rows; i++) {
621 unsigned long id = 0, s1 = 0, s2 = 0;
622 valid_number(stances->GetRowName(i), (long &)id);
623 valid_number(stances->QueryField(i, 0), (long &)s1);
624 valid_number(stances->QueryField(i, 1), (long &)s2);
625
626 if (s1 >= MAX_ANIMS || s2 >= MAX_ANIMS) {
627 Log(ERROR, "CharAnimations", "Invalid stances entry: %04x %d %d",
628 (unsigned int) id, (unsigned int) s1, (unsigned int) s2);
629 continue;
630 }
631
632 for (int j = 0; j < AvatarsCount; j++) {
633 if (id < AvatarTable[j].AnimID) break;
634 if (id == AvatarTable[j].AnimID) {
635 AvatarTable[j].StanceOverride[s1] = s2;
636 break;
637 }
638 }
639 }
640 }
641
642 AutoTable avatarShadows("avatar_shadows");
643 if (avatarShadows) {
644 int rows = avatarShadows->GetRowCount();
645 for (int i = 0; i < rows; ++i) {
646 unsigned long id = 0;
647 valid_number(avatarShadows->GetRowName(i), (long &)id);
648
649 for (int j = 0; j < AvatarsCount; j++) {
650 if (id < AvatarTable[j].AnimID) {
651 break;
652 }
653 if (AvatarTable[j].AnimID == id) {
654 strnlwrcpy(AvatarTable[j].ShadowAnimation, avatarShadows->QueryField(i, 0), 4);
655 break;
656 }
657 }
658 }
659 }
660 }
661
CharAnimations(unsigned int AnimID,ieDword ArmourLevel)662 CharAnimations::CharAnimations(unsigned int AnimID, ieDword ArmourLevel)
663 {
664 Colors = NULL;
665 for (size_t i = 0; i < PAL_MAX; ++i) {
666 change[i] = true;
667 }
668 previousStanceID = nextStanceID = 0;
669 StanceID = 0;
670 autoSwitchOnEnd = false;
671 lockPalette = false;
672 if (!AvatarsCount) {
673 InitAvatarsTable();
674 }
675
676 for (size_t i = 0; i < MAX_ANIMS; i++) {
677 for (size_t j = 0; j < MAX_ORIENT; j++) {
678 Anims[i][j] = NULL;
679 shadowAnimations[i][j] = NULL;
680 }
681 }
682 ArmorType = 0;
683 RangedType = 0;
684 WeaponType = 0;
685 for (size_t i = 0; i < 5; ++i) {
686 PaletteResRef[i][0] = 0;
687 }
688 WeaponRef[0] = 0;
689 HelmetRef[0] = 0;
690 OffhandRef[0] = 0;
691 for (size_t i = 0; i < PAL_MAX * 8; ++i) {
692 ColorMods[i].type = RGBModifier::NONE;
693 ColorMods[i].speed = 0;
694 // make initial phase depend on location to make the pulse appear
695 // less even
696 ColorMods[i].phase = 5*i;
697 ColorMods[i].locked = false;
698 }
699 GlobalColorMod.type = RGBModifier::NONE;
700 GlobalColorMod.speed = 0;
701 GlobalColorMod.phase = 0;
702 GlobalColorMod.locked = false;
703 GlobalColorMod.rgb = Color();
704 lastModUpdate = 0;
705
706 AvatarsRowNum=AvatarsCount;
707 if (core->HasFeature(GF_ONE_BYTE_ANIMID) ) {
708 ieDword tmp = AnimID&0xf000;
709 if (tmp==0x6000 || tmp==0xe000) {
710 AnimID&=0xff;
711 }
712 }
713
714 while (AvatarsRowNum--) {
715 if (AvatarTable[AvatarsRowNum].AnimID<=AnimID) {
716 SetArmourLevel( ArmourLevel );
717 return;
718 }
719 }
720 ResRef[0]=0;
721 Log(ERROR, "CharAnimations", "Invalid or nonexistent avatar entry:%04X", AnimID);
722 }
723
724 //we have to drop them when armourlevel changes
DropAnims()725 void CharAnimations::DropAnims()
726 {
727 Animation** tmppoi;
728 int partCount = GetTotalPartCount();
729 for (int StanceID = 0; StanceID < MAX_ANIMS; StanceID++) {
730 for (int i = 0; i < MAX_ORIENT; i++) {
731 if (Anims[StanceID][i]) {
732 tmppoi = Anims[StanceID][i];
733 for (int j = 0; j < partCount; j++)
734 delete Anims[StanceID][i][j];
735 delete[] tmppoi;
736
737 // anims can only be duplicated at the Animation** level
738 for (int IDb=StanceID;IDb < MAX_ANIMS; IDb++) {
739 for (int i2 = 0; i2<MAX_ORIENT; i2++) {
740 if (Anims[IDb][i2] == tmppoi) {
741 Anims[IDb][i2] = 0;
742 }
743 }
744 }
745 }
746 }
747 }
748 }
749
~CharAnimations(void)750 CharAnimations::~CharAnimations(void)
751 {
752 DropAnims();
753 int i;
754 for (i = 0; i <= PAL_MAIN_5; ++i)
755 gamedata->FreePalette(PartPalettes[i], PaletteResRef[i]);
756 for (; i < PAL_MAX; ++i)
757 gamedata->FreePalette(PartPalettes[i], 0);
758 for (i = 0; i < PAL_MAX; ++i)
759 gamedata->FreePalette(ModPartPalettes[i], 0);
760
761 if (shadowPalette) {
762 gamedata->FreePalette(shadowPalette, 0);
763 }
764
765 for (i = 0; i < MAX_ANIMS; ++i) {
766 for (int j = 0; j < MAX_ORIENT; ++j) {
767 if (shadowAnimations[i][j]) {
768 delete shadowAnimations[i][j][0];
769 delete[] shadowAnimations[i][j];
770 j += 1;
771 }
772 }
773 }
774 }
775 /*
776 This is a simple Idea of how the animation are coded
777
778 There are the following animation types:
779
780 IE_ANI_CODE_MIRROR: The code automatically mirrors the needed frames
781 (as in the example above)
782
783 These Animations are stores using the following template:
784 [NAME][ARMORTYPE][ACTIONCODE]
785
786 Each BAM File contains only 9 Orientations, the missing 7 Animations
787 are created by Horizontally Mirroring the 1-7 Orientations.
788
789 IE_ANI_CODE_MIRROR_2: another mirroring type with more animations
790 [NAME]g[1,11-15,2,21-26]
791
792 IE_ANI_CODE_MIRROR_3: Almost identical to IE_ANI_CODE_MIRROR_2, but with fewer cycles in g26
793
794 IE_ANI_ONE_FILE: The whole animation is in one file, no mirroring needed.
795 Each animation group is 16 Cycles.
796
797 IE_ANI_TWO_FILES: The whole animation is in 2 files. The East and West part are in 2 BAM Files.
798 Example:
799 ACHKg1
800 ACHKg1E
801
802 Each BAM File contains many animation groups, each animation group
803 stores 5 Orientations, the missing 3 are stored in East BAM Files.
804
805
806 IE_ANI_FOUR_FILES: The Animation is coded in Four Files. Probably it is an old Two File animation with
807 additional frames added in a second time.
808
809 IE_ANI_FOUR_FILES_2: Like IE_ANI_FOUR_FILES but with only 16 cycles per frame.
810
811 IE_ANI_FOUR_FILES_3: A variation of the four files animation without equipment, and
812 with even and odd orientations split across two files, plus the standard
813 separate eastern parts, so the layout is
814 [NAME][H|L]G1[/E]
815
816 IE_ANI_TWENTYTWO: This Animation Type stores the Animation in the following format
817 [NAME][ACTIONCODE][/E]
818 ACTIONCODE=A1-6, CA, SX, SA (sling is A1)
819 The g1 file contains several animation states. See MHR
820 Probably it could use A7-9 files too, bringing the file numbers to 28.
821 This is the original bg1 format.
822
823 IE_ANI_SIX_FILES: The layout for these files is:
824 [NAME][g1-3][/E]
825 Each state contains 16 Orientations, but the last 6 are stored in the East file.
826 g1 contains only the walking animation.
827 G2 contains stand, ready, get hit, die and twitch.
828 g3 contains 3 attacks.
829
830 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
831
832 IE_ANI_TWO_FILES_2: Animations using this type are stored using the following template:
833 [NAME]g1[/E]
834 Each state contains 8 Orientations, but the second 4 are stored in the East file.
835 From the standard animations, only AHRS and ACOW belong to this type.
836
837 IE_ANI_TWO_FILES_3: Animations using this type are stored using the following template:
838 [NAME][ACTIONTYPE][/E]
839
840 Example:
841 MBFI*
842 MBFI*E
843
844 Each BAM File contains one animation group, each animation group
845 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).
846 This is the standard IWD animation, but BG2 also has it.
847 See MMR
848
849 IE_ANI_TWO_FILES_3B: Animations using this type are stored using the following template:
850 [NAME][ACTIONTYPE][/E]
851
852 Example:
853 MBFI*
854 MBFI*E
855
856 This is a cut down version of IE_ANI_TWO_FILES_3. A2, CA and SP suffixes are missing.
857 This is the standard IWD animation, but BG2 also has it.
858 See MOR2
859
860 IE_ANI_TWO_FILES_3C: Animations using this type are stored using the following template:
861 [NAME][ACTIONTYPE]
862
863 Example:
864 MWDR*
865
866 This is a cut down version of IE_ANI_TWO_FILES_3. E(ast) files are missing.
867 See MWOR (missing de and gu suffixes)
868
869 IE_ANI_TWO_FILES_4: This type stores animations in two files (G1 and G2) which each having only
870 one cycle. And both of those seem to be identical.
871
872 IE_ANI_TWO_FILES_5: Also uses G1 and G2 only but contains various cycles, including some special moves,
873 with 9 orientations each. Only used by MMEL.
874
875 IE_ANI_TWO_PIECE: This is a modified IE_ANI_SIX_FILES with supporting still frames (using a
876 different palette) stored in a second set of files. Currently only used by MAKH
877
878 IE_ANI_FOUR_FRAMES: These animations are large, four bams make a frame.
879
880 IE_ANI_FOUR_FRAMES_2: Another variation of the four frames format with more files.
881
882 IE_ANI_NINE_FRAMES: These animations are huge, nine bams make a frame.
883
884
885 IE_ANI_FRAGMENT: These animations are used for projectile graphics.
886 A single file contains 5 cycles (code mirror for east animation)
887
888 IE_ANI_PST_ANIMATION_1:
889 IE_ANI_PST_ANIMATION_2:
890 IE_ANI_PST_ANIMATION_3:
891 Planescape: Torment Animations are stored in a different
892 way than the other games. This format uses the following template:
893 [C/D][ACTIONTYPE][NAME][B]
894
895 Example:
896 CAT1MRTB
897
898 Each Animation stores 5 Orientations, which are automatically mirrored
899 to form an 8 Orientation Animation. PST Animations have a different Palette
900 format. This Animation Type handles the PST Palette format too.
901
902 NOTE: Walking/Running animations store 9 Orientations.
903 The second variation is missing the resting stance (STD) and the transitions.
904 These creatures are always in combat stance (don't rest).
905 Animation_3 is without STC (combat stance), they are always standing
906
907 IE_ANI_PST_STAND: This is a modified PST animation, it contains only a
908 Standing image for every orientations, it follows the
909 [C/D]STD[NAME][B] standard.
910
911 IE_ANI_PST_GHOST: This is a special static animation with no standard
912 All armourlevels are drawn simultaneously. There is no orientation or stance.
913
914
915 WEST PART | EAST PART
916 |
917 NW NNW N NNE NE
918 NW 006 007 008 009 010 NE
919 WNW 005 | 011 ENE
920 W 004 xxx 012 E
921 WSW 003 | 013 ESE
922 SW 002 001 000 015 014 SE
923 SW SSW S SSE SE
924 |
925 |
926
927 */
928
GetAnimation(unsigned char Stance,unsigned char Orient)929 Animation** CharAnimations::GetAnimation(unsigned char Stance, unsigned char Orient)
930 {
931 if (Stance >= MAX_ANIMS) {
932 error("CharAnimation", "Illegal stance ID\n");
933 }
934
935 //for paletted dragon animations, we need the stance id
936 StanceID = nextStanceID = Stance;
937 int AnimType = GetAnimType();
938
939 //alter stance here if it is missing and you know a substitute
940 //probably we should feed this result back to the actor?
941 switch (AnimType) {
942 case -1: //invalid animation
943 return NULL;
944
945 case IE_ANI_PST_STAND:
946 StanceID = IE_ANI_AWAKE;
947 break;
948 case IE_ANI_PST_GHOST:
949 StanceID = IE_ANI_AWAKE;
950 Orient = 0;
951 break;
952 case IE_ANI_PST_ANIMATION_3: //stc->std
953 if (StanceID == IE_ANI_READY) {
954 StanceID = IE_ANI_AWAKE;
955 }
956 break;
957 case IE_ANI_PST_ANIMATION_2: //std->stc
958 if (StanceID == IE_ANI_AWAKE) {
959 StanceID = IE_ANI_READY;
960 }
961 break;
962 }
963
964 //TODO: Implement Auto Resource Loading
965 //setting up the sequencing of animation cycles
966 autoSwitchOnEnd = false;
967 switch (StanceID) {
968 case IE_ANI_DAMAGE:
969 nextStanceID = IE_ANI_READY;
970 autoSwitchOnEnd = true;
971 break;
972 case IE_ANI_SLEEP: //going to sleep
973 case IE_ANI_DIE: //going to die
974 nextStanceID = IE_ANI_TWITCH;
975 autoSwitchOnEnd = true;
976 break;
977 case IE_ANI_WALK:
978 case IE_ANI_RUN:
979 case IE_ANI_CAST: // looping
980 case IE_ANI_READY:
981 case IE_ANI_AWAKE:
982 case IE_ANI_TWITCH: //dead, sleeping
983 break;
984 case IE_ANI_EMERGE:
985 case IE_ANI_GET_UP:
986 case IE_ANI_HEAD_TURN:
987 case IE_ANI_PST_START:
988 nextStanceID = IE_ANI_AWAKE;
989 autoSwitchOnEnd = true;
990 break;
991 case IE_ANI_CONJURE: //ending
992 case IE_ANI_SHOOT:
993 case IE_ANI_ATTACK:
994 case IE_ANI_ATTACK_JAB:
995 case IE_ANI_ATTACK_SLASH:
996 case IE_ANI_ATTACK_BACKSLASH:
997 nextStanceID = IE_ANI_READY;
998 autoSwitchOnEnd = true;
999 break;
1000 default:
1001 Log(MESSAGE, "CharAnimation", "Invalid Stance: %d", StanceID);
1002 break;
1003 }
1004
1005 StanceID = MaybeOverrideStance(StanceID);
1006
1007 bool lastFrameOnly = false;
1008 //pst (and some other) animations don't have separate animations for sleep/die
1009 if (Stance == IE_ANI_TWITCH &&
1010 (AnimType >= IE_ANI_PST_ANIMATION_1 || MaybeOverrideStance(IE_ANI_DIE) == StanceID))
1011 {
1012 lastFrameOnly = true;
1013 }
1014
1015 Animation** anims = Anims[StanceID][Orient];
1016 if (anims) {
1017 MaybeUpdateMainPalette(anims);
1018 previousStanceID = StanceID;
1019
1020 if (lastFrameOnly) {
1021 anims[0]->SetPos(anims[0]->GetFrameCount() - 1);
1022 }
1023
1024 return anims;
1025 }
1026
1027 int partCount = GetTotalPartCount();
1028 int actorPartCount = GetActorPartCount();
1029 if (partCount <= 0) return 0;
1030 anims = new Animation*[partCount];
1031
1032 EquipResRefData* equipdat = 0;
1033 for (int part = 0; part < partCount; ++part)
1034 {
1035 anims[part] = 0;
1036
1037 //newresref is based on the prefix (ResRef) and various
1038 // other things.
1039 //this is longer than expected so it won't overflow
1040 char NewResRef[12];
1041 unsigned char Cycle = 0;
1042 if (part < actorPartCount) {
1043 // Character animation parts
1044
1045 if (equipdat) delete equipdat;
1046
1047 //we need this long for special anims
1048 strlcpy( NewResRef, ResRef, sizeof(ieResRef) );
1049 GetAnimResRef( StanceID, Orient, NewResRef, Cycle, part, equipdat);
1050 } else {
1051 // Equipment animation parts
1052
1053 anims[part] = 0;
1054 if (GetSize() == 0) continue;
1055
1056 if (part == actorPartCount) {
1057 if (WeaponRef[0] == 0) continue;
1058 // weapon
1059 GetEquipmentResRef(WeaponRef,false,NewResRef,Cycle,equipdat);
1060 } else if (part == actorPartCount+1) {
1061 if (OffhandRef[0] == 0) continue;
1062 if (WeaponType == IE_ANI_WEAPON_2H) continue;
1063 // off-hand
1064 if (WeaponType == IE_ANI_WEAPON_1H) {
1065 GetEquipmentResRef(OffhandRef,false,NewResRef,Cycle,
1066 equipdat);
1067 } else { // IE_ANI_WEAPON_2W
1068 GetEquipmentResRef(OffhandRef,true,NewResRef,Cycle,
1069 equipdat);
1070 }
1071 } else if (part == actorPartCount+2) {
1072 if (HelmetRef[0] == 0) continue;
1073 // helmet
1074 GetEquipmentResRef(HelmetRef,false,NewResRef,Cycle,equipdat);
1075 }
1076 }
1077 NewResRef[8]=0; //cutting right to size
1078
1079 AnimationFactory* af = ( AnimationFactory* )
1080 gamedata->GetFactoryResource( NewResRef,
1081 IE_BAM_CLASS_ID, IE_NORMAL );
1082
1083 if (!af) {
1084 if (part < actorPartCount) {
1085 Log(ERROR, "CharAnimations", "Couldn't create animationfactory: %s (%04x)",
1086 NewResRef, GetAnimationID());
1087 for (int i = 0; i < part; ++i)
1088 delete anims[i];
1089 delete[] anims;
1090 delete equipdat;
1091 return 0;
1092 } else {
1093 // not fatal if animation for equipment is missing
1094 continue;
1095 }
1096 }
1097
1098 Animation* a = af->GetCycle( Cycle );
1099 anims[part] = a;
1100
1101 if (!a) {
1102 if (part < actorPartCount) {
1103 Log(ERROR, "CharAnimations", "Couldn't load animation: %s, cycle %d",
1104 NewResRef, Cycle);
1105 for (int i = 0; i < part; ++i)
1106 delete anims[i];
1107 delete[] anims;
1108 delete equipdat;
1109 return 0;
1110 } else {
1111 // not fatal if animation for equipment is missing
1112 continue;
1113 }
1114 }
1115
1116 if (part < actorPartCount) {
1117 PaletteType ptype = PAL_MAIN;
1118 if (AnimType == IE_ANI_NINE_FRAMES) {
1119 //these animations use several palettes
1120 ptype = NINE_FRAMES_PALETTE(StanceID);
1121 }
1122
1123 //if you need to revert this change, consider true paletted
1124 //animations which need a GlobalColorMod (mgir for example)
1125
1126 //if (!palette[PAL_MAIN] && ((GlobalColorMod.type!=RGBModifier::NONE) || (NoPalette()!=1)) ) {
1127 if(!PartPalettes[ptype]) {
1128 // This is the first time we're loading an Animation.
1129 // We copy the palette of its first frame into our own palette
1130 PartPalettes[ptype] = a->GetFrame(0)->GetPalette()->Copy();
1131 // ...and setup the colours properly
1132 SetupColors(ptype);
1133 } else if (ptype == PAL_MAIN) {
1134 MaybeUpdateMainPalette(anims);
1135 }
1136 } else if (part == actorPartCount) {
1137 if (!PartPalettes[PAL_WEAPON]) {
1138 PartPalettes[PAL_WEAPON] = a->GetFrame(0)->GetPalette()->Copy();
1139 SetupColors(PAL_WEAPON);
1140 }
1141 } else if (part == actorPartCount+1) {
1142 if (!PartPalettes[PAL_OFFHAND]) {
1143 PartPalettes[PAL_OFFHAND] = a->GetFrame(0)->GetPalette()->Copy();
1144 SetupColors(PAL_OFFHAND);
1145 }
1146 } else if (part == actorPartCount+2) {
1147 if (!PartPalettes[PAL_HELMET]) {
1148 PartPalettes[PAL_HELMET] = a->GetFrame(0)->GetPalette()->Copy();
1149 SetupColors(PAL_HELMET);
1150 }
1151 }
1152
1153 //animation is affected by game flags
1154 a->gameAnimation = true;
1155 if (lastFrameOnly) {
1156 a->SetPos(a->GetFrameCount() - 1);
1157 } else {
1158 a->SetPos(0);
1159 }
1160
1161 //setting up the sequencing of animation cycles
1162 switch (StanceID) {
1163 case IE_ANI_DAMAGE:
1164 case IE_ANI_SLEEP:
1165 case IE_ANI_TWITCH:
1166 case IE_ANI_DIE:
1167 case IE_ANI_PST_START:
1168 case IE_ANI_HEAD_TURN:
1169 case IE_ANI_CONJURE:
1170 case IE_ANI_SHOOT:
1171 case IE_ANI_ATTACK:
1172 case IE_ANI_ATTACK_JAB:
1173 case IE_ANI_ATTACK_SLASH:
1174 case IE_ANI_ATTACK_BACKSLASH:
1175 a->Flags |= A_ANI_PLAYONCE;
1176 break;
1177 case IE_ANI_EMERGE:
1178 case IE_ANI_GET_UP:
1179 a->playReversed = true;
1180 a->Flags |= A_ANI_PLAYONCE;
1181 break;
1182 }
1183 switch (AnimType) {
1184 case IE_ANI_NINE_FRAMES: //dragon animations
1185 case IE_ANI_FOUR_FRAMES: //wyvern animations
1186 case IE_ANI_FOUR_FRAMES_2:
1187 case IE_ANI_BIRD:
1188 case IE_ANI_CODE_MIRROR:
1189 case IE_ANI_CODE_MIRROR_2: //9 orientations
1190 case IE_ANI_CODE_MIRROR_3:
1191 case IE_ANI_PST_ANIMATION_3: //no stc just std
1192 case IE_ANI_PST_ANIMATION_2: //no std just stc
1193 case IE_ANI_PST_ANIMATION_1:
1194 case IE_ANI_FRAGMENT:
1195 case IE_ANI_TWO_FILES_3C:
1196 case IE_ANI_TWO_FILES_5:
1197 if (Orient > 8) {
1198 a->MirrorAnimation( );
1199 }
1200 break;
1201 default:
1202 break;
1203 }
1204
1205 // make animarea of part 0 encompass the animarea of the other parts
1206 if (part > 0)
1207 anims[0]->AddAnimArea(a);
1208
1209 }
1210
1211 switch (AnimType) {
1212 case IE_ANI_NINE_FRAMES: //dragon animations
1213 case IE_ANI_FOUR_FRAMES: //wyvern animations
1214 case IE_ANI_FOUR_FRAMES_2:
1215 case IE_ANI_BIRD:
1216 case IE_ANI_CODE_MIRROR:
1217 case IE_ANI_SIX_FILES: //16 anims some are stored elsewhere
1218 case IE_ANI_ONE_FILE: //16 orientations
1219 case IE_ANI_TWO_FILES_5: // 9 orientations
1220 case IE_ANI_CODE_MIRROR_2: //9 orientations
1221 case IE_ANI_CODE_MIRROR_3:
1222 case IE_ANI_PST_GHOST:
1223 Anims[StanceID][Orient] = anims;
1224 break;
1225 case IE_ANI_TWO_FILES:
1226 case IE_ANI_TWENTYTWO:
1227 case IE_ANI_TWO_FILES_2:
1228 case IE_ANI_TWO_FILES_3:
1229 case IE_ANI_TWO_FILES_3B:
1230 case IE_ANI_TWO_FILES_3C:
1231 case IE_ANI_FOUR_FILES:
1232 case IE_ANI_FOUR_FILES_2:
1233 case IE_ANI_SIX_FILES_2:
1234 case IE_ANI_TWO_PIECE:
1235 case IE_ANI_FRAGMENT:
1236 case IE_ANI_PST_STAND:
1237 Orient&=~1;
1238 Anims[StanceID][Orient] = anims;
1239 Anims[StanceID][Orient + 1] = anims;
1240 break;
1241 case IE_ANI_FOUR_FILES_3:
1242 //only 8 orientations for WALK
1243 if (StanceID == IE_ANI_WALK) {
1244 Orient&=~1;
1245 Anims[StanceID][Orient] = anims;
1246 Anims[StanceID][Orient + 1] = anims;
1247 } else {
1248 Anims[StanceID][Orient] = anims;
1249 }
1250 break;
1251 case IE_ANI_TWO_FILES_4:
1252 for (int i = 0; i < MAX_ANIMS; ++i) {
1253 for (int j = 0; j < MAX_ORIENT; ++j) {
1254 Anims[i][j] = anims;
1255 }
1256 }
1257 break;
1258
1259 case IE_ANI_PST_ANIMATION_3: //no stc just std
1260 case IE_ANI_PST_ANIMATION_2: //no std just stc
1261 case IE_ANI_PST_ANIMATION_1:
1262 switch (StanceID) {
1263 case IE_ANI_WALK:
1264 case IE_ANI_RUN:
1265 case IE_ANI_PST_START:
1266 Anims[StanceID][Orient] = anims;
1267 break;
1268 default:
1269 Orient &=~1;
1270 Anims[StanceID][Orient] = anims;
1271 Anims[StanceID][Orient + 1] = anims;
1272 break;
1273 }
1274 break;
1275 default:
1276 error("CharAnimations", "Unknown animation type\n");
1277 }
1278 delete equipdat;
1279 previousStanceID = StanceID;
1280
1281 return Anims[StanceID][Orient];
1282 }
1283
GetShadowAnimation(unsigned char stance,unsigned char orientation)1284 Animation** CharAnimations::GetShadowAnimation(unsigned char stance, unsigned char orientation) {
1285 if (GetTotalPartCount() <= 0 || IE_ANI_TWENTYTWO != GetAnimType()) {
1286 return NULL;
1287 }
1288
1289 unsigned char stanceID = MaybeOverrideStance(stance);
1290
1291 switch (stanceID) {
1292 case IE_ANI_WALK:
1293 case IE_ANI_RUN:
1294 case IE_ANI_CAST:
1295 case IE_ANI_SHOOT:
1296 case IE_ANI_ATTACK:
1297 case IE_ANI_ATTACK_JAB:
1298 case IE_ANI_ATTACK_SLASH:
1299 case IE_ANI_ATTACK_BACKSLASH:
1300 case IE_ANI_AWAKE:
1301 case IE_ANI_HEAD_TURN:
1302 case IE_ANI_DIE:
1303 case IE_ANI_READY:
1304 case IE_ANI_CONJURE:
1305 break;
1306 default:
1307 return NULL;
1308 }
1309
1310 if (shadowAnimations[stanceID][orientation]) {
1311 return shadowAnimations[stanceID][orientation];
1312 }
1313
1314 Animation** animations = NULL;
1315
1316 if (AvatarTable[AvatarsRowNum].ShadowAnimation[0]) {
1317 int partCount = GetTotalPartCount();
1318 animations = new Animation*[partCount];
1319
1320 char shadowName[12] = {0};
1321 memcpy(shadowName, AvatarTable[AvatarsRowNum].ShadowAnimation, 4);
1322
1323 for (int i = 0; i < partCount; ++i) {
1324 animations[i] = NULL;
1325 }
1326
1327 EquipResRefData *dummy = NULL;
1328 unsigned char cycle = 0;
1329 AddMHRSuffix(shadowName, stanceID, cycle, orientation, dummy);
1330 delete dummy;
1331 shadowName[8] = 0;
1332
1333 AnimationFactory* af = static_cast<AnimationFactory*>(
1334 gamedata->GetFactoryResource(shadowName, IE_BAM_CLASS_ID, IE_NORMAL));
1335
1336 if (!af) {
1337 delete[] animations;
1338 return NULL;
1339 }
1340
1341 Animation *animation = af->GetCycle(cycle);
1342 animations[0] = animation;
1343
1344 if (!animation) {
1345 delete[] animations;
1346 return NULL;
1347 }
1348
1349 if (!shadowPalette) {
1350 shadowPalette = animation->GetFrame(0)->GetPalette()->Copy();
1351 }
1352
1353 switch (StanceID) {
1354 case IE_ANI_DAMAGE:
1355 case IE_ANI_TWITCH:
1356 case IE_ANI_DIE:
1357 case IE_ANI_HEAD_TURN:
1358 case IE_ANI_CONJURE:
1359 case IE_ANI_SHOOT:
1360 case IE_ANI_ATTACK:
1361 case IE_ANI_ATTACK_JAB:
1362 case IE_ANI_ATTACK_SLASH:
1363 case IE_ANI_ATTACK_BACKSLASH:
1364 animation->Flags |= A_ANI_PLAYONCE;
1365 break;
1366 }
1367
1368 animation->gameAnimation = true;
1369 animation->SetPos(0);
1370 animations[0]->AddAnimArea(animation);
1371
1372 orientation &= ~1;
1373 shadowAnimations[stanceID][orientation] = animations;
1374 shadowAnimations[stanceID][orientation + 1] = animations;
1375
1376 return shadowAnimations[stanceID][orientation];
1377 }
1378
1379 return NULL;
1380 }
1381
1382 static const int one_file[MAX_ANIMS] = {2, 1, 0, 0, 2, 3, 0, 1, 0, 4, 1, 0, 0, 0, 3, 1, 4, 4, 4};
1383
GetAnimResRef(unsigned char StanceID,unsigned char Orient,char * NewResRef,unsigned char & Cycle,int Part,EquipResRefData * & EquipData)1384 void CharAnimations::GetAnimResRef(unsigned char StanceID,
1385 unsigned char Orient,
1386 char* NewResRef, unsigned char& Cycle,
1387 int Part, EquipResRefData*& EquipData)
1388 {
1389 EquipData = 0;
1390 Orient &= 15;
1391 switch (GetAnimType()) {
1392 case IE_ANI_FOUR_FRAMES:
1393 AddFFSuffix( NewResRef, StanceID, Cycle, Orient, Part );
1394 break;
1395
1396 case IE_ANI_FOUR_FRAMES_2:
1397 AddFF2Suffix( NewResRef, StanceID, Cycle, Orient, Part );
1398 break;
1399
1400 case IE_ANI_NINE_FRAMES:
1401 AddNFSuffix( NewResRef, StanceID, Cycle, Orient, Part );
1402 break;
1403
1404 case IE_ANI_CODE_MIRROR:
1405 AddVHRSuffix( NewResRef, StanceID, Cycle, Orient, EquipData );
1406 break;
1407
1408 case IE_ANI_BIRD:
1409 // TODO: use 0-8 for gliding; those only have a single frame
1410 Cycle = 9 + SixteenToNine[Orient];
1411 break;
1412
1413 case IE_ANI_FRAGMENT:
1414 Cycle = SixteenToFive[Orient];
1415 break;
1416
1417 case IE_ANI_ONE_FILE:
1418 Cycle = (ieByte) (one_file[StanceID] * 16 + Orient);
1419 break;
1420
1421 case IE_ANI_SIX_FILES:
1422 AddSixSuffix( NewResRef, StanceID, Cycle, Orient );
1423 break;
1424
1425 case IE_ANI_TWENTYTWO: //5+3 animations
1426 AddMHRSuffix( NewResRef, StanceID, Cycle, Orient, EquipData );
1427 break;
1428
1429 case IE_ANI_TWO_FILES_2: //4+4 animations
1430 AddLR2Suffix( NewResRef, StanceID, Cycle, Orient );
1431 break;
1432
1433 case IE_ANI_TWO_FILES_3: //IWD style anims
1434 AddMMRSuffix(NewResRef, StanceID, Cycle, Orient, false);
1435 break;
1436
1437 case IE_ANI_TWO_FILES_3B: //IWD style anims
1438 AddMMR2Suffix( NewResRef, StanceID, Cycle, Orient );
1439 break;
1440
1441 case IE_ANI_TWO_FILES_3C: //IWD style anims
1442 AddMMRSuffix(NewResRef, StanceID, Cycle, Orient, true);
1443 break;
1444
1445 case IE_ANI_TWO_FILES_4:
1446 strcat( NewResRef, "g1");
1447 Cycle = 0;
1448 break;
1449
1450 case IE_ANI_TWO_FILES_5:
1451 AddTwoFiles5Suffix( NewResRef, StanceID, Cycle, Orient );
1452 break;
1453
1454 case IE_ANI_TWO_FILES:
1455 AddTwoFileSuffix(NewResRef, StanceID, Cycle, Orient );
1456 break;
1457
1458 case IE_ANI_FOUR_FILES:
1459 AddLRSuffix( NewResRef, StanceID, Cycle, Orient, EquipData );
1460 break;
1461
1462 case IE_ANI_FOUR_FILES_2:
1463 AddLRSuffix2( NewResRef, StanceID, Cycle, Orient, EquipData );
1464 break;
1465
1466 case IE_ANI_FOUR_FILES_3:
1467 AddHLSuffix( NewResRef, StanceID, Cycle, Orient );
1468 break;
1469
1470 case IE_ANI_SIX_FILES_2: //MOGR (variant of FOUR_FILES)
1471 AddLR3Suffix( NewResRef, StanceID, Cycle, Orient );
1472 break;
1473
1474 case IE_ANI_TWO_PIECE: //MAKH
1475 AddTwoPieceSuffix( NewResRef, StanceID, Cycle, Orient, Part );
1476 break;
1477
1478 case IE_ANI_CODE_MIRROR_2: //9 orientations
1479 AddVHR2Suffix( NewResRef, StanceID, Cycle, Orient );
1480 break;
1481
1482 case IE_ANI_CODE_MIRROR_3: // like IE_ANI_CODE_MIRROR_2 but with fewer cycles in g26
1483 AddVHR3Suffix( NewResRef, StanceID, Cycle, Orient );
1484 break;
1485
1486 case IE_ANI_PST_ANIMATION_1:
1487 case IE_ANI_PST_ANIMATION_2:
1488 case IE_ANI_PST_ANIMATION_3:
1489 AddPSTSuffix( NewResRef, StanceID, Cycle, Orient );
1490 break;
1491
1492 case IE_ANI_PST_STAND:
1493 sprintf(NewResRef,"%cSTD%4s",ResRef[0], ResRef + 1);
1494 Cycle = SixteenToFive[Orient];
1495 break;
1496 case IE_ANI_PST_GHOST: // pst static animations
1497 //still doesn't handle the second cycle of the golem anim
1498 Cycle = 0;
1499 strnlwrcpy(NewResRef, AvatarTable[AvatarsRowNum].Prefixes[Part], 8);
1500 break;
1501 default:
1502 error("CharAnimations", "Unknown animation type in avatars.2da row: %d\n", AvatarsRowNum);
1503 }
1504 }
1505
GetEquipmentResRef(const char * equipRef,bool offhand,char * dest,unsigned char & Cycle,EquipResRefData * equip)1506 void CharAnimations::GetEquipmentResRef(const char* equipRef, bool offhand,
1507 char *dest, unsigned char& Cycle, EquipResRefData* equip)
1508 {
1509 switch (GetAnimType()) {
1510 case IE_ANI_FOUR_FILES:
1511 case IE_ANI_FOUR_FILES_2:
1512 GetLREquipmentRef(dest, Cycle, equipRef, offhand, equip);
1513 break;
1514 case IE_ANI_CODE_MIRROR:
1515 GetVHREquipmentRef(dest, Cycle, equipRef, offhand, equip);
1516 break;
1517 case IE_ANI_TWENTYTWO:
1518 GetMHREquipmentRef(dest, Cycle, equipRef, offhand, equip);
1519 break;
1520 default:
1521 error("CharAnimations", "Unsupported animation type for equipment animation.\n");
1522 }
1523 }
1524
GetZOrder(unsigned char Orient)1525 const int* CharAnimations::GetZOrder(unsigned char Orient)
1526 {
1527 switch (GetAnimType()) {
1528 case IE_ANI_CODE_MIRROR:
1529 return zOrder_Mirror16[Orient];
1530 case IE_ANI_TWENTYTWO:
1531 return zOrder_8[Orient/2];
1532 case IE_ANI_FOUR_FILES:
1533 return 0; // FIXME
1534 case IE_ANI_TWO_PIECE:
1535 return zOrder_TwoPiece;
1536 default:
1537 return 0;
1538 }
1539 }
1540
1541
AddPSTSuffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient)1542 void CharAnimations::AddPSTSuffix(char *dest, unsigned char StanceID,
1543 unsigned char& Cycle, unsigned char Orient)
1544 {
1545 const char *Prefix;
1546
1547 switch (StanceID) {
1548 case IE_ANI_ATTACK:
1549 case IE_ANI_ATTACK_SLASH:
1550 case IE_ANI_ATTACK_JAB:
1551 case IE_ANI_ATTACK_BACKSLASH:
1552 Cycle=SixteenToFive[Orient];
1553 Prefix="at1"; break;
1554 case IE_ANI_DAMAGE:
1555 Cycle=SixteenToFive[Orient];
1556 Prefix="hit"; break;
1557 case IE_ANI_GET_UP:
1558 case IE_ANI_EMERGE:
1559 Cycle=SixteenToFive[Orient];
1560 Prefix="gup"; break;
1561 case IE_ANI_AWAKE:
1562 Cycle=SixteenToFive[Orient];
1563 Prefix="std"; break;
1564 case IE_ANI_READY:
1565 Cycle=SixteenToFive[Orient];
1566 Prefix="stc"; break;
1567 case IE_ANI_DIE:
1568 case IE_ANI_SLEEP:
1569 case IE_ANI_TWITCH:
1570 Cycle=SixteenToFive[Orient];
1571 Prefix="dfb"; break;
1572 case IE_ANI_RUN:
1573 Cycle=SixteenToNine[Orient];
1574 Prefix="run"; break;
1575 case IE_ANI_WALK:
1576 Cycle=SixteenToNine[Orient];
1577 Prefix="wlk"; break;
1578 case IE_ANI_HEAD_TURN:
1579 Cycle=SixteenToFive[Orient];
1580 if (RAND(0,1)) {
1581 Prefix="sf2";
1582 sprintf(dest,"%c%3s%4s", ResRef[0], Prefix, ResRef+1);
1583 if (gamedata->Exists(dest, IE_BAM_CLASS_ID) ) {
1584 return;
1585 }
1586 }
1587 Prefix="sf1";
1588 sprintf(dest,"%c%3s%4s", ResRef[0], Prefix, ResRef+1);
1589 if (gamedata->Exists(dest, IE_BAM_CLASS_ID) ) {
1590 return;
1591 }
1592 Prefix = "stc";
1593 break;
1594 case IE_ANI_PST_START:
1595 Cycle=0;
1596 Prefix="ms1"; break;
1597 default: //just in case
1598 Cycle=SixteenToFive[Orient];
1599 Prefix="stc"; break;
1600 }
1601 sprintf(dest,"%c%3s%4s", ResRef[0], Prefix, ResRef+1);
1602 }
1603
AddVHR2Suffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient)1604 void CharAnimations::AddVHR2Suffix(char *dest, unsigned char StanceID,
1605 unsigned char& Cycle, unsigned char Orient)
1606 {
1607 Cycle=SixteenToNine[Orient];
1608
1609 switch (StanceID) {
1610 case IE_ANI_ATTACK: //temporarily
1611 case IE_ANI_ATTACK_BACKSLASH:
1612 strcat(dest, "g21");
1613 Cycle+=9;
1614 break;
1615
1616 case IE_ANI_ATTACK_SLASH:
1617 strcat(dest, "g2");
1618 break;
1619
1620 case IE_ANI_ATTACK_JAB:
1621 strcat(dest, "g22");
1622 Cycle+=18;
1623 break;
1624
1625 case IE_ANI_CAST: //looping
1626 strcat(dest, "g25");
1627 Cycle+=45;
1628 break;
1629
1630 case IE_ANI_CONJURE://ending
1631 strcat(dest, "g26");
1632 Cycle+=54;
1633 break;
1634
1635 case IE_ANI_SHOOT:
1636 strcat(dest, "g24");
1637 Cycle+=27;
1638 break;
1639
1640 case IE_ANI_HEAD_TURN:
1641 case IE_ANI_AWAKE:
1642 strcat(dest, "g12");
1643 Cycle+=18;
1644 break;
1645
1646 case IE_ANI_SLEEP:
1647 case IE_ANI_TWITCH:
1648 strcat(dest, "g15");
1649 Cycle+=45;
1650 break;
1651
1652 case IE_ANI_DIE:
1653 case IE_ANI_EMERGE:
1654 case IE_ANI_GET_UP:
1655 case IE_ANI_PST_START:
1656 strcat(dest, "g14");
1657 Cycle+=36;
1658 break;
1659
1660 case IE_ANI_DAMAGE:
1661 strcat(dest, "g13");
1662 Cycle+=27;
1663 break;
1664
1665 case IE_ANI_READY:
1666 strcat(dest, "g1");
1667 Cycle+=9;
1668 break;
1669
1670 case IE_ANI_WALK:
1671 strcat(dest, "g11");
1672 break;
1673
1674 case IE_ANI_HIDE:
1675 strcat(dest, "g22");
1676 break;
1677 default:
1678 error("CharAnimation", "VHR2 Animation: unhandled stance: %s %d\n", dest, StanceID);
1679 }
1680 }
1681
AddVHR3Suffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient)1682 void CharAnimations::AddVHR3Suffix(char *dest, unsigned char StanceID,
1683 unsigned char& Cycle, unsigned char Orient)
1684 {
1685 Cycle=SixteenToNine[Orient];
1686
1687 switch (StanceID) {
1688 case IE_ANI_ATTACK: //temporarily
1689 case IE_ANI_ATTACK_BACKSLASH:
1690 strcat(dest, "g21");
1691 Cycle+=9;
1692 break;
1693
1694 case IE_ANI_ATTACK_SLASH:
1695 strcat(dest, "g2");
1696 break;
1697
1698 case IE_ANI_ATTACK_JAB:
1699 case IE_ANI_CONJURE://ending
1700 strcat(dest, "g22");
1701 Cycle+=18;
1702 break;
1703
1704 case IE_ANI_CAST: //looping
1705 strcat(dest, "g22");
1706 Cycle+=27;
1707 break;
1708
1709 case IE_ANI_SHOOT:
1710 strcat(dest, "g23");
1711 Cycle+=27;
1712 break;
1713
1714 case IE_ANI_HEAD_TURN:
1715 case IE_ANI_AWAKE:
1716 case IE_ANI_HIDE:
1717 strcat(dest, "g12");
1718 Cycle+=18;
1719 break;
1720
1721 case IE_ANI_SLEEP:
1722 case IE_ANI_TWITCH:
1723 strcat(dest, "g15");
1724 Cycle+=45;
1725 break;
1726
1727 case IE_ANI_DIE:
1728 case IE_ANI_EMERGE:
1729 case IE_ANI_GET_UP:
1730 case IE_ANI_PST_START:
1731 strcat(dest, "g14");
1732 Cycle+=36;
1733 break;
1734
1735 case IE_ANI_DAMAGE:
1736 strcat(dest, "g13");
1737 Cycle+=27;
1738 break;
1739
1740 case IE_ANI_READY:
1741 strcat(dest, "g1");
1742 Cycle+=9;
1743 break;
1744
1745 case IE_ANI_WALK:
1746 strcat(dest, "g11");
1747 break;
1748 default:
1749 error("CharAnimation", "VHR3 Animation: unhandled stance: %s %d\n", dest, StanceID);
1750 }
1751 }
1752
1753 // Note: almost like SixSuffix
AddFFSuffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient,int Part)1754 void CharAnimations::AddFFSuffix(char *dest, unsigned char StanceID,
1755 unsigned char& Cycle, unsigned char Orient, int Part)
1756 {
1757 Cycle=SixteenToNine[Orient];
1758 switch (StanceID) {
1759 case IE_ANI_WALK:
1760 strcat(dest, "g1");
1761 break;
1762
1763 case IE_ANI_ATTACK:
1764 case IE_ANI_ATTACK_SLASH:
1765 strcat(dest, "g3");
1766 break;
1767
1768 case IE_ANI_ATTACK_BACKSLASH:
1769 strcat(dest, "g3");
1770 Cycle += 16;
1771 break;
1772
1773 case IE_ANI_ATTACK_JAB:
1774 case IE_ANI_CAST:
1775 case IE_ANI_CONJURE:
1776 strcat(dest, "g3");
1777 Cycle += 32;
1778 break;
1779
1780 case IE_ANI_HEAD_TURN: //could be wrong
1781 case IE_ANI_HIDE: //could be wrong
1782 case IE_ANI_AWAKE:
1783 strcat(dest, "g2");
1784 break;
1785
1786 case IE_ANI_READY:
1787 strcat(dest, "g2");
1788 Cycle += 16;
1789 break;
1790
1791 case IE_ANI_DAMAGE:
1792 strcat(dest, "g2");
1793 Cycle += 32;
1794 break;
1795
1796 case IE_ANI_DIE:
1797 case IE_ANI_GET_UP:
1798 case IE_ANI_EMERGE:
1799 case IE_ANI_PST_START:
1800 strcat(dest, "g2");
1801 Cycle += 48;
1802 break;
1803
1804 case IE_ANI_SLEEP:
1805 case IE_ANI_TWITCH:
1806 strcat(dest, "g2");
1807 Cycle += 64;
1808 break;
1809
1810 default:
1811 error("CharAnimation", "Four frames Animation: unhandled stance: %s %d\n", dest, StanceID);
1812
1813 }
1814 size_t last = strnlen(dest, 6);
1815 dest[last] = (char) (Part+'1');
1816 dest[last+1] = 0;
1817 }
1818
AddFF2Suffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient,int Part) const1819 void CharAnimations::AddFF2Suffix(char *dest, unsigned char StanceID,
1820 unsigned char& Cycle, unsigned char Orient, int Part) const
1821 {
1822 Cycle = SixteenToNine[Orient];
1823 switch (StanceID) {
1824 case IE_ANI_HEAD_TURN:
1825 strcat(dest, "g101");
1826 break;
1827
1828 case IE_ANI_READY:
1829 case IE_ANI_AWAKE:
1830 strcat(dest, "g102");
1831 Cycle += 9;
1832 break;
1833
1834 case IE_ANI_WALK:
1835 strcat(dest, "g101");
1836 break;
1837
1838 case IE_ANI_CAST:
1839 case IE_ANI_CONJURE:
1840 strcat(dest, "g205");
1841 Cycle += 45;
1842 break;
1843
1844 case IE_ANI_ATTACK:
1845 case IE_ANI_ATTACK_SLASH:
1846 strcat(dest, "g206");
1847 Cycle += 54;
1848 break;
1849
1850 case IE_ANI_ATTACK_BACKSLASH:
1851 strcat(dest, "g202");
1852 break;
1853
1854 case IE_ANI_ATTACK_JAB:
1855 strcat(dest, "g203");
1856 Cycle += 18;
1857 break;
1858
1859 case IE_ANI_DIE:
1860 case IE_ANI_GET_UP:
1861 case IE_ANI_EMERGE:
1862 strcat(dest, "g104");
1863 Cycle += 36;
1864 break;
1865
1866 case IE_ANI_SLEEP:
1867 case IE_ANI_TWITCH:
1868 case IE_ANI_DAMAGE:
1869 strcat(dest, "g103");
1870 Cycle += 27;
1871 break;
1872
1873 default:
1874 error("CharAnimation", "Four frames 2 Animation: unhandled stance: %s %d\n", dest, StanceID);
1875
1876 }
1877 size_t last = strnlen(dest, 6);
1878 dest[last] = (char) (Part+'1');
1879 dest[last+1] = 0;
1880 }
1881
AddNFSuffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient,int Part)1882 void CharAnimations::AddNFSuffix(char *dest, unsigned char StanceID,
1883 unsigned char& Cycle, unsigned char Orient, int Part)
1884 {
1885 char prefix[10];
1886
1887 Cycle = SixteenToNine[Orient];
1888 snprintf(prefix, 9, "%s%c%d%c%d", dest, StancePrefix[StanceID], (Part+1)%100,
1889 CyclePrefix[StanceID], Cycle);
1890 strnlwrcpy(dest,prefix,8);
1891 Cycle=(ieByte) (Cycle+CycleOffset[StanceID]);
1892 }
1893
1894 //Attack
1895 //h1, h2, w2
1896 //static const char *SlashPrefix[]={"a1","a4","a7"};
1897 //static const char *BackPrefix[]={"a2","a5","a8"};
1898 //static const char *JabPrefix[]={"a3","a6","a9"};
1899 static const char *SlashPrefix[]={"a1","a2","a7"};
1900 static const char *BackPrefix[]={"a3","a4","a8"};
1901 static const char *JabPrefix[]={"a5","a6","a9"};
1902 static const char *RangedPrefix[]={"sa","sx","ss"};
1903 static const char *RangedPrefixOld[]={"sa","sx","a1"};
1904
AddVHRSuffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient,EquipResRefData * & EquipData)1905 void CharAnimations::AddVHRSuffix(char *dest, unsigned char StanceID,
1906 unsigned char& Cycle, unsigned char Orient, EquipResRefData*& EquipData)
1907 {
1908 Cycle = SixteenToNine[Orient];
1909 EquipData = new EquipResRefData;
1910 EquipData->Suffix[0] = 0;
1911 switch (StanceID) {
1912 case IE_ANI_ATTACK:
1913 case IE_ANI_ATTACK_SLASH:
1914 strcat(dest, SlashPrefix[WeaponType]);
1915 strlcpy(EquipData->Suffix, SlashPrefix[WeaponType], sizeof(EquipData->Suffix));
1916 break;
1917
1918 case IE_ANI_ATTACK_BACKSLASH:
1919 strcat(dest, BackPrefix[WeaponType]);
1920 strlcpy(EquipData->Suffix, BackPrefix[WeaponType], sizeof(EquipData->Suffix));
1921 break;
1922
1923 case IE_ANI_ATTACK_JAB:
1924 strcat(dest, JabPrefix[WeaponType]);
1925 strlcpy(EquipData->Suffix, JabPrefix[WeaponType], sizeof(EquipData->Suffix));
1926 break;
1927
1928 case IE_ANI_AWAKE:
1929 strcat(dest, "g17");
1930 strcpy( EquipData->Suffix, "g1" );
1931 Cycle += 63;
1932 break;
1933
1934 case IE_ANI_CAST: //looping
1935 strcat(dest, "ca");
1936 strcpy( EquipData->Suffix, "ca" );
1937 break;
1938
1939 case IE_ANI_CONJURE: //ending
1940 strcat(dest, "ca");
1941 strcpy( EquipData->Suffix, "ca" );
1942 Cycle += 9;
1943 break;
1944
1945 case IE_ANI_DAMAGE:
1946 strcat(dest, "g14");
1947 strcpy( EquipData->Suffix, "g1" );
1948 Cycle += 36;
1949 break;
1950
1951 case IE_ANI_DIE:
1952 strcat(dest, "g15");
1953 strcpy( EquipData->Suffix, "g1" );
1954 Cycle += 45;
1955 break;
1956 //I cannot find an emerge animation...
1957 //Maybe is Die reversed
1958 case IE_ANI_GET_UP:
1959 case IE_ANI_EMERGE:
1960 case IE_ANI_PST_START:
1961 strcat(dest, "g19");
1962 strcpy( EquipData->Suffix, "g1" );
1963 Cycle += 81;
1964 break;
1965
1966 case IE_ANI_HEAD_TURN:
1967 if (RAND(0,1)) {
1968 strcat(dest, "g12");
1969 Cycle += 18;
1970 } else {
1971 strcat(dest, "g18");
1972 Cycle += 72;
1973 }
1974 strcpy( EquipData->Suffix, "g1" );
1975 break;
1976
1977 //Unknown... maybe only a transparency effect apply
1978 case IE_ANI_HIDE:
1979 break;
1980
1981 case IE_ANI_READY:
1982 if ( WeaponType == IE_ANI_WEAPON_2H ) {
1983 strcat(dest, "g13");
1984 Cycle += 27;
1985 } else {
1986 strcat(dest, "g1");
1987 Cycle += 9;
1988 }
1989 strcpy( EquipData->Suffix, "g1" );
1990 break;
1991 //This depends on the ranged weapon equipped
1992 case IE_ANI_SHOOT:
1993 strcat(dest, RangedPrefix[RangedType]);
1994 strlcpy(EquipData->Suffix, RangedPrefix[RangedType], sizeof(EquipData->Suffix));
1995 break;
1996
1997 case IE_ANI_SLEEP:
1998 case IE_ANI_TWITCH:
1999 strcat(dest, "g16");
2000 strcpy( EquipData->Suffix, "g1" );
2001 Cycle += 54;
2002 break;
2003
2004 case IE_ANI_WALK:
2005 strcat(dest, "g11");
2006 strcpy( EquipData->Suffix, "g1" );
2007 break;
2008
2009 default:
2010 error("CharAnimation", "VHR Animation: unhandled stance: %s %d\n", dest, StanceID);
2011 }
2012 EquipData->Cycle = Cycle;
2013 }
2014
GetVHREquipmentRef(char * dest,unsigned char & Cycle,const char * equipRef,bool offhand,EquipResRefData * equip)2015 void CharAnimations::GetVHREquipmentRef(char *dest, unsigned char& Cycle,
2016 const char* equipRef, bool offhand,
2017 EquipResRefData* equip)
2018 {
2019 Cycle = equip->Cycle;
2020 if (offhand) {
2021 sprintf(dest, "wq%c%c%co%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix);
2022 } else {
2023 sprintf(dest, "wq%c%c%c%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix);
2024 }
2025 }
2026
AddSixSuffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient)2027 void CharAnimations::AddSixSuffix(char *dest, unsigned char StanceID,
2028 unsigned char& Cycle, unsigned char Orient)
2029 {
2030 switch (StanceID) {
2031 case IE_ANI_WALK:
2032 strcat(dest, "g1");
2033 Cycle = Orient;
2034 break;
2035
2036 case IE_ANI_ATTACK:
2037 case IE_ANI_ATTACK_SLASH:
2038 strcat(dest, "g3");
2039 Cycle = Orient;
2040 break;
2041
2042 case IE_ANI_ATTACK_BACKSLASH:
2043 strcat(dest, "g3");
2044 Cycle = 16 + Orient;
2045 break;
2046
2047 case IE_ANI_ATTACK_JAB:
2048 strcat(dest, "g3");
2049 Cycle = 32 + Orient;
2050 break;
2051
2052 case IE_ANI_HEAD_TURN: //could be wrong
2053 case IE_ANI_AWAKE:
2054 case IE_ANI_CAST: //could be wrong
2055 case IE_ANI_CONJURE:
2056 strcat(dest, "g2");
2057 Cycle = 0 + Orient;
2058 break;
2059
2060 case IE_ANI_READY:
2061 case IE_ANI_HIDE: //could be wrong
2062 strcat(dest, "g2");
2063 Cycle = 16 + Orient;
2064 break;
2065
2066 case IE_ANI_DAMAGE:
2067 strcat(dest, "g2");
2068 Cycle = 32 + Orient;
2069 break;
2070
2071 case IE_ANI_DIE:
2072 case IE_ANI_GET_UP:
2073 case IE_ANI_EMERGE:
2074 case IE_ANI_PST_START:
2075 strcat(dest, "g2");
2076 Cycle = 48 + Orient;
2077 break;
2078
2079 case IE_ANI_TWITCH:
2080 case IE_ANI_SLEEP:
2081 strcat(dest, "g2");
2082 Cycle = 64 + Orient;
2083 break;
2084
2085 default:
2086 error("CharAnimation", "Six Animation: unhandled stance: %s %d\n", dest, StanceID);
2087
2088 }
2089 if (Orient>9) {
2090 strcat(dest, "e");
2091 }
2092 }
2093
AddLR2Suffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient)2094 void CharAnimations::AddLR2Suffix(char *dest, unsigned char StanceID,
2095 unsigned char& Cycle, unsigned char Orient)
2096 {
2097 Orient /= 2;
2098
2099 switch (StanceID) {
2100 case IE_ANI_READY:
2101 case IE_ANI_CAST: //looping
2102 case IE_ANI_CONJURE://ending
2103 case IE_ANI_HIDE:
2104 case IE_ANI_WALK:
2105 case IE_ANI_AWAKE:
2106 Cycle = 0 + Orient;
2107 break;
2108
2109 case IE_ANI_SHOOT:
2110 case IE_ANI_ATTACK:
2111 case IE_ANI_ATTACK_SLASH:
2112 case IE_ANI_ATTACK_BACKSLASH:
2113 case IE_ANI_ATTACK_JAB:
2114 case IE_ANI_HEAD_TURN:
2115 Cycle = 8 + Orient;
2116 break;
2117
2118 case IE_ANI_DIE:
2119 case IE_ANI_GET_UP:
2120 case IE_ANI_EMERGE:
2121 case IE_ANI_PST_START:
2122 Cycle = 24 + Orient;
2123 break;
2124
2125 case IE_ANI_DAMAGE:
2126 Cycle = 16 + Orient;
2127 break;
2128
2129 case IE_ANI_SLEEP:
2130 case IE_ANI_TWITCH:
2131 Cycle = 32 + Orient;
2132 break;
2133 default:
2134 error("CharAnimation", "LR2 Animation: unhandled stance: %s %d\n", dest, StanceID);
2135 }
2136 if (Orient>=4) {
2137 strcat(dest, "g1e");
2138 } else {
2139 strcat(dest, "g1");
2140 }
2141 }
2142
AddMHRSuffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient,EquipResRefData * & EquipData)2143 void CharAnimations::AddMHRSuffix(char *dest, unsigned char StanceID,
2144 unsigned char& Cycle, unsigned char Orient, EquipResRefData*& EquipData)
2145 {
2146 Orient /= 2;
2147 EquipData = new EquipResRefData;
2148 EquipData->Suffix[0] = 0;
2149
2150 switch (StanceID) {
2151 case IE_ANI_ATTACK:
2152 case IE_ANI_ATTACK_SLASH:
2153 strcat (dest, SlashPrefix[WeaponType]);
2154 strlcpy(EquipData->Suffix, SlashPrefix[WeaponType], sizeof(EquipData->Suffix));
2155 Cycle = Orient;
2156 break;
2157
2158 case IE_ANI_ATTACK_BACKSLASH:
2159 strcat (dest, BackPrefix[WeaponType]);
2160 strlcpy(EquipData->Suffix, BackPrefix[WeaponType], sizeof(EquipData->Suffix));
2161 Cycle = Orient;
2162 break;
2163
2164 case IE_ANI_ATTACK_JAB:
2165 strcat (dest, JabPrefix[WeaponType]);
2166 strlcpy(EquipData->Suffix, JabPrefix[WeaponType], sizeof(EquipData->Suffix));
2167 Cycle = Orient;
2168 break;
2169
2170 case IE_ANI_READY:
2171 strcat(dest, "g1");
2172 strcpy( EquipData->Suffix, "g1" );
2173 if ( WeaponType == IE_ANI_WEAPON_2W ) {
2174 Cycle = 24 + Orient;
2175 } else {
2176 Cycle = 8 + Orient;
2177 }
2178 break;
2179
2180 case IE_ANI_CAST://looping
2181 strcat(dest, "ca");
2182 strcpy( EquipData->Suffix, "ca" );
2183 Cycle = 8 + Orient;
2184 break;
2185
2186 case IE_ANI_CONJURE://ending
2187 strcat(dest, "ca");
2188 strcpy( EquipData->Suffix, "ca" );
2189 Cycle = Orient;
2190 break;
2191
2192 case IE_ANI_DAMAGE:
2193 strcat(dest, "g1");
2194 strcpy( EquipData->Suffix, "g1" );
2195 Cycle = 40 + Orient;
2196 break;
2197
2198 case IE_ANI_DIE:
2199 case IE_ANI_GET_UP:
2200 case IE_ANI_PST_START:
2201 case IE_ANI_EMERGE: // I cannot find an emerge animation... Maybe it is Die reversed
2202 strcat(dest, "g1");
2203 strcpy( EquipData->Suffix, "g1" );
2204 Cycle = 48 + Orient;
2205 break;
2206 case IE_ANI_HEAD_TURN:
2207 strcat(dest, "g1");
2208 strcpy( EquipData->Suffix, "g1" );
2209 Cycle = 32 + Orient;
2210 break;
2211
2212 //Unknown... maybe only a transparency effect apply
2213 case IE_ANI_HIDE:
2214 break;
2215
2216 case IE_ANI_AWAKE:
2217 strcat(dest, "g1");
2218 strcpy( EquipData->Suffix, "g1" );
2219 Cycle = 16 + Orient;
2220 break;
2221
2222 //This depends on the ranged weapon equipped
2223 case IE_ANI_SHOOT:
2224 strcat (dest, RangedPrefixOld[RangedType]);
2225 strlcpy(EquipData->Suffix, RangedPrefixOld[RangedType], sizeof(EquipData->Suffix));
2226 Cycle = Orient;
2227 break;
2228
2229 case IE_ANI_SLEEP:
2230 strcat(dest, "g1");
2231 strcpy( EquipData->Suffix, "g1" );
2232 Cycle = 64 + Orient;
2233 break;
2234
2235 case IE_ANI_TWITCH:
2236 strcat(dest, "g1");
2237 strcpy( EquipData->Suffix, "g1" );
2238 Cycle = 56 + Orient;
2239 break;
2240
2241 case IE_ANI_WALK:
2242 strcat(dest, "g1");
2243 strcpy( EquipData->Suffix, "g1" );
2244 Cycle = Orient;
2245 break;
2246 default:
2247 error("CharAnimation", "MHR Animation: unhandled stance: %s %d\n", dest, StanceID);
2248 }
2249 if (Orient>=5) {
2250 strcat(dest, "e");
2251 strcat( EquipData->Suffix, "e" );
2252 }
2253 // NOTE: the two shadow animations (cshd, sshd) also have x-suffixed files,
2254 // but those are used (instead of the eastern ones) only if sprite
2255 // mirroring is on. "Mirror sprites" in bgee.lua, probably what was
2256 // SoftMirrorBlt in the original ini. Pretty useless.
2257 EquipData->Cycle = Cycle;
2258 }
2259
GetMHREquipmentRef(char * dest,unsigned char & Cycle,const char * equipRef,bool offhand,EquipResRefData * equip)2260 void CharAnimations::GetMHREquipmentRef(char *dest, unsigned char& Cycle,
2261 const char* equipRef, bool offhand,
2262 EquipResRefData* equip)
2263 {
2264 Cycle = equip->Cycle;
2265 if (offhand) {
2266 //i think there is no offhand stuff for bg1, lets use the bg2 equivalent here?
2267 sprintf(dest, "wq%c%c%co%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix);
2268 } else {
2269 sprintf(dest, "wp%c%c%c%s", GetSize(), equipRef[0], equipRef[1], equip->Suffix);
2270 }
2271 }
2272
AddTwoFileSuffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient)2273 void CharAnimations::AddTwoFileSuffix( char *dest, unsigned char StanceID,
2274 unsigned char& Cycle, unsigned char Orient)
2275 {
2276 switch(StanceID) {
2277 case IE_ANI_HEAD_TURN:
2278 Cycle = 16 + Orient / 2;
2279 break;
2280 case IE_ANI_DAMAGE:
2281 Cycle = 24 + Orient / 2;
2282 break;
2283 case IE_ANI_SLEEP:
2284 case IE_ANI_TWITCH:
2285 Cycle = 40 + Orient / 2;
2286 break;
2287 case IE_ANI_GET_UP:
2288 case IE_ANI_EMERGE:
2289 case IE_ANI_DIE:
2290 case IE_ANI_PST_START:
2291 Cycle = 32 + Orient / 2;
2292 break;
2293 case IE_ANI_WALK:
2294 Cycle = Orient / 2;
2295 break;
2296 default:
2297 Cycle = 8 + Orient / 2;
2298 break;
2299 }
2300 strcat(dest, "g1");
2301 if (Orient > 9) {
2302 strcat(dest, "e");
2303 }
2304 }
2305
AddTwoFiles5Suffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient)2306 void CharAnimations::AddTwoFiles5Suffix( char *dest, unsigned char StanceID,
2307 unsigned char& Cycle, unsigned char Orient)
2308 {
2309 const char *suffix;
2310 Cycle=SixteenToNine[Orient];
2311
2312 switch(StanceID) {
2313 case IE_ANI_WALK:
2314 suffix = "g1";
2315 break;
2316 case IE_ANI_READY:
2317 Cycle += 9;
2318 suffix = "g1";
2319 break;
2320 case IE_ANI_HEAD_TURN:
2321 Cycle += 18;
2322 suffix = "g1";
2323 break;
2324 case IE_ANI_DAMAGE:
2325 Cycle += 27;
2326 suffix = "g1";
2327 break;
2328 case IE_ANI_DIE:
2329 Cycle += 36;
2330 suffix = "g1";
2331 break;
2332 case IE_ANI_SLEEP:
2333 case IE_ANI_TWITCH:
2334 Cycle += 45;
2335 suffix = "g1";
2336 break;
2337 // dead but not quite dead...
2338 // Cycle += 54;
2339 // suffix = "g1";
2340 // break;
2341 case IE_ANI_GET_UP:
2342 case IE_ANI_EMERGE:
2343 Cycle += 63;
2344 suffix = "g1";
2345 break;
2346 case IE_ANI_ATTACK:
2347 suffix = "g2";
2348 break;
2349 case IE_ANI_SHOOT:
2350 Cycle += 9;
2351 suffix = "g2";
2352 break;
2353 // yet another attack
2354 // Cycle += 18;
2355 // suffix = "g2";
2356 // break;
2357 case IE_ANI_ATTACK_BACKSLASH:
2358 Cycle += 27;
2359 suffix = "g2";
2360 break;
2361 case IE_ANI_ATTACK_JAB:
2362 Cycle += 36;
2363 suffix = "g2";
2364 break;
2365 case IE_ANI_CONJURE:
2366 Cycle += 45;
2367 suffix = "g2";
2368 break;
2369 case IE_ANI_ATTACK_SLASH:
2370 case IE_ANI_CAST:
2371 Cycle += 54;
2372 suffix = "g2";
2373 break;
2374 default:
2375 Cycle += 18;
2376 suffix = "g1";
2377 }
2378 strcat(dest, suffix);
2379 }
2380
AddLRSuffix2(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient,EquipResRefData * & EquipData)2381 void CharAnimations::AddLRSuffix2( char *dest, unsigned char StanceID,
2382 unsigned char& Cycle, unsigned char Orient, EquipResRefData *&EquipData)
2383 {
2384 EquipData = new EquipResRefData;
2385 EquipData->Suffix[0] = 0;
2386 switch (StanceID) {
2387 case IE_ANI_ATTACK:
2388 case IE_ANI_ATTACK_BACKSLASH:
2389 case IE_ANI_ATTACK_SLASH:
2390 case IE_ANI_ATTACK_JAB:
2391 strcat(dest, "g2");
2392 strcpy( EquipData->Suffix, "g2" );
2393 Cycle = Orient / 2;
2394 break;
2395 case IE_ANI_CAST:
2396 case IE_ANI_CONJURE:
2397 case IE_ANI_SHOOT:
2398 strcat(dest, "g2");
2399 strcpy( EquipData->Suffix, "g2" );
2400 Cycle = 8 + Orient / 2;
2401 break;
2402 case IE_ANI_WALK:
2403 strcat(dest, "g1");
2404 strcpy( EquipData->Suffix, "g1" );
2405 Cycle = Orient / 2;
2406 break;
2407 case IE_ANI_READY:
2408 strcat(dest, "g1");
2409 strcpy( EquipData->Suffix, "g1" );
2410 Cycle = 8 + Orient / 2;
2411 break;
2412 case IE_ANI_HEAD_TURN: //could be wrong
2413 case IE_ANI_AWAKE:
2414 strcat(dest, "g1");
2415 strcpy( EquipData->Suffix, "g1" );
2416 Cycle = 16 + Orient / 2;
2417 break;
2418 case IE_ANI_DAMAGE:
2419 strcat(dest, "g1");
2420 strcpy( EquipData->Suffix, "g1" );
2421 Cycle = 24 + Orient / 2;
2422 break;
2423 case IE_ANI_GET_UP:
2424 case IE_ANI_EMERGE:
2425 case IE_ANI_PST_START:
2426 case IE_ANI_DIE:
2427 strcat(dest, "g1");
2428 strcpy( EquipData->Suffix, "g1" );
2429 Cycle = 32 + Orient / 2;
2430 break;
2431 case IE_ANI_SLEEP:
2432 case IE_ANI_HIDE:
2433 case IE_ANI_TWITCH:
2434 strcat(dest, "g1");
2435 strcpy( EquipData->Suffix, "g1" );
2436 Cycle = 40 + Orient / 2;
2437 break;
2438 default:
2439 error("CharAnimation", "LRSuffix2 Animation: unhandled stance: %s %d\n", dest, StanceID);
2440 }
2441 if (Orient > 9) {
2442 strcat(dest, "e");
2443 strcat( EquipData->Suffix, "e");
2444 }
2445 EquipData->Cycle = Cycle;
2446 }
2447
AddTwoPieceSuffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient,int Part)2448 void CharAnimations::AddTwoPieceSuffix(char *dest, unsigned char StanceID,
2449 unsigned char& Cycle, unsigned char Orient, int Part)
2450 {
2451 if (Part == 1) {
2452 strcat(dest, "d");
2453 }
2454
2455 switch (StanceID) {
2456 case IE_ANI_DIE:
2457 strcat(dest, "g1");
2458 Cycle = 8 + Orient / 2;
2459 break;
2460 case IE_ANI_TWITCH:
2461 case IE_ANI_SLEEP:
2462 strcat(dest, "g1");
2463 Cycle = 16 + Orient / 2;
2464 break;
2465 case IE_ANI_READY:
2466 case IE_ANI_HEAD_TURN:
2467 case IE_ANI_AWAKE:
2468 case IE_ANI_DAMAGE:
2469 strcat(dest, "g1");
2470 Cycle = 24 + Orient / 2;
2471 break;
2472 case IE_ANI_WALK:
2473 strcat(dest, "g2");
2474 Cycle = Orient / 2;
2475 break;
2476 case IE_ANI_GET_UP:
2477 case IE_ANI_EMERGE:
2478 strcat(dest, "g2");
2479 Cycle = 8 + Orient / 2;
2480 break;
2481 case IE_ANI_HIDE:
2482 strcat(dest, "g2");
2483 Cycle = 16 + Orient / 2;
2484 break;
2485 case IE_ANI_ATTACK:
2486 case IE_ANI_ATTACK_BACKSLASH:
2487 strcat(dest, "g3");
2488 Cycle = Orient / 2;
2489 break;
2490 case IE_ANI_ATTACK_SLASH:
2491 case IE_ANI_ATTACK_JAB:
2492 case IE_ANI_CAST:
2493 case IE_ANI_CONJURE:
2494 case IE_ANI_SHOOT:
2495 strcat(dest, "g3");
2496 Cycle = 8 + Orient / 2;
2497 break;
2498 default:
2499 error("CharAnimation", "Two-piece Animation: unhandled stance: %s %d", dest, StanceID);
2500 }
2501 if (Orient > 9) {
2502 strcat(dest, "e");
2503 }
2504 }
2505
AddLRSuffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient,EquipResRefData * & EquipData)2506 void CharAnimations::AddLRSuffix( char *dest, unsigned char StanceID,
2507 unsigned char& Cycle, unsigned char Orient, EquipResRefData *&EquipData)
2508 {
2509 EquipData = new EquipResRefData;
2510 EquipData->Suffix[0] = 0;
2511 switch (StanceID) {
2512 case IE_ANI_ATTACK:
2513 case IE_ANI_ATTACK_BACKSLASH:
2514 strcat(dest, "g2");
2515 strcpy( EquipData->Suffix, "g2" );
2516 Cycle = Orient / 2;
2517 break;
2518 case IE_ANI_ATTACK_SLASH:
2519 case IE_ANI_CAST:
2520 case IE_ANI_CONJURE:
2521 strcat(dest, "g2");
2522 strcpy( EquipData->Suffix, "g2" );
2523 Cycle = 8 + Orient / 2;
2524 break;
2525 case IE_ANI_ATTACK_JAB:
2526 case IE_ANI_SHOOT:
2527 strcat(dest, "g2");
2528 strcpy( EquipData->Suffix, "g2" );
2529 Cycle = 16 + Orient / 2;
2530 break;
2531 case IE_ANI_WALK:
2532 case IE_ANI_HIDE: // unknown, just a guess
2533 strcat(dest, "g1");
2534 strcpy( EquipData->Suffix, "g1" );
2535 Cycle = Orient / 2;
2536 break;
2537 case IE_ANI_AWAKE:
2538 strcat(dest, "g1");
2539 strcpy( EquipData->Suffix, "g1" );
2540 Cycle = 8 + Orient / 2;
2541 break;
2542 case IE_ANI_READY:
2543 case IE_ANI_HEAD_TURN: //could be wrong
2544 strcat(dest, "g1");
2545 strcpy( EquipData->Suffix, "g1" );
2546 Cycle = 16 + Orient / 2;
2547 break;
2548 case IE_ANI_DAMAGE:
2549 strcat(dest, "g1");
2550 strcpy( EquipData->Suffix, "g1" );
2551 Cycle = 24 + Orient / 2;
2552 break;
2553 case IE_ANI_GET_UP:
2554 case IE_ANI_EMERGE:
2555 case IE_ANI_PST_START:
2556 case IE_ANI_DIE:
2557 strcat(dest, "g1");
2558 strcpy( EquipData->Suffix, "g1" );
2559 Cycle = 32 + Orient / 2;
2560 break;
2561 case IE_ANI_TWITCH:
2562 case IE_ANI_SLEEP:
2563 strcat(dest, "g1");
2564 strcpy( EquipData->Suffix, "g1" );
2565 Cycle = 40 + Orient / 2;
2566 break;
2567 default:
2568 error("CharAnimation", "LR Animation: unhandled stance: %s %d\n", dest, StanceID);
2569 }
2570 if (Orient > 9) {
2571 strcat(dest, "e");
2572 strcat( EquipData->Suffix, "e");
2573 }
2574 EquipData->Cycle = Cycle;
2575 }
2576
GetLREquipmentRef(char * dest,unsigned char & Cycle,const char * equipRef,bool,EquipResRefData * equip)2577 void CharAnimations::GetLREquipmentRef(char *dest, unsigned char& Cycle,
2578 const char* equipRef, bool /*offhand*/,
2579 EquipResRefData* equip)
2580 {
2581 Cycle = equip->Cycle;
2582 //hackhackhack
2583 sprintf(dest, "%4s%c%s", ResRef, equipRef[0], equip->Suffix);
2584 }
2585
2586 //Only for the ogre animation (MOGR)
AddLR3Suffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient)2587 void CharAnimations::AddLR3Suffix( char *dest, unsigned char StanceID,
2588 unsigned char& Cycle, unsigned char Orient)
2589 {
2590 switch (StanceID) {
2591 case IE_ANI_ATTACK:
2592 case IE_ANI_ATTACK_BACKSLASH:
2593 strcat(dest, "g2");
2594 Cycle = Orient / 2;
2595 break;
2596 case IE_ANI_ATTACK_SLASH:
2597 case IE_ANI_ATTACK_JAB: //there is no third attack animation
2598 strcat(dest, "g2");
2599 Cycle = 8 + Orient / 2;
2600 break;
2601 case IE_ANI_CAST:
2602 case IE_ANI_CONJURE:
2603 case IE_ANI_SHOOT:
2604 strcat(dest, "g3");
2605 Cycle = Orient / 2;
2606 break;
2607 case IE_ANI_WALK:
2608 strcat(dest, "g1");
2609 Cycle = 16 + Orient / 2;
2610 break;
2611 case IE_ANI_READY:
2612 strcat(dest, "g1");
2613 Cycle = 8 + Orient / 2;
2614 break;
2615 case IE_ANI_HEAD_TURN: //could be wrong
2616 case IE_ANI_AWAKE:
2617 case IE_ANI_HIDE:
2618 strcat(dest, "g1");
2619 Cycle = Orient / 2;
2620 break;
2621 case IE_ANI_DAMAGE:
2622 strcat(dest, "g3");
2623 Cycle = 8 + Orient / 2;
2624 break;
2625 case IE_ANI_DIE:
2626 case IE_ANI_GET_UP:
2627 case IE_ANI_EMERGE:
2628 case IE_ANI_PST_START:
2629 case IE_ANI_SLEEP:
2630 strcat(dest, "g3");
2631 Cycle = 16 + Orient / 2;
2632 break;
2633 case IE_ANI_TWITCH:
2634 strcat(dest, "g3");
2635 Cycle = 24 + Orient / 2;
2636 break;
2637 default:
2638 error("CharAnimation", "LR3 Animation: unhandled stance: %s %d\n", dest, StanceID);
2639 }
2640 if (Orient > 9) {
2641 strcat(dest, "e");
2642 }
2643 }
2644
AddMMR2Suffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient)2645 void CharAnimations::AddMMR2Suffix(char *dest, unsigned char StanceID,
2646 unsigned char& Cycle, unsigned char Orient)
2647 {
2648 switch (StanceID) {
2649 case IE_ANI_ATTACK:
2650 case IE_ANI_ATTACK_SLASH:
2651 case IE_ANI_ATTACK_BACKSLASH:
2652 case IE_ANI_ATTACK_JAB:
2653 case IE_ANI_CONJURE:
2654 case IE_ANI_CAST:
2655 strcat(dest, "a1");
2656 Cycle = ( Orient / 2 );
2657 break;
2658
2659 case IE_ANI_SHOOT:
2660 strcat(dest, "a4");
2661 Cycle = ( Orient / 2 );
2662 break;
2663
2664 case IE_ANI_AWAKE:
2665 case IE_ANI_READY:
2666 strcat(dest, "sd");
2667 Cycle = ( Orient / 2 );
2668 break;
2669
2670 case IE_ANI_HEAD_TURN:
2671 strcat(dest, "sc");
2672 Cycle = ( Orient / 2 );
2673 break;
2674
2675 case IE_ANI_DAMAGE:
2676 strcat(dest, "gh");
2677 Cycle = ( Orient / 2 );
2678 break;
2679
2680 case IE_ANI_DIE:
2681 strcat(dest, "de");
2682 Cycle = ( Orient / 2 );
2683 break;
2684
2685 case IE_ANI_GET_UP:
2686 case IE_ANI_EMERGE:
2687 case IE_ANI_PST_START:
2688 strcat(dest, "gu");
2689 Cycle = ( Orient / 2 );
2690 break;
2691
2692 //Unknown... maybe only a transparency effect apply
2693 case IE_ANI_HIDE:
2694 break;
2695
2696 case IE_ANI_SLEEP:
2697 strcat(dest, "sl");
2698 Cycle = ( Orient / 2 );
2699 break;
2700
2701 case IE_ANI_TWITCH:
2702 strcat(dest, "tw");
2703 Cycle = ( Orient / 2 );
2704 break;
2705
2706 case IE_ANI_WALK:
2707 strcat(dest, "wk");
2708 Cycle = ( Orient / 2 );
2709 break;
2710 default:
2711 error("CharAnimation", "MMR Animation: unhandled stance: %s %d\n", dest, StanceID);
2712 }
2713 if (Orient > 9) {
2714 strcat(dest, "e");
2715 }
2716 }
2717
AddMMRSuffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient,bool mirror)2718 void CharAnimations::AddMMRSuffix(char *dest, unsigned char StanceID,
2719 unsigned char& Cycle, unsigned char Orient, bool mirror)
2720 {
2721 if (mirror) {
2722 Cycle = SixteenToFive[Orient];
2723 } else {
2724 Cycle = Orient / 2;
2725 }
2726 switch (StanceID) {
2727 case IE_ANI_ATTACK:
2728 case IE_ANI_ATTACK_SLASH:
2729 case IE_ANI_ATTACK_BACKSLASH:
2730 strcat(dest, "a1");
2731 break;
2732
2733 case IE_ANI_SHOOT:
2734 strcat(dest, "a4");
2735 break;
2736
2737 case IE_ANI_ATTACK_JAB:
2738 strcat(dest, "a2");
2739 break;
2740
2741 case IE_ANI_AWAKE:
2742 case IE_ANI_READY:
2743 strcat(dest, "sd");
2744 break;
2745
2746 case IE_ANI_CONJURE:
2747 strcat(dest, "ca");
2748 break;
2749
2750 case IE_ANI_CAST:
2751 strcat(dest, "sp");
2752 break;
2753
2754 case IE_ANI_HEAD_TURN:
2755 strcat(dest, "sc");
2756 break;
2757
2758 case IE_ANI_DAMAGE:
2759 strcat(dest, "gh");
2760 break;
2761
2762 case IE_ANI_DIE:
2763 strcat(dest, "de");
2764 break;
2765
2766 case IE_ANI_GET_UP:
2767 case IE_ANI_EMERGE:
2768 case IE_ANI_PST_START:
2769 strcat(dest, "gu");
2770 break;
2771
2772 //Unknown... maybe only a transparency effect apply
2773 case IE_ANI_HIDE:
2774 break;
2775
2776 case IE_ANI_SLEEP:
2777 strcat(dest, "sl");
2778 break;
2779
2780 case IE_ANI_TWITCH:
2781 strcat(dest, "tw");
2782 break;
2783
2784 case IE_ANI_WALK:
2785 strcat(dest, "wk");
2786 break;
2787 default:
2788 error("CharAnimation", "MMR Animation: unhandled stance: %s %d\n", dest, StanceID);
2789 }
2790 if (!mirror && Orient > 9) {
2791 strcat(dest, "e");
2792 }
2793 }
2794
AddHLSuffix(char * dest,unsigned char StanceID,unsigned char & Cycle,unsigned char Orient)2795 void CharAnimations::AddHLSuffix(char *dest, unsigned char StanceID,
2796 unsigned char& Cycle, unsigned char Orient)
2797 {
2798 //even orientations in 'h', odd in 'l', and since the WALK animation
2799 //with fewer orientations is first in h, all other stances in that
2800 //file need to be offset by those cycles
2801 int offset = ((Orient % 2)^1) * 8;
2802
2803 switch (StanceID) {
2804
2805 case IE_ANI_WALK:
2806 //only available in 8 orientations instead of the usual 16
2807 Cycle = 0 + Orient / 2;
2808 offset = 1;
2809 break;
2810
2811 case IE_ANI_HEAD_TURN:
2812 Cycle = offset + Orient / 2;
2813 break;
2814
2815 case IE_ANI_AWAKE:
2816 case IE_ANI_READY:
2817 //the following are not available
2818 case IE_ANI_CAST:
2819 case IE_ANI_CONJURE:
2820 case IE_ANI_HIDE:
2821 case IE_ANI_SHOOT:
2822 case IE_ANI_ATTACK:
2823 case IE_ANI_ATTACK_SLASH:
2824 case IE_ANI_ATTACK_BACKSLASH:
2825 case IE_ANI_ATTACK_JAB:
2826 Cycle = 8 + offset + Orient / 2;
2827 break;
2828
2829 case IE_ANI_DAMAGE:
2830 Cycle = 16 + offset + Orient / 2;
2831 break;
2832
2833 case IE_ANI_DIE:
2834 case IE_ANI_GET_UP:
2835 case IE_ANI_EMERGE:
2836 Cycle = 24 + offset + Orient / 2;
2837 break;
2838
2839 case IE_ANI_SLEEP:
2840 case IE_ANI_TWITCH:
2841 Cycle = 32 + offset + Orient / 2;
2842 break;
2843
2844 default:
2845 error("CharAnimation", "HL Animation: unhandled stance: %s %d", dest, StanceID);
2846 }
2847 strcat(dest, offset ? "hg1" : "lg1");
2848 if (Orient > 9) {
2849 strcat(dest, "e");
2850 }
2851 }
2852
PulseRGBModifiers()2853 void CharAnimations::PulseRGBModifiers()
2854 {
2855 unsigned long time = core->GetGame()->Ticks;
2856
2857 if (time - lastModUpdate <= 40)
2858 return;
2859
2860 if (time - lastModUpdate > 400) lastModUpdate = time - 40;
2861
2862 int inc = (time - lastModUpdate)/40;
2863
2864 if (GlobalColorMod.type != RGBModifier::NONE &&
2865 GlobalColorMod.speed > 0)
2866 {
2867 GlobalColorMod.phase += inc;
2868 for (size_t i = 0; i < PAL_MAX; ++i) {
2869 change[i] = true;
2870 }
2871
2872 // reset if done
2873 if (GlobalColorMod.phase > 2*GlobalColorMod.speed) {
2874 GlobalColorMod.type = RGBModifier::NONE;
2875 GlobalColorMod.phase = 0;
2876 GlobalColorMod.speed = 0;
2877 GlobalColorMod.locked = false;
2878 }
2879 }
2880
2881 for (size_t i = 0; i < PAL_MAX * 8; ++i) {
2882 if (ColorMods[i].type != RGBModifier::NONE &&
2883 ColorMods[i].speed > 0)
2884 {
2885 change[i>>3] = true;
2886 ColorMods[i].phase += inc;
2887 if (ColorMods[i].phase > 2*ColorMods[i].speed) {
2888 ColorMods[i].type = RGBModifier::NONE;
2889 ColorMods[i].phase = 0;
2890 ColorMods[i].speed = 0;
2891 ColorMods[i].locked = false;
2892 }
2893 }
2894 }
2895
2896 for (size_t i = 0; i < PAL_MAX; ++i) {
2897 if (change[i]) {
2898 change[i] = false;
2899 SetupColors((PaletteType) i);
2900 }
2901 }
2902
2903 lastModUpdate += inc*40;
2904 }
2905
DebugDump()2906 void CharAnimations::DebugDump()
2907 {
2908 Log (DEBUG, "CharAnimations", "Anim ID : %04x", GetAnimationID() );
2909 Log (DEBUG, "CharAnimations", "BloodColor: %d", GetBloodColor() );
2910 Log (DEBUG, "CharAnimations", "Flags : %04x", GetFlags() );
2911 }
2912
2913 }
2914