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