13 Commits

Author SHA1 Message Date
Ethan Lee 391148415c Network: Update to latest Steamworks SDK ABI.
This is mostly to support AArch64.
2026-07-15 10:12:36 -04:00
Ethan Lee 05a5abbfbd CMake: Rework Linux RPATH generation.
This is mostly to fix the AArch64 rpath. i686 will be different after this
change, but I haven't been shipping that architecture for a while now...

Also, took out BIN_LIBROOT which wasn't doing anything, woops!
2026-07-15 10:05:51 -04:00
NyakoFox 8c70c9eb97 Set id and loose_extra fields no matter what
The PR #1278 seems to have introduced a segfault. When an empty music
track is found, it skips past `id` (and `loose_extra`) being set.
Functions which use `id` expect a string, not NULL, causing a crash
whenever `isextra` is called, which happens to be every time the
`music` or `play` commands are invoked.

This fix simply moves the setting of these variables upwards, BEFORE
the valid check, to make sure they're always set.
2026-05-14 18:15:43 -04:00
Dav999 85dae94d2e Avoid compiler warning about signedness mismatch
This warning kept appearing for me:

Script.cpp:350:35: warning: comparison of integer expressions of
different signedness: ‘int’ and
‘std::__cxx11::basic_string<char>::size_type’
{aka ‘long unsigned int’} [-Wsign-compare]

  350 |                 for (int i = 0; i < words[1].size(); i++)
      |                                 ~~^~~~~~~~~~~~~~~~~

So I just made it a size_t instead.
2026-05-14 06:10:52 -04:00
Dav999 08aa7c9087 Remove nuisance Vorbis errors on blank music slots
When vvvvvvmusic.vvv files contain blank slots before the last valid
song, the following error message would be output for all of them:

[ERROR] Unable to create Vorbis handle, error 30

Now, this is very common: many levels, for example, ship a music file
where songs start at slot 16, or alternatively they used slots 0-15 but
didn't need every slot. Or IDs are skipped so that certain songs are
on their own page in the music editor. Either way, I've seen bursts of
this message appear in my console a lot when loading levels lol, so it
became time this was silenced by not bothering to load a <=1 byte song,
and giving a (silenced by default) debug message in that case instead.

(It checks for <= 1 byte, because in all these cases, the empty slots
have a single null byte in them. I looked up why that is again, and it
is because, in 2019, "Rumor goes that 0-byte tracks actually mess
things up in VVVVVV". We could probably verify if that's the case now,
but music files have been made this way for ages, and it's pretty clear
a 1-byte song is not usable.)
2026-05-14 06:10:52 -04:00
NyakoFox 191b989116 Fix double script execution when entering playtesting
`twoframedelayfix()` now gets called in `resetplayer` due to #1258, to
fix the two-frame script delay when you respawn. Unfortunately, there
seems to be some strange bug where starting playtesting in a script box
activates the script twice. While I'm not exactly sure WHY this
happens logic-wise, we can quickly squash this issue by checking if
the player is reset due to dying.
2026-05-07 20:45:23 -04:00
Nyako c02f8e004c Load an unlimited amount of loose music (#1171)
* Load an unlimited amount of loose music

Binary blobs can now store 128 tracks, and music can now be read from
loose files. Unfortunately, the two cannot be used together -- loose
music can still only use 16 tracks. This commit attempts to fix that,
allowing for music playback by filename.

* Rework music track loading

The current "loose songs" system does not load files from custom
assets. This is from the #412 PR, and is NOT the "extra loose songs"
system that this PR implements, but they both work in the same area so
I decided to squash both of these bugs at once (plus, it helped clean
up the code and make a saner system, so...)

This commit also allows "loose music" to override music stored in the
`vvvvvvmusic.vvv` binary blob. When reading a blob, it will first check
if a loose file exists at the current path it's trying to find a track
at; if it exists, it will load that instead. If the blob does not
exist, the system will try to locate all expected built-in tracks
directly from the assets folder instead of doing that during blob
loading.

The `play` command has some safety removed due to an old exploit which
needs to be kept -- `music(5b)` should play track 5. This is used in
many levels and cannot be broken; unfortunately this means that we no
longer get the nice error when a song fails to be played, but that's
better than breaking a large amount of levels.

This commit does NOT address loading a "extra" loose track overtop of
a custom blob track, because with the current tooling, and the way it
will most likely continue to work in the future, every single custom
track in blobs have a completely empty path. If someone decides to
modify their blob in a hex editor or makes their own tooling, this
issue may show up again, but that is a problem which can and probably
should be addressed at a later date. The required code to solve such a
problem would be far more than what this PR should address, and for a
situation so unlikely, it's easy enough to just avoid adding the same
custom song twice, one in a music file, and one loose, because if
you're making a level, you're probably going to use one or the other.

* Fix mentioned issues from review
2026-05-06 19:03:05 -04:00
Ethan Lee ad7e2689be Update to FAudio 26.05 2026-05-05 16:51:13 -04:00
NyakoFox c2a78ba688 Fix two-frame script delay when respawning
At some point, there was some "kludge" added to the game which allowed
script boxes to immediately get triggered when you enter a room, rather
than the update order unfortunately causing scripts to trigger after two
frames.

For some reason, dying and respawning in a room does not have the same
fix, causing really bad inconsistencies for anything that needs precise
timing.

Despite the initial implementation of the kludge being somewhat careless
and breaking levels which relied on timing, this one should not break
anything, but in fact fix things, surprisingly.
2026-05-05 09:16:15 -04:00
NyakoFox 0d69dd3820 Fix audio buffer issues on some platforms
On certain ports of the game, and possibly some Linux distros, the
game's audio would crackle, or slow down with loud buzzing. This commit
attempts to fix that, by enabling `FAUDIO_1024_QUANTUM`, which should
increase the internal FAudio buffer size.
2026-04-30 17:06:30 -04:00
Ally 4e6697352c Add an undoing & redoing system to the editor (#1085)
* Add undoing & redoing to the editor

It's very easy to make mistakes in VVVVVV's built-in level editor, with
no way to undo them. This commit adds an undo and redo system, bound to
CTRL+Z for undo and CTRL+Y for redo. The undo and redo stacks don't
have any limits, but could easily happen in the future. VVVVVV's data
is small enough where this should never be an issue, however.

No notes show up for undoing and redoing, because keeping track of what
specific action you're doing may bloat the system, and would get
annoying for the end-user. Notes are a bit annoying in general, even.

* Add level resizing to undo/redo system

* searchable gettext for undo/redo notes

* A few fixes and cleanup

The main fix was how holding right click to remove tiles did not
commit an action.

* Spikes also need to commit

* Cancelling placing a terminal/script box shouldn't have undo events

* Don't commit tile events if removing entities

* Clear redo buffer on level load

* Remove unneeded pointers from memcpy

* Add strings to lang files

* Fix definition in Editor.h

* Explain double-uncommit

* Don't unconditionally commit tiles on room change

I'm not that sure what I was thinking back then, but switching rooms
would commit tiles no matter what, causing a huge mess. The behavior
was intended to stop the "tile placement" action and commit it, but
just happened no matter what... So this has been fixed, and a few
comments have been added as well.

* Fix mentioned issues & make process_undo static

---------

Co-authored-by: NyakoFox <nyakowofox@gmail.com>
2026-04-25 13:46:01 -04:00
NyakoFox a5e353a0fa Solve render recaching issues
Past solutions were just "recache the screen textures under these known
circumstances" where whenever things OUTSIDE of those known
circumstances happened, the issue would reoccur.

I recently learned about an SDL event, `SDL_RENDER_TARGETS_RESET`,
which is for this exact problem. I ripped out all of the other places
`Screen::recacheTextures()` was called, and just slotted it in there,
and it worked perfectly.

...well, the old behavior worked perfectly; but the old behavior was
flawed as well, because it only checked for "ingame_titlemode" (if
you're in the main menu during gameplay) and forgot to check for the
map screen... plus, it didn't ever regenerate the minimap in custom
levels, which is another "persistant" render target.

Hopefully, this is the last time we'll ever have to think about this
one. I'm certainly sick of it.

This should 100% be backported into 2.4, as the bug occurs there as
well.
2026-04-12 09:09:27 -04:00
NyakoFox 994b3602e5 Clamp editor mouse coordinates
The editor has never clamped mouse bounds, and instead relied on SDL to
return clamped mouse coordinates. Unfortunately, in #1140, this detail
was missed, and the behavior changed, allowing the cursor to leave the
bounds of the screen.

This isn't much of a problem most of the time because anything that
uses position as array indeces has bounds checks. Unfortunately,
placing entities outside of a room's bounds leads to entities you can't
ever touch ever again without modifying the level externally. This is
the worst with checkpoints, as pressing Enter in a room will now take
you to the out-of-bounds checkpoint, causing you to immediately wrap to
another room.

This fix should be backported to 2.4, as the issue can lead to level
files which need manual editing to fix!
2026-04-12 09:08:48 -04:00
39 changed files with 734 additions and 121 deletions
+8 -8
View File
@@ -51,18 +51,18 @@ endif()
# RPATH
if(NOT WIN32)
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
set(BIN_LIBROOT "Frameworks")
set(BIN_RPATH "@executable_path/Frameworks")
elseif(APPLE)
set(BIN_LIBROOT "osx")
set(BIN_RPATH "@executable_path/osx")
elseif(CMAKE_SIZEOF_VOID_P MATCHES "8")
set(BIN_LIBROOT "lib64")
set(BIN_RPATH "\$ORIGIN/lib64")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--disable-new-dtags")
else()
set(BIN_LIBROOT "lib")
set(BIN_RPATH "\$ORIGIN/lib")
SET(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-Wl,--disable-new-dtags")
if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
# Naming quirk for backward compatibility
SET(BIN_RPATH "\$ORIGIN/lib64")
else()
SET(BIN_RPATH "\$ORIGIN/lib${CMAKE_SYSTEM_PROCESSOR}")
endif()
endif()
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
+2
View File
@@ -646,6 +646,8 @@
<string english="Enemy Type Changed" translation="تغير نوع الأعداء" explanation="level editor, user changed enemy appearance for the room" max="38*3" max_local="38*3"/>
<string english="Platform speed is now {speed}" translation="تغيرت سرعة المنصات إلى {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3" max_local="38*3"/>
<string english="Enemy speed is now {speed}" translation="تغيرت سرعة الأعداء إلى {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3" max_local="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3" max_local="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3" max_local="38*3"/>
<string english="Reloaded resources" translation="أعيد فتح ملفات الموارد" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3" max_local="38*3"/>
<string english="ERROR: Invalid format" translation="خطأ: صيغة المكتوب غير مناسبة" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3" max_local="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="فتحت الغرفة: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3" max_local="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Sha canviat el tipus denemic" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="La velocitat de les plataformes és ara {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="La velocitat dels enemics és ara {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Shan recarregat els recursos" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="ERROR: Format invàlid" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Sha obert el mapa: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Newidiodd Math y Gelyn" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Cyflymder llwyfan yw {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Cyflymder y gelyn yw {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Adnoddau wedi&apos;u hail-lwytho" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="GWALL: Fformat annilys" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Map wedi&apos;i lwytho: {filename}.vvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Feindtyp geändert" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Plattformgeschwindigkeit ist jetzt {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Feindgeschwindigkeit ist jetzt {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Ressourcen neu geladen" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="FEHLER: ungültiges Format" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Karte geladen: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Malamika tipo ŝanĝiĝis" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Platforma rapido nun estas {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Malamika rapido nun estas {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Resursoj reŝargiĝis" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="ERARO: malĝusta formo" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Ŝargiĝis mapo: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Tipo de enemigo cambiado" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="La velocidad plataforma es {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Velocidad del enemigo en {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Recursos recargados" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="ERROR: Formato no válido" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Mapa cargado: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Tipo de enemigo cambiado" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Velocidad de las plataformas: {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Velocidad de los enemigos: {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Recursos recargados" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="ERROR: Formato no válido" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Mapa cargado: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Tipo de enemigo cambiado" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Velocidad de las plataformas: {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Velocidad de los enemigos: {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Recursos recargados" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="ERROR: Formato no válido" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Mapa cargado: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="نوع دشمن تغییر کرد" explanation="level editor, user changed enemy appearance for the room" max="38*3" max_local="38*3"/>
<string english="Platform speed is now {speed}" translation="سرعت سکو اکنون برابر با {speed} است" explanation="level editor, user changed speed of platforms for the room" max="38*3" max_local="38*3"/>
<string english="Enemy speed is now {speed}" translation="سرعت دشمن اکنون برابر با {speed} است" explanation="level editor, user changed speed of enemies for the room" max="38*3" max_local="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3" max_local="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3" max_local="38*3"/>
<string english="Reloaded resources" translation="بارگذاری مجدد منابع" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3" max_local="38*3"/>
<string english="ERROR: Invalid format" translation="خطا: فرمت اشتباه" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3" max_local="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="نقشه‌ی بارگذاری شده {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3" max_local="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Type d&apos;ennemis modifié" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Vitesse des plateformes réglée sur {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Vitesse des ennemis réglée sur {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Recharger les ressources" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="ERREUR : format invalide" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Carte chargée : {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -640,6 +640,8 @@ Déan cóip chúltaca, ar eagla na heagla." explanation="translation maintenance
<string english="Enemy Type Changed" translation="Athraíodh Cineál Naimhde" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Luas na n-ardán {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Luas na naimhde {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Athlódáladh acmhainní" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="EARRÁID: Formáid Neamhbhailí" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Mapa lódáilte: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Tipo di nemico cambiato" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="La velocità piattaforma ora è {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="La velocità dei nemici è ora {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Risorse ricaricate" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="ERRORE: Formato non valido" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Mappa caricata: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -674,6 +674,8 @@ Steam Deckには対応していません。" explanation="" max="38*5" max_local
<string english="Enemy Type Changed" translation="敵の種類を変更しました" explanation="level editor, user changed enemy appearance for the room" max="38*3" max_local="38*2"/>
<string english="Platform speed is now {speed}" translation="プラットフォームの速度を {speed} に変更しました" explanation="level editor, user changed speed of platforms for the room" max="38*3" max_local="38*2"/>
<string english="Enemy speed is now {speed}" translation="敵のスピードを {speed} に変更しました" explanation="level editor, user changed speed of enemies for the room" max="38*3" max_local="38*2"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3" max_local="38*2"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3" max_local="38*2"/>
<string english="Reloaded resources" translation="リソースを再読み込みしました" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3" max_local="38*2"/>
<string english="ERROR: Invalid format" translation="エラー: 無効な記述形式" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3" max_local="38*2"/>
<string english="Loaded map: {filename}.vvvvvv" translation="{filename}.vvvvvv をロードしました" explanation="successfully loaded level file" max="38*3" max_local="38*2"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="적 종류 변경됨" explanation="level editor, user changed enemy appearance for the room" max="38*3" max_local="30*3"/>
<string english="Platform speed is now {speed}" translation="플랫폼 속도 현재 {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3" max_local="30*3"/>
<string english="Enemy speed is now {speed}" translation="적의 속도 현재 {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3" max_local="30*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3" max_local="30*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3" max_local="30*3"/>
<string english="Reloaded resources" translation="자원 다시 불러오기" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3" max_local="30*3"/>
<string english="ERROR: Invalid format" translation="오류: 이용 불가능한 포맷" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3" max_local="30*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="불러온 지도: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3" max_local="30*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Vijandtype aangepast" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Platformsnelheid is nu {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Vijandsnelheid is nu {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Bronnen opnieuw geladen" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="FOUT: Ongeldig formaat" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Level geladen: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Zmieniono Typ Wroga" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Prędkość platformy: {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Prędkość przeciwników: {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Załadowano zasoby ponownie" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="BŁĄD: Niewłaściwy format" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Wczytano poziom: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="O tipo de inimigo foi alterado" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="A velocidade da plataforma agora é {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="A velocidade do inimigo agora é {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Recursos recarregados" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="ERRO: formato inválido" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Mapa carregado: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Tipo de inimigo alterado" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Velocidade atual da plataforma: {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Velocidade dos inimigos: {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Recursos recarregados" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="ERRO: Formato inválido" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Mapa carregado: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -663,6 +663,8 @@
<string english="Enemy Type Changed" translation="Тип врагов изменён" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Установлена скорость платформ {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Установлена скорость врагов {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Ресурсы перезагружены" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="ОШИБКА: Недопустимый формат" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Карта загружена: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Zmiyniōno Zorta Niyprzŏciela" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Gibkoś platformy: {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Gibkoś ôpacznikōw: {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Nafolowano zasoby drugi rŏz" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="FELER: Felerny format" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Nafolowano poziōm: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Düşman Türü Değişti" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Platform hızı: {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Şu anki düşman hızı: {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Kaynaklar tekrar yüklendi" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="HATA: Geçersiz format" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Yüklenen harita: {dosyaadi}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -638,6 +638,8 @@
<string english="Enemy Type Changed" translation="Тип ворога змінено" explanation="level editor, user changed enemy appearance for the room" max="38*3"/>
<string english="Platform speed is now {speed}" translation="Тепер швидкість платформи {speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3"/>
<string english="Enemy speed is now {speed}" translation="Тепер швидкість ворога {speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3"/>
<string english="Reloaded resources" translation="Ресурси перезавантажено" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3"/>
<string english="ERROR: Invalid format" translation="ПОМИЛКА: Неприпустимий формат" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3"/>
<string english="Loaded map: {filename}.vvvvvv" translation="Завантажено мапу: {filename}.vvvvvv" explanation="successfully loaded level file" max="38*3"/>
+2
View File
@@ -648,6 +648,8 @@
<string english="Enemy Type Changed" translation="敌人类型已改变" explanation="level editor, user changed enemy appearance for the room" max="38*3" max_local="25*2"/>
<string english="Platform speed is now {speed}" translation="平台速度现在为{speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3" max_local="25*2"/>
<string english="Enemy speed is now {speed}" translation="敌人速度现在为{speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3" max_local="25*2"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3" max_local="25*2"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3" max_local="25*2"/>
<string english="Reloaded resources" translation="资源已重新载入" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3" max_local="25*2"/>
<string english="ERROR: Invalid format" translation="错误:格式不符合" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3" max_local="25*2"/>
<string english="Loaded map: {filename}.vvvvvv" translation="已载入地图:{filename}.vvvvvv" explanation="successfully loaded level file" max="38*3" max_local="25*2"/>
+2
View File
@@ -648,6 +648,8 @@
<string english="Enemy Type Changed" translation="敵人類型已改變" explanation="level editor, user changed enemy appearance for the room" max="38*3" max_local="25*2"/>
<string english="Platform speed is now {speed}" translation="平臺速度現在為{speed}" explanation="level editor, user changed speed of platforms for the room" max="38*3" max_local="25*2"/>
<string english="Enemy speed is now {speed}" translation="敵人速度現在爲{speed}" explanation="level editor, user changed speed of enemies for the room" max="38*3" max_local="25*2"/>
<string english="ERROR: Nothing to undo" translation="" explanation="level editor, user tried to undo with nothing to undo" max="38*3" max_local="25*2"/>
<string english="ERROR: Nothing to redo" translation="" explanation="level editor, user tried to redo with nothing to redo" max="38*3" max_local="25*2"/>
<string english="Reloaded resources" translation="資源已重新載入" explanation="level editor, reloaded graphics assets/resources, music and sound effects" max="38*3" max_local="25*2"/>
<string english="ERROR: Invalid format" translation="錯誤:格式不符合" explanation="user was supposed to enter something like `12,12`, but entered `as@df`" max="38*3" max_local="25*2"/>
<string english="Loaded map: {filename}.vvvvvv" translation="已載入地圖:{filename}.vvvvvv" explanation="successfully loaded level file" max="38*3" max_local="25*2"/>
+372 -36
View File
@@ -412,6 +412,11 @@ void editorclass::reset(void)
state = EditorState_DRAW;
substate = EditorSubState_MAIN;
undo_buffer.clear();
redo_buffer.clear();
placing_tiles = false;
}
void editorclass::show_note(const char* text)
@@ -2262,11 +2267,29 @@ void editorclass::add_entity(int rx, int ry, int xp, int yp, int tp, int p1, int
entity.p6 = p6;
entity.scriptname = "";
EditorUndoInfo info;
info.room_x = rx;
info.room_y = ry;
info.type = EditorUndoType_ENTITY_ADDED;
info.entity = entity;
info.entity_id = customentities.size();
undo_buffer.push_back(info);
redo_buffer.clear();
customentities.push_back(entity);
}
void editorclass::remove_entity(int t)
{
EditorUndoInfo info;
info.room_x = levx;
info.room_y = levy;
info.type = EditorUndoType_ENTITY_REMOVED;
info.entity_id = t;
info.entity = customentities[t];
undo_buffer.push_back(info);
redo_buffer.clear();
customentities.erase(customentities.begin() + t);
}
@@ -2284,6 +2307,86 @@ int editorclass::get_entity_at(int rx, int ry, int xp, int yp)
return -1;
}
static void update_old_tiles()
{
extern editorclass ed;
for (int i = 0; i < SCREEN_WIDTH_TILES * SCREEN_HEIGHT_TILES; i++)
{
ed.old_tiles[i] = ed.get_tile(i % SCREEN_WIDTH_TILES, i / SCREEN_WIDTH_TILES);
}
}
static void commit_entity(int id)
{
// We're gonna modify an entity, so save the old version
extern editorclass ed;
EditorUndoInfo info;
info.room_x = ed.levx;
info.room_y = ed.levy;
info.type = EditorUndoType_ENTITY_MODIFIED;
info.entity_id = id;
info.entity = customentities[id];
ed.undo_buffer.push_back(info);
ed.redo_buffer.clear();
}
static void commit_tiles()
{
// We either let go of the mouse button, or we switched rooms, so we need to commit the tiles to the undo buffer
extern editorclass ed;
EditorUndoInfo info;
info.room_x = ed.levx;
info.room_y = ed.levy;
info.type = EditorUndoType_TILES;
SDL_memcpy(info.tiles, ed.old_tiles, sizeof(ed.old_tiles));
ed.undo_buffer.push_back(info);
ed.redo_buffer.clear();
}
static void commit_roomdata_change()
{
extern editorclass ed;
EditorUndoInfo info;
info.room_x = ed.levx;
info.room_y = ed.levy;
info.type = EditorUndoType_ROOMDATA;
info.room_data = *cl.getroomprop(ed.levx, ed.levy);
ed.undo_buffer.push_back(info);
ed.redo_buffer.clear();
}
static void commit_roomdata_tiles_change()
{
extern editorclass ed;
EditorUndoInfo info;
info.room_x = ed.levx;
info.room_y = ed.levy;
info.type = EditorUndoType_ROOMDATA_TILES;
update_old_tiles();
SDL_memcpy(info.tiles, ed.old_tiles, sizeof(ed.old_tiles));
info.room_data = *cl.getroomprop(ed.levx, ed.levy);
ed.undo_buffer.push_back(info);
ed.redo_buffer.clear();
}
static void uncommit()
{
extern editorclass ed;
ed.undo_buffer.pop_back();
}
static void set_tile_interpolated(const int x1, const int x2, const int y1, const int y2, const int tile)
{
extern editorclass ed;
@@ -2418,9 +2521,19 @@ void editorclass::tool_remove()
{
case EditorTool_WALLS:
case EditorTool_BACKING:
if (!placing_tiles)
{
placing_tiles = true;
update_old_tiles();
}
handle_tile_placement(0);
break;
case EditorTool_SPIKES:
if (!placing_tiles)
{
placing_tiles = true;
update_old_tiles();
}
set_tile_interpolated(old_tilex, tilex, old_tiley, tiley, 0);
break;
default:
@@ -2448,11 +2561,13 @@ void editorclass::entity_clicked(const int index)
{
case 1:
// Enemies
commit_entity(index);
entity->p1 = (entity->p1 + 1) % 4;
break;
case 2:
{
// Moving Platforms and Conveyors
commit_entity(index);
const bool conveyor = entity->p1 >= 5;
entity->p1++;
if (conveyor)
@@ -2468,6 +2583,7 @@ void editorclass::entity_clicked(const int index)
case 10:
// Checkpoints
// If it's not textured as a checkpoint, then just leave it be
commit_entity(index);
if (entity->p1 == 0 || entity->p1 == 1)
{
entity->p1 = (entity->p1 + 1) % 2;
@@ -2476,27 +2592,34 @@ void editorclass::entity_clicked(const int index)
case 11:
case 16:
// Gravity Lines, Start Point
commit_entity(index);
entity->p1 = (entity->p1 + 1) % 2;
break;
case 15:
// Crewmates
commit_entity(index);
entity->p1 = (entity->p1 + 1) % 6;
break;
case 17:
// Roomtext
commit_entity(index);
get_input_line(TEXT_ROOMTEXT, "Enter roomtext:", &entity->scriptname);
text_entity = index;
break;
case 18:
// Terminals
commit_entity(index);
if (entity->p1 == 0 || entity->p1 == 1)
{
// Flip the terminal, but if it's not textured as a terminal leave it alone
entity->p1 = (entity->p1 + 1) % 2;
}
SDL_FALLTHROUGH;
get_input_line(TEXT_SCRIPT, "Enter script name:", &entity->scriptname);
text_entity = index;
break;
case 19:
// Script Boxes (and terminals)
commit_entity(index);
get_input_line(TEXT_SCRIPT, "Enter script name:", &entity->scriptname);
text_entity = index;
break;
@@ -2519,6 +2642,12 @@ void editorclass::tool_place()
{
int tile = 0;
if (!placing_tiles)
{
placing_tiles = true;
update_old_tiles();
}
if (cl.getroomprop(levx, levy)->directmode >= 1)
{
tile = direct_mode_tile;
@@ -2536,6 +2665,12 @@ void editorclass::tool_place()
break;
}
case EditorTool_SPIKES:
if (!placing_tiles)
{
placing_tiles = true;
update_old_tiles();
}
set_tile_interpolated(old_tilex, tilex, old_tiley, tiley, 8);
break;
case EditorTool_TRINKETS:
@@ -2636,17 +2771,22 @@ void editorclass::tool_place()
}
break;
case EditorTool_START_POINT:
//If there is another start point, destroy it
lclickdelay = 1;
//If there is another start point, move it instead
for (size_t i = 0; i < customentities.size(); i++)
{
if (customentities[i].t == 16)
{
remove_entity(i);
i--;
commit_entity(i);
customentities[i].rx = levx;
customentities[i].ry = levy;
customentities[i].x = tilex;
customentities[i].y = tiley;
customentities[i].p1 = 0;
return;
}
}
add_entity(levx, levy, tilex, tiley, 16, 0);
lclickdelay = 1;
break;
default:
break;
@@ -2999,21 +3139,25 @@ static void handle_draw_input()
{
if (key.keymap[SDLK_F1])
{
commit_roomdata_tiles_change();
ed.switch_tileset(shift_down);
ed.keydelay = 6;
}
if (key.keymap[SDLK_F2])
{
commit_roomdata_tiles_change();
ed.switch_tilecol(shift_down);
ed.keydelay = 6;
}
if (key.keymap[SDLK_F3])
{
commit_roomdata_change();
ed.switch_enemy(shift_down);
ed.keydelay = 6;
}
if (key.keymap[SDLK_F4])
{
commit_roomdata_change();
ed.keydelay = 6;
ed.substate = EditorSubState_DRAW_BOX;
ed.box_corner = BoxCorner_FIRST;
@@ -3021,6 +3165,7 @@ static void handle_draw_input()
}
if (key.keymap[SDLK_F5])
{
commit_roomdata_change();
ed.keydelay = 6;
ed.substate = EditorSubState_DRAW_BOX;
ed.box_corner = BoxCorner_FIRST;
@@ -3028,6 +3173,7 @@ static void handle_draw_input()
}
if (key.keymap[SDLK_F10])
{
commit_roomdata_tiles_change();
if (cl.getroomprop(ed.levx, ed.levy)->directmode == 1)
{
cl.setroomdirectmode(ed.levx, ed.levy, 0);
@@ -3057,11 +3203,13 @@ static void handle_draw_input()
if (key.keymap[SDLK_w])
{
commit_roomdata_change();
ed.switch_warpdir(shift_down);
ed.keydelay = 6;
}
if (key.keymap[SDLK_e])
{
commit_roomdata_change();
ed.keydelay = 6;
ed.get_input_line(TEXT_ROOMNAME, "Enter new room name:", const_cast<std::string*>(&(cl.getroomprop(ed.levx, ed.levy)->roomname)));
game.mapheld = true;
@@ -3104,6 +3252,7 @@ static void handle_draw_input()
const bool shift = key.keymap[SDLK_LSHIFT] || key.keymap[SDLK_RSHIFT];
if (key.keymap[SDLK_COMMA])
{
commit_roomdata_change();
if (ctrl)
{
if (shift)
@@ -3123,6 +3272,7 @@ static void handle_draw_input()
}
else if (key.keymap[SDLK_PERIOD])
{
commit_roomdata_change();
if (ctrl)
{
if (shift)
@@ -3194,6 +3344,127 @@ void editorclass::get_input_line(const enum TextMode mode, const std::string& pr
old_entity_text = key.keybuffer;
}
static void handle_undo(const bool undo)
{
extern editorclass ed;
std::vector<EditorUndoInfo>* buffer = undo ? &ed.undo_buffer : &ed.redo_buffer;
if (buffer->size() == 0)
{
ed.show_note(undo ? loc::gettext("ERROR: Nothing to undo") : loc::gettext("ERROR: Nothing to redo"));
return;
}
EditorUndoInfo info = buffer->back();
buffer->pop_back();
ed.levx = info.room_x;
ed.levy = info.room_y;
ed.updatetiles = true;
ed.changeroom = true;
graphics.backgrounddrawn = false;
graphics.foregrounddrawn = false;
EditorUndoInfo new_info;
new_info.room_x = info.room_x;
new_info.room_y = info.room_y;
new_info.type = info.type;
switch (info.type)
{
case EditorUndoType_TILES:
for (size_t i = 0; i < SCREEN_WIDTH_TILES * SCREEN_HEIGHT_TILES; i++)
{
const int x = i % SCREEN_WIDTH_TILES;
const int y = i / SCREEN_WIDTH_TILES;
ed.old_tiles[i] = ed.get_tile(x, y);
cl.settile(ed.levx, ed.levy, x, y, info.tiles[i]);
}
SDL_memcpy(new_info.tiles, ed.old_tiles, sizeof(ed.old_tiles));
break;
case EditorUndoType_ENTITY_ADDED:
// Remove the entity
if (!INBOUNDS_VEC(info.entity_id, customentities))
{
// Not sure how this would happen, but we should just consume it...
return;
}
new_info.type = EditorUndoType_ENTITY_REMOVED;
new_info.entity = customentities[info.entity_id];
new_info.entity_id = info.entity_id;
customentities.erase(customentities.begin() + info.entity_id);
break;
case EditorUndoType_ENTITY_REMOVED:
// Add the entity back
customentities.insert(customentities.begin() + info.entity_id, info.entity);
new_info.type = EditorUndoType_ENTITY_ADDED;
new_info.entity_id = info.entity_id;
new_info.entity = info.entity;
break;
case EditorUndoType_ENTITY_MODIFIED:
// Restore the entity
if (!INBOUNDS_VEC(info.entity_id, customentities))
{
return;
}
new_info.entity = customentities[info.entity_id];
new_info.entity_id = info.entity_id;
customentities[info.entity_id] = info.entity;
break;
case EditorUndoType_ROOMDATA:
new_info.room_data = cl.roomproperties[info.room_x + info.room_y * cl.maxwidth];
cl.roomproperties[info.room_x + info.room_y * cl.maxwidth] = info.room_data;
graphics.backgrounddrawn = false;
break;
case EditorUndoType_ROOMDATA_TILES:
// Restore the room data
for (size_t i = 0; i < SCREEN_WIDTH_TILES * SCREEN_HEIGHT_TILES; i++)
{
const int x = i % SCREEN_WIDTH_TILES;
const int y = i / SCREEN_WIDTH_TILES;
ed.old_tiles[i] = ed.get_tile(x, y);
cl.settile(ed.levx, ed.levy, x, y, info.tiles[i]);
}
SDL_memcpy(new_info.tiles, ed.old_tiles, sizeof(ed.old_tiles));
new_info.room_data = cl.roomproperties[info.room_x + info.room_y * cl.maxwidth];
cl.roomproperties[info.room_x + info.room_y * cl.maxwidth] = info.room_data;
graphics.backgrounddrawn = false;
graphics.foregrounddrawn = false;
ed.updatetiles = true;
break;
case EditorUndoType_LEVEL_SIZE:
// Restore the level size
new_info.level_width = cl.mapwidth;
new_info.level_height = cl.mapheight;
cl.mapwidth = info.level_width;
cl.mapheight = info.level_height;
break;
}
if (undo)
{
ed.redo_buffer.push_back(new_info);
}
else
{
ed.undo_buffer.push_back(new_info);
}
}
void editorinput(void)
{
extern editorclass ed;
@@ -3203,11 +3474,17 @@ void editorinput(void)
return;
}
bool undo_pressed = false;
bool redo_pressed = false;
bool shift_down = key.keymap[SDLK_LSHIFT] || key.keymap[SDLK_RSHIFT];
bool ctrl_down = key.keymap[SDLK_LCTRL] || key.keymap[SDLK_RCTRL];
ed.old_tilex = ed.tilex;
ed.old_tiley = ed.tiley;
ed.tilex = key.mousex / 8;
ed.tiley = key.mousey / 8;
ed.tilex = SDL_clamp(key.mousex, 0, SCREEN_WIDTH_PIXELS - 1) / 8;
ed.tiley = SDL_clamp(key.mousey, 0, SCREEN_HEIGHT_PIXELS - 1) / 8;
bool up_pressed = key.isDown(SDLK_UP) || key.isDown(SDL_CONTROLLER_BUTTON_DPAD_UP);
bool down_pressed = key.isDown(SDLK_DOWN) || key.isDown(SDL_CONTROLLER_BUTTON_DPAD_DOWN);
@@ -3228,11 +3505,23 @@ void editorinput(void)
{
game.press_right = true;
}
if (key.isDown(KEYBOARD_z) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v) || key.isDown(game.controllerButton_flip))
if ((key.isDown(KEYBOARD_z) && !ctrl_down) || key.isDown(KEYBOARD_SPACE) || key.isDown(KEYBOARD_v) || key.isDown(game.controllerButton_flip))
{
game.press_action = true;
};
if (key.isDown(KEYBOARD_z) && ctrl_down && (ed.keydelay == 0))
{
ed.keydelay = 6;
undo_pressed = true;
}
if (key.isDown(SDLK_y) && ctrl_down && (ed.keydelay == 0))
{
ed.keydelay = 6;
redo_pressed = true;
}
if (key.keymap[SDLK_F9] && (ed.keydelay == 0)) {
ed.keydelay = 30;
ed.show_note(loc::gettext("Reloaded resources"));
@@ -3263,9 +3552,6 @@ void editorinput(void)
game.mapheld = false;
}
bool shift_down = key.keymap[SDLK_LSHIFT] || key.keymap[SDLK_RSHIFT];
bool ctrl_down = key.keymap[SDLK_LCTRL] || key.keymap[SDLK_RCTRL];
// Do different things depending on the current state (and substate)
switch (ed.state)
{
@@ -3274,6 +3560,16 @@ void editorinput(void)
switch (ed.substate)
{
case EditorSubState_MAIN:
if (undo_pressed)
{
handle_undo(true);
}
if (redo_pressed)
{
handle_undo(false);
}
if (escape_pressed)
{
// We're just in draw mode, so go to the settings menu
@@ -3322,6 +3618,8 @@ void editorinput(void)
}
else if (shift_down)
{
int old_width = cl.mapwidth;
int old_height = cl.mapheight;
if (up_pressed) cl.mapheight--;
if (down_pressed) cl.mapheight++;
@@ -3331,26 +3629,48 @@ void editorinput(void)
cl.mapwidth = SDL_clamp(cl.mapwidth, 1, cl.maxwidth);
cl.mapheight = SDL_clamp(cl.mapheight, 1, cl.maxheight);
ed.updatetiles = true;
ed.changeroom = true;
graphics.backgrounddrawn = false;
graphics.foregrounddrawn = false;
if (old_width != cl.mapwidth || old_height != cl.mapheight)
{
ed.updatetiles = true;
ed.changeroom = true;
graphics.backgrounddrawn = false;
graphics.foregrounddrawn = false;
ed.levx = POS_MOD(ed.levx, cl.mapwidth);
ed.levy = POS_MOD(ed.levy, cl.mapheight);
ed.levx = POS_MOD(ed.levx, cl.mapwidth);
ed.levy = POS_MOD(ed.levy, cl.mapheight);
char buffer[3 * SCREEN_WIDTH_CHARS + 1];
vformat_buf(
buffer, sizeof(buffer),
loc::gettext("Mapsize is now [{width},{height}]"),
"width:int, height:int",
cl.mapwidth, cl.mapheight
);
char buffer[3 * SCREEN_WIDTH_CHARS + 1];
vformat_buf(
buffer, sizeof(buffer),
loc::gettext("Mapsize is now [{width},{height}]"),
"width:int, height:int",
cl.mapwidth, cl.mapheight
);
ed.show_note(buffer);
ed.show_note(buffer);
EditorUndoInfo info;
info.type = EditorUndoType_LEVEL_SIZE;
info.level_width = old_width;
info.level_height = old_height;
info.room_x = ed.levx;
info.room_y = ed.levy;
ed.undo_buffer.push_back(info);
ed.redo_buffer.clear();
}
}
else
{
if (ed.placing_tiles)
{
// We were in the middle of placing tiles. Commit it, since we're done with the previous room.
commit_tiles();
// Must be done after every tile commit, as it's responsible for the "old tiles" cache
ed.placing_tiles = false;
}
ed.updatetiles = true;
ed.changeroom = true;
graphics.backgrounddrawn = false;
@@ -3372,19 +3692,26 @@ void editorinput(void)
}
// Mouse input
if (key.leftbutton && ed.lclickdelay == 0)
{
ed.tool_place();
}
else if (!key.leftbutton)
{
ed.lclickdelay = 0;
}
if (key.rightbutton)
{
ed.tool_remove();
}
else
{
if (key.leftbutton && ed.lclickdelay == 0)
{
ed.tool_place();
}
else if (!key.leftbutton)
{
ed.lclickdelay = 0;
if (ed.placing_tiles)
{
commit_tiles();
ed.placing_tiles = false;
}
}
}
if (key.middlebutton)
{
@@ -3536,14 +3863,24 @@ void editorinput(void)
if (escape_pressed)
{
// Cancel it, and remove the enemy it's tied to if necessary
// Escape was pressed, cancel text entry
key.disabletextentry();
if (ed.current_text_mode >= FIRST_ENTTEXT && ed.current_text_mode <= LAST_ENTTEXT)
{
*ed.current_text_ptr = ed.old_entity_text;
// Looks like we're giving an entity text for the first time, so cancelling should remove the entity
if (ed.old_entity_text == "")
{
// Remove it.
ed.remove_entity(ed.text_entity);
// We have to uncommit twice here; once to prevent saving the "remove entity" action...
uncommit();
// ...and once more to undo the "add entity" action we're cancelling
uncommit();
}
}
@@ -3625,7 +3962,6 @@ void editorinput(void)
if (game.currentmenuname == Menu::ed_settings)
{
ed.state = EditorState_DRAW;
gameScreen.recacheTextures();
}
else
{
+32
View File
@@ -133,6 +133,33 @@ struct GhostInfo
int frame; // .drawframe
};
enum EditorUndoTypes
{
EditorUndoType_TILES, // Tiles modified
EditorUndoType_ROOMDATA, // Room data modified
EditorUndoType_ROOMDATA_TILES, // Room data modified (and stores tiles)
EditorUndoType_ENTITY_ADDED, // Entity added
EditorUndoType_ENTITY_REMOVED, // Entity removed
EditorUndoType_ENTITY_MODIFIED, // Entity properties modified
EditorUndoType_LEVEL_SIZE // Level size modified
};
struct EditorUndoInfo
{
EditorUndoTypes type;
int tiles[SCREEN_WIDTH_TILES * SCREEN_HEIGHT_TILES];
int room_x;
int room_y;
EditorTilesets tileset;
int tilecol;
int entity_id;
CustomEntity entity;
RoomProperty room_data;
int level_width;
int level_height;
};
class editorclass
{
public:
@@ -282,6 +309,11 @@ public:
std::vector<GhostInfo> ghosts;
int current_ghosts;
std::vector<EditorUndoInfo> undo_buffer;
std::vector<EditorUndoInfo> redo_buffer;
bool placing_tiles;
int old_tiles[SCREEN_WIDTH_TILES * SCREEN_HEIGHT_TILES];
};
void editorrender(void);
+9
View File
@@ -1,6 +1,7 @@
#include "FileSystemUtils.h"
#include <physfs.h>
#include <physfsrwops.h>
#include <SDL.h>
#include <stdarg.h>
#include <stdio.h>
@@ -959,6 +960,14 @@ fail:
}
}
SDL_RWops* FILESYSTEM_loadAssetRWops(const char* name)
{
char path[MAX_PATH];
getMountedPath(path, sizeof(path), name);
return PHYSFSRWOPS_openRead(path);
}
void FILESYSTEM_loadAssetToMemory(
const char* name,
unsigned char** mem,
+3
View File
@@ -5,6 +5,7 @@
class binaryBlob;
#include <stddef.h>
#include <SDL_rwops.h>
// Forward declaration, including the entirety of tinyxml2.h across all files this file is included in is unnecessary
namespace tinyxml2 { class XMLDocument; }
@@ -35,6 +36,8 @@ bool FILESYSTEM_areAssetsInSameRealDir(const char* filenameA, const char* filena
bool FILESYSTEM_saveFile(const char* name, const unsigned char* data, size_t len);
void FILESYSTEM_loadFileToMemory(const char *name, unsigned char **mem,
size_t *len);
SDL_RWops* FILESYSTEM_loadAssetRWops(const char* name);
void FILESYSTEM_loadAssetToMemory(
const char* name,
unsigned char** mem,
-1
View File
@@ -7926,7 +7926,6 @@ void Game::mapmenuchange(const enum GameGamestate newgamestate, const bool user_
gamestate = newgamestate;
graphics.resumegamemode = false;
mapheld = true;
gameScreen.recacheTextures();
if (prevgamestate == GAMEMODE)
{
+4 -1
View File
@@ -459,6 +459,10 @@ void KeyPoll::Poll(void)
break;
}
case SDL_RENDER_TARGETS_RESET:
gameScreen.recacheTextures();
break;
/* Window Events */
case SDL_WINDOWEVENT:
switch (evt.window.event)
@@ -496,7 +500,6 @@ void KeyPoll::Poll(void)
}
}
SDL_DisableScreenSaver();
gameScreen.recacheTextures();
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
if (!game.disablepause)
+7 -1
View File
@@ -785,12 +785,18 @@ void mapclass::resetplayer(void)
void mapclass::resetplayer(const bool player_died)
{
bool was_in_tower = towermode;
game.deathseq = -1;
if (game.roomx != game.saverx || game.roomy != game.savery)
{
gotoroom(game.saverx, game.savery);
if (player_died)
{
twoframedelayfix();
}
}
game.deathseq = -1;
int i = obj.getplayer();
if(INBOUNDS_VEC(i, obj.entities))
{
+202 -58
View File
@@ -3,7 +3,6 @@
#include <SDL.h>
#include <FAudio.h>
#include <physfsrwops.h>
#include "Alloc.h"
#include "BinaryBlob.h"
@@ -379,14 +378,25 @@ float SoundTrack::volume = 0.0f;
class MusicTrack
{
public:
MusicTrack(SDL_RWops *rw)
MusicTrack(SDL_RWops *rw, const char* _id, bool _loose_extra)
{
SDL_zerop(this);
id = SDL_strdup(_id);
loose_extra = _loose_extra;
if (rw->size(rw) <= 1)
{
// Don't bother
vlog_debug("Skipping empty music track");
goto end;
}
read_buf = (Uint8*) SDL_malloc(rw->size(rw));
SDL_RWread(rw, read_buf, rw->size(rw), 1);
int err;
stb_vorbis_info vorbis_info;
stb_vorbis_comment vorbis_comment;
vorbis = stb_vorbis_open_memory(read_buf, rw->size(rw), &err, NULL);
if (vorbis == NULL)
{
@@ -425,6 +435,7 @@ end:
VVV_free(read_buf);
VVV_free(decoded_buf_playing);
VVV_free(decoded_buf_reserve);
VVV_free(id);
if (!IsHalted())
{
VVV_freefunc(FAudioVoice_DestroyVoice, musicVoice);
@@ -533,6 +544,8 @@ end:
Uint8* decoded_buf_playing;
Uint8* decoded_buf_reserve;
Uint8* read_buf;
char* id;
bool loose_extra;
bool shouldloop;
bool valid;
@@ -736,6 +749,42 @@ musicclass::musicclass(void)
usingmmmmmm = false;
}
static void make_id_from_filename(char* id, size_t id_size, const char* filename)
{
// Create the ID
size_t current_char = 0;
size_t item_len = SDL_strlen(filename);
for (size_t i = 0; i < item_len; i++)
{
// If it's a space, we don't want to include this.
if (filename[i] == ' ')
{
continue;
}
// Otherwise, add it to our ID string, lowered
id[current_char] = SDL_tolower(filename[i]);
current_char++;
if (current_char >= (id_size - 1))
{
break;
}
}
// Null-terminate the string
id[current_char] = '\0';
// Chop off the extension!
char* dot = SDL_strrchr(id, '.');
if (dot != NULL)
{
*dot = '\0';
}
}
static void add_builtin_sound(const char* id)
{
char asset_filename[256];
@@ -743,9 +792,31 @@ static void add_builtin_sound(const char* id)
soundTracks.push_back(SoundTrack(asset_filename, id, false));
}
static void add_builtin_track(SDL_RWops* rw, const char* track_name)
{
// Make an ID from the track name
char id[256];
SDL_strlcpy(id, track_name, sizeof(id));
// Strip "music/" prefix if it exists
if (SDL_strncmp(id, "music/", 6) == 0)
{
SDL_memmove(id, id + 6, SDL_strlen(id) - 5);
}
// Strip file extension if any
char* dot = SDL_strrchr(id, '.');
if (dot != NULL)
{
*dot = '\0';
}
musicTracks.push_back(MusicTrack(rw, id, false));
}
void musicclass::init(void)
{
if (FAudioCreate(&faudioctx, 0, FAUDIO_DEFAULT_PROCESSOR))
if (FAudioCreate(&faudioctx, FAUDIO_1024_QUANTUM, FAUDIO_DEFAULT_PROCESSOR))
{
vlog_error("Unable to initialize FAudio");
return;
@@ -795,36 +866,7 @@ void musicclass::init(void)
char id[256];
SDL_snprintf(asset_filename, sizeof(asset_filename), "sounds/%s", item);
// Create the ID
size_t current_char = 0;
size_t item_len = SDL_strlen(item);
for (size_t i = 0; i < item_len; i++)
{
// If it's a space, we don't want to include this.
if (item[i] == ' ')
{
continue;
}
// Otherwise, add it to our ID string, lowered
id[current_char] = SDL_tolower(item[i]);
current_char++;
if (current_char >= 255)
{
break;
}
}
// Null-terminate the string
id[current_char] = '\0';
// Chop off the extension!
char* dot = SDL_strrchr(id, '.');
if (dot != NULL)
{
*dot = '\0';
}
make_id_from_filename(id, sizeof(id), item);
if (soundidexists(id))
{
@@ -852,28 +894,41 @@ void musicclass::init(void)
if (!mmmmmm_blob.unPackBinary("mmmmmm.vvv"))
{
// If mmmmmm.vvv is invalid, or doesn't exist...
SDL_RWops* rw;
if (pppppp_blob.unPackBinary("vvvvvvmusic.vvv"))
{
vlog_info("Loading music from PPPPPP blob...");
mmmmmm = false;
usingmmmmmm=false;
usingmmmmmm = false;
int index;
SDL_RWops* rw;
#define TRACK_LOAD_BLOB(blob, track_name) \
index = blob.getIndex("data/" track_name); \
if (index >= 0 && index < blob.max_headers) \
vlog_debug("Searching for track " track_name " as loose file"); \
rw = FILESYSTEM_loadAssetRWops(track_name); \
if (rw != NULL) \
{ \
rw = SDL_RWFromConstMem(blob.getAddress(index), blob.getSize(index)); \
if (rw == NULL) \
vlog_debug("Found loose music file " track_name); \
add_builtin_track(rw, track_name); \
} \
else \
{ \
index = blob.getIndex("data/" track_name); \
if (index >= 0 && index < blob.max_headers) \
{ \
vlog_error("Unable to read music file header: %s", SDL_GetError()); \
} \
else \
{ \
musicTracks.push_back(MusicTrack(rw)); \
rw = SDL_RWFromConstMem(blob.getAddress(index), blob.getSize(index)); \
if (rw == NULL) \
{ \
vlog_error("Unable to read music file header: %s", SDL_GetError()); \
} \
else \
{ \
add_builtin_track(rw, track_name); \
} \
} \
}
@@ -885,21 +940,23 @@ void musicclass::init(void)
}
else
{
vlog_info("Loading music from loose files...");
vlog_info("No music blobs found");
SDL_RWops* rw;
#define FOREACH_TRACK(_, track_name) \
rw = PHYSFSRWOPS_openRead(track_name); \
if (rw == NULL) \
#define TRACK_LOAD_LOOSE(_, track_name) \
vlog_debug("Searching for track " track_name " as loose file"); \
rw = FILESYSTEM_loadAssetRWops(track_name); \
if (rw != NULL) \
{ \
vlog_error("Unable to read loose music file: %s", SDL_GetError()); \
vlog_debug("Found loose music file \"" track_name "\""); \
add_builtin_track(rw, track_name); \
} \
else \
{ \
musicTracks.push_back(MusicTrack(rw)); \
vlog_error("Unable to load loose music file: %s", SDL_GetError()); \
}
#define FOREACH_TRACK(_, track_name) TRACK_LOAD_LOOSE(_, track_name)
TRACK_NAMES(_)
#undef FOREACH_TRACK
@@ -923,7 +980,7 @@ void musicclass::init(void)
while (mmmmmm_blob.nextExtra(&index_))
{
rw = SDL_RWFromConstMem(mmmmmm_blob.getAddress(index_), mmmmmm_blob.getSize(index_));
musicTracks.push_back(MusicTrack( rw ));
add_builtin_track(rw, mmmmmm_blob.m_headers[index_].name);
num_mmmmmm_tracks++;
index_++;
@@ -945,11 +1002,53 @@ void musicclass::init(void)
while (pppppp_blob.nextExtra(&index_))
{
rw = SDL_RWFromConstMem(pppppp_blob.getAddress(index_), pppppp_blob.getSize(index_));
musicTracks.push_back(MusicTrack( rw ));
add_builtin_track(rw, pppppp_blob.m_headers[index_].name);
num_pppppp_tracks++;
index_++;
}
EnumHandle music_handle = {};
const char* music_item;
while ((music_item = FILESYSTEM_enumerateAssets("music", &music_handle)) != NULL)
{
char asset_filename[256];
char id[256];
SDL_snprintf(asset_filename, sizeof(asset_filename), "music/%s", music_item);
make_id_from_filename(id, sizeof(id), music_item);
if (idexists(id))
{
// Make sure we haven't already loaded this file
continue;
}
vlog_info("Reading loose extra music file %s as %s", music_item, id);
unsigned char* mem;
size_t len;
FILESYSTEM_loadAssetToMemory(asset_filename, &mem, &len);
if (mem == NULL)
{
vlog_error("Unable to load loose extra music file to memory: %s", SDL_GetError());
}
else
{
rw = SDL_RWFromConstMem(mem, len);
if (rw == NULL)
{
vlog_error("Unable to read loose extra music file from memory: %s", SDL_GetError());
}
else
{
musicTracks.push_back(MusicTrack(rw, id, true));
num_pppppp_tracks++;
}
VVV_free(mem);
}
}
FILESYSTEM_freeEnumerate(&music_handle);
}
void musicclass::destroy(void)
@@ -983,7 +1082,7 @@ void musicclass::set_sound_volume(int volume)
SoundTrack::SetVolume(volume * user_sound_volume / USER_VOLUME_MAX);
}
void musicclass::play(int t)
bool musicclass::play(int t)
{
if (mmmmmm && usingmmmmmm)
{
@@ -1007,7 +1106,7 @@ void musicclass::play(int t)
if (currentsong == t && !m_doFadeOutVol)
{
return;
return true;
}
currentsong = t;
@@ -1015,14 +1114,14 @@ void musicclass::play(int t)
if (t == -1)
{
return;
return true;
}
if (!INBOUNDS_VEC(t, musicTracks))
{
vlog_error("play() out-of-bounds!");
currentsong = -1;
return;
return false;
}
if (currentsong == Music_PATHCOMPLETE ||
@@ -1064,6 +1163,51 @@ void musicclass::play(int t)
fadeMusicVolumeIn(3000);
}
}
return true;
}
bool musicclass::playid(const char* id)
{
for (size_t i = 0; i < musicTracks.size(); i++)
{
if (SDL_strcmp(musicTracks[i].id, id) == 0)
{
return play(i);
}
}
vlog_error("playid() couldn't find music ID: %s", id);
return false;
}
bool musicclass::idexists(const char* id)
{
for (size_t i = 0; i < musicTracks.size(); i++)
{
if (SDL_strcmp(musicTracks[i].id, id) == 0)
{
return true;
}
}
return false;
}
bool musicclass::isextra(int t)
{
if (INBOUNDS_VEC(t, musicTracks))
{
return musicTracks[t].loose_extra;
}
return false;
}
const char* musicclass::getid(int t)
{
if (INBOUNDS_VEC(t, musicTracks))
{
return musicTracks[t].id;
}
return NULL;
}
void musicclass::resume(void)
+5 -1
View File
@@ -73,7 +73,11 @@ public:
void set_music_volume(int volume);
void set_sound_volume(int volume);
void play(int t);
bool play(int t);
bool playid(const char* id);
bool idexists(const char* id);
bool isextra(int t);
const char* getid(int t);
void resume(void);
void resumefade(const int fadein_ms);
void pause(void);
+11 -6
View File
@@ -5,6 +5,8 @@
#include "Alloc.h"
#include "Constants.h"
#include "CustomLevels.h"
#include "Enums.h"
#include "Exit.h"
#include "FileSystemUtils.h"
#include "Game.h"
@@ -14,6 +16,7 @@
#include "GraphicsResources.h"
#endif
#include "InterimVersion.h"
#include "Map.h"
#include "Render.h"
#include "Vlogging.h"
@@ -152,7 +155,6 @@ void Screen::ResizeScreen(int x, int y)
if (!isWindowed || isForcedFullscreen())
{
int result = SDL_SetWindowFullscreen(m_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
recacheTextures();
if (result != 0)
{
vlog_error("Error: could not set the game to fullscreen mode: %s", SDL_GetError());
@@ -175,7 +177,6 @@ void Screen::ResizeScreen(int x, int y)
SDL_WINDOWPOS_CENTERED_DISPLAY(windowDisplay)
);
}
recacheTextures();
}
}
@@ -352,8 +353,6 @@ void Screen::toggleVSync(void)
{
vsync = !vsync;
SDL_RenderSetVSync(m_renderer, (int) vsync);
recacheTextures();
}
void Screen::recacheTextures(void)
@@ -366,15 +365,21 @@ void Screen::recacheTextures(void)
graphics.towerbg.tdrawback = true;
graphics.titlebg.tdrawback = true;
if (game.ingame_titlemode)
if (game.gamestate == MAPMODE || game.ingame_titlemode)
{
// Redraw the cached gameplay texture if we're in the in-game menu.
// Redraw the cached gameplay texture if we're in the map screen.
// Additionally, reset alpha so things don't jitter when re-entering gameplay.
float oldAlpha = graphics.alpha;
graphics.alpha = 0;
gamerender();
graphics.alpha = oldAlpha;
}
if (map.custommode)
{
// If we're in a custom level, regenerate the minimap, which also got cleared.
cl.generatecustomminimap();
}
}
bool Screen::isForcedFullscreen(void)
+18 -2
View File
@@ -347,7 +347,7 @@ void scriptclass::run(void)
int current = 0;
// Crawl through the string
for (int i = 0; i < words[1].size(); i++)
for (size_t i = 0; i < words[1].size(); i++)
{
// If the current character is a number, add it to the current version part
if (words[1][i] >= '0' && words[1][i] <= '9')
@@ -520,6 +520,7 @@ void scriptclass::run(void)
{
played = music.playef(sound_id);
}
if (!played)
{
vlog_error("playef() couldn't play sound: %s", words[1].c_str());
@@ -527,7 +528,22 @@ void scriptclass::run(void)
}
if (words[0] == "play")
{
music.play(ss_toi(words[1]));
bool played = false;
int song_id = ss_toi(words[1].c_str());
if (music.idexists(words[1].c_str()))
{
played = music.playid(words[1].c_str());
}
else if (!music.isextra(song_id))
{
played = music.play(song_id);
}
if (!played)
{
vlog_error("play() couldn't play song: %s", words[1].c_str());
}
}
if (words[0] == "stopmusic")
{
+12 -6
View File
@@ -10,8 +10,8 @@
/* Steamworks interface versions */
#define VVVVVV_STEAMCLIENT "SteamClient017"
#define VVVVVV_STEAMUSERSTATS "STEAMUSERSTATS_INTERFACE_VERSION011"
#define VVVVVV_STEAMCLIENT "SteamClient023"
#define VVVVVV_STEAMUSERSTATS "STEAMUSERSTATS_INTERFACE_VERSION013"
#define VVVVVV_STEAMSCREENSHOTS "STEAMSCREENSHOTS_INTERFACE_VERSION003"
/* Shared object file name */
@@ -45,8 +45,16 @@ struct SteamAPICallCompleted_t
uint32_t m_cubParam;
};
typedef enum ESteamAPIInitResult
{
k_ESteamAPIInitResult_OK = 0,
k_ESteamAPIInitResult_FailedGeneric = 1,
k_ESteamAPIInitResult_NoSteamClient = 2,
k_ESteamAPIInitResult_VersionMismatch = 3,
} ESteamAPIInitResult;
#define FUNC_LIST \
FOREACH_FUNC(uint8_t, SteamAPI_Init, (void)) \
FOREACH_FUNC(ESteamAPIInitResult, SteamAPI_InitFlat, (void*)) \
FOREACH_FUNC(void, SteamAPI_Shutdown, (void)) \
FOREACH_FUNC(void, SteamAPI_RunCallbacks, (void)) \
FOREACH_FUNC(struct ISteamClient*, SteamInternal_CreateInterface, (const char*)) \
@@ -58,7 +66,6 @@ struct SteamAPICallCompleted_t
int32_t, \
const char* \
)) \
FOREACH_FUNC(uint8_t, SteamAPI_ISteamUserStats_RequestCurrentStats, (struct ISteamUserStats*)) \
FOREACH_FUNC(uint8_t, SteamAPI_ISteamUserStats_StoreStats, (struct ISteamUserStats*)) \
FOREACH_FUNC(uint8_t, SteamAPI_ISteamUserStats_SetAchievement, ( \
struct ISteamUserStats*, \
@@ -177,7 +184,7 @@ int32_t STEAM_init(void)
FUNC_LIST
#undef FOREACH_FUNC
if (!SteamAPI_Init())
if (SteamAPI_InitFlat(NULL) != k_ESteamAPIInitResult_OK)
{
vlog_error("Steamworks not initialized!");
ClearPointers();
@@ -207,7 +214,6 @@ int32_t STEAM_init(void)
ClearPointers();
return 0;
}
SteamAPI_ISteamUserStats_RequestCurrentStats(steamUserStats);
steamScreenshots = SteamAPI_ISteamClient_GetISteamScreenshots(
steamClient,
steamUser,