diff --git a/src/BoE.vsproj/Common/Common.vcxproj b/src/BoE.vsproj/Common/Common.vcxproj index 6de547ab..24153085 100644 --- a/src/BoE.vsproj/Common/Common.vcxproj +++ b/src/BoE.vsproj/Common/Common.vcxproj @@ -11,7 +11,6 @@ - diff --git a/src/BoE.vsproj/Common/Common.vcxproj.filters b/src/BoE.vsproj/Common/Common.vcxproj.filters index ad04848a..6dc26235 100644 --- a/src/BoE.vsproj/Common/Common.vcxproj.filters +++ b/src/BoE.vsproj/Common/Common.vcxproj.filters @@ -197,9 +197,6 @@ Tools\Header Files - - Classes - Classes diff --git a/src/BoE.xcodeproj/project.pbxproj b/src/BoE.xcodeproj/project.pbxproj index 783a873d..895a6034 100644 --- a/src/BoE.xcodeproj/project.pbxproj +++ b/src/BoE.xcodeproj/project.pbxproj @@ -117,14 +117,14 @@ 913D005C0F9FEEC300184C18 /* porting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 913D005A0F9FEEC200184C18 /* porting.cpp */; }; 913D005D0F9FEEC300184C18 /* porting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 913D005A0F9FEEC200184C18 /* porting.cpp */; }; 913D05B60FA1E9E300184C18 /* party.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 913D05B50FA1E9E300184C18 /* party.cpp */; }; - 913D05B70FA1E9E300184C18 /* party.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 913D05B50FA1E9E300184C18 /* party.cpp */; }; 913D05B80FA1E9E300184C18 /* party.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 913D05B50FA1E9E300184C18 /* party.cpp */; }; 913D05BC0FA1EA0A00184C18 /* pc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 913D05BB0FA1EA0A00184C18 /* pc.cpp */; }; - 913D05BD0FA1EA0A00184C18 /* pc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 913D05BB0FA1EA0A00184C18 /* pc.cpp */; }; 913D05BE0FA1EA0A00184C18 /* pc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 913D05BB0FA1EA0A00184C18 /* pc.cpp */; }; 913D6C050FC57A8E00E12527 /* boeresources.icns in Resources */ = {isa = PBXBuildFile; fileRef = 913D6C040FC57A8E00E12527 /* boeresources.icns */; }; 914698F81A73434400F20F5E /* shop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91FDB5791A4E774E00DE5983 /* shop.cpp */; }; 914698FC1A74216F00F20F5E /* living.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914698FB1A7362D900F20F5E /* living.cpp */; }; + 914699001A747C6500F20F5E /* creature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914698FE1A747C4500F20F5E /* creature.cpp */; }; + 914699011A747C6600F20F5E /* creature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914698FE1A747C4500F20F5E /* creature.cpp */; }; 914701A718F62ABF008A6DC9 /* dungeon.ttf in Copy Fonts */ = {isa = PBXBuildFile; fileRef = 914701A418F629D4008A6DC9 /* dungeon.ttf */; }; 914701A818F62AC0008A6DC9 /* maidenword.ttf in Copy Fonts */ = {isa = PBXBuildFile; fileRef = 914701A518F629D4008A6DC9 /* maidenword.ttf */; }; 914B2AA318E7E507007B6799 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 914B2AA118E7E500007B6799 /* Cocoa.framework */; }; @@ -193,9 +193,7 @@ 91AC60AA0FA26C1B00EEAE67 /* tmpltown.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91AC60A70FA26C1B00EEAE67 /* tmpltown.cpp */; }; 91AC61C60FA2729900EEAE67 /* universe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91AC61C50FA2729900EEAE67 /* universe.cpp */; }; 91AC620B0FA2853700EEAE67 /* creatlist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91AC620A0FA2853700EEAE67 /* creatlist.cpp */; }; - 91AC620C0FA2853700EEAE67 /* creatlist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91AC620A0FA2853700EEAE67 /* creatlist.cpp */; }; 91AC620D0FA2853700EEAE67 /* creatlist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91AC620A0FA2853700EEAE67 /* creatlist.cpp */; }; - 91AC65520FA3441B00EEAE67 /* universe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91AC61C50FA2729900EEAE67 /* universe.cpp */; }; 91AC65AD0FA34AC600EEAE67 /* universe.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91AC61C50FA2729900EEAE67 /* universe.cpp */; }; 91ACCE6418FFB61A00FAEF8B /* bladbase.exs in Copy Base Scenarios */ = {isa = PBXBuildFile; fileRef = 91B3EF250F969CE300BF5B67 /* bladbase.exs */; }; 91ACCE7619002E5F00FAEF8B /* sfml-audio.framework in Copy Libraries and Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8DD18F87F3700E3EA15 /* sfml-audio.framework */; }; @@ -246,6 +244,12 @@ 91C749B81A2D6670008E0E10 /* strings in Copy Strings */ = {isa = PBXBuildFile; fileRef = 91C749B71A2D6432008E0E10 /* strings */; }; 91C749BA1A2D670D008E0E10 /* dialogs in Copy Dialog Definitions */ = {isa = PBXBuildFile; fileRef = 91C749B91A2D66F7008E0E10 /* dialogs */; }; 91D634560F8FD77800674AB3 /* BoE.icns in Resources */ = {isa = PBXBuildFile; fileRef = 2B8F435C0C0973680012E4A8 /* BoE.icns */; }; + 91E30F2B1A74819C0057C54A /* fileio_party.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E30F2A1A74819B0057C54A /* fileio_party.cpp */; }; + 91E30F2C1A74819D0057C54A /* fileio_party.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E30F2A1A74819B0057C54A /* fileio_party.cpp */; }; + 91E30F2E1A7481C40057C54A /* fileio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E30F2D1A7481C20057C54A /* fileio.cpp */; }; + 91E30F2F1A7481C50057C54A /* fileio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E30F2D1A7481C20057C54A /* fileio.cpp */; }; + 91E30F301A7481C50057C54A /* fileio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E30F2D1A7481C20057C54A /* fileio.cpp */; }; + 91E30F311A748ABA0057C54A /* fileio_scen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C7A60F9F615400C21460 /* fileio_scen.cpp */; }; 91E5C1F30F9E489B00C21460 /* graphtool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B3F10A0F9779C300BF5B67 /* graphtool.cpp */; }; 91E5C1F40F9E489B00C21460 /* soundtool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B3F10F0F9779D000BF5B67 /* soundtool.cpp */; }; 91E5C1F50F9E489B00C21460 /* mathutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B3F11E0F97801F00BF5B67 /* mathutil.cpp */; }; @@ -261,9 +265,8 @@ 91E5C79E0F9F60FA00C21460 /* outdoors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C79D0F9F60FA00C21460 /* outdoors.cpp */; }; 91E5C79F0F9F60FA00C21460 /* outdoors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C79D0F9F60FA00C21460 /* outdoors.cpp */; }; 91E5C7A00F9F60FA00C21460 /* outdoors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C79D0F9F60FA00C21460 /* outdoors.cpp */; }; - 91E5C7A70F9F615400C21460 /* fileio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C7A60F9F615400C21460 /* fileio.cpp */; }; - 91E5C7A80F9F615400C21460 /* fileio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C7A60F9F615400C21460 /* fileio.cpp */; }; - 91E5C7A90F9F615400C21460 /* fileio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C7A60F9F615400C21460 /* fileio.cpp */; }; + 91E5C7A70F9F615400C21460 /* fileio_scen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C7A60F9F615400C21460 /* fileio_scen.cpp */; }; + 91E5C7A80F9F615400C21460 /* fileio_scen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C7A60F9F615400C21460 /* fileio_scen.cpp */; }; 91E5C7B80F9F619D00C21460 /* talking.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C7B70F9F619D00C21460 /* talking.cpp */; }; 91E5C7B90F9F619D00C21460 /* talking.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C7B70F9F619D00C21460 /* talking.cpp */; }; 91E5C7BA0F9F619D00C21460 /* talking.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91E5C7B70F9F619D00C21460 /* talking.cpp */; }; @@ -584,6 +587,8 @@ 913FB40A1A5C90840067B9D2 /* pictypes.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = pictypes.hpp; sourceTree = ""; }; 914698FA1A7362C200F20F5E /* living.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = living.hpp; sourceTree = ""; }; 914698FB1A7362D900F20F5E /* living.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = living.cpp; sourceTree = ""; }; + 914698FD1A747BED00F20F5E /* creature.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = creature.hpp; sourceTree = ""; }; + 914698FE1A747C4500F20F5E /* creature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = creature.cpp; sourceTree = ""; }; 914701A418F629D4008A6DC9 /* dungeon.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = dungeon.ttf; sourceTree = ""; }; 914701A518F629D4008A6DC9 /* maidenword.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = maidenword.ttf; sourceTree = ""; }; 914701A918F64A85008A6DC9 /* dialog.xsd */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = dialog.xsd; path = schemas/dialog.xsd; sourceTree = ""; }; @@ -625,7 +630,6 @@ 91AC607F0FA26A3B00EEAE67 /* regtown.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = regtown.cpp; sourceTree = ""; }; 91AC60A60FA26C1B00EEAE67 /* tmpltown.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tmpltown.h; sourceTree = ""; }; 91AC60A70FA26C1B00EEAE67 /* tmpltown.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tmpltown.cpp; sourceTree = ""; }; - 91AC61300FA270B300EEAE67 /* classes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = classes.h; sourceTree = SOURCE_ROOT; }; 91AC61C40FA2729900EEAE67 /* universe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = universe.h; sourceTree = ""; }; 91AC61C50FA2729900EEAE67 /* universe.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = universe.cpp; sourceTree = ""; }; 91AC62090FA2853700EEAE67 /* creatlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = creatlist.h; sourceTree = ""; }; @@ -686,13 +690,15 @@ 91D635AD0F90E7B500674AB3 /* valleydy.meg */ = {isa = PBXFileReference; lastKnownFileType = file; path = valleydy.meg; sourceTree = ""; }; 91D635AE0F90E7B500674AB3 /* zakhazi.exs */ = {isa = PBXFileReference; lastKnownFileType = file; path = zakhazi.exs; sourceTree = ""; }; 91D635AF0F90E7B500674AB3 /* zakhazi.meg */ = {isa = PBXFileReference; lastKnownFileType = file; path = zakhazi.meg; sourceTree = ""; }; + 91E30F2A1A74819B0057C54A /* fileio_party.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fileio_party.cpp; sourceTree = ""; }; + 91E30F2D1A7481C20057C54A /* fileio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fileio.cpp; sourceTree = ""; }; 91E5C5A10F9EACE200C21460 /* oldstructs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = oldstructs.h; path = ../oldstructs.h; sourceTree = ""; }; 91E5C7970F9F60EC00C21460 /* town.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = town.h; sourceTree = ""; }; 91E5C7980F9F60EC00C21460 /* town.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = town.cpp; sourceTree = ""; }; 91E5C79C0F9F60FA00C21460 /* outdoors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = outdoors.h; sourceTree = ""; }; 91E5C79D0F9F60FA00C21460 /* outdoors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = outdoors.cpp; sourceTree = ""; }; 91E5C7A50F9F615400C21460 /* fileio.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = fileio.hpp; sourceTree = ""; }; - 91E5C7A60F9F615400C21460 /* fileio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fileio.cpp; sourceTree = ""; }; + 91E5C7A60F9F615400C21460 /* fileio_scen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fileio_scen.cpp; sourceTree = ""; }; 91E5C7B60F9F619D00C21460 /* talking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = talking.h; sourceTree = ""; }; 91E5C7B70F9F619D00C21460 /* talking.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = talking.cpp; sourceTree = ""; }; 91EC480E18FBAA8700BB1E86 /* prefs.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = prefs.hpp; sourceTree = ""; }; @@ -855,7 +861,6 @@ children = ( 913D03330FA0FFE800184C18 /* headers */, 913D03320FA0FFE700184C18 /* src */, - 91AC61300FA270B300EEAE67 /* classes.h */, 91E5C5A10F9EACE200C21460 /* oldstructs.h */, 915325161A2E1DA8000A9A1C /* oldstructs.cpp */, ); @@ -875,6 +880,7 @@ isa = PBXGroup; children = ( 91AC620A0FA2853700EEAE67 /* creatlist.cpp */, + 914698FE1A747C4500F20F5E /* creature.cpp */, 91279D3D0F9D1D6A007B0D52 /* item.cpp */, 914698FB1A7362D900F20F5E /* living.cpp */, 91279BE10F9D0F73007B0D52 /* location.cpp */, @@ -901,6 +907,7 @@ isa = PBXGroup; children = ( 91AC62090FA2853700EEAE67 /* creatlist.h */, + 914698FD1A747BED00F20F5E /* creature.hpp */, 91279D3C0F9D1D6A007B0D52 /* item.h */, 914698FA1A7362C200F20F5E /* living.hpp */, 91279BE00F9D0F73007B0D52 /* location.h */, @@ -928,7 +935,9 @@ isa = PBXGroup; children = ( 91C688E70FD702B9000F6D01 /* cursors.mac.mm */, - 91E5C7A60F9F615400C21460 /* fileio.cpp */, + 91E30F2D1A7481C20057C54A /* fileio.cpp */, + 91E30F2A1A74819B0057C54A /* fileio_party.cpp */, + 91E5C7A60F9F615400C21460 /* fileio_scen.cpp */, 91B3F10A0F9779C300BF5B67 /* graphtool.cpp */, 91B3F11E0F97801F00BF5B67 /* mathutil.cpp */, 915E09081A316D89008BDF00 /* map_parse.cpp */, @@ -1458,7 +1467,7 @@ 91279D3E0F9D1D6A007B0D52 /* item.cpp in Sources */, 91E5C79B0F9F60EC00C21460 /* town.cpp in Sources */, 91E5C79F0F9F60FA00C21460 /* outdoors.cpp in Sources */, - 91E5C7A80F9F615400C21460 /* fileio.cpp in Sources */, + 91E5C7A80F9F615400C21460 /* fileio_scen.cpp in Sources */, 91E5C7B90F9F619D00C21460 /* talking.cpp in Sources */, 913D005B0F9FEEC300184C18 /* porting.cpp in Sources */, 913D05B60FA1E9E300184C18 /* party.cpp in Sources */, @@ -1496,6 +1505,9 @@ 9179A4671A48683100FEF872 /* stack.cpp in Sources */, 91FDB57B1A4E77CA00DE5983 /* shop.cpp in Sources */, 914698FC1A74216F00F20F5E /* living.cpp in Sources */, + 914699011A747C6600F20F5E /* creature.cpp in Sources */, + 91E30F2B1A74819C0057C54A /* fileio_party.cpp in Sources */, + 91E30F2E1A7481C40057C54A /* fileio.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1519,7 +1531,6 @@ 91279D3F0F9D1D6A007B0D52 /* item.cpp in Sources */, 91E5C79A0F9F60EC00C21460 /* town.cpp in Sources */, 91E5C7A00F9F60FA00C21460 /* outdoors.cpp in Sources */, - 91E5C7A90F9F615400C21460 /* fileio.cpp in Sources */, 91E5C7BA0F9F619D00C21460 /* talking.cpp in Sources */, 913D005D0F9FEEC300184C18 /* porting.cpp in Sources */, 913D05B80FA1E9E300184C18 /* party.cpp in Sources */, @@ -1553,6 +1564,10 @@ 9179A4661A48683100FEF872 /* stack.cpp in Sources */, 91222FC11A72366D008413A5 /* spell.cpp in Sources */, 914698F81A73434400F20F5E /* shop.cpp in Sources */, + 914699001A747C6500F20F5E /* creature.cpp in Sources */, + 91E30F2C1A74819D0057C54A /* fileio_party.cpp in Sources */, + 91E30F2F1A7481C50057C54A /* fileio.cpp in Sources */, + 91E30F311A748ABA0057C54A /* fileio_scen.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1580,15 +1595,11 @@ 91279D400F9D1D6A007B0D52 /* item.cpp in Sources */, 91E5C7990F9F60EC00C21460 /* town.cpp in Sources */, 91E5C79E0F9F60FA00C21460 /* outdoors.cpp in Sources */, - 91E5C7A70F9F615400C21460 /* fileio.cpp in Sources */, + 91E5C7A70F9F615400C21460 /* fileio_scen.cpp in Sources */, 91E5C7B80F9F619D00C21460 /* talking.cpp in Sources */, 913D005C0F9FEEC300184C18 /* porting.cpp in Sources */, - 913D05B70FA1E9E300184C18 /* party.cpp in Sources */, - 913D05BD0FA1EA0A00184C18 /* pc.cpp in Sources */, 91AC60810FA26A3B00EEAE67 /* regtown.cpp in Sources */, 91AC60A90FA26C1B00EEAE67 /* tmpltown.cpp in Sources */, - 91AC620C0FA2853700EEAE67 /* creatlist.cpp in Sources */, - 91AC65520FA3441B00EEAE67 /* universe.cpp in Sources */, 91C1FCA60FCB6F7000EBAA65 /* button.cpp in Sources */, 91C1FCA70FCB6F7100EBAA65 /* control.cpp in Sources */, 91C1FCA80FCB6F7100EBAA65 /* dialog.cpp in Sources */, @@ -1615,6 +1626,7 @@ 9179A4651A48683100FEF872 /* stack.cpp in Sources */, 91FDB57C1A4E77CA00DE5983 /* shop.cpp in Sources */, 919086E01A65CA300071F7A0 /* tinyprint.cpp in Sources */, + 91E30F301A7481C50057C54A /* fileio.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/boe.actions.cpp b/src/boe.actions.cpp index eee74646..c23b98fb 100644 --- a/src/boe.actions.cpp +++ b/src/boe.actions.cpp @@ -4,7 +4,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.actions.h" #include "boe.graphutil.h" #include "boe.graphics.h" diff --git a/src/boe.combat.cpp b/src/boe.combat.cpp index 4233c0c8..b7e12bf7 100644 --- a/src/boe.combat.cpp +++ b/src/boe.combat.cpp @@ -3,7 +3,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.monster.h" #include "boe.graphics.h" #include "boe.locutils.h" @@ -1646,7 +1646,7 @@ void fire_missile(location target) { univ.party[missile_firer].heal(missile.abil_data[0] / 2); } else if(missile.ability == eItemAbil::ANTIMAGIC_WEAPON) { short before = cur_monst->get_magic(); - if(mu + cl > 0 && get_ran(1,0,1) == 1) + if(cur_monst->mu + cur_monst->cl > 0 && get_ran(1,0,1) == 1) cur_monst->drain_sp(missile.abil_data[0]); if(before > cur_monst->get_magic()) { add_string_to_buf(" Missile drains energy."); diff --git a/src/boe.dlgutil.cpp b/src/boe.dlgutil.cpp index 2968e993..6ef2388e 100644 --- a/src/boe.dlgutil.cpp +++ b/src/boe.dlgutil.cpp @@ -3,7 +3,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.dlgutil.h" #include "boe.text.h" diff --git a/src/boe.fileio.cpp b/src/boe.fileio.cpp index 0fdab648..6dec8b83 100644 --- a/src/boe.fileio.cpp +++ b/src/boe.fileio.cpp @@ -3,7 +3,7 @@ #include #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.fileio.h" #include "boe.text.h" #include "boe.town.h" diff --git a/src/boe.graphics.cpp b/src/boe.graphics.cpp index 8fe7c847..3c659d98 100644 --- a/src/boe.graphics.cpp +++ b/src/boe.graphics.cpp @@ -4,7 +4,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.graphics.h" #include "boe.newgraph.h" #include "boe.graphutil.h" diff --git a/src/boe.graphutil.cpp b/src/boe.graphutil.cpp index ca6910fb..858560e0 100644 --- a/src/boe.graphutil.cpp +++ b/src/boe.graphutil.cpp @@ -6,7 +6,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.graphutil.h" #include "boe.text.h" #include "boe.locutils.h" diff --git a/src/boe.infodlg.cpp b/src/boe.infodlg.cpp index 43afe8c2..b62ff292 100644 --- a/src/boe.infodlg.cpp +++ b/src/boe.infodlg.cpp @@ -4,7 +4,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.graphics.h" #include "boe.newgraph.h" diff --git a/src/boe.infodlg.h b/src/boe.infodlg.h index a6f9d095..f0093eea 100644 --- a/src/boe.infodlg.h +++ b/src/boe.infodlg.h @@ -6,6 +6,7 @@ #include "item.h" #include "monster.h" #include "pc.h" +#include "creature.hpp" class cDialog; void display_spells(eSkill mode,short force_spell,cDialog* parent); diff --git a/src/boe.itemdata.cpp b/src/boe.itemdata.cpp index 5f8819d7..509bf3b7 100644 --- a/src/boe.itemdata.cpp +++ b/src/boe.itemdata.cpp @@ -4,7 +4,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.itemdata.h" #include "mathutil.hpp" diff --git a/src/boe.items.cpp b/src/boe.items.cpp index 7287016c..aa40facf 100644 --- a/src/boe.items.cpp +++ b/src/boe.items.cpp @@ -4,7 +4,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.graphics.h" #include "boe.text.h" diff --git a/src/boe.locutils.cpp b/src/boe.locutils.cpp index bd22537b..a23b0ad2 100644 --- a/src/boe.locutils.cpp +++ b/src/boe.locutils.cpp @@ -2,7 +2,7 @@ #include "mathutil.hpp" #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.locutils.h" #include "boe.text.h" #include "boe.monster.h" diff --git a/src/boe.main.cpp b/src/boe.main.cpp index 257f9057..6f34b0ed 100644 --- a/src/boe.main.cpp +++ b/src/boe.main.cpp @@ -1,7 +1,7 @@ #define DIR_ARRAY_DEF #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include #include "boe.graphics.h" diff --git a/src/boe.monster.cpp b/src/boe.monster.cpp index d2153792..2fd64580 100644 --- a/src/boe.monster.cpp +++ b/src/boe.monster.cpp @@ -3,7 +3,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.locutils.h" #include "boe.monster.h" #include "boe.text.h" diff --git a/src/boe.monster.h b/src/boe.monster.h index 31f5f144..11305a69 100644 --- a/src/boe.monster.h +++ b/src/boe.monster.h @@ -1,5 +1,6 @@ #include "pict.hpp" +#include "creature.hpp" short out_enc_lev_tot(short which); void create_wand_monst(); diff --git a/src/boe.newgraph.cpp b/src/boe.newgraph.cpp index 558a5068..15ccf66a 100644 --- a/src/boe.newgraph.cpp +++ b/src/boe.newgraph.cpp @@ -5,7 +5,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.graphics.h" #include "boe.graphutil.h" #include "boe.monster.h" diff --git a/src/boe.party.cpp b/src/boe.party.cpp index 2201bb62..c6d0abb4 100644 --- a/src/boe.party.cpp +++ b/src/boe.party.cpp @@ -6,7 +6,7 @@ #include #include -#include "classes.h" +#include "universe.h" #include "boe.fileio.h" #include "boe.graphics.h" diff --git a/src/boe.specials.cpp b/src/boe.specials.cpp index 48c4ae36..679928b4 100644 --- a/src/boe.specials.cpp +++ b/src/boe.specials.cpp @@ -6,7 +6,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.party.h" #include "boe.town.h" #include "boe.text.h" diff --git a/src/boe.specials.h b/src/boe.specials.h index 68f5171a..5bb441b4 100644 --- a/src/boe.specials.h +++ b/src/boe.specials.h @@ -1,3 +1,6 @@ + +#include "creature.hpp" + bool town_specials(short which,short t_num); bool handle_wandering_specials (short which,short mode); bool check_special_terrain(location where_check,eSpecCtx mode,short which_pc,short *spec_num, diff --git a/src/boe.startup.cpp b/src/boe.startup.cpp index 7551d605..d7ceb05c 100644 --- a/src/boe.startup.cpp +++ b/src/boe.startup.cpp @@ -1,7 +1,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.newgraph.h" #include "boe.graphics.h" #include "boe.fileio.h" diff --git a/src/boe.text.cpp b/src/boe.text.cpp index 72525cf1..2194d28d 100644 --- a/src/boe.text.cpp +++ b/src/boe.text.cpp @@ -5,7 +5,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.text.h" #include "boe.locutils.h" #include "mathutil.hpp" diff --git a/src/boe.town.cpp b/src/boe.town.cpp index 13b1fe15..b13bba0e 100644 --- a/src/boe.town.cpp +++ b/src/boe.town.cpp @@ -4,7 +4,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.graphutil.h" #include "boe.graphics.h" diff --git a/src/boe.townspec.cpp b/src/boe.townspec.cpp index bcc865ab..c23a6784 100644 --- a/src/boe.townspec.cpp +++ b/src/boe.townspec.cpp @@ -1,7 +1,7 @@ #include "boe.global.h" -#include "classes.h" +#include "universe.h" #include "boe.party.h" #include "boe.town.h" #include "boe.items.h" diff --git a/src/classes.h b/src/classes.h deleted file mode 100644 index 17628ff9..00000000 --- a/src/classes.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * classes.h - * BoE - * - * Created by Celtic Minstrel on 24/04/09. - * - * This file simply includes all the classes in an order that satisfies all dependencies. - * - */ - -// TODO: Delete this file, and move the function defined here to a more appropriate place. - -#include "simpletypes.h" -#include "location.h" -#include "terrain.h" -#include "vehicle.h" -#include "item.h" -#include "special.h" -#include "monster.h" -#include "talking.h" -#include "town.h" -#include "regtown.h" -#include "tmpltown.h" -#include "outdoors.h" -#include "scenario.h" -#include "pc.h" -#include "creatlist.h" -#include "party.h" -#include "universe.h" diff --git a/src/classes/creatlist.cpp b/src/classes/creatlist.cpp index e9eda3a8..ecef8dae 100644 --- a/src/classes/creatlist.cpp +++ b/src/classes/creatlist.cpp @@ -6,12 +6,13 @@ * */ +#include "creatlist.h" + #include #include #include #include -#include "classes.h" #include "oldstructs.h" void cPopulation::append(legacy::creature_list_type old){ diff --git a/src/classes/creatlist.h b/src/classes/creatlist.h index 0cca4750..5a3e2d14 100644 --- a/src/classes/creatlist.h +++ b/src/classes/creatlist.h @@ -11,6 +11,7 @@ #include "monster.h" #include +#include "creature.hpp" namespace legacy { struct creature_list_type; diff --git a/src/classes/creature.cpp b/src/classes/creature.cpp new file mode 100644 index 00000000..a03c7908 --- /dev/null +++ b/src/classes/creature.cpp @@ -0,0 +1,264 @@ +// +// creature.cpp +// BoE +// +// Created by Celtic Minstrel on 15-01-24. +// +// + +#include "creature.hpp" + +#include +#include +#include "oldstructs.h" +#include "mathutil.hpp" + +const short cCreature::charm_odds[20] = {90,90,85,80,78, 75,73,60,40,30, 20,10,4,1,0, 0,0,0,0,0}; + +cCreature::cCreature(){ + number = active = attitude = start_attitude = 0; + start_loc.x = start_loc.y = cur_loc.x = cur_loc.y = targ_loc.x = targ_loc.y = 80; + mobility = 1; + summoned = 0; + time_flag = eMonstTime::ALWAYS; + spec1 = spec2 = spec_enc_code = time_code = monster_time = 0; + personality = special_on_kill = facial_pic = -1; + target = 6; +} + +cCreature::cCreature(int num) : cCreature() { + number = num; +} + +void cCreature::append(legacy::creature_data_type old){ + active = old.active; + attitude = old.attitude; + number = old.number; + cur_loc.x = old.m_loc.x; + cur_loc.y = old.m_loc.y; + cMonster::append(old.m_d); + mobility = old.mobile; + summoned = old.summoned; + number = old.monst_start.number; + start_attitude = old.monst_start.start_attitude; + start_loc.x = old.monst_start.start_loc.x; + start_loc.y = old.monst_start.start_loc.y; + mobility = old.monst_start.mobile; + switch(old.monst_start.time_flag) { + case 0: time_flag = eMonstTime::ALWAYS; break; + case 1: time_flag = eMonstTime::APPEAR_ON_DAY; break; + case 2: time_flag = eMonstTime::DISAPPEAR_ON_DAY; break; + case 4: time_flag = eMonstTime::SOMETIMES_A; break; + case 5: time_flag = eMonstTime::SOMETIMES_B; break; + case 6: time_flag = eMonstTime::SOMETIMES_C; break; + case 7: time_flag = eMonstTime::APPEAR_WHEN_EVENT; break; + case 8: time_flag = eMonstTime::DISAPPEAR_WHEN_EVENT; break; + } + spec1 = old.monst_start.spec1; + spec2 = old.monst_start.spec2; + spec_enc_code = old.monst_start.spec_enc_code; + time_code = old.monst_start.time_code; + monster_time = old.monst_start.monster_time; + personality = old.monst_start.personality; + special_on_kill = old.monst_start.special_on_kill; + facial_pic = old.monst_start.facial_pic; + health = old.m_d.health; + mp = old.m_d.mp; + max_mp = old.m_d.max_mp; + ap = old.m_d.ap; + morale = old.m_d.morale; + m_morale = old.m_d.m_morale; + for(int i = 0; i < 15; i++) + status[(eStatus) i] = old.m_d.status[i]; + direction = eDirection(old.m_d.direction); +} + +void cCreature::avatar() { + health = m_health; + status[eStatus::POISON] = 0; + status[eStatus::BLESS_CURSE] = 8; + status[eStatus::HASTE_SLOW] = 8; + status[eStatus::WEBS] = 0; + status[eStatus::DISEASE] = 0; + if(status[eStatus::DUMB] > 0) + status[eStatus::DUMB] = 0; + status[eStatus::MARTYRS_SHIELD] = 8; +} + +void cCreature::heal(int amt) { + if(!is_alive()) return; + if(health >= m_health) return; + health += amt; + if(health > m_health) + health = m_health; +} + +void cCreature::cure(int amt) { + if(!is_alive()) return; + if(status[eStatus::POISON] <= amt) + status[eStatus::POISON] = 0; + else status[eStatus::POISON] -= amt; +} + +void cCreature::restore_sp(int amt) { + if(!is_alive()) return; + mp += amt; + if(mp > max_mp) + mp = max_mp; +} + +void cCreature::drain_sp(int drain) { + drain = magic_adjust(drain); + if(drain > 0) { + if(mu > 0 && mp > 4) + drain = min(mp, drain / 3); + else if(cl > 0 && mp > 10) + drain = min(mp, drain / 2); + mp -= drain; + if(mp < 0) mp = 0; + } +} + +bool cCreature::is_alive() const { + return active > 0; +} + +location cCreature::get_loc() const { + return cur_loc; +} + +bool cCreature::is_shielded() const { + if(status[eStatus::MARTYRS_SHIELD] > 0) + return true; + if(abil[eMonstAbil::MARTYRS_SHIELD].active && get_ran(1,1,1000) <= abil[eMonstAbil::MARTYRS_SHIELD].special.extra1) + return true; + return false; +} + +int cCreature::get_shared_dmg(int base_dmg) const { + if(abil[eMonstAbil::MARTYRS_SHIELD].active) { + base_dmg *= abil[eMonstAbil::MARTYRS_SHIELD].special.extra2; + base_dmg /= 100; + } + return base_dmg; +} + +int cCreature::magic_adjust(int how_much) { + if(how_much <= 0) return how_much; + if(abil[eMonstAbil::ABSORB_SPELLS].active && get_ran(1,1,1000) <= abil[eMonstAbil::ABSORB_SPELLS].special.extra1) { + int gain = abil[eMonstAbil::ABSORB_SPELLS].special.extra2; + if(32767 - health > gain) + health = 32767; + else health += gain; + return 0; + } + // TODO: Magic resistance status effect? + how_much *= magic_res; + how_much /= 100; + return how_much; +} + +int cCreature::get_health() const { + return health; +} + +int cCreature::get_magic() const { + return mp; +} + +int cCreature::get_level() const { + return level; +} + +void cCreature::writeTo(std::ostream& file) const { + file << "MONSTER " << number << '\n'; + file << "ATTITUDE " << attitude << '\n'; + file << "STARTATT " << start_attitude << '\n'; + file << "STARTLOC " << start_loc.x << ' ' << start_loc.y << '\n'; + file << "LOCATION " << cur_loc.x << ' ' << cur_loc.y << '\n'; + file << "MOBILITY " << mobility << '\n'; + file << "TIMEFLAG " << time_flag << '\n'; + file << "SUMMONED " << summoned << '\n'; + file << "SPEC " << spec1 << ' ' << spec2 << '\n'; + file << "SPECCODE " << spec_enc_code << '\n'; + file << "TIMECODE " << time_code << '\n'; + file << "TIME " << monster_time << '\n'; + file << "TALK " << personality << '\n'; + file << "DEATH " << special_on_kill << '\n'; + file << "FACE " << facial_pic << '\n'; + file << "TARGET " << target << '\n'; + file << "TARGLOC " << targ_loc.x << ' ' << targ_loc.y << '\n'; + for(auto stat : status) { + if(stat.second != 0) + file << "STATUS " << stat.first << ' ' << stat.second << '\n'; + } + file << "CURHP " << health << '\n'; + file << "CURSP " << mp << '\n'; + file << "MORALE " << morale << '\n'; + file << "DIRECTION " << direction << '\n'; + // TODO: Should we be saving "max_mp" and/or "m_morale"? +} + +void cCreature::readFrom(std::istream& file) { + while(file) { + std::string cur; + getline(file, cur); + std::cout << "Parsing line in town.txt: " << cur << std::endl; + std::istringstream line(cur); + line >> cur; + if(cur == "MONSTER") + line >> number; + else if(cur == "ATTITUDE") + line >> attitude; + else if(cur == "STARTATT") { + unsigned int i; + line >> i; + start_attitude = i; + } else if(cur == "STARTLOC") + line >> start_loc.x >> start_loc.y; + else if(cur == "LOCATION") + line >> cur_loc.x >> cur_loc.y; + else if(cur == "MOBILITY") { + unsigned int i; + line >> i; + mobility = i; + } else if(cur == "TIMEFLAG") { + line >> time_flag; + } else if(cur == "SUMMONED") + line >> summoned; + else if(cur == "SPEC") + line >> spec1 >> spec2; + else if(cur == "SPECCODE") { + int i; + line >> i; + spec_enc_code = i; + } else if(cur == "TIMECODE") { + int i; + line >> i; + time_code = i; + } else if(cur == "TIME") + line >> monster_time; + else if(cur == "TALK") + line >> personality; + else if(cur == "DEATH") + line >> special_on_kill; + else if(cur == "FACE") + line >> facial_pic; + else if(cur == "TARGET") + line >> target; + else if(cur == "TARGLOC") + line >> targ_loc.x >> targ_loc.y; + else if(cur == "CURHP") + line >> health; + else if(cur == "CURSP") + line >> mp; + else if(cur == "MORALE") + line >> morale; + else if(cur == "DIRECTION") + line >> direction; + else if(cur == "STATUS") { + eStatus i; + line >> i >> status[i]; + } + } +} diff --git a/src/classes/creature.hpp b/src/classes/creature.hpp new file mode 100644 index 00000000..f85f702c --- /dev/null +++ b/src/classes/creature.hpp @@ -0,0 +1,69 @@ +// +// creature.hpp +// BoE +// +// Created by Celtic Minstrel on 15-01-24. +// +// + +#ifndef BoE_creature_hpp +#define BoE_creature_hpp + +#include +#include "location.h" +#include "monster.h" +#include "living.hpp" +#include "simpletypes.h" + +class cCreature : public cMonster, public cTownperson, public iLiving { +public: + static const short charm_odds[20]; + short active, attitude; + location cur_loc; + short summoned; + short target; + location targ_loc; + short health; + short mp; + short max_mp; + short morale,m_morale; // these are calculated in-game based on the level + + cCreature(); + cCreature(int num); + + void heal(int how_much); + void poison(int how_much); + void cure(int how_much); + void acid(int how_much); + void curse(int how_much); + void slow(int how_much); + void web(int how_much); + void disease(int how_much); + void dumbfound(int how_much); + void scare(int how_much); + void sleep(eStatus type, int how_much, int adj); + void avatar(); + void drain_sp(int how_much); + void restore_sp(int how_much); + void petrify(int adj); + void kill(eMainStatus type = eMainStatus::DEAD); + + int get_health() const; + int get_magic() const; + int get_level() const; + + bool is_alive() const; + bool is_shielded() const; + int get_shared_dmg(int base_dmg) const; + location get_loc() const; + + int magic_adjust(int base); + + void spell_note(int which); + + void append(legacy::creature_data_type old); + void writeTo(std::ostream& file) const; + void readFrom(std::istream& file); +}; + +#endif diff --git a/src/classes/item.cpp b/src/classes/item.cpp index 38e60797..869a45dd 100644 --- a/src/classes/item.cpp +++ b/src/classes/item.cpp @@ -6,16 +6,19 @@ * */ +#include "item.h" + #include #include #include +#include #include #include -#include "classes.h" #include "boe.consts.h" // TODO: If this is needed here, maybe it shouldn't be in the "boe" namespace #include "oldstructs.h" #include "spell.hpp" +#include "graphtool.hpp" // for get_str() extern const std::multiset equippable = { eItemType::ONE_HANDED, eItemType::TWO_HANDED, eItemType::BOW, eItemType::ARROW, eItemType::THROWN_MISSILE, diff --git a/src/classes/monster.cpp b/src/classes/monster.cpp index b2c0eb08..38b130a3 100644 --- a/src/classes/monster.cpp +++ b/src/classes/monster.cpp @@ -6,6 +6,8 @@ * */ +#include "monster.h" + #include #include #include @@ -13,15 +15,12 @@ #include #include -#include "classes.h" #include "oldstructs.h" #include "fileio.hpp" #include "spell.hpp" -#include "mathutil.hpp" static uAbility test; static_assert(&test.active == &test.missile.active, "uAbility union has incorrect layout"); -const short cCreature::charm_odds[20] = {90,90,85,80,78, 75,73,60,40,30, 20,10,4,1,0, 0,0,0,0,0}; void cMonster::append(legacy::monster_record_type& old){ level = old.level; @@ -387,21 +386,6 @@ cMonster::cMonster(){ see_spec = -1; } -cCreature::cCreature(){ - number = active = attitude = start_attitude = 0; - start_loc.x = start_loc.y = cur_loc.x = cur_loc.y = targ_loc.x = targ_loc.y = 80; - mobility = 1; - summoned = 0; - time_flag = eMonstTime::ALWAYS; - spec1 = spec2 = spec_enc_code = time_code = monster_time = 0; - personality = special_on_kill = facial_pic = -1; - target = 6; -} - -cCreature::cCreature(int num) : cCreature() { - number = num; -} - cTownperson::cTownperson() { start_loc = {80,80}; number = 0; @@ -451,146 +435,6 @@ void cTownperson::append(legacy::creature_start_type old){ facial_pic = NO_PIC; } -void cCreature::append(legacy::creature_data_type old){ - active = old.active; - attitude = old.attitude; - number = old.number; - cur_loc.x = old.m_loc.x; - cur_loc.y = old.m_loc.y; - cMonster::append(old.m_d); - mobility = old.mobile; - summoned = old.summoned; - number = old.monst_start.number; - start_attitude = old.monst_start.start_attitude; - start_loc.x = old.monst_start.start_loc.x; - start_loc.y = old.monst_start.start_loc.y; - mobility = old.monst_start.mobile; - switch(old.monst_start.time_flag) { - case 0: time_flag = eMonstTime::ALWAYS; break; - case 1: time_flag = eMonstTime::APPEAR_ON_DAY; break; - case 2: time_flag = eMonstTime::DISAPPEAR_ON_DAY; break; - case 4: time_flag = eMonstTime::SOMETIMES_A; break; - case 5: time_flag = eMonstTime::SOMETIMES_B; break; - case 6: time_flag = eMonstTime::SOMETIMES_C; break; - case 7: time_flag = eMonstTime::APPEAR_WHEN_EVENT; break; - case 8: time_flag = eMonstTime::DISAPPEAR_WHEN_EVENT; break; - } - spec1 = old.monst_start.spec1; - spec2 = old.monst_start.spec2; - spec_enc_code = old.monst_start.spec_enc_code; - time_code = old.monst_start.time_code; - monster_time = old.monst_start.monster_time; - personality = old.monst_start.personality; - special_on_kill = old.monst_start.special_on_kill; - facial_pic = old.monst_start.facial_pic; - health = old.m_d.health; - mp = old.m_d.mp; - max_mp = old.m_d.max_mp; - ap = old.m_d.ap; - morale = old.m_d.morale; - m_morale = old.m_d.m_morale; - for(int i = 0; i < 15; i++) - status[(eStatus) i] = old.m_d.status[i]; - direction = eDirection(old.m_d.direction); -} - -void cCreature::avatar() { - health = m_health; - status[eStatus::POISON] = 0; - status[eStatus::BLESS_CURSE] = 8; - status[eStatus::HASTE_SLOW] = 8; - status[eStatus::WEBS] = 0; - status[eStatus::DISEASE] = 0; - if(status[eStatus::DUMB] > 0) - status[eStatus::DUMB] = 0; - status[eStatus::MARTYRS_SHIELD] = 8; -} - -void cCreature::heal(int amt) { - if(!is_alive()) return; - if(health >= m_health) return; - health += amt; - if(health > m_health) - health = m_health; -} - -void cCreature::cure(int amt) { - if(!is_alive()) return; - if(status[eStatus::POISON] <= amt) - status[eStatus::POISON] = 0; - else status[eStatus::POISON] -= amt; -} - -void cCreature::restore_sp(int amt) { - if(!is_alive()) return; - mp += amt; - if(mp > max_mp) - mp = max_mp; -} - -void cCreature::drain_sp(int drain) { - drain = magic_adjust(drain); - if(drain > 0) { - if(mu > 0 && mp > 4) - drain = min(mp, drain / 3); - else if(cl > 0 && mp > 10) - drain = min(mp, drain / 2); - mp -= drain; - if(mp < 0) mp = 0; - } -} - -bool cCreature::is_alive() const { - return active > 0; -} - -location cCreature::get_loc() const { - return cur_loc; -} - -bool cCreature::is_shielded() const { - if(status[eStatus::MARTYRS_SHIELD] > 0) - return true; - if(abil[eMonstAbil::MARTYRS_SHIELD].active && get_ran(1,1,1000) <= abil[eMonstAbil::MARTYRS_SHIELD].special.extra1) - return true; - return false; -} - -int cCreature::get_shared_dmg(int base_dmg) const { - if(abil[eMonstAbil::MARTYRS_SHIELD].active) { - base_dmg *= abil[eMonstAbil::MARTYRS_SHIELD].special.extra2; - base_dmg /= 100; - } - return base_dmg; -} - -int cCreature::magic_adjust(int how_much) { - if(how_much <= 0) return how_much; - if(abil[eMonstAbil::ABSORB_SPELLS].active && get_ran(1,1,1000) <= abil[eMonstAbil::ABSORB_SPELLS].special.extra1) { - int gain = abil[eMonstAbil::ABSORB_SPELLS].special.extra2; - if(32767 - health > gain) - health = 32767; - else health += gain; - return 0; - } - // TODO: Magic resistance status effect? - how_much *= magic_res; - how_much /= 100; - return how_much; -} - -int cCreature::get_health() const { - return health; -} - -int cCreature::get_magic() const { - return mp; -} - -int cCreature::get_level() const { - return level; -} - std::ostream& operator<<(std::ostream& out, const cMonster::cAttack& att) { out << int(att.dice) << 'd' << int(att.sides); return out; @@ -1193,95 +1037,3 @@ void cMonster::readFrom(std::istream& file) { } } -void cCreature::writeTo(std::ostream& file) const { - file << "MONSTER " << number << '\n'; - file << "ATTITUDE " << attitude << '\n'; - file << "STARTATT " << start_attitude << '\n'; - file << "STARTLOC " << start_loc.x << ' ' << start_loc.y << '\n'; - file << "LOCATION " << cur_loc.x << ' ' << cur_loc.y << '\n'; - file << "MOBILITY " << mobility << '\n'; - file << "TIMEFLAG " << time_flag << '\n'; - file << "SUMMONED " << summoned << '\n'; - file << "SPEC " << spec1 << ' ' << spec2 << '\n'; - file << "SPECCODE " << spec_enc_code << '\n'; - file << "TIMECODE " << time_code << '\n'; - file << "TIME " << monster_time << '\n'; - file << "TALK " << personality << '\n'; - file << "DEATH " << special_on_kill << '\n'; - file << "FACE " << facial_pic << '\n'; - file << "TARGET " << target << '\n'; - file << "TARGLOC " << targ_loc.x << ' ' << targ_loc.y << '\n'; - for(auto stat : status) { - if(stat.second != 0) - file << "STATUS " << stat.first << ' ' << stat.second << '\n'; - } - file << "CURHP " << health << '\n'; - file << "CURSP " << mp << '\n'; - file << "MORALE " << morale << '\n'; - file << "DIRECTION " << direction << '\n'; - // TODO: Should we be saving "max_mp" and/or "m_morale"? -} - -void cCreature::readFrom(std::istream& file) { - while(file) { - std::string cur; - getline(file, cur); - std::cout << "Parsing line in town.txt: " << cur << std::endl; - std::istringstream line(cur); - line >> cur; - if(cur == "MONSTER") - line >> number; - else if(cur == "ATTITUDE") - line >> attitude; - else if(cur == "STARTATT") { - unsigned int i; - line >> i; - start_attitude = i; - } else if(cur == "STARTLOC") - line >> start_loc.x >> start_loc.y; - else if(cur == "LOCATION") - line >> cur_loc.x >> cur_loc.y; - else if(cur == "MOBILITY") { - unsigned int i; - line >> i; - mobility = i; - } else if(cur == "TIMEFLAG") { - line >> time_flag; - } else if(cur == "SUMMONED") - line >> summoned; - else if(cur == "SPEC") - line >> spec1 >> spec2; - else if(cur == "SPECCODE") { - int i; - line >> i; - spec_enc_code = i; - } else if(cur == "TIMECODE") { - int i; - line >> i; - time_code = i; - } else if(cur == "TIME") - line >> monster_time; - else if(cur == "TALK") - line >> personality; - else if(cur == "DEATH") - line >> special_on_kill; - else if(cur == "FACE") - line >> facial_pic; - else if(cur == "TARGET") - line >> target; - else if(cur == "TARGLOC") - line >> targ_loc.x >> targ_loc.y; - else if(cur == "CURHP") - line >> health; - else if(cur == "CURSP") - line >> mp; - else if(cur == "MORALE") - line >> morale; - else if(cur == "DIRECTION") - line >> direction; - else if(cur == "STATUS") { - eStatus i; - line >> i >> status[i]; - } - } -} diff --git a/src/classes/monster.h b/src/classes/monster.h index 67555c12..b4cdb827 100644 --- a/src/classes/monster.h +++ b/src/classes/monster.h @@ -170,57 +170,6 @@ public: cTownperson(location loc, mon_num_t num, const cMonster& monst); }; -class cCreature : public cMonster, public cTownperson, public iLiving { -public: - static const short charm_odds[20]; - short active, attitude; - location cur_loc; - short summoned; - short target; - location targ_loc; - short health; - short mp; - short max_mp; - short morale,m_morale; // these are calculated in-game based on the level - - cCreature(); - cCreature(int num); - - void heal(int how_much); - void poison(int how_much); - void cure(int how_much); - void acid(int how_much); - void curse(int how_much); - void slow(int how_much); - void web(int how_much); - void disease(int how_much); - void dumbfound(int how_much); - void scare(int how_much); - void sleep(eStatus type, int how_much, int adj); - void avatar(); - void drain_sp(int how_much); - void restore_sp(int how_much); - void petrify(int adj); - void kill(eMainStatus type = eMainStatus::DEAD); - - int get_health() const; - int get_magic() const; - int get_level() const; - - bool is_alive() const; - bool is_shielded() const; - int get_shared_dmg(int base_dmg) const; - location get_loc() const; - - int magic_adjust(int base); - - void spell_note(int which); - - void append(legacy::creature_data_type old); - void writeTo(std::ostream& file) const; - void readFrom(std::istream& file); -}; - std::ostream& operator << (std::ostream& out, eStatus e); std::istream& operator >> (std::istream& in, eStatus& e); std::ostream& operator << (std::ostream& out, eRace e); diff --git a/src/classes/outdoors.cpp b/src/classes/outdoors.cpp index 0e85adaf..142fd487 100644 --- a/src/classes/outdoors.cpp +++ b/src/classes/outdoors.cpp @@ -6,14 +6,16 @@ * */ +#include "outdoors.h" + #include #include #include #include #include "dlogutil.hpp" -#include "classes.h" #include "oldstructs.h" +#include "scenario.h" void cOutdoors::append(legacy::outdoor_record_type& old){ int i,j; diff --git a/src/classes/party.cpp b/src/classes/party.cpp index aaab99fe..1d5618c3 100644 --- a/src/classes/party.cpp +++ b/src/classes/party.cpp @@ -6,14 +6,17 @@ * */ +#include "party.h" + #include #include #include #include #include +#include "scenario.h" +#include "universe.h" #include "dlogutil.hpp" -#include "classes.h" #include "oldstructs.h" #include "fileio.hpp" diff --git a/src/classes/pc.cpp b/src/classes/pc.cpp index 630f2abb..c5ce0ee6 100644 --- a/src/classes/pc.cpp +++ b/src/classes/pc.cpp @@ -13,7 +13,7 @@ #include #include -#include "classes.h" +#include "universe.h" #include "oldstructs.h" #include "mathutil.hpp" diff --git a/src/classes/regtown.cpp b/src/classes/regtown.cpp index 97ee218c..c190d8a1 100644 --- a/src/classes/regtown.cpp +++ b/src/classes/regtown.cpp @@ -6,13 +6,15 @@ * */ +#include "regtown.h" + #include #include #include #include +#include "scenario.h" #include "dlogutil.hpp" -#include "classes.h" #include "oldstructs.h" #include "fileio.hpp" diff --git a/src/classes/scenario.cpp b/src/classes/scenario.cpp index d5587097..0e863e8b 100644 --- a/src/classes/scenario.cpp +++ b/src/classes/scenario.cpp @@ -6,12 +6,13 @@ * */ +#include "scenario.h" + #include #include #include #include -#include "classes.h" #include "oldstructs.h" cScenario::~cScenario() { diff --git a/src/classes/special.cpp b/src/classes/special.cpp index cd746298..229d30a1 100644 --- a/src/classes/special.cpp +++ b/src/classes/special.cpp @@ -6,6 +6,8 @@ * */ +#include "special.h" + #include "special.h" #include #include @@ -14,7 +16,6 @@ #include #include "dlogutil.hpp" -#include "classes.h" #include "oldstructs.h" cSpecial::cSpecial(){ diff --git a/src/classes/talking.cpp b/src/classes/talking.cpp index 5eb51cfe..31d7a4a0 100644 --- a/src/classes/talking.cpp +++ b/src/classes/talking.cpp @@ -6,12 +6,13 @@ * */ +#include "talking.h" + #include #include #include #include -#include "classes.h" #include "oldstructs.h" void cSpeech::append(legacy::talking_record_type& old){ diff --git a/src/classes/talking.h b/src/classes/talking.h index 395b7db0..ac354a34 100644 --- a/src/classes/talking.h +++ b/src/classes/talking.h @@ -10,6 +10,8 @@ #define BOE_DATA_TALKING_H #include +#include +#include "simpletypes.h" namespace legacy { struct talking_record_type; diff --git a/src/classes/terrain.cpp b/src/classes/terrain.cpp index 5691dd3c..aac4d350 100644 --- a/src/classes/terrain.cpp +++ b/src/classes/terrain.cpp @@ -6,13 +6,15 @@ * */ +#include "terrain.h" + #include #include #include #include -#include "classes.h" #include "oldstructs.h" +#include "graphtool.hpp" // for NO_PIC #include "boe.consts.h" // TODO: Put these constants in a global file void cTerrain::append(legacy::terrain_type_type& old){ diff --git a/src/classes/tmpltown.cpp b/src/classes/tmpltown.cpp index ed5e9f80..3da6f6c1 100644 --- a/src/classes/tmpltown.cpp +++ b/src/classes/tmpltown.cpp @@ -6,13 +6,13 @@ * */ +#include "tmpltown.h" + #include #include #include #include -#include "classes.h" - ter_num_t& cBigTemplTown::terrain(size_t x, size_t y){ location pos(x,y); return cBigTown::terrain(x,y); diff --git a/src/classes/town.cpp b/src/classes/town.cpp index dccce21a..231c50cc 100644 --- a/src/classes/town.cpp +++ b/src/classes/town.cpp @@ -6,12 +6,14 @@ * */ +#include "town.h" + #include #include #include #include -#include "classes.h" +#include "scenario.h" #include "oldstructs.h" #include "mathutil.hpp" diff --git a/src/classes/town.h b/src/classes/town.h index da190e46..7edf2eec 100644 --- a/src/classes/town.h +++ b/src/classes/town.h @@ -17,6 +17,7 @@ #include "special.h" #include "monster.h" #include "talking.h" +#include "item.h" namespace legacy { struct town_record_type; diff --git a/src/classes/universe.cpp b/src/classes/universe.cpp index d70f2a23..d61849f7 100644 --- a/src/classes/universe.cpp +++ b/src/classes/universe.cpp @@ -6,13 +6,15 @@ * */ +#include "universe.h" + #include #include #include #include #include -#include "classes.h" +#include "regtown.h" #include "oldstructs.h" #include "mathutil.hpp" #include "fileio.hpp" diff --git a/src/classes/vehicle.cpp b/src/classes/vehicle.cpp index 9d9b98e8..10be3371 100644 --- a/src/classes/vehicle.cpp +++ b/src/classes/vehicle.cpp @@ -6,12 +6,13 @@ * */ +#include "vehicle.h" + #include #include #include #include -#include "classes.h" #include "oldstructs.h" cVehicle::cVehicle() : diff --git a/src/pcedit/pc.action.cpp b/src/pcedit/pc.action.cpp index 5caf8370..5b6a3359 100644 --- a/src/pcedit/pc.action.cpp +++ b/src/pcedit/pc.action.cpp @@ -3,7 +3,7 @@ #include "pc.graphics.h" #include "pc.global.h" -#include "classes.h" +#include "universe.h" #include "pc.editors.h" #include "pc.fileio.h" #include "pc.action.h" diff --git a/src/pcedit/pc.editors.cpp b/src/pcedit/pc.editors.cpp index c116fc35..aa6328bd 100644 --- a/src/pcedit/pc.editors.cpp +++ b/src/pcedit/pc.editors.cpp @@ -1,7 +1,7 @@ #include "pc.graphics.h" #include "pc.global.h" -#include "classes.h" +#include "universe.h" #include "pc.editors.h" #include "graphtool.hpp" #include "dialog.hpp" diff --git a/src/pcedit/pc.fileio.cpp b/src/pcedit/pc.fileio.cpp index c913faac..a0a141d6 100644 --- a/src/pcedit/pc.fileio.cpp +++ b/src/pcedit/pc.fileio.cpp @@ -3,7 +3,7 @@ #include #include "pc.global.h" -#include "classes.h" +#include "universe.h" #include "pc.fileio.h" #include "pc.graphics.h" #include "graphtool.hpp" diff --git a/src/pcedit/pc.graphics.cpp b/src/pcedit/pc.graphics.cpp index 12fa3fcc..e3952788 100644 --- a/src/pcedit/pc.graphics.cpp +++ b/src/pcedit/pc.graphics.cpp @@ -1,7 +1,7 @@ #include #include "pc.global.h" -#include "classes.h" +#include "universe.h" #include "pc.graphics.h" #include "pc.editors.h" #include "pc.action.h" diff --git a/src/pcedit/pc.main.cpp b/src/pcedit/pc.main.cpp index 246eeba0..6c9db790 100644 --- a/src/pcedit/pc.main.cpp +++ b/src/pcedit/pc.main.cpp @@ -2,7 +2,7 @@ #include #include #include "pc.global.h" -#include "classes.h" +#include "universe.h" #include "pc.graphics.h" #include "pc.editors.h" #include "pc.action.h" diff --git a/src/scenedit/scen.actions.cpp b/src/scenedit/scen.actions.cpp index fccb44b4..3d9f11a5 100644 --- a/src/scenedit/scen.actions.cpp +++ b/src/scenedit/scen.actions.cpp @@ -3,7 +3,7 @@ #include #include #include "scen.global.h" -#include "classes.h" +#include "scenario.h" #include "graphtool.hpp" #include "scen.graphics.h" #include "scen.actions.h" diff --git a/src/scenedit/scen.btnmg.cpp b/src/scenedit/scen.btnmg.cpp index 2bbaf103..13a83eb4 100644 --- a/src/scenedit/scen.btnmg.cpp +++ b/src/scenedit/scen.btnmg.cpp @@ -3,7 +3,6 @@ #include #include "scen.global.h" -#include "classes.h" #include "graphtool.hpp" #include "scen.graphics.h" #include diff --git a/src/scenedit/scen.core.cpp b/src/scenedit/scen.core.cpp index ed5fe641..40d449f3 100644 --- a/src/scenedit/scen.core.cpp +++ b/src/scenedit/scen.core.cpp @@ -5,7 +5,8 @@ #include #include #include "scen.global.h" -#include "classes.h" +#include "scenario.h" +#include "regtown.h" #include "graphtool.hpp" #include "scen.graphics.h" #include "scen.core.h" diff --git a/src/scenedit/scen.fileio.cpp b/src/scenedit/scen.fileio.cpp index fc3d090c..2091b1ef 100644 --- a/src/scenedit/scen.fileio.cpp +++ b/src/scenedit/scen.fileio.cpp @@ -1,7 +1,7 @@ #include #include "scen.global.h" -#include "classes.h" +#include "scenario.h" #include #include #include diff --git a/src/scenedit/scen.graphics.cpp b/src/scenedit/scen.graphics.cpp index bd6e53b8..240ce057 100644 --- a/src/scenedit/scen.graphics.cpp +++ b/src/scenedit/scen.graphics.cpp @@ -3,7 +3,7 @@ #include #include #include "scen.global.h" -#include "classes.h" +#include "scenario.h" #include "graphtool.hpp" #include "scen.graphics.h" #include diff --git a/src/scenedit/scen.graphics.h b/src/scenedit/scen.graphics.h index 9efaeb0d..8b232f4c 100644 --- a/src/scenedit/scen.graphics.h +++ b/src/scenedit/scen.graphics.h @@ -1,3 +1,6 @@ + +#include "simpletypes.h" + void Set_up_win (); void run_startup_g(); void load_graphics(); diff --git a/src/scenedit/scen.keydlgs.cpp b/src/scenedit/scen.keydlgs.cpp index 13158779..542e2a2f 100644 --- a/src/scenedit/scen.keydlgs.cpp +++ b/src/scenedit/scen.keydlgs.cpp @@ -5,7 +5,7 @@ #include #include #include "scen.global.h" -#include "classes.h" +#include "scenario.h" #include "graphtool.hpp" #include "scen.graphics.h" #include "scen.keydlgs.h" diff --git a/src/scenedit/scen.main.cpp b/src/scenedit/scen.main.cpp index c5aa78cf..eadfd7c5 100644 --- a/src/scenedit/scen.main.cpp +++ b/src/scenedit/scen.main.cpp @@ -3,7 +3,7 @@ #include #include "scen.global.h" -#include "classes.h" +#include "scenario.h" #include "graphtool.hpp" #include "scen.graphics.h" #include "scen.actions.h" diff --git a/src/scenedit/scen.townout.cpp b/src/scenedit/scen.townout.cpp index 68b85ddb..d91c7f8c 100644 --- a/src/scenedit/scen.townout.cpp +++ b/src/scenedit/scen.townout.cpp @@ -4,7 +4,8 @@ #include #include #include "scen.global.h" -#include "classes.h" +#include "scenario.h" +#include "regtown.h" #include "graphtool.hpp" #include "scen.graphics.h" #include "scen.townout.h" @@ -592,7 +593,6 @@ static void save_out_wand(cDialog& me, short which, cOutdoors::cWandering& wand, static bool edit_out_wand_event_filter(cDialog& me, std::string hit, short& which, cOutdoors::cWandering& wand, short mode) { if(!me.toast(true)) return true; save_out_wand(me, which, wand, mode); - cCreature store_m; if(hit == "left") { me.untoast(); which--; diff --git a/src/tools/fileio.cpp b/src/tools/fileio.cpp index 90073a40..b75bf1b2 100644 --- a/src/tools/fileio.cpp +++ b/src/tools/fileio.cpp @@ -11,39 +11,12 @@ #include #include -#include "dlogutil.hpp" -#include "gzstream.h" - -#include "classes.h" -#include "map_parse.hpp" -#include "graphtool.hpp" -#include "mathutil.hpp" - -#include "porting.hpp" #include "restypes.hpp" -#include "tarball.hpp" #include "cursors.hpp" -bool cur_scen_is_mac = true, mac_is_intel; -extern sf::Texture items_gworld,tiny_obj_gworld,fields_gworld,roads_gworld,boom_gworld,missiles_gworld; -extern sf::Texture dlogpics_gworld,monst_gworld[],terrain_gworld[],anim_gworld,talkfaces_gworld,pc_gworld; -extern sf::Texture status_gworld, vehicle_gworld, small_ter_gworld; -extern cCustomGraphics spec_scen_g; +bool mac_is_intel; fs::path progDir, tempDir; -void load_spec_graphics(fs::path scen_file); -// Load old scenarios (town talk is handled by the town loading function) -static bool load_scenario_v1(fs::path file_to_load, cScenario& scenario); -static bool load_outdoors_v1(fs::path scen_file, location which_out,cOutdoors& the_out, legacy::scenario_data_type& scenario); -static bool load_town_v1(fs::path scen_file, short which_town, cTown& the_town, legacy::scenario_data_type& scenario); -// Load new scenarios -static bool load_outdoors(fs::path out_base, location which_out, cOutdoors& the_out); -static bool load_town(fs::path town_base, short which_town, cTown*& the_town); -static bool load_town_talk(fs::path town_base, short which_town, cSpeech& the_talk); -// Load saved games -static bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there, bool must_port); -static bool load_party_v2(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there); - // Cursors included here so that they needn't be unnecessarily duplicated in platform-specific files cursor_type current_cursor = sword_curs; cursor_type arrow_curs[3][3] = { @@ -110,912 +83,6 @@ void check_for_intel() { mac_is_intel = endian.c; } -bool load_scenario(fs::path file_to_load, cScenario& scenario) { - scenario = cScenario(); - // TODO: Implement checking to determine whether it's old or new - return load_scenario_v1(file_to_load, scenario); -} - -bool load_scenario_v1(fs::path file_to_load, cScenario& scenario){ - short i,n; - bool file_ok = false; - long len; - char temp_str[256]; - legacy::scenario_data_type *temp_scenario = new legacy::scenario_data_type; - legacy::scen_item_data_type *item_data = new legacy::scen_item_data_type; - // TODO: Convert this (and all the others in this file) to use C++ streams - FILE* file_id = fopen(file_to_load.string().c_str(),"rb"); - if(file_id == NULL) { - // TODO: The third parameter to oopsError is supposed to specify whether we're in the scenario editor or the game, but I don't think this code knows that. - // TODO: Alternatively, nuke oopsError and just use giveError. It's more informative, anyway. - oopsError(10, 0, 0); - return false; - } - - len = (long) sizeof(scenario_header_flags); - - if(fread(&scenario.format, len, 1, file_id) < 1){ - fclose(file_id); - oopsError(11, 0, 0); - return false; - } - - if((scenario.format.flag1 == 10) && (scenario.format.flag2 == 20) && - (scenario.format.flag3 == 30) && (scenario.format.flag4 == 40)) { - cur_scen_is_mac = true; - file_ok = true; - } - else if((scenario.format.flag1 == 20) && (scenario.format.flag2 == 40) && - (scenario.format.flag3 == 60) && (scenario.format.flag4 == 80)) { - cur_scen_is_mac = false; - file_ok = true; - } - if(!file_ok) { - fclose(file_id); - giveError("This is not a legitimate Blades of Exile scenario."); - return false; - } - - len = (long) sizeof(legacy::scenario_data_type); - n = fread(temp_scenario, len, 1, file_id); - if(n < 1){ - fclose(file_id); - oopsError(12, 0, 0); - return false; - } - port_scenario(temp_scenario); - len = sizeof(legacy::scen_item_data_type); // item data - n = fread(item_data, len, 1, file_id); - if(n < 1){ - fclose(file_id); - oopsError(13, 0, 0); - return false; - } - port_item_list(item_data); - scenario.append(*temp_scenario); - scenario.append(*item_data); - - // TODO: Consider skipping the fread and assignment when len is 0 - for(i = 0; i < 270; i++) { - len = (long) (temp_scenario->scen_str_len[i]); - n = fread(temp_str, len, 1, file_id); - temp_str[len] = 0; - if(i == 0) scenario.scen_name = temp_str; - else if(i == 1 || i == 2) - scenario.who_wrote[i-1] = temp_str; - else if(i == 3) - scenario.contact_info = temp_str; - else if(i >= 4 && i < 10) - scenario.intro_strs[i-4] = temp_str; - else if(i >= 10 && i < 60) - scenario.journal_strs[i-10] = temp_str; - else if(i >= 60 && i < 160) { - if(i % 2 == 0) scenario.special_items[(i-60)/2].name = temp_str; - else scenario.special_items[(i-60)/2].descr = temp_str; - } else if(i >= 260) continue; // These were never ever used, for some reason. - else scenario.spec_strs[i-160] = temp_str; - } - - fclose(file_id); - - scenario.ter_types[23].fly_over = false; - - scenario.scen_file = file_to_load; - load_spec_graphics(scenario.scen_file); - - // Now load all the outdoor sectors - scenario.outdoors.resize(temp_scenario->out_width, temp_scenario->out_height); - for(int x = 0; x < temp_scenario->out_width; x++) { - for(int y = 0; y < temp_scenario->out_height; y++) { - scenario.outdoors[x][y] = new cOutdoors(scenario); - load_outdoors_v1(scenario.scen_file, loc(x,y), *scenario.outdoors[x][y], *temp_scenario); - } - } - - // Then load all the towns - scenario.towns.resize(scenario.format.num_towns); - for(int i = 0; i < scenario.format.num_towns; i++) { - switch(temp_scenario->town_size[i]) { - case 0: scenario.towns[i] = new cBigTown(scenario); break; - case 1: scenario.towns[i] = new cMedTown(scenario); break; - case 2: scenario.towns[i] = new cTinyTown(scenario); break; - } - load_town_v1(scenario.scen_file, i, *scenario.towns[i], *temp_scenario); - } - - delete temp_scenario; - delete item_data; - return true; -} - -static long get_town_offset(short which_town, legacy::scenario_data_type& scenario){ - int i,j; - long len_to_jump,store; - - len_to_jump = sizeof(scenario_header_flags); - len_to_jump += sizeof(legacy::scenario_data_type); - len_to_jump += sizeof(legacy::scen_item_data_type); - for(i = 0; i < 300; i++) - len_to_jump += (long) scenario.scen_str_len[i]; - store = 0; - for(i = 0; i < 100; i++) - for(j = 0; j < 2; j++) - store += (long) (scenario.out_data_size[i][j]); - for(i = 0; i < which_town; i++) - for(j = 0; j < 5; j++) - store += (long) (scenario.town_data_size[i][j]); - len_to_jump += store; - - return len_to_jump; -} - -bool load_town_v1(fs::path scen_file, short which_town, cTown& the_town, legacy::scenario_data_type& scenario) { - short i,n; - long len,len_to_jump = 0; - char temp_str[256]; - legacy::town_record_type store_town; - legacy::talking_record_type store_talk; - legacy::big_tr_type t_d; - legacy::ave_tr_type ave_t; - legacy::tiny_tr_type tiny_t; - - FILE* file_id = fopen(scen_file.string().c_str(), "rb"); - if(file_id == NULL) { - oopsError(14, 0, 0); - return false; - } - - len_to_jump = get_town_offset(which_town, scenario); - n = fseek(file_id, len_to_jump, SEEK_SET); - if(n != 0) { - fclose(file_id); - oopsError(15, 0, 0); - return false; - } - - len = sizeof(legacy::town_record_type); - n = fread(&store_town, len, 1, file_id); - if(n < 1) { - fclose(file_id); - oopsError(16, 0, 0); - return false; - } - port_town(&store_town); - - switch(scenario.town_size[which_town]) { - case 0: - len = sizeof(legacy::big_tr_type); - n = fread(&t_d, len, 1, file_id); - port_t_d(&t_d); - the_town.append(store_town); - the_town.append(t_d, which_town); - break; - - case 1: - len = sizeof(legacy::ave_tr_type); - n = fread(&ave_t, len, 1, file_id); - port_ave_t(&ave_t); - the_town.append(store_town); - the_town.append(ave_t, which_town); - break; - - case 2: - len = sizeof(legacy::tiny_tr_type); - n = fread(&tiny_t, len, 1, file_id); - port_tiny_t(&tiny_t); - the_town.append(store_town); - the_town.append(tiny_t, which_town); - break; - } - - for(i = 0; i < 140; i++) { - len = (long) (store_town.strlens[i]); - n = fread(temp_str, len, 1, file_id); - temp_str[len] = 0; - if(i == 0) the_town.town_name = temp_str; - else if(i >= 1 && i < 17) - the_town.room_rect[i-1].descr = temp_str; - else if(i >= 17 && i < 20) - the_town.comment[i-17] = temp_str; - else if(i >= 20 && i < 120) - the_town.spec_strs[i-20] = temp_str; - else if(i >= 120 && i < 140) - the_town.sign_strs[i-120] = temp_str; - } - - len = sizeof(legacy::talking_record_type); - n = fread(&store_talk, len, 1, file_id); - if(n < 1) { - fclose(file_id); - oopsError(17, 0, 0); - return false; - } - port_talk_nodes(&store_talk); - the_town.talking.append(store_talk); - - for(i = 0; i < 170; i++) { - len = (long) (the_town.talking.strlens[i]); - n = fread(temp_str, len, 1, file_id); - temp_str[len] = 0; - if(i >= 0 && i < 10) - the_town.talking.people[i].title = temp_str; - else if(i >= 10 && i < 20) - the_town.talking.people[i-10].look = temp_str; - else if(i >= 20 && i < 30) - the_town.talking.people[i-20].name = temp_str; - else if(i >= 30 && i < 40) - the_town.talking.people[i-30].job = temp_str; - else if(i >= 160) - the_town.talking.people[i-160].dunno = temp_str; - else { - if(i % 2 == 0) - the_town.talking.talk_nodes[(i-40)/2].str1 = temp_str; - else the_town.talking.talk_nodes[(i-40)/2].str2 = temp_str; - } - } - - n = fclose(file_id); - if(n != 0) { - oopsError(18, 0, 0); - } - - return true; -} - -bool load_town(fs::path town_base, short which_town, cTown*& the_town) { - // TODO: This stuff goes in load_scenario() now -// fs::path town_base = scenario.scen_file/"towns"; - std::string base_fname = "t" + std::to_string(which_town), fname; - // TODO: Implement all this. - // First load the main town data. - fname = base_fname + ".xml"; - // Next, load in the town map. - fname = base_fname + ".map"; - map_data map = load_map(town_base/fname, true); - // Then load the town's special nodes. - fname = base_fname + ".spec"; - // Load the town's special encounter strings - fname = base_fname + ".txt"; - // And finally, load the town's dialogue nodes. - load_town_talk(town_base, which_town, the_town->talking); - return false; -} - -bool load_town_talk(fs::path town_base, short which_town, cSpeech& the_talk) { - // TODO: Implement this. - std::string fname = "t" + std::to_string(which_town) + "talk.xml"; - return false; -} - -static long get_outdoors_offset(location& which_out, legacy::scenario_data_type& scenario){ - int i,j,out_sec_num; - long len_to_jump,store; - out_sec_num = scenario.out_width * which_out.y + which_out.x; - - len_to_jump = sizeof(scenario_header_flags); - len_to_jump += sizeof(legacy::scenario_data_type); - len_to_jump += sizeof(legacy::scen_item_data_type); - for(i = 0; i < 300; i++) - len_to_jump += (long) scenario.scen_str_len[i]; - store = 0; - for(i = 0; i < out_sec_num; i++) - for(j = 0; j < 2; j++) - store += (long) (scenario.out_data_size[i][j]); - len_to_jump += store; - - return len_to_jump; -} - -//mode -> 0 - primary load 1 - add to top 2 - right 3 - bottom 4 - left -bool load_outdoors_v1(fs::path scen_file, location which_out,cOutdoors& the_out, legacy::scenario_data_type& scenario){ - short i,n; - long len,len_to_jump; - char temp_str[256]; - legacy::outdoor_record_type store_out; - - FILE* file_id = fopen(scen_file.string().c_str(), "rb"); - if(file_id == NULL) { - oopsError(32, 0, 0); - return false; - } - - len_to_jump = get_outdoors_offset(which_out, scenario); - n = fseek(file_id, len_to_jump, SEEK_SET); - if(n != 0) { - fclose(file_id); - oopsError(33, 0, 0); - return false; - } - - len = sizeof(legacy::outdoor_record_type); - n = fread(&store_out, len, 1, file_id); - if(n < 1) { - fclose(file_id); - oopsError(34, 0, 0); - return false; - } - - the_out.x = which_out.x; - the_out.y = which_out.y; - port_out(&store_out); - the_out.append(store_out); - for(i = 0; i < 108; i++) { - len = (long) (store_out.strlens[i]); - n = fread(temp_str, len, 1, file_id); - temp_str[len] = 0; - if(i == 0) the_out.out_name = temp_str; - else if(i == 9) the_out.comment = temp_str; - else if(i < 9) the_out.info_rect[i-1].descr = temp_str; - else if(i >= 10 && i < 100) - the_out.spec_strs[i-10] = temp_str; - else if(i >= 100 && i < 108) - the_out.sign_strs[i-100] = temp_str; - } - - n = fclose(file_id); - if(n != 0) { - oopsError(35, 0, 0); - } - return true; -} - -bool load_outdoors(fs::path out_base, location which_out,cOutdoors& the_out) { - // TODO: This bit goes in load_scenario() now -// fs::path town_base = scenario.scen_file/"outdoors"; - std::string base_fname = "tut" + std::to_string(which_out.x) + "~" + std::to_string(which_out.y), fname; - // TODO: Implement all this. - // First load the main sector data. - fname = base_fname + ".xml"; - // Next, load in the sector map. - fname = base_fname + ".map"; - map_data map = load_map(out_base/fname, false); - // Then load the sector's special nodes. - fname = base_fname + ".spec"; - // Load the sector's special encounter strings - fname = base_fname + ".txt"; - return false; -} - -#ifdef __APPLE__ -bool tryLoadPictFromResourceFile(fs::path& gpath, sf::Image& graphics_store); -#endif - -void load_spec_graphics(fs::path scen_file) { - static const char*const noGraphics = "The game will still work without the custom graphics, but some things will not look right."; - short i; - fs::path path(scen_file); - std::cout << "Loading scenario graphics... (" << path << ")\n"; - // Tried path.replace_extension, but that only deleted the extension, so I have to do it manually - std::string filename = path.stem().string(); - path = path.parent_path(); - if(spec_scen_g) spec_scen_g.clear(); - // TODO: Load new-style sheets - { - static sf::Image graphics_store; - bool foundGraphics = false; -#ifdef __APPLE__ - fs::path gpath = path/(filename + ".meg"); - if(fs::exists(gpath)) - foundGraphics = tryLoadPictFromResourceFile(gpath, graphics_store); -#endif - if(!foundGraphics) { - fs::path gpath = path/(filename + ".bmp"); - if(fs::exists(gpath)) { - if(graphics_store.loadFromFile(gpath.string())) - foundGraphics = true; - else giveError("An old-style .bmp graphics file was found, but there was an error reading from the file.",noGraphics); - } - } - if(foundGraphics) { - // If we're here, we found old-style graphics. - // This means they need an alpha channel - graphics_store.createMaskFromColor(sf::Color::White); - spec_scen_g.is_old = true; - spec_scen_g.sheets = new sf::Texture[1]; - spec_scen_g.sheets[0].loadFromImage(graphics_store); - } else { - // Check for new-style graphics - } - }//else{} - - // TODO: This should really reload ALL textures... - // Now load regular graphics - items_gworld.loadFromImage(*ResMgr::get("objects")); - tiny_obj_gworld.loadFromImage(*ResMgr::get("tinyobj")); - fields_gworld.loadFromImage(*ResMgr::get("fields")); - roads_gworld.loadFromImage(*ResMgr::get("trim")); - boom_gworld.loadFromImage(*ResMgr::get("booms")); - missiles_gworld.loadFromImage(*ResMgr::get("missiles")); - dlogpics_gworld.loadFromImage(*ResMgr::get("dlogpics")); - status_gworld.loadFromImage(*ResMgr::get("staticons")); - - for(i = 0; i < NUM_MONST_SHEETS; i++){ - std::ostringstream sout; - sout << "monst" << i + 1; - monst_gworld[i].loadFromImage(*ResMgr::get(sout.str())); - } - for(i = 0; i < NUM_TER_SHEETS; i++){ - std::ostringstream sout; - sout << "ter" << i + 1; - terrain_gworld[i].loadFromImage(*ResMgr::get(sout.str())); - } - anim_gworld.loadFromImage(*ResMgr::get("teranim")); - talkfaces_gworld.loadFromImage(*ResMgr::get("talkportraits")); - pc_gworld.loadFromImage(*ResMgr::get("pcs")); - vehicle_gworld.loadFromImage(*ResMgr::get("vehicle")); - small_ter_gworld.loadFromImage(*ResMgr::get("termap")); - // TODO: Scenario icons ... -} - -bool load_party(fs::path file_to_load, cUniverse& univ){ - bool town_restore = false; - bool maps_there = false; - bool in_scen = false; - enum {old_mac, old_win, new_oboe, unknown} format; - typedef unsigned short ushort; - - long len; - short vers,n; - struct {ushort a; ushort b; ushort c; ushort d; ushort e;} flags; - - // TODO: Putting these flags in hex would make some things a bit clearer - static const unsigned short mac_flags[3][2] = { - {5790,1342}, // slot 0 ... 5790 - out, 1342 - town - {100,200}, // slot 1 ... 100 - in scenario, 200 - not in - {3422,5567} // slot 2 ... 3422 - no maps, 5567 - maps - }; - static const unsigned short win_flags[3][2] = { - {40470,15877}, // slot 0 ... 40470 - out, 15877 - town - {25600,51200}, // slot 1 ... 25600 - in scenario, 51200 - not in - {24077,48917} // slot 2 ... 24077 - no maps, 48917 - maps - }; - // but if the first flag is 0x0B0E, we have a new-format save - // the three flags still follow that. - FILE* file_id = fopen(file_to_load.string().c_str(), "rb"); - if(file_id == NULL) { - cChoiceDlog("load-game-fail").show(); - return false; - } - - len = sizeof(flags); // 10 - - n = fread(&flags, len, 1, file_id); - if(n < 1) { - fclose(file_id); - cChoiceDlog("not-save-game").show(); - return false; - } - - if(mac_is_intel && flags.a == 0x0B0E){ // new format - format = new_oboe; - if(flags.b == mac_flags[0][1]) town_restore = true; - else if(flags.b != mac_flags[0][0]) format = unknown; - if(flags.c == mac_flags[1][0]) in_scen = true; - else if(flags.c != mac_flags[1][1]) format = unknown; - if(flags.d == mac_flags[2][1]) maps_there = true; - else if(flags.d != mac_flags[2][0]) format = unknown; - vers = flags.e; - }else if(!mac_is_intel && flags.a == 0x0E0B){ // new format - format = new_oboe; - flip_short((short*)&flags.b); - flip_short((short*)&flags.c); - flip_short((short*)&flags.d); - flip_short((short*)&flags.e); - if(flags.b == mac_flags[0][1]) town_restore = true; - else if(flags.b != mac_flags[0][0]) format = unknown; - if(flags.c == mac_flags[1][0]) in_scen = true; - else if(flags.c != mac_flags[1][1]) format = unknown; - if(flags.d == mac_flags[2][1]) maps_there = true; - else if(flags.d != mac_flags[2][0]) format = unknown; - vers = flags.e; - }else if(flags.a == mac_flags[0][0] || flags.a == mac_flags[0][1]){ // old format - if(mac_is_intel){ // it's actually a windows save - flip_short((short*)&flags.a); - flip_short((short*)&flags.b); - flip_short((short*)&flags.c); - format = old_win; - if(flags.a == win_flags[0][1]) town_restore = true; - else if(flags.a != win_flags[0][0]) format = unknown; - if(flags.b == win_flags[1][0]) in_scen = true; - else if(flags.b != win_flags[1][1]) format = unknown; - if(flags.c == win_flags[2][1]) maps_there = true; - else if(flags.c != win_flags[2][0]) format = unknown; - }else{ // mac save - format = old_mac; - if(flags.a == mac_flags[0][1]) town_restore = true; - else if(flags.a != mac_flags[0][0]) format = unknown; - if(flags.b == mac_flags[1][0]) in_scen = true; - else if(flags.b != mac_flags[1][1]) format = unknown; - if(flags.c == mac_flags[2][1]) maps_there = true; - else if(flags.c != mac_flags[2][0]) format = unknown; - } - }else if(flags.a == win_flags[0][0] || flags.a == win_flags[0][1]){ // old format - if(mac_is_intel){ // it's actually a macintosh save - flip_short((short*)&flags.a); - flip_short((short*)&flags.b); - flip_short((short*)&flags.c); - format = old_mac; - if(flags.a == mac_flags[0][1]) town_restore = true; - else if(flags.a != mac_flags[0][0]) format = unknown; - if(flags.b == mac_flags[1][0]) in_scen = true; - else if(flags.b != mac_flags[1][1]) format = unknown; - if(flags.c == mac_flags[2][1]) maps_there = true; - else if(flags.c != mac_flags[2][0]) format = unknown; - }else{ // win save - format = old_win; - if(flags.a == win_flags[0][1]) town_restore = true; - else if(flags.a != win_flags[0][0]) format = unknown; - if(flags.b == win_flags[1][0]) in_scen = true; - else if(flags.b != win_flags[1][1]) format = unknown; - if(flags.c == win_flags[2][1]) maps_there = true; - else if(flags.c != win_flags[2][0]) format = unknown; - } - }else format = unknown; - - fclose(file_id); - switch(format){ - case old_mac: - return load_party_v1(file_to_load, univ, town_restore, in_scen, maps_there, mac_is_intel); - case old_win: - return load_party_v1(file_to_load, univ, town_restore, in_scen, maps_there, !mac_is_intel); - case new_oboe: - return load_party_v2(file_to_load, univ, town_restore, in_scen, maps_there); - case unknown: - cChoiceDlog("not-save-game").show(); - return false; - } - - return true; -} - -bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there, bool must_port){ - std::ifstream fin(file_to_load.c_str(), std::ios_base::binary); - fin.seekg(3*sizeof(short),std::ios_base::beg); // skip the header, which is 6 bytes in the old format - - legacy::party_record_type store_party; - legacy::setup_save_type store_setup; - legacy::pc_record_type store_pc[6]; - legacy::out_info_type store_out_info; - legacy::current_town_type store_c_town; - legacy::big_tr_type t_d; - legacy::town_item_list t_i; - legacy::stored_items_list_type stored_items[3]; - legacy::stored_town_maps_type town_maps; - legacy::stored_outdoor_maps_type o_maps; - unsigned char misc_i[64][64], sfx[64][64]; - char *party_ptr; - char *pc_ptr; - long len,store_len,count; - - // LOAD PARTY - len = (long) sizeof(legacy::party_record_type); // should be 46398 - store_len = len; - fin.read((char*)&store_party, len); - if(must_port) port_party(&store_party); - party_ptr = (char*) &store_party; - for(count = 0; count < store_len; count++) - party_ptr[count] ^= 0x5C; - - // LOAD SETUP - len = (long) sizeof(legacy::setup_save_type); - fin.read((char*)&store_setup, len); - - // LOAD PCS - store_len = (long) sizeof(legacy::pc_record_type); - for(int i = 0; i < 6; i++) { - len = store_len; - fin.read((char*)&store_pc[i], len); - if(must_port) port_pc(&store_pc[i]); - pc_ptr = (char*) &store_pc[i]; - for(count = 0; count < store_len; count++) - pc_ptr[count] ^= 0x6B; - } - - if(in_scen) { - - // LOAD OUTDOOR MAP - len = (long) sizeof(legacy::out_info_type); - fin.read((char*)&store_out_info, len); - - // LOAD TOWN - if(town_restore) { - len = (long) sizeof(legacy::current_town_type); - fin.read((char*)&store_c_town, len); - if(must_port) port_c_town(&store_c_town); - - len = (long) sizeof(legacy::big_tr_type); - fin.read((char*)&t_d, len); - if(must_port) port_t_d(&t_d); - - len = (long) sizeof(legacy::town_item_list); - fin.read((char*)&t_i, len); - }else univ.town.num = 200; - - // LOAD STORED ITEMS - for(int i = 0; i < 3; i++) { - len = (long) sizeof(legacy::stored_items_list_type); - fin.read((char*)&stored_items[i], len); - } - - // LOAD SAVED MAPS - if(maps_there) { - len = (long) sizeof(legacy::stored_town_maps_type); - fin.read((char*)&town_maps, len); - - len = (long) sizeof(legacy::stored_outdoor_maps_type); - fin.read((char*)&o_maps, len); - } - - // LOAD SFX & MISC_I - len = (long) (64 * 64); - fin.read((char*)sfx, len); - - fin.read((char*)misc_i, len); - - } // end if_scen - - fin.close(); - - univ.~cUniverse(); - new(&univ) cUniverse(' '); - - if(in_scen){ - fs::path path; - path = progDir/"Blades of Exile Scenarios"/univ.party.scen_name; - - if(!load_scenario(path, univ.scenario)) - return false; - univ.file = path; - }else{ - univ.party.scen_name = ""; - } - - univ.party.append(store_party); - univ.party.append(store_setup); - univ.party.append(store_pc); - if(in_scen){ - univ.out.append(store_out_info); - if(town_restore){ - univ.town.append(store_c_town); - univ.town.append(t_d); - univ.town.append(t_i); - } - for(int i = 0; i < 3; i++) - univ.party.append(stored_items[i],i); - univ.append(town_maps); - univ.append(o_maps); - univ.town.append(sfx, misc_i); - } - - // Compatibility flags - // TODO: Pretty sure I did this elsewhere, so probably don't need it here - if(in_scen && univ.scenario.format.prog_make_ver[0] < 2){ - univ.party.stuff_done[305][8] = 1; - } else { - univ.party.stuff_done[305][8] = 0; - } - - return true; -} - -bool load_party_v2(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there){ - if(!fs::exists(tempDir)) fs::create_directories(tempDir); - fs::path tempPath = tempDir/"loadtemp.exg"; - - { // First, strip off the header and save to a temporary location. - std::ifstream fin(file_to_load.c_str(), std::ios_base::binary); - std::ofstream fout(tempPath.c_str(), std::ios_base::binary); - fin.seekg(10); - fout << fin.rdbuf(); - fin.close(); - fout.close(); - } - - igzstream zin(tempPath.string().c_str()); - tarball partyIn; - partyIn.readFrom(zin); - zin.close(); - - univ.~cUniverse(); - new(&univ) cUniverse(' '); - - { // Load main party data first - std::istream& fin = partyIn.getFile("save/party.txt"); - if(!fin) { - cChoiceDlog("load-game-fail").show(); - return false; - } - univ.party.readFrom(fin); - } - - { // Then the "setup" array - std::istream& fin = partyIn.getFile("save/setup.dat"); - if(!fin) { - cChoiceDlog("load-game-fail").show(); - return false; - } - uint16_t magic; - fin.read((char*)&magic, 2); - fin.read((char*)&univ.party.setup, sizeof(univ.party.setup)); - if(magic == 0x0E0B) // should be 0x0B0E! - for(auto& i : univ.party.setup) - for(auto& j : i) - for(auto& k : j) - flip_short(reinterpret_cast(&k)); - } - - // Next load the PCs - for(int i = 0; i < 6; i++) { - static char fname[] = "save/pc1.txt"; - fname[7] = i + '1'; - std::istream& fin = partyIn.getFile(fname); - if(!fin) { - cChoiceDlog("load-game-fail").show(); - return false; - } - univ.party[i].readFrom(fin); - } - - if(in_scen) { - fs::path path; - path = progDir/"Blades of Exile Scenarios"/univ.party.scen_name; - - if(!load_scenario(path, univ.scenario)) - return false; - - if(town_restore) { - // Load town data - std::istream& fin = partyIn.getFile("save/town.txt"); - if(!fin) { - cChoiceDlog("load-game-fail").show(); - return false; - } - univ.town.readFrom(fin); - - if(maps_there) { - // Read town maps - std::istream& fin = partyIn.getFile("save/townmaps.dat"); - // TODO: Warn if maps missing - for(int i = 0; i < 200; i++) - for(int j = 0; j < 8; j++) - for(int k = 0; k < 64; k++) - univ.town_maps[i][j][k] = fin.get(); - } - } - - // Load outdoors data - std::istream& fin = partyIn.getFile("save/out.txt"); - if(!fin) { - cChoiceDlog("load-game-fail").show(); - return false; - } - univ.out.readFrom(fin); - - if(maps_there) { - // Read outdoor maps - std::istream& fin = partyIn.getFile("save/outmaps.dat"); - // TODO: Warn if maps missing - for(int i = 0; i < 100; i++) - for(int j = 0; j < 6; j++) - for(int k = 0; k < 48; k++) - univ.out_maps[i][j][k] = fin.get(); - } - } else univ.party.scen_name = ""; - - if(partyIn.hasFile("save/export.png")) { - std::istream& fin = partyIn.getFile("save/export.png"); - sf::Image party_sheet; - StdInputStream stream(fin); - if(party_sheet.loadFromStream(stream)) { - spec_scen_g.party_sheet.reset(new sf::Texture); - spec_scen_g.party_sheet->create(party_sheet.getSize().x, party_sheet.getSize().y); - spec_scen_g.party_sheet->update(party_sheet); - } else giveError("There was an error loading the party custom graphics."); - } - - return true; -} - -//mode; // 0 - normal 1 - save as -bool save_party(fs::path dest_file, const cUniverse& univ) { - if(!fs::exists(tempDir)) fs::create_directories(tempDir); - - // Make sure it has the proper file extension - std::string fname = dest_file.filename().string(); - size_t dot = fname.find_last_of('.'); - if(dot == std::string::npos || fname.substr(dot) != ".exg") - fname += ".exg"; - dest_file = dest_file.parent_path()/fname; - - bool in_scen = univ.party.scen_name != ""; - bool in_town = univ.town.num < 200; - bool save_maps = !univ.party.stuff_done[306][0]; - - tarball partyOut; - - // First, write the main party data - univ.party.writeTo(partyOut.newFile("save/party.txt")); - { - std::ostream& fout = partyOut.newFile("save/setup.dat"); - static uint16_t magic = 0x0B0E; - fout.write((char*)&magic, 2); - fout.write((char*)&univ.party.setup, sizeof(univ.party.setup)); - } - - // Then write the data for each of the party members - for(int i = 0; i < 6; i++) { - static char fname[] = "save/pc1.txt"; - fname[7] = i + '1'; - univ.party[i].writeTo(partyOut.newFile(fname)); - } - - if(in_scen) { - if(in_town) { - // Write the current town data - univ.town.writeTo(partyOut.newFile("save/town.txt")); - - if(save_maps) { - // Write the town map data - std::ostream& fout = partyOut.newFile("save/townmaps.dat"); - for(int i = 0; i < 200; i++) - for(int j = 0; j < 8; j++) - for(int k = 0; k < 64; k++) - fout.put(univ.town_maps[i][j][k]); - } - } - - // Write the current outdoors data - univ.out.writeTo(partyOut.newFile("save/out.txt")); - - if(save_maps) { - // Write the outdoors map data - std::ostream& fout = partyOut.newFile("save/outmaps.dat"); - for(int i = 0; i < 100; i++) - for(int j = 0; j < 6; j++) - for(int k = 0; k < 48; k++) - fout.put(univ.out_maps[i][j][k]); - } - } - - if(spec_scen_g.party_sheet) { - sf::Image party_pics = spec_scen_g.party_sheet->copyToImage(); - party_pics.flipVertically(); - fs::path tempPath = tempDir/"temp.png"; - party_pics.saveToFile(tempPath.string()); - std::ostream& pic_out = partyOut.newFile("save/export.png"); - std::ifstream fin(tempPath.string().c_str(), std::ios::binary); - pic_out << fin.rdbuf(); - fin.close(); - } - - // Write out the compressed data - fs::path tempPath = tempDir/"savetemp.exg"; - ogzstream zout(tempPath.string().c_str()); - partyOut.writeTo(zout); - zout.close(); - - // Now add the header. We use the temporary file because we want the header to be uncompressed. - int16_t flags[] = { - 0x0B0E, // to indicate new format - static_cast(in_town ? 1342 : 5790), // is the party in town? - static_cast(in_scen ? 100 : 200), // is the party in a scenario? - static_cast(save_maps ? 5567 : 3422), // is the save maps feature enabled? - OBOE_CURRENT_VERSION >> 8, // current version number, major and minor revisions only - // Version 1 indicates a beta format that may not be supported in the final release - }; - if(!mac_is_intel) // must flip all the flags to little-endian - for(int i = 0; i < 5; i++) - flip_short(&flags[i]); - - std::ifstream fin(tempPath.c_str(), std::ios_base::binary); - std::ofstream fout(dest_file.c_str(), std::ios_base::binary); - fout.write((char*) flags, 10); - fout << fin.rdbuf(); - fin.close(); - fout.close(); - return true; -} - std::string read_maybe_quoted_string(std::istream& from) { std::string result; from >> std::ws; diff --git a/src/tools/fileio_party.cpp b/src/tools/fileio_party.cpp new file mode 100644 index 00000000..40a267bd --- /dev/null +++ b/src/tools/fileio_party.cpp @@ -0,0 +1,499 @@ +// +// fileio_party.cpp +// BoE +// +// Created by Celtic Minstrel on 15-01-24. +// +// + +#include "fileio.hpp" + +#include +#include + +#include "dlogutil.hpp" +#include "gzstream.h" + +#include "universe.h" +#include "graphtool.hpp" + +#include "porting.hpp" +#include "tarball.hpp" + +extern bool mac_is_intel; +extern fs::path progDir, tempDir; +extern cCustomGraphics spec_scen_g; + +// Load saved games +static bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there, bool must_port); +static bool load_party_v2(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there); + +bool load_party(fs::path file_to_load, cUniverse& univ){ + bool town_restore = false; + bool maps_there = false; + bool in_scen = false; + enum {old_mac, old_win, new_oboe, unknown} format; + typedef unsigned short ushort; + + long len; + short vers,n; + struct {ushort a; ushort b; ushort c; ushort d; ushort e;} flags; + + // TODO: Putting these flags in hex would make some things a bit clearer + static const unsigned short mac_flags[3][2] = { + {5790,1342}, // slot 0 ... 5790 - out, 1342 - town + {100,200}, // slot 1 ... 100 - in scenario, 200 - not in + {3422,5567} // slot 2 ... 3422 - no maps, 5567 - maps + }; + static const unsigned short win_flags[3][2] = { + {40470,15877}, // slot 0 ... 40470 - out, 15877 - town + {25600,51200}, // slot 1 ... 25600 - in scenario, 51200 - not in + {24077,48917} // slot 2 ... 24077 - no maps, 48917 - maps + }; + // but if the first flag is 0x0B0E, we have a new-format save + // the three flags still follow that. + FILE* file_id = fopen(file_to_load.string().c_str(), "rb"); + if(file_id == NULL) { + cChoiceDlog("load-game-fail").show(); + return false; + } + + len = sizeof(flags); // 10 + + n = fread(&flags, len, 1, file_id); + if(n < 1) { + fclose(file_id); + cChoiceDlog("not-save-game").show(); + return false; + } + + if(mac_is_intel && flags.a == 0x0B0E){ // new format + format = new_oboe; + if(flags.b == mac_flags[0][1]) town_restore = true; + else if(flags.b != mac_flags[0][0]) format = unknown; + if(flags.c == mac_flags[1][0]) in_scen = true; + else if(flags.c != mac_flags[1][1]) format = unknown; + if(flags.d == mac_flags[2][1]) maps_there = true; + else if(flags.d != mac_flags[2][0]) format = unknown; + vers = flags.e; + }else if(!mac_is_intel && flags.a == 0x0E0B){ // new format + format = new_oboe; + flip_short((short*)&flags.b); + flip_short((short*)&flags.c); + flip_short((short*)&flags.d); + flip_short((short*)&flags.e); + if(flags.b == mac_flags[0][1]) town_restore = true; + else if(flags.b != mac_flags[0][0]) format = unknown; + if(flags.c == mac_flags[1][0]) in_scen = true; + else if(flags.c != mac_flags[1][1]) format = unknown; + if(flags.d == mac_flags[2][1]) maps_there = true; + else if(flags.d != mac_flags[2][0]) format = unknown; + vers = flags.e; + }else if(flags.a == mac_flags[0][0] || flags.a == mac_flags[0][1]){ // old format + if(mac_is_intel){ // it's actually a windows save + flip_short((short*)&flags.a); + flip_short((short*)&flags.b); + flip_short((short*)&flags.c); + format = old_win; + if(flags.a == win_flags[0][1]) town_restore = true; + else if(flags.a != win_flags[0][0]) format = unknown; + if(flags.b == win_flags[1][0]) in_scen = true; + else if(flags.b != win_flags[1][1]) format = unknown; + if(flags.c == win_flags[2][1]) maps_there = true; + else if(flags.c != win_flags[2][0]) format = unknown; + }else{ // mac save + format = old_mac; + if(flags.a == mac_flags[0][1]) town_restore = true; + else if(flags.a != mac_flags[0][0]) format = unknown; + if(flags.b == mac_flags[1][0]) in_scen = true; + else if(flags.b != mac_flags[1][1]) format = unknown; + if(flags.c == mac_flags[2][1]) maps_there = true; + else if(flags.c != mac_flags[2][0]) format = unknown; + } + }else if(flags.a == win_flags[0][0] || flags.a == win_flags[0][1]){ // old format + if(mac_is_intel){ // it's actually a macintosh save + flip_short((short*)&flags.a); + flip_short((short*)&flags.b); + flip_short((short*)&flags.c); + format = old_mac; + if(flags.a == mac_flags[0][1]) town_restore = true; + else if(flags.a != mac_flags[0][0]) format = unknown; + if(flags.b == mac_flags[1][0]) in_scen = true; + else if(flags.b != mac_flags[1][1]) format = unknown; + if(flags.c == mac_flags[2][1]) maps_there = true; + else if(flags.c != mac_flags[2][0]) format = unknown; + }else{ // win save + format = old_win; + if(flags.a == win_flags[0][1]) town_restore = true; + else if(flags.a != win_flags[0][0]) format = unknown; + if(flags.b == win_flags[1][0]) in_scen = true; + else if(flags.b != win_flags[1][1]) format = unknown; + if(flags.c == win_flags[2][1]) maps_there = true; + else if(flags.c != win_flags[2][0]) format = unknown; + } + }else format = unknown; + + fclose(file_id); + switch(format){ + case old_mac: + return load_party_v1(file_to_load, univ, town_restore, in_scen, maps_there, mac_is_intel); + case old_win: + return load_party_v1(file_to_load, univ, town_restore, in_scen, maps_there, !mac_is_intel); + case new_oboe: + return load_party_v2(file_to_load, univ, town_restore, in_scen, maps_there); + case unknown: + cChoiceDlog("not-save-game").show(); + return false; + } + + return true; +} + +bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there, bool must_port){ + std::ifstream fin(file_to_load.c_str(), std::ios_base::binary); + fin.seekg(3*sizeof(short),std::ios_base::beg); // skip the header, which is 6 bytes in the old format + + legacy::party_record_type store_party; + legacy::setup_save_type store_setup; + legacy::pc_record_type store_pc[6]; + legacy::out_info_type store_out_info; + legacy::current_town_type store_c_town; + legacy::big_tr_type t_d; + legacy::town_item_list t_i; + legacy::stored_items_list_type stored_items[3]; + legacy::stored_town_maps_type town_maps; + legacy::stored_outdoor_maps_type o_maps; + unsigned char misc_i[64][64], sfx[64][64]; + char *party_ptr; + char *pc_ptr; + long len,store_len,count; + + // LOAD PARTY + len = (long) sizeof(legacy::party_record_type); // should be 46398 + store_len = len; + fin.read((char*)&store_party, len); + if(must_port) port_party(&store_party); + party_ptr = (char*) &store_party; + for(count = 0; count < store_len; count++) + party_ptr[count] ^= 0x5C; + + // LOAD SETUP + len = (long) sizeof(legacy::setup_save_type); + fin.read((char*)&store_setup, len); + + // LOAD PCS + store_len = (long) sizeof(legacy::pc_record_type); + for(int i = 0; i < 6; i++) { + len = store_len; + fin.read((char*)&store_pc[i], len); + if(must_port) port_pc(&store_pc[i]); + pc_ptr = (char*) &store_pc[i]; + for(count = 0; count < store_len; count++) + pc_ptr[count] ^= 0x6B; + } + + if(in_scen) { + + // LOAD OUTDOOR MAP + len = (long) sizeof(legacy::out_info_type); + fin.read((char*)&store_out_info, len); + + // LOAD TOWN + if(town_restore) { + len = (long) sizeof(legacy::current_town_type); + fin.read((char*)&store_c_town, len); + if(must_port) port_c_town(&store_c_town); + + len = (long) sizeof(legacy::big_tr_type); + fin.read((char*)&t_d, len); + if(must_port) port_t_d(&t_d); + + len = (long) sizeof(legacy::town_item_list); + fin.read((char*)&t_i, len); + }else univ.town.num = 200; + + // LOAD STORED ITEMS + for(int i = 0; i < 3; i++) { + len = (long) sizeof(legacy::stored_items_list_type); + fin.read((char*)&stored_items[i], len); + } + + // LOAD SAVED MAPS + if(maps_there) { + len = (long) sizeof(legacy::stored_town_maps_type); + fin.read((char*)&town_maps, len); + + len = (long) sizeof(legacy::stored_outdoor_maps_type); + fin.read((char*)&o_maps, len); + } + + // LOAD SFX & MISC_I + len = (long) (64 * 64); + fin.read((char*)sfx, len); + + fin.read((char*)misc_i, len); + + } // end if_scen + + fin.close(); + + univ.~cUniverse(); + new(&univ) cUniverse(' '); + + if(in_scen){ + fs::path path; + path = progDir/"Blades of Exile Scenarios"/univ.party.scen_name; + + if(!load_scenario(path, univ.scenario)) + return false; + univ.file = path; + }else{ + univ.party.scen_name = ""; + } + + univ.party.append(store_party); + univ.party.append(store_setup); + univ.party.append(store_pc); + if(in_scen){ + univ.out.append(store_out_info); + if(town_restore){ + univ.town.append(store_c_town); + univ.town.append(t_d); + univ.town.append(t_i); + } + for(int i = 0; i < 3; i++) + univ.party.append(stored_items[i],i); + univ.append(town_maps); + univ.append(o_maps); + univ.town.append(sfx, misc_i); + } + + // Compatibility flags + // TODO: Pretty sure I did this elsewhere, so probably don't need it here + if(in_scen && univ.scenario.format.prog_make_ver[0] < 2){ + univ.party.stuff_done[305][8] = 1; + } else { + univ.party.stuff_done[305][8] = 0; + } + + return true; +} + +bool load_party_v2(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there){ + if(!fs::exists(tempDir)) fs::create_directories(tempDir); + fs::path tempPath = tempDir/"loadtemp.exg"; + + { // First, strip off the header and save to a temporary location. + std::ifstream fin(file_to_load.c_str(), std::ios_base::binary); + std::ofstream fout(tempPath.c_str(), std::ios_base::binary); + fin.seekg(10); + fout << fin.rdbuf(); + fin.close(); + fout.close(); + } + + igzstream zin(tempPath.string().c_str()); + tarball partyIn; + partyIn.readFrom(zin); + zin.close(); + + univ.~cUniverse(); + new(&univ) cUniverse(' '); + + { // Load main party data first + std::istream& fin = partyIn.getFile("save/party.txt"); + if(!fin) { + cChoiceDlog("load-game-fail").show(); + return false; + } + univ.party.readFrom(fin); + } + + { // Then the "setup" array + std::istream& fin = partyIn.getFile("save/setup.dat"); + if(!fin) { + cChoiceDlog("load-game-fail").show(); + return false; + } + uint16_t magic; + fin.read((char*)&magic, 2); + fin.read((char*)&univ.party.setup, sizeof(univ.party.setup)); + if(magic == 0x0E0B) // should be 0x0B0E! + for(auto& i : univ.party.setup) + for(auto& j : i) + for(auto& k : j) + flip_short(reinterpret_cast(&k)); + } + + // Next load the PCs + for(int i = 0; i < 6; i++) { + static char fname[] = "save/pc1.txt"; + fname[7] = i + '1'; + std::istream& fin = partyIn.getFile(fname); + if(!fin) { + cChoiceDlog("load-game-fail").show(); + return false; + } + univ.party[i].readFrom(fin); + } + + if(in_scen) { + fs::path path; + path = progDir/"Blades of Exile Scenarios"/univ.party.scen_name; + + if(!load_scenario(path, univ.scenario)) + return false; + + if(town_restore) { + // Load town data + std::istream& fin = partyIn.getFile("save/town.txt"); + if(!fin) { + cChoiceDlog("load-game-fail").show(); + return false; + } + univ.town.readFrom(fin); + + if(maps_there) { + // Read town maps + std::istream& fin = partyIn.getFile("save/townmaps.dat"); + // TODO: Warn if maps missing + for(int i = 0; i < 200; i++) + for(int j = 0; j < 8; j++) + for(int k = 0; k < 64; k++) + univ.town_maps[i][j][k] = fin.get(); + } + } + + // Load outdoors data + std::istream& fin = partyIn.getFile("save/out.txt"); + if(!fin) { + cChoiceDlog("load-game-fail").show(); + return false; + } + univ.out.readFrom(fin); + + if(maps_there) { + // Read outdoor maps + std::istream& fin = partyIn.getFile("save/outmaps.dat"); + // TODO: Warn if maps missing + for(int i = 0; i < 100; i++) + for(int j = 0; j < 6; j++) + for(int k = 0; k < 48; k++) + univ.out_maps[i][j][k] = fin.get(); + } + } else univ.party.scen_name = ""; + + if(partyIn.hasFile("save/export.png")) { + std::istream& fin = partyIn.getFile("save/export.png"); + sf::Image party_sheet; + StdInputStream stream(fin); + if(party_sheet.loadFromStream(stream)) { + spec_scen_g.party_sheet.reset(new sf::Texture); + spec_scen_g.party_sheet->create(party_sheet.getSize().x, party_sheet.getSize().y); + spec_scen_g.party_sheet->update(party_sheet); + } else giveError("There was an error loading the party custom graphics."); + } + + return true; +} + +//mode; // 0 - normal 1 - save as +bool save_party(fs::path dest_file, const cUniverse& univ) { + if(!fs::exists(tempDir)) fs::create_directories(tempDir); + + // Make sure it has the proper file extension + std::string fname = dest_file.filename().string(); + size_t dot = fname.find_last_of('.'); + if(dot == std::string::npos || fname.substr(dot) != ".exg") + fname += ".exg"; + dest_file = dest_file.parent_path()/fname; + + bool in_scen = univ.party.scen_name != ""; + bool in_town = univ.town.num < 200; + bool save_maps = !univ.party.stuff_done[306][0]; + + tarball partyOut; + + // First, write the main party data + univ.party.writeTo(partyOut.newFile("save/party.txt")); + { + std::ostream& fout = partyOut.newFile("save/setup.dat"); + static uint16_t magic = 0x0B0E; + fout.write((char*)&magic, 2); + fout.write((char*)&univ.party.setup, sizeof(univ.party.setup)); + } + + // Then write the data for each of the party members + for(int i = 0; i < 6; i++) { + static char fname[] = "save/pc1.txt"; + fname[7] = i + '1'; + univ.party[i].writeTo(partyOut.newFile(fname)); + } + + if(in_scen) { + if(in_town) { + // Write the current town data + univ.town.writeTo(partyOut.newFile("save/town.txt")); + + if(save_maps) { + // Write the town map data + std::ostream& fout = partyOut.newFile("save/townmaps.dat"); + for(int i = 0; i < 200; i++) + for(int j = 0; j < 8; j++) + for(int k = 0; k < 64; k++) + fout.put(univ.town_maps[i][j][k]); + } + } + + // Write the current outdoors data + univ.out.writeTo(partyOut.newFile("save/out.txt")); + + if(save_maps) { + // Write the outdoors map data + std::ostream& fout = partyOut.newFile("save/outmaps.dat"); + for(int i = 0; i < 100; i++) + for(int j = 0; j < 6; j++) + for(int k = 0; k < 48; k++) + fout.put(univ.out_maps[i][j][k]); + } + } + + if(spec_scen_g.party_sheet) { + sf::Image party_pics = spec_scen_g.party_sheet->copyToImage(); + party_pics.flipVertically(); + fs::path tempPath = tempDir/"temp.png"; + party_pics.saveToFile(tempPath.string()); + std::ostream& pic_out = partyOut.newFile("save/export.png"); + std::ifstream fin(tempPath.string().c_str(), std::ios::binary); + pic_out << fin.rdbuf(); + fin.close(); + } + + // Write out the compressed data + fs::path tempPath = tempDir/"savetemp.exg"; + ogzstream zout(tempPath.string().c_str()); + partyOut.writeTo(zout); + zout.close(); + + // Now add the header. We use the temporary file because we want the header to be uncompressed. + int16_t flags[] = { + 0x0B0E, // to indicate new format + static_cast(in_town ? 1342 : 5790), // is the party in town? + static_cast(in_scen ? 100 : 200), // is the party in a scenario? + static_cast(save_maps ? 5567 : 3422), // is the save maps feature enabled? + OBOE_CURRENT_VERSION >> 8, // current version number, major and minor revisions only + // Version 1 indicates a beta format that may not be supported in the final release + }; + if(!mac_is_intel) // must flip all the flags to little-endian + for(int i = 0; i < 5; i++) + flip_short(&flags[i]); + + std::ifstream fin(tempPath.c_str(), std::ios_base::binary); + std::ofstream fout(dest_file.c_str(), std::ios_base::binary); + fout.write((char*) flags, 10); + fout << fin.rdbuf(); + fin.close(); + fout.close(); + return true; +} + diff --git a/src/tools/fileio_scen.cpp b/src/tools/fileio_scen.cpp new file mode 100644 index 00000000..a34ff205 --- /dev/null +++ b/src/tools/fileio_scen.cpp @@ -0,0 +1,476 @@ +// +// fileio_scen.cpp +// BoE +// +// Created by Celtic Minstrel on 15-01-24. +// +// + +#include "fileio.hpp" + +#include +#include + +#include "dlogutil.hpp" + +#include "scenario.h" +#include "regtown.h" +#include "map_parse.hpp" +#include "graphtool.hpp" + +#include "porting.hpp" +#include "restypes.hpp" + +bool cur_scen_is_mac = true; +extern sf::Texture items_gworld,tiny_obj_gworld,fields_gworld,roads_gworld,boom_gworld,missiles_gworld; +extern sf::Texture dlogpics_gworld,monst_gworld[],terrain_gworld[],anim_gworld,talkfaces_gworld,pc_gworld; +extern sf::Texture status_gworld, vehicle_gworld, small_ter_gworld; +extern cCustomGraphics spec_scen_g; +//fs::path progDir, tempDir; + +void load_spec_graphics(fs::path scen_file); +// Load old scenarios (town talk is handled by the town loading function) +static bool load_scenario_v1(fs::path file_to_load, cScenario& scenario); +static bool load_outdoors_v1(fs::path scen_file, location which_out,cOutdoors& the_out, legacy::scenario_data_type& scenario); +static bool load_town_v1(fs::path scen_file, short which_town, cTown& the_town, legacy::scenario_data_type& scenario); +// Load new scenarios +static bool load_outdoors(fs::path out_base, location which_out, cOutdoors& the_out); +static bool load_town(fs::path town_base, short which_town, cTown*& the_town); +static bool load_town_talk(fs::path town_base, short which_town, cSpeech& the_talk); + +bool load_scenario(fs::path file_to_load, cScenario& scenario) { + scenario = cScenario(); + // TODO: Implement checking to determine whether it's old or new + return load_scenario_v1(file_to_load, scenario); +} + +bool load_scenario_v1(fs::path file_to_load, cScenario& scenario){ + short i,n; + bool file_ok = false; + long len; + char temp_str[256]; + legacy::scenario_data_type *temp_scenario = new legacy::scenario_data_type; + legacy::scen_item_data_type *item_data = new legacy::scen_item_data_type; + // TODO: Convert this (and all the others in this file) to use C++ streams + FILE* file_id = fopen(file_to_load.string().c_str(),"rb"); + if(file_id == NULL) { + // TODO: The third parameter to oopsError is supposed to specify whether we're in the scenario editor or the game, but I don't think this code knows that. + // TODO: Alternatively, nuke oopsError and just use giveError. It's more informative, anyway. + oopsError(10, 0, 0); + return false; + } + + len = (long) sizeof(scenario_header_flags); + + if(fread(&scenario.format, len, 1, file_id) < 1){ + fclose(file_id); + oopsError(11, 0, 0); + return false; + } + + if((scenario.format.flag1 == 10) && (scenario.format.flag2 == 20) && + (scenario.format.flag3 == 30) && (scenario.format.flag4 == 40)) { + cur_scen_is_mac = true; + file_ok = true; + } + else if((scenario.format.flag1 == 20) && (scenario.format.flag2 == 40) && + (scenario.format.flag3 == 60) && (scenario.format.flag4 == 80)) { + cur_scen_is_mac = false; + file_ok = true; + } + if(!file_ok) { + fclose(file_id); + giveError("This is not a legitimate Blades of Exile scenario."); + return false; + } + + len = (long) sizeof(legacy::scenario_data_type); + n = fread(temp_scenario, len, 1, file_id); + if(n < 1){ + fclose(file_id); + oopsError(12, 0, 0); + return false; + } + port_scenario(temp_scenario); + len = sizeof(legacy::scen_item_data_type); // item data + n = fread(item_data, len, 1, file_id); + if(n < 1){ + fclose(file_id); + oopsError(13, 0, 0); + return false; + } + port_item_list(item_data); + scenario.append(*temp_scenario); + scenario.append(*item_data); + + // TODO: Consider skipping the fread and assignment when len is 0 + for(i = 0; i < 270; i++) { + len = (long) (temp_scenario->scen_str_len[i]); + n = fread(temp_str, len, 1, file_id); + temp_str[len] = 0; + if(i == 0) scenario.scen_name = temp_str; + else if(i == 1 || i == 2) + scenario.who_wrote[i-1] = temp_str; + else if(i == 3) + scenario.contact_info = temp_str; + else if(i >= 4 && i < 10) + scenario.intro_strs[i-4] = temp_str; + else if(i >= 10 && i < 60) + scenario.journal_strs[i-10] = temp_str; + else if(i >= 60 && i < 160) { + if(i % 2 == 0) scenario.special_items[(i-60)/2].name = temp_str; + else scenario.special_items[(i-60)/2].descr = temp_str; + } else if(i >= 260) continue; // These were never ever used, for some reason. + else scenario.spec_strs[i-160] = temp_str; + } + + fclose(file_id); + + scenario.ter_types[23].fly_over = false; + + scenario.scen_file = file_to_load; + load_spec_graphics(scenario.scen_file); + + // Now load all the outdoor sectors + scenario.outdoors.resize(temp_scenario->out_width, temp_scenario->out_height); + for(int x = 0; x < temp_scenario->out_width; x++) { + for(int y = 0; y < temp_scenario->out_height; y++) { + scenario.outdoors[x][y] = new cOutdoors(scenario); + load_outdoors_v1(scenario.scen_file, loc(x,y), *scenario.outdoors[x][y], *temp_scenario); + } + } + + // Then load all the towns + scenario.towns.resize(scenario.format.num_towns); + for(int i = 0; i < scenario.format.num_towns; i++) { + switch(temp_scenario->town_size[i]) { + case 0: scenario.towns[i] = new cBigTown(scenario); break; + case 1: scenario.towns[i] = new cMedTown(scenario); break; + case 2: scenario.towns[i] = new cTinyTown(scenario); break; + } + load_town_v1(scenario.scen_file, i, *scenario.towns[i], *temp_scenario); + } + + delete temp_scenario; + delete item_data; + return true; +} + +static long get_town_offset(short which_town, legacy::scenario_data_type& scenario){ + int i,j; + long len_to_jump,store; + + len_to_jump = sizeof(scenario_header_flags); + len_to_jump += sizeof(legacy::scenario_data_type); + len_to_jump += sizeof(legacy::scen_item_data_type); + for(i = 0; i < 300; i++) + len_to_jump += (long) scenario.scen_str_len[i]; + store = 0; + for(i = 0; i < 100; i++) + for(j = 0; j < 2; j++) + store += (long) (scenario.out_data_size[i][j]); + for(i = 0; i < which_town; i++) + for(j = 0; j < 5; j++) + store += (long) (scenario.town_data_size[i][j]); + len_to_jump += store; + + return len_to_jump; +} + +bool load_town_v1(fs::path scen_file, short which_town, cTown& the_town, legacy::scenario_data_type& scenario) { + short i,n; + long len,len_to_jump = 0; + char temp_str[256]; + legacy::town_record_type store_town; + legacy::talking_record_type store_talk; + legacy::big_tr_type t_d; + legacy::ave_tr_type ave_t; + legacy::tiny_tr_type tiny_t; + + FILE* file_id = fopen(scen_file.string().c_str(), "rb"); + if(file_id == NULL) { + oopsError(14, 0, 0); + return false; + } + + len_to_jump = get_town_offset(which_town, scenario); + n = fseek(file_id, len_to_jump, SEEK_SET); + if(n != 0) { + fclose(file_id); + oopsError(15, 0, 0); + return false; + } + + len = sizeof(legacy::town_record_type); + n = fread(&store_town, len, 1, file_id); + if(n < 1) { + fclose(file_id); + oopsError(16, 0, 0); + return false; + } + port_town(&store_town); + + switch(scenario.town_size[which_town]) { + case 0: + len = sizeof(legacy::big_tr_type); + n = fread(&t_d, len, 1, file_id); + port_t_d(&t_d); + the_town.append(store_town); + the_town.append(t_d, which_town); + break; + + case 1: + len = sizeof(legacy::ave_tr_type); + n = fread(&ave_t, len, 1, file_id); + port_ave_t(&ave_t); + the_town.append(store_town); + the_town.append(ave_t, which_town); + break; + + case 2: + len = sizeof(legacy::tiny_tr_type); + n = fread(&tiny_t, len, 1, file_id); + port_tiny_t(&tiny_t); + the_town.append(store_town); + the_town.append(tiny_t, which_town); + break; + } + + for(i = 0; i < 140; i++) { + len = (long) (store_town.strlens[i]); + n = fread(temp_str, len, 1, file_id); + temp_str[len] = 0; + if(i == 0) the_town.town_name = temp_str; + else if(i >= 1 && i < 17) + the_town.room_rect[i-1].descr = temp_str; + else if(i >= 17 && i < 20) + the_town.comment[i-17] = temp_str; + else if(i >= 20 && i < 120) + the_town.spec_strs[i-20] = temp_str; + else if(i >= 120 && i < 140) + the_town.sign_strs[i-120] = temp_str; + } + + len = sizeof(legacy::talking_record_type); + n = fread(&store_talk, len, 1, file_id); + if(n < 1) { + fclose(file_id); + oopsError(17, 0, 0); + return false; + } + port_talk_nodes(&store_talk); + the_town.talking.append(store_talk); + + for(i = 0; i < 170; i++) { + len = (long) (the_town.talking.strlens[i]); + n = fread(temp_str, len, 1, file_id); + temp_str[len] = 0; + if(i >= 0 && i < 10) + the_town.talking.people[i].title = temp_str; + else if(i >= 10 && i < 20) + the_town.talking.people[i-10].look = temp_str; + else if(i >= 20 && i < 30) + the_town.talking.people[i-20].name = temp_str; + else if(i >= 30 && i < 40) + the_town.talking.people[i-30].job = temp_str; + else if(i >= 160) + the_town.talking.people[i-160].dunno = temp_str; + else { + if(i % 2 == 0) + the_town.talking.talk_nodes[(i-40)/2].str1 = temp_str; + else the_town.talking.talk_nodes[(i-40)/2].str2 = temp_str; + } + } + + n = fclose(file_id); + if(n != 0) { + oopsError(18, 0, 0); + } + + return true; +} + +bool load_town(fs::path town_base, short which_town, cTown*& the_town) { + // TODO: This stuff goes in load_scenario() now + // fs::path town_base = scenario.scen_file/"towns"; + std::string base_fname = "t" + std::to_string(which_town), fname; + // TODO: Implement all this. + // First load the main town data. + fname = base_fname + ".xml"; + // Next, load in the town map. + fname = base_fname + ".map"; + map_data map = load_map(town_base/fname, true); + // Then load the town's special nodes. + fname = base_fname + ".spec"; + // Load the town's special encounter strings + fname = base_fname + ".txt"; + // And finally, load the town's dialogue nodes. + load_town_talk(town_base, which_town, the_town->talking); + return false; +} + +bool load_town_talk(fs::path town_base, short which_town, cSpeech& the_talk) { + // TODO: Implement this. + std::string fname = "t" + std::to_string(which_town) + "talk.xml"; + return false; +} + +static long get_outdoors_offset(location& which_out, legacy::scenario_data_type& scenario){ + int i,j,out_sec_num; + long len_to_jump,store; + out_sec_num = scenario.out_width * which_out.y + which_out.x; + + len_to_jump = sizeof(scenario_header_flags); + len_to_jump += sizeof(legacy::scenario_data_type); + len_to_jump += sizeof(legacy::scen_item_data_type); + for(i = 0; i < 300; i++) + len_to_jump += (long) scenario.scen_str_len[i]; + store = 0; + for(i = 0; i < out_sec_num; i++) + for(j = 0; j < 2; j++) + store += (long) (scenario.out_data_size[i][j]); + len_to_jump += store; + + return len_to_jump; +} + +//mode -> 0 - primary load 1 - add to top 2 - right 3 - bottom 4 - left +bool load_outdoors_v1(fs::path scen_file, location which_out,cOutdoors& the_out, legacy::scenario_data_type& scenario){ + short i,n; + long len,len_to_jump; + char temp_str[256]; + legacy::outdoor_record_type store_out; + + FILE* file_id = fopen(scen_file.string().c_str(), "rb"); + if(file_id == NULL) { + oopsError(32, 0, 0); + return false; + } + + len_to_jump = get_outdoors_offset(which_out, scenario); + n = fseek(file_id, len_to_jump, SEEK_SET); + if(n != 0) { + fclose(file_id); + oopsError(33, 0, 0); + return false; + } + + len = sizeof(legacy::outdoor_record_type); + n = fread(&store_out, len, 1, file_id); + if(n < 1) { + fclose(file_id); + oopsError(34, 0, 0); + return false; + } + + the_out.x = which_out.x; + the_out.y = which_out.y; + port_out(&store_out); + the_out.append(store_out); + for(i = 0; i < 108; i++) { + len = (long) (store_out.strlens[i]); + n = fread(temp_str, len, 1, file_id); + temp_str[len] = 0; + if(i == 0) the_out.out_name = temp_str; + else if(i == 9) the_out.comment = temp_str; + else if(i < 9) the_out.info_rect[i-1].descr = temp_str; + else if(i >= 10 && i < 100) + the_out.spec_strs[i-10] = temp_str; + else if(i >= 100 && i < 108) + the_out.sign_strs[i-100] = temp_str; + } + + n = fclose(file_id); + if(n != 0) { + oopsError(35, 0, 0); + } + return true; +} + +bool load_outdoors(fs::path out_base, location which_out,cOutdoors& the_out) { + // TODO: This bit goes in load_scenario() now + // fs::path town_base = scenario.scen_file/"outdoors"; + std::string base_fname = "tut" + std::to_string(which_out.x) + "~" + std::to_string(which_out.y), fname; + // TODO: Implement all this. + // First load the main sector data. + fname = base_fname + ".xml"; + // Next, load in the sector map. + fname = base_fname + ".map"; + map_data map = load_map(out_base/fname, false); + // Then load the sector's special nodes. + fname = base_fname + ".spec"; + // Load the sector's special encounter strings + fname = base_fname + ".txt"; + return false; +} + +#ifdef __APPLE__ +bool tryLoadPictFromResourceFile(fs::path& gpath, sf::Image& graphics_store); +#endif + +void load_spec_graphics(fs::path scen_file) { + static const char*const noGraphics = "The game will still work without the custom graphics, but some things will not look right."; + short i; + fs::path path(scen_file); + std::cout << "Loading scenario graphics... (" << path << ")\n"; + // Tried path.replace_extension, but that only deleted the extension, so I have to do it manually + std::string filename = path.stem().string(); + path = path.parent_path(); + if(spec_scen_g) spec_scen_g.clear(); + // TODO: Load new-style sheets + { + static sf::Image graphics_store; + bool foundGraphics = false; +#ifdef __APPLE__ + fs::path gpath = path/(filename + ".meg"); + if(fs::exists(gpath)) + foundGraphics = tryLoadPictFromResourceFile(gpath, graphics_store); +#endif + if(!foundGraphics) { + fs::path gpath = path/(filename + ".bmp"); + if(fs::exists(gpath)) { + if(graphics_store.loadFromFile(gpath.string())) + foundGraphics = true; + else giveError("An old-style .bmp graphics file was found, but there was an error reading from the file.",noGraphics); + } + } + if(foundGraphics) { + // If we're here, we found old-style graphics. + // This means they need an alpha channel + graphics_store.createMaskFromColor(sf::Color::White); + spec_scen_g.is_old = true; + spec_scen_g.sheets = new sf::Texture[1]; + spec_scen_g.sheets[0].loadFromImage(graphics_store); + } else { + // Check for new-style graphics + } + }//else{} + + // TODO: This should really reload ALL textures... + // Now load regular graphics + items_gworld.loadFromImage(*ResMgr::get("objects")); + tiny_obj_gworld.loadFromImage(*ResMgr::get("tinyobj")); + fields_gworld.loadFromImage(*ResMgr::get("fields")); + roads_gworld.loadFromImage(*ResMgr::get("trim")); + boom_gworld.loadFromImage(*ResMgr::get("booms")); + missiles_gworld.loadFromImage(*ResMgr::get("missiles")); + dlogpics_gworld.loadFromImage(*ResMgr::get("dlogpics")); + status_gworld.loadFromImage(*ResMgr::get("staticons")); + + for(i = 0; i < NUM_MONST_SHEETS; i++){ + std::ostringstream sout; + sout << "monst" << i + 1; + monst_gworld[i].loadFromImage(*ResMgr::get(sout.str())); + } + for(i = 0; i < NUM_TER_SHEETS; i++){ + std::ostringstream sout; + sout << "ter" << i + 1; + terrain_gworld[i].loadFromImage(*ResMgr::get(sout.str())); + } + anim_gworld.loadFromImage(*ResMgr::get("teranim")); + talkfaces_gworld.loadFromImage(*ResMgr::get("talkportraits")); + pc_gworld.loadFromImage(*ResMgr::get("pcs")); + vehicle_gworld.loadFromImage(*ResMgr::get("vehicle")); + small_ter_gworld.loadFromImage(*ResMgr::get("termap")); + // TODO: Scenario icons ... +}