Giter VIP home page Giter VIP logo

exult / exult Goto Github PK

View Code? Open in Web Editor NEW
497.0 36.0 79.0 45.26 MB

Exult is a project to recreate Ultima 7 for modern operating systems, using the game's original plot, data, and graphics files.

Home Page: http://exult.info

License: GNU General Public License v2.0

Makefile 0.84% C++ 76.99% C 2.44% Shell 0.20% UnrealScript 15.85% Batchfile 0.02% LLVM 0.20% Yacc 0.93% Inno Setup 0.51% M4 0.64% Roff 0.18% Objective-C 0.16% Objective-C++ 0.11% Java 0.87% CMake 0.07%
ultima ultima7 rpg-game-engine c-plus-plus-14 ultima-vii serpent-isle black-gate games windows-snapshot forge-of-virtue

exult's Introduction

Badges

Chat on IRC

License: GPL v2

CodeFactor Grade CodeQL

CI Android CI FreeBSD CI iOS CI Mac OS X CI OmniOS CI Ubuntu CI Windows MinGW CI Windows MSVC

Coverity Scan Analysis Coverity Scan Results

snapshots Latest Windows snapshot

What is Exult?


Ultima 7, an RPG from the early 1990's, still has a huge following. But, being a DOS game with a very nonstandard memory manager, it is difficult to run it on the latest computers. Exult is a project to create an Ultima 7 game engine that runs on modern operating systems, capable of using the data and graphics files that come with the game.

Exult is written in C++ and runs on, at least, Linux, Mac OS X and Windows using the SDL library to make porting to other platforms relatively easy. The current version supports all of "Ultima 7: The Black Gate" and "Ultima 7 part 2: The Serpent Isle", allowing you to finish both games. This is only possible due to the work done by other fans who have decoded the various Ultima 7 data files, especially Gary Thompson, Maxim Shatskih, Jakob Schonberg, and Wouter Dijkslag.

Exult aims to let those people who own Ultima 7 (copyright 1993) play the game on modern hardware, in as close to (or perhaps even surpassing) its original splendor as is possible. You need to own "Ultima 7: The Black Gate" and/or "Ultima 7: Serpent Isle" and optionally the add-ons (not required to run) in order to use Exult, and we encourage you to buy a legal copy.

For more information, either consult the README file on the repository, or view its HTML version here.

exult's People

Contributors

alagner avatar anyzio avatar aurelienmarchand avatar begasus avatar ceckak avatar cxong avatar cybersphinx avatar davidludwig avatar dominusexult avatar dragon-baroque avatar drcode1 avatar driver1998 avatar fingolfin avatar imgbotapp avatar kirben avatar knightcaptain avatar knightcaptainu7 avatar kwstubbs avatar ludovicus3 avatar malignantmanor avatar marzojr avatar mbanck avatar notstanley4330 avatar nunotexbsd avatar ptgeorge avatar tristantarrant avatar ungesundes-halbwissen avatar wench avatar wjp avatar wss-itguy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

exult's Issues

Studio not seeing U7 Paperdoll art

I can't seem to view Ultima 7 paperdoll art but I can view Ultima 7: Serpent Isle paperdoll art.
for U7 it just doesn't show up in the Shape Files. Any ideas?

Segfault on exit on SDL2 running without Xorg

Hi there,

I have been experimenting with Exult today, and I found it a very mature engine reimplementation. However, it seems to segfault on exit badly when it's run on X-less SDL2.
To build an SDL2 debug version that can work without X on a GNU/Linux system, just configure it with:

CFLAGS="-O0 -ggdb" ./configure --prefix=/usr --enable-video-kmsdrm --enable-video-opengles
Then configure and build exult and run it normally from a TTY console (CTRL+ALT+Fn).
It runs fine, but it seems to cause memory corruption that crashes SDL2 on quit, inside SDL_Quit().
You may see via GDB that SDL2 crashes in KMSDRM_WarpMouseGlobal(), and SDL2 function of the KMSDRM backend, but that's not always the case: it crashes in different points, so it smells like memory corruption to me.

Could you please test Exult in an x-less SDL2 enviroment, please?

Thanks!

EDIT: In order to get Exult to build in an X-less enviroment, you may have to comment out this line:

exult/exult.cc

Line 199 in 9f80a70

return ConnectionNumber(display);

A few ideas for ES UI improvements

Kind of a reminder to myself.

In terminal:

  • When started from Exult on Windows, Exult should connect stdout and stderr from ES to the terminal.
  • ES spams "Error sending to server" when it is not connected to Exult.

In main window:

  • A message should be displayed that NPCs can only be viewed/edited in conjunction with Exult.
  • There should be a way to scale shapes for display.
  • Shapes display should draw a shape's frames based on maximum frame dimensions, and allow selecting frames or shapes based on this size. This would assist selecting a shape whose first frame is empty (with frame display off) or an empty frame (otherwise).
  • Map menu should add "create mini map" - the functionality is in Exult (Shift-F3) but should rather be an Exult Studio feature.
  • Exult Studio error messages while working in Exult should show a message in Exult - see #104.

In Shape Info window:

  • Weapon tab: family and projectile should show the shape in question when 'Specific shape' is selected.
  • Ammo tab: family and sprite should show the shape in question when 'Specific shape' is selected.
  • Animation tab: maybe add an animation preview? Might be more trouble than it is worth.
  • NPC Paperdoll tab: it should display the composite paperdoll from head, arms, and body (see note below).
  • Make NPC paperdoll display on BG.
  • SFX tab: there should be a play button which causes Exult to play the SFX (or an error message if Exult is not connected).
  • Content Rules tab: it should display either the shape in the Shape field, or nothing for all shapes.
  • Frame Flags tab: it should display the frame selected in the Frame field, or nothing for all frames.
  • Frame HPs tab: it should display the frame selected in the Frame field, or nothing for all frames.
  • Frame Names tab: it should display the frame selected in the Frame field, or nothing for all frames.
  • Frame Usecode tab: it should display the frame selected in the Frame field, or nothing for all frames.
  • Obj Paperdoll tab: it should display the frame selected in the Frame field, or nothing for all frames. Additionally, it should display the paperdoll shape and frames selected in the Paperdoll fields (see note below).
  • Make Obj Paperdoll display on BG.
  • Shape Brightness tab: it should display the frame selected in the Frame field, or nothing for all frames.
  • Warmth tab: it should display the frame selected in the Frame field, or nothing for all frames.

In NPC window:

  • Maybe there should be a button to show the NPC in the map.
  • Flags tab: there should be a way to edit/display the current polymorph shape.
  • Schedules tab: there should be a button to show the location of the schedule on the map, and to set the position from a click on Exult.

in Egg window:

  • When an egg is selected in Exult, its range should be displayed in mapedit mode whenever it makes sense (party/avatar near, avatar far); and it should be updated when distance is changed in ES.
  • Jubebox, Sound Effect, and Voice tabs: there should be a button to play the music/SFX/voice in Exult.
  • Missile tab: the missile sprite should be displayed.
  • Teleport tab: there should be a button to show the target coordinates/path egg.
  • Intermap tab: there should be a button to show the target coordinates.

Note 1: these would require loading the SI paperdoll data and the paperdoll data bundled in exult*.flx, which would be a plus. In other words, issue #75.

Review look of ExultStudio in GTK+ 3

Published a new branch gtk3-look on my fork Dragon-Baroque/exult.

  1. It contains a review of the look of the various windows of ExultStudio when using GTK+ 3. This is divided into the two commits :
  • The first commit contains the replacement Glade file exult_studio.glade,
  • The second commit contains the replacement C++ files.
  1. It contains the implementation of the Frames mode in the NPC browser of the main window,
  2. It contains a connection to CSS style sheets for personal customization of ExultStudio.

If you create a CSS style sheet file named exult_studio.css to the folder share/exult where the exult_studio.glade file resides, ExultStudio exploits it. At this point I can only provide a trivial example of what you can do with CSS style sheets to customize some look attributes of named or typed widgets : StudioCSS.zip

You can play further using the GTK+ Inspector along with ExultStudio :
GTK_DEBUG=interactive exult_studio
launches the Inspector and allows you to create new CSS and see its effect immediately.
The widgets are named as they are in the Glade file id field and no user CSS class exist so far.

Dragon Baroque, Jan 24 2021

Exult Studio - Can't view/extract frames over 31

I'm probably doing something wrong but in Exult Studio I can only view/export frames 0-31 of the sprites in shapes.vga.

As far I could see that's fine for the ground sprites 0-149 which have a max of 32 frames but for the creature sprites it should go higher, as currently with the creatures I can only see their up and down animations (not left and right).

For example in serpent isle, with the blonde lady avatar facing left I can double click her and it tells me it's shape 1029, frame 32 and facing left is shape 1029, frame 48 but I've not managed to see or extract these frames in studio.

Disappearing objects and crashes (on iOS only?)

I've had reports from users that they had crashes (they think in taverns) and one sent me a screenshot with all the objects in Moonshade having disappeared.
sigh
The old bug is not leaving us alone, it seems :(

Of course I was not able to reproduce this and so far I'm still waiting on savegames from them.

One thing, though, C++ standard on the iOS build was not set, so I don't know what it used. I've set it now to C++17. Could that be a culprit or am I just fishing?

158050748_184658879810444_8906708509382544722_n

BG: show congratulations screen after destroying the black gate

After the endgame view you'd get the congratulations screen in the original. We don't show that.
I've managed to only show it when the endgame plays in game but not when you view the endgame from the menu via DominusExult@c40c507

But I'm not managing to get the time elapsed and I don't know how to display it.
First problem I'm having is that I can't make use of clock->get_day()

Mixed Light Sources math.

//???
{
	for nearby_light_sources;
		int obj_relative_pos = abs(avatar_pos(x, y) - lightsource_pos(x, y));
		int light_relative = sum((obj_relative_pos)(8 / 3, 4)); // multiply relative_obj_pos (x3 - x/3, 4y) and add together for percentage of impermissible light.
		if $nearby_light_source = shapeid0x 'torch';
			int light = 150;
		if $nearby_light_source = shapeid0x 'lamp';
			int light = 60;
		if $nearby_light_source = shapeid0x 'candle';
			int light = 30;
		if $nearby_light_source > 0;
		int $nearby_light_source = round(light - ((light / 100) * light_relative);
		else if $nearby_light_source = 0;
		int $nearby_light_source = 0;
	lux = const char 0 + ( sum $nearby_light_source)
	return lux;
}

Emptying variables math and everything might be way off in this outline, as well as possible expansions for detected light sources and possibly using intrinsics. I don't know.

//gameclk.cc
{
if (light || special) && is_dark_palette(pal)) {
	if lux > 11;
		light_palette = PALETTE_CANDLE;
	if (special)
		light_palette = PALETTE_SPELL;
	else if (lux > 89)
		light_palette = PALETTE_SINGLE_LIGHT;
	else if (lux > 255) 
		light_palette = PALETTE_MANY_LIGHTS;

		return light_palette;
}

SI: asan crash when teleporting in Sleeping Bull

when I use the switches below Sleeping Bull to teleport in one of the chambers, and then hit the switch to teleport back, I got this crash:

AddressSanitizer:DEADLYSIGNAL
=================================================================
==10380==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000038 (pc 0x559fd232c367 bp 0x000000000000 sp 0x7ffe39394940 T0)
==10380==The signal is caused by a READ memory access.
==10380==Hint: address points to the zero page.
    #0 0x559fd232c366 in Map_chunk::remove(Game_object*) objs/chunks.cc:840
    #1 0x559fd21c6711 in Usecode_internal::set_item_shape(Usecode_value&, Usecode_value&) usecode/ucinternal.cc:799
    #2 0x559fd222c2b2 in Usecode_internal::UI_set_item_shape(int, Usecode_value*) usecode/intrinsics.cc:215
    #3 0x559fd21c2d2f in Usecode_internal::Execute_Intrinsic(Usecode_value (Usecode_internal::*)(int, Usecode_value*), char const*, int, int, Usecode_value*) usecode/ucinternal.cc:1605
    #4 0x559fd21c2d2f in Usecode_internal::call_intrinsic(int, int) usecode/ucinternal.cc:1669
    #5 0x559fd21d6950 in Usecode_internal::run() usecode/ucinternal.cc:2598
    #6 0x559fd21e6d62 in Usecode_internal::call_usecode(int, Game_object*, Usecode_machine::Usecode_events) usecode/ucinternal.cc:2990
    #7 0x559fd235e1c2 in Game_object::activate(int) objs/objs.cc:1027
    #8 0x559fd235e1c2 in Game_object::activate(int) objs/objs.cc:1017
    #9 0x559fd1a267fa in Activate_actor_action::handle_event(Actor*) actions.cc:695
    #10 0x559fd1a27fdb in Actor_action::handle_event_safely(Actor*, bool&) actions.cc:61
    #11 0x559fd1a27fdb in Sequence_actor_action::handle_event(Actor*) actions.cc:807
    #12 0x559fd1a27fdb in Actor_action::handle_event_safely(Actor*, bool&) actions.cc:61
    #13 0x559fd1a27fdb in Sequence_actor_action::handle_event(Actor*) actions.cc:807
    #14 0x559fd1a2f358 in Path_walking_actor_action::handle_event(Actor*) actions.cc:208
    #15 0x559fd1a6ff26 in Npc_actor::handle_event(unsigned long, unsigned long) actors.cc:5020
    #16 0x559fd1c59d4c in Time_queue::activate0(unsigned int) tqueue.cc:198
    #17 0x559fd1b16161 in Time_queue::activate(unsigned int) tqueue.h:119
    #18 0x559fd1b16161 in Time_queue::activate(unsigned int) tqueue.h:114
    #19 0x559fd1b16161 in Handle_events exult.cc:1265
    #20 0x559fd1b16161 in Play exult.cc:1056
    #21 0x559fd1b16161 in exult_main exult.cc:713
    #22 0x559fd191bb53 in main exult.cc:409
    #23 0x7f54a85f609a in __libc_start_main ../csu/libc-start.c:308
    #24 0x559fd1922749  (/usr/games/exult+0xde749)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV objs/chunks.cc:840 in Map_chunk::remove(Game_object*)
==10380==ABORTING

Leaving this here for the time being and trying to reproduce, but it's been a while since I last saved.

Xcode Analyzer results

I ran Exult through the Xcode analyzer and thought this list might be interesting:

Dead store Group
exult/version.cc:116:2: Value stored to 'firstoption' is never read
exult/usecode/ucdisasm.cc:230:2: Value stored to 'ip' is never read
exult/usecode/ucsymtbl.cc:225:35: Although the value stored to 'magic' is used in the enclosing expression, the value is never actually read from 'magic'
exult/shapeid.cc:314:2: Value stored to 'ok' is never read
exult/usecode/ucsched.cc:692:22: Although the value stored to 'barge' is used in the enclosing expression, the value is never actually read from 'barge'
exult/menulist.cc:389:4: Value stored to 'mouse_updated' is never read
exult/gumps/Stats_gump.cc:246:3: Value stored to 'attsx' is never read
exult/gamemap.cc:860:10: Although the value stored to 'entlen' is used in the enclosing expression, the value is never actually read from 'entlen'
exult/gamedat.cc:1051:21: Value stored to 'err' is never read
exult/gumps/Gump.cc:386:3: Value stored to 'obj' is never read
exult/files/zip/zip.cc:504:6: Value stored to 'err' is never read
exult/gamerend.cc:296:6: Value stored to 'dx' during its initialization is never read
exult/gamerend.cc:297:6: Value stored to 'dy' during its initialization is never read
exult/gamemgr/sigame.cc:468:3: Value stored to 'next' is never read
exult/gamemgr/bggame.cc:532:10: Value stored to 'ticks' during its initialization is never read
exult/gamemgr/bggame.cc:1695:3: Value stored to 'next' is never read
exult/exultmenu.cc:223:32: Although the value stored to 'ypos' is used in the enclosing expression, the value is never actually read from 'ypos'
exult/exultmenu.cc:281:32: Although the value stored to 'ypos' is used in the enclosing expression, the value is never actually read from 'ypos'
exult/files/zip/unzip.cc:581:3: Value stored to 'lSeek' is never read
exult/files/zip/unzip.cc:583:3: Value stored to 'lSeek' is never read
exult/files/zip/unzip.cc:840:3: Value stored to 'err' is never read
exult/cheat_screen.cc:1063:37: Value stored to 'mode' is never read
exult/cheat_screen.cc:1064:23: Value stored to 'mode' is never read
exult/cheat_screen.cc:2604:27: Value stored to 'mode' is never read
exult/cheat_screen.cc:2605:23: Value stored to 'mode' is never read
exult/audio/midi_drivers/CoreMidiDriver.cpp:39:2: Value stored to 'err' is never read
exult/actions.cc:237:18: Although the value stored to 'blk' is used in the enclosing expression, the value is never actually read from 'blk'
exult/audio/midi_drivers/XMidiFile.cpp:1435:4: Value stored to 'len' is never read
exult/audio/midi_drivers/XMidiFile.cpp:1706:2: Value stored to 'time' is never read
exult/exult.cc:1583:14: Although the value stored to 'gump' is used in the enclosing expression, the value is never actually read from 'gump'
exult/audio/midi_drivers/LowLevelMidiDriver.cpp:1437:40: Value stored to 'size' is never read
exult/audio/midi_drivers/LowLevelMidiDriver.cpp:1496:6: Value stored to 'sysex_size' is never read

Logic error Group
exult/pathfinder/Astar.cc:40:3: Forming reference to null pointer
exult/usecode/ucsched.cc:626:24: The left operand of '>' is a garbage value (within a call to 'get_int_value')
exult/shapes/font.cc:118:4: Called C++ object pointer is null
exult/shapes/font.cc:143:6: Called C++ object pointer is null
exult/shapes/font.cc:184:4: Called C++ object pointer is null
exult/shapes/font.cc:211:4: Called C++ object pointer is null
exult/keys.cc:755:58: The left operand of '==' is a garbage value
exult/shapes/vgafile.cc:273:8: Branch condition evaluates to a garbage value
exult/imagewin/scale_2x.cc:55:2: Array access (from variable 'src1') results in a null pointer dereference (within a call to 'Scale2x_noblur')
exult/imagewin/scale_2x.cc:69:2: Array access (from variable 'src1') results in a null pointer dereference (within a call to 'Scale2x_noblur')
exult/imagewin/scale_2x.cc:83:2: Array access (from variable 'src1') results in a null pointer dereference (within a call to 'Scale2x_noblur')
exult/imagewin/scale_2x.cc:97:2: Array access (from variable 'src1') results in a null pointer dereference (within a call to 'Scale2x_noblur')
exult/imagewin/scale_bilinear.cc:43:2: Dereference of null pointer (loaded from variable 'ar') (within a call to 'Scale_2xBilinear')
exult/imagewin/scale_bilinear.cc:59:2: Dereference of null pointer (loaded from variable 'ar') (within a call to 'Scale_2xBilinear')
exult/imagewin/scale_bilinear.cc:75:2: Dereference of null pointer (loaded from variable 'ar') (within a call to 'Scale_2xBilinear')
exult/imagewin/scale_bilinear.cc:91:2: Dereference of null pointer (loaded from variable 'ar') (within a call to 'Scale_2xBilinear')
exult/imagewin/scale_bilinear.cc:110:2: Dereference of null pointer (loaded from variable 'ar') (within a call to 'Scale_2xBilinearPlus')
exult/imagewin/scale_bilinear.cc:126:2: Dereference of null pointer (loaded from variable 'ar') (within a call to 'Scale_2xBilinearPlus')
exult/imagewin/scale_bilinear.cc:142:2: Dereference of null pointer (loaded from variable 'ar') (within a call to 'Scale_2xBilinearPlus')
exult/imagewin/scale_bilinear.cc:158:2: Dereference of null pointer (loaded from variable 'ar') (within a call to 'Scale_2xBilinearPlus')
exult/usecode/ucinternal.cc:516:13: The left operand of '>' is a garbage value (within a call to 'get_int_value')
exult/usecode/ucinternal.cc:2869:10: Dereference of undefined pointer value (within a call to 'get_class_ptr')
exult/gamemap.cc:840:3: Called C++ object pointer is null
exult/gamemap.cc:842:7: Called C++ object pointer is null
exult/gamemap.cc:1594:3: Called C++ object pointer is null (within a call to 'ensure_chunk_read')
exult/files/crc.cc:128:34: The right operand of '^' is a garbage value
exult/imagewin/scale_xbr.cc:50:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/imagewin/scale_xbr.cc:64:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/imagewin/scale_xbr.cc:78:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/imagewin/scale_xbr.cc:92:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/imagewin/scale_xbr.cc:109:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/imagewin/scale_xbr.cc:123:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/imagewin/scale_xbr.cc:137:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/imagewin/scale_xbr.cc:151:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/imagewin/scale_xbr.cc:168:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/imagewin/scale_xbr.cc:182:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/imagewin/scale_xbr.cc:196:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/imagewin/scale_xbr.cc:210:2: Forming reference to null pointer (within a call to 'Scale_xBR')
exult/files/zip/unzip.cc:149:4: Assigned value is garbage or undefined
exult/files/zip/unzip.cc:168:4: Assigned value is garbage or undefined
exult/files/zip/unzip.cc:193:13: 1st function call argument is an uninitialized value
exult/audio/midi_drivers/mt32emu/TVP.cpp:257:48: The result of the left shift is undefined because the left operand is negative
exult/usecode/intrinsics.cc:3331:14: The left operand of '>' is a garbage value (within a call to 'get_int_value')

Memory error Group
exult/shapes/shapevga.cc:387:1: Potential memory leak
exult/readnpcs.cc:236:1: Potential leak of memory pointed to by 'schedules'

Memory (Core Foundation/Objective-C/OSObject) Group
exult/ios/ios_utils.mm:81:2: Potential leak of an object of type 'UIViewController *'

Crash when Music is set to CoreMidi and MT32

When I configured Exult to use CoreMIDI and my real MT-32 through a Roland USB adapter, Exult crashes. When configured by running Exult through the terminal, the crash info is the following:

Exult version 1.5.0git
Built at: May 14 2016 10:24:50
Compile-time options: USE_FMOPL_MIDI, USE_MT32EMU_MIDI, HAVE_ZIP_SUPPORT, HAVE_OPENGL
Compiler: gcc, version: 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)

Platform: Mac OS X
Exult path settings:
Data : /Library/Application Support/Exult/data
Digital music : /Library/Application Support/Exult/data/music

Looking for 'blackgate' at '/Library/Application Support/Exult/blackgate'... found game with identity 'FORGE'
Looking for 'forgeofvirtue' at '/Library/Application Support/Exult/forgeofvirtue'... but it wasn't there.
Looking for 'serpentisle' at '/Library/Application Support/Exult/serpentisle'... found game with identity 'SILVER SEED'
Looking for 'silverseed' at '/Library/Application Support/Exult/silverseed'... but it wasn't there.
Black Gate : not found (<BLACKGATE_STATIC>/)
Forge of Virtue : found
exult_bg.flx : not found (/Library/Application Support/Exult/data/exult_bg.flx)
Serpent Isle : not found (<SERPENTISLE_STATIC>/)
Silver Seed : found
exult_si.flx : not found (/Library/Application Support/Exult/data/exult_si.flx)
Checking rendering support
Windowed 8 bpp ok 16 bpp ok 32 bpp ok
640x480 8 bpp ok 16 bpp ok 32 bpp ok
800x600 8 bpp ok 16 bpp ok 32 bpp ok
1024x768 8 bpp ok 16 bpp ok 32 bpp ok
1280x720 8 bpp ok 16 bpp ok 32 bpp ok
1280x1024 8 bpp ok 16 bpp ok 32 bpp ok
1344x756 8 bpp ok 16 bpp ok 32 bpp ok
1600x900 8 bpp ok 16 bpp ok 32 bpp ok
1600x1200 8 bpp ok 16 bpp ok 32 bpp ok
1680x1050 8 bpp ok 16 bpp ok 32 bpp ok
1920x1080 8 bpp ok 16 bpp ok 32 bpp ok
1920x1200 8 bpp ok 16 bpp ok 32 bpp ok
2560x1440 8 bpp ok 16 bpp ok 32 bpp ok
Creating AudioMixer...
Audio opened using format: 44100 Hz 2 Channels
Timbers Precached: On play only
OGG Vorbis Digital Music: Disabled
Trying config specified Midi driver: `CoreMidi'
CoreMidi driver found 1 destinations:
0: Unknown / Invalid
Success!
Midi Output: Enabled
LLMD: Uploading Rhythm for note 28
LLMD: Uploading Rhythm for note 33
LLMD: Uploading Rhythm for note 74
LLMD: Uploading Rhythm for note 76
LLMD: Uploading Rhythm for note 77
LLMD: Uploading Rhythm for note 78
LLMD: Uploading Rhythm for note 79
LLMD: Uploading Rhythm for note 80
LLMD: Uploading Rhythm for note 81
LLMD: Uploading Rhythm for note 82
LLMD: Uploading Rhythm for note 83
LLMD: Uploading Rhythm for note 84
LLMD: Uploading Rhythm for note 85
LLMD: Uploading Rhythm for note 86
LLMD: Uploading Rhythm for note 87
Segmentation fault: 11
logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

Using CoreMIDI with GS, GM and GS127 works on my Roland SC-88 Pro (GS127 under CM64 mode). Strangely, when I tried again, I left the GS127 option and the MT-32 started outputting the most of the correct notes, but as soon as I changed it to MT32, it crashed again.

Support for Apple's tvOS

Unfortunately it’s not really possible to use Exult on an AppleTV, due to

  • Gamepad support - we are working on this, so you can control the Avatar with one thumbstick (that is already working) and the mouse pointer with the other and using buttons for mouseclicks and other functions (both not added yet)

  • Game files support: that is the big, impossible hurdle :(
    AppleTV has big restrictions on adding files. There is absolutely no way to add all the game files after installing Exult. The iTunes File sharing we can use on the iOS devices does not exist for tvOS. The only way is to bundle the game files with the Exult app but that is legally not possible. You could do this if you were to install Exult yourself on the tvOS device but that is not really something for everyone (you need macOS and Xcode) and newer tvOS devices lack the USB-C port which is needed to connect the device to your mac.

  • Savegames: again same restrictions. We would need to add Cloudkit support so the files are in the icloud. You can’t just save the stuff to the documents folder as we do on iOS devices.

  • This is probably going to affect the exult.cfg as well. I haven't tested as far but from what I understand it's very likely that creating the cfg file is prohibited as well.

So, it’s not something we can work around and won’t be able to solve unless Apple loosens its grip on the tvOS devices :(

see https://stackoverflow.com/questions/58977501/xcode-tvos-error-you-don-t-have-permission-to-save-the-file-filename-txt-i for)

(This issue serves as a reminder for the next time this gets asked for)

Proposals for changes in Exult Audio

I have a few changes to offer, mostly in the Audio support for Exult.

  • Fixes to the Timidity MIDI driver : Enhancement to the expected location and the parsing of the Configuration file ( all platforms ), Fix to the detection of Little Endian vs Big Endian ( Linux ),
  • Enhancement to the ALSA MIDI driver : If the default - alsa_port or 65:0 - fails to connect, try to detect a valid MIDI output port. Explanation : the port 65:0 come for MIDI synthesizer sound cards. Now, MIDI is provided by software synthesis, essentially by the three synthesizers natively supported by Exult : MT32Emu, Timidity, and FluidSynth. All three can register as ALSA servers at ports 128:0 and up, by time order of registration. My proposal, to avoid requesting the user to code an alsa_port in the configuration exult.cfg, is to ask ALSA to name the ALSA clients with available output MIDI and connect to the first that accepts.

I have a few questions :

  • Would you like to discuss / review the code of the above proposal ?
  • Is it acceptable to set the alsa_port in the exult.cfg to the detected MIDI server when the default port address failed - whether coming from exult.cfg or being 65:0, or is the setting of the alsa_port reserved to the human user ?
  • Similarly for the FluidSynth MIDI : A recent accepted patch uses the default FluidSynth SoundFont when none is declared in the fluidsynth_soundfont tag of the exult.cfg. It it acceptable to record it also in the fluidsynth_soundfont tag of the exult.cfg ?

I have also a pending change to the exult.cfg writer, which keeps each value tag in one like, reserving the indentation for nested tags : you now get :

 ...
 <audio>
  <disablepause>no</disablepause>
  <enabled>yes</enabled>
  <midi>
   <enabled>yes</enabled>
   <convert>gm</convert>
   <use_oggs>no</use_oggs>
   ...

All the changes are ready for review. Please tell me about an acceptable delivery format, I mean, one commit per item, or one commit for all of them...

Dragon-Baroque, March 1st, 2021

Using with GOG version

First of all - thank you for this amazing piece of software and sorry for such a lame question. I'm just not sure if that's even possible so i don't want to waste my time if it's not.

I've just bought an Ultima VII collection on GOG.com which is probably the most common go-to place for buying Ultima VII right now. However, it seems that they're packing the game in some sort of non-standard way which gives me some troubles while trying to follow instructions in the README.

First thing is - i'm on a Mac, i have two .app files for both Black Gate and SI: Ultima VII™ - The Black Gate + The Forge of Virtue.app and Ultima VII™ - Serpent Isle + The Silver Seed.app. What i've found in the README is that i should put these .app files somewhere in ~/Library/Application Support/Exult but i'm not sure where to put them (in blackgate and serpentisle maybe?) nor how to rename the .app files (as their original names are pretty complicated, i'm almost sure it can cause some troubles). No matter what i try, Exult gives me an error that it can't find exult data files.

I first want to try to do that without touching the exult.cfg file as it's not an issue for me to move the app files here and there. If that's not possible, i'm gonna try the exult.cfg approach.

Thanks!


Not related, probably it deserves a separate issue: i've seen you guys migrated from sourceforge to github but your website is still on sourceforge. You need some help with migrating the website to github as well? It can be nicely integrated with that repo, can be auto-deplyed under https://exult.github.io domain when readme changes etc, pretty convenient :)

Buildmap function broken by switch to SDL2

With the switch to SDL2 each of the superchunks that Exult screenshots have an extra black border of 4 pixels. So instead of 2048x2048 pixels, each pcx file is 2056x2056.

Since these screenshots are made using the point scaler at 1x buildmap was actually completely broken until fc6962d.

Instant gamma shift bug on blackgate keyring mod

If you start keyring mod, then in the intro when Iolo and Petre are babbling press esc and go to video settings you get a abrupt transition to twilight and if you press esc you'll see the gradual morning.

The menus are also affected by the gamma shift, which is kind of bad i suppose, when you want to set a option in a dark cave.

I assume the game starts at morning-twilight time and the video code makes a executive decision to fix things. It doesn't happen in normal u7 for some reason.

Can smooth scrolling ever be made to look good with the frame limited animations?

The animations look even more unnatural without the long distance jumps of the normal background walking so they switch over very fast indeed, so i was wondering if it would be too bad to extend their number of frames displayed in proportion to the smooth scrolling and the number of frames the new scrolling gives to the old distance?

It probably looks bad, but does i look worse? Especially for the poor followers who look like the Avatar pays them in crack and ecstasy.

Of course a better solution would be to create new intermediary animations, or find a AI program that can do that ( https://grisk.itch.io/dain-app and https://justpaste.it/5dvd7 or https://github.com/akirbaes/_AutoDain ) and publish alternative animation pack for that setting. Though i'm not sure if a AI can actually interpolate this kind of pixel art since it's missing all intermediate sets.

Exult Studio no longer shows corrects stats of examined NPCs

When you doubleclick an NPC in mapedit mode the NPC editor window of Exult Studio pops up. The stats shown are not correct but only show the value 1 for everything (strength, intelligence...).

This seems to have originated in the devel merge branch, all Windows snapshots I have since we switched to 1.7 show this problem, while the 1.6 release works correctly.

RFC: Switch to gtkmm/glibmm

This is something I have been considering for some time. Gtk+ code is obtuse, verbose, and error prone because it is a C API. It also would generate a huge amount of warnings when compiled in Exult, were it not for the fact that I have written a magic header to replace some macros with versions that do not generate these warnings. But this is not a good solution going forward.

gtkmm/glibmm are lightweight C++ wrappers over the C API that:

  1. wraps the Gtk+ types into C++ types that have methods
  2. uses reference counting types to automatically free what needs to be freed
  3. uses the type system to catch errors
  4. provides C++ style iterators that can be used to simplify code greatly
  5. reduces a lot of boilerplate because this code is contained in the wrapper
  6. does not need to use tons of macros for casting between types

Here is a tiny example of the difference:

	GtkTreeView *tree = GTK_TREE_VIEW(
	                        ExultStudio::get_instance()->get_widget(treename));
	GtkTreeModel *model = gtk_tree_view_get_model(tree);
	GtkTreeIter iter;
	if (gtk_tree_model_get_iter_first(model, &iter))
		// Tree has contents.
		do {
			update(info, model, &iter);
		} while (gtk_tree_model_iter_next(model, &iter));
	auto tree = ExultStudio::get_instance()->get_widget<Gtk::TreeView>(treename);
	// Also checked in the Gtk::Builder function to get the widget
	it (!tree) {
		return;
	}
	auto model = tree->get_model();
	for (auto row: model->children())  {
		update(info, model, row);
	}

gtkmm/glibmm are available on Windows (msys2, cygwin, and vcpkg), Linux, and OSX (MacPorts, Homebrew), and most of it will disappear on compilation anyway (due to being on the headers and being inlined to the corresponding Gtk+ calls).

Any opinions?

Mod fallback path?

In my ppa, i just build the executable with a 'system dir' default path, and on installation ask the user for their game location when installing and copy the files to the system dirs. This is good practice in order to avoid 'surprises' later on when something is disconnected or removed and as a bonus the user doesn't even have to create a exult.cfg with the paths (it gets created without them which is ok since the code already searches system paths if that setting is not there).

This works for both the keyring and serpent isle fixes mods because they are maintained in the exult git repository and can be built from there. Even better, it keeps those mods always updated.

That's fine and all, but for the 3rd party mods, this scheme is bad because the package will not and can not download files off random web places. I could install a script that does that, but it's bad practice and more trouble for the users since it contradicts what the exult readme says to do and would break easily.

Instead, i'd like to request that exult adopts a 'two phase' search for content.
first is the result of the configure swich --datadir= (which is what i'm using for the install to system paths)
then $HOME/.exult (for mods and such things. Only search for mods -ie: dirs - that aren't already set in the system path)
With this idea, the user still doesn't have to edit the exult.cfg if he doesn't want to, but can add new mods (i don't feel strongly about the user overriding the package mods and would consider any user error of replacing the keyring or sifixes with a outdated version, just that, user error).

I could simply pretend this issue doesn't exist and specify that all the mods must be specified on the $HOME/.exult.cfg but that's a lot of trouble for the users (also i think it might not work with the games divided like this, at least i wasn't able to).

It's noticeable that 'shadow' directories (empty) are already created by exult in $HOME/.exult/ for each game and mod installed on the 'system dir'.
For example, this is a fresh $HOME/.exult/ i start exult from my ppa for the first time:


├── blackgate
│   ├── gamedat
│   └── mods
│       └── keyring
│           ├── gamedat
│           └── saves
├── forgeofvirtue
│   └── gamedat
├── serpentbeta
│   └── gamedat
├── serpentisle
│   ├── gamedat
│   └── mods
│       └── sifixes
│           ├── gamedat
│           └── saves
└── silverseed
    └── gamedat

18 directories, 0 files

It reminds me of a overlay filesystem already, but it doesn't work like one (yet).

I actually only copy serpent isle and blackgate from the user. If they have the silver seed and forge of virtue installed on the originals they get them, otherwise zilch. I should fix it so SI beta is a option too, but i've been lazy.

Feature request: optional list-mode inventory

I was thinking today of Spoony's criticisms of the gump inventory, specifically with SI and how it is easy to not see a key, ring, etc.

Especially as we move to higher resolution screens where everything is smaller than before, it would be nice to have a list mode inventory as an option for containers that you could switch between.

hanging note bug on track 35 (and other non looping tracks?)

It's a long standing bug that was introduced between the 1.2 release (June 2004) and a Windows snapshot from October 2009 (I found on my hard drive).
It's reproducible on Windows via MIDI and possibly on all platforms via FMOpl (on macOS it doesn't happen with CoreAudio but with FMOpl).
Going through commits that affect audio, especially MIDI I found that there actually were not too many.

But of course we have the big one
d8771b6 with the MIDI code from Pentagram overhauling the Exult code

0ed8f9b <- probably not it

ff9973e and follow up 381f6f3 look interesting and have the potential to be the cause.

(there were other commits to the audio code but I preliminary judged them to not be the cause)

sporadic segfaults when switching between main and si menus while music is playing

If I enable music, switching between the main exult menu and the serpent isle menu (I don't have BG) sometimes (pretty often though) hits segfaults.

As they are only sometimes, those aren't 100% reproducable and might depend on timing, and also I get different backtraces, so they might be different bugs:

Digital SFX's file specified: ... but file not found, and fallbacks are missing
Resetting AudioMixer...
played intro

Thread 1 "exult" received signal SIGSEGV, Segmentation fault.
0x000055555588679a in Shape::reset (this=0x5555575cf920) at vgafile.cc:979
979				delete frames[i];
(gdb) bt full
#0  0x000055555588679a in Shape::reset (this=0x5555575cf920) at vgafile.cc:979
        i = 61
        i = <optimized out>
#1  0x000055555586a5d9 in Shape_file::~Shape_file (this=0x5555575cf920, __in_chrg=<optimized out>)
    at vgafile.h:269
No locals.
#2  Shape_file::~Shape_file (this=0x5555575cf920, __in_chrg=<optimized out>) at vgafile.h:269
No locals.
#3  Font::clean_up (this=this@entry=0x5555575ce3e0) at font.cc:695
No locals.
#4  0x000055555586bb21 in Font::~Font (this=0x5555575ce3e0, __in_chrg=<optimized out>) at font.cc:691
No locals.
#5  FontManager::reset (this=0x55555598e0e0 <fontManager>) at font.cc:876
        i = {<std::__detail::_Node_iterator_base<std::pair<char const* const, Font*>, true>> = {
            _M_cur = 0x5555575ce3b0}, <No data fields>}
#6  0x00005555555e0bdd in Init () at exult.cc:905
        skip_splash = false
        basegame = <optimized out>
        newgame = <optimized out>
        audio = <optimized out>
        midi = <optimized out>
        info = {version = {major = 2 '\002', minor = 0 '\000', patch = 9 '\t'}, subsystem = <optimized out>, 
          info = {x11 = {display = <optimized out>, window = <optimized out>}, wl = {
              display = <optimized out>, surface = <optimized out>, shell_surface = <optimized out>}, 
            dummy = {<optimized out> <repeats 64 times>}}}
        audio = <optimized out>
        midi = <optimized out>
#7  0x00005555555e21b9 in exult_main (runpath=0x7fffffffe5e8 "/usr/games/exult") at exult.cc:699
        music_path = "/usr/share/games/exult/music"
        data_path = "/usr/share/games/exult"
        default_music = "/usr/share/games/exult/music"
        crc_ok = <optimized out>
        flexname = 0x555555901e68 "<DATA>/exult_si.flx"
        crc = <optimized out>
        config_ignore_crc = false
        vs = std::vector of length 2, capacity 2 = {"blackgate", "serpentisle"}
        uctrace = "NO"
        result = <optimized out>
#8  0x00005555555a73a9 in main (argc=1, argv=0x7fffffffe328) at exult.cc:409
        needhelp = false
        showversion = false
        result = <optimized out>
        parameters = {options = std::vector of length 21, capacity 32 = {{option = "-h", {
                bval = 0x7fffffffe1ce, sval = 0x7fffffffe1ce, ival = 0x7fffffffe1ce, uval = 0x7fffffffe1ce}, 
              {dbval = true, dsval = 0x1 <error: Cannot access memory at address 0x1>, dival = 1, 
                duval = 1}, valuetype = Args::Opts::type_bool}, {option = "--help", {bval = 0x7fffffffe1ce, 
                sval = 0x7fffffffe1ce, ival = 0x7fffffffe1ce, uval = 0x7fffffffe1ce}, {dbval = true, 
                dsval = 0x1 <error: Cannot access memory at address 0x1>, dival = 1, duval = 1}, 
              valuetype = Args::Opts::type_bool}, {option = "/?", {bval = 0x7fffffffe1ce, 
                sval = 0x7fffffffe1ce, ival = 0x7fffffffe1ce, uval = 0x7fffffffe1ce}, {dbval = true, 
                dsval = 0x1 <error: Cannot access memory at address 0x1>, dival = 1, duval = 1}, 
[...]
Digital SFX's file specified: ... but file not found, and fallbacks are missing
free(): invalid next size (fast)

Thread 1 "exult" received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50	../sysdeps/unix/sysv/linux/raise.c: Datei oder Verzeichnis nicht gefunden.
(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007ffff767c535 in __GI_abort () at abort.c:79
#2  0x00007ffff76d3508 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff77de28d "%s\n")
    at ../sysdeps/posix/libc_fatal.c:181
#3  0x00007ffff76d9c1a in malloc_printerr (str=str@entry=0x7ffff77dff88 "free(): invalid next size (fast)")
    at malloc.c:5341
#4  0x00007ffff76db4d6 in _int_free (av=0x7ffff7815c40 <main_arena>, p=0x5555575d93c0, 
    have_lock=<optimized out>) at malloc.c:4241
#5  0x000055555586cfc1 in __gnu_cxx::new_allocator<char>::deallocate (this=0x5555575e32d0, 
    __p=<optimized out>) at /usr/include/c++/8/ext/new_allocator.h:116
#6  std::allocator_traits<std::allocator<char> >::deallocate (__a=..., __n=<optimized out>, 
    __p=<optimized out>) at /usr/include/c++/8/bits/alloc_traits.h:462
#7  std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_destroy (
    __size=<optimized out>, this=0x5555575e32d0) at /usr/include/c++/8/bits/basic_string.h:226
#8  std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_dispose (
    this=0x5555575e32d0) at /usr/include/c++/8/bits/basic_string.h:221
#9  std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string (
    this=0x5555575e32d0, __in_chrg=<optimized out>) at /usr/include/c++/8/bits/basic_string.h:657
#10 std::_Destroy<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > (
    __pointer=0x5555575e32d0) at /usr/include/c++/8/bits/stl_construct.h:98
#11 std::_Destroy_aux<false>::__destroy<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*> (__last=<optimized out>, __first=0x5555575e32d0) at /usr/include/c++/8/bits/stl_construct.h:108
#12 std::_Destroy<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*> (
    __last=<optimized out>, __first=<optimized out>) at /usr/include/c++/8/bits/stl_construct.h:137
#13 std::_Destroy<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > (__last=<optimized out>, 
    __first=<optimized out>) at /usr/include/c++/8/bits/stl_construct.h:206
#14 std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::_M_erase_at_end (
    this=0x55555598e160 <item_names[abi:cxx11]>, __pos=0x5555575dd7b0)
    at /usr/include/c++/8/bits/stl_vector.h:1658
#15 std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::clear (
    this=0x55555598e160 <item_names[abi:cxx11]>) at /usr/include/c++/8/bits/stl_vector.h:1386
#16 Free_text_list (items=std::vector of length 1024, capacity 1024 = {...}) at items.cc:357
#17 Free_text () at items.cc:362
#18 0x000055555586d806 in Setup_text (si=true, expansion=<optimized out>, sibeta=false) at items.cc:308
#19 0x00005555555e0a38 in Init () at game.h:99
#20 0x00005555555e21b9 in exult_main (runpath=0x7fffffffe5e8 "/usr/games/exult") at exult.cc:699
#21 0x00005555555a73a9 in main (argc=1, argv=0x7fffffffe328) at exult.cc:409
Digital SFX's file specified: ... but file not found, and fallbacks are missing
free(): invalid next size (fast)

Thread 5 "SDLAudioP1" received signal SIGABRT, Aborted.
[Switching to Thread 0x7ffff2d83700 (LWP 4183)]
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50	../sysdeps/unix/sysv/linux/raise.c: Datei oder Verzeichnis nicht gefunden.
(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
        set = {__val = {234975239, 140737329893672, 93824996964176, 93824996964208, 0, 140737345046524, 2, 
            9223372036854775822, 0, 0, 0, 0, 0, 0, 0, 0}}
        pid = <optimized out>
        tid = <optimized out>
        ret = <optimized out>
#1  0x00007ffff767c535 in __GI_abort () at abort.c:79
        save_stage = 1
        act = {__sigaction_handler = {sa_handler = 0x1729c, sa_sigaction = 0x1729c}, sa_mask = {__val = {
              847482504, 32, 12951514634538332160, 102, 93824993224145, 2305843146956083265, 
              7595430041490911824, 8242270567191832430, 140699741746021, 140737267640848, 93824996965520, 
              140737267640864, 140737329773697, 0, 140737267640928, 140737267641184}}, 
          sa_flags = -220714400, sa_restorer = 0x1000}
        sigs = {__val = {32, 0 <repeats 15 times>}}
#2  0x00007ffff76d3508 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff77de28d "%s\n")
    at ../sysdeps/posix/libc_fatal.c:181
        ap = {{gp_offset = 24, fp_offset = 21845, overflow_arg_area = 0x7ffff2d82b70, 
            reg_save_area = 0x7ffff2d82b00}}
        fd = 2
        list = <optimized out>
        nlist = <optimized out>
        cp = <optimized out>
        written = <optimized out>
#3  0x00007ffff76d9c1a in malloc_printerr (str=str@entry=0x7ffff77dff88 "free(): invalid next size (fast)")
    at malloc.c:5341
No locals.
#4  0x00007ffff76db4d6 in _int_free (av=0x7ffff7815c40 <main_arena>, p=0x5555575cadd0, 
    have_lock=<optimized out>) at malloc.c:4241
        fail = <optimized out>
        idx = <optimized out>
        old = <optimized out>
        old2 = <optimized out>
        size = 64
        fb = <optimized out>
        nextchunk = <optimized out>
        nextsize = <optimized out>
        nextinuse = <optimized out>
        prevsize = <optimized out>
        bck = <optimized out>
        fwd = <optimized out>
        __PRETTY_FUNCTION__ = "_int_free"
#5  0x000055555565161b in XMidiEvent::FreeThis (this=0x5555575c49c0) at XMidiEvent.h:151
        e = <optimized out>
        e = <optimized out>
        e = <optimized out>
#6  XMidiEventList::decrementCounter (this=0x555557158b80) at XMidiEventList.cpp:221
No locals.
#7  0x000055555564710f in LowLevelMidiDriver::playSequences (this=0x55555710ea10)
    at LowLevelMidiDriver.cpp:757
        message = {type = LowLevelMidiDriver::LLMD_MSG_FINISH, sequence = 0, data = {play = {
              list = 0x5555575ef370, repeat = 96, volume = 21845, branch = 1432383654}, pause = {
              paused = 112}, volume = {level = 1465840496}, speed = {percentage = 1465840496}, 
            init_failed = {code = 1465840496}, precache = {list = 0x5555575ef370}}}
        i = <optimized out>
#8  0x0000555555647608 in LowLevelMidiDriver::produceSamples (bytes=<optimized out>, samples=0x555555bbfcd0, 
    this=0x55555710ea10) at LowLevelMidiDriver.cpp:691
        samples_to_produce = 98
        stereo_mult = 2
        num_samples = 512
        stereo_mult = <optimized out>
        num_samples = <optimized out>
        samples_to_produce = <optimized out>
#9  LowLevelMidiDriver::produceSamples (this=0x55555710ea10, samples=<optimized out>, bytes=<optimized out>)
    at LowLevelMidiDriver.cpp:663
        stereo_mult = <optimized out>
        num_samples = <optimized out>
        samples_to_produce = <optimized out>
#10 0x00005555556415b3 in Pentagram::AudioMixer::MixAudio (this=0x555556e89bf0, stream=0x555555bbfcd0, 
    bytes=2048) at AudioMixer.cc:383
        i = <optimized out>
#11 0x00007ffff7e8b929 in ?? () from /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0
No symbol table info available.
#12 0x00007ffff7ed4e8c in ?? () from /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0
No symbol table info available.
#13 0x00007ffff7f48119 in ?? () from /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0
No symbol table info available.
#14 0x00007ffff6bdbfa3 in start_thread (arg=<optimized out>) at pthread_create.c:486
        ret = <optimized out>
        pd = <optimized out>
        now = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737267644160, -6219027106396189317, 140737488344494, 
                140737488344495, 140737267644160, 93824998960704, 6219038409163984251, 6219047432310279547}, 
              mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, 
              canceltype = 0}}}
        not_first_call = <optimized out>
#15 0x00007ffff77534cf in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
No locals.

Configure error when compiling

Hello, when compiling on Fedora 24 pulling fresh from git, it pushes the following error and fails to compile.

checking for SDL - version >= 1.2.0... yes
./configure: line 19706: syntax error near unexpected token `newline'
./configure: line 19706: `      XIPH_PATH_OGG('

z-ordering issues when dragging objects over text

When a text description of an object is shown, and one drags another object over it, then the dragged object is rendered below the text, while the mouse pointer dragging it is rendered above the text.

In the original, the description text disappears when the mouse pointer is dragging something and reappears when it no longer does.

This is with version 1.6.0.

exult

Removal of X11 dependency in Delay and Server_delay

Proposed a new branch "exult_x11_dependencies" on Dragon-Baroque/exult.

It removes the ConnectionNumber / xfd dependency of Exult over X11 in Delay() ( gumps/gump_util.h ) and Server_delay ( server/server.cc ) using either pure SDL cross platform ( Delay ) or SDL + UNIX select without xfd ( Server_delay ).

@KnightCaptain's pull requests

@KnightCaptain made some PRs in the last half year, that fixed numerous issues and added various improvements; but since the commits were unclean (whitespace issues, etc) they weren't merged as is, and he later just closed them all.
That's a bit sad, imo. Anyone working on getting them cleaned up so they can be merged before they will be forgotten ? @KnightCaptain : what's your plan ?

RFC: Replacing build systems with cmake

One thing I have been thinking of is swapping our build system to cmake. From the perspective I am looking at, it has the following advantages:

  • It works on Linux, BSDs, OSX, and Windows
  • It has toolchain support for Android and iOS, so we could maybe finally have a proper Android port
  • Unlike autotools, it works well on msys2/cygwin no Windows (./configure takes an eternity due to the expense of CreateProcess on Windows relative to fork on POSIX systems, and may randomly fail due to ASLR on CreateProcess)
  • There are several useful libraries using cmake which we could use as git submodules (say, fmt, scnlib, or mt32emu) which would be recursively built without issues (this might help on cross compilation)
  • We currently are using 4 build systems (autotools, an explicit makefile on Windows, XCode for iOS cross compilation, broken Visual Studio solutions which need updating)
  • It has several project generators; for example, for XCode and Visual Studio (see above point)

Major drawback is that I have little actual knowledge of cmake and would have to study it :)

Any thoughts?

Allow bigger combos in Exult Studio

When doing mountain ranges it would be great to have bigger combos available. Right now the size is 32x32 tiles (or 4x4 mountain pieces).

Normalization of SDL User Events in Exult

Exult uses SDL User Events inconsistently :
ShortcutBar_gump uses SDL_USEREVENT directly, TouchUI registers one User Event to SDL.
They end up using the same User Event.

I have published a commit in the branch "exult_user_events" on Dragon-Baroque/exult to
centralize the management of SDL User Events.
A longer explanation is in the Exult_Review_of_SDL_User_Events.md.

Build system includes files from wrong places

Discovered that on MacOS accidentally while building.
Compiler started complaining:

clang++ -std=c++17 -DHAVE_CONFIG_H -I. -I../..  -I./../../headers -I./include -I./../../conf -I./../.. -I./../../.. -I./..  -Wall -Wextra -pedantic -Wc++14-compat -Wc++17-compat -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wextra-semi -Wformat-nonliteral -Wformat-security -Wlogical-not-parentheses -Wmissing-include-dirs -Wnon-virtual-dtor -Wnull-dereference -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshift-negative-value -Wshift-overflow -Wtrigraphs -Wundef -Wuninitialized -Wwrite-strings -Wzero-as-null-pointer-constant -Wabsolute-value -Wdeprecated-register -Wmismatched-tags -Wunused-private-field  -DEXULT_DATADIR=\"/Library/Application\ Support/Exult/data\" -Wall -Wextra -pedantic -Wc++14-compat -Wc++17-compat -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wextra-semi -Wformat-nonliteral -Wformat-security -Wlogical-not-parentheses -Wmissing-include-dirs -Wnon-virtual-dtor -Wnull-dereference -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshift-negative-value -Wshift-overflow -Wtrigraphs -Wundef -Wuninitialized -Wwrite-strings -Wzero-as-null-pointer-constant -Wabsolute-value -Wdeprecated-register -Wmismatched-tags -Wunused-private-field   -stdlib=libc++  -MT head2data.o -MD -MP -MF .deps/head2data.Tpo -c -o head2data.o head2data.cc
In file included from head2data.cc:6:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/iostream:38:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ios:216:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__locale:15:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:505:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string_view:176:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__string:57:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:644:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:657:
./../../../new:1:1: error: unknown type name 'adfdsfas'
adfdsfas

I turns out that I have ~/new containing some random strings (building from ~/exult).
Apparently, the '-I' switch seems to be the culprit, in this particular case:
-I./../../..
but I guess the problem lies in the general way these paths are assembled together.
Rather minor thing, still - annoying ;)

Replacing xdrag with SDL_DROPTEXT

@Dragon-Baroque ported Exult Studio to GTK+3 and we talked about whether it would be possible to replace xdrag on *nix systems with SDL_DROPTEXT. The reason why I asked was to make Exult not depend on XWindows when you enable Exult Studio support. Since you can build Exult Studio with Quartz (instead of XQuartz/X11/XWindows) and Exult itself does not need X11 at all, this would be a great thing.
Dragon-Baroque's analysis he sent me per email to keep a public reminder:

I have looked further into your question whether Exult could receive dropped objects from ExultStudio in native Quartz.
I have changed my position of using SDL_DROPTEXT.
Instead I think now that your were right it taking example from the SDL source code.
To complement SDL, I had the source code of GTK+ doing Drag and Drop with Quartz.
Side comment : it should be much simpler than the X11 code.

Initialization from src/video/cocoa/SDL_cocoawindow.m

[data->nswindow registerForDraggedTypes:[NSArray arrayWithObject:(NSString *)...]]

except that you replace the underlined argument by a NSArray of 4 NSString ( or perhaps NSString *, this is confusing ) :

"U7SHAPEID", "U7CHUNKID", "U7NPCID", "U7COMBOID" ( from shapes/u7drag.h )

Callback 1 from src/video/cocoa/SDL_cocoawindow.m, just the entrance and the exit

 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{ @autoreleasepool
{
NSPasteboard *pasteboard = [sender draggingPasteboard];

...

return YES;

}}

At first I suggest to just put a fprintf to stderr to let you know that you have had indeed a Drop event in Exult from any Npc / Combo / Chunk or regular Shape from ExultStudio.
If this works you can enrich it with

NSPoint point = [sender draggingLocation];

Then take from the same code in SDL some converter from NSPoint to x,y in SDL units.
By the way, it seems that the Y direction is reversed in Quartz compared to SDL and GTK+.
You should then be able to retrieve the data with some

NSData * data = [pasteboard dataForType:[NSString stringWithUTF8String:"U7...ID"]];

where you place the "U7CHUNKID" or ..., the one that you should actually retrieve from the array - it should be a single element array

[pasteboard types]

The NSData * can then be used with

[data bytes] gives the byte array pointer

[data length] gives the byte array length

With all that you should be able to call Drop callbacks like in xdrag.cc

Callback 2

- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
{
NSPoint point = [sender draggingLocation];

...
return NSDragOperationCopy;
}

Where again, you should be able to retrieve mouse location from the NSPoint, and possibly too, to retrieve the NSData from the NSPasteboard from the NSDraggingInfo, exactly like in performDragOperation.

If you get both the mouse location and the data, you would have everything needed to call the Move callbacks like in xdrag.cc.

NB: From what I have seen in SDL and GTK+, I am quite confident that you can obtain

  • The 2 callbacks being called when you perform a Drag&Drop operation from ExultStudio,
  • The location of the mouse.

I am far less secure about the extraction of the data, and even whether it shall be available in the callbacks without further requests to Quartz.

Two missing Builtin Groups in ExultStudio

On Dragon-Baroque/exult, branch shape_group_editor :

  1. Added Two builtin groups for Frame usecode and for Light,
  2. Fixed various defects in the Warmth and Frame usecode pages of the Shape Editor.

1.4.9 final release?

I see that 1.4.9rc1 was released in 2016. Was there ever a final release for 1.4.9?

configure strips/overwrites user-supplied CXXFLAGS

Around line 130 in configure.ac, all -O and -g options are stripped from CXXLAGS (and CFLAGS before, but there's a lot less C than C++ code in exult if at all I think):

# Lets clean up CXXFLAGS of -O[0-3gs]? and -g[0-3]?
for cxxflag in $CXXFLAGS; do
        AS_CASE([$cxxflag],
                [-O|-O0|-O1|-O2|-O3|-Os|-Og|-g|-g1|-g2|-g3], [],
                [NEWCXXFLAGS="$NEWCXXFLAGS $cxxflag"])
done
CXXFLAGS="$NEWCXXFLAGS"

Later on, -g and -O are set based on the value of --with-optmization (with -O2 being normal/the default if that is not passed explicitly), but that means the user cannot set -g and -O independently.

I think --with-optimization should either check whether CXXFLAGS are already set and leave -g and -O alone, or provide another custom option or so, that just doesn't strip it out (that might mean that the above quoted AS_CASE call needs to be folded into the --with-optimization logic).

Joystick forgets it's being pulled

David Ludwig's joystick works remarkably well. Very nice and natural movement of the party, even in barges.
Only one problem, after a certain, short, amount of time of steadily pulling the joypad, Exult seems to forget that it is being pulled until you slightly move the joystick again.

Best way to recreate: pull the joystick completely in one direction (keep it steady and avoid any wiggling) . The party will move in that direction and eventually stop until you slightly move the joystick again.
AFAICT there seems to be a check or a loop missing that will tell Exult "oh I am still in this gamecontroller event"

nightly build notification spam

i'm getting notified everyday about a nightly build. imo those builds should only be made if there was a change. also they create a release - probably it would be better to just manually create a release tag now and then.

Address sanitizer problems

In order not to clutter the old bug report, I'll be posting those random address sanitizer problems here.
Teleportation egg-related problem, use-after-free; Fawn, stairs from Serpent Gate up. Line numbers might be slightly off, as I've added extra logs to egg.cc, the problem occurs somewhere in hatch_now as I keep getting "WEAK PTR 2EXPIRED"; possibly I'll be able to debug it further soon, but at this moment I have this:
asan_egg.txt

@@ -1049,10 +1052,15 @@ void Egg_object::hatch(
                // Time to hatch the egg.
                // Watch it in case it gets deleted.
                Game_object_weak watch = weak_from_this();;
+        std::cout << "WEAK PTR" << (watch.expired() ? "EXPIRED\n" : "\n");
                hatch_now(obj, must);
+        std::cout << "WEAK PTR 2" << (watch.expired() ? "EXPIRED\n" : "\n");
                if (flags & (1 << static_cast<int>(once))) {
-                   if (!watch.expired())
-                           remove_this(nullptr);
+        std::cout << "ONCE\n";
+                   if (!watch.expired()) {
+                std::cout << "EXPIRED\n";
+                           remove_this(nullptr); 
+            }
                        return;
                }
        }

Portable pack

Hello. Can you make portable version of your wondeful engine?

A NO-SCALING option is needed for low-powered devices running SDL2

Hi there

I have tried Exult on my Raspberry PI 3b+ and, to my surprise, its SLOW as hell.
I could easily track the problem: software fullscreen scaling is waaaaay above the head for a low-powered ARM device, thats a total waste of CPU in such platforms.

So, in order to play Ultima 7 I have to hack my way inside Exults code, in imagewin/imagewin.c: what I have to do is

  1. In the Exult menu, set the game to a 320x200 windowed mode (its not a real window, there is no way SDL2 will create a window in a KMS/DRM enviroment like mine with no Xorg).
  2. Force FULLSCREEN on the SDL2 side: for that I have to add
    flags =| SDL_WINDOW_FULLSCREEN_DESKTOP;
    just before each SDL_CreateWindow() call.

This way, Exult thinks its running in a 320x200 window, and stops eating up all the CPU on the Pi3 to do hardware scaling, BUT I tell SDL2 to create a fullscreen window, so SDL2 does the scaling in hardware instead.

I measured CPU usage and letting SDL2 do the scaling has a huge impact: according to TOP, using CPU scaling Exult was using 70-80% of one of the cores, while letting SDL2 do it in harware as I have explained, it uses ~6-10% on one of the cores! Of course making the game playable in the process...

What I mean is: SDL2 does scaling in hardware (using GLES in the case of the Raspberry Pi and other ARM platforms). So, please, we need a NO SCALING OPTION, that combined with the FULLSCREEN OPTION would let SDL2 do the scaling instead of using the CPU for it. Using the CPU for scaling is just plain wrong these days...
Can you guys please add such an option?

Thanks for your attention!

Manuel

Narrowing conversion error in recent gccs

static char v2hdr[] = { -1, -1, -1, -1, 'e', 'x', 'l', 't',

Seems to only occur in some platforms, arm64 particularly. Maybe char there is unsigned?

chunklst.cc: In constructor ‘Chunk_chooser::Chunk_chooser(Vga_file*, std::istream&, unsigned char*, int, int, Shape_group*)’:
chunklst.cc:740:24: error: narrowing conversion of ‘-1’ from ‘int’ to ‘char’ [-Wnarrowing]
  740 |                        };
      |                        ^
chunklst.cc:740:24: error: narrowing conversion of ‘-1’ from ‘int’ to ‘char’ [-Wnarrowing]
chunklst.cc:740:24: error: narrowing conversion of ‘-1’ from ‘int’ to ‘char’ [-Wnarrowing]
chunklst.cc:740:24: error: narrowing conversion of ‘-1’ from ‘int’ to ‘char’ [-Wnarrowing]
make[3]: *** [Makefile:669: chunklst.o] Error 1

Duplicate files in Studio file list with case sensitive filesystems

Description

On Linux, opening game Forge of Virtue with mod KeyRing results in spurious file pairs in Studio file list, if Forge of Virtue is installed with the files upper cased to follow the DOS convention.

  • The file list shows shapes.vga ( from Exult, of the KeyRing mod ) and SHAPES.VGA ( from Forge of Virtue )

And some other similar pairs. The shapes.vga is expected, the SHAPES.VGA is not.

Analysis

  • In mapedit/studio.cc, function add_to_tree, Studio first gathers the <PATCH> files from the KeyRing mod.
  • Then it gathers the <STATIC> files from the Forge of Virtue base game, while removing the files already found from the <PATCH> with a call to U7exists against the current fname.
  • This existence test with U7exists works immediately and properly on case insensitive file systems ( Windows, default macOS ), but fails on case sensitive file systems ( Linux ) because U7exists is called outside its definition domain :
    The DOS case insensitive part of the call to U7exists [ or actually to any U7... function ] should be in lower case for the upper casing trial loop of base_to_uppercase in files/utils.cc to work properly.
  • This is precisely not the case at hand : the U7exists function is called with <PATCH>/SHAPES.VGA whereas shapes.vga resides in the <PATCH> folder.
  • For this existence test to work on case insensitive file systems the argument to U7exists should be transformed to <PATCH>/shapes.vga by lower casing the fname.

Dragon Baroque, January 8 2021

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.