Compare commits
42 Commits
snapshot-3
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
6ce8e10adb | ||
|
47384c5572 | ||
|
de345a85a1 | ||
|
6de252eb34 | ||
|
b39f3c7f55 | ||
|
58c0ab4747 | ||
|
73daf67c34 | ||
|
3edb8c4233 | ||
|
351dc6ec87 | ||
|
0cfb91ce86 | ||
|
efeac4fd8a | ||
|
36619df4f4 | ||
|
9f02999947 | ||
|
2c55a8a9d9 | ||
|
1a0eb73ea0 | ||
|
f8873debc6 | ||
|
51f714de0f | ||
|
e371d6345b | ||
|
e55fc8703a | ||
|
40e2e4a62a | ||
|
e9fdb254af | ||
|
5e8a28b946 | ||
|
a53595ce68 | ||
|
e8c24e7e23 | ||
|
7edc413cdc | ||
|
53b9b0e286 | ||
|
99cd354a16 | ||
|
d56e8387cf | ||
|
c1c1daa9e5 | ||
|
bfdfebc1d5 | ||
|
502df57cae | ||
|
a0ba5f5398 | ||
|
178519dbb0 | ||
|
bb471e63e1 | ||
|
4b866c409a | ||
|
3fb356e2a9 | ||
|
8452d96bf6 | ||
|
eef8943a3c | ||
|
5160f4ad33 | ||
|
7870ec56a3 | ||
|
16f50b808d | ||
|
aa8ee76fbb |
2
.github/prepare.py
vendored
2
.github/prepare.py
vendored
@ -114,7 +114,7 @@ for arch, platform, libc, statdyn, bplatform, runso
|
||||
( 'x86_64', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build
|
||||
( 'x86_64', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', True, True, '.pdb', None,'x86_64-win-msvc-static', 'release', 10 ),
|
||||
( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 10 ),
|
||||
( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, 'backendvs', None, 'debug', 0 ), # priority = 0: backend=vs build
|
||||
# ( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, 'backendvs', None, 'debug', 0 ), # priority = 0: backend=vs build
|
||||
( 'x86_64', 'windows', 'msvc', 'dynamic', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'release', 10 ),
|
||||
( 'x86', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', False, False, None, None, None, 'debug', 0 ), # priority = 0: static debug build
|
||||
( 'x86', 'windows', 'msvc', 'static', 'windows', 'windows-2019', '.exe', True, True, '.pdb', None, 'i686-win-msvc-static', 'release', 10 ),
|
||||
|
4
.github/starcatcher-publish.sh
vendored
4
.github/starcatcher-publish.sh
vendored
@ -13,6 +13,8 @@ chmod 660 ~/.netrc
|
||||
mountpoint=ftpmnt
|
||||
mkdir $mountpoint
|
||||
curlftpfs "$PUBLISH_HOSTPORT" $mountpoint -o ssl,ciphers='ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-GCM-SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256'
|
||||
cp $PUBLISH_FILENAME $mountpoint/${PUBLISH_DIRECTORY:-.}/
|
||||
if [[ -z ${PUBLISH_ACCESSCHECK-} ]]; then
|
||||
cp $PUBLISH_FILENAME $mountpoint/${PUBLISH_DIRECTORY:-.}/
|
||||
fi
|
||||
fusermount -u $mountpoint
|
||||
rmdir $mountpoint
|
||||
|
7
.github/workflows/build.yaml
vendored
7
.github/workflows/build.yaml
vendored
@ -41,6 +41,13 @@ jobs:
|
||||
env:
|
||||
PUBLISH_HOSTPORT: ${{ secrets.STARCATCHER_PUBLISH_HOSTPORT }}
|
||||
GITHUB_REF: ${{ github.ref }}
|
||||
- if: steps.prepare.outputs.do_publish == 'yes'
|
||||
run: sudo apt update && sudo apt install curlftpfs && bash -c './.github/starcatcher-publish.sh'
|
||||
env:
|
||||
PUBLISH_HOSTPORT: ${{ secrets.STARCATCHER_PUBLISH_HOSTPORT }}
|
||||
PUBLISH_USERNAME: ${{ secrets.STARCATCHER_PUBLISH_USERNAME }}
|
||||
PUBLISH_PASSWORD: ${{ secrets.STARCATCHER_PUBLISH_PASSWORD }}
|
||||
PUBLISH_ACCESSCHECK: yes
|
||||
- if: steps.prepare.outputs.do_release == 'yes'
|
||||
id: create_release
|
||||
env:
|
||||
|
@ -1,4 +1,4 @@
|
||||
The Powder Toy - January 2023
|
||||
The Powder Toy - April 2024
|
||||
==========================
|
||||
|
||||
Get the latest version [from the Powder Toy website](https://powdertoy.co.uk/Download.html).
|
||||
@ -108,6 +108,7 @@ Controls
|
||||
| Shift + R | Horizontal mirror for selected area when pasting stamps |
|
||||
| Ctrl + Shift + R | Vertical mirror for selected area when pasting stamps |
|
||||
| R | Rotate selected area counterclockwise when pasting stamps |
|
||||
| F11 | Toggle fullscreen |
|
||||
|
||||
Command Line
|
||||
---------------------------------------------------------------------------
|
||||
|
16
meson.build
16
meson.build
@ -376,6 +376,22 @@ if host_platform == 'emscripten'
|
||||
'-o', app_exe + '.js', # so we get a .wasm, and a .js
|
||||
]
|
||||
endif
|
||||
if get_option('export_lua_symbols')
|
||||
if is_static and lua_variant != 'none' and not project_export_dynamic
|
||||
if host_platform == 'windows'
|
||||
error('Lua symbols are currently impossible to export correctly on Windows')
|
||||
elif c_compiler.has_link_argument('-Wl,--export-dynamic-symbol')
|
||||
project_link_args += [
|
||||
'-Wl,--export-dynamic-symbol=lua_*',
|
||||
'-Wl,--export-dynamic-symbol=luaL_*',
|
||||
'-Wl,--export-dynamic-symbol=luaopen_*',
|
||||
]
|
||||
else
|
||||
warning('your linker does not support -Wl,--export-dynamic-symbol so Meson will be instructed to export all symbols in order to enable loading Lua shared modules, which may blow up the size of the resulting binary')
|
||||
project_export_dynamic = true
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
if get_option('build_powder')
|
||||
powder_deps += project_deps + [
|
||||
|
@ -40,42 +40,42 @@ option(
|
||||
'display_version_major',
|
||||
type: 'integer',
|
||||
min: 0,
|
||||
value: 97,
|
||||
value: 98,
|
||||
description: 'Major component of the display version, should more or less map to the MINOR version in semantic versioning'
|
||||
)
|
||||
option(
|
||||
'display_version_minor',
|
||||
type: 'integer',
|
||||
min: 0,
|
||||
value: 0,
|
||||
value: 2,
|
||||
description: 'Minor component of the display version, should more or less map to the PATCH version in semantic versioning'
|
||||
)
|
||||
option(
|
||||
'build_num',
|
||||
type: 'integer',
|
||||
min: 0,
|
||||
value: 361,
|
||||
value: 365,
|
||||
description: 'Build number, should be strictly monotonously increasing across public releases'
|
||||
)
|
||||
option(
|
||||
'upstream_version_major',
|
||||
type: 'integer',
|
||||
min: 0,
|
||||
value: 97,
|
||||
value: 98,
|
||||
description: 'Major component of the upstream display version, mod owners should not change this but merge upstream changes to it'
|
||||
)
|
||||
option(
|
||||
'upstream_version_minor',
|
||||
type: 'integer',
|
||||
min: 0,
|
||||
value: 0,
|
||||
value: 2,
|
||||
description: 'Minor component of the upstream display version, mod owners should not change this but merge upstream changes to it'
|
||||
)
|
||||
option(
|
||||
'upstream_build_num',
|
||||
type: 'integer',
|
||||
min: 0,
|
||||
value: 361,
|
||||
value: 365,
|
||||
description: 'Upstream build number, mod owners should not change this but merge upstream changes to it'
|
||||
)
|
||||
option(
|
||||
@ -305,3 +305,9 @@ option(
|
||||
value: true,
|
||||
description: 'Ask Windows nicely for UTF-8 as the codepage'
|
||||
)
|
||||
option(
|
||||
'export_lua_symbols',
|
||||
type: 'boolean',
|
||||
value: false,
|
||||
description: 'Export Lua symbols to enable loading of Lua shared modules'
|
||||
)
|
||||
|
@ -445,19 +445,20 @@ int Main(int argc, char *argv[])
|
||||
engine.Begin();
|
||||
engine.SetFastQuit(prefs.Get("FastQuit", true));
|
||||
engine.TouchUI = prefs.Get("TouchUI", DEFAULT_TOUCH_UI);
|
||||
engine.windowFrameOps = windowFrameOps;
|
||||
|
||||
SDLOpen();
|
||||
|
||||
if (Client::Ref().IsFirstRun() && FORCE_WINDOW_FRAME_OPS == forceWindowFrameOpsNone)
|
||||
{
|
||||
auto guessed = GuessBestScale();
|
||||
if (windowFrameOps.scale != guessed)
|
||||
if (engine.windowFrameOps.scale != guessed)
|
||||
{
|
||||
windowFrameOps.scale = guessed;
|
||||
engine.windowFrameOps.scale = guessed;
|
||||
prefs.Set("Scale", windowFrameOps.scale);
|
||||
showLargeScreenDialog = true;
|
||||
}
|
||||
}
|
||||
engine.windowFrameOps = windowFrameOps;
|
||||
|
||||
SDLOpen();
|
||||
|
||||
bool enableBluescreen = USE_BLUESCREEN && !true_arg(arguments["disable-bluescreen"]);
|
||||
if (enableBluescreen)
|
||||
|
@ -22,6 +22,8 @@ int main(int argc, char *argv[])
|
||||
auto inputFilename = ByteString(argv[1]);
|
||||
auto outputFilename = ByteString(argv[2]) + ".png";
|
||||
|
||||
auto simulationData = std::make_unique<SimulationData>();
|
||||
|
||||
std::vector<char> fileData;
|
||||
if (!Platform::ReadFile(fileData, inputFilename))
|
||||
{
|
||||
@ -40,7 +42,6 @@ int main(int argc, char *argv[])
|
||||
throw e;
|
||||
}
|
||||
|
||||
auto simulationData = std::make_unique<SimulationData>();
|
||||
Simulation * sim = new Simulation();
|
||||
Renderer * ren = new Renderer(sim);
|
||||
|
||||
@ -63,6 +64,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
ren->clearScreen();
|
||||
int w = Graphics::TextSize("Save file invalid").X + 15, x = (XRES-w)/2, y = (YRES-24)/2;
|
||||
ren->DrawRect(RectSized(Vec2{ x, y }, Vec2{ w, 24 }), 0xC0C0C0_rgb);
|
||||
ren->BlendText({ x+8, y+8 }, "Save file invalid", 0xC0C0F0_rgb .WithAlpha(255));
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include "client/http/StartupRequest.h"
|
||||
#include "ClientListener.h"
|
||||
#include "Format.h"
|
||||
#include "MD5.h"
|
||||
#include "client/GameSave.h"
|
||||
#include "client/SaveFile.h"
|
||||
#include "client/SaveInfo.h"
|
||||
@ -378,7 +377,6 @@ void Client::RescanStamps()
|
||||
newStampIDs.push_back(stampID);
|
||||
}
|
||||
}
|
||||
auto oldCount = newStampIDs.size();
|
||||
auto stampIDsSet = std::set<ByteString>(stampIDs.begin(), stampIDs.end());
|
||||
for (auto &stampID : stampFilesSet)
|
||||
{
|
||||
@ -390,8 +388,6 @@ void Client::RescanStamps()
|
||||
}
|
||||
if (changed)
|
||||
{
|
||||
// Move newly discovered stamps to front.
|
||||
std::rotate(newStampIDs.begin(), newStampIDs.begin() + oldCount, newStampIDs.end());
|
||||
stampIDs = newStampIDs;
|
||||
WriteStamps();
|
||||
}
|
||||
|
@ -51,9 +51,18 @@ GameSave::GameSave(const std::vector<char> &data, bool newWantAuthors)
|
||||
void GameSave::MapPalette()
|
||||
{
|
||||
int partMap[PT_NUM];
|
||||
bool ignoreMissingErrors[PT_NUM];
|
||||
for(int i = 0; i < PT_NUM; i++)
|
||||
{
|
||||
partMap[i] = i;
|
||||
ignoreMissingErrors[i] = false;
|
||||
}
|
||||
if (version <= Version(98, 2))
|
||||
{
|
||||
ignoreMissingErrors[PT_ICEI] = true;
|
||||
ignoreMissingErrors[PT_SNOW] = true;
|
||||
ignoreMissingErrors[PT_RSST] = true;
|
||||
ignoreMissingErrors[PT_RSSS] = true;
|
||||
}
|
||||
|
||||
auto &sd = SimulationData::CRef();
|
||||
@ -90,12 +99,14 @@ void GameSave::MapPalette()
|
||||
}
|
||||
}
|
||||
}
|
||||
auto paletteLookup = [this, &partMap](int type) {
|
||||
auto paletteLookup = [this, &partMap](int type, bool ignoreMissingErrors) {
|
||||
if (type > 0 && type < PT_NUM)
|
||||
{
|
||||
auto carriedType = partMap[type];
|
||||
if (!carriedType) // type is not 0 so this shouldn't be 0 either
|
||||
{
|
||||
if (ignoreMissingErrors)
|
||||
return type;
|
||||
missingElements.ids.insert(type);
|
||||
}
|
||||
type = carriedType;
|
||||
@ -113,7 +124,7 @@ void GameSave::MapPalette()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
tempPart.type = paletteLookup(tempPart.type);
|
||||
tempPart.type = paletteLookup(tempPart.type, false);
|
||||
for (auto index : possiblyCarriesType)
|
||||
{
|
||||
if (elements[tempPart.type].CarriesTypeIn & (1U << index))
|
||||
@ -121,7 +132,7 @@ void GameSave::MapPalette()
|
||||
auto *prop = reinterpret_cast<int *>(reinterpret_cast<char *>(&tempPart) + properties[index].Offset);
|
||||
auto carriedType = *prop & int(pmapmask);
|
||||
auto extra = *prop >> pmapbits;
|
||||
carriedType = paletteLookup(carriedType);
|
||||
carriedType = paletteLookup(carriedType, ignoreMissingErrors[tempPart.type]);
|
||||
*prop = PMAP(extra, carriedType);
|
||||
}
|
||||
}
|
||||
@ -2336,6 +2347,14 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
|
||||
{
|
||||
RESTRICTVERSION(97, 0);
|
||||
}
|
||||
if (particles[i].type == PT_RSST || particles[i].type == PT_RSSS)
|
||||
{
|
||||
RESTRICTVERSION(98, 0);
|
||||
}
|
||||
if (particles[i].type == PT_ETRD && (particles[i].tmp || particles[i].tmp2))
|
||||
{
|
||||
RESTRICTVERSION(98, 0);
|
||||
}
|
||||
|
||||
//Get the pmap entry for the next particle in the same position
|
||||
i = partsPosLink[i];
|
||||
|
@ -1,231 +0,0 @@
|
||||
// based on public-domain code from Colin Plumb (1993)
|
||||
#include "MD5.h"
|
||||
#include <cstring>
|
||||
|
||||
static unsigned getu32(const unsigned char *addr)
|
||||
{
|
||||
return (((((unsigned long)addr[3] << 8) | addr[2]) << 8) | addr[1]) << 8 | addr[0];
|
||||
}
|
||||
|
||||
static void putu32(unsigned data, unsigned char *addr)
|
||||
{
|
||||
addr[0] = (unsigned char)data;
|
||||
addr[1] = (unsigned char)(data >> 8);
|
||||
addr[2] = (unsigned char)(data >> 16);
|
||||
addr[3] = (unsigned char)(data >> 24);
|
||||
}
|
||||
|
||||
void md5_init(struct md5_context *ctx)
|
||||
{
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
}
|
||||
|
||||
void md5_update(struct md5_context *ctx, unsigned char const *buf, unsigned len)
|
||||
{
|
||||
unsigned t;
|
||||
|
||||
// update bit count
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = (t + ((unsigned)len << 3)) & 0xffffffff) < t)
|
||||
ctx->bits[1]++; // carry
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f;
|
||||
|
||||
// use leading data to top up the buffer
|
||||
|
||||
if (t)
|
||||
{
|
||||
unsigned char *p = ctx->in + t;
|
||||
|
||||
t = 64-t;
|
||||
if (len < t)
|
||||
{
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
md5_transform(ctx->buf, ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
|
||||
// following 64-byte chunks
|
||||
|
||||
while (len >= 64)
|
||||
{
|
||||
memcpy(ctx->in, buf, 64);
|
||||
md5_transform(ctx->buf, ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
// save rest of bytes for later
|
||||
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
void md5_final(unsigned char digest[16], struct md5_context *ctx)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned char *p;
|
||||
|
||||
// #bytes mod64
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
// first char of padding = 0x80
|
||||
p = ctx->in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
// calculate # of bytes to pad
|
||||
count = 64 - 1 - count;
|
||||
|
||||
// Pad out to 56 mod 64
|
||||
if (count < 8)
|
||||
{
|
||||
// we need to finish a whole block before padding
|
||||
memset(p, 0, count);
|
||||
md5_transform(ctx->buf, ctx->in);
|
||||
memset(ctx->in, 0, 56);
|
||||
}
|
||||
else
|
||||
{
|
||||
// just pad to 56 bytes
|
||||
memset(p, 0, count-8);
|
||||
}
|
||||
|
||||
// append length & final transform
|
||||
putu32(ctx->bits[0], ctx->in + 56);
|
||||
putu32(ctx->bits[1], ctx->in + 60);
|
||||
|
||||
md5_transform(ctx->buf, ctx->in);
|
||||
putu32(ctx->buf[0], digest);
|
||||
putu32(ctx->buf[1], digest + 4);
|
||||
putu32(ctx->buf[2], digest + 8);
|
||||
putu32(ctx->buf[3], digest + 12);
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
}
|
||||
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
void md5_transform(unsigned buf[4], const unsigned char inraw[64])
|
||||
{
|
||||
unsigned a, b, c, d;
|
||||
unsigned in[16];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; ++i)
|
||||
in[i] = getu32 (inraw + 4 * i);
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
static char hexChars[] = "0123456789abcdef";
|
||||
void md5_ascii(char *result, unsigned char const *buf, unsigned len)
|
||||
{
|
||||
struct md5_context md5;
|
||||
unsigned char hash[16];
|
||||
int i;
|
||||
|
||||
if (len==0)
|
||||
len = strlen((char *)buf);
|
||||
|
||||
md5_init(&md5);
|
||||
md5_update(&md5, buf, len);
|
||||
md5_final(hash, &md5);
|
||||
|
||||
for (i=0; i<16; i++)
|
||||
{
|
||||
result[i*2] = hexChars[(hash[i]>>4)&0xF];
|
||||
result[i*2+1] = hexChars[hash[i]&0x0F];
|
||||
}
|
||||
result[32] = 0;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
struct md5_context
|
||||
{
|
||||
unsigned buf[4];
|
||||
unsigned bits[2];
|
||||
unsigned char in[64];
|
||||
};
|
||||
|
||||
void md5_init(struct md5_context *context);
|
||||
void md5_update(struct md5_context *context, unsigned char const *buf, unsigned len);
|
||||
void md5_final(unsigned char digest[16], struct md5_context *context);
|
||||
void md5_transform(unsigned buf[4], const unsigned char in[64]);
|
||||
|
||||
void md5_ascii(char *result, unsigned char const *buf, unsigned len);
|
@ -14,4 +14,13 @@ namespace http
|
||||
sortByVotes,
|
||||
sortByDate,
|
||||
};
|
||||
|
||||
enum Period
|
||||
{
|
||||
allSaves,
|
||||
todaySaves,
|
||||
weekSaves,
|
||||
monthSaves,
|
||||
yearSaves,
|
||||
};
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <ctime>
|
||||
#include "SearchSavesRequest.h"
|
||||
#include "Config.h"
|
||||
#include "client/Client.h"
|
||||
@ -6,7 +7,7 @@
|
||||
|
||||
namespace http
|
||||
{
|
||||
static ByteString Url(int start, int count, ByteString query, Sort sort, Category category)
|
||||
static ByteString Url(int start, int count, ByteString query, Period period, Sort sort, Category category)
|
||||
{
|
||||
ByteStringBuilder builder;
|
||||
builder << SCHEME << SERVER << "/Browse.json?Start=" << start << "&Count=" << count;
|
||||
@ -17,6 +18,38 @@ namespace http
|
||||
}
|
||||
query += str;
|
||||
};
|
||||
|
||||
time_t currentTime = time(NULL);
|
||||
|
||||
if(period)
|
||||
{
|
||||
switch (period)
|
||||
{
|
||||
case todaySaves:
|
||||
currentTime -= 60*60*24; // One day
|
||||
break;
|
||||
case weekSaves:
|
||||
currentTime -= 60*60*24*7; // One week
|
||||
break;
|
||||
case monthSaves:
|
||||
currentTime -= 60*60*24*31; // One month
|
||||
break;
|
||||
case yearSaves:
|
||||
currentTime -= 60*60*24*365; // One year
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
struct tm currentTimeData = *localtime(¤tTime);
|
||||
ByteStringBuilder afterQuery;
|
||||
|
||||
afterQuery << "after:" << currentTimeData.tm_year+1900 << "-" <<
|
||||
(currentTimeData.tm_mon < 9 ? "0" : "") << currentTimeData.tm_mon+1 << "-" <<
|
||||
(currentTimeData.tm_mday < 10 ? "0" : "") << currentTimeData.tm_mday;
|
||||
appendToQuery(afterQuery.Build());
|
||||
}
|
||||
|
||||
switch (sort)
|
||||
{
|
||||
case sortByDate:
|
||||
@ -48,7 +81,7 @@ namespace http
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
SearchSavesRequest::SearchSavesRequest(int start, int count, ByteString query, Sort sort, Category category) : APIRequest(Url(start, count, query, sort, category), authUse, false)
|
||||
SearchSavesRequest::SearchSavesRequest(int start, int count, ByteString query, Period period, Sort sort, Category category) : APIRequest(Url(start, count, query, period, sort, category), authUse, false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ namespace http
|
||||
class SearchSavesRequest : public APIRequest
|
||||
{
|
||||
public:
|
||||
SearchSavesRequest(int start, int count, ByteString query, Sort sort, Category category);
|
||||
SearchSavesRequest(int start, int count, ByteString query, Period period, Sort sort, Category category);
|
||||
|
||||
std::pair<int, std::vector<std::unique_ptr<SaveInfo>>> Finish();
|
||||
};
|
||||
|
@ -52,6 +52,10 @@ namespace http
|
||||
return;
|
||||
}
|
||||
auto &info = versions[key];
|
||||
if (info.isNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto getOr = [&info](ByteString key, int defaultValue) -> int {
|
||||
if (!info.isMember(key))
|
||||
{
|
||||
@ -59,7 +63,7 @@ namespace http
|
||||
}
|
||||
return info[key].asInt();
|
||||
};
|
||||
auto build = getOr(key == "Snapshot" ? "Snapshot" : "Build", -1);
|
||||
auto build = getOr(key == "Snapshot" ? "Snapshot" : "Build", 0);
|
||||
if (!updateAvailableFunc(build))
|
||||
{
|
||||
return;
|
||||
@ -68,8 +72,8 @@ namespace http
|
||||
channel,
|
||||
ByteString::Build(SCHEME, alternate ? UPDATESERVER : SERVER, info["File"].asString()),
|
||||
ByteString(info["Changelog"].asString()).FromUtf8(),
|
||||
getOr("Major", -1),
|
||||
getOr("Minor", -1),
|
||||
getOr("Major", 0),
|
||||
getOr("Minor", 0),
|
||||
build,
|
||||
};
|
||||
};
|
||||
|
@ -1,5 +1,4 @@
|
||||
client_files = files(
|
||||
'MD5.cpp',
|
||||
'SaveFile.cpp',
|
||||
'SaveInfo.cpp',
|
||||
'ThumbnailRendererTask.cpp',
|
||||
|
@ -112,6 +112,14 @@ struct Vec2
|
||||
);
|
||||
}
|
||||
|
||||
Vec2<T> Min(Vec2<T> other) const
|
||||
{
|
||||
return Vec2<T>(
|
||||
std::min(X, other.X),
|
||||
std::min(Y, other.Y)
|
||||
);
|
||||
}
|
||||
|
||||
// Return a rectangle starting at origin, whose dimensions match this vector
|
||||
template<typename S = T, typename = std::enable_if_t<std::is_integral_v<S>>>
|
||||
constexpr inline Rect<T> OriginRect() const
|
||||
|
@ -58,7 +58,7 @@ bool ReadFile(std::vector<char> &fileData, ByteString filename)
|
||||
if (f) f.seekg(0, std::ios::end);
|
||||
if (f) fileData.resize(f.tellg());
|
||||
if (f) f.seekg(0);
|
||||
if (f) f.read(&fileData[0], fileData.size());
|
||||
if (f && fileData.size()) f.read(&fileData[0], fileData.size());
|
||||
if (!f)
|
||||
{
|
||||
std::cerr << "ReadFile: " << filename << ": " << strerror(errno) << std::endl;
|
||||
|
@ -183,6 +183,8 @@ void Renderer::render_parts()
|
||||
gfctx.pipeSubcallTpart = nullptr;
|
||||
int deca, decr, decg, decb, cola, colr, colg, colb, firea, firer, fireg, fireb, pixel_mode, q, i, t, nx, ny, x, y;
|
||||
int orbd[4] = {0, 0, 0, 0}, orbl[4] = {0, 0, 0, 0};
|
||||
int drawing_budget = 1000000; //Serves as an upper bound for costly effects such as SPARK, FLARE and LFLARE
|
||||
|
||||
if(!sim)
|
||||
return;
|
||||
auto *parts = sim->parts;
|
||||
@ -633,7 +635,7 @@ void Renderer::render_parts()
|
||||
{
|
||||
auto flicker = float(gfctx.rng()%20);
|
||||
auto gradv = 4*sim->parts[i].life + flicker;
|
||||
for (x = 0; gradv>0.5; x++) {
|
||||
for (x = 0; (gradv>0.5) && (drawing_budget > 0); x++) {
|
||||
auto col = RGBA<uint8_t>(
|
||||
std::min(0xFF, colr * int(gradv) / 255),
|
||||
std::min(0xFF, colg * int(gradv) / 255),
|
||||
@ -644,6 +646,7 @@ void Renderer::render_parts()
|
||||
AddPixel({ nx, ny+x }, col);
|
||||
AddPixel({ nx, ny-x }, col);
|
||||
gradv = gradv/1.5f;
|
||||
drawing_budget--;
|
||||
}
|
||||
}
|
||||
if(pixel_mode & PMODE_FLARE)
|
||||
@ -660,12 +663,13 @@ void Renderer::render_parts()
|
||||
BlendPixel({ nx-1, ny-1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
BlendPixel({ nx+1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
BlendPixel({ nx-1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
for (x = 1; gradv>0.5; x++) {
|
||||
for (x = 1; (gradv>0.5) && (drawing_budget > 0); x++) {
|
||||
AddPixel({ nx+x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
AddPixel({ nx-x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
AddPixel({ nx, ny+x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
AddPixel({ nx, ny-x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
gradv = gradv/1.2f;
|
||||
drawing_budget--;
|
||||
}
|
||||
}
|
||||
if(pixel_mode & PMODE_LFLARE)
|
||||
@ -682,12 +686,13 @@ void Renderer::render_parts()
|
||||
BlendPixel({ nx-1, ny-1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
BlendPixel({ nx+1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
BlendPixel({ nx-1, ny+1 }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
for (x = 1; gradv>0.5; x++) {
|
||||
for (x = 1; (gradv>0.5) && (drawing_budget > 0); x++) {
|
||||
AddPixel({ nx+x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
AddPixel({ nx-x, ny }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
AddPixel({ nx, ny+x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
AddPixel({ nx, ny-x }, RGBA<uint8_t>(colr, colg, colb, int(gradv)));
|
||||
gradv = gradv/1.01f;
|
||||
drawing_budget--;
|
||||
}
|
||||
}
|
||||
if (pixel_mode & EFFECT_GRAVIN)
|
||||
|
@ -39,7 +39,7 @@ class LoadFilesTask: public Task
|
||||
bool doWork() override
|
||||
{
|
||||
std::vector<ByteString> files = Platform::DirectorySearch(directory, search, { ".cps" });
|
||||
std::sort(files.rbegin(), files.rend(), [](ByteString a, ByteString b) { return a.ToLower() < b.ToLower(); });
|
||||
std::sort(files.rbegin(), files.rend(), [](ByteString a, ByteString b) { return a.ToLower() > b.ToLower(); });
|
||||
|
||||
notifyProgress(-1);
|
||||
for(std::vector<ByteString>::iterator iter = files.begin(), end = files.end(); iter != end; ++iter)
|
||||
|
@ -1111,8 +1111,11 @@ void GameController::SetActiveTool(int toolSelection, Tool * tool)
|
||||
gameModel->SetLastTool(tool);
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
if(gameModel->GetActiveTool(i) == gameModel->GetMenuList().at(SC_WALL)->GetToolList().at(WL_GRAV))
|
||||
auto *activeTool = gameModel->GetActiveTool(i);
|
||||
if (activeTool && activeTool->Identifier == "DEFAULT_WL_GRVTY")
|
||||
{
|
||||
gameModel->GetRenderer()->gravityZonesEnabled = true;
|
||||
}
|
||||
}
|
||||
if (tool->Identifier == "DEFAULT_UI_PROPERTY")
|
||||
{
|
||||
|
@ -15,7 +15,8 @@ class DropDownWindow : public ui::Window
|
||||
|
||||
public:
|
||||
DropDownWindow(DropDown * dropDown):
|
||||
Window(dropDown->GetScreenPos() + ui::Point(-1, -1 - dropDown->optionIndex * 16), ui::Point(dropDown->Size.X+2, 2+dropDown->options.size()*16)),
|
||||
Window(dropDown->GetScreenPos() + ui::Point(-1, -1 - (dropDown->optionIndex*16 < dropDown->GetScreenPos().Y ? dropDown->optionIndex*16 : 0)),
|
||||
ui::Point(dropDown->Size.X+2, 2+dropDown->options.size()*16)),
|
||||
dropDown(dropDown),
|
||||
appearance(dropDown->Appearance)
|
||||
{
|
||||
|
@ -83,6 +83,8 @@ void Engine::ShowWindow(Window * window)
|
||||
{
|
||||
window->Position.Y = (g->Size().Y - window->Size.Y) / 2;
|
||||
}
|
||||
window->Size = window->Size.Min(g->Size());
|
||||
window->Position = window->Position.Clamp(RectBetween<int>({0, 0}, g->Size()));
|
||||
/*if(window->Position.Y > 0)
|
||||
{
|
||||
windowTargetPosition = window->Position;
|
||||
|
@ -114,32 +114,35 @@ void Panel::OnMouseClick(int localx, int localy, unsigned button)
|
||||
|
||||
void Panel::OnMouseDown(int x, int y, unsigned button)
|
||||
{
|
||||
auto localx = x - Position.X;
|
||||
auto localy = y - Position.Y;
|
||||
//check if clicked a child
|
||||
for(int i = children.size()-1; i >= 0 ; --i)
|
||||
if (MouseDownInside)
|
||||
{
|
||||
//child must be enabled
|
||||
if(children[i]->Enabled)
|
||||
auto localx = x - Position.X;
|
||||
auto localy = y - Position.Y;
|
||||
//check if clicked a child
|
||||
for(int i = children.size()-1; i >= 0 ; --i)
|
||||
{
|
||||
//is mouse inside?
|
||||
if( localx >= children[i]->Position.X + ViewportPosition.X &&
|
||||
localy >= children[i]->Position.Y + ViewportPosition.Y &&
|
||||
localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X &&
|
||||
localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y )
|
||||
//child must be enabled
|
||||
if(children[i]->Enabled)
|
||||
{
|
||||
GetParentWindow()->FocusComponent(children[i]);
|
||||
children[i]->MouseDownInside = true;
|
||||
break;
|
||||
//is mouse inside?
|
||||
if( localx >= children[i]->Position.X + ViewportPosition.X &&
|
||||
localy >= children[i]->Position.Y + ViewportPosition.Y &&
|
||||
localx < children[i]->Position.X + ViewportPosition.X + children[i]->Size.X &&
|
||||
localy < children[i]->Position.Y + ViewportPosition.Y + children[i]->Size.Y )
|
||||
{
|
||||
GetParentWindow()->FocusComponent(children[i]);
|
||||
children[i]->MouseDownInside = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XOnMouseDown(x, y, button);
|
||||
for (size_t i = 0; i < children.size(); ++i)
|
||||
{
|
||||
if(children[i]->Enabled)
|
||||
children[i]->OnMouseDown(x - Position.X - ViewportPosition.X, y - Position.Y - ViewportPosition.Y, button);
|
||||
XOnMouseDown(x, y, button);
|
||||
for (size_t i = 0; i < children.size(); ++i)
|
||||
{
|
||||
if(children[i]->Enabled)
|
||||
children[i]->OnMouseDown(x - Position.X - ViewportPosition.X, y - Position.Y - ViewportPosition.Y, button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,7 @@ void ScrollPanel::XOnMouseDown(int x, int y, unsigned int button)
|
||||
{
|
||||
if (MouseDownInside)
|
||||
{
|
||||
CancelPanning();
|
||||
if (isMouseInsideScrollbar)
|
||||
{
|
||||
scrollbarSelected = true;
|
||||
@ -86,24 +87,31 @@ void ScrollPanel::XOnMouseDown(int x, int y, unsigned int button)
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollPanel::CancelPanning()
|
||||
{
|
||||
panning = false;
|
||||
panHistory = {};
|
||||
yScrollVel = 0;
|
||||
}
|
||||
|
||||
void ScrollPanel::XOnMouseUp(int x, int y, unsigned int button)
|
||||
{
|
||||
scrollbarSelected = false;
|
||||
panning = false;
|
||||
auto oldPanHistory = panHistory;
|
||||
CancelPanning();
|
||||
{
|
||||
auto it = panHistory.end();
|
||||
while (it != panHistory.begin() && *(it - 1))
|
||||
auto it = oldPanHistory.end();
|
||||
while (it != oldPanHistory.begin() && *(it - 1))
|
||||
{
|
||||
--it;
|
||||
}
|
||||
if (it < panHistory.end())
|
||||
if (it < oldPanHistory.end())
|
||||
{
|
||||
auto offsetYDiff = panHistory.back()->offsetY - (*it)->offsetY;
|
||||
auto tickDiff = panHistory.back()->ticks - (*it)->ticks;
|
||||
auto offsetYDiff = oldPanHistory.back()->offsetY - (*it)->offsetY;
|
||||
auto tickDiff = oldPanHistory.back()->ticks - (*it)->ticks;
|
||||
yScrollVel += offsetYDiff / tickDiff * (1000.f / Engine::Ref().GetFps());
|
||||
}
|
||||
}
|
||||
panHistory = {};
|
||||
isMouseInsideScrollbarArea = false;
|
||||
scrollbarClickLocation = 0;
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ namespace ui
|
||||
{
|
||||
class ScrollPanel: public Panel
|
||||
{
|
||||
void CancelPanning();
|
||||
|
||||
protected:
|
||||
int scrollBarWidth;
|
||||
Point maxOffset;
|
||||
|
@ -59,6 +59,8 @@ void LocalBrowserModel::OpenSave(int index)
|
||||
{
|
||||
stamp = std::move(savesList[index]);
|
||||
savesList.clear();
|
||||
notifyPageChanged();
|
||||
notifySavesListChanged();
|
||||
}
|
||||
|
||||
bool LocalBrowserModel::GetMoveToFront()
|
||||
|
@ -76,13 +76,13 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
|
||||
auto *checkbox = new ui::Checkbox(ui::Point(8 + indent * 15, currentY), ui::Point(1, 16), text, "");
|
||||
autoWidth(checkbox, 0);
|
||||
checkbox->SetActionCallback({ action });
|
||||
scrollPanel->AddChild(checkbox);
|
||||
currentY += 14;
|
||||
if (info.size())
|
||||
{
|
||||
addLabel(indent, info);
|
||||
}
|
||||
currentY += 4;
|
||||
scrollPanel->AddChild(checkbox);
|
||||
return checkbox;
|
||||
};
|
||||
auto addDropDown = [this, ¤tY, &autoWidth](String info, std::vector<std::pair<String, int>> options, std::function<void ()> action) {
|
||||
@ -137,10 +137,11 @@ OptionsView::OptionsView() : ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
|
||||
ambientAirTemp->SetDefocusCallback({ [this] {
|
||||
UpdateAirTemp(ambientAirTemp->GetText(), true);
|
||||
}});
|
||||
ambientAirTemp->SetLimit(9);
|
||||
scrollPanel->AddChild(ambientAirTemp);
|
||||
ambientAirTempPreview = new ui::Button(ui::Point(Size.X-31, currentY), ui::Point(16, 16), "", "Preview");
|
||||
scrollPanel->AddChild(ambientAirTempPreview);
|
||||
auto *label = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Ambient air temperature");
|
||||
auto *label = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-105, 16), "Ambient air temperature");
|
||||
label->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
label->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||
scrollPanel->AddChild(label);
|
||||
|
@ -111,9 +111,9 @@ PreviewView::PreviewView(std::unique_ptr<VideoBuffer> newSavePreview):
|
||||
AddComponent(missingElementsButton);
|
||||
|
||||
if(showAvatars)
|
||||
saveNameLabel = new ui::Label(ui::Point(39, (YRES/2)+4), ui::Point(180, 16), "");
|
||||
saveNameLabel = new ui::Label(ui::Point(39, (YRES/2)+4), ui::Point(265, 16), "");
|
||||
else
|
||||
saveNameLabel = new ui::Label(ui::Point(5, (YRES/2)+4), ui::Point(200, 16), "");
|
||||
saveNameLabel = new ui::Label(ui::Point(5, (YRES/2)+4), ui::Point(300, 16), "");
|
||||
saveNameLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
saveNameLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||
AddComponent(saveNameLabel);
|
||||
@ -129,9 +129,9 @@ PreviewView::PreviewView(std::unique_ptr<VideoBuffer> newSavePreview):
|
||||
AddComponent(saveDescriptionLabel);
|
||||
|
||||
if(showAvatars)
|
||||
authorDateLabel = new ui::Label(ui::Point(39, (YRES/2)+4+15), ui::Point(180, 16), "");
|
||||
authorDateLabel = new ui::Label(ui::Point(39, (YRES/2)+4+15), ui::Point(200, 16), "");
|
||||
else
|
||||
authorDateLabel = new ui::Label(ui::Point(5, (YRES/2)+4+15), ui::Point(200, 16), "");
|
||||
authorDateLabel = new ui::Label(ui::Point(5, (YRES/2)+4+15), ui::Point(220, 16), "");
|
||||
authorDateLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
authorDateLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||
AddComponent(authorDateLabel);
|
||||
@ -148,7 +148,7 @@ PreviewView::PreviewView(std::unique_ptr<VideoBuffer> newSavePreview):
|
||||
AddComponent(avatarButton);
|
||||
}
|
||||
|
||||
viewsLabel = new ui::Label(ui::Point((XRES/2)-80, (YRES/2)+4+15), ui::Point(80, 16), "");
|
||||
viewsLabel = new ui::Label(ui::Point((XRES/2)-88, (YRES/2)+4+15), ui::Point(88, 16), "");
|
||||
viewsLabel->Appearance.HorizontalAlign = ui::Appearance::AlignRight;
|
||||
viewsLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||
AddComponent(viewsLabel);
|
||||
@ -644,6 +644,7 @@ void PreviewView::NotifyCommentBoxEnabledChanged(PreviewModel * sender)
|
||||
} });
|
||||
addCommentBox->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
addCommentBox->SetMultiline(true);
|
||||
addCommentBox->SetLimit(1000);
|
||||
AddComponent(addCommentBox);
|
||||
submitCommentButton = new ui::Button(ui::Point(Size.X-40, Size.Y-19), ui::Point(40, 19), "Submit");
|
||||
submitCommentButton->SetActionCallback({ [this] { submitComment(); } });
|
||||
|
@ -70,7 +70,7 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
|
||||
int currentY = 5;
|
||||
|
||||
// username label
|
||||
ui::Label * title = new ui::Label(ui::Point(4, currentY), ui::Point(Size.X-8-(40+8+75), 15), info.username.FromUtf8());
|
||||
ui::Label * title = new ui::Label(ui::Point(4, currentY), ui::Point(Size.X-8-(40+16+75), 15), info.username.FromUtf8());
|
||||
title->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
scrollPanel->AddChild(title);
|
||||
|
||||
@ -90,13 +90,13 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
|
||||
currentY += 23;
|
||||
|
||||
// age
|
||||
ui::Label * ageTitle = new ui::Label(ui::Point(4, currentY), ui::Point(18, 15), "Age:");
|
||||
ui::Label * ageTitle = new ui::Label(ui::Point(4, currentY), ui::Point(23, 15), "Age:");
|
||||
ageTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
ageTitle->SetTextColour(ui::Colour(180, 180, 180));
|
||||
scrollPanel->AddChild(ageTitle);
|
||||
|
||||
// can't figure out how to tell a null from a 0 in the json library we use
|
||||
ui::Label *age = new ui::Label(ui::Point(8+ageTitle->Size.X, currentY), ui::Point(40, 15), info.age ? String::Build(info.age) : "\bgNot Provided");
|
||||
ui::Label *age = new ui::Label(ui::Point(5+ageTitle->Size.X, currentY), ui::Point(Size.X-ageTitle->Size.X-56, 15), info.age ? String::Build(info.age) : "\bgNot Provided");
|
||||
age->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
scrollPanel->AddChild(age);
|
||||
currentY += 2+age->Size.Y;
|
||||
@ -108,20 +108,25 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
|
||||
scrollPanel->AddChild(locationTitle);
|
||||
|
||||
if (editable)
|
||||
location = new ui::Textbox(ui::Point(8+locationTitle->Size.X, currentY), ui::Point(Size.X-locationTitle->Size.X-16, 17), info.location);
|
||||
{
|
||||
location = new ui::Textbox(ui::Point(5+locationTitle->Size.X, currentY), ui::Point(Size.X-locationTitle->Size.X-16, 17), info.location);
|
||||
((ui::Textbox*)location)->SetLimit(40);
|
||||
}
|
||||
else
|
||||
location = new ui::Label(ui::Point(4+locationTitle->Size.X, currentY), ui::Point(Size.X-locationTitle->Size.X-14, 17), info.location);
|
||||
{
|
||||
location = new ui::Label(ui::Point(5+locationTitle->Size.X, currentY), ui::Point(Size.X-locationTitle->Size.X-14, 17), info.location);
|
||||
}
|
||||
location->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
scrollPanel->AddChild(location);
|
||||
currentY += 2+location->Size.Y;
|
||||
|
||||
// website
|
||||
ui::Label * websiteTitle = new ui::Label(ui::Point(4, currentY), ui::Point(38, 15), "Website:");
|
||||
ui::Label * websiteTitle = new ui::Label(ui::Point(1, currentY), ui::Point(42, 15), "Website:");
|
||||
websiteTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
websiteTitle->SetTextColour(ui::Colour(180, 180, 180));
|
||||
scrollPanel->AddChild(websiteTitle);
|
||||
|
||||
ui::Label *website = new ui::Label(ui::Point(8+websiteTitle->Size.X, currentY), ui::Point(Size.X-websiteTitle->Size.X-16, 15), info.website.FromUtf8());
|
||||
ui::Label *website = new ui::Label(ui::Point(2+websiteTitle->Size.X, currentY), ui::Point(Size.X-websiteTitle->Size.X-16, 15), info.website.FromUtf8());
|
||||
website->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
scrollPanel->AddChild(website);
|
||||
currentY += 2+website->Size.Y;
|
||||
@ -134,34 +139,34 @@ void ProfileActivity::setUserInfo(UserInfo newInfo)
|
||||
currentY += savesTitle->Size.Y;
|
||||
|
||||
// saves count
|
||||
ui::Label * saveCountTitle = new ui::Label(ui::Point(12, currentY), ui::Point(30, 15), "Count:");
|
||||
ui::Label * saveCountTitle = new ui::Label(ui::Point(12, currentY), ui::Point(32, 15), "Count:");
|
||||
saveCountTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
saveCountTitle->SetTextColour(ui::Colour(180, 180, 180));
|
||||
scrollPanel->AddChild(saveCountTitle);
|
||||
|
||||
ui::Label *savesCount = new ui::Label(ui::Point(12+saveCountTitle->Size.X, currentY), ui::Point(Size.X-saveCountTitle->Size.X-16, 15), String::Build(info.saveCount));
|
||||
ui::Label *savesCount = new ui::Label(ui::Point(13+saveCountTitle->Size.X, currentY), ui::Point(Size.X-saveCountTitle->Size.X-24, 15), String::Build(info.saveCount));
|
||||
savesCount->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
scrollPanel->AddChild(savesCount);
|
||||
currentY += savesCount->Size.Y;
|
||||
|
||||
// average score
|
||||
ui::Label * averageScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(70, 15), "Average Score:");
|
||||
ui::Label * averageScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(72, 15), "Average Score:");
|
||||
averageScoreTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
averageScoreTitle->SetTextColour(ui::Colour(180, 180, 180));
|
||||
scrollPanel->AddChild(averageScoreTitle);
|
||||
|
||||
ui::Label *averageScore = new ui::Label(ui::Point(12+averageScoreTitle->Size.X, currentY), ui::Point(Size.X-averageScoreTitle->Size.X-16, 15), String::Build(info.averageScore));
|
||||
ui::Label *averageScore = new ui::Label(ui::Point(13+averageScoreTitle->Size.X, currentY), ui::Point(Size.X-averageScoreTitle->Size.X-24, 15), String::Build(info.averageScore));
|
||||
averageScore->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
scrollPanel->AddChild(averageScore);
|
||||
currentY += averageScore->Size.Y;
|
||||
|
||||
// highest score
|
||||
ui::Label * highestScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(69, 15), "Highest Score:");
|
||||
ui::Label * highestScoreTitle = new ui::Label(ui::Point(12, currentY), ui::Point(71, 15), "Highest Score:");
|
||||
highestScoreTitle->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
highestScoreTitle->SetTextColour(ui::Colour(180, 180, 180));
|
||||
scrollPanel->AddChild(highestScoreTitle);
|
||||
|
||||
ui::Label *highestScore = new ui::Label(ui::Point(12+highestScoreTitle->Size.X, currentY), ui::Point(Size.X-highestScoreTitle->Size.X-16, 15), String::Build(info.highestScore));
|
||||
ui::Label *highestScore = new ui::Label(ui::Point(13+highestScoreTitle->Size.X, currentY), ui::Point(Size.X-highestScoreTitle->Size.X-24, 15), String::Build(info.highestScore));
|
||||
highestScore->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
scrollPanel->AddChild(highestScore);
|
||||
currentY += 2+highestScore->Size.Y;
|
||||
|
@ -79,6 +79,7 @@ ServerSaveActivity::ServerSaveActivity(std::unique_ptr<SaveInfo> newSave, OnUplo
|
||||
nameField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||
nameField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
nameField->SetActionCallback({ [this] { CheckName(nameField->GetText()); } });
|
||||
nameField->SetLimit(50);
|
||||
AddComponent(nameField);
|
||||
FocusComponent(nameField);
|
||||
|
||||
|
@ -136,6 +136,32 @@ void SearchController::SetPageRelative(int offset)
|
||||
searchModel->UpdateSaveList(page, searchModel->GetLastQuery());
|
||||
}
|
||||
|
||||
void SearchController::ChangePeriod(int period)
|
||||
{
|
||||
switch(period)
|
||||
{
|
||||
case 0:
|
||||
searchModel->SetPeriod(http::allSaves);
|
||||
break;
|
||||
case 1:
|
||||
searchModel->SetPeriod(http::todaySaves);
|
||||
break;
|
||||
case 2:
|
||||
searchModel->SetPeriod(http::weekSaves);
|
||||
break;
|
||||
case 3:
|
||||
searchModel->SetPeriod(http::monthSaves);
|
||||
break;
|
||||
case 4:
|
||||
searchModel->SetPeriod(http::yearSaves);
|
||||
break;
|
||||
default:
|
||||
searchModel->SetPeriod(http::allSaves);
|
||||
}
|
||||
|
||||
searchModel->UpdateSaveList(1, searchModel->GetLastQuery());
|
||||
}
|
||||
|
||||
void SearchController::ChangeSort()
|
||||
{
|
||||
if(searchModel->GetSort() == http::sortByDate)
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
void Refresh();
|
||||
void SetPage(int page);
|
||||
void SetPageRelative(int offset);
|
||||
void ChangePeriod(int period);
|
||||
void ChangeSort();
|
||||
void ShowOwn(bool show);
|
||||
void ShowFavourite(bool show);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <cmath>
|
||||
|
||||
SearchModel::SearchModel():
|
||||
currentPeriod(http::allSaves),
|
||||
currentSort(http::sortByVotes),
|
||||
currentPage(1),
|
||||
resultCount(0),
|
||||
@ -30,11 +31,11 @@ bool SearchModel::GetShowTags()
|
||||
return showTags;
|
||||
}
|
||||
|
||||
void SearchModel::BeginSearchSaves(int start, int count, String query, http::Sort sort, http::Category category)
|
||||
void SearchModel::BeginSearchSaves(int start, int count, String query, http::Period period, http::Sort sort, http::Category category)
|
||||
{
|
||||
lastError = "";
|
||||
resultCount = 0;
|
||||
searchSaves = std::make_unique<http::SearchSavesRequest>(start, count, query.ToUtf8(), sort, category);
|
||||
searchSaves = std::make_unique<http::SearchSavesRequest>(start, count, query.ToUtf8(), period, sort, category);
|
||||
searchSaves->Start();
|
||||
}
|
||||
|
||||
@ -95,7 +96,7 @@ bool SearchModel::UpdateSaveList(int pageNumber, String query)
|
||||
//resultCount = 0;
|
||||
currentPage = pageNumber;
|
||||
|
||||
if(pageNumber == 1 && !showOwn && !showFavourite && currentSort == http::sortByVotes && query == "")
|
||||
if(pageNumber == 1 && !showOwn && !showFavourite && currentPeriod == http::allSaves && currentSort == http::sortByVotes && query == "")
|
||||
SetShowTags(true);
|
||||
else
|
||||
SetShowTags(false);
|
||||
@ -120,7 +121,7 @@ bool SearchModel::UpdateSaveList(int pageNumber, String query)
|
||||
{
|
||||
category = http::categoryMyOwn;
|
||||
}
|
||||
BeginSearchSaves((currentPage-1)*20, 20, lastQuery, currentSort, category);
|
||||
BeginSearchSaves((currentPage-1)*20, 20, lastQuery, currentPeriod, currentSort, category);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -178,6 +179,7 @@ void SearchModel::AddObserver(SearchView * observer)
|
||||
observers.push_back(observer);
|
||||
observer->NotifySaveListChanged(this);
|
||||
observer->NotifyPageChanged(this);
|
||||
observer->NotifyPeriodChanged(this);
|
||||
observer->NotifySortChanged(this);
|
||||
observer->NotifyShowOwnChanged(this);
|
||||
observer->NotifyTagListChanged(this);
|
||||
@ -258,6 +260,15 @@ void SearchModel::notifyPageChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void SearchModel::notifyPeriodChanged()
|
||||
{
|
||||
for (size_t i = 0; i < observers.size(); i++)
|
||||
{
|
||||
SearchView* cObserver = observers[i];
|
||||
cObserver->NotifyPeriodChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
void SearchModel::notifySortChanged()
|
||||
{
|
||||
for (size_t i = 0; i < observers.size(); i++)
|
||||
@ -296,7 +307,7 @@ void SearchModel::notifySelectedChanged()
|
||||
|
||||
int SearchModel::GetPageCount()
|
||||
{
|
||||
if (!showOwn && !showFavourite && currentSort == http::sortByVotes && lastQuery == "")
|
||||
if (!showOwn && !showFavourite && currentPeriod == http::allSaves && currentSort == http::sortByVotes && lastQuery == "")
|
||||
return std::max(1, (int)(ceil(resultCount/20.0f))+1); //add one for front page (front page saves are repeated twice)
|
||||
else
|
||||
return std::max(1, (int)(ceil(resultCount/20.0f)));
|
||||
|
@ -18,7 +18,7 @@ class SearchModel
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<http::SearchSavesRequest> searchSaves;
|
||||
void BeginSearchSaves(int start, int count, String query, http::Sort sort, http::Category category);
|
||||
void BeginSearchSaves(int start, int count, String query, http::Period period, http::Sort sort, http::Category category);
|
||||
std::vector<std::unique_ptr<SaveInfo>> EndSearchSaves();
|
||||
|
||||
void BeginGetTags(int start, int count, String query);
|
||||
@ -26,6 +26,7 @@ private:
|
||||
std::unique_ptr<http::SearchTagsRequest> getTags;
|
||||
|
||||
std::unique_ptr<SaveInfo> loadedSave;
|
||||
http::Period currentPeriod;
|
||||
http::Sort currentSort;
|
||||
String lastQuery;
|
||||
String lastError;
|
||||
@ -42,6 +43,7 @@ private:
|
||||
void notifyTagListChanged();
|
||||
void notifySelectedChanged();
|
||||
void notifyPageChanged();
|
||||
void notifyPeriodChanged();
|
||||
void notifySortChanged();
|
||||
void notifyShowOwnChanged();
|
||||
void notifyShowFavouriteChanged();
|
||||
@ -61,6 +63,8 @@ public:
|
||||
int GetPageCount();
|
||||
int GetPageNum() { return currentPage; }
|
||||
String GetLastQuery() { return lastQuery; }
|
||||
void SetPeriod(http::Period period) { if(!searchSaves) { currentPeriod = period; } notifyPeriodChanged(); }
|
||||
http::Period GetPeriod() { return currentPeriod; }
|
||||
void SetSort(http::Sort sort) { if(!searchSaves) { currentSort = sort; } notifySortChanged(); }
|
||||
http::Sort GetSort() { return currentSort; }
|
||||
void SetShowOwn(bool show) { if(!searchSaves) { if(show!=showOwn) { showOwn = show; } } notifyShowOwnChanged(); }
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "gui/interface/RichLabel.h"
|
||||
#include "gui/interface/Textbox.h"
|
||||
#include "gui/interface/Spinner.h"
|
||||
#include "gui/interface/DropDown.h"
|
||||
#include "PowderToySDL.h"
|
||||
#include "graphics/Graphics.h"
|
||||
#include "SimulationConfig.h"
|
||||
@ -43,13 +44,25 @@ SearchView::SearchView():
|
||||
AddComponent(pageCountLabel);
|
||||
AddComponent(pageTextbox);
|
||||
|
||||
searchField = new ui::Textbox(ui::Point(60, 10), ui::Point(WINDOWW-238, 17), "", "[search]");
|
||||
searchField = new ui::Textbox(ui::Point(60, 10), ui::Point(WINDOWW-283, 17), "", "[search]");
|
||||
searchField->Appearance.icon = IconSearch;
|
||||
searchField->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
searchField->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||
searchField->SetActionCallback({ [this] { doSearch(); } });
|
||||
searchField->SetLimit(100);
|
||||
FocusComponent(searchField);
|
||||
|
||||
dateRange = new ui::DropDown(ui::Point(WINDOWW-185, 10), ui::Point(36, 17));
|
||||
dateRange->SetActionCallback({ [this] { c->ChangePeriod(dateRange->GetOption().second); } });
|
||||
dateRange->AddOption({"All", 0});
|
||||
dateRange->AddOption({"Day", 1});
|
||||
dateRange->AddOption({"Week", 2});
|
||||
dateRange->AddOption({"Month", 3});
|
||||
dateRange->AddOption({"Year", 4});
|
||||
dateRange->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
|
||||
dateRange->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||
AddComponent(dateRange);
|
||||
|
||||
sortButton = new ui::Button(ui::Point(WINDOWW-140, 10), ui::Point(61, 17), "Sort");
|
||||
sortButton->SetIcon(IconVoteSort);
|
||||
sortButton->SetTogglable(true);
|
||||
@ -201,6 +214,11 @@ void SearchView::Search(String query)
|
||||
c->DoSearch(query, true);
|
||||
}
|
||||
|
||||
void SearchView::NotifyPeriodChanged(SearchModel * sender)
|
||||
{
|
||||
dateRange->SetOption(sender->GetPeriod());
|
||||
}
|
||||
|
||||
void SearchView::NotifySortChanged(SearchModel * sender)
|
||||
{
|
||||
if(sender->GetSort() == http::sortByVotes)
|
||||
@ -489,7 +507,7 @@ void SearchView::NotifySaveListChanged(SearchModel * sender)
|
||||
loadingSpinner->Visible = false;
|
||||
if (!errorLabel)
|
||||
{
|
||||
errorLabel = new ui::Label(ui::Point((WINDOWW/2)-100, (WINDOWH/2)-6), ui::Point(200, 12), "Error");
|
||||
errorLabel = new ui::Label(ui::Point(0, (WINDOWH/2)-6), ui::Point(WINDOWW, 12), "Error");
|
||||
AddComponent(errorLabel);
|
||||
}
|
||||
if (!sender->GetSavesLoaded())
|
||||
|
@ -11,6 +11,7 @@ namespace ui
|
||||
class Label;
|
||||
class Spinner;
|
||||
class Textbox;
|
||||
class DropDown;
|
||||
}
|
||||
|
||||
class SearchModel;
|
||||
@ -32,6 +33,7 @@ private:
|
||||
ui::Label * pageCountLabel;
|
||||
ui::Label * tagsLabel;
|
||||
ui::RichLabel * motdLabel = nullptr;
|
||||
ui::DropDown * dateRange;
|
||||
ui::Button * sortButton;
|
||||
ui::Button * ownButton;
|
||||
ui::Spinner * loadingSpinner;
|
||||
@ -52,6 +54,7 @@ public:
|
||||
void NotifySaveListChanged(SearchModel * sender);
|
||||
void NotifySelectedChanged(SearchModel * sender);
|
||||
void NotifyPageChanged(SearchModel * sender);
|
||||
void NotifyPeriodChanged(SearchModel * sender);
|
||||
void NotifySortChanged(SearchModel * sender);
|
||||
void NotifyShowOwnChanged(SearchModel * sender);
|
||||
void NotifyShowFavouriteChanged(SearchModel * sender);
|
||||
|
@ -30,6 +30,7 @@ TagsView::TagsView():
|
||||
tagInput->Appearance.icon = IconTag;
|
||||
tagInput->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
tagInput->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||
tagInput->SetLimit(16);
|
||||
AddComponent(tagInput);
|
||||
FocusComponent(tagInput);
|
||||
|
||||
|
@ -856,7 +856,7 @@ void LuaElements::Open(lua_State *L)
|
||||
LCONST(TYPE_GAS);
|
||||
LCONST(TYPE_ENERGY);
|
||||
LCONST(PROP_CONDUCTS);
|
||||
LCONST(PROP_BLACK);
|
||||
LCONST(PROP_PHOTPASS);
|
||||
LCONST(PROP_NEUTPENETRATE);
|
||||
LCONST(PROP_NEUTABSORB);
|
||||
LCONST(PROP_NEUTPASS);
|
||||
|
@ -50,7 +50,10 @@ static int beginMessageBox(lua_State *L)
|
||||
auto message = PickIfType(L, 2, String("Message"));
|
||||
auto large = PickIfType(L, 3, false);
|
||||
auto cb = std::make_shared<LuaSmartRef>(); // * Bind to main lua state (might be different from L).
|
||||
cb->Assign(L, lua_gettop(L));
|
||||
if (lua_gettop(L))
|
||||
{
|
||||
cb->Assign(L, lua_gettop(L));
|
||||
}
|
||||
new InformationMessage(title, message, large, { [cb]() {
|
||||
auto *lsi = GetLSI();
|
||||
auto L = lsi->L;
|
||||
@ -74,7 +77,10 @@ static int beginThrowError(lua_State *L)
|
||||
{
|
||||
auto errorMessage = PickIfType(L, 1, String("Error text"));
|
||||
auto cb = std::make_shared<LuaSmartRef>(); // * Bind to main lua state (might be different from L).
|
||||
cb->Assign(L, lua_gettop(L));
|
||||
if (lua_gettop(L))
|
||||
{
|
||||
cb->Assign(L, lua_gettop(L));
|
||||
}
|
||||
new ErrorMessage("Error", errorMessage, { [cb]() {
|
||||
auto *lsi = GetLSI();
|
||||
auto L = lsi->L;
|
||||
@ -101,7 +107,10 @@ static int beginInput(lua_State *L)
|
||||
auto text = PickIfType(L, 3, String(""));
|
||||
auto shadow = PickIfType(L, 4, String(""));
|
||||
auto cb = std::make_shared<LuaSmartRef>(); // * Bind to main lua state (might be different from L).
|
||||
cb->Assign(L, lua_gettop(L));
|
||||
if (lua_gettop(L))
|
||||
{
|
||||
cb->Assign(L, lua_gettop(L));
|
||||
}
|
||||
auto handle = [cb](std::optional<String> input) {
|
||||
auto *lsi = GetLSI();
|
||||
auto L = lsi->L;
|
||||
@ -140,7 +149,10 @@ static int beginConfirm(lua_State *L)
|
||||
auto message = PickIfType(L, 2, String("Message"));
|
||||
auto buttonText = PickIfType(L, 3, String("Confirm"));
|
||||
auto cb = std::make_shared<LuaSmartRef>(); // * Bind to main lua state (might be different from L).
|
||||
cb->Assign(L, lua_gettop(L));
|
||||
if (lua_gettop(L))
|
||||
{
|
||||
cb->Assign(L, lua_gettop(L));
|
||||
}
|
||||
auto handle = [cb](int result) {
|
||||
auto *lsi = GetLSI();
|
||||
auto L = lsi->L;
|
||||
|
@ -9,6 +9,7 @@ elem.FLAG_MOVABLE = sim.FLAG_MOVABLE
|
||||
elem.FLAG_PHOTDECO = sim.FLAG_PHOTDECO
|
||||
elem.FLAG_SKIPMOVE = sim.FLAG_SKIPMOVE
|
||||
elem.FLAG_STAGNANT = sim.FLAG_STAGNANT
|
||||
elem.PROP_BLACK = 0
|
||||
elem.PROP_DRAWONCTYPE = 0
|
||||
elem.ST_GAS = 0
|
||||
elem.ST_LIQUID = 0
|
||||
|
@ -20,6 +20,11 @@ void Prefs::Read()
|
||||
Json::CharReaderBuilder rbuilder;
|
||||
std::unique_ptr<Json::CharReader> const reader(rbuilder.newCharReader());
|
||||
ByteString errs;
|
||||
if (!data.size())
|
||||
{
|
||||
std::cerr << "no json data" << std::endl;
|
||||
return;
|
||||
}
|
||||
if (!reader->parse(&data[0], &data[0] + data.size(), &root, &errs))
|
||||
{
|
||||
std::cerr << errs << std::endl;
|
||||
|
@ -17,7 +17,7 @@ constexpr auto TYPE_GAS = UINT32_C(0x00000008); //8 Gases (Includes p
|
||||
constexpr auto TYPE_ENERGY = UINT32_C(0x00000010); //16 Energy (Thunder, Light, Neutrons etc.)
|
||||
constexpr auto STATE_FLAGS = UINT32_C(0x0000001F);
|
||||
constexpr auto PROP_CONDUCTS = UINT32_C(0x00000020); //32 Conducts electricity
|
||||
constexpr auto PROP_BLACK = UINT32_C(0x00000040); //64 Absorbs Photons (not currently implemented or used, a photwl attribute might be better)
|
||||
constexpr auto PROP_PHOTPASS = UINT32_C(0x00000040); //64 Photons pass through (may refract as in glass)
|
||||
constexpr auto PROP_NEUTPENETRATE = UINT32_C(0x00000080); //128 Penetrated by neutrons
|
||||
constexpr auto PROP_NEUTABSORB = UINT32_C(0x00000100); //256 Absorbs neutrons, reflect is default
|
||||
constexpr auto PROP_NEUTPASS = UINT32_C(0x00000200); //512 Neutrons pass through, such as with glass
|
||||
|
@ -186,16 +186,14 @@ void SimulationData::init_can_move()
|
||||
if (elements[movingType].Properties & TYPE_PART)
|
||||
can_move[movingType][PT_SAWD] = 0;
|
||||
}
|
||||
//a list of lots of things PHOT can move through
|
||||
// TODO: replace with property
|
||||
|
||||
for (destinationType = 0; destinationType < PT_NUM; destinationType++)
|
||||
{
|
||||
if (destinationType == PT_GLAS || destinationType == PT_PHOT || destinationType == PT_FILT || destinationType == PT_INVIS
|
||||
|| destinationType == PT_CLNE || destinationType == PT_PCLN || destinationType == PT_BCLN || destinationType == PT_PBCN
|
||||
|| destinationType == PT_WATR || destinationType == PT_DSTW || destinationType == PT_SLTW || destinationType == PT_GLOW
|
||||
|| destinationType == PT_ISOZ || destinationType == PT_ISZS || destinationType == PT_QRTZ || destinationType == PT_PQRT
|
||||
|| destinationType == PT_H2 || destinationType == PT_BGLA || destinationType == PT_C5 || destinationType == PT_RSST)
|
||||
//a list of lots of things PHOT can move through
|
||||
if (elements[destinationType].Properties & PROP_PHOTPASS)
|
||||
can_move[PT_PHOT][destinationType] = 2;
|
||||
|
||||
//Things PROT and GRVT cannot move through
|
||||
if (destinationType != PT_DMND && destinationType != PT_INSL && destinationType != PT_VOID && destinationType != PT_PVOD && destinationType != PT_VIBR && destinationType != PT_BVBR && destinationType != PT_PRTI && destinationType != PT_PRTO)
|
||||
{
|
||||
can_move[PT_PROT][destinationType] = 2;
|
||||
|
@ -31,7 +31,7 @@ void Element::Element_BCLN()
|
||||
HeatConduct = 251;
|
||||
Description = "Breakable Clone.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_LIFE_DEC | PROP_LIFE_KILL_DEC | PROP_NOCTYPEDRAW;
|
||||
Properties = TYPE_SOLID | PROP_PHOTPASS | PROP_LIFE_DEC | PROP_LIFE_KILL_DEC | PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
|
@ -29,7 +29,7 @@ void Element::Element_BGLA()
|
||||
HeatConduct = 150;
|
||||
Description = "Broken Glass, heavy particles formed when glass breaks under pressure. Meltable. Bagels.";
|
||||
|
||||
Properties = TYPE_PART | PROP_NEUTPASS | PROP_HOT_GLOW;
|
||||
Properties = TYPE_PART | PROP_NEUTPASS | PROP_PHOTPASS | PROP_HOT_GLOW;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -32,7 +32,7 @@ void Element::Element_C5()
|
||||
HeatConduct = 88;
|
||||
Description = "Cold explosive, set off by anything cold.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NEUTPENETRATE | PROP_LIFE_DEC;
|
||||
Properties = TYPE_SOLID | PROP_NEUTPENETRATE | PROP_PHOTPASS | PROP_LIFE_DEC;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -31,7 +31,7 @@ void Element::Element_CLNE()
|
||||
HeatConduct = 251;
|
||||
Description = "Clone. Duplicates any particles it touches.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NOCTYPEDRAW;
|
||||
Properties = TYPE_SOLID | PROP_PHOTPASS | PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
|
@ -33,7 +33,7 @@ void Element::Element_DSTW()
|
||||
LatentHeat = 7500;
|
||||
Description = "Distilled water, does not conduct electricity.";
|
||||
|
||||
Properties = TYPE_LIQUID|PROP_NEUTPASS;
|
||||
Properties = TYPE_LIQUID | PROP_NEUTPASS | PROP_PHOTPASS;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -33,7 +33,7 @@ void Element::Element_FILT()
|
||||
HeatConduct = 251;
|
||||
Description = "Filter for photons, changes the color.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NOAMBHEAT | PROP_LIFE_DEC;
|
||||
Properties = TYPE_SOLID | PROP_PHOTPASS | PROP_NOAMBHEAT | PROP_LIFE_DEC;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -32,7 +32,7 @@ void Element::Element_GLAS()
|
||||
HeatConduct = 150;
|
||||
Description = "Glass. Meltable. Shatters under pressure, and refracts photons.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NEUTPASS | PROP_HOT_GLOW | PROP_SPARKSETTLE;
|
||||
Properties = TYPE_SOLID | PROP_NEUTPASS | PROP_PHOTPASS | PROP_HOT_GLOW | PROP_SPARKSETTLE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -33,7 +33,7 @@ void Element::Element_GLOW()
|
||||
HeatConduct = 44;
|
||||
Description = "Glow, Glows under pressure.";
|
||||
|
||||
Properties = TYPE_LIQUID | PROP_LIFE_DEC;
|
||||
Properties = TYPE_LIQUID | PROP_PHOTPASS | PROP_LIFE_DEC;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
@ -59,17 +59,21 @@ static int update(UPDATE_FUNC_ARGS)
|
||||
auto r = pmap[y+ry][x+rx];
|
||||
if (!r)
|
||||
continue;
|
||||
|
||||
if (TYP(r)==PT_WATR && sim->rng.chance(1, 400))
|
||||
{
|
||||
sim->kill_part(i);
|
||||
sim->part_change_type(ID(r),x+rx,y+ry,PT_DEUT);
|
||||
parts[ID(r)].life = 10;
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (TYP(r) == PT_GEL) //GLOW + GEL = RSST
|
||||
{
|
||||
sim->kill_part(i);
|
||||
sim->part_change_type(ID(r),x+rx,y+ry,PT_RSST);
|
||||
parts[ID(r)].tmp = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ void Element::Element_H2()
|
||||
HeatConduct = 251;
|
||||
Description = "Hydrogen. Combusts with OXYG to make WATR. Undergoes fusion at high temperature and pressure.";
|
||||
|
||||
Properties = TYPE_GAS;
|
||||
Properties = TYPE_GAS | PROP_PHOTPASS;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -34,6 +34,7 @@ void Element::Element_ICEI()
|
||||
Description = "Crushes under pressure. Cools down air.";
|
||||
|
||||
Properties = TYPE_SOLID|PROP_LIFE_DEC|PROP_NEUTPASS;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -32,7 +32,7 @@ void Element::Element_INVIS()
|
||||
HeatConduct = 164;
|
||||
Description = "Invisible to particles while under pressure.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NEUTPASS;
|
||||
Properties = TYPE_SOLID | PROP_NEUTPASS | PROP_PHOTPASS;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -32,7 +32,7 @@ void Element::Element_ISOZ()
|
||||
HeatConduct = 29;
|
||||
Description = "Isotope-Z. Radioactive liquid, decays into photons when touching PHOT or under negative pressure.";
|
||||
|
||||
Properties = TYPE_LIQUID|PROP_NEUTPENETRATE;
|
||||
Properties = TYPE_LIQUID | PROP_NEUTPENETRATE | PROP_PHOTPASS;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -32,7 +32,7 @@ void Element::Element_ISZS()
|
||||
HeatConduct = 251;
|
||||
Description = "Solid form of ISOZ, slowly decays into PHOT.";
|
||||
|
||||
Properties = TYPE_SOLID;
|
||||
Properties = TYPE_SOLID | PROP_PHOTPASS;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -54,6 +54,8 @@ void Element::Element_NEUT()
|
||||
|
||||
static int update(UPDATE_FUNC_ARGS)
|
||||
{
|
||||
auto &sd = SimulationData::CRef();
|
||||
auto &elements = sd.elements;
|
||||
unsigned int pressureFactor = 3 + (int)sim->pv[y/CELL][x/CELL];
|
||||
for (int rx = -1; rx <= 1; rx++)
|
||||
{
|
||||
@ -178,7 +180,7 @@ static int update(UPDATE_FUNC_ARGS)
|
||||
sim->create_part(ID(r), x, y, ct_under);
|
||||
|
||||
//If there's a correct tmp set, use it for ctype
|
||||
if(tmp_under > 0 && ct_under < PT_NUM)
|
||||
if((tmp_under > 0) && (tmp_under < PT_NUM) && (elements[ct_under].CarriesTypeIn & (1U << FIELD_CTYPE)))
|
||||
parts[ID(r)].ctype = tmp_under;
|
||||
}
|
||||
else
|
||||
|
@ -33,7 +33,7 @@ void Element::Element_PBCN()
|
||||
HeatConduct = 251;
|
||||
Description = "Powered breakable clone.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NOCTYPEDRAW;
|
||||
Properties = TYPE_SOLID | PROP_PHOTPASS | PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
|
@ -33,7 +33,7 @@ void Element::Element_PCLN()
|
||||
HeatConduct = 251;
|
||||
Description = "Powered clone. When activated, duplicates any particles it touches.";
|
||||
|
||||
Properties = TYPE_SOLID | PROP_NOCTYPEDRAW;
|
||||
Properties = TYPE_SOLID | PROP_PHOTPASS | PROP_NOCTYPEDRAW;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
|
@ -36,7 +36,7 @@ void Element::Element_PHOT()
|
||||
HeatConduct = 251;
|
||||
Description = "Photons. Refracts through glass, scattered by quartz, and color-changed by different elements. Ignites flammable materials.";
|
||||
|
||||
Properties = TYPE_ENERGY|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC;
|
||||
Properties = TYPE_ENERGY | PROP_PHOTPASS | PROP_LIFE_DEC | PROP_LIFE_KILL_DEC;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
@ -57,6 +57,9 @@ void Element::Element_PHOT()
|
||||
|
||||
static int update(UPDATE_FUNC_ARGS)
|
||||
{
|
||||
auto &sd = SimulationData::CRef();
|
||||
auto &elements = sd.elements;
|
||||
|
||||
if (!(parts[i].ctype&0x3FFFFFFF)) {
|
||||
sim->kill_part(i);
|
||||
return 1;
|
||||
@ -121,7 +124,7 @@ static int update(UPDATE_FUNC_ARGS)
|
||||
sim->create_part(ID(r), x, y, ct_under);
|
||||
|
||||
//If there's a correct tmp set, use it for ctype
|
||||
if(tmp_under > 0 && ct_under < PT_NUM)
|
||||
if((tmp_under > 0) && (tmp_under < PT_NUM) && (elements[ct_under].CarriesTypeIn & (1U << FIELD_CTYPE)))
|
||||
parts[ID(r)].ctype = tmp_under;
|
||||
}
|
||||
else
|
||||
|
@ -32,7 +32,7 @@ void Element::Element_PQRT()
|
||||
HeatConduct = 3;
|
||||
Description = "Powdered quartz, broken form of QRTZ.";
|
||||
|
||||
Properties = TYPE_PART| PROP_HOT_GLOW;
|
||||
Properties = TYPE_PART | PROP_PHOTPASS | PROP_HOT_GLOW;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -238,7 +238,7 @@ static int update(UPDATE_FUNC_ARGS)
|
||||
break;
|
||||
|
||||
case PT_RSST: // RSST -> BIZR
|
||||
sim->part_change_type(ID(r), x + rx, y + ry, PT_BIZR);
|
||||
sim->create_part(ID(r), x + rx, y + ry, PT_BIZR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ void Element::Element_QRTZ()
|
||||
HeatConduct = 3;
|
||||
Description = "Quartz, breakable mineral. Conducts but becomes brittle at lower temperatures.";
|
||||
|
||||
Properties = TYPE_SOLID|PROP_HOT_GLOW|PROP_LIFE_DEC;
|
||||
Properties = TYPE_SOLID | PROP_PHOTPASS | PROP_HOT_GLOW | PROP_LIFE_DEC;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -33,6 +33,7 @@ void Element::Element_RSSS()
|
||||
Description = "Solidified resist. Blocks pressure and insulates electricity. Liquefies on contact with neutrons.";
|
||||
|
||||
Properties = TYPE_SOLID|PROP_NEUTPASS;
|
||||
CarriesTypeIn = (1U << FIELD_CTYPE) | (1U << FIELD_TMP);
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -32,7 +32,8 @@ void Element::Element_RSST()
|
||||
HeatConduct = 55;
|
||||
Description = "Resist. Solidifies on contact with photons, is destroyed by electrons and spark.";
|
||||
|
||||
Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPASS;
|
||||
Properties = TYPE_LIQUID | PROP_CONDUCTS | PROP_LIFE_DEC | PROP_NEUTPASS | PROP_PHOTPASS;
|
||||
CarriesTypeIn = (1U << FIELD_CTYPE) | (1U << FIELD_TMP);
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
@ -60,7 +61,7 @@ int update(UPDATE_FUNC_ARGS)
|
||||
// RSST + GUNP = FIRW
|
||||
if(TYP(r) == PT_GUNP)
|
||||
{
|
||||
sim->part_change_type(i, x, y, PT_FIRW);
|
||||
sim->create_part(i, x, y, PT_FIRW);
|
||||
sim->kill_part(ID(r));
|
||||
return 1;
|
||||
}
|
||||
@ -68,7 +69,7 @@ int update(UPDATE_FUNC_ARGS)
|
||||
// RSST + BCOL = FSEP
|
||||
if(TYP(r) == PT_BCOL)
|
||||
{
|
||||
sim->part_change_type(i, x, y, PT_FSEP);
|
||||
sim->create_part(i, x, y, PT_FSEP);
|
||||
parts[i].life = 50;
|
||||
sim->kill_part(ID(r));
|
||||
return 1;
|
||||
@ -80,6 +81,13 @@ int update(UPDATE_FUNC_ARGS)
|
||||
if(parts[ID(r)].ctype != PT_RSST)
|
||||
parts[i].ctype = parts[ID(r)].ctype;
|
||||
}
|
||||
|
||||
// Set RSST tmp from nearby breakable clone
|
||||
if((TYP(r) == PT_BCLN) || (TYP(r) == PT_PBCN))
|
||||
{
|
||||
if(parts[ID(r)].ctype != PT_RSST)
|
||||
parts[i].tmp = parts[ID(r)].ctype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ void Element::Element_SLTW()
|
||||
LatentHeat = 7500;
|
||||
Description = "Saltwater, conducts electricity, difficult to freeze.";
|
||||
|
||||
Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPENETRATE;
|
||||
Properties = TYPE_LIQUID | PROP_CONDUCTS | PROP_LIFE_DEC | PROP_NEUTPENETRATE | PROP_PHOTPASS;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -35,6 +35,7 @@ void Element::Element_SNOW()
|
||||
Description = "Light particles. Created when ICE breaks under pressure.";
|
||||
|
||||
Properties = TYPE_PART|PROP_NEUTPASS;
|
||||
CarriesTypeIn = 1U << FIELD_CTYPE;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
@ -33,7 +33,7 @@ void Element::Element_WATR()
|
||||
LatentHeat = 7500;
|
||||
Description = "Water. Conducts electricity, freezes, and extinguishes fires.";
|
||||
|
||||
Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPASS;
|
||||
Properties = TYPE_LIQUID | PROP_CONDUCTS | PROP_LIFE_DEC | PROP_NEUTPASS | PROP_PHOTPASS;
|
||||
|
||||
LowPressure = IPL;
|
||||
LowPressureTransition = NT;
|
||||
|
Reference in New Issue
Block a user