Merge branch 'develop' into avoid_rebuilding_df_statics_if_core_h_changes
commit
f3658db85f
@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
Copyright © 2018 Pauli <suokkos@gmail.com>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must
|
||||||
|
not claim that you wrote the original software. If you use this
|
||||||
|
software in a product, an acknowledgment in the product
|
||||||
|
documentation would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*! \file dfhack_llimits.h
|
||||||
|
* dfhack specific lua porting header that overrides lua defaults for thread
|
||||||
|
* safety.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef CRITICAL_SECTION mutex_t;
|
||||||
|
#else
|
||||||
|
typedef pthread_mutex_t mutex_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct lua_extra_state {
|
||||||
|
mutex_t* mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define luai_mutex(L) ((lua_extra_state*)lua_getextraspace(L))->mutex
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define luai_userstateopen(L) luai_mutex(L) = (mutex_t*)malloc(sizeof(mutex_t)); InitializeCriticalSection(luai_mutex(L))
|
||||||
|
#define luai_userstateclose(L) lua_unlock(L); DeleteCriticalSection(luai_mutex(L)); free(luai_mutex(L))
|
||||||
|
#define lua_lock(L) EnterCriticalSection(luai_mutex(L))
|
||||||
|
#define lua_unlock(L) LeaveCriticalSection(luai_mutex(L))
|
||||||
|
#else
|
||||||
|
#define luai_userstateopen(L) luai_mutex(L) = (mutex_t*)malloc(sizeof(mutex_t)); *luai_mutex(L) = PTHREAD_MUTEX_INITIALIZER
|
||||||
|
#define luai_userstateclose(L) lua_unlock(L); pthread_mutex_destroy(luai_mutex(L)); free(luai_mutex(L))
|
||||||
|
#define lua_lock(L) pthread_mutex_lock(luai_mutex(L))
|
||||||
|
#define lua_unlock(L) pthread_mutex_unlock(luai_mutex(L))
|
||||||
|
#endif
|
@ -0,0 +1,232 @@
|
|||||||
|
/*
|
||||||
|
https://github.com/DFHack/dfhack
|
||||||
|
Copyright (c) 2009-2018 DFHack Team
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must
|
||||||
|
not claim that you wrote the original software. If you use this
|
||||||
|
software in a product, an acknowledgment in the product documentation
|
||||||
|
would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef CL_MOD_PERSISTENCE
|
||||||
|
#define CL_MOD_PERSISTENCE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup grp_persistence Persistence: code related to saving and loading data
|
||||||
|
* @ingroup grp_modules
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Export.h"
|
||||||
|
#include "Error.h"
|
||||||
|
|
||||||
|
namespace DFHack
|
||||||
|
{
|
||||||
|
class Core;
|
||||||
|
|
||||||
|
namespace Persistence
|
||||||
|
{
|
||||||
|
struct LegacyData;
|
||||||
|
class Internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DFHACK_EXPORT PersistentDataItem {
|
||||||
|
size_t index;
|
||||||
|
std::shared_ptr<Persistence::LegacyData> data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const int NumInts = 7;
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
size_t get_index() const
|
||||||
|
{
|
||||||
|
CHECK_INVALID_ARGUMENT(isValid());
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
int entry_id() const { return isValid() ? int(index) + 100 : 0; }
|
||||||
|
|
||||||
|
int raw_id() const { return isValid() ? -int(index) - 100 : 0; }
|
||||||
|
|
||||||
|
const std::string &key() const;
|
||||||
|
|
||||||
|
std::string &val();
|
||||||
|
const std::string &val() const;
|
||||||
|
int &ival(int i);
|
||||||
|
int ival(int i) const;
|
||||||
|
|
||||||
|
// Pack binary data into string field.
|
||||||
|
// Since DF serialization chokes on NUL bytes,
|
||||||
|
// use bit magic to ensure none of the bytes is 0.
|
||||||
|
// Choose the lowest bit for padding so that
|
||||||
|
// sign-extend can be used normally.
|
||||||
|
|
||||||
|
size_t data_size() const
|
||||||
|
{
|
||||||
|
return val().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_data(size_t off, size_t sz = 1) const
|
||||||
|
{
|
||||||
|
return (data_size() >= off + sz);
|
||||||
|
}
|
||||||
|
void ensure_data(size_t off, size_t sz = 0)
|
||||||
|
{
|
||||||
|
if (data_size() < off + sz)
|
||||||
|
{
|
||||||
|
val().resize(off + sz, '\x01');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<size_t N>
|
||||||
|
uint8_t (&pdata(size_t off))[N]
|
||||||
|
{
|
||||||
|
ensure_data(off, N);
|
||||||
|
typedef uint8_t array[N];
|
||||||
|
return *(array *)(val().data() + off);
|
||||||
|
}
|
||||||
|
template<size_t N>
|
||||||
|
const uint8_t (&pdata(size_t off) const)[N]
|
||||||
|
{
|
||||||
|
CHECK_INVALID_ARGUMENT(check_data(off, N));
|
||||||
|
typedef const uint8_t array[N];
|
||||||
|
return *(array *)(val().data() + off);
|
||||||
|
}
|
||||||
|
template<size_t N>
|
||||||
|
const uint8_t (&cpdata(size_t off) const)[N]
|
||||||
|
{
|
||||||
|
return pdata<N>(off);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t int7_size = 1;
|
||||||
|
uint8_t get_uint7(size_t off) const
|
||||||
|
{
|
||||||
|
auto p = pdata<int7_size>(off);
|
||||||
|
return p[0] >> 1;
|
||||||
|
}
|
||||||
|
int8_t get_int7(size_t off) const
|
||||||
|
{
|
||||||
|
return int8_t(get_uint7(off));
|
||||||
|
}
|
||||||
|
void set_uint7(size_t off, uint8_t val)
|
||||||
|
{
|
||||||
|
auto p = pdata<int7_size>(off);
|
||||||
|
p[0] = uint8_t((val << 1) | 1);
|
||||||
|
}
|
||||||
|
void set_int7(size_t off, int8_t val)
|
||||||
|
{
|
||||||
|
set_uint7(off, uint8_t(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t int28_size = 4;
|
||||||
|
uint32_t get_uint28(size_t off) const
|
||||||
|
{
|
||||||
|
auto p = pdata<int28_size>(off);
|
||||||
|
return (p[0]>>1) | ((p[1]&~1U)<<6) | ((p[2]&~1U)<<13) | ((p[3]&~1U)<<20);
|
||||||
|
}
|
||||||
|
int32_t get_int28(size_t off) const
|
||||||
|
{
|
||||||
|
return int32_t(get_uint28(off));
|
||||||
|
}
|
||||||
|
void set_uint28(size_t off, uint32_t val)
|
||||||
|
{
|
||||||
|
auto p = pdata<int28_size>(off);
|
||||||
|
p[0] = uint8_t((val<<1) | 1);
|
||||||
|
p[1] = uint8_t((val>>6) | 1);
|
||||||
|
p[2] = uint8_t((val>>13) | 1);
|
||||||
|
p[3] = uint8_t((val>>20) | 1);
|
||||||
|
}
|
||||||
|
void set_int28(size_t off, int32_t val)
|
||||||
|
{
|
||||||
|
set_uint28(off, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistentDataItem() : index(0), data(nullptr) {}
|
||||||
|
PersistentDataItem(size_t index, const std::shared_ptr<Persistence::LegacyData> &data)
|
||||||
|
: index(index), data(data) {}
|
||||||
|
};
|
||||||
|
namespace Persistence
|
||||||
|
{
|
||||||
|
class Internal
|
||||||
|
{
|
||||||
|
static void clear();
|
||||||
|
static void save();
|
||||||
|
static void load();
|
||||||
|
friend class ::DFHack::Core;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns a new PersistentDataItem with the specified key.
|
||||||
|
// If there is no world loaded or the key is empty, returns an invalid item.
|
||||||
|
DFHACK_EXPORT PersistentDataItem addItem(const std::string &key);
|
||||||
|
// Returns an existing PersistentDataItem with the specified key.
|
||||||
|
// If "added" is not null and there is no such item, a new item is returned and
|
||||||
|
// the bool value is set to true. If "added" is not null and an item is found or
|
||||||
|
// no new item can be created, the bool value is set to false.
|
||||||
|
DFHACK_EXPORT PersistentDataItem getByKey(const std::string &key, bool *added = nullptr);
|
||||||
|
// Returns an existing PersistentDataItem with the specified index.
|
||||||
|
// If there is no world loaded or the index is empty, returns an invalid item.
|
||||||
|
DFHACK_EXPORT PersistentDataItem getByIndex(size_t index);
|
||||||
|
// If the item is invalid, returns false. Otherwise, deletes the item and returns
|
||||||
|
// true. All references to the item are invalid as soon as this function returns.
|
||||||
|
DFHACK_EXPORT bool deleteItem(const PersistentDataItem &item);
|
||||||
|
// Fills the vector with references to each persistent item.
|
||||||
|
DFHACK_EXPORT void getAll(std::vector<PersistentDataItem> &vec);
|
||||||
|
// Fills the vector with references to each persistent item with a key that is
|
||||||
|
// greater than or equal to "min" and less than "max".
|
||||||
|
DFHACK_EXPORT void getAllByKeyRange(std::vector<PersistentDataItem> &vec, const std::string &min, const std::string &max);
|
||||||
|
// Fills the vector with references to each persistent item with a key that is
|
||||||
|
// equal to the given key.
|
||||||
|
DFHACK_EXPORT void getAllByKey(std::vector<PersistentDataItem> &vec, const std::string &key);
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && __GNUC__ < 5
|
||||||
|
// file stream move constructors are missing in libstdc++ before version 5.
|
||||||
|
template<typename T>
|
||||||
|
class DFHACK_EXPORT gcc_4_fstream_shim : public T
|
||||||
|
{
|
||||||
|
const std::string file;
|
||||||
|
public:
|
||||||
|
explicit gcc_4_fstream_shim() : T(), file() {}
|
||||||
|
explicit gcc_4_fstream_shim(const std::string &file) : T(file), file() {}
|
||||||
|
gcc_4_fstream_shim(gcc_4_fstream_shim<T> && s) : T(), file(s.file)
|
||||||
|
{
|
||||||
|
if (!file.empty())
|
||||||
|
{
|
||||||
|
T::open(file.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#define FSTREAM(x) gcc_4_fstream_shim<x>
|
||||||
|
#else
|
||||||
|
#define FSTREAM(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Returns an input stream that data can be read from. If no world is currently loaded,
|
||||||
|
// or no data has been saved with the specified key, the stream is invalid and acts
|
||||||
|
// as if the file is empty.
|
||||||
|
DFHACK_EXPORT FSTREAM(std::ifstream) readSaveData(const std::string &key);
|
||||||
|
// Returns an output stream that data can be saved to. If no world is currently loaded,
|
||||||
|
// an invalid stream is returned, and writing to it has no effect.
|
||||||
|
DFHACK_EXPORT FSTREAM(std::ofstream) writeSaveData(const std::string &key);
|
||||||
|
|
||||||
|
#undef FSTREAM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,420 @@
|
|||||||
|
/*
|
||||||
|
https://github.com/peterix/dfhack
|
||||||
|
Copyright (c) 2009-2012 Petr Mrázek (peterix@gmail.com)
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must
|
||||||
|
not claim that you wrote the original software. If you use this
|
||||||
|
software in a product, an acknowledgment in the product documentation
|
||||||
|
would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Internal.h"
|
||||||
|
#include <array>
|
||||||
|
#include <map>
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
|
#include "Core.h"
|
||||||
|
#include "DataDefs.h"
|
||||||
|
#include "modules/Persistence.h"
|
||||||
|
#include "modules/World.h"
|
||||||
|
|
||||||
|
#include "df/historical_figure.h"
|
||||||
|
|
||||||
|
using namespace DFHack;
|
||||||
|
|
||||||
|
static std::vector<std::shared_ptr<Persistence::LegacyData>> legacy_data;
|
||||||
|
static std::multimap<std::string, size_t> index_cache;
|
||||||
|
|
||||||
|
struct Persistence::LegacyData
|
||||||
|
{
|
||||||
|
const std::string key;
|
||||||
|
std::string str_value;
|
||||||
|
std::array<int, PersistentDataItem::NumInts> int_values;
|
||||||
|
|
||||||
|
explicit LegacyData(const std::string &key) : key(key)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < PersistentDataItem::NumInts; i++)
|
||||||
|
{
|
||||||
|
int_values.at(i) = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
explicit LegacyData(Json::Value &json) : key(json["k"].asString())
|
||||||
|
{
|
||||||
|
str_value = json["s"].asString();
|
||||||
|
for (int i = 0; i < PersistentDataItem::NumInts; i++)
|
||||||
|
{
|
||||||
|
int_values.at(i) = json["i"][i].asInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
explicit LegacyData(const df::language_name &name) : key(name.first_name)
|
||||||
|
{
|
||||||
|
str_value = name.nickname;
|
||||||
|
for (int i = 0; i < PersistentDataItem::NumInts; i++)
|
||||||
|
{
|
||||||
|
int_values.at(i) = name.words[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value toJSON()
|
||||||
|
{
|
||||||
|
Json::Value json(Json::objectValue);
|
||||||
|
json["k"] = key;
|
||||||
|
json["s"] = str_value;
|
||||||
|
Json::Value ints(Json::arrayValue);
|
||||||
|
for (int i = 0; i < PersistentDataItem::NumInts; i++)
|
||||||
|
{
|
||||||
|
ints[i] = int_values.at(i);
|
||||||
|
}
|
||||||
|
json["i"] = std::move(ints);
|
||||||
|
|
||||||
|
return std::move(json);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string &PersistentDataItem::key() const
|
||||||
|
{
|
||||||
|
CHECK_INVALID_ARGUMENT(isValid());
|
||||||
|
return data->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string &PersistentDataItem::val()
|
||||||
|
{
|
||||||
|
CHECK_INVALID_ARGUMENT(isValid());
|
||||||
|
return data->str_value;
|
||||||
|
}
|
||||||
|
const std::string &PersistentDataItem::val() const
|
||||||
|
{
|
||||||
|
CHECK_INVALID_ARGUMENT(isValid());
|
||||||
|
return data->str_value;
|
||||||
|
}
|
||||||
|
int &PersistentDataItem::ival(int i)
|
||||||
|
{
|
||||||
|
CHECK_INVALID_ARGUMENT(isValid());
|
||||||
|
CHECK_INVALID_ARGUMENT(i >= 0 && i < NumInts);
|
||||||
|
return data->int_values.at(i);
|
||||||
|
}
|
||||||
|
int PersistentDataItem::ival(int i) const
|
||||||
|
{
|
||||||
|
CHECK_INVALID_ARGUMENT(isValid());
|
||||||
|
CHECK_INVALID_ARGUMENT(i >= 0 && i < NumInts);
|
||||||
|
return data->int_values.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PersistentDataItem::isValid() const
|
||||||
|
{
|
||||||
|
if (data == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CoreSuspender suspend;
|
||||||
|
|
||||||
|
if (legacy_data.size() <= index)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return legacy_data.at(index) == data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Persistence::Internal::clear()
|
||||||
|
{
|
||||||
|
CoreSuspender suspend;
|
||||||
|
|
||||||
|
legacy_data.clear();
|
||||||
|
index_cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Persistence::Internal::save()
|
||||||
|
{
|
||||||
|
CoreSuspender suspend;
|
||||||
|
|
||||||
|
Json::Value json(Json::arrayValue);
|
||||||
|
for (size_t i = 0; i < legacy_data.size(); i++)
|
||||||
|
{
|
||||||
|
if (legacy_data.at(i) != nullptr)
|
||||||
|
{
|
||||||
|
while (json.size() < i)
|
||||||
|
{
|
||||||
|
json[json.size()] = Json::Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
json[int(i)] = legacy_data.at(i)->toJSON();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto file = writeSaveData("legacy-data");
|
||||||
|
file << json;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convertHFigs()
|
||||||
|
{
|
||||||
|
auto &figs = df::historical_figure::get_vector();
|
||||||
|
|
||||||
|
auto src = figs.begin();
|
||||||
|
while (src != figs.end() && (*src)->id > -100)
|
||||||
|
{
|
||||||
|
++src;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src == figs.end())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dst = src;
|
||||||
|
while (src != figs.end())
|
||||||
|
{
|
||||||
|
auto fig = *src;
|
||||||
|
if (fig->id > -100)
|
||||||
|
{
|
||||||
|
*dst = *src;
|
||||||
|
++dst;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fig->name.has_name && !fig->name.first_name.empty())
|
||||||
|
{
|
||||||
|
size_t index = size_t(-fig->id - 100);
|
||||||
|
if (legacy_data.size() <= index)
|
||||||
|
{
|
||||||
|
legacy_data.resize(index + 1);
|
||||||
|
}
|
||||||
|
legacy_data.at(index) = std::shared_ptr<Persistence::LegacyData>(new Persistence::LegacyData(fig->name));
|
||||||
|
}
|
||||||
|
delete fig;
|
||||||
|
}
|
||||||
|
++src;
|
||||||
|
}
|
||||||
|
|
||||||
|
figs.erase(dst, figs.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Persistence::Internal::load()
|
||||||
|
{
|
||||||
|
CoreSuspender suspend;
|
||||||
|
|
||||||
|
clear();
|
||||||
|
|
||||||
|
auto file = readSaveData("legacy-data");
|
||||||
|
Json::Value json;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file >> json;
|
||||||
|
}
|
||||||
|
catch (std::exception &)
|
||||||
|
{
|
||||||
|
// empty file?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.isArray())
|
||||||
|
{
|
||||||
|
legacy_data.resize(json.size());
|
||||||
|
for (size_t i = 0; i < legacy_data.size(); i++)
|
||||||
|
{
|
||||||
|
if (json[int(i)].isObject())
|
||||||
|
{
|
||||||
|
legacy_data.at(i) = std::shared_ptr<LegacyData>(new LegacyData(json[int(i)]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
convertHFigs();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < legacy_data.size(); i++)
|
||||||
|
{
|
||||||
|
if (legacy_data.at(i) == nullptr)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
index_cache.insert(std::make_pair(legacy_data.at(i)->key, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistentDataItem Persistence::addItem(const std::string &key)
|
||||||
|
{
|
||||||
|
if (key.empty() || !Core::getInstance().isWorldLoaded())
|
||||||
|
return PersistentDataItem();
|
||||||
|
|
||||||
|
CoreSuspender suspend;
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
while (index < legacy_data.size() && legacy_data.at(index) != nullptr)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptr = std::shared_ptr<LegacyData>(new LegacyData(key));
|
||||||
|
|
||||||
|
if (index == legacy_data.size())
|
||||||
|
{
|
||||||
|
legacy_data.push_back(ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
legacy_data.at(index) = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
index_cache.insert(std::make_pair(key, index));
|
||||||
|
|
||||||
|
return PersistentDataItem(index, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistentDataItem Persistence::getByKey(const std::string &key, bool *added)
|
||||||
|
{
|
||||||
|
CoreSuspender suspend;
|
||||||
|
|
||||||
|
auto it = index_cache.find(key);
|
||||||
|
|
||||||
|
if (added)
|
||||||
|
{
|
||||||
|
*added = it == index_cache.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it != index_cache.end())
|
||||||
|
{
|
||||||
|
return PersistentDataItem(it->second, legacy_data.at(it->second));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!added)
|
||||||
|
{
|
||||||
|
return PersistentDataItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
return addItem(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistentDataItem Persistence::getByIndex(size_t index)
|
||||||
|
{
|
||||||
|
CoreSuspender suspend;
|
||||||
|
|
||||||
|
if (index < legacy_data.size() && legacy_data.at(index) != nullptr)
|
||||||
|
{
|
||||||
|
return PersistentDataItem(index, legacy_data.at(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
return PersistentDataItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Persistence::deleteItem(const PersistentDataItem &item)
|
||||||
|
{
|
||||||
|
CoreSuspender suspend;
|
||||||
|
|
||||||
|
if (!item.isValid())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t index = item.get_index();
|
||||||
|
auto range = index_cache.equal_range(item.key());
|
||||||
|
for (auto it = range.first; it != range.second; ++it)
|
||||||
|
{
|
||||||
|
if (it->second == index)
|
||||||
|
{
|
||||||
|
index_cache.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
legacy_data.at(index) = nullptr;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Persistence::getAll(std::vector<PersistentDataItem> &vec)
|
||||||
|
{
|
||||||
|
vec.clear();
|
||||||
|
|
||||||
|
CoreSuspender suspend;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < legacy_data.size(); i++)
|
||||||
|
{
|
||||||
|
if (legacy_data.at(i) != nullptr)
|
||||||
|
{
|
||||||
|
vec.push_back(PersistentDataItem(i, legacy_data.at(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Persistence::getAllByKeyRange(std::vector<PersistentDataItem> &vec, const std::string &min, const std::string &max)
|
||||||
|
{
|
||||||
|
vec.clear();
|
||||||
|
|
||||||
|
CoreSuspender suspend;
|
||||||
|
|
||||||
|
auto begin = index_cache.lower_bound(min);
|
||||||
|
auto end = index_cache.lower_bound(max);
|
||||||
|
for (auto it = begin; it != end; ++it)
|
||||||
|
{
|
||||||
|
vec.push_back(PersistentDataItem(it->second, legacy_data.at(it->second)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Persistence::getAllByKey(std::vector<PersistentDataItem> &vec, const std::string &key)
|
||||||
|
{
|
||||||
|
vec.clear();
|
||||||
|
|
||||||
|
CoreSuspender suspend;
|
||||||
|
|
||||||
|
auto range = index_cache.equal_range(key);
|
||||||
|
for (auto it = range.first; it != range.second; ++it)
|
||||||
|
{
|
||||||
|
vec.push_back(PersistentDataItem(it->second, legacy_data.at(it->second)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string filterSaveFileName(std::string s)
|
||||||
|
{
|
||||||
|
for (auto &ch : s)
|
||||||
|
{
|
||||||
|
if (!isalnum(ch) && ch != '-' && ch != '_')
|
||||||
|
{
|
||||||
|
ch = '_';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getSaveFilePath(const std::string &world, const std::string &name)
|
||||||
|
{
|
||||||
|
return "data/save/" + world + "/dfhack-" + filterSaveFileName(name) + ".dat";
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && __GNUC__ < 5
|
||||||
|
// file stream move constructors are missing in libstdc++ before version 5.
|
||||||
|
#define FSTREAM(x) Persistence::gcc_4_fstream_shim<x>
|
||||||
|
#else
|
||||||
|
#define FSTREAM(x) x
|
||||||
|
#endif
|
||||||
|
FSTREAM(std::ifstream) Persistence::readSaveData(const std::string &name)
|
||||||
|
{
|
||||||
|
if (!Core::getInstance().isWorldLoaded())
|
||||||
|
{
|
||||||
|
// No world loaded - return unopened stream.
|
||||||
|
return FSTREAM(std::ifstream)();
|
||||||
|
}
|
||||||
|
|
||||||
|
return FSTREAM(std::ifstream)(getSaveFilePath(World::ReadWorldFolder(), name));
|
||||||
|
}
|
||||||
|
|
||||||
|
FSTREAM(std::ofstream) Persistence::writeSaveData(const std::string &name)
|
||||||
|
{
|
||||||
|
if (!Core::getInstance().isWorldLoaded())
|
||||||
|
{
|
||||||
|
// No world loaded - return unopened stream.
|
||||||
|
return FSTREAM(std::ofstream)();
|
||||||
|
}
|
||||||
|
|
||||||
|
return FSTREAM(std::ofstream)(getSaveFilePath("current", name));
|
||||||
|
}
|
||||||
|
#undef FSTREAM
|
@ -1 +1 @@
|
|||||||
Subproject commit 44215836d5b57c3722b126aaf481f652385f3a23
|
Subproject commit 4388fbfb8f51be41777406c6e7c518f738c195c7
|
@ -1,754 +0,0 @@
|
|||||||
/* The code is copied from Ragundo's repo referenced below.
|
|
||||||
The changes are:
|
|
||||||
- The addition of a .h file reference.
|
|
||||||
- The simplification of the code using ofsub to remove the use of (and
|
|
||||||
.h reference to) that function (analysis of the code showed the
|
|
||||||
simplified code is the result, as the ofsub expressions will never be
|
|
||||||
true given the range of the values it can be passed in these functions).
|
|
||||||
- The change of the main function to take a separate y coordinate for
|
|
||||||
use in the tropicality determination to allow proper determination of
|
|
||||||
the tropicality of mid level tiles ("region tiles") referencing a
|
|
||||||
neighboring world tile's biome.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
This software is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the authors be held liable for any damages
|
|
||||||
arising from the use of this software.
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it
|
|
||||||
freely, subject to the following restrictions:
|
|
||||||
1. The origin of this software must not be misrepresented; you must not
|
|
||||||
claim that you wrote the original software. If you use this software
|
|
||||||
in a product, an acknowledgment in the product documentation would be
|
|
||||||
appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// You can always find the latest version of this plugin in Github
|
|
||||||
// https://github.com/ragundo/exportmaps
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "DataDefs.h"
|
|
||||||
#include <df/region_map_entry.h>
|
|
||||||
#include <df/world.h>
|
|
||||||
#include <df/world_data.h>
|
|
||||||
#include <df/biome_type.h>
|
|
||||||
|
|
||||||
#include "biome_type.h"
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
Local functions forward declaration
|
|
||||||
*****************************************************************************/
|
|
||||||
std::pair<bool, bool> check_tropicality(df::region_map_entry& region,
|
|
||||||
int a1
|
|
||||||
);
|
|
||||||
|
|
||||||
int get_lake_biome(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude
|
|
||||||
);
|
|
||||||
|
|
||||||
int get_ocean_biome(df::region_map_entry& region,
|
|
||||||
bool is_tropical_area_by_latitude
|
|
||||||
);
|
|
||||||
|
|
||||||
int get_desert_biome(df::region_map_entry& region);
|
|
||||||
|
|
||||||
int get_biome_grassland(bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
);
|
|
||||||
|
|
||||||
int get_biome_savanna(bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
);
|
|
||||||
|
|
||||||
int get_biome_shrubland(bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
);
|
|
||||||
|
|
||||||
int get_biome_marsh(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
);
|
|
||||||
|
|
||||||
int get_biome_forest(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
);
|
|
||||||
|
|
||||||
int get_biome_swamp(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
);
|
|
||||||
|
|
||||||
int get_biome_desert_or_grassland_or_savanna(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
);
|
|
||||||
|
|
||||||
int get_biome_shrubland_or_marsh(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
);
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
Module main function.
|
|
||||||
Return the biome type, given a position coordinate expressed in world_tiles
|
|
||||||
The world ref coordinates are used for tropicality determination and may refer
|
|
||||||
to a tile neighboring the "official" one.
|
|
||||||
*****************************************************************************/
|
|
||||||
int get_biome_type(int world_coord_x,
|
|
||||||
int world_coord_y,
|
|
||||||
int world_ref_coord_y
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// Biome is per region, so get the region where this biome exists
|
|
||||||
df::region_map_entry& region = df::global::world->world_data->region_map[world_coord_x][world_coord_y];
|
|
||||||
|
|
||||||
// Check if the y reference position coordinate belongs to a tropical area
|
|
||||||
std::pair<bool, bool> p = check_tropicality(region,
|
|
||||||
world_ref_coord_y
|
|
||||||
);
|
|
||||||
bool is_possible_tropical_area_by_latitude = p.first;
|
|
||||||
bool is_tropical_area_by_latitude = p.second;
|
|
||||||
|
|
||||||
// Begin the discrimination
|
|
||||||
if (region.flags.is_set(df::region_map_entry_flags::is_lake)) // is it a lake?
|
|
||||||
return get_lake_biome(region,
|
|
||||||
is_possible_tropical_area_by_latitude
|
|
||||||
);
|
|
||||||
|
|
||||||
// Not a lake. Check elevation
|
|
||||||
// Elevation greater then 149 means a mountain biome
|
|
||||||
// Elevation below 100 means a ocean biome
|
|
||||||
// Elevation between 100 and 149 are land biomes
|
|
||||||
|
|
||||||
if (region.elevation >= 150) // is it a mountain?
|
|
||||||
return df::enums::biome_type::biome_type::MOUNTAIN; // 0
|
|
||||||
|
|
||||||
if (region.elevation < 100) // is it a ocean?
|
|
||||||
return get_ocean_biome(region,
|
|
||||||
is_possible_tropical_area_by_latitude
|
|
||||||
);
|
|
||||||
|
|
||||||
// land biome. Elevation between 100 and 149
|
|
||||||
if (region.temperature <= -5)
|
|
||||||
{
|
|
||||||
if (region.drainage < 75)
|
|
||||||
return df::enums::biome_type::biome_type::TUNDRA; // 2
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::GLACIER; // 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not a lake, mountain, ocean, glacier or tundra
|
|
||||||
// Vegetation determines the biome type
|
|
||||||
if (region.vegetation < 66)
|
|
||||||
{
|
|
||||||
if (region.vegetation < 33)
|
|
||||||
return get_biome_desert_or_grassland_or_savanna(region,
|
|
||||||
is_possible_tropical_area_by_latitude,
|
|
||||||
is_tropical_area_by_latitude,
|
|
||||||
world_coord_y,
|
|
||||||
world_coord_x
|
|
||||||
);
|
|
||||||
else // vegetation between 33 and 65
|
|
||||||
return get_biome_shrubland_or_marsh(region,
|
|
||||||
is_possible_tropical_area_by_latitude,
|
|
||||||
is_tropical_area_by_latitude,
|
|
||||||
world_coord_y,
|
|
||||||
world_coord_x
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not a lake, mountain, ocean, glacier, tundra, desert, grassland or savanna
|
|
||||||
// vegetation >= 66
|
|
||||||
if (region.drainage >= 33)
|
|
||||||
return get_biome_forest(region,
|
|
||||||
is_possible_tropical_area_by_latitude,
|
|
||||||
is_tropical_area_by_latitude,
|
|
||||||
world_coord_y,
|
|
||||||
world_coord_x
|
|
||||||
);
|
|
||||||
|
|
||||||
// Not a lake, mountain, ocean, glacier, tundra, desert, grassland, savanna or forest
|
|
||||||
// vegetation >= 66, drainage < 33
|
|
||||||
return get_biome_swamp(region,
|
|
||||||
is_possible_tropical_area_by_latitude,
|
|
||||||
is_tropical_area_by_latitude,
|
|
||||||
world_coord_y,
|
|
||||||
world_coord_x);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
std::pair<bool, bool> check_tropicality_no_poles_world(df::region_map_entry& region,
|
|
||||||
int y_pos
|
|
||||||
)
|
|
||||||
{
|
|
||||||
bool is_possible_tropical_area_by_latitude = false;
|
|
||||||
bool is_tropical_area_by_latitude = false;
|
|
||||||
|
|
||||||
// If there're no poles, tropical area is determined by temperature
|
|
||||||
if (region.temperature >= 75)
|
|
||||||
is_possible_tropical_area_by_latitude = true;
|
|
||||||
is_tropical_area_by_latitude = region.temperature >= 85;
|
|
||||||
|
|
||||||
return std::pair<bool, bool>(is_possible_tropical_area_by_latitude,
|
|
||||||
is_tropical_area_by_latitude
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
std::pair<bool, bool> check_tropicality_north_pole_only_world(df::region_map_entry& region,
|
|
||||||
int y_pos
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int v6;
|
|
||||||
bool is_possible_tropical_area_by_latitude = false;
|
|
||||||
bool is_tropical_area_by_latitude = false;
|
|
||||||
df::world_data* wdata = df::global::world->world_data;
|
|
||||||
|
|
||||||
// Scale the smaller worlds to the big one
|
|
||||||
if (wdata->world_height == 17)
|
|
||||||
v6 = 16 * y_pos;
|
|
||||||
else if (wdata->world_height == 33)
|
|
||||||
v6 = 8 * y_pos;
|
|
||||||
else if (wdata->world_height == 65)
|
|
||||||
v6 = 4 * y_pos;
|
|
||||||
else if (wdata->world_height == 129)
|
|
||||||
v6 = 2 * y_pos;
|
|
||||||
else
|
|
||||||
v6 = y_pos;
|
|
||||||
|
|
||||||
is_possible_tropical_area_by_latitude = v6 > 170;
|
|
||||||
is_tropical_area_by_latitude = v6 >= 200;
|
|
||||||
|
|
||||||
return std::pair<bool, bool>(is_possible_tropical_area_by_latitude,
|
|
||||||
is_tropical_area_by_latitude
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
std::pair<bool, bool> check_tropicality_south_pole_only_world(df::region_map_entry& region,
|
|
||||||
int y_pos
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int v6 = df::global::world->world_data->world_height - y_pos - 1;
|
|
||||||
bool is_possible_tropical_area_by_latitude = false;
|
|
||||||
bool is_tropical_area_by_latitude = false;
|
|
||||||
df::world_data* wdata = df::global::world->world_data;
|
|
||||||
|
|
||||||
if (wdata->world_height == 17)
|
|
||||||
v6 *= 16;
|
|
||||||
else if (wdata->world_height == 33)
|
|
||||||
v6 *= 8;
|
|
||||||
else if (wdata->world_height == 65)
|
|
||||||
v6 *= 4;
|
|
||||||
else if (wdata->world_height == 129)
|
|
||||||
v6 *= 2;
|
|
||||||
else
|
|
||||||
v6 *= 1;
|
|
||||||
|
|
||||||
is_possible_tropical_area_by_latitude = v6 > 170;
|
|
||||||
is_tropical_area_by_latitude = v6 >= 200;
|
|
||||||
|
|
||||||
return std::pair<bool, bool>(is_possible_tropical_area_by_latitude,
|
|
||||||
is_tropical_area_by_latitude
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
std::pair<bool, bool> check_tropicality_both_poles_world(df::region_map_entry& region,
|
|
||||||
int y_pos
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int v6;
|
|
||||||
bool is_possible_tropical_area_by_latitude = false;
|
|
||||||
bool is_tropical_area_by_latitude = false;
|
|
||||||
df::world_data* wdata = df::global::world->world_data;
|
|
||||||
|
|
||||||
if (y_pos < wdata->world_height / 2)
|
|
||||||
v6 = 2 * y_pos;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v6 = wdata->world_height + 2 * (wdata->world_height / 2 - y_pos) - 1;
|
|
||||||
if (v6 < 0)
|
|
||||||
v6 = 0;
|
|
||||||
if (v6 >= wdata->world_height)
|
|
||||||
v6 = wdata->world_height - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wdata->world_height == 17)
|
|
||||||
v6 *= 16;
|
|
||||||
else if (wdata->world_height == 33)
|
|
||||||
v6 *= 8;
|
|
||||||
else if (wdata->world_height == 65)
|
|
||||||
v6 *= 4;
|
|
||||||
else if (wdata->world_height == 129)
|
|
||||||
v6 *= 2;
|
|
||||||
else
|
|
||||||
v6 *= 1;
|
|
||||||
|
|
||||||
is_possible_tropical_area_by_latitude = v6 > 170;
|
|
||||||
is_tropical_area_by_latitude = v6 >= 200;
|
|
||||||
|
|
||||||
return std::pair<bool, bool>(is_possible_tropical_area_by_latitude,
|
|
||||||
is_tropical_area_by_latitude
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
std::pair<bool, bool> check_tropicality(df::region_map_entry& region,
|
|
||||||
int y_pos
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int flip_latitude = df::global::world->world_data->flip_latitude;
|
|
||||||
|
|
||||||
if (flip_latitude == -1) // NO POLES
|
|
||||||
return check_tropicality_no_poles_world(region,
|
|
||||||
y_pos
|
|
||||||
);
|
|
||||||
|
|
||||||
else if (flip_latitude == 0) // NORTH POLE ONLY
|
|
||||||
return check_tropicality_north_pole_only_world(region,
|
|
||||||
y_pos
|
|
||||||
);
|
|
||||||
|
|
||||||
else if (flip_latitude == 1) // SOUTH_POLE ONLY
|
|
||||||
return check_tropicality_south_pole_only_world(region,
|
|
||||||
y_pos
|
|
||||||
);
|
|
||||||
|
|
||||||
else if (flip_latitude == 2) // BOTH POLES
|
|
||||||
return check_tropicality_both_poles_world(region,
|
|
||||||
y_pos
|
|
||||||
);
|
|
||||||
|
|
||||||
return std::pair<bool, bool>(false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_parameter_percentage(int flip_latitude,
|
|
||||||
int y_pos,
|
|
||||||
int rainfall,
|
|
||||||
int world_height
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
int ypos = y_pos;
|
|
||||||
|
|
||||||
if (flip_latitude == -1) // NO POLES
|
|
||||||
return 100;
|
|
||||||
|
|
||||||
else if (flip_latitude == 1) // SOUTH POLE
|
|
||||||
ypos = world_height - y_pos - 1;
|
|
||||||
else if (flip_latitude == 2) // NORTH & SOUTH POLE
|
|
||||||
{
|
|
||||||
if (ypos < world_height / 2)
|
|
||||||
ypos *= 2;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ypos = world_height + 2 * (world_height / 2 - ypos) - 1;
|
|
||||||
if (ypos < 0)
|
|
||||||
ypos = 0;
|
|
||||||
if (ypos >= world_height)
|
|
||||||
ypos = world_height - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int latitude; // 0 - 256 (size of a large world)
|
|
||||||
switch (world_height)
|
|
||||||
{
|
|
||||||
case 17: // Pocket world
|
|
||||||
latitude = 16 * ypos;
|
|
||||||
break;
|
|
||||||
case 33: // Smaller world
|
|
||||||
latitude = 8 * ypos;
|
|
||||||
break;
|
|
||||||
case 65: // Small world
|
|
||||||
latitude = 4 * ypos;
|
|
||||||
break;
|
|
||||||
case 129: // Medium world
|
|
||||||
latitude = 2 * ypos;
|
|
||||||
break;
|
|
||||||
default: // Large world
|
|
||||||
latitude = ypos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// latitude > 220
|
|
||||||
if ((latitude - 171) > 49)
|
|
||||||
return 100;
|
|
||||||
|
|
||||||
|
|
||||||
// Latitude between 191 and 200
|
|
||||||
if ((latitude > 190) && (latitude < 201))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Latitude between 201 and 220
|
|
||||||
if ((latitude > 190) && (latitude >= 201))
|
|
||||||
result = rainfall + 16 * (latitude - 207);
|
|
||||||
else
|
|
||||||
// Latitude between 0 and 190
|
|
||||||
result = (16 * (184 - latitude) - rainfall);
|
|
||||||
|
|
||||||
if (result < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (result > 100)
|
|
||||||
return 100;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
// return some unknow parameter as a percentage
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_region_parameter(int y,
|
|
||||||
int x,
|
|
||||||
char a4
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int result = 100;
|
|
||||||
|
|
||||||
if ((df::global::cur_season && *df::global::cur_season != 1) || !a4)
|
|
||||||
{
|
|
||||||
int world_height = df::global::world->world_data->world_height;
|
|
||||||
if (world_height > 65) // Medium and large worlds
|
|
||||||
{
|
|
||||||
// access to region 2D array
|
|
||||||
df::region_map_entry& region = df::global::world->world_data->region_map[x][y];
|
|
||||||
return get_parameter_percentage(df::global::world->world_data->flip_latitude,
|
|
||||||
y,
|
|
||||||
region.rainfall,
|
|
||||||
world_height
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_lake_biome(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// salinity values tell us the lake type
|
|
||||||
// greater than 66 is a salt water lake
|
|
||||||
// between 33 and 65 is a brackish water lake
|
|
||||||
// less than 33 is a fresh water lake
|
|
||||||
if (region.salinity < 66)
|
|
||||||
{
|
|
||||||
if (region.salinity < 33)
|
|
||||||
if (is_possible_tropical_area_by_latitude)
|
|
||||||
return df::enums::biome_type::biome_type::LAKE_TROPICAL_FRESHWATER; // 39
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::LAKE_TEMPERATE_FRESHWATER; // 36
|
|
||||||
else // salinity >= 33
|
|
||||||
if (is_possible_tropical_area_by_latitude)
|
|
||||||
return df::enums::biome_type::biome_type::LAKE_TROPICAL_BRACKISHWATER; // 40
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::LAKE_TEMPERATE_BRACKISHWATER; // 37
|
|
||||||
}
|
|
||||||
else // salinity >= 66
|
|
||||||
{
|
|
||||||
if (is_possible_tropical_area_by_latitude)
|
|
||||||
return df::enums::biome_type::biome_type::LAKE_TROPICAL_SALTWATER;// 41
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::LAKE_TEMPERATE_SALTWATER; // 38
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_ocean_biome(df::region_map_entry& region,
|
|
||||||
bool is_tropical_area_by_latitude
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (is_tropical_area_by_latitude)
|
|
||||||
return df::enums::biome_type::biome_type::OCEAN_TROPICAL; // 27
|
|
||||||
else
|
|
||||||
if (region.temperature <= -5)
|
|
||||||
return df::enums::biome_type::biome_type::OCEAN_ARCTIC; // 29
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::OCEAN_TEMPERATE; // 28
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_desert_biome(df::region_map_entry& region)
|
|
||||||
{
|
|
||||||
if (region.drainage < 66)
|
|
||||||
{
|
|
||||||
if (region.drainage < 33)
|
|
||||||
return df::enums::biome_type::biome_type::DESERT_SAND; // 26
|
|
||||||
else // drainage between 33 and 65
|
|
||||||
return df::enums::biome_type::biome_type::DESERT_ROCK; // 25
|
|
||||||
}
|
|
||||||
// drainage >= 66
|
|
||||||
return df::enums::biome_type::biome_type::DESERT_BADLAND; // 24
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_biome_grassland(bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if ((is_possible_tropical_area_by_latitude && (get_region_parameter(y, x, 0) < 66)) || is_tropical_area_by_latitude)
|
|
||||||
return df::enums::biome_type::biome_type::GRASSLAND_TROPICAL; // 21
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::GRASSLAND_TEMPERATE; //18;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_biome_savanna(bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if ((is_possible_tropical_area_by_latitude && (get_region_parameter(y, x, 0) <= 6)) || is_tropical_area_by_latitude)
|
|
||||||
return df::enums::biome_type::biome_type::SAVANNA_TROPICAL; // 22
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::SAVANNA_TEMPERATE; //19;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_biome_desert_or_grassland_or_savanna(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (region.vegetation < 20)
|
|
||||||
{
|
|
||||||
if (region.vegetation < 10)
|
|
||||||
return get_desert_biome(region);
|
|
||||||
else // vegetation between 10 and 19
|
|
||||||
return get_biome_grassland(is_possible_tropical_area_by_latitude, is_tropical_area_by_latitude, y, x);
|
|
||||||
}
|
|
||||||
// vegetation between 20 and 32
|
|
||||||
return get_biome_savanna(is_possible_tropical_area_by_latitude, is_tropical_area_by_latitude, y, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_biome_shrubland(bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (is_possible_tropical_area_by_latitude && (get_region_parameter(y, x, 0) < 66 || is_tropical_area_by_latitude))
|
|
||||||
return df::enums::biome_type::biome_type::SHRUBLAND_TROPICAL; // 23
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::SHRUBLAND_TEMPERATE; // 20
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_biome_marsh(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (region.salinity < 66)
|
|
||||||
{
|
|
||||||
if ((is_possible_tropical_area_by_latitude && (get_region_parameter(y, x, 0) < 66)) || is_tropical_area_by_latitude)
|
|
||||||
return df::enums::biome_type::biome_type::MARSH_TROPICAL_FRESHWATER; // 10
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::MARSH_TEMPERATE_FRESHWATER; // 5
|
|
||||||
}
|
|
||||||
else // drainage < 33, salinity >= 66
|
|
||||||
{
|
|
||||||
if ((is_possible_tropical_area_by_latitude && (get_region_parameter(y, x, 0) < 66)) || is_tropical_area_by_latitude)
|
|
||||||
return df::enums::biome_type::biome_type::MARSH_TROPICAL_SALTWATER; // 11
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::MARSH_TEMPERATE_SALTWATER; // 6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_biome_shrubland_or_marsh(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (region.drainage >= 33)
|
|
||||||
return get_biome_shrubland(is_possible_tropical_area_by_latitude,
|
|
||||||
is_tropical_area_by_latitude,
|
|
||||||
y,
|
|
||||||
x
|
|
||||||
);
|
|
||||||
// drainage < 33
|
|
||||||
return get_biome_marsh(region,
|
|
||||||
is_possible_tropical_area_by_latitude,
|
|
||||||
is_tropical_area_by_latitude,
|
|
||||||
y,
|
|
||||||
x
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_biome_forest(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int parameter = get_region_parameter(y, x, 0);
|
|
||||||
|
|
||||||
// drainage >= 33, not tropical area
|
|
||||||
if (!is_possible_tropical_area_by_latitude)
|
|
||||||
{
|
|
||||||
if ((region.rainfall < 75) || (region.temperature < 65))
|
|
||||||
{
|
|
||||||
if (region.temperature >= 10)
|
|
||||||
return df::enums::biome_type::biome_type::FOREST_TEMPERATE_CONIFER; // 13
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::FOREST_TAIGA; // 12
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::FOREST_TEMPERATE_BROADLEAF; // 14
|
|
||||||
}
|
|
||||||
else // drainage >= 33, tropical area
|
|
||||||
{
|
|
||||||
if (((parameter < 66) || is_tropical_area_by_latitude) && (region.rainfall < 75))
|
|
||||||
return df::enums::biome_type::biome_type::FOREST_TROPICAL_CONIFER; // 15
|
|
||||||
if (parameter < 66)
|
|
||||||
return df::enums::biome_type::biome_type::FOREST_TROPICAL_DRY_BROADLEAF; // 16
|
|
||||||
if (is_tropical_area_by_latitude)
|
|
||||||
return df::enums::biome_type::biome_type::FOREST_TROPICAL_MOIST_BROADLEAF; // 17
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((region.rainfall < 75) || (region.temperature < 65))
|
|
||||||
{
|
|
||||||
if (region.temperature >= 10)
|
|
||||||
return df::enums::biome_type::biome_type::FOREST_TEMPERATE_CONIFER; // 13
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::FOREST_TAIGA; // 12
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::FOREST_TEMPERATE_BROADLEAF; // 14
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
// Utility function
|
|
||||||
//
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
int get_biome_swamp(df::region_map_entry& region,
|
|
||||||
bool is_possible_tropical_area_by_latitude,
|
|
||||||
bool is_tropical_area_by_latitude,
|
|
||||||
int y,
|
|
||||||
int x
|
|
||||||
)
|
|
||||||
{
|
|
||||||
int parameter = get_region_parameter(y, x, 0);
|
|
||||||
|
|
||||||
if (is_possible_tropical_area_by_latitude)
|
|
||||||
{
|
|
||||||
if (region.salinity < 66)
|
|
||||||
{
|
|
||||||
if ((parameter < 66) || is_tropical_area_by_latitude)
|
|
||||||
return df::enums::biome_type::biome_type::SWAMP_TROPICAL_FRESHWATER; // 7
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::SWAMP_TEMPERATE_FRESHWATER;// 3
|
|
||||||
}
|
|
||||||
else // elevation between 100 and 149, vegetation >= 66, drainage < 33, salinity >= 66
|
|
||||||
{
|
|
||||||
if ((parameter < 66) || is_tropical_area_by_latitude)
|
|
||||||
{
|
|
||||||
if (region.drainage < 10)
|
|
||||||
return df::enums::biome_type::biome_type::SWAMP_MANGROVE; //9
|
|
||||||
else // drainage >= 10
|
|
||||||
return df::enums::biome_type::biome_type::SWAMP_TROPICAL_SALTWATER; // 8
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::SWAMP_TEMPERATE_SALTWATER; // 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // elevation between 100 and 149, vegetation >= 66, drainage < 33, not tropical area
|
|
||||||
{
|
|
||||||
if (region.salinity >= 66)
|
|
||||||
return df::enums::biome_type::biome_type::SWAMP_TEMPERATE_SALTWATER; // 4
|
|
||||||
else
|
|
||||||
return df::enums::biome_type::biome_type::SWAMP_TEMPERATE_FRESHWATER; // 3
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
// world_coord_x/y is the location of the tile "owning" the biome, while world_ref_coord_y is the
|
|
||||||
// location of the tile the biome appears on. They differ when a mid level tile ("region tile")
|
|
||||||
// refers to a neighboring tile for the biome parameters. The difference can affect the tropicality
|
|
||||||
// determination. Since Tropicality is determined by latitude, the x coordinate of the reference is
|
|
||||||
// omitted.
|
|
||||||
//
|
|
||||||
int get_biome_type(int world_coord_x, int world_coord_y, int world_ref_coord_y);
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
|||||||
|
local _ENV = mkmodule('plugins.map-render')
|
||||||
|
|
||||||
|
--[[
|
||||||
|
|
||||||
|
Native functions:
|
||||||
|
|
||||||
|
* render_map_rect(x,y,z,w,h)
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
return _ENV
|
@ -0,0 +1,125 @@
|
|||||||
|
#include "Core.h"
|
||||||
|
#include "Console.h"
|
||||||
|
#include "Export.h"
|
||||||
|
#include "PluginManager.h"
|
||||||
|
#include "VersionInfo.h"
|
||||||
|
#include "VTableInterpose.h"
|
||||||
|
#include "LuaTools.h"
|
||||||
|
|
||||||
|
#include "DataDefs.h"
|
||||||
|
|
||||||
|
#include "df/viewscreen_dwarfmodest.h"
|
||||||
|
#include "df/init.h"
|
||||||
|
#include "df/renderer.h"
|
||||||
|
#include "df/graphic.h"
|
||||||
|
#include "df/enabler.h"
|
||||||
|
#include "df/map_renderer.h"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
using namespace DFHack;
|
||||||
|
using namespace df::enums;
|
||||||
|
|
||||||
|
DFHACK_PLUGIN("map-render");
|
||||||
|
REQUIRE_GLOBAL(window_x)
|
||||||
|
REQUIRE_GLOBAL(window_y)
|
||||||
|
REQUIRE_GLOBAL(window_z)
|
||||||
|
REQUIRE_GLOBAL_NO_USE(gps)
|
||||||
|
REQUIRE_GLOBAL_NO_USE(enabler)
|
||||||
|
REQUIRE_GLOBAL_NO_USE(twbt_render_map)
|
||||||
|
REQUIRE_GLOBAL(init)
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
// On Windows there's no parameter pointing to the map_renderer structure
|
||||||
|
typedef void(_stdcall *RENDER_MAP)(int);
|
||||||
|
|
||||||
|
RENDER_MAP _render_map;
|
||||||
|
|
||||||
|
void render_map(){ _render_map(0); }
|
||||||
|
#else
|
||||||
|
REQUIRE_GLOBAL(map_renderer)
|
||||||
|
|
||||||
|
typedef void(*RENDER_MAP)(void*, int);
|
||||||
|
|
||||||
|
RENDER_MAP _render_map;
|
||||||
|
|
||||||
|
void render_map(){ _render_map(map_renderer,0); }
|
||||||
|
#endif
|
||||||
|
static int render_map_rect(lua_State* L)
|
||||||
|
{
|
||||||
|
CoreSuspender suspender;
|
||||||
|
|
||||||
|
int x = luaL_checkint(L, 1);
|
||||||
|
int y = luaL_checkint(L, 2);
|
||||||
|
int z = luaL_checkint(L, 3);
|
||||||
|
int w = luaL_checkint(L, 4);
|
||||||
|
int h = luaL_checkint(L, 5);
|
||||||
|
uint8_t *s = df::global::gps->screen;
|
||||||
|
//backup state
|
||||||
|
//TODO: figure out if we can replace screen with other pointer. That way it could be a bit more tidy
|
||||||
|
int32_t win_h = df::global::gps->dimy;
|
||||||
|
int32_t was_x = *window_x;
|
||||||
|
int32_t was_y = *window_y;
|
||||||
|
int32_t was_z = *window_z;
|
||||||
|
int32_t gx = init->display.grid_x;
|
||||||
|
int32_t gy = init->display.grid_y;
|
||||||
|
init->display.grid_x = w+1;
|
||||||
|
init->display.grid_y = h+1;
|
||||||
|
*window_x = x;
|
||||||
|
*window_y = y;
|
||||||
|
*window_z = z;
|
||||||
|
//force full redraw
|
||||||
|
df::global::gps->force_full_display_count = 1;
|
||||||
|
//this modifies screen so it REALLY wants to redraw stuff
|
||||||
|
for (int ty = 0; ty < h; ty++)
|
||||||
|
for (int tx = 0; tx < w; tx++)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
int t = (tx + 1)*win_h + ty + 1;
|
||||||
|
s[t * 4 + i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render_map();
|
||||||
|
//restore state
|
||||||
|
*window_x = was_x;
|
||||||
|
*window_y = was_y;
|
||||||
|
*window_z = was_z;
|
||||||
|
init->display.grid_x = gx;
|
||||||
|
init->display.grid_y = gy;
|
||||||
|
|
||||||
|
lua_createtable(L,w*h*4,0);
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
for (int ty = 0; ty < h; ty++)
|
||||||
|
for (int tx = 0; tx < w; tx++)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 4;i++)
|
||||||
|
{
|
||||||
|
int t = (tx + 1)*win_h + ty + 1;
|
||||||
|
lua_pushnumber(L, s[t*4+i]);
|
||||||
|
lua_rawseti(L, -2, counter);
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DFHACK_PLUGIN_LUA_COMMANDS{
|
||||||
|
DFHACK_LUA_COMMAND(render_map_rect),
|
||||||
|
DFHACK_LUA_END
|
||||||
|
};
|
||||||
|
|
||||||
|
DFhackCExport command_result plugin_init(color_ostream &out, std::vector<PluginCommand> &commands)
|
||||||
|
{
|
||||||
|
auto addr =reinterpret_cast<RENDER_MAP>(Core::getInstance().vinfo->getAddress("twbt_render_map"));
|
||||||
|
if (addr == nullptr)
|
||||||
|
return CR_FAILURE;
|
||||||
|
_render_map = addr;
|
||||||
|
return CR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DFhackCExport command_result plugin_shutdown(color_ostream &out)
|
||||||
|
{
|
||||||
|
return CR_OK;
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
syntax = "proto2";
|
||||||
|
package DwarfControl;
|
||||||
|
|
||||||
|
//Attempts to provide a complete framework for reading everything from a fortress needed for vizualization
|
||||||
|
option optimize_for = LITE_RUNTIME;
|
||||||
|
|
||||||
|
// Plugin: RemoteFortressReader
|
||||||
|
|
||||||
|
import "ui_sidebar_mode.proto";
|
||||||
|
import "RemoteFortressReader.proto";
|
||||||
|
|
||||||
|
// RPC GetSideMenu : EmptyMessage -> SidebarState
|
||||||
|
// RPC SetSideMenu : SidebarCommand -> EmptyMessage
|
||||||
|
|
||||||
|
|
||||||
|
enum BuildCategory
|
||||||
|
{
|
||||||
|
NotCategory = 0;
|
||||||
|
SiegeEngines = 1;
|
||||||
|
Traps = 2;
|
||||||
|
Workshops = 3;
|
||||||
|
Furnaces = 4;
|
||||||
|
Constructions = 5;
|
||||||
|
MachineComponents = 6;
|
||||||
|
Track = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MenuAction
|
||||||
|
{
|
||||||
|
MenuNone = 0;
|
||||||
|
MenuSelect = 1;
|
||||||
|
MenuCancel = 2;
|
||||||
|
MenuSelectAll = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BuildSelectorStage
|
||||||
|
{
|
||||||
|
StageNoMat = 0;
|
||||||
|
StagePlace = 1;
|
||||||
|
StageItemSelect = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SidebarState
|
||||||
|
{
|
||||||
|
optional proto.enums.ui_sidebar_mode.ui_sidebar_mode mode = 1;
|
||||||
|
repeated MenuItem menu_items = 2;
|
||||||
|
optional BuildSelector build_selector = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MenuItem
|
||||||
|
{
|
||||||
|
optional RemoteFortressReader.BuildingType building_type = 1;
|
||||||
|
optional int32 existing_count = 2;
|
||||||
|
optional BuildCategory build_category = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SidebarCommand
|
||||||
|
{
|
||||||
|
optional proto.enums.ui_sidebar_mode.ui_sidebar_mode mode = 1;
|
||||||
|
optional int32 menu_index = 2;
|
||||||
|
optional MenuAction action = 3;
|
||||||
|
optional RemoteFortressReader.Coord selection_coord = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BuiildReqChoice
|
||||||
|
{
|
||||||
|
optional int32 distance = 1;
|
||||||
|
optional string name = 2;
|
||||||
|
optional int32 num_candidates = 3;
|
||||||
|
optional int32 used_count = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BuildItemReq
|
||||||
|
{
|
||||||
|
//Put filter here = 1
|
||||||
|
optional int32 count_required = 2;
|
||||||
|
optional int32 count_max = 3;
|
||||||
|
optional int32 count_provided = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BuildSelector
|
||||||
|
{
|
||||||
|
optional RemoteFortressReader.BuildingType building_type = 1;
|
||||||
|
optional BuildSelectorStage stage = 2;
|
||||||
|
repeated BuiildReqChoice choices = 3;
|
||||||
|
optional int32 sel_index = 4;
|
||||||
|
repeated BuildItemReq requirements = 5;
|
||||||
|
optional int32 req_index = 6;
|
||||||
|
repeated string errors = 7;
|
||||||
|
optional int32 radius_x_low = 8;
|
||||||
|
optional int32 radius_y_low = 9;
|
||||||
|
optional int32 radius_x_high = 10;
|
||||||
|
optional int32 radius_y_high = 11;
|
||||||
|
optional RemoteFortressReader.Coord cursor = 12;
|
||||||
|
repeated int32 tiles = 13;
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package proto.enums.ui_sidebar_mode;
|
||||||
|
|
||||||
|
//Attempts to provide a complete framework for reading everything from a fortress needed for vizualization
|
||||||
|
option optimize_for = LITE_RUNTIME;
|
||||||
|
|
||||||
|
enum ui_sidebar_mode
|
||||||
|
{
|
||||||
|
Default = 0;
|
||||||
|
Squads = 1;
|
||||||
|
DesignateMine = 2;
|
||||||
|
DesignateRemoveRamps = 3;
|
||||||
|
DesignateUpStair = 4;
|
||||||
|
DesignateDownStair = 5;
|
||||||
|
DesignateUpDownStair = 6;
|
||||||
|
DesignateUpRamp = 7;
|
||||||
|
DesignateChannel = 8;
|
||||||
|
DesignateGatherPlants = 9;
|
||||||
|
DesignateRemoveDesignation = 10;
|
||||||
|
DesignateSmooth = 11;
|
||||||
|
DesignateCarveTrack = 12;
|
||||||
|
DesignateEngrave = 13;
|
||||||
|
DesignateCarveFortification = 14;
|
||||||
|
Stockpiles = 15;
|
||||||
|
Build = 16;
|
||||||
|
QueryBuilding = 17;
|
||||||
|
Orders = 18;
|
||||||
|
OrdersForbid = 19;
|
||||||
|
OrdersRefuse = 20;
|
||||||
|
OrdersWorkshop = 21;
|
||||||
|
OrdersZone = 22;
|
||||||
|
BuildingItems = 23;
|
||||||
|
ViewUnits = 24;
|
||||||
|
LookAround = 25;
|
||||||
|
DesignateItemsClaim = 26;
|
||||||
|
DesignateItemsForbid = 27;
|
||||||
|
DesignateItemsMelt = 28;
|
||||||
|
DesignateItemsUnmelt = 29;
|
||||||
|
DesignateItemsDump = 30;
|
||||||
|
DesignateItemsUndump = 31;
|
||||||
|
DesignateItemsHide = 32;
|
||||||
|
DesignateItemsUnhide = 33;
|
||||||
|
DesignateChopTrees = 34;
|
||||||
|
DesignateToggleEngravings = 35;
|
||||||
|
DesignateToggleMarker = 36;
|
||||||
|
Hotkeys = 37;
|
||||||
|
DesignateTrafficHigh = 38;
|
||||||
|
DesignateTrafficNormal = 39;
|
||||||
|
DesignateTrafficLow = 40;
|
||||||
|
DesignateTrafficRestricted = 41;
|
||||||
|
Zones = 42;
|
||||||
|
ZonesPenInfo = 43;
|
||||||
|
ZonesPitInfo = 44;
|
||||||
|
ZonesHospitalInfo = 45;
|
||||||
|
ZonesGatherInfo = 46;
|
||||||
|
DesignateRemoveConstruction = 47;
|
||||||
|
DepotAccess = 48;
|
||||||
|
NotesPoints = 49;
|
||||||
|
NotesRoutes = 50;
|
||||||
|
Burrows = 51;
|
||||||
|
Hauling = 52;
|
||||||
|
ArenaWeather = 53;
|
||||||
|
ArenaTrees = 54;
|
||||||
|
}
|
@ -1,2 +1,2 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#define DF_VERSION_INT 44002
|
#define DF_VERSION_INT 44012
|
||||||
|
@ -0,0 +1,493 @@
|
|||||||
|
#include "dwarf_control.h"
|
||||||
|
#include "DataDefs.h"
|
||||||
|
#include "df_version_int.h"
|
||||||
|
|
||||||
|
#include "df/build_req_choice_genst.h"
|
||||||
|
#include "df/build_req_choice_specst.h"
|
||||||
|
#include "df/build_req_choicest.h"
|
||||||
|
#include "df/building_def.h"
|
||||||
|
#include "df/building_def_furnacest.h"
|
||||||
|
#include "df/building_def_workshopst.h"
|
||||||
|
#include "df/job.h"
|
||||||
|
#include "df/job_list_link.h"
|
||||||
|
#include "df/interface_button_construction_building_selectorst.h"
|
||||||
|
#include "df/interface_button_construction_category_selectorst.h"
|
||||||
|
#include "df/ui.h"
|
||||||
|
#include "df/ui_build_selector.h"
|
||||||
|
#include "df/ui_sidebar_menus.h"
|
||||||
|
#include "df/viewscreen.h"
|
||||||
|
#include "df/world.h"
|
||||||
|
|
||||||
|
#include "modules/Buildings.h"
|
||||||
|
#include "modules/Gui.h"
|
||||||
|
#include "modules/Job.h"
|
||||||
|
#include "modules/MapCache.h"
|
||||||
|
#include "modules/Maps.h"
|
||||||
|
#include "modules/World.h"
|
||||||
|
|
||||||
|
#include "MiscUtils.h"
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
using namespace DFHack;
|
||||||
|
using namespace RemoteFortressReader;
|
||||||
|
using namespace df::enums;
|
||||||
|
using namespace Gui;
|
||||||
|
using namespace df::global;
|
||||||
|
|
||||||
|
extern std::queue<interface_key::interface_key> keyQueue;
|
||||||
|
|
||||||
|
void GetBuildingSize(
|
||||||
|
int16_t type,
|
||||||
|
int16_t subtype,
|
||||||
|
int16_t custom,
|
||||||
|
int16_t &rad_x_low,
|
||||||
|
int16_t &rad_y_low,
|
||||||
|
int16_t &rad_x_high,
|
||||||
|
int16_t &rad_y_high
|
||||||
|
)
|
||||||
|
{
|
||||||
|
rad_x_low = 0;
|
||||||
|
rad_y_low = 0;
|
||||||
|
rad_x_high = 0;
|
||||||
|
rad_y_high = 0;
|
||||||
|
df::building_def* customBuilding = 0;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case building_type::FarmPlot:
|
||||||
|
case building_type::Bridge:
|
||||||
|
case building_type::RoadDirt:
|
||||||
|
case building_type::RoadPaved:
|
||||||
|
case building_type::Stockpile:
|
||||||
|
case building_type::Civzone:
|
||||||
|
case building_type::ScrewPump:
|
||||||
|
case building_type::Construction:
|
||||||
|
case building_type::AxleHorizontal:
|
||||||
|
case building_type::WaterWheel:
|
||||||
|
case building_type::Rollers:
|
||||||
|
{
|
||||||
|
bool widthOdd = world->building_width % 2;
|
||||||
|
rad_x_low = world->building_width / 2;
|
||||||
|
if(widthOdd)
|
||||||
|
rad_x_high = world->building_width / 2;
|
||||||
|
else
|
||||||
|
rad_x_high = (world->building_width / 2) - 1;
|
||||||
|
bool heightOdd = world->building_width % 2;
|
||||||
|
rad_y_low = world->building_height / 2;
|
||||||
|
if (widthOdd)
|
||||||
|
rad_y_high = world->building_height / 2;
|
||||||
|
else
|
||||||
|
rad_y_high = (world->building_height / 2) - 1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case building_type::Furnace:
|
||||||
|
if (subtype != furnace_type::Custom)
|
||||||
|
{
|
||||||
|
rad_x_low = rad_y_low = rad_x_high = rad_y_high = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
customBuilding = world->raws.buildings.furnaces[custom];
|
||||||
|
break;
|
||||||
|
case building_type::TradeDepot:
|
||||||
|
case building_type::Shop:
|
||||||
|
rad_x_low = rad_y_low = rad_x_high = rad_y_high = 2;
|
||||||
|
return;
|
||||||
|
case building_type::Workshop:
|
||||||
|
switch (subtype)
|
||||||
|
{
|
||||||
|
case workshop_type::Carpenters:
|
||||||
|
case workshop_type::Farmers:
|
||||||
|
case workshop_type::Masons:
|
||||||
|
case workshop_type::Craftsdwarfs:
|
||||||
|
case workshop_type::Jewelers:
|
||||||
|
case workshop_type::MetalsmithsForge:
|
||||||
|
case workshop_type::MagmaForge:
|
||||||
|
case workshop_type::Bowyers:
|
||||||
|
case workshop_type::Mechanics:
|
||||||
|
case workshop_type::Butchers:
|
||||||
|
case workshop_type::Leatherworks:
|
||||||
|
case workshop_type::Tanners:
|
||||||
|
case workshop_type::Clothiers:
|
||||||
|
case workshop_type::Fishery:
|
||||||
|
case workshop_type::Still:
|
||||||
|
case workshop_type::Loom:
|
||||||
|
case workshop_type::Kitchen:
|
||||||
|
case workshop_type::Ashery:
|
||||||
|
case workshop_type::Dyers:
|
||||||
|
rad_x_low = rad_y_low = rad_x_high = rad_y_high = 1;
|
||||||
|
return;
|
||||||
|
case workshop_type::Siege:
|
||||||
|
case workshop_type::Kennels:
|
||||||
|
rad_x_low = rad_y_low = rad_x_high = rad_y_high = 2;
|
||||||
|
return;
|
||||||
|
case workshop_type::Custom:
|
||||||
|
customBuilding = world->raws.buildings.workshops[custom];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case building_type::SiegeEngine:
|
||||||
|
case building_type::Wagon:
|
||||||
|
case building_type::Windmill:
|
||||||
|
rad_x_low = rad_y_low = rad_x_high = rad_y_high = 1;
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (customBuilding)
|
||||||
|
{
|
||||||
|
rad_x_low = customBuilding->workloc_x;
|
||||||
|
rad_y_low = customBuilding->workloc_y;
|
||||||
|
rad_x_high = customBuilding->dim_x - rad_x_low - 1;
|
||||||
|
rad_y_high = customBuilding->dim_y - rad_y_low - 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command_result SendDigCommand(color_ostream &stream, const DigCommand *in)
|
||||||
|
{
|
||||||
|
MapExtras::MapCache mc;
|
||||||
|
|
||||||
|
for (int i = 0; i < in->locations_size(); i++)
|
||||||
|
{
|
||||||
|
auto pos = in->locations(i);
|
||||||
|
auto des = mc.designationAt(DFCoord(pos.x(), pos.y(), pos.z()));
|
||||||
|
switch (in->designation())
|
||||||
|
{
|
||||||
|
case NO_DIG:
|
||||||
|
des.bits.dig = tile_dig_designation::No;
|
||||||
|
break;
|
||||||
|
case DEFAULT_DIG:
|
||||||
|
des.bits.dig = tile_dig_designation::Default;
|
||||||
|
break;
|
||||||
|
case UP_DOWN_STAIR_DIG:
|
||||||
|
des.bits.dig = tile_dig_designation::UpDownStair;
|
||||||
|
break;
|
||||||
|
case CHANNEL_DIG:
|
||||||
|
des.bits.dig = tile_dig_designation::Channel;
|
||||||
|
break;
|
||||||
|
case RAMP_DIG:
|
||||||
|
des.bits.dig = tile_dig_designation::Ramp;
|
||||||
|
break;
|
||||||
|
case DOWN_STAIR_DIG:
|
||||||
|
des.bits.dig = tile_dig_designation::DownStair;
|
||||||
|
break;
|
||||||
|
case UP_STAIR_DIG:
|
||||||
|
des.bits.dig = tile_dig_designation::UpStair;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mc.setDesignationAt(DFCoord(pos.x(), pos.y(), pos.z()), des);
|
||||||
|
|
||||||
|
#if DF_VERSION_INT >= 43005
|
||||||
|
//remove and job postings related.
|
||||||
|
for (df::job_list_link * listing = &(df::global::world->jobs.list); listing != NULL; listing = listing->next)
|
||||||
|
{
|
||||||
|
if (listing->item == NULL)
|
||||||
|
continue;
|
||||||
|
auto type = listing->item->job_type;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case job_type::CarveFortification:
|
||||||
|
case job_type::DetailWall:
|
||||||
|
case job_type::DetailFloor:
|
||||||
|
case job_type::Dig:
|
||||||
|
case job_type::CarveUpwardStaircase:
|
||||||
|
case job_type::CarveDownwardStaircase:
|
||||||
|
case job_type::CarveUpDownStaircase:
|
||||||
|
case job_type::CarveRamp:
|
||||||
|
case job_type::DigChannel:
|
||||||
|
case job_type::FellTree:
|
||||||
|
case job_type::GatherPlants:
|
||||||
|
case job_type::RemoveConstruction:
|
||||||
|
case job_type::CarveTrack:
|
||||||
|
{
|
||||||
|
if (listing->item->pos == DFCoord(pos.x(), pos.y(), pos.z()))
|
||||||
|
{
|
||||||
|
Job::removeJob(listing->item);
|
||||||
|
goto JOB_FOUND;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JOB_FOUND:
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
mc.WriteAll();
|
||||||
|
return CR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_result SetPauseState(color_ostream &stream, const SingleBool *in)
|
||||||
|
{
|
||||||
|
DFHack::World::SetPauseState(in->value());
|
||||||
|
return CR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyBuildMenu(DwarfControl::SidebarState * out)
|
||||||
|
{
|
||||||
|
auto menus = df::global::ui_sidebar_menus;
|
||||||
|
auto build_selector = df::global::ui_build_selector;
|
||||||
|
if (build_selector->building_type == -1)
|
||||||
|
for (size_t i = 0; i < menus->building.choices_visible.size(); i++)
|
||||||
|
{
|
||||||
|
auto menu_item = menus->building.choices_visible[i];
|
||||||
|
auto send_item = out->add_menu_items();
|
||||||
|
STRICT_VIRTUAL_CAST_VAR(building, df::interface_button_construction_building_selectorst, menu_item);
|
||||||
|
if (building)
|
||||||
|
{
|
||||||
|
auto send_bld = send_item->mutable_building_type();
|
||||||
|
send_bld->set_building_type(building->building_type);
|
||||||
|
send_bld->set_building_subtype(building->building_subtype);
|
||||||
|
send_bld->set_building_custom(building->custom_type);
|
||||||
|
send_item->set_existing_count(building->existing_count);
|
||||||
|
}
|
||||||
|
STRICT_VIRTUAL_CAST_VAR(sub_category, df::interface_button_construction_category_selectorst, menu_item);
|
||||||
|
if (sub_category)
|
||||||
|
{
|
||||||
|
send_item->set_build_category((DwarfControl::BuildCategory)sub_category->category_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto send_selector = out->mutable_build_selector();
|
||||||
|
auto send_bld = send_selector->mutable_building_type();
|
||||||
|
send_bld->set_building_type(build_selector->building_type);
|
||||||
|
send_bld->set_building_subtype(build_selector->building_subtype);
|
||||||
|
send_bld->set_building_custom(build_selector->custom_type);
|
||||||
|
send_selector->set_stage((DwarfControl::BuildSelectorStage)build_selector->stage);
|
||||||
|
for (size_t i = 0; i < build_selector->errors.size(); i++)
|
||||||
|
{
|
||||||
|
if (build_selector->errors[i])
|
||||||
|
send_selector->add_errors(*build_selector->errors[i]);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < build_selector->choices.size(); i++)
|
||||||
|
{
|
||||||
|
auto choice = build_selector->choices[i];
|
||||||
|
auto send_choice = send_selector->add_choices();
|
||||||
|
send_choice->set_distance(choice->distance);
|
||||||
|
std::string name;
|
||||||
|
choice->getName(&name);
|
||||||
|
send_choice->set_name(name);
|
||||||
|
send_choice->set_num_candidates(choice->getNumCandidates());
|
||||||
|
send_choice->set_used_count(choice->getUsedCount());
|
||||||
|
}
|
||||||
|
int16_t x_low, y_low, x_high, y_high;
|
||||||
|
GetBuildingSize(build_selector->building_type, build_selector->building_subtype, build_selector->custom_type, x_low, y_low, x_high, y_high);
|
||||||
|
send_selector->set_radius_x_low(x_low);
|
||||||
|
send_selector->set_radius_y_low(y_low);
|
||||||
|
send_selector->set_radius_x_high(x_high);
|
||||||
|
send_selector->set_radius_y_high(y_high);
|
||||||
|
if (build_selector->stage >= 1)
|
||||||
|
{
|
||||||
|
auto send_cursor = send_selector->mutable_cursor();
|
||||||
|
send_cursor->set_x(cursor->x);
|
||||||
|
send_cursor->set_y(cursor->y);
|
||||||
|
send_cursor->set_z(cursor->z);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0; y < (y_low + y_high + 1); y++)
|
||||||
|
for (int x = 0; x < (x_low + x_high + 1); x++)
|
||||||
|
{
|
||||||
|
send_selector->add_tiles(build_selector->tiles[x][y]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command_result GetSideMenu(DFHack::color_ostream &stream, const dfproto::EmptyMessage *in, DwarfControl::SidebarState *out)
|
||||||
|
{
|
||||||
|
auto ui = df::global::ui;
|
||||||
|
out->set_mode((proto::enums::ui_sidebar_mode::ui_sidebar_mode)ui->main.mode);
|
||||||
|
auto mode = ui->main.mode;
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case ui_sidebar_mode::Default:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::Squads:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateMine:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateRemoveRamps:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateUpStair:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateDownStair:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateUpDownStair:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateUpRamp:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateChannel:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateGatherPlants:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateRemoveDesignation:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateSmooth:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateCarveTrack:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateEngrave:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateCarveFortification:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::Stockpiles:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::Build:
|
||||||
|
CopyBuildMenu(out);
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::QueryBuilding:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::Orders:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::OrdersForbid:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::OrdersRefuse:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::OrdersWorkshop:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::OrdersZone:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::BuildingItems:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::ViewUnits:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::LookAround:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateItemsClaim:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateItemsForbid:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateItemsMelt:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateItemsUnmelt:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateItemsDump:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateItemsUndump:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateItemsHide:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateItemsUnhide:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateChopTrees:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateToggleEngravings:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateToggleMarker:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::Hotkeys:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateTrafficHigh:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateTrafficNormal:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateTrafficLow:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateTrafficRestricted:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::Zones:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::ZonesPenInfo:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::ZonesPitInfo:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::ZonesHospitalInfo:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::ZonesGatherInfo:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DesignateRemoveConstruction:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::DepotAccess:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::NotesPoints:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::NotesRoutes:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::Burrows:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::Hauling:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::ArenaWeather:
|
||||||
|
break;
|
||||||
|
case ui_sidebar_mode::ArenaTrees:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return CR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_result SetSideMenu(DFHack::color_ostream &stream, const DwarfControl::SidebarCommand *in)
|
||||||
|
{
|
||||||
|
auto ui = df::global::ui;
|
||||||
|
if (in->has_mode())
|
||||||
|
{
|
||||||
|
ui_sidebar_mode::ui_sidebar_mode set_mode = (ui_sidebar_mode::ui_sidebar_mode)in->mode();
|
||||||
|
if (ui->main.mode != set_mode)
|
||||||
|
{
|
||||||
|
ui->main.mode = ui_sidebar_mode::Default;
|
||||||
|
switch (set_mode)
|
||||||
|
{
|
||||||
|
case ui_sidebar_mode::Build:
|
||||||
|
keyQueue.push(interface_key::D_BUILDING);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ui->main.mode = set_mode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (ui->main.mode)
|
||||||
|
{
|
||||||
|
case ui_sidebar_mode::Build:
|
||||||
|
if (in->has_action())
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
if (in->has_menu_index())
|
||||||
|
index = in->menu_index();
|
||||||
|
if(ui_build_selector->building_type == -1)
|
||||||
|
df::global::ui_sidebar_menus->building.cursor = index;
|
||||||
|
if (ui_build_selector->stage == 2)
|
||||||
|
{
|
||||||
|
ui_build_selector->sel_index = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ui_build_selector->stage == 1)
|
||||||
|
{
|
||||||
|
if (in->has_selection_coord())
|
||||||
|
{
|
||||||
|
df::global::cursor->x = in->selection_coord().x();
|
||||||
|
df::global::cursor->y = in->selection_coord().y();
|
||||||
|
df::global::cursor->z = in->selection_coord().z();
|
||||||
|
getCurViewscreen()->feed_key(interface_key::CURSOR_LEFT);
|
||||||
|
getCurViewscreen()->feed_key(interface_key::CURSOR_RIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto viewScreen = getCurViewscreen();
|
||||||
|
if (in->has_action())
|
||||||
|
{
|
||||||
|
switch (in->action())
|
||||||
|
{
|
||||||
|
case DwarfControl::MenuSelect:
|
||||||
|
keyQueue.push(interface_key::SELECT);
|
||||||
|
break;
|
||||||
|
case DwarfControl::MenuCancel:
|
||||||
|
keyQueue.push(interface_key::LEAVESCREEN);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CR_OK;
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef DWARF_CONTROL_H
|
||||||
|
#define DWARF_CONTROL_H
|
||||||
|
|
||||||
|
#include "RemoteClient.h"
|
||||||
|
#include "RemoteFortressReader.pb.h"
|
||||||
|
#include "DwarfControl.pb.h"
|
||||||
|
|
||||||
|
DFHack::command_result SendDigCommand(DFHack::color_ostream &stream, const RemoteFortressReader::DigCommand *in);
|
||||||
|
DFHack::command_result SetPauseState(DFHack::color_ostream &stream, const RemoteFortressReader::SingleBool *in);
|
||||||
|
DFHack::command_result GetSideMenu(DFHack::color_ostream &stream, const dfproto::EmptyMessage *in, DwarfControl::SidebarState *out);
|
||||||
|
DFHack::command_result SetSideMenu(DFHack::color_ostream &stream, const DwarfControl::SidebarCommand *in);
|
||||||
|
|
||||||
|
#endif // !DWARF_CONTROL_H
|
||||||
|
|
||||||
|
|
@ -1 +1 @@
|
|||||||
Subproject commit 4a0f63e044d02532c948d67780dfd128fbd6d043
|
Subproject commit 03e96477ca84e42c87db93bd2d781c73687795a8
|
@ -1 +1 @@
|
|||||||
Subproject commit a242a7cd81ae7046146f86c3103360449e1d9ca8
|
Subproject commit 8ef283377c9830fb932ea888d89b551873af36cf
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
cd ..
|
cd ..
|
||||||
grep DF_VERSION CMakeLists.txt | perl -ne 'print "$&\n" if /[\d\.]+/'
|
grep -i 'set(DF_VERSION' CMakeLists.txt | perl -ne 'print "$&\n" if /[\d\.]+/'
|
||||||
|
Loading…
Reference in New Issue