From 4ffbb3295210719738fa0b3a5362274cb4bdce9d Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Wed, 13 Jan 2021 15:05:22 +0100 Subject: [PATCH] [hellfire] Allow continuing Diablo saves in Hellfire and vice versa --- Source/drlg_l1.cpp | 6 +- Source/interfac.cpp | 1 + Source/itemdat.cpp | 43 +----------- Source/items.cpp | 48 ++++++++++++-- Source/loadsave.cpp | 86 +++++++++++++++++------- Source/loadsave.h | 4 ++ Source/multi.cpp | 1 + Source/pack.cpp | 9 ++- Source/pfile.cpp | 120 +++++++++++++++------------------- Source/pfile.h | 1 - SourceX/DiabloUI/diabloui.cpp | 2 +- structs.h | 1 + 12 files changed, 183 insertions(+), 139 deletions(-) diff --git a/Source/drlg_l1.cpp b/Source/drlg_l1.cpp index 3d90d9bac..a2f237d5b 100644 --- a/Source/drlg_l1.cpp +++ b/Source/drlg_l1.cpp @@ -2568,7 +2568,7 @@ static void DRLG_L5(int entry) } } else if (entry == ENTRY_MAIN) { if (currlevel < 21) { - if (gbIsHellfire) { + if (!plr[myplr].pOriginalCathedral) { if (DRLG_PlaceMiniSet(STAIRSUP, 1, 1, 0, 0, TRUE, -1, 0) < 0) doneflag = FALSE; if (DRLG_PlaceMiniSet(STAIRSDOWN, 1, 1, 0, 0, FALSE, -1, 1) < 0) @@ -2594,7 +2594,7 @@ static void DRLG_L5(int entry) } ViewY++; } - } else if (gbIsHellfire && entry == ENTRY_PREV) { + } else if (!plr[myplr].pOriginalCathedral && entry == ENTRY_PREV) { if (currlevel < 21) { if (DRLG_PlaceMiniSet(STAIRSUP, 1, 1, 0, 0, FALSE, -1, 0) < 0) doneflag = FALSE; @@ -2618,7 +2618,7 @@ static void DRLG_L5(int entry) } } else { if (currlevel < 21) { - if (gbIsHellfire) { + if (!plr[myplr].pOriginalCathedral) { if (DRLG_PlaceMiniSet(STAIRSUP, 1, 1, 0, 0, FALSE, -1, 0) < 0) doneflag = FALSE; if (DRLG_PlaceMiniSet(STAIRSDOWN, 1, 1, 0, 0, FALSE, -1, 1) < 0) diff --git a/Source/interfac.cpp b/Source/interfac.cpp index ecb032a88..317a5780b 100644 --- a/Source/interfac.cpp +++ b/Source/interfac.cpp @@ -314,6 +314,7 @@ void ShowProgress(unsigned int uMsg) IncProgress(); break; case WM_DIABNEWGAME: + plr[myplr].pOriginalCathedral = !gbIsHellfire; IncProgress(); FreeGameMem(); IncProgress(); diff --git a/Source/itemdat.cpp b/Source/itemdat.cpp index 9f3b879be..b5d1c9b6b 100644 --- a/Source/itemdat.cpp +++ b/Source/itemdat.cpp @@ -16,11 +16,7 @@ ItemDataStruct AllItemsList[] = { /*IDI_WARRSHLD */ { IDROP_NEVER, ICLASS_ARMOR, ILOC_ONEHAND, ICURS_BUCKLER, ITYPE_SHIELD, UITYPE_NONE, "Buckler", NULL, 2, 10, 0, 0, 3, 3, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 50, 50 }, /*IDI_WARRCLUB */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_CLUB, ITYPE_MACE, UITYPE_SPIKCLUB, "Club", NULL, 1, 20, 1, 6, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 20, 20 }, /*IDI_ROGUE */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_BOW, ITYPE_BOW, UITYPE_NONE, "Short Bow", NULL, 1, 30, 1, 4, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 100, 100 }, -#ifndef HELLFIRE -/*IDI_SORCEROR */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_STAFF, ITYPE_STAFF, UITYPE_NONE, "Short Staff of Charged Bolt", NULL, 1, 25, 2, 4, 0, 0, 0, 20, 0, ISPL_NONE, IMISC_STAFF, SPL_CBOLT, FALSE, 520, 520 }, -#else /*IDI_SORCEROR */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_STAFF, ITYPE_STAFF, UITYPE_NONE, "Short Staff of Mana", NULL, 1, 25, 2, 4, 0, 0, 0, 20, 0, ISPL_NONE, IMISC_STAFF, SPL_MANA, FALSE, 520, 520 }, -#endif /*IDI_CLEAVER */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_CLEAVER, ITYPE_AXE, UITYPE_CLEAVER, "Cleaver", NULL, 10, 10, 4, 24, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 2000, 2000 }, /*IDI_SKCROWN */ { IDROP_NEVER, ICLASS_ARMOR, ILOC_HELM, ICURS_THE_UNDEAD_CROWN, ITYPE_HELM, UITYPE_SKCROWN, "The Undead Crown", NULL, 0, 50, 0, 0, 15, 15, 0, 0, 0, ISPL_RNDSTEALLIFE, IMISC_UNIQUE, SPL_NULL, FALSE, 10000, 10000 }, /*IDI_INFRARING */ { IDROP_NEVER, ICLASS_MISC, ILOC_RING, ICURS_EMPYREAN_BAND, ITYPE_RING, UITYPE_INFRARING, "Empyrean Band", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 8000, 8000 }, @@ -37,11 +33,7 @@ ItemDataStruct AllItemsList[] = { /*IDI_FUNGALTM */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_FUNGAL_TOME, ITYPE_MISC, UITYPE_NONE, "Fungal Tome", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_SPECELIX */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SPECTRAL_ELIXIR, ITYPE_MISC, UITYPE_ELIXIR, "Spectral Elixir", NULL, 15, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SPECELIX, SPL_NULL, FALSE, 0, 0 }, /*IDI_BLDSTONE */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_BLOOD_STONE, ITYPE_MISC, UITYPE_NONE, "Blood Stone", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -#ifndef HELLFIRE -/*IDI_MAPOFDOOM */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_MAP_OF_THE_STARS, ITYPE_MISC, UITYPE_MAPOFDOOM, "Map of the Stars", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_MAPOFDOOM, SPL_NULL, TRUE, 0, 0 }, -#else /*IDI_MAPOFDOOM */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_MAP_OF_THE_STARS, ITYPE_MISC, UITYPE_MAPOFDOOM, "Cathedral Map", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_MAPOFDOOM, SPL_NULL, TRUE, 0, 0 }, -#endif /*IDI_EAR */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_EAR_SORCEROR, ITYPE_MISC, UITYPE_NONE, "Heart", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_EAR, SPL_NULL, FALSE, 0, 0 }, /*IDI_HEAL */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_HEALING, ITYPE_MISC, UITYPE_NONE, "Potion of Healing", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_HEAL, SPL_NULL, TRUE, 50, 50 }, /*IDI_MANA */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_MANA, ITYPE_MISC, UITYPE_NONE, "Potion of Mana", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_MANA, SPL_NULL, TRUE, 50, 50 }, @@ -51,28 +43,9 @@ ItemDataStruct AllItemsList[] = { /*IDI_FULLHEAL */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_FULL_HEALING, ITYPE_MISC, UITYPE_NONE, "Potion of Full Healing", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_FULLHEAL, SPL_NULL, TRUE, 150, 150 }, /*IDI_FULLMANA */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, "Potion of Full Mana", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_FULLMANA, SPL_NULL, TRUE, 150, 150 }, /*IDI_GRISWOLD */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_BROAD_SWORD, ITYPE_SWORD, UITYPE_GRISWOLD, "Griswold's Edge", NULL, 8, 50, 4, 12, 0, 0, 40, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 750, 750 }, -#ifndef HELLFIRE -/*IDI_LGTFORGE */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_MACE, ITYPE_MACE, UITYPE_LGTFORGE, "Lightforge", NULL, 2, 32, 1, 8, 0, 0, 16, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 200, 200 }, -#else /*IDI_LGTFORGE */ { IDROP_NEVER, ICLASS_ARMOR, ILOC_ARMOR, ICURS_BOVINE, ITYPE_HARMOR, UITYPE_BOVINE, "Bovine Plate", NULL, 0, 40, 0, 0, 0, 0, 50, 0, 0, ISPL_NONE, IMISC_UNIQUE, SPL_NULL, FALSE, 0, 0 }, -#endif /*IDI_LAZSTAFF */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_STAFF_OF_LAZARUS, ITYPE_MISC, UITYPE_LAZSTAFF, "Staff of Lazarus", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_RESURRECT */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Resurrect", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLLT, SPL_RESURRECT, TRUE, 250, 250 }, -#ifndef HELLFIRE -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -/* */ { IDROP_NEVER, ICLASS_NONE, ILOC_NONE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -#else /*IDI_OIL */ { IDROP_NEVER, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_OIL, ITYPE_MISC, UITYPE_NONE, "Blacksmith Oil", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_OILBSMTH, SPL_NULL, TRUE, 100, 100 }, /*IDI_SHORTSTAFF */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_STAFF, ITYPE_STAFF, UITYPE_NONE, "Short Staff", NULL, 1, 25, 2, 4, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 20, 20 }, /*IDI_BARDSWORD */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_ONEHAND, ICURS_SHORT_SWORD, ITYPE_SWORD, UITYPE_NONE, "Sword", NULL, 2, 8, 1, 5, 0, 0, 15, 0, 20, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 20, 20 }, @@ -86,7 +59,6 @@ ItemDataStruct AllItemsList[] = { /*IDI_FULLNOTE */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_RECONSTRUCTED_NOTE, ITYPE_MISC, UITYPE_NONE, "Reconstructed Note", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NOTE, SPL_NULL, TRUE, 0, 0 }, /*IDI_BROWNSUIT */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_BROWN_SUIT, ITYPE_MISC, UITYPE_NONE, "Brown Suit", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, /*IDI_GREYSUIT */ { IDROP_NEVER, ICLASS_QUEST, ILOC_UNEQUIPABLE, ICURS_GREY_SUIT, ITYPE_MISC, UITYPE_NONE, "Grey Suit", NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, -#endif /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, ICURS_CAP, ITYPE_HELM, UITYPE_NONE, "Cap", "Cap", 1, 15, 0, 0, 1, 3, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 15, 20 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, ICURS_SKULL_CAP, ITYPE_HELM, UITYPE_SKULLCAP, "Skull Cap", "Cap", 4, 20, 0, 0, 2, 4, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 25, 30 }, /* */ { IDROP_REGULAR, ICLASS_ARMOR, ILOC_HELM, ICURS_HELM, ITYPE_HELM, UITYPE_HELM, "Helm", "Helm", 8, 30, 0, 0, 4, 6, 25, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 40, 70 }, @@ -122,20 +94,16 @@ ItemDataStruct AllItemsList[] = { /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, "Potion of Full Mana", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_FULLMANA, SPL_NULL, TRUE, 150, 150 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_REJUVENATION, ITYPE_MISC, UITYPE_NONE, "Potion of Rejuvenation", NULL, 3, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_REJUV, SPL_NULL, TRUE, 120, 120 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_POTION_OF_FULL_REJUVENATION, ITYPE_MISC, UITYPE_NONE, "Potion of Full Rejuvenation", NULL, 7, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_FULLREJUV, SPL_NULL, TRUE, 600, 600 }, -#ifdef HELLFIRE /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_OIL, ITYPE_MISC, UITYPE_NONE, "Blacksmith Oil", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_OILBSMTH, SPL_NULL, TRUE, 100, 100 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_OIL, ITYPE_MISC, UITYPE_NONE, "Oil of Accuracy", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_OILACC, SPL_NULL, TRUE, 500, 500 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_OIL, ITYPE_MISC, UITYPE_NONE, "Oil of Sharpness", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_OILSHARP, SPL_NULL, TRUE, 500, 500 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_OIL, ITYPE_MISC, UITYPE_NONE, "Oil", NULL, 10, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_OILOF, SPL_NULL, TRUE, 0, 0 }, -#endif /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_ELIXIR_OF_STRENGTH, ITYPE_MISC, UITYPE_NONE, "Elixir of Strength", NULL, 15, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_ELIXSTR, SPL_NULL, TRUE, 5000, 5000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_ELIXIR_OF_MAGIC, ITYPE_MISC, UITYPE_NONE, "Elixir of Magic", NULL, 15, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_ELIXMAG, SPL_NULL, TRUE, 5000, 5000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_ELIXIR_OF_DEXTERITY, ITYPE_MISC, UITYPE_NONE, "Elixir of Dexterity", NULL, 15, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_ELIXDEX, SPL_NULL, TRUE, 5000, 5000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_ELIXIR_OF_VITALITY, ITYPE_MISC, UITYPE_NONE, "Elixir of Vitality", NULL, 20, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_ELIXVIT, SPL_NULL, TRUE, 5000, 5000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Healing", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLL, SPL_HEAL, TRUE, 50, 50 }, -#ifdef HELLFIRE /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Search", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLL, SPL_SEARCH, TRUE, 50, 50 }, -#endif /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Lightning", NULL, 4, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLLT, SPL_LIGHTNING, TRUE, 150, 150 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Identify", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLL, SPL_IDENTIFY, TRUE, 100, 100 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_SCROLL_OF, ITYPE_MISC, UITYPE_NONE, "Scroll of Resurrect", NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_SCROLLT, SPL_RESURRECT, TRUE, 250, 250 }, @@ -204,13 +172,12 @@ ItemDataStruct AllItemsList[] = { /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_RING, ICURS_RING, ITYPE_RING, UITYPE_RING, "Ring", "Ring", 15, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_RING, SPL_NULL, FALSE, 1000, 1000 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_AMULET, ICURS_AMULET, ITYPE_AMULET, UITYPE_AMULET, "Amulet", "Amulet", 8, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_AMULET, SPL_NULL, FALSE, 1200, 1200 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_AMULET, ICURS_AMULET, ITYPE_AMULET, UITYPE_AMULET, "Amulet", "Amulet", 16, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_AMULET, SPL_NULL, FALSE, 1200, 1200 }, -#ifdef HELLFIRE /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_RUNE_OF_FIRE, ITYPE_MISC, UITYPE_NONE, "Rune of Fire", "Rune", 1, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_RUNEF, SPL_NULL, TRUE, 100, 100 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_RUNE_OF_LIGHTNING, ITYPE_MISC, UITYPE_NONE, "Rune of Lightning", "Rune", 3, 0, 0, 0, 0, 0, 0, 13, 0, ISPL_NONE, IMISC_RUNEL, SPL_NULL, TRUE, 200, 200 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_GREATER_RUNE_OF_FIRE, ITYPE_MISC, UITYPE_NONE, "Greater Rune of Fire", "Rune", 7, 0, 0, 0, 0, 0, 0, 42, 0, ISPL_NONE, IMISC_GR_RUNEF, SPL_NULL, TRUE, 400, 400 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_GREATER_RUNE_OF_LIGHTNING, ITYPE_MISC, UITYPE_NONE, "Greater Rune of Lightning", "Rune", 7, 0, 0, 0, 0, 0, 0, 42, 0, ISPL_NONE, IMISC_GR_RUNEL, SPL_NULL, TRUE, 500, 500 }, /* */ { IDROP_REGULAR, ICLASS_MISC, ILOC_UNEQUIPABLE, ICURS_RUNE_OF_STONE, ITYPE_MISC, UITYPE_NONE, "Rune of Stone", "Rune", 7, 0, 0, 0, 0, 0, 0, 25, 0, ISPL_NONE, IMISC_RUNES, SPL_NULL, TRUE, 300, 300 }, -#endif +/*IDI_SORCEROR */ { IDROP_NEVER, ICLASS_WEAPON, ILOC_TWOHAND, ICURS_SHORT_STAFF, ITYPE_STAFF, UITYPE_NONE, "Short Staff of Charged Bolt", NULL, 1, 25, 2, 4, 0, 0, 0, 20, 0, ISPL_NONE, IMISC_STAFF, SPL_CBOLT, FALSE, 520, 520 }, /* */ { IDROP_NEVER, ICLASS_NONE, ILOC_INVALID, ICURS_POTION_OF_FULL_MANA, ITYPE_MISC, UITYPE_NONE, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, ISPL_NONE, IMISC_NONE, SPL_NULL, FALSE, 0, 0 }, // clang-format on }; @@ -314,7 +281,7 @@ const PLStruct PL_Prefix[] = { { "Bountiful", IPL_CHARGES, 3, 3, 9, PLT_STAFF , GOE_ANY, FALSE, TRUE, 3000, 3000, 3 }, { "Flaming", IPL_FIREDAM, 1, 10, 7, PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 5000, 5000, 2 }, { "Lightning", IPL_LIGHTDAM, 2, 20, 18, PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 10000, 10000, 2 }, -#ifdef HELLFIRE +#ifdef HELLFIRE { "Jester's", IPL_JESTERS, 1, 1, 7, PLT_WEAP , GOE_ANY, FALSE, TRUE, 1200, 1200, 3 }, { "Crystalline", IPL_CRYSTALLINE, 30, 70, 5, PLT_WEAP , GOE_ANY, FALSE, TRUE, 1000, 3000, 3 }, { "Doppelganger's", IPL_DOPPELGANGER, 81, 95, 11, PLT_WEAP | PLT_STAFF , GOE_ANY, FALSE, TRUE, 2000, 2400, 10 }, @@ -485,11 +452,7 @@ const UItemStruct UniqueItemList[] = { { "Veil of Steel", UITYPE_STEELVEIL, 1, 6, 63800, IPL_ALLRES, 50, 50, IPL_LIGHT_CURSE, 2, 2, IPL_ACP, 60, 60, IPL_MANA_CURSE, 30, 30, IPL_STR, 15, 15, IPL_VIT, 15, 15 }, { "Arkaine's Valor", UITYPE_ARMOFVAL, 1, 4, 42000, IPL_SETAC, 25, 25, IPL_VIT, 10, 10, IPL_GETHIT, 3, 3, IPL_FASTRECOVER, 3, 3, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Griswold's Edge", UITYPE_GRISWOLD, 1, 6, 42000, IPL_FIREDAM, 1, 10, IPL_TOHIT, 25, 25, IPL_FASTATTACK, 2, 2, IPL_KNOCKBACK, 0, 0, IPL_MANA, 20, 20, IPL_LIFE_CURSE, 20, 20 }, -#ifdef HELLFIRE { "Bovine Plate", UITYPE_BOVINE, 1, 6, 400, IPL_SETAC, 150, 150, IPL_INDESTRUCTIBLE, 0, 0, IPL_LIGHT, 5, 5, IPL_ALLRES, 30, 30, IPL_MANA_CURSE, 50, 50, IPL_SPLLVLADD, -2, -2 }, -#else - { "Lightforge", UITYPE_MACE, 1, 6, 26675, IPL_LIGHT, 4, 4, IPL_DAMP, 150, 150, IPL_TOHIT, 25, 25, IPL_FIREDAM, 10, 20, IPL_INDESTRUCTIBLE, 0, 0, IPL_ATTRIBS, 8, 8 }, -#endif { "The Rift Bow", UITYPE_SHORTBOW, 1, 3, 1800, IPL_RNDARROWVEL, 0, 0, IPL_DAMMOD, 2, 2, IPL_DEX_CURSE, 3, 3, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "The Needler", UITYPE_SHORTBOW, 2, 4, 8900, IPL_TOHIT, 50, 50, IPL_SETDAM, 1, 3, IPL_FASTATTACK, 2, 2, IPL_INVCURS, 158, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "The Celestial Bow", UITYPE_LONGBOW, 2, 4, 1200, IPL_NOMINSTR, 0, 0, IPL_DAMMOD, 2, 2, IPL_SETAC, 5, 5, IPL_INVCURS, 133, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, @@ -570,7 +533,6 @@ const UItemStruct UniqueItemList[] = { { "The Bleeder", UITYPE_RING, 2, 4, 8500, IPL_MAGICRES, 20, 20, IPL_MANA, 30, 30, IPL_LIFE_CURSE, 10, 10, IPL_INVCURS, 8, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Constricting Ring", UITYPE_RING, 5, 3, 62000, IPL_ALLRES, 75, 75, IPL_DRAINLIFE, 0, 0, IPL_INVCURS, 14, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Ring of Engagement", UITYPE_RING, 11, 5, 12476, IPL_GETHIT, 1, 2, IPL_THORNS, 1, 3, IPL_SETAC, 5, 5, IPL_TARGAC, 4, 12, IPL_INVCURS, 13, 0, IPL_TOHIT, 0, 0 }, -#ifdef HELLFIRE { "Giant's Knuckle", UITYPE_RING, 8, 3, 8000, IPL_STR, 60, 60, IPL_DEX_CURSE, 30, 30, IPL_INVCURS, 179, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Mercurial Ring", UITYPE_RING, 8, 3, 8000, IPL_DEX, 60, 60, IPL_STR_CURSE, 30, 30, IPL_INVCURS, 176, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Xorine's Ring", UITYPE_RING, 8, 3, 8000, IPL_MAG, 60, 60, IPL_STR_CURSE, 30, 30, IPL_INVCURS, 168, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, @@ -591,7 +553,6 @@ const UItemStruct UniqueItemList[] = { { "Demon Plate Armor", UITYPE_FULLPLATE, 25, 3, 80000, IPL_SETAC, 80, 80, IPL_ACDEMON, 0, 0, IPL_INVCURS, 225, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Acolyte's Amulet", UITYPE_AMULET, 10, 2, 10000, IPL_MANATOLIFE, 50, 50, IPL_INVCURS, 183, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, { "Gladiator's Ring", UITYPE_RING, 10, 2, 10000, IPL_LIFETOMANA, 40, 40, IPL_INVCURS, 186, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, -#endif { "", UITYPE_INVALID, 0, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0, IPL_TOHIT, 0, 0 }, // clang-format on }; diff --git a/Source/items.cpp b/Source/items.cpp index 79e72286e..660a6af2f 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -319,6 +319,18 @@ int premiumLvlAddHellfire[] = { // clang-format on }; +bool ShouldSkipItem(int i) +{ + if (!gbIsHellfire) { + return (i >= 35 && i <= 47) // Hellfire exclusive items + || (i >= 83 && i <= 86) // Oils + || i == 92 // Scroll of Search + || (i >= 161 && i <= 165); // Runes + } + + return false; +} + int get_ring_max_value(int i) { int j, res; @@ -1353,14 +1365,13 @@ void CreatePlrItems(int p) GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_RIGHT]); #ifdef _DEBUG - if (!debug_mode_key_w) { + if (!debug_mode_key_w) #endif + { SetPlrHandItem(&plr[p].HoldItem, IDI_WARRCLUB); GetPlrHandSeed(&plr[p].HoldItem); AutoPlace(p, 0, 1, 3, TRUE); -#ifdef _DEBUG } -#endif SetPlrHandItem(&plr[p].SpdList[0], IDI_HEAL); GetPlrHandSeed(&plr[p].SpdList[0]); @@ -1379,7 +1390,7 @@ void CreatePlrItems(int p) GetPlrHandSeed(&plr[p].SpdList[1]); break; case PC_SORCERER: - SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], IDI_SORCEROR); + SetPlrHandItem(&plr[p].InvBody[INVLOC_HAND_LEFT], gbIsHellfire ? IDI_SORCEROR : 166); GetPlrHandSeed(&plr[p].InvBody[INVLOC_HAND_LEFT]); SetPlrHandItem(&plr[p].SpdList[0], gbIsHellfire ? IDI_HEAL : IDI_MANA); @@ -2478,6 +2489,9 @@ int RndItem(int m) ri = 0; for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) { + if (ShouldSkipItem(i)) + continue; + if (AllItemsList[i].iRnd == IDROP_DOUBLE && monster[m].mLevel >= AllItemsList[i].iMinMLvl && ri < 512) { ril[ri] = i; @@ -2510,6 +2524,9 @@ int RndUItem(int m) int curlv = items_get_currlevel(); ri = 0; for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) { + if (ShouldSkipItem(i)) + continue; + okflag = TRUE; if (AllItemsList[i].iRnd == IDROP_NEVER) okflag = FALSE; @@ -2552,6 +2569,9 @@ int RndAllItems() int curlv = items_get_currlevel(); ri = 0; for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) { + if (ShouldSkipItem(i)) + continue; + if (AllItemsList[i].iRnd != IDROP_NEVER && 2 * curlv >= AllItemsList[i].iMinMLvl && ri < 512) { ril[ri] = i; ri++; @@ -2573,6 +2593,9 @@ int RndTypeItems(int itype, int imid, int lvl) ri = 0; for (i = 0; AllItemsList[i].iLoc != ILOC_INVALID; i++) { + if (ShouldSkipItem(i)) + continue; + okflag = TRUE; if (AllItemsList[i].iRnd == IDROP_NEVER) okflag = FALSE; @@ -2602,6 +2625,8 @@ int CheckUnique(int i, int lvl, int uper, BOOL recreate) numu = 0; memset(uok, 0, sizeof(uok)); for (j = 0; UniqueItemList[j].UIItemId != UITYPE_INVALID; j++) { + if (!gbIsHellfire && j > 89) + break; if (UniqueItemList[j].UIItemId == AllItemsList[item[i].IDidx].iItemId && lvl >= UniqueItemList[j].UIMinLvl && (recreate || !UniqueItemFlag[j] || gbMaxPlayers != 1)) { @@ -4488,6 +4513,9 @@ int RndSmithItem(int lvl) ri = 0; for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) { + if (ShouldSkipItem(i)) + continue; + if (AllItemsList[i].iRnd != IDROP_NEVER && SmithItemOk(i) && lvl >= AllItemsList[i].iMinMLvl && ri < 512) { ril[ri] = i; @@ -4604,6 +4632,9 @@ int RndPremiumItem(int minlvl, int maxlvl) ri = 0; for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) { + if (ShouldSkipItem(i)) + continue; + if (AllItemsList[i].iRnd != IDROP_NEVER) { if (PremiumItemOk(i)) { if (AllItemsList[i].iMinMLvl >= minlvl && AllItemsList[i].iMinMLvl <= maxlvl && ri < 512) { @@ -4797,6 +4828,9 @@ int RndWitchItem(int lvl) ri = 0; for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) { + if (ShouldSkipItem(i)) + continue; + if (AllItemsList[i].iRnd != IDROP_NEVER && WitchItemOk(i) && lvl >= AllItemsList[i].iMinMLvl && ri < 512) { @@ -4931,6 +4965,9 @@ int RndBoyItem(int lvl) ri = 0; for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) { + if (ShouldSkipItem(i)) + continue; + if (AllItemsList[i].iRnd != IDROP_NEVER && PremiumItemOk(i) && lvl >= AllItemsList[i].iMinMLvl && ri < 512) { ril[ri] = i; @@ -5147,6 +5184,9 @@ int RndHealerItem(int lvl) ri = 0; for (i = 1; AllItemsList[i].iLoc != ILOC_INVALID; i++) { + if (ShouldSkipItem(i)) + continue; + if (AllItemsList[i].iRnd != IDROP_NEVER && HealerItemOk(i) && lvl >= AllItemsList[i].iMinMLvl && ri < 512) { ril[ri] = i; diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index b8ac4f24d..045724d6e 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -19,15 +19,7 @@ static char BLoad() return *tbuff++; } -static int WLoad() -{ - int rv = *tbuff++ << 24; - rv |= *tbuff++ << 16; - rv |= *tbuff++ << 8; - rv |= *tbuff++; - - return rv; -} +#define WLoad ILoad static int ILoad() { @@ -183,6 +175,9 @@ static void LoadItemData(ItemStruct *pItem) tbuff += 1; // Alignment CopyInt(tbuff, &pItem->_iStatFlag); CopyInt(tbuff, &pItem->IDidx); + if (!gbIsHellfireSaveGame) { + pItem->IDidx = RemapItemIdxFromDiablo(pItem->IDidx); + } CopyInt(tbuff, &pItem->offs016C); if (gbIsHellfireSaveGame) CopyInt(tbuff, &pItem->_iDamAcFlags); @@ -387,7 +382,13 @@ static void LoadPlayer(int i) CopyChar(tbuff, &pPlayer->pBattleNet); } CopyChar(tbuff, &pPlayer->pManaShield); - CopyBytes(tbuff, 3, &pPlayer->bReserved); + if (gbIsHellfireSaveGame) { + CopyChar(tbuff, &pPlayer->pOriginalCathedral); + } else { + tbuff += 1; + pPlayer->pOriginalCathedral = true; + } + CopyBytes(tbuff, 2, &pPlayer->bReserved); CopyShort(tbuff, &pPlayer->wReflection); CopyShorts(tbuff, 7, &pPlayer->wReserved); @@ -687,17 +688,53 @@ static void LoadPortal(int i) CopyInt(tbuff, &pPortal->setlvl); } -static bool IsHeaderValid(int magicNumber) +int RemapItemIdxFromDiablo(int i) +{ + if (i == IDI_SORCEROR) { + return 166; + } + if (i >= 156) { + i += 5; // Hellfire exclusive items + } + if (i >= 88) { + i += 1; // Scroll of Search + } + if (i >= 83) { + i += 4; // Oils + } + + return i; +} + +int RemapItemIdxToDiablo(int i) +{ + if (i == 166) { + return IDI_SORCEROR; + } + if ((i >= 83 && i <= 86) || i == 92 || i >= 161) { + return -1; // Hellfire exclusive items + } + if (i >= 93) { + i -= 1; // Scroll of Search + } + if (i >= 87) { + i -= 4; // Oils + } + + return i; +} + +bool IsHeaderValid(int magicNumber) { gbIsHellfireSaveGame = false; if (magicNumber == 'SHAR') { return true; - } else if (gbIsHellfire && magicNumber == 'SHLF') { + } else if (magicNumber == 'SHLF') { gbIsHellfireSaveGame = true; return true; } else if (!gbIsSpawn && magicNumber == 'RETL') { return true; - } else if (!gbIsSpawn && gbIsHellfire && magicNumber == 'HELF') { + } else if (!gbIsSpawn && magicNumber == 'HELF') { gbIsHellfireSaveGame = true; return true; } @@ -713,14 +750,12 @@ void LoadGame(BOOL firstflag) { int i, j; DWORD dwLen; - char szName[MAX_PATH]; BYTE *LoadBuff; int _ViewX, _ViewY, _nummonsters, _numitems, _nummissiles, _nobjects; FreeGameMem(); pfile_remove_temp_files(); - pfile_get_game_name(szName); - LoadBuff = pfile_read(szName, &dwLen); + LoadBuff = pfile_read("game", &dwLen); tbuff = LoadBuff; if (!IsHeaderValid(ILoad())) @@ -927,10 +962,19 @@ static void OSave(BOOL v) static void SaveItem(ItemStruct *pItem) { + int idx = RemapItemIdxToDiablo(pItem->IDidx); + int iType = pItem->_itype; + if (idx != -1) { + idx = 0; + iType = ITYPE_NONE; + } + CopyInt(&pItem->_iSeed, tbuff); CopyShort(&pItem->_iCreateInfo, tbuff); tbuff += 2; // Alignment - CopyInt(&pItem->_itype, tbuff); + + CopyInt(&iType, tbuff); + CopyInt(&pItem->_ix, tbuff); CopyInt(&pItem->_iy, tbuff); CopyInt(&pItem->_iAnimFlag, tbuff); @@ -999,7 +1043,7 @@ static void SaveItem(ItemStruct *pItem) CopyChar(&pItem->_iMinDex, tbuff); tbuff += 1; // Alignment CopyInt(&pItem->_iStatFlag, tbuff); - CopyInt(&pItem->IDidx, tbuff); + CopyInt(&idx, tbuff); CopyInt(&pItem->offs016C, tbuff); if (gbIsHellfire) CopyInt(&pItem->_iDamAcFlags, tbuff); @@ -1196,7 +1240,7 @@ static void SavePlayer(int i) else CopyChar(&pPlayer->pBattleNet, tbuff); CopyChar(&pPlayer->pManaShield, tbuff); - CopyChar(&pPlayer->pDungMsgs2, tbuff); + CopyChar(&pPlayer->pOriginalCathedral, tbuff); CopyBytes(&pPlayer->bReserved, 2, tbuff); CopyShort(&pPlayer->wReflection, tbuff); CopyShorts(&pPlayer->wReserved, 7, tbuff); @@ -1496,7 +1540,6 @@ static void SavePortal(int i) void SaveGame() { int i, j; - char szName[MAX_PATH]; DWORD dwLen = codec_get_encoded_len(FILEBUFF); BYTE *SaveBuff = DiabloAllocPtr(dwLen); @@ -1648,9 +1691,8 @@ void SaveGame() OSave(automapflag); WSave(AutoMapScale); - pfile_get_game_name(szName); dwLen = codec_get_encoded_len(tbuff - SaveBuff); - pfile_write_save_file(szName, SaveBuff, tbuff - SaveBuff, dwLen); + pfile_write_save_file("game", SaveBuff, tbuff - SaveBuff, dwLen); mem_free_dbg(SaveBuff); gbValidSaveFile = TRUE; pfile_rename_temp_to_perm(); diff --git a/Source/loadsave.h b/Source/loadsave.h index f4d27abe7..cadbc2ee7 100644 --- a/Source/loadsave.h +++ b/Source/loadsave.h @@ -12,8 +12,12 @@ DEVILUTION_BEGIN_NAMESPACE extern "C" { #endif +extern bool gbIsHellfireSaveGame; extern int giNumberOfLevels; +int RemapItemIdxFromDiablo(int i); +int RemapItemIdxToDiablo(int i); +bool IsHeaderValid(int magicNumber); void LoadGame(BOOL firstflag); void SaveGame(); void SaveLevel(); diff --git a/Source/multi.cpp b/Source/multi.cpp index ee9d57543..5d904f4ad 100644 --- a/Source/multi.cpp +++ b/Source/multi.cpp @@ -913,6 +913,7 @@ void recv_plrinfo(int pnum, TCmdPlrInfoHdr *p, BOOL recv) sgwPackPlrOffsetTbl[pnum] = 0; multi_player_left_msg(pnum, 0); plr[pnum]._pGFXLoad = 0; + gbIsHellfireSaveGame = gbIsHellfire; UnPackPlayer(&netplr[pnum], pnum, TRUE); if (!recv) { diff --git a/Source/pack.cpp b/Source/pack.cpp index 5bd8d07f0..9b51a096f 100644 --- a/Source/pack.cpp +++ b/Source/pack.cpp @@ -12,7 +12,11 @@ void PackItem(PkItemStruct *id, ItemStruct *is) if (is->_itype == ITYPE_NONE) { id->idx = 0xFFFF; } else { - id->idx = SwapLE16(is->IDidx); + int idx = is->IDidx; + if (!gbIsHellfire) { + idx = RemapItemIdxToDiablo(idx); + } + id->idx = SwapLE16(idx); if (is->IDidx == IDI_EAR) { id->iCreateInfo = is->_iName[8] | (is->_iName[7] << 8); id->iSeed = SwapLE32(is->_iName[12] | ((is->_iName[11] | ((is->_iName[10] | (is->_iName[9] << 8)) << 8)) << 8)); @@ -132,6 +136,9 @@ void UnPackItem(PkItemStruct *is, ItemStruct *id) if (idx == 0xFFFF) { id->_itype = ITYPE_NONE; } else { + if (!gbIsHellfireSaveGame) { + idx = RemapItemIdxFromDiablo(idx); + } if (idx == IDI_EAR) { RecreateEar( MAXITEMS, diff --git a/Source/pfile.cpp b/Source/pfile.cpp index 9973a463f..8bfb1ef4f 100644 --- a/Source/pfile.cpp +++ b/Source/pfile.cpp @@ -66,18 +66,27 @@ static DWORD pfile_get_save_num_from_name(const char *name) return i; } -static BOOL pfile_read_hero(HANDLE archive, PkPlayerStruct *pPack) +static BYTE *pfile_read_archive(HANDLE archive, const char *pszName, DWORD *pdwLen) { + DWORD nread; HANDLE file; - DWORD dwlen; BYTE *buf; - if (!SFileOpenFileEx(archive, "hero", 0, &file)) { - return FALSE; - } else { - buf = NULL; - BOOL ret = FALSE; + if (!SFileOpenFileEx(archive, pszName, 0, &file)) + return NULL; + + *pdwLen = SFileGetFileSize(file, NULL); + if (*pdwLen == 0) + return NULL; + + buf = DiabloAllocPtr(*pdwLen); + if (!SFileReadFile(file, buf, *pdwLen, &nread, NULL)) + return NULL; + SFileCloseFile(file); + + { const char *password; + DWORD nSize = 16; if (gbIsSpawn) { password = PASSWORD_SPAWN_SINGLE; @@ -89,23 +98,30 @@ static BOOL pfile_read_hero(HANDLE archive, PkPlayerStruct *pPack) password = PASSWORD_MULTI; } - dwlen = SFileGetFileSize(file, NULL); - if (dwlen) { - DWORD read; - buf = DiabloAllocPtr(dwlen); - if (SFileReadFile(file, buf, dwlen, &read, NULL)) { - read = codec_decode(buf, dwlen, password); - if (read == sizeof(*pPack)) { - memcpy(pPack, buf, sizeof(*pPack)); - ret = TRUE; - } - } - } - if (buf) - mem_free_dbg(buf); - SFileCloseFile(file); - return ret; + *pdwLen = codec_decode(buf, *pdwLen, password); + if (*pdwLen == 0) + return NULL; } + return buf; +} + +static BOOL pfile_read_hero(HANDLE archive, PkPlayerStruct *pPack) +{ + DWORD read; + BYTE *buf; + + buf = pfile_read_archive(archive, "hero", &read); + if (buf == NULL) + return FALSE; + + BOOL ret = FALSE; + if (read == sizeof(*pPack)) { + memcpy(pPack, buf, sizeof(*pPack)); + ret = TRUE; + } + + mem_free_dbg(buf); + return ret; } static void pfile_encode_hero(const PkPlayerStruct *pPack) @@ -262,8 +278,9 @@ BOOL pfile_ui_set_hero_infos(BOOL (*ui_add_hero_info)(_uiheroinfo *)) if (pfile_read_hero(archive, &pkplr)) { _uiheroinfo uihero; strcpy(hero_names[i], pkplr.pName); + bool hasSaveGame = pfile_archive_contains_game(archive, i); UnPackPlayer(&pkplr, 0, FALSE); - game_2_ui_player(plr, &uihero, pfile_archive_contains_game(archive, i)); + game_2_ui_player(plr, &uihero, hasSaveGame); ui_add_hero_info(&uihero); } pfile_SFileCloseArchive(archive); @@ -275,16 +292,18 @@ BOOL pfile_ui_set_hero_infos(BOOL (*ui_add_hero_info)(_uiheroinfo *)) BOOL pfile_archive_contains_game(HANDLE hsArchive, DWORD save_num) { - HANDLE file; - if (gbMaxPlayers != 1) return FALSE; - if (!SFileOpenFileEx(hsArchive, "game", 0, &file)) + DWORD dwLen; + BYTE *gameData = pfile_read_archive(hsArchive, "game", &dwLen); + if (gameData == NULL) return FALSE; - SFileCloseFile(file); - return TRUE; + int hdr = (gameData[0] << 24) | (gameData[1] << 16) | (gameData[2] << 8) | gameData[3]; + mem_free_dbg(gameData); + + return IsHeaderValid(hdr); } void pfile_ui_set_class_stats(unsigned int player_class_nr, _uidefaultstats *class_stats) @@ -374,8 +393,8 @@ void pfile_read_player_from_save() if (!pfile_read_hero(archive, &pkplr)) app_fatal("Unable to load character"); - UnPackPlayer(&pkplr, myplr, FALSE); gbValidSaveFile = pfile_archive_contains_game(archive, save_num); + UnPackPlayer(&pkplr, myplr, FALSE); pfile_SFileCloseArchive(archive); } @@ -407,11 +426,6 @@ void GetPermLevelNames(char *szPerm) } } -void pfile_get_game_name(char *dst) -{ - strcpy(dst, "game"); -} - static BOOL GetPermSaveNames(DWORD dwIndex, char *szPerm) { const char *fmt; @@ -510,8 +524,8 @@ void pfile_write_save_file(const char *pszName, BYTE *pbData, DWORD dwLen, DWORD BYTE *pfile_read(const char *pszName, DWORD *pdwLen) { - DWORD save_num, nread; - HANDLE archive, save; + DWORD save_num; + HANDLE archive; BYTE *buf; save_num = pfile_get_save_num_from_name(plr[myplr]._pName); @@ -519,37 +533,11 @@ BYTE *pfile_read(const char *pszName, DWORD *pdwLen) if (archive == NULL) app_fatal("Unable to open save file archive"); - if (!SFileOpenFileEx(archive, pszName, 0, &save)) - app_fatal("Unable to open save file"); - - *pdwLen = SFileGetFileSize(save, NULL); - if (*pdwLen == 0) - app_fatal("Invalid save file"); - - buf = DiabloAllocPtr(*pdwLen); - if (!SFileReadFile(save, buf, *pdwLen, &nread, NULL)) - app_fatal("Unable to read save file"); - SFileCloseFile(save); + buf = pfile_read_archive(archive, pszName, pdwLen); pfile_SFileCloseArchive(archive); + if (buf == NULL) + app_fatal("Invalid %s file", pszName); - { - const char *password; - DWORD nSize = 16; - - if (gbIsSpawn) { - password = PASSWORD_SPAWN_SINGLE; - if (gbMaxPlayers > 1) - password = PASSWORD_SPAWN_MULTI; - } else { - password = PASSWORD_SINGLE; - if (gbMaxPlayers > 1) - password = PASSWORD_MULTI; - } - - *pdwLen = codec_decode(buf, *pdwLen, password); - if (*pdwLen == 0) - app_fatal("Invalid save file"); - } return buf; } diff --git a/Source/pfile.h b/Source/pfile.h index e1e6e266a..d4ce23e58 100644 --- a/Source/pfile.h +++ b/Source/pfile.h @@ -29,7 +29,6 @@ BOOL pfile_delete_save(_uiheroinfo *hero_info); void pfile_read_player_from_save(); void GetTempLevelNames(char *szTemp); void GetPermLevelNames(char *szPerm); -void pfile_get_game_name(char *dst); void pfile_remove_temp_files(); void pfile_rename_temp_to_perm(); void pfile_write_save_file(const char *pszName, BYTE *pbData, DWORD dwLen, DWORD qwLen); diff --git a/SourceX/DiabloUI/diabloui.cpp b/SourceX/DiabloUI/diabloui.cpp index d8372854f..0a7120461 100644 --- a/SourceX/DiabloUI/diabloui.cpp +++ b/SourceX/DiabloUI/diabloui.cpp @@ -425,7 +425,7 @@ void LoadUiGFX() LoadMaskedArt("ui_art\\focus.pcx", &ArtFocus[FOCUS_MED], 8); LoadMaskedArt("ui_art\\focus42.pcx", &ArtFocus[FOCUS_BIG], 8); LoadMaskedArt("ui_art\\cursor.pcx", &ArtCursor, 1, 0); - LoadArt("ui_art\\heros.pcx", &ArtHero, hellfire_mpq ? 6 : 4); + LoadArt("ui_art\\heros.pcx", &ArtHero, gbIsHellfire ? 6 : 4); } void UiInitialize() diff --git a/structs.h b/structs.h index bedc49df4..4f0cf8514 100644 --- a/structs.h +++ b/structs.h @@ -344,6 +344,7 @@ typedef struct PlayerStruct { unsigned char pBattleNet; BOOLEAN pManaShield; unsigned char pDungMsgs2; + BOOLEAN pOriginalCathedral; char bReserved[2]; short wReflection; short wReserved[7];