From cef9cc22bcbe0ad1fdeb8d071f2fb14fa24c552e Mon Sep 17 00:00:00 2001 From: cbnolok Date: Sat, 10 Aug 2024 18:59:54 +0200 Subject: [PATCH] Merged DavideRei PR: Read mobtypes.txt and handle standard and custom creatures animations #1266 --- Changelog.txt | 50 + src/CMakeSources.cmake | 2 + src/common/CUOInstall.cpp | 5 + src/common/CUOInstall.h | 3 + src/game/CServerConfig.cpp | 3 + src/game/CServerConfig.h | 1 + src/game/chars/CCharAct.cpp | 1463 ++++++++++++++++++++--- src/game/chars/CCharAttacker.cpp | 5 + src/game/chars/CCharBase.cpp | 2 +- src/game/chars/CCharNPCAct.cpp | 2 + src/game/chars/CCharSpell.cpp | 3 +- src/game/clients/CClientTarg.cpp | 3 +- src/game/uo_files/CUOMobtypes.cpp | 98 ++ src/game/uo_files/CUOMobtypes.h | 45 + src/game/uo_files/uofiles_enums.h | 102 +- src/game/uo_files/uofiles_enums_creid.h | 25 +- src/sphere.ini | 3 + 17 files changed, 1662 insertions(+), 153 deletions(-) create mode 100644 src/game/uo_files/CUOMobtypes.cpp create mode 100644 src/game/uo_files/CUOMobtypes.h diff --git a/Changelog.txt b/Changelog.txt index 011002d12..56d6c719a 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3808,3 +3808,53 @@ Added: 'H' shortcut for variables to get the value as hexadecimal. New values: SPELLFLAG_FIELD_RANDOMDECAY 02000 SPELLFLAG_NO_ELEMENTALENGINE 04000 + +10-08-2024, DavideRei +- Added: read mobtypes.txt (if available among mul files) and cache it to check animations type when using creatures animations +- Added: alert anim on NPCs when they start combat, pillage anim when they loot something (items on ground or in bodies) and "summon" anim when they are summoned or added +- Modified: now standard anims (SEA_MONSTER, ANIMAL, MONSTER) and UOP anims are handled correctly depending on which actions anim they have on anim files (checked on last client version). + Please note that some actions are handled by the client (for example walk, run, fly, getHit while flying, die) and they could not work depending on which client you are using. +- Added: missing/new actions to be used with .ANIM command. + ANIM_ALERT = 35, + ANIM_THROW = 36, + ANIM_PILLAGE = 37, + ANIM_STOMP = 38, + ANIM_FLY = 39, + ANIM_LAND = 40, + ANIM_GETHIT_AIR = 41, + ANIM_SUMMON = 42, + ANIM_SPECIAL = 43, //UOP anims + ANIM_BOSS_SPECIAL_1 = 44, //Only few UOP anims: Order Variant, Chaos Variant, Stygian Dragon, Scalis + ANIM_BOSS_SPECIAL_2 = 45, //Only few UOP anims: Order Variant, Chaos Variant, Stygian Dragon, Scalis + +- Modified: now custom anims can be handled by scripts using ANIM command under CHARDEF, to set which anim actions they have/don't have, using the following flags. + MONSTER (H slot) default configuration is with actions: 0 (Walk), 1 (Stand), 2 (Die1), 3 (Die2), 4 (Attack1), 5 (Attack2), 6 (Attack3), 10 (GetHit), 11 (Pillage), 15 (Block Right), 16 (Block Left), 17 (Idle), 18 (Fidget) + No DIE2 action = 01, + No ATTACK1 action = 02, + No ATTACK2 action = 04, + No ATTACK3 action = 08, + No GETHIT action = 010, + No PILLAGE action = 020, + STOMP action = 040, + CAST2 action = 080, + CAST3 action = 0100, + No BLOCKR action = 0200, + No BLOCKL action = 0400, + No FIDGET1 action = 0800, + No FIDGET2 action = 01000, + FLY action = 02000, + Anims with Attacks 1-2-3 in actions 9,10,11 and with GetHit in action 20 (there are many custom WOW anims with this configuration) = 0x10000 + + ANIMAL (L slot) default configuration is with all actions: 1 - 12 + No EAT action = 01, + No ALERT action = 02, + No ATTACK2 action = 04, + No GETHIT action = 08, + No FIDGET1 action = 010, + No FIDGET2 action = 020, + No LIEDOWN action = 040, + No DIE2 action = 080 + + So for example if you have a MONSTER (H slot) flying custom anim, with Cast2 action but not Pillage action you can set ANIM=020A0 + If you have a custom anim with default configuration, you don't need to set ANIM= + diff --git a/src/CMakeSources.cmake b/src/CMakeSources.cmake index d6976347d..4c5feb64b 100644 --- a/src/CMakeSources.cmake +++ b/src/CMakeSources.cmake @@ -89,6 +89,8 @@ src/game/uo_files/CUOMapList.h src/game/uo_files/CUOMapList.cpp src/game/uo_files/CUOMapMeter.h src/game/uo_files/CUOMapMeter.cpp +src/game/uo_files/CUOMobtypes.h +src/game/uo_files/CUOMobtypes.cpp src/game/uo_files/CUOMultiItemRec.h src/game/uo_files/CUOMultiItemRec.cpp src/game/uo_files/CUOStaticItemRec.h diff --git a/src/common/CUOInstall.cpp b/src/common/CUOInstall.cpp index ff252ec86..d22146431 100644 --- a/src/common/CUOInstall.cpp +++ b/src/common/CUOInstall.cpp @@ -486,6 +486,11 @@ VERFILE_TYPE CUOInstall::OpenFiles( ullong ullMask ) m_tiledata.Load(); + if (g_Cfg.m_fUseMobTypes) + { + m_mobtypes.Load(); + } + return (VERFILE_TYPE)i; } diff --git a/src/common/CUOInstall.h b/src/common/CUOInstall.h index b62151b31..f4417d531 100644 --- a/src/common/CUOInstall.h +++ b/src/common/CUOInstall.h @@ -10,6 +10,7 @@ #include "../game/uo_files/CUOTiledata.h" #include "../game/uo_files/CUOIndexRec.h" #include "../game/uo_files/CUOMapList.h" +#include "../game/uo_files/CUOMobtypes.h" #include "sphere_library/CSFile.h" #include "CSVFile.h" @@ -52,6 +53,8 @@ extern struct CUOInstall CSVFile m_CsvFiles[8]; // doors.txt, stairs.txt (x2), roof.txt, misc.txt, teleprts.txt, floors.txt, walls.txt + CUOMobTypes m_mobtypes; + public: CSString GetFullExePath( lpctstr pszName = nullptr ) const; CSString GetFullCDPath( lpctstr pszName = nullptr ) const; diff --git a/src/game/CServerConfig.cpp b/src/game/CServerConfig.cpp index 56c6df51d..87f9f526f 100644 --- a/src/game/CServerConfig.cpp +++ b/src/game/CServerConfig.cpp @@ -45,6 +45,7 @@ CServerConfig::CServerConfig() _iMapCacheTime = 2ll * 60 * MSECS_PER_SEC; _iSectorSleepDelay = 10ll * 60 * MSECS_PER_SEC; m_fUseMapDiffs = false; + m_fUseMobTypes = false; m_iDebugFlags = 0; //DEBUGF_NPC_EMOTE m_fSecure = true; @@ -707,6 +708,7 @@ enum RC_TYPE RC_USEEXTRABUFFER, // m_fUseExtraBuffer RC_USEHTTP, // m_fUseHTTP RC_USEMAPDIFFS, // m_fUseMapDiffs + RC_USEMOBTYPES, // m_fUseMobTypes RC_USENOCRYPT, // m_Usenocrypt RC_USEPACKETPRIORITY, // m_fUsePacketPriorities RC_VENDORMARKUP, // m_iVendorMarkup @@ -992,6 +994,7 @@ const CAssocReg CServerConfig::sm_szLoadKeys[RC_QTY + 1] { "USEEXTRABUFFER", { ELEM_BOOL, static_castOFFSETOF(CServerConfig,m_fUseExtraBuffer) }}, { "USEHTTP", { ELEM_INT, static_castOFFSETOF(CServerConfig,m_fUseHTTP) }}, { "USEMAPDIFFS", { ELEM_BOOL, static_castOFFSETOF(CServerConfig,m_fUseMapDiffs) }}, + { "USEMOBTYPES", { ELEM_BOOL, static_castOFFSETOF(CServerConfig,m_fUseMobTypes) } }, { "USENOCRYPT", { ELEM_BOOL, static_castOFFSETOF(CServerConfig,m_fUsenocrypt) }}, // we don't want no-crypt clients { "USEPACKETPRIORITY", { ELEM_BOOL, static_castOFFSETOF(CServerConfig,m_fUsePacketPriorities) }}, { "VENDORMARKUP", { ELEM_INT, static_castOFFSETOF(CServerConfig,m_iVendorMarkup) }}, diff --git a/src/game/CServerConfig.h b/src/game/CServerConfig.h index 0f19cf212..8e3d8e0a2 100644 --- a/src/game/CServerConfig.h +++ b/src/game/CServerConfig.h @@ -240,6 +240,7 @@ extern class CServerConfig : public CResourceHolder int64 _iMapCacheTime; // Time in sec to keep unused map data.. int64 _iSectorSleepDelay; // The mask for how long sectors will sleep. bool m_fUseMapDiffs; // Whether or not to use map diff files. + bool m_fUseMobTypes; // Whether or not to use mobtypes.txt file. CSString m_sWorldBaseDir; // save\" = world files go here. CSString m_sAcctBaseDir; // Where do the account files go/come from ? diff --git a/src/game/chars/CCharAct.cpp b/src/game/chars/CCharAct.cpp index 71ae37737..481093daa 100644 --- a/src/game/chars/CCharAct.cpp +++ b/src/game/chars/CCharAct.cpp @@ -23,6 +23,7 @@ #include "../triggers.h" #include "CChar.h" #include "CCharNPC.h" +#include "../../common/CUOInstall.h" // "GONAME", "GOTYPE", "GOCHAR" // 0 = object name @@ -900,169 +901,1337 @@ ANIM_TYPE CChar::GenerateAnimate( ANIM_TYPE action, bool fTranslate, bool fBackw case ANIM_SALUTE: case ANIM_EAT: return ANIM_HORSE_ATTACK_XBOW; + case ANIM_ALERT: + case ANIM_SUMMON: + return ANIM_HORSE_STAND; + case ANIM_PILLAGE: + return ANIM_HORSE_SLAP; default: return ANIM_HORSE_STAND; } } - else if (!IsPlayableCharacter()) //( GetDispID() < CREID_MAN ) Possible fix for anims not being displayed above 400 + else if (!IsPlayableCharacter()) { // Animals have certain anims. Monsters have others. - if (GetDispID() >= CREID_HORSE_TAN) + CUOMobTypesType mobTypesRow = { 0, 0 }; + + CREID_TYPE dispID = GetDispID(); + + //Check mobtypes.txt to get the anim type + if (g_Cfg.m_fUseMobTypes && g_Install.m_mobtypes.IsLoaded()) + { + mobTypesRow.m_type = g_Install.m_mobtypes.GetEntry((ushort)dispID)->m_type; + mobTypesRow.m_flags = g_Install.m_mobtypes.GetEntry((ushort)dispID)->m_flags; + } + else + { + //Old Method + if (GetDispID() >= CREID_HORSE_TAN) + { + mobTypesRow.m_type = 2; + } + } + + //Standard UOP Animations + if (mobTypesRow.m_flags & ATFLAG_UseUopAnimation) + { + + //Only mount animations, 3 actions + if (dispID == CREID_BOURA_AR || dispID == CREID_TARANTULA || dispID == CREID_DRAGON_SERPENTINE_ETH) + { + switch (action) + { + case ANIM_WALK_UNARM: + case ANIM_WALK_ARM: + case ANIM_WALK_WAR: + case ANIM_CAST_DIR: + case ANIM_CAST_AREA: + case ANIM_GET_HIT: + case ANIM_ATTACK_1H_SLASH: + case ANIM_ATTACK_1H_PIERCE: + case ANIM_ATTACK_1H_BASH: + case ANIM_ATTACK_2H_BASH: + case ANIM_ATTACK_2H_SLASH: + case ANIM_ATTACK_2H_PIERCE: + case ANIM_ATTACK_WRESTLE: + case ANIM_ATTACK_BOW: + case ANIM_ATTACK_XBOW: + case ANIM_HORSE_RIDE_SLOW: + return ANIM_UOP_WALK_MOUNTED; + + case ANIM_RUN_UNARM: + case ANIM_RUN_ARMED: + case ANIM_HORSE_RIDE_FAST: + return ANIM_UOP_RUN_MOUNTED; + + default: + return ANIM_UOP_STAND_MOUNTED; + } + } + //Only 3 actions + else if (dispID == CREID_HOMUNCULUS) + { + switch (action) + { + case ANIM_DIE_BACK: + case ANIM_DIE_FORWARD: + return ANIM_UOP_DIE_BACKWARD; + + case ANIM_SPECIAL: + case ANIM_SUMMON: + return ANIM_UOP_SPECIAL; + + default: + return ANIM_UOP_STAND; + } + } + + switch (action) + { + case ANIM_WALK_UNARM: + case ANIM_WALK_ARM: + //Creatures without walk animation + if (dispID == CREID_TUNNEL_SPIRIT_BODY || dispID == CREID_CHARYBDIS || (dispID >= CREID_PUMPKIN_DEMON && dispID <= CREID_CLOCKWORK_EXODUS) || dispID == CREID_JACK_IN_THE_BOX) + { + return ANIM_UOP_WALK_COMBAT; + } + else if (dispID == CREID_ANIMATED_WEAPON || dispID == CREID_LITHOS) + { + return ANIM_UOP_STAND; + } + else if (dispID == CREID_TS_TENTACLE || dispID == CREID_CHARYBDIS_TENTACLE) + { + return ANIM_UOP_STAND_COMBAT; + } + else + { + return ANIM_UOP_WALK; + } + + case ANIM_WALK_WAR: + //Creatures without walk combat animation + if (dispID == CREID_PARROT_BIRD || dispID == CREID_TURKEY_GIANT || dispID == CREID_HELLHOUND_ANCIENT || dispID == CREID_GIANT_GORILLA || dispID == CREID_HORSE_PALOMINO) + { + return ANIM_UOP_WALK; + } + else if (dispID == CREID_PHOENIX) + { + return ANIM_UOP_FLY; + } + else if (dispID == CREID_ANIMATED_WEAPON || dispID == CREID_TS_TENTACLE || dispID == CREID_CHARYBDIS_TENTACLE || dispID == CREID_LITHOS) + { + return ANIM_UOP_STAND_COMBAT; + } + else + { + return ANIM_UOP_WALK_COMBAT; + } + + case ANIM_RUN_UNARM: + case ANIM_RUN_ARMED: + //If the creature can fly we can use flying action for running + if (mobTypesRow.m_flags & ATFLAG_CanFlying) + { + //Phoenix and Parrot Bird don't have run anims + if (IsStatFlag(STATF_FLY | STATF_HOVERING) || (dispID == CREID_PARROT_BIRD || dispID == CREID_PHOENIX) ) + return ANIM_UOP_FLY; + else + return ANIM_UOP_RUN; + } + else + { + //Creatures without run anim + if (dispID == CREID_TUNNEL_SPIRIT_BODY || dispID == CREID_CHARYBDIS || (dispID >= CREID_PUMPKIN_DEMON && dispID <= CREID_CLOCKWORK_EXODUS)) + { + return ANIM_UOP_WALK_COMBAT; + } + else if (dispID == CREID_ANIMATED_WEAPON) + { + return ANIM_UOP_STAND; + } + else if (dispID == CREID_TS_TENTACLE || dispID == CREID_CHARYBDIS_TENTACLE) + { + return ANIM_UOP_STAND_COMBAT; + } + else + { + return ANIM_UOP_RUN; + } + } + + case ANIM_STAND: + //Creatures without stand anim + if (dispID == CREID_TUNNEL_SPIRIT_BODY || dispID == CREID_TS_TENTACLE || dispID == CREID_CHARYBDIS || dispID == CREID_CHARYBDIS_TENTACLE || dispID == CREID_CLOCKWORK_EXODUS || dispID == CREID_JACK_IN_THE_BOX) + { + return ANIM_UOP_STAND_COMBAT; + } + else + { + return ANIM_UOP_STAND; + } + + case ANIM_STAND_WAR_1H: + case ANIM_STAND_WAR_2H: + if (dispID == CREID_PARROT_BIRD) + { + return ANIM_UOP_STAND; + } + else + { + return ANIM_UOP_STAND_COMBAT; + } + + case ANIM_FIDGET1: + case ANIM_BOW: + case ANIM_EAT: + if (dispID == CREID_PUMPKIN_FRIGHT) + { + return ANIM_UOP_PEACE_TO_COMBAT; + } + else if (dispID == CREID_ANIMATED_WEAPON || dispID == CREID_TUNNEL_SPIRIT_BODY || dispID == CREID_TS_TENTACLE || (dispID >= CREID_CHARYBDIS && dispID <= CREID_CLOCKWORK_EXODUS) || dispID == CREID_JACK_IN_THE_BOX) + { + return ANIM_UOP_SPECIAL; + } + else + { + return ANIM_UOP_FIDGET; + } + + case ANIM_FIDGET_YAWN: + case ANIM_SALUTE: + if (dispID == CREID_PARROT_BIRD || dispID == CREID_PHOENIX || dispID == CREID_TURKEY_GIANT || dispID == CREID_PUMPKIN_DEMON) + { + return ANIM_UOP_FIDGET; + } + else if(dispID == CREID_PUMPKIN_FRIGHT) + { + return ANIM_UOP_PEACE_TO_COMBAT; + } + else if (dispID == CREID_ANIMATED_WEAPON || dispID == CREID_TS_TENTACLE || (dispID >= CREID_CHARYBDIS && dispID <= CREID_CLOCKWORK_EXODUS)) + { + return ANIM_UOP_SPECIAL; + } + else + { + return ANIM_UOP_ROAR; + } + + case ANIM_CAST_DIR: + case ANIM_CAST_AREA: + case ANIM_ATTACK_BOW: + case ANIM_ATTACK_XBOW: + case ANIM_THROW: + + // 2 actions for cast + if (dispID == CREID_CLOCKWORK_EXODUS) + { + switch (g_Rand.GetVal(2)) + { + case 0: return ANIM_UOP_CAST_1; break; + case 1: return ANIM_UOP_CAST_2; break; + } + } + //Creatures with cast action + else if (dispID == CREID_DRAGON_CRIMSON || dispID == CREID_DRAGON_PLATINUM || dispID == CREID_GRUBBER || dispID == CREID_STONE_FORM || dispID == CREID_ABYSSAL_INFERNAL + || (dispID >= CREID_ELEM_LAVA && dispID <= CREID_GARG_UNDEAD) || dispID == CREID_GOBLIN_GREEN_MAGE || dispID == CREID_MEDUSA || dispID == CREID_SLASHER_VEILS + || dispID == CREID_DRAGON_STYGIAN || dispID == CREID_LICH_PRIMEVAL || dispID == CREID_SCALIS || dispID == CREID_HELLHOUND_ANCIENT || dispID == CREID_MINOTAUR_LORD + || dispID == CREID_PUMPKIN_FRIGHT || dispID == CREID_CLOCKWORK_EXODUS || dispID == CREID_MYRMIDEX_DRONE || dispID == CREID_MYRMIDEX_WARRIOR || dispID == CREID_ZIPACTRIOTL + || dispID == CREID_LASHER || dispID == CREID_WINDRUNNER || dispID == CREID_HYDROS || dispID == CREID_JACK_IN_THE_BOX || (dispID >= CREID_LITHOS && dispID <= CREID_PYROS) + || dispID == CREID_KHAL_ANKUR || dispID == CREID_WAR_BOAR_MOUNT) + { + return ANIM_UOP_CAST_1; + } + else if (dispID == CREID_PARROT_BIRD || dispID == CREID_PHOENIX || dispID == CREID_TURKEY_GIANT) + { + return ANIM_UOP_FIDGET; + } + else if (dispID == CREID_ANIMATED_WEAPON) + { + return ANIM_UOP_SPECIAL; + } + else if (dispID == CREID_TS_TENTACLE || dispID == CREID_CHARYBDIS_TENTACLE) + { + return ANIM_UOP_ATTACK_1; + } + else if (dispID == CREID_CHARYBDIS) + { + return ANIM_UOP_GETHIT; + } + else if (dispID == CREID_PUMPKIN_DEMON) + { + return ANIM_UOP_PEACE_TO_COMBAT; + } + else + { + return ANIM_UOP_ROAR; + } + break; + + case ANIM_GET_HIT: + //No GetHit + if (dispID == CREID_TURKEY_GIANT || dispID == CREID_CLOCKWORK_EXODUS) + { + return ANIM_UOP_STAND_COMBAT; + } + else + { + return ANIM_UOP_GETHIT; + } + break; + + case ANIM_ATTACK_1H_SLASH: + case ANIM_ATTACK_1H_PIERCE: + case ANIM_ATTACK_1H_BASH: + case ANIM_ATTACK_2H_BASH: + case ANIM_ATTACK_2H_SLASH: + case ANIM_ATTACK_2H_PIERCE: + case ANIM_ATTACK_WRESTLE: + //No attack + if (dispID == CREID_TUNNEL_SPIRIT_BODY || dispID == CREID_CHARYBDIS) + { + return ANIM_UOP_BLOCK; + } + else if (dispID == CREID_PARROT_BIRD) + { + return ANIM_UOP_FIDGET; + } + //No attack 2 + else if (dispID == CREID_ANIMATED_WEAPON || dispID == CREID_TS_TENTACLE || dispID == CREID_TURKEY_GIANT || dispID == CREID_HORSE_PALOMINO || dispID == CREID_BLOOD_FOX || dispID == CREID_KRUMPUS_IMP || (dispID >= CREID_CHARYBDIS_TENTACLE && dispID <= CREID_PUMPKIN_FRIGHT) || (dispID >= CREID_DOG_NEWFOUNDLAND && dispID <= CREID_DOG_ROTTWEILER)) + { + return ANIM_UOP_ATTACK_1; + } + else + { + switch (g_Rand.GetVal(2)) + { + case 0: return ANIM_UOP_ATTACK_1; break; + case 1: return ANIM_UOP_ATTACK_2; break; + } + break; + } + + case ANIM_DIE_BACK: + return ANIM_UOP_DIE_BACKWARD; + + case ANIM_DIE_FORWARD: + //No die forward + if (dispID == CREID_ANIMATED_WEAPON || dispID == CREID_TUNNEL_SPIRIT_BODY || dispID == CREID_TS_TENTACLE || dispID == CREID_PARROT_BIRD || dispID == CREID_PHOENIX || dispID == CREID_TURKEY_GIANT + || dispID == CREID_HELLHOUND_ANCIENT || (dispID >= CREID_CHARYBDIS && dispID <= CREID_PUMPKIN_FRIGHT) || dispID == CREID_GIANT_GORILLA || dispID == CREID_BLOOD_FOX || dispID == CREID_FROST_MITE + || dispID == CREID_STRATOS || dispID == CREID_KRUMPUS_IMP || (dispID >= CREID_WAR_BOAR_MOUNT && dispID <= CREID_WAR_CAPYBARA_BABY) || (dispID >= CREID_RABBIT_DOOM_BABY && dispID <= CREID_DOG_ROTTWEILER)) + { + return ANIM_UOP_DIE_BACKWARD; + } + else + { + return ANIM_UOP_DIE_FORWARD; + } + + case ANIM_BLOCK: + //No Block + if (dispID == CREID_TURKEY_GIANT || dispID == CREID_CLOCKWORK_EXODUS) + { + return ANIM_UOP_STAND_COMBAT; + } + else if (dispID == CREID_ANIMATED_WEAPON || dispID == CREID_TS_TENTACLE || dispID == CREID_PARROT_BIRD || dispID == CREID_PHOENIX || dispID == CREID_CHARYBDIS_TENTACLE || dispID == CREID_PUMPKIN_FRIGHT || dispID == CREID_FROST_MITE) + { + return ANIM_UOP_GETHIT; + } + else + { + return ANIM_UOP_BLOCK; + } + + case ANIM_PILLAGE: + //Creatures with Pillage + if (dispID == CREID_GARG_FIRE || dispID == CREID_DRAGON_CRIMSON || dispID == CREID_DRAGON_PLATINUM || dispID == CREID_TROGLODYTE || dispID == CREID_GRUBBER || dispID == CREID_BLOODWORM || dispID == CREID_VOLLEM || dispID == CREID_GOBLIN_GRAY + || dispID == CREID_STONE_FORM || (dispID >= CREID_MADDENING_HORROR && dispID <= CREID_GOBLIN_GREEN_MAGE) || dispID == CREID_MEDUSA || dispID == CREID_SKREE || dispID == CREID_SPIDER_TRAPDOOR || dispID == CREID_FIRE_ANT || dispID == CREID_DREAM_WRAITH + || dispID == CREID_SLASHER_VEILS || dispID == CREID_GARG_ENSLAVED || dispID == CREID_DRAGON_STYGIAN || dispID == CREID_RISING_COLOSSUS || dispID == CREID_LICH_PRIMEVAL || dispID == CREID_SCALIS || dispID == CREID_MINOTAUR_LORD + || dispID == CREID_DRAGON_TURTLE || dispID == CREID_SAUROSAURUS || dispID == CREID_MYRMIDEX_LARVAE || dispID == CREID_DRAGON_TURTLE_HATCHL || dispID == CREID_MYRMIDEX_DRONE || dispID == CREID_MYRMIDEX_WARRIOR || dispID == CREID_ZIPACTRIOTL || dispID == CREID_KHAL_ANKUR) + { + return ANIM_UOP_PILLAGE; + } + else + { + return ANIM_UOP_FIDGET; + } + + case ANIM_STOMP: + return ANIM_UOP_ROAR; + + case ANIM_FLY: + return ANIM_UOP_FLY; + + case ANIM_ALERT: + return ANIM_UOP_PEACE_TO_COMBAT; + + case ANIM_SPECIAL: + return ANIM_UOP_SPECIAL; + + case ANIM_BOSS_SPECIAL_1: + case ANIM_HORSE_RIDE_SLOW: + return ANIM_UOP_WALK_MOUNTED; + + case ANIM_BOSS_SPECIAL_2: + case ANIM_HORSE_RIDE_FAST: + return ANIM_UOP_RUN_MOUNTED; + + case ANIM_HORSE_STAND: + return ANIM_UOP_STAND_MOUNTED; + + case ANIM_SUMMON: + if (dispID == CREID_WILD_TIGER || dispID == CREID_TIGER_ETHEREAL || (dispID >= CREID_GIANT_GORILLA && dispID <= CREID_TYRANNOSAURUS_REX) || dispID == CREID_LASHER || dispID == CREID_HORSE_PALOMINO + || (dispID >= CREID_TRICERATOPS && dispID <= CREID_FROST_MITE) || dispID == CREID_LION || dispID == CREID_HYDROS || (dispID >= CREID_LITHOS && dispID <= CREID_PYROS) || dispID == CREID_TIGER_UNDEAD + || (dispID >= CREID_CRAB_COCONUT_MOUNT && dispID <= CREID_CRAB_COCONUT_LARGE) || (dispID >= CREID_WAR_BOAR_MOUNT && dispID <= CREID_WAR_CAPYBARA_BABY) || (dispID >= CREID_RABBIT_DOOM_BABY && dispID <= CREID_DOG_ROTTWEILER)) + { + return ANIM_UOP_ROAR; + } + else if (dispID == CREID_PARROT_BIRD) + { + return ANIM_UOP_GETHIT; + } + else if (dispID == CREID_PHOENIX || dispID == CREID_TURKEY_GIANT || dispID == CREID_PUMPKIN_DEMON || dispID == CREID_PUMPKIN_FRIGHT) + { + return ANIM_UOP_PEACE_TO_COMBAT; + } + else + { + return ANIM_UOP_SPECIAL; + } + + default: + return ANIM_WALK_UNARM; + } + } + //Sea Monster: H slot with only 9 actions in L slot order + //Only Sea Serpent and Dolphin + else if (mobTypesRow.m_type == 1) + { + switch (action) + { + case ANIM_WALK_UNARM: + case ANIM_WALK_ARM: + case ANIM_WALK_WAR: + return ANIM_MON_WALK; + + case ANIM_RUN_UNARM: + case ANIM_RUN_ARMED: + return ANIM_MON_STAND; + + case ANIM_STAND: + case ANIM_STAND_WAR_1H: + case ANIM_STAND_WAR_2H: + return ANIM_MON_DIE1; + + case ANIM_FIDGET1: + return ANIM_MON_DIE2; + + case ANIM_FIDGET_YAWN: + return ANIM_MON_ATTACK1; + + case ANIM_CAST_DIR: + if (dispID == CREID_DOLPHIN) //Dolphin doesn't have ANIM_MON_ATTACK2 and ANIM_MON_ATTACK3 + return ANIM_MON_AttackBow; + else + return ANIM_MON_ATTACK2; + + case ANIM_CAST_AREA: + if (dispID == CREID_DOLPHIN) //Dolphin doesn't have ANIM_MON_ATTACK2 and ANIM_MON_ATTACK3 + return ANIM_MON_DIE2; + else + return ANIM_MON_ATTACK3; + + case ANIM_GET_HIT: + return ANIM_MON_AttackBow; + + case ANIM_ATTACK_1H_SLASH: + case ANIM_ATTACK_1H_PIERCE: + case ANIM_ATTACK_1H_BASH: + case ANIM_ATTACK_2H_BASH: + case ANIM_ATTACK_2H_SLASH: + case ANIM_ATTACK_2H_PIERCE: + case ANIM_ATTACK_BOW: + case ANIM_ATTACK_XBOW: + case ANIM_ATTACK_WRESTLE: + if (dispID == CREID_DOLPHIN) //Dolphin doesn't have ANIM_MON_ATTACK2 and ANIM_MON_ATTACK3 + { + switch (g_Rand.GetVal(2)) + { + case 0: return ANIM_MON_AttackBow; break; + case 1: return ANIM_MON_DIE2; break; + } + } + else + { + switch (g_Rand.GetVal(3)) + { + case 0: return ANIM_MON_ATTACK2; break; + case 1: return ANIM_MON_ATTACK2; break; + case 2: return ANIM_MON_ATTACK3; break; + } + } + break; + case ANIM_DIE_BACK: + case ANIM_DIE_FORWARD: + return ANIM_MON_AttackXBow; + + case ANIM_BLOCK: + return ANIM_MON_AttackBow; + + case ANIM_BOW: + case ANIM_SALUTE: + return ANIM_MON_ATTACK1; + + case ANIM_EAT: + case ANIM_PILLAGE: + case ANIM_ALERT: + return ANIM_MON_DIE2; + + case ANIM_THROW: + if (dispID == CREID_DOLPHIN) //Dolphin doesn't have ANIM_MON_ATTACK2 and ANIM_MON_ATTACK3 + { + return ANIM_MON_AttackBow; + } + else + { + return ANIM_MON_ATTACK2; + } + + case ANIM_SUMMON: + return ANIM_MON_ATTACK1; + + default: + return ANIM_MON_WALK; + } + } + //Animal + else if ((mobTypesRow.m_type == 2 && !(mobTypesRow.m_flags & ATFLAG_CalculateOffsetLowGroupExtended)) + || (mobTypesRow.m_type == 0 && (mobTypesRow.m_flags & ATFLAG_CalculateOffsetByLowGroup))) { - // All animals have all these anims thankfully - switch (action) - { - case ANIM_WALK_UNARM: - case ANIM_WALK_ARM: - case ANIM_WALK_WAR: - return ANIM_ANI_WALK; - case ANIM_RUN_UNARM: - case ANIM_RUN_ARMED: - return ANIM_ANI_RUN; - case ANIM_STAND: - case ANIM_STAND_WAR_1H: - case ANIM_STAND_WAR_2H: - - case ANIM_FIDGET1: - return ANIM_ANI_FIDGET1; - case ANIM_FIDGET_YAWN: - return ANIM_ANI_FIDGET2; - case ANIM_CAST_DIR: - return ANIM_ANI_ATTACK1; - case ANIM_CAST_AREA: - return ANIM_ANI_EAT; - case ANIM_GET_HIT: - return ANIM_ANI_GETHIT; - - case ANIM_ATTACK_1H_SLASH: - case ANIM_ATTACK_1H_PIERCE: - case ANIM_ATTACK_1H_BASH: - case ANIM_ATTACK_2H_BASH: - case ANIM_ATTACK_2H_SLASH: - case ANIM_ATTACK_2H_PIERCE: - case ANIM_ATTACK_BOW: - case ANIM_ATTACK_XBOW: - case ANIM_ATTACK_WRESTLE: - switch (g_Rand.GetVal(2)) - { - case 0: return ANIM_ANI_ATTACK1; - case 1: return ANIM_ANI_ATTACK2; - } + //Partial actions + if (dispID == CREID_PARROT || dispID == CREID_BIRD_CROW) + { + switch (action) + { + case ANIM_WALK_UNARM: + case ANIM_WALK_ARM: + case ANIM_WALK_WAR: + case ANIM_RUN_UNARM: + case ANIM_RUN_ARMED: + return ANIM_ANI_WALK; + + case ANIM_STAND: + case ANIM_STAND_WAR_1H: + case ANIM_STAND_WAR_2H: + return ANIM_ANI_STAND; + + case ANIM_FIDGET1: + case ANIM_CAST_DIR: + case ANIM_CAST_AREA: + case ANIM_GET_HIT: + case ANIM_BLOCK: + case ANIM_DIE_BACK: + case ANIM_DIE_FORWARD: + case ANIM_ALERT: + case ANIM_SUMMON: + return ANIM_ANI_FIDGET1; + + case ANIM_FIDGET_YAWN: + case ANIM_ATTACK_1H_SLASH: + case ANIM_ATTACK_1H_PIERCE: + case ANIM_ATTACK_1H_BASH: + case ANIM_ATTACK_2H_BASH: + case ANIM_ATTACK_2H_SLASH: + case ANIM_ATTACK_2H_PIERCE: + case ANIM_ATTACK_BOW: + case ANIM_ATTACK_XBOW: + case ANIM_ATTACK_WRESTLE: + case ANIM_BOW: + case ANIM_SALUTE: + case ANIM_EAT: + case ANIM_PILLAGE: + case ANIM_THROW: + return ANIM_ANI_FIDGET2; + + default: + return ANIM_ANI_STAND; + } + } + + ushort attackActions = 2; + + // Standard and Custom Anims + switch (action) + { + case ANIM_WALK_UNARM: + case ANIM_WALK_ARM: + case ANIM_WALK_WAR: + return ANIM_ANI_WALK; + + case ANIM_RUN_UNARM: + case ANIM_RUN_ARMED: + return ANIM_ANI_RUN; + + case ANIM_STAND: + case ANIM_STAND_WAR_1H: + case ANIM_STAND_WAR_2H: + return ANIM_ANI_STAND; + + case ANIM_FIDGET1: + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET1) + { + if (!(pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET2)) + { + return ANIM_ANI_FIDGET2; + } + else + { + return ANIM_ANI_STAND; + } + } + else + { + return ANIM_ANI_FIDGET1; + } + + case ANIM_FIDGET_YAWN: + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET2) + { + if (!(pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET1)) + { + return ANIM_ANI_FIDGET1; + } + else + { + return ANIM_ANI_STAND; + } + } + else + { + return ANIM_ANI_FIDGET2; + } + + case ANIM_CAST_DIR: + return ANIM_ANI_ATTACK1; + + case ANIM_CAST_AREA: + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_EAT) + { + return ANIM_ANI_ATTACK1; + } + else + { + return ANIM_ANI_EAT; + } + + case ANIM_GET_HIT: + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_GETHIT) + { + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET1) + { + if (!(pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET2)) + { + return ANIM_ANI_FIDGET2; + } + else + { + return ANIM_ANI_STAND; + } + } + else + { + return ANIM_ANI_FIDGET1; + } + } + else + { + return ANIM_ANI_GETHIT; + } + + case ANIM_ATTACK_1H_SLASH: + case ANIM_ATTACK_1H_PIERCE: + case ANIM_ATTACK_1H_BASH: + case ANIM_ATTACK_2H_BASH: + case ANIM_ATTACK_2H_SLASH: + case ANIM_ATTACK_2H_PIERCE: + case ANIM_ATTACK_BOW: + case ANIM_ATTACK_XBOW: + case ANIM_ATTACK_WRESTLE: + case ANIM_THROW: + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_ATTACK2) + { + attackActions--; + } + + switch (g_Rand.GetVal(attackActions)) + { + case 0: return ANIM_ANI_ATTACK1; break; + case 1: return ANIM_ANI_ATTACK2; break; + } break; - case ANIM_DIE_BACK: - return ANIM_ANI_DIE1; - case ANIM_DIE_FORWARD: - return ANIM_ANI_DIE2; - case ANIM_BLOCK: - case ANIM_BOW: - case ANIM_SALUTE: - return ANIM_ANI_SLEEP; - case ANIM_EAT: - return ANIM_ANI_EAT; - default: - break; - } - ASSERT(action < ANIM_MASK_MAX); - while (action != ANIM_WALK_UNARM && !(pCharDef->m_Anims & (1ULL << action))) - { - // This anim is not supported. Try to use one that is. - switch (action) - { - case ANIM_ANI_SLEEP: // All have this. - return ANIM_ANI_EAT; - default: - return ANIM_WALK_UNARM; - } - } + case ANIM_DIE_BACK: + return ANIM_ANI_DIE1; + + case ANIM_DIE_FORWARD: + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_DIE2) + { + return ANIM_ANI_DIE1; + } + else + { + return ANIM_ANI_DIE2; + } + + case ANIM_BLOCK: + return ANIM_ANI_GETHIT; + + case ANIM_BOW: + case ANIM_SALUTE: + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_LIEDOWN) + { + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET1) + { + if (!(pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET2)) + { + return ANIM_ANI_FIDGET2; + } + else + { + return ANIM_ANI_STAND; + } + } + else + { + return ANIM_ANI_FIDGET1; + } + } + //No Lie Down + else if (dispID == CREID_CAT || dispID == CREID_PANTHER || dispID == CREID_COW_BW || dispID == CREID_DOG || dispID == CREID_WOLF_TIMBER || (dispID >= CREID_COW_BROWN && dispID <= CREID_BULL_BROWN_DK)) + { + return ANIM_ANI_FIDGET1; + } + else if (dispID == CREID_SQUIRREL) + { + return ANIM_ANI_FIDGET2; + } + else + { + return ANIM_ANI_SLEEP; + } + + case ANIM_EAT: + case ANIM_PILLAGE: + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_EAT) + { + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET1) + { + if (!(pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET2)) + { + return ANIM_ANI_FIDGET2; + } + else + { + return ANIM_ANI_STAND; + } + } + else + { + return ANIM_ANI_FIDGET1; + } + } + else + { + return ANIM_ANI_EAT; + } + + case ANIM_ALERT: + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_ALERT) + { + if (pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET1) + { + if (!(pCharDef->m_Anims & AFLAG_CUST_ANI_NO_FIDGET2)) + { + return ANIM_ANI_FIDGET2; + } + else + { + return ANIM_ANI_STAND; + } + } + else + { + return ANIM_ANI_FIDGET1; + } + } + //No Alert + else if (dispID == CREID_SQUIRREL) + { + return ANIM_ANI_FIDGET2; + } + //Bugged Alert + else if (dispID == CREID_CAT || dispID == CREID_PANTHER || dispID == CREID_COW_BW || dispID == CREID_DOG || dispID == CREID_WOLF_TIMBER || (dispID >= CREID_COW_BROWN && dispID <= CREID_BULL_BROWN_DK)) + { + return ANIM_ANI_FIDGET2; + } + else + { + return ANIM_ANI_ALERT; + } + + case ANIM_SUMMON: + return ANIM_ANI_ATTACK1; + + default: + return ANIM_ANI_STAND; + } } - else - { - // Monsters don't have all the anims. + else + { + // Monsters don't have all the anims. + + ANIM_TYPE attack1 = ANIM_MON_ATTACK1; + ANIM_TYPE cast1 = ANIM_MON_WALK, cast2 = ANIM_MON_WALK, cast3 = ANIM_MON_WALK; + ushort castActions = 0, attackActions = 3, blockActions = 2; + + //Standard and Custom Anims + switch (action) + { + case ANIM_WALK_UNARM: + case ANIM_WALK_ARM: + case ANIM_WALK_WAR: + return ANIM_MON_WALK; + + case ANIM_RUN_UNARM: + case ANIM_RUN_ARMED: + //If the creature can fly we can use flying action for running + if ((mobTypesRow.m_flags & ATFLAG_CanFlying) + || (pCharDef->m_Anims & AFLAG_CUST_MON_FLY)) //Custom anims with Fly action + { + return ANIM_MON_FLY; + } + else + { + return ANIM_MON_WALK; + } + + case ANIM_STAND: + case ANIM_STAND_WAR_1H: + case ANIM_STAND_WAR_2H: + //Stand action in crossbow + if (mobTypesRow.m_flags & ATFLAG_IdleAt8Frame) + { + return ANIM_MON_AttackXBow; + } + else + { + return ANIM_MON_STAND; + } + + case ANIM_FIDGET1: + case ANIM_BOW: + if (pCharDef->m_Anims & AFLAG_CUST_MON_NO_FIDGET1) //Custom Anims without Fidget1 + { + if (!(pCharDef->m_Anims & AFLAG_CUST_MON_NO_FIDGET2)) //Custom Anims with Fidget2 + { + return ANIM_MON_FIDGET2; + } + else + { + return ANIM_MON_STAND; + } + } + else + { + return ANIM_MON_FIDGET1; + } + + case ANIM_FIDGET_YAWN: + case ANIM_SALUTE: + case ANIM_EAT: + if (pCharDef->m_Anims & AFLAG_CUST_MON_NO_FIDGET2) //Custom Anims without Fidget2 + { + if (!(pCharDef->m_Anims & AFLAG_CUST_MON_NO_FIDGET1)) //Custom Anims with Fidget1 + { + return ANIM_MON_FIDGET1; + } + else + { + return ANIM_MON_STAND; + } + } + else if (dispID == CREID_EAGLE || dispID == CREID_DRAGON_CRIMSON || dispID == CREID_DRAGON_PLATINUM) //No Fidget + { + return ANIM_MON_FIDGET1; + } + else + { + return ANIM_MON_FIDGET2; + } + + case ANIM_CAST_DIR: + case ANIM_CAST_AREA: + case ANIM_ATTACK_BOW: //return ANIM_MON_AttackBow; //Always Empty except for standard ID 13, 15 and 16 + case ANIM_ATTACK_XBOW: //return ANIM_MON_AttackXBow; //Always Empty except for standard ID 13, 15 and 16 + + //Check how many cast actions are present + //Stomp action is not a cast for Corpser, Earth Elemental and Gorilla + if (((mobTypesRow.m_flags & ATFLAG_StompAction) + && (dispID != CREID_CORPSER && dispID != CREID_EARTH_ELEM && dispID != CREID_GORILLA)) + || (pCharDef->m_Anims & AFLAG_CUST_MON_STOMP)) //Custom Anim with Stomp action + { + cast1 = ANIM_MON_Stomp; + castActions++; + } + //Cast 2 + if (dispID == CREID_TERA_MATRIARCH || dispID == CREID_OPHID_SHAMAN || dispID == CREID_GARGOYLE || dispID == CREID_DEMON || dispID == CREID_DEMON_SWORD || dispID == CREID_LICH + || (pCharDef->m_Anims & AFLAG_CUST_MON_CAST2)) //Custom Anim with Cast2 action + { + if (castActions == 0) + { + cast1 = ANIM_MON_Cast2; + } + else + { + cast2 = ANIM_MON_Cast2; + } + castActions++; + } + //Cast 3 + if (dispID == CREID_TERA_MATRIARCH || dispID == CREID_OPHID_SHAMAN + || (pCharDef->m_Anims & AFLAG_CUST_MON_CAST3)) //Custom Anim with Cast3 action + { + if (castActions == 0) + { + cast1 = ANIM_MON_Cast3; + } + else if (castActions == 1) + { + cast2 = ANIM_MON_Cast3; + } + else + { + cast3 = ANIM_MON_Cast3; + } + castActions++; + } + + if (castActions > 0) + { + switch (g_Rand.GetVal(castActions)) + { + case 0: return cast1; break; + case 1: return cast2; break; + case 2: return cast3; break; + } + } + else //No cast Actions + { + if (mobTypesRow.m_flags & ATFLAG_ReplaceAttack1With2) + { + attack1 = ANIM_MON_ATTACK2; + } + + //Special handling for custom anims (some WOW anims) with attacks 4-6 in 9-11 + if (pCharDef->m_Anims & AFLAG_CUST_MON_ATTACKSFROM9) + { + switch (g_Rand.GetVal(3)) + { + case 0: return ANIM_MON_AttackThrow; break; + case 1: return ANIM_MON_GETHIT; break; + case 2: return ANIM_MON_PILLAGE; break; + } + } + + if (dispID == CREID_SHADOW_LORD + || (pCharDef->m_Anims & AFLAG_CUST_MON_NO_ATTACK1)) //Custom Anim without Attack1 + { + attackActions--; + } + if (dispID == CREID_EAGLE || dispID == CREID_SHADOW_LORD + || (pCharDef->m_Anims & AFLAG_CUST_MON_NO_ATTACK2)) //Custom Anim without Attack2 + { + attackActions--; + } + if (dispID == CREID_EAGLE || dispID == CREID_DRAGON_CRIMSON || dispID == CREID_DRAGON_PLATINUM || dispID == CREID_SHADOW_LORD + || (pCharDef->m_Anims & AFLAG_CUST_MON_NO_ATTACK3)) //Custom Anim without Attack3 + { + attackActions--; + } + + if (attackActions > 0) + { + switch (g_Rand.GetVal(attackActions)) + { + case 0: return attack1; break; + case 1: return ANIM_MON_ATTACK2; break; + case 2: return ANIM_MON_ATTACK3; break; + } + } + else if (dispID == CREID_SHADOW_LORD) //No Attacks + { + switch (g_Rand.GetVal(2)) + { + case 0: return ANIM_MON_FIDGET1; break; + case 1: return ANIM_MON_FIDGET2; break; + } + } + else + { + return ANIM_MON_STAND; + } + } + break; - switch (action) - { - case ANIM_CAST_DIR: - return ANIM_MON_Stomp; - case ANIM_CAST_AREA: - return ANIM_MON_PILLAGE; - case ANIM_DIE_BACK: - return ANIM_MON_DIE1; - case ANIM_DIE_FORWARD: - return ANIM_MON_DIE2; - case ANIM_GET_HIT: - switch (g_Rand.GetValFast(3)) - { - case 0: return ANIM_MON_GETHIT; break; - case 1: return ANIM_MON_BlockRight; break; - case 2: return ANIM_MON_BlockLeft; break; - } - break; - case ANIM_ATTACK_1H_SLASH: - case ANIM_ATTACK_1H_PIERCE: - case ANIM_ATTACK_1H_BASH: - case ANIM_ATTACK_2H_BASH: - case ANIM_ATTACK_2H_PIERCE: - case ANIM_ATTACK_2H_SLASH: - case ANIM_ATTACK_BOW: - case ANIM_ATTACK_XBOW: - case ANIM_ATTACK_WRESTLE: - switch (g_Rand.GetValFast(3)) - { - case 0: return ANIM_MON_ATTACK1; - case 1: return ANIM_MON_ATTACK2; - case 2: return ANIM_MON_ATTACK3; - } + case ANIM_GET_HIT: + if (IsStatFlag(STATF_FLY | STATF_HOVERING)) //Running or Flying + { + if (mobTypesRow.m_flags & ATFLAG_Use2IfHittedWhileRunning) + { + return ANIM_MON_DIE1; + } + //GetHit while flying + else if ((mobTypesRow.m_flags & ATFLAG_CanFlying) && !(mobTypesRow.m_flags & ATFLAG_Use10IfHittedWhileFlying)) + { + return ANIM_MON_DIE_FLIGHT; + } + } + if (mobTypesRow.m_flags & ATFLAG_ReplaceGetHitBlockPillage) + { + return ANIM_MON_STAND; + } + else if (pCharDef->m_Anims & AFLAG_CUST_MON_ATTACKSFROM9) //Custom Anims with GetHit in Land/TakeOff action + { + return ANIM_MON_LAND; + } + else if (pCharDef->m_Anims & AFLAG_CUST_MON_NO_GETHIT) //Cutsom Anims without GetHit + { + if (pCharDef->m_Anims & AFLAG_CUST_MON_NO_BLOCKR) + { + blockActions--; + } + if (pCharDef->m_Anims & AFLAG_CUST_MON_NO_BLOCKL) + { + blockActions--; + } + if (blockActions > 0) + { + switch (g_Rand.GetVal(blockActions)) + { + case 0: return ANIM_MON_BlockRight; break; + case 1: return ANIM_MON_BlockLeft; break; + } + } + else + { + return ANIM_MON_STAND; + } + } + else if (dispID == CREID_BIRD || dispID == CREID_GAZER || dispID == CREID_SHADOW_LORD) //No GetHit + { + return ANIM_MON_FIDGET1; + } + else + { + return ANIM_MON_GETHIT; + } break; - default: - return ANIM_WALK_UNARM; - } - // NOTE: Available actions depend HEAVILY on creature type ! - // ??? Monsters don't have all anims in common ! - // translate these ! - ASSERT(action < ANIM_MASK_MAX); - while (action != ANIM_WALK_UNARM && !(pCharDef->m_Anims & (1ULL << action))) - { - // This anim is not supported. Try to use one that is. - switch (action) - { - case ANIM_MON_ATTACK1: // All have this. - DEBUG_ERR(("Anim 0%x This is wrong! Invalid SCP file data.\n", GetDispID())); - return ANIM_WALK_UNARM; - - case ANIM_MON_ATTACK2: // Dolphins, Eagles don't have this. - case ANIM_MON_ATTACK3: - return ANIM_MON_ATTACK1; // ALL creatures have at least this attack. - case ANIM_MON_Cast2: // Trolls, Spiders, many others don't have this. - return ANIM_MON_BlockRight; // Birds don't have this ! - case ANIM_MON_BlockRight: - return ANIM_MON_BlockLeft; - case ANIM_MON_BlockLeft: - return ANIM_MON_GETHIT; - case ANIM_MON_GETHIT: - if (pCharDef->m_Anims & (1 << ANIM_MON_Cast2)) - return ANIM_MON_Cast2; - else - return ANIM_WALK_UNARM; - - case ANIM_MON_Stomp: - return ANIM_MON_PILLAGE; - case ANIM_MON_PILLAGE: - return ANIM_MON_ATTACK3; - case ANIM_MON_AttackBow: - case ANIM_MON_AttackXBow: - return ANIM_MON_ATTACK3; - case ANIM_MON_AttackThrow: - return ANIM_MON_AttackXBow; - default: - DEBUG_ERR(("Anim Unsupported 0%x for 0%x\n", action, GetDispID())); - return ANIM_WALK_UNARM; - } - } + case ANIM_ATTACK_1H_SLASH: + case ANIM_ATTACK_1H_PIERCE: + case ANIM_ATTACK_1H_BASH: + case ANIM_ATTACK_2H_BASH: + case ANIM_ATTACK_2H_SLASH: + case ANIM_ATTACK_2H_PIERCE: + case ANIM_ATTACK_WRESTLE: + + if (mobTypesRow.m_flags & ATFLAG_ReplaceAttack1With2) + { + attack1 = ANIM_MON_ATTACK2; + } + + //Special handling for custom anims (some WOW anims) with attacks 4-6 in 9-11 + if (pCharDef->m_Anims & AFLAG_CUST_MON_ATTACKSFROM9) + { + switch (g_Rand.GetVal(3)) + { + case 0: return ANIM_MON_AttackThrow; break; + case 1: return ANIM_MON_GETHIT; break; + case 2: return ANIM_MON_PILLAGE; break; + } + } + + if (dispID == CREID_SHADOW_LORD + || (pCharDef->m_Anims & AFLAG_CUST_MON_NO_ATTACK1)) //Custom Anim without Attack1 + { + attackActions--; + } + if (dispID == CREID_EAGLE || dispID == CREID_SHADOW_LORD + || (pCharDef->m_Anims & AFLAG_CUST_MON_NO_ATTACK2)) //Custom Anim without Attack2 + { + attackActions--; + } + if (dispID == CREID_EAGLE || dispID == CREID_DRAGON_CRIMSON || dispID == CREID_DRAGON_PLATINUM || dispID == CREID_SHADOW_LORD + || (pCharDef->m_Anims & AFLAG_CUST_MON_NO_ATTACK3)) //Custom Anim without Attack3 + { + attackActions--; + } + + if (attackActions > 0) + { + switch (g_Rand.GetVal(attackActions)) + { + case 0: return attack1; break; + case 1: return ANIM_MON_ATTACK2; break; + case 2: return ANIM_MON_ATTACK3; break; + } + } + else if (dispID == CREID_SHADOW_LORD) //No Attacks + { + switch (g_Rand.GetVal(2)) + { + case 0: return ANIM_MON_FIDGET1; break; + case 1: return ANIM_MON_FIDGET2; break; + } + } + else + { + return ANIM_MON_STAND; + } + break; + + case ANIM_DIE_BACK: + //Die while flying animation + if ((mobTypesRow.m_flags & ATFLAG_StompAction) && (mobTypesRow.m_flags & ATFLAG_CanFlying) && (mobTypesRow.m_flags & ATFLAG_Use10IfHittedWhileFlying) + && IsStatFlag(STATF_FLY | STATF_HOVERING)) + { + return ANIM_MON_DIE_FLIGHT; + } + else + { + return ANIM_MON_DIE1; + } + + case ANIM_DIE_FORWARD: + //Die while flying animation + if ((mobTypesRow.m_flags & ATFLAG_StompAction) && (mobTypesRow.m_flags & ATFLAG_CanFlying) && (mobTypesRow.m_flags & ATFLAG_Use10IfHittedWhileFlying) + && IsStatFlag(STATF_FLY | STATF_HOVERING)) + { + return ANIM_MON_DIE_FLIGHT; + } + else if (pCharDef->m_Anims & AFLAG_CUST_MON_NO_DIE2) //Custom Anims without Die2 + { + return ANIM_MON_DIE1; + } + else if (dispID == CREID_SHADOW_LORD) //No Die2 + { + return ANIM_MON_DIE1; + } + else + { + return ANIM_MON_DIE2; + } + + case ANIM_BLOCK: + if (mobTypesRow.m_flags & ATFLAG_ReplaceGetHitBlockPillage) + { + return ANIM_MON_STAND; + } + else if (pCharDef->m_Anims & AFLAG_CUST_MON_ATTACKSFROM9) //Custom Anims with only Block Left + { + return ANIM_MON_BlockLeft; + } + else if (dispID == CREID_BIRD || dispID == CREID_GAZER || dispID == CREID_SLIME || dispID == CREID_SHADOW_LORD) //No block + { + return ANIM_MON_FIDGET2; + } + + if (dispID == CREID_EAGLE || dispID == CREID_CORPSER + || (pCharDef->m_Anims & AFLAG_CUST_MON_NO_BLOCKR)) //Custom anims without BlockRight + { + blockActions--; + } + if (dispID == CREID_EAGLE || dispID == CREID_CORPSER || dispID == CREID_DRAGON_CRIMSON || dispID == CREID_DRAGON_PLATINUM + || (pCharDef->m_Anims & AFLAG_CUST_MON_NO_BLOCKL)) //Custom anims without BlockLeft + { + blockActions--; + } + if (blockActions > 0) + { + switch (g_Rand.GetVal(blockActions)) + { + case 0: return ANIM_MON_BlockRight; break; + case 1: return ANIM_MON_BlockLeft; break; + } + } + else if (pCharDef->m_Anims & AFLAG_CUST_MON_NO_GETHIT) //Custom anims without GetHit + { + return ANIM_MON_STAND; + } + else + { + return ANIM_MON_GETHIT; + } + break; + + case ANIM_THROW: + if (mobTypesRow.m_flags & ATFLAG_IdleAt8Frame) //Action Throw in Bow action + { + return ANIM_MON_AttackBow; + } + else if (((mobTypesRow.m_flags & ATFLAG_StompAction) + && (dispID != CREID_CORPSER && dispID != CREID_EARTH_ELEM && dispID != CREID_GORILLA)) + || (pCharDef->m_Anims & AFLAG_CUST_MON_STOMP)) //Custom anims with Stomp action + { + return ANIM_MON_Stomp; + } + else + { + if (pCharDef->m_Anims & AFLAG_CUST_MON_ATTACKSFROM9) //Custom anims with first attack in AttackThrow + { + return ANIM_MON_AttackThrow; + } + else if (pCharDef->m_Anims & AFLAG_CUST_MON_NO_ATTACK1) //Custom anims without Attack1 + { + return ANIM_MON_STAND; + } + else + { + return ANIM_MON_ATTACK1; + //return ANIM_MON_AttackThrow; //Always Empty except for Custom Anims with AFLAG_CUST_MON_ATTACKSFROM9 flag + } + } + + case ANIM_PILLAGE: + if (mobTypesRow.m_flags & ATFLAG_ReplaceGetHitBlockPillage) + { + return ANIM_MON_FIDGET1; + } + else if (pCharDef->m_Anims & AFLAG_CUST_MON_ATTACKSFROM9) + { + return ANIM_MON_FIDGET1; + } + else if ((pCharDef->m_Anims & AFLAG_CUST_MON_NO_PILLAGE) && (!(pCharDef->m_Anims & AFLAG_CUST_MON_NO_FIDGET1))) //Custom Anims with No Pillage but Fidget1 + { + return ANIM_MON_FIDGET1; + } + else if ((pCharDef->m_Anims & AFLAG_CUST_MON_NO_PILLAGE) && (!(pCharDef->m_Anims & AFLAG_CUST_MON_NO_FIDGET2))) //Custom Anims with No Pillage but Fidget2 + { + return ANIM_MON_FIDGET2; + } + else if (dispID == CREID_BIRD || dispID == CREID_EAGLE || dispID == CREID_GAZER || dispID == CREID_SHADOW_LORD) //No Pillage + { + return ANIM_MON_FIDGET1; + } + else if (dispID == CREID_CORPSER) //No Pillage + { + return ANIM_MON_FIDGET2; + } + else + { + return ANIM_MON_PILLAGE; + } + + case ANIM_STOMP: + case ANIM_SPECIAL: + case ANIM_SUMMON: + if ((mobTypesRow.m_flags & ATFLAG_StompAction) || (pCharDef->m_Anims & AFLAG_CUST_MON_STOMP)) + { + return ANIM_MON_Stomp; + } + else if ((mobTypesRow.m_flags & ATFLAG_CanFlying) && !(pCharDef->m_Anims & AFLAG_CUST_MON_FLY)) //Standard flying anims with Land/TakeOff action + { + return ANIM_MON_LAND; + } + else + { + if (dispID == CREID_SHADOW_LORD) //No Attack + { + return ANIM_MON_FIDGET1; + } + else if (pCharDef->m_Anims & AFLAG_CUST_MON_ATTACKSFROM9) //Custom anims with first attack in AttackThrow + { + return ANIM_MON_AttackThrow; + } + else if (pCharDef->m_Anims & AFLAG_CUST_MON_NO_ATTACK1) //Custom anims without Attack1 + { + return ANIM_MON_STAND; + } + else + { + return ANIM_MON_ATTACK1; + } + } + + case ANIM_ALERT: + if (((mobTypesRow.m_flags & ATFLAG_StompAction) && dispID != CREID_CORPSER && dispID != CREID_EARTH_ELEM) + || (pCharDef->m_Anims & AFLAG_CUST_MON_STOMP)) //Custom anims with Stomp action + { + return ANIM_MON_Stomp; + } + else if ((mobTypesRow.m_flags & ATFLAG_CanFlying) && !(pCharDef->m_Anims & AFLAG_CUST_MON_FLY)) //Standard flying anims with Land/TakeOff action + { + return ANIM_MON_LAND; + } + else + { + return ANIM_MON_STAND; + } + + case ANIM_FLY: + if (mobTypesRow.m_flags & ATFLAG_ReplaceFlyAction) + { + return ANIM_MON_WALK; + } + else + { + return ANIM_MON_FLY; + } + + case ANIM_LAND: + if (mobTypesRow.m_flags & ATFLAG_ReplaceFlyAction) + { + return ANIM_MON_STAND; + } + else + { + return ANIM_MON_LAND; + } + + case ANIM_GETHIT_AIR: + if (mobTypesRow.m_flags & ATFLAG_ReplaceFlyAction) + { + return ANIM_MON_STAND; + } + else if (mobTypesRow.m_flags & ATFLAG_Use10IfHittedWhileFlying) + { + return ANIM_MON_GETHIT; + } + else + { + return ANIM_MON_DIE_FLIGHT; + } + + default: + return ANIM_MON_STAND; + } } } + else + { + //Not mounted human + switch (action) + { + case ANIM_ALERT: + return ANIM_FIDGET1; + case ANIM_SUMMON: + return ANIM_SALUTE; + case ANIM_PILLAGE: + return ANIM_BOW; + case ANIM_THROW: + return ANIM_ATTACK_1H_BASH; + } + } } return action; diff --git a/src/game/chars/CCharAttacker.cpp b/src/game/chars/CCharAttacker.cpp index c43e8ecbd..7b449d1e2 100644 --- a/src/game/chars/CCharAttacker.cpp +++ b/src/game/chars/CCharAttacker.cpp @@ -23,6 +23,11 @@ bool CChar::Attacker_Add(CChar * pChar, int threat) TRIGRET_TYPE tRet = OnTrigger(CTRIG_CombatStart, pChar, 0); if (tRet == TRIGRET_RET_TRUE) return false; + else + { + if (pChar->IsNPC()) + UpdateAnimate(ANIM_ALERT); + } } CScriptTriggerArgs Args; diff --git a/src/game/chars/CCharBase.cpp b/src/game/chars/CCharBase.cpp index a4483eafb..4914a6063 100644 --- a/src/game/chars/CCharBase.cpp +++ b/src/game/chars/CCharBase.cpp @@ -20,7 +20,7 @@ CCharBase::CCharBase( CREID_TYPE id ) : m_defense = 0; m_defenseBase = 0; m_defenseRange = 0; - m_Anims = 0xFFFFFF; + m_Anims = 0; m_MaxFood = 0; // Default value _wBloodHue = 0; m_wColor = 0; diff --git a/src/game/chars/CCharNPCAct.cpp b/src/game/chars/CCharNPCAct.cpp index eb79497c2..f9c28d38b 100644 --- a/src/game/chars/CCharNPCAct.cpp +++ b/src/game/chars/CCharNPCAct.cpp @@ -1573,6 +1573,8 @@ void CChar::NPC_Act_Looting() Speak(g_Cfg.GetDefaultMsg(DEFMSG_LOOT_RUMMAGE), HUE_TEXT_DEF, TALKMODE_EMOTE); ItemBounce(pItem, false); + UpdateAnimate(ANIM_PILLAGE); + SetTimeout(1000); } bool CChar::NPC_Act_Flee() diff --git a/src/game/chars/CCharSpell.cpp b/src/game/chars/CCharSpell.cpp index c97448fc3..922a9f068 100644 --- a/src/game/chars/CCharSpell.cpp +++ b/src/game/chars/CCharSpell.cpp @@ -354,7 +354,8 @@ CChar * CChar::Spell_Summon_Place( CChar * pChar, CPointMap ptTarg, int64 iDurat //pChar->NPC_PetSetOwner(this); pChar->OnSpellEffect(SPELL_Summon, this, Skill_GetAdjusted((SKILL_TYPE)iSkill), nullptr, false, iDuration); pChar->Update(); - pChar->UpdateAnimate(ANIM_CAST_DIR); + pChar->UpdateAnimate(ANIM_SUMMON); + pChar->SetTimeout(2000); pChar->SoundChar(CRESND_GETHIT); m_Act_UID = pChar->GetUID(); // for last target stuff return pChar; diff --git a/src/game/clients/CClientTarg.cpp b/src/game/clients/CClientTarg.cpp index 3ea9bb43e..85d379fcf 100644 --- a/src/game/clients/CClientTarg.cpp +++ b/src/game/clients/CClientTarg.cpp @@ -333,7 +333,8 @@ bool CClient::OnTarg_Char_Add( CObjBase * pObj, const CPointMap & pt ) pChar->MoveToChar(pt); pChar->NPC_CreateTrigger(); // removed from NPC_LoadScript() and triggered after char placement pChar->Update(); - pChar->UpdateAnimate(ANIM_CAST_DIR); + pChar->UpdateAnimate(ANIM_SUMMON); + pChar->SetTimeout(2000); pChar->SoundChar(CRESND_GETHIT); m_pChar->m_Act_UID = pChar->GetUID(); // for last target stuff. (trigger stuff) return true; diff --git a/src/game/uo_files/CUOMobtypes.cpp b/src/game/uo_files/CUOMobtypes.cpp new file mode 100644 index 000000000..2cf64a7ee --- /dev/null +++ b/src/game/uo_files/CUOMobtypes.cpp @@ -0,0 +1,98 @@ +/** +* @file CUOMobtypes.cpp +* +*/ + +#include "../../sphere/threads.h" +#include "../../common/CException.h" +#include "../../common/CExpression.h" +#include "../../common/CLog.h" +#include "../../common/CUOInstall.h" +#include "../../game/uo_files/uofiles_enums_creid.h" +#include "CUOMobtypes.h" + +void CUOMobTypes::Load() +{ + ADDTOCALLSTACK("CUOMobTypes::Load"); + g_Log.Event(LOGM_INIT, "Caching mobtypes.txt...\n"); + + CUOMobTypesType mobTypesRow = {0,0}; + + _mobTypesEntries.clear(); + + CSFileText csvMobTypes; + + if (g_Install.OpenFile(csvMobTypes, "mobtypes.txt", (word)(OF_READ | OF_TEXT | OF_DEFAULTMODE))) + { + _mobTypesEntries.resize(CREID_QTY); + for (int i = 0; i < _mobTypesEntries.size(); i++) + { + mobTypesRow.m_type = 4; + mobTypesRow.m_flags = 0; + _mobTypesEntries[i] = mobTypesRow; + } + + tchar* pszTemp = Str_GetTemp(); + size_t count = 0; + while (!csvMobTypes.IsEOF()) + { + csvMobTypes.ReadString(pszTemp, 200); + if (*pszTemp) + { + count++; + + std::string tmpString = pszTemp; + + int len = (int)tmpString.length(); + len = Str_TrimEndWhitespace(tmpString.data(), len); + + if (len == 0 || tmpString[0] == '#') //Empty line or commented + continue; + + //Split the string + std::vector splitArray; + splitArray.resize(3); + size_t iQty = Str_ParseCmds(tmpString.data(), splitArray.data(), 3, " \t#"); + + if (splitArray.size() < 3) + { + g_Log.EventError("Mobtypes.txt: not enough parameters on line %" PRIuSIZE_T " \n", count); + continue; + } + + if (!IsStrNumeric(splitArray[0])) + { + g_Log.EventError("Mobtypes.txt: non numeric ID on line %" PRIuSIZE_T " \n", count); + continue; + } + + int animIndex = std::stoi(splitArray[0]); + std::string sType = splitArray[1]; + if (sType == "MONSTER") + mobTypesRow.m_type = 0; + else if (sType == "SEA_MONSTER") + mobTypesRow.m_type = 1; + else if (sType == "ANIMAL") + mobTypesRow.m_type = 2; + else if (sType == "HUMAN") + mobTypesRow.m_type = 3; + else if (sType == "EQUIPMENT") + mobTypesRow.m_type = 4; + else + { + mobTypesRow.m_type = 0; + g_Log.EventError("Mobtypes.txt: wrong type found on line %" PRIuSIZE_T " \n", count); + } + + mobTypesRow.m_flags = std::strtol(splitArray[2], NULL, 16); + + if (animIndex <= _mobTypesEntries.size()) //Safety check + { + _mobTypesEntries[animIndex] = mobTypesRow; + } + } + } + csvMobTypes.Close(); + } +} + diff --git a/src/game/uo_files/CUOMobtypes.h b/src/game/uo_files/CUOMobtypes.h new file mode 100644 index 000000000..7b7c2bbb7 --- /dev/null +++ b/src/game/uo_files/CUOMobtypes.h @@ -0,0 +1,45 @@ +/** +* @file CUOMobtypes.h +* +*/ + +#ifndef _INC_CUOMOBTYPES_H +#define _INC_CUOMOBTYPES_H + +#include +#include "../../common/common.h" + +/** +* mobtypes.txt +*/ +struct CUOMobTypesType +{ + ushort m_type; // 0 = MONSTER, 1 = SEA_MONSTER, 2 = ANIMAL, 3 = HUMAN, 4 = EQUIPMENT + dword m_flags; + +}; + +class CUOMobTypes +{ + std::vector _mobTypesEntries; + +public: + void Load(); + + inline const bool IsLoaded() { + if (_mobTypesEntries.size() > 0) + return true; + else + return false; + } + + inline const CUOMobTypesType* GetEntry(ushort id) { + return &(_mobTypesEntries[id]); + } +}; + + + + + +#endif // _INC_CUOMOBTYPES_H diff --git a/src/game/uo_files/uofiles_enums.h b/src/game/uo_files/uofiles_enums.h index 72f73988e..3f30306ca 100644 --- a/src/game/uo_files/uofiles_enums.h +++ b/src/game/uo_files/uofiles_enums.h @@ -227,7 +227,48 @@ enum ANIM_TYPE // not all creatures animate the same for some reason. ANIM_ANI_SLEEP = 0x0b, // lie down (not all have this) ANIM_ANI_DIE2 = 0x0c, - ANIM_QTY_ANI = 13, + ANIM_QTY_ANI = 13, + + //UOP anims + ANIM_UOP_WALK_COMBAT = 0, + ANIM_UOP_STAND_COMBAT = 1, + ANIM_UOP_DIE_BACKWARD = 2, + ANIM_UOP_DIE_FORWARD = 3, + ANIM_UOP_ATTACK_1 = 4, + ANIM_UOP_ATTACK_2 = 5, + + ANIM_UOP_GETHIT = 10, + ANIM_UOP_PILLAGE = 11, + ANIM_UOP_CAST_1 = 12, + ANIM_UOP_CAST_2 = 13, + + ANIM_UOP_BLOCK = 15, + + ANIM_UOP_FLY = 19, + + ANIM_UOP_WALK = 22, + ANIM_UOP_SPECIAL = 23, + ANIM_UOP_RUN = 24, + ANIM_UOP_STAND = 25, + ANIM_UOP_FIDGET = 26, + ANIM_UOP_ROAR = 27, + ANIM_UOP_PEACE_TO_COMBAT = 28, + ANIM_UOP_WALK_MOUNTED = 29, //Or Boss Special 1 + ANIM_UOP_RUN_MOUNTED = 30, //Or Boss Special 2 + ANIM_UOP_STAND_MOUNTED = 31, + + //Missing actions + ANIM_ALERT = 35, + ANIM_THROW = 36, + ANIM_PILLAGE = 37, + ANIM_STOMP = 38, + ANIM_FLY = 39, + ANIM_LAND = 40, + ANIM_GETHIT_AIR = 41, + ANIM_SUMMON = 42, + ANIM_SPECIAL = 43, //UOP anims + ANIM_BOSS_SPECIAL_1 = 44, //Only few UOP anims: Order Variant, Chaos Variant, Stygian Dragon, Scalis + ANIM_BOSS_SPECIAL_2 = 45, //Only few UOP anims: Order Variant, Chaos Variant, Stygian Dragon, Scalis ANIM_QTY = 0x32, ANIM_MASK_MAX = 64 // CCharBase::m_Anims bitmask can hold a maximum of 64 values (1 << 63) @@ -280,6 +321,65 @@ enum ANIM_TYPE_NEW // not all creatures animate the same for some reason. http:/ }; +enum ANIM_TYPE_FLAGS +{ + //Mobtypes.txt + ATFLAG_None = 0x00000, + ATFLAG_Use10IfHittedWhileFlying = 0x00001, + ATFLAG_Use2IfHittedWhileRunning = 0x00002, + ATFLAG_IdleAt8Frame = 0x00004, + ATFLAG_CanFlying = 0x00008, + ATFLAG_Unknown10 = 0x00010, //HUMAN 10, Unknown + ATFLAG_CalculateOffsetLowGroupExtended = 0x00020, //Animal in Monster Slot + ATFLAG_CalculateOffsetByLowGroup = 0x00040, //Monster in Animal slot + ATFLAG_ReplaceAttack1With2 = 0x00080, + ATFLAG_ReplaceGetHitBlockPillage = 0x00100, + ATFLAG_ReplaceFlyAction = 0x00200, + ATFLAG_CalculateOffsetByPeopleGroup = 0x00400, //Animal or Monster in People slot: doesn't seems to be used + ATFLAG_Unknown800 = 0x00800, //MONSTER 800, unknown: Corpser, Gazer, Reaper + ATFLAG_StompAction = 0x01000, + ATFLAG_Unknown2000 = 0x02000, //Used for UOP but unknown + ATFLAG_Unknown4000 = 0x04000, //ANIMAL 4000, Unknown (Open Animal Backpack?) Polar Bear, HIRYU, Ridgeback, Savage Ridgeback, Giant Beetle + ATFLAG_Unknown8000 = 0x08000, //HUMAN 8000, Unknown + ATFLAG_UseUopAnimation = 0x10000, + ATFLAG_HumanPaperdoll = 0x20000, //Let Open Paperdoll in Standard Client + ATFLAG_Unknown40000 = 0x40000, //Unused + ATFLAG_Unknown80000 = 0x80000, //Unused + + //Custom in monster script ANIM= + //The default configuration is with this actions: + // 0 (Walk), 1 (Stand), 2 (Die1), 3 (Die2), + // 4 (Attack1), 5 (Attack2), 6 (Attack3), + // 10 (GetHit), 11 (Pillage), 15 (Block Right), 16 (Block Left), + // 17 (Idle), 18 (Fidget) + AFLAG_CUST_MON_NO_DIE2 = 0x01, + AFLAG_CUST_MON_NO_ATTACK1 = 0x02, + AFLAG_CUST_MON_NO_ATTACK2 = 0x04, + AFLAG_CUST_MON_NO_ATTACK3 = 0x08, + AFLAG_CUST_MON_NO_GETHIT = 0x10, + AFLAG_CUST_MON_NO_PILLAGE = 0x20, + AFLAG_CUST_MON_STOMP = 0x40, + AFLAG_CUST_MON_CAST2 = 0x80, + AFLAG_CUST_MON_CAST3 = 0x100, + AFLAG_CUST_MON_NO_BLOCKR = 0x200, + AFLAG_CUST_MON_NO_BLOCKL = 0x400, + AFLAG_CUST_MON_NO_FIDGET1 = 0x800, + AFLAG_CUST_MON_NO_FIDGET2 = 0x1000, + AFLAG_CUST_MON_FLY = 0x2000, + AFLAG_CUST_MON_ATTACKSFROM9 = 0x10000, + + //Custom in animal script ANIM= + //The default configuration is with all actions: 1 - 12 + AFLAG_CUST_ANI_NO_EAT = 0x01, + AFLAG_CUST_ANI_NO_ALERT = 0x02, + AFLAG_CUST_ANI_NO_ATTACK2 = 0x04, + AFLAG_CUST_ANI_NO_GETHIT = 0x08, + AFLAG_CUST_ANI_NO_FIDGET1 = 0x10, + AFLAG_CUST_ANI_NO_FIDGET2 = 0x20, + AFLAG_CUST_ANI_NO_LIEDOWN = 0x40, + AFLAG_CUST_ANI_NO_DIE2 = 0x80 +}; + enum CRESND_TYPE // Placeholders (not real sound IDs): the SoundChar method chooses the best sound for each creature { diff --git a/src/game/uo_files/uofiles_enums_creid.h b/src/game/uo_files/uofiles_enums_creid.h index 29f9d0a8d..cb22346d2 100644 --- a/src/game/uo_files/uofiles_enums_creid.h +++ b/src/game/uo_files/uofiles_enums_creid.h @@ -405,10 +405,11 @@ enum CREID_TYPE : uint32_t // enum the creature animations. (dont allow any othe CREID_DRAGON_STYGIAN = 0x33A, CREID_TROGLODYTE = 0x10B, CREID_GRUBBER = 0x10E, - CREID_BLOODWORM = 0x11E, + CREID_BLOODWORM = 0x11F, CREID_VOLLEM = 0x125, CREID_GOBLIN_GRAY = 0x14E, CREID_BOURA_AR = 0x1B0, // Armored boura + CREID_ANIMATED_WEAPON = 0x2B4, CREID_STONE_FORM = 0x2C1, CREID_ABYSSAL_INFERNAL = 0x2C9, CREID_BEETLE_IRON = 0x2CA, @@ -438,12 +439,16 @@ enum CREID_TYPE : uint32_t // enum the creature animations. (dont allow any othe CREID_WOLF_LEATHER = 0x2E3, CREID_DREAM_WRAITH = 0x2E4, CREID_SLASHER_VEILS = 0x2E5, + CREID_TUNNEL_SPIRIT_BODY = 0x2E6, + CREID_TS_TENTACLE = 0x2E7, CREID_VAMPIRE = 0x2E8, CREID_VAMPIRE_FEMALE = 0x2E9, CREID_GARG_ENSLAVED = 0x2F1, + CREID_RISING_COLOSSUS = 0x33d, CREID_LICH_PRIMEVAL = 0x33e, - CREID_RISING_COLOSSUS = 0x33d, + CREID_PARROT_BIRD = 0x33f, + CREID_PHOENIX = 0x340, CREID_TURKEY_GIANT = 0x402, // HS (High Seas) monsters @@ -501,6 +506,22 @@ enum CREID_TYPE : uint32_t // enum the creature animations. (dont allow any othe CREID_STRATOS = 0x598, CREID_PYROS = 0x599, CREID_DRAGON_SERPENTINE_ETH = 0x59A, + CREID_TIGER_UNDEAD = 0x5A1, + CREID_KHAL_ANKUR = 0x5C7, + CREID_KRUMPUS_IMP = 0x5CD, + CREID_CRAB_COCONUT_MOUNT = 0x5E6, + CREID_CRAB_COCONUT_SMALL = 0x5E7, + CREID_CRAB_COCONUT_LARGE = 0x5E8, + CREID_WAR_BOAR_MOUNT = 0x5F6, + CREID_WAR_CAPYBARA = 0x5F7, + CREID_WAR_CAPYBARA_BABY = 0x5F8, + CREID_RABBIT_DOOM_BABY = 0x606, + CREID_DOG_NEWFOUNDLAND = 0x60A, + CREID_DOG_ALASKAN_MALAMUTE = 0x60B, + CREID_DOG_GREAT_DANE = 0x60C, + CREID_DOG_SAINT_BERNARD = 0x60D, + CREID_DOG_BLACK_RUSSIAN_TERRIER = 0x60F, + CREID_DOG_ROTTWEILER = 0x610, /* ---- Special ---- */ diff --git a/src/sphere.ini b/src/sphere.ini index 737c8a22d..bf500f6a2 100644 --- a/src/sphere.ini +++ b/src/sphere.ini @@ -115,6 +115,9 @@ MapViewSize=18 // Max visibility for normal items, default 24. MapViewSizeMax=24 +// To enable the use of Mobtypes.txt file to check chars animations types +UseMobTypes=0 + /////////////////////////////////////////////////////////////// //////// World Save Information ///////////////////////////////////////////////////////////////