Browse Source

[hellfire] Allow continuing Diablo saves in Hellfire and vice versa

pull/977/head
Anders Jenbo 5 years ago
parent
commit
4ffbb32952
  1. 6
      Source/drlg_l1.cpp
  2. 1
      Source/interfac.cpp
  3. 43
      Source/itemdat.cpp
  4. 48
      Source/items.cpp
  5. 86
      Source/loadsave.cpp
  6. 4
      Source/loadsave.h
  7. 1
      Source/multi.cpp
  8. 9
      Source/pack.cpp
  9. 120
      Source/pfile.cpp
  10. 1
      Source/pfile.h
  11. 2
      SourceX/DiabloUI/diabloui.cpp
  12. 1
      structs.h

6
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)

1
Source/interfac.cpp

@ -314,6 +314,7 @@ void ShowProgress(unsigned int uMsg)
IncProgress();
break;
case WM_DIABNEWGAME:
plr[myplr].pOriginalCathedral = !gbIsHellfire;
IncProgress();
FreeGameMem();
IncProgress();

43
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
};

48
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;

86
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();

4
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();

1
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) {

9
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,

120
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;
}

1
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);

2
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()

1
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];

Loading…
Cancel
Save