Allow taking items from a scenario even if they summon monsters or have custom graphics. Breaks older saved games.
(Older saved games might still work if not in a scenario.) - Remove items that call a special node when entering a new scenario - Remove stone block if a monster is placed on it - Monsters captured by Capture Soul now persist across scenarios - Fix barrels/crates not being restored when re-entering the town - Fix issue when saving monster status effects - Fix version number stored in saved game file; also, it's now stored in hexadecimal - Fix issue with saving which would have caused all but the first timer to be ignored when loading the saved game - Fix timers being written to out-of-bounds memory when loading a saved game - Fix use of std::skipws where std::ws was intended - Fix issue with the fields array being shifted right by one tile on loading; also, fields array is now saved as hexadecimal - Fields and terrain array use the town's dimension instead of dimension hard-coded (in the case of fields) or stored in the file - Fix PC editor remove from scenario option not working properly - Reconstruct the universe when loading a saved game to ensure there isn't leakage from the previous universe - Fix excess padding in output tarballs when the filesize is a multiple of 512 - Add hasFile function to tarball class
This commit is contained in:
@@ -739,6 +739,9 @@ bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bo
|
||||
|
||||
fin.close();
|
||||
|
||||
univ.~cUniverse();
|
||||
new(&univ) cUniverse();
|
||||
|
||||
if(in_scen){
|
||||
fs::path path;
|
||||
path = progDir/"Blades of Exile Scenarios"/univ.party.scen_name;
|
||||
@@ -879,9 +882,19 @@ bool load_party_v2(fs::path file_to_load, cUniverse& univ, bool town_restore, bo
|
||||
for(int k = 0; k < 48; k++)
|
||||
univ.out_maps[i][j][k] = fin.get();
|
||||
}
|
||||
}
|
||||
} else univ.party.scen_name = "";
|
||||
|
||||
// TODO: Also get the party custom graphics sheet
|
||||
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)) {
|
||||
//party_sheet.flipVertically();
|
||||
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;
|
||||
}
|
||||
@@ -947,7 +960,16 @@ bool save_party(fs::path dest_file, const cUniverse& univ) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add the party graphics sheet
|
||||
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";
|
||||
@@ -979,7 +1001,7 @@ bool save_party(fs::path dest_file, const cUniverse& univ) {
|
||||
|
||||
std::string read_maybe_quoted_string(std::istream& from) {
|
||||
std::string result;
|
||||
from >> std::skipws;
|
||||
from >> std::ws;
|
||||
if(from.peek() == '"' || from.peek() == '\'') {
|
||||
char delim = from.get();
|
||||
getline(from, result, delim);
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <SFML/System/InputStream.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
class cScenario;
|
||||
@@ -30,10 +31,10 @@ std::string maybe_quote_string(std::string which);
|
||||
template<typename T, int D>
|
||||
void writeArray(std::ostream& to, const T(* array)[D], int width, int height) {
|
||||
using int_type = decltype(T() + 1);
|
||||
for(int i = 0; i < width; i++) {
|
||||
to << array[i][0];
|
||||
for(int j = 1; j < height; j++)
|
||||
to << '\t' << int_type(array[i][j]);
|
||||
for(int y = 0; y < height; y++) {
|
||||
to << array[0][y];
|
||||
for(int x = 1; x < width; x++)
|
||||
to << '\t' << int_type(array[x][y]);
|
||||
to << '\n';
|
||||
}
|
||||
to << '\f';
|
||||
@@ -42,15 +43,45 @@ void writeArray(std::ostream& to, const T(* array)[D], int width, int height) {
|
||||
template<typename T, int D>
|
||||
void readArray(std::istream& from, T(* array)[D], int width, int height) {
|
||||
using int_type = decltype(T() + 1);
|
||||
from >> std::ws;
|
||||
std::string arrayContents;
|
||||
getline(from, arrayContents, '\f');
|
||||
std::istringstream arrayIn(arrayContents);
|
||||
for(int i = 0; i < width; i++) {
|
||||
for(int y = 0; y < height; y++) {
|
||||
std::string line;
|
||||
getline(arrayIn, line);
|
||||
std::istringstream lineIn(line);
|
||||
for(int j = 0; j < height; j++)
|
||||
lineIn >> array[i][j];
|
||||
lineIn.flags(from.flags());
|
||||
int_type temp;
|
||||
for(int x = 0; x < width; x++)
|
||||
lineIn >> temp, array[x][y] = temp;
|
||||
if(!arrayIn) break;
|
||||
}
|
||||
}
|
||||
|
||||
// SFML doesn't support standard C++ streams, so I need to do this in order to load images from a stream.
|
||||
class StdInputStream : public sf::InputStream {
|
||||
std::istream& stream;
|
||||
public:
|
||||
StdInputStream(std::istream& stream) : stream(stream) {}
|
||||
virtual ~StdInputStream() {}
|
||||
// TODO: All four of these functions should return -1 on failure, but I'm not quite sure which conditions should be counted as failure
|
||||
virtual sf::Int64 read(void *data, sf::Int64 size) {
|
||||
stream.read((char*)data, size);
|
||||
return stream.gcount();
|
||||
}
|
||||
virtual sf::Int64 seek(sf::Int64 position) {
|
||||
stream.seekg(position);
|
||||
return tell();
|
||||
}
|
||||
virtual sf::Int64 tell() {
|
||||
return stream.tellg();
|
||||
}
|
||||
virtual sf::Int64 getSize() {
|
||||
auto was_at = stream.tellg();
|
||||
stream.seekg(0, std::ios::end);
|
||||
auto pos = stream.tellg();
|
||||
stream.seekg(was_at);
|
||||
return pos;
|
||||
}
|
||||
};
|
||||
|
@@ -661,29 +661,94 @@ rectangle calc_rect(short i, short j){
|
||||
|
||||
graf_pos cCustomGraphics::find_graphic(pic_num_t which_rect, bool party) {
|
||||
short sheet = which_rect / 100;
|
||||
if(is_old) sheet = 0;
|
||||
if(is_old || party) sheet = 0;
|
||||
else which_rect %= 100;
|
||||
rectangle store_rect = {0,0,36,28};
|
||||
|
||||
store_rect.offset(28 * (which_rect % 10),36 * (which_rect / 10));
|
||||
return std::make_pair(party ? this->party : &sheets[sheet],store_rect);
|
||||
return std::make_pair(party ? party_sheet.get() : &sheets[sheet],store_rect);
|
||||
}
|
||||
|
||||
size_t cCustomGraphics::count() {
|
||||
if(sheets == NULL) return 0;
|
||||
else if(is_old) {
|
||||
rectangle bounds(sheets[0]);
|
||||
size_t cCustomGraphics::count(bool party) {
|
||||
if(!party && sheets == NULL) return 0;
|
||||
else if(party && party_sheet == NULL) return 0;
|
||||
else if(is_old || party) {
|
||||
rectangle bounds(party ? *party_sheet : sheets[0]);
|
||||
if(bounds.width() < 280) return bounds.width() / 28;
|
||||
return bounds.height() / 36;
|
||||
return 10 * bounds.height() / 36;
|
||||
} else {
|
||||
size_t count = 100 * (numSheets - 1);
|
||||
rectangle bounds(sheets[numSheets - 1]);
|
||||
if(bounds.width() < 280) count += bounds.width() / 28;
|
||||
else count += bounds.height() / 36;
|
||||
else count += 10 * bounds.height() / 36;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
void cCustomGraphics::copy_graphic(pic_num_t dest, pic_num_t src, size_t numSlots) {
|
||||
if(numSlots < 1) return;
|
||||
if(!party_sheet) {
|
||||
sf::Image empty;
|
||||
empty.create(280, 180, sf::Color::Transparent);
|
||||
party_sheet.reset(new sf::Texture);
|
||||
party_sheet->create(280, 180);
|
||||
party_sheet->update(empty);
|
||||
numSheets = 1;
|
||||
}
|
||||
size_t havePics = count();
|
||||
if(havePics < dest + numSlots) {
|
||||
int addRows = 1;
|
||||
while(havePics + 10 * addRows < dest + numSlots)
|
||||
addRows++;
|
||||
sf::RenderTexture temp;
|
||||
temp.create(280, party_sheet->getSize().y + 36 * addRows);
|
||||
temp.clear(sf::Color::Transparent);
|
||||
rect_draw_some_item(*party_sheet, rectangle(*party_sheet), temp, rectangle(*party_sheet));
|
||||
*party_sheet = temp.getTexture();
|
||||
}
|
||||
sf::Texture* from_sheet;
|
||||
sf::Texture* to_sheet;
|
||||
sf::Texture* last_src = nullptr;
|
||||
sf::RenderTexture temp;
|
||||
rectangle from_rect, to_rect;
|
||||
for(size_t i = 0; i < numSlots; i++) {
|
||||
graf_pos_ref(from_sheet, from_rect) = find_graphic(src + i);
|
||||
graf_pos_ref(to_sheet, to_rect) = find_graphic(dest + i, true);
|
||||
if(to_sheet != last_src) {
|
||||
if(last_src) *last_src = temp.getTexture();
|
||||
last_src = to_sheet;
|
||||
temp.create(to_sheet->getSize().x, to_sheet->getSize().y);
|
||||
rect_draw_some_item(*to_sheet, rectangle(*to_sheet), temp, rectangle(*to_sheet));
|
||||
}
|
||||
rect_draw_some_item(*from_sheet, from_rect, temp, to_rect);
|
||||
}
|
||||
*last_src = temp.getTexture();
|
||||
}
|
||||
|
||||
void cCustomGraphics::convert_sheets() {
|
||||
if(!is_old) return;
|
||||
int num_graphics = count();
|
||||
is_old = false;
|
||||
sf::Image old_graph = sheets[0].copyToImage();
|
||||
delete[] sheets;
|
||||
numSheets = num_graphics / 100;
|
||||
if(num_graphics % 100) numSheets++;
|
||||
sheets = new sf::Texture[numSheets];
|
||||
for(size_t i = 0; i < numSheets; i++) {
|
||||
sf::IntRect subrect;
|
||||
subrect.top = i * 280;
|
||||
subrect.width = 280;
|
||||
subrect.height = 360;
|
||||
|
||||
sf::Image sheet;
|
||||
sheet.create(280, 360);
|
||||
sheet.copy(old_graph, 0, 0, subrect);
|
||||
|
||||
sheets[i].create(280, 360);
|
||||
sheets[i].update(sheet);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This doesn't belong in this file
|
||||
std::string get_str(std::string list, short j){
|
||||
if(j == 0) return list;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#define GRAPHTOOL_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <SFML/Graphics.hpp>
|
||||
@@ -65,20 +66,22 @@ using hilite_t = std::pair<size_t,size_t>;
|
||||
struct cCustomGraphics {
|
||||
size_t numSheets;
|
||||
sf::Texture* sheets = NULL;
|
||||
sf::Texture* party = NULL;
|
||||
std::shared_ptr<sf::Texture> party_sheet;
|
||||
bool is_old = false;
|
||||
void clear() {
|
||||
if(sheets != NULL) delete[] sheets;
|
||||
sheets = NULL;
|
||||
}
|
||||
~cCustomGraphics() {
|
||||
if(party != NULL) delete party;
|
||||
clear();
|
||||
}
|
||||
explicit operator bool() {
|
||||
return sheets;
|
||||
}
|
||||
void convert_sheets();
|
||||
void copy_graphic(pic_num_t dest, pic_num_t src, size_t numSlots);
|
||||
graf_pos find_graphic(pic_num_t pic, bool party = false);
|
||||
size_t count();
|
||||
size_t count(bool party = false);
|
||||
};
|
||||
|
||||
struct snippet_t {
|
||||
|
@@ -65,7 +65,8 @@ void tarball::writeTo(std::ostream& out) {
|
||||
entry.header = generateTarHeader(entry.filename, size);
|
||||
out.write((char*)&entry.header, sizeof(header_posix_ustar));
|
||||
out << entry.contents.rdbuf();
|
||||
out.write(padding, padLength);
|
||||
if(padLength < 512)
|
||||
out.write(padding, padLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +89,8 @@ void tarball::readFrom(std::istream& in) {
|
||||
// Skip past the padding without using seekg.
|
||||
// This is because the gzstreams don't support seekg.
|
||||
// We're done with the data in this buffer, anyway, so just dump the padding here.
|
||||
in.read(buf, padLength);
|
||||
if(padLength < 512)
|
||||
in.read(buf, padLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,3 +113,12 @@ std::istream& tarball::getFile(std::string fname) {
|
||||
empty.seekg(0);
|
||||
return empty;
|
||||
}
|
||||
|
||||
bool tarball::hasFile(std::string fname) {
|
||||
for(tarfile& entry : files) {
|
||||
if(entry.filename == fname) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -52,6 +52,7 @@ public:
|
||||
std::ostream& newFile(std::string fname);
|
||||
void newDirectory(std::string dname);
|
||||
std::istream& getFile(std::string fname);
|
||||
bool hasFile(std::string fname);
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user