[Scummvm-git-logs] scummvm master -> fa6b927ca889b216bbf9b4636e46adcc5417be23
sev-
noreply at scummvm.org
Tue May 5 11:04:27 UTC 2026
This automated email contains information about 400 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
d698c4885d PELROCK: Initial engine skeleton
8583a0febd PELROCK: Loads scene and main character
afac30a24c PELROCK: Reads room animations and renders on screen
91575276ca PELROCK: Reads hotspots and walkboxes
94e520c797 PELROCK: Separate animation sets
09d049a337 PELROCK: Display animations
1c9ef9c65b PELROCK: Implements Room exits
4aec798219 PELROCK: Load cursors, move alfred when changing room
a20b8fde58 PELROCK: Reads popup balloon animation and icons
faa428a45e PELROCK: Generalize bg copy and restoration
a09737f03c PELROCK: Positioning of action balloon
47ddfa060b PELROCK: Font rendering
8febd828eb PELROCK: identifies valid actions associated with hotspots
f131a5bad9 PELROCK: Calculates clickable areas
f0a541069d PELROCK: Selects sprites that are candidates for hotspots
98858463ec PELROCK: Display available actions
2efc7a1a41 PELROCK: Renders descriptions
7c6d67b89e PELROCK: Fixes verb action selection
a75cf60c5c PELROCK: Load conversations
1647b7d852 PELROCK: Reads conversations correctly into a tree
ae3266b3e1 PELROCK: Split alfred frames
6850b9a42b PELROCK: Displays walking and talking animations
0535b469a4 PELROCK: Properly refreshes scenes
0a07291d34 PELROCK: Change list to array
5ce6183800 PELROCK: Plays subanimations in order following control bytes
c3c6f36c95 PELROCK: Animation timing
7e0d3a6bad PELROCK: Walk target calculation
1623209a0b PELROCK: Quick and dirty walking algorithm
65b577da75 PELROCK: Improve walk algorithm
92489bb33e PELROCK: Improve text display
18060a6d5f PELROCK: Adds extra pixel char width on font
cbe2b9958d PELROCK: Font rendering
7148baeb87 PELROCK: Eliminates extra space in text dialog
b007fac21b PELROCK: Click on action
75f2713f77 PELROCK: Better long click handling
262ff0cfb3 PELROCK: Fixes wrong description loading
ac8813f39d PELROCK: Loads NPCs Talking anims
e65b34ec6c PELROCK: Reads second talking animation properly
b79204d594 PELROCK: Fixes talking animations offset
397b1d1fe8 PELROCK: Fixes text color selection
1ecefd962b PELROCK: Creates ResourceManager
36661bdcee PELROCK: Refactors room resource loading into its own class
9779766739 PELROCK: Refactor to use common extractSingleFrame function
b25ff75330 PELROCK: refactor animations
89c6caf126 PELROCK: Refactor other resource loading
07471b2029 PELROCK: Creates ResourceManager
321e401256 PELROCK: Comb animation
04a7b8c2c4 PELROCK: Alfred interacting animation
aaeac0248f PELROCK: Turn if into switch when handling alfred state
3226b5217a PELROCK: Initial Intro video playback
45624b5954 PELROCK: Renders first video sequence
8e3b5c5526 PELROCK: Initial scaling algorithm
79fdb25fcf PELROCK: Initial scaling algorithm
2df4ff4791 PELROCK: Loads shadow map
3240f59bd4 PELROCK: Character shading
58faeb41d2 PELROCK: Dialog choice overlay
a7e5c9cf2a PELROCK: Loads room names
10986e7bb0 PELROCK: Music playback (from mp3)
d2fa47a115 PELROCK: Fix music stopage
f1a3cd07d2 PELROCK: Renders settings screen
a0bc558ee0 PELROCK: Plays Sfx
b899645c4b PELROCK: Condense Alfred state
4e21a273c6 PELROCK: Rudimentary ambient sound generation
9c95c80859 PELROCK: Sprite movements (left/right and top/down)
ea20c30125 PELROCK: Fixes walking algorithm
ac84939fbb PELROCK: Refactor actions
a74e8c2904 PELROCK: Fixed walk before talk
f345388fbc PELROCK: Debug position markers
5751f8c2d5 PELROCK: Sprite order
d64304311f PELROCK: Sets temporary Alfred zorder
df8045d555 PELROCK: Fixes decompression script
9f89aabd1a PELROCK: Loads and renders inventory icons
8463665fa1 PELROCK: Reads the right settings screen
4c4a20c93c PELROCK: Loads right palette for settings menu
c7ec5a2917 PELROCK: Splits menu and game event handling
15b0077a61 PELROCK: Remove g_engine references from engine
9a2c56321b PELROCK: Loads inventory descriptions
4ebec869e3 PELROCK: Associates descriptions to objects
c3300ba0c6 PELROCK: Fixes persistent text
47ba1000c9 PELROCK: Navigate through inventory icons
e3517058e6 PELROCK: Fixes decoding issues
9b14c94681 PELROCK: Room 2 palette anim
7dd082958e PELROCK: Palette anim from room 0
9fc45ddbca PELROCK: Consolidate palette animations
e20590b5bd PELROCK: Loads stickers
a3fb1e4e1c PELROCK: Refactor pathfinding into its own module
7bc6fce6fc PELROCK: Restructuring of renderloop
b58ca4248c PELROCK: Create EventManager
e6ad7d5ed4 PELROCK: First attempt at conversation flow
4a16eee238 PELROCK: Creates double font
105ea475b0 PELROCK: Implements double height font
f5a9d2bcf2 PELROCK: Decodes text bytes properly
deb0853882 PELROCK: Fixes responses during conversations
318b7f345f PELROCK: Initial attempt at word wrapping algorithm
570547df39 PELROCK: Center text above character
dce198bd6e PELROCK: Enable talking animations
97e87afd09 PELROCK: Highlighting of conversation choices
2c4d6eb290 PELROCK: Fixes word wrap rendering
d5fd802816 PELROCK: Stop conversation when no more choices are available.
1d9b7dc63b PELROCK: Applies z-movement to sprites
d0f1be8645 PELROCK: Animation speeds for talking
60d73a5f1c PELROCK: Fixes incorrect zorder drawing
2326250c3d PELROCK: Moves menu handling into its own class
567ff2ce41 PELROCK: Loads menu texts
ae7169c6f8 PELROCK: Processes new line commands
fcb23865fd PELROCK: Process colored text
c45bf2369c PELROCK: Add and remove Stickers
69fc606859 PELROCK: Opens/Closes door and enables exit
1ea9598309 PELROCK: Refactor popup state
0d4a8eee0a PELROCK: Loads extra screens
eb5618572c PELROCK: Queued actions
7728e3ea12 PELROCK: Improve exit calculation
ed2e14da57 PELROCK: Simple inventory management
b533f0ac91 PELROCK: Remove debug artifacts
558c76b6d5 PELROCK: Idle animation
cf4d609cda PELROCK: Fixes text processing
441230ed99 PELROCK: Action Handler
3566f40b75 PELROCK: Adds item to action popup
b4f04b9518 PELROCK: Additional text processing
fedc0a9a10 PELROCK: Inventory icon flashes when picked up
2e4bbe82e6 PELROCK: Cleanup of pelrock engine class
149fd0a54e PELROCK: Better handling of mouse events
70b784d2d0 PELROCK: Calculate facing direction
262ec696c5 PELROCK: Fixes crash with non-existing hotspot
86f6b84e83 PELROCK: Pickup animation
e960d138d9 PELROCK: State change through function
ae72e1d66e PELROCK: Fixes redundant frame when changing alfred state
b8398b86dc PELROCK: Implements menu buttons
0a5f0560a5 PELROCK: Refactor button resource reading
f5a3133cb4 PELROCK: Properly place all menu buttons
ce313b2056 PELROCK: Plays entire intro video
33afb68090 PELROCK: Fix missing alfred frame on queued actions
4f3db80507 PELROCK: Switch to using AudioCDManager
62b56b6c36 PELROCK: Renders subtitles on intro video
291103f79b PELROCK: Proper colors in video subtitles
07706d3261 PELROCK: Word wraps subtitles
476564d982 PELROCK: Improvements on text positioning
0a3c9e5e6e PELROCK: Improvements on text positioning
a527041b51 PELROCK: Checks mouse hover against sprite pixel masks
a13abbc63c PELROCK: Refactor sprite data to preprocess animations
65a66c21d0 PELROCK: Reads voice files
22ff6faa73 PELROCK: Plays intro speech
828e6d9b84 PELROCK: Read metadata parameters from byte buffer
bd027e3ecf PELROCK: Reset room states before loading
67b294ed5b PELROCK: Video timing
fc798c1b53 PELROCK: Saves room changes in memory gamestate
6da8f84da2 PELROCK: Refactor dialog handler, reset and skip disabled conversations
40001b9ba5 PELROCK: Saves state of disabled conversation choices
8b077e1e02 PELROCK: Selects correct conversation when multiple npcs exist
89d26fe2a9 PELROCK: Fixes descriptions not being cleared
3622f07b3d PELROCK: Disables conversation roots
19c6f7bc1a PELROCK: Fixes dialog lines being read incorrectly
eafad6d16d PELROCK: Fix text positioning for NPCs
b1034e8745 PELROCK: Initial save/load implementation
b0044c74d6 PELROCK: Fix extra Alfred being show when clicking on target object
33b640a79e PELROCK: Swap palette remaps
7701be0918 PELROCK: Walk to center of hotspots
c80e1a25bc PELROCK: Use inventory item with hotspot
d8d5873eee PELROCK: Wrong combination responses
1481f31147 PELROCK: Pickup sauces
dec2e69b73 PELROCK: open/close doors
16ebb316a2 PELROCK: Triggers side effects in other rooms
5140ab1362 PELROCK: Shows action popup over alfred, fixes hover priority, mouse position capture
d3db3eff48 PELROCK: Use stuff with Alfred
8f89c446f2 PELROCK: Reading recipe
e78e9488e0 PELROCK: Fixes timing issues in sprites, walking speed and palette animations
b4f94c59fc PELROCK: Scaling improvements
8e6c8b01a4 PELROCK: Additional debugging capabilities
37add58b12 PELROCK: Implement all palette animations
7f740aff3c PELROCK: Better sound management
c8c2995f9e PELROCK: Add actions for room 3
b3e454c6ff PELROCK: Implements Room 15
0078df575b PELROCK: Implements actions on Room 4
fa5ee4b021 PELROCK: Improvements on dialog handling
aeae414a3e PELROCK: Room 4 conversation marker
bc0118e171 PELROCK: Implements computer on room 9
463759106f PELROCK: Cleanup
451919142a PELROCK: Finish room 4
9379385a8e PELROCK: Adds forced terminator to conversations
acdc0fd107 PELROCK: Dialog in room 5
08d7b47d4d PELROCK: Fixes dialog in room 7, fixes zorder
c6066f1707 PELROCK: WIP mouse movement in room 9
8fde0bac53 PELROCK: Implements library mouse (pass-by animations)
83b8fb17e9 PELROCK: Computer-book logic
dd28828c1a PELROCK: implement reading of books
a6ed3a2764 PELROCK: Implements room 14
bdad1b18ac PELROCK: Room changes refactor
f22d5018c2 PELROCK: Enable animations when museum is open
2e9a0fb46e PELROCK: Room 17
97258764ff PELROCK: Implements passer-by animations
d369e67fd7 PELROCK: Model mouse animation in room9 as passer-by
8d94e680e8 PELROCK: Implements palette animation on statue
fb9ae7561f PELROCK: Adds side effect to reading recipe
a0f37b533d PELROCK: Fixes animations in room 40
6480e47ea4 PELROCK: Implements water reflection effect
ea33ffd967 PELROCK: Restrict reflection effect to y position
2a510cdcec PELROCK: Disable branches in travel agency
7002cdd213 PELROCK: Map animation
73d9d97fb9 PELROCK: Fix walking algorithm so it doesnt exit the room when interacting with doors
14dfa22ef4 PELROCK: implements fade to black
d65032835f PELROCK: Room 21 (map)
562e221780 PELROCK: show entire inventory when picking object
4d4ff456f0 PERLOCK: adjust mouse hover over Alfred
398957a124 PELROCK: Improve action selection
433b1eb364 PELROCK: Dialog refactor into functions
c27335f362 PELROCK: Implements cascade disable of choice trees in conversations
90c330d345 PELROCK: Room 22 actions
876544feb3 PELROCK: Fixes shading bug
104e61136d PELROCK: Palette effect on room 28
99d7edabea PELROCK: Room 23
1c366f311f PELROCK: Implements crocodile animation
186db8d250 PELROCK: Sfx in menu
ae81d1088f PELROCK: Fixes conversation root model to be setRoot
77340b2dde PELROCK: Room 25
8067a173d1 PELROCK: Implements picking up objects in room 28
1f929725d2 PELROCK: Spell book
496946f4b2 PELROCK: Implements Egyptian museum
87d5093bfd PELROCK: Play sound when opening secret door
556703dc94 PELROCK: Implements Rooms 31 and 32
426763e30a PELROCK: Implements Room 33
92cb18e7b7 PELROCK: Fixes animation always playing when entering room 38
9519dd6c93 PELROCK: Tunnel exit animation
d89bbc6eb9 PELROCK: Fixes conversations in room 27
d8f0c53e7f PELROCK: Activate room 27's new conversations when opening Safe
a3d3a1778e PELROCK: Fix conversation advancement on previously done tirggers
d7e147ed85 PELROCK: Trigger police after going to jail
f2af94bf4c PELROCK: Doll animation in prison cell
2d39406a85 PELROCK: Disables interaction during cutscenes
d385e8a507 PELROCK: Implements using glue + patches to build inflated doll
cdb379e9ad PELROCK: Fixes resetting palette in room 28
7d7038667e PELROCK: Fixes statue never giving object 8 (note)
44a1836877 PELROCK: "Running" sprites in rooms 34, 36
19605d40a5 PELROCK: Implements room 37
1e225caa41 PELROCK: Implemented time travel animation
63056fbb62 PELROCK: Swimming pool cutscene (partial implementation)
bcf440271c PELROCK: Implement police showing up after raiding tomb
e71aa5b8d1 PELROCK: Full animations in swimming pool cutscene
bd9ee4a407 PELROCK: Implements rest of swimming cutscene
afa4597b81 PELROCK: Fixes bug in walkAndAction where alfred wouldnt end up looking in the right direction
892a4db753 PELROCK: Stone pass skeleton
82bcbdcdac PELROCK: Implements cutscenes in room 41
831355caa2 PELROCK: Implements rooms 43, 44, 45
4043d1ffc2 PELROCK: Crawl animation for room 55, fixes palette remappings
e71946da22 PELROCK: Room 47
c5a47052d4 PELROCK: Wrong door cutscene in Room 48
91be0ceead PELROCK: Correct choice of door in room 48 (hatch)
f26411b289 PELROCK: Room 49
20202772b6 PELROCK: Trigger newspaper scene also in room 0
39cca76119 PELROCK: Implements timing and spells in rooms 51-54
943271a5e7 PELROCK: Stop frame counter during dialog
8c0062a954 PELROCK: Play sound when using amulet and during electric shock
ced34be28f PELROCK: Gods/Sorcerer scenes in rooms 51, 52, 53, 54
f26de9e5e1 PELROCK: Implements missing useless item combinations
63179eff5e PELROCK: Loads CD Player screen
14945d2f9c PELROCK: CD Player (except pause)
3f7f9b75f0 PELROCK: Implements background book
6f69e96103 PELROCK: Improves styling in Library Computer
ccc3065030 PELROCK: Implements ending cutscene on room 52
27d21a0a07 PELROCK: Implements scene with girl in the outro
7fe5550209 PELROCK: Enables final hotspot after fight sequence
78a126017c PELROCK: Loads inventory paging arrows
e197092b5e PELROCK: Implements inventory overlay when using items
8ccb1b06a2 PELROCK: Implements inventory overlay scroll and click
1f188c55f8 PELROCK: Scroll dialog choices
d574cf97d0 PELROCK: add correct sizing to dialogue surface
3d1eb5b388 PELROCK: Implements missing actions
121b734d34 PELROCK: Credits in main menu
87769a6d09 PELROCK: Refactor alfred special anim code into its own function
c491840579 PELROCK: Fixes positioning action balloon and inventory scroll
d0997de296 PELROCK: Pickup bush in room 2, door in room 47
2510f3061b PELROCK: Implements action and continue trigger in conversations
3b03b4ba43 PELROCK: Implements credits in the ending
923774a099 PELROCK: Implements pyramid shaking scene
919f61d3f8 PELROCK: Pyramid collapsing animation on room 36
e53ffc7a6d PELROCK: Adjusts text in credits slideshow
24970d5b90 PELROCK: Post intro cutscene
fc84b9a894 PELROCK: Fix warnings
849b58d6a5 PELROCK: Fixes fall-through with salesman
0a34967556 PELROCK: Fall through room 15
692e16d654 PELROCK: Implements dog pee animation in room 19 and pigeons scene in 24
2f0ac42165 PELROCK: Implements sound effects and music in intro video
0e07504d16 PELROCK: Fixes animation in room 3 and computer text
60acdb4c8d PELROCK: Fixes menu descriptions
c2cbca370c PELROCK: Fixes walkboxes in room 14
197f9e676d PELROCK: Fixes music in travel scene
acae2fa733 PELROCK: Fixes using pumpkin with river
3ec216e9e9 PELROCK: Migrate to using ManagedSurfaces
133fe537c9 PELROCK: Fixes original bug in statue
d94c6dc379 PELROCK: Fixes intro timing
a4c9db112d PELROCK: Fixes inventory overlay glitches (autoscrolls on last icon)
cef88966e5 PELROCK: Fixes stone delivery sequence in rooms 41 & 42
b0fe4b04a9 PELROCK: Fixes credits not restarting
1f06f64278 PELROCK: Fixes credits changing color upon repeat
aa3c4639b8 PELROCK: Fixes removal of letter x in ingame texts
e482a187e1 PELROCK: Fixes for end cutscene
23093df6e0 PELROCK: General code cleanup
b7057581cb PELROCK: Disable looping for incidental music
f1b6d3a7ed PELROCK: Fixes stale item staying in action popup after use
ad219ccbbd PELROCK: Fixes book titles not having new lines
8577942222 PELROCK: Implement loading of background book
719de81bfb PELROCK: Removes all items when moving to Egypt
8962a72e54 PELROCK: Fixes zorder
0aa4161923 PELROCK: Adds extra stickers with glowy eyes to statues in final fight
d9d8e6cac0 PELROCK: Implements background viewer
cbf01025e9 PELROCK: Refactor cdplayer, background book, spellbook
8767c0a4bc PELROCK: Turn all offsets and sizes into constants
0171a5e989 PELROCK: Prevent sticker flicker on room change
58677e4489 PELROCK: Closes main menu after loading/saving
3fb39ab5c7 PELROCK: Implement TTL for dialogue lines
0e5168ea3a PELROCK: Move pertinent code into graphics
57a84acae1 PELROCK: Fixes mouse hover breaking if positioned where action popup used to be
4736dc2ad8 PELROCK: Implements original timing when walking/talking (halving the speed)
f0fdccb1d8 PELROCK: Respect original timing too for NPC talking animations
266df65e9a PELROCK: Fixes idle animation of talking character in room 39
1a9467777c PELROCK: Icons and scaling for volume control
cb596d4fbe PELROCK: Volume icons scale up/down with left button rather than click
4fefe69117 PELROCK: Implements volume controls
9333118fe9 PELROCK: Sounds in menu
7aff19c6ea sve thumbnail
cf6c76d0f5 PELROCK: Saves games with the right thumbnail
48b3c9d8d9 PELROCK: First implementation of sliding screensaver
9e1917d9f0 PELROCK: Enables fake teeth animation in room 3, increases amount of random responses
a7ded25994 PELROCK: Fixes for interaction with the statue in room 7
c507068bb2 PELROCK: Refactors main menu and adds confirmation upon exit
1d6826d392 PELROCK: Implements original save/load screens
7f8b161088 PELROCK: Missing actions
9954449942 PELROCK: Fixes conversation bug (present in the original) in room 45
e35f47c289 PELROCK: Fixes exit confirmation
5708dae5d5 PELROCK: Fixes styling of saving name input
2b1bcc34dc PELROCK: Fixes spells in spellbook having extraneous characters
9ede09dccf PELROCK: Amend checkConversation signature
6b269d2203 PELROCK: Fixes bug (present in the original) when handing books to librarian or using them on alfred
b74947e4da PELROCK: Allows loading from ScummVM's main menu
a5964bf279 PELROCK: Fixes extraneous characters on intro's subtitles
c1c9772c50 PELROCK: Fixes bug (present in the original) where endless loop can happen during conversation
67735982b7 PELROCK: Fixes not being able to use stuff with Alfred from inventory overlay
780c84181b PELROCK: Fix sounds in inventory to leave click as default sound
13834000a9 PELROCK: Scale tile shuffling with tile count in sliding puzzle minigame
e31fce39dd PELROCK: Improves anti-piracy joke
b6f5b1bd5a PELROCK: Fixes bug that would make travel agency inaccesible
d3e3cb2d7d PELROCK: Fix extraneous idle Alfred showing up after being eaten by croc
027a91d16b PELROCK: Ensure same ambient sound doesnt overlap with itself
ecd269a800 PELROCK: Clear inventory before time travelling
dd1ab34e35 PELROCK: Cleanup video, fonts and actions
ffd5b9652e PELROCK: Cleanup of dialog and computer
89189c032b PELROCK: Cleanup of menu and graphics
cf7004677e PELROCK: Cleanup of pathfinding and room
9afa4e1c63 PELROCK: Cleanup of sound and spellbook
903b6e4d22 PELROCK: Cleanup utils
ce2b01f4fa PELROCK: Types cleanup
34129b6bff PELROCK: Cleanup of offsets
cb81706019 PELROCK: Fix warnings
13330521f9 PELROCK: Move inventory item sounds lookup table into implementation
97c26c5ec3 PELROCK: Rename size constants for custom fonts
5977e6a2f3 PELROCK: Removal of warnings due to incompatible types
c5b87203f0 PELROCK: Fix mismatched free/deletes
98b3285bae PELROCK: Fixes leak on Dialog surface
1e2346f201 PELROCK: Fixes leak with passer-by-animations and palette animations
d81b5918a5 PELROCK: Make sure to clear animations before loading new ones
ee7fa87c94 PELROCK: Fix menu buttons not being cleared
b827ac0f9b PELROCK: Fixes leak in room reset data
693a07ddec PELROCK: Fix savegame data leak
fefda1a14e PELROCK: Avoid leaking choice list
a9f9e974d0 PELROCK: Make sure to free all pointers in room, pelrock and resources
1653e473e9 PELROCK: Moves sticker pixel data into its own structure
6c8e9d1496 PELROCK: Fix leak when loading game, and on conversation exit
5a73a5c07a PELROCK: Fix error when converting offsets
fab16d9824 PELROCK: Consolidate drawColoredTexts functions in graphics
c1e9301f6b PELROCK: Make crocodile sprite stick in crocodile sequence
920635b2f4 PELROCK: Improvements on idle animation and screensaver minigame
c2cf7a3d40 PELROCK: Fix scaling algorithm so feet arent cropped
c128562144 PELROCK: Add option to disable screensaver
c849d9789c PELROCK: Cleanup of pelrock.cpp
d7b1739e88 PELROCK: Fix sticker in egyptian museum door
9c2bfd6fb0 PELROCK: Set extra flags in case they are needed
e37bc9064d PELROCK: Translate flag names into English (from the original Spanish)
97706b2f17 PELROCK: Introduce getBoolFlag to prevent unsafe comparison on Windows
d4878a08f9 PELROCK: Normalize types for chrono
ebb2a7be7c PELROCK: Remove extraneous debug lines
244339e0fb PELROCK: Fix double-free after swimming pool cutscene
16fae188a6 PELROCK: Credits
7707b16203 PELROCK: Remove unnecessary files
f968301d6f PELROCK: Make sure to free textSurface in intro video
23a9a6592b PELROCK: Move video to root of the engine
a89f9d1c53 PELROCK: Header cleanup
a25a581670 PELROCK: Cleans up sliding puzzle
e84cbd9ff2 PELROCK: Decorate errors with function signature
9e1d34ce2e PELROCK: Simplify pixel setting in fonts
c83cb780a1 PELROCK: Fixes on syntax according to code reviews
1dfb93703d PELROCK: Syntax fixes from code reviews
a51d5b0afb PELROCK: Added ALFRED.2 to the detection tables
e87dd28ce1 PELROCK: Replace usage of char with byte where platform sensitive
963da1bbe5 PELROCK: Remove statics from room header
828574c3f5 PELROCK: Create menu sfx utility functions
b3bfc1776e PELROCK: Refactor Room metadata loading so it doesnt return by value
8534001165 PELROCK: Fix warnings on overflowing chars
d44fc4aaa5 PELROCK: Remove duplicate logic into resetPasserByAnim
e71a30c895 PELROCK: Create constructor for PasserBy animations
5c953ada38 PELROCK: Creates macro for deleting button sprites in menu
fa6b927ca8 PELROCK: Fixes talking animation occasionally not advancing frames on original timing
Commit: d698c4885d76c9e5c20c62485b6f4ad4afd66a09
https://github.com/scummvm/scummvm/commit/d698c4885d76c9e5c20c62485b6f4ad4afd66a09
Author: gsanmartin (gabriel.sanmartin at dna.inc)
Date: 2026-05-05T12:58:57+02:00
Commit Message:
PELROCK: Initial engine skeleton
Changed paths:
A engines/pelrock/POTFILES
A engines/pelrock/configure.engine
A engines/pelrock/console.cpp
A engines/pelrock/console.h
A engines/pelrock/credits.pl
A engines/pelrock/detection.cpp
A engines/pelrock/detection.h
A engines/pelrock/detection_tables.h
A engines/pelrock/metaengine.cpp
A engines/pelrock/metaengine.h
A engines/pelrock/module.mk
A engines/pelrock/pelrock.cpp
A engines/pelrock/pelrock.h
diff --git a/engines/pelrock/POTFILES b/engines/pelrock/POTFILES
new file mode 100644
index 00000000000..c09b6bf0735
--- /dev/null
+++ b/engines/pelrock/POTFILES
@@ -0,0 +1 @@
+engines/pelrock/metaengine.cpp
diff --git a/engines/pelrock/configure.engine b/engines/pelrock/configure.engine
new file mode 100644
index 00000000000..a4ac40cb140
--- /dev/null
+++ b/engines/pelrock/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
+add_engine pelrock "Pelrock" no "" "" "" ""
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
new file mode 100644
index 00000000000..1964cb5e3f6
--- /dev/null
+++ b/engines/pelrock/console.cpp
@@ -0,0 +1,38 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "pelrock/console.h"
+
+namespace Pelrock {
+
+Console::Console() : GUI::Debugger() {
+ registerCmd("test", WRAP_METHOD(Console, Cmd_test));
+}
+
+Console::~Console() {
+}
+
+bool Console::Cmd_test(int argc, const char **argv) {
+ debugPrintf("Test\n");
+ return true;
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/console.h b/engines/pelrock/console.h
new file mode 100644
index 00000000000..f17d71e587e
--- /dev/null
+++ b/engines/pelrock/console.h
@@ -0,0 +1,40 @@
+
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PELROCK_CONSOLE_H
+#define PELROCK_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Pelrock {
+
+class Console : public GUI::Debugger {
+private:
+ bool Cmd_test(int argc, const char **argv);
+public:
+ Console();
+ ~Console() override;
+};
+
+} // End of namespace Pelrock
+
+#endif // PELROCK_CONSOLE_H
diff --git a/engines/pelrock/credits.pl b/engines/pelrock/credits.pl
new file mode 100644
index 00000000000..3f3ab6a82f2
--- /dev/null
+++ b/engines/pelrock/credits.pl
@@ -0,0 +1,3 @@
+begin_section("Pelrock");
+ add_person("Name 1", "Handle 1", "");
+end_section();
diff --git a/engines/pelrock/detection.cpp b/engines/pelrock/detection.cpp
new file mode 100644
index 00000000000..d0b46ac7502
--- /dev/null
+++ b/engines/pelrock/detection.cpp
@@ -0,0 +1,45 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "base/plugins.h"
+#include "common/config-manager.h"
+#include "common/file.h"
+#include "common/md5.h"
+#include "common/str-array.h"
+#include "common/translation.h"
+#include "common/util.h"
+#include "pelrock/detection.h"
+#include "pelrock/detection_tables.h"
+
+const DebugChannelDef PelrockMetaEngineDetection::debugFlagList[] = {
+ { Pelrock::kDebugGraphics, "Graphics", "Graphics debug level" },
+ { Pelrock::kDebugPath, "Path", "Pathfinding debug level" },
+ { Pelrock::kDebugFilePath, "FilePath", "File path debug level" },
+ { Pelrock::kDebugScan, "Scan", "Scan for unrecognised games" },
+ { Pelrock::kDebugScript, "Script", "Enable debug script dump" },
+ DEBUG_CHANNEL_END
+};
+
+PelrockMetaEngineDetection::PelrockMetaEngineDetection() : AdvancedMetaEngineDetection(
+ Pelrock::gameDescriptions, Pelrock::pelrockGames) {
+}
+
+REGISTER_PLUGIN_STATIC(PELROCK_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, PelrockMetaEngineDetection);
diff --git a/engines/pelrock/detection.h b/engines/pelrock/detection.h
new file mode 100644
index 00000000000..263ea2e9ac3
--- /dev/null
+++ b/engines/pelrock/detection.h
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PELROCK_DETECTION_H
+#define PELROCK_DETECTION_H
+
+#include "engines/advancedDetector.h"
+
+namespace Pelrock {
+
+enum PelrockDebugChannels {
+ kDebugGraphics = 1,
+ kDebugPath,
+ kDebugScan,
+ kDebugFilePath,
+ kDebugScript,
+};
+
+extern const PlainGameDescriptor pelrockGames[];
+
+extern const ADGameDescription gameDescriptions[];
+
+#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
+
+} // End of namespace Pelrock
+
+class PelrockMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
+ static const DebugChannelDef debugFlagList[];
+
+public:
+ PelrockMetaEngineDetection();
+ ~PelrockMetaEngineDetection() override {}
+
+ const char *getName() const override {
+ return "pelrock";
+ }
+
+ const char *getEngineName() const override {
+ return "Pelrock";
+ }
+
+ const char *getOriginalCopyright() const override {
+ return "Pelrock (C)";
+ }
+
+ const DebugChannelDef *getDebugChannels() const override {
+ return debugFlagList;
+ }
+};
+
+#endif // PELROCK_DETECTION_H
diff --git a/engines/pelrock/detection_tables.h b/engines/pelrock/detection_tables.h
new file mode 100644
index 00000000000..3faf9ddbcf5
--- /dev/null
+++ b/engines/pelrock/detection_tables.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Pelrock {
+
+const PlainGameDescriptor pelrockGames[] = {
+ { "pelrock", "Pelrock" },
+ { 0, 0 }
+};
+
+const ADGameDescription gameDescriptions[] = {
+ {
+ "pelrock",
+ nullptr,
+ AD_ENTRY1s("file1.bin", "00000000000000000000000000000000", 11111),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/metaengine.cpp b/engines/pelrock/metaengine.cpp
new file mode 100644
index 00000000000..a6268bedeaf
--- /dev/null
+++ b/engines/pelrock/metaengine.cpp
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/translation.h"
+
+#include "pelrock/metaengine.h"
+#include "pelrock/detection.h"
+#include "pelrock/pelrock.h"
+
+namespace Pelrock {
+
+static const ADExtraGuiOptionsMap optionsList[] = {
+ {
+ GAMEOPTION_ORIGINAL_SAVELOAD,
+ {
+ _s("Use original save/load screens"),
+ _s("Use the original save/load screens instead of the ScummVM ones"),
+ "original_menus",
+ false,
+ 0,
+ 0
+ }
+ },
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
+} // End of namespace Pelrock
+
+const char *PelrockMetaEngine::getName() const {
+ return "pelrock";
+}
+
+const ADExtraGuiOptionsMap *PelrockMetaEngine::getAdvancedExtraGuiOptions() const {
+ return Pelrock::optionsList;
+}
+
+Common::Error PelrockMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ *engine = new Pelrock::PelrockEngine(syst, desc);
+ return Common::kNoError;
+}
+
+bool PelrockMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return checkExtendedSaves(f) ||
+ (f == kSupportsLoadingDuringStartup);
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(PELROCK)
+REGISTER_PLUGIN_DYNAMIC(PELROCK, PLUGIN_TYPE_ENGINE, PelrockMetaEngine);
+#else
+REGISTER_PLUGIN_STATIC(PELROCK, PLUGIN_TYPE_ENGINE, PelrockMetaEngine);
+#endif
diff --git a/engines/pelrock/metaengine.h b/engines/pelrock/metaengine.h
new file mode 100644
index 00000000000..d1649be567f
--- /dev/null
+++ b/engines/pelrock/metaengine.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PELROCK_METAENGINE_H
+#define PELROCK_METAENGINE_H
+
+#include "engines/advancedDetector.h"
+
+class PelrockMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
+public:
+ const char *getName() const override;
+
+ Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
+
+ /**
+ * Determine whether the engine supports the specified MetaEngine feature.
+ *
+ * Used by e.g. the launcher to determine whether to enable the Load button.
+ */
+ bool hasFeature(MetaEngineFeature f) const override;
+
+ const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override;
+};
+
+#endif // PELROCK_METAENGINE_H
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
new file mode 100644
index 00000000000..5a2724a9990
--- /dev/null
+++ b/engines/pelrock/module.mk
@@ -0,0 +1,17 @@
+MODULE := engines/pelrock
+
+MODULE_OBJS = \
+ pelrock.o \
+ console.o \
+ metaengine.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
+
+# Detection objects
+DETECT_OBJS += $(MODULE)/detection.o
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
new file mode 100644
index 00000000000..85bb1a67cc6
--- /dev/null
+++ b/engines/pelrock/pelrock.cpp
@@ -0,0 +1,109 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "pelrock/pelrock.h"
+#include "graphics/framelimiter.h"
+#include "pelrock/detection.h"
+#include "pelrock/console.h"
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/events.h"
+#include "common/system.h"
+#include "engines/util.h"
+#include "graphics/paletteman.h"
+
+namespace Pelrock {
+
+PelrockEngine *g_engine;
+
+PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst),
+ _gameDescription(gameDesc), _randomSource("Pelrock") {
+ g_engine = this;
+}
+
+PelrockEngine::~PelrockEngine() {
+ delete _screen;
+}
+
+uint32 PelrockEngine::getFeatures() const {
+ return _gameDescription->flags;
+}
+
+Common::String PelrockEngine::getGameId() const {
+ return _gameDescription->gameId;
+}
+
+Common::Error PelrockEngine::run() {
+ // Initialize 320x200 paletted graphics mode
+ initGraphics(320, 200);
+ _screen = new Graphics::Screen();
+
+ // Set the engine's debugger console
+ setDebugger(new Console());
+
+ // If a savegame was selected from the launcher, load it
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (saveSlot != -1)
+ (void)loadGameState(saveSlot);
+
+ // Draw a series of boxes on screen as a sample
+ for (int i = 0; i < 100; ++i)
+ _screen->frameRect(Common::Rect(i, i, 320 - i, 200 - i), i);
+ _screen->update();
+
+ // Simple event handling loop
+ byte pal[256 * 3] = { 0 };
+ Common::Event e;
+ int offset = 0;
+
+ Graphics::FrameLimiter limiter(g_system, 60);
+ while (!shouldQuit()) {
+ while (g_system->getEventManager()->pollEvent(e)) {
+ }
+
+ // Cycle through a simple palette
+ ++offset;
+ for (int i = 0; i < 256; ++i)
+ pal[i * 3 + 1] = (i + offset) % 256;
+ g_system->getPaletteManager()->setPalette(pal, 0, 256);
+ // Delay for a bit. All events loops should have a delay
+ // to prevent the system being unduly loaded
+ limiter.delayBeforeSwap();
+ _screen->update();
+ limiter.startFrame();
+ }
+
+ return Common::kNoError;
+}
+
+Common::Error PelrockEngine::syncGame(Common::Serializer &s) {
+ // The Serializer has methods isLoading() and isSaving()
+ // if you need to specific steps; for example setting
+ // an array size after reading it's length, whereas
+ // for saving it would write the existing array's length
+ int dummy = 0;
+ s.syncAsUint32LE(dummy);
+
+ return Common::kNoError;
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
new file mode 100644
index 00000000000..4ce714f965d
--- /dev/null
+++ b/engines/pelrock/pelrock.h
@@ -0,0 +1,105 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PELROCK_H
+#define PELROCK_H
+
+#include "common/scummsys.h"
+#include "common/system.h"
+#include "common/error.h"
+#include "common/fs.h"
+#include "common/hash-str.h"
+#include "common/random.h"
+#include "common/serializer.h"
+#include "common/util.h"
+#include "engines/engine.h"
+#include "engines/savestate.h"
+#include "graphics/screen.h"
+
+#include "pelrock/detection.h"
+
+namespace Pelrock {
+
+struct PelrockGameDescription;
+
+class PelrockEngine : public Engine {
+private:
+ const ADGameDescription *_gameDescription;
+ Common::RandomSource _randomSource;
+protected:
+ // Engine APIs
+ Common::Error run() override;
+public:
+ Graphics::Screen *_screen = nullptr;
+public:
+ PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
+ ~PelrockEngine() override;
+
+ uint32 getFeatures() const;
+
+ /**
+ * Returns the game Id
+ */
+ Common::String getGameId() const;
+
+ /**
+ * Gets a random number
+ */
+ uint32 getRandomNumber(uint maxNum) {
+ return _randomSource.getRandomNumber(maxNum);
+ }
+
+ bool hasFeature(EngineFeature f) const override {
+ return
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime) ||
+ (f == kSupportsReturnToLauncher);
+ };
+
+ bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override {
+ return true;
+ }
+ bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override {
+ return true;
+ }
+
+ /**
+ * Uses a serializer to allow implementing savegame
+ * loading and saving using a single method
+ */
+ Common::Error syncGame(Common::Serializer &s);
+
+ Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override {
+ Common::Serializer s(nullptr, stream);
+ return syncGame(s);
+ }
+ Common::Error loadGameStream(Common::SeekableReadStream *stream) override {
+ Common::Serializer s(stream, nullptr);
+ return syncGame(s);
+ }
+};
+
+extern PelrockEngine *g_engine;
+#define SHOULD_QUIT ::Pelrock::g_engine->shouldQuit()
+
+} // End of namespace Pelrock
+
+#endif // PELROCK_H
Commit: 8583a0febd726a12eb7f5d425374066ee25a66fd
https://github.com/scummvm/scummvm/commit/8583a0febd726a12eb7f5d425374066ee25a66fd
Author: gsanmartin (gabriel.sanmartin at dna.inc)
Date: 2026-05-05T12:58:58+02:00
Commit Message:
PELROCK: Loads scene and main character
Changed paths:
A engines/pelrock/.gitignore
A engines/pelrock/types.h
engines/pelrock/detection_tables.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/.gitignore b/engines/pelrock/.gitignore
new file mode 100644
index 00000000000..7e97ef32309
--- /dev/null
+++ b/engines/pelrock/.gitignore
@@ -0,0 +1,3 @@
+*.o
+*.a
+.deps
diff --git a/engines/pelrock/detection_tables.h b/engines/pelrock/detection_tables.h
index 3faf9ddbcf5..f4c05cbab9e 100644
--- a/engines/pelrock/detection_tables.h
+++ b/engines/pelrock/detection_tables.h
@@ -30,7 +30,7 @@ const ADGameDescription gameDescriptions[] = {
{
"pelrock",
nullptr,
- AD_ENTRY1s("file1.bin", "00000000000000000000000000000000", 11111),
+ AD_ENTRY1s("ALFRED.1", "ee0047cfcceece9c4f6a426245b6f449", 12915352),
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_UNSTABLE,
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 85bb1a67cc6..5aaf7421da7 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -19,24 +19,30 @@
*
*/
-#include "pelrock/pelrock.h"
-#include "graphics/framelimiter.h"
-#include "pelrock/detection.h"
-#include "pelrock/console.h"
-#include "common/scummsys.h"
#include "common/config-manager.h"
#include "common/debug-channels.h"
#include "common/events.h"
+#include "common/file.h"
+#include "common/scummsys.h"
#include "common/system.h"
#include "engines/util.h"
+#include "graphics/cursorman.h"
+#include "graphics/framelimiter.h"
#include "graphics/paletteman.h"
+#include "image/pcx.h"
+#include "image/png.h"
+
+#include "pelrock.h"
+#include "pelrock/console.h"
+#include "pelrock/detection.h"
+#include "pelrock/pelrock.h"
namespace Pelrock {
PelrockEngine *g_engine;
PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst),
- _gameDescription(gameDesc), _randomSource("Pelrock") {
+ _gameDescription(gameDesc), _randomSource("Pelrock") {
g_engine = this;
}
@@ -54,7 +60,7 @@ Common::String PelrockEngine::getGameId() const {
Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
- initGraphics(320, 200);
+ initGraphics(640, 400);
_screen = new Graphics::Screen();
// Set the engine's debugger console
@@ -65,28 +71,23 @@ Common::Error PelrockEngine::run() {
if (saveSlot != -1)
(void)loadGameState(saveSlot);
- // Draw a series of boxes on screen as a sample
- for (int i = 0; i < 100; ++i)
- _screen->frameRect(Common::Rect(i, i, 320 - i, 200 - i), i);
- _screen->update();
-
// Simple event handling loop
- byte pal[256 * 3] = { 0 };
Common::Event e;
- int offset = 0;
-
Graphics::FrameLimiter limiter(g_system, 60);
+
+ init();
+ if (shouldPlayIntro == false) {
+ stateGame = GAME;
+ } else {
+ stateGame = INTRO;
+ playIntro();
+ }
+
while (!shouldQuit()) {
while (g_system->getEventManager()->pollEvent(e)) {
}
-
- // Cycle through a simple palette
- ++offset;
- for (int i = 0; i < 256; ++i)
- pal[i * 3 + 1] = (i + offset) % 256;
- g_system->getPaletteManager()->setPalette(pal, 0, 256);
- // Delay for a bit. All events loops should have a delay
- // to prevent the system being unduly loaded
+ frames();
+ _screen->update();
limiter.delayBeforeSwap();
_screen->update();
limiter.startFrame();
@@ -95,6 +96,1823 @@ Common::Error PelrockEngine::run() {
return Common::kNoError;
}
+void PelrockEngine::init() {
+ CursorMan.setDefaultArrowCursor();
+ CursorMan.showMouse(true);
+ if (gameInitialized == false) {
+ pixelsShadows = new byte[640 * 400];
+ // sabeUsarElLibroMagico = 0;
+ // magicWords = false;
+ // apagaLaLuz = false;
+ // showUsingObject = -1;
+ // prevWhichScreen = -1;
+ // whichScreen = -1;
+ gameInitialized = true;
+
+ // tutorial.init();
+
+ prevDirX = 0;
+ prevDirY = 0;
+ dirAlfred = 2;
+
+ objectToShow = "";
+
+ // factX = (float) widthScreen / (float) 640.0f;
+ // factY = (float) heightScreen / (float) 400.0f;
+
+ // xAlfred = (186 * factX);
+ // yAlfred = (307 * factY);
+ // xAlfred = 186;
+ // yAlfred = 307;
+
+ // for (int i = 0; i < 14; i++)
+ // {
+ // myPestanas[i].x = (int) ((float) myPestanas[i].x * factX);
+ // myPestanas[i].y = (int) ((float) myPestanas[i].y * factY);
+ // myPestanas[i].w = (int) ((float) myPestanas[i].w * factX);
+ // myPestanas[i].h = (int) ((float) myPestanas[i].h * factY);
+ // }
+
+ // movingAlfred = ALFRED_STOPPED;
+
+ // listUsedBranchs = new LinkedList<Integer>();
+ // listUsedBranchs.clear();
+
+ // listRects = new LinkedList<Integer>();
+ // listRects.clear();
+
+ // timeIddle = SystemClock.uptimeMillis();
+
+ // myListLibros = new LinkedList<libros>();
+ // myListLibros.clear();
+
+ // myListDesactAnims = new LinkedList<dactAnims>();
+ // myListDesactAnims.clear();
+
+ // myListChangesConvs = new LinkedList<changesConvs>();
+ // myListChangesConvs.clear();
+
+ // myListPegas = new LinkedList<pegas>();
+ // myListPegas.clear();
+
+ // myListObjects = new LinkedList<objects>();
+ // myListObjects.clear();
+
+ // myListUsingObjects = new LinkedList<Integer>();
+ // myListUsingObjects.clear();
+
+ // isPersonajeTalking = -1;
+
+ // stanteriaABuscar = -1;
+
+ // selectedUsingObject = false;
+
+ // currentTrack = "";
+
+ // mainVolumen = 50;
+ // mainTextSpeed = 50;
+
+ // extraDataToSave = new byte[98];
+
+ // leeLibros();
+ // myoverlay.setCredits();
+ loadAnims();
+ // loadOtherBitmaps();
+ setScreen(0, 2);
+ // setScreen(0, 2);
+ // valSound1 = 0;
+ // valSound2 = 0;
+ // valSound3 = 0;
+
+ // loadExtraTextsToTranslate();
+
+ // loadTutorialText();
+
+ // if (myMainActivity == null)
+ // myMainActivity = this;// new AlfredActivity();
+
+ // this.addContentView(myoverlay,
+ // new android.view.ViewGroup.LayoutParams(
+ // android.view.ViewGroup.LayoutParams.FILL_PARENT,
+ // android.view.ViewGroup.LayoutParams.FILL_PARENT));
+
+ // settingsLayout = new RelativeLayout(myContext);
+ // settingsLayout
+ // .setLayoutParams(new android.view.ViewGroup.LayoutParams(
+ // android.view.ViewGroup.LayoutParams.FILL_PARENT,
+ // android.view.ViewGroup.LayoutParams.FILL_PARENT));
+
+ // settingsElem1 = new SeekBar(myContext);
+ // settingsElem2 = new SeekBar(myContext);
+ // settingsElem3 = new Spinner(myContext);
+ // settingsElem4 = new Button(myContext);
+
+ // String[] items = new String[myLanguages.length];// {"English",
+ // // "Spanish",
+ // // "Three"};
+ // for (i = 0; i < myLanguages.length; i++)
+ // {
+ // items[i] = new String();
+ // items[i] = myLanguages[i].nShow;
+ // }
+
+ // mySpinAdapter<String> adapter = new mySpinAdapter<String>(myContext,
+ // items);
+
+ // settingsElem3.setAdapter(adapter);
+
+ // settingsElem3.setSelection(whichLanguageIndex);
+
+ // String stringTutorial = "";
+ // String namet = AlfredActivity.destinationFolder + "/tutorial.kk";
+ // File ft = new File(namet);
+
+ // if (ft.exists() == true)
+ // {
+ // byte b[] = tools.readFile(namet);
+ // b[0]++;
+
+ // if (b[0] >= 3)
+ // {
+ // b[0] = 3;
+ // playTutorial = false;
+ // stringTutorial = "OFF";
+ // } else
+ // {
+ // playTutorial = true;
+ // stringTutorial = "ON";
+ // }
+
+ // tools.createFile(namet, b);
+
+ // } else
+ // {
+ // byte b[] = new byte[1];
+
+ // b[0] = 0;
+
+ // tools.createFile(namet, b);
+ // playTutorial = true;
+ // stringTutorial = "ON";
+ // }
+
+ // String finalText = "Tutorial " + stringTutorial;
+
+ // settingsElem4.setText(finalText);
+ // settingsElem4.postInvalidate();
+ // settingsElem4.setBackgroundColor(0x00000000);
+
+ // settingsElem1.setOnSeekBarChangeListener(
+ // new SeekBar.OnSeekBarChangeListener()
+ // {
+
+ // public void onProgressChanged(SeekBar seekBar,
+ // int progress, boolean fromTouch)
+ // {
+ // setVolumen(progress);
+ // }
+
+ // public void onStartTrackingTouch(SeekBar seekBar)
+ // {
+ // }
+
+ // public void onStopTrackingTouch(SeekBar seekBar)
+ // {
+ // }
+ // });
+ // settingsElem2.setOnSeekBarChangeListener(
+ // new SeekBar.OnSeekBarChangeListener()
+ // {
+
+ // public void onProgressChanged(SeekBar seekBar,
+ // int progress, boolean fromTouch)
+ // {
+ // // mainTextSpeed=progress;
+ // factTimeToShow = 10 + (100 - progress);
+ // }
+
+ // public void onStartTrackingTouch(SeekBar seekBar)
+ // {
+ // }
+
+ // public void onStopTrackingTouch(SeekBar seekBar)
+ // {
+ // }
+ // });
+
+ // settingsElem3.setOnItemSelectedListener(new OnItemSelectedListener()
+ // {
+
+ // @Override
+ // public void onItemSelected(AdapterView<?> arg0, View arg1,
+ // int arg2, long arg3)
+ // {
+
+ // // trying to avoid undesired spinner selection changed
+ // // event, a known problem
+ // if (m_intSpinnerInitiCount < NO_OF_EVENTS)
+ // {
+ // m_intSpinnerInitiCount++;
+ // } else
+ // {
+ // whichLanguage = myLanguages[arg2].nInternal;
+ // whichLanguageInt = arg2;
+ // loadExtraTextsToTranslate();
+ // setScreen(whichScreen, dirAlfred);
+ // leeLibros();
+ // myoverlay.setCredits();
+ // loadTutorialText();
+ // }
+ // }
+
+ // @Override
+ // public void onNothingSelected(AdapterView<?> arg0)
+ // {
+
+ // }
+
+ // });
+
+ // // set up list view
+ // //////////////////
+ // saveLoadLayout = new LinearLayout(myContext);
+ // saveLoadLayout
+ // .setLayoutParams(new android.view.ViewGroup.LayoutParams(
+ // android.view.ViewGroup.LayoutParams.FILL_PARENT,
+ // android.view.ViewGroup.LayoutParams.FILL_PARENT));
+
+ // saveLoadListView = new ListView(myContext);
+
+ // saveLoadListView.setOnItemClickListener(new OnItemClickListener()
+ // {
+
+ // @Override
+ // public void onItemClick(AdapterView<?> arg0, View arg1,
+ // final int arg2, long arg3)
+ // {
+
+ // if (saveOrLoad == 0)// save
+ // {
+
+ // AlertDialog.Builder alert = new AlertDialog.Builder(
+ // myContext);
+
+ // alert.setTitle("Dreamtripper");
+ // alert.setMessage(extraThingsToTranslate[4]);
+ // alert.setIcon(R.drawable.alfred);
+ // final EditText input = new EditText(myContext);
+ // String pp = nombrePartidas[arg2];
+ // if (pp.compareTo(extraThingsToTranslate[7]) == 0)
+ // pp = "";
+ // input.setText(pp);
+ // alert.setView(input);
+
+ // alert.setPositiveButton("Ok",
+ // new DialogInterface.OnClickListener()
+ // {
+ // public void onClick(DialogInterface dialog,
+ // int whichButton)
+ // {
+ // grabaPartida(arg2,
+ // input.getText().toString());
+ // tools.showMessage(myContext,
+ // "Dreamtripper",
+ // extraThingsToTranslate[6],
+ // "OK");
+ // getNamesPartidas();
+ // }
+ // });
+
+ // alert.setNegativeButton("Cancel",
+ // new DialogInterface.OnClickListener()
+ // {
+ // public void onClick(DialogInterface dialog,
+ // int whichButton)
+ // {
+ // }
+ // });
+
+ // alert.show();
+
+ // } else
+ // {// load
+
+ // cargaPartida(arg2);
+
+ // }
+
+ // }
+
+ // });
+
+ // saveLoadLayout.addView(saveLoadListView,
+ // new android.view.ViewGroup.LayoutParams(
+ // android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
+ // android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ // settingsLayout.addView(settingsElem1,
+ // new android.view.ViewGroup.LayoutParams(
+ // (int) ((float) 180 * factX),
+ // (int) ((float) 50 * factY)));
+
+ // settingsLayout.addView(settingsElem2,
+ // new android.view.ViewGroup.LayoutParams(
+ // (int) ((float) 180 * factX),
+ // (int) ((float) 50 * factY)));
+
+ // settingsLayout.addView(settingsElem3,
+ // new android.view.ViewGroup.LayoutParams(
+ // (int) ((float) 120 * factX),
+ // (int) ((float) 50 * factY)));
+
+ // settingsLayout.addView(settingsElem4,
+ // new android.view.ViewGroup.LayoutParams(
+ // (int) ((float) 130 * factX),
+ // (int) ((float) 50 * factY)));
+
+ // ViewGroup.MarginLayoutParams mlp2 = (ViewGroup.MarginLayoutParams) settingsElem1
+ // .getLayoutParams();
+ // mlp2.setMargins((int) ((float) 300 * factX),
+ // (int) ((float) 195 * factY),
+ // (int) ((float) (640 - 460) * factX),
+ // (int) ((float) (400 - 245) * factY));
+
+ // ViewGroup.MarginLayoutParams mlp3 = (ViewGroup.MarginLayoutParams) settingsElem2
+ // .getLayoutParams();
+ // mlp3.setMargins((int) ((float) 300 * factX),
+ // (int) ((float) 235 * factY),
+ // (int) ((float) (640 - 460) * factX),
+ // (int) ((float) (400 - 285) * factY));
+
+ // ViewGroup.MarginLayoutParams mlp4 = (ViewGroup.MarginLayoutParams) settingsElem3
+ // .getLayoutParams();
+ // mlp4.setMargins((int) ((float) 340 * factX),
+ // (int) ((float) 285 * factY),
+ // (int) ((float) (640 - 460) * factX),
+ // (int) ((float) (400 - 325) * factY));
+
+ // ViewGroup.MarginLayoutParams mlp5 = (ViewGroup.MarginLayoutParams) settingsElem4
+ // .getLayoutParams();
+ // mlp5.setMargins((int) ((float) 210 * factX),
+ // (int) ((float) 285 * factY),
+ // (int) ((float) (640 - 360) * factX),
+ // (int) ((float) (400 - 325) * factY));
+
+ // ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) saveLoadListView
+ // .getLayoutParams();
+ // mlp.setMargins((int) ((float) 223 * factX),
+ // (int) ((float) 200 * factY),
+ // (int) ((float) (640 - 466) * factX),
+ // (int) ((float) (400 - 312) * factY));
+
+ // settingsElem1.setProgress(mainVolumen);
+ // settingsElem2.setProgress(mainTextSpeed);
+
+ // this.addContentView(saveLoadLayout,
+ // new android.view.ViewGroup.LayoutParams(
+ // android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
+ // android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ // this.addContentView(settingsLayout,
+ // new android.view.ViewGroup.LayoutParams(
+ // android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
+ // android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ // settingsElem4.setOnClickListener(new OnClickListener()
+ // {
+
+ // @Override
+ // public void onClick(View arg0)
+ // {
+
+ // String stringTutorial = "";
+ // String namet = AlfredActivity.destinationFolder
+ // + "/tutorial.kk";
+
+ // byte b[] = tools.readFile(namet);
+ // if (playTutorial == false)// (b[0]==0)
+ // {
+ // b[0] = 0;
+ // playTutorial = true;
+ // stringTutorial = "ON";
+
+ // tutorial.init();
+
+ // } else
+ // {
+ // b[0] = 4;
+ // playTutorial = false;
+ // stringTutorial = "OFF";
+ // }
+
+ // tools.createFile(namet, b);
+
+ // String fiinalText = "Tutorial " + stringTutorial;
+
+ // settingsElem4.setText(fiinalText);
+ // settingsElem4.postInvalidate();
+
+ // }
+
+ // });
+
+ // hideList();
+ // hideSettings();
+
+ // myExtraText = new extraText();
+
+ // String name = AlfredActivity.destinationFolder + "/test.kk";
+ // File f = new File(name);
+ // if (f.exists() == true)
+ // {
+ // byte b[] = tools.readFile(name);
+
+ // if (b[0] < 3)
+ // {
+ // b[0]++;
+ // playIntro = true;
+ // } else
+ // playIntro = false;
+
+ // tools.createFile(name, b);
+
+ // } else
+ // {
+ // byte b[] = new byte[1];
+
+ // b[0] = 0;
+ // tools.createFile(name, b);
+ // playIntro = true;
+ // }
+
+ // // playIntro=true;
+ // if (playIntro == false)
+ // {
+ // stateGame = GAME;
+ // } else
+ // {
+
+ // stateGame = INTRO;
+ // varCheckRealTime = 0;
+ // getWindow().setFormat(PixelFormat.TRANSLUCENT);
+ // videoHolder = new myVideoView(this);
+
+ // videoHolder.setWH(widthScreen, heightScreen);
+
+ // // videoHolder.setLayoutParams(params)
+
+ // Uri video = Uri.parse("android.resource://" + getPackageName()
+ // + "/" + R.raw.intro2); // do not add any extension
+ // videoHolder.setVideoURI(video);
+
+ // LinearLayout.LayoutParams paramsVideo = new LinearLayout.LayoutParams(
+ // widthScreen, heightScreen);
+
+ // videoOverlay vo = new videoOverlay(myContext, assetManager,
+ // videoHolder);
+
+ // this.addContentView(videoHolder, paramsVideo);// new
+ // // android.view.ViewGroup.LayoutParams(paramsVideo));
+
+ // this.addContentView(vo, paramsVideo);// new
+ // // android.view.ViewGroup.LayoutParams(paramsVideo));
+
+ // // superTime=SystemClock.uptimeMillis();
+ // videoHolder.start();
+
+ // AlfredActivity.playTrack(22, false);
+
+ // videoHolder.setOnTouchListener(new OnTouchListener()
+ // {
+ // @Override
+ // public boolean onTouch(View arg0, MotionEvent arg1)
+ // {
+ // videoHolder.setVisibility(View.GONE);
+ // videoHolder.stopPlayback();
+
+ // AlfredActivity.myHandler
+ // .sendEmptyMessage(AlfredActivity.INTRO_END);
+
+ // return false;
+ // }
+
+ // });
+
+ // videoHolder.setOnCompletionListener(new OnCompletionListener()
+ // {
+
+ // @Override
+ // public void onCompletion(MediaPlayer arg0)
+ // {
+ // wait2(4000);
+ // }
+
+ // });
+
+ // }
+ }
+}
+
+void PelrockEngine::playIntro() {
+}
+
+void PelrockEngine::loadAnims() {
+ loadMainCharacterAnims();
+ // try
+ // {
+
+ // // andar, acciones y hablar...
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred1.png");
+
+ // for (int i = 0; i < 60; i++)
+ // {
+ // alfredBitmap[i] = Bitmap.createBitmap(mainAlfredAnim, i * 51, 0,
+ // 51, 102);
+ // }
+
+ // mainAlfredAnim.recycle();
+
+ // // andar por el tunel
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred13.png");
+
+ // for (int i = 0; i < 18; i++)
+ // {
+ // alfredBitmap2[i] = Bitmap.createBitmap(mainAlfredAnim, i * 130,
+ // 0, 130, 55);
+ // }
+
+ // mainAlfredAnim.recycle();
+
+ // // animacion de peinarse mirando a la izquierda...
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred2.png");
+
+ // for (int i = 0; i < 11; i++)
+ // alfredBitmapExtra1[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 51, 0, 51, 102);
+
+ // mainAlfredAnim.recycle();
+
+ // // animacion de peinarse mirando a la derecha...
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred3.png");
+
+ // for (int i = 0; i < 11; i++)
+ // alfredBitmapExtra2[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 51, 0, 51, 102);
+
+ // mainAlfredAnim.recycle();
+
+ // // animacion de leer...
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred4.png");
+
+ // for (int i = 0; i < 10; i++)
+ // alfredBitmapExtra3[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 51, 0, 51, 102);
+
+ // // animacion de electrocutarse...
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred5.png");
+
+ // for (int i = 0; i < 8; i++)
+ // alfredBitmapExtra4[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 82, 0, 82, 58);
+
+ // // animacion de cocodrilo...
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/crocodillo.png");
+
+ // for (int i = 0; i < 14; i++)
+ // alfredBitmapExtra5[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 171, 0, 171, 109);
+
+ // // animacion de escondite...
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred6.png");
+
+ // for (int i = 0; i < 12; i++)
+ // alfredBitmapExtra6[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 113, 0, 113, 103);
+
+ // // animacion de bajada al tunel...
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred7.png");
+
+ // for (int i = 0; i < 11; i++)
+ // alfredBitmapExtra7[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 33, 0, 33, 72);
+
+ // // animacion de subida del tunel...
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred8.png");
+
+ // for (int i = 0; i < 9; i++)
+ // alfredBitmapExtra8[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 33, 0, 33, 72);
+
+ // // animacion de escapada del tunel (llega al zoco)
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred9.png");
+
+ // for (int i = 0; i < 16; i++)
+ // alfredBitmapExtra9[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 158, 0, 158, 115);
+
+ // // animacion de puesta del muneco hinchable
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred10.png");
+
+ // for (int i = 0; i < 17; i++)
+ // alfredBitmapExtra10[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 177, 0, 177, 124);
+
+ // // animacion de magia (1)
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/magia1.png");
+
+ // for (int i = 0; i < 11; i++)
+ // alfredBitmapExtra11[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 98, 0, 98, 138);
+
+ // // animacion de magia (2)
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/magia2.png");
+
+ // for (int i = 0; i < 12; i++)
+ // alfredBitmapExtra12[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 98, 0, 98, 138);
+
+ // // animacion de pedras
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred11.png");
+
+ // for (int i = 0; i < 7; i++)
+ // alfredBitmapExtra13[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 208, 0, 208, 102);
+
+ // // animacion de desnudo
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred12.png");
+
+ // for (int i = 0; i < 4; i++)
+ // alfredBitmapExtra14[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 51, 0, 51, 102);
+
+ // // animacion de despertarse
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred14.png");
+
+ // for (int i = 0; i < 14; i++)
+ // alfredBitmapExtra15[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 71, 0, 71, 66);
+
+ // // animacion de tirar piedra
+ // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred15.png");
+
+ // for (int i = 0; i < 4; i++)
+ // alfredBitmapExtra16[i] = Bitmap.createBitmap(mainAlfredAnim,
+ // i * 71, 0, 71, 101);
+
+ // mainAlfredAnim.recycle();
+
+ // } catch (IOException e)
+ // {
+ // }
+}
+
+const int EXPECTED_SIZE = 640 * 400;
+size_t decompress_rle_block(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data) {
+ // Check for uncompressed markers
+ if (size == 0x8000 || size == 0x6800) {
+ *out_data = (uint8_t *)malloc(size);
+ memcpy(*out_data, data + offset, size);
+ return size;
+ }
+
+ // RLE compressed
+ *out_data = (uint8_t *)malloc(EXPECTED_SIZE * 2); // Allocate enough space
+ size_t result_size = 0;
+
+ uint32_t pos = offset;
+ uint32_t end = offset + size;
+
+ while (pos + 2 <= end && pos + 2 <= data_size) {
+ // Check for BUDA marker
+ if (pos + 4 <= data_size &&
+ data[pos] == 'B' && data[pos + 1] == 'U' &&
+ data[pos + 2] == 'D' && data[pos + 3] == 'A') {
+ break;
+ }
+
+ uint8_t count = data[pos];
+ uint8_t value = data[pos + 1];
+
+ for (int i = 0; i < count; i++) {
+ (*out_data)[result_size++] = value;
+ }
+
+ pos += 2;
+ }
+
+ return result_size;
+}
+
+void PelrockEngine::getPalette(Common::File *roomFile, int roomOffset, byte *palette) {
+ // get palette
+ int paletteOffset = roomOffset + (11 * 8);
+ roomFile->seek(paletteOffset, SEEK_SET);
+ uint32 offset = roomFile->readUint32LE();
+ uint32 size = roomFile->readUint32LE();
+
+ roomFile->seek(offset, SEEK_SET);
+
+ roomFile->read(palette, size);
+ for (int i = 0; i < 256; i++) {
+ palette[i * 3] = palette[i * 3] << 2;
+ palette[i * 3 + 1] = palette[i * 3 + 1] << 2;
+ palette[i * 3 + 2] = palette[i * 3 + 2] << 2;
+ }
+
+}
+
+void PelrockEngine::getBackground(Common::File *roomFile, int roomOffset, byte *background) {
+ roomFile->seek(0, SEEK_SET);
+ // get screen
+ size_t combined_size = 0;
+ size_t uncompressed_size = 0;
+ for (int pair_idx = 0; pair_idx < 8; pair_idx++) {
+ uint32_t pair_offset = roomOffset + (pair_idx * 8);
+ if (pair_offset + 8 > roomFile->size())
+ continue;
+
+ roomFile->seek(pair_offset, SEEK_SET);
+ uint32_t offset = roomFile->readUint32LE();
+ uint32_t size = roomFile->readUint32LE();
+ uncompressed_size += size;
+
+ if (offset > 0 && size > 0 && offset < roomFile->size()) {
+ byte *data = new byte[size];
+ roomFile->seek(offset, SEEK_SET);
+ roomFile->read(data, size);
+ uint8_t *block_data = NULL;
+ size_t block_size = decompress_rle_block(data, size, 0, size, &block_data);
+
+ memcpy(background + combined_size, block_data, block_size);
+ combined_size += block_size + 1;
+ free(block_data);
+ delete[] data;
+ }
+ }
+}
+
+void PelrockEngine::loadMainCharacterAnims() {
+ Common::File alfred3;
+ if (!alfred3.open(Common::Path("ALFRED.3"))) {
+ error("Could not open ALFRED.3");
+ return;
+ }
+ int alfred3Size = alfred3.size();
+ unsigned char *bufferFile = (unsigned char *)malloc(alfred3Size);
+ alfred3.seek(0, SEEK_SET);
+ alfred3.read(bufferFile, alfred3Size);
+ alfred3.close();
+
+ int index = 0;
+ int index3 = 0;
+ uint32_t capacity = 3060 * 102;
+ unsigned char *pic = new unsigned char[capacity];
+ decompress_rle_block(bufferFile, alfred3Size, 0, alfred3Size, &pic);
+ memcpy(standingAnim, pic, 3060 * 102);
+}
+
+void PelrockEngine::frames() {
+ for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
+ for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
+ unsigned int src_pos = (curAlfredFrame * kAlfredFrameHeight * kAlfredFrameWidth) + (y * kAlfredFrameWidth) + x;
+ if(standingAnim[src_pos] != 255)
+ _screen->setPixel(x + xAlfred, y + yAlfred, standingAnim[src_pos]);
+ }
+ }
+ _screen->markAllDirty();
+ _screen->update();
+}
+
+void PelrockEngine::setScreen(int number, int dir) {
+
+ Common::File roomFile;
+ if (!roomFile.open(Common::Path("ALFRED.1"))) {
+ error("Could not open ALFRED.1");
+ return;
+ }
+
+
+ int roomOffset = number * kRoomStructSize;
+
+ byte *palette = new byte[256 * 3];
+ getPalette(&roomFile, roomOffset, palette);
+
+ int paletteOffset = roomOffset + (11 * 8);
+ roomFile.seek(paletteOffset, SEEK_SET);
+ uint32 offset = roomFile.readUint32LE();
+
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+
+ byte *background = new byte[640 * 400];
+ getBackground(&roomFile, roomOffset, background);
+ for (int i = 0; i < 640; i++) {
+ for (int j = 0; j < 400; j++) {
+ _screen->setPixel(i, j, background[j * 640 + i]);
+ }
+ }
+ _screen->markAllDirty();
+ roomFile.close();
+ delete[] background;
+ delete[] palette;
+}
+
+void PelrockEngine::setScreenJava(int s, int dir) {
+ screenReady = false;
+ dirAlfred = dir;
+
+ // vueltaALaCarcel = false;
+ // timeToGoToPiss = -1;
+ // myoverlay.shakeScreen = false;
+ // walkingAgain = false;
+
+ // myoverlay.indexCicleColores = 0;
+
+ // stringToShowOnTutorial = "";
+
+ // magicWords = false;
+
+ // myMovingAlfredThread.isOtherTalking = false;
+ // isPersonajeTalking = -1;
+ // myMovingAlfredThread.showTextNowOtros = false;
+
+ // // pantalla................
+ // if (screenBitmap != null)
+ // {
+ // screenBitmap.recycle();
+ // screenBitmap = null;
+ // }
+
+ prevWhichScreen = whichScreen;
+
+ whichScreen = s;
+
+ // objetos.getObjectList(assetManager, s);
+ // objectToShow = "";
+
+ Common::String nameScreen = Common::String::format("pantallas/pantalla%d.png", s);
+ Common::String nameCamino = Common::String::format("caminos/pantalla%d.txt", s);
+
+ Common::File screen;
+ if (!screen.open(Common::Path(nameScreen))) {
+ error("Could not find pantalla!");
+ }
+ decoder->loadStream(screen);
+ Graphics::Palette palette = decoder->getPalette();
+ g_system->getPaletteManager()->setPalette(palette);
+ const Graphics::Surface *surf = decoder->getSurface();
+ if (!surf)
+ error("No surface");
+
+ g_engine->_screen->blitFrom(*surf);
+
+ _screen->markAllDirty();
+
+ // Config c = null;
+ // try
+ // {
+ // screenBitmap = getBitmapFromAsset(nameScreen);
+
+ // c = screenBitmap.getConfig();
+ // screenBitmap = screenBitmap.copy(c, true);
+ // } catch (IOException e)
+ // {
+ // }
+
+ Common::String nameColorsx = Common::String::format("colors%d.png", s);
+ Common::String nameColors = "colors/" + nameColorsx;
+ // try
+ // {
+ // screenColors = getBitmapFromAsset(nameColors);
+ // } catch (IOException e)
+ // {
+ // screenColors = null;
+ // }
+ // if (screenColors != null)
+ // setFakePalette(nameColorsx, screenColors);
+
+ Common::String nameShadows = Common::String::format("shadows/shadows_%d.png", s); // <-- fixed: include s
+ Common::File shadows;
+ if (shadows.open(Common::Path(nameShadows)) != Common::kNoError) {
+ error("Error opening shadows: %s", nameShadows.c_str());
+ return;
+ }
+ if (decoder->loadStream(shadows) != Common::kNoError) {
+ error("Decoder failed loading shadows: %s", nameShadows.c_str());
+ return;
+ }
+ const Graphics::Surface *shadowSurf = decoder->getSurface();
+ if (!shadowSurf) {
+ error("No shadow surface for %s", nameShadows.c_str());
+ return;
+ }
+ Common::copy((byte *)shadowSurf->getPixels(), (byte *)shadowSurf->getPixels() + 640 * 400, pixelsShadows);
+
+ // try
+ // {
+ // shadowColors = getBitmapFromAsset(nameShadows);
+ // } catch (IOException e)
+ // {
+ // shadowColors = null;
+ // }
+
+ // shadowColors.getPixels(pixelsShadows, 0, 640, 0, 0, 640, 400);
+
+ Common::File caminos;
+ if (!caminos.open(Common::Path(nameCamino))) {
+ error("Cant find camino");
+ }
+
+ // // caminos................
+ // BufferedReader br = null;
+ // List<String> wordList = new ArrayList<String>();
+
+ // try
+ // {
+ // br = new BufferedReader(
+ // new InputStreamReader(assetManager.open(nameCamino)));
+ // String word;
+ // while ((word = br.readLine()) != null)
+ // wordList.add(word);
+ // } catch (IOException e)
+ // {
+ // }
+
+ // paths.caminos = new defCam();
+
+ // int k = wordList.size();
+
+ // List<rectCam> provList = new LinkedList<rectCam>();
+ // provList.clear();
+
+ // List<conex> provListCon = new LinkedList<conex>();
+ // provListCon.clear();
+
+ // List<anims> provListAnims = new LinkedList<anims>();
+ // provListAnims.clear();
+
+ // myScale = null;
+
+ // scale aux4 = null;
+
+ // String line;
+ // int ind = -1;
+ // int prevInd = 0;
+ // int which = 0;
+
+ // for (int i = 0; i < k; i++)
+ // {
+
+ // line = wordList.get(i);
+
+ // if (line.compareTo("paths") == 0)
+ // which = 0;
+ // else if (line.compareTo("conexions") == 0)
+ // which = 1;
+ // else if (line.compareTo("anims") == 0)
+ // which = 2;
+ // else if (line.compareTo("scale") == 0)
+ // which = 3;
+ // else
+ // {
+
+ // switch (which)
+ // {
+ // case 0:
+
+ // rectCam aux = new rectCam();
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux.x = (int) (Float
+ // .parseFloat(line.substring(prevInd, ind)) * factX);
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux.y = (int) (Float
+ // .parseFloat(line.substring(prevInd, ind)) * factY);
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux.w = (int) (Float
+ // .parseFloat(line.substring(prevInd, ind)) * factX);
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux.h = (int) (Float.parseFloat(line.substring(prevInd))
+ // * factY);
+ // prevInd = ind + 1;
+
+ // ind = -1;
+ // prevInd = 0;
+
+ // provList.add(aux);
+
+ // break;
+
+ // case 1:
+
+ // conex aux2 = new conex();
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux2.x = (int) (Float
+ // .parseFloat(line.substring(prevInd, ind)) * factX);
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux2.y = (int) (Float
+ // .parseFloat(line.substring(prevInd, ind)) * factY);
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux2.which = (int) (Integer
+ // .parseInt(line.substring(prevInd, ind)));
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux2.ready = (int) (Integer
+ // .parseInt(line.substring(prevInd, ind)));
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux2.nx = (int) (Float
+ // .parseFloat(line.substring(prevInd, ind)) * factX);
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux2.ny = (int) (Float
+ // .parseFloat(line.substring(prevInd, ind)) * factY);
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux2.ndir = (int) (Integer
+ // .parseInt(line.substring(prevInd)));
+ // prevInd = ind + 1;
+
+ // ind = -1;
+ // prevInd = 0;
+
+ // provListCon.add(aux2);
+ // break;
+
+ // case 2:
+
+ // anims aux3 = new anims();
+
+ // aux3.activated = true;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux3.x = (int) (Integer
+ // .parseInt(line.substring(prevInd, ind)) * factX);
+ // aux3.backupX = aux3.x;
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux3.y = (int) (Integer
+ // .parseInt(line.substring(prevInd, ind)) * factY);
+ // aux3.backupY = aux3.y;
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux3.moving = (boolean) (Boolean
+ // .parseBoolean((line.substring(prevInd, ind))));
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux3.frames = (int) (Integer
+ // .parseInt(line.substring(prevInd, ind)));
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // if (ind == -1)
+ // aux3.speed = (int) (Integer
+ // .parseInt(line.substring(prevInd)));
+ // else
+ // aux3.speed = (int) (Integer
+ // .parseInt(line.substring(prevInd, ind)));
+ // prevInd = ind + 1;
+
+ // aux3.whichFrame = 0;
+ // aux3.nSpeed = 0;
+
+ // if (ind != -1)// otros datos en las animaciones...
+ // {
+ // int kk;
+ // if (aux3.moving == false)// los datos extras son de
+ // // animaciones 'combinadas'
+ // {
+
+ // ind = line.indexOf(',', ind + 1);
+ // kk = (int) (Integer
+ // .parseInt(line.substring(prevInd, ind)));
+ // prevInd = ind + 1;
+
+ // aux3.animParts = new parts[kk];
+ // aux3.time = 0;
+ // aux3.whichPart = 0;
+
+ // for (int j = 0; j < kk; j++)
+ // {
+ // aux3.animParts[j] = new parts();
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux3.animParts[j].nframes = (int) (Integer
+ // .parseInt(
+ // line.substring(prevInd, ind)));
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // if (ind == -1)
+ // aux3.animParts[j].duration = (int) (Integer
+ // .parseInt(line.substring(prevInd)));
+ // else
+ // aux3.animParts[j].duration = (int) (Integer
+ // .parseInt(line.substring(prevInd,
+ // ind)));
+
+ // prevInd = ind + 1;
+
+ // }
+
+ // } else
+ // {
+
+ // ind = line.indexOf(',', ind + 1);
+ // kk = (int) (Integer
+ // .parseInt(line.substring(prevInd, ind)));
+ // prevInd = ind + 1;
+
+ // aux3.incAnims = new movements[kk];
+
+ // aux3.whichMovement = 0;
+ // aux3.isMovingAlready = false;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux3.startMoving = (int) (Integer
+ // .parseInt(line.substring(prevInd, ind)));
+ // prevInd = ind + 1;
+
+ // for (int j = 0; j < kk; j++)
+ // {
+ // aux3.incAnims[j] = new movements();
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux3.incAnims[j].ix = (float) (Float.parseFloat(
+ // line.substring(prevInd, ind)));
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux3.incAnims[j].iy = (float) (Float.parseFloat(
+ // line.substring(prevInd, ind)));
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // if (ind == -1)
+ // aux3.incAnims[j].duration = (int) (Integer
+ // .parseInt(line.substring(prevInd)));
+ // else
+ // aux3.incAnims[j].duration = (int) (Integer
+ // .parseInt(line.substring(prevInd,
+ // ind)));
+ // prevInd = ind + 1;
+
+ // aux3.incAnims[j].nduration = 0;
+
+ // }
+
+ // }
+
+ // }
+
+ // ind = -1;
+ // prevInd = 0;
+
+ // provListAnims.add(aux3);
+
+ // break;
+
+ // case 3:
+
+ // aux4 = new scale();
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux4.miny = (int) (Float
+ // .parseFloat(line.substring(prevInd, ind)) * factY);
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux4.factmin = (int) (Integer
+ // .parseInt(line.substring(prevInd, ind)));
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux4.maxy = (int) (Float
+ // .parseFloat(line.substring(prevInd, ind)) * factY);
+ // prevInd = ind + 1;
+
+ // ind = line.indexOf(',', ind + 1);
+ // aux4.factmax = (int) (Integer
+ // .parseInt(line.substring(prevInd)));
+ // prevInd = ind + 1;
+
+ // prevInd += 0;
+ // break;
+ // }
+
+ // }
+
+ // }
+
+ // // myAnims
+
+ // int realPaths = provList.size();
+
+ // paths.caminos.cams = new rectCam[realPaths];
+
+ // int t;
+ // for (t = 0; t < realPaths; t++)
+ // {
+ // paths.caminos.cams[t] = new rectCam();
+ // paths.caminos.cams[t] = provList.get(t);
+ // }
+
+ // int realConex = provListCon.size();
+
+ // myConex = new conex[realConex];
+ // for (t = 0; t < realConex; t++)
+ // {
+ // myConex[t] = new conex();
+ // myConex[t] = provListCon.get(t);
+ // }
+
+ // int realAnims = provListAnims.size();
+
+ // bitmapAnims = new Bitmap[realAnims];
+
+ // try
+ // {
+ // myAnims = new anims[realAnims];
+ // for (t = 0; t < realAnims; t++)
+ // {
+
+ // myAnims[t] = new anims();
+ // myAnims[t] = provListAnims.get(t);
+
+ // bitmapAnims[t] = getBitmapFromAsset(
+ // "animaciones/anim" + String.valueOf(whichScreen)
+ // + String.valueOf(t) + ".png");
+
+ // myAnims[t].realWFrame = bitmapAnims[t].getWidth();
+ // myAnims[t].realHFrame = bitmapAnims[t].getHeight();
+
+ // myAnims[t].w = (int) ((float) bitmapAnims[t].getWidth()
+ // * factX);
+ // myAnims[t].h = (int) ((float) bitmapAnims[t].getHeight()
+ // * factY);
+
+ // myAnims[t].predOrder = t;
+ // }
+ // } catch (Exception e)
+ // {
+ // }
+
+ // for (int i = 0; i < realPaths; i++)
+ // {
+ // paths.caminos.cams[i].vecinos = new LinkedList<Integer>();
+ // paths.caminos.cams[i].index = i;
+ // paths.caminos.cams[i].marked = false;
+
+ // for (int j = 0; j < realPaths; j++)
+ // {
+ // if ((i != j) && (paths.esVecino(i, j)))
+ // paths.caminos.cams[i].vecinos.add(j);
+ // }
+ // }
+
+ // if (aux4 != null)
+ // {
+ // myScale = aux4;
+ // }
+
+ // checkPegatinas(whichScreen);
+ // checkObjects(whichScreen);
+
+ // myConversaciones.loadConversations(whichScreen);
+
+ // // a ver si alguna conversacion esta cambiada
+ // if (myConversaciones.mytalkingAnims[whichScreen].myPersonajes != null)
+ // {
+
+ // int x = myConversaciones.mytalkingAnims[whichScreen].myPersonajes.length;
+
+ // for (int i = 0; i < x; i++)
+ // myConversaciones.mytalkingAnims[whichScreen].myPersonajes[i].currentConversationEach = 0;
+
+ // }
+
+ // int n = myListChangesConvs.size();
+ // for (int i = 0; i < n; i++)
+ // {
+ // changesConvs aux = new changesConvs();
+ // aux = myListChangesConvs.get(i);
+
+ // if (whichScreen == aux.screen)
+ // {
+ // myConversaciones.mytalkingAnims[whichScreen].myPersonajes[aux.which].currentConversationEach = aux.n;// .setConversation(whichScreen,
+ // // aux.which,
+ // // aux.n);
+ // }
+ // }
+
+ // myoverlay.isFadedOut = false;
+
+ // // a ver si se ha desactivado alguna animacion
+ // n = myListDesactAnims.size();
+
+ // for (int i = 0; i < n; i++)
+ // {
+ // dactAnims aux = new dactAnims();
+ // aux = myListDesactAnims.get(i);
+
+ // if (whichScreen == aux.screen)
+ // myAnims[aux.which].activated = false;
+ // }
+
+ // // personajes pe[];
+ // personajes pe[] = AlfredActivity.myConversaciones.mytalkingAnims[whichScreen].myPersonajes;
+ // // lista de cosas sueltas a hacer...
+
+ // pintaPeriodicoDandoVueltas = false;
+ // int j;
+ // switch (whichScreen)
+ // {
+
+ // case 51:
+ // desactivaAnims(51, 0);
+ // desactivaAnims(51, myAnims.length - 1);
+ // resetDiosesTime();
+ // break;
+
+ // case 52:
+ // desactivaAnims(52, 0);
+ // desactivaAnims(52, 1);
+ // desactivaAnims(52, 2);
+ // desactivaAnims(52, 3);
+ // desactivaAnims(52, 4);
+ // desactivaAnims(52, 5);
+ // ponPegatina(52, 145);
+ // desactivaAnims(52, myAnims.length - 1);
+ // resetDiosesTime();
+ // break;
+
+ // case 53:
+ // desactivaAnims(53, 0);
+ // desactivaAnims(53, myAnims.length - 1);
+ // resetDiosesTime();
+ // break;
+
+ // case 54:
+ // desactivaAnims(54, 0);
+ // desactivaAnims(54, myAnims.length - 1);
+ // resetDiosesTime();
+ // break;
+
+ // case 0:
+ // if ((readExtraVariable(VUELTA_A_EMPEZAR) == 1)
+ // && (readExtraVariable(FROM_INTRO) == 0))
+ // {
+ // setExtraVariables(AlfredActivity.VUELTA_A_EMPEZAR, 2);
+ // myoverlay.setAnimExtra(14, 15, 21, 71, 66, 0, 0);
+ // myMovingAlfredThread.showTextNow = true;
+ // whichObject = 0;
+ // textToShow = extraThingsToTranslate[117];
+
+ // }
+
+ // break;
+
+ // case 48:
+
+ // AlfredActivity.myMovingAlfredThread.saySomethingOther(
+ // AlfredActivity.extraThingsToTranslate[115], 0);
+ // setExtraVariables(AlfredActivity.A_POR_LA_PRINCESA, 1);
+
+ // desactivaAnims(48, 7);
+
+ // break;
+
+ // case 44:
+
+ // if (readExtraVariable(AlfredActivity.PIEDRA_FAKE_MOJADA) == 3)
+ // updateConexion(55, 1);
+
+ // break;
+
+ // case 41:
+ // j = getOrderAnims(2);
+ // myAnims[j].activated = false;
+
+ // j = getOrderAnims(3);
+ // myAnims[j].activated = false;
+
+ // if (readExtraVariable(AlfredActivity.GUARDIAS_BORRACHOS) == 1)
+ // updateConexion(43, 1);
+
+ // break;
+
+ // case 40:
+
+ // finalObject = 0;
+ // whichObject = 0;
+ // actionToDo = 1;
+ // myMovingAlfredThread.stateOfTalking = 0;
+ // gotoPos(290, 370, 3);
+ // whichAction = objetos.HABLAR;
+ // afterMovingAlfred = ALFRED_TALKING;
+ // posibilityOfFakeAnswer = false;
+ // varCheckRealTime = -1;
+
+ // break;
+
+ // case 39:
+
+ // j = getOrderAnims(0);
+ // myAnims[j].activated = false;
+
+ // j = getOrderAnims(7);
+ // myAnims[j].activated = false;
+
+ // j = getOrderAnims(8);
+ // myAnims[j].activated = false;
+
+ // j = getOrderAnims(9);
+ // myAnims[j].activated = false;
+
+ // j = getOrderAnims(10);
+ // myAnims[j].activated = false;
+
+ // break;
+
+ // case 34:
+ // if (readExtraVariable(AlfredActivity.VIGILANTE_PAJEANDOSE) == 1)
+ // {
+ // int i = getOrderAnims(0);
+ // myAnims[i].activated = false;
+ // updateConexion(35, 1);
+
+ // }
+ // break;
+
+ // case 21:
+
+ // if ((prevWhichScreen == 36)
+ // && (readExtraVariable(AlfredActivity.PIRAMIDE_JODIDA) == 1))
+ // {
+ // updateConexion(36, 0);
+ // AlfredActivity.ponPegatina(21, 79);
+ // AlfredActivity.addPegatina(21, 79);
+ // }
+
+ // break;
+
+ // case 36:
+
+ // byte z = readExtraVariable(AlfredActivity.PIRAMIDE_JODIDA);
+ // if (z >= 3)
+ // setExtraVariables(AlfredActivity.PIRAMIDE_JODIDA, 1);
+
+ // int i;
+
+ // if (readExtraVariable(AlfredActivity.PIRAMIDE_JODIDA) == 1) // se ha
+ // // cargado
+ // // la
+ // // piramide
+ // {
+
+ // i = getOrderAnims(0);
+ // myAnims[i].x = (int) (328.0f * factX);
+ // myAnims[i].y = (int) (209.0f * factY);
+ // myAnims[i].moving = false;
+ // myAnims[i].incAnims = null;// new movements[1];
+
+ // myAnims[i].speed = 1000000;
+
+ // i = getOrderAnims(2);
+ // myAnims[i].activated = true;
+ // myAnims[i].speed = 16;
+ // } else// if (prevWhichScreen==21)//no ha hecho nada
+ // {
+ // i = getOrderAnims(0);
+
+ // if (prevWhichScreen == 21)
+ // {
+ // myAnims[i].activated = true;
+ // myAnims[i].speed = 1000000;
+ // updateConexion(37, 0);
+ // } else
+ // {
+ // myAnims[i].activated = false;
+ // updateConexion(37, 1);
+ // }
+
+ // i = getOrderAnims(2);
+ // myAnims[i].activated = false;
+
+ // }
+
+ // break;
+
+ // case 26:
+
+ // mypersonajes = pe[0];
+
+ // if (myListUsingObjects.contains(82) == false)// no tiene dinero
+ // mypersonajes.setConversation(26, 0, 0);
+ // else
+ // mypersonajes.setConversation(26, 0, 1);
+
+ // mypersonajes = pe[1];
+ // mypersonajes.setConversation(26, 1, 0);
+
+ // if ((AlfredActivity
+ // .readExtraVariable(AlfredActivity.A_LA_CARCEL) == 1)
+ // && (prevWhichScreen == 27)
+ // && (AlfredActivity.readExtraVariable(
+ // AlfredActivity.SE_HA_PUESTO_EL_MUNECO) == 0))
+ // {
+ // mypersonajes = pe[1];
+ // mypersonajes.setConversation(26, 1, 1);
+ // // myAnims[0].activated=true;
+ // finalObject = 1;
+ // whichObject = 1;
+ // actionToDo = 1;
+ // myMovingAlfredThread.stateOfTalking = 0;
+ // gotoPos(314, 240, 3);
+ // whichAction = objetos.HABLAR;// .h
+ // afterMovingAlfred = ALFRED_TALKING;
+ // posibilityOfFakeAnswer = false;
+ // varCheckRealTime = -1;
+ // }
+ // if ((AlfredActivity
+ // .readExtraVariable(AlfredActivity.A_LA_CARCEL) == 1)
+ // && (prevWhichScreen == 27)
+ // && (AlfredActivity.readExtraVariable(
+ // AlfredActivity.SE_HA_PUESTO_EL_MUNECO) == 1))
+ // {
+ // mypersonajes = pe[1];
+ // mypersonajes.setConversation(26, 1, 2);
+ // }
+
+ // break;
+
+ // case 27:
+ // if (prevWhichScreen == 33)// viene del tunel
+ // {
+ // xAlfred = 90.0f * factX;
+ // yAlfred = 380.0f * factY;
+ // myoverlay.setAnimExtra(16, 9, 12, 158, 115, 0, 0);
+ // }
+
+ // // mypersonajes = pe[0];
+
+ // if (myListUsingObjects.contains(82) == false)
+ // {
+ // mypersonajes = pe[0];
+ // mypersonajes.setConversation(27, 0, 0);
+ // mypersonajes = pe[1];
+ // mypersonajes.setConversation(27, 1, 0);
+ // } else
+ // {
+ // mypersonajes = pe[0];
+ // mypersonajes.setConversation(27, 0, 1);
+ // mypersonajes = pe[1];
+ // mypersonajes.setConversation(27, 1, 1);
+ // }
+
+ // break;
+
+ // case 32:
+ // if (prevWhichScreen == 31)// viene de la carcel
+ // {
+ // xAlfred = 321.0f * factX;
+ // yAlfred = 125.0f * factY;
+ // myoverlay.setAnimExtra(11, 7, 9, 33, 72, 0, 0);
+ // AlfredActivity.myConversaciones.mytalkingAnims[31].myPersonajes[0]
+ // .setConversation(31, 0, 3);
+ // // mypersonajes = pe[0];
+ // // mypersonajes.setConversation(31, 0, 3);
+ // }
+
+ // break;
+
+ // case 38:
+ // if (AlfredActivity
+ // .readExtraVariable(AlfredActivity.ROBA_PELO_PRINCESA) == 0)
+ // {
+ // xAlfred = 230.0f * factX;
+ // yAlfred = 283.0f * factY;
+ // myoverlay.setAnimExtra(12, 6, 8, 113, 103, -32, 15);
+ // }
+ // break;
+ // case 30:
+ // myAnims[0].activated = false;
+ // myAnims[4].activated = false;
+
+ // if ((readExtraVariable(PUERTA_SECRETA_ABIERTA) == 1)
+ // && (AlfredActivity.readExtraVariable(
+ // AlfredActivity.ROBA_PELO_PRINCESA) != 2))
+ // updateConexion(38, 1);
+
+ // if (AlfredActivity
+ // .readExtraVariable(AlfredActivity.ROBA_PELO_PRINCESA) == 1)
+ // {
+
+ // setExtraVariables(AlfredActivity.ROBA_PELO_PRINCESA, 2);
+ // myAnims[0].activated = true;
+ // finalObject = 0;
+ // actionToDo = 0;
+ // myMovingAlfredThread.stateOfTalking = 0;
+ // gotoPos(391, 344, 1);
+ // whichAction = objetos.HABLAR;// .h
+ // afterMovingAlfred = ALFRED_TALKING;
+ // posibilityOfFakeAnswer = false;
+ // varCheckRealTime = -1;
+ // }
+ // break;
+
+ // case 4:
+ // if (readExtraVariable(ELECTROCUTACION) == 0)
+ // {
+ // setExtraVariables(AlfredActivity.ELECTROCUTACION, 1);
+ // hideObject(7);
+ // }
+ // if (readExtraVariable(AlfredActivity.CABLES_PUESTOS) == 3)
+ // showObject(8);
+ // else
+ // hideObject(8);
+ // case 8:
+ // case 14:
+ // if (AlfredActivity.readExtraVariable(
+ // AlfredActivity.VENDEDOR_DEJA_DE_JODER) == 1)
+ // {
+ // paths.caminos.cams[0].w = (int) (599.0f * AlfredActivity.factX);
+ // AlfredActivity.updateConexion(16, 1);
+ // }
+ // case 16:
+ // case 19:
+
+ // if ((readExtraVariable(PUESTA_SALSA_PICANTE_EN_MENU) == 1)
+ // && (readExtraVariable(JEFE_ENCARCELADO) == 0)
+ // && (Math.random() < 0.25f))
+ // {
+ // // muestra periodico, quita al jefe, etc...
+ // setExtraVariables(AlfredActivity.JEFE_ENCARCELADO, 1);
+ // AlfredActivity.addObject(13, 0, false);// anula de que se pueda
+ // // clickar al jefe
+ // AlfredActivity.desactivaAnims(13, 0);
+ // AlfredActivity.desactivaAnims(13, 1);
+
+ // myConversaciones.mytalkingAnims[12].myPersonajes[0]
+ // .setConversation(12, 0, 1);// .currentConversationEach[aux.which]=aux.n;//.setConversation(whichScreen,
+ // // aux.which, aux.n);
+
+ // String x = "extrascreens/"
+ // + extraScreens[(1 * myLanguages.length)
+ // + whichLanguageInt]
+ // + ".png";
+
+ // try
+ // {
+ // periodico = getBitmapFromAsset(x);
+ // } catch (IOException e)
+ // {
+ // }
+
+ // Config cx = periodico.getConfig();
+ // periodico = periodico.copy(cx, true);
+
+ // pintaPeriodicoDandoVueltas = true;
+
+ // }
+
+ // break;
+ // case 9:
+ // // personajes pe[] =
+ // // AlfredActivity.myConversaciones.mytalkingAnims[whichScreen].myPersonajes;
+ // mypersonajes = pe[0];
+
+ // if (myListUsingObjects.contains(10) == false)
+ // mypersonajes.setConversation(9, 0, 0);
+ // else
+ // mypersonajes.setConversation(9, 0, 3);
+ // break;
+ // case 20:
+ // // personajes pe[] =
+ // // AlfredActivity.myConversaciones.mytalkingAnims[whichScreen].myPersonajes;
+ // mypersonajes = pe[0];
+ // if (myListUsingObjects.contains(75) == true)
+ // mypersonajes.setConversation(20, 0, 2);
+ // else
+ // {
+ // if (myListUsingObjects.contains(59) == true)// &&
+ // // (myListUsingObjects.contains(59)==true))
+ // mypersonajes.setConversation(20, 0, 1);
+ // else
+ // mypersonajes.setConversation(20, 0, 0);
+ // }
+ // break;
+ // case 28:
+ // if (AlfredActivity.readExtraVariable(
+ // AlfredActivity.CROCODILLO_ENCENDIDO) == 1)
+ // {
+ // hideObject(0);
+ // showObject(1);
+ // showObject(2);
+ // showObject(3);
+ // showObject(4);
+ // myoverlay.isFadedOut = false;
+ // } else
+ // {
+ // hideObject(1);
+ // hideObject(2);
+ // hideObject(3);
+ // hideObject(4);
+ // myoverlay.isFadedOut = true;
+ // }
+ // break;
+
+ // }
+
+ // if (whichScreen == 55)
+ // {
+ // if (prevWhichScreen == 44)
+ // myMovingAlfredThread.alfredFrame = 0;
+ // else
+ // myMovingAlfredThread.alfredFrame = 17;
+ // } else
+ // {
+ // switch (dirAlfred)
+ // {
+ // case 0:
+ // myMovingAlfredThread.alfredFrame = 0;
+ // break;
+ // case 1:
+ // myMovingAlfredThread.alfredFrame = 9;
+ // break;
+ // case 2:
+ // myMovingAlfredThread.alfredFrame = 18;
+ // break;
+ // case 3:
+ // myMovingAlfredThread.alfredFrame = 23;
+ // break;
+ // }
+
+ // }
+
+ // BufferedReader brfx;
+ // String word;
+ // List<String> wordListfx = new ArrayList<String>();
+ // wordListfx.clear();
+ // String name = "fx/screen" + String.valueOf(whichScreen) + ".txt";
+
+ // try
+ // {
+ // brfx = new BufferedReader(
+ // new InputStreamReader(assetManager.open(name)));
+ // while ((word = brfx.readLine()) != null)
+ // wordListfx.add(word);
+ // } catch (IOException e)
+ // {
+ // }
+
+ // int size = wordListfx.size();
+ // filelistFX = new String[size];
+
+ // for (int i = 0; i < size; i++)
+ // {
+ // filelistFX[i] = new String();
+ // filelistFX[i] = wordListfx.get(i) + ".mp3";
+ // }
+
+ // if (filelistFX.length > 0)
+ // {
+ // int off = (int) (10000.0f + (Math.random() * 5000.0f));
+ // timeFXtoPlay = SystemClock.uptimeMillis() + off;
+ // }
+
+ // boolean loop;
+ // if (whichScreen != 48)
+ // loop = true;
+ // else
+ // loop = false;
+
+ // playTrack(whichScreen, loop);
+
+ // fundidoTime = false;
+
+ // timeStartScreen = SystemClock.uptimeMillis();
+
+ // screenReady = true;
+}
+
Common::Error PelrockEngine::syncGame(Common::Serializer &s) {
// The Serializer has methods isLoading() and isSaving()
// if you need to specific steps; for example setting
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 4ce714f965d..e8589a7e34a 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -33,17 +33,49 @@
#include "engines/engine.h"
#include "engines/savestate.h"
#include "graphics/screen.h"
+#include "image/png.h"
#include "pelrock/detection.h"
+#include "pelrock/types.h"
namespace Pelrock {
struct PelrockGameDescription;
+const int kAlfredFrameWidth = 51;
+const int kAlfredFrameHeight = 102;
+
class PelrockEngine : public Engine {
private:
const ADGameDescription *_gameDescription;
Common::RandomSource _randomSource;
+ Image::PNGDecoder *decoder = new Image::PNGDecoder();
+ void init();
+ void playIntro();
+ void setScreen(int s, int dir);
+ void setScreenJava(int s, int dir);
+ void loadAnims();
+ void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
+ void getBackground(Common::File *roomFile, int roomOffset, byte *background);
+ void loadMainCharacterAnims();
+ void frames();
+
+ int xAlfred = 200;
+ int yAlfred = 200;
+ bool shouldPlayIntro = false;
+ GameState stateGame = GAME;
+ bool gameInitialized = false;
+ bool screenReady = false;
+ int dirAlfred = 0;
+ int prevDirX = 0;
+ int prevDirY = 0;
+ Common::String objectToShow = "";
+ int prevWhichScreen = 0;
+ int whichScreen = 0;
+ byte *pixelsShadows;// =new int[640*400];
+ byte *standingAnim = new byte[3060 * 102];
+
+ int curAlfredFrame = 9;
protected:
// Engine APIs
Common::Error run() override;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
new file mode 100644
index 00000000000..84f39ef3542
--- /dev/null
+++ b/engines/pelrock/types.h
@@ -0,0 +1,36 @@
+
+namespace Pelrock {
+
+ const int kRoomStructSize = 104;
+ const int kNumRooms = 56;
+
+
+ enum GameState {
+ GAME = 100,
+ MENU = 101,
+ CREDITS = 102,
+ SAVELOAD = 103,
+ SETTINGS = 104,
+ EXTRA_SCREEN = 105,
+ INTRO = 106,
+ PROMOTE = 107,
+ };
+
+ // struct rectCam
+ // {
+ // Common::List<int> vecinos;
+ // bool marked;
+ // int index;
+ // int x;
+ // int y;
+ // int w;
+ // int h;
+ // };
+
+ // struct defCam
+ // {
+ // rectCam cams[];
+ // };
+
+
+} // End of namespace Pelrock
Commit: afac30a24c6b30104fdb13d7826de99f34dcdc47
https://github.com/scummvm/scummvm/commit/afac30a24c6b30104fdb13d7826de99f34dcdc47
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:58:58+02:00
Commit Message:
PELROCK: Reads room animations and renders on screen
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 5aaf7421da7..18310095298 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -21,6 +21,7 @@
#include "common/config-manager.h"
#include "common/debug-channels.h"
+#include "common/endian.h"
#include "common/events.h"
#include "common/file.h"
#include "common/scummsys.h"
@@ -178,7 +179,7 @@ void PelrockEngine::init() {
// myoverlay.setCredits();
loadAnims();
// loadOtherBitmaps();
- setScreen(0, 2);
+ setScreen(1, 2);
// setScreen(0, 2);
// valSound1 = 0;
// valSound2 = 0;
@@ -851,6 +852,59 @@ void PelrockEngine::getBackground(Common::File *roomFile, int roomOffset, byte *
}
}
+Common::List<Anim> PelrockEngine::getRoomAnimations(Common::File *roomFile, int roomOffset) {
+ uint32_t pair_offset = roomOffset + (8 * 8);
+ roomFile->seek(pair_offset, SEEK_SET);
+ uint32_t offset = roomFile->readUint32LE();
+ uint32_t size = roomFile->readUint32LE();
+
+ byte *data = new byte[size];
+ roomFile->seek(offset, SEEK_SET);
+ roomFile->read(data, size);
+
+ unsigned char *pic = new byte[10000 * 10000];
+ if (offset > 0 && size > 0) {
+ decompress_rle_block(data, size, 0, size, &pic);
+ } else {
+ return Common::List<Anim>();
+ }
+ Common::List<Anim> anims = Common::List<Anim>();
+ uint32_t spriteEnd = offset + size;
+ uint32_t metadata_start = spriteEnd + 108;
+ uint32_t picOffset = 0;
+ for(int i = 0; i < 10; i++) {
+ uint32_t animOffset = metadata_start + (i * 44);
+ roomFile->seek(animOffset, SEEK_SET);
+
+ int16 x = roomFile->readSint16LE();
+ int16 y = roomFile->readSint16LE();
+ byte w = roomFile->readByte();
+ byte h = roomFile->readByte();
+ roomFile->skip(2); // reserved
+ int secAnimCount = roomFile->readByte();
+ roomFile->skip(1);
+ byte frames = 0;
+ for( int i =0; i < secAnimCount; i++) {
+ frames += roomFile->readByte();
+ }
+ if (w > 0 && h > 0 && frames > 0) {
+ Anim anim;
+ anim.x = x;
+ anim.y = y;
+ anim.w = w;
+ anim.h = h;
+ anim.nframes = frames;
+ uint32_t needed = anim.w * anim.h * anim.nframes;
+ anim.animData = new byte[needed];
+ Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
+ picOffset += needed;
+ debug("Anim %d: x=%d y=%d w=%d h=%d nframes=%d", i, anim.x, anim.y, anim.w, anim.h, anim.nframes);
+ anims.push_back(anim);
+ }
+ }
+ return anims;
+}
+
void PelrockEngine::loadMainCharacterAnims() {
Common::File alfred3;
if (!alfred3.open(Common::Path("ALFRED.3"))) {
@@ -891,7 +945,6 @@ void PelrockEngine::setScreen(int number, int dir) {
return;
}
-
int roomOffset = number * kRoomStructSize;
byte *palette = new byte[256 * 3];
@@ -910,6 +963,23 @@ void PelrockEngine::setScreen(int number, int dir) {
_screen->setPixel(i, j, background[j * 640 + i]);
}
}
+ Common::List<Anim> anims = getRoomAnimations(&roomFile, roomOffset);
+ int num = 0;
+ for (Common::List<Anim>::iterator i = anims.begin(); i != anims.end(); i++) {
+ byte *frame = new byte[i->w * i->h];
+
+ Common::copy(i->animData, i->animData + (i->w * i->h), frame);
+
+ for (int y = 0; y < i->h; y++) {
+ for (int x = 0; x < i->w; x++) {
+ unsigned int src_pos = (y * i->w) + x;
+ int xPos = i->x + x;
+ int yPos = i->y + y;
+ if(frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
+ _screen->setPixel(xPos, yPos, frame[src_pos]);
+ }
+ }
+ }
_screen->markAllDirty();
roomFile.close();
delete[] background;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index e8589a7e34a..2028ea96faf 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -57,6 +57,7 @@ private:
void loadAnims();
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
+ Common::List<Anim> getRoomAnimations(Common::File *roomFile, int roomOffset);
void loadMainCharacterAnims();
void frames();
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 84f39ef3542..4e6ed97c133 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -4,6 +4,15 @@ namespace Pelrock {
const int kRoomStructSize = 104;
const int kNumRooms = 56;
+ struct Anim {
+ int x;
+ int y;
+ int w;
+ int h;
+ int nframes;
+ int speed;
+ byte *animData;
+ };
enum GameState {
GAME = 100,
Commit: 91575276ca2ed9fbdc3de512e4b1ec131eed23b4
https://github.com/scummvm/scummvm/commit/91575276ca2ed9fbdc3de512e4b1ec131eed23b4
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:58:58+02:00
Commit Message:
PELROCK: Reads hotspots and walkboxes
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 18310095298..7230963e247 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -86,7 +86,13 @@ Common::Error PelrockEngine::run() {
while (!shouldQuit()) {
while (g_system->getEventManager()->pollEvent(e)) {
+ if (e.type == Common::EVENT_MOUSEMOVE) {
+ mouseX = e.mouse.x;
+ mouseY = e.mouse.y;
+ debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
+ }
}
+ checkMouseHover();
frames();
_screen->update();
limiter.delayBeforeSwap();
@@ -179,7 +185,7 @@ void PelrockEngine::init() {
// myoverlay.setCredits();
loadAnims();
// loadOtherBitmaps();
- setScreen(1, 2);
+ setScreen(2, 2);
// setScreen(0, 2);
// valSound1 = 0;
// valSound2 = 0;
@@ -819,7 +825,6 @@ void PelrockEngine::getPalette(Common::File *roomFile, int roomOffset, byte *pal
palette[i * 3 + 1] = palette[i * 3 + 1] << 2;
palette[i * 3 + 2] = palette[i * 3 + 2] << 2;
}
-
}
void PelrockEngine::getBackground(Common::File *roomFile, int roomOffset, byte *background) {
@@ -852,43 +857,43 @@ void PelrockEngine::getBackground(Common::File *roomFile, int roomOffset, byte *
}
}
-Common::List<Anim> PelrockEngine::getRoomAnimations(Common::File *roomFile, int roomOffset) {
+Common::List<AnimSet> PelrockEngine::getRoomAnimations(Common::File *roomFile, int roomOffset) {
uint32_t pair_offset = roomOffset + (8 * 8);
roomFile->seek(pair_offset, SEEK_SET);
- uint32_t offset = roomFile->readUint32LE();
- uint32_t size = roomFile->readUint32LE();
+ uint32_t offset = roomFile->readUint32LE();
+ uint32_t size = roomFile->readUint32LE();
byte *data = new byte[size];
roomFile->seek(offset, SEEK_SET);
roomFile->read(data, size);
unsigned char *pic = new byte[10000 * 10000];
- if (offset > 0 && size > 0) {
- decompress_rle_block(data, size, 0, size, &pic);
+ if (offset > 0 && size > 0) {
+ decompress_rle_block(data, size, 0, size, &pic);
} else {
- return Common::List<Anim>();
+ return Common::List<AnimSet>();
}
- Common::List<Anim> anims = Common::List<Anim>();
+ Common::List<AnimSet> anims = Common::List<AnimSet>();
uint32_t spriteEnd = offset + size;
uint32_t metadata_start = spriteEnd + 108;
uint32_t picOffset = 0;
- for(int i = 0; i < 10; i++) {
- uint32_t animOffset = metadata_start + (i * 44);
+ for (int i = 0; i < 10; i++) {
+ uint32_t animOffset = metadata_start + (i * 44);
roomFile->seek(animOffset, SEEK_SET);
int16 x = roomFile->readSint16LE();
int16 y = roomFile->readSint16LE();
byte w = roomFile->readByte();
- byte h = roomFile->readByte();
+ byte h = roomFile->readByte();
roomFile->skip(2); // reserved
- int secAnimCount = roomFile->readByte();
+ int secAnimCount = roomFile->readByte();
roomFile->skip(1);
- byte frames = 0;
- for( int i =0; i < secAnimCount; i++) {
- frames += roomFile->readByte();
+ byte frames = 0;
+ for (int i = 0; i < secAnimCount; i++) {
+ frames += roomFile->readByte();
}
if (w > 0 && h > 0 && frames > 0) {
- Anim anim;
+ AnimSet anim;
anim.x = x;
anim.y = y;
anim.w = w;
@@ -905,6 +910,68 @@ Common::List<Anim> PelrockEngine::getRoomAnimations(Common::File *roomFile, int
return anims;
}
+Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int roomOffset) {
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ roomFile->seek(pair10_offset_pos, SEEK_SET);
+ // roomFile->skip(4);
+ uint32_t pair10_data_offset = roomFile->readUint32LE();
+ uint32_t pair10_size = roomFile->readUint32LE();
+
+ uint32_t walkbox_countOffset = pair10_data_offset + 0x213;
+ roomFile->seek(walkbox_countOffset, SEEK_SET);
+ byte walkbox_count = roomFile->readByte();
+ debug("Walkbox count: %d", walkbox_count);
+ uint32_t walkbox_offset = pair10_data_offset + 0x218;
+ Common::List<WalkBox> walkboxes;
+ for (int i = 0; i < walkbox_count; i++) {
+ uint32_t box_offset = walkbox_offset + i * 9;
+ roomFile->seek(box_offset, SEEK_SET);
+ int16 x1 = roomFile->readSint16LE();
+ int16 y1 = roomFile->readSint16LE();
+ int16 w = roomFile->readSint16LE();
+ int16 h = roomFile->readSint16LE();
+ byte flags = roomFile->readByte();
+ debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+ WalkBox box;
+ box.x = x1;
+ box.y = y1;
+ box.w = w;
+ box.h = h;
+ box.flags = flags;
+ walkboxes.push_back(box);
+ }
+ return walkboxes;
+}
+
+void PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ roomFile->seek(pair10_offset_pos, SEEK_SET);
+ // roomFile->skip(4);
+ uint32_t pair10_data_offset = roomFile->readUint32LE();
+ uint32_t pair10_size = roomFile->readUint32LE();
+ uint32_t count_offset = pair10_data_offset + 0x47a;
+ roomFile->seek(count_offset, SEEK_SET);
+ byte hotspot_count = roomFile->readByte();
+ uint32_t hotspot_data_start = pair10_data_offset + 0x47c;
+ Common::List<HotSpot> hotspots;
+ for (int i = 0; i < hotspot_count; i++) {
+ uint32_t obj_offset = hotspot_data_start + i * 9;
+ roomFile->seek(obj_offset, SEEK_SET);
+ byte obj_bytes[9];
+ roomFile->read(obj_bytes, 9);
+ byte type_byte = obj_bytes[0];
+ HotSpot spot;
+ spot.x = obj_bytes[1] | (obj_bytes[2] << 8);
+ spot.y = obj_bytes[3] | (obj_bytes[4] << 8);
+ spot.w = obj_bytes[5];
+ spot.h = obj_bytes[6];
+ spot.extra = obj_bytes[7] | (obj_bytes[8] << 8);
+ // debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, type_byte, spot.x, spot.y, spot.w, spot.h, spot.extra);
+ hotspots.push_back(spot);
+ }
+ _hotspots = hotspots;
+}
+
void PelrockEngine::loadMainCharacterAnims() {
Common::File alfred3;
if (!alfred3.open(Common::Path("ALFRED.3"))) {
@@ -929,7 +996,7 @@ void PelrockEngine::frames() {
for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
unsigned int src_pos = (curAlfredFrame * kAlfredFrameHeight * kAlfredFrameWidth) + (y * kAlfredFrameWidth) + x;
- if(standingAnim[src_pos] != 255)
+ if (standingAnim[src_pos] != 255)
_screen->setPixel(x + xAlfred, y + yAlfred, standingAnim[src_pos]);
}
}
@@ -937,6 +1004,17 @@ void PelrockEngine::frames() {
_screen->update();
}
+void PelrockEngine::checkMouseHover() {
+ for (Common::List<HotSpot>::iterator i = _hotspots.begin(); i != _hotspots.end(); i++) {
+ if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
+ mouseY >= i->y && mouseY <= (i->y + i->h)) {
+ // _currentHotspot = &(*i);
+ debug("Hotspot at (%d,%d) size (%d,%d) extra %d", i->x, i->y, i->w, i->h, i->extra);
+ return;
+ }
+ }
+}
+
void PelrockEngine::setScreen(int number, int dir) {
Common::File roomFile;
@@ -963,9 +1041,9 @@ void PelrockEngine::setScreen(int number, int dir) {
_screen->setPixel(i, j, background[j * 640 + i]);
}
}
- Common::List<Anim> anims = getRoomAnimations(&roomFile, roomOffset);
+ Common::List<AnimSet> anims = getRoomAnimations(&roomFile, roomOffset);
int num = 0;
- for (Common::List<Anim>::iterator i = anims.begin(); i != anims.end(); i++) {
+ for (Common::List<AnimSet>::iterator i = anims.begin(); i != anims.end(); i++) {
byte *frame = new byte[i->w * i->h];
Common::copy(i->animData, i->animData + (i->w * i->h), frame);
@@ -975,11 +1053,22 @@ void PelrockEngine::setScreen(int number, int dir) {
unsigned int src_pos = (y * i->w) + x;
int xPos = i->x + x;
int yPos = i->y + y;
- if(frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
+ if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
_screen->setPixel(xPos, yPos, frame[src_pos]);
}
}
}
+ loadHotspots(&roomFile, roomOffset);
+ Common::List<WalkBox> walkboxes = loadWalkboxes(&roomFile, roomOffset);
+ int walkboxCount = 0;
+ for (Common::List<WalkBox>::iterator i = walkboxes.begin(); i != walkboxes.end(); i++) {
+ // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
+ _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
+ _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
+ _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ walkboxCount++;
+ }
_screen->markAllDirty();
roomFile.close();
delete[] background;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 2028ea96faf..25943a7563c 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -22,13 +22,13 @@
#ifndef PELROCK_H
#define PELROCK_H
-#include "common/scummsys.h"
-#include "common/system.h"
#include "common/error.h"
#include "common/fs.h"
#include "common/hash-str.h"
#include "common/random.h"
+#include "common/scummsys.h"
#include "common/serializer.h"
+#include "common/system.h"
#include "common/util.h"
#include "engines/engine.h"
#include "engines/savestate.h"
@@ -55,12 +55,25 @@ private:
void setScreen(int s, int dir);
void setScreenJava(int s, int dir);
void loadAnims();
+ // Room data
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
- Common::List<Anim> getRoomAnimations(Common::File *roomFile, int roomOffset);
+ Common::List<AnimSet> getRoomAnimations(Common::File *roomFile, int roomOffset);
+ void loadHotspots(Common::File *roomFile, int roomOffset);
void loadMainCharacterAnims();
+ Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
+
+ // render loop
void frames();
+ void checkMouseHover();
+ byte *standingAnim = new byte[3060 * 102];
+ Common::List<HotSpot> _hotspots;
+ int curAlfredFrame = 9;
+ uint16 mouseX = 0;
+ uint16 mouseY = 0;
+
+ // From the original code
int xAlfred = 200;
int yAlfred = 200;
bool shouldPlayIntro = false;
@@ -73,15 +86,14 @@ private:
Common::String objectToShow = "";
int prevWhichScreen = 0;
int whichScreen = 0;
- byte *pixelsShadows;// =new int[640*400];
- byte *standingAnim = new byte[3060 * 102];
-
- int curAlfredFrame = 9;
+ byte *pixelsShadows; // =new int[640*400];
protected:
// Engine APIs
Common::Error run() override;
+
public:
Graphics::Screen *_screen = nullptr;
+
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
~PelrockEngine() override;
@@ -101,10 +113,9 @@ public:
}
bool hasFeature(EngineFeature f) const override {
- return
- (f == kSupportsLoadingDuringRuntime) ||
- (f == kSupportsSavingDuringRuntime) ||
- (f == kSupportsReturnToLauncher);
+ return (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime) ||
+ (f == kSupportsReturnToLauncher);
};
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 4e6ed97c133..f6deee0d174 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -1,45 +1,70 @@
namespace Pelrock {
- const int kRoomStructSize = 104;
- const int kNumRooms = 56;
-
- struct Anim {
- int x;
- int y;
- int w;
- int h;
- int nframes;
- int speed;
- byte *animData;
- };
-
- enum GameState {
- GAME = 100,
- MENU = 101,
- CREDITS = 102,
- SAVELOAD = 103,
- SETTINGS = 104,
- EXTRA_SCREEN = 105,
- INTRO = 106,
- PROMOTE = 107,
- };
-
- // struct rectCam
- // {
- // Common::List<int> vecinos;
- // bool marked;
- // int index;
- // int x;
- // int y;
- // int w;
- // int h;
- // };
-
- // struct defCam
- // {
- // rectCam cams[];
- // };
+const int kRoomStructSize = 104;
+const int kNumRooms = 56;
+struct Anim {
+ int x;
+ int y;
+ int w;
+ int h;
+ int nframes;
+ byte *animData;
+};
+
+struct AnimSet {
+ int x;
+ int y;
+ int w;
+ int h;
+ int nframes;
+ int speed;
+ byte *animData;
+};
+
+struct HotSpot {
+ int x;
+ int y;
+ int id;
+ int w;
+ int h;
+ int extra;
+};
+
+struct WalkBox {
+ int16 x;
+ int16 y;
+ int16 w;
+ int16 h;
+ byte flags;
+};
+
+enum GameState {
+ GAME = 100,
+ MENU = 101,
+ CREDITS = 102,
+ SAVELOAD = 103,
+ SETTINGS = 104,
+ EXTRA_SCREEN = 105,
+ INTRO = 106,
+ PROMOTE = 107,
+};
+
+// struct rectCam
+// {
+// Common::List<int> vecinos;
+// bool marked;
+// int index;
+// int x;
+// int y;
+// int w;
+// int h;
+// };
+
+// struct defCam
+// {
+// rectCam cams[];
+// };
} // End of namespace Pelrock
Commit: 94e520c79741df41f715712fff4dcaa2a689b791
https://github.com/scummvm/scummvm/commit/94e520c79741df41f715712fff4dcaa2a689b791
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:58:58+02:00
Commit Message:
PELROCK: Separate animation sets
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 7230963e247..d3736b1f2cd 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -89,7 +89,7 @@ Common::Error PelrockEngine::run() {
if (e.type == Common::EVENT_MOUSEMOVE) {
mouseX = e.mouse.x;
mouseY = e.mouse.y;
- debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
+ // debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
}
}
checkMouseHover();
@@ -877,35 +877,57 @@ Common::List<AnimSet> PelrockEngine::getRoomAnimations(Common::File *roomFile, i
uint32_t spriteEnd = offset + size;
uint32_t metadata_start = spriteEnd + 108;
uint32_t picOffset = 0;
- for (int i = 0; i < 10; i++) {
+ for (int i = 0; i < 7; i++) {
uint32_t animOffset = metadata_start + (i * 44);
roomFile->seek(animOffset, SEEK_SET);
- int16 x = roomFile->readSint16LE();
- int16 y = roomFile->readSint16LE();
- byte w = roomFile->readByte();
- byte h = roomFile->readByte();
+ AnimSet animSet;
+ animSet.x = roomFile->readSint16LE();
+ animSet.y = roomFile->readSint16LE();
+ animSet.w = roomFile->readByte();
+ animSet.h = roomFile->readByte();
roomFile->skip(2); // reserved
- int secAnimCount = roomFile->readByte();
+ animSet.numAnims = roomFile->readByte();
+ debug("AnimSet %d: x=%d y=%d w=%d h=%d numAnims=%d", i, animSet.x, animSet.y, animSet.w, animSet.h, animSet.numAnims);
+ animSet.animData = new Anim[animSet.numAnims];
roomFile->skip(1);
- byte frames = 0;
- for (int i = 0; i < secAnimCount; i++) {
- frames += roomFile->readByte();
- }
- if (w > 0 && h > 0 && frames > 0) {
- AnimSet anim;
- anim.x = x;
- anim.y = y;
- anim.w = w;
- anim.h = h;
+
+ for (int j = 0; j < animSet.numAnims; j++) {
+ byte frames = roomFile->readByte();
+ Anim anim;
+ anim.x = animSet.x;
+ anim.y = animSet.y;
+ anim.w = animSet.w;
+ anim.h = animSet.h;
anim.nframes = frames;
- uint32_t needed = anim.w * anim.h * anim.nframes;
- anim.animData = new byte[needed];
- Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
- picOffset += needed;
- debug("Anim %d: x=%d y=%d w=%d h=%d nframes=%d", i, anim.x, anim.y, anim.w, anim.h, anim.nframes);
- anims.push_back(anim);
+ anim.animData = new byte[anim.nframes];
+ if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
+ uint32_t needed = anim.w * anim.h * anim.nframes;
+ anim.animData = new byte[needed];
+ Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
+ animSet.animData[j] = anim;
+ debug("Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes);
+ picOffset += needed;
+ } else {
+ debug("Anim %d-%d: invalid dimensions, skipping", i, j);
+ }
+ animSet.animData[j] = anim;
}
+ anims.push_back(animSet);
+ // if (w > 0 && h > 0 && frames > 0) {
+ // AnimSet anim;
+ // anim.x = x;
+ // anim.y = y;
+ // anim.w = w;
+ // anim.h = h;
+ // anim.numAnims = frames;
+ // uint32_t needed = anim.w * anim.h * anim.nframes;
+ // anim.animData = new byte[needed];
+ // Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
+ // picOffset += needed;
+ // debug("Anim %d: x=%d y=%d w=%d h=%d nframes=%d", i, anim.x, anim.y, anim.w, anim.h, anim.nframes);
+ // anims.push_back(anim);
+ // }
}
return anims;
}
@@ -931,7 +953,7 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
int16 w = roomFile->readSint16LE();
int16 h = roomFile->readSint16LE();
byte flags = roomFile->readByte();
- debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+ // debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
WalkBox box;
box.x = x1;
box.y = y1;
@@ -1009,7 +1031,7 @@ void PelrockEngine::checkMouseHover() {
if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
mouseY >= i->y && mouseY <= (i->y + i->h)) {
// _currentHotspot = &(*i);
- debug("Hotspot at (%d,%d) size (%d,%d) extra %d", i->x, i->y, i->w, i->h, i->extra);
+ // debug("Hotspot at (%d,%d) size (%d,%d) extra %d", i->x, i->y, i->w, i->h, i->extra);
return;
}
}
@@ -1044,19 +1066,29 @@ void PelrockEngine::setScreen(int number, int dir) {
Common::List<AnimSet> anims = getRoomAnimations(&roomFile, roomOffset);
int num = 0;
for (Common::List<AnimSet>::iterator i = anims.begin(); i != anims.end(); i++) {
- byte *frame = new byte[i->w * i->h];
-
- Common::copy(i->animData, i->animData + (i->w * i->h), frame);
+ debug("Processing animation set %d, numAnims %d", num, i->numAnims);
+ if (i->numAnims == 0) {
+ num++;
+ continue;
+ }
- for (int y = 0; y < i->h; y++) {
- for (int x = 0; x < i->w; x++) {
- unsigned int src_pos = (y * i->w) + x;
- int xPos = i->x + x;
- int yPos = i->y + y;
- if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
- _screen->setPixel(xPos, yPos, frame[src_pos]);
+ for (int j = 0; j < i->numAnims; j++) {
+ debug("Drawing animation %d of set %d at (%d,%d) size (%d,%d) nframes %d", j, num, i->x, i->y, i->w, i->h, i->animData[j].nframes);
+ int frameSize = i->animData[j].w * i->animData[j].h;
+ byte *frame = new byte[frameSize];
+ Common::copy(i->animData[j].animData, i->animData[j].animData + (frameSize), frame);
+
+ for (int y = 0; y < i->h; y++) {
+ for (int x = 0; x < i->w; x++) {
+ unsigned int src_pos = (y * i->w) + x;
+ int xPos = i->x + x;
+ int yPos = i->y + y;
+ if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
+ _screen->setPixel(xPos, yPos, frame[src_pos]);
+ }
}
}
+ num++;
}
loadHotspots(&roomFile, roomOffset);
Common::List<WalkBox> walkboxes = loadWalkboxes(&roomFile, roomOffset);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index f6deee0d174..55fd78550fe 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -18,9 +18,9 @@ struct AnimSet {
int y;
int w;
int h;
- int nframes;
int speed;
- byte *animData;
+ int numAnims;
+ Anim *animData;
};
struct HotSpot {
Commit: 09d049a337ffbe64c592acfd70d4106b72a50bef
https://github.com/scummvm/scummvm/commit/09d049a337ffbe64c592acfd70d4106b72a50bef
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:58:59+02:00
Commit Message:
PELROCK: Display animations
Changed paths:
A engines/pelrock/chrono.cpp
A engines/pelrock/chrono.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
new file mode 100644
index 00000000000..226b09807bc
--- /dev/null
+++ b/engines/pelrock/chrono.cpp
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/system.h"
+
+#include "pelrock/chrono.h"
+#include "pelrock/pelrock.h"
+
+namespace Pelrock {
+
+ChronoManager::ChronoManager(/* args */) : _lastTick(0) {
+}
+
+ChronoManager::~ChronoManager() {
+}
+
+void ChronoManager::updateChrono() {
+ uint32 currentTime = g_system->getMillis();
+
+ if ((currentTime - _lastTick) >= kTickMs / _speedMultiplier) {
+ _gameTick = true;
+ _tickCount++;
+ if (_tickCount == kHalfTickMultiplier) {
+ _tickCount = 0;
+ _gameTickHalfSpeed = true;
+ } else {
+ _gameTickHalfSpeed = false;
+ }
+ _lastTick = currentTime;
+ } else {
+ _gameTick = false;
+ }
+}
+
+void ChronoManager::changeSpeed() {
+ if (_speedMultiplier == 1)
+ _speedMultiplier = 4;
+ else
+ _speedMultiplier = 1;
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
new file mode 100644
index 00000000000..5257563225f
--- /dev/null
+++ b/engines/pelrock/chrono.h
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_CHRONO_H
+#define PELROCK_CHRONO_H
+
+#include "common/scummsys.h"
+
+namespace Pelrock {
+
+// const int kTickMs = 20;
+const int kTickMs = 50;
+const int kHalfTickMultiplier = 2;
+
+class ChronoManager {
+private:
+ uint32 _lastTick = 0;
+ byte _tickCount = 0;
+ byte _speedMultiplier = 1;
+
+public:
+ ChronoManager();
+ ~ChronoManager();
+ void updateChrono();
+ void changeSpeed();
+
+ bool _gameTick = false;
+ bool _gameTickHalfSpeed = false;
+};
+
+} // End of namespace Pelrock
+#endif
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index 5a2724a9990..bc1a263acdd 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -2,6 +2,7 @@ MODULE := engines/pelrock
MODULE_OBJS = \
pelrock.o \
+ chrono.o \
console.o \
metaengine.o
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index d3736b1f2cd..86f8c122760 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -45,10 +45,12 @@ PelrockEngine *g_engine;
PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst),
_gameDescription(gameDesc), _randomSource("Pelrock") {
g_engine = this;
+ _chronoManager = new ChronoManager();
}
PelrockEngine::~PelrockEngine() {
delete _screen;
+ delete _chronoManager;
}
uint32 PelrockEngine::getFeatures() const {
@@ -85,6 +87,7 @@ Common::Error PelrockEngine::run() {
}
while (!shouldQuit()) {
+ _chronoManager->updateChrono();
while (g_system->getEventManager()->pollEvent(e)) {
if (e.type == Common::EVENT_MOUSEMOVE) {
mouseX = e.mouse.x;
@@ -774,7 +777,7 @@ void PelrockEngine::loadAnims() {
}
const int EXPECTED_SIZE = 640 * 400;
-size_t decompress_rle_block(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data) {
+size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data) {
// Check for uncompressed markers
if (size == 0x8000 || size == 0x6800) {
*out_data = (uint8_t *)malloc(size);
@@ -847,7 +850,7 @@ void PelrockEngine::getBackground(Common::File *roomFile, int roomOffset, byte *
roomFile->seek(offset, SEEK_SET);
roomFile->read(data, size);
uint8_t *block_data = NULL;
- size_t block_size = decompress_rle_block(data, size, 0, size, &block_data);
+ size_t block_size = rleDecompress(data, size, 0, size, &block_data);
memcpy(background + combined_size, block_data, block_size);
combined_size += block_size + 1;
@@ -869,7 +872,7 @@ Common::List<AnimSet> PelrockEngine::getRoomAnimations(Common::File *roomFile, i
unsigned char *pic = new byte[10000 * 10000];
if (offset > 0 && size > 0) {
- decompress_rle_block(data, size, 0, size, &pic);
+ rleDecompress(data, size, 0, size, &pic);
} else {
return Common::List<AnimSet>();
}
@@ -899,6 +902,7 @@ Common::List<AnimSet> PelrockEngine::getRoomAnimations(Common::File *roomFile, i
anim.y = animSet.y;
anim.w = animSet.w;
anim.h = animSet.h;
+ anim.curFrame = 0;
anim.nframes = frames;
anim.animData = new byte[anim.nframes];
if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
@@ -909,11 +913,13 @@ Common::List<AnimSet> PelrockEngine::getRoomAnimations(Common::File *roomFile, i
debug("Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes);
picOffset += needed;
} else {
+ continue;
debug("Anim %d-%d: invalid dimensions, skipping", i, j);
}
animSet.animData[j] = anim;
}
anims.push_back(animSet);
+
// if (w > 0 && h > 0 && frames > 0) {
// AnimSet anim;
// anim.x = x;
@@ -1010,20 +1016,77 @@ void PelrockEngine::loadMainCharacterAnims() {
int index3 = 0;
uint32_t capacity = 3060 * 102;
unsigned char *pic = new unsigned char[capacity];
- decompress_rle_block(bufferFile, alfred3Size, 0, alfred3Size, &pic);
+ rleDecompress(bufferFile, alfred3Size, 0, alfred3Size, &pic);
memcpy(standingAnim, pic, 3060 * 102);
}
void PelrockEngine::frames() {
- for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
- for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
- unsigned int src_pos = (curAlfredFrame * kAlfredFrameHeight * kAlfredFrameWidth) + (y * kAlfredFrameWidth) + x;
- if (standingAnim[src_pos] != 255)
- _screen->setPixel(x + xAlfred, y + yAlfred, standingAnim[src_pos]);
+ if (_chronoManager->_gameTick) {
+ for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
+ for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
+ unsigned int src_pos = (curAlfredFrame * kAlfredFrameHeight * kAlfredFrameWidth) + (y * kAlfredFrameWidth) + x;
+ if (standingAnim[src_pos] != 255)
+ _screen->setPixel(x + xAlfred, y + yAlfred, standingAnim[src_pos]);
+ }
+ }
+ int num = 0;
+
+ for (Common::List<AnimSet>::iterator i = _currentRoomAnims.begin(); i != _currentRoomAnims.end(); i++) {
+ debug("Processing animation set %d, numAnims %d", num, i->numAnims);
+ if (i->numAnims == 0) {
+ num++;
+ continue;
+ }
+
+ for (int j = 0; j < i->numAnims; j++) {
+ debug("Drawing animation %d of set %d at (%d,%d) size (%d,%d) nframes %d", j, num, i->x, i->y, i->w, i->h, i->animData[j].nframes);
+ int x = i->animData[j].x;
+ int y = i->animData[j].y;
+ int w = i->animData[j].w;
+ int h = i->animData[j].h;
+
+ int frameSize = i->animData[j].w * i->animData[j].h;
+ int curFrame = i->animData[j].curFrame;
+ byte *frame = new byte[frameSize];
+ Common::copy(i->animData[j].animData + (curFrame * i->h * i->w), i->animData[j].animData + (curFrame * i->h * i->w) + (frameSize), frame);
+ debug("Current frame %d of %d", curFrame, i->animData[j].nframes);
+
+ byte *bg = new byte[frameSize];
+ for (int j = 0; j < w; j++) {
+ for (int i = 0; i < h; i++) {
+ int idx = i * w + j;
+ *(bg + idx) = _currentBackground[(y + i) * 640 + (x + j)];
+ }
+ }
+
+ for (int i = 0; i < w; i++) {
+ for (int j = 0; j < h; j++) {
+ int index = (j * w + i);
+ *(byte *)g_engine->_screen->getBasePtr(x + i, y + j) = bg[index];
+ }
+ }
+
+ for (int y = 0; y < i->h; y++) {
+ for (int x = 0; x < i->w; x++) {
+
+ unsigned int src_pos = (y * i->w) + x;
+ int xPos = i->x + x;
+ int yPos = i->y + y;
+ if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
+ _screen->setPixel(xPos, yPos, frame[src_pos]);
+ }
+ }
+ if (i->animData[j].curFrame < i->animData[j].nframes - 1) {
+ i->animData[j].curFrame++;
+ } else {
+ i->animData[j].curFrame = 0;
+ }
+ }
+ num++;
}
+ _screen->markAllDirty();
+ _screen->update();
}
- _screen->markAllDirty();
- _screen->update();
}
void PelrockEngine::checkMouseHover() {
@@ -1058,38 +1121,17 @@ void PelrockEngine::setScreen(int number, int dir) {
byte *background = new byte[640 * 400];
getBackground(&roomFile, roomOffset, background);
+ if(_currentBackground != nullptr)
+ delete[] _currentBackground;
+ _currentBackground = new byte[640 * 400];
+ Common::copy(background, background + 640 * 400, _currentBackground);
for (int i = 0; i < 640; i++) {
for (int j = 0; j < 400; j++) {
_screen->setPixel(i, j, background[j * 640 + i]);
}
}
- Common::List<AnimSet> anims = getRoomAnimations(&roomFile, roomOffset);
- int num = 0;
- for (Common::List<AnimSet>::iterator i = anims.begin(); i != anims.end(); i++) {
- debug("Processing animation set %d, numAnims %d", num, i->numAnims);
- if (i->numAnims == 0) {
- num++;
- continue;
- }
+ _currentRoomAnims = getRoomAnimations(&roomFile, roomOffset);
- for (int j = 0; j < i->numAnims; j++) {
- debug("Drawing animation %d of set %d at (%d,%d) size (%d,%d) nframes %d", j, num, i->x, i->y, i->w, i->h, i->animData[j].nframes);
- int frameSize = i->animData[j].w * i->animData[j].h;
- byte *frame = new byte[frameSize];
- Common::copy(i->animData[j].animData, i->animData[j].animData + (frameSize), frame);
-
- for (int y = 0; y < i->h; y++) {
- for (int x = 0; x < i->w; x++) {
- unsigned int src_pos = (y * i->w) + x;
- int xPos = i->x + x;
- int yPos = i->y + y;
- if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
- _screen->setPixel(xPos, yPos, frame[src_pos]);
- }
- }
- }
- num++;
- }
loadHotspots(&roomFile, roomOffset);
Common::List<WalkBox> walkboxes = loadWalkboxes(&roomFile, roomOffset);
int walkboxCount = 0;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 25943a7563c..026bc2eb928 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -24,6 +24,7 @@
#include "common/error.h"
#include "common/fs.h"
+#include "common/file.h"
#include "common/hash-str.h"
#include "common/random.h"
#include "common/scummsys.h"
@@ -35,6 +36,7 @@
#include "graphics/screen.h"
#include "image/png.h"
+#include "pelrock/chrono.h"
#include "pelrock/detection.h"
#include "pelrock/types.h"
@@ -67,11 +69,15 @@ private:
void frames();
void checkMouseHover();
+ ChronoManager *_chronoManager = nullptr;
byte *standingAnim = new byte[3060 * 102];
Common::List<HotSpot> _hotspots;
+ Common::List<AnimSet> _currentRoomAnims;
+ int *_currentAnimFrames = nullptr;
int curAlfredFrame = 9;
uint16 mouseX = 0;
uint16 mouseY = 0;
+ byte *_currentBackground = nullptr;
// From the original code
int xAlfred = 200;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 55fd78550fe..842df26840c 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -10,6 +10,7 @@ struct Anim {
int w;
int h;
int nframes;
+ int curFrame;
byte *animData;
};
Commit: 1c9ef9c65bb465bfc2a03a3f5d26ba56e65a7893
https://github.com/scummvm/scummvm/commit/1c9ef9c65bb465bfc2a03a3f5d26ba56e65a7893
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:58:59+02:00
Commit Message:
PELROCK: Implements Room exits
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 86f8c122760..48715e0d6ad 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -93,6 +93,8 @@ Common::Error PelrockEngine::run() {
mouseX = e.mouse.x;
mouseY = e.mouse.y;
// debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
+ } else if (e.type == Common::EVENT_LBUTTONUP) {
+ checkMouseClick(e.mouse.x, e.mouse.y);
}
}
checkMouseHover();
@@ -188,7 +190,7 @@ void PelrockEngine::init() {
// myoverlay.setCredits();
loadAnims();
// loadOtherBitmaps();
- setScreen(2, 2);
+ setScreen(1, 2);
// setScreen(0, 2);
// valSound1 = 0;
// valSound2 = 0;
@@ -971,6 +973,33 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
return walkboxes;
}
+Common::List<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffset) {
+ Common::List<Exit> exits;
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ roomFile->seek(pair10_offset_pos, SEEK_SET);
+ uint32_t pair10_data_offset = roomFile->readUint32LE();
+ uint32_t pair10_size = roomFile->readUint32LE();
+ roomFile->seek(pair10_data_offset + 0x1BE, SEEK_SET);
+ int exit_count = roomFile->readByte();
+ roomFile->seek(pair10_data_offset + 0x1BF, SEEK_SET);
+ for (int i = 0; i < exit_count; i++) {
+ Exit exit;
+ exit.targetRoom = roomFile->readUint16LE();
+ exit.flags = roomFile->readByte();
+ exit.x = roomFile->readUint16LE();
+ exit.y = roomFile->readUint16LE();
+ exit.w = roomFile->readByte();
+ exit.h = roomFile->readByte();
+
+ exit.targetX = roomFile->readUint16LE();
+ exit.targetY = roomFile->readUint16LE();
+ exit.dir = roomFile->readByte();
+ debug("Exit %d: x=%d y=%d w=%d h=%d targetRoom=%d targetX=%d targetY=%d", i, exit.x, exit.y, exit.w, exit.h, exit.targetRoom, exit.targetX, exit.targetY);
+ exits.push_back(exit);
+ }
+ return exits;
+}
+
void PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
roomFile->seek(pair10_offset_pos, SEEK_SET);
@@ -1032,14 +1061,14 @@ void PelrockEngine::frames() {
int num = 0;
for (Common::List<AnimSet>::iterator i = _currentRoomAnims.begin(); i != _currentRoomAnims.end(); i++) {
- debug("Processing animation set %d, numAnims %d", num, i->numAnims);
+ // debug("Processing animation set %d, numAnims %d", num, i->numAnims);
if (i->numAnims == 0) {
num++;
continue;
}
for (int j = 0; j < i->numAnims; j++) {
- debug("Drawing animation %d of set %d at (%d,%d) size (%d,%d) nframes %d", j, num, i->x, i->y, i->w, i->h, i->animData[j].nframes);
+ // debug("Drawing animation %d of set %d at (%d,%d) size (%d,%d) nframes %d", j, num, i->x, i->y, i->w, i->h, i->animData[j].nframes);
int x = i->animData[j].x;
int y = i->animData[j].y;
int w = i->animData[j].w;
@@ -1049,22 +1078,22 @@ void PelrockEngine::frames() {
int curFrame = i->animData[j].curFrame;
byte *frame = new byte[frameSize];
Common::copy(i->animData[j].animData + (curFrame * i->h * i->w), i->animData[j].animData + (curFrame * i->h * i->w) + (frameSize), frame);
- debug("Current frame %d of %d", curFrame, i->animData[j].nframes);
-
- byte *bg = new byte[frameSize];
- for (int j = 0; j < w; j++) {
- for (int i = 0; i < h; i++) {
- int idx = i * w + j;
- *(bg + idx) = _currentBackground[(y + i) * 640 + (x + j)];
- }
- }
-
- for (int i = 0; i < w; i++) {
- for (int j = 0; j < h; j++) {
- int index = (j * w + i);
- *(byte *)g_engine->_screen->getBasePtr(x + i, y + j) = bg[index];
- }
- }
+ // debug("Current frame %d of %d", curFrame, i->animData[j].nframes);
+
+ // byte *bg = new byte[frameSize];
+ // for (int j = 0; j < w; j++) {
+ // for (int i = 0; i < h; i++) {
+ // int idx = i * w + j;
+ // *(bg + idx) = _currentBackground[(y + i) * 640 + (x + j)];
+ // }
+ // }
+
+ // for (int i = 0; i < w; i++) {
+ // for (int j = 0; j < h; j++) {
+ // int index = (j * w + i);
+ // *(byte *)g_engine->_screen->getBasePtr(x + i, y + j) = bg[index];
+ // }
+ // }
for (int y = 0; y < i->h; y++) {
for (int x = 0; x < i->w; x++) {
@@ -1089,6 +1118,25 @@ void PelrockEngine::frames() {
}
}
+void PelrockEngine::checkMouseClick(int x, int y) {
+ for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
+ if (x >= i->x && x <= (i->x + i->w) &&
+ y >= i->y && y <= (i->y + i->h)) {
+ debug("Clicked Exit at (%d,%d) size (%d,%d) to room %d", i->x, i->y, i->w, i->h, i->targetRoom);
+ setScreen(i->targetRoom, i->dir);
+ return;
+ }
+ }
+ for (Common::List<HotSpot>::iterator i = _hotspots.begin(); i != _hotspots.end(); i++) {
+ if (x >= i->x && x <= (i->x + i->w) &&
+ y >= i->y && y <= (i->y + i->h)) {
+ debug("Clicked Hotspot at (%d,%d) size (%d,%d) extra %d", i->x, i->y, i->w, i->h, i->extra);
+ // process hotspot action based on i->extra or other properties
+ return;
+ }
+ }
+}
+
void PelrockEngine::checkMouseHover() {
for (Common::List<HotSpot>::iterator i = _hotspots.begin(); i != _hotspots.end(); i++) {
if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
@@ -1121,7 +1169,7 @@ void PelrockEngine::setScreen(int number, int dir) {
byte *background = new byte[640 * 400];
getBackground(&roomFile, roomOffset, background);
- if(_currentBackground != nullptr)
+ if (_currentBackground != nullptr)
delete[] _currentBackground;
_currentBackground = new byte[640 * 400];
Common::copy(background, background + 640 * 400, _currentBackground);
@@ -1143,6 +1191,18 @@ void PelrockEngine::setScreen(int number, int dir) {
_screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
walkboxCount++;
}
+
+ _currentRoomExits = loadExits(&roomFile, roomOffset);
+
+ for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
+ // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
+ _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
+ _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
+ _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ walkboxCount++;
+ }
+
_screen->markAllDirty();
roomFile.close();
delete[] background;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 026bc2eb928..62b3cdeeea1 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -23,8 +23,8 @@
#define PELROCK_H
#include "common/error.h"
-#include "common/fs.h"
#include "common/file.h"
+#include "common/fs.h"
#include "common/hash-str.h"
#include "common/random.h"
#include "common/scummsys.h"
@@ -63,16 +63,19 @@ private:
Common::List<AnimSet> getRoomAnimations(Common::File *roomFile, int roomOffset);
void loadHotspots(Common::File *roomFile, int roomOffset);
void loadMainCharacterAnims();
+ Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
// render loop
void frames();
void checkMouseHover();
+ void checkMouseClick(int x, int y);
ChronoManager *_chronoManager = nullptr;
byte *standingAnim = new byte[3060 * 102];
Common::List<HotSpot> _hotspots;
Common::List<AnimSet> _currentRoomAnims;
+ Common::List<Exit> _currentRoomExits;
int *_currentAnimFrames = nullptr;
int curAlfredFrame = 9;
uint16 mouseX = 0;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 842df26840c..9b776ee65ef 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -10,10 +10,23 @@ struct Anim {
int w;
int h;
int nframes;
- int curFrame;
+ int curFrame;
byte *animData;
};
+struct Exit {
+ uint16 x;
+ uint16 y;
+ byte w;
+ byte h;
+ uint16 targetRoom;
+ uint16 targetX;
+ uint16 targetY;
+ uint16 targetDir;
+ byte dir;
+ byte flags;
+};
+
struct AnimSet {
int x;
int y;
Commit: 4aec798219ee64285a342ed5fc2863fc20b0e1a3
https://github.com/scummvm/scummvm/commit/4aec798219ee64285a342ed5fc2863fc20b0e1a3
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:58:59+02:00
Commit Message:
PELROCK: Load cursors, move alfred when changing room
Changed paths:
A engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
new file mode 100644
index 00000000000..1312a564db7
--- /dev/null
+++ b/engines/pelrock/offsets.h
@@ -0,0 +1,38 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_OFFSETS_H
+#define PELROCK_OFFSETS_H
+
+#include "common/scummsys.h"
+
+namespace Pelrock {
+
+ uint32_t cursor_offsets[5] = {
+ 0x0FDDFD,
+ 0x0FDCDD,
+ 0x0FDF1D,
+ 0x0FE33D,
+ 0x367EF0
+ };
+
+} // End of namespace Pelrock
+#endif
+
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 48715e0d6ad..41ad51cf1a4 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -37,6 +37,7 @@
#include "pelrock/console.h"
#include "pelrock/detection.h"
#include "pelrock/pelrock.h"
+#include "pelrock/offsets.h"
namespace Pelrock {
@@ -51,6 +52,9 @@ PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) :
PelrockEngine::~PelrockEngine() {
delete _screen;
delete _chronoManager;
+ for(int i =0; i<5; i++) {
+ delete[] _cursorMasks[i];
+ }
}
uint32 PelrockEngine::getFeatures() const {
@@ -109,519 +113,14 @@ Common::Error PelrockEngine::run() {
}
void PelrockEngine::init() {
- CursorMan.setDefaultArrowCursor();
+ loadCursors();
+
+ changeCursor(DEFAULT);
CursorMan.showMouse(true);
if (gameInitialized == false) {
- pixelsShadows = new byte[640 * 400];
- // sabeUsarElLibroMagico = 0;
- // magicWords = false;
- // apagaLaLuz = false;
- // showUsingObject = -1;
- // prevWhichScreen = -1;
- // whichScreen = -1;
gameInitialized = true;
-
- // tutorial.init();
-
- prevDirX = 0;
- prevDirY = 0;
- dirAlfred = 2;
-
- objectToShow = "";
-
- // factX = (float) widthScreen / (float) 640.0f;
- // factY = (float) heightScreen / (float) 400.0f;
-
- // xAlfred = (186 * factX);
- // yAlfred = (307 * factY);
- // xAlfred = 186;
- // yAlfred = 307;
-
- // for (int i = 0; i < 14; i++)
- // {
- // myPestanas[i].x = (int) ((float) myPestanas[i].x * factX);
- // myPestanas[i].y = (int) ((float) myPestanas[i].y * factY);
- // myPestanas[i].w = (int) ((float) myPestanas[i].w * factX);
- // myPestanas[i].h = (int) ((float) myPestanas[i].h * factY);
- // }
-
- // movingAlfred = ALFRED_STOPPED;
-
- // listUsedBranchs = new LinkedList<Integer>();
- // listUsedBranchs.clear();
-
- // listRects = new LinkedList<Integer>();
- // listRects.clear();
-
- // timeIddle = SystemClock.uptimeMillis();
-
- // myListLibros = new LinkedList<libros>();
- // myListLibros.clear();
-
- // myListDesactAnims = new LinkedList<dactAnims>();
- // myListDesactAnims.clear();
-
- // myListChangesConvs = new LinkedList<changesConvs>();
- // myListChangesConvs.clear();
-
- // myListPegas = new LinkedList<pegas>();
- // myListPegas.clear();
-
- // myListObjects = new LinkedList<objects>();
- // myListObjects.clear();
-
- // myListUsingObjects = new LinkedList<Integer>();
- // myListUsingObjects.clear();
-
- // isPersonajeTalking = -1;
-
- // stanteriaABuscar = -1;
-
- // selectedUsingObject = false;
-
- // currentTrack = "";
-
- // mainVolumen = 50;
- // mainTextSpeed = 50;
-
- // extraDataToSave = new byte[98];
-
- // leeLibros();
- // myoverlay.setCredits();
loadAnims();
- // loadOtherBitmaps();
- setScreen(1, 2);
- // setScreen(0, 2);
- // valSound1 = 0;
- // valSound2 = 0;
- // valSound3 = 0;
-
- // loadExtraTextsToTranslate();
-
- // loadTutorialText();
-
- // if (myMainActivity == null)
- // myMainActivity = this;// new AlfredActivity();
-
- // this.addContentView(myoverlay,
- // new android.view.ViewGroup.LayoutParams(
- // android.view.ViewGroup.LayoutParams.FILL_PARENT,
- // android.view.ViewGroup.LayoutParams.FILL_PARENT));
-
- // settingsLayout = new RelativeLayout(myContext);
- // settingsLayout
- // .setLayoutParams(new android.view.ViewGroup.LayoutParams(
- // android.view.ViewGroup.LayoutParams.FILL_PARENT,
- // android.view.ViewGroup.LayoutParams.FILL_PARENT));
-
- // settingsElem1 = new SeekBar(myContext);
- // settingsElem2 = new SeekBar(myContext);
- // settingsElem3 = new Spinner(myContext);
- // settingsElem4 = new Button(myContext);
-
- // String[] items = new String[myLanguages.length];// {"English",
- // // "Spanish",
- // // "Three"};
- // for (i = 0; i < myLanguages.length; i++)
- // {
- // items[i] = new String();
- // items[i] = myLanguages[i].nShow;
- // }
-
- // mySpinAdapter<String> adapter = new mySpinAdapter<String>(myContext,
- // items);
-
- // settingsElem3.setAdapter(adapter);
-
- // settingsElem3.setSelection(whichLanguageIndex);
-
- // String stringTutorial = "";
- // String namet = AlfredActivity.destinationFolder + "/tutorial.kk";
- // File ft = new File(namet);
-
- // if (ft.exists() == true)
- // {
- // byte b[] = tools.readFile(namet);
- // b[0]++;
-
- // if (b[0] >= 3)
- // {
- // b[0] = 3;
- // playTutorial = false;
- // stringTutorial = "OFF";
- // } else
- // {
- // playTutorial = true;
- // stringTutorial = "ON";
- // }
-
- // tools.createFile(namet, b);
-
- // } else
- // {
- // byte b[] = new byte[1];
-
- // b[0] = 0;
-
- // tools.createFile(namet, b);
- // playTutorial = true;
- // stringTutorial = "ON";
- // }
-
- // String finalText = "Tutorial " + stringTutorial;
-
- // settingsElem4.setText(finalText);
- // settingsElem4.postInvalidate();
- // settingsElem4.setBackgroundColor(0x00000000);
-
- // settingsElem1.setOnSeekBarChangeListener(
- // new SeekBar.OnSeekBarChangeListener()
- // {
-
- // public void onProgressChanged(SeekBar seekBar,
- // int progress, boolean fromTouch)
- // {
- // setVolumen(progress);
- // }
-
- // public void onStartTrackingTouch(SeekBar seekBar)
- // {
- // }
-
- // public void onStopTrackingTouch(SeekBar seekBar)
- // {
- // }
- // });
- // settingsElem2.setOnSeekBarChangeListener(
- // new SeekBar.OnSeekBarChangeListener()
- // {
-
- // public void onProgressChanged(SeekBar seekBar,
- // int progress, boolean fromTouch)
- // {
- // // mainTextSpeed=progress;
- // factTimeToShow = 10 + (100 - progress);
- // }
-
- // public void onStartTrackingTouch(SeekBar seekBar)
- // {
- // }
-
- // public void onStopTrackingTouch(SeekBar seekBar)
- // {
- // }
- // });
-
- // settingsElem3.setOnItemSelectedListener(new OnItemSelectedListener()
- // {
-
- // @Override
- // public void onItemSelected(AdapterView<?> arg0, View arg1,
- // int arg2, long arg3)
- // {
-
- // // trying to avoid undesired spinner selection changed
- // // event, a known problem
- // if (m_intSpinnerInitiCount < NO_OF_EVENTS)
- // {
- // m_intSpinnerInitiCount++;
- // } else
- // {
- // whichLanguage = myLanguages[arg2].nInternal;
- // whichLanguageInt = arg2;
- // loadExtraTextsToTranslate();
- // setScreen(whichScreen, dirAlfred);
- // leeLibros();
- // myoverlay.setCredits();
- // loadTutorialText();
- // }
- // }
-
- // @Override
- // public void onNothingSelected(AdapterView<?> arg0)
- // {
-
- // }
-
- // });
-
- // // set up list view
- // //////////////////
- // saveLoadLayout = new LinearLayout(myContext);
- // saveLoadLayout
- // .setLayoutParams(new android.view.ViewGroup.LayoutParams(
- // android.view.ViewGroup.LayoutParams.FILL_PARENT,
- // android.view.ViewGroup.LayoutParams.FILL_PARENT));
-
- // saveLoadListView = new ListView(myContext);
-
- // saveLoadListView.setOnItemClickListener(new OnItemClickListener()
- // {
-
- // @Override
- // public void onItemClick(AdapterView<?> arg0, View arg1,
- // final int arg2, long arg3)
- // {
-
- // if (saveOrLoad == 0)// save
- // {
-
- // AlertDialog.Builder alert = new AlertDialog.Builder(
- // myContext);
-
- // alert.setTitle("Dreamtripper");
- // alert.setMessage(extraThingsToTranslate[4]);
- // alert.setIcon(R.drawable.alfred);
- // final EditText input = new EditText(myContext);
- // String pp = nombrePartidas[arg2];
- // if (pp.compareTo(extraThingsToTranslate[7]) == 0)
- // pp = "";
- // input.setText(pp);
- // alert.setView(input);
-
- // alert.setPositiveButton("Ok",
- // new DialogInterface.OnClickListener()
- // {
- // public void onClick(DialogInterface dialog,
- // int whichButton)
- // {
- // grabaPartida(arg2,
- // input.getText().toString());
- // tools.showMessage(myContext,
- // "Dreamtripper",
- // extraThingsToTranslate[6],
- // "OK");
- // getNamesPartidas();
- // }
- // });
-
- // alert.setNegativeButton("Cancel",
- // new DialogInterface.OnClickListener()
- // {
- // public void onClick(DialogInterface dialog,
- // int whichButton)
- // {
- // }
- // });
-
- // alert.show();
-
- // } else
- // {// load
-
- // cargaPartida(arg2);
-
- // }
-
- // }
-
- // });
-
- // saveLoadLayout.addView(saveLoadListView,
- // new android.view.ViewGroup.LayoutParams(
- // android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
- // android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
-
- // settingsLayout.addView(settingsElem1,
- // new android.view.ViewGroup.LayoutParams(
- // (int) ((float) 180 * factX),
- // (int) ((float) 50 * factY)));
-
- // settingsLayout.addView(settingsElem2,
- // new android.view.ViewGroup.LayoutParams(
- // (int) ((float) 180 * factX),
- // (int) ((float) 50 * factY)));
-
- // settingsLayout.addView(settingsElem3,
- // new android.view.ViewGroup.LayoutParams(
- // (int) ((float) 120 * factX),
- // (int) ((float) 50 * factY)));
-
- // settingsLayout.addView(settingsElem4,
- // new android.view.ViewGroup.LayoutParams(
- // (int) ((float) 130 * factX),
- // (int) ((float) 50 * factY)));
-
- // ViewGroup.MarginLayoutParams mlp2 = (ViewGroup.MarginLayoutParams) settingsElem1
- // .getLayoutParams();
- // mlp2.setMargins((int) ((float) 300 * factX),
- // (int) ((float) 195 * factY),
- // (int) ((float) (640 - 460) * factX),
- // (int) ((float) (400 - 245) * factY));
-
- // ViewGroup.MarginLayoutParams mlp3 = (ViewGroup.MarginLayoutParams) settingsElem2
- // .getLayoutParams();
- // mlp3.setMargins((int) ((float) 300 * factX),
- // (int) ((float) 235 * factY),
- // (int) ((float) (640 - 460) * factX),
- // (int) ((float) (400 - 285) * factY));
-
- // ViewGroup.MarginLayoutParams mlp4 = (ViewGroup.MarginLayoutParams) settingsElem3
- // .getLayoutParams();
- // mlp4.setMargins((int) ((float) 340 * factX),
- // (int) ((float) 285 * factY),
- // (int) ((float) (640 - 460) * factX),
- // (int) ((float) (400 - 325) * factY));
-
- // ViewGroup.MarginLayoutParams mlp5 = (ViewGroup.MarginLayoutParams) settingsElem4
- // .getLayoutParams();
- // mlp5.setMargins((int) ((float) 210 * factX),
- // (int) ((float) 285 * factY),
- // (int) ((float) (640 - 360) * factX),
- // (int) ((float) (400 - 325) * factY));
-
- // ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) saveLoadListView
- // .getLayoutParams();
- // mlp.setMargins((int) ((float) 223 * factX),
- // (int) ((float) 200 * factY),
- // (int) ((float) (640 - 466) * factX),
- // (int) ((float) (400 - 312) * factY));
-
- // settingsElem1.setProgress(mainVolumen);
- // settingsElem2.setProgress(mainTextSpeed);
-
- // this.addContentView(saveLoadLayout,
- // new android.view.ViewGroup.LayoutParams(
- // android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
- // android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
-
- // this.addContentView(settingsLayout,
- // new android.view.ViewGroup.LayoutParams(
- // android.view.ViewGroup.LayoutParams.WRAP_CONTENT,
- // android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
-
- // settingsElem4.setOnClickListener(new OnClickListener()
- // {
-
- // @Override
- // public void onClick(View arg0)
- // {
-
- // String stringTutorial = "";
- // String namet = AlfredActivity.destinationFolder
- // + "/tutorial.kk";
-
- // byte b[] = tools.readFile(namet);
- // if (playTutorial == false)// (b[0]==0)
- // {
- // b[0] = 0;
- // playTutorial = true;
- // stringTutorial = "ON";
-
- // tutorial.init();
-
- // } else
- // {
- // b[0] = 4;
- // playTutorial = false;
- // stringTutorial = "OFF";
- // }
-
- // tools.createFile(namet, b);
-
- // String fiinalText = "Tutorial " + stringTutorial;
-
- // settingsElem4.setText(fiinalText);
- // settingsElem4.postInvalidate();
-
- // }
-
- // });
-
- // hideList();
- // hideSettings();
-
- // myExtraText = new extraText();
-
- // String name = AlfredActivity.destinationFolder + "/test.kk";
- // File f = new File(name);
- // if (f.exists() == true)
- // {
- // byte b[] = tools.readFile(name);
-
- // if (b[0] < 3)
- // {
- // b[0]++;
- // playIntro = true;
- // } else
- // playIntro = false;
-
- // tools.createFile(name, b);
-
- // } else
- // {
- // byte b[] = new byte[1];
-
- // b[0] = 0;
- // tools.createFile(name, b);
- // playIntro = true;
- // }
-
- // // playIntro=true;
- // if (playIntro == false)
- // {
- // stateGame = GAME;
- // } else
- // {
-
- // stateGame = INTRO;
- // varCheckRealTime = 0;
- // getWindow().setFormat(PixelFormat.TRANSLUCENT);
- // videoHolder = new myVideoView(this);
-
- // videoHolder.setWH(widthScreen, heightScreen);
-
- // // videoHolder.setLayoutParams(params)
-
- // Uri video = Uri.parse("android.resource://" + getPackageName()
- // + "/" + R.raw.intro2); // do not add any extension
- // videoHolder.setVideoURI(video);
-
- // LinearLayout.LayoutParams paramsVideo = new LinearLayout.LayoutParams(
- // widthScreen, heightScreen);
-
- // videoOverlay vo = new videoOverlay(myContext, assetManager,
- // videoHolder);
-
- // this.addContentView(videoHolder, paramsVideo);// new
- // // android.view.ViewGroup.LayoutParams(paramsVideo));
-
- // this.addContentView(vo, paramsVideo);// new
- // // android.view.ViewGroup.LayoutParams(paramsVideo));
-
- // // superTime=SystemClock.uptimeMillis();
- // videoHolder.start();
-
- // AlfredActivity.playTrack(22, false);
-
- // videoHolder.setOnTouchListener(new OnTouchListener()
- // {
- // @Override
- // public boolean onTouch(View arg0, MotionEvent arg1)
- // {
- // videoHolder.setVisibility(View.GONE);
- // videoHolder.stopPlayback();
-
- // AlfredActivity.myHandler
- // .sendEmptyMessage(AlfredActivity.INTRO_END);
-
- // return false;
- // }
-
- // });
-
- // videoHolder.setOnCompletionListener(new OnCompletionListener()
- // {
-
- // @Override
- // public void onCompletion(MediaPlayer arg0)
- // {
- // wait2(4000);
- // }
-
- // });
-
- // }
+ setScreen(0, 2);
}
}
@@ -630,152 +129,6 @@ void PelrockEngine::playIntro() {
void PelrockEngine::loadAnims() {
loadMainCharacterAnims();
- // try
- // {
-
- // // andar, acciones y hablar...
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred1.png");
-
- // for (int i = 0; i < 60; i++)
- // {
- // alfredBitmap[i] = Bitmap.createBitmap(mainAlfredAnim, i * 51, 0,
- // 51, 102);
- // }
-
- // mainAlfredAnim.recycle();
-
- // // andar por el tunel
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred13.png");
-
- // for (int i = 0; i < 18; i++)
- // {
- // alfredBitmap2[i] = Bitmap.createBitmap(mainAlfredAnim, i * 130,
- // 0, 130, 55);
- // }
-
- // mainAlfredAnim.recycle();
-
- // // animacion de peinarse mirando a la izquierda...
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred2.png");
-
- // for (int i = 0; i < 11; i++)
- // alfredBitmapExtra1[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 51, 0, 51, 102);
-
- // mainAlfredAnim.recycle();
-
- // // animacion de peinarse mirando a la derecha...
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred3.png");
-
- // for (int i = 0; i < 11; i++)
- // alfredBitmapExtra2[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 51, 0, 51, 102);
-
- // mainAlfredAnim.recycle();
-
- // // animacion de leer...
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred4.png");
-
- // for (int i = 0; i < 10; i++)
- // alfredBitmapExtra3[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 51, 0, 51, 102);
-
- // // animacion de electrocutarse...
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred5.png");
-
- // for (int i = 0; i < 8; i++)
- // alfredBitmapExtra4[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 82, 0, 82, 58);
-
- // // animacion de cocodrilo...
- // mainAlfredAnim = getBitmapFromAsset("animaciones/crocodillo.png");
-
- // for (int i = 0; i < 14; i++)
- // alfredBitmapExtra5[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 171, 0, 171, 109);
-
- // // animacion de escondite...
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred6.png");
-
- // for (int i = 0; i < 12; i++)
- // alfredBitmapExtra6[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 113, 0, 113, 103);
-
- // // animacion de bajada al tunel...
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred7.png");
-
- // for (int i = 0; i < 11; i++)
- // alfredBitmapExtra7[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 33, 0, 33, 72);
-
- // // animacion de subida del tunel...
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred8.png");
-
- // for (int i = 0; i < 9; i++)
- // alfredBitmapExtra8[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 33, 0, 33, 72);
-
- // // animacion de escapada del tunel (llega al zoco)
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred9.png");
-
- // for (int i = 0; i < 16; i++)
- // alfredBitmapExtra9[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 158, 0, 158, 115);
-
- // // animacion de puesta del muneco hinchable
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred10.png");
-
- // for (int i = 0; i < 17; i++)
- // alfredBitmapExtra10[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 177, 0, 177, 124);
-
- // // animacion de magia (1)
- // mainAlfredAnim = getBitmapFromAsset("animaciones/magia1.png");
-
- // for (int i = 0; i < 11; i++)
- // alfredBitmapExtra11[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 98, 0, 98, 138);
-
- // // animacion de magia (2)
- // mainAlfredAnim = getBitmapFromAsset("animaciones/magia2.png");
-
- // for (int i = 0; i < 12; i++)
- // alfredBitmapExtra12[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 98, 0, 98, 138);
-
- // // animacion de pedras
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred11.png");
-
- // for (int i = 0; i < 7; i++)
- // alfredBitmapExtra13[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 208, 0, 208, 102);
-
- // // animacion de desnudo
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred12.png");
-
- // for (int i = 0; i < 4; i++)
- // alfredBitmapExtra14[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 51, 0, 51, 102);
-
- // // animacion de despertarse
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred14.png");
-
- // for (int i = 0; i < 14; i++)
- // alfredBitmapExtra15[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 71, 0, 71, 66);
-
- // // animacion de tirar piedra
- // mainAlfredAnim = getBitmapFromAsset("animaciones/alfred15.png");
-
- // for (int i = 0; i < 4; i++)
- // alfredBitmapExtra16[i] = Bitmap.createBitmap(mainAlfredAnim,
- // i * 71, 0, 71, 101);
-
- // mainAlfredAnim.recycle();
-
- // } catch (IOException e)
- // {
- // }
}
const int EXPECTED_SIZE = 640 * 400;
@@ -973,6 +326,24 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
return walkboxes;
}
+void PelrockEngine::loadCursors() {
+ Common::File alfred7File;
+ if(!alfred7File.open("ALFRED.7")) {
+ error("Couldnt find file ALFRED.7");
+ }
+ for (int i= 0; i < 5; i++) {
+ uint32_t cursorOffset = cursor_offsets[i];
+ alfred7File.seek(cursorOffset);
+ _cursorMasks[i] = new byte[kCursorSize];
+ alfred7File.read(_cursorMasks[i], kCursorSize);
+ for(int j = 0; j < kCursorSize; j++) {
+ byte *cursorMask = _cursorMasks[i];
+ if(cursorMask[j] == 255) cursorMask[j] = 0;
+ }
+ }
+ alfred7File.close();
+}
+
Common::List<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffset) {
Common::List<Exit> exits;
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
@@ -1050,14 +421,9 @@ void PelrockEngine::loadMainCharacterAnims() {
}
void PelrockEngine::frames() {
+
if (_chronoManager->_gameTick) {
- for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
- for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
- unsigned int src_pos = (curAlfredFrame * kAlfredFrameHeight * kAlfredFrameWidth) + (y * kAlfredFrameWidth) + x;
- if (standingAnim[src_pos] != 255)
- _screen->setPixel(x + xAlfred, y + yAlfred, standingAnim[src_pos]);
- }
- }
+
int num = 0;
for (Common::List<AnimSet>::iterator i = _currentRoomAnims.begin(); i != _currentRoomAnims.end(); i++) {
@@ -1068,7 +434,6 @@ void PelrockEngine::frames() {
}
for (int j = 0; j < i->numAnims; j++) {
- // debug("Drawing animation %d of set %d at (%d,%d) size (%d,%d) nframes %d", j, num, i->x, i->y, i->w, i->h, i->animData[j].nframes);
int x = i->animData[j].x;
int y = i->animData[j].y;
int w = i->animData[j].w;
@@ -1080,20 +445,23 @@ void PelrockEngine::frames() {
Common::copy(i->animData[j].animData + (curFrame * i->h * i->w), i->animData[j].animData + (curFrame * i->h * i->w) + (frameSize), frame);
// debug("Current frame %d of %d", curFrame, i->animData[j].nframes);
- // byte *bg = new byte[frameSize];
- // for (int j = 0; j < w; j++) {
- // for (int i = 0; i < h; i++) {
- // int idx = i * w + j;
- // *(bg + idx) = _currentBackground[(y + i) * 640 + (x + j)];
- // }
- // }
-
- // for (int i = 0; i < w; i++) {
- // for (int j = 0; j < h; j++) {
- // int index = (j * w + i);
- // *(byte *)g_engine->_screen->getBasePtr(x + i, y + j) = bg[index];
- // }
- // }
+ byte *bg = new byte[frameSize];
+ for (int j = 0; j < w; j++) {
+ for (int i = 0; i < h; i++) {
+ int idx = i * w + j;
+ if(y + i < 400 && x + j < 640) {
+ *(bg + idx) = _currentBackground[(y + i) * 640 + (x + j)];
+ }
+ }
+ }
+
+ for (int i = 0; i < w; i++) {
+ for (int j = 0; j < h; j++) {
+ int index = (j * w + i);
+ if(x + i < 640 && y + j < 400)
+ *(byte *)g_engine->_screen->getBasePtr(x + i, y + j) = bg[index];
+ }
+ }
for (int y = 0; y < i->h; y++) {
for (int x = 0; x < i->w; x++) {
@@ -1112,6 +480,15 @@ void PelrockEngine::frames() {
}
}
num++;
+
+ for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
+ for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
+ unsigned int src_pos = (curAlfredFrame * kAlfredFrameHeight * kAlfredFrameWidth) + (y * kAlfredFrameWidth) + x;
+ // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
+ if (standingAnim[src_pos] != 255)
+ _screen->setPixel(x + xAlfred, y + yAlfred, standingAnim[src_pos]);
+ }
+ }
}
_screen->markAllDirty();
_screen->update();
@@ -1123,6 +500,8 @@ void PelrockEngine::checkMouseClick(int x, int y) {
if (x >= i->x && x <= (i->x + i->w) &&
y >= i->y && y <= (i->y + i->h)) {
debug("Clicked Exit at (%d,%d) size (%d,%d) to room %d", i->x, i->y, i->w, i->h, i->targetRoom);
+ xAlfred = i->targetX;
+ yAlfred = i->targetY - kAlfredFrameHeight;
setScreen(i->targetRoom, i->dir);
return;
}
@@ -1137,12 +516,16 @@ void PelrockEngine::checkMouseClick(int x, int y) {
}
}
+void PelrockEngine::changeCursor(Cursor cursor) {
+ CursorMan.replaceCursor(_cursorMasks[cursor], kCursorWidth, kCursorHeight, 0, 0, 0);
+}
+
void PelrockEngine::checkMouseHover() {
for (Common::List<HotSpot>::iterator i = _hotspots.begin(); i != _hotspots.end(); i++) {
if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
mouseY >= i->y && mouseY <= (i->y + i->h)) {
// _currentHotspot = &(*i);
- // debug("Hotspot at (%d,%d) size (%d,%d) extra %d", i->x, i->y, i->w, i->h, i->extra);
+ debug("Hotspot at (%d,%d) size (%d,%d) extra %d", i->x, i->y, i->w, i->h, i->extra);
return;
}
}
@@ -1181,6 +564,16 @@ void PelrockEngine::setScreen(int number, int dir) {
_currentRoomAnims = getRoomAnimations(&roomFile, roomOffset);
loadHotspots(&roomFile, roomOffset);
+ int hotsPotCount = 0;
+ for (Common::List<HotSpot>::iterator i = _hotspots.begin(); i != _hotspots.end(); i++) {
+ // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
+ _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 100 + hotsPotCount);
+ _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 100 + hotsPotCount);
+ _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 100 + hotsPotCount);
+ _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 100 + hotsPotCount);
+ hotsPotCount++;
+ }
+
Common::List<WalkBox> walkboxes = loadWalkboxes(&roomFile, roomOffset);
int walkboxCount = 0;
for (Common::List<WalkBox>::iterator i = walkboxes.begin(); i != walkboxes.end(); i++) {
@@ -1209,1003 +602,6 @@ void PelrockEngine::setScreen(int number, int dir) {
delete[] palette;
}
-void PelrockEngine::setScreenJava(int s, int dir) {
- screenReady = false;
- dirAlfred = dir;
-
- // vueltaALaCarcel = false;
- // timeToGoToPiss = -1;
- // myoverlay.shakeScreen = false;
- // walkingAgain = false;
-
- // myoverlay.indexCicleColores = 0;
-
- // stringToShowOnTutorial = "";
-
- // magicWords = false;
-
- // myMovingAlfredThread.isOtherTalking = false;
- // isPersonajeTalking = -1;
- // myMovingAlfredThread.showTextNowOtros = false;
-
- // // pantalla................
- // if (screenBitmap != null)
- // {
- // screenBitmap.recycle();
- // screenBitmap = null;
- // }
-
- prevWhichScreen = whichScreen;
-
- whichScreen = s;
-
- // objetos.getObjectList(assetManager, s);
- // objectToShow = "";
-
- Common::String nameScreen = Common::String::format("pantallas/pantalla%d.png", s);
- Common::String nameCamino = Common::String::format("caminos/pantalla%d.txt", s);
-
- Common::File screen;
- if (!screen.open(Common::Path(nameScreen))) {
- error("Could not find pantalla!");
- }
- decoder->loadStream(screen);
- Graphics::Palette palette = decoder->getPalette();
- g_system->getPaletteManager()->setPalette(palette);
- const Graphics::Surface *surf = decoder->getSurface();
- if (!surf)
- error("No surface");
-
- g_engine->_screen->blitFrom(*surf);
-
- _screen->markAllDirty();
-
- // Config c = null;
- // try
- // {
- // screenBitmap = getBitmapFromAsset(nameScreen);
-
- // c = screenBitmap.getConfig();
- // screenBitmap = screenBitmap.copy(c, true);
- // } catch (IOException e)
- // {
- // }
-
- Common::String nameColorsx = Common::String::format("colors%d.png", s);
- Common::String nameColors = "colors/" + nameColorsx;
- // try
- // {
- // screenColors = getBitmapFromAsset(nameColors);
- // } catch (IOException e)
- // {
- // screenColors = null;
- // }
- // if (screenColors != null)
- // setFakePalette(nameColorsx, screenColors);
-
- Common::String nameShadows = Common::String::format("shadows/shadows_%d.png", s); // <-- fixed: include s
- Common::File shadows;
- if (shadows.open(Common::Path(nameShadows)) != Common::kNoError) {
- error("Error opening shadows: %s", nameShadows.c_str());
- return;
- }
- if (decoder->loadStream(shadows) != Common::kNoError) {
- error("Decoder failed loading shadows: %s", nameShadows.c_str());
- return;
- }
- const Graphics::Surface *shadowSurf = decoder->getSurface();
- if (!shadowSurf) {
- error("No shadow surface for %s", nameShadows.c_str());
- return;
- }
- Common::copy((byte *)shadowSurf->getPixels(), (byte *)shadowSurf->getPixels() + 640 * 400, pixelsShadows);
-
- // try
- // {
- // shadowColors = getBitmapFromAsset(nameShadows);
- // } catch (IOException e)
- // {
- // shadowColors = null;
- // }
-
- // shadowColors.getPixels(pixelsShadows, 0, 640, 0, 0, 640, 400);
-
- Common::File caminos;
- if (!caminos.open(Common::Path(nameCamino))) {
- error("Cant find camino");
- }
-
- // // caminos................
- // BufferedReader br = null;
- // List<String> wordList = new ArrayList<String>();
-
- // try
- // {
- // br = new BufferedReader(
- // new InputStreamReader(assetManager.open(nameCamino)));
- // String word;
- // while ((word = br.readLine()) != null)
- // wordList.add(word);
- // } catch (IOException e)
- // {
- // }
-
- // paths.caminos = new defCam();
-
- // int k = wordList.size();
-
- // List<rectCam> provList = new LinkedList<rectCam>();
- // provList.clear();
-
- // List<conex> provListCon = new LinkedList<conex>();
- // provListCon.clear();
-
- // List<anims> provListAnims = new LinkedList<anims>();
- // provListAnims.clear();
-
- // myScale = null;
-
- // scale aux4 = null;
-
- // String line;
- // int ind = -1;
- // int prevInd = 0;
- // int which = 0;
-
- // for (int i = 0; i < k; i++)
- // {
-
- // line = wordList.get(i);
-
- // if (line.compareTo("paths") == 0)
- // which = 0;
- // else if (line.compareTo("conexions") == 0)
- // which = 1;
- // else if (line.compareTo("anims") == 0)
- // which = 2;
- // else if (line.compareTo("scale") == 0)
- // which = 3;
- // else
- // {
-
- // switch (which)
- // {
- // case 0:
-
- // rectCam aux = new rectCam();
-
- // ind = line.indexOf(',', ind + 1);
- // aux.x = (int) (Float
- // .parseFloat(line.substring(prevInd, ind)) * factX);
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux.y = (int) (Float
- // .parseFloat(line.substring(prevInd, ind)) * factY);
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux.w = (int) (Float
- // .parseFloat(line.substring(prevInd, ind)) * factX);
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux.h = (int) (Float.parseFloat(line.substring(prevInd))
- // * factY);
- // prevInd = ind + 1;
-
- // ind = -1;
- // prevInd = 0;
-
- // provList.add(aux);
-
- // break;
-
- // case 1:
-
- // conex aux2 = new conex();
-
- // ind = line.indexOf(',', ind + 1);
- // aux2.x = (int) (Float
- // .parseFloat(line.substring(prevInd, ind)) * factX);
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux2.y = (int) (Float
- // .parseFloat(line.substring(prevInd, ind)) * factY);
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux2.which = (int) (Integer
- // .parseInt(line.substring(prevInd, ind)));
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux2.ready = (int) (Integer
- // .parseInt(line.substring(prevInd, ind)));
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux2.nx = (int) (Float
- // .parseFloat(line.substring(prevInd, ind)) * factX);
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux2.ny = (int) (Float
- // .parseFloat(line.substring(prevInd, ind)) * factY);
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux2.ndir = (int) (Integer
- // .parseInt(line.substring(prevInd)));
- // prevInd = ind + 1;
-
- // ind = -1;
- // prevInd = 0;
-
- // provListCon.add(aux2);
- // break;
-
- // case 2:
-
- // anims aux3 = new anims();
-
- // aux3.activated = true;
-
- // ind = line.indexOf(',', ind + 1);
- // aux3.x = (int) (Integer
- // .parseInt(line.substring(prevInd, ind)) * factX);
- // aux3.backupX = aux3.x;
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux3.y = (int) (Integer
- // .parseInt(line.substring(prevInd, ind)) * factY);
- // aux3.backupY = aux3.y;
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux3.moving = (boolean) (Boolean
- // .parseBoolean((line.substring(prevInd, ind))));
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux3.frames = (int) (Integer
- // .parseInt(line.substring(prevInd, ind)));
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // if (ind == -1)
- // aux3.speed = (int) (Integer
- // .parseInt(line.substring(prevInd)));
- // else
- // aux3.speed = (int) (Integer
- // .parseInt(line.substring(prevInd, ind)));
- // prevInd = ind + 1;
-
- // aux3.whichFrame = 0;
- // aux3.nSpeed = 0;
-
- // if (ind != -1)// otros datos en las animaciones...
- // {
- // int kk;
- // if (aux3.moving == false)// los datos extras son de
- // // animaciones 'combinadas'
- // {
-
- // ind = line.indexOf(',', ind + 1);
- // kk = (int) (Integer
- // .parseInt(line.substring(prevInd, ind)));
- // prevInd = ind + 1;
-
- // aux3.animParts = new parts[kk];
- // aux3.time = 0;
- // aux3.whichPart = 0;
-
- // for (int j = 0; j < kk; j++)
- // {
- // aux3.animParts[j] = new parts();
-
- // ind = line.indexOf(',', ind + 1);
- // aux3.animParts[j].nframes = (int) (Integer
- // .parseInt(
- // line.substring(prevInd, ind)));
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // if (ind == -1)
- // aux3.animParts[j].duration = (int) (Integer
- // .parseInt(line.substring(prevInd)));
- // else
- // aux3.animParts[j].duration = (int) (Integer
- // .parseInt(line.substring(prevInd,
- // ind)));
-
- // prevInd = ind + 1;
-
- // }
-
- // } else
- // {
-
- // ind = line.indexOf(',', ind + 1);
- // kk = (int) (Integer
- // .parseInt(line.substring(prevInd, ind)));
- // prevInd = ind + 1;
-
- // aux3.incAnims = new movements[kk];
-
- // aux3.whichMovement = 0;
- // aux3.isMovingAlready = false;
-
- // ind = line.indexOf(',', ind + 1);
- // aux3.startMoving = (int) (Integer
- // .parseInt(line.substring(prevInd, ind)));
- // prevInd = ind + 1;
-
- // for (int j = 0; j < kk; j++)
- // {
- // aux3.incAnims[j] = new movements();
-
- // ind = line.indexOf(',', ind + 1);
- // aux3.incAnims[j].ix = (float) (Float.parseFloat(
- // line.substring(prevInd, ind)));
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux3.incAnims[j].iy = (float) (Float.parseFloat(
- // line.substring(prevInd, ind)));
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // if (ind == -1)
- // aux3.incAnims[j].duration = (int) (Integer
- // .parseInt(line.substring(prevInd)));
- // else
- // aux3.incAnims[j].duration = (int) (Integer
- // .parseInt(line.substring(prevInd,
- // ind)));
- // prevInd = ind + 1;
-
- // aux3.incAnims[j].nduration = 0;
-
- // }
-
- // }
-
- // }
-
- // ind = -1;
- // prevInd = 0;
-
- // provListAnims.add(aux3);
-
- // break;
-
- // case 3:
-
- // aux4 = new scale();
-
- // ind = line.indexOf(',', ind + 1);
- // aux4.miny = (int) (Float
- // .parseFloat(line.substring(prevInd, ind)) * factY);
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux4.factmin = (int) (Integer
- // .parseInt(line.substring(prevInd, ind)));
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux4.maxy = (int) (Float
- // .parseFloat(line.substring(prevInd, ind)) * factY);
- // prevInd = ind + 1;
-
- // ind = line.indexOf(',', ind + 1);
- // aux4.factmax = (int) (Integer
- // .parseInt(line.substring(prevInd)));
- // prevInd = ind + 1;
-
- // prevInd += 0;
- // break;
- // }
-
- // }
-
- // }
-
- // // myAnims
-
- // int realPaths = provList.size();
-
- // paths.caminos.cams = new rectCam[realPaths];
-
- // int t;
- // for (t = 0; t < realPaths; t++)
- // {
- // paths.caminos.cams[t] = new rectCam();
- // paths.caminos.cams[t] = provList.get(t);
- // }
-
- // int realConex = provListCon.size();
-
- // myConex = new conex[realConex];
- // for (t = 0; t < realConex; t++)
- // {
- // myConex[t] = new conex();
- // myConex[t] = provListCon.get(t);
- // }
-
- // int realAnims = provListAnims.size();
-
- // bitmapAnims = new Bitmap[realAnims];
-
- // try
- // {
- // myAnims = new anims[realAnims];
- // for (t = 0; t < realAnims; t++)
- // {
-
- // myAnims[t] = new anims();
- // myAnims[t] = provListAnims.get(t);
-
- // bitmapAnims[t] = getBitmapFromAsset(
- // "animaciones/anim" + String.valueOf(whichScreen)
- // + String.valueOf(t) + ".png");
-
- // myAnims[t].realWFrame = bitmapAnims[t].getWidth();
- // myAnims[t].realHFrame = bitmapAnims[t].getHeight();
-
- // myAnims[t].w = (int) ((float) bitmapAnims[t].getWidth()
- // * factX);
- // myAnims[t].h = (int) ((float) bitmapAnims[t].getHeight()
- // * factY);
-
- // myAnims[t].predOrder = t;
- // }
- // } catch (Exception e)
- // {
- // }
-
- // for (int i = 0; i < realPaths; i++)
- // {
- // paths.caminos.cams[i].vecinos = new LinkedList<Integer>();
- // paths.caminos.cams[i].index = i;
- // paths.caminos.cams[i].marked = false;
-
- // for (int j = 0; j < realPaths; j++)
- // {
- // if ((i != j) && (paths.esVecino(i, j)))
- // paths.caminos.cams[i].vecinos.add(j);
- // }
- // }
-
- // if (aux4 != null)
- // {
- // myScale = aux4;
- // }
-
- // checkPegatinas(whichScreen);
- // checkObjects(whichScreen);
-
- // myConversaciones.loadConversations(whichScreen);
-
- // // a ver si alguna conversacion esta cambiada
- // if (myConversaciones.mytalkingAnims[whichScreen].myPersonajes != null)
- // {
-
- // int x = myConversaciones.mytalkingAnims[whichScreen].myPersonajes.length;
-
- // for (int i = 0; i < x; i++)
- // myConversaciones.mytalkingAnims[whichScreen].myPersonajes[i].currentConversationEach = 0;
-
- // }
-
- // int n = myListChangesConvs.size();
- // for (int i = 0; i < n; i++)
- // {
- // changesConvs aux = new changesConvs();
- // aux = myListChangesConvs.get(i);
-
- // if (whichScreen == aux.screen)
- // {
- // myConversaciones.mytalkingAnims[whichScreen].myPersonajes[aux.which].currentConversationEach = aux.n;// .setConversation(whichScreen,
- // // aux.which,
- // // aux.n);
- // }
- // }
-
- // myoverlay.isFadedOut = false;
-
- // // a ver si se ha desactivado alguna animacion
- // n = myListDesactAnims.size();
-
- // for (int i = 0; i < n; i++)
- // {
- // dactAnims aux = new dactAnims();
- // aux = myListDesactAnims.get(i);
-
- // if (whichScreen == aux.screen)
- // myAnims[aux.which].activated = false;
- // }
-
- // // personajes pe[];
- // personajes pe[] = AlfredActivity.myConversaciones.mytalkingAnims[whichScreen].myPersonajes;
- // // lista de cosas sueltas a hacer...
-
- // pintaPeriodicoDandoVueltas = false;
- // int j;
- // switch (whichScreen)
- // {
-
- // case 51:
- // desactivaAnims(51, 0);
- // desactivaAnims(51, myAnims.length - 1);
- // resetDiosesTime();
- // break;
-
- // case 52:
- // desactivaAnims(52, 0);
- // desactivaAnims(52, 1);
- // desactivaAnims(52, 2);
- // desactivaAnims(52, 3);
- // desactivaAnims(52, 4);
- // desactivaAnims(52, 5);
- // ponPegatina(52, 145);
- // desactivaAnims(52, myAnims.length - 1);
- // resetDiosesTime();
- // break;
-
- // case 53:
- // desactivaAnims(53, 0);
- // desactivaAnims(53, myAnims.length - 1);
- // resetDiosesTime();
- // break;
-
- // case 54:
- // desactivaAnims(54, 0);
- // desactivaAnims(54, myAnims.length - 1);
- // resetDiosesTime();
- // break;
-
- // case 0:
- // if ((readExtraVariable(VUELTA_A_EMPEZAR) == 1)
- // && (readExtraVariable(FROM_INTRO) == 0))
- // {
- // setExtraVariables(AlfredActivity.VUELTA_A_EMPEZAR, 2);
- // myoverlay.setAnimExtra(14, 15, 21, 71, 66, 0, 0);
- // myMovingAlfredThread.showTextNow = true;
- // whichObject = 0;
- // textToShow = extraThingsToTranslate[117];
-
- // }
-
- // break;
-
- // case 48:
-
- // AlfredActivity.myMovingAlfredThread.saySomethingOther(
- // AlfredActivity.extraThingsToTranslate[115], 0);
- // setExtraVariables(AlfredActivity.A_POR_LA_PRINCESA, 1);
-
- // desactivaAnims(48, 7);
-
- // break;
-
- // case 44:
-
- // if (readExtraVariable(AlfredActivity.PIEDRA_FAKE_MOJADA) == 3)
- // updateConexion(55, 1);
-
- // break;
-
- // case 41:
- // j = getOrderAnims(2);
- // myAnims[j].activated = false;
-
- // j = getOrderAnims(3);
- // myAnims[j].activated = false;
-
- // if (readExtraVariable(AlfredActivity.GUARDIAS_BORRACHOS) == 1)
- // updateConexion(43, 1);
-
- // break;
-
- // case 40:
-
- // finalObject = 0;
- // whichObject = 0;
- // actionToDo = 1;
- // myMovingAlfredThread.stateOfTalking = 0;
- // gotoPos(290, 370, 3);
- // whichAction = objetos.HABLAR;
- // afterMovingAlfred = ALFRED_TALKING;
- // posibilityOfFakeAnswer = false;
- // varCheckRealTime = -1;
-
- // break;
-
- // case 39:
-
- // j = getOrderAnims(0);
- // myAnims[j].activated = false;
-
- // j = getOrderAnims(7);
- // myAnims[j].activated = false;
-
- // j = getOrderAnims(8);
- // myAnims[j].activated = false;
-
- // j = getOrderAnims(9);
- // myAnims[j].activated = false;
-
- // j = getOrderAnims(10);
- // myAnims[j].activated = false;
-
- // break;
-
- // case 34:
- // if (readExtraVariable(AlfredActivity.VIGILANTE_PAJEANDOSE) == 1)
- // {
- // int i = getOrderAnims(0);
- // myAnims[i].activated = false;
- // updateConexion(35, 1);
-
- // }
- // break;
-
- // case 21:
-
- // if ((prevWhichScreen == 36)
- // && (readExtraVariable(AlfredActivity.PIRAMIDE_JODIDA) == 1))
- // {
- // updateConexion(36, 0);
- // AlfredActivity.ponPegatina(21, 79);
- // AlfredActivity.addPegatina(21, 79);
- // }
-
- // break;
-
- // case 36:
-
- // byte z = readExtraVariable(AlfredActivity.PIRAMIDE_JODIDA);
- // if (z >= 3)
- // setExtraVariables(AlfredActivity.PIRAMIDE_JODIDA, 1);
-
- // int i;
-
- // if (readExtraVariable(AlfredActivity.PIRAMIDE_JODIDA) == 1) // se ha
- // // cargado
- // // la
- // // piramide
- // {
-
- // i = getOrderAnims(0);
- // myAnims[i].x = (int) (328.0f * factX);
- // myAnims[i].y = (int) (209.0f * factY);
- // myAnims[i].moving = false;
- // myAnims[i].incAnims = null;// new movements[1];
-
- // myAnims[i].speed = 1000000;
-
- // i = getOrderAnims(2);
- // myAnims[i].activated = true;
- // myAnims[i].speed = 16;
- // } else// if (prevWhichScreen==21)//no ha hecho nada
- // {
- // i = getOrderAnims(0);
-
- // if (prevWhichScreen == 21)
- // {
- // myAnims[i].activated = true;
- // myAnims[i].speed = 1000000;
- // updateConexion(37, 0);
- // } else
- // {
- // myAnims[i].activated = false;
- // updateConexion(37, 1);
- // }
-
- // i = getOrderAnims(2);
- // myAnims[i].activated = false;
-
- // }
-
- // break;
-
- // case 26:
-
- // mypersonajes = pe[0];
-
- // if (myListUsingObjects.contains(82) == false)// no tiene dinero
- // mypersonajes.setConversation(26, 0, 0);
- // else
- // mypersonajes.setConversation(26, 0, 1);
-
- // mypersonajes = pe[1];
- // mypersonajes.setConversation(26, 1, 0);
-
- // if ((AlfredActivity
- // .readExtraVariable(AlfredActivity.A_LA_CARCEL) == 1)
- // && (prevWhichScreen == 27)
- // && (AlfredActivity.readExtraVariable(
- // AlfredActivity.SE_HA_PUESTO_EL_MUNECO) == 0))
- // {
- // mypersonajes = pe[1];
- // mypersonajes.setConversation(26, 1, 1);
- // // myAnims[0].activated=true;
- // finalObject = 1;
- // whichObject = 1;
- // actionToDo = 1;
- // myMovingAlfredThread.stateOfTalking = 0;
- // gotoPos(314, 240, 3);
- // whichAction = objetos.HABLAR;// .h
- // afterMovingAlfred = ALFRED_TALKING;
- // posibilityOfFakeAnswer = false;
- // varCheckRealTime = -1;
- // }
- // if ((AlfredActivity
- // .readExtraVariable(AlfredActivity.A_LA_CARCEL) == 1)
- // && (prevWhichScreen == 27)
- // && (AlfredActivity.readExtraVariable(
- // AlfredActivity.SE_HA_PUESTO_EL_MUNECO) == 1))
- // {
- // mypersonajes = pe[1];
- // mypersonajes.setConversation(26, 1, 2);
- // }
-
- // break;
-
- // case 27:
- // if (prevWhichScreen == 33)// viene del tunel
- // {
- // xAlfred = 90.0f * factX;
- // yAlfred = 380.0f * factY;
- // myoverlay.setAnimExtra(16, 9, 12, 158, 115, 0, 0);
- // }
-
- // // mypersonajes = pe[0];
-
- // if (myListUsingObjects.contains(82) == false)
- // {
- // mypersonajes = pe[0];
- // mypersonajes.setConversation(27, 0, 0);
- // mypersonajes = pe[1];
- // mypersonajes.setConversation(27, 1, 0);
- // } else
- // {
- // mypersonajes = pe[0];
- // mypersonajes.setConversation(27, 0, 1);
- // mypersonajes = pe[1];
- // mypersonajes.setConversation(27, 1, 1);
- // }
-
- // break;
-
- // case 32:
- // if (prevWhichScreen == 31)// viene de la carcel
- // {
- // xAlfred = 321.0f * factX;
- // yAlfred = 125.0f * factY;
- // myoverlay.setAnimExtra(11, 7, 9, 33, 72, 0, 0);
- // AlfredActivity.myConversaciones.mytalkingAnims[31].myPersonajes[0]
- // .setConversation(31, 0, 3);
- // // mypersonajes = pe[0];
- // // mypersonajes.setConversation(31, 0, 3);
- // }
-
- // break;
-
- // case 38:
- // if (AlfredActivity
- // .readExtraVariable(AlfredActivity.ROBA_PELO_PRINCESA) == 0)
- // {
- // xAlfred = 230.0f * factX;
- // yAlfred = 283.0f * factY;
- // myoverlay.setAnimExtra(12, 6, 8, 113, 103, -32, 15);
- // }
- // break;
- // case 30:
- // myAnims[0].activated = false;
- // myAnims[4].activated = false;
-
- // if ((readExtraVariable(PUERTA_SECRETA_ABIERTA) == 1)
- // && (AlfredActivity.readExtraVariable(
- // AlfredActivity.ROBA_PELO_PRINCESA) != 2))
- // updateConexion(38, 1);
-
- // if (AlfredActivity
- // .readExtraVariable(AlfredActivity.ROBA_PELO_PRINCESA) == 1)
- // {
-
- // setExtraVariables(AlfredActivity.ROBA_PELO_PRINCESA, 2);
- // myAnims[0].activated = true;
- // finalObject = 0;
- // actionToDo = 0;
- // myMovingAlfredThread.stateOfTalking = 0;
- // gotoPos(391, 344, 1);
- // whichAction = objetos.HABLAR;// .h
- // afterMovingAlfred = ALFRED_TALKING;
- // posibilityOfFakeAnswer = false;
- // varCheckRealTime = -1;
- // }
- // break;
-
- // case 4:
- // if (readExtraVariable(ELECTROCUTACION) == 0)
- // {
- // setExtraVariables(AlfredActivity.ELECTROCUTACION, 1);
- // hideObject(7);
- // }
- // if (readExtraVariable(AlfredActivity.CABLES_PUESTOS) == 3)
- // showObject(8);
- // else
- // hideObject(8);
- // case 8:
- // case 14:
- // if (AlfredActivity.readExtraVariable(
- // AlfredActivity.VENDEDOR_DEJA_DE_JODER) == 1)
- // {
- // paths.caminos.cams[0].w = (int) (599.0f * AlfredActivity.factX);
- // AlfredActivity.updateConexion(16, 1);
- // }
- // case 16:
- // case 19:
-
- // if ((readExtraVariable(PUESTA_SALSA_PICANTE_EN_MENU) == 1)
- // && (readExtraVariable(JEFE_ENCARCELADO) == 0)
- // && (Math.random() < 0.25f))
- // {
- // // muestra periodico, quita al jefe, etc...
- // setExtraVariables(AlfredActivity.JEFE_ENCARCELADO, 1);
- // AlfredActivity.addObject(13, 0, false);// anula de que se pueda
- // // clickar al jefe
- // AlfredActivity.desactivaAnims(13, 0);
- // AlfredActivity.desactivaAnims(13, 1);
-
- // myConversaciones.mytalkingAnims[12].myPersonajes[0]
- // .setConversation(12, 0, 1);// .currentConversationEach[aux.which]=aux.n;//.setConversation(whichScreen,
- // // aux.which, aux.n);
-
- // String x = "extrascreens/"
- // + extraScreens[(1 * myLanguages.length)
- // + whichLanguageInt]
- // + ".png";
-
- // try
- // {
- // periodico = getBitmapFromAsset(x);
- // } catch (IOException e)
- // {
- // }
-
- // Config cx = periodico.getConfig();
- // periodico = periodico.copy(cx, true);
-
- // pintaPeriodicoDandoVueltas = true;
-
- // }
-
- // break;
- // case 9:
- // // personajes pe[] =
- // // AlfredActivity.myConversaciones.mytalkingAnims[whichScreen].myPersonajes;
- // mypersonajes = pe[0];
-
- // if (myListUsingObjects.contains(10) == false)
- // mypersonajes.setConversation(9, 0, 0);
- // else
- // mypersonajes.setConversation(9, 0, 3);
- // break;
- // case 20:
- // // personajes pe[] =
- // // AlfredActivity.myConversaciones.mytalkingAnims[whichScreen].myPersonajes;
- // mypersonajes = pe[0];
- // if (myListUsingObjects.contains(75) == true)
- // mypersonajes.setConversation(20, 0, 2);
- // else
- // {
- // if (myListUsingObjects.contains(59) == true)// &&
- // // (myListUsingObjects.contains(59)==true))
- // mypersonajes.setConversation(20, 0, 1);
- // else
- // mypersonajes.setConversation(20, 0, 0);
- // }
- // break;
- // case 28:
- // if (AlfredActivity.readExtraVariable(
- // AlfredActivity.CROCODILLO_ENCENDIDO) == 1)
- // {
- // hideObject(0);
- // showObject(1);
- // showObject(2);
- // showObject(3);
- // showObject(4);
- // myoverlay.isFadedOut = false;
- // } else
- // {
- // hideObject(1);
- // hideObject(2);
- // hideObject(3);
- // hideObject(4);
- // myoverlay.isFadedOut = true;
- // }
- // break;
-
- // }
-
- // if (whichScreen == 55)
- // {
- // if (prevWhichScreen == 44)
- // myMovingAlfredThread.alfredFrame = 0;
- // else
- // myMovingAlfredThread.alfredFrame = 17;
- // } else
- // {
- // switch (dirAlfred)
- // {
- // case 0:
- // myMovingAlfredThread.alfredFrame = 0;
- // break;
- // case 1:
- // myMovingAlfredThread.alfredFrame = 9;
- // break;
- // case 2:
- // myMovingAlfredThread.alfredFrame = 18;
- // break;
- // case 3:
- // myMovingAlfredThread.alfredFrame = 23;
- // break;
- // }
-
- // }
-
- // BufferedReader brfx;
- // String word;
- // List<String> wordListfx = new ArrayList<String>();
- // wordListfx.clear();
- // String name = "fx/screen" + String.valueOf(whichScreen) + ".txt";
-
- // try
- // {
- // brfx = new BufferedReader(
- // new InputStreamReader(assetManager.open(name)));
- // while ((word = brfx.readLine()) != null)
- // wordListfx.add(word);
- // } catch (IOException e)
- // {
- // }
-
- // int size = wordListfx.size();
- // filelistFX = new String[size];
-
- // for (int i = 0; i < size; i++)
- // {
- // filelistFX[i] = new String();
- // filelistFX[i] = wordListfx.get(i) + ".mp3";
- // }
-
- // if (filelistFX.length > 0)
- // {
- // int off = (int) (10000.0f + (Math.random() * 5000.0f));
- // timeFXtoPlay = SystemClock.uptimeMillis() + off;
- // }
-
- // boolean loop;
- // if (whichScreen != 48)
- // loop = true;
- // else
- // loop = false;
-
- // playTrack(whichScreen, loop);
-
- // fundidoTime = false;
-
- // timeStartScreen = SystemClock.uptimeMillis();
-
- // screenReady = true;
-}
-
Common::Error PelrockEngine::syncGame(Common::Serializer &s) {
// The Serializer has methods isLoading() and isSaving()
// if you need to specific steps; for example setting
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 62b3cdeeea1..cf0c5c80bb4 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -57,6 +57,7 @@ private:
void setScreen(int s, int dir);
void setScreenJava(int s, int dir);
void loadAnims();
+
// Room data
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
@@ -65,11 +66,14 @@ private:
void loadMainCharacterAnims();
Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
+ void loadCursors();
+
// render loop
void frames();
void checkMouseHover();
void checkMouseClick(int x, int y);
+ void changeCursor(Cursor cursor);
ChronoManager *_chronoManager = nullptr;
byte *standingAnim = new byte[3060 * 102];
@@ -81,6 +85,7 @@ private:
uint16 mouseX = 0;
uint16 mouseY = 0;
byte *_currentBackground = nullptr;
+ byte *_cursorMasks[5] = { nullptr };
// From the original code
int xAlfred = 200;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 9b776ee65ef..3f94a55293e 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -1,6 +1,48 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_TYPES_H
+#define PELROCK_TYPES_H
namespace Pelrock {
+enum Cursor {
+ DEFAULT,
+ HOTSPOT,
+ EXIT,
+ ANIMATION,
+ COMBINATION
+};
+
+// enum HoverState {
+// NONE,
+// INTERACTIVE,
+// HOSTPOT,
+// SPECIAl;
+
+
+// };
+
+const int kCursorWidth = 16;
+const int kCursorHeight = 18;
+const int kCursorSize = 288; // 16 * 18
const int kRoomStructSize = 104;
const int kNumRooms = 56;
@@ -82,3 +124,5 @@ enum GameState {
// };
} // End of namespace Pelrock
+
+#endif
Commit: a20b8fde588e3194f521a2bac17c8347d49d3f74
https://github.com/scummvm/scummvm/commit/a20b8fde588e3194f521a2bac17c8347d49d3f74
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:00+02:00
Commit Message:
PELROCK: Reads popup balloon animation and icons
Changed paths:
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 1312a564db7..3444f3edbd6 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -33,6 +33,9 @@ namespace Pelrock {
0x367EF0
};
+ uint32_t kBalloonFramesOffset = 2176936;
+ uint32_t kBalloonFramesSize = 24950;
+
} // End of namespace Pelrock
#endif
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 41ad51cf1a4..a94a11c264b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -36,8 +36,8 @@
#include "pelrock.h"
#include "pelrock/console.h"
#include "pelrock/detection.h"
-#include "pelrock/pelrock.h"
#include "pelrock/offsets.h"
+#include "pelrock/pelrock.h"
namespace Pelrock {
@@ -52,9 +52,14 @@ PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) :
PelrockEngine::~PelrockEngine() {
delete _screen;
delete _chronoManager;
- for(int i =0; i<5; i++) {
+ for (int i = 0; i < 5; i++) {
delete[] _cursorMasks[i];
}
+ for (int i = 0; i < kNumVerbIcons; i++) {
+ delete[] _verbIcons[i];
+ }
+
+ delete[] _popUpBalloon;
}
uint32 PelrockEngine::getFeatures() const {
@@ -97,8 +102,19 @@ Common::Error PelrockEngine::run() {
mouseX = e.mouse.x;
mouseY = e.mouse.y;
// debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
+ } else if (e.type == Common::EVENT_LBUTTONDOWN) {
+ _mouseDownTime = g_system->getMillis();
+ _isMouseDown = true;
} else if (e.type == Common::EVENT_LBUTTONUP) {
- checkMouseClick(e.mouse.x, e.mouse.y);
+ if (_isMouseDown) {
+ uint32 clickDuration = g_system->getMillis() - _mouseDownTime;
+ if (clickDuration >= kLongClickDuration) {
+ checkLongMouseClick(e.mouse.x, e.mouse.y);
+ } else {
+ checkMouseClick(e.mouse.x, e.mouse.y);
+ }
+ _isMouseDown = false;
+ }
}
}
checkMouseHover();
@@ -114,6 +130,7 @@ Common::Error PelrockEngine::run() {
void PelrockEngine::init() {
loadCursors();
+ loadInteractionIcons();
changeCursor(DEFAULT);
CursorMan.showMouse(true);
@@ -328,22 +345,52 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
void PelrockEngine::loadCursors() {
Common::File alfred7File;
- if(!alfred7File.open("ALFRED.7")) {
+ if (!alfred7File.open("ALFRED.7")) {
error("Couldnt find file ALFRED.7");
}
- for (int i= 0; i < 5; i++) {
+ for (int i = 0; i < 5; i++) {
uint32_t cursorOffset = cursor_offsets[i];
alfred7File.seek(cursorOffset);
_cursorMasks[i] = new byte[kCursorSize];
alfred7File.read(_cursorMasks[i], kCursorSize);
- for(int j = 0; j < kCursorSize; j++) {
- byte *cursorMask = _cursorMasks[i];
- if(cursorMask[j] == 255) cursorMask[j] = 0;
- }
}
alfred7File.close();
}
+void PelrockEngine::loadInteractionIcons() {
+ Common::File alfred7File;
+ if (!alfred7File.open("ALFRED.7")) {
+ error("Couldnt find file ALFRED.7");
+ }
+
+ alfred7File.seek(kBalloonFramesOffset, SEEK_SET);
+
+ uint32_t totalBalloonSize = kBalloonWidth * kBalloonHeight * kBalloonFrames;
+ _popUpBalloon = new byte[totalBalloonSize];
+
+ uint32_t compressedSize = kBalloonFramesSize;
+
+ byte *raw = new byte[compressedSize];
+ alfred7File.read(raw, compressedSize);
+ rleDecompress(raw, compressedSize, 0, compressedSize, &_popUpBalloon);
+
+ delete[] raw;
+
+ alfred7File.close();
+ Common::File alfred4File;
+ if (!alfred4File.open("ALFRED.4")) {
+ error("Couldnt find file ALFRED.4");
+ }
+
+ int iconSize = kVerbIconHeight * kVerbIconWidth;
+ for (int i = 0; i < kNumVerbIcons; i++) {
+ uint32_t iconOffset = i * iconSize;
+ _verbIcons[i] = new byte[iconSize];
+ alfred4File.read(_verbIcons[i], iconSize);
+ }
+ alfred4File.close();
+}
+
Common::List<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffset) {
Common::List<Exit> exits;
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
@@ -449,7 +496,7 @@ void PelrockEngine::frames() {
for (int j = 0; j < w; j++) {
for (int i = 0; i < h; i++) {
int idx = i * w + j;
- if(y + i < 400 && x + j < 640) {
+ if (y + i < 400 && x + j < 640) {
*(bg + idx) = _currentBackground[(y + i) * 640 + (x + j)];
}
}
@@ -458,7 +505,7 @@ void PelrockEngine::frames() {
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
int index = (j * w + i);
- if(x + i < 640 && y + j < 400)
+ if (x + i < 640 && y + j < 400)
*(byte *)g_engine->_screen->getBasePtr(x + i, y + j) = bg[index];
}
}
@@ -482,52 +529,121 @@ void PelrockEngine::frames() {
num++;
for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
- for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
- unsigned int src_pos = (curAlfredFrame * kAlfredFrameHeight * kAlfredFrameWidth) + (y * kAlfredFrameWidth) + x;
- // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
- if (standingAnim[src_pos] != 255)
- _screen->setPixel(x + xAlfred, y + yAlfred, standingAnim[src_pos]);
+ for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
+ unsigned int src_pos = (curAlfredFrame * kAlfredFrameHeight * kAlfredFrameWidth) + (y * kAlfredFrameWidth) + x;
+ // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
+ if (standingAnim[src_pos] != 255)
+ _screen->setPixel(x + xAlfred, y + yAlfred, standingAnim[src_pos]);
+ }
}
}
- }
_screen->markAllDirty();
_screen->update();
}
}
-void PelrockEngine::checkMouseClick(int x, int y) {
+void PelrockEngine::checkLongMouseClick(int x, int y) {
+ HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
+ if (hotspot != nullptr) {
+ showActionBalloon(hotspot->x, hotspot->y);
+ }
+}
+
+HotSpot *PelrockEngine::isHotspotUnder(int x, int y) {
+
+ for (Common::List<HotSpot>::iterator i = _hotspots.begin(); i != _hotspots.end(); i++) {
+ if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
+ mouseY >= i->y && mouseY <= (i->y + i->h)) {
+ debug("Hotspot at (%d,%d) size (%d,%d) extra %d", i->x, i->y, i->w, i->h, i->extra);
+ return &(*i);
+ }
+ }
+ return nullptr;
+}
+
+Exit *PelrockEngine::isExitUnder(int x, int y) {
for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
if (x >= i->x && x <= (i->x + i->w) &&
y >= i->y && y <= (i->y + i->h)) {
- debug("Clicked Exit at (%d,%d) size (%d,%d) to room %d", i->x, i->y, i->w, i->h, i->targetRoom);
- xAlfred = i->targetX;
- yAlfred = i->targetY - kAlfredFrameHeight;
- setScreen(i->targetRoom, i->dir);
- return;
+ return &(*i);
}
}
- for (Common::List<HotSpot>::iterator i = _hotspots.begin(); i != _hotspots.end(); i++) {
- if (x >= i->x && x <= (i->x + i->w) &&
- y >= i->y && y <= (i->y + i->h)) {
- debug("Clicked Hotspot at (%d,%d) size (%d,%d) extra %d", i->x, i->y, i->w, i->h, i->extra);
- // process hotspot action based on i->extra or other properties
- return;
+ return nullptr;
+}
+
+AnimSet *PelrockEngine::isSpriteUnder(int x, int y) {
+ for (Common::List<AnimSet>::iterator i = _currentRoomAnims.begin(); i != _currentRoomAnims.end(); i++) {
+ if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
+ mouseY >= i->y && mouseY <= (i->y + i->h)) {
+ debug("Sprite at (%d,%d) size (%d,%d)", i->x, i->y, i->w, i->h);
+ return &(*i);
+ }
+ }
+ return nullptr;
+}
+
+void PelrockEngine::showActionBalloon(int posx, int posy) {
+ int curFrame = 0;
+
+ for (uint32_t y = 0; y < kBalloonHeight; y++) {
+ for (uint32_t x = 0; x < kBalloonWidth; x++) {
+ unsigned int src_pos = (curFrame * kBalloonHeight * kBalloonWidth) + (y * kBalloonWidth) + x;
+ if (_popUpBalloon[src_pos] != 255)
+ _screen->setPixel(x + posx, y + posy, _popUpBalloon[src_pos]);
+ }
+ }
+
+ for (uint32_t y = 0; y < kVerbIconHeight; y++) {
+ for (uint32_t x = 0; x < kVerbIconWidth; x++) {
+ unsigned int src_pos = y * kVerbIconWidth + x;
+ debug("Color = %d", _verbIcons[LOOK][src_pos]);
+ if (_verbIcons[LOOK][src_pos] != 1)
+ _screen->setPixel(x + posx + 10, y + posy + 10, _verbIcons[LOOK][src_pos]);
}
}
}
+void PelrockEngine::checkMouseClick(int x, int y) {
+
+ Exit *exit = isExitUnder(mouseX, mouseY);
+ if (exit != nullptr) {
+ xAlfred = exit->targetX;
+ yAlfred = exit->targetY - kAlfredFrameHeight;
+ setScreen(exit->targetRoom, exit->dir);
+ }
+
+ HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
+ if (hotspot != nullptr) {
+ debug("Clicked Hotspot at (%d,%d) size (%d,%d) extra %d", hotspot->x, hotspot->y, hotspot->w, hotspot->h, hotspot->extra);
+ changeCursor(HOTSPOT);
+ }
+}
+
void PelrockEngine::changeCursor(Cursor cursor) {
- CursorMan.replaceCursor(_cursorMasks[cursor], kCursorWidth, kCursorHeight, 0, 0, 0);
+ CursorMan.replaceCursor(_cursorMasks[cursor], kCursorWidth, kCursorHeight, 0, 0, 255);
}
void PelrockEngine::checkMouseHover() {
- for (Common::List<HotSpot>::iterator i = _hotspots.begin(); i != _hotspots.end(); i++) {
- if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
- mouseY >= i->y && mouseY <= (i->y + i->h)) {
- // _currentHotspot = &(*i);
- debug("Hotspot at (%d,%d) size (%d,%d) extra %d", i->x, i->y, i->w, i->h, i->extra);
- return;
- }
+ bool isSomethingUnder = false;
+
+ AnimSet *sprite = isSpriteUnder(mouseX, mouseY);
+ if (sprite != nullptr) {
+ isSomethingUnder = true;
+ changeCursor(HOTSPOT);
+ }
+
+ HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
+ if (hotspot != nullptr) {
+ isSomethingUnder = true;
+ changeCursor(HOTSPOT);
+ }
+ Exit *exit = isExitUnder(mouseX, mouseY);
+ if (exit != nullptr) {
+ isSomethingUnder = true;
+ changeCursor(EXIT);
+ }
+ if (!isSomethingUnder) {
+ changeCursor(DEFAULT);
}
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index cf0c5c80bb4..e5461be2b81 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -67,13 +67,18 @@ private:
Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
void loadCursors();
-
+ void loadInteractionIcons();
// render loop
void frames();
void checkMouseHover();
void checkMouseClick(int x, int y);
+ void checkLongMouseClick(int x, int y);
void changeCursor(Cursor cursor);
+ HotSpot* isHotspotUnder(int x, int y);
+ Exit* isExitUnder(int x, int y);
+ AnimSet* isSpriteUnder(int x, int y);
+ void showActionBalloon(int posx, int posy);
ChronoManager *_chronoManager = nullptr;
byte *standingAnim = new byte[3060 * 102];
@@ -87,6 +92,12 @@ private:
byte *_currentBackground = nullptr;
byte *_cursorMasks[5] = { nullptr };
+ uint32 _mouseDownTime;
+ bool _isMouseDown;
+
+ byte *_verbIcons[9] = { nullptr };
+ byte *_popUpBalloon = nullptr;
+
// From the original code
int xAlfred = 200;
int yAlfred = 200;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 3f94a55293e..a5e4e81ce1c 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -27,10 +27,22 @@ enum Cursor {
DEFAULT,
HOTSPOT,
EXIT,
- ANIMATION,
+ ALFRED,
COMBINATION
};
+enum VerbIcons {
+ PICKUP,
+ TALK,
+ WALK,
+ LOOK,
+ PUSH,
+ PULL,
+ OPEN,
+ CLOSE,
+ UNKNOWN
+};
+
// enum HoverState {
// NONE,
// INTERACTIVE,
@@ -40,11 +52,18 @@ enum Cursor {
// };
+static const uint32 kLongClickDuration = 500; // 500ms for long click
const int kCursorWidth = 16;
const int kCursorHeight = 18;
const int kCursorSize = 288; // 16 * 18
const int kRoomStructSize = 104;
const int kNumRooms = 56;
+const int kVerbIconWidth = 60;
+const int kVerbIconHeight = 60;
+const int kNumVerbIcons = 9;
+const int kBalloonWidth = 247;
+const int kBalloonHeight = 112;
+const int kBalloonFrames = 4;
struct Anim {
int x;
Commit: faa428a45e5695c49afdc1cde2b1bab334006c3d
https://github.com/scummvm/scummvm/commit/faa428a45e5695c49afdc1cde2b1bab334006c3d
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:00+02:00
Commit Message:
PELROCK: Generalize bg copy and restoration
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a94a11c264b..6f23066c9d0 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -467,6 +467,27 @@ void PelrockEngine::loadMainCharacterAnims() {
memcpy(standingAnim, pic, 3060 * 102);
}
+byte *PelrockEngine::grabBackgroundSlice(int x, int y, int w, int h) {
+ byte *bg = new byte[w * h];
+ for (int j = 0; j < w; j++) {
+ for (int i = 0; i < h; i++) {
+ int idx = i * w + j;
+ if (y + i < 400 && x + j < 640) {
+ *(bg + idx) = _currentBackground[(y + i) * 640 + (x + j)];
+ }
+ }
+ }
+ return bg;
+}
+void PelrockEngine::putBackgroundSlice(int x, int y, int w, int h, byte *slice) {
+ for (int i = 0; i < w; i++) {
+ for (int j = 0; j < h; j++) {
+ int index = (j * w + i);
+ if (x + i < 640 && y + j < 400)
+ *(byte *)g_engine->_screen->getBasePtr(x + i, y + j) = slice[index];
+ }
+ }
+}
void PelrockEngine::frames() {
if (_chronoManager->_gameTick) {
@@ -492,24 +513,8 @@ void PelrockEngine::frames() {
Common::copy(i->animData[j].animData + (curFrame * i->h * i->w), i->animData[j].animData + (curFrame * i->h * i->w) + (frameSize), frame);
// debug("Current frame %d of %d", curFrame, i->animData[j].nframes);
- byte *bg = new byte[frameSize];
- for (int j = 0; j < w; j++) {
- for (int i = 0; i < h; i++) {
- int idx = i * w + j;
- if (y + i < 400 && x + j < 640) {
- *(bg + idx) = _currentBackground[(y + i) * 640 + (x + j)];
- }
- }
- }
-
- for (int i = 0; i < w; i++) {
- for (int j = 0; j < h; j++) {
- int index = (j * w + i);
- if (x + i < 640 && y + j < 400)
- *(byte *)g_engine->_screen->getBasePtr(x + i, y + j) = bg[index];
- }
- }
-
+ byte *bg = grabBackgroundSlice(x, y, w, h);
+ putBackgroundSlice(x, y, w, h, bg);
for (int y = 0; y < i->h; y++) {
for (int x = 0; x < i->w; x++) {
@@ -536,6 +541,24 @@ void PelrockEngine::frames() {
_screen->setPixel(x + xAlfred, y + yAlfred, standingAnim[src_pos]);
}
}
+
+ if (_displayPopup) {
+
+ // byte *bgDialog = new byte[kBalloonWidth * kBalloonHeight];
+ // for (int j = 0; j < kBalloonWidth; j++) {
+ // for (int i = 0; i < kBalloonHeight; i++) {
+ // int idx = i * kBalloonWidth + j;
+ // if (_popupY + i < 400 && _popupX + j < 640) {
+ // *(bgDialog + idx) = _currentBackground[(_popupY + i) * 640 + (_popupX + j)];
+ // }
+ // }
+ // }
+ showActionBalloon(_popupX, _popupY, _currentPopupFrame);
+ if (_currentPopupFrame < 3) {
+ _currentPopupFrame++;
+ } else
+ _currentPopupFrame = 0;
+ }
}
_screen->markAllDirty();
_screen->update();
@@ -545,7 +568,11 @@ void PelrockEngine::frames() {
void PelrockEngine::checkLongMouseClick(int x, int y) {
HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
if (hotspot != nullptr) {
- showActionBalloon(hotspot->x, hotspot->y);
+ _popupX = hotspot->x;
+ _popupY = hotspot->y;
+ _displayPopup = true;
+ _currentPopupFrame = 0;
+ // _bgPopupBalloon =
}
}
@@ -582,8 +609,7 @@ AnimSet *PelrockEngine::isSpriteUnder(int x, int y) {
return nullptr;
}
-void PelrockEngine::showActionBalloon(int posx, int posy) {
- int curFrame = 0;
+void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
for (uint32_t y = 0; y < kBalloonHeight; y++) {
for (uint32_t x = 0; x < kBalloonWidth; x++) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index e5461be2b81..c383e212594 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -68,6 +68,8 @@ private:
Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
void loadCursors();
void loadInteractionIcons();
+ byte *grabBackgroundSlice(int x, int y, int w, int h);
+ void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
// render loop
void frames();
@@ -78,7 +80,7 @@ private:
HotSpot* isHotspotUnder(int x, int y);
Exit* isExitUnder(int x, int y);
AnimSet* isSpriteUnder(int x, int y);
- void showActionBalloon(int posx, int posy);
+ void showActionBalloon(int posx, int posy, int curFrame);
ChronoManager *_chronoManager = nullptr;
byte *standingAnim = new byte[3060 * 102];
@@ -97,6 +99,15 @@ private:
byte *_verbIcons[9] = { nullptr };
byte *_popUpBalloon = nullptr;
+ byte *_bgPopupBalloon = nullptr;
+
+
+ bool _displayPopup = false;
+ int _popupX = 0;
+ int _popupY = 0;
+ int _currentPopupFrame = 0;
+
+
// From the original code
int xAlfred = 200;
Commit: a09737f03cbb39bf3daa5f6c47a4c6b66fecaf3f
https://github.com/scummvm/scummvm/commit/a09737f03cbb39bf3daa5f6c47a4c6b66fecaf3f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:00+02:00
Commit Message:
PELROCK: Positioning of action balloon
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 6f23066c9d0..aee6269b941 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -553,6 +553,9 @@ void PelrockEngine::frames() {
// }
// }
// }
+ if(_bgPopupBalloon!=nullptr) {
+ putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
+ }
showActionBalloon(_popupX, _popupY, _currentPopupFrame);
if (_currentPopupFrame < 3) {
_currentPopupFrame++;
@@ -568,11 +571,26 @@ void PelrockEngine::frames() {
void PelrockEngine::checkLongMouseClick(int x, int y) {
HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
if (hotspot != nullptr) {
- _popupX = hotspot->x;
- _popupY = hotspot->y;
+ // _popupX = hotspot->x;
+ // _popupY = hotspot->y;
+ if(_bgPopupBalloon != nullptr) {
+ putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
+ delete[] _bgPopupBalloon;
+ }
+ _popupX = x - kBalloonWidth / 2;
+ if(_popupX < 0) _popupX = 0;
+ if(_popupX + kBalloonWidth > 640) {
+ _popupX -= 640 - (_popupX + kBalloonWidth);
+ }
+
+ _popupY = y - kBalloonHeight;
+ if(_popupY < 0) {
+ _popupY = 0;
+ }
_displayPopup = true;
_currentPopupFrame = 0;
- // _bgPopupBalloon =
+
+ _bgPopupBalloon = grabBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight);
}
}
@@ -622,7 +640,6 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
for (uint32_t y = 0; y < kVerbIconHeight; y++) {
for (uint32_t x = 0; x < kVerbIconWidth; x++) {
unsigned int src_pos = y * kVerbIconWidth + x;
- debug("Color = %d", _verbIcons[LOOK][src_pos]);
if (_verbIcons[LOOK][src_pos] != 1)
_screen->setPixel(x + posx + 10, y + posy + 10, _verbIcons[LOOK][src_pos]);
}
@@ -631,6 +648,13 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
void PelrockEngine::checkMouseClick(int x, int y) {
+ _displayPopup = false;
+ if(_bgPopupBalloon != nullptr) {
+ putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
+ delete[] _bgPopupBalloon;
+ _bgPopupBalloon = nullptr;
+ }
+
Exit *exit = isExitUnder(mouseX, mouseY);
if (exit != nullptr) {
xAlfred = exit->targetX;
Commit: 47ddfa060bcbbcee3bd8f02139a093a294c1deb7
https://github.com/scummvm/scummvm/commit/47ddfa060bcbbcee3bd8f02139a093a294c1deb7
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:01+02:00
Commit Message:
PELROCK: Font rendering
Changed paths:
A engines/pelrock/fonts/large_font.cpp
A engines/pelrock/fonts/large_font.h
A engines/pelrock/fonts/small_font.cpp
A engines/pelrock/fonts/small_font.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
new file mode 100644
index 00000000000..07f41a0e63f
--- /dev/null
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -0,0 +1,104 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "pelrock/fonts/large_font.h"
+
+namespace Pelrock {
+
+LargeFont::LargeFont() : _fontData(nullptr) {
+}
+
+LargeFont::~LargeFont() {
+ delete[] _fontData;
+}
+
+bool LargeFont::load(const Common::String &filename) {
+ Common::File file;
+ if (!file.open(Common::Path(filename))) {
+ return false;
+ }
+
+ file.seek(0x7DC8, SEEK_SET);
+ const int dataSize = 96 * 48; // 96 characters à 48 bytes
+ _fontData = new byte[dataSize];
+ file.read(_fontData, dataSize);
+ debug("LargeFont::load: Loading large font data from %s, size %d bytes", filename.c_str(), dataSize);
+ file.close();
+
+ return true;
+}
+
+int LargeFont::getCharWidth(uint32 chr) const {
+ return CHAR_WIDTH;
+}
+
+void LargeFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
+
+ // """Extract a single character from the large font data (12x24 pixels)
+ // Each character is 48 bytes (24 rows à 2 bytes per row)"""
+ // offset = char_index * 0x30 # 48 bytes per character
+ // char_data = data[offset:offset + 0x30]
+
+ // # Create 12x24 pixel array
+ // pixels = np.zeros((24, 12), dtype=np.uint8)
+
+ // # Process each row (2 bytes per row)
+ // for row in range(24):
+ // byte1 = char_data[row * 2]
+ // byte2 = char_data[row * 2 + 1]
+
+ // # Process 12 bits (12 pixels) from the two bytes
+ // for bit in range(8):
+ // pixels[row, bit] = 255 if (byte1 & (0x80 >> bit)) else 0
+ // for bit in range(4):
+ // pixels[row, bit + 8] = 255 if (byte2 & (0x80 >> bit)) else 0
+
+ // return pixels
+
+ if (!_fontData || chr > 255) {
+ return;
+ }
+ chr -= 32; // Adjust for font starting at ASCII 32
+ int charOffset = chr * 0x30;
+ debug("LargeFont::drawChar: Drawing char %d at offset %d", chr, charOffset);
+ for (int i = 0; i < 24; i++) {
+ byte rowByte1 = _fontData[charOffset + i * 2];
+ byte rowByte2 = _fontData[charOffset + i * 2 + 1];
+ for (int bit = 0; bit < 8; bit++) {
+ bool pixelOn = (rowByte1 & (0x80 >> bit)) != 0;
+ if (pixelOn) {
+ if ((x + bit) < dst->w && (y + i) < dst->h) {
+ *((byte *)dst->getBasePtr(x + bit, y + i)) = color;
+ }
+ }
+ }
+ for (int bit = 0; bit < 4; bit++) {
+ bool pixelOn = (rowByte2 & (0x80 >> bit)) != 0;
+ if (pixelOn) {
+ if ((x + bit + 8) < dst->w && (y + i) < dst->h) {
+ *((byte *)dst->getBasePtr(x + bit + 8, y + i)) = color;
+ }
+ }
+ }
+ }
+}
+
+} // namespace Pelrock
diff --git a/engines/pelrock/fonts/large_font.h b/engines/pelrock/fonts/large_font.h
new file mode 100644
index 00000000000..bd87b9012d2
--- /dev/null
+++ b/engines/pelrock/fonts/large_font.h
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_LARGEFONT_H
+#define PELROCK_LARGEFONT_H
+
+#include "common/file.h"
+#include "common/str.h"
+#include "graphics/font.h"
+#include "graphics/surface.h"
+
+namespace Pelrock {
+class LargeFont : public Graphics::Font {
+public:
+ LargeFont();
+ ~LargeFont();
+
+ bool load(const Common::String &filename);
+
+ // Required Font interface methods
+ int getFontHeight() const override { return CHAR_HEIGHT; }
+ int getMaxCharWidth() const override { return CHAR_WIDTH; }
+ int getCharWidth(uint32 chr) const override;
+ void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
+
+private:
+ static const int CHAR_WIDTH = 12;
+ static const int CHAR_HEIGHT = 24;
+ byte *_fontData;
+};
+} // End of namespace Pelrock
+#endif
diff --git a/engines/pelrock/fonts/small_font.cpp b/engines/pelrock/fonts/small_font.cpp
new file mode 100644
index 00000000000..9ab959e3bcb
--- /dev/null
+++ b/engines/pelrock/fonts/small_font.cpp
@@ -0,0 +1,74 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "pelrock/fonts/small_font.h"
+
+namespace Pelrock {
+
+SmallFont::SmallFont() : _fontData(nullptr) {
+}
+
+SmallFont::~SmallFont() {
+ delete[] _fontData;
+}
+
+bool SmallFont::load(const Common::String &filename) {
+ Common::File file;
+ if (!file.open(Common::Path(filename))) {
+ return false;
+ }
+
+ file.seek(0x8F32, SEEK_SET);
+
+ // const int dataSize = 256 * 8 * 8; // 256 characters, 8x8 pixels
+ const int dataSize = 2048; // 256 characters, 8x8 pixels
+ _fontData = new byte[dataSize];
+ file.read(_fontData, dataSize);
+ file.close();
+
+ return true;
+}
+
+int SmallFont::getCharWidth(uint32 chr) const {
+ return CHAR_WIDTH;
+}
+
+void SmallFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
+ if (!_fontData || chr > 255) {
+ return;
+ }
+
+ int charOffset = chr * 8;
+
+ for (int i = 0; i < 8; i++) {
+ byte rowByte = _fontData[charOffset + i];
+ for (int bit = 0; bit < 8; bit++) {
+ bool pixelOn = (rowByte & (0x80 >> bit)) != 0;
+ if (pixelOn) {
+ if ((x + bit) < dst->w && (y + i) < dst->h) {
+ *((byte *)dst->getBasePtr(x + bit, y + i)) = color;
+ }
+ }
+ }
+ }
+}
+
+} // namespace Pelrock
diff --git a/engines/pelrock/fonts/small_font.h b/engines/pelrock/fonts/small_font.h
new file mode 100644
index 00000000000..f1fb165503a
--- /dev/null
+++ b/engines/pelrock/fonts/small_font.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_SMALLFONT_H
+#define PELROCK_SMALLFONT_H
+
+#include "common/file.h"
+#include "common/str.h"
+#include "graphics/font.h"
+#include "graphics/surface.h"
+
+namespace Pelrock {
+class SmallFont : public Graphics::Font {
+public:
+ SmallFont();
+ ~SmallFont();
+
+ bool load(const Common::String &filename);
+
+ // Required Font interface methods
+ int getFontHeight() const override { return CHAR_HEIGHT; }
+ int getMaxCharWidth() const override { return CHAR_WIDTH; }
+ int getCharWidth(uint32 chr) const override;
+ void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
+
+private:
+ static const int CHAR_WIDTH = 8;
+ static const int CHAR_HEIGHT = 8;
+ byte *_fontData;
+};
+
+} // End of namespace Pelrock
+#endif
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index bc1a263acdd..0c1e387371a 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -4,7 +4,9 @@ MODULE_OBJS = \
pelrock.o \
chrono.o \
console.o \
- metaengine.o
+ metaengine.o \
+ fonts/small_font.o \
+ fonts/large_font.o \
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index aee6269b941..595fc4855d8 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -36,6 +36,7 @@
#include "pelrock.h"
#include "pelrock/console.h"
#include "pelrock/detection.h"
+#include "pelrock/fonts/small_font.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
@@ -60,6 +61,9 @@ PelrockEngine::~PelrockEngine() {
}
delete[] _popUpBalloon;
+ if (_bgPopupBalloon)
+ delete[] _bgPopupBalloon;
+ delete _smallFont;
}
uint32 PelrockEngine::getFeatures() const {
@@ -131,6 +135,10 @@ Common::Error PelrockEngine::run() {
void PelrockEngine::init() {
loadCursors();
loadInteractionIcons();
+ _smallFont = new SmallFont();
+ _smallFont->load("ALFRED.4");
+ _largeFont = new LargeFont();
+ _largeFont->load("ALFRED.7");
changeCursor(DEFAULT);
CursorMan.showMouse(true);
@@ -138,6 +146,9 @@ void PelrockEngine::init() {
gameInitialized = true;
loadAnims();
setScreen(0, 2);
+ _smallFont->drawString(g_engine->_screen, Common::String("Welcome to Pelrock!"), 0, 0, 400, 102);
+ _largeFont->drawString(g_engine->_screen, Common::String("Click to start"), 200, 180, 400, 102);
+ _screen->update();
}
}
@@ -434,8 +445,8 @@ void PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
roomFile->seek(obj_offset, SEEK_SET);
byte obj_bytes[9];
roomFile->read(obj_bytes, 9);
- byte type_byte = obj_bytes[0];
HotSpot spot;
+ spot.type = obj_bytes[0];
spot.x = obj_bytes[1] | (obj_bytes[2] << 8);
spot.y = obj_bytes[3] | (obj_bytes[4] << 8);
spot.w = obj_bytes[5];
@@ -553,7 +564,7 @@ void PelrockEngine::frames() {
// }
// }
// }
- if(_bgPopupBalloon!=nullptr) {
+ if (_bgPopupBalloon != nullptr) {
putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
}
showActionBalloon(_popupX, _popupY, _currentPopupFrame);
@@ -573,18 +584,19 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
if (hotspot != nullptr) {
// _popupX = hotspot->x;
// _popupY = hotspot->y;
- if(_bgPopupBalloon != nullptr) {
+ if (_bgPopupBalloon != nullptr) {
putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
delete[] _bgPopupBalloon;
}
_popupX = x - kBalloonWidth / 2;
- if(_popupX < 0) _popupX = 0;
- if(_popupX + kBalloonWidth > 640) {
+ if (_popupX < 0)
+ _popupX = 0;
+ if (_popupX + kBalloonWidth > 640) {
_popupX -= 640 - (_popupX + kBalloonWidth);
}
_popupY = y - kBalloonHeight;
- if(_popupY < 0) {
+ if (_popupY < 0) {
_popupY = 0;
}
_displayPopup = true;
@@ -599,7 +611,20 @@ HotSpot *PelrockEngine::isHotspotUnder(int x, int y) {
for (Common::List<HotSpot>::iterator i = _hotspots.begin(); i != _hotspots.end(); i++) {
if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
mouseY >= i->y && mouseY <= (i->y + i->h)) {
- debug("Hotspot at (%d,%d) size (%d,%d) extra %d", i->x, i->y, i->w, i->h, i->extra);
+ int lookable = i->extra & 0x0B;
+ int openable = i->extra & 0x0F;
+ debug("Hotspot at (%d,%d) size (%d,%d) extra %d, type = %d, lookable = %d, openable=%d", i->x, i->y, i->w, i->h, i->extra, i->type, lookable, openable);
+ /*
+ LOOK = 0x0B # Look at
+ TAKE = 0x0C # Take/Pick up
+ USE = 0x0D # Use
+ TALK = 0x0E # Talk to
+ OPEN = 0x0F # Open
+ CLOSE = 0x10 # Close
+ PUSH = 0x11 # Push/Move
+ PULL = 0x12 # Pull
+ GIVE = 0x13 # Give
+ */
return &(*i);
}
}
@@ -649,7 +674,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
void PelrockEngine::checkMouseClick(int x, int y) {
_displayPopup = false;
- if(_bgPopupBalloon != nullptr) {
+ if (_bgPopupBalloon != nullptr) {
putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
delete[] _bgPopupBalloon;
_bgPopupBalloon = nullptr;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index c383e212594..427b4218254 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -38,6 +38,8 @@
#include "pelrock/chrono.h"
#include "pelrock/detection.h"
+#include "pelrock/fonts/large_font.h"
+#include "pelrock/fonts/small_font.h"
#include "pelrock/types.h"
namespace Pelrock {
@@ -77,9 +79,9 @@ private:
void checkMouseClick(int x, int y);
void checkLongMouseClick(int x, int y);
void changeCursor(Cursor cursor);
- HotSpot* isHotspotUnder(int x, int y);
- Exit* isExitUnder(int x, int y);
- AnimSet* isSpriteUnder(int x, int y);
+ HotSpot *isHotspotUnder(int x, int y);
+ Exit *isExitUnder(int x, int y);
+ AnimSet *isSpriteUnder(int x, int y);
void showActionBalloon(int posx, int posy, int curFrame);
ChronoManager *_chronoManager = nullptr;
@@ -92,22 +94,22 @@ private:
uint16 mouseX = 0;
uint16 mouseY = 0;
byte *_currentBackground = nullptr;
- byte *_cursorMasks[5] = { nullptr };
+ byte *_cursorMasks[5] = {nullptr};
uint32 _mouseDownTime;
- bool _isMouseDown;
+ bool _isMouseDown;
- byte *_verbIcons[9] = { nullptr };
+ byte *_verbIcons[9] = {nullptr};
byte *_popUpBalloon = nullptr;
byte *_bgPopupBalloon = nullptr;
-
bool _displayPopup = false;
int _popupX = 0;
int _popupY = 0;
int _currentPopupFrame = 0;
-
+ SmallFont *_smallFont = nullptr;
+ LargeFont *_largeFont = nullptr;
// From the original code
int xAlfred = 200;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index a5e4e81ce1c..4a97adf12c4 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -99,6 +99,7 @@ struct AnimSet {
};
struct HotSpot {
+ byte type;
int x;
int y;
int id;
Commit: 8febd828eb4093a3d5df37caad0151ca54fca021
https://github.com/scummvm/scummvm/commit/8febd828eb4093a3d5df37caad0151ca54fca021
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:01+02:00
Commit Message:
PELROCK: identifies valid actions associated with hotspots
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 595fc4855d8..985e3fd1728 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -146,9 +146,6 @@ void PelrockEngine::init() {
gameInitialized = true;
loadAnims();
setScreen(0, 2);
- _smallFont->drawString(g_engine->_screen, Common::String("Welcome to Pelrock!"), 0, 0, 400, 102);
- _largeFont->drawString(g_engine->_screen, Common::String("Click to start"), 200, 180, 400, 102);
- _screen->update();
}
}
@@ -243,7 +240,7 @@ void PelrockEngine::getBackground(Common::File *roomFile, int roomOffset, byte *
}
}
-Common::List<AnimSet> PelrockEngine::getRoomAnimations(Common::File *roomFile, int roomOffset) {
+Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
uint32_t pair_offset = roomOffset + (8 * 8);
roomFile->seek(pair_offset, SEEK_SET);
uint32_t offset = roomFile->readUint32LE();
@@ -265,9 +262,8 @@ Common::List<AnimSet> PelrockEngine::getRoomAnimations(Common::File *roomFile, i
uint32_t picOffset = 0;
for (int i = 0; i < 7; i++) {
uint32_t animOffset = metadata_start + (i * 44);
- roomFile->seek(animOffset, SEEK_SET);
-
AnimSet animSet;
+ roomFile->seek(animOffset, SEEK_SET);
animSet.x = roomFile->readSint16LE();
animSet.y = roomFile->readSint16LE();
animSet.w = roomFile->readByte();
@@ -354,6 +350,7 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
return walkboxes;
}
+
void PelrockEngine::loadCursors() {
Common::File alfred7File;
if (!alfred7File.open("ALFRED.7")) {
@@ -431,8 +428,8 @@ Common::List<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffs
void PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+
roomFile->seek(pair10_offset_pos, SEEK_SET);
- // roomFile->skip(4);
uint32_t pair10_data_offset = roomFile->readUint32LE();
uint32_t pair10_size = roomFile->readUint32LE();
uint32_t count_offset = pair10_data_offset + 0x47a;
@@ -456,6 +453,9 @@ void PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
hotspots.push_back(spot);
}
_hotspots = hotspots;
+ // uint32_t hover_areas_start = pair10_data_offset + 0x1BE;
+ // roomFile->seek(hover_areas_start, SEEK_SET);
+
}
void PelrockEngine::loadMainCharacterAnims() {
@@ -499,6 +499,42 @@ void PelrockEngine::putBackgroundSlice(int x, int y, int w, int h, byte *slice)
}
}
}
+Common::List<VerbIcons> PelrockEngine::populateActionsMenu(HotSpot hotspot) {
+ Common::List<VerbIcons> verbs;
+ verbs.push_back(LOOK);
+
+ if(hotspot.type & 1) {
+ debug("Hotspot allows OPEN action");
+ verbs.push_back(OPEN);
+ }
+ if(hotspot.type & 2) {
+ debug("Hotspot allows CLOSE action");
+ verbs.push_back(CLOSE);
+ }
+ if(hotspot.type & 4) {
+ debug("Hotspot allows UNKNOWN action");
+ verbs.push_back(UNKNOWN);
+ }
+ if(hotspot.type & 8) {
+ debug("Hotspot allows PICKUP action");
+ verbs.push_back(PICKUP);
+ }
+ if(hotspot.type & 16) {
+ debug("Hotspot allows TALK action");
+ verbs.push_back(TALK);
+ }
+ if(hotspot.type & 32) {
+ debug("Hotspot allows WALK action");
+ verbs.push_back(PUSH);
+ }
+ if(hotspot.type & 128) {
+ debug("Hotspot allows PULL action");
+ verbs.push_back(PULL);
+ }
+ return verbs;
+}
+
+
void PelrockEngine::frames() {
if (_chronoManager->_gameTick) {
@@ -601,7 +637,8 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
}
_displayPopup = true;
_currentPopupFrame = 0;
-
+ _currentHotspot = hotspot;
+ populateActionsMenu(*hotspot);
_bgPopupBalloon = grabBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight);
}
}
@@ -613,18 +650,7 @@ HotSpot *PelrockEngine::isHotspotUnder(int x, int y) {
mouseY >= i->y && mouseY <= (i->y + i->h)) {
int lookable = i->extra & 0x0B;
int openable = i->extra & 0x0F;
- debug("Hotspot at (%d,%d) size (%d,%d) extra %d, type = %d, lookable = %d, openable=%d", i->x, i->y, i->w, i->h, i->extra, i->type, lookable, openable);
- /*
- LOOK = 0x0B # Look at
- TAKE = 0x0C # Take/Pick up
- USE = 0x0D # Use
- TALK = 0x0E # Talk to
- OPEN = 0x0F # Open
- CLOSE = 0x10 # Close
- PUSH = 0x11 # Push/Move
- PULL = 0x12 # Pull
- GIVE = 0x13 # Give
- */
+ // debug("Hotspot at (%d,%d) size (%d,%d) extra %d, type = %d, lookable = %d, openable=%d", i->x, i->y, i->w, i->h, i->extra, i->type, lookable, openable);
return &(*i);
}
}
@@ -645,7 +671,7 @@ AnimSet *PelrockEngine::isSpriteUnder(int x, int y) {
for (Common::List<AnimSet>::iterator i = _currentRoomAnims.begin(); i != _currentRoomAnims.end(); i++) {
if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
mouseY >= i->y && mouseY <= (i->y + i->h)) {
- debug("Sprite at (%d,%d) size (%d,%d)", i->x, i->y, i->w, i->h);
+ debug("Sprite at (%d,%d) size (%d,%d), type = %d, extra = %d, enabled=%d", i->x, i->y, i->w, i->h, i->type, i->extra, i->enabled);
return &(*i);
}
}
@@ -662,6 +688,10 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
}
+ // for (Common::List<VerbIcons>::iterator i = verbList.begin(); i != verbList.end(); i++) {
+ // debug("Verb icon to show: %d", *i);
+ // }
+
for (uint32_t y = 0; y < kVerbIconHeight; y++) {
for (uint32_t x = 0; x < kVerbIconWidth; x++) {
unsigned int src_pos = y * kVerbIconWidth + x;
@@ -752,7 +782,7 @@ void PelrockEngine::setScreen(int number, int dir) {
_screen->setPixel(i, j, background[j * 640 + i]);
}
}
- _currentRoomAnims = getRoomAnimations(&roomFile, roomOffset);
+ _currentRoomAnims = loadRoomAnimations(&roomFile, roomOffset);
loadHotspots(&roomFile, roomOffset);
int hotsPotCount = 0;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 427b4218254..3aff9bcd841 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -63,15 +63,17 @@ private:
// Room data
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
- Common::List<AnimSet> getRoomAnimations(Common::File *roomFile, int roomOffset);
- void loadHotspots(Common::File *roomFile, int roomOffset);
+ Common::List<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
void loadMainCharacterAnims();
+ void loadHotspots(Common::File *roomFile, int roomOffset);
Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
+ void loadRoomMetadata(Common::File *roomFile, int roomOffset);
void loadCursors();
void loadInteractionIcons();
byte *grabBackgroundSlice(int x, int y, int w, int h);
void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
+ Common::List<VerbIcons> populateActionsMenu(HotSpot hotspot);
// render loop
void frames();
@@ -87,6 +89,7 @@ private:
ChronoManager *_chronoManager = nullptr;
byte *standingAnim = new byte[3060 * 102];
Common::List<HotSpot> _hotspots;
+ Common::List<HoverArea> _hoverAreas;
Common::List<AnimSet> _currentRoomAnims;
Common::List<Exit> _currentRoomExits;
int *_currentAnimFrames = nullptr;
@@ -107,6 +110,7 @@ private:
int _popupX = 0;
int _popupY = 0;
int _currentPopupFrame = 0;
+ HotSpot *_currentHotspot = nullptr;
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 4a97adf12c4..f30cb37c2f0 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -89,6 +89,7 @@ struct Exit {
};
struct AnimSet {
+ byte type;
int x;
int y;
int w;
@@ -96,6 +97,15 @@ struct AnimSet {
int speed;
int numAnims;
Anim *animData;
+ byte extra;
+ bool enabled;
+};
+
+struct HoverArea {
+ int x;
+ int y;
+ int w;
+ int h;
};
struct HotSpot {
Commit: f131a5bad9d1d85fae9c8adcaa5b42d5413c07ab
https://github.com/scummvm/scummvm/commit/f131a5bad9d1d85fae9c8adcaa5b42d5413c07ab
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:01+02:00
Commit Message:
PELROCK: Calculates clickable areas
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 985e3fd1728..bed6c3a3d89 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -146,6 +146,7 @@ void PelrockEngine::init() {
gameInitialized = true;
loadAnims();
setScreen(0, 2);
+ // setScreen(24, 2);
}
}
@@ -258,6 +259,8 @@ Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
}
Common::List<AnimSet> anims = Common::List<AnimSet>();
uint32_t spriteEnd = offset + size;
+
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
uint32_t metadata_start = spriteEnd + 108;
uint32_t picOffset = 0;
for (int i = 0; i < 7; i++) {
@@ -268,7 +271,8 @@ Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
animSet.y = roomFile->readSint16LE();
animSet.w = roomFile->readByte();
animSet.h = roomFile->readByte();
- roomFile->skip(2); // reserved
+ animSet.extra = roomFile->readByte();
+ roomFile->skip(1); // reserved
animSet.numAnims = roomFile->readByte();
debug("AnimSet %d: x=%d y=%d w=%d h=%d numAnims=%d", i, animSet.x, animSet.y, animSet.w, animSet.h, animSet.numAnims);
animSet.animData = new Anim[animSet.numAnims];
@@ -338,7 +342,7 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
int16 w = roomFile->readSint16LE();
int16 h = roomFile->readSint16LE();
byte flags = roomFile->readByte();
- // debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+ debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
WalkBox box;
box.x = x1;
box.y = y1;
@@ -449,7 +453,7 @@ void PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
spot.w = obj_bytes[5];
spot.h = obj_bytes[6];
spot.extra = obj_bytes[7] | (obj_bytes[8] << 8);
- // debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, type_byte, spot.x, spot.y, spot.w, spot.h, spot.extra);
+ debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
hotspots.push_back(spot);
}
_hotspots = hotspots;
@@ -610,6 +614,16 @@ void PelrockEngine::frames() {
_currentPopupFrame = 0;
}
}
+
+ int walkboxCount = 0;
+ for (Common::List<WalkBox>::iterator i = _currentRoomWalkboxes.begin(); i != _currentRoomWalkboxes.end(); i++) {
+ // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
+ _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
+ _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
+ _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ walkboxCount++;
+ }
_screen->markAllDirty();
_screen->update();
}
@@ -671,7 +685,7 @@ AnimSet *PelrockEngine::isSpriteUnder(int x, int y) {
for (Common::List<AnimSet>::iterator i = _currentRoomAnims.begin(); i != _currentRoomAnims.end(); i++) {
if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
mouseY >= i->y && mouseY <= (i->y + i->h)) {
- debug("Sprite at (%d,%d) size (%d,%d), type = %d, extra = %d, enabled=%d", i->x, i->y, i->w, i->h, i->type, i->extra, i->enabled);
+ // debug("Sprite at (%d,%d) size (%d,%d), type = %d, extra = %d, enabled=%d", i->x, i->y, i->w, i->h, i->type, i->extra, i->enabled);
return &(*i);
}
}
@@ -731,25 +745,119 @@ void PelrockEngine::changeCursor(Cursor cursor) {
void PelrockEngine::checkMouseHover() {
bool isSomethingUnder = false;
+
+ // Calculate walk target first (before checking anything else)
+ Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
+
+ // Check if walk target hits any exit
+ bool exitDetected = false;
+ Exit *exit = isExitAtPoint(walkTarget.x, walkTarget.y);
+ if (exit != nullptr) {
+ exitDetected = true;
+ }
+
AnimSet *sprite = isSpriteUnder(mouseX, mouseY);
if (sprite != nullptr) {
isSomethingUnder = true;
- changeCursor(HOTSPOT);
}
HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
if (hotspot != nullptr) {
isSomethingUnder = true;
+ }
+ // Exit *exit = isExitUnder(mouseX, mouseY);
+ // if (exit != nullptr) {
+ // isSomethingUnder = true;
+ // changeCursor(EXIT);
+ // }
+ if (isSomethingUnder && exitDetected) {
+ changeCursor(COMBINATION);
+ }
+ else if (isSomethingUnder) {
changeCursor(HOTSPOT);
}
- Exit *exit = isExitUnder(mouseX, mouseY);
- if (exit != nullptr) {
- isSomethingUnder = true;
+ else if (exitDetected) {
changeCursor(EXIT);
- }
- if (!isSomethingUnder) {
+ } else {
changeCursor(DEFAULT);
}
+
+}
+
+Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
+ // Starting point for pathfinding
+ int sourceX = mouseX;
+ int sourceY = mouseY;
+
+ // TODO: If hovering over a sprite/hotspot, adjust source point to sprite center
+ // For now, just use mouse position
+
+ // Find nearest walkable point in walkboxes
+ uint32 minDistance = 0xFFFFFFFF;
+ Common::Point bestTarget(sourceX, sourceY);
+
+ for (Common::List<WalkBox>::iterator it = _currentRoomWalkboxes.begin();
+ it != _currentRoomWalkboxes.end(); ++it) {
+
+ // Calculate distance from source point to this walkbox (Manhattan distance)
+ int dx = 0;
+ int dy = 0;
+
+ // Calculate horizontal distance
+ if (sourceX < it->x) {
+ dx = it->x - sourceX;
+ } else if (sourceX > it->x + it->w) {
+ dx = sourceX - (it->x + it->w);
+ }
+ // else: sourceX is inside walkbox horizontally, dx = 0
+
+ // Calculate vertical distance
+ if (sourceY < it->y) {
+ dy = it->y - sourceY;
+ } else if (sourceY > it->y + it->h) {
+ dy = sourceY - (it->y + it->h);
+ }
+ // else: sourceY is inside walkbox vertically, dy = 0
+
+ uint32 distance = dx + dy;
+
+ if (distance < minDistance) {
+ minDistance = distance;
+
+ // Calculate target point (nearest point on walkbox to source)
+ int targetX = sourceX;
+ int targetY = sourceY;
+
+ if (sourceX < it->x) {
+ targetX = it->x;
+ } else if (sourceX > it->x + it->w) {
+ targetX = it->x + it->w;
+ }
+
+ if (sourceY < it->y) {
+ targetY = it->y;
+ } else if (sourceY > it->y + it->h) {
+ targetY = it->y + it->h;
+ }
+
+ bestTarget.x = targetX;
+ bestTarget.y = targetY;
+ }
+ }
+
+ return bestTarget;
+}
+
+Exit *PelrockEngine::isExitAtPoint(int x, int y) {
+ for (Common::List<Exit>::iterator i = _currentRoomExits.begin();
+ i != _currentRoomExits.end(); ++i) {
+ // Check if point is inside exit trigger rectangle
+ if (x >= i->x && x <= (i->x + i->w) &&
+ y >= i->y && y <= (i->y + i->h)) {
+ return &(*i);
+ }
+ }
+ return nullptr;
}
void PelrockEngine::setScreen(int number, int dir) {
@@ -795,19 +903,11 @@ void PelrockEngine::setScreen(int number, int dir) {
hotsPotCount++;
}
- Common::List<WalkBox> walkboxes = loadWalkboxes(&roomFile, roomOffset);
- int walkboxCount = 0;
- for (Common::List<WalkBox>::iterator i = walkboxes.begin(); i != walkboxes.end(); i++) {
- // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
- _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
- _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
- _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- walkboxCount++;
- }
+ _currentRoomWalkboxes = loadWalkboxes(&roomFile, roomOffset);
_currentRoomExits = loadExits(&roomFile, roomOffset);
+ int walkboxCount = 0;
for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
// _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
_screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 3aff9bcd841..b37df6e9ce7 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -74,7 +74,8 @@ private:
byte *grabBackgroundSlice(int x, int y, int w, int h);
void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
Common::List<VerbIcons> populateActionsMenu(HotSpot hotspot);
-
+ Common::Point calculateWalkTarget(int mouseX, int mouseY);
+ Exit *isExitAtPoint(int x, int y);
// render loop
void frames();
void checkMouseHover();
@@ -92,6 +93,7 @@ private:
Common::List<HoverArea> _hoverAreas;
Common::List<AnimSet> _currentRoomAnims;
Common::List<Exit> _currentRoomExits;
+ Common::List<WalkBox> _currentRoomWalkboxes;
int *_currentAnimFrames = nullptr;
int curAlfredFrame = 9;
uint16 mouseX = 0;
Commit: f0a541069d5e21b93933a5cdd9163e77b1d8e1ce
https://github.com/scummvm/scummvm/commit/f0a541069d5e21b93933a5cdd9163e77b1d8e1ce
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:01+02:00
Commit Message:
PELROCK: Selects sprites that are candidates for hotspots
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index bed6c3a3d89..de827a6a239 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -145,8 +145,8 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(0, 2);
- // setScreen(24, 2);
+ // setScreen(0, 2);
+ setScreen(2, 2);
}
}
@@ -265,42 +265,54 @@ Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
uint32_t picOffset = 0;
for (int i = 0; i < 7; i++) {
uint32_t animOffset = metadata_start + (i * 44);
- AnimSet animSet;
+ byte *animData = new byte[44];
roomFile->seek(animOffset, SEEK_SET);
- animSet.x = roomFile->readSint16LE();
- animSet.y = roomFile->readSint16LE();
- animSet.w = roomFile->readByte();
- animSet.h = roomFile->readByte();
- animSet.extra = roomFile->readByte();
- roomFile->skip(1); // reserved
- animSet.numAnims = roomFile->readByte();
- debug("AnimSet %d: x=%d y=%d w=%d h=%d numAnims=%d", i, animSet.x, animSet.y, animSet.w, animSet.h, animSet.numAnims);
- animSet.animData = new Anim[animSet.numAnims];
- roomFile->skip(1);
+ roomFile->read(animData, 44);
+ AnimSet animSet;
+ animSet.x = animData[0] | (animData[1] << 8);
+ animSet.y = animData[2] | (animData[3] << 8);
+ animSet.w = animData[4];
+ animSet.h = animData[5];
+ animSet.extra = animData[6];
+ // roomFile->skip(1); // reserved
+ animSet.numAnims = animData[8];
+ animSet.spriteType = animData[33];
+ animSet.actionFlags = animData[34];
+ animSet.isDisabled = animData[38];
+
+ animSet.animData = new Anim[animSet.numAnims];
+ debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
+ // roomFile->skip(1);
+ int subAnimOffset = 10;
for (int j = 0; j < animSet.numAnims; j++) {
- byte frames = roomFile->readByte();
+
Anim anim;
anim.x = animSet.x;
anim.y = animSet.y;
anim.w = animSet.w;
anim.h = animSet.h;
anim.curFrame = 0;
- anim.nframes = frames;
+
+ anim.nframes = animData[subAnimOffset + j];
+ anim.loopCount = animData[subAnimOffset + 4 + j];
+ anim.speed = animData[subAnimOffset + 8 + j];
anim.animData = new byte[anim.nframes];
if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
uint32_t needed = anim.w * anim.h * anim.nframes;
anim.animData = new byte[needed];
Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
animSet.animData[j] = anim;
- debug("Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes);
+ debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
picOffset += needed;
} else {
continue;
debug("Anim %d-%d: invalid dimensions, skipping", i, j);
}
animSet.animData[j] = anim;
+
}
+
anims.push_back(animSet);
// if (w > 0 && h > 0 && frames > 0) {
@@ -354,6 +366,62 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
return walkboxes;
}
+void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
+
+ Common::List<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
+
+ Common::List<HotSpot> hotspots;
+
+
+
+ for (Common::List<AnimSet>::iterator i = anims.begin(); i != anims.end(); i++) {
+ if(!i->isDisabled) {
+ hotspots.push_back(
+ HotSpot{
+ i->actionFlags,
+ i->x,
+ i->y,
+ i->w,
+ i->h,
+ i->extra,
+ }
+ );
+ }
+ }
+
+ Common::List<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
+ Common::List<Exit> exits = loadExits(roomFile, roomOffset);
+ Common::List<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
+
+
+
+ int hotsPotCount = 0;
+ for (Common::List<HotSpot>::iterator i = staticHotspots.begin(); i != staticHotspots.end(); i++) {
+ // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
+ _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 100 + hotsPotCount);
+ _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 100 + hotsPotCount);
+ _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 100 + hotsPotCount);
+ _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 100 + hotsPotCount);
+ hotsPotCount++;
+ hotspots.push_back(*i);
+ }
+
+ int walkboxCount = 0;
+ for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
+ // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
+ _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
+ _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
+ _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ walkboxCount++;
+ }
+
+
+ _currentRoomAnims = anims;
+ _currentRoomHotspots = hotspots;
+ _currentRoomExits = exits;
+ _currentRoomWalkboxes = walkboxes;
+}
void PelrockEngine::loadCursors() {
Common::File alfred7File;
@@ -424,13 +492,12 @@ Common::List<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffs
exit.targetX = roomFile->readUint16LE();
exit.targetY = roomFile->readUint16LE();
exit.dir = roomFile->readByte();
- debug("Exit %d: x=%d y=%d w=%d h=%d targetRoom=%d targetX=%d targetY=%d", i, exit.x, exit.y, exit.w, exit.h, exit.targetRoom, exit.targetX, exit.targetY);
exits.push_back(exit);
}
return exits;
}
-void PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
+Common::List<HotSpot>PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
roomFile->seek(pair10_offset_pos, SEEK_SET);
@@ -456,7 +523,7 @@ void PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
hotspots.push_back(spot);
}
- _hotspots = hotspots;
+ return hotspots;
// uint32_t hover_areas_start = pair10_data_offset + 0x1BE;
// roomFile->seek(hover_areas_start, SEEK_SET);
@@ -659,7 +726,7 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
HotSpot *PelrockEngine::isHotspotUnder(int x, int y) {
- for (Common::List<HotSpot>::iterator i = _hotspots.begin(); i != _hotspots.end(); i++) {
+ for (Common::List<HotSpot>::iterator i = _currentRoomHotspots.begin(); i != _currentRoomHotspots.end(); i++) {
if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
mouseY >= i->y && mouseY <= (i->y + i->h)) {
int lookable = i->extra & 0x0B;
@@ -724,7 +791,10 @@ void PelrockEngine::checkMouseClick(int x, int y) {
_bgPopupBalloon = nullptr;
}
- Exit *exit = isExitUnder(mouseX, mouseY);
+ Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
+
+ Exit *exit = isExitAtPoint(walkTarget.x, walkTarget.y);
+
if (exit != nullptr) {
xAlfred = exit->targetX;
yAlfred = exit->targetY - kAlfredFrameHeight;
@@ -756,11 +826,6 @@ void PelrockEngine::checkMouseHover() {
exitDetected = true;
}
- AnimSet *sprite = isSpriteUnder(mouseX, mouseY);
- if (sprite != nullptr) {
- isSomethingUnder = true;
- }
-
HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
if (hotspot != nullptr) {
isSomethingUnder = true;
@@ -890,32 +955,9 @@ void PelrockEngine::setScreen(int number, int dir) {
_screen->setPixel(i, j, background[j * 640 + i]);
}
}
- _currentRoomAnims = loadRoomAnimations(&roomFile, roomOffset);
-
- loadHotspots(&roomFile, roomOffset);
- int hotsPotCount = 0;
- for (Common::List<HotSpot>::iterator i = _hotspots.begin(); i != _hotspots.end(); i++) {
- // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
- _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 100 + hotsPotCount);
- _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 100 + hotsPotCount);
- _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 100 + hotsPotCount);
- _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 100 + hotsPotCount);
- hotsPotCount++;
- }
- _currentRoomWalkboxes = loadWalkboxes(&roomFile, roomOffset);
- _currentRoomExits = loadExits(&roomFile, roomOffset);
-
- int walkboxCount = 0;
- for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
- // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
- _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
- _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
- _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- walkboxCount++;
- }
+ loadRoomMetadata(&roomFile, roomOffset);
_screen->markAllDirty();
roomFile.close();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index b37df6e9ce7..457e4ab4f8e 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -63,9 +63,9 @@ private:
// Room data
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
- Common::List<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
void loadMainCharacterAnims();
- void loadHotspots(Common::File *roomFile, int roomOffset);
+ Common::List<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
+ Common::List<HotSpot>loadHotspots(Common::File *roomFile, int roomOffset);
Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
void loadRoomMetadata(Common::File *roomFile, int roomOffset);
@@ -89,7 +89,7 @@ private:
ChronoManager *_chronoManager = nullptr;
byte *standingAnim = new byte[3060 * 102];
- Common::List<HotSpot> _hotspots;
+ Common::List<HotSpot> _currentRoomHotspots;
Common::List<HoverArea> _hoverAreas;
Common::List<AnimSet> _currentRoomAnims;
Common::List<Exit> _currentRoomExits;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index f30cb37c2f0..25ec19546a8 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -73,6 +73,8 @@ struct Anim {
int nframes;
int curFrame;
byte *animData;
+ byte loopCount;
+ byte speed;
};
struct Exit {
@@ -90,15 +92,16 @@ struct Exit {
struct AnimSet {
byte type;
- int x;
- int y;
- int w;
- int h;
- int speed;
- int numAnims;
+ int x; //0
+ int y;//2
+ int w;//4
+ int h;//5
+ byte extra; //6
+ int numAnims; //8
+ byte spriteType; //33
+ byte actionFlags;//34
+ bool isDisabled; //38
Anim *animData;
- byte extra;
- bool enabled;
};
struct HoverArea {
Commit: 98858463ec5b1ef6c27fc1795dc749ecbb9f0f08
https://github.com/scummvm/scummvm/commit/98858463ec5b1ef6c27fc1795dc749ecbb9f0f08
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:02+02:00
Commit Message:
PELROCK: Display available actions
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index de827a6a239..b75db195894 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -280,7 +280,6 @@ Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
animSet.actionFlags = animData[34];
animSet.isDisabled = animData[38];
-
animSet.animData = new Anim[animSet.numAnims];
debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
// roomFile->skip(1);
@@ -310,7 +309,6 @@ Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
debug("Anim %d-%d: invalid dimensions, skipping", i, j);
}
animSet.animData[j] = anim;
-
}
anims.push_back(animSet);
@@ -372,10 +370,8 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
Common::List<HotSpot> hotspots;
-
-
for (Common::List<AnimSet>::iterator i = anims.begin(); i != anims.end(); i++) {
- if(!i->isDisabled) {
+ if (!i->isDisabled) {
hotspots.push_back(
HotSpot{
i->actionFlags,
@@ -384,8 +380,7 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
i->w,
i->h,
i->extra,
- }
- );
+ });
}
}
@@ -393,8 +388,6 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
Common::List<Exit> exits = loadExits(roomFile, roomOffset);
Common::List<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
-
-
int hotsPotCount = 0;
for (Common::List<HotSpot>::iterator i = staticHotspots.begin(); i != staticHotspots.end(); i++) {
// _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
@@ -416,7 +409,6 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
walkboxCount++;
}
-
_currentRoomAnims = anims;
_currentRoomHotspots = hotspots;
_currentRoomExits = exits;
@@ -497,7 +489,7 @@ Common::List<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffs
return exits;
}
-Common::List<HotSpot>PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
+Common::List<HotSpot> PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
roomFile->seek(pair10_offset_pos, SEEK_SET);
@@ -526,7 +518,6 @@ Common::List<HotSpot>PelrockEngine::loadHotspots(Common::File *roomFile, int roo
return hotspots;
// uint32_t hover_areas_start = pair10_data_offset + 0x1BE;
// roomFile->seek(hover_areas_start, SEEK_SET);
-
}
void PelrockEngine::loadMainCharacterAnims() {
@@ -574,38 +565,37 @@ Common::List<VerbIcons> PelrockEngine::populateActionsMenu(HotSpot hotspot) {
Common::List<VerbIcons> verbs;
verbs.push_back(LOOK);
- if(hotspot.type & 1) {
+ if (hotspot.type & 1) {
debug("Hotspot allows OPEN action");
verbs.push_back(OPEN);
}
- if(hotspot.type & 2) {
+ if (hotspot.type & 2) {
debug("Hotspot allows CLOSE action");
verbs.push_back(CLOSE);
}
- if(hotspot.type & 4) {
+ if (hotspot.type & 4) {
debug("Hotspot allows UNKNOWN action");
verbs.push_back(UNKNOWN);
}
- if(hotspot.type & 8) {
+ if (hotspot.type & 8) {
debug("Hotspot allows PICKUP action");
verbs.push_back(PICKUP);
}
- if(hotspot.type & 16) {
+ if (hotspot.type & 16) {
debug("Hotspot allows TALK action");
verbs.push_back(TALK);
}
- if(hotspot.type & 32) {
+ if (hotspot.type & 32) {
debug("Hotspot allows WALK action");
verbs.push_back(PUSH);
}
- if(hotspot.type & 128) {
+ if (hotspot.type & 128) {
debug("Hotspot allows PULL action");
verbs.push_back(PULL);
}
return verbs;
}
-
void PelrockEngine::frames() {
if (_chronoManager->_gameTick) {
@@ -719,7 +709,6 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
_displayPopup = true;
_currentPopupFrame = 0;
_currentHotspot = hotspot;
- populateActionsMenu(*hotspot);
_bgPopupBalloon = grabBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight);
}
}
@@ -769,15 +758,32 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
}
- // for (Common::List<VerbIcons>::iterator i = verbList.begin(); i != verbList.end(); i++) {
- // debug("Verb icon to show: %d", *i);
- // }
+ Common::List<VerbIcons> availableActions = populateActionsMenu(*_currentHotspot);
+
+ for (Common::List<VerbIcons>::iterator i = availableActions.begin(); i != availableActions.end(); i++) {
+ debug("Verb icon to show: %d", *i);
+ }
for (uint32_t y = 0; y < kVerbIconHeight; y++) {
for (uint32_t x = 0; x < kVerbIconWidth; x++) {
unsigned int src_pos = y * kVerbIconWidth + x;
if (_verbIcons[LOOK][src_pos] != 1)
- _screen->setPixel(x + posx + 10, y + posy + 10, _verbIcons[LOOK][src_pos]);
+ _screen->setPixel(x + posx + 20, y + posy + 20, _verbIcons[LOOK][src_pos]);
+ }
+ }
+
+ for (Common::List<VerbIcons>::iterator i = availableActions.begin(); i != availableActions.end(); i++) {
+ VerbIcons verb = *i;
+ int index = 0;
+ for (Common::List<VerbIcons>::iterator j = availableActions.begin(); j != i; j++) {
+ index++;
+ }
+ for (uint32_t y = 0; y < kVerbIconHeight; y++) {
+ for (uint32_t x = 0; x < kVerbIconWidth; x++) {
+ unsigned int src_pos = y * kVerbIconWidth + x;
+ if (_verbIcons[verb][src_pos] != 1)
+ _screen->setPixel(x + posx + 20 + (index * (kVerbIconWidth + 2)), y + posy + 20, _verbIcons[verb][src_pos]);
+ }
}
}
}
@@ -793,7 +799,7 @@ void PelrockEngine::checkMouseClick(int x, int y) {
Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
- Exit *exit = isExitAtPoint(walkTarget.x, walkTarget.y);
+ Exit *exit = isExitAtPoint(walkTarget.x, walkTarget.y);
if (exit != nullptr) {
xAlfred = exit->targetX;
@@ -815,16 +821,15 @@ void PelrockEngine::changeCursor(Cursor cursor) {
void PelrockEngine::checkMouseHover() {
bool isSomethingUnder = false;
+ // Calculate walk target first (before checking anything else)
+ Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
- // Calculate walk target first (before checking anything else)
- Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
-
- // Check if walk target hits any exit
- bool exitDetected = false;
- Exit *exit = isExitAtPoint(walkTarget.x, walkTarget.y);
- if (exit != nullptr) {
- exitDetected = true;
- }
+ // Check if walk target hits any exit
+ bool exitDetected = false;
+ Exit *exit = isExitAtPoint(walkTarget.x, walkTarget.y);
+ if (exit != nullptr) {
+ exitDetected = true;
+ }
HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
if (hotspot != nullptr) {
@@ -837,92 +842,89 @@ void PelrockEngine::checkMouseHover() {
// }
if (isSomethingUnder && exitDetected) {
changeCursor(COMBINATION);
- }
- else if (isSomethingUnder) {
+ } else if (isSomethingUnder) {
changeCursor(HOTSPOT);
- }
- else if (exitDetected) {
+ } else if (exitDetected) {
changeCursor(EXIT);
} else {
changeCursor(DEFAULT);
}
-
}
Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
- // Starting point for pathfinding
- int sourceX = mouseX;
- int sourceY = mouseY;
+ // Starting point for pathfinding
+ int sourceX = mouseX;
+ int sourceY = mouseY;
- // TODO: If hovering over a sprite/hotspot, adjust source point to sprite center
- // For now, just use mouse position
+ // TODO: If hovering over a sprite/hotspot, adjust source point to sprite center
+ // For now, just use mouse position
- // Find nearest walkable point in walkboxes
- uint32 minDistance = 0xFFFFFFFF;
- Common::Point bestTarget(sourceX, sourceY);
+ // Find nearest walkable point in walkboxes
+ uint32 minDistance = 0xFFFFFFFF;
+ Common::Point bestTarget(sourceX, sourceY);
- for (Common::List<WalkBox>::iterator it = _currentRoomWalkboxes.begin();
- it != _currentRoomWalkboxes.end(); ++it) {
+ for (Common::List<WalkBox>::iterator it = _currentRoomWalkboxes.begin();
+ it != _currentRoomWalkboxes.end(); ++it) {
- // Calculate distance from source point to this walkbox (Manhattan distance)
- int dx = 0;
- int dy = 0;
+ // Calculate distance from source point to this walkbox (Manhattan distance)
+ int dx = 0;
+ int dy = 0;
- // Calculate horizontal distance
- if (sourceX < it->x) {
- dx = it->x - sourceX;
- } else if (sourceX > it->x + it->w) {
- dx = sourceX - (it->x + it->w);
- }
- // else: sourceX is inside walkbox horizontally, dx = 0
+ // Calculate horizontal distance
+ if (sourceX < it->x) {
+ dx = it->x - sourceX;
+ } else if (sourceX > it->x + it->w) {
+ dx = sourceX - (it->x + it->w);
+ }
+ // else: sourceX is inside walkbox horizontally, dx = 0
- // Calculate vertical distance
- if (sourceY < it->y) {
- dy = it->y - sourceY;
- } else if (sourceY > it->y + it->h) {
- dy = sourceY - (it->y + it->h);
- }
- // else: sourceY is inside walkbox vertically, dy = 0
+ // Calculate vertical distance
+ if (sourceY < it->y) {
+ dy = it->y - sourceY;
+ } else if (sourceY > it->y + it->h) {
+ dy = sourceY - (it->y + it->h);
+ }
+ // else: sourceY is inside walkbox vertically, dy = 0
- uint32 distance = dx + dy;
+ uint32 distance = dx + dy;
- if (distance < minDistance) {
- minDistance = distance;
+ if (distance < minDistance) {
+ minDistance = distance;
- // Calculate target point (nearest point on walkbox to source)
- int targetX = sourceX;
- int targetY = sourceY;
+ // Calculate target point (nearest point on walkbox to source)
+ int targetX = sourceX;
+ int targetY = sourceY;
- if (sourceX < it->x) {
- targetX = it->x;
- } else if (sourceX > it->x + it->w) {
- targetX = it->x + it->w;
- }
+ if (sourceX < it->x) {
+ targetX = it->x;
+ } else if (sourceX > it->x + it->w) {
+ targetX = it->x + it->w;
+ }
- if (sourceY < it->y) {
- targetY = it->y;
- } else if (sourceY > it->y + it->h) {
- targetY = it->y + it->h;
- }
+ if (sourceY < it->y) {
+ targetY = it->y;
+ } else if (sourceY > it->y + it->h) {
+ targetY = it->y + it->h;
+ }
- bestTarget.x = targetX;
- bestTarget.y = targetY;
- }
- }
+ bestTarget.x = targetX;
+ bestTarget.y = targetY;
+ }
+ }
- return bestTarget;
+ return bestTarget;
}
Exit *PelrockEngine::isExitAtPoint(int x, int y) {
- for (Common::List<Exit>::iterator i = _currentRoomExits.begin();
- i != _currentRoomExits.end(); ++i) {
- // Check if point is inside exit trigger rectangle
- if (x >= i->x && x <= (i->x + i->w) &&
- y >= i->y && y <= (i->y + i->h)) {
- return &(*i);
- }
- }
- return nullptr;
+ for (Common::List<Exit>::iterator i = _currentRoomExits.begin();
+ i != _currentRoomExits.end(); ++i) {
+ // Check if point is inside exit trigger rectangle
+ if (x >= i->x && x <= (i->x + i->w) &&
+ y >= i->y && y <= (i->y + i->h)) {
+ return &(*i);
+ }
+ }
+ return nullptr;
}
void PelrockEngine::setScreen(int number, int dir) {
@@ -956,7 +958,6 @@ void PelrockEngine::setScreen(int number, int dir) {
}
}
-
loadRoomMetadata(&roomFile, roomOffset);
_screen->markAllDirty();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 457e4ab4f8e..45d751e42e1 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -65,7 +65,7 @@ private:
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
void loadMainCharacterAnims();
Common::List<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
- Common::List<HotSpot>loadHotspots(Common::File *roomFile, int roomOffset);
+ Common::List<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
void loadRoomMetadata(Common::File *roomFile, int roomOffset);
@@ -74,8 +74,8 @@ private:
byte *grabBackgroundSlice(int x, int y, int w, int h);
void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
Common::List<VerbIcons> populateActionsMenu(HotSpot hotspot);
- Common::Point calculateWalkTarget(int mouseX, int mouseY);
- Exit *isExitAtPoint(int x, int y);
+ Common::Point calculateWalkTarget(int mouseX, int mouseY);
+ Exit *isExitAtPoint(int x, int y);
// render loop
void frames();
void checkMouseHover();
Commit: 2efc7a1a41591703b6e41478bcca4636fd25fe49
https://github.com/scummvm/scummvm/commit/2efc7a1a41591703b6e41478bcca4636fd25fe49
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:02+02:00
Commit Message:
PELROCK: Renders descriptions
Changed paths:
engines/pelrock/chrono.cpp
engines/pelrock/chrono.h
engines/pelrock/fonts/large_font.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index 226b09807bc..355df50a828 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/events.h"
#include "common/system.h"
#include "pelrock/chrono.h"
@@ -57,4 +58,17 @@ void ChronoManager::changeSpeed() {
_speedMultiplier = 1;
}
+void ChronoManager::delay(uint32 ms) {
+ uint32 delayStart = g_system->getMillis();
+
+ ms = ms / _speedMultiplier;
+ Common::Event e;
+ while ((g_system->getMillis() - delayStart) < ms && !g_engine->shouldQuit()) {
+ while (g_system->getEventManager()->pollEvent(e)) {
+
+ }
+ g_engine->_screen->update();
+ }
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 5257563225f..0adce498a89 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -40,6 +40,7 @@ public:
~ChronoManager();
void updateChrono();
void changeSpeed();
+ void delay(uint32 ms);
bool _gameTick = false;
bool _gameTickHalfSpeed = false;
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index 07f41a0e63f..0e41a4dd812 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -51,34 +51,12 @@ int LargeFont::getCharWidth(uint32 chr) const {
}
void LargeFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
-
- // """Extract a single character from the large font data (12x24 pixels)
- // Each character is 48 bytes (24 rows à 2 bytes per row)"""
- // offset = char_index * 0x30 # 48 bytes per character
- // char_data = data[offset:offset + 0x30]
-
- // # Create 12x24 pixel array
- // pixels = np.zeros((24, 12), dtype=np.uint8)
-
- // # Process each row (2 bytes per row)
- // for row in range(24):
- // byte1 = char_data[row * 2]
- // byte2 = char_data[row * 2 + 1]
-
- // # Process 12 bits (12 pixels) from the two bytes
- // for bit in range(8):
- // pixels[row, bit] = 255 if (byte1 & (0x80 >> bit)) else 0
- // for bit in range(4):
- // pixels[row, bit + 8] = 255 if (byte2 & (0x80 >> bit)) else 0
-
- // return pixels
-
- if (!_fontData || chr > 255) {
+ chr -= 32; // Adjust for font starting at ASCII 32
+ if (!_fontData || chr > 255 || chr < 0) {
return;
}
- chr -= 32; // Adjust for font starting at ASCII 32
int charOffset = chr * 0x30;
- debug("LargeFont::drawChar: Drawing char %d at offset %d", chr, charOffset);
+
for (int i = 0; i < 24; i++) {
byte rowByte1 = _fontData[charOffset + i * 2];
byte rowByte2 = _fontData[charOffset + i * 2 + 1];
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b75db195894..748071a4d46 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -243,6 +243,7 @@ void PelrockEngine::getBackground(Common::File *roomFile, int roomOffset, byte *
Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
uint32_t pair_offset = roomOffset + (8 * 8);
+ debug("Sprite pair offset position: %d", pair_offset);
roomFile->seek(pair_offset, SEEK_SET);
uint32_t offset = roomFile->readUint32LE();
uint32_t size = roomFile->readUint32LE();
@@ -279,7 +280,9 @@ Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
animSet.spriteType = animData[33];
animSet.actionFlags = animData[34];
animSet.isDisabled = animData[38];
-
+ if(animSet.numAnims == 0) {
+ break;
+ }
animSet.animData = new Anim[animSet.numAnims];
debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
// roomFile->skip(1);
@@ -352,7 +355,7 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
int16 w = roomFile->readSint16LE();
int16 h = roomFile->readSint16LE();
byte flags = roomFile->readByte();
- debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+ // debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
WalkBox box;
box.x = x1;
box.y = y1;
@@ -364,39 +367,83 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
return walkboxes;
}
+Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roomFile, int roomOffset) {
+ uint32_t pair12_offset_pos = roomOffset + (12 * 8);
+ roomFile->seek(pair12_offset_pos, SEEK_SET);
+ // roomFile->skip(4);
+ uint32_t pair12_data_offset = roomFile->readUint32LE();
+ uint32_t pair12_size = roomFile->readUint32LE();
+
+ roomFile->seek(pair12_data_offset, SEEK_SET);
+ byte *data = new byte[pair12_size];
+ roomFile->read(data, pair12_size);
+ Common::Array<Description> descriptions;
+ uint32_t pos = 0;
+ while (pos < (pair12_size)) {
+ // char *desc = new char[256];
+ int desc_pos = 0;
+ if(data[pos] == 0xFF) {
+ Description description;
+ description.itemId = data[++pos];
+ pos += 2;
+ description.index = data[pos++];
+ description.text = "";
+ // debug("Found description terminator");
+ while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
+ // debug(" char: %c", data[pos]);
+ if(data[pos] != 0x00) {
+ description.text.append(1, (char)data[pos]);
+ }
+ // desc[desc_pos++] = (char)data[pos];
+ // debug("Current desc: %s", desc);
+ pos++;
+ }
+ debug("Found description for item %d index %d, text: %s", description.itemId, description.index, description.text.c_str());
+
+ descriptions.push_back(description);
+ }
+ pos++;
+ }
+
+ delete[] data;
+ // for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
+ // debug("Room description: %s", i->c_str());
+ // }
+ return descriptions;
+}
+
void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
- Common::List<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
+ Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset);
- Common::List<HotSpot> hotspots;
+ Common::List<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
+ Common::Array<HotSpot> hotspots;
+ int count = 0;
for (Common::List<AnimSet>::iterator i = anims.begin(); i != anims.end(); i++) {
- if (!i->isDisabled) {
- hotspots.push_back(
- HotSpot{
- i->actionFlags,
- i->x,
- i->y,
- i->w,
- i->h,
- i->extra,
- });
- }
+
+ HotSpot thisHotspot;
+ thisHotspot.x = i->x;
+ thisHotspot.y = i->y;
+ thisHotspot.w = i->w;
+ thisHotspot.h = i->h;
+ thisHotspot.extra = i->extra;
+ thisHotspot.type = i->actionFlags;
+ thisHotspot.isEnabled = !i->isDisabled;
+ thisHotspot.description = descriptions[count].text;
+ hotspots.push_back(thisHotspot);
+ count++;
}
- Common::List<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
+ Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
Common::List<Exit> exits = loadExits(roomFile, roomOffset);
Common::List<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
- int hotsPotCount = 0;
- for (Common::List<HotSpot>::iterator i = staticHotspots.begin(); i != staticHotspots.end(); i++) {
- // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
- _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 100 + hotsPotCount);
- _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 100 + hotsPotCount);
- _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 100 + hotsPotCount);
- _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 100 + hotsPotCount);
- hotsPotCount++;
- hotspots.push_back(*i);
+ debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
+ for (int i = 0; i < staticHotspots.size(); i++) {
+ HotSpot hotspot = staticHotspots[i];
+ hotspot.description = descriptions[anims.size() + i].text;
+ hotspots.push_back(hotspot);
}
int walkboxCount = 0;
@@ -413,6 +460,17 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
_currentRoomHotspots = hotspots;
_currentRoomExits = exits;
_currentRoomWalkboxes = walkboxes;
+ _currentRoomDescriptions = descriptions;
+
+
+ for(int i=0; i < _currentRoomHotspots.size(); i++) {
+ HotSpot hotspot = _currentRoomHotspots[i];
+ debug("Hotspot %d: x=%d y=%d w=%d h=%d type=%d enabled? %d desc=%s", i, hotspot.x, hotspot.y, hotspot.w, hotspot.h, hotspot.type, hotspot.isEnabled, hotspot.description.c_str());
+ _screen->drawLine(hotspot.x, hotspot.y, hotspot.x + hotspot.w, hotspot.y, 200 + i);
+ _screen->drawLine(hotspot.x, hotspot.y + hotspot.h, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
+ _screen->drawLine(hotspot.x, hotspot.y, hotspot.x, hotspot.y + hotspot.h, 200 + i);
+ _screen->drawLine(hotspot.x + hotspot.w, hotspot.y, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
+ }
}
void PelrockEngine::loadCursors() {
@@ -489,9 +547,9 @@ Common::List<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffs
return exits;
}
-Common::List<HotSpot> PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
+Common::Array<HotSpot> PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
-
+ debug("Hotspot(10) pair offset position: %d", pair10_offset_pos);
roomFile->seek(pair10_offset_pos, SEEK_SET);
uint32_t pair10_data_offset = roomFile->readUint32LE();
uint32_t pair10_size = roomFile->readUint32LE();
@@ -499,7 +557,7 @@ Common::List<HotSpot> PelrockEngine::loadHotspots(Common::File *roomFile, int ro
roomFile->seek(count_offset, SEEK_SET);
byte hotspot_count = roomFile->readByte();
uint32_t hotspot_data_start = pair10_data_offset + 0x47c;
- Common::List<HotSpot> hotspots;
+ Common::Array<HotSpot> hotspots;
for (int i = 0; i < hotspot_count; i++) {
uint32_t obj_offset = hotspot_data_start + i * 9;
roomFile->seek(obj_offset, SEEK_SET);
@@ -715,13 +773,15 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
HotSpot *PelrockEngine::isHotspotUnder(int x, int y) {
- for (Common::List<HotSpot>::iterator i = _currentRoomHotspots.begin(); i != _currentRoomHotspots.end(); i++) {
- if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
- mouseY >= i->y && mouseY <= (i->y + i->h)) {
- int lookable = i->extra & 0x0B;
- int openable = i->extra & 0x0F;
+ for (size_t i = 0; i < _currentRoomHotspots.size(); i++) {
+ HotSpot hotspot = _currentRoomHotspots[i];
+ if (hotspot.isEnabled &&
+ mouseX >= hotspot.x && mouseX <= (hotspot.x + hotspot.w) &&
+ mouseY >= hotspot.y && mouseY <= (hotspot.y + hotspot.h)) {
+ int lookable = hotspot.extra & 0x0B;
+ int openable = hotspot.extra & 0x0F;
// debug("Hotspot at (%d,%d) size (%d,%d) extra %d, type = %d, lookable = %d, openable=%d", i->x, i->y, i->w, i->h, i->extra, i->type, lookable, openable);
- return &(*i);
+ return &hotspot;
}
}
return nullptr;
@@ -809,7 +869,9 @@ void PelrockEngine::checkMouseClick(int x, int y) {
HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
if (hotspot != nullptr) {
- debug("Clicked Hotspot at (%d,%d) size (%d,%d) extra %d", hotspot->x, hotspot->y, hotspot->w, hotspot->h, hotspot->extra);
+
+ showDescription(hotspot->description.c_str(), xAlfred, yAlfred, 13);
+
changeCursor(HOTSPOT);
}
}
@@ -927,6 +989,35 @@ Exit *PelrockEngine::isExitAtPoint(int x, int y) {
return nullptr;
}
+void PelrockEngine::showDescription(Common::String text, int x, int y, byte color) {
+ Common::Rect rect = _largeFont->getBoundingBox(text.c_str());
+ if(x + rect.width() > 640) {
+ x = 640 - rect.width();
+ }
+ if(y + rect.height() > 400) {
+ y = 400 - rect.height();
+ }
+ x = 0;
+ y = 0;
+ if(_bgText != nullptr) {
+ putBackgroundSlice(x, y, 640, 400, _bgText);
+ delete[] _bgText;
+ }
+ int16 w = MIN(rect.width(), (int16)(640 - x));
+ int16 h = MIN(rect.height(), (int16)(400 - y));
+ debug("grabbing bg slice at (%d,%d) w=%d h=%d", x, y, w, h);
+
+ _bgText = grabBackgroundSlice(x, y, 640, 400);
+ _largeFont->drawString(_screen, text.c_str(), x - 1, y, 640, 0); // Left
+ _largeFont->drawString(_screen, text.c_str(), x + 1, y, 640, 0); // Right
+ _largeFont->drawString(_screen, text.c_str(), x, y - 1, 640, 0); // Top
+ _largeFont->drawString(_screen, text.c_str(), x, y + 1, 640, 0); // Bottom
+
+ // Draw main text on top
+ _largeFont->drawString(_screen, text.c_str(), x, y, 640, color);
+
+}
+
void PelrockEngine::setScreen(int number, int dir) {
Common::File roomFile;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 45d751e42e1..e461ed006d2 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -65,9 +65,10 @@ private:
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
void loadMainCharacterAnims();
Common::List<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
- Common::List<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
+ Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
+ Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset);
void loadRoomMetadata(Common::File *roomFile, int roomOffset);
void loadCursors();
void loadInteractionIcons();
@@ -76,6 +77,8 @@ private:
Common::List<VerbIcons> populateActionsMenu(HotSpot hotspot);
Common::Point calculateWalkTarget(int mouseX, int mouseY);
Exit *isExitAtPoint(int x, int y);
+ void showDescription(Common::String text, int x, int y, byte color);
+
// render loop
void frames();
void checkMouseHover();
@@ -89,11 +92,12 @@ private:
ChronoManager *_chronoManager = nullptr;
byte *standingAnim = new byte[3060 * 102];
- Common::List<HotSpot> _currentRoomHotspots;
+ Common::Array<HotSpot> _currentRoomHotspots;
Common::List<HoverArea> _hoverAreas;
Common::List<AnimSet> _currentRoomAnims;
Common::List<Exit> _currentRoomExits;
Common::List<WalkBox> _currentRoomWalkboxes;
+ Common::Array<Description> _currentRoomDescriptions;
int *_currentAnimFrames = nullptr;
int curAlfredFrame = 9;
uint16 mouseX = 0;
@@ -107,6 +111,7 @@ private:
byte *_verbIcons[9] = {nullptr};
byte *_popUpBalloon = nullptr;
byte *_bgPopupBalloon = nullptr;
+ byte *_bgText = nullptr;
bool _displayPopup = false;
int _popupX = 0;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 25ec19546a8..b909eb4ca86 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -112,13 +112,21 @@ struct HoverArea {
};
struct HotSpot {
- byte type;
+ int id;
int x;
int y;
- int id;
int w;
int h;
+ byte type;
int extra;
+ bool isEnabled = true;
+ Common::String description;
+};
+
+struct Description {
+ byte itemId;
+ byte index;
+ Common::String text;
};
struct WalkBox {
Commit: 7c6d67b89ee2b4a77057a572fa00d56cc991f894
https://github.com/scummvm/scummvm/commit/7c6d67b89ee2b4a77057a572fa00d56cc991f894
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:02+02:00
Commit Message:
PELROCK: Fixes verb action selection
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 748071a4d46..aed4e05ac88 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -280,7 +280,7 @@ Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
animSet.spriteType = animData[33];
animSet.actionFlags = animData[34];
animSet.isDisabled = animData[38];
- if(animSet.numAnims == 0) {
+ if (animSet.numAnims == 0) {
break;
}
animSet.animData = new Anim[animSet.numAnims];
@@ -382,7 +382,7 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
while (pos < (pair12_size)) {
// char *desc = new char[256];
int desc_pos = 0;
- if(data[pos] == 0xFF) {
+ if (data[pos] == 0xFF) {
Description description;
description.itemId = data[++pos];
pos += 2;
@@ -391,7 +391,7 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
// debug("Found description terminator");
while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
// debug(" char: %c", data[pos]);
- if(data[pos] != 0x00) {
+ if (data[pos] != 0x00) {
description.text.append(1, (char)data[pos]);
}
// desc[desc_pos++] = (char)data[pos];
@@ -430,7 +430,6 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
thisHotspot.extra = i->extra;
thisHotspot.type = i->actionFlags;
thisHotspot.isEnabled = !i->isDisabled;
- thisHotspot.description = descriptions[count].text;
hotspots.push_back(thisHotspot);
count++;
}
@@ -442,7 +441,6 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
for (int i = 0; i < staticHotspots.size(); i++) {
HotSpot hotspot = staticHotspots[i];
- hotspot.description = descriptions[anims.size() + i].text;
hotspots.push_back(hotspot);
}
@@ -462,10 +460,9 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
_currentRoomWalkboxes = walkboxes;
_currentRoomDescriptions = descriptions;
-
- for(int i=0; i < _currentRoomHotspots.size(); i++) {
+ for (int i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
- debug("Hotspot %d: x=%d y=%d w=%d h=%d type=%d enabled? %d desc=%s", i, hotspot.x, hotspot.y, hotspot.w, hotspot.h, hotspot.type, hotspot.isEnabled, hotspot.description.c_str());
+ debug("Hotspot %d: x=%d y=%d w=%d h=%d type=%d enabled? %d desc=%s", i, hotspot.x, hotspot.y, hotspot.w, hotspot.h, hotspot.type, hotspot.isEnabled, _currentRoomDescriptions[i].text.c_str());
_screen->drawLine(hotspot.x, hotspot.y, hotspot.x + hotspot.w, hotspot.y, 200 + i);
_screen->drawLine(hotspot.x, hotspot.y + hotspot.h, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
_screen->drawLine(hotspot.x, hotspot.y, hotspot.x, hotspot.y + hotspot.h, 200 + i);
@@ -619,35 +616,36 @@ void PelrockEngine::putBackgroundSlice(int x, int y, int w, int h, byte *slice)
}
}
}
-Common::List<VerbIcons> PelrockEngine::populateActionsMenu(HotSpot hotspot) {
+Common::List<VerbIcons> PelrockEngine::populateActionsMenu(HotSpot *hotspot) {
Common::List<VerbIcons> verbs;
+ debug("Populating actions menu for hotspot type %d", hotspot->type);
verbs.push_back(LOOK);
- if (hotspot.type & 1) {
+ if (hotspot->type & 1) {
debug("Hotspot allows OPEN action");
verbs.push_back(OPEN);
}
- if (hotspot.type & 2) {
+ if (hotspot->type & 2) {
debug("Hotspot allows CLOSE action");
verbs.push_back(CLOSE);
}
- if (hotspot.type & 4) {
+ if (hotspot->type & 4) {
debug("Hotspot allows UNKNOWN action");
verbs.push_back(UNKNOWN);
}
- if (hotspot.type & 8) {
+ if (hotspot->type & 8) {
debug("Hotspot allows PICKUP action");
verbs.push_back(PICKUP);
}
- if (hotspot.type & 16) {
+ if (hotspot->type & 16) {
debug("Hotspot allows TALK action");
verbs.push_back(TALK);
}
- if (hotspot.type & 32) {
+ if (hotspot->type & 32) {
debug("Hotspot allows WALK action");
verbs.push_back(PUSH);
}
- if (hotspot.type & 128) {
+ if (hotspot->type & 128) {
debug("Hotspot allows PULL action");
verbs.push_back(PULL);
}
@@ -745,8 +743,8 @@ void PelrockEngine::frames() {
}
void PelrockEngine::checkLongMouseClick(int x, int y) {
- HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
- if (hotspot != nullptr) {
+ int hotspotIndex = isHotspotUnder(mouseX, mouseY);
+ if (hotspotIndex != -1) {
// _popupX = hotspot->x;
// _popupY = hotspot->y;
if (_bgPopupBalloon != nullptr) {
@@ -766,25 +764,23 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
}
_displayPopup = true;
_currentPopupFrame = 0;
- _currentHotspot = hotspot;
+ _currentHotspot = &_currentRoomHotspots[hotspotIndex];
+ debug("Current hotspot type: %d", _currentHotspot->type);
_bgPopupBalloon = grabBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight);
}
}
-HotSpot *PelrockEngine::isHotspotUnder(int x, int y) {
+int PelrockEngine::isHotspotUnder(int x, int y) {
for (size_t i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
if (hotspot.isEnabled &&
mouseX >= hotspot.x && mouseX <= (hotspot.x + hotspot.w) &&
mouseY >= hotspot.y && mouseY <= (hotspot.y + hotspot.h)) {
- int lookable = hotspot.extra & 0x0B;
- int openable = hotspot.extra & 0x0F;
- // debug("Hotspot at (%d,%d) size (%d,%d) extra %d, type = %d, lookable = %d, openable=%d", i->x, i->y, i->w, i->h, i->extra, i->type, lookable, openable);
- return &hotspot;
+ return i;
}
}
- return nullptr;
+ return -1;
}
Exit *PelrockEngine::isExitUnder(int x, int y) {
@@ -818,11 +814,11 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
}
- Common::List<VerbIcons> availableActions = populateActionsMenu(*_currentHotspot);
+ Common::List<VerbIcons> availableActions = populateActionsMenu(_currentHotspot);
- for (Common::List<VerbIcons>::iterator i = availableActions.begin(); i != availableActions.end(); i++) {
- debug("Verb icon to show: %d", *i);
- }
+ // for (Common::List<VerbIcons>::iterator i = availableActions.begin(); i != availableActions.end(); i++) {
+ // debug("Verb icon to show: %d", *i);
+ // }
for (uint32_t y = 0; y < kVerbIconHeight; y++) {
for (uint32_t x = 0; x < kVerbIconWidth; x++) {
@@ -851,6 +847,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
void PelrockEngine::checkMouseClick(int x, int y) {
_displayPopup = false;
+ _currentHotspot = nullptr;
if (_bgPopupBalloon != nullptr) {
putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
delete[] _bgPopupBalloon;
@@ -867,10 +864,9 @@ void PelrockEngine::checkMouseClick(int x, int y) {
setScreen(exit->targetRoom, exit->dir);
}
- HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
- if (hotspot != nullptr) {
-
- showDescription(hotspot->description.c_str(), xAlfred, yAlfred, 13);
+ int hotspotIndex = isHotspotUnder(mouseX, mouseY);
+ if (hotspotIndex != -1) {
+ showDescription(_currentRoomDescriptions[hotspotIndex].text.c_str(), xAlfred, yAlfred, 13);
changeCursor(HOTSPOT);
}
@@ -893,8 +889,8 @@ void PelrockEngine::checkMouseHover() {
exitDetected = true;
}
- HotSpot *hotspot = isHotspotUnder(mouseX, mouseY);
- if (hotspot != nullptr) {
+ int hotspotIndex = isHotspotUnder(mouseX, mouseY);
+ if (hotspotIndex != -1) {
isSomethingUnder = true;
}
// Exit *exit = isExitUnder(mouseX, mouseY);
@@ -991,15 +987,15 @@ Exit *PelrockEngine::isExitAtPoint(int x, int y) {
void PelrockEngine::showDescription(Common::String text, int x, int y, byte color) {
Common::Rect rect = _largeFont->getBoundingBox(text.c_str());
- if(x + rect.width() > 640) {
+ if (x + rect.width() > 640) {
x = 640 - rect.width();
}
- if(y + rect.height() > 400) {
+ if (y + rect.height() > 400) {
y = 400 - rect.height();
}
x = 0;
y = 0;
- if(_bgText != nullptr) {
+ if (_bgText != nullptr) {
putBackgroundSlice(x, y, 640, 400, _bgText);
delete[] _bgText;
}
@@ -1008,14 +1004,13 @@ void PelrockEngine::showDescription(Common::String text, int x, int y, byte colo
debug("grabbing bg slice at (%d,%d) w=%d h=%d", x, y, w, h);
_bgText = grabBackgroundSlice(x, y, 640, 400);
- _largeFont->drawString(_screen, text.c_str(), x - 1, y, 640, 0); // Left
- _largeFont->drawString(_screen, text.c_str(), x + 1, y, 640, 0); // Right
- _largeFont->drawString(_screen, text.c_str(), x, y - 1, 640, 0); // Top
- _largeFont->drawString(_screen, text.c_str(), x, y + 1, 640, 0); // Bottom
-
- // Draw main text on top
- _largeFont->drawString(_screen, text.c_str(), x, y, 640, color);
+ _largeFont->drawString(_screen, text.c_str(), x - 1, y, 640, 0); // Left
+ _largeFont->drawString(_screen, text.c_str(), x + 1, y, 640, 0); // Right
+ _largeFont->drawString(_screen, text.c_str(), x, y - 1, 640, 0); // Top
+ _largeFont->drawString(_screen, text.c_str(), x, y + 1, 640, 0); // Bottom
+ // Draw main text on top
+ _largeFont->drawString(_screen, text.c_str(), x, y, 640, color);
}
void PelrockEngine::setScreen(int number, int dir) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index e461ed006d2..2886cb59c4f 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -74,7 +74,7 @@ private:
void loadInteractionIcons();
byte *grabBackgroundSlice(int x, int y, int w, int h);
void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
- Common::List<VerbIcons> populateActionsMenu(HotSpot hotspot);
+ Common::List<VerbIcons> populateActionsMenu(HotSpot *hotspot);
Common::Point calculateWalkTarget(int mouseX, int mouseY);
Exit *isExitAtPoint(int x, int y);
void showDescription(Common::String text, int x, int y, byte color);
@@ -85,7 +85,7 @@ private:
void checkMouseClick(int x, int y);
void checkLongMouseClick(int x, int y);
void changeCursor(Cursor cursor);
- HotSpot *isHotspotUnder(int x, int y);
+ int isHotspotUnder(int x, int y);
Exit *isExitUnder(int x, int y);
AnimSet *isSpriteUnder(int x, int y);
void showActionBalloon(int posx, int posy, int curFrame);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index b909eb4ca86..3e6b3b780db 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -120,7 +120,6 @@ struct HotSpot {
byte type;
int extra;
bool isEnabled = true;
- Common::String description;
};
struct Description {
Commit: a75cf60c5ca6015a8367989adffeb6644b3eb5c1
https://github.com/scummvm/scummvm/commit/a75cf60c5ca6015a8367989adffeb6644b3eb5c1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:03+02:00
Commit Message:
PELROCK: Load conversations
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index aed4e05ac88..4dca90ae336 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -243,7 +243,7 @@ void PelrockEngine::getBackground(Common::File *roomFile, int roomOffset, byte *
Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
uint32_t pair_offset = roomOffset + (8 * 8);
- debug("Sprite pair offset position: %d", pair_offset);
+ // debug("Sprite pair offset position: %d", pair_offset);
roomFile->seek(pair_offset, SEEK_SET);
uint32_t offset = roomFile->readUint32LE();
uint32_t size = roomFile->readUint32LE();
@@ -284,8 +284,7 @@ Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
break;
}
animSet.animData = new Anim[animSet.numAnims];
- debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
- // roomFile->skip(1);
+ // debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
int subAnimOffset = 10;
for (int j = 0; j < animSet.numAnims; j++) {
@@ -305,7 +304,7 @@ Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
anim.animData = new byte[needed];
Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
animSet.animData[j] = anim;
- debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
+ // debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
picOffset += needed;
} else {
continue;
@@ -367,7 +366,7 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
return walkboxes;
}
-Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roomFile, int roomOffset) {
+Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos) {
uint32_t pair12_offset_pos = roomOffset + (12 * 8);
roomFile->seek(pair12_offset_pos, SEEK_SET);
// roomFile->skip(4);
@@ -379,6 +378,7 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
roomFile->read(data, pair12_size);
Common::Array<Description> descriptions;
uint32_t pos = 0;
+ uint32_t lastDescPos = 0;
while (pos < (pair12_size)) {
// char *desc = new char[256];
int desc_pos = 0;
@@ -401,10 +401,12 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
debug("Found description for item %d index %d, text: %s", description.itemId, description.index, description.text.c_str());
descriptions.push_back(description);
+ lastDescPos = pos;
}
pos++;
}
-
+ debug("End of descriptions at position %d", pos);
+ outPos = lastDescPos+1;
delete[] data;
// for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
// debug("Room description: %s", i->c_str());
@@ -412,9 +414,199 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
return descriptions;
}
+bool isControlByte(byte b) {
+ // 0xFD: 'END_LINE',
+ // 0xFC: 'TEXT_TERM',
+ // 0xFB: 'CHOICE',
+ // 0xFA: 'SKIP',
+ // 0xF9: 'PAGE_BREAK',
+ // 0xF8: 'ACTION',
+ // 0xF7: 'END_BRANCH',
+ // 0xF6: 'LINE_CONT',
+ // 0xF5: 'END_BRANCH_2',
+ // 0xF4: 'END_CONV',
+ // 0xF1: 'CHOICE_ALT',
+ // 0xF0: 'GO_BACK',
+ // 0xFE: 'END_BRANCH_3',
+ // 0xEB: 'END_ALT',
+ // 0xFF: 'DESC_START',
+ // 0x08: 'SPEAKER',
+ if (b == 0xFD || b == 0xFC || b == 0xFB || b == 0xFA || b == 0xF9 || b == 0xF8 ||
+ b == 0xF7 || b == 0xF6 || b == 0xF5 || b == 0xF4 || b == 0xF1 ||
+ b == 0xF0 || b == 0xFE || b == 0xEB || b == 0xFF || b == 0x08) {
+ return true;
+ }
+ return false;
+}
+
+bool isTerminalByte(byte b) {
+ return (b == 0xFD || b == 0xF4 || b == 0xEB || b == 0xF7 || b == 0xF5 || b == 0xFE || b == 0xFC);
+}
+
+
+/**
+ * def decode_byte(b):
+ """Decode a byte to character"""
+ special = {
+ 0x80: 'ñ', 0x81: 'Ã', 0x82: '¡', 0x83: '¿', 0x84: 'ú',
+ 0x7B: 'á', 0x7C: 'é', 0x7D: 'Ã', 0x7E: 'ó', 0x7F: 'ú',
+ }
+
+ if b in special:
+ return special[b]
+ elif 0x20 <= b <= 0x7A:
+ return chr(b)
+ else:
+ return f'[{b:02X}]'
+ */
+char32_t decodeByte(byte b) {
+ if ( b == 0x80) {
+ return 'n';
+ } else if (b == 0x81) {
+ return 'i';
+ } else if (b == 0x82) {
+ return 'X';
+ } else if (b == 0x83) {
+ return 'X';
+ } else if (b == 0x84) {
+ return 'u';
+ } else if (b == 0x7B) {
+ return 'a';
+ } else if (b == 0x7C) {
+ return 'e';
+ } else if (b == 0x7D) {
+ return 'i';
+ } else if (b == 0x7E) {
+ return 'o';
+ } else if (b == 0x7F) {
+ return 'u';
+ } else if (b >= 0x20 && b <= 0x7A) {
+ return (char)b;
+ } else {
+ // return string in format [XX]
+ return '.';
+ }
+
+}
+
+Common::String PelrockEngine::getControlName(byte b) {
+ switch (b) {
+ case 0xFD: return "END_LINE";
+ case 0xFC: return "TEXT_TERM";
+ case 0xFB: return "CHOICE";
+ case 0xFA: return "SKIP";
+ case 0xF9: return "PAGE_BREAK";
+ case 0xF8: return "ACTION";
+ case 0xF7: return "END_BRANCH";
+ case 0xF6: return "LINE_CONT";
+ case 0xF5: return "END_BRANCH_2";
+ case 0xF4: return "END_CONV";
+ case 0xF1: return "CHOICE_ALT";
+ case 0xF0: return "GO_BACK";
+ case 0xFE: return "END_BRANCH_3";
+ case 0xEB: return "END_ALT";
+ case 0xFF: return "DESC_START";
+ case 0x08: return "SPEAKER";
+ default: return Common::String::format("UNKNOWN(0x%02X)", b);
+ }
+}
+
+Common::Array<ConversationLine> PelrockEngine::loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos) {
+ Common::Array<ConversationLine> conversations;
+
+ debug("Loading conversations starting at position %d", startPos);
+
+ uint32_t pair12_offset_pos = roomOffset + (12 * 8);
+ roomFile->seek(pair12_offset_pos, SEEK_SET);
+ uint32_t pair12_data_offset = roomFile->readUint32LE();
+ uint32_t pair12_size = roomFile->readUint32LE();
+
+ startPos += 2;
+ uint32_t conversation_start = pair12_data_offset + startPos;
+ uint32_t conversation_size = pair12_size - startPos;
+
+ roomFile->seek(conversation_start, SEEK_SET);
+ byte *data = new byte[conversation_size];
+ roomFile->read(data, conversation_size);
+
+ uint32_t i = 0;
+ int lineNum = 1;
+
+ while (i < conversation_size) {
+ uint32_t lineStart = i;
+ ConversationLine line;
+ line.offset = startPos + lineStart;
+ line.speaker = 0;
+
+ // Read until we hit an end marker
+ while (i < conversation_size) {
+ byte b = data[i];
+
+ if (b == 0x08) { // SPEAKER
+ i++;
+ if (i < conversation_size) {
+ line.speaker = data[i];
+ line.controlBytes.push_back(Common::String::format("SPEAKER(0x%02X)", line.speaker));
+ i++;
+ }
+ continue;
+ } else if (isControlByte(b)) {
+ line.controlBytes.push_back(Common::String::format("%s(0x%02X)",
+ getControlName(b).c_str(), b));
+ i++;
+
+ // Check for end markers
+ if (isTerminalByte(b)) {
+ break;
+ }
+ } else {
+ // Regular text character
+ if (b != 0x00) {
+ line.text += decodeByte(b);
+ }
+ i++;
+ }
+ }
+
+ // Store raw bytes for this line
+ for (uint32_t j = lineStart; j < i && j < conversation_size; j++) {
+ line.rawBytes.push_back(data[j]);
+ }
+
+ // Only add line if it has content
+ if (!line.text.empty() || line.controlBytes.size() > 0) {
+ // debug("Line %d (offset %d): %s", lineNum, line.offset, line.text.c_str());
+ if (line.controlBytes.size() > 0) {
+ Common::String controls;
+ for (uint k = 0; k < line.controlBytes.size(); k++) {
+ if (k > 0) controls += ", ";
+ controls += line.controlBytes[k];
+ }
+ // debug(" Controls: %s", controls.c_str());
+ }
+ conversations.push_back(line);
+ lineNum++;
+ }
+ }
+
+ delete[] data;
+ debug("Loaded %d conversation lines", conversations.size());
+ return conversations;
+}
+
void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
+ uint32_t outPos = 0;
+
+ Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
+ debug("After decsriptions, position is %d", outPos);
+ Common::Array<ConversationLine> conversations = loadConversations(roomFile, roomOffset, outPos);
+ for(int i = 0; i < conversations.size(); i++) {
+ if( conversations[i].text.empty()) {
+ continue;
+ }
+ debug("Conversation %d: %s", i, conversations[i].text.c_str());
+ }
- Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset);
Common::List<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
@@ -438,6 +630,7 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
Common::List<Exit> exits = loadExits(roomFile, roomOffset);
Common::List<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
+
debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
for (int i = 0; i < staticHotspots.size(); i++) {
HotSpot hotspot = staticHotspots[i];
@@ -462,7 +655,7 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
- debug("Hotspot %d: x=%d y=%d w=%d h=%d type=%d enabled? %d desc=%s", i, hotspot.x, hotspot.y, hotspot.w, hotspot.h, hotspot.type, hotspot.isEnabled, _currentRoomDescriptions[i].text.c_str());
+ // debug("Hotspot %d: x=%d y=%d w=%d h=%d type=%d enabled? %d desc=%s", i, hotspot.x, hotspot.y, hotspot.w, hotspot.h, hotspot.type, hotspot.isEnabled, _currentRoomDescriptions[i].text.c_str());
_screen->drawLine(hotspot.x, hotspot.y, hotspot.x + hotspot.w, hotspot.y, 200 + i);
_screen->drawLine(hotspot.x, hotspot.y + hotspot.h, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
_screen->drawLine(hotspot.x, hotspot.y, hotspot.x, hotspot.y + hotspot.h, 200 + i);
@@ -567,7 +760,7 @@ Common::Array<HotSpot> PelrockEngine::loadHotspots(Common::File *roomFile, int r
spot.w = obj_bytes[5];
spot.h = obj_bytes[6];
spot.extra = obj_bytes[7] | (obj_bytes[8] << 8);
- debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
+ // debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
hotspots.push_back(spot);
}
return hotspots;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 2886cb59c4f..332090cf5f0 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -68,7 +68,9 @@ private:
Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
- Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset);
+ Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos);
+ Common::Array<ConversationLine> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
+ Common::String getControlName(byte b);
void loadRoomMetadata(Common::File *roomFile, int roomOffset);
void loadCursors();
void loadInteractionIcons();
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 3e6b3b780db..9e648bef778 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -21,6 +21,10 @@
#ifndef PELROCK_TYPES_H
#define PELROCK_TYPES_H
+#include "common/types.h"
+#include "common/scummsys.h"
+#include "common/system.h"
+
namespace Pelrock {
enum Cursor {
@@ -122,6 +126,16 @@ struct HotSpot {
bool isEnabled = true;
};
+struct ConversationLine {
+ Common::String text;
+ Common::Array<Common::String> controlBytes;
+ byte speaker;
+ uint32 offset;
+ Common::Array<byte> rawBytes;
+
+ ConversationLine() : speaker(0), offset(0) {}
+};
+
struct Description {
byte itemId;
byte index;
@@ -147,20 +161,22 @@ enum GameState {
PROMOTE = 107,
};
-// struct rectCam
-// {
-// Common::List<int> vecinos;
-// bool marked;
-// int index;
-// int x;
-// int y;
-// int w;
-// int h;
-// };
-
-// struct defCam
-// {
-// rectCam cams[];
+// enum ConversationMarkers : byte {
+// END_LINE(0xFD),
+// TEXT_TERM(0xFC),
+// CHOICE(0xFB),
+// SKIP(0xFA),
+// PAGE_BREAK(0xF9),
+// ACTION(0xF8),
+// END_BRANCH(0xF7),
+// LINE_CONT(0xF6),
+// END_BRANCH_2(0xF5),
+// END_CONV(0xF4),
+// GO_BACK(0xF0),
+// END_BRANCH_3(0xFE),
+// END_ALT(0xEB),
+// DESC_START(0xFF),
+// SPEAKER(0x08)
// };
} // End of namespace Pelrock
Commit: 1647b7d852a993cc3b12a35174192c16d5bd0ea2
https://github.com/scummvm/scummvm/commit/1647b7d852a993cc3b12a35174192c16d5bd0ea2
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:03+02:00
Commit Message:
PELROCK: Reads conversations correctly into a tree
Changed paths:
engines/pelrock/fonts/large_font.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index 0e41a4dd812..9f94f855921 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -52,11 +52,10 @@ int LargeFont::getCharWidth(uint32 chr) const {
void LargeFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
chr -= 32; // Adjust for font starting at ASCII 32
- if (!_fontData || chr > 255 || chr < 0) {
+ if (!_fontData || chr > 96 || chr < 0) {
return;
}
int charOffset = chr * 0x30;
-
for (int i = 0; i < 24; i++) {
byte rowByte1 = _fontData[charOffset + i * 2];
byte rowByte2 = _fontData[charOffset + i * 2 + 1];
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 4dca90ae336..28c8aa3bc8c 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -414,35 +414,6 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
return descriptions;
}
-bool isControlByte(byte b) {
- // 0xFD: 'END_LINE',
- // 0xFC: 'TEXT_TERM',
- // 0xFB: 'CHOICE',
- // 0xFA: 'SKIP',
- // 0xF9: 'PAGE_BREAK',
- // 0xF8: 'ACTION',
- // 0xF7: 'END_BRANCH',
- // 0xF6: 'LINE_CONT',
- // 0xF5: 'END_BRANCH_2',
- // 0xF4: 'END_CONV',
- // 0xF1: 'CHOICE_ALT',
- // 0xF0: 'GO_BACK',
- // 0xFE: 'END_BRANCH_3',
- // 0xEB: 'END_ALT',
- // 0xFF: 'DESC_START',
- // 0x08: 'SPEAKER',
- if (b == 0xFD || b == 0xFC || b == 0xFB || b == 0xFA || b == 0xF9 || b == 0xF8 ||
- b == 0xF7 || b == 0xF6 || b == 0xF5 || b == 0xF4 || b == 0xF1 ||
- b == 0xF0 || b == 0xFE || b == 0xEB || b == 0xFF || b == 0x08) {
- return true;
- }
- return false;
-}
-
-bool isTerminalByte(byte b) {
- return (b == 0xFD || b == 0xF4 || b == 0xEB || b == 0xF7 || b == 0xF5 || b == 0xFE || b == 0xFC);
-}
-
/**
* def decode_byte(b):
@@ -461,25 +432,25 @@ bool isTerminalByte(byte b) {
*/
char32_t decodeByte(byte b) {
if ( b == 0x80) {
- return 'n';
+ return '\xA4';
} else if (b == 0x81) {
- return 'i';
+ return '\xA1';
} else if (b == 0x82) {
- return 'X';
+ return '\xAD';
} else if (b == 0x83) {
- return 'X';
+ return '\xA8';
} else if (b == 0x84) {
- return 'u';
+ return '\xA3';
} else if (b == 0x7B) {
- return 'a';
+ return '\xA0';
} else if (b == 0x7C) {
- return 'e';
+ return '\x82';
} else if (b == 0x7D) {
- return 'i';
+ return '\xA1';
} else if (b == 0x7E) {
- return 'o';
+ return '\xA2';
} else if (b == 0x7F) {
- return 'u';
+ return '\xA3';
} else if (b >= 0x20 && b <= 0x7A) {
return (char)b;
} else {
@@ -489,8 +460,23 @@ char32_t decodeByte(byte b) {
}
+void PelrockEngine::talk() {
+ if(_currentRoomConversations.size() == 0)
+ return;
+ int x = _currentRoomHotspots[0].x;
+ int y = _currentRoomHotspots[0].y;
+ debug("Say %s", _currentRoomConversations[0].text.c_str());
+ showDescription(_currentRoomConversations[0].text, x, y, _currentRoomConversations[0].speakerId);
+ for(int i = 0; i < _currentRoomConversations[0].choices.size(); i++) {
+ int idx = _currentRoomConversations.size() - 1 - i;
+ _smallFont->drawString(_screen, _currentRoomConversations[0].choices[idx].text.c_str(), 0, 400 - ((i + 1) * 12), 640, 14);
+ }
+
+
+}
+
Common::String PelrockEngine::getControlName(byte b) {
- switch (b) {
+ switch (b) {
case 0xFD: return "END_LINE";
case 0xFC: return "TEXT_TERM";
case 0xFB: return "CHOICE";
@@ -511,87 +497,378 @@ Common::String PelrockEngine::getControlName(byte b) {
}
}
-Common::Array<ConversationLine> PelrockEngine::loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos) {
- Common::Array<ConversationLine> conversations;
+Common::String PelrockEngine::cleanText(const Common::String &text) {
+ Common::String cleaned = text;
- debug("Loading conversations starting at position %d", startPos);
+ // Trim leading/trailing whitespace
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ while (!cleaned.empty() && Common::isSpace(cleaned.lastChar())) {
+ cleaned.deleteLastChar();
+ }
- uint32_t pair12_offset_pos = roomOffset + (12 * 8);
- roomFile->seek(pair12_offset_pos, SEEK_SET);
- uint32_t pair12_data_offset = roomFile->readUint32LE();
- uint32_t pair12_size = roomFile->readUint32LE();
+ // Remove leading [XX][00] patterns
+ while (!cleaned.empty() && cleaned.contains('[')) {
+ uint idx = 0;
+ for (uint i = 0; i < cleaned.size() && i < 15; i++) {
+ if (cleaned[i] == '[') {
+ idx = i;
+ break;
+ }
+ }
- startPos += 2;
- uint32_t conversation_start = pair12_data_offset + startPos;
- uint32_t conversation_size = pair12_size - startPos;
+ if (idx < 10) {
+ int endIdx = -1;
+ for (uint i = idx; i < cleaned.size() && i < idx + 10; i++) {
+ if (cleaned[i] == ']') {
+ endIdx = i;
+ break;
+ }
+ }
- roomFile->seek(conversation_start, SEEK_SET);
- byte *data = new byte[conversation_size];
- roomFile->read(data, conversation_size);
+ if (endIdx > (int)idx && endIdx < (int)idx + 10) {
+ cleaned = cleaned.c_str() + endIdx + 1;
+ // Trim leading whitespace again
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
- uint32_t i = 0;
- int lineNum = 1;
-
- while (i < conversation_size) {
- uint32_t lineStart = i;
- ConversationLine line;
- line.offset = startPos + lineStart;
- line.speaker = 0;
-
- // Read until we hit an end marker
- while (i < conversation_size) {
- byte b = data[i];
-
- if (b == 0x08) { // SPEAKER
- i++;
- if (i < conversation_size) {
- line.speaker = data[i];
- line.controlBytes.push_back(Common::String::format("SPEAKER(0x%02X)", line.speaker));
- i++;
+ // Remove single leading control characters
+ if (cleaned.size() > 1) {
+ byte first = (byte)cleaned[0];
+ byte second = (byte)cleaned[1];
+
+ if ((first == 'A' || first == 'H') &&
+ (Common::isUpper(second) || second == 0x83 || second == 0x82 || second == '[')) {
+ cleaned.deleteChar(0);
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ } else if (strchr("#%')!+,.-\"*&$(/", first)) {
+ cleaned.deleteChar(0);
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ }
+ }
+
+ return cleaned;
+}
+
+Common::Array<ConversationElement> PelrockEngine::parseConversationElements(const byte *convData, uint32 size) {
+ Common::Array<ConversationElement> elements;
+ Common::HashMap<int, int> choiceIndices; // Track choice index occurrences
+ uint32 pos = 0;
+
+ // First pass: parse elements and track choice indices
+ while (pos < size) {
+ byte b = convData[pos];
+
+ if (b == 0x08) { // SPEAKER
+ pos++;
+ if (pos < size) {
+ byte speakerId = convData[pos];
+ Common::String speaker = (speakerId == 0x0D) ? "ALFRED" : "NPC";
+ pos++;
+
+ // Read text
+ Common::String text;
+ while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
+ convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
+ convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
+ convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
+ convData[pos] != 0xF0) {
+ char32_t ch = decodeByte(convData[pos]);
+ if (ch != '.') {
+ text += ch;
+ }
+ pos++;
}
- continue;
- } else if (isControlByte(b)) {
- line.controlBytes.push_back(Common::String::format("%s(0x%02X)",
- getControlName(b).c_str(), b));
- i++;
-
- // Check for end markers
- if (isTerminalByte(b)) {
- break;
+
+ text = cleanText(text);
+ if (!text.empty()) {
+ ConversationElement elem;
+ elem.type = ConversationElement::DIALOGUE;
+ elem.speakerId = speakerId;
+ elem.speaker = speaker;
+ elem.text = text;
+ elem.choiceIndex = -1;
+ elements.push_back(elem);
}
- } else {
- // Regular text character
- if (b != 0x00) {
- line.text += decodeByte(b);
+ }
+ } else if (b == 0xFB || b == 0xF1) { // CHOICE marker
+ pos++;
+ int choiceIndex = -1;
+ if (pos < size) {
+ choiceIndex = convData[pos];
+ // Track this choice index
+ if (choiceIndices.contains(choiceIndex)) {
+ choiceIndices[choiceIndex]++;
+ } else {
+ choiceIndices[choiceIndex] = 1;
+ }
+ pos++;
+ }
+
+ // Skip next 2 bytes (speaker marker)
+ if (pos < size) pos++;
+ if (pos < size) pos++;
+
+ // Read text
+ Common::String text;
+ while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
+ convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
+ convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
+ convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
+ convData[pos] != 0xF0) {
+ char32_t ch = decodeByte(convData[pos]);
+ if (ch != '.') {
+ text += ch;
}
- i++;
+ pos++;
+ }
+
+ text = cleanText(text);
+ if (!text.empty()) {
+ ConversationElement elem;
+ elem.type = ConversationElement::CHOICE_MARKER;
+ elem.text = text;
+ elem.choiceIndex = choiceIndex;
+ elements.push_back(elem);
}
+ } else if (b == 0xF8) { // ACTION
+ pos += 3;
+ } else if (b == 0xF4) { // END_CONV
+ ConversationElement elem;
+ elem.type = ConversationElement::END_CONV;
+ elements.push_back(elem);
+ pos++;
+ } else if (b == 0xF7) { // END_BRANCH
+ ConversationElement elem;
+ elem.type = ConversationElement::END_BRANCH;
+ elements.push_back(elem);
+ pos++;
+ } else if (b == 0xFD || b == 0xFC || b == 0xF5 || b == 0xFE || b == 0xEB || b == 0xF0) {
+ pos++;
+ } else {
+ pos++;
}
+ }
- // Store raw bytes for this line
- for (uint32_t j = lineStart; j < i && j < conversation_size; j++) {
- line.rawBytes.push_back(data[j]);
+ // Second pass: mark which indices are actual choices (appear multiple times)
+ for (uint i = 0; i < elements.size(); i++) {
+ if (elements[i].choiceIndex >= 0) {
+ elements[i].isRealChoice = (choiceIndices[elements[i].choiceIndex] > 1);
}
+ }
+
+ return elements;
+}
+
+Common::Array<ConversationNode> PelrockEngine::buildTreeStructure(const Common::Array<ConversationElement> &elements) {
+ Common::Array<ConversationNode> roots;
+ Common::Array<StackEntry> stack;
+ ConversationNode *currentRoot = nullptr;
+ uint i = 0;
+
+ while (i < elements.size()) {
+ const ConversationElement &elem = elements[i];
+
+ if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "NPC") {
+ if (stack.empty()) {
+ // New root conversation
+ ConversationNode root;
+ root.type = ConversationNode::ROOT;
+ root.text = elem.text;
+ roots.push_back(root);
+ currentRoot = &roots[roots.size() - 1];
+ } else {
+ // NPC response within a branch
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ ConversationNode response;
+ response.type = ConversationNode::RESPONSE;
+ response.speaker = "NPC";
+ response.speakerId = elem.speakerId;
+ response.text = elem.text;
+ parent->responses.push_back(response);
+ }
+ i++;
+
+ } else if (elem.type == ConversationElement::CHOICE_MARKER) {
+ if (elem.isRealChoice) {
+ // Real choice - player selects from menu
+ ConversationNode choiceNode;
+ choiceNode.type = ConversationNode::CHOICE;
+ choiceNode.text = elem.text;
+ choiceNode.choiceIndex = elem.choiceIndex;
+
+ // Find where to attach this choice
+ while (!stack.empty() && stack[stack.size() - 1].index >= elem.choiceIndex) {
+ stack.pop_back();
+ }
- // Only add line if it has content
- if (!line.text.empty() || line.controlBytes.size() > 0) {
- // debug("Line %d (offset %d): %s", lineNum, line.offset, line.text.c_str());
- if (line.controlBytes.size() > 0) {
- Common::String controls;
- for (uint k = 0; k < line.controlBytes.size(); k++) {
- if (k > 0) controls += ", ";
- controls += line.controlBytes[k];
+ if (!stack.empty()) {
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ parent->subchoices.push_back(choiceNode);
+
+ // Get pointer to the newly added choice
+ ConversationNode *newChoice = &parent->subchoices[parent->subchoices.size() - 1];
+
+ StackEntry entry;
+ entry.node = newChoice;
+ entry.index = elem.choiceIndex;
+ stack.push_back(entry);
+ } else {
+ if (currentRoot) {
+ currentRoot->choices.push_back(choiceNode);
+
+ // Get pointer to the newly added choice
+ ConversationNode *newChoice = ¤tRoot->choices[currentRoot->choices.size() - 1];
+
+ StackEntry entry;
+ entry.node = newChoice;
+ entry.index = elem.choiceIndex;
+ stack.push_back(entry);
+ }
}
- // debug(" Controls: %s", controls.c_str());
+ } else {
+ // Auto-dialogue - ALFRED just speaks
+ if (!stack.empty()) {
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ ConversationNode response;
+ response.type = ConversationNode::RESPONSE;
+ response.speaker = "ALFRED";
+ response.speakerId = 0x0D;
+ response.text = elem.text;
+ parent->responses.push_back(response);
+ }
+ }
+ i++;
+
+ } else if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "ALFRED") {
+ if (!stack.empty()) {
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ ConversationNode response;
+ response.type = ConversationNode::RESPONSE;
+ response.speaker = "ALFRED";
+ response.text = elem.text;
+ response.speakerId = 0x0D;
+ parent->responses.push_back(response);
}
- conversations.push_back(line);
- lineNum++;
+ i++;
+
+ } else if (elem.type == ConversationElement::END_CONV) {
+ if (!stack.empty()) {
+ stack[stack.size() - 1].node->terminated = true;
+ stack.pop_back();
+ }
+ i++;
+
+ } else if (elem.type == ConversationElement::END_BRANCH) {
+ stack.clear();
+ currentRoot = nullptr;
+ i++;
+
+ } else {
+ i++;
}
}
- delete[] data;
- debug("Loaded %d conversation lines", conversations.size());
- return conversations;
+ return roots;
+}
+
+Common::Array<ConversationNode> PelrockEngine::loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos) {
+
+ debug("Loading conversations starting at position %d", startPos);
+
+ uint32_t pair12_offset_pos = roomOffset + (12 * 8);
+ roomFile->seek(pair12_offset_pos, SEEK_SET);
+ uint32_t pair12_data_offset = roomFile->readUint32LE();
+ uint32_t pair12_size = roomFile->readUint32LE();
+
+ // startPos += 2;
+ uint32_t conversation_start = pair12_data_offset + startPos;
+ uint32_t conversation_size = pair12_size - startPos;
+
+ roomFile->seek(conversation_start, SEEK_SET);
+ byte *data = new byte[conversation_size];
+ roomFile->read(data, conversation_size);
+
+ Common::Array<ConversationElement> elements = parseConversationElements(data, conversation_size);
+ Common::Array<ConversationNode> roots = buildTreeStructure(elements);
+ return roots;
+
+ // uint32_t i = 0;
+ // int lineNum = 1;
+
+ // while (i < conversation_size) {
+ // uint32_t lineStart = i;
+ // ConversationLine line;
+ // line.offset = startPos + lineStart;
+ // line.speaker = 0;
+
+ // // Read until we hit an end marker
+ // while (i < conversation_size) {
+ // byte b = data[i];
+
+ // if (b == 0x08) { // SPEAKER
+ // i++;
+ // if (i < conversation_size) {
+ // line.speaker = data[i];
+ // line.controlBytes.push_back(Common::String::format("SPEAKER(0x%02X)", line.speaker));
+ // i++;
+ // }
+ // continue;
+ // } else if (isControlByte(b)) {
+ // line.controlBytes.push_back(Common::String::format("%s(0x%02X)",
+ // getControlName(b).c_str(), b));
+ // i++;
+
+ // // Check for end markers
+ // if (isTerminalByte(b)) {
+ // break;
+ // }
+ // } else {
+ // // Regular text character
+ // if (b != 0x00) {
+ // line.text += decodeByte(b);
+ // }
+ // i++;
+ // }
+ // }
+
+ // // Store raw bytes for this line
+ // for (uint32_t j = lineStart; j < i && j < conversation_size; j++) {
+ // line.rawBytes.push_back(data[j]);
+ // }
+
+ // // Only add line if it has content
+ // if (!line.text.empty() || line.controlBytes.size() > 0) {
+ // // debug("Line %d (offset %d): %s", lineNum, line.offset, line.text.c_str());
+ // if (line.controlBytes.size() > 0) {
+ // Common::String controls;
+ // for (uint k = 0; k < line.controlBytes.size(); k++) {
+ // if (k > 0) controls += ", ";
+ // controls += line.controlBytes[k];
+ // }
+ // // debug(" Controls: %s", controls.c_str());
+ // }
+ // conversations.push_back(line);
+ // lineNum++;
+ // }
+ // }
+
+ // delete[] data;
+ // debug("Loaded %d conversation lines", conversations.size());
+ // return conversations;
}
void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
@@ -599,14 +876,14 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
debug("After decsriptions, position is %d", outPos);
- Common::Array<ConversationLine> conversations = loadConversations(roomFile, roomOffset, outPos);
- for(int i = 0; i < conversations.size(); i++) {
- if( conversations[i].text.empty()) {
+ Common::Array<ConversationNode> roots = loadConversations(roomFile, roomOffset, outPos);
+ for(int i = 0; i < roots.size(); i++) {
+ if( roots[i].text.empty()) {
continue;
}
- debug("Conversation %d: %s", i, conversations[i].text.c_str());
+ debug("Conversation %d: %s", i, roots[i].text.c_str());
}
-
+ _currentRoomConversations = roots;
Common::List<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
@@ -1059,9 +1336,9 @@ void PelrockEngine::checkMouseClick(int x, int y) {
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
if (hotspotIndex != -1) {
- showDescription(_currentRoomDescriptions[hotspotIndex].text.c_str(), xAlfred, yAlfred, 13);
-
- changeCursor(HOTSPOT);
+ talk();
+ // showDescription(_currentRoomDescriptions[hotspotIndex].text.c_str(), xAlfred, yAlfred, 13);
+ // changeCursor(HOTSPOT);
}
}
@@ -1180,14 +1457,21 @@ Exit *PelrockEngine::isExitAtPoint(int x, int y) {
void PelrockEngine::showDescription(Common::String text, int x, int y, byte color) {
Common::Rect rect = _largeFont->getBoundingBox(text.c_str());
- if (x + rect.width() > 640) {
- x = 640 - rect.width();
+ if (x + 2 + rect.width() > 640) {
+ x = 640 - rect.width() - 2;
}
- if (y + rect.height() > 400) {
+ if (y + 2 + rect.height() > 400) {
y = 400 - rect.height();
}
- x = 0;
- y = 0;
+ if(x - 2 < 0) {
+ x = 2;
+ }
+ if(y - 2 < 0) {
+ y = 2;
+ }
+
+ x = 2;
+ y = 2;
if (_bgText != nullptr) {
putBackgroundSlice(x, y, 640, 400, _bgText);
delete[] _bgText;
@@ -1198,9 +1482,13 @@ void PelrockEngine::showDescription(Common::String text, int x, int y, byte colo
_bgText = grabBackgroundSlice(x, y, 640, 400);
_largeFont->drawString(_screen, text.c_str(), x - 1, y, 640, 0); // Left
+ _largeFont->drawString(_screen, text.c_str(), x - 2, y, 640, 0); // Left
_largeFont->drawString(_screen, text.c_str(), x + 1, y, 640, 0); // Right
+ _largeFont->drawString(_screen, text.c_str(), x + 2, y, 640, 0); // Right
_largeFont->drawString(_screen, text.c_str(), x, y - 1, 640, 0); // Top
+ _largeFont->drawString(_screen, text.c_str(), x, y - 2, 640, 0); // Top
_largeFont->drawString(_screen, text.c_str(), x, y + 1, 640, 0); // Bottom
+ _largeFont->drawString(_screen, text.c_str(), x, y + 2, 640, 0); // Bottom
// Draw main text on top
_largeFont->drawString(_screen, text.c_str(), x, y, 640, color);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 332090cf5f0..09c0a7b3587 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -69,7 +69,13 @@ private:
Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos);
- Common::Array<ConversationLine> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
+
+ Common::String cleanText(const Common::String &text);
+ Common::Array<ConversationElement> parseConversationElements(const byte *convData, uint32 size);
+ Common::Array<ConversationNode> buildTreeStructure(const Common::Array<ConversationElement> &elements);
+ Common::Array<ConversationNode> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
+
+ void talk();
Common::String getControlName(byte b);
void loadRoomMetadata(Common::File *roomFile, int roomOffset);
void loadCursors();
@@ -100,6 +106,8 @@ private:
Common::List<Exit> _currentRoomExits;
Common::List<WalkBox> _currentRoomWalkboxes;
Common::Array<Description> _currentRoomDescriptions;
+ Common::Array<ConversationNode> _currentRoomConversations;
+
int *_currentAnimFrames = nullptr;
int curAlfredFrame = 9;
uint16 mouseX = 0;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 9e648bef778..35514e2a7c5 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -126,14 +126,47 @@ struct HotSpot {
bool isEnabled = true;
};
-struct ConversationLine {
+struct ConversationElement {
+ enum Type {
+ DIALOGUE,
+ CHOICE_MARKER,
+ END_CONV,
+ END_BRANCH
+ } type;
+
+ Common::String speaker;
+ byte speakerId;
Common::String text;
- Common::Array<Common::String> controlBytes;
- byte speaker;
- uint32 offset;
- Common::Array<byte> rawBytes;
+ int choiceIndex;
+ bool isRealChoice;
- ConversationLine() : speaker(0), offset(0) {}
+ ConversationElement() : type(DIALOGUE), choiceIndex(-1), isRealChoice(false) {}
+};
+
+
+struct ConversationNode {
+ enum NodeType {
+ ROOT,
+ CHOICE,
+ RESPONSE
+ } type;
+
+ Common::String text;
+ Common::String speaker;
+ byte speakerId;
+ int choiceIndex;
+ bool terminated;
+
+ Common::Array<ConversationNode> choices;
+ Common::Array<ConversationNode> responses;
+ Common::Array<ConversationNode> subchoices;
+
+ ConversationNode() : type(ROOT), choiceIndex(-1), terminated(false) {}
+};
+
+struct StackEntry {
+ ConversationNode *node;
+ int index;
};
struct Description {
Commit: ae3266b3e1fc5666c020883a6458ae6ea7a6e9e8
https://github.com/scummvm/scummvm/commit/ae3266b3e1fc5666c020883a6458ae6ea7a6e9e8
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:03+02:00
Commit Message:
PELROCK: Split alfred frames
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 28c8aa3bc8c..c8014a6d8f2 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -154,7 +154,7 @@ void PelrockEngine::playIntro() {
}
void PelrockEngine::loadAnims() {
- loadMainCharacterAnims();
+ loadAlfredAnims();
}
const int EXPECTED_SIZE = 640 * 400;
@@ -406,7 +406,7 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
pos++;
}
debug("End of descriptions at position %d", pos);
- outPos = lastDescPos+1;
+ outPos = lastDescPos + 1;
delete[] data;
// for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
// debug("Room description: %s", i->c_str());
@@ -414,24 +414,23 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
return descriptions;
}
-
/**
* def decode_byte(b):
- """Decode a byte to character"""
- special = {
- 0x80: 'ñ', 0x81: 'Ã', 0x82: '¡', 0x83: '¿', 0x84: 'ú',
- 0x7B: 'á', 0x7C: 'é', 0x7D: 'Ã', 0x7E: 'ó', 0x7F: 'ú',
- }
-
- if b in special:
- return special[b]
- elif 0x20 <= b <= 0x7A:
- return chr(b)
- else:
- return f'[{b:02X}]'
+ """Decode a byte to character"""
+ special = {
+ 0x80: 'ñ', 0x81: 'Ã', 0x82: '¡', 0x83: '¿', 0x84: 'ú',
+ 0x7B: 'á', 0x7C: 'é', 0x7D: 'Ã', 0x7E: 'ó', 0x7F: 'ú',
+ }
+
+ if b in special:
+ return special[b]
+ elif 0x20 <= b <= 0x7A:
+ return chr(b)
+ else:
+ return f'[{b:02X}]'
*/
char32_t decodeByte(byte b) {
- if ( b == 0x80) {
+ if (b == 0x80) {
return '\xA4';
} else if (b == 0x81) {
return '\xA1';
@@ -457,418 +456,434 @@ char32_t decodeByte(byte b) {
// return string in format [XX]
return '.';
}
-
}
void PelrockEngine::talk() {
- if(_currentRoomConversations.size() == 0)
+ if (_currentRoomConversations.size() == 0)
return;
int x = _currentRoomHotspots[0].x;
int y = _currentRoomHotspots[0].y;
debug("Say %s", _currentRoomConversations[0].text.c_str());
- showDescription(_currentRoomConversations[0].text, x, y, _currentRoomConversations[0].speakerId);
- for(int i = 0; i < _currentRoomConversations[0].choices.size(); i++) {
- int idx = _currentRoomConversations.size() - 1 - i;
- _smallFont->drawString(_screen, _currentRoomConversations[0].choices[idx].text.c_str(), 0, 400 - ((i + 1) * 12), 640, 14);
- }
-
-
+ // showDescription(_currentRoomConversations[0].text, x, y, _currentRoomConversations[0].speakerId);
+ // for(int i = 0; i < _currentRoomConversations[0].choices.size(); i++) {
+ // int idx = _currentRoomConversations.size() - 1 - i;
+ // _smallFont->drawString(_screen, _currentRoomConversations[0].choices[idx].text.c_str(), 0, 400 - ((i + 1) * 12), 640, 14);
+ // }
}
Common::String PelrockEngine::getControlName(byte b) {
switch (b) {
- case 0xFD: return "END_LINE";
- case 0xFC: return "TEXT_TERM";
- case 0xFB: return "CHOICE";
- case 0xFA: return "SKIP";
- case 0xF9: return "PAGE_BREAK";
- case 0xF8: return "ACTION";
- case 0xF7: return "END_BRANCH";
- case 0xF6: return "LINE_CONT";
- case 0xF5: return "END_BRANCH_2";
- case 0xF4: return "END_CONV";
- case 0xF1: return "CHOICE_ALT";
- case 0xF0: return "GO_BACK";
- case 0xFE: return "END_BRANCH_3";
- case 0xEB: return "END_ALT";
- case 0xFF: return "DESC_START";
- case 0x08: return "SPEAKER";
- default: return Common::String::format("UNKNOWN(0x%02X)", b);
- }
+ case 0xFD:
+ return "END_LINE";
+ case 0xFC:
+ return "TEXT_TERM";
+ case 0xFB:
+ return "CHOICE";
+ case 0xFA:
+ return "SKIP";
+ case 0xF9:
+ return "PAGE_BREAK";
+ case 0xF8:
+ return "ACTION";
+ case 0xF7:
+ return "END_BRANCH";
+ case 0xF6:
+ return "LINE_CONT";
+ case 0xF5:
+ return "END_BRANCH_2";
+ case 0xF4:
+ return "END_CONV";
+ case 0xF1:
+ return "CHOICE_ALT";
+ case 0xF0:
+ return "GO_BACK";
+ case 0xFE:
+ return "END_BRANCH_3";
+ case 0xEB:
+ return "END_ALT";
+ case 0xFF:
+ return "DESC_START";
+ case 0x08:
+ return "SPEAKER";
+ default:
+ return Common::String::format("UNKNOWN(0x%02X)", b);
+ }
}
Common::String PelrockEngine::cleanText(const Common::String &text) {
- Common::String cleaned = text;
-
- // Trim leading/trailing whitespace
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- while (!cleaned.empty() && Common::isSpace(cleaned.lastChar())) {
- cleaned.deleteLastChar();
- }
-
- // Remove leading [XX][00] patterns
- while (!cleaned.empty() && cleaned.contains('[')) {
- uint idx = 0;
- for (uint i = 0; i < cleaned.size() && i < 15; i++) {
- if (cleaned[i] == '[') {
- idx = i;
- break;
- }
- }
-
- if (idx < 10) {
- int endIdx = -1;
- for (uint i = idx; i < cleaned.size() && i < idx + 10; i++) {
- if (cleaned[i] == ']') {
- endIdx = i;
- break;
- }
- }
-
- if (endIdx > (int)idx && endIdx < (int)idx + 10) {
- cleaned = cleaned.c_str() + endIdx + 1;
- // Trim leading whitespace again
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- // Remove single leading control characters
- if (cleaned.size() > 1) {
- byte first = (byte)cleaned[0];
- byte second = (byte)cleaned[1];
-
- if ((first == 'A' || first == 'H') &&
- (Common::isUpper(second) || second == 0x83 || second == 0x82 || second == '[')) {
- cleaned.deleteChar(0);
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- } else if (strchr("#%')!+,.-\"*&$(/", first)) {
- cleaned.deleteChar(0);
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- }
- }
-
- return cleaned;
+ Common::String cleaned = text;
+
+ // Trim leading/trailing whitespace
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ while (!cleaned.empty() && Common::isSpace(cleaned.lastChar())) {
+ cleaned.deleteLastChar();
+ }
+
+ // Remove leading [XX][00] patterns
+ while (!cleaned.empty() && cleaned.contains('[')) {
+ uint idx = 0;
+ for (uint i = 0; i < cleaned.size() && i < 15; i++) {
+ if (cleaned[i] == '[') {
+ idx = i;
+ break;
+ }
+ }
+
+ if (idx < 10) {
+ int endIdx = -1;
+ for (uint i = idx; i < cleaned.size() && i < idx + 10; i++) {
+ if (cleaned[i] == ']') {
+ endIdx = i;
+ break;
+ }
+ }
+
+ if (endIdx > (int)idx && endIdx < (int)idx + 10) {
+ cleaned = cleaned.c_str() + endIdx + 1;
+ // Trim leading whitespace again
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ // Remove single leading control characters
+ if (cleaned.size() > 1) {
+ byte first = (byte)cleaned[0];
+ byte second = (byte)cleaned[1];
+
+ if ((first == 'A' || first == 'H') &&
+ (Common::isUpper(second) || second == 0x83 || second == 0x82 || second == '[')) {
+ cleaned.deleteChar(0);
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ } else if (strchr("#%')!+,.-\"*&$(/", first)) {
+ cleaned.deleteChar(0);
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ }
+ }
+
+ return cleaned;
}
Common::Array<ConversationElement> PelrockEngine::parseConversationElements(const byte *convData, uint32 size) {
- Common::Array<ConversationElement> elements;
- Common::HashMap<int, int> choiceIndices; // Track choice index occurrences
- uint32 pos = 0;
-
- // First pass: parse elements and track choice indices
- while (pos < size) {
- byte b = convData[pos];
-
- if (b == 0x08) { // SPEAKER
- pos++;
- if (pos < size) {
- byte speakerId = convData[pos];
- Common::String speaker = (speakerId == 0x0D) ? "ALFRED" : "NPC";
- pos++;
-
- // Read text
- Common::String text;
- while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
- convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
- convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
- convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
- convData[pos] != 0xF0) {
- char32_t ch = decodeByte(convData[pos]);
- if (ch != '.') {
- text += ch;
- }
- pos++;
- }
-
- text = cleanText(text);
- if (!text.empty()) {
- ConversationElement elem;
- elem.type = ConversationElement::DIALOGUE;
+ Common::Array<ConversationElement> elements;
+ Common::HashMap<int, int> choiceIndices; // Track choice index occurrences
+ uint32 pos = 0;
+
+ // First pass: parse elements and track choice indices
+ while (pos < size) {
+ byte b = convData[pos];
+
+ if (b == 0x08) { // SPEAKER
+ pos++;
+ if (pos < size) {
+ byte speakerId = convData[pos];
+ Common::String speaker = (speakerId == 0x0D) ? "ALFRED" : "NPC";
+ pos++;
+
+ // Read text
+ Common::String text;
+ while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
+ convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
+ convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
+ convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
+ convData[pos] != 0xF0) {
+ char32_t ch = decodeByte(convData[pos]);
+ if (ch != '.') {
+ text += ch;
+ }
+ pos++;
+ }
+
+ text = cleanText(text);
+ if (!text.empty()) {
+ ConversationElement elem;
+ elem.type = ConversationElement::DIALOGUE;
elem.speakerId = speakerId;
- elem.speaker = speaker;
- elem.text = text;
- elem.choiceIndex = -1;
- elements.push_back(elem);
- }
- }
- } else if (b == 0xFB || b == 0xF1) { // CHOICE marker
- pos++;
- int choiceIndex = -1;
- if (pos < size) {
- choiceIndex = convData[pos];
- // Track this choice index
- if (choiceIndices.contains(choiceIndex)) {
- choiceIndices[choiceIndex]++;
- } else {
- choiceIndices[choiceIndex] = 1;
- }
- pos++;
- }
-
- // Skip next 2 bytes (speaker marker)
- if (pos < size) pos++;
- if (pos < size) pos++;
-
- // Read text
- Common::String text;
- while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
- convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
- convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
- convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
- convData[pos] != 0xF0) {
- char32_t ch = decodeByte(convData[pos]);
- if (ch != '.') {
- text += ch;
- }
- pos++;
- }
-
- text = cleanText(text);
- if (!text.empty()) {
- ConversationElement elem;
- elem.type = ConversationElement::CHOICE_MARKER;
- elem.text = text;
- elem.choiceIndex = choiceIndex;
- elements.push_back(elem);
- }
- } else if (b == 0xF8) { // ACTION
- pos += 3;
- } else if (b == 0xF4) { // END_CONV
- ConversationElement elem;
- elem.type = ConversationElement::END_CONV;
- elements.push_back(elem);
- pos++;
- } else if (b == 0xF7) { // END_BRANCH
- ConversationElement elem;
- elem.type = ConversationElement::END_BRANCH;
- elements.push_back(elem);
- pos++;
- } else if (b == 0xFD || b == 0xFC || b == 0xF5 || b == 0xFE || b == 0xEB || b == 0xF0) {
- pos++;
- } else {
- pos++;
- }
- }
-
- // Second pass: mark which indices are actual choices (appear multiple times)
- for (uint i = 0; i < elements.size(); i++) {
- if (elements[i].choiceIndex >= 0) {
- elements[i].isRealChoice = (choiceIndices[elements[i].choiceIndex] > 1);
- }
- }
-
- return elements;
+ elem.speaker = speaker;
+ elem.text = text;
+ elem.choiceIndex = -1;
+ elements.push_back(elem);
+ }
+ }
+ } else if (b == 0xFB || b == 0xF1) { // CHOICE marker
+ pos++;
+ int choiceIndex = -1;
+ if (pos < size) {
+ choiceIndex = convData[pos];
+ // Track this choice index
+ if (choiceIndices.contains(choiceIndex)) {
+ choiceIndices[choiceIndex]++;
+ } else {
+ choiceIndices[choiceIndex] = 1;
+ }
+ pos++;
+ }
+
+ // Skip next 2 bytes (speaker marker)
+ if (pos < size)
+ pos++;
+ if (pos < size)
+ pos++;
+
+ // Read text
+ Common::String text;
+ while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
+ convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
+ convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
+ convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
+ convData[pos] != 0xF0) {
+ char32_t ch = decodeByte(convData[pos]);
+ if (ch != '.') {
+ text += ch;
+ }
+ pos++;
+ }
+
+ text = cleanText(text);
+ if (!text.empty()) {
+ ConversationElement elem;
+ elem.type = ConversationElement::CHOICE_MARKER;
+ elem.text = text;
+ elem.choiceIndex = choiceIndex;
+ elements.push_back(elem);
+ }
+ } else if (b == 0xF8) { // ACTION
+ pos += 3;
+ } else if (b == 0xF4) { // END_CONV
+ ConversationElement elem;
+ elem.type = ConversationElement::END_CONV;
+ elements.push_back(elem);
+ pos++;
+ } else if (b == 0xF7) { // END_BRANCH
+ ConversationElement elem;
+ elem.type = ConversationElement::END_BRANCH;
+ elements.push_back(elem);
+ pos++;
+ } else if (b == 0xFD || b == 0xFC || b == 0xF5 || b == 0xFE || b == 0xEB || b == 0xF0) {
+ pos++;
+ } else {
+ pos++;
+ }
+ }
+
+ // Second pass: mark which indices are actual choices (appear multiple times)
+ for (uint i = 0; i < elements.size(); i++) {
+ if (elements[i].choiceIndex >= 0) {
+ elements[i].isRealChoice = (choiceIndices[elements[i].choiceIndex] > 1);
+ }
+ }
+
+ return elements;
}
Common::Array<ConversationNode> PelrockEngine::buildTreeStructure(const Common::Array<ConversationElement> &elements) {
- Common::Array<ConversationNode> roots;
- Common::Array<StackEntry> stack;
- ConversationNode *currentRoot = nullptr;
- uint i = 0;
-
- while (i < elements.size()) {
- const ConversationElement &elem = elements[i];
-
- if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "NPC") {
- if (stack.empty()) {
- // New root conversation
- ConversationNode root;
- root.type = ConversationNode::ROOT;
- root.text = elem.text;
- roots.push_back(root);
- currentRoot = &roots[roots.size() - 1];
- } else {
- // NPC response within a branch
- ConversationNode *parent = stack[stack.size() - 1].node;
- ConversationNode response;
- response.type = ConversationNode::RESPONSE;
- response.speaker = "NPC";
+ Common::Array<ConversationNode> roots;
+ Common::Array<StackEntry> stack;
+ ConversationNode *currentRoot = nullptr;
+ uint i = 0;
+
+ while (i < elements.size()) {
+ const ConversationElement &elem = elements[i];
+
+ if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "NPC") {
+ if (stack.empty()) {
+ // New root conversation
+ ConversationNode root;
+ root.type = ConversationNode::ROOT;
+ root.text = elem.text;
+ roots.push_back(root);
+ currentRoot = &roots[roots.size() - 1];
+ } else {
+ // NPC response within a branch
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ ConversationNode response;
+ response.type = ConversationNode::RESPONSE;
+ response.speaker = "NPC";
response.speakerId = elem.speakerId;
- response.text = elem.text;
- parent->responses.push_back(response);
- }
- i++;
-
- } else if (elem.type == ConversationElement::CHOICE_MARKER) {
- if (elem.isRealChoice) {
- // Real choice - player selects from menu
- ConversationNode choiceNode;
- choiceNode.type = ConversationNode::CHOICE;
- choiceNode.text = elem.text;
- choiceNode.choiceIndex = elem.choiceIndex;
-
- // Find where to attach this choice
- while (!stack.empty() && stack[stack.size() - 1].index >= elem.choiceIndex) {
- stack.pop_back();
- }
-
- if (!stack.empty()) {
- ConversationNode *parent = stack[stack.size() - 1].node;
- parent->subchoices.push_back(choiceNode);
-
- // Get pointer to the newly added choice
- ConversationNode *newChoice = &parent->subchoices[parent->subchoices.size() - 1];
-
- StackEntry entry;
- entry.node = newChoice;
- entry.index = elem.choiceIndex;
- stack.push_back(entry);
- } else {
- if (currentRoot) {
- currentRoot->choices.push_back(choiceNode);
-
- // Get pointer to the newly added choice
- ConversationNode *newChoice = ¤tRoot->choices[currentRoot->choices.size() - 1];
-
- StackEntry entry;
- entry.node = newChoice;
- entry.index = elem.choiceIndex;
- stack.push_back(entry);
- }
- }
- } else {
- // Auto-dialogue - ALFRED just speaks
- if (!stack.empty()) {
- ConversationNode *parent = stack[stack.size() - 1].node;
- ConversationNode response;
- response.type = ConversationNode::RESPONSE;
- response.speaker = "ALFRED";
- response.speakerId = 0x0D;
- response.text = elem.text;
- parent->responses.push_back(response);
- }
- }
- i++;
-
- } else if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "ALFRED") {
- if (!stack.empty()) {
- ConversationNode *parent = stack[stack.size() - 1].node;
- ConversationNode response;
- response.type = ConversationNode::RESPONSE;
- response.speaker = "ALFRED";
- response.text = elem.text;
+ response.text = elem.text;
+ parent->responses.push_back(response);
+ }
+ i++;
+
+ } else if (elem.type == ConversationElement::CHOICE_MARKER) {
+ if (elem.isRealChoice) {
+ // Real choice - player selects from menu
+ ConversationNode choiceNode;
+ choiceNode.type = ConversationNode::CHOICE;
+ choiceNode.text = elem.text;
+ choiceNode.choiceIndex = elem.choiceIndex;
+
+ // Find where to attach this choice
+ while (!stack.empty() && stack[stack.size() - 1].index >= elem.choiceIndex) {
+ stack.pop_back();
+ }
+
+ if (!stack.empty()) {
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ parent->subchoices.push_back(choiceNode);
+
+ // Get pointer to the newly added choice
+ ConversationNode *newChoice = &parent->subchoices[parent->subchoices.size() - 1];
+
+ StackEntry entry;
+ entry.node = newChoice;
+ entry.index = elem.choiceIndex;
+ stack.push_back(entry);
+ } else {
+ if (currentRoot) {
+ currentRoot->choices.push_back(choiceNode);
+
+ // Get pointer to the newly added choice
+ ConversationNode *newChoice = ¤tRoot->choices[currentRoot->choices.size() - 1];
+
+ StackEntry entry;
+ entry.node = newChoice;
+ entry.index = elem.choiceIndex;
+ stack.push_back(entry);
+ }
+ }
+ } else {
+ // Auto-dialogue - ALFRED just speaks
+ if (!stack.empty()) {
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ ConversationNode response;
+ response.type = ConversationNode::RESPONSE;
+ response.speaker = "ALFRED";
response.speakerId = 0x0D;
- parent->responses.push_back(response);
- }
- i++;
-
- } else if (elem.type == ConversationElement::END_CONV) {
- if (!stack.empty()) {
- stack[stack.size() - 1].node->terminated = true;
- stack.pop_back();
- }
- i++;
-
- } else if (elem.type == ConversationElement::END_BRANCH) {
- stack.clear();
- currentRoot = nullptr;
- i++;
-
- } else {
- i++;
- }
- }
-
- return roots;
+ response.text = elem.text;
+ parent->responses.push_back(response);
+ }
+ }
+ i++;
+
+ } else if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "ALFRED") {
+ if (!stack.empty()) {
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ ConversationNode response;
+ response.type = ConversationNode::RESPONSE;
+ response.speaker = "ALFRED";
+ response.text = elem.text;
+ response.speakerId = 0x0D;
+ parent->responses.push_back(response);
+ }
+ i++;
+
+ } else if (elem.type == ConversationElement::END_CONV) {
+ if (!stack.empty()) {
+ stack[stack.size() - 1].node->terminated = true;
+ stack.pop_back();
+ }
+ i++;
+
+ } else if (elem.type == ConversationElement::END_BRANCH) {
+ stack.clear();
+ currentRoot = nullptr;
+ i++;
+
+ } else {
+ i++;
+ }
+ }
+
+ return roots;
}
Common::Array<ConversationNode> PelrockEngine::loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos) {
- debug("Loading conversations starting at position %d", startPos);
+ debug("Loading conversations starting at position %d", startPos);
- uint32_t pair12_offset_pos = roomOffset + (12 * 8);
- roomFile->seek(pair12_offset_pos, SEEK_SET);
- uint32_t pair12_data_offset = roomFile->readUint32LE();
- uint32_t pair12_size = roomFile->readUint32LE();
+ uint32_t pair12_offset_pos = roomOffset + (12 * 8);
+ roomFile->seek(pair12_offset_pos, SEEK_SET);
+ uint32_t pair12_data_offset = roomFile->readUint32LE();
+ uint32_t pair12_size = roomFile->readUint32LE();
// startPos += 2;
- uint32_t conversation_start = pair12_data_offset + startPos;
- uint32_t conversation_size = pair12_size - startPos;
+ uint32_t conversation_start = pair12_data_offset + startPos;
+ uint32_t conversation_size = pair12_size - startPos;
- roomFile->seek(conversation_start, SEEK_SET);
- byte *data = new byte[conversation_size];
- roomFile->read(data, conversation_size);
+ roomFile->seek(conversation_start, SEEK_SET);
+ byte *data = new byte[conversation_size];
+ roomFile->read(data, conversation_size);
Common::Array<ConversationElement> elements = parseConversationElements(data, conversation_size);
Common::Array<ConversationNode> roots = buildTreeStructure(elements);
return roots;
- // uint32_t i = 0;
- // int lineNum = 1;
-
- // while (i < conversation_size) {
- // uint32_t lineStart = i;
- // ConversationLine line;
- // line.offset = startPos + lineStart;
- // line.speaker = 0;
-
- // // Read until we hit an end marker
- // while (i < conversation_size) {
- // byte b = data[i];
-
- // if (b == 0x08) { // SPEAKER
- // i++;
- // if (i < conversation_size) {
- // line.speaker = data[i];
- // line.controlBytes.push_back(Common::String::format("SPEAKER(0x%02X)", line.speaker));
- // i++;
- // }
- // continue;
- // } else if (isControlByte(b)) {
- // line.controlBytes.push_back(Common::String::format("%s(0x%02X)",
- // getControlName(b).c_str(), b));
- // i++;
-
- // // Check for end markers
- // if (isTerminalByte(b)) {
- // break;
- // }
- // } else {
- // // Regular text character
- // if (b != 0x00) {
- // line.text += decodeByte(b);
- // }
- // i++;
- // }
- // }
-
- // // Store raw bytes for this line
- // for (uint32_t j = lineStart; j < i && j < conversation_size; j++) {
- // line.rawBytes.push_back(data[j]);
- // }
-
- // // Only add line if it has content
- // if (!line.text.empty() || line.controlBytes.size() > 0) {
- // // debug("Line %d (offset %d): %s", lineNum, line.offset, line.text.c_str());
- // if (line.controlBytes.size() > 0) {
- // Common::String controls;
- // for (uint k = 0; k < line.controlBytes.size(); k++) {
- // if (k > 0) controls += ", ";
- // controls += line.controlBytes[k];
- // }
- // // debug(" Controls: %s", controls.c_str());
- // }
- // conversations.push_back(line);
- // lineNum++;
- // }
- // }
-
- // delete[] data;
- // debug("Loaded %d conversation lines", conversations.size());
- // return conversations;
+ // uint32_t i = 0;
+ // int lineNum = 1;
+
+ // while (i < conversation_size) {
+ // uint32_t lineStart = i;
+ // ConversationLine line;
+ // line.offset = startPos + lineStart;
+ // line.speaker = 0;
+
+ // // Read until we hit an end marker
+ // while (i < conversation_size) {
+ // byte b = data[i];
+
+ // if (b == 0x08) { // SPEAKER
+ // i++;
+ // if (i < conversation_size) {
+ // line.speaker = data[i];
+ // line.controlBytes.push_back(Common::String::format("SPEAKER(0x%02X)", line.speaker));
+ // i++;
+ // }
+ // continue;
+ // } else if (isControlByte(b)) {
+ // line.controlBytes.push_back(Common::String::format("%s(0x%02X)",
+ // getControlName(b).c_str(), b));
+ // i++;
+
+ // // Check for end markers
+ // if (isTerminalByte(b)) {
+ // break;
+ // }
+ // } else {
+ // // Regular text character
+ // if (b != 0x00) {
+ // line.text += decodeByte(b);
+ // }
+ // i++;
+ // }
+ // }
+
+ // // Store raw bytes for this line
+ // for (uint32_t j = lineStart; j < i && j < conversation_size; j++) {
+ // line.rawBytes.push_back(data[j]);
+ // }
+
+ // // Only add line if it has content
+ // if (!line.text.empty() || line.controlBytes.size() > 0) {
+ // // debug("Line %d (offset %d): %s", lineNum, line.offset, line.text.c_str());
+ // if (line.controlBytes.size() > 0) {
+ // Common::String controls;
+ // for (uint k = 0; k < line.controlBytes.size(); k++) {
+ // if (k > 0) controls += ", ";
+ // controls += line.controlBytes[k];
+ // }
+ // // debug(" Controls: %s", controls.c_str());
+ // }
+ // conversations.push_back(line);
+ // lineNum++;
+ // }
+ // }
+
+ // delete[] data;
+ // debug("Loaded %d conversation lines", conversations.size());
+ // return conversations;
}
void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
@@ -877,8 +892,8 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
debug("After decsriptions, position is %d", outPos);
Common::Array<ConversationNode> roots = loadConversations(roomFile, roomOffset, outPos);
- for(int i = 0; i < roots.size(); i++) {
- if( roots[i].text.empty()) {
+ for (int i = 0; i < roots.size(); i++) {
+ if (roots[i].text.empty()) {
continue;
}
debug("Conversation %d: %s", i, roots[i].text.c_str());
@@ -907,7 +922,6 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
Common::List<Exit> exits = loadExits(roomFile, roomOffset);
Common::List<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
-
debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
for (int i = 0; i < staticHotspots.size(); i++) {
HotSpot hotspot = staticHotspots[i];
@@ -915,14 +929,14 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
}
int walkboxCount = 0;
- for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
- // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
- _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
- _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
- _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- walkboxCount++;
- }
+ // for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
+ // // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
+ // _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
+ // _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ // _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
+ // _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ // walkboxCount++;
+ // }
_currentRoomAnims = anims;
_currentRoomHotspots = hotspots;
@@ -930,14 +944,14 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
_currentRoomWalkboxes = walkboxes;
_currentRoomDescriptions = descriptions;
- for (int i = 0; i < _currentRoomHotspots.size(); i++) {
- HotSpot hotspot = _currentRoomHotspots[i];
- // debug("Hotspot %d: x=%d y=%d w=%d h=%d type=%d enabled? %d desc=%s", i, hotspot.x, hotspot.y, hotspot.w, hotspot.h, hotspot.type, hotspot.isEnabled, _currentRoomDescriptions[i].text.c_str());
- _screen->drawLine(hotspot.x, hotspot.y, hotspot.x + hotspot.w, hotspot.y, 200 + i);
- _screen->drawLine(hotspot.x, hotspot.y + hotspot.h, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
- _screen->drawLine(hotspot.x, hotspot.y, hotspot.x, hotspot.y + hotspot.h, 200 + i);
- _screen->drawLine(hotspot.x + hotspot.w, hotspot.y, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
- }
+ // for (int i = 0; i < _currentRoomHotspots.size(); i++) {
+ // HotSpot hotspot = _currentRoomHotspots[i];
+ // // debug("Hotspot %d: x=%d y=%d w=%d h=%d type=%d enabled? %d desc=%s", i, hotspot.x, hotspot.y, hotspot.w, hotspot.h, hotspot.type, hotspot.isEnabled, _currentRoomDescriptions[i].text.c_str());
+ // _screen->drawLine(hotspot.x, hotspot.y, hotspot.x + hotspot.w, hotspot.y, 200 + i);
+ // _screen->drawLine(hotspot.x, hotspot.y + hotspot.h, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
+ // _screen->drawLine(hotspot.x, hotspot.y, hotspot.x, hotspot.y + hotspot.h, 200 + i);
+ // _screen->drawLine(hotspot.x + hotspot.w, hotspot.y, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
+ // }
}
void PelrockEngine::loadCursors() {
@@ -1045,7 +1059,16 @@ Common::Array<HotSpot> PelrockEngine::loadHotspots(Common::File *roomFile, int r
// roomFile->seek(hover_areas_start, SEEK_SET);
}
-void PelrockEngine::loadMainCharacterAnims() {
+void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight) {
+ for (int y = 0; y < frameHeight; y++) {
+ for (int x = 0; x < frameWidth; x++) {
+ unsigned int src_pos = (frameIndex * frameHeight * frameWidth) + (y * frameWidth) + x;
+ dest[y * frameWidth + x] = source[src_pos];
+ }
+ }
+}
+
+void PelrockEngine::loadAlfredAnims() {
Common::File alfred3;
if (!alfred3.open(Common::Path("ALFRED.3"))) {
error("Could not open ALFRED.3");
@@ -1062,7 +1085,38 @@ void PelrockEngine::loadMainCharacterAnims() {
uint32_t capacity = 3060 * 102;
unsigned char *pic = new unsigned char[capacity];
rleDecompress(bufferFile, alfred3Size, 0, alfred3Size, &pic);
- memcpy(standingAnim, pic, 3060 * 102);
+
+ for (int i = 0; i < 4; i++) {
+ standingAnimFrames[i] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
+
+ int prevWalkingFrames = 0;
+ int talkingFramesOffset = walkingAnimLengths[0] + walkingAnimLengths[1] + walkingAnimLengths[2] + walkingAnimLengths[3];
+ int prevTalkingFrames = 0;
+ for (int j = 0; j < i; j++) {
+ prevWalkingFrames += walkingAnimLengths[j] + 1;
+ prevTalkingFrames += talkingFramesOffset + talkingAnimLengths[j];
+ }
+ walkingAnimFrames[i] = new byte *[walkingAnimLengths[i]];
+
+ int standingFrame = prevWalkingFrames;
+ debug("Loading standing frame %d at index %d", i, standingFrame);
+ extractSingleFrame(pic, standingAnimFrames[i], standingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ for (int j = 0; j < walkingAnimLengths[i]; j++) {
+
+ walkingAnimFrames[i][j] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
+ int walkingFrame = prevWalkingFrames + 1 + j;
+ extractSingleFrame(pic, walkingAnimFrames[i][j], walkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ }
+
+ talkingAnimFrames[i] = new byte *[talkingAnimLengths[i]];
+
+ int talkingStartFrame = prevWalkingFrames + 1 + walkingAnimLengths[i];
+ for (int j = 0; j < talkingAnimLengths[i]; j++) {
+ talkingAnimFrames[i][j] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
+ int talkingFrame = talkingStartFrame + j;
+ extractSingleFrame(pic, talkingAnimFrames[i][j], talkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ }
+ }
}
byte *PelrockEngine::grabBackgroundSlice(int x, int y, int w, int h) {
@@ -1169,10 +1223,10 @@ void PelrockEngine::frames() {
for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
- unsigned int src_pos = (curAlfredFrame * kAlfredFrameHeight * kAlfredFrameWidth) + (y * kAlfredFrameWidth) + x;
+ unsigned int src_pos = (y * kAlfredFrameWidth) + x;
// debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
- if (standingAnim[src_pos] != 255)
- _screen->setPixel(x + xAlfred, y + yAlfred, standingAnim[src_pos]);
+ if (standingAnimFrames[dirAlfred][src_pos] != 255)
+ _screen->setPixel(x + xAlfred, y + yAlfred, standingAnimFrames[dirAlfred][src_pos]);
}
}
@@ -1463,10 +1517,10 @@ void PelrockEngine::showDescription(Common::String text, int x, int y, byte colo
if (y + 2 + rect.height() > 400) {
y = 400 - rect.height();
}
- if(x - 2 < 0) {
+ if (x - 2 < 0) {
x = 2;
}
- if(y - 2 < 0) {
+ if (y - 2 < 0) {
y = 2;
}
@@ -1501,6 +1555,7 @@ void PelrockEngine::setScreen(int number, int dir) {
error("Could not open ALFRED.1");
return;
}
+ dirAlfred = dir;
int roomOffset = number * kRoomStructSize;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 09c0a7b3587..c26c380e890 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -63,7 +63,7 @@ private:
// Room data
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
- void loadMainCharacterAnims();
+ void loadAlfredAnims();
Common::List<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
@@ -71,7 +71,7 @@ private:
Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos);
Common::String cleanText(const Common::String &text);
- Common::Array<ConversationElement> parseConversationElements(const byte *convData, uint32 size);
+ Common::Array<ConversationElement> parseConversationElements(const byte *convData, uint32 size);
Common::Array<ConversationNode> buildTreeStructure(const Common::Array<ConversationElement> &elements);
Common::Array<ConversationNode> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
@@ -99,7 +99,14 @@ private:
void showActionBalloon(int posx, int posy, int curFrame);
ChronoManager *_chronoManager = nullptr;
- byte *standingAnim = new byte[3060 * 102];
+
+ // byte *standingAnim = new byte[3060 * 102];
+
+ byte **walkingAnimFrames[4]; // 4 arrays of arrays
+ byte *standingAnimFrames[4]; // 4 directions
+ int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+ byte **talkingAnimFrames[4]; // 4 arrays of arrays
+ int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
Common::Array<HotSpot> _currentRoomHotspots;
Common::List<HoverArea> _hoverAreas;
Common::List<AnimSet> _currentRoomAnims;
@@ -109,6 +116,10 @@ private:
Common::Array<ConversationNode> _currentRoomConversations;
int *_currentAnimFrames = nullptr;
+ // From the original code
+ int xAlfred = 200;
+ int yAlfred = 200;
+ int dirAlfred = 0;
int curAlfredFrame = 9;
uint16 mouseX = 0;
uint16 mouseY = 0;
@@ -132,14 +143,10 @@ private:
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
- // From the original code
- int xAlfred = 200;
- int yAlfred = 200;
bool shouldPlayIntro = false;
GameState stateGame = GAME;
bool gameInitialized = false;
bool screenReady = false;
- int dirAlfred = 0;
int prevDirX = 0;
int prevDirY = 0;
Common::String objectToShow = "";
Commit: 6850b9a42bb726ced827014c4d7a592cb230a9f3
https://github.com/scummvm/scummvm/commit/6850b9a42bb726ced827014c4d7a592cb230a9f3
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:04+02:00
Commit Message:
PELROCK: Displays walking and talking animations
Changed paths:
engines/pelrock/chrono.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 0adce498a89..1a5c902bced 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -26,7 +26,7 @@
namespace Pelrock {
// const int kTickMs = 20;
-const int kTickMs = 50;
+const int kTickMs = 200;
const int kHalfTickMultiplier = 2;
class ChronoManager {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index c8014a6d8f2..a58a333d374 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -64,6 +64,16 @@ PelrockEngine::~PelrockEngine() {
if (_bgPopupBalloon)
delete[] _bgPopupBalloon;
delete _smallFont;
+ for (int i = 0; i < 4; i++) {
+
+ // free all frame buffers
+ for (int j = 0; j < walkingAnimLengths[i]; j++) {
+ delete[] walkingAnimFrames[i][j];
+ }
+
+ // free the array of pointers
+ delete[] walkingAnimFrames[i];
+ }
}
uint32 PelrockEngine::getFeatures() const {
@@ -102,7 +112,18 @@ Common::Error PelrockEngine::run() {
while (!shouldQuit()) {
_chronoManager->updateChrono();
while (g_system->getEventManager()->pollEvent(e)) {
- if (e.type == Common::EVENT_MOUSEMOVE) {
+ if (e.type == Common::EVENT_KEYDOWN) {
+ if (e.kbd.keycode == Common::KEYCODE_w) {
+ isAlfredWalking = true;
+ isAlfredTalking = false;
+ } else if (e.kbd.keycode == Common::KEYCODE_t) {
+ isAlfredWalking = false;
+ isAlfredTalking = true;
+ } else if (e.kbd.keycode == Common::KEYCODE_s) {
+ isAlfredWalking = false;
+ isAlfredTalking = false;
+ }
+ } else if (e.type == Common::EVENT_MOUSEMOVE) {
mouseX = e.mouse.x;
mouseY = e.mouse.y;
// debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
@@ -124,9 +145,8 @@ Common::Error PelrockEngine::run() {
checkMouseHover();
frames();
_screen->update();
- limiter.delayBeforeSwap();
- _screen->update();
- limiter.startFrame();
+ // limiter.delayBeforeSwap();
+ // limiter.startFrame();
}
return Common::kNoError;
@@ -354,7 +374,7 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
int16 w = roomFile->readSint16LE();
int16 h = roomFile->readSint16LE();
byte flags = roomFile->readByte();
- // debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+ debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
WalkBox box;
box.x = x1;
box.y = y1;
@@ -920,6 +940,7 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
Common::List<Exit> exits = loadExits(roomFile, roomOffset);
+
Common::List<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
@@ -929,14 +950,6 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
}
int walkboxCount = 0;
- // for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
- // // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
- // _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
- // _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- // _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
- // _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- // walkboxCount++;
- // }
_currentRoomAnims = anims;
_currentRoomHotspots = hotspots;
@@ -952,6 +965,15 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
// _screen->drawLine(hotspot.x, hotspot.y, hotspot.x, hotspot.y + hotspot.h, 200 + i);
// _screen->drawLine(hotspot.x + hotspot.w, hotspot.y, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
// }
+
+ for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
+ debug("Exit: x=%d y=%d w=%d h=%d to room %d", i->x, i->y, i->w, i->h, i->targetRoom);
+ // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
+ // _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0);
+ // _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0);
+ // _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0);
+ // _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h);
+ }
}
void PelrockEngine::loadCursors() {
@@ -1088,14 +1110,16 @@ void PelrockEngine::loadAlfredAnims() {
for (int i = 0; i < 4; i++) {
standingAnimFrames[i] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
+ int talkingFramesOffset = walkingAnimLengths[0] + walkingAnimLengths[1] + walkingAnimLengths[2] + walkingAnimLengths[3] + 4;
int prevWalkingFrames = 0;
- int talkingFramesOffset = walkingAnimLengths[0] + walkingAnimLengths[1] + walkingAnimLengths[2] + walkingAnimLengths[3];
int prevTalkingFrames = 0;
+
for (int j = 0; j < i; j++) {
prevWalkingFrames += walkingAnimLengths[j] + 1;
- prevTalkingFrames += talkingFramesOffset + talkingAnimLengths[j];
+ prevTalkingFrames += talkingAnimLengths[j];
}
+
walkingAnimFrames[i] = new byte *[walkingAnimLengths[i]];
int standingFrame = prevWalkingFrames;
@@ -1110,7 +1134,7 @@ void PelrockEngine::loadAlfredAnims() {
talkingAnimFrames[i] = new byte *[talkingAnimLengths[i]];
- int talkingStartFrame = prevWalkingFrames + 1 + walkingAnimLengths[i];
+ int talkingStartFrame = talkingFramesOffset + prevTalkingFrames;
for (int j = 0; j < talkingAnimLengths[i]; j++) {
talkingAnimFrames[i][j] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
int talkingFrame = talkingStartFrame + j;
@@ -1179,9 +1203,8 @@ Common::List<VerbIcons> PelrockEngine::populateActionsMenu(HotSpot *hotspot) {
void PelrockEngine::frames() {
if (_chronoManager->_gameTick) {
-
+ debug("Game tick!");
int num = 0;
-
for (Common::List<AnimSet>::iterator i = _currentRoomAnims.begin(); i != _currentRoomAnims.end(); i++) {
// debug("Processing animation set %d, numAnims %d", num, i->numAnims);
if (i->numAnims == 0) {
@@ -1220,38 +1243,71 @@ void PelrockEngine::frames() {
}
}
num++;
+ }
- for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
- for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
- unsigned int src_pos = (y * kAlfredFrameWidth) + x;
- // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
- if (standingAnimFrames[dirAlfred][src_pos] != 255)
- _screen->setPixel(x + xAlfred, y + yAlfred, standingAnimFrames[dirAlfred][src_pos]);
- }
+ if (_bgAlfred != nullptr) {
+ putBackgroundSlice(xAlfred, yAlfred, kAlfredFrameWidth, kAlfredFrameHeight, _bgAlfred);
+ delete[] _bgAlfred;
+ _bgAlfred = nullptr;
+ }
+ _bgAlfred = grabBackgroundSlice(xAlfred, yAlfred, kAlfredFrameWidth, kAlfredFrameHeight);
+
+ if (isAlfredWalking) {
+ debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
+ drawAlfred(walkingAnimFrames[dirAlfred][curAlfredFrame]);
+ // for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
+ // for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
+ // unsigned int src_pos = (y * kAlfredFrameWidth) + x;
+ // // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
+ // if (walkingAnimFrames[dirAlfred][curAlfredFrame][src_pos] != 255)
+ // _screen->setPixel(x + xAlfred, y + yAlfred, standingAnimFrames[dirAlfred][src_pos]);
+ // }
+ // }
+ if (curAlfredFrame < walkingAnimLengths[dirAlfred] - 1) {
+ curAlfredFrame++;
+ } else {
+ curAlfredFrame = 0;
}
-
- if (_displayPopup) {
-
- // byte *bgDialog = new byte[kBalloonWidth * kBalloonHeight];
- // for (int j = 0; j < kBalloonWidth; j++) {
- // for (int i = 0; i < kBalloonHeight; i++) {
- // int idx = i * kBalloonWidth + j;
- // if (_popupY + i < 400 && _popupX + j < 640) {
- // *(bgDialog + idx) = _currentBackground[(_popupY + i) * 640 + (_popupX + j)];
- // }
- // }
- // }
- if (_bgPopupBalloon != nullptr) {
- putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
- }
- showActionBalloon(_popupX, _popupY, _currentPopupFrame);
- if (_currentPopupFrame < 3) {
- _currentPopupFrame++;
- } else
- _currentPopupFrame = 0;
+ debug("CurAlfredFrame from walking is now %d", curAlfredFrame);
+ } else if (isAlfredTalking) {
+ drawAlfred(talkingAnimFrames[dirAlfred][curAlfredFrame]);
+ if (curAlfredFrame < talkingAnimLengths[dirAlfred] - 1) {
+ curAlfredFrame++;
+ } else {
+ curAlfredFrame = 0;
+ }
+ debug("CurAlfredFrame from talking is now %d", curAlfredFrame);
+ } else {
+ drawAlfred(standingAnimFrames[dirAlfred]);
+ // for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
+ // for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
+ // unsigned int src_pos = (y * kAlfredFrameWidth) + x;
+ // // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
+ // if (standingAnimFrames[dirAlfred][src_pos] != 255)
+ // _screen->setPixel(x + xAlfred, y + yAlfred, standingAnimFrames[dirAlfred][src_pos]);
+ // }
+ // }
+ }
+ if (_displayPopup) {
+
+ // byte *bgDialog = new byte[kBalloonWidth * kBalloonHeight];
+ // for (int j = 0; j < kBalloonWidth; j++) {
+ // for (int i = 0; i < kBalloonHeight; i++) {
+ // int idx = i * kBalloonWidth + j;
+ // if (_popupY + i < 400 && _popupX + j < 640) {
+ // *(bgDialog + idx) = _currentBackground[(_popupY + i) * 640 + (_popupX + j)];
+ // }
+ // }
+ // }
+ if (_bgPopupBalloon != nullptr) {
+ putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
}
+ showActionBalloon(_popupX, _popupY, _currentPopupFrame);
+ if (_currentPopupFrame < 3) {
+ _currentPopupFrame++;
+ } else
+ _currentPopupFrame = 0;
}
-
int walkboxCount = 0;
for (Common::List<WalkBox>::iterator i = _currentRoomWalkboxes.begin(); i != _currentRoomWalkboxes.end(); i++) {
// _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
@@ -1266,6 +1322,17 @@ void PelrockEngine::frames() {
}
}
+void PelrockEngine::drawAlfred(byte *buf) {
+ for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
+ for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
+ unsigned int src_pos = (y * kAlfredFrameWidth) + x;
+ // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
+ if (buf[src_pos] != 255 && x + xAlfred >= 0 && y + yAlfred >= 0 && x + xAlfred < 640 && y + yAlfred < 400)
+ _screen->setPixel(x + xAlfred, y + yAlfred, buf[src_pos]);
+ }
+ }
+}
+
void PelrockEngine::checkLongMouseClick(int x, int y) {
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
if (hotspotIndex != -1) {
@@ -1558,7 +1625,7 @@ void PelrockEngine::setScreen(int number, int dir) {
dirAlfred = dir;
int roomOffset = number * kRoomStructSize;
-
+ curAlfredFrame = 0;
byte *palette = new byte[256 * 3];
getPalette(&roomFile, roomOffset, palette);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index c26c380e890..94761a47665 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -89,6 +89,7 @@ private:
// render loop
void frames();
+ void drawAlfred(byte *buf);
void checkMouseHover();
void checkMouseClick(int x, int y);
void checkLongMouseClick(int x, int y);
@@ -108,7 +109,6 @@ private:
byte **talkingAnimFrames[4]; // 4 arrays of arrays
int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
Common::Array<HotSpot> _currentRoomHotspots;
- Common::List<HoverArea> _hoverAreas;
Common::List<AnimSet> _currentRoomAnims;
Common::List<Exit> _currentRoomExits;
Common::List<WalkBox> _currentRoomWalkboxes;
@@ -120,7 +120,9 @@ private:
int xAlfred = 200;
int yAlfred = 200;
int dirAlfred = 0;
- int curAlfredFrame = 9;
+ int curAlfredFrame = 0;
+ bool isAlfredWalking = false;
+ bool isAlfredTalking = false;
uint16 mouseX = 0;
uint16 mouseY = 0;
byte *_currentBackground = nullptr;
@@ -133,6 +135,7 @@ private:
byte *_popUpBalloon = nullptr;
byte *_bgPopupBalloon = nullptr;
byte *_bgText = nullptr;
+ byte *_bgAlfred = nullptr;
bool _displayPopup = false;
int _popupX = 0;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 35514e2a7c5..d1bc429980c 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -108,12 +108,6 @@ struct AnimSet {
Anim *animData;
};
-struct HoverArea {
- int x;
- int y;
- int w;
- int h;
-};
struct HotSpot {
int id;
Commit: 0535b469a44adcbd44ef93a75227704a23edbb7b
https://github.com/scummvm/scummvm/commit/0535b469a44adcbd44ef93a75227704a23edbb7b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:04+02:00
Commit Message:
PELROCK: Properly refreshes scenes
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a58a333d374..8933a301f11 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -61,8 +61,8 @@ PelrockEngine::~PelrockEngine() {
}
delete[] _popUpBalloon;
- if (_bgPopupBalloon)
- delete[] _bgPopupBalloon;
+ // if (_bgPopupBalloon)
+ // delete[] _bgPopupBalloon;
delete _smallFont;
for (int i = 0; i < 4; i++) {
@@ -89,6 +89,7 @@ Common::Error PelrockEngine::run() {
initGraphics(640, 400);
_screen = new Graphics::Screen();
+
// Set the engine's debugger console
setDebugger(new Console());
@@ -155,6 +156,10 @@ Common::Error PelrockEngine::run() {
void PelrockEngine::init() {
loadCursors();
loadInteractionIcons();
+
+ _compositeBuffer = new byte[640 * 400];
+ _currentBackground = new byte[640 * 400];
+
_smallFont = new SmallFont();
_smallFont->load("ALFRED.4");
_largeFont = new LargeFont();
@@ -165,8 +170,9 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- // setScreen(0, 2);
- setScreen(2, 2);
+ setScreen(0, 2);
+ // setScreen(2, 2);
+ // setScreen(28, 0);
}
}
@@ -957,17 +963,17 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
_currentRoomWalkboxes = walkboxes;
_currentRoomDescriptions = descriptions;
- // for (int i = 0; i < _currentRoomHotspots.size(); i++) {
- // HotSpot hotspot = _currentRoomHotspots[i];
- // // debug("Hotspot %d: x=%d y=%d w=%d h=%d type=%d enabled? %d desc=%s", i, hotspot.x, hotspot.y, hotspot.w, hotspot.h, hotspot.type, hotspot.isEnabled, _currentRoomDescriptions[i].text.c_str());
- // _screen->drawLine(hotspot.x, hotspot.y, hotspot.x + hotspot.w, hotspot.y, 200 + i);
- // _screen->drawLine(hotspot.x, hotspot.y + hotspot.h, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
- // _screen->drawLine(hotspot.x, hotspot.y, hotspot.x, hotspot.y + hotspot.h, 200 + i);
- // _screen->drawLine(hotspot.x + hotspot.w, hotspot.y, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
- // }
+ for (int i = 0; i < _currentRoomHotspots.size(); i++) {
+ HotSpot hotspot = _currentRoomHotspots[i];
+ // debug("Hotspot %d: x=%d y=%d w=%d h=%d type=%d enabled? %d extra=%d, desc=%s", i, hotspot.x, hotspot.y, hotspot.w, hotspot.h, hotspot.type, hotspot.isEnabled, hotspot.extra, _currentRoomDescriptions[i].text.c_str());
+ _screen->drawLine(hotspot.x, hotspot.y, hotspot.x + hotspot.w, hotspot.y, 200 + i);
+ _screen->drawLine(hotspot.x, hotspot.y + hotspot.h, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
+ _screen->drawLine(hotspot.x, hotspot.y, hotspot.x, hotspot.y + hotspot.h, 200 + i);
+ _screen->drawLine(hotspot.x + hotspot.w, hotspot.y, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
+ }
for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
- debug("Exit: x=%d y=%d w=%d h=%d to room %d", i->x, i->y, i->w, i->h, i->targetRoom);
+ // debug("Exit: x=%d y=%d w=%d h=%d to room %d", i->x, i->y, i->w, i->h, i->targetRoom);
// _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
// _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0);
// _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0);
@@ -1164,6 +1170,30 @@ void PelrockEngine::putBackgroundSlice(int x, int y, int w, int h, byte *slice)
}
}
}
+
+// Helper function for transparent blitting
+void drawSpriteToBuffer(byte *buffer, int bufferWidth,
+ byte *sprite, int x, int y,
+ int width, int height,
+ int transparentColor) {
+ for (int py = 0; py < height; py++) {
+ for (int px = 0; px < width; px++) {
+ int srcIdx = py * width + px;
+ byte pixel = sprite[srcIdx];
+
+ if (pixel != transparentColor) {
+ int destX = x + px;
+ int destY = y + py;
+
+ if (destX >= 0 && destX < 640 &&
+ destY >= 0 && destY < 400) {
+ buffer[destY * bufferWidth + destX] = pixel;
+ }
+ }
+ }
+ }
+}
+
Common::List<VerbIcons> PelrockEngine::populateActionsMenu(HotSpot *hotspot) {
Common::List<VerbIcons> verbs;
debug("Populating actions menu for hotspot type %d", hotspot->type);
@@ -1203,16 +1233,15 @@ Common::List<VerbIcons> PelrockEngine::populateActionsMenu(HotSpot *hotspot) {
void PelrockEngine::frames() {
if (_chronoManager->_gameTick) {
+
+ memcpy(_compositeBuffer, _currentBackground, 640 * 400);
+
debug("Game tick!");
- int num = 0;
for (Common::List<AnimSet>::iterator i = _currentRoomAnims.begin(); i != _currentRoomAnims.end(); i++) {
// debug("Processing animation set %d, numAnims %d", num, i->numAnims);
- if (i->numAnims == 0) {
- num++;
- continue;
- }
- for (int j = 0; j < i->numAnims; j++) {
+ int j = 0;
+ // for (int j = 0; j < i->numAnims; j++) {
int x = i->animData[j].x;
int y = i->animData[j].y;
int w = i->animData[j].w;
@@ -1224,45 +1253,38 @@ void PelrockEngine::frames() {
Common::copy(i->animData[j].animData + (curFrame * i->h * i->w), i->animData[j].animData + (curFrame * i->h * i->w) + (frameSize), frame);
// debug("Current frame %d of %d", curFrame, i->animData[j].nframes);
- byte *bg = grabBackgroundSlice(x, y, w, h);
- putBackgroundSlice(x, y, w, h, bg);
- for (int y = 0; y < i->h; y++) {
- for (int x = 0; x < i->w; x++) {
-
- unsigned int src_pos = (y * i->w) + x;
- int xPos = i->x + x;
- int yPos = i->y + y;
- if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
- _screen->setPixel(xPos, yPos, frame[src_pos]);
- }
- }
+ // byte *bg = grabBackgroundSlice(x, y, w, h);
+ // putBackgroundSlice(x, y, w, h, bg);
+ drawSpriteToBuffer(_compositeBuffer, 640, frame, i->x, i->y, i->w, i->h, 255);
+ // for (int y = 0; y < i->h; y++) {
+ // for (int x = 0; x < i->w; x++) {
+
+ // unsigned int src_pos = (y * i->w) + x;
+ // int xPos = i->x + x;
+ // int yPos = i->y + y;
+ // if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
+ // _screen->setPixel(xPos, yPos, frame[src_pos]);
+ // }
+ // }
if (i->animData[j].curFrame < i->animData[j].nframes - 1) {
i->animData[j].curFrame++;
} else {
i->animData[j].curFrame = 0;
}
- }
- num++;
+ // }
}
- if (_bgAlfred != nullptr) {
- putBackgroundSlice(xAlfred, yAlfred, kAlfredFrameWidth, kAlfredFrameHeight, _bgAlfred);
- delete[] _bgAlfred;
- _bgAlfred = nullptr;
- }
- _bgAlfred = grabBackgroundSlice(xAlfred, yAlfred, kAlfredFrameWidth, kAlfredFrameHeight);
+ // if (_bgAlfred != nullptr) {
+ // putBackgroundSlice(xAlfred, yAlfred, kAlfredFrameWidth, kAlfredFrameHeight, _bgAlfred);
+ // delete[] _bgAlfred;
+ // _bgAlfred = nullptr;
+ // }
+ // _bgAlfred = grabBackgroundSlice(xAlfred, yAlfred, kAlfredFrameWidth, kAlfredFrameHeight);
if (isAlfredWalking) {
debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
drawAlfred(walkingAnimFrames[dirAlfred][curAlfredFrame]);
- // for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
- // for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
- // unsigned int src_pos = (y * kAlfredFrameWidth) + x;
- // // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
- // if (walkingAnimFrames[dirAlfred][curAlfredFrame][src_pos] != 255)
- // _screen->setPixel(x + xAlfred, y + yAlfred, standingAnimFrames[dirAlfred][src_pos]);
- // }
- // }
+
if (curAlfredFrame < walkingAnimLengths[dirAlfred] - 1) {
curAlfredFrame++;
} else {
@@ -1279,14 +1301,6 @@ void PelrockEngine::frames() {
debug("CurAlfredFrame from talking is now %d", curAlfredFrame);
} else {
drawAlfred(standingAnimFrames[dirAlfred]);
- // for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
- // for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
- // unsigned int src_pos = (y * kAlfredFrameWidth) + x;
- // // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
- // if (standingAnimFrames[dirAlfred][src_pos] != 255)
- // _screen->setPixel(x + xAlfred, y + yAlfred, standingAnimFrames[dirAlfred][src_pos]);
- // }
- // }
}
if (_displayPopup) {
@@ -1299,38 +1313,40 @@ void PelrockEngine::frames() {
// }
// }
// }
- if (_bgPopupBalloon != nullptr) {
- putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
- }
+ // if (_bgPopupBalloon != nullptr) {
+ // putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
+ // }
showActionBalloon(_popupX, _popupY, _currentPopupFrame);
if (_currentPopupFrame < 3) {
_currentPopupFrame++;
} else
_currentPopupFrame = 0;
}
- int walkboxCount = 0;
- for (Common::List<WalkBox>::iterator i = _currentRoomWalkboxes.begin(); i != _currentRoomWalkboxes.end(); i++) {
- // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
- _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
- _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
- _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- walkboxCount++;
- }
+ // int walkboxCount = 0;
+ // for (Common::List<WalkBox>::iterator i = _currentRoomWalkboxes.begin(); i != _currentRoomWalkboxes.end(); i++) {
+ // // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
+ // _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
+ // _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ // _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
+ // _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
+ // walkboxCount++;
+ // }
+ memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
_screen->markAllDirty();
- _screen->update();
+ // _screen->update();
}
}
void PelrockEngine::drawAlfred(byte *buf) {
- for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
- for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
- unsigned int src_pos = (y * kAlfredFrameWidth) + x;
- // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
- if (buf[src_pos] != 255 && x + xAlfred >= 0 && y + yAlfred >= 0 && x + xAlfred < 640 && y + yAlfred < 400)
- _screen->setPixel(x + xAlfred, y + yAlfred, buf[src_pos]);
- }
- }
+ // for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
+ // for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
+ // unsigned int src_pos = (y * kAlfredFrameWidth) + x;
+ // // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
+ // if (buf[src_pos] != 255 && x + xAlfred >= 0 && y + yAlfred >= 0 && x + xAlfred < 640 && y + yAlfred < 400)
+ // _screen->setPixel(x + xAlfred, y + yAlfred, buf[src_pos]);
+ // }
+ // }
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, xAlfred, yAlfred, kAlfredFrameWidth, kAlfredFrameHeight, 255);
}
void PelrockEngine::checkLongMouseClick(int x, int y) {
@@ -1338,10 +1354,10 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
if (hotspotIndex != -1) {
// _popupX = hotspot->x;
// _popupY = hotspot->y;
- if (_bgPopupBalloon != nullptr) {
- putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
- delete[] _bgPopupBalloon;
- }
+ // if (_bgPopupBalloon != nullptr) {
+ // putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
+ // delete[] _bgPopupBalloon;
+ // }
_popupX = x - kBalloonWidth / 2;
if (_popupX < 0)
_popupX = 0;
@@ -1357,7 +1373,7 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
_currentPopupFrame = 0;
_currentHotspot = &_currentRoomHotspots[hotspotIndex];
debug("Current hotspot type: %d", _currentHotspot->type);
- _bgPopupBalloon = grabBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight);
+ // _bgPopupBalloon = grabBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight);
}
}
@@ -1397,41 +1413,22 @@ AnimSet *PelrockEngine::isSpriteUnder(int x, int y) {
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
- for (uint32_t y = 0; y < kBalloonHeight; y++) {
- for (uint32_t x = 0; x < kBalloonWidth; x++) {
- unsigned int src_pos = (curFrame * kBalloonHeight * kBalloonWidth) + (y * kBalloonWidth) + x;
- if (_popUpBalloon[src_pos] != 255)
- _screen->setPixel(x + posx, y + posy, _popUpBalloon[src_pos]);
- }
- }
-
+ drawSpriteToBuffer(_compositeBuffer, 640, _popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
Common::List<VerbIcons> availableActions = populateActionsMenu(_currentHotspot);
// for (Common::List<VerbIcons>::iterator i = availableActions.begin(); i != availableActions.end(); i++) {
// debug("Verb icon to show: %d", *i);
// }
- for (uint32_t y = 0; y < kVerbIconHeight; y++) {
- for (uint32_t x = 0; x < kVerbIconWidth; x++) {
- unsigned int src_pos = y * kVerbIconWidth + x;
- if (_verbIcons[LOOK][src_pos] != 1)
- _screen->setPixel(x + posx + 20, y + posy + 20, _verbIcons[LOOK][src_pos]);
- }
- }
-
+ drawSpriteToBuffer(_compositeBuffer, 640, _verbIcons[LOOK], posx + 20, posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
for (Common::List<VerbIcons>::iterator i = availableActions.begin(); i != availableActions.end(); i++) {
VerbIcons verb = *i;
int index = 0;
for (Common::List<VerbIcons>::iterator j = availableActions.begin(); j != i; j++) {
index++;
}
- for (uint32_t y = 0; y < kVerbIconHeight; y++) {
- for (uint32_t x = 0; x < kVerbIconWidth; x++) {
- unsigned int src_pos = y * kVerbIconWidth + x;
- if (_verbIcons[verb][src_pos] != 1)
- _screen->setPixel(x + posx + 20 + (index * (kVerbIconWidth + 2)), y + posy + 20, _verbIcons[verb][src_pos]);
- }
- }
+ drawSpriteToBuffer(_compositeBuffer, 640, _verbIcons[verb], posx + 20 + (index * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
+
}
}
@@ -1439,11 +1436,11 @@ void PelrockEngine::checkMouseClick(int x, int y) {
_displayPopup = false;
_currentHotspot = nullptr;
- if (_bgPopupBalloon != nullptr) {
- putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
- delete[] _bgPopupBalloon;
- _bgPopupBalloon = nullptr;
- }
+ // if (_bgPopupBalloon != nullptr) {
+ // putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
+ // delete[] _bgPopupBalloon;
+ // _bgPopupBalloon = nullptr;
+ // }
Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
@@ -1458,6 +1455,7 @@ void PelrockEngine::checkMouseClick(int x, int y) {
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
if (hotspotIndex != -1) {
talk();
+ debug("Hotspot clicked: %d", _currentRoomHotspots[hotspotIndex].extra);
// showDescription(_currentRoomDescriptions[hotspotIndex].text.c_str(), xAlfred, yAlfred, 13);
// changeCursor(HOTSPOT);
}
@@ -1593,15 +1591,15 @@ void PelrockEngine::showDescription(Common::String text, int x, int y, byte colo
x = 2;
y = 2;
- if (_bgText != nullptr) {
- putBackgroundSlice(x, y, 640, 400, _bgText);
- delete[] _bgText;
- }
+ // if (_bgText != nullptr) {
+ // putBackgroundSlice(x, y, 640, 400, _bgText);
+ // delete[] _bgText;
+ // }
int16 w = MIN(rect.width(), (int16)(640 - x));
int16 h = MIN(rect.height(), (int16)(400 - y));
debug("grabbing bg slice at (%d,%d) w=%d h=%d", x, y, w, h);
- _bgText = grabBackgroundSlice(x, y, 640, 400);
+ // _bgText = grabBackgroundSlice(x, y, 640, 400);
_largeFont->drawString(_screen, text.c_str(), x - 1, y, 640, 0); // Left
_largeFont->drawString(_screen, text.c_str(), x - 2, y, 640, 0); // Left
_largeFont->drawString(_screen, text.c_str(), x + 1, y, 640, 0); // Right
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 94761a47665..e9bbf720bb5 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -82,6 +82,8 @@ private:
void loadInteractionIcons();
byte *grabBackgroundSlice(int x, int y, int w, int h);
void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
+
+
Common::List<VerbIcons> populateActionsMenu(HotSpot *hotspot);
Common::Point calculateWalkTarget(int mouseX, int mouseY);
Exit *isExitAtPoint(int x, int y);
@@ -108,6 +110,7 @@ private:
int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
byte **talkingAnimFrames[4]; // 4 arrays of arrays
int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+
Common::Array<HotSpot> _currentRoomHotspots;
Common::List<AnimSet> _currentRoomAnims;
Common::List<Exit> _currentRoomExits;
@@ -125,7 +128,6 @@ private:
bool isAlfredTalking = false;
uint16 mouseX = 0;
uint16 mouseY = 0;
- byte *_currentBackground = nullptr;
byte *_cursorMasks[5] = {nullptr};
uint32 _mouseDownTime;
@@ -133,9 +135,14 @@ private:
byte *_verbIcons[9] = {nullptr};
byte *_popUpBalloon = nullptr;
- byte *_bgPopupBalloon = nullptr;
- byte *_bgText = nullptr;
- byte *_bgAlfred = nullptr;
+
+ byte *_currentBackground; // Clean background - NEVER modified
+ byte *_compositeBuffer; // Working composition buffer
+
+ // byte *_currentBackground = nullptr;
+ // byte *_bgPopupBalloon = nullptr;
+ // byte *_bgText = nullptr;
+ // byte *_bgAlfred = nullptr;
bool _displayPopup = false;
int _popupX = 0;
Commit: 0a07291d3431a35d00f41a91c6fcecc426e0712b
https://github.com/scummvm/scummvm/commit/0a07291d3431a35d00f41a91c6fcecc426e0712b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:04+02:00
Commit Message:
PELROCK: Change list to array
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 8933a301f11..3a10a865267 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -89,7 +89,6 @@ Common::Error PelrockEngine::run() {
initGraphics(640, 400);
_screen = new Graphics::Screen();
-
// Set the engine's debugger console
setDebugger(new Console());
@@ -158,7 +157,7 @@ void PelrockEngine::init() {
loadInteractionIcons();
_compositeBuffer = new byte[640 * 400];
- _currentBackground = new byte[640 * 400];
+ _currentBackground = new byte[640 * 400];
_smallFont = new SmallFont();
_smallFont->load("ALFRED.4");
@@ -267,7 +266,7 @@ void PelrockEngine::getBackground(Common::File *roomFile, int roomOffset, byte *
}
}
-Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
+Common::Array<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
uint32_t pair_offset = roomOffset + (8 * 8);
// debug("Sprite pair offset position: %d", pair_offset);
roomFile->seek(pair_offset, SEEK_SET);
@@ -282,9 +281,9 @@ Common::List<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
if (offset > 0 && size > 0) {
rleDecompress(data, size, 0, size, &pic);
} else {
- return Common::List<AnimSet>();
+ return Common::Array<AnimSet>();
}
- Common::List<AnimSet> anims = Common::List<AnimSet>();
+ Common::Array<AnimSet> anims = Common::Array<AnimSet>();
uint32_t spriteEnd = offset + size;
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
@@ -926,20 +925,20 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
}
_currentRoomConversations = roots;
- Common::List<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
+ Common::Array<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
Common::Array<HotSpot> hotspots;
int count = 0;
- for (Common::List<AnimSet>::iterator i = anims.begin(); i != anims.end(); i++) {
+ for (int i = 0; i < anims.size(); i++) {
HotSpot thisHotspot;
- thisHotspot.x = i->x;
- thisHotspot.y = i->y;
- thisHotspot.w = i->w;
- thisHotspot.h = i->h;
- thisHotspot.extra = i->extra;
- thisHotspot.type = i->actionFlags;
- thisHotspot.isEnabled = !i->isDisabled;
+ thisHotspot.x = anims[i].x;
+ thisHotspot.y = anims[i].y;
+ thisHotspot.w = anims[i].w;
+ thisHotspot.h = anims[i].h;
+ thisHotspot.extra = anims[i].extra;
+ thisHotspot.type = anims[i].actionFlags;
+ thisHotspot.isEnabled = !anims[i].isDisabled;
hotspots.push_back(thisHotspot);
count++;
}
@@ -1234,44 +1233,43 @@ void PelrockEngine::frames() {
if (_chronoManager->_gameTick) {
- memcpy(_compositeBuffer, _currentBackground, 640 * 400);
+ memcpy(_compositeBuffer, _currentBackground, 640 * 400);
debug("Game tick!");
- for (Common::List<AnimSet>::iterator i = _currentRoomAnims.begin(); i != _currentRoomAnims.end(); i++) {
+ for (int i = 0; i < _currentRoomAnims.size(); i++) {
// debug("Processing animation set %d, numAnims %d", num, i->numAnims);
int j = 0;
- // for (int j = 0; j < i->numAnims; j++) {
- int x = i->animData[j].x;
- int y = i->animData[j].y;
- int w = i->animData[j].w;
- int h = i->animData[j].h;
-
- int frameSize = i->animData[j].w * i->animData[j].h;
- int curFrame = i->animData[j].curFrame;
- byte *frame = new byte[frameSize];
- Common::copy(i->animData[j].animData + (curFrame * i->h * i->w), i->animData[j].animData + (curFrame * i->h * i->w) + (frameSize), frame);
- // debug("Current frame %d of %d", curFrame, i->animData[j].nframes);
-
- // byte *bg = grabBackgroundSlice(x, y, w, h);
- // putBackgroundSlice(x, y, w, h, bg);
- drawSpriteToBuffer(_compositeBuffer, 640, frame, i->x, i->y, i->w, i->h, 255);
- // for (int y = 0; y < i->h; y++) {
- // for (int x = 0; x < i->w; x++) {
-
- // unsigned int src_pos = (y * i->w) + x;
- // int xPos = i->x + x;
- // int yPos = i->y + y;
- // if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
- // _screen->setPixel(xPos, yPos, frame[src_pos]);
- // }
- // }
- if (i->animData[j].curFrame < i->animData[j].nframes - 1) {
- i->animData[j].curFrame++;
- } else {
- i->animData[j].curFrame = 0;
- }
+
+ int x = _currentRoomAnims[i].animData[j].x;
+ int y = _currentRoomAnims[i].animData[j].y;
+ int w = _currentRoomAnims[i].animData[j].w;
+ int h = _currentRoomAnims[i].animData[j].h;
+
+ int frameSize = _currentRoomAnims[i].animData[j].w * _currentRoomAnims[i].animData[j].h;
+ int curFrame = _currentRoomAnims[i].animData[j].curFrame;
+ byte *frame = new byte[frameSize];
+ Common::copy(_currentRoomAnims[i].animData[j].animData + (curFrame * _currentRoomAnims[i].animData[j].h * _currentRoomAnims[i].animData[j].w), _currentRoomAnims[i].animData[j].animData + (curFrame * _currentRoomAnims[i].animData[j].h * _currentRoomAnims[i].animData[j].w) + (frameSize), frame);
+ // debug("Current frame %d of %d", curFrame, i->animData[j].nframes);
+
+ // byte *bg = grabBackgroundSlice(x, y, w, h);
+ // putBackgroundSlice(x, y, w, h, bg);
+ drawSpriteToBuffer(_compositeBuffer, 640, frame, _currentRoomAnims[i].x, _currentRoomAnims[i].y, _currentRoomAnims[i].w, _currentRoomAnims[i].h, 255);
+ // for (int y = 0; y < i->h; y++) {
+ // for (int x = 0; x < i->w; x++) {
+
+ // unsigned int src_pos = (y * i->w) + x;
+ // int xPos = i->x + x;
+ // int yPos = i->y + y;
+ // if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
+ // _screen->setPixel(xPos, yPos, frame[src_pos]);
+ // }
// }
+ if (_currentRoomAnims[i].animData[j].curFrame < _currentRoomAnims[i].animData[j].nframes - 1) {
+ _currentRoomAnims[i].animData[j].curFrame++;
+ } else {
+ _currentRoomAnims[i].animData[j].curFrame = 0;
+ }
}
// if (_bgAlfred != nullptr) {
@@ -1400,17 +1398,6 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
return nullptr;
}
-AnimSet *PelrockEngine::isSpriteUnder(int x, int y) {
- for (Common::List<AnimSet>::iterator i = _currentRoomAnims.begin(); i != _currentRoomAnims.end(); i++) {
- if (mouseX >= i->x && mouseX <= (i->x + i->w) &&
- mouseY >= i->y && mouseY <= (i->y + i->h)) {
- // debug("Sprite at (%d,%d) size (%d,%d), type = %d, extra = %d, enabled=%d", i->x, i->y, i->w, i->h, i->type, i->extra, i->enabled);
- return &(*i);
- }
- }
- return nullptr;
-}
-
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
@@ -1428,7 +1415,6 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
index++;
}
drawSpriteToBuffer(_compositeBuffer, 640, _verbIcons[verb], posx + 20 + (index * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
-
}
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index e9bbf720bb5..2cb9fe8393b 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -64,7 +64,7 @@ private:
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
void loadAlfredAnims();
- Common::List<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
+ Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
@@ -83,7 +83,6 @@ private:
byte *grabBackgroundSlice(int x, int y, int w, int h);
void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
-
Common::List<VerbIcons> populateActionsMenu(HotSpot *hotspot);
Common::Point calculateWalkTarget(int mouseX, int mouseY);
Exit *isExitAtPoint(int x, int y);
@@ -112,7 +111,7 @@ private:
int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
Common::Array<HotSpot> _currentRoomHotspots;
- Common::List<AnimSet> _currentRoomAnims;
+ Common::Array<AnimSet> _currentRoomAnims;
Common::List<Exit> _currentRoomExits;
Common::List<WalkBox> _currentRoomWalkboxes;
Common::Array<Description> _currentRoomDescriptions;
@@ -136,8 +135,8 @@ private:
byte *_verbIcons[9] = {nullptr};
byte *_popUpBalloon = nullptr;
- byte *_currentBackground; // Clean background - NEVER modified
- byte *_compositeBuffer; // Working composition buffer
+ byte *_currentBackground; // Clean background - NEVER modified
+ byte *_compositeBuffer; // Working composition buffer
// byte *_currentBackground = nullptr;
// byte *_bgPopupBalloon = nullptr;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index d1bc429980c..a9b6c632e08 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -102,6 +102,7 @@ struct AnimSet {
int h;//5
byte extra; //6
int numAnims; //8
+ int curAnimIndex;
byte spriteType; //33
byte actionFlags;//34
bool isDisabled; //38
Commit: 5ce6183800745b5d9052a52b76e26596bd86b27b
https://github.com/scummvm/scummvm/commit/5ce6183800745b5d9052a52b76e26596bd86b27b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:04+02:00
Commit Message:
PELROCK: Plays subanimations in order following control bytes
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 3a10a865267..7caabf4dcab 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1239,17 +1239,15 @@ void PelrockEngine::frames() {
for (int i = 0; i < _currentRoomAnims.size(); i++) {
// debug("Processing animation set %d, numAnims %d", num, i->numAnims);
- int j = 0;
+ int x = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].x;
+ int y = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].y;
+ int w = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w;
+ int h = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h;
- int x = _currentRoomAnims[i].animData[j].x;
- int y = _currentRoomAnims[i].animData[j].y;
- int w = _currentRoomAnims[i].animData[j].w;
- int h = _currentRoomAnims[i].animData[j].h;
-
- int frameSize = _currentRoomAnims[i].animData[j].w * _currentRoomAnims[i].animData[j].h;
- int curFrame = _currentRoomAnims[i].animData[j].curFrame;
+ int frameSize = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h;
+ int curFrame = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame;
byte *frame = new byte[frameSize];
- Common::copy(_currentRoomAnims[i].animData[j].animData + (curFrame * _currentRoomAnims[i].animData[j].h * _currentRoomAnims[i].animData[j].w), _currentRoomAnims[i].animData[j].animData + (curFrame * _currentRoomAnims[i].animData[j].h * _currentRoomAnims[i].animData[j].w) + (frameSize), frame);
+ Common::copy(_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].animData + (curFrame * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w), _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].animData + (curFrame * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w) + (frameSize), frame);
// debug("Current frame %d of %d", curFrame, i->animData[j].nframes);
// byte *bg = grabBackgroundSlice(x, y, w, h);
@@ -1265,10 +1263,22 @@ void PelrockEngine::frames() {
// _screen->setPixel(xPos, yPos, frame[src_pos]);
// }
// }
- if (_currentRoomAnims[i].animData[j].curFrame < _currentRoomAnims[i].animData[j].nframes - 1) {
- _currentRoomAnims[i].animData[j].curFrame++;
+ if (_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame < _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].nframes - 1) {
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame++;
} else {
- _currentRoomAnims[i].animData[j].curFrame = 0;
+ if(_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop < _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].loopCount - 1){
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame = 0;
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop++;
+ } else {
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame = 0;
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop = 0;
+ if(_currentRoomAnims[i].curAnimIndex < _currentRoomAnims[i].numAnims - 1){
+ _currentRoomAnims[i].curAnimIndex++;
+ }
+ else {
+ _currentRoomAnims[i].curAnimIndex = 0;
+ }
+ }
}
}
@@ -1291,6 +1301,7 @@ void PelrockEngine::frames() {
debug("CurAlfredFrame from walking is now %d", curAlfredFrame);
} else if (isAlfredTalking) {
drawAlfred(talkingAnimFrames[dirAlfred][curAlfredFrame]);
+
if (curAlfredFrame < talkingAnimLengths[dirAlfred] - 1) {
curAlfredFrame++;
} else {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index a9b6c632e08..2552fe5f975 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -75,7 +75,8 @@ struct Anim {
int w;
int h;
int nframes;
- int curFrame;
+ int curFrame = 0;
+ int curLoop = 0;
byte *animData;
byte loopCount;
byte speed;
@@ -102,7 +103,7 @@ struct AnimSet {
int h;//5
byte extra; //6
int numAnims; //8
- int curAnimIndex;
+ int curAnimIndex = 0;
byte spriteType; //33
byte actionFlags;//34
bool isDisabled; //38
Commit: c3c6f36c951cff99ece66fbcae492cd06ac0bab6
https://github.com/scummvm/scummvm/commit/c3c6f36c951cff99ece66fbcae492cd06ac0bab6
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:05+02:00
Commit Message:
PELROCK: Animation timing
Changed paths:
engines/pelrock/chrono.h
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 1a5c902bced..9dab952fadd 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -26,7 +26,7 @@
namespace Pelrock {
// const int kTickMs = 20;
-const int kTickMs = 200;
+const int kTickMs = 55;
const int kHalfTickMultiplier = 2;
class ChronoManager {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 7caabf4dcab..b49a2e55ffd 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1252,34 +1252,40 @@ void PelrockEngine::frames() {
// byte *bg = grabBackgroundSlice(x, y, w, h);
// putBackgroundSlice(x, y, w, h, bg);
- drawSpriteToBuffer(_compositeBuffer, 640, frame, _currentRoomAnims[i].x, _currentRoomAnims[i].y, _currentRoomAnims[i].w, _currentRoomAnims[i].h, 255);
- // for (int y = 0; y < i->h; y++) {
- // for (int x = 0; x < i->w; x++) {
-
- // unsigned int src_pos = (y * i->w) + x;
- // int xPos = i->x + x;
- // int yPos = i->y + y;
- // if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
- // _screen->setPixel(xPos, yPos, frame[src_pos]);
- // }
- // }
- if (_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame < _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].nframes - 1) {
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame++;
- } else {
- if(_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop < _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].loopCount - 1){
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame = 0;
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop++;
+
+ drawSpriteToBuffer(_compositeBuffer, 640, frame, _currentRoomAnims[i].x, _currentRoomAnims[i].y, _currentRoomAnims[i].w, _currentRoomAnims[i].h, 255);
+ // for (int y = 0; y < i->h; y++) {
+ // for (int x = 0; x < i->w; x++) {
+
+ // unsigned int src_pos = (y * i->w) + x;
+ // int xPos = i->x + x;
+ // int yPos = i->y + y;
+ // if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
+ // _screen->setPixel(xPos, yPos, frame[src_pos]);
+ // }
+ // }
+ if (_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].elpapsedFrames == _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].speed) {
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].elpapsedFrames = 0;
+ if (_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame < _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].nframes - 1) {
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame++;
} else {
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame = 0;
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop = 0;
- if(_currentRoomAnims[i].curAnimIndex < _currentRoomAnims[i].numAnims - 1){
- _currentRoomAnims[i].curAnimIndex++;
- }
- else {
- _currentRoomAnims[i].curAnimIndex = 0;
+ if (_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop < _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].loopCount - 1) {
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame = 0;
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop++;
+ } else {
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame = 0;
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop = 0;
+ if (_currentRoomAnims[i].curAnimIndex < _currentRoomAnims[i].numAnims - 1) {
+ _currentRoomAnims[i].curAnimIndex++;
+ } else {
+ _currentRoomAnims[i].curAnimIndex = 0;
+ }
}
}
}
+ else {
+ _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].elpapsedFrames++;
+ }
}
// if (_bgAlfred != nullptr) {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 2552fe5f975..4f56d8d5393 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -80,6 +80,7 @@ struct Anim {
byte *animData;
byte loopCount;
byte speed;
+ byte elpapsedFrames = 0;
};
struct Exit {
Commit: 7e0d3a6bad0427f0a5fee894fb0e7695f074c683
https://github.com/scummvm/scummvm/commit/7e0d3a6bad0427f0a5fee894fb0e7695f074c683
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:05+02:00
Commit Message:
PELROCK: Walk target calculation
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b49a2e55ffd..0b1990ac05e 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -845,70 +845,6 @@ Common::Array<ConversationNode> PelrockEngine::loadConversations(Common::File *r
Common::Array<ConversationElement> elements = parseConversationElements(data, conversation_size);
Common::Array<ConversationNode> roots = buildTreeStructure(elements);
return roots;
-
- // uint32_t i = 0;
- // int lineNum = 1;
-
- // while (i < conversation_size) {
- // uint32_t lineStart = i;
- // ConversationLine line;
- // line.offset = startPos + lineStart;
- // line.speaker = 0;
-
- // // Read until we hit an end marker
- // while (i < conversation_size) {
- // byte b = data[i];
-
- // if (b == 0x08) { // SPEAKER
- // i++;
- // if (i < conversation_size) {
- // line.speaker = data[i];
- // line.controlBytes.push_back(Common::String::format("SPEAKER(0x%02X)", line.speaker));
- // i++;
- // }
- // continue;
- // } else if (isControlByte(b)) {
- // line.controlBytes.push_back(Common::String::format("%s(0x%02X)",
- // getControlName(b).c_str(), b));
- // i++;
-
- // // Check for end markers
- // if (isTerminalByte(b)) {
- // break;
- // }
- // } else {
- // // Regular text character
- // if (b != 0x00) {
- // line.text += decodeByte(b);
- // }
- // i++;
- // }
- // }
-
- // // Store raw bytes for this line
- // for (uint32_t j = lineStart; j < i && j < conversation_size; j++) {
- // line.rawBytes.push_back(data[j]);
- // }
-
- // // Only add line if it has content
- // if (!line.text.empty() || line.controlBytes.size() > 0) {
- // // debug("Line %d (offset %d): %s", lineNum, line.offset, line.text.c_str());
- // if (line.controlBytes.size() > 0) {
- // Common::String controls;
- // for (uint k = 0; k < line.controlBytes.size(); k++) {
- // if (k > 0) controls += ", ";
- // controls += line.controlBytes[k];
- // }
- // // debug(" Controls: %s", controls.c_str());
- // }
- // conversations.push_back(line);
- // lineNum++;
- // }
- // }
-
- // delete[] data;
- // debug("Loaded %d conversation lines", conversations.size());
- // return conversations;
}
void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
@@ -1248,22 +1184,9 @@ void PelrockEngine::frames() {
int curFrame = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame;
byte *frame = new byte[frameSize];
Common::copy(_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].animData + (curFrame * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w), _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].animData + (curFrame * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w) + (frameSize), frame);
- // debug("Current frame %d of %d", curFrame, i->animData[j].nframes);
-
- // byte *bg = grabBackgroundSlice(x, y, w, h);
- // putBackgroundSlice(x, y, w, h, bg);
-
- drawSpriteToBuffer(_compositeBuffer, 640, frame, _currentRoomAnims[i].x, _currentRoomAnims[i].y, _currentRoomAnims[i].w, _currentRoomAnims[i].h, 255);
- // for (int y = 0; y < i->h; y++) {
- // for (int x = 0; x < i->w; x++) {
-
- // unsigned int src_pos = (y * i->w) + x;
- // int xPos = i->x + x;
- // int yPos = i->y + y;
- // if (frame[src_pos] != 255 && xPos > 0 && yPos > 0 && xPos < 640 && yPos < 400)
- // _screen->setPixel(xPos, yPos, frame[src_pos]);
- // }
- // }
+
+ drawSpriteToBuffer(_compositeBuffer, 640, frame, _currentRoomAnims[i].x, _currentRoomAnims[i].y, _currentRoomAnims[i].w, _currentRoomAnims[i].h, 255);
+
if (_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].elpapsedFrames == _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].speed) {
_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].elpapsedFrames = 0;
if (_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame < _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].nframes - 1) {
@@ -1288,13 +1211,6 @@ void PelrockEngine::frames() {
}
}
- // if (_bgAlfred != nullptr) {
- // putBackgroundSlice(xAlfred, yAlfred, kAlfredFrameWidth, kAlfredFrameHeight, _bgAlfred);
- // delete[] _bgAlfred;
- // _bgAlfred = nullptr;
- // }
- // _bgAlfred = grabBackgroundSlice(xAlfred, yAlfred, kAlfredFrameWidth, kAlfredFrameHeight);
-
if (isAlfredWalking) {
debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
drawAlfred(walkingAnimFrames[dirAlfred][curAlfredFrame]);
@@ -1337,42 +1253,37 @@ void PelrockEngine::frames() {
} else
_currentPopupFrame = 0;
}
- // int walkboxCount = 0;
- // for (Common::List<WalkBox>::iterator i = _currentRoomWalkboxes.begin(); i != _currentRoomWalkboxes.end(); i++) {
- // // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
- // _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0 + walkboxCount);
- // _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- // _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0 + walkboxCount);
- // _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h, 0 + walkboxCount);
- // walkboxCount++;
- // }
+
+
+
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+
+ if(_curWalkTarget.x < 640 && _curWalkTarget.y < 400 && _curWalkTarget.x >=0 && _curWalkTarget.y >=0) {
+ _screen->setPixel(_curWalkTarget.x, _curWalkTarget.y, 100);
+ if(_curWalkTarget.x - 1 > 0 && _curWalkTarget.y - 1 > 0) {
+ _screen->setPixel(_curWalkTarget.x - 1, _curWalkTarget.y - 1, 100);
+ }
+ if(_curWalkTarget.x - 1 > 0 && _curWalkTarget.y + 1 < 400)
+ _screen->setPixel(_curWalkTarget.x - 1, _curWalkTarget.y + 1, 100);
+ if(_curWalkTarget.x + 1 < 640 && _curWalkTarget.y - 1 > 0)
+ _screen->setPixel(_curWalkTarget.x + 1, _curWalkTarget.y - 1, 100);
+ if(_curWalkTarget.x + 1 < 640 && _curWalkTarget.y + 1 < 400)
+ _screen->setPixel(_curWalkTarget.x + 1, _curWalkTarget.y + 1, 100);
+ }
_screen->markAllDirty();
// _screen->update();
}
}
void PelrockEngine::drawAlfred(byte *buf) {
- // for (uint32_t y = 0; y < kAlfredFrameHeight; y++) {
- // for (uint32_t x = 0; x < kAlfredFrameWidth; x++) {
- // unsigned int src_pos = (y * kAlfredFrameWidth) + x;
- // // debug("Xpos = %d, yPos=%d", x + xAlfred, y + yAlfred);
- // if (buf[src_pos] != 255 && x + xAlfred >= 0 && y + yAlfred >= 0 && x + xAlfred < 640 && y + yAlfred < 400)
- // _screen->setPixel(x + xAlfred, y + yAlfred, buf[src_pos]);
- // }
- // }
+
drawSpriteToBuffer(_compositeBuffer, 640, buf, xAlfred, yAlfred, kAlfredFrameWidth, kAlfredFrameHeight, 255);
}
void PelrockEngine::checkLongMouseClick(int x, int y) {
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
if (hotspotIndex != -1) {
- // _popupX = hotspot->x;
- // _popupY = hotspot->y;
- // if (_bgPopupBalloon != nullptr) {
- // putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
- // delete[] _bgPopupBalloon;
- // }
+
_popupX = x - kBalloonWidth / 2;
if (_popupX < 0)
_popupX = 0;
@@ -1388,7 +1299,6 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
_currentPopupFrame = 0;
_currentHotspot = &_currentRoomHotspots[hotspotIndex];
debug("Current hotspot type: %d", _currentHotspot->type);
- // _bgPopupBalloon = grabBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight);
}
}
@@ -1420,9 +1330,6 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
Common::List<VerbIcons> availableActions = populateActionsMenu(_currentHotspot);
- // for (Common::List<VerbIcons>::iterator i = availableActions.begin(); i != availableActions.end(); i++) {
- // debug("Verb icon to show: %d", *i);
- // }
drawSpriteToBuffer(_compositeBuffer, 640, _verbIcons[LOOK], posx + 20, posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
for (Common::List<VerbIcons>::iterator i = availableActions.begin(); i != availableActions.end(); i++) {
@@ -1435,18 +1342,32 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
}
+void PelrockEngine::walkTo(int x, int y) {
+ isAlfredWalking = true;
+ curAlfredFrame = 0;
+
+ // if (x > xAlfred) {
+ // dirAlfred = RIGHT;
+ // } else if (x < xAlfred) {
+ // dirAlfred = LEFT;
+ // } else if (y < yAlfred) {
+ // dirAlfred = UP;
+ // } else if (y > yAlfred) {
+ // dirAlfred = DOWN;
+ // }
+ debug("Setting Alfred to walk towards (%d, %d) from (%d, %d) in direction %d", x, y, xAlfred, yAlfred, dirAlfred);
+}
+
void PelrockEngine::checkMouseClick(int x, int y) {
_displayPopup = false;
_currentHotspot = nullptr;
- // if (_bgPopupBalloon != nullptr) {
- // putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
- // delete[] _bgPopupBalloon;
- // _bgPopupBalloon = nullptr;
- // }
- Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
+ Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
+ walkTo(walkTarget.x, walkTarget.y);
+ _curWalkTarget = walkTarget;
+ debug("Calculated walk target at (%d, %d)", walkTarget.x, walkTarget.y);
Exit *exit = isExitAtPoint(walkTarget.x, walkTarget.y);
if (exit != nullptr) {
@@ -1459,9 +1380,9 @@ void PelrockEngine::checkMouseClick(int x, int y) {
if (hotspotIndex != -1) {
talk();
debug("Hotspot clicked: %d", _currentRoomHotspots[hotspotIndex].extra);
- // showDescription(_currentRoomDescriptions[hotspotIndex].text.c_str(), xAlfred, yAlfred, 13);
- // changeCursor(HOTSPOT);
}
+
+
}
void PelrockEngine::changeCursor(Cursor cursor) {
@@ -1485,11 +1406,7 @@ void PelrockEngine::checkMouseHover() {
if (hotspotIndex != -1) {
isSomethingUnder = true;
}
- // Exit *exit = isExitUnder(mouseX, mouseY);
- // if (exit != nullptr) {
- // isSomethingUnder = true;
- // changeCursor(EXIT);
- // }
+
if (isSomethingUnder && exitDetected) {
changeCursor(COMBINATION);
} else if (isSomethingUnder) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 2cb9fe8393b..89f2475ed6b 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -75,6 +75,8 @@ private:
Common::Array<ConversationNode> buildTreeStructure(const Common::Array<ConversationElement> &elements);
Common::Array<ConversationNode> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
+ void walkTo(int x, int y);
+
void talk();
Common::String getControlName(byte b);
void loadRoomMetadata(Common::File *roomFile, int roomOffset);
@@ -152,6 +154,10 @@ private:
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
+
+ Common::Point _curWalkTarget;
+
+
bool shouldPlayIntro = false;
GameState stateGame = GAME;
bool gameInitialized = false;
Commit: 1623209a0bcb388f995027d86385f9e3ee22383b
https://github.com/scummvm/scummvm/commit/1623209a0bcb388f995027d86385f9e3ee22383b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:05+02:00
Commit Message:
PELROCK: Quick and dirty walking algorithm
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 0b1990ac05e..1af81195bf9 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -84,6 +84,14 @@ Common::String PelrockEngine::getGameId() const {
return _gameDescription->gameId;
}
+void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color) {
+ // debug("Drawing rect at (%d,%d) w=%d h=%d color=%d", x, y, w, h, color);
+ surface->drawLine(x, y, x + w, y, color);
+ surface->drawLine(x, y + h, x + w, y + h, color);
+ surface->drawLine(x, y, x, y + h, color);
+ surface->drawLine(x + w, y, x + w, y + h, color);
+}
+
Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
initGraphics(640, 400);
@@ -358,7 +366,7 @@ Common::Array<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
return anims;
}
-Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int roomOffset) {
+Common::Array<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int roomOffset) {
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
roomFile->seek(pair10_offset_pos, SEEK_SET);
// roomFile->skip(4);
@@ -370,7 +378,7 @@ Common::List<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int r
byte walkbox_count = roomFile->readByte();
debug("Walkbox count: %d", walkbox_count);
uint32_t walkbox_offset = pair10_data_offset + 0x218;
- Common::List<WalkBox> walkboxes;
+ Common::Array<WalkBox> walkboxes;
for (int i = 0; i < walkbox_count; i++) {
uint32_t box_offset = walkbox_offset + i * 9;
roomFile->seek(box_offset, SEEK_SET);
@@ -882,7 +890,7 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
Common::List<Exit> exits = loadExits(roomFile, roomOffset);
- Common::List<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
+ Common::Array<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
for (int i = 0; i < staticHotspots.size(); i++) {
@@ -901,10 +909,7 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
// debug("Hotspot %d: x=%d y=%d w=%d h=%d type=%d enabled? %d extra=%d, desc=%s", i, hotspot.x, hotspot.y, hotspot.w, hotspot.h, hotspot.type, hotspot.isEnabled, hotspot.extra, _currentRoomDescriptions[i].text.c_str());
- _screen->drawLine(hotspot.x, hotspot.y, hotspot.x + hotspot.w, hotspot.y, 200 + i);
- _screen->drawLine(hotspot.x, hotspot.y + hotspot.h, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
- _screen->drawLine(hotspot.x, hotspot.y, hotspot.x, hotspot.y + hotspot.h, 200 + i);
- _screen->drawLine(hotspot.x + hotspot.w, hotspot.y, hotspot.x + hotspot.w, hotspot.y + hotspot.h, 200 + i);
+ // drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
}
for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
@@ -1171,7 +1176,7 @@ void PelrockEngine::frames() {
memcpy(_compositeBuffer, _currentBackground, 640 * 400);
- debug("Game tick!");
+ // debug("Game tick!");
for (int i = 0; i < _currentRoomAnims.size(); i++) {
// debug("Processing animation set %d, numAnims %d", num, i->numAnims);
@@ -1205,14 +1210,66 @@ void PelrockEngine::frames() {
}
}
}
- }
- else {
+ } else {
_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].elpapsedFrames++;
}
}
if (isAlfredWalking) {
- debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
+ debug("Alfred is walking, current step %d of %d", _current_step, _currentContext.movement_count);
+ MovementStep step = _currentContext.movement_buffer[_current_step];
+ debug("Alfred step: distance_x=%d, distance_y=%d", step.distance_x, step.distance_y);
+
+ if (step.distance_x > 0) {
+ if (step.flags & MOVE_RIGHT) {
+ dirAlfred = 0;
+ xAlfred += MIN((uint16_t)6, step.distance_x);
+ }
+ if (step.flags & MOVE_LEFT) {
+ dirAlfred = 1;
+ xAlfred -= MIN((uint16_t)6, step.distance_x);
+ }
+ }
+ if (step.distance_y > 0) {
+ if (step.flags & MOVE_DOWN) {
+ dirAlfred = 2;
+ yAlfred += MIN((uint16_t)6, step.distance_y);
+ }
+ if (step.flags & MOVE_UP) {
+ dirAlfred = 3;
+ yAlfred -= MIN((uint16_t)6, step.distance_y);
+ }
+ }
+
+ if (step.distance_x > 0)
+ step.distance_x -= MIN((uint16_t)6, step.distance_x);
+
+ if (step.distance_y > 0)
+ step.distance_y -= MIN((uint16_t)6, step.distance_y);
+ debug("Alfred position after step: x=%d, y=%d, step distance_x=%d, step distance_y=%d", xAlfred, yAlfred, step.distance_x, step.distance_y);
+ if (step.distance_x <= 0 && step.distance_y <= 0) {
+ debug("Alfred completed step %d", _current_step);
+ _current_step++;
+ if (_current_step >= _currentContext.movement_count) {
+ debug("Alfred reached his walk target.");
+ _current_step = 0;
+ isAlfredWalking = false;
+ }
+ } else {
+ _currentContext.movement_buffer[_current_step] = step;
+ }
+ // _current_step++;
+ // if(_current_step >= _currentContext.movement_count) {
+ // debug("Alfred reached his walk target.");
+ // _current_step = 0;
+ // isAlfredWalking = false;
+ // }
+ // if (step->flags & MOVE_RIGHT) printf("RIGHT ");
+ // if (step->flags & MOVE_LEFT) printf("LEFT ");
+ // if (step->flags & MOVE_DOWN) printf("DOWN ");
+ // if (step->flags & MOVE_UP) printf("UP ");
+
+ // debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
drawAlfred(walkingAnimFrames[dirAlfred][curAlfredFrame]);
if (curAlfredFrame < walkingAnimLengths[dirAlfred] - 1) {
@@ -1220,7 +1277,7 @@ void PelrockEngine::frames() {
} else {
curAlfredFrame = 0;
}
- debug("CurAlfredFrame from walking is now %d", curAlfredFrame);
+ // debug("CurAlfredFrame from walking is now %d", curAlfredFrame);
} else if (isAlfredTalking) {
drawAlfred(talkingAnimFrames[dirAlfred][curAlfredFrame]);
@@ -1254,21 +1311,31 @@ void PelrockEngine::frames() {
_currentPopupFrame = 0;
}
-
-
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
-
- if(_curWalkTarget.x < 640 && _curWalkTarget.y < 400 && _curWalkTarget.x >=0 && _curWalkTarget.y >=0) {
+ // debug("Drawing walkboxes..., %d, _currentRoomWalkboxes.size()=%d", _currentRoomWalkboxes.size(), _currentRoomWalkboxes.size());
+ for (int i = 0; i < _currentRoomWalkboxes.size(); i++) {
+ // debug("Drawing walkbox %d", i);
+ WalkBox box = _currentRoomWalkboxes[i];
+ drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
+ }
+ if (_curWalkTarget.x < 640 && _curWalkTarget.y < 400 && _curWalkTarget.x >= 0 && _curWalkTarget.y >= 0) {
_screen->setPixel(_curWalkTarget.x, _curWalkTarget.y, 100);
- if(_curWalkTarget.x - 1 > 0 && _curWalkTarget.y - 1 > 0) {
+ if (_curWalkTarget.x - 1 > 0 && _curWalkTarget.y - 1 > 0)
_screen->setPixel(_curWalkTarget.x - 1, _curWalkTarget.y - 1, 100);
- }
- if(_curWalkTarget.x - 1 > 0 && _curWalkTarget.y + 1 < 400)
+ if (_curWalkTarget.x - 1 > 0 && _curWalkTarget.y + 1 < 400)
_screen->setPixel(_curWalkTarget.x - 1, _curWalkTarget.y + 1, 100);
- if(_curWalkTarget.x + 1 < 640 && _curWalkTarget.y - 1 > 0)
+ if (_curWalkTarget.x + 1 < 640 && _curWalkTarget.y - 1 > 0)
_screen->setPixel(_curWalkTarget.x + 1, _curWalkTarget.y - 1, 100);
- if(_curWalkTarget.x + 1 < 640 && _curWalkTarget.y + 1 < 400)
+ if (_curWalkTarget.x + 1 < 640 && _curWalkTarget.y + 1 < 400)
_screen->setPixel(_curWalkTarget.x + 1, _curWalkTarget.y + 1, 100);
+ if (_curWalkTarget.x - 2 > 0)
+ _screen->setPixel(_curWalkTarget.x - 2, _curWalkTarget.y, 100);
+ if (_curWalkTarget.x + 2 < 640)
+ _screen->setPixel(_curWalkTarget.x + 2, _curWalkTarget.y, 100);
+ if (_curWalkTarget.y - 2 > 0)
+ _screen->setPixel(_curWalkTarget.x, _curWalkTarget.y - 2, 100);
+ if (_curWalkTarget.y + 2 < 400)
+ _screen->setPixel(_curWalkTarget.x, _curWalkTarget.y + 2, 100);
}
_screen->markAllDirty();
// _screen->update();
@@ -1277,7 +1344,7 @@ void PelrockEngine::frames() {
void PelrockEngine::drawAlfred(byte *buf) {
- drawSpriteToBuffer(_compositeBuffer, 640, buf, xAlfred, yAlfred, kAlfredFrameWidth, kAlfredFrameHeight, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, xAlfred, yAlfred - kAlfredFrameHeight, kAlfredFrameWidth, kAlfredFrameHeight, 255);
}
void PelrockEngine::checkLongMouseClick(int x, int y) {
@@ -1330,7 +1397,6 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
Common::List<VerbIcons> availableActions = populateActionsMenu(_currentHotspot);
-
drawSpriteToBuffer(_compositeBuffer, 640, _verbIcons[LOOK], posx + 20, posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
for (Common::List<VerbIcons>::iterator i = availableActions.begin(); i != availableActions.end(); i++) {
VerbIcons verb = *i;
@@ -1346,6 +1412,39 @@ void PelrockEngine::walkTo(int x, int y) {
isAlfredWalking = true;
curAlfredFrame = 0;
+ PathContext context = {NULL, NULL, NULL, 0, 0, 0};
+
+ pathFind(x, y, &context);
+ debug("\nPath Information:\n");
+ debug("================\n");
+
+ debug("Walkbox path (%d boxes): ", context.path_length);
+ for (int i = 0; i < context.path_length && context.path_buffer[i] != PATH_END; i++) {
+ debug("%d ", context.path_buffer[i]);
+ }
+
+ debug("Movement steps (%d steps):\n", context.movement_count);
+ for (int i = 0; i < context.movement_count; i++) {
+ MovementStep *step = &context.movement_buffer[i];
+ debug(" Step %d: ", i);
+
+ if (step->flags & MOVE_RIGHT)
+ debug("RIGHT ");
+ if (step->flags & MOVE_LEFT)
+ debug("LEFT ");
+ if (step->flags & MOVE_DOWN)
+ debug("DOWN ");
+ if (step->flags & MOVE_UP)
+ debug("UP ");
+
+ debug("(dx=%d, dy=%d)\n", step->distance_x, step->distance_y);
+ }
+
+ debug("\nCompressed path (%d bytes): ", context.compressed_length);
+ for (int i = 0; i < context.compressed_length; i++) {
+ debug("%02X ", context.compressed_path[i]);
+ }
+
// if (x > xAlfred) {
// dirAlfred = RIGHT;
// } else if (x < xAlfred) {
@@ -1356,6 +1455,298 @@ void PelrockEngine::walkTo(int x, int y) {
// dirAlfred = DOWN;
// }
debug("Setting Alfred to walk towards (%d, %d) from (%d, %d) in direction %d", x, y, xAlfred, yAlfred, dirAlfred);
+ _currentContext = context;
+ debug("Path find complete, movement count: %d", _currentContext.movement_count);
+}
+
+bool PelrockEngine::pathFind(int x, int y, PathContext *context) {
+
+ if (context->path_buffer == NULL) {
+ context->path_buffer = (uint8_t *)malloc(MAX_PATH_LENGTH);
+ }
+ if (context->movement_buffer == NULL) {
+ context->movement_buffer = (MovementStep *)malloc(MAX_MOVEMENT_STEPS * sizeof(MovementStep));
+ }
+ // if (context->compressed_path == NULL) {
+ // context->compressed_path = (uint8_t*)malloc(MAX_COMPRESSED_PATH);
+ // }
+
+ int startX = xAlfred;
+ int startY = yAlfred;
+ Common::Point target = calculateWalkTarget(x, y);
+ x = target.x;
+ y = target.y;
+ debug("Startx= %d, starty= %d, destx= %d, desty= %d", startX, startY, x, y);
+
+ uint8_t start_box = find_walkbox_for_point(startX, startY);
+ uint8_t dest_box = find_walkbox_for_point(x, y);
+
+ debug("Pathfinding from (%d, %d) in box %d to (%d, %d) in box %d\n",
+ startX, startY, start_box,
+ x, y, dest_box);
+ // Check if both points are in valid walkboxes
+ if (start_box == 0xFF || dest_box == 0xFF) {
+ debug("Error: Start or destination not in any walkbox\n");
+ return false;
+ }
+ // Special case: same walkbox
+ if (start_box == dest_box) {
+ // Generate direct movement
+ MovementStep direct_step;
+ direct_step.flags = 0;
+ if (startX < x) {
+ direct_step.distance_x = x - startX;
+ direct_step.flags |= MOVE_RIGHT;
+ } else {
+ direct_step.distance_x = startX - x;
+ direct_step.flags |= MOVE_LEFT;
+ }
+
+ if (startY < y) {
+ direct_step.distance_y = y - startY;
+ direct_step.flags |= MOVE_DOWN;
+ } else {
+ direct_step.distance_y = startY - y;
+ direct_step.flags |= MOVE_UP;
+ }
+
+ context->movement_buffer[0] = direct_step;
+ context->movement_count = 1;
+ } else {
+ // Build walkbox path
+ context->path_length = build_walkbox_path(start_box, dest_box,
+ context->path_buffer);
+
+ if (context->path_length == 0) {
+ debug("Error: No path found\n");
+ return false;
+ }
+
+ // Generate movement steps
+ context->movement_count = generate_movement_steps(
+ context->path_buffer,
+ context->path_length,
+ startX, startY,
+ x, y,
+ context->movement_buffer);
+ }
+ return true;
+}
+
+/**
+ * Calculate movement needed to reach a target within a walkbox
+ */
+void calculate_movement_to_target(uint16_t current_x, uint16_t current_y,
+ uint16_t target_x, uint16_t target_y,
+ WalkBox *box,
+ MovementStep *step) {
+ step->flags = 0;
+ step->distance_x = 0;
+ step->distance_y = 0;
+
+ // Calculate horizontal movement
+ if (current_x < box->x) {
+ // Need to move right to enter walkbox
+ step->distance_x = box->x - current_x;
+ step->flags |= MOVE_RIGHT;
+ } else if (current_x > box->x + box->w) {
+ // Need to move left to enter walkbox
+ step->distance_x = current_x - (box->x + box->w);
+ step->flags |= MOVE_LEFT;
+ }
+
+ // Calculate vertical movement
+ if (current_y < box->y) {
+ // Need to move down to enter walkbox
+ step->distance_y = box->y - current_y;
+ step->flags |= MOVE_DOWN;
+ } else if (current_y > box->y + box->h) {
+ // Need to move up to enter walkbox
+ step->distance_y = current_y - (box->y + box->h);
+ step->flags |= MOVE_UP;
+ }
+}
+
+/**
+ * Generate movement steps from walkbox path
+ * Returns: number of movement steps generated
+ */
+uint16_t PelrockEngine::generate_movement_steps(uint8_t *path_buffer,
+ uint16_t path_length,
+ uint16_t start_x, uint16_t start_y,
+ uint16_t dest_x, uint16_t dest_y,
+ MovementStep *movement_buffer) {
+ uint16_t current_x = start_x;
+ uint16_t current_y = start_y;
+ uint16_t movement_index = 0;
+
+ // Generate movements for each walkbox in path
+ for (uint16_t i = 0; i < path_length && path_buffer[i] != PATH_END; i++) {
+ uint8_t box_index = path_buffer[i];
+ WalkBox *box = &_currentRoomWalkboxes[box_index];
+
+ MovementStep step;
+ calculate_movement_to_target(current_x, current_y,
+ dest_x, dest_y,
+ box, &step);
+
+ if (step.distance_x > 0 || step.distance_y > 0) {
+ movement_buffer[movement_index++] = step;
+
+ // Update current position
+ if (step.flags & MOVE_RIGHT) {
+ current_x = box->x;
+ } else if (step.flags & MOVE_LEFT) {
+ current_x = box->x + box->w;
+ }
+
+ if (step.flags & MOVE_DOWN) {
+ current_y = box->y;
+ } else if (step.flags & MOVE_UP) {
+ current_y = box->y + box->h;
+ }
+ }
+ }
+
+ // Final movement to exact destination
+ MovementStep final_step;
+ final_step.flags = 0;
+
+ if (current_x < dest_x) {
+ final_step.distance_x = dest_x - current_x;
+ final_step.flags |= MOVE_RIGHT;
+ } else if (current_x > dest_x) {
+ final_step.distance_x = current_x - dest_x;
+ final_step.flags |= MOVE_LEFT;
+ } else {
+ final_step.distance_x = 0;
+ }
+
+ if (current_y < dest_y) {
+ final_step.distance_y = dest_y - current_y;
+ final_step.flags |= MOVE_DOWN;
+ } else if (current_y > dest_y) {
+ final_step.distance_y = current_y - dest_y;
+ final_step.flags |= MOVE_UP;
+ } else {
+ final_step.distance_y = 0;
+ }
+
+ if (final_step.distance_x > 0 || final_step.distance_y > 0) {
+ movement_buffer[movement_index++] = final_step;
+ }
+
+ return movement_index;
+}
+
+uint16_t PelrockEngine::build_walkbox_path(
+ uint8_t start_box,
+ uint8_t dest_box,
+ uint8_t *path_buffer) {
+ uint16_t path_index = 0;
+ uint8_t current_box = start_box;
+
+ // Initialize path with start walkbox
+ path_buffer[path_index++] = start_box;
+
+ // Clear visited flags
+ clear_visited_flags();
+
+ // Breadth-first search through walkboxes
+ while (current_box != dest_box && path_index < MAX_PATH_LENGTH - 1) {
+ uint8_t next_box = get_adjacent_walkbox(current_box);
+
+ if (next_box == 0xFF) {
+ // Dead end - backtrack
+ if (path_index > 1) {
+ path_index--;
+ current_box = path_buffer[path_index - 1];
+ } else {
+ // No path exists
+ return 0;
+ }
+ } else if (next_box == dest_box) {
+ // Found destination
+ path_buffer[path_index++] = dest_box;
+ break;
+ } else {
+ // Continue searching
+ path_buffer[path_index++] = next_box;
+ current_box = next_box;
+ }
+ }
+
+ // Terminate path
+ path_buffer[path_index] = PATH_END;
+
+ return path_index;
+}
+
+void PelrockEngine::clear_visited_flags() {
+ for (int i = 0; i < _currentRoomWalkboxes.size(); i++) {
+ _currentRoomWalkboxes[i].flags = 0;
+ }
+}
+
+/**
+ * Check if two walkboxes overlap or touch (are adjacent)
+ */
+bool walkboxes_adjacent(WalkBox *box1, WalkBox *box2) {
+ uint16_t box1_x_max = box1->x + box1->w;
+ uint16_t box1_y_max = box1->y + box1->h;
+ uint16_t box2_x_max = box2->x + box2->w;
+ uint16_t box2_y_max = box2->y + box2->h;
+
+ // Check if X ranges overlap
+ bool x_overlap = (box1->x <= box2_x_max) && (box2->x <= box1_x_max);
+
+ // Check if Y ranges overlap
+ bool y_overlap = (box1->y <= box2_y_max) && (box2->y <= box1_y_max);
+
+ return x_overlap && y_overlap;
+}
+
+uint8_t PelrockEngine::get_adjacent_walkbox(uint8_t current_box_index) {
+ WalkBox *current_box = &_currentRoomWalkboxes[current_box_index];
+
+ // Mark current walkbox as visited
+ current_box->flags = 0x01;
+
+ // Search for adjacent unvisited walkbox
+ for (uint8_t i = 0; i < _currentRoomWalkboxes.size(); i++) {
+ // Skip current walkbox
+ if (i == current_box_index) {
+ continue;
+ }
+
+ // Skip already visited walkboxes
+ if (_currentRoomWalkboxes[i].flags == 0x01) {
+ continue;
+ }
+
+ // Check if walkboxes are adjacent
+ if (walkboxes_adjacent(current_box, &_currentRoomWalkboxes[i])) {
+ return i;
+ }
+ }
+
+ return 0xFF; // No adjacent walkbox found
+}
+
+bool PelrockEngine::point_in_walkbox(WalkBox *box, uint16_t x, uint16_t y) {
+ return (x >= box->x &&
+ x <= box->x + box->w &&
+ y >= box->y &&
+ y <= box->y + box->h);
+}
+
+uint8_t PelrockEngine::find_walkbox_for_point(uint16_t x, uint16_t y) {
+ for (uint8_t i = 0; i < _currentRoomWalkboxes.size(); i++) {
+ if (point_in_walkbox(&_currentRoomWalkboxes[i], x, y)) {
+ return i;
+ }
+ }
+ return 0xFF; // Not found
}
void PelrockEngine::checkMouseClick(int x, int y) {
@@ -1363,17 +1754,17 @@ void PelrockEngine::checkMouseClick(int x, int y) {
_displayPopup = false;
_currentHotspot = nullptr;
-
Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
- walkTo(walkTarget.x, walkTarget.y);
_curWalkTarget = walkTarget;
debug("Calculated walk target at (%d, %d)", walkTarget.x, walkTarget.y);
Exit *exit = isExitAtPoint(walkTarget.x, walkTarget.y);
if (exit != nullptr) {
xAlfred = exit->targetX;
- yAlfred = exit->targetY - kAlfredFrameHeight;
+ yAlfred = exit->targetY;
setScreen(exit->targetRoom, exit->dir);
+ } else {
+ walkTo(walkTarget.x, walkTarget.y);
}
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
@@ -1381,8 +1772,6 @@ void PelrockEngine::checkMouseClick(int x, int y) {
talk();
debug("Hotspot clicked: %d", _currentRoomHotspots[hotspotIndex].extra);
}
-
-
}
void PelrockEngine::changeCursor(Cursor cursor) {
@@ -1430,26 +1819,27 @@ Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
uint32 minDistance = 0xFFFFFFFF;
Common::Point bestTarget(sourceX, sourceY);
- for (Common::List<WalkBox>::iterator it = _currentRoomWalkboxes.begin();
- it != _currentRoomWalkboxes.end(); ++it) {
+ // for (Common::List<WalkBox>::iterator it = _currentRoomWalkboxes.begin();
+ // it != _currentRoomWalkboxes.end(); ++it) {
+ for (size_t i = 0; i < _currentRoomWalkboxes.size(); i++) {
// Calculate distance from source point to this walkbox (Manhattan distance)
int dx = 0;
int dy = 0;
// Calculate horizontal distance
- if (sourceX < it->x) {
- dx = it->x - sourceX;
- } else if (sourceX > it->x + it->w) {
- dx = sourceX - (it->x + it->w);
+ if (sourceX < _currentRoomWalkboxes[i].x) {
+ dx = _currentRoomWalkboxes[i].x - sourceX;
+ } else if (sourceX > _currentRoomWalkboxes[i].x + _currentRoomWalkboxes[i].w) {
+ dx = sourceX - (_currentRoomWalkboxes[i].x + _currentRoomWalkboxes[i].w);
}
// else: sourceX is inside walkbox horizontally, dx = 0
// Calculate vertical distance
- if (sourceY < it->y) {
- dy = it->y - sourceY;
- } else if (sourceY > it->y + it->h) {
- dy = sourceY - (it->y + it->h);
+ if (sourceY < _currentRoomWalkboxes[i].y) {
+ dy = _currentRoomWalkboxes[i].y - sourceY;
+ } else if (sourceY > _currentRoomWalkboxes[i].y + _currentRoomWalkboxes[i].h) {
+ dy = sourceY - (_currentRoomWalkboxes[i].y + _currentRoomWalkboxes[i].h);
}
// else: sourceY is inside walkbox vertically, dy = 0
@@ -1462,16 +1852,16 @@ Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
int targetX = sourceX;
int targetY = sourceY;
- if (sourceX < it->x) {
- targetX = it->x;
- } else if (sourceX > it->x + it->w) {
- targetX = it->x + it->w;
+ if (sourceX < _currentRoomWalkboxes[i].x) {
+ targetX = _currentRoomWalkboxes[i].x;
+ } else if (sourceX > _currentRoomWalkboxes[i].x + _currentRoomWalkboxes[i].w) {
+ targetX = _currentRoomWalkboxes[i].x + _currentRoomWalkboxes[i].w;
}
- if (sourceY < it->y) {
- targetY = it->y;
- } else if (sourceY > it->y + it->h) {
- targetY = it->y + it->h;
+ if (sourceY < _currentRoomWalkboxes[i].y) {
+ targetY = _currentRoomWalkboxes[i].y;
+ } else if (sourceY > _currentRoomWalkboxes[i].y + _currentRoomWalkboxes[i].h) {
+ targetY = _currentRoomWalkboxes[i].y + _currentRoomWalkboxes[i].h;
}
bestTarget.x = targetX;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 89f2475ed6b..34b767a0dfd 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -67,7 +67,7 @@ private:
Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
- Common::List<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
+ Common::Array<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos);
Common::String cleanText(const Common::String &text);
@@ -76,6 +76,17 @@ private:
Common::Array<ConversationNode> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
void walkTo(int x, int y);
+ bool pathFind(int x, int y, PathContext *context);
+ uint8_t find_walkbox_for_point(uint16_t x, uint16_t y);
+ bool point_in_walkbox(WalkBox *box, uint16_t x, uint16_t y);
+ uint16_t build_walkbox_path(uint8_t start_box, uint8_t dest_box, uint8_t *path_buffer);
+ uint8_t get_adjacent_walkbox(uint8_t current_box_index);
+ void clear_visited_flags();
+ uint16_t generate_movement_steps(uint8_t *path_buffer,
+ uint16_t path_length,
+ uint16_t start_x, uint16_t start_y,
+ uint16_t dest_x, uint16_t dest_y,
+ MovementStep *movement_buffer);
void talk();
Common::String getControlName(byte b);
@@ -112,10 +123,13 @@ private:
byte **talkingAnimFrames[4]; // 4 arrays of arrays
int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+ PathContext _currentContext;
+ int _current_step = 0;
+
Common::Array<HotSpot> _currentRoomHotspots;
Common::Array<AnimSet> _currentRoomAnims;
Common::List<Exit> _currentRoomExits;
- Common::List<WalkBox> _currentRoomWalkboxes;
+ Common::Array<WalkBox> _currentRoomWalkboxes;
Common::Array<Description> _currentRoomDescriptions;
Common::Array<ConversationNode> _currentRoomConversations;
@@ -154,10 +168,8 @@ private:
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
-
Common::Point _curWalkTarget;
-
bool shouldPlayIntro = false;
GameState stateGame = GAME;
bool gameInitialized = false;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 4f56d8d5393..065d773f4b7 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -21,9 +21,9 @@
#ifndef PELROCK_TYPES_H
#define PELROCK_TYPES_H
-#include "common/types.h"
#include "common/scummsys.h"
#include "common/system.h"
+#include "common/types.h"
namespace Pelrock {
@@ -53,13 +53,12 @@ enum VerbIcons {
// HOSTPOT,
// SPECIAl;
-
// };
static const uint32 kLongClickDuration = 500; // 500ms for long click
const int kCursorWidth = 16;
const int kCursorHeight = 18;
-const int kCursorSize = 288; // 16 * 18
+const int kCursorSize = 288; // 16 * 18
const int kRoomStructSize = 104;
const int kNumRooms = 56;
const int kVerbIconWidth = 60;
@@ -69,6 +68,35 @@ const int kBalloonWidth = 247;
const int kBalloonHeight = 112;
const int kBalloonFrames = 4;
+// Direction flags (bit-packed)
+#define MOVE_RIGHT 0x01 // Move right (positive X)
+#define MOVE_LEFT 0x02 // Move left (negative X)
+#define MOVE_HORIZ 0x03 // Horizontal movement mask
+#define MOVE_DOWN 0x04 // Move down (positive Y)
+#define MOVE_UP 0x08 // Move up (negative Y)
+#define MOVE_VERT 0x0C // Vertical movement mask
+#define MAX_PATH_LENGTH 100
+#define MAX_MOVEMENT_STEPS 100 // 500 bytes / 5 bytes per step
+#define PATH_END 0xFF // End of path marker
+
+typedef struct {
+ uint8_t flags; // Direction flags (see MOVE_* constants)
+ uint16_t distance_x; // Horizontal distance to move
+ uint16_t distance_y; // Vertical distance to move
+} MovementStep;
+
+/**
+ * Pathfinding context
+ */
+typedef struct {
+ uint8_t *path_buffer; // Sequence of walkbox indices
+ MovementStep *movement_buffer; // Array of movement steps
+ uint8_t *compressed_path; // Final compressed path
+ uint16_t path_length;
+ uint16_t movement_count;
+ uint16_t compressed_length;
+} PathContext;
+
struct Anim {
int x;
int y;
@@ -98,20 +126,19 @@ struct Exit {
struct AnimSet {
byte type;
- int x; //0
- int y;//2
- int w;//4
- int h;//5
- byte extra; //6
- int numAnims; //8
+ int x; // 0
+ int y; // 2
+ int w; // 4
+ int h; // 5
+ byte extra; // 6
+ int numAnims; // 8
int curAnimIndex = 0;
- byte spriteType; //33
- byte actionFlags;//34
- bool isDisabled; //38
+ byte spriteType; // 33
+ byte actionFlags; // 34
+ bool isDisabled; // 38
Anim *animData;
};
-
struct HotSpot {
int id;
int x;
@@ -124,46 +151,45 @@ struct HotSpot {
};
struct ConversationElement {
- enum Type {
- DIALOGUE,
- CHOICE_MARKER,
- END_CONV,
- END_BRANCH
- } type;
-
- Common::String speaker;
+ enum Type {
+ DIALOGUE,
+ CHOICE_MARKER,
+ END_CONV,
+ END_BRANCH
+ } type;
+
+ Common::String speaker;
byte speakerId;
- Common::String text;
- int choiceIndex;
- bool isRealChoice;
+ Common::String text;
+ int choiceIndex;
+ bool isRealChoice;
- ConversationElement() : type(DIALOGUE), choiceIndex(-1), isRealChoice(false) {}
+ ConversationElement() : type(DIALOGUE), choiceIndex(-1), isRealChoice(false) {}
};
-
struct ConversationNode {
- enum NodeType {
- ROOT,
- CHOICE,
- RESPONSE
- } type;
-
- Common::String text;
- Common::String speaker;
+ enum NodeType {
+ ROOT,
+ CHOICE,
+ RESPONSE
+ } type;
+
+ Common::String text;
+ Common::String speaker;
byte speakerId;
- int choiceIndex;
- bool terminated;
+ int choiceIndex;
+ bool terminated;
- Common::Array<ConversationNode> choices;
- Common::Array<ConversationNode> responses;
- Common::Array<ConversationNode> subchoices;
+ Common::Array<ConversationNode> choices;
+ Common::Array<ConversationNode> responses;
+ Common::Array<ConversationNode> subchoices;
- ConversationNode() : type(ROOT), choiceIndex(-1), terminated(false) {}
+ ConversationNode() : type(ROOT), choiceIndex(-1), terminated(false) {}
};
struct StackEntry {
- ConversationNode *node;
- int index;
+ ConversationNode *node;
+ int index;
};
struct Description {
Commit: 65b577da752a9b4562d16af6e48572e3e2960e1f
https://github.com/scummvm/scummvm/commit/65b577da752a9b4562d16af6e48572e3e2960e1f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:06+02:00
Commit Message:
PELROCK: Improve walk algorithm
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1af81195bf9..ff3b418667b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -152,6 +152,7 @@ Common::Error PelrockEngine::run() {
}
checkMouseHover();
frames();
+
_screen->update();
// limiter.delayBeforeSwap();
// limiter.startFrame();
@@ -177,7 +178,7 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(0, 2);
+ setScreen(0, 1);
// setScreen(2, 2);
// setScreen(28, 0);
}
@@ -888,7 +889,7 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
}
Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
- Common::List<Exit> exits = loadExits(roomFile, roomOffset);
+ Common::Array<Exit> exits = loadExits(roomFile, roomOffset);
Common::Array<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
@@ -908,17 +909,12 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
- // debug("Hotspot %d: x=%d y=%d w=%d h=%d type=%d enabled? %d extra=%d, desc=%s", i, hotspot.x, hotspot.y, hotspot.w, hotspot.h, hotspot.type, hotspot.isEnabled, hotspot.extra, _currentRoomDescriptions[i].text.c_str());
- // drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
+ drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
}
- for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
- // debug("Exit: x=%d y=%d w=%d h=%d to room %d", i->x, i->y, i->w, i->h, i->targetRoom);
- // _screen->fillRect(Common::Rect(i->x, i->y, i->x + i->w, i->y + i->h), 255);
- // _screen->drawLine(i->x, i->y, i->x + i->w, i->y, 0);
- // _screen->drawLine(i->x, i->y + i->h, i->x + i->w, i->y + i->h, 0);
- // _screen->drawLine(i->x, i->y, i->x, i->y + i->h, 0);
- // _screen->drawLine(i->x + i->w, i->y, i->x + i->w, i->y + i->h);
+ for (int i = 0; i < _currentRoomExits.size(); i++) {
+ Exit exit = _currentRoomExits[i];
+ drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
}
}
@@ -970,8 +966,8 @@ void PelrockEngine::loadInteractionIcons() {
alfred4File.close();
}
-Common::List<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffset) {
- Common::List<Exit> exits;
+Common::Array<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffset) {
+ Common::Array<Exit> exits;
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
roomFile->seek(pair10_offset_pos, SEEK_SET);
uint32_t pair10_data_offset = roomFile->readUint32LE();
@@ -1216,7 +1212,7 @@ void PelrockEngine::frames() {
}
if (isAlfredWalking) {
- debug("Alfred is walking, current step %d of %d", _current_step, _currentContext.movement_count);
+
MovementStep step = _currentContext.movement_buffer[_current_step];
debug("Alfred step: distance_x=%d, distance_y=%d", step.distance_x, step.distance_y);
@@ -1258,25 +1254,24 @@ void PelrockEngine::frames() {
} else {
_currentContext.movement_buffer[_current_step] = step;
}
- // _current_step++;
- // if(_current_step >= _currentContext.movement_count) {
- // debug("Alfred reached his walk target.");
- // _current_step = 0;
- // isAlfredWalking = false;
- // }
- // if (step->flags & MOVE_RIGHT) printf("RIGHT ");
- // if (step->flags & MOVE_LEFT) printf("LEFT ");
- // if (step->flags & MOVE_DOWN) printf("DOWN ");
- // if (step->flags & MOVE_UP) printf("UP ");
- // debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
- drawAlfred(walkingAnimFrames[dirAlfred][curAlfredFrame]);
+ Exit *exit = isExitUnder(xAlfred, yAlfred);
- if (curAlfredFrame < walkingAnimLengths[dirAlfred] - 1) {
- curAlfredFrame++;
- } else {
+ if (exit != nullptr) {
+ xAlfred = exit->targetX;
+ yAlfred = exit->targetY;
+ setScreen(exit->targetRoom, exit->dir);
+ }
+
+ debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
+
+ if (curAlfredFrame >= walkingAnimLengths[dirAlfred]) {
curAlfredFrame = 0;
}
+
+ drawAlfred(walkingAnimFrames[dirAlfred][curAlfredFrame]);
+ curAlfredFrame++;
+
// debug("CurAlfredFrame from walking is now %d", curAlfredFrame);
} else if (isAlfredTalking) {
drawAlfred(talkingAnimFrames[dirAlfred][curAlfredFrame]);
@@ -1383,10 +1378,11 @@ int PelrockEngine::isHotspotUnder(int x, int y) {
}
Exit *PelrockEngine::isExitUnder(int x, int y) {
- for (Common::List<Exit>::iterator i = _currentRoomExits.begin(); i != _currentRoomExits.end(); i++) {
- if (x >= i->x && x <= (i->x + i->w) &&
- y >= i->y && y <= (i->y + i->h)) {
- return &(*i);
+ for (int i = 0; i < _currentRoomExits.size(); i++) {
+ Exit exit = _currentRoomExits[i];
+ if (x >= exit.x && x <= (exit.x + exit.w) &&
+ y >= exit.y && y <= (exit.y + exit.h)) {
+ return &(_currentRoomExits[i]);
}
}
return nullptr;
@@ -1756,22 +1752,22 @@ void PelrockEngine::checkMouseClick(int x, int y) {
Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
_curWalkTarget = walkTarget;
- debug("Calculated walk target at (%d, %d)", walkTarget.x, walkTarget.y);
- Exit *exit = isExitAtPoint(walkTarget.x, walkTarget.y);
+ // debug("Calculated walk target at (%d, %d)", walkTarget.x, walkTarget.y);
+ // Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
- if (exit != nullptr) {
+ /*if (exit != nullptr) {
xAlfred = exit->targetX;
yAlfred = exit->targetY;
setScreen(exit->targetRoom, exit->dir);
- } else {
- walkTo(walkTarget.x, walkTarget.y);
- }
-
- int hotspotIndex = isHotspotUnder(mouseX, mouseY);
- if (hotspotIndex != -1) {
- talk();
- debug("Hotspot clicked: %d", _currentRoomHotspots[hotspotIndex].extra);
- }
+ } else {*/
+ walkTo(walkTarget.x, walkTarget.y);
+ /* } */
+
+ // int hotspotIndex = isHotspotUnder(mouseX, mouseY);
+ // if (hotspotIndex != -1) {
+ // talk();
+ // debug("Hotspot clicked: %d", _currentRoomHotspots[hotspotIndex].extra);
+ // }
}
void PelrockEngine::changeCursor(Cursor cursor) {
@@ -1786,7 +1782,7 @@ void PelrockEngine::checkMouseHover() {
// Check if walk target hits any exit
bool exitDetected = false;
- Exit *exit = isExitAtPoint(walkTarget.x, walkTarget.y);
+ Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
if (exit != nullptr) {
exitDetected = true;
}
@@ -1872,18 +1868,6 @@ Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
return bestTarget;
}
-Exit *PelrockEngine::isExitAtPoint(int x, int y) {
- for (Common::List<Exit>::iterator i = _currentRoomExits.begin();
- i != _currentRoomExits.end(); ++i) {
- // Check if point is inside exit trigger rectangle
- if (x >= i->x && x <= (i->x + i->w) &&
- y >= i->y && y <= (i->y + i->h)) {
- return &(*i);
- }
- }
- return nullptr;
-}
-
void PelrockEngine::showDescription(Common::String text, int x, int y, byte color) {
Common::Rect rect = _largeFont->getBoundingBox(text.c_str());
if (x + 2 + rect.width() > 640) {
@@ -1931,7 +1915,9 @@ void PelrockEngine::setScreen(int number, int dir) {
return;
}
dirAlfred = dir;
-
+ isAlfredWalking = false;
+ isAlfredTalking = false;
+ _current_step = 0;
int roomOffset = number * kRoomStructSize;
curAlfredFrame = 0;
byte *palette = new byte[256 * 3];
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 34b767a0dfd..0d9fb5d617c 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -66,7 +66,7 @@ private:
void loadAlfredAnims();
Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
- Common::List<Exit> loadExits(Common::File *roomFile, int roomOffset);
+ Common::Array<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::Array<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos);
@@ -98,7 +98,6 @@ private:
Common::List<VerbIcons> populateActionsMenu(HotSpot *hotspot);
Common::Point calculateWalkTarget(int mouseX, int mouseY);
- Exit *isExitAtPoint(int x, int y);
void showDescription(Common::String text, int x, int y, byte color);
// render loop
@@ -128,15 +127,15 @@ private:
Common::Array<HotSpot> _currentRoomHotspots;
Common::Array<AnimSet> _currentRoomAnims;
- Common::List<Exit> _currentRoomExits;
+ Common::Array<Exit> _currentRoomExits;
Common::Array<WalkBox> _currentRoomWalkboxes;
Common::Array<Description> _currentRoomDescriptions;
Common::Array<ConversationNode> _currentRoomConversations;
int *_currentAnimFrames = nullptr;
// From the original code
- int xAlfred = 200;
- int yAlfred = 200;
+ int xAlfred = 319;
+ int yAlfred = 302;
int dirAlfred = 0;
int curAlfredFrame = 0;
bool isAlfredWalking = false;
Commit: 92489bb33eefded0a9d2b69688947aaf3d84264b
https://github.com/scummvm/scummvm/commit/92489bb33eefded0a9d2b69688947aaf3d84264b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:06+02:00
Commit Message:
PELROCK: Improve text display
Changed paths:
engines/pelrock/chrono.cpp
engines/pelrock/chrono.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index 355df50a828..9bcbd6a8873 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -36,6 +36,11 @@ ChronoManager::~ChronoManager() {
void ChronoManager::updateChrono() {
uint32 currentTime = g_system->getMillis();
+ if(_textTtl > 0) {
+ _textTtl -= (currentTime - _lastTick);
+ if(_textTtl < 0)
+ _textTtl = 0;
+ }
if ((currentTime - _lastTick) >= kTickMs / _speedMultiplier) {
_gameTick = true;
_tickCount++;
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 9dab952fadd..de19a626789 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -44,6 +44,7 @@ public:
bool _gameTick = false;
bool _gameTickHalfSpeed = false;
+ long _textTtl = 0;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index ff3b418667b..a2cc8946ef3 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -91,7 +91,7 @@ void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byt
surface->drawLine(x, y, x, y + h, color);
surface->drawLine(x + w, y, x + w, y + h, color);
}
-
+Common::Array<Common::Array<Common::String> > wordWrap(Common::String text);
Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
initGraphics(640, 400);
@@ -348,21 +348,6 @@ Common::Array<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile,
}
anims.push_back(animSet);
-
- // if (w > 0 && h > 0 && frames > 0) {
- // AnimSet anim;
- // anim.x = x;
- // anim.y = y;
- // anim.w = w;
- // anim.h = h;
- // anim.numAnims = frames;
- // uint32_t needed = anim.w * anim.h * anim.nframes;
- // anim.animData = new byte[needed];
- // Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
- // picOffset += needed;
- // debug("Anim %d: x=%d y=%d w=%d h=%d nframes=%d", i, anim.x, anim.y, anim.w, anim.h, anim.nframes);
- // anims.push_back(anim);
- // }
}
return anims;
}
@@ -448,21 +433,6 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
return descriptions;
}
-/**
- * def decode_byte(b):
- """Decode a byte to character"""
- special = {
- 0x80: 'ñ', 0x81: 'Ã', 0x82: '¡', 0x83: '¿', 0x84: 'ú',
- 0x7B: 'á', 0x7C: 'é', 0x7D: 'Ã', 0x7E: 'ó', 0x7F: 'ú',
- }
-
- if b in special:
- return special[b]
- elif 0x20 <= b <= 0x7A:
- return chr(b)
- else:
- return f'[{b:02X}]'
- */
char32_t decodeByte(byte b) {
if (b == 0x80) {
return '\xA4';
@@ -1242,6 +1212,7 @@ void PelrockEngine::frames() {
if (step.distance_y > 0)
step.distance_y -= MIN((uint16_t)6, step.distance_y);
+
debug("Alfred position after step: x=%d, y=%d, step distance_x=%d, step distance_y=%d", xAlfred, yAlfred, step.distance_x, step.distance_y);
if (step.distance_x <= 0 && step.distance_y <= 0) {
debug("Alfred completed step %d", _current_step);
@@ -1272,16 +1243,12 @@ void PelrockEngine::frames() {
drawAlfred(walkingAnimFrames[dirAlfred][curAlfredFrame]);
curAlfredFrame++;
- // debug("CurAlfredFrame from walking is now %d", curAlfredFrame);
} else if (isAlfredTalking) {
- drawAlfred(talkingAnimFrames[dirAlfred][curAlfredFrame]);
-
- if (curAlfredFrame < talkingAnimLengths[dirAlfred] - 1) {
- curAlfredFrame++;
- } else {
+ if (curAlfredFrame >= talkingAnimLengths[dirAlfred] - 1) {
curAlfredFrame = 0;
}
- debug("CurAlfredFrame from talking is now %d", curAlfredFrame);
+ drawAlfred(talkingAnimFrames[dirAlfred][curAlfredFrame]);
+ curAlfredFrame++;
} else {
drawAlfred(standingAnimFrames[dirAlfred]);
}
@@ -1307,6 +1274,26 @@ void PelrockEngine::frames() {
}
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+
+ if (!_currentTextPages.empty()) {
+ // debug("Will render text, _chronoManager->_textTtl=%d", _chronoManager->_textTtl);
+ if (_chronoManager->_textTtl > 0) {
+ renderText(_currentTextPages[_currentTextPageIndex], _textColor);
+ } else if (_currentTextPageIndex < _currentTextPages.size() - 1) {
+ _currentTextPageIndex++;
+
+ int totalChars = 0;
+ for (int i = 0; i < _currentTextPages[_currentTextPageIndex].size(); i++) {
+ totalChars += _currentTextPages[_currentTextPageIndex][i].size();
+ }
+ _chronoManager->_textTtl = totalChars * kTextCharDisplayTime;
+ } else {
+ _currentTextPages.clear();
+ _currentTextPageIndex = 0;
+ isAlfredTalking = false;
+ }
+ }
+
// debug("Drawing walkboxes..., %d, _currentRoomWalkboxes.size()=%d", _currentRoomWalkboxes.size(), _currentRoomWalkboxes.size());
for (int i = 0; i < _currentRoomWalkboxes.size(); i++) {
// debug("Drawing walkbox %d", i);
@@ -1337,6 +1324,26 @@ void PelrockEngine::frames() {
}
}
+void PelrockEngine::renderText(Common::Array<Common::String> lines, int color) {
+ if (color == ALFRED_COLOR) {
+ int baseX = xAlfred;
+ int baseY = yAlfred - kAlfredFrameHeight - 10;
+ int maxW = 0;
+ for (size_t i = 0; i < lines.size(); i++) {
+ Common::Rect r = _largeFont->getBoundingBox(lines[i]);
+ if (r.width() > maxW) {
+ maxW = r.width();
+ }
+ }
+ int lineSize = lines.size();
+ for (size_t i = 0; i < lines.size(); i++) {
+ int textX = baseX - (maxW / 2);
+ int textY = baseY - (lineSize * 20) + (i * 20);
+ drawText(lines[i], textX, textY, maxW, color);
+ }
+ }
+}
+
void PelrockEngine::drawAlfred(byte *buf) {
drawSpriteToBuffer(_compositeBuffer, 640, buf, xAlfred, yAlfred - kAlfredFrameHeight, kAlfredFrameWidth, kAlfredFrameHeight, 255);
@@ -1760,14 +1767,15 @@ void PelrockEngine::checkMouseClick(int x, int y) {
yAlfred = exit->targetY;
setScreen(exit->targetRoom, exit->dir);
} else {*/
- walkTo(walkTarget.x, walkTarget.y);
/* } */
- // int hotspotIndex = isHotspotUnder(mouseX, mouseY);
- // if (hotspotIndex != -1) {
- // talk();
- // debug("Hotspot clicked: %d", _currentRoomHotspots[hotspotIndex].extra);
- // }
+ int hotspotIndex = isHotspotUnder(mouseX, mouseY);
+ if (hotspotIndex != -1) {
+ sayAlfred(_currentRoomDescriptions[hotspotIndex].text);
+ debug("Hotspot clicked: %d", _currentRoomHotspots[hotspotIndex].extra);
+ } else {
+ walkTo(walkTarget.x, walkTarget.y);
+ }
}
void PelrockEngine::changeCursor(Cursor cursor) {
@@ -1868,7 +1876,7 @@ Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
return bestTarget;
}
-void PelrockEngine::showDescription(Common::String text, int x, int y, byte color) {
+void PelrockEngine::drawText(Common::String text, int x, int y, int w, byte color) {
Common::Rect rect = _largeFont->getBoundingBox(text.c_str());
if (x + 2 + rect.width() > 640) {
x = 640 - rect.width() - 2;
@@ -1883,28 +1891,153 @@ void PelrockEngine::showDescription(Common::String text, int x, int y, byte colo
y = 2;
}
- x = 2;
- y = 2;
- // if (_bgText != nullptr) {
- // putBackgroundSlice(x, y, 640, 400, _bgText);
- // delete[] _bgText;
- // }
- int16 w = MIN(rect.width(), (int16)(640 - x));
- int16 h = MIN(rect.height(), (int16)(400 - y));
- debug("grabbing bg slice at (%d,%d) w=%d h=%d", x, y, w, h);
-
- // _bgText = grabBackgroundSlice(x, y, 640, 400);
- _largeFont->drawString(_screen, text.c_str(), x - 1, y, 640, 0); // Left
- _largeFont->drawString(_screen, text.c_str(), x - 2, y, 640, 0); // Left
- _largeFont->drawString(_screen, text.c_str(), x + 1, y, 640, 0); // Right
- _largeFont->drawString(_screen, text.c_str(), x + 2, y, 640, 0); // Right
- _largeFont->drawString(_screen, text.c_str(), x, y - 1, 640, 0); // Top
- _largeFont->drawString(_screen, text.c_str(), x, y - 2, 640, 0); // Top
- _largeFont->drawString(_screen, text.c_str(), x, y + 1, 640, 0); // Bottom
- _largeFont->drawString(_screen, text.c_str(), x, y + 2, 640, 0); // Bottom
+ _largeFont->drawString(_screen, text.c_str(), x - 1, y, w, 0, Graphics::kTextAlignCenter); // Left
+ // _largeFont->drawString(_screen, text.c_str(), x - 2, y, 640, 0); // Left
+ _largeFont->drawString(_screen, text.c_str(), x + 1, y, w, 0, Graphics::kTextAlignCenter); // Right
+ // _largeFont->drawString(_screen, text.c_str(), x + 2, y, 640, 0); // Right
+ _largeFont->drawString(_screen, text.c_str(), x, y - 1, w, 0, Graphics::kTextAlignCenter); // Top
+ // _largeFont->drawString(_screen, text.c_str(), x, y - 2, 640, 0); // Top
+ _largeFont->drawString(_screen, text.c_str(), x, y + 1, w, 0, Graphics::kTextAlignCenter); // Bottom
+ // _largeFont->drawString(_screen, text.c_str(), x, y + 2, 640, 0); // Bottom
// Draw main text on top
- _largeFont->drawString(_screen, text.c_str(), x, y, 640, color);
+ _largeFont->drawString(_screen, text.c_str(), x, y, w, color, Graphics::kTextAlignCenter);
+}
+
+void PelrockEngine::sayAlfred(Common::String text) {
+ isAlfredTalking = true;
+ curAlfredFrame = 0;
+ debug("Alfred says: %s", text.c_str());
+ _currentTextPages = wordWrap(text);
+ _textColor = 13;
+ int totalChars = 0;
+ for (int i = 0; i < _currentTextPages[0].size(); i++) {
+ totalChars += _currentTextPages[0][i].size();
+ }
+ _chronoManager->_textTtl = totalChars * kTextCharDisplayTime;
+}
+bool isEndMarker(char char_byte) {
+ return char_byte == CHAR_END_MARKER_1 || char_byte == CHAR_END_MARKER_2 || char_byte == CHAR_END_MARKER_3 || char_byte == CHAR_END_MARKER_4;
+}
+
+int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
+ // return word_length, is_end
+ int wordLength = 0;
+ int pos = startPos;
+ while (pos < text.size()) {
+ char char_byte = text[pos];
+ if (char_byte == CHAR_SPACE || isEndMarker(char_byte)) {
+ break;
+ }
+ wordLength++;
+ pos++;
+ }
+ // Check if we hit an end marker
+ if (pos < text.size() && isEndMarker(text[pos])) {
+ isEnd = true;
+ }
+ // Count ALL trailing spaces as part of this word
+ if (pos < text.size() && !isEnd) {
+ if (text[pos] == CHAR_END_MARKER_3) { // 0xF8 (-8) special case
+ wordLength += 3;
+ } else {
+ // Count all consecutive spaces
+ while (pos < text.size() && text[pos] == CHAR_SPACE) {
+ wordLength++;
+ pos++;
+ }
+ }
+ }
+ return wordLength;
+}
+
+Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator) {
+ Common::String result;
+ for (uint i = 0; i < strings.size(); i++) {
+ result += strings[i];
+ if (i < strings.size() - 1)
+ result += separator;
+ }
+ return result;
+}
+
+Common::Array<Common::Array<Common::String> > wordWrap(Common::String text) {
+
+ Common::Array<Common::Array<Common::String> > pages;
+ Common::Array<Common::String> currentPage;
+ Common::Array<Common::String> currentLine;
+ int charsRemaining = MAX_CHARS_PER_LINE;
+ int position = 0;
+ int currentLineNum = 0;
+ while (position < text.size()) {
+ bool isEnd = false;
+ int wordLength = calculateWordLength(text, position, isEnd);
+ // # Extract the word (including trailing spaces)
+ // word = text[position:position + word_length].decode('latin-1', errors='replace')
+ Common::String word = text.substr(position, wordLength).decode(Common::kLatin1);
+ // # Key decision: if word_length > chars_remaining, wrap to next line
+ if (wordLength > charsRemaining) {
+ // Word is longer than the entire line - need to split
+ currentPage.push_back(joinStrings(currentLine, " "));
+ currentLine.clear();
+ charsRemaining = MAX_CHARS_PER_LINE;
+ currentLineNum++;
+
+ if (currentLineNum >= MAX_LINES) {
+ pages.push_back(currentPage);
+ currentPage.clear();
+ currentLineNum = 0;
+ }
+ }
+ // Add word to current line
+ currentLine.push_back(word);
+ charsRemaining -= wordLength;
+
+ if (charsRemaining == 0 && isEnd) {
+ Common::String lineText = joinStrings(currentLine, "");
+ while (lineText.lastChar() == CHAR_SPACE) {
+ lineText = lineText.substr(0, lineText.size() - 1);
+ }
+ int trailingSpaces = currentLine.size() - lineText.size();
+ if (trailingSpaces > 0) {
+ currentPage.push_back(lineText);
+ // current_line = [' ' * trailing_spaces]
+ Common::String currentLine(trailingSpaces, ' ');
+ charsRemaining = MAX_CHARS_PER_LINE - trailingSpaces;
+ currentLineNum += 1;
+
+ if (currentLineNum >= MAX_LINES) {
+ pages.push_back(currentPage);
+ currentPage.clear();
+ currentLineNum = 0;
+ }
+ }
+ }
+
+ position += wordLength;
+ if (isEnd) {
+ // End of sentence/paragraph/page
+ break;
+ }
+ }
+ if (currentLine.empty() == false) {
+ Common::String lineText = joinStrings(currentLine, "");
+ while (lineText.lastChar() == CHAR_SPACE) {
+ lineText = lineText.substr(0, lineText.size() - 1);
+ }
+ currentPage.push_back(lineText);
+ }
+ if (currentPage.empty() == false) {
+ pages.push_back(currentPage);
+ }
+ debug("Word wrap produced %d pages", pages.size());
+ for (int i = 0; i < pages.size(); i++) {
+ debug(" Page %d:", i);
+ for (int j = 0; j < pages[i].size(); j++) {
+ debug(" Line %d: %s", j, pages[i][j].c_str());
+ }
+ }
+ return pages;
}
void PelrockEngine::setScreen(int number, int dir) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 0d9fb5d617c..6e744c3761e 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -98,10 +98,12 @@ private:
Common::List<VerbIcons> populateActionsMenu(HotSpot *hotspot);
Common::Point calculateWalkTarget(int mouseX, int mouseY);
- void showDescription(Common::String text, int x, int y, byte color);
+ void drawText(Common::String text, int x, int y, int w, byte color);
+ void sayAlfred(Common::String text);
// render loop
void frames();
+ void renderText(Common::Array<Common::String> lines, int color);
void drawAlfred(byte *buf);
void checkMouseHover();
void checkMouseClick(int x, int y);
@@ -124,7 +126,9 @@ private:
PathContext _currentContext;
int _current_step = 0;
-
+ byte _textColor = 0;
+ Common::Array<Common::Array<Common::String> > _currentTextPages = Common::Array<Common::Array<Common::String> >();
+ int _currentTextPageIndex = 0;
Common::Array<HotSpot> _currentRoomHotspots;
Common::Array<AnimSet> _currentRoomAnims;
Common::Array<Exit> _currentRoomExits;
@@ -153,11 +157,6 @@ private:
byte *_currentBackground; // Clean background - NEVER modified
byte *_compositeBuffer; // Working composition buffer
- // byte *_currentBackground = nullptr;
- // byte *_bgPopupBalloon = nullptr;
- // byte *_bgText = nullptr;
- // byte *_bgAlfred = nullptr;
-
bool _displayPopup = false;
int _popupX = 0;
int _popupY = 0;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 065d773f4b7..766df2dc150 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -47,14 +47,6 @@ enum VerbIcons {
UNKNOWN
};
-// enum HoverState {
-// NONE,
-// INTERACTIVE,
-// HOSTPOT,
-// SPECIAl;
-
-// };
-
static const uint32 kLongClickDuration = 500; // 500ms for long click
const int kCursorWidth = 16;
const int kCursorHeight = 18;
@@ -67,6 +59,7 @@ const int kNumVerbIcons = 9;
const int kBalloonWidth = 247;
const int kBalloonHeight = 112;
const int kBalloonFrames = 4;
+const int kTextCharDisplayTime = 100; // 10ms per character
// Direction flags (bit-packed)
#define MOVE_RIGHT 0x01 // Move right (positive X)
@@ -79,8 +72,22 @@ const int kBalloonFrames = 4;
#define MAX_MOVEMENT_STEPS 100 // 500 bytes / 5 bytes per step
#define PATH_END 0xFF // End of path marker
+#define MAX_CHARS_PER_LINE 0x2F // 47 characters
+#define MAX_LINES 5 // Maximum number of lines per page (0-indexed check against 4)
+
+// Control character codes (negative values in signed char)
+#define CHAR_SPACE 0x20 /* ' ' */
+#define CHAR_END_MARKER_1 0xFD /* -3 (end of text marker) */
+#define CHAR_END_MARKER_2 0xF4 /* -0xC (alternate end marker) */
+#define CHAR_END_MARKER_3 0xF8 /* -8 (another end marker) */
+#define CHAR_END_MARKER_4 0xF0 /* -0x10 (another end marker) */
+#define CHAR_NEWLINE 0xF6 /* -10 (newline marker) */
+#define CHAR_PAGE_BREAK 0xF9 /* marker inserted when switching pages */
+
+#define ALFRED_COLOR 0x0D
+
typedef struct {
- uint8_t flags; // Direction flags (see MOVE_* constants)
+ uint8_t flags; /* Direction flags (see MOVE_* constants) */
uint16_t distance_x; // Horizontal distance to move
uint16_t distance_y; // Vertical distance to move
} MovementStep;
@@ -217,24 +224,6 @@ enum GameState {
PROMOTE = 107,
};
-// enum ConversationMarkers : byte {
-// END_LINE(0xFD),
-// TEXT_TERM(0xFC),
-// CHOICE(0xFB),
-// SKIP(0xFA),
-// PAGE_BREAK(0xF9),
-// ACTION(0xF8),
-// END_BRANCH(0xF7),
-// LINE_CONT(0xF6),
-// END_BRANCH_2(0xF5),
-// END_CONV(0xF4),
-// GO_BACK(0xF0),
-// END_BRANCH_3(0xFE),
-// END_ALT(0xEB),
-// DESC_START(0xFF),
-// SPEAKER(0x08)
-// };
-
} // End of namespace Pelrock
#endif
Commit: 18060a6d5fa7b1eaf7e27f80efc811f29572266f
https://github.com/scummvm/scummvm/commit/18060a6d5fa7b1eaf7e27f80efc811f29572266f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:06+02:00
Commit Message:
PELROCK: Adds extra pixel char width on font
Changed paths:
engines/pelrock/fonts/large_font.cpp
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index 9f94f855921..c27b7458c0c 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -47,7 +47,7 @@ bool LargeFont::load(const Common::String &filename) {
}
int LargeFont::getCharWidth(uint32 chr) const {
- return CHAR_WIDTH;
+ return CHAR_WIDTH + 1;
}
void LargeFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
Commit: cbe2b9958d2017062f41c8be01cf54ed775e1ff1
https://github.com/scummvm/scummvm/commit/cbe2b9958d2017062f41c8be01cf54ed775e1ff1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:07+02:00
Commit Message:
PELROCK: Font rendering
Changed paths:
engines/pelrock/chrono.cpp
engines/pelrock/fonts/large_font.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index 9bcbd6a8873..8201dc15427 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -36,11 +36,12 @@ ChronoManager::~ChronoManager() {
void ChronoManager::updateChrono() {
uint32 currentTime = g_system->getMillis();
- if(_textTtl > 0) {
+ if(_textTtl > 0 && g_engine->isAlfredTalking && !g_engine->isAlfredWalking) {
_textTtl -= (currentTime - _lastTick);
if(_textTtl < 0)
_textTtl = 0;
}
+
if ((currentTime - _lastTick) >= kTickMs / _speedMultiplier) {
_gameTick = true;
_tickCount++;
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index c27b7458c0c..9a1dc5894e0 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -37,12 +37,75 @@ bool LargeFont::load(const Common::String &filename) {
}
file.seek(0x7DC8, SEEK_SET);
- const int dataSize = 96 * 48; // 96 characters à 48 bytes
- _fontData = new byte[dataSize];
- file.read(_fontData, dataSize);
+ const int numChars = 96;
+ const int charWidth = 12;
+ const int charHeight = 24;
+ const int pad = 1;
+
+ const int paddedWidth = charWidth + 2 * pad; // 14
+ const int paddedHeight = charHeight + 2 * pad; // 26
+
+ const int dataSize = numChars * paddedHeight * paddedWidth; // 96 characters à 14 à 26 bytes
+ byte *rawFontData = new byte[numChars * 48]; // original format: 96 Ã 48 bytes
+ file.read(rawFontData, numChars * 48);
debug("LargeFont::load: Loading large font data from %s, size %d bytes", filename.c_str(), dataSize);
file.close();
+ delete[] _fontData;
+
+ _fontData = new byte[dataSize];
+ memset(_fontData, 0, dataSize);
+ for (int c = 0; c < numChars; c++) {
+ // Temporary bitmap for character + border
+ bool mask[paddedHeight][paddedWidth] = {false};
+ // Decode character pixels from rawFontData
+ int charOffset = c * 0x30;
+ for (int i = 0; i < charHeight; i++) {
+ byte rowByte1 = rawFontData[charOffset + i * 2];
+ byte rowByte2 = rawFontData[charOffset + i * 2 + 1];
+ for (int bit = 0; bit < 8; bit++) {
+ mask[i + pad][bit + pad] = (rowByte1 & (0x80 >> bit)) != 0;
+ }
+ for (int bit = 0; bit < 4; bit++) {
+ mask[i + pad][bit + 8 + pad] = (rowByte2 & (0x80 >> bit)) != 0;
+ }
+ }
+
+ bool borderMask[paddedHeight][paddedWidth] = {false};
+
+ for (int y = 0; y < paddedHeight; y++) {
+ for (int x = 0; x < paddedWidth; x++) {
+ if (mask[y][x]) {
+ // Mark 3x3 area around character pixel
+ for (int dy = -1; dy <= 1; dy++) {
+ for (int dx = -1; dx <= 1; dx++) {
+ int ny = y + dy;
+ int nx = x + dx;
+ if (ny >= 0 && ny < paddedHeight && nx >= 0 && nx < paddedWidth) {
+ if (!mask[ny][nx]) {
+ borderMask[ny][nx] = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ int outOffset = c * paddedHeight * paddedWidth;
+ for (int y = 0; y < paddedHeight; y++) {
+ for (int x = 0; x < paddedWidth; x++) {
+ if (mask[y][x]) {
+ _fontData[outOffset + y * paddedWidth + x] = 2;
+ } else if (borderMask[y][x]) {
+ _fontData[outOffset + y * paddedWidth + x] = 1;
+ } else {
+ _fontData[outOffset + y * paddedWidth + x] = 0;
+ }
+ }
+ }
+ }
+ delete[] rawFontData;
return true;
}
@@ -55,24 +118,22 @@ void LargeFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint3
if (!_fontData || chr > 96 || chr < 0) {
return;
}
- int charOffset = chr * 0x30;
- for (int i = 0; i < 24; i++) {
- byte rowByte1 = _fontData[charOffset + i * 2];
- byte rowByte2 = _fontData[charOffset + i * 2 + 1];
- for (int bit = 0; bit < 8; bit++) {
- bool pixelOn = (rowByte1 & (0x80 >> bit)) != 0;
- if (pixelOn) {
- if ((x + bit) < dst->w && (y + i) < dst->h) {
- *((byte *)dst->getBasePtr(x + bit, y + i)) = color;
- }
- }
- }
- for (int bit = 0; bit < 4; bit++) {
- bool pixelOn = (rowByte2 & (0x80 >> bit)) != 0;
- if (pixelOn) {
- if ((x + bit + 8) < dst->w && (y + i) < dst->h) {
- *((byte *)dst->getBasePtr(x + bit + 8, y + i)) = color;
- }
+
+ const int paddedWidth = 14;
+ const int paddedHeight = 26;
+ int charOffset = chr * paddedWidth * paddedHeight;
+
+ for (int cy = 0; cy < paddedHeight; cy++) {
+ for (int cx = 0; cx < paddedWidth; cx++) {
+ byte val = _fontData[charOffset + cy * paddedWidth + cx];
+ int px = x + cx;
+ int py = y + cy;
+ if (px < 0 || px >= dst->w || py < 0 || py >= dst->h)
+ continue;
+ if (val == 1) {
+ *((byte *)dst->getBasePtr(px, py)) = 0;
+ } else if (val == 2) {
+ *((byte *)dst->getBasePtr(px, py)) = color;
}
}
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a2cc8946ef3..5300ae37dae 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1275,7 +1275,7 @@ void PelrockEngine::frames() {
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- if (!_currentTextPages.empty()) {
+ if (!isAlfredWalking && !_currentTextPages.empty()) {
// debug("Will render text, _chronoManager->_textTtl=%d", _chronoManager->_textTtl);
if (_chronoManager->_textTtl > 0) {
renderText(_currentTextPages[_currentTextPageIndex], _textColor);
@@ -1773,9 +1773,9 @@ void PelrockEngine::checkMouseClick(int x, int y) {
if (hotspotIndex != -1) {
sayAlfred(_currentRoomDescriptions[hotspotIndex].text);
debug("Hotspot clicked: %d", _currentRoomHotspots[hotspotIndex].extra);
- } else {
- walkTo(walkTarget.x, walkTarget.y);
}
+
+ walkTo(walkTarget.x, walkTarget.y);
}
void PelrockEngine::changeCursor(Cursor cursor) {
@@ -1891,14 +1891,14 @@ void PelrockEngine::drawText(Common::String text, int x, int y, int w, byte colo
y = 2;
}
- _largeFont->drawString(_screen, text.c_str(), x - 1, y, w, 0, Graphics::kTextAlignCenter); // Left
- // _largeFont->drawString(_screen, text.c_str(), x - 2, y, 640, 0); // Left
- _largeFont->drawString(_screen, text.c_str(), x + 1, y, w, 0, Graphics::kTextAlignCenter); // Right
- // _largeFont->drawString(_screen, text.c_str(), x + 2, y, 640, 0); // Right
- _largeFont->drawString(_screen, text.c_str(), x, y - 1, w, 0, Graphics::kTextAlignCenter); // Top
- // _largeFont->drawString(_screen, text.c_str(), x, y - 2, 640, 0); // Top
- _largeFont->drawString(_screen, text.c_str(), x, y + 1, w, 0, Graphics::kTextAlignCenter); // Bottom
- // _largeFont->drawString(_screen, text.c_str(), x, y + 2, 640, 0); // Bottom
+ // _largeFont->drawString(_screen, text.c_str(), x - 1, y, w, 0, Graphics::kTextAlignCenter); // Left
+ // // _largeFont->drawString(_screen, text.c_str(), x - 2, y, w, 0, Graphics::kTextAlignCenter); // Left
+ // _largeFont->drawString(_screen, text.c_str(), x + 1, y, w, 0, Graphics::kTextAlignCenter); // Right
+ // // _largeFont->drawString(_screen, text.c_str(), x + 2, y, w, 0, Graphics::kTextAlignCenter); // Right
+ // _largeFont->drawString(_screen, text.c_str(), x, y - 1, w, 0, Graphics::kTextAlignCenter); // Top
+ // // _largeFont->drawString(_screen, text.c_str(), x, y - 2, w, 0, Graphics::kTextAlignCenter); // Top
+ // _largeFont->drawString(_screen, text.c_str(), x, y + 1, w, 0, Graphics::kTextAlignCenter); // Bottom
+ // // _largeFont->drawString(_screen, text.c_str(), x, y + 2, w, 0, Graphics::kTextAlignCenter); // Bottom
// Draw main text on top
_largeFont->drawString(_screen, text.c_str(), x, y, w, color, Graphics::kTextAlignCenter);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 6e744c3761e..875f38380b7 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -142,8 +142,6 @@ private:
int yAlfred = 302;
int dirAlfred = 0;
int curAlfredFrame = 0;
- bool isAlfredWalking = false;
- bool isAlfredTalking = false;
uint16 mouseX = 0;
uint16 mouseY = 0;
byte *_cursorMasks[5] = {nullptr};
@@ -184,6 +182,8 @@ protected:
public:
Graphics::Screen *_screen = nullptr;
+ bool isAlfredWalking = false;
+ bool isAlfredTalking = false;
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 766df2dc150..10f9bdaf2a6 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -47,6 +47,8 @@ enum VerbIcons {
UNKNOWN
};
+
+
static const uint32 kLongClickDuration = 500; // 500ms for long click
const int kCursorWidth = 16;
const int kCursorHeight = 18;
@@ -72,20 +74,21 @@ const int kTextCharDisplayTime = 100; // 10ms per character
#define MAX_MOVEMENT_STEPS 100 // 500 bytes / 5 bytes per step
#define PATH_END 0xFF // End of path marker
-#define MAX_CHARS_PER_LINE 0x2F // 47 characters
-#define MAX_LINES 5 // Maximum number of lines per page (0-indexed check against 4)
+#define MAX_CHARS_PER_LINE 0x2F // 47 characters
+#define MAX_LINES 5 // Maximum number of lines per page (0-indexed check against 4)
// Control character codes (negative values in signed char)
-#define CHAR_SPACE 0x20 /* ' ' */
-#define CHAR_END_MARKER_1 0xFD /* -3 (end of text marker) */
-#define CHAR_END_MARKER_2 0xF4 /* -0xC (alternate end marker) */
-#define CHAR_END_MARKER_3 0xF8 /* -8 (another end marker) */
-#define CHAR_END_MARKER_4 0xF0 /* -0x10 (another end marker) */
-#define CHAR_NEWLINE 0xF6 /* -10 (newline marker) */
-#define CHAR_PAGE_BREAK 0xF9 /* marker inserted when switching pages */
+#define CHAR_SPACE 0x20 /* ' ' */
+#define CHAR_END_MARKER_1 0xFD /* -3 (end of text marker) */
+#define CHAR_END_MARKER_2 0xF4 /* -0xC (alternate end marker) */
+#define CHAR_END_MARKER_3 0xF8 /* -8 (another end marker) */
+#define CHAR_END_MARKER_4 0xF0 /* -0x10 (another end marker) */
+#define CHAR_NEWLINE 0xF6 /* -10 (newline marker) */
+#define CHAR_PAGE_BREAK 0xF9 /* marker inserted when switching pages */
#define ALFRED_COLOR 0x0D
+
typedef struct {
uint8_t flags; /* Direction flags (see MOVE_* constants) */
uint16_t distance_x; // Horizontal distance to move
Commit: 7148baeb8704be2a2dce2d8bbee701fddae27533
https://github.com/scummvm/scummvm/commit/7148baeb8704be2a2dce2d8bbee701fddae27533
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:07+02:00
Commit Message:
PELROCK: Eliminates extra space in text dialog
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 5300ae37dae..2b4bc07ea21 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1338,7 +1338,7 @@ void PelrockEngine::renderText(Common::Array<Common::String> lines, int color) {
int lineSize = lines.size();
for (size_t i = 0; i < lines.size(); i++) {
int textX = baseX - (maxW / 2);
- int textY = baseY - (lineSize * 20) + (i * 20);
+ int textY = baseY - (lineSize * 25) + (i * 25);
drawText(lines[i], textX, textY, maxW, color);
}
}
@@ -1978,7 +1978,7 @@ Common::Array<Common::Array<Common::String> > wordWrap(Common::String text) {
// # Key decision: if word_length > chars_remaining, wrap to next line
if (wordLength > charsRemaining) {
// Word is longer than the entire line - need to split
- currentPage.push_back(joinStrings(currentLine, " "));
+ currentPage.push_back(joinStrings(currentLine, ""));
currentLine.clear();
charsRemaining = MAX_CHARS_PER_LINE;
currentLineNum++;
Commit: b007fac21bb17e26e9375fe52f113204644ead49
https://github.com/scummvm/scummvm/commit/b007fac21bb17e26e9375fe52f113204644ead49
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:07+02:00
Commit Message:
PELROCK: Click on action
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 2b4bc07ea21..a9201c69717 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -91,6 +91,15 @@ void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byt
surface->drawLine(x, y, x, y + h, color);
surface->drawLine(x + w, y, x + w, y + h, color);
}
+void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color) {
+ // debug("Drawing rect at (%d,%d) w=%d h=%d color=%d", x, y, w, h, color);
+ surface->drawLine(x, y, x + w, y, color);
+ surface->drawLine(x, y + h, x + w, y + h, color);
+ surface->drawLine(x, y, x, y + h, color);
+ surface->drawLine(x + w, y, x + w, y + h, color);
+}
+
+
Common::Array<Common::Array<Common::String> > wordWrap(Common::String text);
Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
@@ -465,9 +474,7 @@ char32_t decodeByte(byte b) {
void PelrockEngine::talk() {
if (_currentRoomConversations.size() == 0)
return;
- int x = _currentRoomHotspots[0].x;
- int y = _currentRoomHotspots[0].y;
- debug("Say %s", _currentRoomConversations[0].text.c_str());
+
// showDescription(_currentRoomConversations[0].text, x, y, _currentRoomConversations[0].speakerId);
// for(int i = 0; i < _currentRoomConversations[0].choices.size(); i++) {
// int idx = _currentRoomConversations.size() - 1 - i;
@@ -843,10 +850,10 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
Common::Array<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
Common::Array<HotSpot> hotspots;
- int count = 0;
for (int i = 0; i < anims.size(); i++) {
HotSpot thisHotspot;
+ thisHotspot.index = i;
thisHotspot.x = anims[i].x;
thisHotspot.y = anims[i].y;
thisHotspot.w = anims[i].w;
@@ -855,7 +862,6 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
thisHotspot.type = anims[i].actionFlags;
thisHotspot.isEnabled = !anims[i].isDisabled;
hotspots.push_back(thisHotspot);
- count++;
}
Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
@@ -866,6 +872,7 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
for (int i = 0; i < staticHotspots.size(); i++) {
HotSpot hotspot = staticHotspots[i];
+ hotspot.index = anims.size() + i;
hotspots.push_back(hotspot);
}
@@ -879,12 +886,12 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
- drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
+ // drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
}
for (int i = 0; i < _currentRoomExits.size(); i++) {
Exit exit = _currentRoomExits[i];
- drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
+ // drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
}
}
@@ -1100,8 +1107,8 @@ void drawSpriteToBuffer(byte *buffer, int bufferWidth,
}
}
-Common::List<VerbIcons> PelrockEngine::populateActionsMenu(HotSpot *hotspot) {
- Common::List<VerbIcons> verbs;
+Common::Array<VerbIcons> PelrockEngine::availableActions(HotSpot *hotspot) {
+ Common::Array<VerbIcons> verbs;
debug("Populating actions menu for hotspot type %d", hotspot->type);
verbs.push_back(LOOK);
@@ -1184,7 +1191,7 @@ void PelrockEngine::frames() {
if (isAlfredWalking) {
MovementStep step = _currentContext.movement_buffer[_current_step];
- debug("Alfred step: distance_x=%d, distance_y=%d", step.distance_x, step.distance_y);
+ // debug("Alfred step: distance_x=%d, distance_y=%d", step.distance_x, step.distance_y);
if (step.distance_x > 0) {
if (step.flags & MOVE_RIGHT) {
@@ -1213,12 +1220,12 @@ void PelrockEngine::frames() {
if (step.distance_y > 0)
step.distance_y -= MIN((uint16_t)6, step.distance_y);
- debug("Alfred position after step: x=%d, y=%d, step distance_x=%d, step distance_y=%d", xAlfred, yAlfred, step.distance_x, step.distance_y);
+ // debug("Alfred position after step: x=%d, y=%d, step distance_x=%d, step distance_y=%d", xAlfred, yAlfred, step.distance_x, step.distance_y);
if (step.distance_x <= 0 && step.distance_y <= 0) {
- debug("Alfred completed step %d", _current_step);
+ // debug("Alfred completed step %d", _current_step);
_current_step++;
if (_current_step >= _currentContext.movement_count) {
- debug("Alfred reached his walk target.");
+ // debug("Alfred reached his walk target.");
_current_step = 0;
isAlfredWalking = false;
}
@@ -1234,7 +1241,7 @@ void PelrockEngine::frames() {
setScreen(exit->targetRoom, exit->dir);
}
- debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
+ // debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
if (curAlfredFrame >= walkingAnimLengths[dirAlfred]) {
curAlfredFrame = 0;
@@ -1298,7 +1305,7 @@ void PelrockEngine::frames() {
for (int i = 0; i < _currentRoomWalkboxes.size(); i++) {
// debug("Drawing walkbox %d", i);
WalkBox box = _currentRoomWalkboxes[i];
- drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
+ // drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
}
if (_curWalkTarget.x < 640 && _curWalkTarget.y < 400 && _curWalkTarget.x >= 0 && _curWalkTarget.y >= 0) {
_screen->setPixel(_curWalkTarget.x, _curWalkTarget.y, 100);
@@ -1324,6 +1331,9 @@ void PelrockEngine::frames() {
}
}
+void PelrockEngine::doAction(byte object, byte action) {
+}
+
void PelrockEngine::renderText(Common::Array<Common::String> lines, int color) {
if (color == ALFRED_COLOR) {
int baseX = xAlfred;
@@ -1395,19 +1405,33 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
return nullptr;
}
+void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY) {
+ for (int y = 0; y < surface->h; y++) {
+ for (int x = 0; x < surface->w; x++) {
+ int px = destX + x;
+ int py = destY + y;
+ if (px >= 0 && px < bufferWidth && py >= 0 && py < bufferHeight) {
+ byte pixel = *((byte *)surface->getBasePtr(x, y));
+ buffer[py * bufferWidth + px] = pixel;
+ }
+ }
+ }
+}
+
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
- Common::List<VerbIcons> availableActions = populateActionsMenu(_currentHotspot);
+ Common::Array<VerbIcons> actions = availableActions(_currentHotspot);
drawSpriteToBuffer(_compositeBuffer, 640, _verbIcons[LOOK], posx + 20, posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
- for (Common::List<VerbIcons>::iterator i = availableActions.begin(); i != availableActions.end(); i++) {
- VerbIcons verb = *i;
- int index = 0;
- for (Common::List<VerbIcons>::iterator j = availableActions.begin(); j != i; j++) {
- index++;
- }
- drawSpriteToBuffer(_compositeBuffer, 640, _verbIcons[verb], posx + 20 + (index * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
+ // Graphics::Surface rects;
+ // rects.create(kVerbIconWidth, kVerbIconHeight, Graphics::PixelFormat::createFormatCLUT8());
+ // drawRect(&rects, 0, 0, kVerbIconWidth, kVerbIconHeight, 255);
+
+ // blitSurfaceToBuffer(&rects, _compositeBuffer, 640, 480, posx + ver, posy + 20);
+
+ for(int i = 0; i < actions.size(); i++) {
+ drawSpriteToBuffer(_compositeBuffer, 640, _verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
}
@@ -1418,32 +1442,32 @@ void PelrockEngine::walkTo(int x, int y) {
PathContext context = {NULL, NULL, NULL, 0, 0, 0};
pathFind(x, y, &context);
- debug("\nPath Information:\n");
- debug("================\n");
+ // debug("\nPath Information:\n");
+ // debug("================\n");
- debug("Walkbox path (%d boxes): ", context.path_length);
+ // debug("Walkbox path (%d boxes): ", context.path_length);
for (int i = 0; i < context.path_length && context.path_buffer[i] != PATH_END; i++) {
debug("%d ", context.path_buffer[i]);
}
- debug("Movement steps (%d steps):\n", context.movement_count);
+ // debug("Movement steps (%d steps):\n", context.movement_count);
for (int i = 0; i < context.movement_count; i++) {
MovementStep *step = &context.movement_buffer[i];
- debug(" Step %d: ", i);
+ // debug(" Step %d: ", i);
- if (step->flags & MOVE_RIGHT)
- debug("RIGHT ");
- if (step->flags & MOVE_LEFT)
- debug("LEFT ");
- if (step->flags & MOVE_DOWN)
- debug("DOWN ");
- if (step->flags & MOVE_UP)
- debug("UP ");
+ // if (step->flags & MOVE_RIGHT)
+ // debug("RIGHT ");
+ // if (step->flags & MOVE_LEFT)
+ // debug("LEFT ");
+ // if (step->flags & MOVE_DOWN)
+ // debug("DOWN ");
+ // if (step->flags & MOVE_UP)
+ // debug("UP ");
- debug("(dx=%d, dy=%d)\n", step->distance_x, step->distance_y);
+ // debug("(dx=%d, dy=%d)\n", step->distance_x, step->distance_y);
}
- debug("\nCompressed path (%d bytes): ", context.compressed_length);
+ // debug("\nCompressed path (%d bytes): ", context.compressed_length);
for (int i = 0; i < context.compressed_length; i++) {
debug("%02X ", context.compressed_path[i]);
}
@@ -1457,9 +1481,9 @@ void PelrockEngine::walkTo(int x, int y) {
// } else if (y > yAlfred) {
// dirAlfred = DOWN;
// }
- debug("Setting Alfred to walk towards (%d, %d) from (%d, %d) in direction %d", x, y, xAlfred, yAlfred, dirAlfred);
+ // debug("Setting Alfred to walk towards (%d, %d) from (%d, %d) in direction %d", x, y, xAlfred, yAlfred, dirAlfred);
_currentContext = context;
- debug("Path find complete, movement count: %d", _currentContext.movement_count);
+ // debug("Path find complete, movement count: %d", _currentContext.movement_count);
}
bool PelrockEngine::pathFind(int x, int y, PathContext *context) {
@@ -1754,9 +1778,34 @@ uint8_t PelrockEngine::find_walkbox_for_point(uint16_t x, uint16_t y) {
void PelrockEngine::checkMouseClick(int x, int y) {
+
+ if(_displayPopup) {
+ Common::Array<VerbIcons> actions = availableActions(_currentHotspot);
+
+ Common::Rect lookRect = Common::Rect(_popupX + 20, _popupY + 20, _popupX + 20 + kVerbIconWidth, _popupY + 20 +kVerbIconHeight);
+ // debug("Look rect: x=%d, y=%d, w=%d, h=%d", lookRect.left, lookRect.top, lookRect, lookRect.h);
+ if(lookRect.contains(x, y)) {
+ debug("Look action clicked");
+ walkTo(_currentHotspot->x, _currentHotspot->y);
+ sayAlfred(_currentRoomDescriptions[_currentHotspot->index].text);
+ _displayPopup = false;
+ return;
+ }
+ for(int i = 0; i < actions.size(); i++) {
+ Common::Rect actionRect = Common::Rect(_popupX + 20 + (i * (kVerbIconWidth + 2)), _popupY + 20, kVerbIconWidth, kVerbIconHeight);
+ if(actionRect.contains(x, y)) {
+ doAction(actions[i], _currentHotspot->extra);
+ _displayPopup = false;
+ return;
+ }
+ }
+ }
+
_displayPopup = false;
_currentHotspot = nullptr;
+
+
Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
_curWalkTarget = walkTarget;
// debug("Calculated walk target at (%d, %d)", walkTarget.x, walkTarget.y);
@@ -1769,11 +1818,11 @@ void PelrockEngine::checkMouseClick(int x, int y) {
} else {*/
/* } */
- int hotspotIndex = isHotspotUnder(mouseX, mouseY);
- if (hotspotIndex != -1) {
- sayAlfred(_currentRoomDescriptions[hotspotIndex].text);
- debug("Hotspot clicked: %d", _currentRoomHotspots[hotspotIndex].extra);
- }
+ // int hotspotIndex = isHotspotUnder(mouseX, mouseY);
+ // if (hotspotIndex != -1) {
+ // sayAlfred(_currentRoomDescriptions[hotspotIndex].text);
+ // debug("Hotspot clicked: %d", _currentRoomHotspots[hotspotIndex].extra);
+ // }
walkTo(walkTarget.x, walkTarget.y);
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 875f38380b7..ba3716dbb72 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -96,13 +96,14 @@ private:
byte *grabBackgroundSlice(int x, int y, int w, int h);
void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
- Common::List<VerbIcons> populateActionsMenu(HotSpot *hotspot);
+ Common::Array<VerbIcons> availableActions(HotSpot *hotspot);
Common::Point calculateWalkTarget(int mouseX, int mouseY);
void drawText(Common::String text, int x, int y, int w, byte color);
void sayAlfred(Common::String text);
// render loop
void frames();
+ void doAction(byte object, byte action);
void renderText(Common::Array<Common::String> lines, int color);
void drawAlfred(byte *buf);
void checkMouseHover();
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 10f9bdaf2a6..f1487f09cca 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -62,6 +62,7 @@ const int kBalloonWidth = 247;
const int kBalloonHeight = 112;
const int kBalloonFrames = 4;
const int kTextCharDisplayTime = 100; // 10ms per character
+const int kVerbIconPadding = 20;
// Direction flags (bit-packed)
#define MOVE_RIGHT 0x01 // Move right (positive X)
@@ -150,6 +151,7 @@ struct AnimSet {
};
struct HotSpot {
+ int index;
int id;
int x;
int y;
Commit: 75f2713f77cad7748925bafd4809b66b9ebe8daa
https://github.com/scummvm/scummvm/commit/75f2713f77cad7748925bafd4809b66b9ebe8daa
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:08+02:00
Commit Message:
PELROCK: Better long click handling
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a9201c69717..b59d4bf9ae8 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -99,7 +99,6 @@ void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color
surface->drawLine(x + w, y, x + w, y + h, color);
}
-
Common::Array<Common::Array<Common::String> > wordWrap(Common::String text);
Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
@@ -145,18 +144,26 @@ Common::Error PelrockEngine::run() {
mouseY = e.mouse.y;
// debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
} else if (e.type == Common::EVENT_LBUTTONDOWN) {
- _mouseDownTime = g_system->getMillis();
- _isMouseDown = true;
- } else if (e.type == Common::EVENT_LBUTTONUP) {
- if (_isMouseDown) {
- uint32 clickDuration = g_system->getMillis() - _mouseDownTime;
- if (clickDuration >= kLongClickDuration) {
- checkLongMouseClick(e.mouse.x, e.mouse.y);
- } else {
- checkMouseClick(e.mouse.x, e.mouse.y);
- }
- _isMouseDown = false;
+ debug("long button down");
+ if (!_isMouseDown) {
+ _mouseClickTime = g_system->getMillis();
+ _isMouseDown = true;
}
+ } else if (e.type == Common::EVENT_LBUTTONUP) {
+ _isMouseDown = false;
+ // if (!_longClick) {
+ checkMouseClick(e.mouse.x, e.mouse.y);
+ _displayPopup = false;
+ // }
+ _longClick = false;
+ }
+ }
+ if (_isMouseDown) {
+ if (g_system->getMillis() - _mouseClickTime >= kLongClickDuration) {
+ debug("long click!");
+ _longClick = true;
+ _isMouseDown = false;
+ checkLongMouseClick(e.mouse.x, e.mouse.y);
}
}
checkMouseHover();
@@ -408,12 +415,11 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
uint32_t pos = 0;
uint32_t lastDescPos = 0;
while (pos < (pair12_size)) {
- // char *desc = new char[256];
int desc_pos = 0;
if (data[pos] == 0xFF) {
Description description;
- description.itemId = data[++pos];
- pos += 2;
+ description.itemId = data[pos + 1];
+ pos += 3;
description.index = data[pos++];
description.text = "";
// debug("Found description terminator");
@@ -422,6 +428,12 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
if (data[pos] != 0x00) {
description.text.append(1, (char)data[pos]);
}
+ if (data[pos] == 0xF8) {
+
+ description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
+ pos += 2;
+ continue;
+ }
// desc[desc_pos++] = (char)data[pos];
// debug("Current desc: %s", desc);
pos++;
@@ -471,10 +483,17 @@ char32_t decodeByte(byte b) {
}
}
-void PelrockEngine::talk() {
+void PelrockEngine::talk(byte object) {
if (_currentRoomConversations.size() == 0)
return;
+ AnimSet *animSet;
+ for (int i = 0; i < _currentRoomAnims.size(); i++) {
+ if (_currentRoomAnims[i].extra == object) {
+ AnimSet *animSet = &_currentRoomAnims[i];
+ }
+ }
+
// showDescription(_currentRoomConversations[0].text, x, y, _currentRoomConversations[0].speakerId);
// for(int i = 0; i < _currentRoomConversations[0].choices.size(); i++) {
// int idx = _currentRoomConversations.size() - 1 - i;
@@ -886,7 +905,7 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
- // drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
+ drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
}
for (int i = 0; i < _currentRoomExits.size(); i++) {
@@ -1109,7 +1128,6 @@ void drawSpriteToBuffer(byte *buffer, int bufferWidth,
Common::Array<VerbIcons> PelrockEngine::availableActions(HotSpot *hotspot) {
Common::Array<VerbIcons> verbs;
- debug("Populating actions menu for hotspot type %d", hotspot->type);
verbs.push_back(LOOK);
if (hotspot->type & 1) {
@@ -1332,6 +1350,9 @@ void PelrockEngine::frames() {
}
void PelrockEngine::doAction(byte object, byte action) {
+ if (action == TALK) {
+ talk(object);
+ }
}
void PelrockEngine::renderText(Common::Array<Common::String> lines, int color) {
@@ -1406,16 +1427,16 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
}
void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY) {
- for (int y = 0; y < surface->h; y++) {
- for (int x = 0; x < surface->w; x++) {
- int px = destX + x;
- int py = destY + y;
- if (px >= 0 && px < bufferWidth && py >= 0 && py < bufferHeight) {
- byte pixel = *((byte *)surface->getBasePtr(x, y));
- buffer[py * bufferWidth + px] = pixel;
- }
- }
- }
+ for (int y = 0; y < surface->h; y++) {
+ for (int x = 0; x < surface->w; x++) {
+ int px = destX + x;
+ int py = destY + y;
+ if (px >= 0 && px < bufferWidth && py >= 0 && py < bufferHeight) {
+ byte pixel = *((byte *)surface->getBasePtr(x, y));
+ buffer[py * bufferWidth + px] = pixel;
+ }
+ }
+ }
}
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
@@ -1430,7 +1451,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
// blitSurfaceToBuffer(&rects, _compositeBuffer, 640, 480, posx + ver, posy + 20);
- for(int i = 0; i < actions.size(); i++) {
+ for (int i = 0; i < actions.size(); i++) {
drawSpriteToBuffer(_compositeBuffer, 640, _verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
}
@@ -1778,22 +1799,24 @@ uint8_t PelrockEngine::find_walkbox_for_point(uint16_t x, uint16_t y) {
void PelrockEngine::checkMouseClick(int x, int y) {
-
- if(_displayPopup) {
+ if (_displayPopup) {
Common::Array<VerbIcons> actions = availableActions(_currentHotspot);
- Common::Rect lookRect = Common::Rect(_popupX + 20, _popupY + 20, _popupX + 20 + kVerbIconWidth, _popupY + 20 +kVerbIconHeight);
+ Common::Rect lookRect = Common::Rect(_popupX + 20, _popupY + 20, _popupX + 20 + kVerbIconWidth, _popupY + 20 + kVerbIconHeight);
// debug("Look rect: x=%d, y=%d, w=%d, h=%d", lookRect.left, lookRect.top, lookRect, lookRect.h);
- if(lookRect.contains(x, y)) {
+ if (lookRect.contains(x, y)) {
debug("Look action clicked");
walkTo(_currentHotspot->x, _currentHotspot->y);
sayAlfred(_currentRoomDescriptions[_currentHotspot->index].text);
_displayPopup = false;
return;
}
- for(int i = 0; i < actions.size(); i++) {
- Common::Rect actionRect = Common::Rect(_popupX + 20 + (i * (kVerbIconWidth + 2)), _popupY + 20, kVerbIconWidth, kVerbIconHeight);
- if(actionRect.contains(x, y)) {
+ for (int i = 0; i < actions.size(); i++) {
+ debug("Checking action %d at index %d for mouse click = %d, %d", actions[i], i, x, y);
+ int x = _popupX + 20 + (i * (kVerbIconWidth + 2));
+ int y = _popupY + 20;
+ Common::Rect actionRect = Common::Rect(x, y, x + kVerbIconWidth, y + kVerbIconHeight);
+ if (actionRect.contains(x, y)) {
doAction(actions[i], _currentHotspot->extra);
_displayPopup = false;
return;
@@ -1804,11 +1827,9 @@ void PelrockEngine::checkMouseClick(int x, int y) {
_displayPopup = false;
_currentHotspot = nullptr;
-
-
Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
_curWalkTarget = walkTarget;
- // debug("Calculated walk target at (%d, %d)", walkTarget.x, walkTarget.y);
+
// Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
/*if (exit != nullptr) {
@@ -1818,12 +1839,6 @@ void PelrockEngine::checkMouseClick(int x, int y) {
} else {*/
/* } */
- // int hotspotIndex = isHotspotUnder(mouseX, mouseY);
- // if (hotspotIndex != -1) {
- // sayAlfred(_currentRoomDescriptions[hotspotIndex].text);
- // debug("Hotspot clicked: %d", _currentRoomHotspots[hotspotIndex].extra);
- // }
-
walkTo(walkTarget.x, walkTarget.y);
}
@@ -1845,7 +1860,9 @@ void PelrockEngine::checkMouseHover() {
}
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
+
if (hotspotIndex != -1) {
+ debug("Hotspot under mouse: %d, (%d,%d)", hotspotIndex, _currentRoomHotspots[hotspotIndex].x, _currentRoomHotspots[hotspotIndex].y);
isSomethingUnder = true;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index ba3716dbb72..712138ccc8b 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -88,7 +88,7 @@ private:
uint16_t dest_x, uint16_t dest_y,
MovementStep *movement_buffer);
- void talk();
+ void talk(byte object);
Common::String getControlName(byte b);
void loadRoomMetadata(Common::File *roomFile, int roomOffset);
void loadCursors();
@@ -147,8 +147,9 @@ private:
uint16 mouseY = 0;
byte *_cursorMasks[5] = {nullptr};
- uint32 _mouseDownTime;
- bool _isMouseDown;
+ uint32 _mouseClickTime;
+ bool _isMouseDown = false;
+ bool _longClick = false;
byte *_verbIcons[9] = {nullptr};
byte *_popUpBalloon = nullptr;
@@ -156,6 +157,7 @@ private:
byte *_currentBackground; // Clean background - NEVER modified
byte *_compositeBuffer; // Working composition buffer
+ bool _lMouseDown = false;
bool _displayPopup = false;
int _popupX = 0;
int _popupY = 0;
@@ -171,12 +173,12 @@ private:
GameState stateGame = GAME;
bool gameInitialized = false;
bool screenReady = false;
- int prevDirX = 0;
- int prevDirY = 0;
- Common::String objectToShow = "";
- int prevWhichScreen = 0;
- int whichScreen = 0;
- byte *pixelsShadows; // =new int[640*400];
+ // int prevDirX = 0;
+ // int prevDirY = 0;
+ // Common::String objectToShow = "";
+ // int prevWhichScreen = 0;
+ // int whichScreen = 0;
+ // byte *pixelsShadows; // =new int[640*400];
protected:
// Engine APIs
Common::Error run() override;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index f1487f09cca..1ba82902c2a 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -207,6 +207,8 @@ struct StackEntry {
struct Description {
byte itemId;
byte index;
+ bool isAction = false;
+ uint16 actionTrigger;
Common::String text;
};
Commit: 262ff0cfb353d9205192e76234f1876de09cb24c
https://github.com/scummvm/scummvm/commit/262ff0cfb353d9205192e76234f1876de09cb24c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:08+02:00
Commit Message:
PELROCK: Fixes wrong description loading
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b59d4bf9ae8..ad8d91652d8 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -429,10 +429,10 @@ Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roo
description.text.append(1, (char)data[pos]);
}
if (data[pos] == 0xF8) {
-
description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
+ debug("Found action trigger: %d", description.actionTrigger);
pos += 2;
- continue;
+ break;
}
// desc[desc_pos++] = (char)data[pos];
// debug("Current desc: %s", desc);
@@ -1862,7 +1862,6 @@ void PelrockEngine::checkMouseHover() {
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
if (hotspotIndex != -1) {
- debug("Hotspot under mouse: %d, (%d,%d)", hotspotIndex, _currentRoomHotspots[hotspotIndex].x, _currentRoomHotspots[hotspotIndex].y);
isSomethingUnder = true;
}
Commit: ac8813f39d0717512f011393904b74f06e527759
https://github.com/scummvm/scummvm/commit/ac8813f39d0717512f011393904b74f06e527759
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:08+02:00
Commit Message:
PELROCK: Loads NPCs Talking anims
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index ad8d91652d8..1adafea6b37 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -484,15 +484,19 @@ char32_t decodeByte(byte b) {
}
void PelrockEngine::talk(byte object) {
+ debug("Talking to object %d", object);
if (_currentRoomConversations.size() == 0)
return;
AnimSet *animSet;
for (int i = 0; i < _currentRoomAnims.size(); i++) {
if (_currentRoomAnims[i].extra == object) {
- AnimSet *animSet = &_currentRoomAnims[i];
+ animSet = &_currentRoomAnims[i];
}
}
+ isNPCATalking = true;
+ NPCTalking = animSet->extra;
+
// showDescription(_currentRoomConversations[0].text, x, y, _currentRoomConversations[0].speakerId);
// for(int i = 0; i < _currentRoomConversations[0].choices.size(); i++) {
@@ -914,6 +918,118 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
}
}
+void readUntilBuda(Common::SeekableReadStream *stream, byte *&buffer, size_t &outSize) {
+ const char marker[] = "BUDA";
+ const int markerLen = 4;
+ size_t bufferSize = 4096;
+ size_t pos = 0;
+
+ buffer = (byte *)malloc(bufferSize);
+
+ while (!stream->eos()) {
+ byte b = stream->readByte();
+ if (pos + 1 > bufferSize) {
+ bufferSize *= 2;
+ buffer = (byte *)realloc(buffer, bufferSize);
+ }
+ buffer[pos++] = b;
+
+ // Check for marker at the end of buffer
+ if (pos >= markerLen &&
+ buffer[pos - 4] == 'B' &&
+ buffer[pos - 3] == 'U' &&
+ buffer[pos - 2] == 'D' &&
+ buffer[pos - 1] == 'A') {
+ break;
+ }
+ }
+ outSize = pos;
+}
+
+void PelrockEngine::loadRoomTalkingAnimations(int roomNumber) {
+
+ int headerIndex = roomNumber;
+ uint32 offset = kTalkingAnimHeaderSize * headerIndex;
+
+ TalkinAnimHeader talkHeader;
+ Common::File talkFile;
+ if (!talkFile.open("ALFRED.2")) {
+ error("Couldnt find file ALFRED.2");
+ }
+
+ talkFile.seek(offset, SEEK_SET);
+
+ talkHeader.spritePointer = talkFile.readUint16LE();
+ talkHeader.unknown1 = talkFile.readByte();
+ talkFile.read(&talkHeader.unknown2, 4);
+ talkHeader.offsetX = talkFile.readByte();
+ talkHeader.offsetY = talkFile.readByte();
+ talkHeader.wAnimA = talkFile.readByte();
+ talkHeader.hAnimA = talkFile.readByte();
+ talkFile.read(&talkHeader.unknown3, 2);
+ talkHeader.numFramesAnimA = talkFile.readByte();
+ talkFile.read(&talkHeader.unknown4, 7);
+ talkHeader.wAnimB = talkFile.readByte();
+ talkHeader.hAnimB = talkFile.readByte();
+ talkHeader.unknown5 = talkFile.readByte();
+ talkHeader.numFramesAnimB = talkFile.readByte();
+ talkFile.read(&talkHeader.unknown6, 29);
+
+ if(talkHeader.spritePointer == 0) {
+ debug("No talking animation for room %d", roomNumber);
+ talkFile.close();
+ return;
+ }
+
+ if(talkHeader.animA != nullptr) {
+ delete[] talkHeader.animA;
+ talkHeader.animA = nullptr;
+ }
+ talkHeader.animA = new byte *[talkHeader.numFramesAnimA];
+
+
+ talkFile.seek(talkHeader.spritePointer, SEEK_SET);
+
+ byte *data = nullptr;
+ byte *decompressed = new byte[talkHeader.wAnimA * talkHeader.hAnimA * talkHeader.numFramesAnimA];
+ size_t dataSize = 0;
+ readUntilBuda(&talkFile, data, dataSize);
+ rleDecompress(data, dataSize, 0, dataSize, &decompressed);
+ debug("Decompressed talking anim A size: %zu", dataSize);
+ for(int i = 0; i < talkHeader.numFramesAnimA; i++) {
+ talkHeader.animA[i] = new byte[talkHeader.wAnimA * talkHeader.hAnimA];
+ Common::copy(decompressed + (i * talkHeader.wAnimA * talkHeader.hAnimA), decompressed + ((i + 1) * talkHeader.wAnimA * talkHeader.hAnimA), talkHeader.animA[i]);
+ }
+ free(data);
+ free(decompressed);
+
+
+ if(talkHeader.numFramesAnimB > 0) {
+ if(talkHeader.animB != nullptr) {
+ delete[] talkHeader.animB;
+ talkHeader.animB = nullptr;
+ }
+ talkHeader.animB = new byte *[talkHeader.numFramesAnimB];
+ // Read second animation frames
+ size_t offsetB = talkHeader.spritePointer + dataSize;
+ talkFile.seek(offsetB, SEEK_SET);
+ byte *dataB = nullptr;
+ byte *decompressedB = new byte[talkHeader.wAnimB * talkHeader.hAnimB * talkHeader.numFramesAnimB];
+ size_t dataBSize = 0;
+ readUntilBuda(&talkFile, dataB, dataBSize);
+ rleDecompress(dataB, 0, dataBSize, dataBSize, &decompressedB);
+ for(int i = 0; i < talkHeader.numFramesAnimB; i++) {
+ talkHeader.animB[i] = new byte[talkHeader.wAnimB * talkHeader.hAnimB];
+ Common::copy(decompressedB + (i * talkHeader.wAnimB * talkHeader.hAnimB), decompressedB + ((i + 1) * talkHeader.wAnimB * talkHeader.hAnimB), talkHeader.animB[i]);
+ }
+ free(dataB);
+ free(decompressedB);
+ }
+ _talkingAnimHeader = talkHeader;
+
+ talkFile.close();
+}
+
void PelrockEngine::loadCursors() {
Common::File alfred7File;
if (!alfred7File.open("ALFRED.7")) {
@@ -1002,16 +1118,14 @@ Common::Array<HotSpot> PelrockEngine::loadHotspots(Common::File *roomFile, int r
for (int i = 0; i < hotspot_count; i++) {
uint32_t obj_offset = hotspot_data_start + i * 9;
roomFile->seek(obj_offset, SEEK_SET);
- byte obj_bytes[9];
- roomFile->read(obj_bytes, 9);
HotSpot spot;
- spot.type = obj_bytes[0];
- spot.x = obj_bytes[1] | (obj_bytes[2] << 8);
- spot.y = obj_bytes[3] | (obj_bytes[4] << 8);
- spot.w = obj_bytes[5];
- spot.h = obj_bytes[6];
- spot.extra = obj_bytes[7] | (obj_bytes[8] << 8);
- // debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
+ spot.type = roomFile->readByte();
+ spot.x = roomFile->readUint16LE();
+ spot.y = roomFile->readUint16LE();
+ spot.w = roomFile->readByte();
+ spot.h = roomFile->readByte();
+ spot.extra = roomFile->readUint16LE();
+ debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
hotspots.push_back(spot);
}
return hotspots;
@@ -1175,6 +1289,13 @@ void PelrockEngine::frames() {
int y = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].y;
int w = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w;
int h = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h;
+ int extra = _currentRoomAnims[i].extra;
+
+ if(NPCTalking == extra) {
+ debug("Skipping anim set %d because NPC is talking", i);
+ talkNPC(&_currentRoomAnims[i]);
+ continue;
+ }
int frameSize = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h;
int curFrame = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame;
@@ -1206,6 +1327,7 @@ void PelrockEngine::frames() {
}
}
+
if (isAlfredWalking) {
MovementStep step = _currentContext.movement_buffer[_current_step];
@@ -1349,7 +1471,7 @@ void PelrockEngine::frames() {
}
}
-void PelrockEngine::doAction(byte object, byte action) {
+void PelrockEngine::doAction(byte action, byte object) {
if (action == TALK) {
talk(object);
}
@@ -1456,6 +1578,23 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
}
+void PelrockEngine::talkNPC(AnimSet *animSet) {
+ //Change with the right index
+ int x = animSet->x + _talkingAnimHeader.offsetX;
+ int y = animSet->y + _talkingAnimHeader.offsetY;
+ int w = _talkingAnimHeader.wAnimA;
+ int h = _talkingAnimHeader.hAnimA;
+ int numFrames = _talkingAnimHeader.numFramesAnimA;
+ int curFrame = _talkingAnimHeader.currentFrameAnimA++;
+ if (curFrame >= numFrames) {
+ _talkingAnimHeader.currentFrameAnimA = 0;
+ curFrame = 0;
+ }
+ debug("Talking NPC frame %d/%d, x=%d, y=%d, w=%d, h=%d", curFrame, numFrames, x, y, w, h);
+
+ drawSpriteToBuffer(_compositeBuffer, 640, _talkingAnimHeader.animA[curFrame], x, y, w, h, 255);
+}
+
void PelrockEngine::walkTo(int x, int y) {
isAlfredWalking = true;
curAlfredFrame = 0;
@@ -1799,9 +1938,13 @@ uint8_t PelrockEngine::find_walkbox_for_point(uint16_t x, uint16_t y) {
void PelrockEngine::checkMouseClick(int x, int y) {
+ if(NPCTalking) NPCTalking = false;
+
if (_displayPopup) {
Common::Array<VerbIcons> actions = availableActions(_currentHotspot);
-
+ for (int i = 0; i < actions.size(); i++) {
+ debug("Available action %d at index %d", actions[i], i);
+ }
Common::Rect lookRect = Common::Rect(_popupX + 20, _popupY + 20, _popupX + 20 + kVerbIconWidth, _popupY + 20 + kVerbIconHeight);
// debug("Look rect: x=%d, y=%d, w=%d, h=%d", lookRect.left, lookRect.top, lookRect, lookRect.h);
if (lookRect.contains(x, y)) {
@@ -1811,12 +1954,15 @@ void PelrockEngine::checkMouseClick(int x, int y) {
_displayPopup = false;
return;
}
- for (int i = 0; i < actions.size(); i++) {
- debug("Checking action %d at index %d for mouse click = %d, %d", actions[i], i, x, y);
+ for (int i = 1; i < actions.size(); i++) {
+
+ // debug("Checking action %d at index %d for mouse click = %d, %d", actions[i], i, x, y);
int x = _popupX + 20 + (i * (kVerbIconWidth + 2));
int y = _popupY + 20;
Common::Rect actionRect = Common::Rect(x, y, x + kVerbIconWidth, y + kVerbIconHeight);
+
if (actionRect.contains(x, y)) {
+ debug("Action %d clicked", actions[i]);
doAction(actions[i], _currentHotspot->extra);
_displayPopup = false;
return;
@@ -2140,6 +2286,7 @@ void PelrockEngine::setScreen(int number, int dir) {
}
loadRoomMetadata(&roomFile, roomOffset);
+ loadRoomTalkingAnimations(number);
_screen->markAllDirty();
roomFile.close();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 712138ccc8b..89017ab9a08 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -91,6 +91,7 @@ private:
void talk(byte object);
Common::String getControlName(byte b);
void loadRoomMetadata(Common::File *roomFile, int roomOffset);
+ void loadRoomTalkingAnimations(int roomNumber);
void loadCursors();
void loadInteractionIcons();
byte *grabBackgroundSlice(int x, int y, int w, int h);
@@ -103,7 +104,7 @@ private:
void sayAlfred(Common::String text);
// render loop
void frames();
- void doAction(byte object, byte action);
+ void doAction(byte action, byte object);
void renderText(Common::Array<Common::String> lines, int color);
void drawAlfred(byte *buf);
void checkMouseHover();
@@ -114,16 +115,19 @@ private:
Exit *isExitUnder(int x, int y);
AnimSet *isSpriteUnder(int x, int y);
void showActionBalloon(int posx, int posy, int curFrame);
+ void talkNPC(AnimSet *animSet);
ChronoManager *_chronoManager = nullptr;
// byte *standingAnim = new byte[3060 * 102];
- byte **walkingAnimFrames[4]; // 4 arrays of arrays
- byte *standingAnimFrames[4]; // 4 directions
- int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
- byte **talkingAnimFrames[4]; // 4 arrays of arrays
- int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+ byte **walkingAnimFrames[4]; // 4 arrays of arrays
+ byte *standingAnimFrames[4] = {nullptr}; // 4 directions
+ int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+ byte **talkingAnimFrames[4]; // 4 arrays of arrays
+ int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+
+ TalkinAnimHeader _talkingAnimHeader;
PathContext _currentContext;
int _current_step = 0;
@@ -168,7 +172,12 @@ private:
LargeFont *_largeFont = nullptr;
Common::Point _curWalkTarget;
+ bool isNPCATalking = false;
+ uint16 NPCTalking = 0;
+ bool isNPCBTalking = false;
+
+ //JAVA
bool shouldPlayIntro = false;
GameState stateGame = GAME;
bool gameInitialized = false;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 1ba82902c2a..803ab5f6cbb 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -54,6 +54,7 @@ const int kCursorWidth = 16;
const int kCursorHeight = 18;
const int kCursorSize = 288; // 16 * 18
const int kRoomStructSize = 104;
+const int kTalkingAnimHeaderSize = 55;
const int kNumRooms = 56;
const int kVerbIconWidth = 60;
const int kVerbIconHeight = 60;
@@ -162,6 +163,33 @@ struct HotSpot {
bool isEnabled = true;
};
+struct TalkinAnimHeader {
+ uint16 spritePointer;
+ byte unknown1;
+ byte unknown2[4];
+
+ int8 offsetX;
+ int8 offsetY;
+
+ byte wAnimA;
+ byte hAnimA;
+ byte unknown3[2];
+ byte numFramesAnimA;
+ byte unknown4[7];
+
+ byte currentFrameAnimA;
+
+ byte wAnimB;
+ byte hAnimB;
+ byte unknown5;
+ byte numFramesAnimB;
+ byte unknown6[29];
+ byte currentFrameAnimB;
+
+ byte **animA = nullptr;
+ byte **animB = nullptr;
+};
+
struct ConversationElement {
enum Type {
DIALOGUE,
Commit: e65b34ec6c46560c2c3cd125aa48edea645e5c0e
https://github.com/scummvm/scummvm/commit/e65b34ec6c46560c2c3cd125aa48edea645e5c0e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:09+02:00
Commit Message:
PELROCK: Reads second talking animation properly
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1adafea6b37..1d8bf432a70 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -194,7 +194,8 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(0, 1);
+ setScreen(5, 0);
+ // setScreen(13, 1);
// setScreen(2, 2);
// setScreen(28, 0);
}
@@ -497,7 +498,6 @@ void PelrockEngine::talk(byte object) {
isNPCATalking = true;
NPCTalking = animSet->extra;
-
// showDescription(_currentRoomConversations[0].text, x, y, _currentRoomConversations[0].speakerId);
// for(int i = 0; i < _currentRoomConversations[0].choices.size(); i++) {
// int idx = _currentRoomConversations.size() - 1 - i;
@@ -918,32 +918,32 @@ void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
}
}
-void readUntilBuda(Common::SeekableReadStream *stream, byte *&buffer, size_t &outSize) {
- const char marker[] = "BUDA";
- const int markerLen = 4;
- size_t bufferSize = 4096;
- size_t pos = 0;
-
- buffer = (byte *)malloc(bufferSize);
+void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize) {
+ const char marker[] = "BUDA";
+ const int markerLen = 4;
+ size_t bufferSize = 4096;
+ size_t pos = 0;
- while (!stream->eos()) {
- byte b = stream->readByte();
- if (pos + 1 > bufferSize) {
- bufferSize *= 2;
- buffer = (byte *)realloc(buffer, bufferSize);
- }
- buffer[pos++] = b;
-
- // Check for marker at the end of buffer
- if (pos >= markerLen &&
- buffer[pos - 4] == 'B' &&
- buffer[pos - 3] == 'U' &&
- buffer[pos - 2] == 'D' &&
- buffer[pos - 1] == 'A') {
- break;
- }
- }
- outSize = pos;
+ buffer = (byte *)malloc(bufferSize);
+ stream->seek(startPos, SEEK_SET);
+ while (!stream->eos()) {
+ byte b = stream->readByte();
+ if (pos + 1 > bufferSize) {
+ bufferSize *= 2;
+ buffer = (byte *)realloc(buffer, bufferSize);
+ }
+ buffer[pos++] = b;
+
+ // Check for marker at the end of buffer
+ if (pos >= markerLen &&
+ buffer[pos - 4] == 'B' &&
+ buffer[pos - 3] == 'U' &&
+ buffer[pos - 2] == 'D' &&
+ buffer[pos - 1] == 'A') {
+ break;
+ }
+ }
+ outSize = pos;
}
void PelrockEngine::loadRoomTalkingAnimations(int roomNumber) {
@@ -962,69 +962,60 @@ void PelrockEngine::loadRoomTalkingAnimations(int roomNumber) {
talkHeader.spritePointer = talkFile.readUint16LE();
talkHeader.unknown1 = talkFile.readByte();
talkFile.read(&talkHeader.unknown2, 4);
- talkHeader.offsetX = talkFile.readByte();
- talkHeader.offsetY = talkFile.readByte();
+ talkHeader.offsetXAnimA = talkFile.readByte();
+ talkHeader.offsetYAnimA = talkFile.readByte();
talkHeader.wAnimA = talkFile.readByte();
talkHeader.hAnimA = talkFile.readByte();
talkFile.read(&talkHeader.unknown3, 2);
talkHeader.numFramesAnimA = talkFile.readByte();
- talkFile.read(&talkHeader.unknown4, 7);
+ talkFile.read(&talkHeader.unknown4, 5);
+
+ talkHeader.offsetXAnimB = talkFile.readByte();
+ talkHeader.offsetYAnimB = talkFile.readByte();
talkHeader.wAnimB = talkFile.readByte();
talkHeader.hAnimB = talkFile.readByte();
- talkHeader.unknown5 = talkFile.readByte();
+ talkFile.read(&talkHeader.unknown5, 2);
talkHeader.numFramesAnimB = talkFile.readByte();
talkFile.read(&talkHeader.unknown6, 29);
+ debug("Talking anim header for room %d: spritePointer=%d, wA=%d, hA=%d, framesA=%d, wB=%d, hB=%d, framesB=%d", roomNumber, talkHeader.spritePointer, talkHeader.wAnimA, talkHeader.hAnimA, talkHeader.numFramesAnimA, talkHeader.wAnimB, talkHeader.hAnimB, talkHeader.numFramesAnimB);
- if(talkHeader.spritePointer == 0) {
+ if (talkHeader.spritePointer == 0) {
debug("No talking animation for room %d", roomNumber);
talkFile.close();
return;
}
- if(talkHeader.animA != nullptr) {
- delete[] talkHeader.animA;
- talkHeader.animA = nullptr;
- }
+ // if(talkHeader.animA != nullptr) {
+ // delete[] talkHeader.animA;
+ // talkHeader.animA = nullptr;
+ // }
talkHeader.animA = new byte *[talkHeader.numFramesAnimA];
-
- talkFile.seek(talkHeader.spritePointer, SEEK_SET);
-
byte *data = nullptr;
- byte *decompressed = new byte[talkHeader.wAnimA * talkHeader.hAnimA * talkHeader.numFramesAnimA];
+ int animASize = talkHeader.wAnimA * talkHeader.hAnimA * talkHeader.numFramesAnimA;
+ byte *decompressed = nullptr;
size_t dataSize = 0;
- readUntilBuda(&talkFile, data, dataSize);
- rleDecompress(data, dataSize, 0, dataSize, &decompressed);
- debug("Decompressed talking anim A size: %zu", dataSize);
- for(int i = 0; i < talkHeader.numFramesAnimA; i++) {
+ readUntilBuda(&talkFile, talkHeader.spritePointer, data, dataSize);
+ size_t decompressedSize = rleDecompress(data, dataSize, 0, dataSize, &decompressed);
+ free(data);
+ debug("Decompressed talking anim A size: %zu, decompressed size: %zu", dataSize, decompressedSize);
+ for (int i = 0; i < talkHeader.numFramesAnimA; i++) {
talkHeader.animA[i] = new byte[talkHeader.wAnimA * talkHeader.hAnimA];
Common::copy(decompressed + (i * talkHeader.wAnimA * talkHeader.hAnimA), decompressed + ((i + 1) * talkHeader.wAnimA * talkHeader.hAnimA), talkHeader.animA[i]);
}
- free(data);
- free(decompressed);
-
- if(talkHeader.numFramesAnimB > 0) {
- if(talkHeader.animB != nullptr) {
- delete[] talkHeader.animB;
- talkHeader.animB = nullptr;
- }
+ if (talkHeader.numFramesAnimB > 0) {
+ // if(talkHeader.animA != nullptr) {
+ // delete[] talkHeader.animA;
+ // talkHeader.animA = nullptr;
+ // }
talkHeader.animB = new byte *[talkHeader.numFramesAnimB];
- // Read second animation frames
- size_t offsetB = talkHeader.spritePointer + dataSize;
- talkFile.seek(offsetB, SEEK_SET);
- byte *dataB = nullptr;
- byte *decompressedB = new byte[talkHeader.wAnimB * talkHeader.hAnimB * talkHeader.numFramesAnimB];
- size_t dataBSize = 0;
- readUntilBuda(&talkFile, dataB, dataBSize);
- rleDecompress(dataB, 0, dataBSize, dataBSize, &decompressedB);
- for(int i = 0; i < talkHeader.numFramesAnimB; i++) {
+ for (int i = 0; i < talkHeader.numFramesAnimB; i++) {
talkHeader.animB[i] = new byte[talkHeader.wAnimB * talkHeader.hAnimB];
- Common::copy(decompressedB + (i * talkHeader.wAnimB * talkHeader.hAnimB), decompressedB + ((i + 1) * talkHeader.wAnimB * talkHeader.hAnimB), talkHeader.animB[i]);
+ Common::copy(decompressed + animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB), decompressed + animASize + ((i + 1) * talkHeader.wAnimB * talkHeader.hAnimB), talkHeader.animB[i]);
}
- free(dataB);
- free(decompressedB);
}
+ free(decompressed);
_talkingAnimHeader = talkHeader;
talkFile.close();
@@ -1291,9 +1282,9 @@ void PelrockEngine::frames() {
int h = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h;
int extra = _currentRoomAnims[i].extra;
- if(NPCTalking == extra) {
- debug("Skipping anim set %d because NPC is talking", i);
- talkNPC(&_currentRoomAnims[i]);
+ if (NPCTalking == extra) {
+ // debug("Skipping anim set %d because NPC is talking", i);
+ talkNPC(&_currentRoomAnims[i], i);
continue;
}
@@ -1327,7 +1318,6 @@ void PelrockEngine::frames() {
}
}
-
if (isAlfredWalking) {
MovementStep step = _currentContext.movement_buffer[_current_step];
@@ -1578,21 +1568,29 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
}
-void PelrockEngine::talkNPC(AnimSet *animSet) {
- //Change with the right index
- int x = animSet->x + _talkingAnimHeader.offsetX;
- int y = animSet->y + _talkingAnimHeader.offsetY;
- int w = _talkingAnimHeader.wAnimA;
- int h = _talkingAnimHeader.hAnimA;
- int numFrames = _talkingAnimHeader.numFramesAnimA;
- int curFrame = _talkingAnimHeader.currentFrameAnimA++;
+void PelrockEngine::talkNPC(AnimSet *animSet, int index) {
+ // Change with the right index
+
+ int x = animSet->x + (index ? _talkingAnimHeader.offsetXAnimB : _talkingAnimHeader.offsetXAnimA);
+ int y = animSet->y + (index ? _talkingAnimHeader.offsetYAnimB : _talkingAnimHeader.offsetYAnimA);
+
+ int w = index ? _talkingAnimHeader.wAnimB : _talkingAnimHeader.wAnimA;
+ int h = index ? _talkingAnimHeader.hAnimB : _talkingAnimHeader.hAnimA;
+ int numFrames = index ? _talkingAnimHeader.numFramesAnimB : _talkingAnimHeader.numFramesAnimA;
+ int curFrame = index ? _talkingAnimHeader.currentFrameAnimB++ : _talkingAnimHeader.currentFrameAnimA++;
if (curFrame >= numFrames) {
- _talkingAnimHeader.currentFrameAnimA = 0;
+ if (index) {
+ _talkingAnimHeader.currentFrameAnimB = 0;
+ } else {
+ _talkingAnimHeader.currentFrameAnimA = 0;
+ }
curFrame = 0;
}
+ byte *frame = index ? _talkingAnimHeader.animB[curFrame] : _talkingAnimHeader.animA[curFrame];
+
debug("Talking NPC frame %d/%d, x=%d, y=%d, w=%d, h=%d", curFrame, numFrames, x, y, w, h);
- drawSpriteToBuffer(_compositeBuffer, 640, _talkingAnimHeader.animA[curFrame], x, y, w, h, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, frame, x, y, w, h, 255);
}
void PelrockEngine::walkTo(int x, int y) {
@@ -1938,7 +1936,8 @@ uint8_t PelrockEngine::find_walkbox_for_point(uint16_t x, uint16_t y) {
void PelrockEngine::checkMouseClick(int x, int y) {
- if(NPCTalking) NPCTalking = false;
+ if (NPCTalking)
+ NPCTalking = false;
if (_displayPopup) {
Common::Array<VerbIcons> actions = availableActions(_currentHotspot);
@@ -1976,16 +1975,17 @@ void PelrockEngine::checkMouseClick(int x, int y) {
Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
_curWalkTarget = walkTarget;
- // Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
-
- /*if (exit != nullptr) {
- xAlfred = exit->targetX;
- yAlfred = exit->targetY;
- setScreen(exit->targetRoom, exit->dir);
- } else {*/
- /* } */
+ { // For quick room navigation
+ Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
- walkTo(walkTarget.x, walkTarget.y);
+ if (exit != nullptr) {
+ xAlfred = exit->targetX;
+ yAlfred = exit->targetY;
+ setScreen(exit->targetRoom, exit->dir);
+ } else {
+ walkTo(walkTarget.x, walkTarget.y);
+ }
+ }
}
void PelrockEngine::changeCursor(Cursor cursor) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 89017ab9a08..65003ca8edb 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -115,7 +115,7 @@ private:
Exit *isExitUnder(int x, int y);
AnimSet *isSpriteUnder(int x, int y);
void showActionBalloon(int posx, int posy, int curFrame);
- void talkNPC(AnimSet *animSet);
+ void talkNPC(AnimSet *animSet, int index);
ChronoManager *_chronoManager = nullptr;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 803ab5f6cbb..6b5d033f84a 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -168,15 +168,17 @@ struct TalkinAnimHeader {
byte unknown1;
byte unknown2[4];
- int8 offsetX;
- int8 offsetY;
+ int8 offsetXAnimA;
+ int8 offsetYAnimA;
byte wAnimA;
byte hAnimA;
byte unknown3[2];
byte numFramesAnimA;
- byte unknown4[7];
+ byte unknown4[5];
+ byte offsetXAnimB;
+ byte offsetYAnimB;
byte currentFrameAnimA;
byte wAnimB;
Commit: b79204d594043e5fd61926fede1ee33fd777c7dc
https://github.com/scummvm/scummvm/commit/b79204d594043e5fd61926fede1ee33fd777c7dc
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:09+02:00
Commit Message:
PELROCK: Fixes talking animations offset
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1d8bf432a70..1f38c9de8bb 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -194,10 +194,9 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(5, 0);
- // setScreen(13, 1);
- // setScreen(2, 2);
- // setScreen(28, 0);
+ // setScreen(5, 0); //museum entrance
+ // setScreen(13, 1); // restaurants kitchen
+ setScreen(2, 2); // hooker
}
}
@@ -959,9 +958,8 @@ void PelrockEngine::loadRoomTalkingAnimations(int roomNumber) {
talkFile.seek(offset, SEEK_SET);
- talkHeader.spritePointer = talkFile.readUint16LE();
- talkHeader.unknown1 = talkFile.readByte();
- talkFile.read(&talkHeader.unknown2, 4);
+ talkHeader.spritePointer = talkFile.readUint32LE();
+ talkFile.read(&talkHeader.unknown2, 3);
talkHeader.offsetXAnimA = talkFile.readByte();
talkHeader.offsetYAnimA = talkFile.readByte();
talkHeader.wAnimA = talkFile.readByte();
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 6b5d033f84a..08e9a30471c 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -164,9 +164,9 @@ struct HotSpot {
};
struct TalkinAnimHeader {
- uint16 spritePointer;
- byte unknown1;
- byte unknown2[4];
+ uint32 spritePointer;
+
+ byte unknown2[3];
int8 offsetXAnimA;
int8 offsetYAnimA;
Commit: 397b1d1fe8b42fd85a7d85806ebe3a6017f1a631
https://github.com/scummvm/scummvm/commit/397b1d1fe8b42fd85a7d85806ebe3a6017f1a631
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:09+02:00
Commit Message:
PELROCK: Fixes text color selection
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1f38c9de8bb..ca348e2d804 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -494,8 +494,16 @@ void PelrockEngine::talk(byte object) {
animSet = &_currentRoomAnims[i];
}
}
- isNPCATalking = true;
- NPCTalking = animSet->extra;
+
+ ConversationNode selectedNode = _currentRoomConversations[0];
+
+ bool isNPC = selectedNode.speakerId != 13;
+ if (isNPC) {
+ sayNPC(animSet, selectedNode.text, selectedNode.speakerId);
+ }
+ // for(int i= 0; i< _currentRoomConversations.size(); i++) {
+ // _currentRoomConversations
+ // }
// showDescription(_currentRoomConversations[0].text, x, y, _currentRoomConversations[0].speakerId);
// for(int i = 0; i < _currentRoomConversations[0].choices.size(); i++) {
@@ -736,6 +744,8 @@ Common::Array<ConversationNode> PelrockEngine::buildTreeStructure(const Common::
ConversationNode root;
root.type = ConversationNode::ROOT;
root.text = elem.text;
+ root.speaker = "NPC";
+ root.speakerId = elem.speakerId;
roots.push_back(root);
currentRoot = &roots[roots.size() - 1];
} else {
@@ -756,6 +766,8 @@ Common::Array<ConversationNode> PelrockEngine::buildTreeStructure(const Common::
ConversationNode choiceNode;
choiceNode.type = ConversationNode::CHOICE;
choiceNode.text = elem.text;
+ choiceNode.speaker = "ALFRED";
+ choiceNode.speakerId = 0x0D; // Player
choiceNode.choiceIndex = elem.choiceIndex;
// Find where to attach this choice
@@ -1280,7 +1292,7 @@ void PelrockEngine::frames() {
int h = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h;
int extra = _currentRoomAnims[i].extra;
- if (NPCTalking == extra) {
+ if (whichNPCTalking == extra) {
// debug("Skipping anim set %d because NPC is talking", i);
talkNPC(&_currentRoomAnims[i], i);
continue;
@@ -1411,9 +1423,9 @@ void PelrockEngine::frames() {
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
if (!isAlfredWalking && !_currentTextPages.empty()) {
- // debug("Will render text, _chronoManager->_textTtl=%d", _chronoManager->_textTtl);
if (_chronoManager->_textTtl > 0) {
- renderText(_currentTextPages[_currentTextPageIndex], _textColor);
+ debug("Will render text, _chronoManager->_textTtl=%d", _chronoManager->_textTtl);
+ renderText(_currentTextPages[_currentTextPageIndex], _textColor, _textPos.x, _textPos.y);
} else if (_currentTextPageIndex < _currentTextPages.size() - 1) {
_currentTextPageIndex++;
@@ -1426,6 +1438,8 @@ void PelrockEngine::frames() {
_currentTextPages.clear();
_currentTextPageIndex = 0;
isAlfredTalking = false;
+ isNPCATalking = false;
+ isNPCBTalking = false;
}
}
@@ -1465,24 +1479,21 @@ void PelrockEngine::doAction(byte action, byte object) {
}
}
-void PelrockEngine::renderText(Common::Array<Common::String> lines, int color) {
- if (color == ALFRED_COLOR) {
- int baseX = xAlfred;
- int baseY = yAlfred - kAlfredFrameHeight - 10;
- int maxW = 0;
- for (size_t i = 0; i < lines.size(); i++) {
- Common::Rect r = _largeFont->getBoundingBox(lines[i]);
- if (r.width() > maxW) {
- maxW = r.width();
- }
- }
- int lineSize = lines.size();
- for (size_t i = 0; i < lines.size(); i++) {
- int textX = baseX - (maxW / 2);
- int textY = baseY - (lineSize * 25) + (i * 25);
- drawText(lines[i], textX, textY, maxW, color);
+void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, int baseX, int baseY) {
+
+ int maxW = 0;
+ for (size_t i = 0; i < lines.size(); i++) {
+ Common::Rect r = _largeFont->getBoundingBox(lines[i]);
+ if (r.width() > maxW) {
+ maxW = r.width();
}
}
+ int lineSize = lines.size();
+ for (size_t i = 0; i < lines.size(); i++) {
+ int textX = baseX - (maxW / 2);
+ int textY = baseY - (lineSize * 25) + (i * 25);
+ drawText(lines[i], textX, textY, maxW, color);
+ }
}
void PelrockEngine::drawAlfred(byte *buf) {
@@ -1934,8 +1945,8 @@ uint8_t PelrockEngine::find_walkbox_for_point(uint16_t x, uint16_t y) {
void PelrockEngine::checkMouseClick(int x, int y) {
- if (NPCTalking)
- NPCTalking = false;
+ if (whichNPCTalking)
+ whichNPCTalking = false;
if (_displayPopup) {
Common::Array<VerbIcons> actions = availableActions(_currentHotspot);
@@ -2087,32 +2098,36 @@ Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
void PelrockEngine::drawText(Common::String text, int x, int y, int w, byte color) {
Common::Rect rect = _largeFont->getBoundingBox(text.c_str());
- if (x + 2 + rect.width() > 640) {
+ if (x + rect.width() > 640) {
x = 640 - rect.width() - 2;
}
- if (y + 2 + rect.height() > 400) {
+ if (y + rect.height() > 400) {
y = 400 - rect.height();
}
- if (x - 2 < 0) {
- x = 2;
+ if (x < 0) {
+ x = 0;
}
- if (y - 2 < 0) {
- y = 2;
+ if (y < 0) {
+ y = 0;
}
-
- // _largeFont->drawString(_screen, text.c_str(), x - 1, y, w, 0, Graphics::kTextAlignCenter); // Left
- // // _largeFont->drawString(_screen, text.c_str(), x - 2, y, w, 0, Graphics::kTextAlignCenter); // Left
- // _largeFont->drawString(_screen, text.c_str(), x + 1, y, w, 0, Graphics::kTextAlignCenter); // Right
- // // _largeFont->drawString(_screen, text.c_str(), x + 2, y, w, 0, Graphics::kTextAlignCenter); // Right
- // _largeFont->drawString(_screen, text.c_str(), x, y - 1, w, 0, Graphics::kTextAlignCenter); // Top
- // // _largeFont->drawString(_screen, text.c_str(), x, y - 2, w, 0, Graphics::kTextAlignCenter); // Top
- // _largeFont->drawString(_screen, text.c_str(), x, y + 1, w, 0, Graphics::kTextAlignCenter); // Bottom
- // // _largeFont->drawString(_screen, text.c_str(), x, y + 2, w, 0, Graphics::kTextAlignCenter); // Bottom
-
// Draw main text on top
_largeFont->drawString(_screen, text.c_str(), x, y, w, color, Graphics::kTextAlignCenter);
}
+void PelrockEngine::sayNPC(AnimSet *anim, Common::String text, byte color) {
+ isNPCATalking = true;
+ whichNPCTalking = anim->extra;
+ debug("NPC says %s, color = %d", text.c_str(), color);
+ _currentTextPages = wordWrap(text);
+ _textColor = color;
+ int totalChars = 0;
+ for (int i = 0; i < _currentTextPages[0].size(); i++) {
+ totalChars += _currentTextPages[0][i].size();
+ }
+ _textPos = Common::Point(anim->x, anim->y - anim->h - 10);
+ _chronoManager->_textTtl = totalChars * kTextCharDisplayTime;
+}
+
void PelrockEngine::sayAlfred(Common::String text) {
isAlfredTalking = true;
curAlfredFrame = 0;
@@ -2123,6 +2138,7 @@ void PelrockEngine::sayAlfred(Common::String text) {
for (int i = 0; i < _currentTextPages[0].size(); i++) {
totalChars += _currentTextPages[0][i].size();
}
+ _textPos = Common::Point(xAlfred, yAlfred - kAlfredFrameHeight - 10);
_chronoManager->_textTtl = totalChars * kTextCharDisplayTime;
}
bool isEndMarker(char char_byte) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 65003ca8edb..1128d9bd5e8 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -102,10 +102,11 @@ private:
void drawText(Common::String text, int x, int y, int w, byte color);
void sayAlfred(Common::String text);
+ void sayNPC(AnimSet *anim, Common::String text, byte color);
// render loop
void frames();
void doAction(byte action, byte object);
- void renderText(Common::Array<Common::String> lines, int color);
+ void renderText(Common::Array<Common::String> lines, int color, int x, int y);
void drawAlfred(byte *buf);
void checkMouseHover();
void checkMouseClick(int x, int y);
@@ -131,9 +132,14 @@ private:
PathContext _currentContext;
int _current_step = 0;
+
+
byte _textColor = 0;
+ Common::Point _textPos;
Common::Array<Common::Array<Common::String> > _currentTextPages = Common::Array<Common::Array<Common::String> >();
int _currentTextPageIndex = 0;
+
+
Common::Array<HotSpot> _currentRoomHotspots;
Common::Array<AnimSet> _currentRoomAnims;
Common::Array<Exit> _currentRoomExits;
@@ -173,7 +179,7 @@ private:
Common::Point _curWalkTarget;
bool isNPCATalking = false;
- uint16 NPCTalking = 0;
+ uint16 whichNPCTalking = 0;
bool isNPCBTalking = false;
Commit: 1ecefd962b11ef03290e6b1e1828f615531aeb61
https://github.com/scummvm/scummvm/commit/1ecefd962b11ef03290e6b1e1828f615531aeb61
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:09+02:00
Commit Message:
PELROCK: Creates ResourceManager
Changed paths:
A engines/pelrock/resources.cpp
A engines/pelrock/resources.h
A engines/pelrock/util.cpp
A engines/pelrock/util.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index 0c1e387371a..458143f1b40 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -5,8 +5,10 @@ MODULE_OBJS = \
chrono.o \
console.o \
metaengine.o \
+ resources.o \
fonts/small_font.o \
fonts/large_font.o \
+ util.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index ca348e2d804..fe611f99409 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -39,6 +39,7 @@
#include "pelrock/fonts/small_font.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
+#include "pelrock/util.h"
namespace Pelrock {
@@ -48,9 +49,14 @@ PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) :
_gameDescription(gameDesc), _randomSource("Pelrock") {
g_engine = this;
_chronoManager = new ChronoManager();
+ _resourceManager = new ResourceManager();
}
PelrockEngine::~PelrockEngine() {
+ delete _resourceManager;
+ delete[] _compositeBuffer;
+ delete[] _currentBackground;
+ delete _largeFont;
delete _screen;
delete _chronoManager;
for (int i = 0; i < 5; i++) {
@@ -84,21 +90,6 @@ Common::String PelrockEngine::getGameId() const {
return _gameDescription->gameId;
}
-void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color) {
- // debug("Drawing rect at (%d,%d) w=%d h=%d color=%d", x, y, w, h, color);
- surface->drawLine(x, y, x + w, y, color);
- surface->drawLine(x, y + h, x + w, y + h, color);
- surface->drawLine(x, y, x, y + h, color);
- surface->drawLine(x + w, y, x + w, y + h, color);
-}
-void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color) {
- // debug("Drawing rect at (%d,%d) w=%d h=%d color=%d", x, y, w, h, color);
- surface->drawLine(x, y, x + w, y, color);
- surface->drawLine(x, y + h, x + w, y + h, color);
- surface->drawLine(x, y, x, y + h, color);
- surface->drawLine(x + w, y, x + w, y + h, color);
-}
-
Common::Array<Common::Array<Common::String> > wordWrap(Common::String text);
Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
@@ -207,43 +198,6 @@ void PelrockEngine::loadAnims() {
loadAlfredAnims();
}
-const int EXPECTED_SIZE = 640 * 400;
-size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data) {
- // Check for uncompressed markers
- if (size == 0x8000 || size == 0x6800) {
- *out_data = (uint8_t *)malloc(size);
- memcpy(*out_data, data + offset, size);
- return size;
- }
-
- // RLE compressed
- *out_data = (uint8_t *)malloc(EXPECTED_SIZE * 2); // Allocate enough space
- size_t result_size = 0;
-
- uint32_t pos = offset;
- uint32_t end = offset + size;
-
- while (pos + 2 <= end && pos + 2 <= data_size) {
- // Check for BUDA marker
- if (pos + 4 <= data_size &&
- data[pos] == 'B' && data[pos + 1] == 'U' &&
- data[pos + 2] == 'D' && data[pos + 3] == 'A') {
- break;
- }
-
- uint8_t count = data[pos];
- uint8_t value = data[pos + 1];
-
- for (int i = 0; i < count; i++) {
- (*out_data)[result_size++] = value;
- }
-
- pos += 2;
- }
-
- return result_size;
-}
-
void PelrockEngine::getPalette(Common::File *roomFile, int roomOffset, byte *palette) {
// get palette
int paletteOffset = roomOffset + (11 * 8);
@@ -291,168 +245,168 @@ void PelrockEngine::getBackground(Common::File *roomFile, int roomOffset, byte *
}
}
-Common::Array<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
- uint32_t pair_offset = roomOffset + (8 * 8);
- // debug("Sprite pair offset position: %d", pair_offset);
- roomFile->seek(pair_offset, SEEK_SET);
- uint32_t offset = roomFile->readUint32LE();
- uint32_t size = roomFile->readUint32LE();
-
- byte *data = new byte[size];
- roomFile->seek(offset, SEEK_SET);
- roomFile->read(data, size);
-
- unsigned char *pic = new byte[10000 * 10000];
- if (offset > 0 && size > 0) {
- rleDecompress(data, size, 0, size, &pic);
- } else {
- return Common::Array<AnimSet>();
- }
- Common::Array<AnimSet> anims = Common::Array<AnimSet>();
- uint32_t spriteEnd = offset + size;
-
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- uint32_t metadata_start = spriteEnd + 108;
- uint32_t picOffset = 0;
- for (int i = 0; i < 7; i++) {
- uint32_t animOffset = metadata_start + (i * 44);
- byte *animData = new byte[44];
- roomFile->seek(animOffset, SEEK_SET);
- roomFile->read(animData, 44);
- AnimSet animSet;
- animSet.x = animData[0] | (animData[1] << 8);
- animSet.y = animData[2] | (animData[3] << 8);
- animSet.w = animData[4];
- animSet.h = animData[5];
- animSet.extra = animData[6];
- // roomFile->skip(1); // reserved
- animSet.numAnims = animData[8];
- animSet.spriteType = animData[33];
- animSet.actionFlags = animData[34];
- animSet.isDisabled = animData[38];
- if (animSet.numAnims == 0) {
- break;
- }
- animSet.animData = new Anim[animSet.numAnims];
- // debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
- int subAnimOffset = 10;
- for (int j = 0; j < animSet.numAnims; j++) {
-
- Anim anim;
- anim.x = animSet.x;
- anim.y = animSet.y;
- anim.w = animSet.w;
- anim.h = animSet.h;
- anim.curFrame = 0;
-
- anim.nframes = animData[subAnimOffset + j];
- anim.loopCount = animData[subAnimOffset + 4 + j];
- anim.speed = animData[subAnimOffset + 8 + j];
- anim.animData = new byte[anim.nframes];
- if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
- uint32_t needed = anim.w * anim.h * anim.nframes;
- anim.animData = new byte[needed];
- Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
- animSet.animData[j] = anim;
- // debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
- picOffset += needed;
- } else {
- continue;
- debug("Anim %d-%d: invalid dimensions, skipping", i, j);
- }
- animSet.animData[j] = anim;
- }
-
- anims.push_back(animSet);
- }
- return anims;
-}
-
-Common::Array<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int roomOffset) {
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- roomFile->seek(pair10_offset_pos, SEEK_SET);
- // roomFile->skip(4);
- uint32_t pair10_data_offset = roomFile->readUint32LE();
- uint32_t pair10_size = roomFile->readUint32LE();
-
- uint32_t walkbox_countOffset = pair10_data_offset + 0x213;
- roomFile->seek(walkbox_countOffset, SEEK_SET);
- byte walkbox_count = roomFile->readByte();
- debug("Walkbox count: %d", walkbox_count);
- uint32_t walkbox_offset = pair10_data_offset + 0x218;
- Common::Array<WalkBox> walkboxes;
- for (int i = 0; i < walkbox_count; i++) {
- uint32_t box_offset = walkbox_offset + i * 9;
- roomFile->seek(box_offset, SEEK_SET);
- int16 x1 = roomFile->readSint16LE();
- int16 y1 = roomFile->readSint16LE();
- int16 w = roomFile->readSint16LE();
- int16 h = roomFile->readSint16LE();
- byte flags = roomFile->readByte();
- debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
- WalkBox box;
- box.x = x1;
- box.y = y1;
- box.w = w;
- box.h = h;
- box.flags = flags;
- walkboxes.push_back(box);
- }
- return walkboxes;
-}
-
-Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos) {
- uint32_t pair12_offset_pos = roomOffset + (12 * 8);
- roomFile->seek(pair12_offset_pos, SEEK_SET);
- // roomFile->skip(4);
- uint32_t pair12_data_offset = roomFile->readUint32LE();
- uint32_t pair12_size = roomFile->readUint32LE();
-
- roomFile->seek(pair12_data_offset, SEEK_SET);
- byte *data = new byte[pair12_size];
- roomFile->read(data, pair12_size);
- Common::Array<Description> descriptions;
- uint32_t pos = 0;
- uint32_t lastDescPos = 0;
- while (pos < (pair12_size)) {
- int desc_pos = 0;
- if (data[pos] == 0xFF) {
- Description description;
- description.itemId = data[pos + 1];
- pos += 3;
- description.index = data[pos++];
- description.text = "";
- // debug("Found description terminator");
- while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
- // debug(" char: %c", data[pos]);
- if (data[pos] != 0x00) {
- description.text.append(1, (char)data[pos]);
- }
- if (data[pos] == 0xF8) {
- description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
- debug("Found action trigger: %d", description.actionTrigger);
- pos += 2;
- break;
- }
- // desc[desc_pos++] = (char)data[pos];
- // debug("Current desc: %s", desc);
- pos++;
- }
- debug("Found description for item %d index %d, text: %s", description.itemId, description.index, description.text.c_str());
-
- descriptions.push_back(description);
- lastDescPos = pos;
- }
- pos++;
- }
- debug("End of descriptions at position %d", pos);
- outPos = lastDescPos + 1;
- delete[] data;
- // for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
- // debug("Room description: %s", i->c_str());
- // }
- return descriptions;
-}
+// Common::Array<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
+// uint32_t pair_offset = roomOffset + (8 * 8);
+// // debug("Sprite pair offset position: %d", pair_offset);
+// roomFile->seek(pair_offset, SEEK_SET);
+// uint32_t offset = roomFile->readUint32LE();
+// uint32_t size = roomFile->readUint32LE();
+
+// byte *data = new byte[size];
+// roomFile->seek(offset, SEEK_SET);
+// roomFile->read(data, size);
+
+// unsigned char *pic = new byte[10000 * 10000];
+// if (offset > 0 && size > 0) {
+// rleDecompress(data, size, 0, size, &pic);
+// } else {
+// return Common::Array<AnimSet>();
+// }
+// Common::Array<AnimSet> anims = Common::Array<AnimSet>();
+// uint32_t spriteEnd = offset + size;
+
+// uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+// uint32_t metadata_start = spriteEnd + 108;
+// uint32_t picOffset = 0;
+// for (int i = 0; i < 7; i++) {
+// uint32_t animOffset = metadata_start + (i * 44);
+// byte *animData = new byte[44];
+// roomFile->seek(animOffset, SEEK_SET);
+// roomFile->read(animData, 44);
+// AnimSet animSet;
+// animSet.x = animData[0] | (animData[1] << 8);
+// animSet.y = animData[2] | (animData[3] << 8);
+// animSet.w = animData[4];
+// animSet.h = animData[5];
+// animSet.extra = animData[6];
+// // roomFile->skip(1); // reserved
+// animSet.numAnims = animData[8];
+// animSet.spriteType = animData[33];
+// animSet.actionFlags = animData[34];
+// animSet.isDisabled = animData[38];
+// if (animSet.numAnims == 0) {
+// break;
+// }
+// animSet.animData = new Anim[animSet.numAnims];
+// // debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
+// int subAnimOffset = 10;
+// for (int j = 0; j < animSet.numAnims; j++) {
+
+// Anim anim;
+// anim.x = animSet.x;
+// anim.y = animSet.y;
+// anim.w = animSet.w;
+// anim.h = animSet.h;
+// anim.curFrame = 0;
+
+// anim.nframes = animData[subAnimOffset + j];
+// anim.loopCount = animData[subAnimOffset + 4 + j];
+// anim.speed = animData[subAnimOffset + 8 + j];
+// anim.animData = new byte[anim.nframes];
+// if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
+// uint32_t needed = anim.w * anim.h * anim.nframes;
+// anim.animData = new byte[needed];
+// Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
+// animSet.animData[j] = anim;
+// // debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
+// picOffset += needed;
+// } else {
+// continue;
+// debug("Anim %d-%d: invalid dimensions, skipping", i, j);
+// }
+// animSet.animData[j] = anim;
+// }
+
+// anims.push_back(animSet);
+// }
+// return anims;
+// }
+
+// Common::Array<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int roomOffset) {
+// uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+// roomFile->seek(pair10_offset_pos, SEEK_SET);
+// // roomFile->skip(4);
+// uint32_t pair10_data_offset = roomFile->readUint32LE();
+// uint32_t pair10_size = roomFile->readUint32LE();
+
+// uint32_t walkbox_countOffset = pair10_data_offset + 0x213;
+// roomFile->seek(walkbox_countOffset, SEEK_SET);
+// byte walkbox_count = roomFile->readByte();
+// debug("Walkbox count: %d", walkbox_count);
+// uint32_t walkbox_offset = pair10_data_offset + 0x218;
+// Common::Array<WalkBox> walkboxes;
+// for (int i = 0; i < walkbox_count; i++) {
+// uint32_t box_offset = walkbox_offset + i * 9;
+// roomFile->seek(box_offset, SEEK_SET);
+// int16 x1 = roomFile->readSint16LE();
+// int16 y1 = roomFile->readSint16LE();
+// int16 w = roomFile->readSint16LE();
+// int16 h = roomFile->readSint16LE();
+// byte flags = roomFile->readByte();
+// debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+// WalkBox box;
+// box.x = x1;
+// box.y = y1;
+// box.w = w;
+// box.h = h;
+// box.flags = flags;
+// walkboxes.push_back(box);
+// }
+// return walkboxes;
+// }
+
+// Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos) {
+// uint32_t pair12_offset_pos = roomOffset + (12 * 8);
+// roomFile->seek(pair12_offset_pos, SEEK_SET);
+// // roomFile->skip(4);
+// uint32_t pair12_data_offset = roomFile->readUint32LE();
+// uint32_t pair12_size = roomFile->readUint32LE();
+
+// roomFile->seek(pair12_data_offset, SEEK_SET);
+// byte *data = new byte[pair12_size];
+// roomFile->read(data, pair12_size);
+// Common::Array<Description> descriptions;
+// uint32_t pos = 0;
+// uint32_t lastDescPos = 0;
+// while (pos < (pair12_size)) {
+// int desc_pos = 0;
+// if (data[pos] == 0xFF) {
+// Description description;
+// description.itemId = data[pos + 1];
+// pos += 3;
+// description.index = data[pos++];
+// description.text = "";
+// // debug("Found description terminator");
+// while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
+// // debug(" char: %c", data[pos]);
+// if (data[pos] != 0x00) {
+// description.text.append(1, (char)data[pos]);
+// }
+// if (data[pos] == 0xF8) {
+// description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
+// debug("Found action trigger: %d", description.actionTrigger);
+// pos += 2;
+// break;
+// }
+// // desc[desc_pos++] = (char)data[pos];
+// // debug("Current desc: %s", desc);
+// pos++;
+// }
+// debug("Found description for item %d index %d, text: %s", description.itemId, description.index, description.text.c_str());
+
+// descriptions.push_back(description);
+// lastDescPos = pos;
+// }
+// pos++;
+// }
+// debug("End of descriptions at position %d", pos);
+// outPos = lastDescPos + 1;
+// delete[] data;
+// // for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
+// // debug("Room description: %s", i->c_str());
+// // }
+// return descriptions;
+// }
char32_t decodeByte(byte b) {
if (b == 0x80) {
@@ -867,67 +821,67 @@ Common::Array<ConversationNode> PelrockEngine::loadConversations(Common::File *r
return roots;
}
-void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
- uint32_t outPos = 0;
-
- Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
- debug("After decsriptions, position is %d", outPos);
- Common::Array<ConversationNode> roots = loadConversations(roomFile, roomOffset, outPos);
- for (int i = 0; i < roots.size(); i++) {
- if (roots[i].text.empty()) {
- continue;
- }
- debug("Conversation %d: %s", i, roots[i].text.c_str());
- }
- _currentRoomConversations = roots;
-
- Common::Array<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
-
- Common::Array<HotSpot> hotspots;
- for (int i = 0; i < anims.size(); i++) {
-
- HotSpot thisHotspot;
- thisHotspot.index = i;
- thisHotspot.x = anims[i].x;
- thisHotspot.y = anims[i].y;
- thisHotspot.w = anims[i].w;
- thisHotspot.h = anims[i].h;
- thisHotspot.extra = anims[i].extra;
- thisHotspot.type = anims[i].actionFlags;
- thisHotspot.isEnabled = !anims[i].isDisabled;
- hotspots.push_back(thisHotspot);
- }
-
- Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
- Common::Array<Exit> exits = loadExits(roomFile, roomOffset);
-
- Common::Array<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
-
- debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
- for (int i = 0; i < staticHotspots.size(); i++) {
- HotSpot hotspot = staticHotspots[i];
- hotspot.index = anims.size() + i;
- hotspots.push_back(hotspot);
- }
-
- int walkboxCount = 0;
-
- _currentRoomAnims = anims;
- _currentRoomHotspots = hotspots;
- _currentRoomExits = exits;
- _currentRoomWalkboxes = walkboxes;
- _currentRoomDescriptions = descriptions;
-
- for (int i = 0; i < _currentRoomHotspots.size(); i++) {
- HotSpot hotspot = _currentRoomHotspots[i];
- drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
- }
-
- for (int i = 0; i < _currentRoomExits.size(); i++) {
- Exit exit = _currentRoomExits[i];
- // drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
- }
-}
+// void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
+// uint32_t outPos = 0;
+
+// Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
+// debug("After decsriptions, position is %d", outPos);
+// Common::Array<ConversationNode> roots = loadConversations(roomFile, roomOffset, outPos);
+// for (int i = 0; i < roots.size(); i++) {
+// if (roots[i].text.empty()) {
+// continue;
+// }
+// debug("Conversation %d: %s", i, roots[i].text.c_str());
+// }
+// _currentRoomConversations = roots;
+
+// Common::Array<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
+
+// Common::Array<HotSpot> hotspots;
+// for (int i = 0; i < anims.size(); i++) {
+
+// HotSpot thisHotspot;
+// thisHotspot.index = i;
+// thisHotspot.x = anims[i].x;
+// thisHotspot.y = anims[i].y;
+// thisHotspot.w = anims[i].w;
+// thisHotspot.h = anims[i].h;
+// thisHotspot.extra = anims[i].extra;
+// thisHotspot.type = anims[i].actionFlags;
+// thisHotspot.isEnabled = !anims[i].isDisabled;
+// hotspots.push_back(thisHotspot);
+// }
+
+// Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
+// Common::Array<Exit> exits = loadExits(roomFile, roomOffset);
+
+// Common::Array<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
+
+// debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
+// for (int i = 0; i < staticHotspots.size(); i++) {
+// HotSpot hotspot = staticHotspots[i];
+// hotspot.index = anims.size() + i;
+// hotspots.push_back(hotspot);
+// }
+
+// int walkboxCount = 0;
+
+// _currentRoomAnims = anims;
+// _currentRoomHotspots = hotspots;
+// _currentRoomExits = exits;
+// _currentRoomWalkboxes = walkboxes;
+// _currentRoomDescriptions = descriptions;
+
+// for (int i = 0; i < _currentRoomHotspots.size(); i++) {
+// HotSpot hotspot = _currentRoomHotspots[i];
+// drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
+// }
+
+// for (int i = 0; i < _currentRoomExits.size(); i++) {
+// Exit exit = _currentRoomExits[i];
+// // drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
+// }
+// }
void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize) {
const char marker[] = "BUDA";
@@ -1079,60 +1033,60 @@ void PelrockEngine::loadInteractionIcons() {
alfred4File.close();
}
-Common::Array<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffset) {
- Common::Array<Exit> exits;
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- roomFile->seek(pair10_offset_pos, SEEK_SET);
- uint32_t pair10_data_offset = roomFile->readUint32LE();
- uint32_t pair10_size = roomFile->readUint32LE();
- roomFile->seek(pair10_data_offset + 0x1BE, SEEK_SET);
- int exit_count = roomFile->readByte();
- roomFile->seek(pair10_data_offset + 0x1BF, SEEK_SET);
- for (int i = 0; i < exit_count; i++) {
- Exit exit;
- exit.targetRoom = roomFile->readUint16LE();
- exit.flags = roomFile->readByte();
- exit.x = roomFile->readUint16LE();
- exit.y = roomFile->readUint16LE();
- exit.w = roomFile->readByte();
- exit.h = roomFile->readByte();
-
- exit.targetX = roomFile->readUint16LE();
- exit.targetY = roomFile->readUint16LE();
- exit.dir = roomFile->readByte();
- exits.push_back(exit);
- }
- return exits;
-}
-
-Common::Array<HotSpot> PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- debug("Hotspot(10) pair offset position: %d", pair10_offset_pos);
- roomFile->seek(pair10_offset_pos, SEEK_SET);
- uint32_t pair10_data_offset = roomFile->readUint32LE();
- uint32_t pair10_size = roomFile->readUint32LE();
- uint32_t count_offset = pair10_data_offset + 0x47a;
- roomFile->seek(count_offset, SEEK_SET);
- byte hotspot_count = roomFile->readByte();
- uint32_t hotspot_data_start = pair10_data_offset + 0x47c;
- Common::Array<HotSpot> hotspots;
- for (int i = 0; i < hotspot_count; i++) {
- uint32_t obj_offset = hotspot_data_start + i * 9;
- roomFile->seek(obj_offset, SEEK_SET);
- HotSpot spot;
- spot.type = roomFile->readByte();
- spot.x = roomFile->readUint16LE();
- spot.y = roomFile->readUint16LE();
- spot.w = roomFile->readByte();
- spot.h = roomFile->readByte();
- spot.extra = roomFile->readUint16LE();
- debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
- hotspots.push_back(spot);
- }
- return hotspots;
- // uint32_t hover_areas_start = pair10_data_offset + 0x1BE;
- // roomFile->seek(hover_areas_start, SEEK_SET);
-}
+// Common::Array<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffset) {
+// Common::Array<Exit> exits;
+// uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+// roomFile->seek(pair10_offset_pos, SEEK_SET);
+// uint32_t pair10_data_offset = roomFile->readUint32LE();
+// uint32_t pair10_size = roomFile->readUint32LE();
+// roomFile->seek(pair10_data_offset + 0x1BE, SEEK_SET);
+// int exit_count = roomFile->readByte();
+// roomFile->seek(pair10_data_offset + 0x1BF, SEEK_SET);
+// for (int i = 0; i < exit_count; i++) {
+// Exit exit;
+// exit.targetRoom = roomFile->readUint16LE();
+// exit.flags = roomFile->readByte();
+// exit.x = roomFile->readUint16LE();
+// exit.y = roomFile->readUint16LE();
+// exit.w = roomFile->readByte();
+// exit.h = roomFile->readByte();
+
+// exit.targetX = roomFile->readUint16LE();
+// exit.targetY = roomFile->readUint16LE();
+// exit.dir = roomFile->readByte();
+// exits.push_back(exit);
+// }
+// return exits;
+// }
+
+// Common::Array<HotSpot> PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
+// uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+// debug("Hotspot(10) pair offset position: %d", pair10_offset_pos);
+// roomFile->seek(pair10_offset_pos, SEEK_SET);
+// uint32_t pair10_data_offset = roomFile->readUint32LE();
+// uint32_t pair10_size = roomFile->readUint32LE();
+// uint32_t count_offset = pair10_data_offset + 0x47a;
+// roomFile->seek(count_offset, SEEK_SET);
+// byte hotspot_count = roomFile->readByte();
+// uint32_t hotspot_data_start = pair10_data_offset + 0x47c;
+// Common::Array<HotSpot> hotspots;
+// for (int i = 0; i < hotspot_count; i++) {
+// uint32_t obj_offset = hotspot_data_start + i * 9;
+// roomFile->seek(obj_offset, SEEK_SET);
+// HotSpot spot;
+// spot.type = roomFile->readByte();
+// spot.x = roomFile->readUint16LE();
+// spot.y = roomFile->readUint16LE();
+// spot.w = roomFile->readByte();
+// spot.h = roomFile->readByte();
+// spot.extra = roomFile->readUint16LE();
+// debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
+// hotspots.push_back(spot);
+// }
+// return hotspots;
+// // uint32_t hover_areas_start = pair10_data_offset + 0x1BE;
+// // roomFile->seek(hover_areas_start, SEEK_SET);
+// }
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight) {
for (int y = 0; y < frameHeight; y++) {
@@ -2299,7 +2253,7 @@ void PelrockEngine::setScreen(int number, int dir) {
}
}
- loadRoomMetadata(&roomFile, roomOffset);
+ _resourceManager->loadRoomMetadata(&roomFile, roomOffset);
loadRoomTalkingAnimations(number);
_screen->markAllDirty();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 1128d9bd5e8..feef1bf91bc 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -40,6 +40,7 @@
#include "pelrock/detection.h"
#include "pelrock/fonts/large_font.h"
#include "pelrock/fonts/small_font.h"
+#include "pelrock/resources.h"
#include "pelrock/types.h"
namespace Pelrock {
@@ -53,7 +54,7 @@ class PelrockEngine : public Engine {
private:
const ADGameDescription *_gameDescription;
Common::RandomSource _randomSource;
- Image::PNGDecoder *decoder = new Image::PNGDecoder();
+
void init();
void playIntro();
void setScreen(int s, int dir);
@@ -64,11 +65,11 @@ private:
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
void loadAlfredAnims();
- Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
- Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
- Common::Array<Exit> loadExits(Common::File *roomFile, int roomOffset);
- Common::Array<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
- Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos);
+ // Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
+ // Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
+ // Common::Array<Exit> loadExits(Common::File *roomFile, int roomOffset);
+ // Common::Array<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
+ // Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos);
Common::String cleanText(const Common::String &text);
Common::Array<ConversationElement> parseConversationElements(const byte *convData, uint32 size);
@@ -90,7 +91,7 @@ private:
void talk(byte object);
Common::String getControlName(byte b);
- void loadRoomMetadata(Common::File *roomFile, int roomOffset);
+ // void loadRoomMetadata(Common::File *roomFile, int roomOffset);
void loadRoomTalkingAnimations(int roomNumber);
void loadCursors();
void loadInteractionIcons();
@@ -122,31 +123,22 @@ private:
// byte *standingAnim = new byte[3060 * 102];
- byte **walkingAnimFrames[4]; // 4 arrays of arrays
- byte *standingAnimFrames[4] = {nullptr}; // 4 directions
- int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
- byte **talkingAnimFrames[4]; // 4 arrays of arrays
- int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+ byte **walkingAnimFrames[4]; // 4 arrays of arrays
+ byte *standingAnimFrames[4] = {nullptr}; // 4 directions
+ int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+ byte **talkingAnimFrames[4]; // 4 arrays of arrays
+ int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
TalkinAnimHeader _talkingAnimHeader;
PathContext _currentContext;
int _current_step = 0;
-
byte _textColor = 0;
Common::Point _textPos;
Common::Array<Common::Array<Common::String> > _currentTextPages = Common::Array<Common::Array<Common::String> >();
int _currentTextPageIndex = 0;
-
- Common::Array<HotSpot> _currentRoomHotspots;
- Common::Array<AnimSet> _currentRoomAnims;
- Common::Array<Exit> _currentRoomExits;
- Common::Array<WalkBox> _currentRoomWalkboxes;
- Common::Array<Description> _currentRoomDescriptions;
- Common::Array<ConversationNode> _currentRoomConversations;
-
int *_currentAnimFrames = nullptr;
// From the original code
int xAlfred = 319;
@@ -182,8 +174,7 @@ private:
uint16 whichNPCTalking = 0;
bool isNPCBTalking = false;
-
- //JAVA
+ // JAVA
bool shouldPlayIntro = false;
GameState stateGame = GAME;
bool gameInitialized = false;
@@ -194,6 +185,9 @@ private:
// int prevWhichScreen = 0;
// int whichScreen = 0;
// byte *pixelsShadows; // =new int[640*400];
+
+ ResourceManager *_resourceManager = nullptr;
+
protected:
// Engine APIs
Common::Error run() override;
@@ -248,6 +242,13 @@ public:
Common::Serializer s(stream, nullptr);
return syncGame(s);
}
+
+ Common::Array<HotSpot> _currentRoomHotspots;
+ Common::Array<AnimSet> _currentRoomAnims;
+ Common::Array<Exit> _currentRoomExits;
+ Common::Array<WalkBox> _currentRoomWalkboxes;
+ Common::Array<Description> _currentRoomDescriptions;
+ Common::Array<ConversationNode> _currentRoomConversations;
};
extern PelrockEngine *g_engine;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
new file mode 100644
index 00000000000..dac515a606d
--- /dev/null
+++ b/engines/pelrock/resources.cpp
@@ -0,0 +1,312 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "pelrock/resources.h"
+#include "pelrock/pelrock.h"
+#include "pelrock/util.h"
+
+namespace Pelrock {
+
+ResourceManager::ResourceManager() {
+}
+
+ResourceManager::~ResourceManager() {
+}
+
+Common::Array<Exit> ResourceManager::loadExits(Common::File *roomFile, int roomOffset) {
+ Common::Array<Exit> exits;
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ roomFile->seek(pair10_offset_pos, SEEK_SET);
+ uint32_t pair10_data_offset = roomFile->readUint32LE();
+ uint32_t pair10_size = roomFile->readUint32LE();
+ roomFile->seek(pair10_data_offset + 0x1BE, SEEK_SET);
+ int exit_count = roomFile->readByte();
+ roomFile->seek(pair10_data_offset + 0x1BF, SEEK_SET);
+ for (int i = 0; i < exit_count; i++) {
+ Exit exit;
+ exit.targetRoom = roomFile->readUint16LE();
+ exit.flags = roomFile->readByte();
+ exit.x = roomFile->readUint16LE();
+ exit.y = roomFile->readUint16LE();
+ exit.w = roomFile->readByte();
+ exit.h = roomFile->readByte();
+
+ exit.targetX = roomFile->readUint16LE();
+ exit.targetY = roomFile->readUint16LE();
+ exit.dir = roomFile->readByte();
+ exits.push_back(exit);
+ }
+ return exits;
+}
+
+Common::Array<HotSpot> ResourceManager::loadHotspots(Common::File *roomFile, int roomOffset) {
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ debug("Hotspot(10) pair offset position: %d", pair10_offset_pos);
+ roomFile->seek(pair10_offset_pos, SEEK_SET);
+ uint32_t pair10_data_offset = roomFile->readUint32LE();
+ uint32_t pair10_size = roomFile->readUint32LE();
+ uint32_t count_offset = pair10_data_offset + 0x47a;
+ roomFile->seek(count_offset, SEEK_SET);
+ byte hotspot_count = roomFile->readByte();
+ uint32_t hotspot_data_start = pair10_data_offset + 0x47c;
+ Common::Array<HotSpot> hotspots;
+ for (int i = 0; i < hotspot_count; i++) {
+ uint32_t obj_offset = hotspot_data_start + i * 9;
+ roomFile->seek(obj_offset, SEEK_SET);
+ HotSpot spot;
+ spot.type = roomFile->readByte();
+ spot.x = roomFile->readUint16LE();
+ spot.y = roomFile->readUint16LE();
+ spot.w = roomFile->readByte();
+ spot.h = roomFile->readByte();
+ spot.extra = roomFile->readUint16LE();
+ debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
+ hotspots.push_back(spot);
+ }
+ return hotspots;
+ // uint32_t hover_areas_start = pair10_data_offset + 0x1BE;
+ // roomFile->seek(hover_areas_start, SEEK_SET);
+}
+
+void ResourceManager::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
+ uint32_t outPos = 0;
+
+ Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
+ debug("After decsriptions, position is %d", outPos);
+ // Common::Array<ConversationNode> roots = loadConversations(roomFile, roomOffset, outPos);
+ // for (int i = 0; i < roots.size(); i++) {
+ // if (roots[i].text.empty()) {
+ // continue;
+ // }
+ // debug("Conversation %d: %s", i, roots[i].text.c_str());
+ // }
+ // g_engine->_currentRoomConversations = roots;
+
+ Common::Array<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
+
+ Common::Array<HotSpot> hotspots;
+ for (int i = 0; i < anims.size(); i++) {
+
+ HotSpot thisHotspot;
+ thisHotspot.index = i;
+ thisHotspot.x = anims[i].x;
+ thisHotspot.y = anims[i].y;
+ thisHotspot.w = anims[i].w;
+ thisHotspot.h = anims[i].h;
+ thisHotspot.extra = anims[i].extra;
+ thisHotspot.type = anims[i].actionFlags;
+ thisHotspot.isEnabled = !anims[i].isDisabled;
+ hotspots.push_back(thisHotspot);
+ }
+
+ Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
+ Common::Array<Exit> exits = loadExits(roomFile, roomOffset);
+
+ Common::Array<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
+
+ debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
+ for (int i = 0; i < staticHotspots.size(); i++) {
+ HotSpot hotspot = staticHotspots[i];
+ hotspot.index = anims.size() + i;
+ hotspots.push_back(hotspot);
+ }
+
+ int walkboxCount = 0;
+
+ g_engine->_currentRoomAnims = anims;
+ g_engine->_currentRoomHotspots = hotspots;
+ g_engine->_currentRoomExits = exits;
+ g_engine->_currentRoomWalkboxes = walkboxes;
+ g_engine->_currentRoomDescriptions = descriptions;
+ for (int i = 0; i < g_engine->_currentRoomHotspots.size(); i++) {
+ HotSpot hotspot = g_engine->_currentRoomHotspots[i];
+ drawRect(g_engine->_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
+ }
+
+ for (int i = 0; i < g_engine->_currentRoomExits.size(); i++) {
+ Exit exit = g_engine->_currentRoomExits[i];
+ // drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
+ }
+}
+Common::Array<AnimSet> ResourceManager::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
+ uint32_t pair_offset = roomOffset + (8 * 8);
+ // debug("Sprite pair offset position: %d", pair_offset);
+ roomFile->seek(pair_offset, SEEK_SET);
+ uint32_t offset = roomFile->readUint32LE();
+ uint32_t size = roomFile->readUint32LE();
+
+ byte *data = new byte[size];
+ roomFile->seek(offset, SEEK_SET);
+ roomFile->read(data, size);
+
+ unsigned char *pic = new byte[10000 * 10000];
+ if (offset > 0 && size > 0) {
+ rleDecompress(data, size, 0, size, &pic);
+ } else {
+ return Common::Array<AnimSet>();
+ }
+ Common::Array<AnimSet> anims = Common::Array<AnimSet>();
+ uint32_t spriteEnd = offset + size;
+
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ uint32_t metadata_start = spriteEnd + 108;
+ uint32_t picOffset = 0;
+ for (int i = 0; i < 7; i++) {
+ uint32_t animOffset = metadata_start + (i * 44);
+ byte *animData = new byte[44];
+ roomFile->seek(animOffset, SEEK_SET);
+ roomFile->read(animData, 44);
+ AnimSet animSet;
+ animSet.x = animData[0] | (animData[1] << 8);
+ animSet.y = animData[2] | (animData[3] << 8);
+ animSet.w = animData[4];
+ animSet.h = animData[5];
+ animSet.extra = animData[6];
+ // roomFile->skip(1); // reserved
+ animSet.numAnims = animData[8];
+ animSet.spriteType = animData[33];
+ animSet.actionFlags = animData[34];
+ animSet.isDisabled = animData[38];
+ if (animSet.numAnims == 0) {
+ break;
+ }
+ animSet.animData = new Anim[animSet.numAnims];
+ // debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
+ int subAnimOffset = 10;
+ for (int j = 0; j < animSet.numAnims; j++) {
+
+ Anim anim;
+ anim.x = animSet.x;
+ anim.y = animSet.y;
+ anim.w = animSet.w;
+ anim.h = animSet.h;
+ anim.curFrame = 0;
+
+ anim.nframes = animData[subAnimOffset + j];
+ anim.loopCount = animData[subAnimOffset + 4 + j];
+ anim.speed = animData[subAnimOffset + 8 + j];
+ anim.animData = new byte[anim.nframes];
+ if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
+ uint32_t needed = anim.w * anim.h * anim.nframes;
+ anim.animData = new byte[needed];
+ Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
+ animSet.animData[j] = anim;
+ // debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
+ picOffset += needed;
+ } else {
+ continue;
+ debug("Anim %d-%d: invalid dimensions, skipping", i, j);
+ }
+ animSet.animData[j] = anim;
+ }
+
+ anims.push_back(animSet);
+ }
+ return anims;
+}
+
+Common::Array<WalkBox> ResourceManager::loadWalkboxes(Common::File *roomFile, int roomOffset) {
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ roomFile->seek(pair10_offset_pos, SEEK_SET);
+ // roomFile->skip(4);
+ uint32_t pair10_data_offset = roomFile->readUint32LE();
+ uint32_t pair10_size = roomFile->readUint32LE();
+
+ uint32_t walkbox_countOffset = pair10_data_offset + 0x213;
+ roomFile->seek(walkbox_countOffset, SEEK_SET);
+ byte walkbox_count = roomFile->readByte();
+ debug("Walkbox count: %d", walkbox_count);
+ uint32_t walkbox_offset = pair10_data_offset + 0x218;
+ Common::Array<WalkBox> walkboxes;
+ for (int i = 0; i < walkbox_count; i++) {
+ uint32_t box_offset = walkbox_offset + i * 9;
+ roomFile->seek(box_offset, SEEK_SET);
+ int16 x1 = roomFile->readSint16LE();
+ int16 y1 = roomFile->readSint16LE();
+ int16 w = roomFile->readSint16LE();
+ int16 h = roomFile->readSint16LE();
+ byte flags = roomFile->readByte();
+ debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+ WalkBox box;
+ box.x = x1;
+ box.y = y1;
+ box.w = w;
+ box.h = h;
+ box.flags = flags;
+ walkboxes.push_back(box);
+ }
+ return walkboxes;
+}
+
+Common::Array<Description> ResourceManager::loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos) {
+ uint32_t pair12_offset_pos = roomOffset + (12 * 8);
+ roomFile->seek(pair12_offset_pos, SEEK_SET);
+ // roomFile->skip(4);
+ uint32_t pair12_data_offset = roomFile->readUint32LE();
+ uint32_t pair12_size = roomFile->readUint32LE();
+
+ roomFile->seek(pair12_data_offset, SEEK_SET);
+ byte *data = new byte[pair12_size];
+ roomFile->read(data, pair12_size);
+ Common::Array<Description> descriptions;
+ uint32_t pos = 0;
+ uint32_t lastDescPos = 0;
+ while (pos < (pair12_size)) {
+ int desc_pos = 0;
+ if (data[pos] == 0xFF) {
+ Description description;
+ description.itemId = data[pos + 1];
+ pos += 3;
+ description.index = data[pos++];
+ description.text = "";
+ // debug("Found description terminator");
+ while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
+ // debug(" char: %c", data[pos]);
+ if (data[pos] != 0x00) {
+ description.text.append(1, (char)data[pos]);
+ }
+ if (data[pos] == 0xF8) {
+ description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
+ debug("Found action trigger: %d", description.actionTrigger);
+ pos += 2;
+ break;
+ }
+ // desc[desc_pos++] = (char)data[pos];
+ // debug("Current desc: %s", desc);
+ pos++;
+ }
+ debug("Found description for item %d index %d, text: %s", description.itemId, description.index, description.text.c_str());
+
+ descriptions.push_back(description);
+ lastDescPos = pos;
+ }
+ pos++;
+ }
+ debug("End of descriptions at position %d", pos);
+ outPos = lastDescPos + 1;
+ delete[] data;
+ // for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
+ // debug("Room description: %s", i->c_str());
+ // }
+ return descriptions;
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
new file mode 100644
index 00000000000..45fcd7b3c31
--- /dev/null
+++ b/engines/pelrock/resources.h
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_RESOURCES_H
+#define PELROCK_RESOURCES_H
+
+#include "common/array.h"
+#include "common/file.h"
+#include "common/scummsys.h"
+
+#include "pelrock/types.h"
+
+namespace Pelrock {
+
+class ResourceManager {
+public:
+ ResourceManager();
+ ~ResourceManager();
+ void loadRoomMetadata(Common::File *roomFile, int roomOffset);
+ void loadRoomTalkingAnimations(int roomNumber);
+
+private:
+ Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
+ Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
+ Common::Array<Exit> loadExits(Common::File *roomFile, int roomOffset);
+ Common::Array<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
+ Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos);
+};
+
+} // End of namespace Pelrock
+
+#endif
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 08e9a30471c..0bb527b3469 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -47,8 +47,6 @@ enum VerbIcons {
UNKNOWN
};
-
-
static const uint32 kLongClickDuration = 500; // 500ms for long click
const int kCursorWidth = 16;
const int kCursorHeight = 18;
@@ -76,21 +74,20 @@ const int kVerbIconPadding = 20;
#define MAX_MOVEMENT_STEPS 100 // 500 bytes / 5 bytes per step
#define PATH_END 0xFF // End of path marker
-#define MAX_CHARS_PER_LINE 0x2F // 47 characters
-#define MAX_LINES 5 // Maximum number of lines per page (0-indexed check against 4)
+#define MAX_CHARS_PER_LINE 0x2F // 47 characters
+#define MAX_LINES 5 // Maximum number of lines per page (0-indexed check against 4)
// Control character codes (negative values in signed char)
-#define CHAR_SPACE 0x20 /* ' ' */
-#define CHAR_END_MARKER_1 0xFD /* -3 (end of text marker) */
-#define CHAR_END_MARKER_2 0xF4 /* -0xC (alternate end marker) */
-#define CHAR_END_MARKER_3 0xF8 /* -8 (another end marker) */
-#define CHAR_END_MARKER_4 0xF0 /* -0x10 (another end marker) */
-#define CHAR_NEWLINE 0xF6 /* -10 (newline marker) */
-#define CHAR_PAGE_BREAK 0xF9 /* marker inserted when switching pages */
+#define CHAR_SPACE 0x20 /* ' ' */
+#define CHAR_END_MARKER_1 0xFD /* -3 (end of text marker) */
+#define CHAR_END_MARKER_2 0xF4 /* -0xC (alternate end marker) */
+#define CHAR_END_MARKER_3 0xF8 /* -8 (another end marker) */
+#define CHAR_END_MARKER_4 0xF0 /* -0x10 (another end marker) */
+#define CHAR_NEWLINE 0xF6 /* -10 (newline marker) */
+#define CHAR_PAGE_BREAK 0xF9 /* marker inserted when switching pages */
#define ALFRED_COLOR 0x0D
-
typedef struct {
uint8_t flags; /* Direction flags (see MOVE_* constants) */
uint16_t distance_x; // Horizontal distance to move
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
new file mode 100644
index 00000000000..7a1ab388d0a
--- /dev/null
+++ b/engines/pelrock/util.cpp
@@ -0,0 +1,79 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "pelrock/util.h"
+#include "pelrock/types.h"
+
+namespace Pelrock {
+
+void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color) {
+ // debug("Drawing rect at (%d,%d) w=%d h=%d color=%d", x, y, w, h, color);
+ surface->drawLine(x, y, x + w, y, color);
+ surface->drawLine(x, y + h, x + w, y + h, color);
+ surface->drawLine(x, y, x, y + h, color);
+ surface->drawLine(x + w, y, x + w, y + h, color);
+}
+
+void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color) {
+ // debug("Drawing rect at (%d,%d) w=%d h=%d color=%d", x, y, w, h, color);
+ surface->drawLine(x, y, x + w, y, color);
+ surface->drawLine(x, y + h, x + w, y + h, color);
+ surface->drawLine(x, y, x, y + h, color);
+ surface->drawLine(x + w, y, x + w, y + h, color);
+}
+
+size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data) {
+ // Check for uncompressed markers
+ if (size == 0x8000 || size == 0x6800) {
+ *out_data = (uint8_t *)malloc(size);
+ memcpy(*out_data, data + offset, size);
+ return size;
+ }
+
+ // RLE compressed
+ *out_data = (uint8_t *)malloc(EXPECTED_SIZE * 2); // Allocate enough space
+ size_t result_size = 0;
+
+ uint32_t pos = offset;
+ uint32_t end = offset + size;
+
+ while (pos + 2 <= end && pos + 2 <= data_size) {
+ // Check for BUDA marker
+ if (pos + 4 <= data_size &&
+ data[pos] == 'B' && data[pos + 1] == 'U' &&
+ data[pos + 2] == 'D' && data[pos + 3] == 'A') {
+ break;
+ }
+
+ uint8_t count = data[pos];
+ uint8_t value = data[pos + 1];
+
+ for (int i = 0; i < count; i++) {
+ (*out_data)[result_size++] = value;
+ }
+
+ pos += 2;
+ }
+
+ return result_size;
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
new file mode 100644
index 00000000000..d5cfa3cc3cf
--- /dev/null
+++ b/engines/pelrock/util.h
@@ -0,0 +1,34 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_UTIL_H
+#define PELROCK_UTIL_H
+
+#include "common/types.h"
+#include "graphics/managed_surface.h"
+#include "graphics/surface.h"
+namespace Pelrock {
+
+const int EXPECTED_SIZE = 640 * 400;
+size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data);
+void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
+void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
+} // End of namespace Pelrock
+#endif // PELROCK_UTIL_H
Commit: 36661bdceee3b33c28437611e027ae6e696c3f24
https://github.com/scummvm/scummvm/commit/36661bdceee3b33c28437611e027ae6e696c3f24
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:10+02:00
Commit Message:
PELROCK: Refactors room resource loading into its own class
Changed paths:
A engines/pelrock/room.cpp
A engines/pelrock/room.h
R engines/pelrock/resources.cpp
R engines/pelrock/resources.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index 458143f1b40..fdaf98bc630 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -5,7 +5,7 @@ MODULE_OBJS = \
chrono.o \
console.o \
metaengine.o \
- resources.o \
+ room.o \
fonts/small_font.o \
fonts/large_font.o \
util.o
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index fe611f99409..b66d2836d6e 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -49,11 +49,11 @@ PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) :
_gameDescription(gameDesc), _randomSource("Pelrock") {
g_engine = this;
_chronoManager = new ChronoManager();
- _resourceManager = new ResourceManager();
+ _room = new RoomManager();
}
PelrockEngine::~PelrockEngine() {
- delete _resourceManager;
+ delete _room;
delete[] _compositeBuffer;
delete[] _currentBackground;
delete _largeFont;
@@ -198,258 +198,19 @@ void PelrockEngine::loadAnims() {
loadAlfredAnims();
}
-void PelrockEngine::getPalette(Common::File *roomFile, int roomOffset, byte *palette) {
- // get palette
- int paletteOffset = roomOffset + (11 * 8);
- roomFile->seek(paletteOffset, SEEK_SET);
- uint32 offset = roomFile->readUint32LE();
- uint32 size = roomFile->readUint32LE();
-
- roomFile->seek(offset, SEEK_SET);
-
- roomFile->read(palette, size);
- for (int i = 0; i < 256; i++) {
- palette[i * 3] = palette[i * 3] << 2;
- palette[i * 3 + 1] = palette[i * 3 + 1] << 2;
- palette[i * 3 + 2] = palette[i * 3 + 2] << 2;
- }
-}
-
-void PelrockEngine::getBackground(Common::File *roomFile, int roomOffset, byte *background) {
- roomFile->seek(0, SEEK_SET);
- // get screen
- size_t combined_size = 0;
- size_t uncompressed_size = 0;
- for (int pair_idx = 0; pair_idx < 8; pair_idx++) {
- uint32_t pair_offset = roomOffset + (pair_idx * 8);
- if (pair_offset + 8 > roomFile->size())
- continue;
-
- roomFile->seek(pair_offset, SEEK_SET);
- uint32_t offset = roomFile->readUint32LE();
- uint32_t size = roomFile->readUint32LE();
- uncompressed_size += size;
-
- if (offset > 0 && size > 0 && offset < roomFile->size()) {
- byte *data = new byte[size];
- roomFile->seek(offset, SEEK_SET);
- roomFile->read(data, size);
- uint8_t *block_data = NULL;
- size_t block_size = rleDecompress(data, size, 0, size, &block_data);
-
- memcpy(background + combined_size, block_data, block_size);
- combined_size += block_size + 1;
- free(block_data);
- delete[] data;
- }
- }
-}
-
-// Common::Array<AnimSet> PelrockEngine::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
-// uint32_t pair_offset = roomOffset + (8 * 8);
-// // debug("Sprite pair offset position: %d", pair_offset);
-// roomFile->seek(pair_offset, SEEK_SET);
-// uint32_t offset = roomFile->readUint32LE();
-// uint32_t size = roomFile->readUint32LE();
-
-// byte *data = new byte[size];
-// roomFile->seek(offset, SEEK_SET);
-// roomFile->read(data, size);
-
-// unsigned char *pic = new byte[10000 * 10000];
-// if (offset > 0 && size > 0) {
-// rleDecompress(data, size, 0, size, &pic);
-// } else {
-// return Common::Array<AnimSet>();
-// }
-// Common::Array<AnimSet> anims = Common::Array<AnimSet>();
-// uint32_t spriteEnd = offset + size;
-
-// uint32_t pair10_offset_pos = roomOffset + (10 * 8);
-// uint32_t metadata_start = spriteEnd + 108;
-// uint32_t picOffset = 0;
-// for (int i = 0; i < 7; i++) {
-// uint32_t animOffset = metadata_start + (i * 44);
-// byte *animData = new byte[44];
-// roomFile->seek(animOffset, SEEK_SET);
-// roomFile->read(animData, 44);
-// AnimSet animSet;
-// animSet.x = animData[0] | (animData[1] << 8);
-// animSet.y = animData[2] | (animData[3] << 8);
-// animSet.w = animData[4];
-// animSet.h = animData[5];
-// animSet.extra = animData[6];
-// // roomFile->skip(1); // reserved
-// animSet.numAnims = animData[8];
-// animSet.spriteType = animData[33];
-// animSet.actionFlags = animData[34];
-// animSet.isDisabled = animData[38];
-// if (animSet.numAnims == 0) {
-// break;
-// }
-// animSet.animData = new Anim[animSet.numAnims];
-// // debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
-// int subAnimOffset = 10;
-// for (int j = 0; j < animSet.numAnims; j++) {
-
-// Anim anim;
-// anim.x = animSet.x;
-// anim.y = animSet.y;
-// anim.w = animSet.w;
-// anim.h = animSet.h;
-// anim.curFrame = 0;
-
-// anim.nframes = animData[subAnimOffset + j];
-// anim.loopCount = animData[subAnimOffset + 4 + j];
-// anim.speed = animData[subAnimOffset + 8 + j];
-// anim.animData = new byte[anim.nframes];
-// if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
-// uint32_t needed = anim.w * anim.h * anim.nframes;
-// anim.animData = new byte[needed];
-// Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
-// animSet.animData[j] = anim;
-// // debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
-// picOffset += needed;
-// } else {
-// continue;
-// debug("Anim %d-%d: invalid dimensions, skipping", i, j);
-// }
-// animSet.animData[j] = anim;
-// }
-
-// anims.push_back(animSet);
-// }
-// return anims;
-// }
-
-// Common::Array<WalkBox> PelrockEngine::loadWalkboxes(Common::File *roomFile, int roomOffset) {
-// uint32_t pair10_offset_pos = roomOffset + (10 * 8);
-// roomFile->seek(pair10_offset_pos, SEEK_SET);
-// // roomFile->skip(4);
-// uint32_t pair10_data_offset = roomFile->readUint32LE();
-// uint32_t pair10_size = roomFile->readUint32LE();
-
-// uint32_t walkbox_countOffset = pair10_data_offset + 0x213;
-// roomFile->seek(walkbox_countOffset, SEEK_SET);
-// byte walkbox_count = roomFile->readByte();
-// debug("Walkbox count: %d", walkbox_count);
-// uint32_t walkbox_offset = pair10_data_offset + 0x218;
-// Common::Array<WalkBox> walkboxes;
-// for (int i = 0; i < walkbox_count; i++) {
-// uint32_t box_offset = walkbox_offset + i * 9;
-// roomFile->seek(box_offset, SEEK_SET);
-// int16 x1 = roomFile->readSint16LE();
-// int16 y1 = roomFile->readSint16LE();
-// int16 w = roomFile->readSint16LE();
-// int16 h = roomFile->readSint16LE();
-// byte flags = roomFile->readByte();
-// debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
-// WalkBox box;
-// box.x = x1;
-// box.y = y1;
-// box.w = w;
-// box.h = h;
-// box.flags = flags;
-// walkboxes.push_back(box);
-// }
-// return walkboxes;
-// }
-
-// Common::Array<Description> PelrockEngine::loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos) {
-// uint32_t pair12_offset_pos = roomOffset + (12 * 8);
-// roomFile->seek(pair12_offset_pos, SEEK_SET);
-// // roomFile->skip(4);
-// uint32_t pair12_data_offset = roomFile->readUint32LE();
-// uint32_t pair12_size = roomFile->readUint32LE();
-
-// roomFile->seek(pair12_data_offset, SEEK_SET);
-// byte *data = new byte[pair12_size];
-// roomFile->read(data, pair12_size);
-// Common::Array<Description> descriptions;
-// uint32_t pos = 0;
-// uint32_t lastDescPos = 0;
-// while (pos < (pair12_size)) {
-// int desc_pos = 0;
-// if (data[pos] == 0xFF) {
-// Description description;
-// description.itemId = data[pos + 1];
-// pos += 3;
-// description.index = data[pos++];
-// description.text = "";
-// // debug("Found description terminator");
-// while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
-// // debug(" char: %c", data[pos]);
-// if (data[pos] != 0x00) {
-// description.text.append(1, (char)data[pos]);
-// }
-// if (data[pos] == 0xF8) {
-// description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
-// debug("Found action trigger: %d", description.actionTrigger);
-// pos += 2;
-// break;
-// }
-// // desc[desc_pos++] = (char)data[pos];
-// // debug("Current desc: %s", desc);
-// pos++;
-// }
-// debug("Found description for item %d index %d, text: %s", description.itemId, description.index, description.text.c_str());
-
-// descriptions.push_back(description);
-// lastDescPos = pos;
-// }
-// pos++;
-// }
-// debug("End of descriptions at position %d", pos);
-// outPos = lastDescPos + 1;
-// delete[] data;
-// // for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
-// // debug("Room description: %s", i->c_str());
-// // }
-// return descriptions;
-// }
-
-char32_t decodeByte(byte b) {
- if (b == 0x80) {
- return '\xA4';
- } else if (b == 0x81) {
- return '\xA1';
- } else if (b == 0x82) {
- return '\xAD';
- } else if (b == 0x83) {
- return '\xA8';
- } else if (b == 0x84) {
- return '\xA3';
- } else if (b == 0x7B) {
- return '\xA0';
- } else if (b == 0x7C) {
- return '\x82';
- } else if (b == 0x7D) {
- return '\xA1';
- } else if (b == 0x7E) {
- return '\xA2';
- } else if (b == 0x7F) {
- return '\xA3';
- } else if (b >= 0x20 && b <= 0x7A) {
- return (char)b;
- } else {
- // return string in format [XX]
- return '.';
- }
-}
-
void PelrockEngine::talk(byte object) {
debug("Talking to object %d", object);
- if (_currentRoomConversations.size() == 0)
+ if (_room->_currentRoomConversations.size() == 0)
return;
AnimSet *animSet;
- for (int i = 0; i < _currentRoomAnims.size(); i++) {
- if (_currentRoomAnims[i].extra == object) {
- animSet = &_currentRoomAnims[i];
+ for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ if (_room->_currentRoomAnims[i].extra == object) {
+ animSet = &_room->_currentRoomAnims[i];
}
}
- ConversationNode selectedNode = _currentRoomConversations[0];
+ ConversationNode selectedNode = _room->_currentRoomConversations[0];
bool isNPC = selectedNode.speakerId != 13;
if (isNPC) {
@@ -466,525 +227,6 @@ void PelrockEngine::talk(byte object) {
// }
}
-Common::String PelrockEngine::getControlName(byte b) {
- switch (b) {
- case 0xFD:
- return "END_LINE";
- case 0xFC:
- return "TEXT_TERM";
- case 0xFB:
- return "CHOICE";
- case 0xFA:
- return "SKIP";
- case 0xF9:
- return "PAGE_BREAK";
- case 0xF8:
- return "ACTION";
- case 0xF7:
- return "END_BRANCH";
- case 0xF6:
- return "LINE_CONT";
- case 0xF5:
- return "END_BRANCH_2";
- case 0xF4:
- return "END_CONV";
- case 0xF1:
- return "CHOICE_ALT";
- case 0xF0:
- return "GO_BACK";
- case 0xFE:
- return "END_BRANCH_3";
- case 0xEB:
- return "END_ALT";
- case 0xFF:
- return "DESC_START";
- case 0x08:
- return "SPEAKER";
- default:
- return Common::String::format("UNKNOWN(0x%02X)", b);
- }
-}
-
-Common::String PelrockEngine::cleanText(const Common::String &text) {
- Common::String cleaned = text;
-
- // Trim leading/trailing whitespace
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- while (!cleaned.empty() && Common::isSpace(cleaned.lastChar())) {
- cleaned.deleteLastChar();
- }
-
- // Remove leading [XX][00] patterns
- while (!cleaned.empty() && cleaned.contains('[')) {
- uint idx = 0;
- for (uint i = 0; i < cleaned.size() && i < 15; i++) {
- if (cleaned[i] == '[') {
- idx = i;
- break;
- }
- }
-
- if (idx < 10) {
- int endIdx = -1;
- for (uint i = idx; i < cleaned.size() && i < idx + 10; i++) {
- if (cleaned[i] == ']') {
- endIdx = i;
- break;
- }
- }
-
- if (endIdx > (int)idx && endIdx < (int)idx + 10) {
- cleaned = cleaned.c_str() + endIdx + 1;
- // Trim leading whitespace again
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- // Remove single leading control characters
- if (cleaned.size() > 1) {
- byte first = (byte)cleaned[0];
- byte second = (byte)cleaned[1];
-
- if ((first == 'A' || first == 'H') &&
- (Common::isUpper(second) || second == 0x83 || second == 0x82 || second == '[')) {
- cleaned.deleteChar(0);
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- } else if (strchr("#%')!+,.-\"*&$(/", first)) {
- cleaned.deleteChar(0);
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- }
- }
-
- return cleaned;
-}
-
-Common::Array<ConversationElement> PelrockEngine::parseConversationElements(const byte *convData, uint32 size) {
- Common::Array<ConversationElement> elements;
- Common::HashMap<int, int> choiceIndices; // Track choice index occurrences
- uint32 pos = 0;
-
- // First pass: parse elements and track choice indices
- while (pos < size) {
- byte b = convData[pos];
-
- if (b == 0x08) { // SPEAKER
- pos++;
- if (pos < size) {
- byte speakerId = convData[pos];
- Common::String speaker = (speakerId == 0x0D) ? "ALFRED" : "NPC";
- pos++;
-
- // Read text
- Common::String text;
- while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
- convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
- convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
- convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
- convData[pos] != 0xF0) {
- char32_t ch = decodeByte(convData[pos]);
- if (ch != '.') {
- text += ch;
- }
- pos++;
- }
-
- text = cleanText(text);
- if (!text.empty()) {
- ConversationElement elem;
- elem.type = ConversationElement::DIALOGUE;
- elem.speakerId = speakerId;
- elem.speaker = speaker;
- elem.text = text;
- elem.choiceIndex = -1;
- elements.push_back(elem);
- }
- }
- } else if (b == 0xFB || b == 0xF1) { // CHOICE marker
- pos++;
- int choiceIndex = -1;
- if (pos < size) {
- choiceIndex = convData[pos];
- // Track this choice index
- if (choiceIndices.contains(choiceIndex)) {
- choiceIndices[choiceIndex]++;
- } else {
- choiceIndices[choiceIndex] = 1;
- }
- pos++;
- }
-
- // Skip next 2 bytes (speaker marker)
- if (pos < size)
- pos++;
- if (pos < size)
- pos++;
-
- // Read text
- Common::String text;
- while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
- convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
- convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
- convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
- convData[pos] != 0xF0) {
- char32_t ch = decodeByte(convData[pos]);
- if (ch != '.') {
- text += ch;
- }
- pos++;
- }
-
- text = cleanText(text);
- if (!text.empty()) {
- ConversationElement elem;
- elem.type = ConversationElement::CHOICE_MARKER;
- elem.text = text;
- elem.choiceIndex = choiceIndex;
- elements.push_back(elem);
- }
- } else if (b == 0xF8) { // ACTION
- pos += 3;
- } else if (b == 0xF4) { // END_CONV
- ConversationElement elem;
- elem.type = ConversationElement::END_CONV;
- elements.push_back(elem);
- pos++;
- } else if (b == 0xF7) { // END_BRANCH
- ConversationElement elem;
- elem.type = ConversationElement::END_BRANCH;
- elements.push_back(elem);
- pos++;
- } else if (b == 0xFD || b == 0xFC || b == 0xF5 || b == 0xFE || b == 0xEB || b == 0xF0) {
- pos++;
- } else {
- pos++;
- }
- }
-
- // Second pass: mark which indices are actual choices (appear multiple times)
- for (uint i = 0; i < elements.size(); i++) {
- if (elements[i].choiceIndex >= 0) {
- elements[i].isRealChoice = (choiceIndices[elements[i].choiceIndex] > 1);
- }
- }
-
- return elements;
-}
-
-Common::Array<ConversationNode> PelrockEngine::buildTreeStructure(const Common::Array<ConversationElement> &elements) {
- Common::Array<ConversationNode> roots;
- Common::Array<StackEntry> stack;
- ConversationNode *currentRoot = nullptr;
- uint i = 0;
-
- while (i < elements.size()) {
- const ConversationElement &elem = elements[i];
-
- if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "NPC") {
- if (stack.empty()) {
- // New root conversation
- ConversationNode root;
- root.type = ConversationNode::ROOT;
- root.text = elem.text;
- root.speaker = "NPC";
- root.speakerId = elem.speakerId;
- roots.push_back(root);
- currentRoot = &roots[roots.size() - 1];
- } else {
- // NPC response within a branch
- ConversationNode *parent = stack[stack.size() - 1].node;
- ConversationNode response;
- response.type = ConversationNode::RESPONSE;
- response.speaker = "NPC";
- response.speakerId = elem.speakerId;
- response.text = elem.text;
- parent->responses.push_back(response);
- }
- i++;
-
- } else if (elem.type == ConversationElement::CHOICE_MARKER) {
- if (elem.isRealChoice) {
- // Real choice - player selects from menu
- ConversationNode choiceNode;
- choiceNode.type = ConversationNode::CHOICE;
- choiceNode.text = elem.text;
- choiceNode.speaker = "ALFRED";
- choiceNode.speakerId = 0x0D; // Player
- choiceNode.choiceIndex = elem.choiceIndex;
-
- // Find where to attach this choice
- while (!stack.empty() && stack[stack.size() - 1].index >= elem.choiceIndex) {
- stack.pop_back();
- }
-
- if (!stack.empty()) {
- ConversationNode *parent = stack[stack.size() - 1].node;
- parent->subchoices.push_back(choiceNode);
-
- // Get pointer to the newly added choice
- ConversationNode *newChoice = &parent->subchoices[parent->subchoices.size() - 1];
-
- StackEntry entry;
- entry.node = newChoice;
- entry.index = elem.choiceIndex;
- stack.push_back(entry);
- } else {
- if (currentRoot) {
- currentRoot->choices.push_back(choiceNode);
-
- // Get pointer to the newly added choice
- ConversationNode *newChoice = ¤tRoot->choices[currentRoot->choices.size() - 1];
-
- StackEntry entry;
- entry.node = newChoice;
- entry.index = elem.choiceIndex;
- stack.push_back(entry);
- }
- }
- } else {
- // Auto-dialogue - ALFRED just speaks
- if (!stack.empty()) {
- ConversationNode *parent = stack[stack.size() - 1].node;
- ConversationNode response;
- response.type = ConversationNode::RESPONSE;
- response.speaker = "ALFRED";
- response.speakerId = 0x0D;
- response.text = elem.text;
- parent->responses.push_back(response);
- }
- }
- i++;
-
- } else if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "ALFRED") {
- if (!stack.empty()) {
- ConversationNode *parent = stack[stack.size() - 1].node;
- ConversationNode response;
- response.type = ConversationNode::RESPONSE;
- response.speaker = "ALFRED";
- response.text = elem.text;
- response.speakerId = 0x0D;
- parent->responses.push_back(response);
- }
- i++;
-
- } else if (elem.type == ConversationElement::END_CONV) {
- if (!stack.empty()) {
- stack[stack.size() - 1].node->terminated = true;
- stack.pop_back();
- }
- i++;
-
- } else if (elem.type == ConversationElement::END_BRANCH) {
- stack.clear();
- currentRoot = nullptr;
- i++;
-
- } else {
- i++;
- }
- }
-
- return roots;
-}
-
-Common::Array<ConversationNode> PelrockEngine::loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos) {
-
- debug("Loading conversations starting at position %d", startPos);
-
- uint32_t pair12_offset_pos = roomOffset + (12 * 8);
- roomFile->seek(pair12_offset_pos, SEEK_SET);
- uint32_t pair12_data_offset = roomFile->readUint32LE();
- uint32_t pair12_size = roomFile->readUint32LE();
-
- // startPos += 2;
- uint32_t conversation_start = pair12_data_offset + startPos;
- uint32_t conversation_size = pair12_size - startPos;
-
- roomFile->seek(conversation_start, SEEK_SET);
- byte *data = new byte[conversation_size];
- roomFile->read(data, conversation_size);
-
- Common::Array<ConversationElement> elements = parseConversationElements(data, conversation_size);
- Common::Array<ConversationNode> roots = buildTreeStructure(elements);
- return roots;
-}
-
-// void PelrockEngine::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
-// uint32_t outPos = 0;
-
-// Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
-// debug("After decsriptions, position is %d", outPos);
-// Common::Array<ConversationNode> roots = loadConversations(roomFile, roomOffset, outPos);
-// for (int i = 0; i < roots.size(); i++) {
-// if (roots[i].text.empty()) {
-// continue;
-// }
-// debug("Conversation %d: %s", i, roots[i].text.c_str());
-// }
-// _currentRoomConversations = roots;
-
-// Common::Array<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
-
-// Common::Array<HotSpot> hotspots;
-// for (int i = 0; i < anims.size(); i++) {
-
-// HotSpot thisHotspot;
-// thisHotspot.index = i;
-// thisHotspot.x = anims[i].x;
-// thisHotspot.y = anims[i].y;
-// thisHotspot.w = anims[i].w;
-// thisHotspot.h = anims[i].h;
-// thisHotspot.extra = anims[i].extra;
-// thisHotspot.type = anims[i].actionFlags;
-// thisHotspot.isEnabled = !anims[i].isDisabled;
-// hotspots.push_back(thisHotspot);
-// }
-
-// Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
-// Common::Array<Exit> exits = loadExits(roomFile, roomOffset);
-
-// Common::Array<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
-
-// debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
-// for (int i = 0; i < staticHotspots.size(); i++) {
-// HotSpot hotspot = staticHotspots[i];
-// hotspot.index = anims.size() + i;
-// hotspots.push_back(hotspot);
-// }
-
-// int walkboxCount = 0;
-
-// _currentRoomAnims = anims;
-// _currentRoomHotspots = hotspots;
-// _currentRoomExits = exits;
-// _currentRoomWalkboxes = walkboxes;
-// _currentRoomDescriptions = descriptions;
-
-// for (int i = 0; i < _currentRoomHotspots.size(); i++) {
-// HotSpot hotspot = _currentRoomHotspots[i];
-// drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
-// }
-
-// for (int i = 0; i < _currentRoomExits.size(); i++) {
-// Exit exit = _currentRoomExits[i];
-// // drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
-// }
-// }
-
-void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize) {
- const char marker[] = "BUDA";
- const int markerLen = 4;
- size_t bufferSize = 4096;
- size_t pos = 0;
-
- buffer = (byte *)malloc(bufferSize);
- stream->seek(startPos, SEEK_SET);
- while (!stream->eos()) {
- byte b = stream->readByte();
- if (pos + 1 > bufferSize) {
- bufferSize *= 2;
- buffer = (byte *)realloc(buffer, bufferSize);
- }
- buffer[pos++] = b;
-
- // Check for marker at the end of buffer
- if (pos >= markerLen &&
- buffer[pos - 4] == 'B' &&
- buffer[pos - 3] == 'U' &&
- buffer[pos - 2] == 'D' &&
- buffer[pos - 1] == 'A') {
- break;
- }
- }
- outSize = pos;
-}
-
-void PelrockEngine::loadRoomTalkingAnimations(int roomNumber) {
-
- int headerIndex = roomNumber;
- uint32 offset = kTalkingAnimHeaderSize * headerIndex;
-
- TalkinAnimHeader talkHeader;
- Common::File talkFile;
- if (!talkFile.open("ALFRED.2")) {
- error("Couldnt find file ALFRED.2");
- }
-
- talkFile.seek(offset, SEEK_SET);
-
- talkHeader.spritePointer = talkFile.readUint32LE();
- talkFile.read(&talkHeader.unknown2, 3);
- talkHeader.offsetXAnimA = talkFile.readByte();
- talkHeader.offsetYAnimA = talkFile.readByte();
- talkHeader.wAnimA = talkFile.readByte();
- talkHeader.hAnimA = talkFile.readByte();
- talkFile.read(&talkHeader.unknown3, 2);
- talkHeader.numFramesAnimA = talkFile.readByte();
- talkFile.read(&talkHeader.unknown4, 5);
-
- talkHeader.offsetXAnimB = talkFile.readByte();
- talkHeader.offsetYAnimB = talkFile.readByte();
- talkHeader.wAnimB = talkFile.readByte();
- talkHeader.hAnimB = talkFile.readByte();
- talkFile.read(&talkHeader.unknown5, 2);
- talkHeader.numFramesAnimB = talkFile.readByte();
- talkFile.read(&talkHeader.unknown6, 29);
- debug("Talking anim header for room %d: spritePointer=%d, wA=%d, hA=%d, framesA=%d, wB=%d, hB=%d, framesB=%d", roomNumber, talkHeader.spritePointer, talkHeader.wAnimA, talkHeader.hAnimA, talkHeader.numFramesAnimA, talkHeader.wAnimB, talkHeader.hAnimB, talkHeader.numFramesAnimB);
-
- if (talkHeader.spritePointer == 0) {
- debug("No talking animation for room %d", roomNumber);
- talkFile.close();
- return;
- }
-
- // if(talkHeader.animA != nullptr) {
- // delete[] talkHeader.animA;
- // talkHeader.animA = nullptr;
- // }
- talkHeader.animA = new byte *[talkHeader.numFramesAnimA];
-
- byte *data = nullptr;
- int animASize = talkHeader.wAnimA * talkHeader.hAnimA * talkHeader.numFramesAnimA;
- byte *decompressed = nullptr;
- size_t dataSize = 0;
- readUntilBuda(&talkFile, talkHeader.spritePointer, data, dataSize);
- size_t decompressedSize = rleDecompress(data, dataSize, 0, dataSize, &decompressed);
- free(data);
- debug("Decompressed talking anim A size: %zu, decompressed size: %zu", dataSize, decompressedSize);
- for (int i = 0; i < talkHeader.numFramesAnimA; i++) {
- talkHeader.animA[i] = new byte[talkHeader.wAnimA * talkHeader.hAnimA];
- Common::copy(decompressed + (i * talkHeader.wAnimA * talkHeader.hAnimA), decompressed + ((i + 1) * talkHeader.wAnimA * talkHeader.hAnimA), talkHeader.animA[i]);
- }
-
- if (talkHeader.numFramesAnimB > 0) {
- // if(talkHeader.animA != nullptr) {
- // delete[] talkHeader.animA;
- // talkHeader.animA = nullptr;
- // }
- talkHeader.animB = new byte *[talkHeader.numFramesAnimB];
- for (int i = 0; i < talkHeader.numFramesAnimB; i++) {
- talkHeader.animB[i] = new byte[talkHeader.wAnimB * talkHeader.hAnimB];
- Common::copy(decompressed + animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB), decompressed + animASize + ((i + 1) * talkHeader.wAnimB * talkHeader.hAnimB), talkHeader.animB[i]);
- }
- }
- free(decompressed);
- _talkingAnimHeader = talkHeader;
-
- talkFile.close();
-}
-
void PelrockEngine::loadCursors() {
Common::File alfred7File;
if (!alfred7File.open("ALFRED.7")) {
@@ -1033,61 +275,6 @@ void PelrockEngine::loadInteractionIcons() {
alfred4File.close();
}
-// Common::Array<Exit> PelrockEngine::loadExits(Common::File *roomFile, int roomOffset) {
-// Common::Array<Exit> exits;
-// uint32_t pair10_offset_pos = roomOffset + (10 * 8);
-// roomFile->seek(pair10_offset_pos, SEEK_SET);
-// uint32_t pair10_data_offset = roomFile->readUint32LE();
-// uint32_t pair10_size = roomFile->readUint32LE();
-// roomFile->seek(pair10_data_offset + 0x1BE, SEEK_SET);
-// int exit_count = roomFile->readByte();
-// roomFile->seek(pair10_data_offset + 0x1BF, SEEK_SET);
-// for (int i = 0; i < exit_count; i++) {
-// Exit exit;
-// exit.targetRoom = roomFile->readUint16LE();
-// exit.flags = roomFile->readByte();
-// exit.x = roomFile->readUint16LE();
-// exit.y = roomFile->readUint16LE();
-// exit.w = roomFile->readByte();
-// exit.h = roomFile->readByte();
-
-// exit.targetX = roomFile->readUint16LE();
-// exit.targetY = roomFile->readUint16LE();
-// exit.dir = roomFile->readByte();
-// exits.push_back(exit);
-// }
-// return exits;
-// }
-
-// Common::Array<HotSpot> PelrockEngine::loadHotspots(Common::File *roomFile, int roomOffset) {
-// uint32_t pair10_offset_pos = roomOffset + (10 * 8);
-// debug("Hotspot(10) pair offset position: %d", pair10_offset_pos);
-// roomFile->seek(pair10_offset_pos, SEEK_SET);
-// uint32_t pair10_data_offset = roomFile->readUint32LE();
-// uint32_t pair10_size = roomFile->readUint32LE();
-// uint32_t count_offset = pair10_data_offset + 0x47a;
-// roomFile->seek(count_offset, SEEK_SET);
-// byte hotspot_count = roomFile->readByte();
-// uint32_t hotspot_data_start = pair10_data_offset + 0x47c;
-// Common::Array<HotSpot> hotspots;
-// for (int i = 0; i < hotspot_count; i++) {
-// uint32_t obj_offset = hotspot_data_start + i * 9;
-// roomFile->seek(obj_offset, SEEK_SET);
-// HotSpot spot;
-// spot.type = roomFile->readByte();
-// spot.x = roomFile->readUint16LE();
-// spot.y = roomFile->readUint16LE();
-// spot.w = roomFile->readByte();
-// spot.h = roomFile->readByte();
-// spot.extra = roomFile->readUint16LE();
-// debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
-// hotspots.push_back(spot);
-// }
-// return hotspots;
-// // uint32_t hover_areas_start = pair10_data_offset + 0x1BE;
-// // roomFile->seek(hover_areas_start, SEEK_SET);
-// }
-
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight) {
for (int y = 0; y < frameHeight; y++) {
for (int x = 0; x < frameWidth; x++) {
@@ -1237,48 +424,48 @@ void PelrockEngine::frames() {
memcpy(_compositeBuffer, _currentBackground, 640 * 400);
// debug("Game tick!");
- for (int i = 0; i < _currentRoomAnims.size(); i++) {
+ for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
// debug("Processing animation set %d, numAnims %d", num, i->numAnims);
-
- int x = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].x;
- int y = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].y;
- int w = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w;
- int h = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h;
- int extra = _currentRoomAnims[i].extra;
+ AnimSet &animSet = _room->_currentRoomAnims[i];
+ int x = animSet.animData[animSet.curAnimIndex].x;
+ int y = animSet.animData[animSet.curAnimIndex].y;
+ int w = animSet.animData[animSet.curAnimIndex].w;
+ int h = animSet.animData[animSet.curAnimIndex].h;
+ int extra = animSet.extra;
if (whichNPCTalking == extra) {
// debug("Skipping anim set %d because NPC is talking", i);
- talkNPC(&_currentRoomAnims[i], i);
+ talkNPC(&animSet, i);
continue;
}
- int frameSize = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h;
- int curFrame = _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame;
+ int frameSize = animSet.animData[animSet.curAnimIndex].w * animSet.animData[animSet.curAnimIndex].h;
+ int curFrame = animSet.animData[animSet.curAnimIndex].curFrame;
byte *frame = new byte[frameSize];
- Common::copy(_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].animData + (curFrame * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w), _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].animData + (curFrame * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].h * _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].w) + (frameSize), frame);
+ Common::copy(animSet.animData[animSet.curAnimIndex].animData + (curFrame * animSet.animData[animSet.curAnimIndex].h * animSet.animData[animSet.curAnimIndex].w), animSet.animData[animSet.curAnimIndex].animData + (curFrame * animSet.animData[animSet.curAnimIndex].h * animSet.animData[animSet.curAnimIndex].w) + (frameSize), frame);
- drawSpriteToBuffer(_compositeBuffer, 640, frame, _currentRoomAnims[i].x, _currentRoomAnims[i].y, _currentRoomAnims[i].w, _currentRoomAnims[i].h, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, frame, animSet.x, animSet.y, animSet.w, animSet.h, 255);
- if (_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].elpapsedFrames == _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].speed) {
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].elpapsedFrames = 0;
- if (_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame < _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].nframes - 1) {
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame++;
+ if (animSet.animData[animSet.curAnimIndex].elpapsedFrames == animSet.animData[animSet.curAnimIndex].speed) {
+ animSet.animData[animSet.curAnimIndex].elpapsedFrames = 0;
+ if (animSet.animData[animSet.curAnimIndex].curFrame < animSet.animData[animSet.curAnimIndex].nframes - 1) {
+ animSet.animData[animSet.curAnimIndex].curFrame++;
} else {
- if (_currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop < _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].loopCount - 1) {
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame = 0;
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop++;
+ if (animSet.animData[animSet.curAnimIndex].curLoop < animSet.animData[animSet.curAnimIndex].loopCount - 1) {
+ animSet.animData[animSet.curAnimIndex].curFrame = 0;
+ animSet.animData[animSet.curAnimIndex].curLoop++;
} else {
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curFrame = 0;
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].curLoop = 0;
- if (_currentRoomAnims[i].curAnimIndex < _currentRoomAnims[i].numAnims - 1) {
- _currentRoomAnims[i].curAnimIndex++;
+ animSet.animData[animSet.curAnimIndex].curFrame = 0;
+ animSet.animData[animSet.curAnimIndex].curLoop = 0;
+ if (animSet.curAnimIndex < animSet.numAnims - 1) {
+ animSet.curAnimIndex++;
} else {
- _currentRoomAnims[i].curAnimIndex = 0;
+ animSet.curAnimIndex = 0;
}
}
}
} else {
- _currentRoomAnims[i].animData[_currentRoomAnims[i].curAnimIndex].elpapsedFrames++;
+ animSet.animData[animSet.curAnimIndex].elpapsedFrames++;
}
}
@@ -1398,9 +585,9 @@ void PelrockEngine::frames() {
}
// debug("Drawing walkboxes..., %d, _currentRoomWalkboxes.size()=%d", _currentRoomWalkboxes.size(), _currentRoomWalkboxes.size());
- for (int i = 0; i < _currentRoomWalkboxes.size(); i++) {
+ for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
// debug("Drawing walkbox %d", i);
- WalkBox box = _currentRoomWalkboxes[i];
+ WalkBox box = _room->_currentRoomWalkboxes[i];
// drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
}
if (_curWalkTarget.x < 640 && _curWalkTarget.y < 400 && _curWalkTarget.x >= 0 && _curWalkTarget.y >= 0) {
@@ -1472,15 +659,15 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
}
_displayPopup = true;
_currentPopupFrame = 0;
- _currentHotspot = &_currentRoomHotspots[hotspotIndex];
+ _currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
debug("Current hotspot type: %d", _currentHotspot->type);
}
}
int PelrockEngine::isHotspotUnder(int x, int y) {
- for (size_t i = 0; i < _currentRoomHotspots.size(); i++) {
- HotSpot hotspot = _currentRoomHotspots[i];
+ for (size_t i = 0; i < _room->_currentRoomHotspots.size(); i++) {
+ HotSpot hotspot = _room->_currentRoomHotspots[i];
if (hotspot.isEnabled &&
mouseX >= hotspot.x && mouseX <= (hotspot.x + hotspot.w) &&
mouseY >= hotspot.y && mouseY <= (hotspot.y + hotspot.h)) {
@@ -1491,11 +678,11 @@ int PelrockEngine::isHotspotUnder(int x, int y) {
}
Exit *PelrockEngine::isExitUnder(int x, int y) {
- for (int i = 0; i < _currentRoomExits.size(); i++) {
- Exit exit = _currentRoomExits[i];
+ for (int i = 0; i < _room->_currentRoomExits.size(); i++) {
+ Exit exit = _room->_currentRoomExits[i];
if (x >= exit.x && x <= (exit.x + exit.w) &&
y >= exit.y && y <= (exit.y + exit.h)) {
- return &(_currentRoomExits[i]);
+ return &(_room->_currentRoomExits[i]);
}
}
return nullptr;
@@ -1534,22 +721,24 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
void PelrockEngine::talkNPC(AnimSet *animSet, int index) {
// Change with the right index
- int x = animSet->x + (index ? _talkingAnimHeader.offsetXAnimB : _talkingAnimHeader.offsetXAnimA);
- int y = animSet->y + (index ? _talkingAnimHeader.offsetYAnimB : _talkingAnimHeader.offsetYAnimA);
+ TalkinAnimHeader animHeader = _room->_talkingAnimHeader;
+
+ int x = animSet->x + (index ? animHeader.offsetXAnimB : animHeader.offsetXAnimA);
+ int y = animSet->y + (index ? animHeader.offsetYAnimB : animHeader.offsetYAnimA);
- int w = index ? _talkingAnimHeader.wAnimB : _talkingAnimHeader.wAnimA;
- int h = index ? _talkingAnimHeader.hAnimB : _talkingAnimHeader.hAnimA;
- int numFrames = index ? _talkingAnimHeader.numFramesAnimB : _talkingAnimHeader.numFramesAnimA;
- int curFrame = index ? _talkingAnimHeader.currentFrameAnimB++ : _talkingAnimHeader.currentFrameAnimA++;
+ int w = index ? animHeader.wAnimB : animHeader.wAnimA;
+ int h = index ? animHeader.hAnimB : animHeader.hAnimA;
+ int numFrames = index ? animHeader.numFramesAnimB : animHeader.numFramesAnimA;
+ int curFrame = index ? animHeader.currentFrameAnimB++ : animHeader.currentFrameAnimA++;
if (curFrame >= numFrames) {
if (index) {
- _talkingAnimHeader.currentFrameAnimB = 0;
+ animHeader.currentFrameAnimB = 0;
} else {
- _talkingAnimHeader.currentFrameAnimA = 0;
+ animHeader.currentFrameAnimA = 0;
}
curFrame = 0;
}
- byte *frame = index ? _talkingAnimHeader.animB[curFrame] : _talkingAnimHeader.animA[curFrame];
+ byte *frame = index ? animHeader.animB[curFrame] : animHeader.animA[curFrame];
debug("Talking NPC frame %d/%d, x=%d, y=%d, w=%d, h=%d", curFrame, numFrames, x, y, w, h);
@@ -1731,7 +920,7 @@ uint16_t PelrockEngine::generate_movement_steps(uint8_t *path_buffer,
// Generate movements for each walkbox in path
for (uint16_t i = 0; i < path_length && path_buffer[i] != PATH_END; i++) {
uint8_t box_index = path_buffer[i];
- WalkBox *box = &_currentRoomWalkboxes[box_index];
+ WalkBox *box = &_room->_currentRoomWalkboxes[box_index];
MovementStep step;
calculate_movement_to_target(current_x, current_y,
@@ -1831,8 +1020,8 @@ uint16_t PelrockEngine::build_walkbox_path(
}
void PelrockEngine::clear_visited_flags() {
- for (int i = 0; i < _currentRoomWalkboxes.size(); i++) {
- _currentRoomWalkboxes[i].flags = 0;
+ for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
+ _room->_currentRoomWalkboxes[i].flags = 0;
}
}
@@ -1855,25 +1044,25 @@ bool walkboxes_adjacent(WalkBox *box1, WalkBox *box2) {
}
uint8_t PelrockEngine::get_adjacent_walkbox(uint8_t current_box_index) {
- WalkBox *current_box = &_currentRoomWalkboxes[current_box_index];
+ WalkBox *current_box = &_room->_currentRoomWalkboxes[current_box_index];
// Mark current walkbox as visited
current_box->flags = 0x01;
// Search for adjacent unvisited walkbox
- for (uint8_t i = 0; i < _currentRoomWalkboxes.size(); i++) {
+ for (uint8_t i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
// Skip current walkbox
if (i == current_box_index) {
continue;
}
// Skip already visited walkboxes
- if (_currentRoomWalkboxes[i].flags == 0x01) {
+ if (_room->_currentRoomWalkboxes[i].flags == 0x01) {
continue;
}
// Check if walkboxes are adjacent
- if (walkboxes_adjacent(current_box, &_currentRoomWalkboxes[i])) {
+ if (walkboxes_adjacent(current_box, &_room->_currentRoomWalkboxes[i])) {
return i;
}
}
@@ -1889,8 +1078,8 @@ bool PelrockEngine::point_in_walkbox(WalkBox *box, uint16_t x, uint16_t y) {
}
uint8_t PelrockEngine::find_walkbox_for_point(uint16_t x, uint16_t y) {
- for (uint8_t i = 0; i < _currentRoomWalkboxes.size(); i++) {
- if (point_in_walkbox(&_currentRoomWalkboxes[i], x, y)) {
+ for (uint8_t i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
+ if (point_in_walkbox(&_room->_currentRoomWalkboxes[i], x, y)) {
return i;
}
}
@@ -1912,7 +1101,7 @@ void PelrockEngine::checkMouseClick(int x, int y) {
if (lookRect.contains(x, y)) {
debug("Look action clicked");
walkTo(_currentHotspot->x, _currentHotspot->y);
- sayAlfred(_currentRoomDescriptions[_currentHotspot->index].text);
+ sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index].text);
_displayPopup = false;
return;
}
@@ -1999,25 +1188,25 @@ Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
// for (Common::List<WalkBox>::iterator it = _currentRoomWalkboxes.begin();
// it != _currentRoomWalkboxes.end(); ++it) {
- for (size_t i = 0; i < _currentRoomWalkboxes.size(); i++) {
+ for (size_t i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
// Calculate distance from source point to this walkbox (Manhattan distance)
int dx = 0;
int dy = 0;
// Calculate horizontal distance
- if (sourceX < _currentRoomWalkboxes[i].x) {
- dx = _currentRoomWalkboxes[i].x - sourceX;
- } else if (sourceX > _currentRoomWalkboxes[i].x + _currentRoomWalkboxes[i].w) {
- dx = sourceX - (_currentRoomWalkboxes[i].x + _currentRoomWalkboxes[i].w);
+ if (sourceX < _room->_currentRoomWalkboxes[i].x) {
+ dx = _room->_currentRoomWalkboxes[i].x - sourceX;
+ } else if (sourceX > _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w) {
+ dx = sourceX - (_room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w);
}
// else: sourceX is inside walkbox horizontally, dx = 0
// Calculate vertical distance
- if (sourceY < _currentRoomWalkboxes[i].y) {
- dy = _currentRoomWalkboxes[i].y - sourceY;
- } else if (sourceY > _currentRoomWalkboxes[i].y + _currentRoomWalkboxes[i].h) {
- dy = sourceY - (_currentRoomWalkboxes[i].y + _currentRoomWalkboxes[i].h);
+ if (sourceY < _room->_currentRoomWalkboxes[i].y) {
+ dy = _room->_currentRoomWalkboxes[i].y - sourceY;
+ } else if (sourceY > _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h) {
+ dy = sourceY - (_room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h);
}
// else: sourceY is inside walkbox vertically, dy = 0
@@ -2030,16 +1219,16 @@ Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
int targetX = sourceX;
int targetY = sourceY;
- if (sourceX < _currentRoomWalkboxes[i].x) {
- targetX = _currentRoomWalkboxes[i].x;
- } else if (sourceX > _currentRoomWalkboxes[i].x + _currentRoomWalkboxes[i].w) {
- targetX = _currentRoomWalkboxes[i].x + _currentRoomWalkboxes[i].w;
+ if (sourceX < _room->_currentRoomWalkboxes[i].x) {
+ targetX = _room->_currentRoomWalkboxes[i].x;
+ } else if (sourceX > _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w) {
+ targetX = _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w;
}
- if (sourceY < _currentRoomWalkboxes[i].y) {
- targetY = _currentRoomWalkboxes[i].y;
- } else if (sourceY > _currentRoomWalkboxes[i].y + _currentRoomWalkboxes[i].h) {
- targetY = _currentRoomWalkboxes[i].y + _currentRoomWalkboxes[i].h;
+ if (sourceY < _room->_currentRoomWalkboxes[i].y) {
+ targetY = _room->_currentRoomWalkboxes[i].y;
+ } else if (sourceY > _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h) {
+ targetY = _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h;
}
bestTarget.x = targetX;
@@ -2233,7 +1422,7 @@ void PelrockEngine::setScreen(int number, int dir) {
int roomOffset = number * kRoomStructSize;
curAlfredFrame = 0;
byte *palette = new byte[256 * 3];
- getPalette(&roomFile, roomOffset, palette);
+ _room->getPalette(&roomFile, roomOffset, palette);
int paletteOffset = roomOffset + (11 * 8);
roomFile.seek(paletteOffset, SEEK_SET);
@@ -2242,7 +1431,7 @@ void PelrockEngine::setScreen(int number, int dir) {
g_system->getPaletteManager()->setPalette(palette, 0, 256);
byte *background = new byte[640 * 400];
- getBackground(&roomFile, roomOffset, background);
+ _room->getBackground(&roomFile, roomOffset, background);
if (_currentBackground != nullptr)
delete[] _currentBackground;
_currentBackground = new byte[640 * 400];
@@ -2253,8 +1442,8 @@ void PelrockEngine::setScreen(int number, int dir) {
}
}
- _resourceManager->loadRoomMetadata(&roomFile, roomOffset);
- loadRoomTalkingAnimations(number);
+ _room->loadRoomMetadata(&roomFile, roomOffset);
+ _room->loadRoomTalkingAnimations(number);
_screen->markAllDirty();
roomFile.close();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index feef1bf91bc..4ef14515529 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -40,7 +40,7 @@
#include "pelrock/detection.h"
#include "pelrock/fonts/large_font.h"
#include "pelrock/fonts/small_font.h"
-#include "pelrock/resources.h"
+#include "pelrock/room.h"
#include "pelrock/types.h"
namespace Pelrock {
@@ -61,20 +61,7 @@ private:
void setScreenJava(int s, int dir);
void loadAnims();
- // Room data
- void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
- void getBackground(Common::File *roomFile, int roomOffset, byte *background);
void loadAlfredAnims();
- // Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
- // Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
- // Common::Array<Exit> loadExits(Common::File *roomFile, int roomOffset);
- // Common::Array<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
- // Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos);
-
- Common::String cleanText(const Common::String &text);
- Common::Array<ConversationElement> parseConversationElements(const byte *convData, uint32 size);
- Common::Array<ConversationNode> buildTreeStructure(const Common::Array<ConversationElement> &elements);
- Common::Array<ConversationNode> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
void walkTo(int x, int y);
bool pathFind(int x, int y, PathContext *context);
@@ -90,9 +77,6 @@ private:
MovementStep *movement_buffer);
void talk(byte object);
- Common::String getControlName(byte b);
- // void loadRoomMetadata(Common::File *roomFile, int roomOffset);
- void loadRoomTalkingAnimations(int roomNumber);
void loadCursors();
void loadInteractionIcons();
byte *grabBackgroundSlice(int x, int y, int w, int h);
@@ -121,15 +105,12 @@ private:
ChronoManager *_chronoManager = nullptr;
- // byte *standingAnim = new byte[3060 * 102];
-
byte **walkingAnimFrames[4]; // 4 arrays of arrays
byte *standingAnimFrames[4] = {nullptr}; // 4 directions
int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
byte **talkingAnimFrames[4]; // 4 arrays of arrays
int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
- TalkinAnimHeader _talkingAnimHeader;
PathContext _currentContext;
int _current_step = 0;
@@ -186,7 +167,7 @@ private:
// int whichScreen = 0;
// byte *pixelsShadows; // =new int[640*400];
- ResourceManager *_resourceManager = nullptr;
+ RoomManager *_room = nullptr;
protected:
// Engine APIs
@@ -242,13 +223,6 @@ public:
Common::Serializer s(stream, nullptr);
return syncGame(s);
}
-
- Common::Array<HotSpot> _currentRoomHotspots;
- Common::Array<AnimSet> _currentRoomAnims;
- Common::Array<Exit> _currentRoomExits;
- Common::Array<WalkBox> _currentRoomWalkboxes;
- Common::Array<Description> _currentRoomDescriptions;
- Common::Array<ConversationNode> _currentRoomConversations;
};
extern PelrockEngine *g_engine;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
deleted file mode 100644
index dac515a606d..00000000000
--- a/engines/pelrock/resources.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "pelrock/resources.h"
-#include "pelrock/pelrock.h"
-#include "pelrock/util.h"
-
-namespace Pelrock {
-
-ResourceManager::ResourceManager() {
-}
-
-ResourceManager::~ResourceManager() {
-}
-
-Common::Array<Exit> ResourceManager::loadExits(Common::File *roomFile, int roomOffset) {
- Common::Array<Exit> exits;
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- roomFile->seek(pair10_offset_pos, SEEK_SET);
- uint32_t pair10_data_offset = roomFile->readUint32LE();
- uint32_t pair10_size = roomFile->readUint32LE();
- roomFile->seek(pair10_data_offset + 0x1BE, SEEK_SET);
- int exit_count = roomFile->readByte();
- roomFile->seek(pair10_data_offset + 0x1BF, SEEK_SET);
- for (int i = 0; i < exit_count; i++) {
- Exit exit;
- exit.targetRoom = roomFile->readUint16LE();
- exit.flags = roomFile->readByte();
- exit.x = roomFile->readUint16LE();
- exit.y = roomFile->readUint16LE();
- exit.w = roomFile->readByte();
- exit.h = roomFile->readByte();
-
- exit.targetX = roomFile->readUint16LE();
- exit.targetY = roomFile->readUint16LE();
- exit.dir = roomFile->readByte();
- exits.push_back(exit);
- }
- return exits;
-}
-
-Common::Array<HotSpot> ResourceManager::loadHotspots(Common::File *roomFile, int roomOffset) {
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- debug("Hotspot(10) pair offset position: %d", pair10_offset_pos);
- roomFile->seek(pair10_offset_pos, SEEK_SET);
- uint32_t pair10_data_offset = roomFile->readUint32LE();
- uint32_t pair10_size = roomFile->readUint32LE();
- uint32_t count_offset = pair10_data_offset + 0x47a;
- roomFile->seek(count_offset, SEEK_SET);
- byte hotspot_count = roomFile->readByte();
- uint32_t hotspot_data_start = pair10_data_offset + 0x47c;
- Common::Array<HotSpot> hotspots;
- for (int i = 0; i < hotspot_count; i++) {
- uint32_t obj_offset = hotspot_data_start + i * 9;
- roomFile->seek(obj_offset, SEEK_SET);
- HotSpot spot;
- spot.type = roomFile->readByte();
- spot.x = roomFile->readUint16LE();
- spot.y = roomFile->readUint16LE();
- spot.w = roomFile->readByte();
- spot.h = roomFile->readByte();
- spot.extra = roomFile->readUint16LE();
- debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
- hotspots.push_back(spot);
- }
- return hotspots;
- // uint32_t hover_areas_start = pair10_data_offset + 0x1BE;
- // roomFile->seek(hover_areas_start, SEEK_SET);
-}
-
-void ResourceManager::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
- uint32_t outPos = 0;
-
- Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
- debug("After decsriptions, position is %d", outPos);
- // Common::Array<ConversationNode> roots = loadConversations(roomFile, roomOffset, outPos);
- // for (int i = 0; i < roots.size(); i++) {
- // if (roots[i].text.empty()) {
- // continue;
- // }
- // debug("Conversation %d: %s", i, roots[i].text.c_str());
- // }
- // g_engine->_currentRoomConversations = roots;
-
- Common::Array<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
-
- Common::Array<HotSpot> hotspots;
- for (int i = 0; i < anims.size(); i++) {
-
- HotSpot thisHotspot;
- thisHotspot.index = i;
- thisHotspot.x = anims[i].x;
- thisHotspot.y = anims[i].y;
- thisHotspot.w = anims[i].w;
- thisHotspot.h = anims[i].h;
- thisHotspot.extra = anims[i].extra;
- thisHotspot.type = anims[i].actionFlags;
- thisHotspot.isEnabled = !anims[i].isDisabled;
- hotspots.push_back(thisHotspot);
- }
-
- Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
- Common::Array<Exit> exits = loadExits(roomFile, roomOffset);
-
- Common::Array<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
-
- debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
- for (int i = 0; i < staticHotspots.size(); i++) {
- HotSpot hotspot = staticHotspots[i];
- hotspot.index = anims.size() + i;
- hotspots.push_back(hotspot);
- }
-
- int walkboxCount = 0;
-
- g_engine->_currentRoomAnims = anims;
- g_engine->_currentRoomHotspots = hotspots;
- g_engine->_currentRoomExits = exits;
- g_engine->_currentRoomWalkboxes = walkboxes;
- g_engine->_currentRoomDescriptions = descriptions;
- for (int i = 0; i < g_engine->_currentRoomHotspots.size(); i++) {
- HotSpot hotspot = g_engine->_currentRoomHotspots[i];
- drawRect(g_engine->_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
- }
-
- for (int i = 0; i < g_engine->_currentRoomExits.size(); i++) {
- Exit exit = g_engine->_currentRoomExits[i];
- // drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
- }
-}
-Common::Array<AnimSet> ResourceManager::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
- uint32_t pair_offset = roomOffset + (8 * 8);
- // debug("Sprite pair offset position: %d", pair_offset);
- roomFile->seek(pair_offset, SEEK_SET);
- uint32_t offset = roomFile->readUint32LE();
- uint32_t size = roomFile->readUint32LE();
-
- byte *data = new byte[size];
- roomFile->seek(offset, SEEK_SET);
- roomFile->read(data, size);
-
- unsigned char *pic = new byte[10000 * 10000];
- if (offset > 0 && size > 0) {
- rleDecompress(data, size, 0, size, &pic);
- } else {
- return Common::Array<AnimSet>();
- }
- Common::Array<AnimSet> anims = Common::Array<AnimSet>();
- uint32_t spriteEnd = offset + size;
-
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- uint32_t metadata_start = spriteEnd + 108;
- uint32_t picOffset = 0;
- for (int i = 0; i < 7; i++) {
- uint32_t animOffset = metadata_start + (i * 44);
- byte *animData = new byte[44];
- roomFile->seek(animOffset, SEEK_SET);
- roomFile->read(animData, 44);
- AnimSet animSet;
- animSet.x = animData[0] | (animData[1] << 8);
- animSet.y = animData[2] | (animData[3] << 8);
- animSet.w = animData[4];
- animSet.h = animData[5];
- animSet.extra = animData[6];
- // roomFile->skip(1); // reserved
- animSet.numAnims = animData[8];
- animSet.spriteType = animData[33];
- animSet.actionFlags = animData[34];
- animSet.isDisabled = animData[38];
- if (animSet.numAnims == 0) {
- break;
- }
- animSet.animData = new Anim[animSet.numAnims];
- // debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
- int subAnimOffset = 10;
- for (int j = 0; j < animSet.numAnims; j++) {
-
- Anim anim;
- anim.x = animSet.x;
- anim.y = animSet.y;
- anim.w = animSet.w;
- anim.h = animSet.h;
- anim.curFrame = 0;
-
- anim.nframes = animData[subAnimOffset + j];
- anim.loopCount = animData[subAnimOffset + 4 + j];
- anim.speed = animData[subAnimOffset + 8 + j];
- anim.animData = new byte[anim.nframes];
- if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
- uint32_t needed = anim.w * anim.h * anim.nframes;
- anim.animData = new byte[needed];
- Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
- animSet.animData[j] = anim;
- // debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
- picOffset += needed;
- } else {
- continue;
- debug("Anim %d-%d: invalid dimensions, skipping", i, j);
- }
- animSet.animData[j] = anim;
- }
-
- anims.push_back(animSet);
- }
- return anims;
-}
-
-Common::Array<WalkBox> ResourceManager::loadWalkboxes(Common::File *roomFile, int roomOffset) {
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- roomFile->seek(pair10_offset_pos, SEEK_SET);
- // roomFile->skip(4);
- uint32_t pair10_data_offset = roomFile->readUint32LE();
- uint32_t pair10_size = roomFile->readUint32LE();
-
- uint32_t walkbox_countOffset = pair10_data_offset + 0x213;
- roomFile->seek(walkbox_countOffset, SEEK_SET);
- byte walkbox_count = roomFile->readByte();
- debug("Walkbox count: %d", walkbox_count);
- uint32_t walkbox_offset = pair10_data_offset + 0x218;
- Common::Array<WalkBox> walkboxes;
- for (int i = 0; i < walkbox_count; i++) {
- uint32_t box_offset = walkbox_offset + i * 9;
- roomFile->seek(box_offset, SEEK_SET);
- int16 x1 = roomFile->readSint16LE();
- int16 y1 = roomFile->readSint16LE();
- int16 w = roomFile->readSint16LE();
- int16 h = roomFile->readSint16LE();
- byte flags = roomFile->readByte();
- debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
- WalkBox box;
- box.x = x1;
- box.y = y1;
- box.w = w;
- box.h = h;
- box.flags = flags;
- walkboxes.push_back(box);
- }
- return walkboxes;
-}
-
-Common::Array<Description> ResourceManager::loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos) {
- uint32_t pair12_offset_pos = roomOffset + (12 * 8);
- roomFile->seek(pair12_offset_pos, SEEK_SET);
- // roomFile->skip(4);
- uint32_t pair12_data_offset = roomFile->readUint32LE();
- uint32_t pair12_size = roomFile->readUint32LE();
-
- roomFile->seek(pair12_data_offset, SEEK_SET);
- byte *data = new byte[pair12_size];
- roomFile->read(data, pair12_size);
- Common::Array<Description> descriptions;
- uint32_t pos = 0;
- uint32_t lastDescPos = 0;
- while (pos < (pair12_size)) {
- int desc_pos = 0;
- if (data[pos] == 0xFF) {
- Description description;
- description.itemId = data[pos + 1];
- pos += 3;
- description.index = data[pos++];
- description.text = "";
- // debug("Found description terminator");
- while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
- // debug(" char: %c", data[pos]);
- if (data[pos] != 0x00) {
- description.text.append(1, (char)data[pos]);
- }
- if (data[pos] == 0xF8) {
- description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
- debug("Found action trigger: %d", description.actionTrigger);
- pos += 2;
- break;
- }
- // desc[desc_pos++] = (char)data[pos];
- // debug("Current desc: %s", desc);
- pos++;
- }
- debug("Found description for item %d index %d, text: %s", description.itemId, description.index, description.text.c_str());
-
- descriptions.push_back(description);
- lastDescPos = pos;
- }
- pos++;
- }
- debug("End of descriptions at position %d", pos);
- outPos = lastDescPos + 1;
- delete[] data;
- // for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
- // debug("Room description: %s", i->c_str());
- // }
- return descriptions;
-}
-
-} // End of namespace Pelrock
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
new file mode 100644
index 00000000000..fa5a029d59a
--- /dev/null
+++ b/engines/pelrock/room.cpp
@@ -0,0 +1,825 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "pelrock/room.h"
+#include "pelrock/pelrock.h"
+#include "pelrock/util.h"
+
+namespace Pelrock {
+
+RoomManager::RoomManager() {
+}
+
+RoomManager::~RoomManager() {
+ // delete[] _currentRoomHotspots;
+ // delete[] _currentRoomAnims;
+ // delete[] _currentRoomExits;
+ // delete[] _currentRoomWalkboxes;
+ // delete[] _currentRoomDescriptions;
+ // delete[] _currentRoomConversations;
+}
+
+void RoomManager::getPalette(Common::File *roomFile, int roomOffset, byte *palette) {
+ // get palette
+ int paletteOffset = roomOffset + (11 * 8);
+ roomFile->seek(paletteOffset, SEEK_SET);
+ uint32 offset = roomFile->readUint32LE();
+ uint32 size = roomFile->readUint32LE();
+
+ roomFile->seek(offset, SEEK_SET);
+
+ roomFile->read(palette, size);
+ for (int i = 0; i < 256; i++) {
+ palette[i * 3] = palette[i * 3] << 2;
+ palette[i * 3 + 1] = palette[i * 3 + 1] << 2;
+ palette[i * 3 + 2] = palette[i * 3 + 2] << 2;
+ }
+}
+
+void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *background) {
+ roomFile->seek(0, SEEK_SET);
+ // get screen
+ size_t combined_size = 0;
+ size_t uncompressed_size = 0;
+ for (int pair_idx = 0; pair_idx < 8; pair_idx++) {
+ uint32_t pair_offset = roomOffset + (pair_idx * 8);
+ if (pair_offset + 8 > roomFile->size())
+ continue;
+
+ roomFile->seek(pair_offset, SEEK_SET);
+ uint32_t offset = roomFile->readUint32LE();
+ uint32_t size = roomFile->readUint32LE();
+ uncompressed_size += size;
+
+ if (offset > 0 && size > 0 && offset < roomFile->size()) {
+ byte *data = new byte[size];
+ roomFile->seek(offset, SEEK_SET);
+ roomFile->read(data, size);
+ uint8_t *block_data = NULL;
+ size_t block_size = rleDecompress(data, size, 0, size, &block_data);
+
+ memcpy(background + combined_size, block_data, block_size);
+ combined_size += block_size + 1;
+ free(block_data);
+ delete[] data;
+ }
+ }
+}
+
+Common::Array<Exit> RoomManager::loadExits(Common::File *roomFile, int roomOffset) {
+ Common::Array<Exit> exits;
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ roomFile->seek(pair10_offset_pos, SEEK_SET);
+ uint32_t pair10_data_offset = roomFile->readUint32LE();
+ uint32_t pair10_size = roomFile->readUint32LE();
+ roomFile->seek(pair10_data_offset + 0x1BE, SEEK_SET);
+ int exit_count = roomFile->readByte();
+ roomFile->seek(pair10_data_offset + 0x1BF, SEEK_SET);
+ for (int i = 0; i < exit_count; i++) {
+ Exit exit;
+ exit.targetRoom = roomFile->readUint16LE();
+ exit.flags = roomFile->readByte();
+ exit.x = roomFile->readUint16LE();
+ exit.y = roomFile->readUint16LE();
+ exit.w = roomFile->readByte();
+ exit.h = roomFile->readByte();
+
+ exit.targetX = roomFile->readUint16LE();
+ exit.targetY = roomFile->readUint16LE();
+ exit.dir = roomFile->readByte();
+ exits.push_back(exit);
+ }
+ return exits;
+}
+
+Common::Array<HotSpot> RoomManager::loadHotspots(Common::File *roomFile, int roomOffset) {
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ debug("Hotspot(10) pair offset position: %d", pair10_offset_pos);
+ roomFile->seek(pair10_offset_pos, SEEK_SET);
+ uint32_t pair10_data_offset = roomFile->readUint32LE();
+ uint32_t pair10_size = roomFile->readUint32LE();
+ uint32_t count_offset = pair10_data_offset + 0x47a;
+ roomFile->seek(count_offset, SEEK_SET);
+ byte hotspot_count = roomFile->readByte();
+ uint32_t hotspot_data_start = pair10_data_offset + 0x47c;
+ Common::Array<HotSpot> hotspots;
+ for (int i = 0; i < hotspot_count; i++) {
+ uint32_t obj_offset = hotspot_data_start + i * 9;
+ roomFile->seek(obj_offset, SEEK_SET);
+ HotSpot spot;
+ spot.type = roomFile->readByte();
+ spot.x = roomFile->readUint16LE();
+ spot.y = roomFile->readUint16LE();
+ spot.w = roomFile->readByte();
+ spot.h = roomFile->readByte();
+ spot.extra = roomFile->readUint16LE();
+ debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
+ hotspots.push_back(spot);
+ }
+ return hotspots;
+ // uint32_t hover_areas_start = pair10_data_offset + 0x1BE;
+ // roomFile->seek(hover_areas_start, SEEK_SET);
+}
+
+void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
+ uint32_t outPos = 0;
+
+ Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
+ debug("After decsriptions, position is %d", outPos);
+ Common::Array<ConversationNode> roots = loadConversations(roomFile, roomOffset, outPos);
+ for (int i = 0; i < roots.size(); i++) {
+ if (roots[i].text.empty()) {
+ continue;
+ }
+ debug("Conversation %d: %s", i, roots[i].text.c_str());
+ }
+ _currentRoomConversations = roots;
+
+ Common::Array<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
+
+ Common::Array<HotSpot> hotspots;
+ for (int i = 0; i < anims.size(); i++) {
+
+ HotSpot thisHotspot;
+ thisHotspot.index = i;
+ thisHotspot.x = anims[i].x;
+ thisHotspot.y = anims[i].y;
+ thisHotspot.w = anims[i].w;
+ thisHotspot.h = anims[i].h;
+ thisHotspot.extra = anims[i].extra;
+ thisHotspot.type = anims[i].actionFlags;
+ thisHotspot.isEnabled = !anims[i].isDisabled;
+ hotspots.push_back(thisHotspot);
+ }
+
+ Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
+ Common::Array<Exit> exits = loadExits(roomFile, roomOffset);
+
+ Common::Array<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
+
+ debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
+ for (int i = 0; i < staticHotspots.size(); i++) {
+ HotSpot hotspot = staticHotspots[i];
+ hotspot.index = anims.size() + i;
+ hotspots.push_back(hotspot);
+ }
+
+ int walkboxCount = 0;
+
+ _currentRoomAnims = anims;
+ _currentRoomHotspots = hotspots;
+ _currentRoomExits = exits;
+ _currentRoomWalkboxes = walkboxes;
+ _currentRoomDescriptions = descriptions;
+ for (int i = 0; i < _currentRoomHotspots.size(); i++) {
+ HotSpot hotspot = _currentRoomHotspots[i];
+ drawRect(g_engine->_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
+ }
+
+ for (int i = 0; i < _currentRoomExits.size(); i++) {
+ Exit exit = _currentRoomExits[i];
+ // drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
+ }
+}
+Common::Array<AnimSet> RoomManager::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
+ uint32_t pair_offset = roomOffset + (8 * 8);
+ // debug("Sprite pair offset position: %d", pair_offset);
+ roomFile->seek(pair_offset, SEEK_SET);
+ uint32_t offset = roomFile->readUint32LE();
+ uint32_t size = roomFile->readUint32LE();
+
+ byte *data = new byte[size];
+ roomFile->seek(offset, SEEK_SET);
+ roomFile->read(data, size);
+
+ unsigned char *pic = new byte[10000 * 10000];
+ if (offset > 0 && size > 0) {
+ rleDecompress(data, size, 0, size, &pic);
+ } else {
+ return Common::Array<AnimSet>();
+ }
+ Common::Array<AnimSet> anims = Common::Array<AnimSet>();
+ uint32_t spriteEnd = offset + size;
+
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ uint32_t metadata_start = spriteEnd + 108;
+ uint32_t picOffset = 0;
+ for (int i = 0; i < 7; i++) {
+ uint32_t animOffset = metadata_start + (i * 44);
+ byte *animData = new byte[44];
+ roomFile->seek(animOffset, SEEK_SET);
+ roomFile->read(animData, 44);
+ AnimSet animSet;
+ animSet.x = animData[0] | (animData[1] << 8);
+ animSet.y = animData[2] | (animData[3] << 8);
+ animSet.w = animData[4];
+ animSet.h = animData[5];
+ animSet.extra = animData[6];
+ // roomFile->skip(1); // reserved
+ animSet.numAnims = animData[8];
+ animSet.spriteType = animData[33];
+ animSet.actionFlags = animData[34];
+ animSet.isDisabled = animData[38];
+ if (animSet.numAnims == 0) {
+ break;
+ }
+ animSet.animData = new Anim[animSet.numAnims];
+ // debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
+ int subAnimOffset = 10;
+ for (int j = 0; j < animSet.numAnims; j++) {
+
+ Anim anim;
+ anim.x = animSet.x;
+ anim.y = animSet.y;
+ anim.w = animSet.w;
+ anim.h = animSet.h;
+ anim.curFrame = 0;
+
+ anim.nframes = animData[subAnimOffset + j];
+ anim.loopCount = animData[subAnimOffset + 4 + j];
+ anim.speed = animData[subAnimOffset + 8 + j];
+ anim.animData = new byte[anim.nframes];
+ if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
+ uint32_t needed = anim.w * anim.h * anim.nframes;
+ anim.animData = new byte[needed];
+ Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
+ animSet.animData[j] = anim;
+ // debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
+ picOffset += needed;
+ } else {
+ continue;
+ debug("Anim %d-%d: invalid dimensions, skipping", i, j);
+ }
+ animSet.animData[j] = anim;
+ }
+
+ anims.push_back(animSet);
+ }
+ return anims;
+}
+
+Common::Array<WalkBox> RoomManager::loadWalkboxes(Common::File *roomFile, int roomOffset) {
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ roomFile->seek(pair10_offset_pos, SEEK_SET);
+ // roomFile->skip(4);
+ uint32_t pair10_data_offset = roomFile->readUint32LE();
+ uint32_t pair10_size = roomFile->readUint32LE();
+
+ uint32_t walkbox_countOffset = pair10_data_offset + 0x213;
+ roomFile->seek(walkbox_countOffset, SEEK_SET);
+ byte walkbox_count = roomFile->readByte();
+ debug("Walkbox count: %d", walkbox_count);
+ uint32_t walkbox_offset = pair10_data_offset + 0x218;
+ Common::Array<WalkBox> walkboxes;
+ for (int i = 0; i < walkbox_count; i++) {
+ uint32_t box_offset = walkbox_offset + i * 9;
+ roomFile->seek(box_offset, SEEK_SET);
+ int16 x1 = roomFile->readSint16LE();
+ int16 y1 = roomFile->readSint16LE();
+ int16 w = roomFile->readSint16LE();
+ int16 h = roomFile->readSint16LE();
+ byte flags = roomFile->readByte();
+ debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+ WalkBox box;
+ box.x = x1;
+ box.y = y1;
+ box.w = w;
+ box.h = h;
+ box.flags = flags;
+ walkboxes.push_back(box);
+ }
+ return walkboxes;
+}
+
+Common::Array<Description> RoomManager::loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos) {
+ uint32_t pair12_offset_pos = roomOffset + (12 * 8);
+ roomFile->seek(pair12_offset_pos, SEEK_SET);
+ // roomFile->skip(4);
+ uint32_t pair12_data_offset = roomFile->readUint32LE();
+ uint32_t pair12_size = roomFile->readUint32LE();
+
+ roomFile->seek(pair12_data_offset, SEEK_SET);
+ byte *data = new byte[pair12_size];
+ roomFile->read(data, pair12_size);
+ Common::Array<Description> descriptions;
+ uint32_t pos = 0;
+ uint32_t lastDescPos = 0;
+ while (pos < (pair12_size)) {
+ int desc_pos = 0;
+ if (data[pos] == 0xFF) {
+ Description description;
+ description.itemId = data[pos + 1];
+ pos += 3;
+ description.index = data[pos++];
+ description.text = "";
+ // debug("Found description terminator");
+ while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
+ // debug(" char: %c", data[pos]);
+ if (data[pos] != 0x00) {
+ description.text.append(1, (char)data[pos]);
+ }
+ if (data[pos] == 0xF8) {
+ description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
+ debug("Found action trigger: %d", description.actionTrigger);
+ pos += 2;
+ break;
+ }
+ // desc[desc_pos++] = (char)data[pos];
+ // debug("Current desc: %s", desc);
+ pos++;
+ }
+ debug("Found description for item %d index %d, text: %s", description.itemId, description.index, description.text.c_str());
+
+ descriptions.push_back(description);
+ lastDescPos = pos;
+ }
+ pos++;
+ }
+ debug("End of descriptions at position %d", pos);
+ outPos = lastDescPos + 1;
+ delete[] data;
+ // for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
+ // debug("Room description: %s", i->c_str());
+ // }
+ return descriptions;
+}
+
+
+char32_t decodeByte(byte b) {
+ if (b == 0x80) {
+ return '\xA4';
+ } else if (b == 0x81) {
+ return '\xA1';
+ } else if (b == 0x82) {
+ return '\xAD';
+ } else if (b == 0x83) {
+ return '\xA8';
+ } else if (b == 0x84) {
+ return '\xA3';
+ } else if (b == 0x7B) {
+ return '\xA0';
+ } else if (b == 0x7C) {
+ return '\x82';
+ } else if (b == 0x7D) {
+ return '\xA1';
+ } else if (b == 0x7E) {
+ return '\xA2';
+ } else if (b == 0x7F) {
+ return '\xA3';
+ } else if (b >= 0x20 && b <= 0x7A) {
+ return (char)b;
+ } else {
+ // return string in format [XX]
+ return '.';
+ }
+}
+
+void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
+
+ int headerIndex = roomNumber;
+ uint32 offset = kTalkingAnimHeaderSize * headerIndex;
+
+ TalkinAnimHeader talkHeader;
+ Common::File talkFile;
+ if (!talkFile.open("ALFRED.2")) {
+ error("Couldnt find file ALFRED.2");
+ }
+
+ talkFile.seek(offset, SEEK_SET);
+
+ talkHeader.spritePointer = talkFile.readUint32LE();
+ talkFile.read(&talkHeader.unknown2, 3);
+ talkHeader.offsetXAnimA = talkFile.readByte();
+ talkHeader.offsetYAnimA = talkFile.readByte();
+ talkHeader.wAnimA = talkFile.readByte();
+ talkHeader.hAnimA = talkFile.readByte();
+ talkFile.read(&talkHeader.unknown3, 2);
+ talkHeader.numFramesAnimA = talkFile.readByte();
+ talkFile.read(&talkHeader.unknown4, 5);
+
+ talkHeader.offsetXAnimB = talkFile.readByte();
+ talkHeader.offsetYAnimB = talkFile.readByte();
+ talkHeader.wAnimB = talkFile.readByte();
+ talkHeader.hAnimB = talkFile.readByte();
+ talkFile.read(&talkHeader.unknown5, 2);
+ talkHeader.numFramesAnimB = talkFile.readByte();
+ talkFile.read(&talkHeader.unknown6, 29);
+ debug("Talking anim header for room %d: spritePointer=%d, wA=%d, hA=%d, framesA=%d, wB=%d, hB=%d, framesB=%d", roomNumber, talkHeader.spritePointer, talkHeader.wAnimA, talkHeader.hAnimA, talkHeader.numFramesAnimA, talkHeader.wAnimB, talkHeader.hAnimB, talkHeader.numFramesAnimB);
+
+ if (talkHeader.spritePointer == 0) {
+ debug("No talking animation for room %d", roomNumber);
+ talkFile.close();
+ return;
+ }
+
+ // if(talkHeader.animA != nullptr) {
+ // delete[] talkHeader.animA;
+ // talkHeader.animA = nullptr;
+ // }
+ talkHeader.animA = new byte *[talkHeader.numFramesAnimA];
+
+ byte *data = nullptr;
+ int animASize = talkHeader.wAnimA * talkHeader.hAnimA * talkHeader.numFramesAnimA;
+ byte *decompressed = nullptr;
+ size_t dataSize = 0;
+ readUntilBuda(&talkFile, talkHeader.spritePointer, data, dataSize);
+ size_t decompressedSize = rleDecompress(data, dataSize, 0, dataSize, &decompressed);
+ free(data);
+ debug("Decompressed talking anim A size: %zu, decompressed size: %zu", dataSize, decompressedSize);
+ for (int i = 0; i < talkHeader.numFramesAnimA; i++) {
+ talkHeader.animA[i] = new byte[talkHeader.wAnimA * talkHeader.hAnimA];
+ Common::copy(decompressed + (i * talkHeader.wAnimA * talkHeader.hAnimA), decompressed + ((i + 1) * talkHeader.wAnimA * talkHeader.hAnimA), talkHeader.animA[i]);
+ }
+
+ if (talkHeader.numFramesAnimB > 0) {
+ // if(talkHeader.animA != nullptr) {
+ // delete[] talkHeader.animA;
+ // talkHeader.animA = nullptr;
+ // }
+ talkHeader.animB = new byte *[talkHeader.numFramesAnimB];
+ for (int i = 0; i < talkHeader.numFramesAnimB; i++) {
+ talkHeader.animB[i] = new byte[talkHeader.wAnimB * talkHeader.hAnimB];
+ Common::copy(decompressed + animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB), decompressed + animASize + ((i + 1) * talkHeader.wAnimB * talkHeader.hAnimB), talkHeader.animB[i]);
+ }
+ }
+ free(decompressed);
+ _talkingAnimHeader = talkHeader;
+
+ talkFile.close();
+}
+
+Common::String RoomManager::getControlName(byte b) {
+ switch (b) {
+ case 0xFD:
+ return "END_LINE";
+ case 0xFC:
+ return "TEXT_TERM";
+ case 0xFB:
+ return "CHOICE";
+ case 0xFA:
+ return "SKIP";
+ case 0xF9:
+ return "PAGE_BREAK";
+ case 0xF8:
+ return "ACTION";
+ case 0xF7:
+ return "END_BRANCH";
+ case 0xF6:
+ return "LINE_CONT";
+ case 0xF5:
+ return "END_BRANCH_2";
+ case 0xF4:
+ return "END_CONV";
+ case 0xF1:
+ return "CHOICE_ALT";
+ case 0xF0:
+ return "GO_BACK";
+ case 0xFE:
+ return "END_BRANCH_3";
+ case 0xEB:
+ return "END_ALT";
+ case 0xFF:
+ return "DESC_START";
+ case 0x08:
+ return "SPEAKER";
+ default:
+ return Common::String::format("UNKNOWN(0x%02X)", b);
+ }
+}
+
+Common::String RoomManager::cleanText(const Common::String &text) {
+ Common::String cleaned = text;
+
+ // Trim leading/trailing whitespace
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ while (!cleaned.empty() && Common::isSpace(cleaned.lastChar())) {
+ cleaned.deleteLastChar();
+ }
+
+ // Remove leading [XX][00] patterns
+ while (!cleaned.empty() && cleaned.contains('[')) {
+ uint idx = 0;
+ for (uint i = 0; i < cleaned.size() && i < 15; i++) {
+ if (cleaned[i] == '[') {
+ idx = i;
+ break;
+ }
+ }
+
+ if (idx < 10) {
+ int endIdx = -1;
+ for (uint i = idx; i < cleaned.size() && i < idx + 10; i++) {
+ if (cleaned[i] == ']') {
+ endIdx = i;
+ break;
+ }
+ }
+
+ if (endIdx > (int)idx && endIdx < (int)idx + 10) {
+ cleaned = cleaned.c_str() + endIdx + 1;
+ // Trim leading whitespace again
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ // Remove single leading control characters
+ if (cleaned.size() > 1) {
+ byte first = (byte)cleaned[0];
+ byte second = (byte)cleaned[1];
+
+ if ((first == 'A' || first == 'H') &&
+ (Common::isUpper(second) || second == 0x83 || second == 0x82 || second == '[')) {
+ cleaned.deleteChar(0);
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ } else if (strchr("#%')!+,.-\"*&$(/", first)) {
+ cleaned.deleteChar(0);
+ while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
+ cleaned.deleteChar(0);
+ }
+ }
+ }
+
+ return cleaned;
+}
+
+Common::Array<ConversationElement> RoomManager::parseConversationElements(const byte *convData, uint32 size) {
+ Common::Array<ConversationElement> elements;
+ Common::HashMap<int, int> choiceIndices; // Track choice index occurrences
+ uint32 pos = 0;
+
+ // First pass: parse elements and track choice indices
+ while (pos < size) {
+ byte b = convData[pos];
+
+ if (b == 0x08) { // SPEAKER
+ pos++;
+ if (pos < size) {
+ byte speakerId = convData[pos];
+ Common::String speaker = (speakerId == 0x0D) ? "ALFRED" : "NPC";
+ pos++;
+
+ // Read text
+ Common::String text;
+ while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
+ convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
+ convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
+ convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
+ convData[pos] != 0xF0) {
+ char32_t ch = decodeByte(convData[pos]);
+ if (ch != '.') {
+ text += ch;
+ }
+ pos++;
+ }
+
+ text = cleanText(text);
+ if (!text.empty()) {
+ ConversationElement elem;
+ elem.type = ConversationElement::DIALOGUE;
+ elem.speakerId = speakerId;
+ elem.speaker = speaker;
+ elem.text = text;
+ elem.choiceIndex = -1;
+ elements.push_back(elem);
+ }
+ }
+ } else if (b == 0xFB || b == 0xF1) { // CHOICE marker
+ pos++;
+ int choiceIndex = -1;
+ if (pos < size) {
+ choiceIndex = convData[pos];
+ // Track this choice index
+ if (choiceIndices.contains(choiceIndex)) {
+ choiceIndices[choiceIndex]++;
+ } else {
+ choiceIndices[choiceIndex] = 1;
+ }
+ pos++;
+ }
+
+ // Skip next 2 bytes (speaker marker)
+ if (pos < size)
+ pos++;
+ if (pos < size)
+ pos++;
+
+ // Read text
+ Common::String text;
+ while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
+ convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
+ convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
+ convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
+ convData[pos] != 0xF0) {
+ char32_t ch = decodeByte(convData[pos]);
+ if (ch != '.') {
+ text += ch;
+ }
+ pos++;
+ }
+
+ text = cleanText(text);
+ if (!text.empty()) {
+ ConversationElement elem;
+ elem.type = ConversationElement::CHOICE_MARKER;
+ elem.text = text;
+ elem.choiceIndex = choiceIndex;
+ elements.push_back(elem);
+ }
+ } else if (b == 0xF8) { // ACTION
+ pos += 3;
+ } else if (b == 0xF4) { // END_CONV
+ ConversationElement elem;
+ elem.type = ConversationElement::END_CONV;
+ elements.push_back(elem);
+ pos++;
+ } else if (b == 0xF7) { // END_BRANCH
+ ConversationElement elem;
+ elem.type = ConversationElement::END_BRANCH;
+ elements.push_back(elem);
+ pos++;
+ } else if (b == 0xFD || b == 0xFC || b == 0xF5 || b == 0xFE || b == 0xEB || b == 0xF0) {
+ pos++;
+ } else {
+ pos++;
+ }
+ }
+
+ // Second pass: mark which indices are actual choices (appear multiple times)
+ for (uint i = 0; i < elements.size(); i++) {
+ if (elements[i].choiceIndex >= 0) {
+ elements[i].isRealChoice = (choiceIndices[elements[i].choiceIndex] > 1);
+ }
+ }
+
+ return elements;
+}
+
+Common::Array<ConversationNode> RoomManager::buildTreeStructure(const Common::Array<ConversationElement> &elements) {
+ Common::Array<ConversationNode> roots;
+ Common::Array<StackEntry> stack;
+ ConversationNode *currentRoot = nullptr;
+ uint i = 0;
+
+ while (i < elements.size()) {
+ const ConversationElement &elem = elements[i];
+
+ if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "NPC") {
+ if (stack.empty()) {
+ // New root conversation
+ ConversationNode root;
+ root.type = ConversationNode::ROOT;
+ root.text = elem.text;
+ root.speaker = "NPC";
+ root.speakerId = elem.speakerId;
+ roots.push_back(root);
+ currentRoot = &roots[roots.size() - 1];
+ } else {
+ // NPC response within a branch
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ ConversationNode response;
+ response.type = ConversationNode::RESPONSE;
+ response.speaker = "NPC";
+ response.speakerId = elem.speakerId;
+ response.text = elem.text;
+ parent->responses.push_back(response);
+ }
+ i++;
+
+ } else if (elem.type == ConversationElement::CHOICE_MARKER) {
+ if (elem.isRealChoice) {
+ // Real choice - player selects from menu
+ ConversationNode choiceNode;
+ choiceNode.type = ConversationNode::CHOICE;
+ choiceNode.text = elem.text;
+ choiceNode.speaker = "ALFRED";
+ choiceNode.speakerId = 0x0D; // Player
+ choiceNode.choiceIndex = elem.choiceIndex;
+
+ // Find where to attach this choice
+ while (!stack.empty() && stack[stack.size() - 1].index >= elem.choiceIndex) {
+ stack.pop_back();
+ }
+
+ if (!stack.empty()) {
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ parent->subchoices.push_back(choiceNode);
+
+ // Get pointer to the newly added choice
+ ConversationNode *newChoice = &parent->subchoices[parent->subchoices.size() - 1];
+
+ StackEntry entry;
+ entry.node = newChoice;
+ entry.index = elem.choiceIndex;
+ stack.push_back(entry);
+ } else {
+ if (currentRoot) {
+ currentRoot->choices.push_back(choiceNode);
+
+ // Get pointer to the newly added choice
+ ConversationNode *newChoice = ¤tRoot->choices[currentRoot->choices.size() - 1];
+
+ StackEntry entry;
+ entry.node = newChoice;
+ entry.index = elem.choiceIndex;
+ stack.push_back(entry);
+ }
+ }
+ } else {
+ // Auto-dialogue - ALFRED just speaks
+ if (!stack.empty()) {
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ ConversationNode response;
+ response.type = ConversationNode::RESPONSE;
+ response.speaker = "ALFRED";
+ response.speakerId = 0x0D;
+ response.text = elem.text;
+ parent->responses.push_back(response);
+ }
+ }
+ i++;
+
+ } else if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "ALFRED") {
+ if (!stack.empty()) {
+ ConversationNode *parent = stack[stack.size() - 1].node;
+ ConversationNode response;
+ response.type = ConversationNode::RESPONSE;
+ response.speaker = "ALFRED";
+ response.text = elem.text;
+ response.speakerId = 0x0D;
+ parent->responses.push_back(response);
+ }
+ i++;
+
+ } else if (elem.type == ConversationElement::END_CONV) {
+ if (!stack.empty()) {
+ stack[stack.size() - 1].node->terminated = true;
+ stack.pop_back();
+ }
+ i++;
+
+ } else if (elem.type == ConversationElement::END_BRANCH) {
+ stack.clear();
+ currentRoot = nullptr;
+ i++;
+
+ } else {
+ i++;
+ }
+ }
+
+ return roots;
+}
+
+Common::Array<ConversationNode> RoomManager::loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos) {
+
+ debug("Loading conversations starting at position %d", startPos);
+
+ uint32_t pair12_offset_pos = roomOffset + (12 * 8);
+ roomFile->seek(pair12_offset_pos, SEEK_SET);
+ uint32_t pair12_data_offset = roomFile->readUint32LE();
+ uint32_t pair12_size = roomFile->readUint32LE();
+
+ // startPos += 2;
+ uint32_t conversation_start = pair12_data_offset + startPos;
+ uint32_t conversation_size = pair12_size - startPos;
+
+ roomFile->seek(conversation_start, SEEK_SET);
+ byte *data = new byte[conversation_size];
+ roomFile->read(data, conversation_size);
+
+ Common::Array<ConversationElement> elements = parseConversationElements(data, conversation_size);
+ Common::Array<ConversationNode> roots = buildTreeStructure(elements);
+ return roots;
+}
+
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/resources.h b/engines/pelrock/room.h
similarity index 63%
rename from engines/pelrock/resources.h
rename to engines/pelrock/room.h
index 45fcd7b3c31..311c7bc66b0 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/room.h
@@ -29,12 +29,22 @@
namespace Pelrock {
-class ResourceManager {
+class RoomManager {
public:
- ResourceManager();
- ~ResourceManager();
+ RoomManager();
+ ~RoomManager();
void loadRoomMetadata(Common::File *roomFile, int roomOffset);
void loadRoomTalkingAnimations(int roomNumber);
+ void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
+ void getBackground(Common::File *roomFile, int roomOffset, byte *background);
+
+ Common::Array<HotSpot> _currentRoomHotspots;
+ Common::Array<AnimSet> _currentRoomAnims;
+ Common::Array<Exit> _currentRoomExits;
+ Common::Array<WalkBox> _currentRoomWalkboxes;
+ Common::Array<Description> _currentRoomDescriptions;
+ Common::Array<ConversationNode> _currentRoomConversations;
+ TalkinAnimHeader _talkingAnimHeader;
private:
Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
@@ -42,6 +52,12 @@ private:
Common::Array<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::Array<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos);
+
+ Common::String getControlName(byte b);
+ Common::String cleanText(const Common::String &text);
+ Common::Array<ConversationElement> parseConversationElements(const byte *convData, uint32 size);
+ Common::Array<ConversationNode> buildTreeStructure(const Common::Array<ConversationElement> &elements);
+ Common::Array<ConversationNode> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 7a1ab388d0a..5f2720d59bb 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+#include "common/stream.h"
#include "pelrock/util.h"
#include "pelrock/types.h"
@@ -76,4 +77,32 @@ size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uin
return result_size;
}
+void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize) {
+ const char marker[] = "BUDA";
+ const int markerLen = 4;
+ size_t bufferSize = 4096;
+ size_t pos = 0;
+
+ buffer = (byte *)malloc(bufferSize);
+ stream->seek(startPos, SEEK_SET);
+ while (!stream->eos()) {
+ byte b = stream->readByte();
+ if (pos + 1 > bufferSize) {
+ bufferSize *= 2;
+ buffer = (byte *)realloc(buffer, bufferSize);
+ }
+ buffer[pos++] = b;
+
+ // Check for marker at the end of buffer
+ if (pos >= markerLen &&
+ buffer[pos - 4] == 'B' &&
+ buffer[pos - 3] == 'U' &&
+ buffer[pos - 2] == 'D' &&
+ buffer[pos - 1] == 'A') {
+ break;
+ }
+ }
+ outSize = pos;
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index d5cfa3cc3cf..1f333132958 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -28,6 +28,8 @@ namespace Pelrock {
const int EXPECTED_SIZE = 640 * 400;
size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data);
+void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize);
+
void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
} // End of namespace Pelrock
Commit: 977976673989fbb2ff622442e1ce718880d316aa
https://github.com/scummvm/scummvm/commit/977976673989fbb2ff622442e1ce718880d316aa
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:10+02:00
Commit Message:
PELROCK: Refactor to use common extractSingleFrame function
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b66d2836d6e..94573b6bf24 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -91,6 +91,7 @@ Common::String PelrockEngine::getGameId() const {
}
Common::Array<Common::Array<Common::String> > wordWrap(Common::String text);
+
Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
initGraphics(640, 400);
@@ -275,14 +276,6 @@ void PelrockEngine::loadInteractionIcons() {
alfred4File.close();
}
-void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight) {
- for (int y = 0; y < frameHeight; y++) {
- for (int x = 0; x < frameWidth; x++) {
- unsigned int src_pos = (frameIndex * frameHeight * frameWidth) + (y * frameWidth) + x;
- dest[y * frameWidth + x] = source[src_pos];
- }
- }
-}
void PelrockEngine::loadAlfredAnims() {
Common::File alfred3;
@@ -349,6 +342,7 @@ byte *PelrockEngine::grabBackgroundSlice(int x, int y, int w, int h) {
}
return bg;
}
+
void PelrockEngine::putBackgroundSlice(int x, int y, int w, int h, byte *slice) {
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
@@ -359,28 +353,6 @@ void PelrockEngine::putBackgroundSlice(int x, int y, int w, int h, byte *slice)
}
}
-// Helper function for transparent blitting
-void drawSpriteToBuffer(byte *buffer, int bufferWidth,
- byte *sprite, int x, int y,
- int width, int height,
- int transparentColor) {
- for (int py = 0; py < height; py++) {
- for (int px = 0; px < width; px++) {
- int srcIdx = py * width + px;
- byte pixel = sprite[srcIdx];
-
- if (pixel != transparentColor) {
- int destX = x + px;
- int destY = y + py;
-
- if (destX >= 0 && destX < 640 &&
- destY >= 0 && destY < 400) {
- buffer[destY * bufferWidth + destX] = pixel;
- }
- }
- }
- }
-}
Common::Array<VerbIcons> PelrockEngine::availableActions(HotSpot *hotspot) {
Common::Array<VerbIcons> verbs;
@@ -442,7 +414,7 @@ void PelrockEngine::frames() {
int frameSize = animSet.animData[animSet.curAnimIndex].w * animSet.animData[animSet.curAnimIndex].h;
int curFrame = animSet.animData[animSet.curAnimIndex].curFrame;
byte *frame = new byte[frameSize];
- Common::copy(animSet.animData[animSet.curAnimIndex].animData + (curFrame * animSet.animData[animSet.curAnimIndex].h * animSet.animData[animSet.curAnimIndex].w), animSet.animData[animSet.curAnimIndex].animData + (curFrame * animSet.animData[animSet.curAnimIndex].h * animSet.animData[animSet.curAnimIndex].w) + (frameSize), frame);
+ extractSingleFrame(animSet.animData[animSet.curAnimIndex].animData, frame, curFrame, animSet.animData[animSet.curAnimIndex].w, animSet.animData[animSet.curAnimIndex].h);
drawSpriteToBuffer(_compositeBuffer, 640, frame, animSet.x, animSet.y, animSet.w, animSet.h, 255);
@@ -565,7 +537,6 @@ void PelrockEngine::frames() {
if (!isAlfredWalking && !_currentTextPages.empty()) {
if (_chronoManager->_textTtl > 0) {
- debug("Will render text, _chronoManager->_textTtl=%d", _chronoManager->_textTtl);
renderText(_currentTextPages[_currentTextPageIndex], _textColor, _textPos.x, _textPos.y);
} else if (_currentTextPageIndex < _currentTextPages.size() - 1) {
_currentTextPageIndex++;
@@ -721,25 +692,24 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
void PelrockEngine::talkNPC(AnimSet *animSet, int index) {
// Change with the right index
- TalkinAnimHeader animHeader = _room->_talkingAnimHeader;
+ TalkinAnimHeader *animHeader = &_room->_talkingAnimHeader;
- int x = animSet->x + (index ? animHeader.offsetXAnimB : animHeader.offsetXAnimA);
- int y = animSet->y + (index ? animHeader.offsetYAnimB : animHeader.offsetYAnimA);
+ int x = animSet->x + (index ? animHeader->offsetXAnimB : animHeader->offsetXAnimA);
+ int y = animSet->y + (index ? animHeader->offsetYAnimB : animHeader->offsetYAnimA);
- int w = index ? animHeader.wAnimB : animHeader.wAnimA;
- int h = index ? animHeader.hAnimB : animHeader.hAnimA;
- int numFrames = index ? animHeader.numFramesAnimB : animHeader.numFramesAnimA;
- int curFrame = index ? animHeader.currentFrameAnimB++ : animHeader.currentFrameAnimA++;
+ int w = index ? animHeader->wAnimB : animHeader->wAnimA;
+ int h = index ? animHeader->hAnimB : animHeader->hAnimA;
+ int numFrames = index ? animHeader->numFramesAnimB : animHeader->numFramesAnimA;
+ int curFrame = index ? animHeader->currentFrameAnimB++ : animHeader->currentFrameAnimA++;
if (curFrame >= numFrames) {
if (index) {
- animHeader.currentFrameAnimB = 0;
+ animHeader->currentFrameAnimB = 0;
} else {
- animHeader.currentFrameAnimA = 0;
+ animHeader->currentFrameAnimA = 0;
}
curFrame = 0;
}
- byte *frame = index ? animHeader.animB[curFrame] : animHeader.animA[curFrame];
-
+ byte *frame = index ? animHeader->animB[curFrame] : animHeader->animA[curFrame];
debug("Talking NPC frame %d/%d, x=%d, y=%d, w=%d, h=%d", curFrame, numFrames, x, y, w, h);
drawSpriteToBuffer(_compositeBuffer, 640, frame, x, y, w, h, 255);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index fa5a029d59a..0321fc19112 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -446,7 +446,8 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
debug("Decompressed talking anim A size: %zu, decompressed size: %zu", dataSize, decompressedSize);
for (int i = 0; i < talkHeader.numFramesAnimA; i++) {
talkHeader.animA[i] = new byte[talkHeader.wAnimA * talkHeader.hAnimA];
- Common::copy(decompressed + (i * talkHeader.wAnimA * talkHeader.hAnimA), decompressed + ((i + 1) * talkHeader.wAnimA * talkHeader.hAnimA), talkHeader.animA[i]);
+ extractSingleFrame(decompressed, talkHeader.animA[i], i, talkHeader.wAnimA, talkHeader.hAnimA);
+
}
if (talkHeader.numFramesAnimB > 0) {
@@ -457,7 +458,7 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
talkHeader.animB = new byte *[talkHeader.numFramesAnimB];
for (int i = 0; i < talkHeader.numFramesAnimB; i++) {
talkHeader.animB[i] = new byte[talkHeader.wAnimB * talkHeader.hAnimB];
- Common::copy(decompressed + animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB), decompressed + animASize + ((i + 1) * talkHeader.wAnimB * talkHeader.hAnimB), talkHeader.animB[i]);
+ extractSingleFrame(decompressed + animASize, talkHeader.animB[i], i, talkHeader.wAnimB, talkHeader.hAnimB);
}
}
free(decompressed);
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 5f2720d59bb..c05d0e4a2a2 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -105,4 +105,37 @@ void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *
outSize = pos;
}
+// Helper function for transparent blitting
+void drawSpriteToBuffer(byte *buffer, int bufferWidth,
+ byte *sprite, int x, int y,
+ int width, int height,
+ int transparentColor) {
+ for (int py = 0; py < height; py++) {
+ for (int px = 0; px < width; px++) {
+ int srcIdx = py * width + px;
+ byte pixel = sprite[srcIdx];
+
+ if (pixel != transparentColor) {
+ int destX = x + px;
+ int destY = y + py;
+
+ if (destX >= 0 && destX < 640 &&
+ destY >= 0 && destY < 400) {
+ buffer[destY * bufferWidth + destX] = pixel;
+ }
+ }
+ }
+ }
+}
+
+
+void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight) {
+ for (int y = 0; y < frameHeight; y++) {
+ for (int x = 0; x < frameWidth; x++) {
+ unsigned int src_pos = (frameIndex * frameHeight * frameWidth) + (y * frameWidth) + x;
+ dest[y * frameWidth + x] = source[src_pos];
+ }
+ }
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 1f333132958..1bda8ed6c8b 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -29,7 +29,12 @@ namespace Pelrock {
const int EXPECTED_SIZE = 640 * 400;
size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data);
void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize);
-
+void drawSpriteToBuffer(byte *buffer, int bufferWidth,
+ byte *sprite, int x, int y,
+ int width, int height,
+ int transparentColor);
+void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY);
+void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight);
void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
} // End of namespace Pelrock
Commit: b25ff75330d7328baeda49dfc9796c3ca8ff04d7
https://github.com/scummvm/scummvm/commit/b25ff75330d7328baeda49dfc9796c3ca8ff04d7
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:10+02:00
Commit Message:
PELROCK: refactor animations
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 94573b6bf24..a680f6e56cb 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -276,7 +276,6 @@ void PelrockEngine::loadInteractionIcons() {
alfred4File.close();
}
-
void PelrockEngine::loadAlfredAnims() {
Common::File alfred3;
if (!alfred3.open(Common::Path("ALFRED.3"))) {
@@ -353,7 +352,6 @@ void PelrockEngine::putBackgroundSlice(int x, int y, int w, int h, byte *slice)
}
}
-
Common::Array<VerbIcons> PelrockEngine::availableActions(HotSpot *hotspot) {
Common::Array<VerbIcons> verbs;
verbs.push_back(LOOK);
@@ -399,46 +397,7 @@ void PelrockEngine::frames() {
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
// debug("Processing animation set %d, numAnims %d", num, i->numAnims);
AnimSet &animSet = _room->_currentRoomAnims[i];
- int x = animSet.animData[animSet.curAnimIndex].x;
- int y = animSet.animData[animSet.curAnimIndex].y;
- int w = animSet.animData[animSet.curAnimIndex].w;
- int h = animSet.animData[animSet.curAnimIndex].h;
- int extra = animSet.extra;
-
- if (whichNPCTalking == extra) {
- // debug("Skipping anim set %d because NPC is talking", i);
- talkNPC(&animSet, i);
- continue;
- }
-
- int frameSize = animSet.animData[animSet.curAnimIndex].w * animSet.animData[animSet.curAnimIndex].h;
- int curFrame = animSet.animData[animSet.curAnimIndex].curFrame;
- byte *frame = new byte[frameSize];
- extractSingleFrame(animSet.animData[animSet.curAnimIndex].animData, frame, curFrame, animSet.animData[animSet.curAnimIndex].w, animSet.animData[animSet.curAnimIndex].h);
-
- drawSpriteToBuffer(_compositeBuffer, 640, frame, animSet.x, animSet.y, animSet.w, animSet.h, 255);
-
- if (animSet.animData[animSet.curAnimIndex].elpapsedFrames == animSet.animData[animSet.curAnimIndex].speed) {
- animSet.animData[animSet.curAnimIndex].elpapsedFrames = 0;
- if (animSet.animData[animSet.curAnimIndex].curFrame < animSet.animData[animSet.curAnimIndex].nframes - 1) {
- animSet.animData[animSet.curAnimIndex].curFrame++;
- } else {
- if (animSet.animData[animSet.curAnimIndex].curLoop < animSet.animData[animSet.curAnimIndex].loopCount - 1) {
- animSet.animData[animSet.curAnimIndex].curFrame = 0;
- animSet.animData[animSet.curAnimIndex].curLoop++;
- } else {
- animSet.animData[animSet.curAnimIndex].curFrame = 0;
- animSet.animData[animSet.curAnimIndex].curLoop = 0;
- if (animSet.curAnimIndex < animSet.numAnims - 1) {
- animSet.curAnimIndex++;
- } else {
- animSet.curAnimIndex = 0;
- }
- }
- }
- } else {
- animSet.animData[animSet.curAnimIndex].elpapsedFrames++;
- }
+ drawNextFrame(&animSet);
}
if (isAlfredWalking) {
@@ -609,10 +568,52 @@ void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, i
}
void PelrockEngine::drawAlfred(byte *buf) {
-
drawSpriteToBuffer(_compositeBuffer, 640, buf, xAlfred, yAlfred - kAlfredFrameHeight, kAlfredFrameWidth, kAlfredFrameHeight, 255);
}
+void PelrockEngine::drawNextFrame(AnimSet *animSet) {
+ Anim &animData = animSet->animData[animSet->curAnimIndex];
+ int x = animData.x;
+ int y = animData.y;
+ int w = animData.w;
+ int h = animData.h;
+ int extra = animSet->extra;
+
+ if (whichNPCTalking == extra) {
+ talkNPC(animSet);
+ return;
+ }
+
+ int frameSize = animData.w * animData.h;
+ int curFrame = animData.curFrame;
+ byte *frame = new byte[frameSize];
+ extractSingleFrame(animData.animData, frame, curFrame, animData.w, animData.h);
+
+ drawSpriteToBuffer(_compositeBuffer, 640, frame, animSet->x, animSet->y, animSet->w, animSet->h, 255);
+
+ if (animData.elpapsedFrames == animData.speed) {
+ animData.elpapsedFrames = 0;
+ if (animData.curFrame < animData.nframes - 1) {
+ animData.curFrame++;
+ } else {
+ if (animData.curLoop < animData.loopCount - 1) {
+ animData.curFrame = 0;
+ animData.curLoop++;
+ } else {
+ animData.curFrame = 0;
+ animData.curLoop = 0;
+ if (animSet->curAnimIndex < animSet->numAnims - 1) {
+ animSet->curAnimIndex++;
+ } else {
+ animSet->curAnimIndex = 0;
+ }
+ }
+ }
+ } else {
+ animData.elpapsedFrames++;
+ }
+}
+
void PelrockEngine::checkLongMouseClick(int x, int y) {
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
if (hotspotIndex != -1) {
@@ -689,9 +690,10 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
}
-void PelrockEngine::talkNPC(AnimSet *animSet, int index) {
+void PelrockEngine::talkNPC(AnimSet *animSet) {
// Change with the right index
+ int index = animSet->index;
TalkinAnimHeader *animHeader = &_room->_talkingAnimHeader;
int x = animSet->x + (index ? animHeader->offsetXAnimB : animHeader->offsetXAnimA);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 4ef14515529..e88afc7063c 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -93,6 +93,7 @@ private:
void doAction(byte action, byte object);
void renderText(Common::Array<Common::String> lines, int color, int x, int y);
void drawAlfred(byte *buf);
+ void drawNextFrame(AnimSet *animSet);
void checkMouseHover();
void checkMouseClick(int x, int y);
void checkLongMouseClick(int x, int y);
@@ -101,7 +102,7 @@ private:
Exit *isExitUnder(int x, int y);
AnimSet *isSpriteUnder(int x, int y);
void showActionBalloon(int posx, int posy, int curFrame);
- void talkNPC(AnimSet *animSet, int index);
+ void talkNPC(AnimSet *animSet);
ChronoManager *_chronoManager = nullptr;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 0321fc19112..b201886d231 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -228,6 +228,7 @@ Common::Array<AnimSet> RoomManager::loadRoomAnimations(Common::File *roomFile, i
roomFile->seek(animOffset, SEEK_SET);
roomFile->read(animData, 44);
AnimSet animSet;
+ animSet.index = i;
animSet.x = animData[0] | (animData[1] << 8);
animSet.y = animData[2] | (animData[3] << 8);
animSet.w = animData[4];
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 0bb527b3469..b88e5f19e66 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -134,6 +134,7 @@ struct Exit {
};
struct AnimSet {
+ int index; // number of the animation in the rooms
byte type;
int x; // 0
int y; // 2
Commit: 89c6caf126b59fe2d5600120822d02c36895a88e
https://github.com/scummvm/scummvm/commit/89c6caf126b59fe2d5600120822d02c36895a88e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:11+02:00
Commit Message:
PELROCK: Refactor other resource loading
Changed paths:
A engines/pelrock/resources.cpp
engines/pelrock/module.mk
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index fdaf98bc630..a30d1632dd7 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -8,7 +8,8 @@ MODULE_OBJS = \
room.o \
fonts/small_font.o \
fonts/large_font.o \
- util.o
+ util.o \
+ resources.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 3444f3edbd6..e6bdc94d920 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -25,7 +25,7 @@
namespace Pelrock {
- uint32_t cursor_offsets[5] = {
+ static const uint32_t cursor_offsets[5] = {
0x0FDDFD,
0x0FDCDD,
0x0FDF1D,
@@ -33,8 +33,8 @@ namespace Pelrock {
0x367EF0
};
- uint32_t kBalloonFramesOffset = 2176936;
- uint32_t kBalloonFramesSize = 24950;
+ static const uint32_t kBalloonFramesOffset = 2176936;
+ static const uint32_t kBalloonFramesSize = 24950;
} // End of namespace Pelrock
#endif
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a680f6e56cb..a517c9f828f 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -228,107 +228,6 @@ void PelrockEngine::talk(byte object) {
// }
}
-void PelrockEngine::loadCursors() {
- Common::File alfred7File;
- if (!alfred7File.open("ALFRED.7")) {
- error("Couldnt find file ALFRED.7");
- }
- for (int i = 0; i < 5; i++) {
- uint32_t cursorOffset = cursor_offsets[i];
- alfred7File.seek(cursorOffset);
- _cursorMasks[i] = new byte[kCursorSize];
- alfred7File.read(_cursorMasks[i], kCursorSize);
- }
- alfred7File.close();
-}
-
-void PelrockEngine::loadInteractionIcons() {
- Common::File alfred7File;
- if (!alfred7File.open("ALFRED.7")) {
- error("Couldnt find file ALFRED.7");
- }
-
- alfred7File.seek(kBalloonFramesOffset, SEEK_SET);
-
- uint32_t totalBalloonSize = kBalloonWidth * kBalloonHeight * kBalloonFrames;
- _popUpBalloon = new byte[totalBalloonSize];
-
- uint32_t compressedSize = kBalloonFramesSize;
-
- byte *raw = new byte[compressedSize];
- alfred7File.read(raw, compressedSize);
- rleDecompress(raw, compressedSize, 0, compressedSize, &_popUpBalloon);
-
- delete[] raw;
-
- alfred7File.close();
- Common::File alfred4File;
- if (!alfred4File.open("ALFRED.4")) {
- error("Couldnt find file ALFRED.4");
- }
-
- int iconSize = kVerbIconHeight * kVerbIconWidth;
- for (int i = 0; i < kNumVerbIcons; i++) {
- uint32_t iconOffset = i * iconSize;
- _verbIcons[i] = new byte[iconSize];
- alfred4File.read(_verbIcons[i], iconSize);
- }
- alfred4File.close();
-}
-
-void PelrockEngine::loadAlfredAnims() {
- Common::File alfred3;
- if (!alfred3.open(Common::Path("ALFRED.3"))) {
- error("Could not open ALFRED.3");
- return;
- }
- int alfred3Size = alfred3.size();
- unsigned char *bufferFile = (unsigned char *)malloc(alfred3Size);
- alfred3.seek(0, SEEK_SET);
- alfred3.read(bufferFile, alfred3Size);
- alfred3.close();
-
- int index = 0;
- int index3 = 0;
- uint32_t capacity = 3060 * 102;
- unsigned char *pic = new unsigned char[capacity];
- rleDecompress(bufferFile, alfred3Size, 0, alfred3Size, &pic);
-
- for (int i = 0; i < 4; i++) {
- standingAnimFrames[i] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
- int talkingFramesOffset = walkingAnimLengths[0] + walkingAnimLengths[1] + walkingAnimLengths[2] + walkingAnimLengths[3] + 4;
-
- int prevWalkingFrames = 0;
- int prevTalkingFrames = 0;
-
- for (int j = 0; j < i; j++) {
- prevWalkingFrames += walkingAnimLengths[j] + 1;
- prevTalkingFrames += talkingAnimLengths[j];
- }
-
- walkingAnimFrames[i] = new byte *[walkingAnimLengths[i]];
-
- int standingFrame = prevWalkingFrames;
- debug("Loading standing frame %d at index %d", i, standingFrame);
- extractSingleFrame(pic, standingAnimFrames[i], standingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
- for (int j = 0; j < walkingAnimLengths[i]; j++) {
-
- walkingAnimFrames[i][j] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
- int walkingFrame = prevWalkingFrames + 1 + j;
- extractSingleFrame(pic, walkingAnimFrames[i][j], walkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
- }
-
- talkingAnimFrames[i] = new byte *[talkingAnimLengths[i]];
-
- int talkingStartFrame = talkingFramesOffset + prevTalkingFrames;
- for (int j = 0; j < talkingAnimLengths[i]; j++) {
- talkingAnimFrames[i][j] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
- int talkingFrame = talkingStartFrame + j;
- extractSingleFrame(pic, talkingAnimFrames[i][j], talkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
- }
- }
-}
-
byte *PelrockEngine::grabBackgroundSlice(int x, int y, int w, int h) {
byte *bg = new byte[w * h];
for (int j = 0; j < w; j++) {
@@ -660,19 +559,6 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
return nullptr;
}
-void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY) {
- for (int y = 0; y < surface->h; y++) {
- for (int x = 0; x < surface->w; x++) {
- int px = destX + x;
- int py = destY + y;
- if (px >= 0 && px < bufferWidth && py >= 0 && py < bufferHeight) {
- byte pixel = *((byte *)surface->getBasePtr(x, y));
- buffer[py * bufferWidth + px] = pixel;
- }
- }
- }
-}
-
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
@@ -1256,6 +1142,7 @@ void PelrockEngine::sayAlfred(Common::String text) {
_textPos = Common::Point(xAlfred, yAlfred - kAlfredFrameHeight - 10);
_chronoManager->_textTtl = totalChars * kTextCharDisplayTime;
}
+
bool isEndMarker(char char_byte) {
return char_byte == CHAR_END_MARKER_1 || char_byte == CHAR_END_MARKER_2 || char_byte == CHAR_END_MARKER_3 || char_byte == CHAR_END_MARKER_4;
}
@@ -1291,16 +1178,6 @@ int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
return wordLength;
}
-Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator) {
- Common::String result;
- for (uint i = 0; i < strings.size(); i++) {
- result += strings[i];
- if (i < strings.size() - 1)
- result += separator;
- }
- return result;
-}
-
Common::Array<Common::Array<Common::String> > wordWrap(Common::String text) {
Common::Array<Common::Array<Common::String> > pages;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
new file mode 100644
index 00000000000..163e307e88b
--- /dev/null
+++ b/engines/pelrock/resources.cpp
@@ -0,0 +1,127 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "pelrock/pelrock.h"
+#include "pelrock/offsets.h"
+#include "pelrock/util.h"
+
+namespace Pelrock {
+void PelrockEngine::loadCursors() {
+ Common::File alfred7File;
+ if (!alfred7File.open("ALFRED.7")) {
+ error("Couldnt find file ALFRED.7");
+ }
+ for (int i = 0; i < 5; i++) {
+ uint32_t cursorOffset = cursor_offsets[i];
+ alfred7File.seek(cursorOffset);
+ _cursorMasks[i] = new byte[kCursorSize];
+ alfred7File.read(_cursorMasks[i], kCursorSize);
+ }
+ alfred7File.close();
+}
+void PelrockEngine::loadInteractionIcons() {
+ Common::File alfred7File;
+ if (!alfred7File.open("ALFRED.7")) {
+ error("Couldnt find file ALFRED.7");
+ }
+
+ alfred7File.seek(kBalloonFramesOffset, SEEK_SET);
+
+ uint32_t totalBalloonSize = kBalloonWidth * kBalloonHeight * kBalloonFrames;
+ _popUpBalloon = new byte[totalBalloonSize];
+
+ uint32_t compressedSize = kBalloonFramesSize;
+
+ byte *raw = new byte[compressedSize];
+ alfred7File.read(raw, compressedSize);
+ rleDecompress(raw, compressedSize, 0, compressedSize, &_popUpBalloon);
+
+ delete[] raw;
+
+ alfred7File.close();
+ Common::File alfred4File;
+ if (!alfred4File.open("ALFRED.4")) {
+ error("Couldnt find file ALFRED.4");
+ }
+
+ int iconSize = kVerbIconHeight * kVerbIconWidth;
+ for (int i = 0; i < kNumVerbIcons; i++) {
+ uint32_t iconOffset = i * iconSize;
+ _verbIcons[i] = new byte[iconSize];
+ alfred4File.read(_verbIcons[i], iconSize);
+ }
+ alfred4File.close();
+}
+
+void PelrockEngine::loadAlfredAnims() {
+ Common::File alfred3;
+ if (!alfred3.open(Common::Path("ALFRED.3"))) {
+ error("Could not open ALFRED.3");
+ return;
+ }
+ int alfred3Size = alfred3.size();
+ unsigned char *bufferFile = (unsigned char *)malloc(alfred3Size);
+ alfred3.seek(0, SEEK_SET);
+ alfred3.read(bufferFile, alfred3Size);
+ alfred3.close();
+
+ int index = 0;
+ int index3 = 0;
+ uint32_t capacity = 3060 * 102;
+ unsigned char *pic = new unsigned char[capacity];
+ rleDecompress(bufferFile, alfred3Size, 0, alfred3Size, &pic);
+
+ for (int i = 0; i < 4; i++) {
+ standingAnimFrames[i] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
+ int talkingFramesOffset = walkingAnimLengths[0] + walkingAnimLengths[1] + walkingAnimLengths[2] + walkingAnimLengths[3] + 4;
+
+ int prevWalkingFrames = 0;
+ int prevTalkingFrames = 0;
+
+ for (int j = 0; j < i; j++) {
+ prevWalkingFrames += walkingAnimLengths[j] + 1;
+ prevTalkingFrames += talkingAnimLengths[j];
+ }
+
+ walkingAnimFrames[i] = new byte *[walkingAnimLengths[i]];
+
+ int standingFrame = prevWalkingFrames;
+ debug("Loading standing frame %d at index %d", i, standingFrame);
+ extractSingleFrame(pic, standingAnimFrames[i], standingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ for (int j = 0; j < walkingAnimLengths[i]; j++) {
+
+ walkingAnimFrames[i][j] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
+ int walkingFrame = prevWalkingFrames + 1 + j;
+ extractSingleFrame(pic, walkingAnimFrames[i][j], walkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ }
+
+ talkingAnimFrames[i] = new byte *[talkingAnimLengths[i]];
+
+ int talkingStartFrame = talkingFramesOffset + prevTalkingFrames;
+ for (int j = 0; j < talkingAnimLengths[i]; j++) {
+ talkingAnimFrames[i][j] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
+ int talkingFrame = talkingStartFrame + j;
+ extractSingleFrame(pic, talkingAnimFrames[i][j], talkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ }
+ }
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index c05d0e4a2a2..e59e7e54468 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -128,7 +128,6 @@ void drawSpriteToBuffer(byte *buffer, int bufferWidth,
}
}
-
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight) {
for (int y = 0; y < frameHeight; y++) {
for (int x = 0; x < frameWidth; x++) {
@@ -138,4 +137,13 @@ void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth
}
}
+Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator) {
+ Common::String result;
+ for (uint i = 0; i < strings.size(); i++) {
+ result += strings[i];
+ if (i < strings.size() - 1)
+ result += separator;
+ }
+ return result;
+}
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 1bda8ed6c8b..ee91d2e394e 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -21,9 +21,13 @@
#ifndef PELROCK_UTIL_H
#define PELROCK_UTIL_H
+#include "common/array.h"
+#include "common/stream.h"
#include "common/types.h"
#include "graphics/managed_surface.h"
#include "graphics/surface.h"
+
+
namespace Pelrock {
const int EXPECTED_SIZE = 640 * 400;
@@ -37,5 +41,6 @@ void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWid
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight);
void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
+Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
} // End of namespace Pelrock
#endif // PELROCK_UTIL_H
Commit: 07471b2029762b82cb3da43f6126850e4175ccf7
https://github.com/scummvm/scummvm/commit/07471b2029762b82cb3da43f6126850e4175ccf7
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:11+02:00
Commit Message:
PELROCK: Creates ResourceManager
Changed paths:
A engines/pelrock/resources.h
engines/pelrock/chrono.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index 8201dc15427..2b2eba5903a 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -36,7 +36,7 @@ ChronoManager::~ChronoManager() {
void ChronoManager::updateChrono() {
uint32 currentTime = g_system->getMillis();
- if(_textTtl > 0 && g_engine->isAlfredTalking && !g_engine->isAlfredWalking) {
+ if(_textTtl > 0 && g_engine->alfredState == ALFRED_TALKING && g_engine->alfredState != ALFRED_WALKING) {
_textTtl -= (currentTime - _lastTick);
if(_textTtl < 0)
_textTtl = 0;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a517c9f828f..9e35172d0e2 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -50,6 +50,7 @@ PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) :
g_engine = this;
_chronoManager = new ChronoManager();
_room = new RoomManager();
+ _res = new ResourceManager();
}
PelrockEngine::~PelrockEngine() {
@@ -59,27 +60,11 @@ PelrockEngine::~PelrockEngine() {
delete _largeFont;
delete _screen;
delete _chronoManager;
- for (int i = 0; i < 5; i++) {
- delete[] _cursorMasks[i];
- }
- for (int i = 0; i < kNumVerbIcons; i++) {
- delete[] _verbIcons[i];
- }
- delete[] _popUpBalloon;
// if (_bgPopupBalloon)
// delete[] _bgPopupBalloon;
delete _smallFont;
- for (int i = 0; i < 4; i++) {
-
- // free all frame buffers
- for (int j = 0; j < walkingAnimLengths[i]; j++) {
- delete[] walkingAnimFrames[i][j];
- }
- // free the array of pointers
- delete[] walkingAnimFrames[i];
- }
}
uint32 PelrockEngine::getFeatures() const {
@@ -122,31 +107,25 @@ Common::Error PelrockEngine::run() {
while (g_system->getEventManager()->pollEvent(e)) {
if (e.type == Common::EVENT_KEYDOWN) {
if (e.kbd.keycode == Common::KEYCODE_w) {
- isAlfredWalking = true;
- isAlfredTalking = false;
+ alfredState = ALFRED_WALKING;
} else if (e.kbd.keycode == Common::KEYCODE_t) {
- isAlfredWalking = false;
- isAlfredTalking = true;
+ alfredState = ALFRED_TALKING;
} else if (e.kbd.keycode == Common::KEYCODE_s) {
- isAlfredWalking = false;
- isAlfredTalking = false;
+ alfredState = ALFRED_IDLE;
}
} else if (e.type == Common::EVENT_MOUSEMOVE) {
mouseX = e.mouse.x;
mouseY = e.mouse.y;
// debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
} else if (e.type == Common::EVENT_LBUTTONDOWN) {
- debug("long button down");
if (!_isMouseDown) {
_mouseClickTime = g_system->getMillis();
_isMouseDown = true;
}
} else if (e.type == Common::EVENT_LBUTTONUP) {
_isMouseDown = false;
- // if (!_longClick) {
checkMouseClick(e.mouse.x, e.mouse.y);
_displayPopup = false;
- // }
_longClick = false;
}
}
@@ -170,8 +149,8 @@ Common::Error PelrockEngine::run() {
}
void PelrockEngine::init() {
- loadCursors();
- loadInteractionIcons();
+ _res->loadCursors();
+ _res->loadInteractionIcons();
_compositeBuffer = new byte[640 * 400];
_currentBackground = new byte[640 * 400];
@@ -183,6 +162,7 @@ void PelrockEngine::init() {
changeCursor(DEFAULT);
CursorMan.showMouse(true);
+
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
@@ -196,7 +176,7 @@ void PelrockEngine::playIntro() {
}
void PelrockEngine::loadAnims() {
- loadAlfredAnims();
+ _res->loadAlfredAnims();
}
void PelrockEngine::talk(byte object) {
@@ -299,7 +279,7 @@ void PelrockEngine::frames() {
drawNextFrame(&animSet);
}
- if (isAlfredWalking) {
+ if (alfredState == ALFRED_WALKING) {
MovementStep step = _currentContext.movement_buffer[_current_step];
// debug("Alfred step: distance_x=%d, distance_y=%d", step.distance_x, step.distance_y);
@@ -338,7 +318,7 @@ void PelrockEngine::frames() {
if (_current_step >= _currentContext.movement_count) {
// debug("Alfred reached his walk target.");
_current_step = 0;
- isAlfredWalking = false;
+ alfredState = ALFRED_IDLE;
}
} else {
_currentContext.movement_buffer[_current_step] = step;
@@ -354,21 +334,21 @@ void PelrockEngine::frames() {
// debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
- if (curAlfredFrame >= walkingAnimLengths[dirAlfred]) {
+ if (curAlfredFrame >= _res->walkingAnimLengths[dirAlfred]) {
curAlfredFrame = 0;
}
- drawAlfred(walkingAnimFrames[dirAlfred][curAlfredFrame]);
+ drawAlfred(_res->walkingAnimFrames[dirAlfred][curAlfredFrame]);
curAlfredFrame++;
- } else if (isAlfredTalking) {
- if (curAlfredFrame >= talkingAnimLengths[dirAlfred] - 1) {
+ } else if (alfredState == ALFRED_TALKING) {
+ if (curAlfredFrame >= _res->talkingAnimLengths[dirAlfred] - 1) {
curAlfredFrame = 0;
}
- drawAlfred(talkingAnimFrames[dirAlfred][curAlfredFrame]);
+ drawAlfred(_res->talkingAnimFrames[dirAlfred][curAlfredFrame]);
curAlfredFrame++;
} else {
- drawAlfred(standingAnimFrames[dirAlfred]);
+ drawAlfred(_res->standingAnimFrames[dirAlfred]);
}
if (_displayPopup) {
@@ -393,7 +373,7 @@ void PelrockEngine::frames() {
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- if (!isAlfredWalking && !_currentTextPages.empty()) {
+ if (alfredState != ALFRED_WALKING && !_currentTextPages.empty()) {
if (_chronoManager->_textTtl > 0) {
renderText(_currentTextPages[_currentTextPageIndex], _textColor, _textPos.x, _textPos.y);
} else if (_currentTextPageIndex < _currentTextPages.size() - 1) {
@@ -407,7 +387,7 @@ void PelrockEngine::frames() {
} else {
_currentTextPages.clear();
_currentTextPageIndex = 0;
- isAlfredTalking = false;
+ alfredState = ALFRED_IDLE;
isNPCATalking = false;
isNPCBTalking = false;
}
@@ -479,7 +459,7 @@ void PelrockEngine::drawNextFrame(AnimSet *animSet) {
int extra = animSet->extra;
if (whichNPCTalking == extra) {
- talkNPC(animSet);
+ drawTalkNPC(animSet);
return;
}
@@ -561,10 +541,10 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
- drawSpriteToBuffer(_compositeBuffer, 640, _popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->_popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
Common::Array<VerbIcons> actions = availableActions(_currentHotspot);
- drawSpriteToBuffer(_compositeBuffer, 640, _verbIcons[LOOK], posx + 20, posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[LOOK], posx + 20, posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
// Graphics::Surface rects;
// rects.create(kVerbIconWidth, kVerbIconHeight, Graphics::PixelFormat::createFormatCLUT8());
// drawRect(&rects, 0, 0, kVerbIconWidth, kVerbIconHeight, 255);
@@ -572,15 +552,15 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
// blitSurfaceToBuffer(&rects, _compositeBuffer, 640, 480, posx + ver, posy + 20);
for (int i = 0; i < actions.size(); i++) {
- drawSpriteToBuffer(_compositeBuffer, 640, _verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
}
-void PelrockEngine::talkNPC(AnimSet *animSet) {
+void PelrockEngine::drawTalkNPC(AnimSet *animSet) {
// Change with the right index
int index = animSet->index;
- TalkinAnimHeader *animHeader = &_room->_talkingAnimHeader;
+ TalkingAnimHeader *animHeader = &_room->_talkingAnimHeader;
int x = animSet->x + (index ? animHeader->offsetXAnimB : animHeader->offsetXAnimA);
int y = animSet->y + (index ? animHeader->offsetYAnimB : animHeader->offsetYAnimA);
@@ -604,7 +584,7 @@ void PelrockEngine::talkNPC(AnimSet *animSet) {
}
void PelrockEngine::walkTo(int x, int y) {
- isAlfredWalking = true;
+ alfredState = ALFRED_WALKING;
curAlfredFrame = 0;
PathContext context = {NULL, NULL, NULL, 0, 0, 0};
@@ -999,7 +979,7 @@ void PelrockEngine::checkMouseClick(int x, int y) {
}
void PelrockEngine::changeCursor(Cursor cursor) {
- CursorMan.replaceCursor(_cursorMasks[cursor], kCursorWidth, kCursorHeight, 0, 0, 255);
+ CursorMan.replaceCursor(_res->_cursorMasks[cursor], kCursorWidth, kCursorHeight, 0, 0, 255);
}
void PelrockEngine::checkMouseHover() {
@@ -1130,7 +1110,7 @@ void PelrockEngine::sayNPC(AnimSet *anim, Common::String text, byte color) {
}
void PelrockEngine::sayAlfred(Common::String text) {
- isAlfredTalking = true;
+ alfredState = ALFRED_TALKING;
curAlfredFrame = 0;
debug("Alfred says: %s", text.c_str());
_currentTextPages = wordWrap(text);
@@ -1265,8 +1245,7 @@ void PelrockEngine::setScreen(int number, int dir) {
return;
}
dirAlfred = dir;
- isAlfredWalking = false;
- isAlfredTalking = false;
+ alfredState = ALFRED_IDLE;
_current_step = 0;
int roomOffset = number * kRoomStructSize;
curAlfredFrame = 0;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index e88afc7063c..c27d002104e 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -40,6 +40,7 @@
#include "pelrock/detection.h"
#include "pelrock/fonts/large_font.h"
#include "pelrock/fonts/small_font.h"
+#include "pelrock/resources.h"
#include "pelrock/room.h"
#include "pelrock/types.h"
@@ -54,6 +55,9 @@ class PelrockEngine : public Engine {
private:
const ADGameDescription *_gameDescription;
Common::RandomSource _randomSource;
+ ChronoManager *_chronoManager = nullptr;
+ RoomManager *_room = nullptr;
+ ResourceManager *_res = nullptr;
void init();
void playIntro();
@@ -61,8 +65,6 @@ private:
void setScreenJava(int s, int dir);
void loadAnims();
- void loadAlfredAnims();
-
void walkTo(int x, int y);
bool pathFind(int x, int y, PathContext *context);
uint8_t find_walkbox_for_point(uint16_t x, uint16_t y);
@@ -77,8 +79,6 @@ private:
MovementStep *movement_buffer);
void talk(byte object);
- void loadCursors();
- void loadInteractionIcons();
byte *grabBackgroundSlice(int x, int y, int w, int h);
void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
@@ -88,64 +88,57 @@ private:
void sayAlfred(Common::String text);
void sayNPC(AnimSet *anim, Common::String text, byte color);
- // render loop
+
void frames();
void doAction(byte action, byte object);
void renderText(Common::Array<Common::String> lines, int color, int x, int y);
void drawAlfred(byte *buf);
void drawNextFrame(AnimSet *animSet);
- void checkMouseHover();
- void checkMouseClick(int x, int y);
- void checkLongMouseClick(int x, int y);
void changeCursor(Cursor cursor);
int isHotspotUnder(int x, int y);
Exit *isExitUnder(int x, int y);
AnimSet *isSpriteUnder(int x, int y);
void showActionBalloon(int posx, int posy, int curFrame);
- void talkNPC(AnimSet *animSet);
-
- ChronoManager *_chronoManager = nullptr;
+ void drawTalkNPC(AnimSet *animSet);
- byte **walkingAnimFrames[4]; // 4 arrays of arrays
- byte *standingAnimFrames[4] = {nullptr}; // 4 directions
- int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
- byte **talkingAnimFrames[4]; // 4 arrays of arrays
- int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+ void checkMouseHover();
+ void checkMouseClick(int x, int y);
+ void checkLongMouseClick(int x, int y);
- PathContext _currentContext;
+ //walking
int _current_step = 0;
+ PathContext _currentContext;
+ //text display
byte _textColor = 0;
Common::Point _textPos;
Common::Array<Common::Array<Common::String> > _currentTextPages = Common::Array<Common::Array<Common::String> >();
int _currentTextPageIndex = 0;
- int *_currentAnimFrames = nullptr;
- // From the original code
+
+ // Alfred
int xAlfred = 319;
int yAlfred = 302;
int dirAlfred = 0;
int curAlfredFrame = 0;
+
uint16 mouseX = 0;
uint16 mouseY = 0;
- byte *_cursorMasks[5] = {nullptr};
-
+ bool _lMouseDown = false;
uint32 _mouseClickTime;
bool _isMouseDown = false;
bool _longClick = false;
- byte *_verbIcons[9] = {nullptr};
- byte *_popUpBalloon = nullptr;
- byte *_currentBackground; // Clean background - NEVER modified
+ byte *_currentBackground = nullptr; // Clean background - NEVER modified
byte *_compositeBuffer; // Working composition buffer
- bool _lMouseDown = false;
bool _displayPopup = false;
int _popupX = 0;
int _popupY = 0;
int _currentPopupFrame = 0;
+
HotSpot *_currentHotspot = nullptr;
SmallFont *_smallFont = nullptr;
@@ -168,7 +161,6 @@ private:
// int whichScreen = 0;
// byte *pixelsShadows; // =new int[640*400];
- RoomManager *_room = nullptr;
protected:
// Engine APIs
@@ -176,9 +168,7 @@ protected:
public:
Graphics::Screen *_screen = nullptr;
- bool isAlfredWalking = false;
- bool isAlfredTalking = false;
-
+ AlfredState alfredState = ALFRED_IDLE;
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
~PelrockEngine() override;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 163e307e88b..1cb5ebdf8b2 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -19,12 +19,37 @@
*
*/
-#include "pelrock/pelrock.h"
+#include "pelrock/resources.h"
#include "pelrock/offsets.h"
+#include "pelrock/pelrock.h"
#include "pelrock/util.h"
namespace Pelrock {
-void PelrockEngine::loadCursors() {
+
+ResourceManager::ResourceManager(/* args */) {
+}
+
+ResourceManager::~ResourceManager() {
+ for (int i = 0; i < 5; i++) {
+ delete[] _cursorMasks[i];
+ }
+ for (int i = 0; i < kNumVerbIcons; i++) {
+ delete[] _verbIcons[i];
+ }
+ delete[] _popUpBalloon;
+ for (int i = 0; i < 4; i++) {
+
+ // free all frame buffers
+ for (int j = 0; j < walkingAnimLengths[i]; j++) {
+ delete[] walkingAnimFrames[i][j];
+ }
+
+ // free the array of pointers
+ delete[] walkingAnimFrames[i];
+ }
+}
+
+void ResourceManager::loadCursors() {
Common::File alfred7File;
if (!alfred7File.open("ALFRED.7")) {
error("Couldnt find file ALFRED.7");
@@ -37,7 +62,7 @@ void PelrockEngine::loadCursors() {
}
alfred7File.close();
}
-void PelrockEngine::loadInteractionIcons() {
+void ResourceManager::loadInteractionIcons() {
Common::File alfred7File;
if (!alfred7File.open("ALFRED.7")) {
error("Couldnt find file ALFRED.7");
@@ -71,7 +96,7 @@ void PelrockEngine::loadInteractionIcons() {
alfred4File.close();
}
-void PelrockEngine::loadAlfredAnims() {
+void ResourceManager::loadAlfredAnims() {
Common::File alfred3;
if (!alfred3.open(Common::Path("ALFRED.3"))) {
error("Could not open ALFRED.3");
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
new file mode 100644
index 00000000000..a1e240055da
--- /dev/null
+++ b/engines/pelrock/resources.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_RESOURCES_H
+#define PELROCK_RESOURCES_H
+
+ #include "common/scummsys.h"
+
+namespace Pelrock {
+
+class ResourceManager {
+private:
+ /* data */
+public:
+ ResourceManager(/* args */);
+ ~ResourceManager();
+
+ void loadCursors();
+ void loadInteractionIcons();
+ void loadAlfredAnims();
+
+ byte **walkingAnimFrames[4]; // 4 arrays of arrays
+ byte *standingAnimFrames[4] = {nullptr}; // 4 directions
+ int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+ byte **talkingAnimFrames[4]; // 4 arrays of arrays
+ int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+ byte *_cursorMasks[5] = {nullptr};
+ byte *_verbIcons[9] = {nullptr};
+ byte *_popUpBalloon = nullptr;
+};
+
+
+} // End of namespace Pelrock
+#endif
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index b201886d231..3b5a3c84deb 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -398,7 +398,7 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
int headerIndex = roomNumber;
uint32 offset = kTalkingAnimHeaderSize * headerIndex;
- TalkinAnimHeader talkHeader;
+ TalkingAnimHeader talkHeader;
Common::File talkFile;
if (!talkFile.open("ALFRED.2")) {
error("Couldnt find file ALFRED.2");
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 311c7bc66b0..10553071ea3 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -18,8 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
-#ifndef PELROCK_RESOURCES_H
-#define PELROCK_RESOURCES_H
+#ifndef PELROCK_ROOM_H
+#define PELROCK_ROOM_H
#include "common/array.h"
#include "common/file.h"
@@ -44,7 +44,7 @@ public:
Common::Array<WalkBox> _currentRoomWalkboxes;
Common::Array<Description> _currentRoomDescriptions;
Common::Array<ConversationNode> _currentRoomConversations;
- TalkinAnimHeader _talkingAnimHeader;
+ TalkingAnimHeader _talkingAnimHeader;
private:
Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index b88e5f19e66..8c02104b280 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -63,6 +63,15 @@ const int kBalloonFrames = 4;
const int kTextCharDisplayTime = 100; // 10ms per character
const int kVerbIconPadding = 20;
+
+enum AlfredState {
+ ALFRED_IDLE,
+ ALFRED_WALKING,
+ ALFRED_TALKING,
+ ALFRED_INTERACTING,
+};
+
+
// Direction flags (bit-packed)
#define MOVE_RIGHT 0x01 // Move right (positive X)
#define MOVE_LEFT 0x02 // Move left (negative X)
@@ -161,7 +170,7 @@ struct HotSpot {
bool isEnabled = true;
};
-struct TalkinAnimHeader {
+struct TalkingAnimHeader {
uint32 spritePointer;
byte unknown2[3];
Commit: 321e4012568784061893b047b03dca2c3c92bfc3
https://github.com/scummvm/scummvm/commit/321e4012568784061893b047b03dca2c3c92bfc3
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:11+02:00
Commit Message:
PELROCK: Comb animation
Changed paths:
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/types.h
engines/pelrock/util.cpp
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index e6bdc94d920..577613b2d31 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -36,6 +36,11 @@ namespace Pelrock {
static const uint32_t kBalloonFramesOffset = 2176936;
static const uint32_t kBalloonFramesSize = 24950;
+ static const uint32_t ALFRED7_ALFRED_COMB_R = 67764;
+ static const uint32_t ALFRED7_ALFRED_COMB_L = 88404;
+
+
+
} // End of namespace Pelrock
#endif
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 9e35172d0e2..58abc31d2c4 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -112,6 +112,8 @@ Common::Error PelrockEngine::run() {
alfredState = ALFRED_TALKING;
} else if (e.kbd.keycode == Common::KEYCODE_s) {
alfredState = ALFRED_IDLE;
+ } else if (e.kbd.keycode == Common::KEYCODE_c) {
+ alfredState = ALFRED_COMB;
}
} else if (e.type == Common::EVENT_MOUSEMOVE) {
mouseX = e.mouse.x;
@@ -338,17 +340,24 @@ void PelrockEngine::frames() {
curAlfredFrame = 0;
}
- drawAlfred(_res->walkingAnimFrames[dirAlfred][curAlfredFrame]);
+ drawAlfred(_res->alfredWalkFrames[dirAlfred][curAlfredFrame]);
curAlfredFrame++;
} else if (alfredState == ALFRED_TALKING) {
if (curAlfredFrame >= _res->talkingAnimLengths[dirAlfred] - 1) {
curAlfredFrame = 0;
}
- drawAlfred(_res->talkingAnimFrames[dirAlfred][curAlfredFrame]);
+ drawAlfred(_res->alfredTalkFrames[dirAlfred][curAlfredFrame]);
curAlfredFrame++;
+ } else if (alfredState == ALFRED_COMB) {
+ if (curAlfredFrame >= 11) {
+ curAlfredFrame = 0;
+ }
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[0][curAlfredFrame], xAlfred, yAlfred - kAlfredFrameHeight, 51, 102, 255);
+ curAlfredFrame++;
+
} else {
- drawAlfred(_res->standingAnimFrames[dirAlfred]);
+ drawAlfred(_res->alfredIdle[dirAlfred]);
}
if (_displayPopup) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index c27d002104e..abef2134ece 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -48,9 +48,6 @@ namespace Pelrock {
struct PelrockGameDescription;
-const int kAlfredFrameWidth = 51;
-const int kAlfredFrameHeight = 102;
-
class PelrockEngine : public Engine {
private:
const ADGameDescription *_gameDescription;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 1cb5ebdf8b2..60e12f573ef 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -41,11 +41,11 @@ ResourceManager::~ResourceManager() {
// free all frame buffers
for (int j = 0; j < walkingAnimLengths[i]; j++) {
- delete[] walkingAnimFrames[i][j];
+ delete[] alfredWalkFrames[i][j];
}
// free the array of pointers
- delete[] walkingAnimFrames[i];
+ delete[] alfredWalkFrames[i];
}
}
@@ -114,8 +114,9 @@ void ResourceManager::loadAlfredAnims() {
unsigned char *pic = new unsigned char[capacity];
rleDecompress(bufferFile, alfred3Size, 0, alfred3Size, &pic);
+ int frameSize = kAlfredFrameHeight * kAlfredFrameWidth;
for (int i = 0; i < 4; i++) {
- standingAnimFrames[i] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
+ alfredIdle[i] = new byte[frameSize];
int talkingFramesOffset = walkingAnimLengths[0] + walkingAnimLengths[1] + walkingAnimLengths[2] + walkingAnimLengths[3] + 4;
int prevWalkingFrames = 0;
@@ -126,27 +127,66 @@ void ResourceManager::loadAlfredAnims() {
prevTalkingFrames += talkingAnimLengths[j];
}
- walkingAnimFrames[i] = new byte *[walkingAnimLengths[i]];
+ alfredWalkFrames[i] = new byte *[walkingAnimLengths[i]];
int standingFrame = prevWalkingFrames;
debug("Loading standing frame %d at index %d", i, standingFrame);
- extractSingleFrame(pic, standingAnimFrames[i], standingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ extractSingleFrame(pic, alfredIdle[i], standingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
for (int j = 0; j < walkingAnimLengths[i]; j++) {
- walkingAnimFrames[i][j] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
+ alfredWalkFrames[i][j] = new byte[frameSize];
int walkingFrame = prevWalkingFrames + 1 + j;
- extractSingleFrame(pic, walkingAnimFrames[i][j], walkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ extractSingleFrame(pic, alfredWalkFrames[i][j], walkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
}
- talkingAnimFrames[i] = new byte *[talkingAnimLengths[i]];
+ alfredTalkFrames[i] = new byte *[talkingAnimLengths[i]];
int talkingStartFrame = talkingFramesOffset + prevTalkingFrames;
for (int j = 0; j < talkingAnimLengths[i]; j++) {
- talkingAnimFrames[i][j] = new byte[kAlfredFrameWidth * kAlfredFrameHeight];
+ alfredTalkFrames[i][j] = new byte[frameSize];
int talkingFrame = talkingStartFrame + j;
- extractSingleFrame(pic, talkingAnimFrames[i][j], talkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ extractSingleFrame(pic, alfredTalkFrames[i][j], talkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
}
}
+
+ free(bufferFile);
+
+ Common::File alfred7;
+ if (!alfred7.open(Common::Path("ALFRED.7"))) {
+ error("Could not open ALFRED.7");
+ return;
+ }
+ int spriteMapSize = frameSize * 11;
+ byte *alfredCombRightRaw;
+ size_t alfredCombRightSize;
+
+ readUntilBuda(&alfred7, ALFRED7_ALFRED_COMB_R, alfredCombRightRaw, alfredCombRightSize);
+ byte *alfredCombRight = nullptr;
+ rleDecompress(alfredCombRightRaw, alfredCombRightSize, 0, alfredCombRightSize, &alfredCombRight);
+
+ alfredCombFrames[0] = new byte *[11];
+ alfredCombFrames[1] = new byte *[11];
+
+ for (int i = 0; i < 11; i++) {
+
+ alfredCombFrames[0][i] = new byte[frameSize];
+ extractSingleFrame(alfredCombRight, alfredCombFrames[0][i], i, kAlfredFrameWidth, kAlfredFrameHeight);
+ }
+
+ byte *alfredCombLeftRaw;
+ size_t alfredCombLeftSize;
+ readUntilBuda(&alfred7, ALFRED7_ALFRED_COMB_L, alfredCombLeftRaw, alfredCombLeftSize);
+ byte *alfredCombLeft = nullptr;
+ rleDecompress(alfredCombLeftRaw, alfredCombLeftSize, 0, spriteMapSize, &alfredCombLeft);
+
+ for (int i = 0; i < 11; i++) {
+ alfredCombFrames[1][i] = new byte[frameSize];
+ extractSingleFrame(alfredCombLeft, alfredCombFrames[1][i], i, kAlfredFrameWidth, kAlfredFrameHeight);
+ }
+
+ alfred7.close();
+ free(alfredCombRightRaw);
+ free(alfredCombLeftRaw);
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index a1e240055da..cab57604def 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -36,11 +36,14 @@ public:
void loadInteractionIcons();
void loadAlfredAnims();
- byte **walkingAnimFrames[4]; // 4 arrays of arrays
- byte *standingAnimFrames[4] = {nullptr}; // 4 directions
+ byte **alfredWalkFrames[4]; // 4 arrays of arrays
+ byte *alfredIdle[4] = {nullptr}; // 4 directions
int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
- byte **talkingAnimFrames[4]; // 4 arrays of arrays
+ byte **alfredTalkFrames[4]; // 4 arrays of arrays
int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+ byte **alfredCombFrames[2];
+
+
byte *_cursorMasks[5] = {nullptr};
byte *_verbIcons[9] = {nullptr};
byte *_popUpBalloon = nullptr;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 8c02104b280..6fd46cfddfe 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -63,12 +63,17 @@ const int kBalloonFrames = 4;
const int kTextCharDisplayTime = 100; // 10ms per character
const int kVerbIconPadding = 20;
+const int kAlfredFrameWidth = 51;
+const int kAlfredFrameHeight = 102;
+
+
enum AlfredState {
ALFRED_IDLE,
ALFRED_WALKING,
ALFRED_TALKING,
ALFRED_INTERACTING,
+ ALFRED_COMB
};
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index e59e7e54468..b3633c300ea 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -68,6 +68,7 @@ size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uin
uint8_t value = data[pos + 1];
for (int i = 0; i < count; i++) {
+ // debug("Pos = %zu, writing value %02X", result_size, value);
(*out_data)[result_size++] = value;
}
@@ -102,6 +103,7 @@ void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *
break;
}
}
+ debug("Read %zu bytes until BUDA marker", pos);
outSize = pos;
}
Commit: 04a7b8c2c4818dc46e8b54778b31dd48cb8dd93a
https://github.com/scummvm/scummvm/commit/04a7b8c2c4818dc46e8b54778b31dd48cb8dd93a
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:12+02:00
Commit Message:
PELROCK: Alfred interacting animation
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/resources.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 58abc31d2c4..f2a723086cd 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -64,7 +64,6 @@ PelrockEngine::~PelrockEngine() {
// if (_bgPopupBalloon)
// delete[] _bgPopupBalloon;
delete _smallFont;
-
}
uint32 PelrockEngine::getFeatures() const {
@@ -114,6 +113,8 @@ Common::Error PelrockEngine::run() {
alfredState = ALFRED_IDLE;
} else if (e.kbd.keycode == Common::KEYCODE_c) {
alfredState = ALFRED_COMB;
+ } else if (e.kbd.keycode == Common::KEYCODE_i) {
+ alfredState = ALFRED_INTERACTING;
}
} else if (e.type == Common::EVENT_MOUSEMOVE) {
mouseX = e.mouse.x;
@@ -336,7 +337,7 @@ void PelrockEngine::frames() {
// debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
- if (curAlfredFrame >= _res->walkingAnimLengths[dirAlfred]) {
+ if (curAlfredFrame >= walkingAnimLengths[dirAlfred]) {
curAlfredFrame = 0;
}
@@ -344,7 +345,7 @@ void PelrockEngine::frames() {
curAlfredFrame++;
} else if (alfredState == ALFRED_TALKING) {
- if (curAlfredFrame >= _res->talkingAnimLengths[dirAlfred] - 1) {
+ if (curAlfredFrame >= talkingAnimLengths[dirAlfred] - 1) {
curAlfredFrame = 0;
}
drawAlfred(_res->alfredTalkFrames[dirAlfred][curAlfredFrame]);
@@ -356,7 +357,14 @@ void PelrockEngine::frames() {
drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[0][curAlfredFrame], xAlfred, yAlfred - kAlfredFrameHeight, 51, 102, 255);
curAlfredFrame++;
- } else {
+ } else if(alfredState == ALFRED_INTERACTING) {
+ if (curAlfredFrame >= interactingAnimLength) {
+ curAlfredFrame = 0;
+ }
+ drawAlfred(_res->alfredInteractFrames[dirAlfred][curAlfredFrame]);
+ curAlfredFrame++;
+ }
+ else {
drawAlfred(_res->alfredIdle[dirAlfred]);
}
if (_displayPopup) {
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 60e12f573ef..c131921fc27 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -38,15 +38,25 @@ ResourceManager::~ResourceManager() {
}
delete[] _popUpBalloon;
for (int i = 0; i < 4; i++) {
-
// free all frame buffers
for (int j = 0; j < walkingAnimLengths[i]; j++) {
delete[] alfredWalkFrames[i][j];
+ delete[] alfredTalkFrames[i][j];
+ }
+
+ for(int j = 0; j < 4; j ++) {
+ delete[] alfredInteractFrames[i][j];
}
// free the array of pointers
delete[] alfredWalkFrames[i];
+ delete[] alfredTalkFrames[i];
+ delete[] alfredInteractFrames[i];
+ delete[] alfredIdle[i];
}
+
+ delete[] alfredCombFrames[0];
+ delete[] alfredCombFrames[1];
}
void ResourceManager::loadCursors() {
@@ -118,13 +128,15 @@ void ResourceManager::loadAlfredAnims() {
for (int i = 0; i < 4; i++) {
alfredIdle[i] = new byte[frameSize];
int talkingFramesOffset = walkingAnimLengths[0] + walkingAnimLengths[1] + walkingAnimLengths[2] + walkingAnimLengths[3] + 4;
-
+ int interactingFramesOffset = talkingFramesOffset + talkingAnimLengths[0] + talkingAnimLengths[1] + talkingAnimLengths[2] + talkingAnimLengths[3];
int prevWalkingFrames = 0;
int prevTalkingFrames = 0;
+ int prevInteractingFrames = 0;
for (int j = 0; j < i; j++) {
prevWalkingFrames += walkingAnimLengths[j] + 1;
prevTalkingFrames += talkingAnimLengths[j];
+ prevInteractingFrames += interactingAnimLength;
}
alfredWalkFrames[i] = new byte *[walkingAnimLengths[i]];
@@ -147,6 +159,15 @@ void ResourceManager::loadAlfredAnims() {
int talkingFrame = talkingStartFrame + j;
extractSingleFrame(pic, alfredTalkFrames[i][j], talkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
}
+
+ alfredInteractFrames[i] = new byte *[interactingAnimLength];
+ int interactingStartFrame = interactingFramesOffset + prevInteractingFrames;
+ for (int j = 0; j < interactingAnimLength; j++) {
+ alfredInteractFrames[i][j] = new byte[frameSize];
+ int interactingFrame = interactingStartFrame + j;
+ extractSingleFrame(pic, alfredInteractFrames[i][j], interactingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ }
+
}
free(bufferFile);
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index cab57604def..bfa3b60efd1 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -25,6 +25,11 @@
namespace Pelrock {
+
+static const int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+static const int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+static const int interactingAnimLength = 2;
+
class ResourceManager {
private:
/* data */
@@ -36,13 +41,14 @@ public:
void loadInteractionIcons();
void loadAlfredAnims();
- byte **alfredWalkFrames[4]; // 4 arrays of arrays
byte *alfredIdle[4] = {nullptr}; // 4 directions
- int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
+
+ byte **alfredWalkFrames[4]; // 4 arrays of arrays
+
byte **alfredTalkFrames[4]; // 4 arrays of arrays
- int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
- byte **alfredCombFrames[2];
+ byte **alfredCombFrames[2];
+ byte **alfredInteractFrames[4];
byte *_cursorMasks[5] = {nullptr};
byte *_verbIcons[9] = {nullptr};
Commit: aaeac0248fb759859ccc8444377cb7a819431c52
https://github.com/scummvm/scummvm/commit/aaeac0248fb759859ccc8444377cb7a819431c52
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:12+02:00
Commit Message:
PELROCK: Turn if into switch when handling alfred state
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f2a723086cd..0f0e6516ac9 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -105,18 +105,26 @@ Common::Error PelrockEngine::run() {
_chronoManager->updateChrono();
while (g_system->getEventManager()->pollEvent(e)) {
if (e.type == Common::EVENT_KEYDOWN) {
- if (e.kbd.keycode == Common::KEYCODE_w) {
- alfredState = ALFRED_WALKING;
- } else if (e.kbd.keycode == Common::KEYCODE_t) {
- alfredState = ALFRED_TALKING;
- } else if (e.kbd.keycode == Common::KEYCODE_s) {
- alfredState = ALFRED_IDLE;
- } else if (e.kbd.keycode == Common::KEYCODE_c) {
- alfredState = ALFRED_COMB;
- } else if (e.kbd.keycode == Common::KEYCODE_i) {
- alfredState = ALFRED_INTERACTING;
- }
- } else if (e.type == Common::EVENT_MOUSEMOVE) {
+ switch (e.kbd.keycode) {
+ case Common::KEYCODE_w:
+ alfredState = ALFRED_WALKING;
+ break;
+ case Common::KEYCODE_t:
+ alfredState = ALFRED_TALKING;
+ break;
+ case Common::KEYCODE_s:
+ alfredState = ALFRED_IDLE;
+ break;
+ case Common::KEYCODE_c:
+ alfredState = ALFRED_COMB;
+ break;
+ case Common::KEYCODE_i:
+ alfredState = ALFRED_INTERACTING;
+ break;
+ default:
+ break;
+ }
+ } else if (e.type == Common::EVENT_MOUSEMOVE) {
mouseX = e.mouse.x;
mouseY = e.mouse.y;
// debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
@@ -282,91 +290,88 @@ void PelrockEngine::frames() {
drawNextFrame(&animSet);
}
- if (alfredState == ALFRED_WALKING) {
-
- MovementStep step = _currentContext.movement_buffer[_current_step];
- // debug("Alfred step: distance_x=%d, distance_y=%d", step.distance_x, step.distance_y);
-
- if (step.distance_x > 0) {
- if (step.flags & MOVE_RIGHT) {
- dirAlfred = 0;
- xAlfred += MIN((uint16_t)6, step.distance_x);
- }
- if (step.flags & MOVE_LEFT) {
- dirAlfred = 1;
- xAlfred -= MIN((uint16_t)6, step.distance_x);
- }
- }
- if (step.distance_y > 0) {
- if (step.flags & MOVE_DOWN) {
- dirAlfred = 2;
- yAlfred += MIN((uint16_t)6, step.distance_y);
- }
- if (step.flags & MOVE_UP) {
- dirAlfred = 3;
- yAlfred -= MIN((uint16_t)6, step.distance_y);
- }
- }
-
- if (step.distance_x > 0)
- step.distance_x -= MIN((uint16_t)6, step.distance_x);
-
- if (step.distance_y > 0)
- step.distance_y -= MIN((uint16_t)6, step.distance_y);
-
- // debug("Alfred position after step: x=%d, y=%d, step distance_x=%d, step distance_y=%d", xAlfred, yAlfred, step.distance_x, step.distance_y);
- if (step.distance_x <= 0 && step.distance_y <= 0) {
- // debug("Alfred completed step %d", _current_step);
- _current_step++;
- if (_current_step >= _currentContext.movement_count) {
- // debug("Alfred reached his walk target.");
- _current_step = 0;
- alfredState = ALFRED_IDLE;
- }
- } else {
- _currentContext.movement_buffer[_current_step] = step;
- }
-
- Exit *exit = isExitUnder(xAlfred, yAlfred);
-
- if (exit != nullptr) {
- xAlfred = exit->targetX;
- yAlfred = exit->targetY;
- setScreen(exit->targetRoom, exit->dir);
- }
-
- // debug("Drawing walking frame %d for direction %d", curAlfredFrame, dirAlfred);
-
- if (curAlfredFrame >= walkingAnimLengths[dirAlfred]) {
- curAlfredFrame = 0;
- }
-
- drawAlfred(_res->alfredWalkFrames[dirAlfred][curAlfredFrame]);
- curAlfredFrame++;
-
- } else if (alfredState == ALFRED_TALKING) {
- if (curAlfredFrame >= talkingAnimLengths[dirAlfred] - 1) {
- curAlfredFrame = 0;
- }
- drawAlfred(_res->alfredTalkFrames[dirAlfred][curAlfredFrame]);
- curAlfredFrame++;
- } else if (alfredState == ALFRED_COMB) {
- if (curAlfredFrame >= 11) {
- curAlfredFrame = 0;
- }
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[0][curAlfredFrame], xAlfred, yAlfred - kAlfredFrameHeight, 51, 102, 255);
- curAlfredFrame++;
-
- } else if(alfredState == ALFRED_INTERACTING) {
- if (curAlfredFrame >= interactingAnimLength) {
- curAlfredFrame = 0;
- }
- drawAlfred(_res->alfredInteractFrames[dirAlfred][curAlfredFrame]);
- curAlfredFrame++;
- }
- else {
- drawAlfred(_res->alfredIdle[dirAlfred]);
- }
+ switch (alfredState) {
+ case ALFRED_WALKING: {
+ MovementStep step = _currentContext.movement_buffer[_current_step];
+
+ if (step.distance_x > 0) {
+ if (step.flags & MOVE_RIGHT) {
+ dirAlfred = 0;
+ xAlfred += MIN((uint16_t)6, step.distance_x);
+ }
+ if (step.flags & MOVE_LEFT) {
+ dirAlfred = 1;
+ xAlfred -= MIN((uint16_t)6, step.distance_x);
+ }
+ }
+ if (step.distance_y > 0) {
+ if (step.flags & MOVE_DOWN) {
+ dirAlfred = 2;
+ yAlfred += MIN((uint16_t)6, step.distance_y);
+ }
+ if (step.flags & MOVE_UP) {
+ dirAlfred = 3;
+ yAlfred -= MIN((uint16_t)6, step.distance_y);
+ }
+ }
+
+ if (step.distance_x > 0)
+ step.distance_x -= MIN((uint16_t)6, step.distance_x);
+
+ if (step.distance_y > 0)
+ step.distance_y -= MIN((uint16_t)6, step.distance_y);
+
+ if (step.distance_x <= 0 && step.distance_y <= 0) {
+ _current_step++;
+ if (_current_step >= _currentContext.movement_count) {
+ _current_step = 0;
+ alfredState = ALFRED_IDLE;
+ }
+ } else {
+ _currentContext.movement_buffer[_current_step] = step;
+ }
+
+ Exit *exit = isExitUnder(xAlfred, yAlfred);
+
+ if (exit != nullptr) {
+ xAlfred = exit->targetX;
+ yAlfred = exit->targetY;
+ setScreen(exit->targetRoom, exit->dir);
+ }
+
+ if (curAlfredFrame >= walkingAnimLengths[dirAlfred]) {
+ curAlfredFrame = 0;
+ }
+
+ drawAlfred(_res->alfredWalkFrames[dirAlfred][curAlfredFrame]);
+ curAlfredFrame++;
+ break;
+ }
+ case ALFRED_TALKING:
+ if (curAlfredFrame >= talkingAnimLengths[dirAlfred] - 1) {
+ curAlfredFrame = 0;
+ }
+ drawAlfred(_res->alfredTalkFrames[dirAlfred][curAlfredFrame]);
+ curAlfredFrame++;
+ break;
+ case ALFRED_COMB:
+ if (curAlfredFrame >= 11) {
+ curAlfredFrame = 0;
+ }
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[0][curAlfredFrame], xAlfred, yAlfred - kAlfredFrameHeight, 51, 102, 255);
+ curAlfredFrame++;
+ break;
+ case ALFRED_INTERACTING:
+ if (curAlfredFrame >= interactingAnimLength) {
+ curAlfredFrame = 0;
+ }
+ drawAlfred(_res->alfredInteractFrames[dirAlfred][curAlfredFrame]);
+ curAlfredFrame++;
+ break;
+ default:
+ drawAlfred(_res->alfredIdle[dirAlfred]);
+ break;
+ }
if (_displayPopup) {
// byte *bgDialog = new byte[kBalloonWidth * kBalloonHeight];
@@ -414,7 +419,7 @@ void PelrockEngine::frames() {
for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
// debug("Drawing walkbox %d", i);
WalkBox box = _room->_currentRoomWalkboxes[i];
- // drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
+ drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
}
if (_curWalkTarget.x < 640 && _curWalkTarget.y < 400 && _curWalkTarget.x >= 0 && _curWalkTarget.y >= 0) {
_screen->setPixel(_curWalkTarget.x, _curWalkTarget.y, 100);
Commit: 3226b5217a173fc6a2cac54a384b0263382c9e14
https://github.com/scummvm/scummvm/commit/3226b5217a173fc6a2cac54a384b0263382c9e14
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:12+02:00
Commit Message:
PELROCK: Initial Intro video playback
Changed paths:
A engines/pelrock/video/video.cpp
A engines/pelrock/video/video.h
engines/pelrock/chrono.cpp
engines/pelrock/chrono.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index 2b2eba5903a..306e38c1ca9 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -22,6 +22,7 @@
#include "common/events.h"
#include "common/system.h"
+#include "chrono.h"
#include "pelrock/chrono.h"
#include "pelrock/pelrock.h"
@@ -36,9 +37,9 @@ ChronoManager::~ChronoManager() {
void ChronoManager::updateChrono() {
uint32 currentTime = g_system->getMillis();
- if(_textTtl > 0 && g_engine->alfredState == ALFRED_TALKING && g_engine->alfredState != ALFRED_WALKING) {
+ if (_textTtl > 0 && g_engine->alfredState == ALFRED_TALKING && g_engine->alfredState != ALFRED_WALKING) {
_textTtl -= (currentTime - _lastTick);
- if(_textTtl < 0)
+ if (_textTtl < 0)
_textTtl = 0;
}
@@ -71,10 +72,24 @@ void ChronoManager::delay(uint32 ms) {
Common::Event e;
while ((g_system->getMillis() - delayStart) < ms && !g_engine->shouldQuit()) {
while (g_system->getEventManager()->pollEvent(e)) {
-
}
g_engine->_screen->update();
}
}
+void ChronoManager::waitForKey() {
+ bool waitForKey = false;
+ Common::Event e;
+ debug("Waiting for key!");
+ while (!waitForKey && !g_engine->shouldQuit()) {
+ while (g_system->getEventManager()->pollEvent(e)) {
+ if (e.type == Common::EVENT_KEYDOWN) {
+ waitForKey = true;
+ }
+ }
+
+ g_engine->_screen->update();
+ g_system->delayMillis(10);
+ }
+}
} // End of namespace Pelrock
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index de19a626789..ffdf43f3b3e 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -41,6 +41,7 @@ public:
void updateChrono();
void changeSpeed();
void delay(uint32 ms);
+ void waitForKey();
bool _gameTick = false;
bool _gameTickHalfSpeed = false;
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index a30d1632dd7..88894769896 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -9,7 +9,8 @@ MODULE_OBJS = \
fonts/small_font.o \
fonts/large_font.o \
util.o \
- resources.o
+ resources.o\
+ video/video.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 0f0e6516ac9..b1a68231810 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -60,6 +60,7 @@ PelrockEngine::~PelrockEngine() {
delete _largeFont;
delete _screen;
delete _chronoManager;
+ delete _videoManager;
// if (_bgPopupBalloon)
// delete[] _bgPopupBalloon;
@@ -80,6 +81,7 @@ Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
initGraphics(640, 400);
_screen = new Graphics::Screen();
+ _videoManager = new VideoManager(_screen);
// Set the engine's debugger console
setDebugger(new Console());
@@ -98,33 +100,33 @@ Common::Error PelrockEngine::run() {
stateGame = GAME;
} else {
stateGame = INTRO;
- playIntro();
+ _videoManager->playIntro();
}
while (!shouldQuit()) {
_chronoManager->updateChrono();
while (g_system->getEventManager()->pollEvent(e)) {
if (e.type == Common::EVENT_KEYDOWN) {
- switch (e.kbd.keycode) {
- case Common::KEYCODE_w:
- alfredState = ALFRED_WALKING;
- break;
- case Common::KEYCODE_t:
- alfredState = ALFRED_TALKING;
- break;
- case Common::KEYCODE_s:
- alfredState = ALFRED_IDLE;
- break;
- case Common::KEYCODE_c:
- alfredState = ALFRED_COMB;
- break;
- case Common::KEYCODE_i:
- alfredState = ALFRED_INTERACTING;
- break;
- default:
- break;
- }
- } else if (e.type == Common::EVENT_MOUSEMOVE) {
+ switch (e.kbd.keycode) {
+ case Common::KEYCODE_w:
+ alfredState = ALFRED_WALKING;
+ break;
+ case Common::KEYCODE_t:
+ alfredState = ALFRED_TALKING;
+ break;
+ case Common::KEYCODE_s:
+ alfredState = ALFRED_IDLE;
+ break;
+ case Common::KEYCODE_c:
+ alfredState = ALFRED_COMB;
+ break;
+ case Common::KEYCODE_i:
+ alfredState = ALFRED_INTERACTING;
+ break;
+ default:
+ break;
+ }
+ } else if (e.type == Common::EVENT_MOUSEMOVE) {
mouseX = e.mouse.x;
mouseY = e.mouse.y;
// debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
@@ -183,9 +185,6 @@ void PelrockEngine::init() {
}
}
-void PelrockEngine::playIntro() {
-}
-
void PelrockEngine::loadAnims() {
_res->loadAlfredAnims();
}
@@ -291,87 +290,87 @@ void PelrockEngine::frames() {
}
switch (alfredState) {
- case ALFRED_WALKING: {
- MovementStep step = _currentContext.movement_buffer[_current_step];
-
- if (step.distance_x > 0) {
- if (step.flags & MOVE_RIGHT) {
- dirAlfred = 0;
- xAlfred += MIN((uint16_t)6, step.distance_x);
- }
- if (step.flags & MOVE_LEFT) {
- dirAlfred = 1;
- xAlfred -= MIN((uint16_t)6, step.distance_x);
- }
- }
- if (step.distance_y > 0) {
- if (step.flags & MOVE_DOWN) {
- dirAlfred = 2;
- yAlfred += MIN((uint16_t)6, step.distance_y);
- }
- if (step.flags & MOVE_UP) {
- dirAlfred = 3;
- yAlfred -= MIN((uint16_t)6, step.distance_y);
- }
- }
-
- if (step.distance_x > 0)
- step.distance_x -= MIN((uint16_t)6, step.distance_x);
-
- if (step.distance_y > 0)
- step.distance_y -= MIN((uint16_t)6, step.distance_y);
-
- if (step.distance_x <= 0 && step.distance_y <= 0) {
- _current_step++;
- if (_current_step >= _currentContext.movement_count) {
- _current_step = 0;
- alfredState = ALFRED_IDLE;
- }
- } else {
- _currentContext.movement_buffer[_current_step] = step;
- }
-
- Exit *exit = isExitUnder(xAlfred, yAlfred);
-
- if (exit != nullptr) {
- xAlfred = exit->targetX;
- yAlfred = exit->targetY;
- setScreen(exit->targetRoom, exit->dir);
- }
-
- if (curAlfredFrame >= walkingAnimLengths[dirAlfred]) {
- curAlfredFrame = 0;
- }
-
- drawAlfred(_res->alfredWalkFrames[dirAlfred][curAlfredFrame]);
- curAlfredFrame++;
- break;
- }
- case ALFRED_TALKING:
- if (curAlfredFrame >= talkingAnimLengths[dirAlfred] - 1) {
- curAlfredFrame = 0;
- }
- drawAlfred(_res->alfredTalkFrames[dirAlfred][curAlfredFrame]);
- curAlfredFrame++;
- break;
- case ALFRED_COMB:
- if (curAlfredFrame >= 11) {
- curAlfredFrame = 0;
- }
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[0][curAlfredFrame], xAlfred, yAlfred - kAlfredFrameHeight, 51, 102, 255);
- curAlfredFrame++;
- break;
- case ALFRED_INTERACTING:
- if (curAlfredFrame >= interactingAnimLength) {
- curAlfredFrame = 0;
- }
- drawAlfred(_res->alfredInteractFrames[dirAlfred][curAlfredFrame]);
- curAlfredFrame++;
- break;
- default:
- drawAlfred(_res->alfredIdle[dirAlfred]);
- break;
- }
+ case ALFRED_WALKING: {
+ MovementStep step = _currentContext.movement_buffer[_current_step];
+
+ if (step.distance_x > 0) {
+ if (step.flags & MOVE_RIGHT) {
+ dirAlfred = 0;
+ xAlfred += MIN((uint16_t)6, step.distance_x);
+ }
+ if (step.flags & MOVE_LEFT) {
+ dirAlfred = 1;
+ xAlfred -= MIN((uint16_t)6, step.distance_x);
+ }
+ }
+ if (step.distance_y > 0) {
+ if (step.flags & MOVE_DOWN) {
+ dirAlfred = 2;
+ yAlfred += MIN((uint16_t)6, step.distance_y);
+ }
+ if (step.flags & MOVE_UP) {
+ dirAlfred = 3;
+ yAlfred -= MIN((uint16_t)6, step.distance_y);
+ }
+ }
+
+ if (step.distance_x > 0)
+ step.distance_x -= MIN((uint16_t)6, step.distance_x);
+
+ if (step.distance_y > 0)
+ step.distance_y -= MIN((uint16_t)6, step.distance_y);
+
+ if (step.distance_x <= 0 && step.distance_y <= 0) {
+ _current_step++;
+ if (_current_step >= _currentContext.movement_count) {
+ _current_step = 0;
+ alfredState = ALFRED_IDLE;
+ }
+ } else {
+ _currentContext.movement_buffer[_current_step] = step;
+ }
+
+ Exit *exit = isExitUnder(xAlfred, yAlfred);
+
+ if (exit != nullptr) {
+ xAlfred = exit->targetX;
+ yAlfred = exit->targetY;
+ setScreen(exit->targetRoom, exit->dir);
+ }
+
+ if (curAlfredFrame >= walkingAnimLengths[dirAlfred]) {
+ curAlfredFrame = 0;
+ }
+
+ drawAlfred(_res->alfredWalkFrames[dirAlfred][curAlfredFrame]);
+ curAlfredFrame++;
+ break;
+ }
+ case ALFRED_TALKING:
+ if (curAlfredFrame >= talkingAnimLengths[dirAlfred] - 1) {
+ curAlfredFrame = 0;
+ }
+ drawAlfred(_res->alfredTalkFrames[dirAlfred][curAlfredFrame]);
+ curAlfredFrame++;
+ break;
+ case ALFRED_COMB:
+ if (curAlfredFrame >= 11) {
+ curAlfredFrame = 0;
+ }
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[0][curAlfredFrame], xAlfred, yAlfred - kAlfredFrameHeight, 51, 102, 255);
+ curAlfredFrame++;
+ break;
+ case ALFRED_INTERACTING:
+ if (curAlfredFrame >= interactingAnimLength) {
+ curAlfredFrame = 0;
+ }
+ drawAlfred(_res->alfredInteractFrames[dirAlfred][curAlfredFrame]);
+ curAlfredFrame++;
+ break;
+ default:
+ drawAlfred(_res->alfredIdle[dirAlfred]);
+ break;
+ }
if (_displayPopup) {
// byte *bgDialog = new byte[kBalloonWidth * kBalloonHeight];
@@ -993,6 +992,8 @@ void PelrockEngine::checkMouseClick(int x, int y) {
if (exit != nullptr) {
xAlfred = exit->targetX;
yAlfred = exit->targetY;
+
+ debug("Placing character at %d, %d", exit->targetX, exit->targetY);
setScreen(exit->targetRoom, exit->dir);
} else {
walkTo(walkTarget.x, walkTarget.y);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index abef2134ece..1ec613533ad 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -43,6 +43,7 @@
#include "pelrock/resources.h"
#include "pelrock/room.h"
#include "pelrock/types.h"
+#include "pelrock/video/video.h"
namespace Pelrock {
@@ -52,12 +53,10 @@ class PelrockEngine : public Engine {
private:
const ADGameDescription *_gameDescription;
Common::RandomSource _randomSource;
- ChronoManager *_chronoManager = nullptr;
RoomManager *_room = nullptr;
ResourceManager *_res = nullptr;
void init();
- void playIntro();
void setScreen(int s, int dir);
void setScreenJava(int s, int dir);
void loadAnims();
@@ -147,8 +146,8 @@ private:
bool isNPCBTalking = false;
// JAVA
- bool shouldPlayIntro = false;
- GameState stateGame = GAME;
+ bool shouldPlayIntro = true;
+ GameState stateGame = INTRO;
bool gameInitialized = false;
bool screenReady = false;
// int prevDirX = 0;
@@ -166,6 +165,8 @@ protected:
public:
Graphics::Screen *_screen = nullptr;
AlfredState alfredState = ALFRED_IDLE;
+ ChronoManager *_chronoManager = nullptr;
+ VideoManager *_videoManager = nullptr;
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
~PelrockEngine() override;
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
new file mode 100644
index 00000000000..03d33b3af42
--- /dev/null
+++ b/engines/pelrock/video/video.cpp
@@ -0,0 +1,113 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/file.h"
+#include "graphics/screen.h"
+
+#include "pelrock/chrono.h"
+#include "pelrock/pelrock.h"
+#include "pelrock/video/video.h"
+#include "video.h"
+
+namespace Pelrock {
+
+VideoManager::VideoManager(Graphics::Screen *screen) : _screen(screen) {
+}
+
+VideoManager::~VideoManager() {
+}
+
+void VideoManager::playIntro() {
+ Common::File videoFile;
+ if (!videoFile.open("ESCENAX.SSN")) {
+ error("Could not open ESCENAX.SSN");
+ return;
+ }
+ loadPalette(videoFile);
+ videoFile.seek(0x5000, SEEK_SET);
+ size_t firstChunkSize = 0x5000 * 13;
+ byte *chunk0 = new byte[firstChunkSize];
+ videoFile.read(chunk0, firstChunkSize);
+ byte *background = decodeCopyBlock(chunk0, firstChunkSize, 0);
+
+ for (int i = 0; i < 640; i++) {
+ for (int j = 0; j < 400; j++) {
+ _screen->setPixel(i, j, background[j * 640 + i]);
+ }
+ }
+ _screen->markAllDirty();
+ _screen->update();
+ g_engine->_chronoManager->waitForKey();
+ videoFile.close();
+}
+void VideoManager::loadPalette(Common::SeekableReadStream &stream) {
+
+ byte paletteData[768];
+ stream.seek(0x0009, SEEK_SET);
+ stream.read(paletteData, 768);
+ byte palette[768];
+ for (int i = 0; i < 256; i++) {
+ palette[i * 3 + 0] = paletteData[i * 3 + 0] << 2;
+ palette[i * 3 + 1] = paletteData[i * 3 + 1] << 2;
+ palette[i * 3 + 2] = paletteData[i * 3 + 2] << 2;
+ }
+ _screen->setPalette(palette);
+ // def extract_palette(data):
+ // """Extract and convert VGA palette to 8-bit RGB"""
+ // file_palette = data[0x0009:0x0009 + 768]
+ // palette = []
+ // for i in range(256):
+ // r = file_palette[i * 3 + 0] * 4
+ // g = file_palette[i * 3 + 1] * 4
+ // b = file_palette[i * 3 + 2] * 4
+ // palette.extend([r, g, b])
+ // return palette
+}
+
+byte *VideoManager::decodeCopyBlock(byte *data, size_t size, uint32 offset) {
+
+ byte *buf = new byte[256000];
+ memset(buf, 0, 256000);
+ uint32 pos = offset + 0x0D;
+ // frames are encoded so that each block copy has a 5-byte header
+ // the first 3 bytes are the offset within the screen to which to
+ // copy the bytes. The 5th byte is the length of the block to copy.
+ while (pos + 5 < size) {
+ byte dest_lo = data[pos];
+ byte dest_mid = data[pos + 1];
+ byte dest_hi = data[pos + 2];
+ byte length = data[pos + 4];
+ if (length == 0) {
+ break;
+ }
+ uint32 dest_offset = dest_lo | (dest_mid << 8) | (dest_hi << 16);
+
+ if (dest_offset + length > 256000) {
+ break;
+ }
+ pos += 5;
+ Common::copy(data + pos, data + pos + length, buf + dest_offset);
+ pos += length;
+ }
+
+ return buf; // Placeholder
+}
+} // End of namespace Pelrock
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
new file mode 100644
index 00000000000..af4b23fe9dc
--- /dev/null
+++ b/engines/pelrock/video/video.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PELROCK_VIDEO_H
+#define PELROCK_VIDEO_H
+
+namespace Pelrock {
+
+static const uint32 offsets[] = {
+ 0x64000,
+ 0x69000,
+ 0x6E000,
+ 0x73000,
+ 0x78000,
+ 0x7D000,
+ 0x82000,
+ 0x87000};
+
+class VideoManager {
+public:
+ VideoManager(Graphics::Screen *screen);
+ ~VideoManager();
+ void playIntro();
+
+private:
+ Graphics::Screen *_screen;
+ void loadPalette(Common::SeekableReadStream &stream);
+ byte *decodeCopyBlock(byte *data, size_t size, uint32 offset);
+};
+
+} // End of namespace Pelrock
+#endif
Commit: 45624b59540b367a5716d9f283af0dd28624d1d5
https://github.com/scummvm/scummvm/commit/45624b59540b367a5716d9f283af0dd28624d1d5
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:13+02:00
Commit Message:
PELROCK: Renders first video sequence
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b1a68231810..f21d8d436c0 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -95,13 +95,14 @@ Common::Error PelrockEngine::run() {
Common::Event e;
Graphics::FrameLimiter limiter(g_system, 60);
- init();
if (shouldPlayIntro == false) {
stateGame = GAME;
} else {
stateGame = INTRO;
_videoManager->playIntro();
+ stateGame = GAME;
}
+ init();
while (!shouldQuit()) {
_chronoManager->updateChrono();
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 03d33b3af42..9ebcc585608 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -42,11 +42,11 @@ void VideoManager::playIntro() {
return;
}
loadPalette(videoFile);
- videoFile.seek(0x5000, SEEK_SET);
- size_t firstChunkSize = 0x5000 * 13;
+ videoFile.seek(frame0offset, SEEK_SET);
+ size_t firstChunkSize = chunkSize * 13;
byte *chunk0 = new byte[firstChunkSize];
videoFile.read(chunk0, firstChunkSize);
- byte *background = decodeCopyBlock(chunk0, firstChunkSize, 0);
+ byte *background = decodeCopyBlock(chunk0, 0);
for (int i = 0; i < 640; i++) {
for (int j = 0; j < 400; j++) {
@@ -55,6 +55,47 @@ void VideoManager::playIntro() {
}
_screen->markAllDirty();
_screen->update();
+ delete[] chunk0;
+ g_engine->_chronoManager->waitForKey();
+
+ size_t chunk1Size = chunkSize * 6;
+ byte chunk1_data[chunk1Size];
+ videoFile.seek(frame1offset, SEEK_SET);
+ videoFile.read(chunk1_data, chunk1Size);
+
+ byte *delta1 = decodeRLE(chunk1_data, chunk1Size, 0x0D);
+ for (int j = 0; j < 256000; j++) {
+ background[j] ^= delta1[j];
+ }
+ delete[] delta1;
+ for (int x = 0; x < 640; x++) {
+ for (int y = 0; y < 400; y++) {
+ _screen->setPixel(x, y, background[y * 640 + x]);
+ }
+ }
+ _screen->markAllDirty();
+ _screen->update();
+ g_engine->_chronoManager->waitForKey();
+
+ for (size_t i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
+ byte *chunk = new byte[chunkSize];
+ videoFile.seek(offsets[i], SEEK_SET);
+ videoFile.read(chunk, chunkSize);
+ byte *delta = decodeCopyBlock(chunk, 0);
+ for (int j = 0; j < 256000; j++) {
+ background[j] ^= delta[j];
+ }
+ delete[] delta;
+ for (int x = 0; x < 640; x++) {
+ for (int y = 0; y < 400; y++) {
+ _screen->setPixel(x, y, background[y * 640 + x]);
+ }
+ }
+ delete[] chunk;
+ _screen->markAllDirty();
+ _screen->update();
+ g_engine->_chronoManager->waitForKey();
+ }
g_engine->_chronoManager->waitForKey();
videoFile.close();
}
@@ -70,19 +111,9 @@ void VideoManager::loadPalette(Common::SeekableReadStream &stream) {
palette[i * 3 + 2] = paletteData[i * 3 + 2] << 2;
}
_screen->setPalette(palette);
- // def extract_palette(data):
- // """Extract and convert VGA palette to 8-bit RGB"""
- // file_palette = data[0x0009:0x0009 + 768]
- // palette = []
- // for i in range(256):
- // r = file_palette[i * 3 + 0] * 4
- // g = file_palette[i * 3 + 1] * 4
- // b = file_palette[i * 3 + 2] * 4
- // palette.extend([r, g, b])
- // return palette
}
-byte *VideoManager::decodeCopyBlock(byte *data, size_t size, uint32 offset) {
+byte *VideoManager::decodeCopyBlock(byte *data, uint32 offset) {
byte *buf = new byte[256000];
memset(buf, 0, 256000);
@@ -90,7 +121,7 @@ byte *VideoManager::decodeCopyBlock(byte *data, size_t size, uint32 offset) {
// frames are encoded so that each block copy has a 5-byte header
// the first 3 bytes are the offset within the screen to which to
// copy the bytes. The 5th byte is the length of the block to copy.
- while (pos + 5 < size) {
+ while (true) {
byte dest_lo = data[pos];
byte dest_mid = data[pos + 1];
byte dest_hi = data[pos + 2];
@@ -110,4 +141,57 @@ byte *VideoManager::decodeCopyBlock(byte *data, size_t size, uint32 offset) {
return buf; // Placeholder
}
+
+byte *VideoManager::decodeRLE(byte *data, size_t size, uint32 offset) {
+ byte *buf = new byte[256000];
+ memset(buf, 0, 256000);
+ uint32 pos = offset;
+ // result = bytearray()
+ // pos = start_pos
+
+ uint32 outPos = 0;
+ while (outPos < 256000 && pos < size) {
+ byte countByte = data[pos];
+ pos += 1;
+
+ if ((countByte & 0xC0) == 0xC0) {
+ // RLE: count in lower 6 bits, next byte is value
+ uint32 count = countByte & 0x3F;
+ if (pos >= size) {
+ break;
+ }
+ byte value = data[pos];
+ pos += 1;
+ for (uint32 i = 0; i < count && outPos < 256000; i++) {
+ buf[outPos++] = value;
+ }
+ } else {
+ // Literal: count is 1, this byte is the value
+ buf[outPos++] = countByte;
+ }
+ }
+ return buf;
+
+ // while len(result) < max_size and pos < len(data):
+ // count_byte = data[pos]
+ // pos += 1
+
+ // if (count_byte & 0xC0) == 0xC0:
+ // # RLE: count in lower 6 bits, next byte is value
+ // count = count_byte & 0x3F
+ // if pos >= len(data):
+ // break
+ // value = data[pos]
+ // pos += 1
+ // result.extend([value] * count)
+ // else:
+ // # Literal: count is 1, this byte is the value
+ // result.append(count_byte)
+
+ // # Pad to exact size
+ // if len(result) < max_size:
+ // result.extend([0] * (max_size - len(result)))
+
+ // return bytes(result[:max_size])
+}
} // End of namespace Pelrock
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index af4b23fe9dc..f9ac45b3a2e 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -24,6 +24,9 @@
namespace Pelrock {
+static const uint32 frame0offset = 0x5000;
+static const uint32 frame1offset = 0x46000;
+static const uint32 chunkSize = 0x5000;
static const uint32 offsets[] = {
0x64000,
0x69000,
@@ -43,7 +46,8 @@ public:
private:
Graphics::Screen *_screen;
void loadPalette(Common::SeekableReadStream &stream);
- byte *decodeCopyBlock(byte *data, size_t size, uint32 offset);
+ byte *decodeCopyBlock(byte *data, uint32 offset);
+ byte *decodeRLE(byte *data, size_t size, uint32 offset);
};
} // End of namespace Pelrock
Commit: 8e3b5c552687625f541555e61e7b7ef8cb5644f3
https://github.com/scummvm/scummvm/commit/8e3b5c552687625f541555e61e7b7ef8cb5644f3
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:13+02:00
Commit Message:
PELROCK: Initial scaling algorithm
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
engines/pelrock/video/video.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f21d8d436c0..cef91e013e3 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -75,7 +75,7 @@ Common::String PelrockEngine::getGameId() const {
return _gameDescription->gameId;
}
-Common::Array<Common::Array<Common::String> > wordWrap(Common::String text);
+Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
@@ -165,6 +165,7 @@ Common::Error PelrockEngine::run() {
void PelrockEngine::init() {
_res->loadCursors();
_res->loadInteractionIcons();
+ calculateScalingMasks();
_compositeBuffer = new byte[640 * 400];
_currentBackground = new byte[640 * 400];
@@ -180,9 +181,9 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- // setScreen(5, 0); //museum entrance
+ setScreen(6, 0); // museum entrance
// setScreen(13, 1); // restaurants kitchen
- setScreen(2, 2); // hooker
+ // setScreen(2, 2); // hooker
}
}
@@ -469,7 +470,108 @@ void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, i
}
void PelrockEngine::drawAlfred(byte *buf) {
- drawSpriteToBuffer(_compositeBuffer, 640, buf, xAlfred, yAlfred - kAlfredFrameHeight, kAlfredFrameWidth, kAlfredFrameHeight, 255);
+
+ ScaleCalculation scale = calculateScaling(yAlfred, _room->_scaleParams);
+
+ int finalHeight = kAlfredFrameHeight - scale.scaleDown + scale.scaleUp;
+ if (finalHeight <= 0) {
+ finalHeight = 1;
+ }
+ float scaleFactor = static_cast<float>(finalHeight) / static_cast<float>(kAlfredFrameHeight);
+ int finalWidth = static_cast<int>(kAlfredFrameWidth * scaleFactor);
+ if (finalWidth <= 0) {
+ finalWidth = 1;
+ }
+ int scaleIndex = finalHeight - 1;
+ if (scaleIndex >= _heightScalingTable.size()) {
+ scaleIndex = _heightScalingTable.size() - 1;
+ }
+ if (scaleIndex < 0) {
+ scaleIndex = 0;
+ }
+ debug("Scaling Alfred frame to final size (%d x %d) from scale factor %.2f", finalWidth, finalHeight, scaleFactor);
+ int linesToSkip = kAlfredFrameHeight - finalHeight;
+
+ debug("lines to skip = %d, finalHeight = %d, finalWidth = %d for position (%d, %d)", linesToSkip, finalHeight, finalWidth, xAlfred, yAlfred);
+
+ if (linesToSkip <= 0) {
+ // No skipping needed, output all lines
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, xAlfred, yAlfred - kAlfredFrameHeight, kAlfredFrameWidth, kAlfredFrameHeight, 255);
+ } else {
+
+ byte *scaledData = new byte[finalWidth * finalHeight];
+ int skipInterval = kAlfredFrameHeight / linesToSkip;
+ Common::Array<float> idealSkipPositions;
+ for (int i = 0; i < linesToSkip; i++) {
+ float idealPos = (i + 0.5f) * skipInterval;
+ idealSkipPositions.push_back(idealPos);
+ }
+
+ debug("Ideal skip positions:");
+ for (size_t i = 0; i < idealSkipPositions.size(); i++) {
+ debug(" %.2f", idealSkipPositions[i]);
+ }
+
+ debug("Height scaling table size =%d", _heightScalingTable.size());
+ Common::Array<int> tableSkipPositions;
+ for (int scanline = 0; scanline < kAlfredFrameHeight; scanline++) {
+ if (_heightScalingTable[scaleIndex][scanline] != 0) {
+ tableSkipPositions.push_back(scanline);
+ }
+ }
+
+ debug("Table skip positions:");
+ for (size_t i = 0; i < tableSkipPositions.size(); i++) {
+ debug(" %d", tableSkipPositions[i]);
+ }
+
+ Common::Array<int> skipTheseLines;
+ for (size_t i = 0; i < idealSkipPositions.size(); i++) {
+ float idealPos = idealSkipPositions[i];
+ int closest = -1;
+ int minDiff = INT32_MAX;
+ for (size_t j = 0; j < tableSkipPositions.size(); j++) {
+ int candidate = tableSkipPositions[j];
+ int diff = static_cast<int>(abs(candidate - idealPos));
+ if (diff < minDiff) {
+ minDiff = diff;
+ closest = candidate;
+ }
+ }
+ if (closest != -1) {
+ skipTheseLines.push_back(closest);
+ }
+ if (skipTheseLines.size() >= static_cast<size_t>(linesToSkip)) {
+ break;
+ }
+ }
+
+ int outY = 0;
+ for (int srcY = 0; srcY < kAlfredFrameHeight; srcY++) {
+ bool skipLine = false;
+ for (size_t skipIdx = 0; skipIdx < skipTheseLines.size(); ++skipIdx) {
+ if (skipTheseLines[skipIdx] == srcY) {
+ skipLine = true;
+ break;
+ }
+ }
+ if (!skipLine) {
+ for (int outX = 0; outX < finalWidth; outX++) {
+ int srcX = static_cast<int>(outX * kAlfredFrameWidth / finalWidth);
+ if (srcX >= kAlfredFrameWidth) {
+ srcX = kAlfredFrameWidth - 1;
+ }
+ int srcIndex = srcY * kAlfredFrameWidth + srcX;
+ int outIndex = outY * finalWidth + outX;
+ scaledData[outIndex] = buf[srcIndex];
+ }
+ outY++;
+ }
+ }
+ drawSpriteToBuffer(_compositeBuffer, 640, scaledData, xAlfred, yAlfred - finalHeight, finalWidth, finalHeight, 255);
+
+ delete[] scaledData;
+ }
}
void PelrockEngine::drawNextFrame(AnimSet *animSet) {
@@ -537,6 +639,126 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
}
}
+void PelrockEngine::calculateScalingMasks() {
+
+ // for scale_factor in range(CHAR_WIDTH):
+ // step = CHAR_WIDTH / (scale_factor + 1.0)
+ // row = []
+ // index = 0.0
+ // source_pixel = 0
+
+ // while index < CHAR_WIDTH:
+ // row.append(source_pixel)
+ // index += step
+ // source_pixel += 1
+ // if source_pixel >= CHAR_WIDTH:
+ // source_pixel = CHAR_WIDTH - 1
+
+ // # Pad to exactly CHAR_WIDTH entries
+ // while len(row) < CHAR_WIDTH:
+ // row.append(row[-1] if row else 0)
+ // width_table.append(row[:CHAR_WIDTH])
+
+ for (int scaleFactor = 0; scaleFactor < kAlfredFrameWidth; scaleFactor++) {
+ float step = kAlfredFrameWidth / (scaleFactor + 1.0f);
+ Common::Array<int> row;
+ float index = 0.0f;
+ int sourcePixel = 0;
+
+ while (index < kAlfredFrameWidth) {
+ row.push_back(sourcePixel);
+ index += step;
+ sourcePixel += 1;
+ if (sourcePixel >= kAlfredFrameWidth) {
+ sourcePixel = kAlfredFrameWidth - 1;
+ }
+ }
+
+ // Pad to exactly CHAR_WIDTH entries
+ while (row.size() < kAlfredFrameWidth) {
+ row.push_back(row.empty() ? 0 : row[row.size() - 1]);
+ }
+
+ _widthScalingTable.push_back(row);
+ }
+
+ // height_table = []
+ // for scale_factor in range(CHAR_HEIGHT):
+ // step = CHAR_HEIGHT / (scale_factor + 1.0)
+ // row = [0] * CHAR_HEIGHT # Initialize all to 0
+
+ // # Mark positions where we should keep/duplicate the scanline
+ // position = step
+ // counter = 1
+ // while position < CHAR_HEIGHT:
+ // idx = round(position)
+ // if idx < CHAR_HEIGHT:
+ // row[idx] = counter
+ // counter += 1
+ // position += step
+
+ // height_table.append(row)
+ for (int scaleFactor = 0; scaleFactor < kAlfredFrameHeight; scaleFactor++) {
+ float step = kAlfredFrameHeight / (scaleFactor + 1.0f);
+ Common::Array<int> row;
+ row.resize(kAlfredFrameHeight, 0);
+ float position = step;
+ int counter = 1;
+ while (position < kAlfredFrameHeight) {
+ int idx = static_cast<int>(round(position));
+ if (idx < kAlfredFrameHeight) {
+ row[idx] = counter;
+ counter++;
+ }
+ position += step;
+ }
+ _heightScalingTable.push_back(row);
+ }
+}
+
+ScaleCalculation PelrockEngine::calculateScaling(int yPos, ScalingParams scalingParams) {
+ int scaleDown = 0;
+ int scaleUp = 0;
+ if (scalingParams.scaleMode == 0xFF) {
+ scaleDown = 0x5e;
+ scaleUp = 0x2f;
+ } else if (scalingParams.scaleMode == 0xFE) {
+ scaleDown = 0;
+ scaleUp = 0;
+ } else if (scalingParams.scaleMode == 0) {
+ if (scalingParams.yThreshold < yPos) {
+ scaleDown = 0;
+ scaleUp = 0;
+ } else {
+ if (scalingParams.scaleDivisor != 0) {
+ scaleDown = (scalingParams.yThreshold - yPos) / scalingParams.scaleDivisor;
+ scaleUp = scaleDown / 2;
+ } else {
+ scaleDown = 0;
+ scaleUp = 0;
+ }
+ }
+ } else {
+ scaleDown = 0;
+ scaleUp = 0;
+ }
+
+ int finalHeight = kAlfredFrameHeight - scaleDown + scaleUp;
+ if (finalHeight < 1)
+ finalHeight = 1;
+
+ int finalWidth = kAlfredFrameWidth * (finalHeight / kAlfredFrameHeight);
+ if (finalWidth < 1)
+ finalWidth = 1;
+
+ ScaleCalculation scaleCalc;
+ scaleCalc.scaledHeight = finalHeight;
+ scaleCalc.scaledWidth = finalWidth;
+ scaleCalc.scaleDown = scaleDown;
+ scaleCalc.scaleUp = scaleUp;
+ return scaleCalc;
+}
+
int PelrockEngine::isHotspotUnder(int x, int y) {
for (size_t i = 0; i < _room->_currentRoomHotspots.size(); i++) {
@@ -1182,9 +1404,9 @@ int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
return wordLength;
}
-Common::Array<Common::Array<Common::String> > wordWrap(Common::String text) {
+Common::Array<Common::Array<Common::String>> wordWrap(Common::String text) {
- Common::Array<Common::Array<Common::String> > pages;
+ Common::Array<Common::Array<Common::String>> pages;
Common::Array<Common::String> currentPage;
Common::Array<Common::String> currentLine;
int charsRemaining = MAX_CHARS_PER_LINE;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 1ec613533ad..425b073bb9a 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -101,21 +101,27 @@ private:
void checkMouseClick(int x, int y);
void checkLongMouseClick(int x, int y);
+ void calculateScalingMasks();
+ ScaleCalculation calculateScaling(int yPos, ScalingParams scalingParams);
- //walking
+ Common::Array<Common::Array<int>> _widthScalingTable;
+ Common::Array<Common::Array<int>> _heightScalingTable;
+
+ // walking
int _current_step = 0;
PathContext _currentContext;
- //text display
+ // text display
byte _textColor = 0;
Common::Point _textPos;
- Common::Array<Common::Array<Common::String> > _currentTextPages = Common::Array<Common::Array<Common::String> >();
+ Common::Array<Common::Array<Common::String>> _currentTextPages = Common::Array<Common::Array<Common::String>>();
int _currentTextPageIndex = 0;
-
// Alfred
- int xAlfred = 319;
- int yAlfred = 302;
+ // int xAlfred = 319;
+ // int yAlfred = 302;
+ int xAlfred = 264;
+ int yAlfred = 394;
int dirAlfred = 0;
int curAlfredFrame = 0;
@@ -126,9 +132,8 @@ private:
bool _isMouseDown = false;
bool _longClick = false;
-
byte *_currentBackground = nullptr; // Clean background - NEVER modified
- byte *_compositeBuffer; // Working composition buffer
+ byte *_compositeBuffer; // Working composition buffer
bool _displayPopup = false;
int _popupX = 0;
@@ -146,7 +151,7 @@ private:
bool isNPCBTalking = false;
// JAVA
- bool shouldPlayIntro = true;
+ bool shouldPlayIntro = false;
GameState stateGame = INTRO;
bool gameInitialized = false;
bool screenReady = false;
@@ -157,7 +162,6 @@ private:
// int whichScreen = 0;
// byte *pixelsShadows; // =new int[640*400];
-
protected:
// Engine APIs
Common::Error run() override;
@@ -167,6 +171,7 @@ public:
AlfredState alfredState = ALFRED_IDLE;
ChronoManager *_chronoManager = nullptr;
VideoManager *_videoManager = nullptr;
+
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
~PelrockEngine() override;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 3b5a3c84deb..23b1e0beefa 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -22,6 +22,7 @@
#include "pelrock/room.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
+#include "room.h"
namespace Pelrock {
@@ -172,7 +173,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
Common::Array<Exit> exits = loadExits(roomFile, roomOffset);
-
+ ScalingParams scalingParams = loadScalingParams(roomFile, roomOffset);
Common::Array<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
@@ -189,6 +190,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
_currentRoomExits = exits;
_currentRoomWalkboxes = walkboxes;
_currentRoomDescriptions = descriptions;
+ _scaleParams = scalingParams;
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
drawRect(g_engine->_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
@@ -287,6 +289,8 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(Common::File *roomFile, int ro
uint32_t walkbox_countOffset = pair10_data_offset + 0x213;
roomFile->seek(walkbox_countOffset, SEEK_SET);
byte walkbox_count = roomFile->readByte();
+
+
debug("Walkbox count: %d", walkbox_count);
uint32_t walkbox_offset = pair10_data_offset + 0x218;
Common::Array<WalkBox> walkboxes;
@@ -823,5 +827,19 @@ Common::Array<ConversationNode> RoomManager::loadConversations(Common::File *roo
return roots;
}
-
+ScalingParams RoomManager::loadScalingParams(Common::File *roomFile, int roomOffset) {
+ uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+ roomFile->seek(pair10_offset_pos, SEEK_SET);
+ // roomFile->skip(4);
+ uint32_t pair10_data_offset = roomFile->readUint32LE();
+ uint32_t pair10_size = roomFile->readUint32LE();
+ uint32_t scalingParamsOffset = pair10_data_offset + 0x214;
+
+ roomFile->seek(scalingParamsOffset, SEEK_SET);
+ ScalingParams scalingParams;
+ scalingParams.yThreshold = roomFile->readSint16LE();
+ scalingParams.scaleDivisor = roomFile->readByte();
+ scalingParams.scaleMode = roomFile->readByte();
+ return scalingParams;
+}
} // End of namespace Pelrock
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 10553071ea3..db12aceb27b 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -45,6 +45,7 @@ public:
Common::Array<Description> _currentRoomDescriptions;
Common::Array<ConversationNode> _currentRoomConversations;
TalkingAnimHeader _talkingAnimHeader;
+ ScalingParams _scaleParams;
private:
Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
@@ -58,6 +59,7 @@ private:
Common::Array<ConversationElement> parseConversationElements(const byte *convData, uint32 size);
Common::Array<ConversationNode> buildTreeStructure(const Common::Array<ConversationElement> &elements);
Common::Array<ConversationNode> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
+ ScalingParams loadScalingParams(Common::File *roomFile, int roomOffset);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 6fd46cfddfe..99ded11b46e 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -262,6 +262,19 @@ struct WalkBox {
byte flags;
};
+struct ScalingParams {
+ int16 yThreshold;
+ byte scaleDivisor;
+ byte scaleMode;
+};
+
+struct ScaleCalculation {
+ int scaledWidth;
+ int scaledHeight;
+ int scaleUp;
+ int scaleDown;
+};
+
enum GameState {
GAME = 100,
MENU = 101,
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 9ebcc585608..93c5fd4a17e 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -146,9 +146,6 @@ byte *VideoManager::decodeRLE(byte *data, size_t size, uint32 offset) {
byte *buf = new byte[256000];
memset(buf, 0, 256000);
uint32 pos = offset;
- // result = bytearray()
- // pos = start_pos
-
uint32 outPos = 0;
while (outPos < 256000 && pos < size) {
byte countByte = data[pos];
@@ -171,27 +168,5 @@ byte *VideoManager::decodeRLE(byte *data, size_t size, uint32 offset) {
}
}
return buf;
-
- // while len(result) < max_size and pos < len(data):
- // count_byte = data[pos]
- // pos += 1
-
- // if (count_byte & 0xC0) == 0xC0:
- // # RLE: count in lower 6 bits, next byte is value
- // count = count_byte & 0x3F
- // if pos >= len(data):
- // break
- // value = data[pos]
- // pos += 1
- // result.extend([value] * count)
- // else:
- // # Literal: count is 1, this byte is the value
- // result.append(count_byte)
-
- // # Pad to exact size
- // if len(result) < max_size:
- // result.extend([0] * (max_size - len(result)))
-
- // return bytes(result[:max_size])
}
} // End of namespace Pelrock
Commit: 79fdb25fcf772bc9404f6606e2980e777ee00fef
https://github.com/scummvm/scummvm/commit/79fdb25fcf772bc9404f6606e2980e777ee00fef
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:13+02:00
Commit Message:
PELROCK: Initial scaling algorithm
Changed paths:
engines/pelrock/offsets.h
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 577613b2d31..15dc427f85e 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -36,8 +36,8 @@ namespace Pelrock {
static const uint32_t kBalloonFramesOffset = 2176936;
static const uint32_t kBalloonFramesSize = 24950;
- static const uint32_t ALFRED7_ALFRED_COMB_R = 67764;
- static const uint32_t ALFRED7_ALFRED_COMB_L = 88404;
+ static const uint32_t ALFRED7_ALFRED_COMB_R = 67768;
+ static const uint32_t ALFRED7_ALFRED_COMB_L = 88408;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index c131921fc27..117fa5f5a5e 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -87,7 +87,7 @@ void ResourceManager::loadInteractionIcons() {
byte *raw = new byte[compressedSize];
alfred7File.read(raw, compressedSize);
- rleDecompress(raw, compressedSize, 0, compressedSize, &_popUpBalloon);
+ rleDecompress(raw, compressedSize, 0, totalBalloonSize, &_popUpBalloon);
delete[] raw;
@@ -122,7 +122,7 @@ void ResourceManager::loadAlfredAnims() {
int index3 = 0;
uint32_t capacity = 3060 * 102;
unsigned char *pic = new unsigned char[capacity];
- rleDecompress(bufferFile, alfred3Size, 0, alfred3Size, &pic);
+ rleDecompress(bufferFile, alfred3Size, 0, capacity, &pic);
int frameSize = kAlfredFrameHeight * kAlfredFrameWidth;
for (int i = 0; i < 4; i++) {
@@ -178,18 +178,18 @@ void ResourceManager::loadAlfredAnims() {
return;
}
int spriteMapSize = frameSize * 11;
+
byte *alfredCombRightRaw;
size_t alfredCombRightSize;
readUntilBuda(&alfred7, ALFRED7_ALFRED_COMB_R, alfredCombRightRaw, alfredCombRightSize);
byte *alfredCombRight = nullptr;
- rleDecompress(alfredCombRightRaw, alfredCombRightSize, 0, alfredCombRightSize, &alfredCombRight);
+ rleDecompress(alfredCombRightRaw, alfredCombRightSize, 0, spriteMapSize, &alfredCombRight);
alfredCombFrames[0] = new byte *[11];
alfredCombFrames[1] = new byte *[11];
for (int i = 0; i < 11; i++) {
-
alfredCombFrames[0][i] = new byte[frameSize];
extractSingleFrame(alfredCombRight, alfredCombFrames[0][i], i, kAlfredFrameWidth, kAlfredFrameHeight);
}
@@ -198,8 +198,12 @@ void ResourceManager::loadAlfredAnims() {
size_t alfredCombLeftSize;
readUntilBuda(&alfred7, ALFRED7_ALFRED_COMB_L, alfredCombLeftRaw, alfredCombLeftSize);
byte *alfredCombLeft = nullptr;
- rleDecompress(alfredCombLeftRaw, alfredCombLeftSize, 0, spriteMapSize, &alfredCombLeft);
+ size_t outSize = rleDecompress(alfredCombLeftRaw, alfredCombLeftSize, 0, spriteMapSize, &alfredCombLeft);
+ debug("Sprite map size: %d, %d, %d", spriteMapSize, alfredCombLeftSize, outSize);
+ for (int i = 0; i < 11; i++) {
+ debug("Extracting comb left frame %d", i);
+ }
for (int i = 0; i < 11; i++) {
alfredCombFrames[1][i] = new byte[frameSize];
extractSingleFrame(alfredCombLeft, alfredCombFrames[1][i], i, kAlfredFrameWidth, kAlfredFrameHeight);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 23b1e0beefa..f79e999bf59 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -27,6 +27,7 @@
namespace Pelrock {
RoomManager::RoomManager() {
+ pixelsShadows = new byte[640*400] { 0 };
}
RoomManager::~RoomManager() {
@@ -36,6 +37,7 @@ RoomManager::~RoomManager() {
// delete[] _currentRoomWalkboxes;
// delete[] _currentRoomDescriptions;
// delete[] _currentRoomConversations;
+ delete[] pixelsShadows;
}
void RoomManager::getPalette(Common::File *roomFile, int roomOffset, byte *palette) {
@@ -75,7 +77,7 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
roomFile->seek(offset, SEEK_SET);
roomFile->read(data, size);
uint8_t *block_data = NULL;
- size_t block_size = rleDecompress(data, size, 0, size, &block_data);
+ size_t block_size = rleDecompress(data, size, 0, 640 * 400, &block_data);
memcpy(background + combined_size, block_data, block_size);
combined_size += block_size + 1;
@@ -212,9 +214,9 @@ Common::Array<AnimSet> RoomManager::loadRoomAnimations(Common::File *roomFile, i
roomFile->seek(offset, SEEK_SET);
roomFile->read(data, size);
- unsigned char *pic = new byte[10000 * 10000];
+ unsigned char *pic = nullptr;
if (offset > 0 && size > 0) {
- rleDecompress(data, size, 0, size, &pic);
+ rleDecompress(data, size, 0, size, &pic, true);
} else {
return Common::Array<AnimSet>();
}
@@ -842,4 +844,29 @@ ScalingParams RoomManager::loadScalingParams(Common::File *roomFile, int roomOff
scalingParams.scaleMode = roomFile->readByte();
return scalingParams;
}
+
+static uint32 readUint24(Common::ReadStream &stream) {
+ uint32 value = stream.readUint16LE();
+ value |= stream.readByte() << 16;
+ return value;
+}
+
+byte *RoomManager::loadShadowMap(int roomNumber) {
+ Common::File shadowMapFile;
+ if (!shadowMapFile.open("ALFRED.5")) {
+ error("Couldnt find file ALFRED.5");
+ }
+
+ uint32 entryOffset = roomNumber * 6;
+
+ shadowMapFile.seek(entryOffset, SEEK_SET);
+ uint32 shadowOffset = readUint24(shadowMapFile);
+
+ shadowMapFile.seek(shadowOffset, SEEK_SET);
+
+ // pixelsShadows = rleDecompress(
+
+
+ return nullptr;
+}
} // End of namespace Pelrock
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index db12aceb27b..04237eb3c84 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -46,6 +46,7 @@ public:
Common::Array<ConversationNode> _currentRoomConversations;
TalkingAnimHeader _talkingAnimHeader;
ScalingParams _scaleParams;
+ byte *pixelsShadows = nullptr;
private:
Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
@@ -60,6 +61,7 @@ private:
Common::Array<ConversationNode> buildTreeStructure(const Common::Array<ConversationElement> &elements);
Common::Array<ConversationNode> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
ScalingParams loadScalingParams(Common::File *roomFile, int roomOffset);
+ byte *loadShadowMap(int roomNumber);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index b3633c300ea..d37fa8fe089 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -41,38 +41,72 @@ void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color
surface->drawLine(x + w, y, x + w, y + h, color);
}
-size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data) {
- // Check for uncompressed markers
- if (size == 0x8000 || size == 0x6800) {
- *out_data = (uint8_t *)malloc(size);
- memcpy(*out_data, data + offset, size);
- return size;
+size_t rleDecompress(
+ const uint8_t *input,
+ size_t inputSize,
+ uint32_t offset,
+ uint32_t expectedSize,
+ uint8_t **out_data,
+ bool untilBuda
+) {
+ // // Check for uncompressed markers
+ if (inputSize == 0x8000 || inputSize == 0x6800) {
+ *out_data = (uint8_t *)malloc(inputSize);
+ memcpy(*out_data, input + offset, inputSize);
+ return inputSize;
}
// RLE compressed
- *out_data = (uint8_t *)malloc(EXPECTED_SIZE * 2); // Allocate enough space
+ size_t bufferCapacity;
size_t result_size = 0;
-
uint32_t pos = offset;
- uint32_t end = offset + size;
- while (pos + 2 <= end && pos + 2 <= data_size) {
+ if (untilBuda) {
+ // Dynamic allocation mode - grow buffer as needed
+ bufferCapacity = 4096;
+ *out_data = (uint8_t *)malloc(bufferCapacity);
+ if (!*out_data)
+ return 0;
+ } else {
+ // Fixed size mode
+ bufferCapacity = expectedSize;
+ *out_data = (uint8_t *)malloc(expectedSize);
+ if (!*out_data)
+ return 0;
+ }
+
+ while (pos + 2 <= inputSize) {
// Check for BUDA marker
- if (pos + 4 <= data_size &&
- data[pos] == 'B' && data[pos + 1] == 'U' &&
- data[pos + 2] == 'D' && data[pos + 3] == 'A') {
+ if (pos + 4 <= inputSize &&
+ input[pos] == 'B' && input[pos + 1] == 'U' &&
+ input[pos + 2] == 'D' && input[pos + 3] == 'A') {
break;
}
- uint8_t count = data[pos];
- uint8_t value = data[pos + 1];
+ uint8_t count = input[pos];
+ uint8_t value = input[pos + 1];
for (int i = 0; i < count; i++) {
+ // If in untilBuda mode, grow buffer as needed
+ if (untilBuda && result_size >= bufferCapacity) {
+ bufferCapacity *= 2;
+ uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
+ if (!newBuf) {
+ free(*out_data);
+ *out_data = nullptr;
+ return 0;
+ }
+ *out_data = newBuf;
+ }
// debug("Pos = %zu, writing value %02X", result_size, value);
(*out_data)[result_size++] = value;
}
pos += 2;
+ // In fixed size mode, stop when we reach expected size
+ if (!untilBuda && result_size >= expectedSize) {
+ break;
+ }
}
return result_size;
@@ -134,6 +168,7 @@ void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth
for (int y = 0; y < frameHeight; y++) {
for (int x = 0; x < frameWidth; x++) {
unsigned int src_pos = (frameIndex * frameHeight * frameWidth) + (y * frameWidth) + x;
+ // debug("Copying pixel from source pos %u to dest pos %d", src_pos, y * frameWidth + x);
dest[y * frameWidth + x] = source[src_pos];
}
}
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index ee91d2e394e..44b61c094c5 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -31,7 +31,7 @@
namespace Pelrock {
const int EXPECTED_SIZE = 640 * 400;
-size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data);
+size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data, bool untilBuda = true);
void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize);
void drawSpriteToBuffer(byte *buffer, int bufferWidth,
byte *sprite, int x, int y,
Commit: 2df4ff4791bb646355af01432631116a758b6b27
https://github.com/scummvm/scummvm/commit/2df4ff4791bb646355af01432631116a758b6b27
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:14+02:00
Commit Message:
PELROCK: Loads shadow map
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index cef91e013e3..0592b3e05d2 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -124,6 +124,9 @@ Common::Error PelrockEngine::run() {
case Common::KEYCODE_i:
alfredState = ALFRED_INTERACTING;
break;
+ case Common::KEYCODE_z:
+ showShadows = !showShadows;
+ break;
default:
break;
}
@@ -441,7 +444,13 @@ void PelrockEngine::frames() {
if (_curWalkTarget.y + 2 < 400)
_screen->setPixel(_curWalkTarget.x, _curWalkTarget.y + 2, 100);
}
+
+ if(showShadows) {
+ memcpy(_screen->getPixels(), _room->_pixelsShadows, 640 * 400);
+ }
+
_screen->markAllDirty();
+
// _screen->update();
}
}
@@ -1516,7 +1525,7 @@ void PelrockEngine::setScreen(int number, int dir) {
}
}
- _room->loadRoomMetadata(&roomFile, roomOffset);
+ _room->loadRoomMetadata(&roomFile, number);
_room->loadRoomTalkingAnimations(number);
_screen->markAllDirty();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 425b073bb9a..a3c93bb0036 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -150,6 +150,8 @@ private:
uint16 whichNPCTalking = 0;
bool isNPCBTalking = false;
+ bool showShadows = false;
+
// JAVA
bool shouldPlayIntro = false;
GameState stateGame = INTRO;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index f79e999bf59..35b2f1c45a9 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -27,7 +27,7 @@
namespace Pelrock {
RoomManager::RoomManager() {
- pixelsShadows = new byte[640*400] { 0 };
+ _pixelsShadows = new byte[640*400] { 0 };
}
RoomManager::~RoomManager() {
@@ -37,7 +37,7 @@ RoomManager::~RoomManager() {
// delete[] _currentRoomWalkboxes;
// delete[] _currentRoomDescriptions;
// delete[] _currentRoomConversations;
- delete[] pixelsShadows;
+ delete[] _pixelsShadows;
}
void RoomManager::getPalette(Common::File *roomFile, int roomOffset, byte *palette) {
@@ -142,9 +142,10 @@ Common::Array<HotSpot> RoomManager::loadHotspots(Common::File *roomFile, int roo
// roomFile->seek(hover_areas_start, SEEK_SET);
}
-void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
+void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
uint32_t outPos = 0;
+ int roomOffset = roomNumber * kRoomStructSize;
Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
debug("After decsriptions, position is %d", outPos);
Common::Array<ConversationNode> roots = loadConversations(roomFile, roomOffset, outPos);
@@ -185,6 +186,9 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
hotspots.push_back(hotspot);
}
+
+ byte *shadows = loadShadowMap(roomNumber);
+
int walkboxCount = 0;
_currentRoomAnims = anims;
@@ -193,6 +197,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
_currentRoomWalkboxes = walkboxes;
_currentRoomDescriptions = descriptions;
_scaleParams = scalingParams;
+ _pixelsShadows = shadows;
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
drawRect(g_engine->_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
@@ -203,6 +208,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomOffset) {
// drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
}
}
+
Common::Array<AnimSet> RoomManager::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
uint32_t pair_offset = roomOffset + (8 * 8);
// debug("Sprite pair offset position: %d", pair_offset);
@@ -859,14 +865,20 @@ byte *RoomManager::loadShadowMap(int roomNumber) {
uint32 entryOffset = roomNumber * 6;
+ debug("Loading shadow map for room %d at offset %d", roomNumber, entryOffset);
+
shadowMapFile.seek(entryOffset, SEEK_SET);
uint32 shadowOffset = readUint24(shadowMapFile);
- shadowMapFile.seek(shadowOffset, SEEK_SET);
+ byte *compressed = nullptr;
+ size_t compressedSize = 0;
+ readUntilBuda(&shadowMapFile, shadowOffset, compressed, compressedSize);
- // pixelsShadows = rleDecompress(
-
-
- return nullptr;
+ debug("Shadow map compressed size: %zu", compressedSize);
+ byte *shadows = nullptr;
+ size_t output = rleDecompress(compressed, compressedSize, 0, 640 * 400, &shadows);
+ free(compressed);
+ return shadows;
}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 04237eb3c84..8044a194ba7 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -33,7 +33,7 @@ class RoomManager {
public:
RoomManager();
~RoomManager();
- void loadRoomMetadata(Common::File *roomFile, int roomOffset);
+ void loadRoomMetadata(Common::File *roomFile, int roomNumber);
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
@@ -46,7 +46,7 @@ public:
Common::Array<ConversationNode> _currentRoomConversations;
TalkingAnimHeader _talkingAnimHeader;
ScalingParams _scaleParams;
- byte *pixelsShadows = nullptr;
+ byte *_pixelsShadows = nullptr;
private:
Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
Commit: 3240f59bd457ba7f68ec50a24ad20bf034f5d3ef
https://github.com/scummvm/scummvm/commit/3240f59bd457ba7f68ec50a24ad20bf034f5d3ef
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:14+02:00
Commit Message:
PELROCK: Character shading
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 0592b3e05d2..dd96f27459a 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -185,8 +185,8 @@ void PelrockEngine::init() {
gameInitialized = true;
loadAnims();
setScreen(6, 0); // museum entrance
- // setScreen(13, 1); // restaurants kitchen
- // setScreen(2, 2); // hooker
+ // setScreen(13, 1); // restaurants kitchen
+ // setScreen(2, 2); // hooker
}
}
@@ -445,7 +445,7 @@ void PelrockEngine::frames() {
_screen->setPixel(_curWalkTarget.x, _curWalkTarget.y + 2, 100);
}
- if(showShadows) {
+ if (showShadows) {
memcpy(_screen->getPixels(), _room->_pixelsShadows, 640 * 400);
}
@@ -503,12 +503,12 @@ void PelrockEngine::drawAlfred(byte *buf) {
debug("lines to skip = %d, finalHeight = %d, finalWidth = %d for position (%d, %d)", linesToSkip, finalHeight, finalWidth, xAlfred, yAlfred);
- if (linesToSkip <= 0) {
- // No skipping needed, output all lines
- drawSpriteToBuffer(_compositeBuffer, 640, buf, xAlfred, yAlfred - kAlfredFrameHeight, kAlfredFrameWidth, kAlfredFrameHeight, 255);
- } else {
+ int shadowPos = yAlfred; // - finalHeight;
+ bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + xAlfred] != 0xFF;
+
+ byte *finalBuf = new byte[finalWidth * finalHeight];
- byte *scaledData = new byte[finalWidth * finalHeight];
+ if (linesToSkip > 0) {
int skipInterval = kAlfredFrameHeight / linesToSkip;
Common::Array<float> idealSkipPositions;
for (int i = 0; i < linesToSkip; i++) {
@@ -572,15 +572,25 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
int srcIndex = srcY * kAlfredFrameWidth + srcX;
int outIndex = outY * finalWidth + outX;
- scaledData[outIndex] = buf[srcIndex];
+ finalBuf[outIndex] = buf[srcIndex];
}
outY++;
}
}
- drawSpriteToBuffer(_compositeBuffer, 640, scaledData, xAlfred, yAlfred - finalHeight, finalWidth, finalHeight, 255);
+ } else {
+ Common::copy(buf, buf + (kAlfredFrameWidth * kAlfredFrameHeight), finalBuf);
+ }
- delete[] scaledData;
+ if (shadeCharacter) {
+ for (int i = 0; i < finalWidth * finalHeight; i++) {
+ if (finalBuf[i] != 255) {
+ finalBuf[i] = _room->alfredRemap[finalBuf[i]];
+ }
+ }
}
+
+ drawSpriteToBuffer(_compositeBuffer, 640, finalBuf, xAlfred, yAlfred - finalHeight, finalWidth, finalHeight, 255);
+ delete[] finalBuf;
}
void PelrockEngine::drawNextFrame(AnimSet *animSet) {
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 35b2f1c45a9..6ab3b08acae 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -188,6 +188,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
byte *shadows = loadShadowMap(roomNumber);
+ loadRemaps(roomNumber);
int walkboxCount = 0;
@@ -878,7 +879,23 @@ byte *RoomManager::loadShadowMap(int roomNumber) {
byte *shadows = nullptr;
size_t output = rleDecompress(compressed, compressedSize, 0, 640 * 400, &shadows);
free(compressed);
+ shadowMapFile.close();
return shadows;
}
+void RoomManager::loadRemaps(int roomNumber) {
+
+ Common::File remapFile;
+ if (!remapFile.open("ALFRED.9")) {
+ error("Couldnt find file ALFRED.9");
+ }
+
+ uint32 remapOffset = 0x200 + (roomNumber * 1024);
+
+ remapFile.seek(remapOffset, SEEK_SET);
+ remapFile.read(alfredRemap, 256);
+ remapFile.read(overlayRemap, 256);
+ remapFile.close();
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 8044a194ba7..688357a92a3 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -47,6 +47,8 @@ public:
TalkingAnimHeader _talkingAnimHeader;
ScalingParams _scaleParams;
byte *_pixelsShadows = nullptr;
+ byte alfredRemap[256];
+ byte overlayRemap[256];
private:
Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
@@ -62,6 +64,7 @@ private:
Common::Array<ConversationNode> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
ScalingParams loadScalingParams(Common::File *roomFile, int roomOffset);
byte *loadShadowMap(int roomNumber);
+ void loadRemaps(int roomNumber);
};
} // End of namespace Pelrock
Commit: 58faeb41d2f033a425677b110ebe20d8a1efee61
https://github.com/scummvm/scummvm/commit/58faeb41d2f033a425677b110ebe20d8a1efee61
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:14+02:00
Commit Message:
PELROCK: Dialog choice overlay
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index dd96f27459a..98830523ea1 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -223,6 +223,18 @@ void PelrockEngine::talk(byte object) {
// }
}
+void PelrockEngine::displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer) {
+ int overlayHeight = choices.size() * kChoiceHeight + 2;
+ int overlayY = 400 - overlayHeight;
+ debug("Displaying choices overlay at y=%d, height=%d", overlayY, overlayHeight);
+ for (int x = 0; x < 640; x++) {
+ for (int y = overlayY; y < 400; y++) {
+ int index = y * 640 + x;
+ compositeBuffer[index] = _room->overlayRemap[compositeBuffer[index]];
+ }
+ }
+}
+
byte *PelrockEngine::grabBackgroundSlice(int x, int y, int w, int h) {
byte *bg = new byte[w * h];
for (int j = 0; j < w; j++) {
@@ -397,6 +409,12 @@ void PelrockEngine::frames() {
_currentPopupFrame = 0;
}
+ Common::Array<Common::String> testChoices;
+ testChoices.push_back("First choice");
+ testChoices.push_back("Second choice");
+ testChoices.push_back("Third choice");
+ displayChoices(testChoices, _compositeBuffer);
+
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
if (alfredState != ALFRED_WALKING && !_currentTextPages.empty()) {
@@ -516,12 +534,12 @@ void PelrockEngine::drawAlfred(byte *buf) {
idealSkipPositions.push_back(idealPos);
}
- debug("Ideal skip positions:");
+ // debug("Ideal skip positions:");
for (size_t i = 0; i < idealSkipPositions.size(); i++) {
debug(" %.2f", idealSkipPositions[i]);
}
- debug("Height scaling table size =%d", _heightScalingTable.size());
+ // debug("Height scaling table size =%d", _heightScalingTable.size());
Common::Array<int> tableSkipPositions;
for (int scanline = 0; scanline < kAlfredFrameHeight; scanline++) {
if (_heightScalingTable[scaleIndex][scanline] != 0) {
@@ -529,10 +547,10 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
}
- debug("Table skip positions:");
- for (size_t i = 0; i < tableSkipPositions.size(); i++) {
- debug(" %d", tableSkipPositions[i]);
- }
+ // debug("Table skip positions:");
+ // for (size_t i = 0; i < tableSkipPositions.size(); i++) {
+ // debug(" %d", tableSkipPositions[i]);
+ // }
Common::Array<int> skipTheseLines;
for (size_t i = 0; i < idealSkipPositions.size(); i++) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index a3c93bb0036..a99f60a6e5e 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -75,6 +75,8 @@ private:
MovementStep *movement_buffer);
void talk(byte object);
+ void displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer);
+
byte *grabBackgroundSlice(int x, int y, int w, int h);
void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 99ded11b46e..587bcbf0301 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -66,7 +66,7 @@ const int kVerbIconPadding = 20;
const int kAlfredFrameWidth = 51;
const int kAlfredFrameHeight = 102;
-
+const int kChoiceHeight = 16; // Height of each choice line in pixels
enum AlfredState {
ALFRED_IDLE,
Commit: a7e5c9cf2ad5ebc3da3411949f5f24e374974d27
https://github.com/scummvm/scummvm/commit/a7e5c9cf2ad5ebc3da3411949f5f24e374974d27
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:15+02:00
Commit Message:
PELROCK: Loads room names
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/util.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 98830523ea1..653ce77042c 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -49,8 +49,6 @@ PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) :
_gameDescription(gameDesc), _randomSource("Pelrock") {
g_engine = this;
_chronoManager = new ChronoManager();
- _room = new RoomManager();
- _res = new ResourceManager();
}
PelrockEngine::~PelrockEngine() {
@@ -82,6 +80,8 @@ Common::Error PelrockEngine::run() {
initGraphics(640, 400);
_screen = new Graphics::Screen();
_videoManager = new VideoManager(_screen);
+ _room = new RoomManager();
+ _res = new ResourceManager();
// Set the engine's debugger console
setDebugger(new Console());
@@ -226,7 +226,7 @@ void PelrockEngine::talk(byte object) {
void PelrockEngine::displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer) {
int overlayHeight = choices.size() * kChoiceHeight + 2;
int overlayY = 400 - overlayHeight;
- debug("Displaying choices overlay at y=%d, height=%d", overlayY, overlayHeight);
+ // debug("Displaying choices overlay at y=%d, height=%d", overlayY, overlayHeight);
for (int x = 0; x < 640; x++) {
for (int y = overlayY; y < 400; y++) {
int index = y * 640 + x;
@@ -516,10 +516,10 @@ void PelrockEngine::drawAlfred(byte *buf) {
if (scaleIndex < 0) {
scaleIndex = 0;
}
- debug("Scaling Alfred frame to final size (%d x %d) from scale factor %.2f", finalWidth, finalHeight, scaleFactor);
+ // debug("Scaling Alfred frame to final size (%d x %d) from scale factor %.2f", finalWidth, finalHeight, scaleFactor);
int linesToSkip = kAlfredFrameHeight - finalHeight;
- debug("lines to skip = %d, finalHeight = %d, finalWidth = %d for position (%d, %d)", linesToSkip, finalHeight, finalWidth, xAlfred, yAlfred);
+ // debug("lines to skip = %d, finalHeight = %d, finalWidth = %d for position (%d, %d)", linesToSkip, finalHeight, finalWidth, xAlfred, yAlfred);
int shadowPos = yAlfred; // - finalHeight;
bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + xAlfred] != 0xFF;
@@ -534,11 +534,6 @@ void PelrockEngine::drawAlfred(byte *buf) {
idealSkipPositions.push_back(idealPos);
}
- // debug("Ideal skip positions:");
- for (size_t i = 0; i < idealSkipPositions.size(); i++) {
- debug(" %.2f", idealSkipPositions[i]);
- }
-
// debug("Height scaling table size =%d", _heightScalingTable.size());
Common::Array<int> tableSkipPositions;
for (int scanline = 0; scanline < kAlfredFrameHeight; scanline++) {
@@ -875,9 +870,6 @@ void PelrockEngine::walkTo(int x, int y) {
// debug("================\n");
// debug("Walkbox path (%d boxes): ", context.path_length);
- for (int i = 0; i < context.path_length && context.path_buffer[i] != PATH_END; i++) {
- debug("%d ", context.path_buffer[i]);
- }
// debug("Movement steps (%d steps):\n", context.movement_count);
for (int i = 0; i < context.movement_count; i++) {
@@ -897,9 +889,6 @@ void PelrockEngine::walkTo(int x, int y) {
}
// debug("\nCompressed path (%d bytes): ", context.compressed_length);
- for (int i = 0; i < context.compressed_length; i++) {
- debug("%02X ", context.compressed_path[i]);
- }
// if (x > xAlfred) {
// dirAlfred = RIGHT;
@@ -923,9 +912,6 @@ bool PelrockEngine::pathFind(int x, int y, PathContext *context) {
if (context->movement_buffer == NULL) {
context->movement_buffer = (MovementStep *)malloc(MAX_MOVEMENT_STEPS * sizeof(MovementStep));
}
- // if (context->compressed_path == NULL) {
- // context->compressed_path = (uint8_t*)malloc(MAX_COMPRESSED_PATH);
- // }
int startX = xAlfred;
int startY = yAlfred;
@@ -1212,11 +1198,8 @@ void PelrockEngine::checkMouseClick(int x, int y) {
if (_displayPopup) {
Common::Array<VerbIcons> actions = availableActions(_currentHotspot);
- for (int i = 0; i < actions.size(); i++) {
- debug("Available action %d at index %d", actions[i], i);
- }
+
Common::Rect lookRect = Common::Rect(_popupX + 20, _popupY + 20, _popupX + 20 + kVerbIconWidth, _popupY + 20 + kVerbIconHeight);
- // debug("Look rect: x=%d, y=%d, w=%d, h=%d", lookRect.left, lookRect.top, lookRect, lookRect.h);
if (lookRect.contains(x, y)) {
debug("Look action clicked");
walkTo(_currentHotspot->x, _currentHotspot->y);
@@ -1226,7 +1209,6 @@ void PelrockEngine::checkMouseClick(int x, int y) {
}
for (int i = 1; i < actions.size(); i++) {
- // debug("Checking action %d at index %d for mouse click = %d, %d", actions[i], i, x, y);
int x = _popupX + 20 + (i * (kVerbIconWidth + 2));
int y = _popupY + 20;
Common::Rect actionRect = Common::Rect(x, y, x + kVerbIconWidth, y + kVerbIconHeight);
@@ -1523,6 +1505,7 @@ Common::Array<Common::Array<Common::String>> wordWrap(Common::String text) {
void PelrockEngine::setScreen(int number, int dir) {
Common::File roomFile;
+ debug("Loading room %s number %d", _room->getRoomName(number).c_str(), number);
if (!roomFile.open(Common::Path("ALFRED.1"))) {
error("Could not open ALFRED.1");
return;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 117fa5f5a5e..d451a8bc859 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -142,7 +142,7 @@ void ResourceManager::loadAlfredAnims() {
alfredWalkFrames[i] = new byte *[walkingAnimLengths[i]];
int standingFrame = prevWalkingFrames;
- debug("Loading standing frame %d at index %d", i, standingFrame);
+
extractSingleFrame(pic, alfredIdle[i], standingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
for (int j = 0; j < walkingAnimLengths[i]; j++) {
@@ -199,11 +199,7 @@ void ResourceManager::loadAlfredAnims() {
readUntilBuda(&alfred7, ALFRED7_ALFRED_COMB_L, alfredCombLeftRaw, alfredCombLeftSize);
byte *alfredCombLeft = nullptr;
size_t outSize = rleDecompress(alfredCombLeftRaw, alfredCombLeftSize, 0, spriteMapSize, &alfredCombLeft);
- debug("Sprite map size: %d, %d, %d", spriteMapSize, alfredCombLeftSize, outSize);
- for (int i = 0; i < 11; i++) {
- debug("Extracting comb left frame %d", i);
- }
for (int i = 0; i < 11; i++) {
alfredCombFrames[1][i] = new byte[frameSize];
extractSingleFrame(alfredCombLeft, alfredCombFrames[1][i], i, kAlfredFrameWidth, kAlfredFrameHeight);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 6ab3b08acae..4aa4ad0c31a 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+#include "common/scummsys.h"
#include "pelrock/room.h"
#include "pelrock/pelrock.h"
@@ -27,7 +28,11 @@
namespace Pelrock {
RoomManager::RoomManager() {
- _pixelsShadows = new byte[640*400] { 0 };
+ _pixelsShadows = new byte[640 * 400]{0};
+ _roomNames = loadRoomNames();
+ for (int i = 0; i < _roomNames.size(); i++) {
+ debug("Room %d name: %s", i, _roomNames[i].c_str());
+ }
}
RoomManager::~RoomManager() {
@@ -115,7 +120,7 @@ Common::Array<Exit> RoomManager::loadExits(Common::File *roomFile, int roomOffse
Common::Array<HotSpot> RoomManager::loadHotspots(Common::File *roomFile, int roomOffset) {
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- debug("Hotspot(10) pair offset position: %d", pair10_offset_pos);
+ // debug("Hotspot(10) pair offset position: %d", pair10_offset_pos);
roomFile->seek(pair10_offset_pos, SEEK_SET);
uint32_t pair10_data_offset = roomFile->readUint32LE();
uint32_t pair10_size = roomFile->readUint32LE();
@@ -134,7 +139,7 @@ Common::Array<HotSpot> RoomManager::loadHotspots(Common::File *roomFile, int roo
spot.w = roomFile->readByte();
spot.h = roomFile->readByte();
spot.extra = roomFile->readUint16LE();
- debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
+ // debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
hotspots.push_back(spot);
}
return hotspots;
@@ -186,7 +191,6 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
hotspots.push_back(hotspot);
}
-
byte *shadows = loadShadowMap(roomNumber);
loadRemaps(roomNumber);
@@ -299,8 +303,7 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(Common::File *roomFile, int ro
roomFile->seek(walkbox_countOffset, SEEK_SET);
byte walkbox_count = roomFile->readByte();
-
- debug("Walkbox count: %d", walkbox_count);
+ // debug("Walkbox count: %d", walkbox_count);
uint32_t walkbox_offset = pair10_data_offset + 0x218;
Common::Array<WalkBox> walkboxes;
for (int i = 0; i < walkbox_count; i++) {
@@ -311,7 +314,7 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(Common::File *roomFile, int ro
int16 w = roomFile->readSint16LE();
int16 h = roomFile->readSint16LE();
byte flags = roomFile->readByte();
- debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+ // debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
WalkBox box;
box.x = x1;
box.y = y1;
@@ -352,7 +355,7 @@ Common::Array<Description> RoomManager::loadRoomDescriptions(Common::File *roomF
}
if (data[pos] == 0xF8) {
description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
- debug("Found action trigger: %d", description.actionTrigger);
+ // debug("Found action trigger: %d", description.actionTrigger);
pos += 2;
break;
}
@@ -360,14 +363,14 @@ Common::Array<Description> RoomManager::loadRoomDescriptions(Common::File *roomF
// debug("Current desc: %s", desc);
pos++;
}
- debug("Found description for item %d index %d, text: %s", description.itemId, description.index, description.text.c_str());
+ // debug("Found description for item %d index %d, text: %s", description.itemId, description.index, description.text.c_str());
descriptions.push_back(description);
lastDescPos = pos;
}
pos++;
}
- debug("End of descriptions at position %d", pos);
+ // debug("End of descriptions at position %d", pos);
outPos = lastDescPos + 1;
delete[] data;
// for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
@@ -376,7 +379,6 @@ Common::Array<Description> RoomManager::loadRoomDescriptions(Common::File *roomF
return descriptions;
}
-
char32_t decodeByte(byte b) {
if (b == 0x80) {
return '\xA4';
@@ -457,11 +459,10 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
readUntilBuda(&talkFile, talkHeader.spritePointer, data, dataSize);
size_t decompressedSize = rleDecompress(data, dataSize, 0, dataSize, &decompressed);
free(data);
- debug("Decompressed talking anim A size: %zu, decompressed size: %zu", dataSize, decompressedSize);
+ // debug("Decompressed talking anim A size: %zu, decompressed size: %zu", dataSize, decompressedSize);
for (int i = 0; i < talkHeader.numFramesAnimA; i++) {
talkHeader.animA[i] = new byte[talkHeader.wAnimA * talkHeader.hAnimA];
extractSingleFrame(decompressed, talkHeader.animA[i], i, talkHeader.wAnimA, talkHeader.hAnimA);
-
}
if (talkHeader.numFramesAnimB > 0) {
@@ -866,8 +867,6 @@ byte *RoomManager::loadShadowMap(int roomNumber) {
uint32 entryOffset = roomNumber * 6;
- debug("Loading shadow map for room %d at offset %d", roomNumber, entryOffset);
-
shadowMapFile.seek(entryOffset, SEEK_SET);
uint32 shadowOffset = readUint24(shadowMapFile);
@@ -875,7 +874,6 @@ byte *RoomManager::loadShadowMap(int roomNumber) {
size_t compressedSize = 0;
readUntilBuda(&shadowMapFile, shadowOffset, compressed, compressedSize);
- debug("Shadow map compressed size: %zu", compressedSize);
byte *shadows = nullptr;
size_t output = rleDecompress(compressed, compressedSize, 0, 640 * 400, &shadows);
free(compressed);
@@ -898,4 +896,38 @@ void RoomManager::loadRemaps(int roomNumber) {
remapFile.close();
}
+Common::Array<Common::String> RoomManager::loadRoomNames() {
+ Common::Array<Common::String> roomNames;
+ Common::File juegoExe;
+ if (!juegoExe.open(Common::Path("JUEGO.EXE"))) {
+ error("Couldnt find file JUEGO.EXE");
+ }
+
+ size_t namesSize = 1335;
+ juegoExe.seek(0x49315, SEEK_SET);
+ byte *namesData = new byte[namesSize];
+ juegoExe.read(namesData, namesSize);
+ uint32 pos = 0;
+ Common::String currentName = "";
+ while (pos < namesSize) {
+ if (namesData[pos] == 0xFD &&
+ namesData[pos + 1] == 0x00 &&
+ namesData[pos + 2] == 0x08 &&
+ namesData[pos + 3] == 0x02) {
+ if (currentName.size() > 0 ) {
+ debug("Found room name: %s", currentName.c_str());
+ roomNames.push_back(currentName);
+ }
+ currentName = "";
+ pos += 4;
+ continue;
+ }
+ currentName += (char)namesData[pos];
+ pos++;
+ }
+ delete[] namesData;
+ juegoExe.close();
+ return roomNames;
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 688357a92a3..97c72dcd8bb 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -37,6 +37,12 @@ public:
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
+ Common::String getRoomName(int roomNumber) {
+ if (roomNumber >= 0 && roomNumber < _roomNames.size()) {
+ return _roomNames[roomNumber];
+ }
+ return "Unknown Room";
+ }
Common::Array<HotSpot> _currentRoomHotspots;
Common::Array<AnimSet> _currentRoomAnims;
@@ -49,6 +55,7 @@ public:
byte *_pixelsShadows = nullptr;
byte alfredRemap[256];
byte overlayRemap[256];
+ Common::Array<Common::String> _roomNames;
private:
Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
@@ -65,6 +72,8 @@ private:
ScalingParams loadScalingParams(Common::File *roomFile, int roomOffset);
byte *loadShadowMap(int roomNumber);
void loadRemaps(int roomNumber);
+ Common::Array<Common::String> loadRoomNames();
+
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index d37fa8fe089..46e3e532e4a 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -137,7 +137,6 @@ void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *
break;
}
}
- debug("Read %zu bytes until BUDA marker", pos);
outSize = pos;
}
Commit: 10986e7bb073cd7b849f1f1c3685f06e735699ec
https://github.com/scummvm/scummvm/commit/10986e7bb073cd7b849f1f1c3685f06e735699ec
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:15+02:00
Commit Message:
PELROCK: Music playback (from mp3)
Changed paths:
A engines/pelrock/sound.cpp
A engines/pelrock/sound.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index 88894769896..f6b1579cff6 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -10,6 +10,7 @@ MODULE_OBJS = \
fonts/large_font.o \
util.o \
resources.o\
+ sound.o \
video/video.o
# This module can be built as a plugin
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 653ce77042c..474b10a4f69 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -52,14 +52,15 @@ PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) :
}
PelrockEngine::~PelrockEngine() {
- delete _room;
delete[] _compositeBuffer;
delete[] _currentBackground;
delete _largeFont;
delete _screen;
delete _chronoManager;
delete _videoManager;
-
+ delete _soundManager;
+ delete _room;
+ delete _res;
// if (_bgPopupBalloon)
// delete[] _bgPopupBalloon;
delete _smallFont;
@@ -82,6 +83,7 @@ Common::Error PelrockEngine::run() {
_videoManager = new VideoManager(_screen);
_room = new RoomManager();
_res = new ResourceManager();
+ _soundManager = new SoundManager(_mixer);
// Set the engine's debugger console
setDebugger(new Console());
@@ -184,7 +186,8 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(6, 0); // museum entrance
+ setScreen(0, 0);
+ // setScreen(6, 0); // museum entrance
// setScreen(13, 1); // restaurants kitchen
// setScreen(2, 2); // hooker
}
@@ -1538,7 +1541,11 @@ void PelrockEngine::setScreen(int number, int dir) {
_room->loadRoomMetadata(&roomFile, number);
_room->loadRoomTalkingAnimations(number);
-
+ if(_room->_musicTrack > 0)
+ _soundManager->playMusicTrack(_room->_musicTrack);
+ else {
+ _soundManager->stopMusic();
+ }
_screen->markAllDirty();
roomFile.close();
delete[] background;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index a99f60a6e5e..6b1ac2a4e02 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -42,6 +42,7 @@
#include "pelrock/fonts/small_font.h"
#include "pelrock/resources.h"
#include "pelrock/room.h"
+#include "pelrock/sound.h"
#include "pelrock/types.h"
#include "pelrock/video/video.h"
@@ -175,6 +176,7 @@ public:
AlfredState alfredState = ALFRED_IDLE;
ChronoManager *_chronoManager = nullptr;
VideoManager *_videoManager = nullptr;
+ SoundManager *_soundManager = nullptr;
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index d451a8bc859..02a952a46b1 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -44,7 +44,7 @@ ResourceManager::~ResourceManager() {
delete[] alfredTalkFrames[i][j];
}
- for(int j = 0; j < 4; j ++) {
+ for(int j = 0; j < 2; j ++) {
delete[] alfredInteractFrames[i][j];
}
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 4aa4ad0c31a..27fc9d7601c 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -28,7 +28,7 @@
namespace Pelrock {
RoomManager::RoomManager() {
- _pixelsShadows = new byte[640 * 400]{0};
+ _pixelsShadows = new byte[640 * 400];
_roomNames = loadRoomNames();
for (int i = 0; i < _roomNames.size(); i++) {
debug("Room %d name: %s", i, _roomNames[i].c_str());
@@ -42,7 +42,10 @@ RoomManager::~RoomManager() {
// delete[] _currentRoomWalkboxes;
// delete[] _currentRoomDescriptions;
// delete[] _currentRoomConversations;
- delete[] _pixelsShadows;
+ if(_pixelsShadows != nullptr) {
+ delete[] _pixelsShadows;
+ _pixelsShadows = nullptr;
+ }
}
void RoomManager::getPalette(Common::File *roomFile, int roomOffset, byte *palette) {
@@ -194,15 +197,18 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
byte *shadows = loadShadowMap(roomNumber);
loadRemaps(roomNumber);
- int walkboxCount = 0;
+ Common::Array<int> sfx = loadRoomSfx(roomFile, roomOffset);
+ int walkboxCount = 0;
_currentRoomAnims = anims;
_currentRoomHotspots = hotspots;
_currentRoomExits = exits;
_currentRoomWalkboxes = walkboxes;
_currentRoomDescriptions = descriptions;
_scaleParams = scalingParams;
- _pixelsShadows = shadows;
+ Common::copy(shadows, shadows + (640 * 400), _pixelsShadows);
+ _musicTrack = loadMusicTrackForRoom(roomFile, roomOffset);
+ _roomSfx = sfx;
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
drawRect(g_engine->_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
@@ -930,4 +936,33 @@ Common::Array<Common::String> RoomManager::loadRoomNames() {
return roomNames;
}
+byte RoomManager::loadMusicTrackForRoom(Common::File *roomFile, int roomOffset) {
+ uint32_t pair9offset = roomOffset + (9 * 8);
+ roomFile->seek(pair9offset, SEEK_SET);
+ uint32_t pair9_data_offset = roomFile->readUint32LE();
+ uint32_t pair9_size = roomFile->readUint32LE();
+
+ roomFile->seek(pair9_data_offset, SEEK_SET);
+ byte musicTrack = roomFile->readByte();
+ debug("Music track for room at offset %d is %d", roomOffset, musicTrack);
+ return musicTrack + 1;
+}
+
+Common::Array<int> RoomManager::loadRoomSfx(Common::File *roomFile, int roomOffset) {
+ uint32_t pair9offset = roomOffset + (9 * 8);
+ roomFile->seek(pair9offset, SEEK_SET);
+ uint32_t pair9_data_offset = roomFile->readUint32LE();
+ uint32_t pair9_size = roomFile->readUint32LE();
+
+ roomFile->seek(pair9_data_offset, SEEK_SET);
+ roomFile->skip(1); // skip music track byte
+ Common::Array<int> roomSfx;
+ for(int i=0; i< 9; i++) {
+ byte sfx = roomFile->readByte();
+ roomSfx.push_back((int)sfx);
+ debug("SFX %d for room at offset %d is %d", i, roomOffset, sfx);
+ }
+ return roomSfx;
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 97c72dcd8bb..c5cc6f209f6 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -56,6 +56,8 @@ public:
byte alfredRemap[256];
byte overlayRemap[256];
Common::Array<Common::String> _roomNames;
+ byte _musicTrack = 0;
+ Common::Array<int> _roomSfx;
private:
Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
@@ -73,7 +75,8 @@ private:
byte *loadShadowMap(int roomNumber);
void loadRemaps(int roomNumber);
Common::Array<Common::String> loadRoomNames();
-
+ byte loadMusicTrackForRoom(Common::File *roomFile, int roomOffset);
+ Common::Array<int> loadRoomSfx(Common::File *roomFile, int roomOffset);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
new file mode 100644
index 00000000000..3733aaa76a1
--- /dev/null
+++ b/engines/pelrock/sound.cpp
@@ -0,0 +1,97 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "audio/audiostream.h"
+#include "audio/decoders/mp3.h"
+#include "audio/mixer.h"
+#include "common/file.h"
+#include "common/scummsys.h"
+
+#include "pelrock/sound.h"
+
+namespace Pelrock {
+
+SoundManager::SoundManager(Audio::Mixer *mixer)
+ : _mixer(mixer), _currentVolume(255), _musicFile(nullptr) {
+ // TODO: Initialize sound manager
+}
+
+SoundManager::~SoundManager() {
+ stopSound();
+ stopMusic();
+}
+
+void SoundManager::playSound(const Common::String &filename, int volume) {
+ // TODO: Play sound file
+}
+
+void SoundManager::stopSound() {
+ // _mixer->stopHandle(_soundHandle);
+ // TODO: Stop currently playing sound
+}
+
+void SoundManager::setVolume(int volume) {
+ // TODO: Set sound volume
+}
+
+bool SoundManager::isPlaying() const {
+ // TODO: Return whether a sound is playing
+ return false;
+}
+
+void SoundManager::stopMusic() {
+ if(_isMusicPlaying) {
+ _mixer->stopHandle(_musicHandle);
+ _isMusicPlaying = false;
+ }
+}
+
+void SoundManager::playMusicTrack(int trackNumber) {
+ if(_currentMusicTrack == trackNumber && _isMusicPlaying) {
+ // Already playing this track
+ return;
+ }
+ _currentMusicTrack = trackNumber;
+ stopSound();
+ // Open the file
+ _musicFile = new Common::File();
+ Common::String filename = Common::String::format("music/track%d.mp3", trackNumber);
+
+ if (!_musicFile->open(Common::Path(filename))) {
+ delete _musicFile;
+ _musicFile = nullptr;
+ return;
+ }
+#ifdef USE_MAD
+ Audio::SeekableAudioStream *stream = Audio::makeMP3Stream(_musicFile, DisposeAfterUse::YES);
+ if (!stream) {
+ _musicFile->close();
+ delete _musicFile;
+ _musicFile = nullptr;
+ return;
+ }
+ Audio::AudioStream *loopStream = Audio::makeLoopingAudioStream(stream, 0);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, loopStream, -1, _currentVolume);
+ _isMusicPlaying = true;
+ _musicFile = nullptr;
+#endif
+}
+} // End of namespace Pelrock
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
new file mode 100644
index 00000000000..6b7a0d67d8f
--- /dev/null
+++ b/engines/pelrock/sound.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PELROCK_SOUND_H
+#define PELROCK_SOUND_H
+
+#include "common/file.h"
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "audio/mixer.h"
+
+namespace Pelrock {
+
+class SoundManager {
+public:
+ SoundManager(Audio::Mixer *mixer);
+ ~SoundManager();
+
+ void playSound(const Common::String &filename, int volume = 255);
+ void stopSound();
+ void stopMusic();
+ void setVolume(int volume);
+ bool isPlaying() const;
+ void playMusicTrack(int trackNumber);
+ bool isMusicPlaying() const {
+ return _isMusicPlaying;
+ }
+
+private:
+ Audio::Mixer *_mixer;
+ Audio::SoundHandle _soundHandle;
+ Audio::SoundHandle _musicHandle;
+ bool _isMusicPlaying = false;
+ int _currentVolume;
+ Common::File *_musicFile;
+ byte _currentMusicTrack = 0;
+};
+
+} // End of namespace Pelrock
+
+#endif // PELROCK_SOUND_H
Commit: d2fa47a1150836545daab5492b48765099d9a7e9
https://github.com/scummvm/scummvm/commit/d2fa47a1150836545daab5492b48765099d9a7e9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:15+02:00
Commit Message:
PELROCK: Fix music stopage
Changed paths:
engines/pelrock/room.cpp
engines/pelrock/sound.cpp
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 27fc9d7601c..647b6470c3d 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -945,7 +945,7 @@ byte RoomManager::loadMusicTrackForRoom(Common::File *roomFile, int roomOffset)
roomFile->seek(pair9_data_offset, SEEK_SET);
byte musicTrack = roomFile->readByte();
debug("Music track for room at offset %d is %d", roomOffset, musicTrack);
- return musicTrack + 1;
+ return musicTrack > 0 ? musicTrack + 1 : 0;
}
Common::Array<int> RoomManager::loadRoomSfx(Common::File *roomFile, int roomOffset) {
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 3733aaa76a1..538cd52fc16 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -23,6 +23,7 @@
#include "audio/decoders/mp3.h"
#include "audio/mixer.h"
#include "common/file.h"
+#include "common/debug.h"
#include "common/scummsys.h"
#include "pelrock/sound.h"
@@ -59,6 +60,7 @@ bool SoundManager::isPlaying() const {
void SoundManager::stopMusic() {
if(_isMusicPlaying) {
+ debug("Stopping music");
_mixer->stopHandle(_musicHandle);
_isMusicPlaying = false;
}
@@ -70,7 +72,7 @@ void SoundManager::playMusicTrack(int trackNumber) {
return;
}
_currentMusicTrack = trackNumber;
- stopSound();
+ stopMusic();
// Open the file
_musicFile = new Common::File();
Common::String filename = Common::String::format("music/track%d.mp3", trackNumber);
@@ -89,7 +91,7 @@ void SoundManager::playMusicTrack(int trackNumber) {
return;
}
Audio::AudioStream *loopStream = Audio::makeLoopingAudioStream(stream, 0);
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, loopStream, -1, _currentVolume);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, loopStream, -1, _currentVolume);
_isMusicPlaying = true;
_musicFile = nullptr;
#endif
Commit: f1a3cd07d25ad973aeaae7c7f900ae54fd5f0b2e
https://github.com/scummvm/scummvm/commit/f1a3cd07d25ad973aeaae7c7f900ae54fd5f0b2e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:15+02:00
Commit Message:
PELROCK: Renders settings screen
Changed paths:
engines/pelrock/chrono.h
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/sound.h
engines/pelrock/types.h
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index ffdf43f3b3e..aa389db418d 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -25,8 +25,9 @@
namespace Pelrock {
-// const int kTickMs = 20;
-const int kTickMs = 55;
+const int kTickMs = 18;
+// const int kTickMs = 55;
+// const int kTickMs = 15;
const int kHalfTickMultiplier = 2;
class ChronoManager {
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 15dc427f85e..e69c4a34e87 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -39,6 +39,9 @@ namespace Pelrock {
static const uint32_t ALFRED7_ALFRED_COMB_R = 67768;
static const uint32_t ALFRED7_ALFRED_COMB_L = 88408;
+ static const uint32_t kSettingsMenuOffset = 910097; // Placeholder offset
+ static const uint32_t kSettingsPaletteOffset = 1038141; // 640 * 480
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 474b10a4f69..b217520a886 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -146,6 +146,13 @@ Common::Error PelrockEngine::run() {
checkMouseClick(e.mouse.x, e.mouse.y);
_displayPopup = false;
_longClick = false;
+ } else if (e.type == Common::EVENT_RBUTTONUP) {
+ if (stateGame != SETTINGS)
+ stateGame = SETTINGS;
+ else {
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+ stateGame = GAME;
+ }
}
}
if (_isMouseDown) {
@@ -157,7 +164,16 @@ Common::Error PelrockEngine::run() {
}
}
checkMouseHover();
- frames();
+ if (stateGame == SETTINGS) {
+
+ memcpy(_screen->getPixels(), _res->_mainMenu, 640 * 400);
+ g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+
+ } else if (stateGame == GAME) {
+ frames();
+ }
_screen->update();
// limiter.delayBeforeSwap();
@@ -171,7 +187,7 @@ void PelrockEngine::init() {
_res->loadCursors();
_res->loadInteractionIcons();
calculateScalingMasks();
-
+ _res->loadSettingsMenu();
_compositeBuffer = new byte[640 * 400];
_currentBackground = new byte[640 * 400];
@@ -188,8 +204,8 @@ void PelrockEngine::init() {
loadAnims();
setScreen(0, 0);
// setScreen(6, 0); // museum entrance
- // setScreen(13, 1); // restaurants kitchen
- // setScreen(2, 2); // hooker
+ // setScreen(13, 1); // restaurants kitchen
+ // setScreen(2, 2); // hooker
}
}
@@ -1541,7 +1557,7 @@ void PelrockEngine::setScreen(int number, int dir) {
_room->loadRoomMetadata(&roomFile, number);
_room->loadRoomTalkingAnimations(number);
- if(_room->_musicTrack > 0)
+ if (_room->_musicTrack > 0)
_soundManager->playMusicTrack(_room->_musicTrack);
else {
_soundManager->stopMusic();
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 02a952a46b1..193133af40c 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -23,6 +23,8 @@
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
+#include "resources.h"
+#include "room.h"
namespace Pelrock {
@@ -44,7 +46,7 @@ ResourceManager::~ResourceManager() {
delete[] alfredTalkFrames[i][j];
}
- for(int j = 0; j < 2; j ++) {
+ for (int j = 0; j < 2; j++) {
delete[] alfredInteractFrames[i][j];
}
@@ -55,8 +57,9 @@ ResourceManager::~ResourceManager() {
delete[] alfredIdle[i];
}
- delete[] alfredCombFrames[0];
- delete[] alfredCombFrames[1];
+ delete[] alfredCombFrames[0];
+ delete[] alfredCombFrames[1];
+ delete _mainMenu;
}
void ResourceManager::loadCursors() {
@@ -72,6 +75,7 @@ void ResourceManager::loadCursors() {
}
alfred7File.close();
}
+
void ResourceManager::loadInteractionIcons() {
Common::File alfred7File;
if (!alfred7File.open("ALFRED.7")) {
@@ -167,7 +171,6 @@ void ResourceManager::loadAlfredAnims() {
int interactingFrame = interactingStartFrame + j;
extractSingleFrame(pic, alfredInteractFrames[i][j], interactingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
}
-
}
free(bufferFile);
@@ -210,4 +213,44 @@ void ResourceManager::loadAlfredAnims() {
free(alfredCombLeftRaw);
}
+
+void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32 offset, int numBlocks, byte *outputBuffer) {
+ stream->seek(offset, SEEK_SET);
+ // get screen
+ size_t combined_size = 0;
+ for (int i = 0; i < numBlocks; i++) {
+ byte *thisBlock = nullptr;
+ size_t blockSize = 0;
+ readUntilBuda(stream, stream->pos(), thisBlock, blockSize);
+ uint8_t *block_data = nullptr;
+ size_t decompressedSize = rleDecompress(thisBlock, blockSize, 0, 640 * 400, &block_data, true);
+ memcpy(outputBuffer + combined_size, block_data, decompressedSize);
+ combined_size += decompressedSize + 1;
+ free(block_data);
+ free(thisBlock);
+ }
+}
+
+void ResourceManager::loadSettingsMenu() {
+ Common::File alfred7;
+ if (!alfred7.open(Common::Path("ALFRED.7"))) {
+ error("Could not open ALFRED.7");
+ return;
+ }
+
+ _mainMenu = new byte[640 * 400];
+
+ alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
+ alfred7.read(_mainMenuPalette, 768);
+ for (int i = 0; i < 256; i++) {
+ _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
+ _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
+ _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
+ }
+
+ mergeRleBlocks(&alfred7, kSettingsMenuOffset, 8, _mainMenu);
+ alfred7.close();
+}
+
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index bfa3b60efd1..6bed0e95310 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -21,40 +21,44 @@
#ifndef PELROCK_RESOURCES_H
#define PELROCK_RESOURCES_H
- #include "common/scummsys.h"
+#include "common/scummsys.h"
+#include "common/stream.h"
namespace Pelrock {
-
static const int walkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
static const int talkingAnimLengths[4] = {8, 8, 4, 4}; // size of each inner array
static const int interactingAnimLength = 2;
class ResourceManager {
private:
- /* data */
+ void mergeRleBlocks(Common::SeekableReadStream *stream, uint32 offset, int numBlocks, byte *outputBuffer);
public:
ResourceManager(/* args */);
~ResourceManager();
+ void loadSettingsMenu();
void loadCursors();
void loadInteractionIcons();
void loadAlfredAnims();
+ byte *loadExtra();
- byte *alfredIdle[4] = {nullptr}; // 4 directions
+ byte *alfredIdle[4] = {nullptr}; // 4 directions
- byte **alfredWalkFrames[4]; // 4 arrays of arrays
+ byte **alfredWalkFrames[4]; // 4 arrays of arrays
- byte **alfredTalkFrames[4]; // 4 arrays of arrays
+ byte **alfredTalkFrames[4]; // 4 arrays of arrays
byte **alfredCombFrames[2];
byte **alfredInteractFrames[4];
- byte *_cursorMasks[5] = {nullptr};
+ byte *_cursorMasks[5] = {nullptr};
byte *_verbIcons[9] = {nullptr};
byte *_popUpBalloon = nullptr;
-};
+ byte *_mainMenu = nullptr;
+ byte _mainMenuPalette[768] = {0};
+};
} // End of namespace Pelrock
#endif
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 647b6470c3d..0f84e8c6e2b 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -63,13 +63,13 @@ void RoomManager::getPalette(Common::File *roomFile, int roomOffset, byte *palet
palette[i * 3 + 1] = palette[i * 3 + 1] << 2;
palette[i * 3 + 2] = palette[i * 3 + 2] << 2;
}
+ memcpy(_roomPalette, palette, 768);
}
void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *background) {
roomFile->seek(0, SEEK_SET);
// get screen
size_t combined_size = 0;
- size_t uncompressed_size = 0;
for (int pair_idx = 0; pair_idx < 8; pair_idx++) {
uint32_t pair_offset = roomOffset + (pair_idx * 8);
if (pair_offset + 8 > roomFile->size())
@@ -78,7 +78,6 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
roomFile->seek(pair_offset, SEEK_SET);
uint32_t offset = roomFile->readUint32LE();
uint32_t size = roomFile->readUint32LE();
- uncompressed_size += size;
if (offset > 0 && size > 0 && offset < roomFile->size()) {
byte *data = new byte[size];
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index c5cc6f209f6..245a38c198d 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -53,6 +53,7 @@ public:
TalkingAnimHeader _talkingAnimHeader;
ScalingParams _scaleParams;
byte *_pixelsShadows = nullptr;
+ byte _roomPalette[768];
byte alfredRemap[256];
byte overlayRemap[256];
Common::Array<Common::String> _roomNames;
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 6b7a0d67d8f..75f36dc0a0e 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -52,6 +52,7 @@ private:
int _currentVolume;
Common::File *_musicFile;
byte _currentMusicTrack = 0;
+ Audio::SoundHandle _sfxHandles[8];
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 587bcbf0301..df49d413a5b 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -283,9 +283,9 @@ enum GameState {
SETTINGS = 104,
EXTRA_SCREEN = 105,
INTRO = 106,
- PROMOTE = 107,
};
+
} // End of namespace Pelrock
#endif
Commit: a0bc558ee022f2c0e97be5709ed4cde511896c67
https://github.com/scummvm/scummvm/commit/a0bc558ee022f2c0e97be5709ed4cde511896c67
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:16+02:00
Commit Message:
PELROCK: Plays Sfx
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b217520a886..3e749204dc2 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -186,8 +186,10 @@ Common::Error PelrockEngine::run() {
void PelrockEngine::init() {
_res->loadCursors();
_res->loadInteractionIcons();
- calculateScalingMasks();
_res->loadSettingsMenu();
+ _soundManager->loadSoundIndex();
+
+ calculateScalingMasks();
_compositeBuffer = new byte[640 * 400];
_currentBackground = new byte[640 * 400];
@@ -1562,6 +1564,11 @@ void PelrockEngine::setScreen(int number, int dir) {
else {
_soundManager->stopMusic();
}
+ for (int i = 0; i < kNumSfxPerRoom; i++) {
+ if (_room->_roomSfx[i])
+ _soundManager->playSound(_room->_roomSfx[i]);
+ }
+
_screen->markAllDirty();
roomFile.close();
delete[] background;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 0f84e8c6e2b..f8ffb32b25f 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -20,8 +20,8 @@
*/
#include "common/scummsys.h"
-#include "pelrock/room.h"
#include "pelrock/pelrock.h"
+#include "pelrock/room.h"
#include "pelrock/util.h"
#include "room.h"
@@ -30,9 +30,6 @@ namespace Pelrock {
RoomManager::RoomManager() {
_pixelsShadows = new byte[640 * 400];
_roomNames = loadRoomNames();
- for (int i = 0; i < _roomNames.size(); i++) {
- debug("Room %d name: %s", i, _roomNames[i].c_str());
- }
}
RoomManager::~RoomManager() {
@@ -42,7 +39,7 @@ RoomManager::~RoomManager() {
// delete[] _currentRoomWalkboxes;
// delete[] _currentRoomDescriptions;
// delete[] _currentRoomConversations;
- if(_pixelsShadows != nullptr) {
+ if (_pixelsShadows != nullptr) {
delete[] _pixelsShadows;
_pixelsShadows = nullptr;
}
@@ -196,8 +193,6 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
byte *shadows = loadShadowMap(roomNumber);
loadRemaps(roomNumber);
- Common::Array<int> sfx = loadRoomSfx(roomFile, roomOffset);
-
int walkboxCount = 0;
_currentRoomAnims = anims;
_currentRoomHotspots = hotspots;
@@ -207,7 +202,8 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
_scaleParams = scalingParams;
Common::copy(shadows, shadows + (640 * 400), _pixelsShadows);
_musicTrack = loadMusicTrackForRoom(roomFile, roomOffset);
- _roomSfx = sfx;
+ _roomSfx = loadRoomSfx(roomFile, roomOffset);
+
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
drawRect(g_engine->_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
@@ -901,8 +897,8 @@ void RoomManager::loadRemaps(int roomNumber) {
remapFile.close();
}
-Common::Array<Common::String> RoomManager::loadRoomNames() {
- Common::Array<Common::String> roomNames;
+Common::StringArray RoomManager::loadRoomNames() {
+ Common::StringArray roomNames;
Common::File juegoExe;
if (!juegoExe.open(Common::Path("JUEGO.EXE"))) {
error("Couldnt find file JUEGO.EXE");
@@ -919,8 +915,7 @@ Common::Array<Common::String> RoomManager::loadRoomNames() {
namesData[pos + 1] == 0x00 &&
namesData[pos + 2] == 0x08 &&
namesData[pos + 3] == 0x02) {
- if (currentName.size() > 0 ) {
- debug("Found room name: %s", currentName.c_str());
+ if (currentName.size() > 0) {
roomNames.push_back(currentName);
}
currentName = "";
@@ -947,7 +942,7 @@ byte RoomManager::loadMusicTrackForRoom(Common::File *roomFile, int roomOffset)
return musicTrack > 0 ? musicTrack + 1 : 0;
}
-Common::Array<int> RoomManager::loadRoomSfx(Common::File *roomFile, int roomOffset) {
+Common::Array<byte> RoomManager::loadRoomSfx(Common::File *roomFile, int roomOffset) {
uint32_t pair9offset = roomOffset + (9 * 8);
roomFile->seek(pair9offset, SEEK_SET);
uint32_t pair9_data_offset = roomFile->readUint32LE();
@@ -955,11 +950,11 @@ Common::Array<int> RoomManager::loadRoomSfx(Common::File *roomFile, int roomOffs
roomFile->seek(pair9_data_offset, SEEK_SET);
roomFile->skip(1); // skip music track byte
- Common::Array<int> roomSfx;
- for(int i=0; i< 9; i++) {
+ Common::Array<byte> roomSfx(kNumSfxPerRoom);
+ for (int i = 0; i < kNumSfxPerRoom; i++) {
byte sfx = roomFile->readByte();
- roomSfx.push_back((int)sfx);
- debug("SFX %d for room at offset %d is %d", i, roomOffset, sfx);
+ roomSfx[i] = sfx;
+ debug("SFX %d for room at offset %d is %d (%s)", i, roomOffset, sfx, SOUND_FILENAMES[sfx]);
}
return roomSfx;
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 245a38c198d..3ec5fbf4ad1 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -29,6 +29,8 @@
namespace Pelrock {
+static const int kNumSfxPerRoom = 8;
+
class RoomManager {
public:
RoomManager();
@@ -56,9 +58,9 @@ public:
byte _roomPalette[768];
byte alfredRemap[256];
byte overlayRemap[256];
- Common::Array<Common::String> _roomNames;
+ Common::StringArray _roomNames;
byte _musicTrack = 0;
- Common::Array<int> _roomSfx;
+ Common::Array<byte> _roomSfx;
private:
Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
@@ -75,9 +77,9 @@ private:
ScalingParams loadScalingParams(Common::File *roomFile, int roomOffset);
byte *loadShadowMap(int roomNumber);
void loadRemaps(int roomNumber);
- Common::Array<Common::String> loadRoomNames();
+ Common::StringArray loadRoomNames();
byte loadMusicTrackForRoom(Common::File *roomFile, int roomOffset);
- Common::Array<int> loadRoomSfx(Common::File *roomFile, int roomOffset);
+ Common::Array<byte> loadRoomSfx(Common::File *roomFile, int roomOffset);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 538cd52fc16..4501b869086 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -21,32 +21,144 @@
#include "audio/audiostream.h"
#include "audio/decoders/mp3.h"
+#include "audio/decoders/raw.h"
+#include "audio/decoders/wave.h"
+
#include "audio/mixer.h"
-#include "common/file.h"
#include "common/debug.h"
+#include "common/endian.h"
+#include "common/file.h"
+#include "common/memstream.h"
#include "common/scummsys.h"
#include "pelrock/sound.h"
+#include "sound.h"
namespace Pelrock {
SoundManager::SoundManager(Audio::Mixer *mixer)
- : _mixer(mixer), _currentVolume(255), _musicFile(nullptr) {
+ : _mixer(mixer), _currentVolume(255), _musicFile(nullptr) {
// TODO: Initialize sound manager
}
SoundManager::~SoundManager() {
- stopSound();
- stopMusic();
+ stopAllSounds();
+ stopMusic();
}
-void SoundManager::playSound(const Common::String &filename, int volume) {
+void SoundManager::playSound(byte index, int volume) {
+ debug("Playing sound index %d (%s)", index, SOUND_FILENAMES[index]);
+ auto it = _soundMap.find(SOUND_FILENAMES[index]);
+ if (it != _soundMap.end()) {
+ playSound(it->_value, volume);
+ } else {
+ debug("Sound file %s not found in sound map", SOUND_FILENAMES[index]);
+ }
+}
+
+void SoundManager::playSound(SonidoFile sound, int volume) {
+ Common::File sonidosFile;
+ if (!sonidosFile.open(Common::Path("SONIDOS.DAT"))) {
+ debug("Failed to open SONIDOS.DAT");
+ return;
+ }
+
+ sonidosFile.seek(sound.offset, SEEK_SET);
+ byte *data = new byte[sound.size];
+ sonidosFile.read(data, sound.size);
+ sonidosFile.close();
+
+ SoundFormat format = detectFormat(data, sound.size);
+ uint32_t sampleRate = getSampleRate(data, format);
+ Audio::AudioStream *stream = nullptr;
+
+ if (format == SOUND_FORMAT_RIFF) {
+ // For WAV/RIFF files, use the wave decoder
+ Common::MemoryReadStream *memStream = new Common::MemoryReadStream(data, sound.size, DisposeAfterUse::YES);
+ stream = Audio::makeWAVStream(memStream, DisposeAfterUse::YES);
+ } else if (format == SOUND_FORMAT_RAWPCM || format == SOUND_FORMAT_MILES || format == SOUND_FORMAT_MILES2) {
+ // Determine the offset to skip the header
+ uint32 headerSize = 0;
+ if (format == SOUND_FORMAT_MILES || format == SOUND_FORMAT_MILES2) {
+ headerSize = 80;
+ }
+
+ uint32 pcmSize = sound.size - headerSize;
+ byte *pcmData = (byte *)malloc(pcmSize);
+ memcpy(pcmData, data + headerSize, pcmSize);
+ delete[] data;
+
+ // Create raw audio stream (8-bit unsigned mono is common for old games)
+ stream = Audio::makeRawStream(pcmData, pcmSize, sampleRate,
+ Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
+ } else {
+ debug("Unknown sound format");
+ delete[] data;
+ return;
+ }
+
+ if (stream) {
+ int channel = findFreeChannel();
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
+ }
// TODO: Play sound file
}
-void SoundManager::stopSound() {
- // _mixer->stopHandle(_soundHandle);
- // TODO: Stop currently playing sound
+SoundFormat SoundManager::detectFormat(byte *data, uint32 size) {
+
+ if (size < 16) {
+ return SOUND_FORMAT_INVALID;
+ }
+ byte byte0 = data[0];
+ byte byte1 = data[1];
+
+ if (data[0] == 'R' && data[1] == 'I' && data[2] == 'F' && data[3] == 'F') {
+ return SOUND_FORMAT_RIFF;
+ }
+ if (byte0 == 0x01 && byte1 == 0x2e) {
+ return SOUND_FORMAT_MILES;
+ }
+ if (byte0 == 0x01 && (byte1 >= 0x40 && byte1 <= 0x7f)) {
+ return SOUND_FORMAT_MILES2;
+ }
+ if (size <= 100) {
+ return SOUND_FORMAT_INVALID;
+ }
+ return SOUND_FORMAT_RAWPCM;
+}
+
+int SoundManager::getSampleRate(byte *data, SoundFormat format) {
+
+ uint32 sampleRate = 11025; // Default sample rate
+ if (format == SOUND_FORMAT_RIFF) {
+ sampleRate = READ_LE_UINT32(data + 0x18);
+ } else if (format == SOUND_FORMAT_MILES) {
+ sampleRate = READ_LE_UINT32(data + 0x1C);
+ } else if (format == SOUND_FORMAT_MILES2) {
+ sampleRate = READ_LE_UINT32(data + 0x10);
+ }
+ return sampleRate;
+}
+
+int SoundManager::findFreeChannel() {
+ for (int i = 0; i < kMaxChannels; i++) {
+ if (!_mixer->isSoundHandleActive(_sfxHandles[i])) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+void SoundManager::stopAllSounds() {
+ for (int i = 0; i < kMaxChannels; i++) {
+ _mixer->stopHandle(_sfxHandles[i]);
+ }
+}
+
+void SoundManager::stopSound(int channel) {
+ if (channel >= 0 && channel < kMaxChannels) {
+ _mixer->stopHandle(_sfxHandles[channel]);
+ }
}
void SoundManager::setVolume(int volume) {
@@ -54,24 +166,35 @@ void SoundManager::setVolume(int volume) {
}
bool SoundManager::isPlaying() const {
- // TODO: Return whether a sound is playing
+ for (int i = 0; i < 8; i++) {
+ if (_mixer->isSoundHandleActive(_sfxHandles[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SoundManager::isPlaying(int channel) const {
+ if (channel >= 0 && channel < kMaxChannels) {
+ return _mixer->isSoundHandleActive(_sfxHandles[channel]);
+ }
return false;
}
void SoundManager::stopMusic() {
- if(_isMusicPlaying) {
- debug("Stopping music");
- _mixer->stopHandle(_musicHandle);
- _isMusicPlaying = false;
- }
+ if (_isMusicPlaying) {
+ debug("Stopping music");
+ _mixer->stopHandle(_musicHandle);
+ _isMusicPlaying = false;
+ }
}
void SoundManager::playMusicTrack(int trackNumber) {
- if(_currentMusicTrack == trackNumber && _isMusicPlaying) {
- // Already playing this track
- return;
- }
- _currentMusicTrack = trackNumber;
+ if (_currentMusicTrack == trackNumber && _isMusicPlaying) {
+ // Already playing this track
+ return;
+ }
+ _currentMusicTrack = trackNumber;
stopMusic();
// Open the file
_musicFile = new Common::File();
@@ -79,21 +202,51 @@ void SoundManager::playMusicTrack(int trackNumber) {
if (!_musicFile->open(Common::Path(filename))) {
delete _musicFile;
- _musicFile = nullptr;
- return;
+ _musicFile = nullptr;
+ return;
}
#ifdef USE_MAD
Audio::SeekableAudioStream *stream = Audio::makeMP3Stream(_musicFile, DisposeAfterUse::YES);
if (!stream) {
_musicFile->close();
- delete _musicFile;
- _musicFile = nullptr;
+ delete _musicFile;
+ _musicFile = nullptr;
return;
}
Audio::AudioStream *loopStream = Audio::makeLoopingAudioStream(stream, 0);
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, loopStream, -1, _currentVolume);
- _isMusicPlaying = true;
- _musicFile = nullptr;
+ _isMusicPlaying = true;
+ _musicFile = nullptr;
#endif
}
+
+void Pelrock::SoundManager::loadSoundIndex() {
+
+ Common::File sonidosFile;
+ if (!sonidosFile.open(Common::Path("SONIDOS.DAT"))) {
+ debug("Failed to open SONIDOS.DAT");
+ return;
+ }
+ // Read header
+ char magic[4];
+ sonidosFile.read(magic, 4);
+ if (strncmp(magic, "PACK", 4) != 0) {
+ debug("SONIDOS.DAT has invalid magic");
+ return;
+ }
+ byte fileCount = sonidosFile.readByte();
+ debug("SONIDOS.DAT contains %u files", fileCount);
+ sonidosFile.skip(3); // Padding bytes
+
+ for (uint32_t i = 0; i < fileCount; i++) {
+ SonidoFile sonido;
+ sonido.filename = sonidosFile.readString('\0', 12);
+ sonidosFile.skip(1);
+ sonido.offset = sonidosFile.readUint32LE();
+ sonido.size = sonidosFile.readUint32LE();
+ _soundMap[sonido.filename] = sonido;
+ }
+ sonidosFile.close();
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 75f36dc0a0e..362b22e511d 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -22,37 +22,169 @@
#ifndef PELROCK_SOUND_H
#define PELROCK_SOUND_H
+#include "audio/mixer.h"
#include "common/file.h"
#include "common/scummsys.h"
#include "common/str.h"
-#include "audio/mixer.h"
namespace Pelrock {
+typedef struct {
+ Common::String filename;
+ uint32_t offset;
+ uint32_t size;
+ unsigned char *data;
+} SonidoFile;
+
+static const char *SOUND_FILENAMES[] = {
+ "NO_SOUND.SMP", // 0 - Silence/disabled
+ "BUHO_ZZZ.SMP", // 1 - Owl
+ "BIRD_1_1.SMP", // 2 - Bird variant 1
+ "BIRD_1_2.SMP", // 3 - Bird variant 2
+ "BIRD_1_3.SMP", // 4 - Bird variant 3
+ "DESPERZZ.SMP", // 5 - Yawn/stretch
+ "HORN_5ZZ.SMP", // 6 - Car horn 5
+ "HORN_6ZZ.SMP", // 7 - Car horn 6
+ "HORN_8ZZ.SMP", // 8 - Car horn 8
+ "SUZIPASS.SMP", // 9 - Suzi passing
+ "CAT_1ZZZ.SMP", // 10 - Cat
+ "DOG_01ZZ.SMP", // 11 - Dog bark 1
+ "DOG_02ZZ.SMP", // 12 - Dog bark 2
+ "DOG_04ZZ.SMP", // 13 - Dog bark 4
+ "DOG_05ZZ.SMP", // 14 - Dog bark 5
+ "DOG_06ZZ.SMP", // 15 - Dog bark 6
+ "DOG_07ZZ.SMP", // 16 - Dog bark 7
+ "DOG_09ZZ.SMP", // 17 - Dog bark 9
+ "ALARMZZZ.SMP", // 18 - Alarm
+ "AMBULAN1.SMP", // 19 - Ambulance
+ "FOUNTAIN.SMP", // 20 - Fountain
+ "GRILLOSZ.SMP", // 21 - Crickets
+ "HOJASZZZ.SMP", // 22 - Leaves rustling
+ "FLASHZZZ.SMP", // 23 - Flash/camera
+ "CUCHI1ZZ.SMP", // 24 - Knife 1
+ "KNRRRRRZ.SMP", // 25 - Snoring
+ "PHONE_02.SMP", // 26 - Phone ring 2
+ "PHONE_03.SMP", // 27 - Phone ring 3
+ "SSSHTZZZ.SMP", // 28 - Shush/quiet
+ "BURGUER1.SMP", // 29 - Burger sizzle
+ "FLIES_2Z.SMP", // 30 - Flies buzzing
+ "PARRILLA.SMP", // 31 - Grill
+ "WATER_2Z.SMP", // 32 - Water
+ "XIQUETZZ.SMP", // 33 - Whistle
+ "RONQUIZZ.SMP", // 34 - Snoring
+ "MOCO1ZZZ.SMP", // 35 - Snot/mucus 1
+ "MOCO2ZZZ.SMP", // 36 - Snot/mucus 2
+ "SPRINGZZ.SMP", // 37 - Spring bounce
+ "MARUJASZ.SMP", // 38 - Gossip/chatter
+ "ELECTROZ.SMP", // 39 - Electric shock
+ "GLASS1ZZ.SMP", // 40 - Glass clink
+ "OPDOORZZ.SMP", // 41 - Door open
+ "CLDOORZZ.SMP", // 42 - Door close
+ "FXH2ZZZZ.SMP", // 43 - Effect 2
+ "BOTEZZZZ.SMP", // 44 - Bottle
+ "ELEC3ZZZ.SMP", // 45 - Electric 3
+ "AJARLZZZ.SMP", // 46 - Ajar/creak
+ "BELCHZZZ.SMP", // 47 - Belch/burp
+ "64ZZZZZZ.SMP", // 48 - Sound effect 64
+ "BIRDOWL2.SMP", // 49 - Bird/owl 2
+ "BUBBLE2Z.SMP", // 50 - Bubbles
+ "BURGUER1.SMP", // 51 - Burger (duplicate)
+ "CACKLEZZ.SMP", // 52 - Cackle/laugh
+ "CERAMIC1.SMP", // 53 - Ceramic break
+ "CLANG5ZZ.SMP", // 54 - Metal clang
+ "CUCHI2ZZ.SMP", // 55 - Knife 2
+ "CUCHI3ZZ.SMP", // 56 - Knife 3
+ "ELEC3ZZZ.SMP", // 57 - Electric 3 (duplicate)
+ "HOJASZZZ.SMP", // 58 - Leaves (duplicate)
+ "LIMA1ZZZ.SMP", // 59 - File/rasp
+ "MOROSZZZ.SMP", // 60 - Moors/crowd
+ "MOROZZZZ.SMP", // 61 - Moor/crowd
+ "MUD1ZZZZ.SMP", // 62 - Mud squelch
+ "PICOZZZZ.SMP", // 63 - Pickaxe
+ "PICO1XZZ.SMP", // 64 - Pickaxe 1
+ "PICO2XZZ.SMP", // 65 - Pickaxe 2
+ "PICO3XZZ.SMP", // 66 - Pickaxe 3
+ "RIMSHOTZ.SMP", // 67 - Rimshot drum
+ "RONCOZZZ.SMP", // 68 - Snoring
+ "SORBOZZZ.SMP", // 69 - Slurp/sip
+ "VIENTO1Z.SMP", // 70 - Wind
+ "2ZZZZZZZ.SMP", // 71 - Sound 2
+ "20ZZZZZZ.SMP", // 72 - Sound 20
+ "21ZZZZZZ.SMP", // 73 - Sound 21
+ "23ZZZZZZ.SMP", // 74 - Sound 23
+ "107ZZZZZ.SMP", // 75 - Sound 107
+ "39ZZZZZZ.SMP", // 76 - Sound 39
+ "81ZZZZZZ.SMP", // 77 - Sound 81
+ "88ZZZZZZ.SMP", // 78 - Sound 88
+ "92ZZZZZZ.SMP", // 79 - Sound 92
+ "SAW_2ZZZ.SMP", // 80 - Saw
+ "QUAKE2ZZ.SMP", // 81 - Earthquake
+ "ROCKSZZZ.SMP", // 82 - Rocks falling
+ "IN_FIREZ.SMP", // 83 - Fire
+ "BEAMZZZZ.SMP", // 84 - Beam/ray
+ "GLISSDWN.SMP", // 85 - Glissando down
+ "REMATERL.SMP", // 86 - Rematerialize
+ "FXH1ZZZZ.SMP", // 87 - Effect 1
+ "FXH3ZZZZ.SMP", // 88 - Effect 3
+ "FXH4ZZZZ.SMP", // 89 - Effect 4
+ "MATCHZZZ.SMP", // 90 - Match strike
+ "SURF_01Z.SMP", // 91 - Surf wave 1
+ "SURF_02Z.SMP", // 92 - Surf wave 2
+ "SURF_04Z.SMP", // 93 - Surf wave 4
+ "TWANGZZZ.SMP", // 94 - Twang
+ "LANDCRAS.SMP", // 95 - Crash landing
+};
+
+enum SoundFormat {
+ SOUND_FORMAT_RAWPCM,
+ SOUND_FORMAT_MILES,
+ SOUND_FORMAT_MILES2,
+ SOUND_FORMAT_RIFF,
+ SOUND_FORMAT_INVALID
+};
+
+struct SoundData {
+ SoundFormat format;
+ int sampleRate;
+ byte *data;
+ uint32 size;
+};
+
+const int kMaxChannels = 15;
+
class SoundManager {
public:
- SoundManager(Audio::Mixer *mixer);
- ~SoundManager();
-
- void playSound(const Common::String &filename, int volume = 255);
- void stopSound();
- void stopMusic();
- void setVolume(int volume);
- bool isPlaying() const;
- void playMusicTrack(int trackNumber);
- bool isMusicPlaying() const {
- return _isMusicPlaying;
- }
+ SoundManager(Audio::Mixer *mixer);
+ ~SoundManager();
+ void playSound(byte index, int volume = 255);
+ void stopAllSounds();
+ void stopSound(int channel);
+ void stopMusic();
+ void setVolume(int volume);
+ bool isPlaying() const;
+ bool isPlaying(int channel) const;
+ void playMusicTrack(int trackNumber);
+ bool isMusicPlaying() const {
+ return _isMusicPlaying;
+ }
+ void loadSoundIndex();
private:
- Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
- Audio::SoundHandle _musicHandle;
- bool _isMusicPlaying = false;
- int _currentVolume;
- Common::File *_musicFile;
- byte _currentMusicTrack = 0;
- Audio::SoundHandle _sfxHandles[8];
+ void playSound(SonidoFile sound, int volume = 255);
+ SoundFormat detectFormat(byte *data, uint32 size);
+ int getSampleRate(byte *data, SoundFormat format);
+ int findFreeChannel();
+
+private:
+ Audio::Mixer *_mixer;
+ bool _isMusicPlaying = false;
+ int _currentVolume;
+ Common::File *_musicFile;
+ byte _currentMusicTrack = 0;
+ Audio::SoundHandle _musicHandle;
+ Audio::SoundHandle _sfxHandles[kMaxChannels];
+
+ Common::HashMap<Common::String, SonidoFile> _soundMap;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index df49d413a5b..8f99d8917d1 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -76,7 +76,6 @@ enum AlfredState {
ALFRED_COMB
};
-
// Direction flags (bit-packed)
#define MOVE_RIGHT 0x01 // Move right (positive X)
#define MOVE_LEFT 0x02 // Move left (negative X)
Commit: b899645c4b616f87fbbf6a21fa9753b94f3f272c
https://github.com/scummvm/scummvm/commit/b899645c4b616f87fbbf6a21fa9753b94f3f272c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:16+02:00
Commit Message:
PELROCK: Condense Alfred state
Changed paths:
engines/pelrock/chrono.cpp
engines/pelrock/chrono.h
engines/pelrock/fonts/large_font.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index 306e38c1ca9..131fd80ce85 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -37,7 +37,7 @@ ChronoManager::~ChronoManager() {
void ChronoManager::updateChrono() {
uint32 currentTime = g_system->getMillis();
- if (_textTtl > 0 && g_engine->alfredState == ALFRED_TALKING && g_engine->alfredState != ALFRED_WALKING) {
+ if (_textTtl > 0 && g_engine->alfredState.animState == ALFRED_TALKING && g_engine->alfredState.animState != ALFRED_WALKING) {
_textTtl -= (currentTime - _lastTick);
if (_textTtl < 0)
_textTtl = 0;
@@ -46,12 +46,6 @@ void ChronoManager::updateChrono() {
if ((currentTime - _lastTick) >= kTickMs / _speedMultiplier) {
_gameTick = true;
_tickCount++;
- if (_tickCount == kHalfTickMultiplier) {
- _tickCount = 0;
- _gameTickHalfSpeed = true;
- } else {
- _gameTickHalfSpeed = false;
- }
_lastTick = currentTime;
} else {
_gameTick = false;
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index aa389db418d..03f10b010cf 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -25,9 +25,13 @@
namespace Pelrock {
-const int kTickMs = 18;
-// const int kTickMs = 55;
+// const int kTickMs = 18;
+// const int kTickMs = 100;
// const int kTickMs = 15;
+// const int kTickMs = 33;
+// const int kTickMs = 38;
+const int kTickMs = 55;
+// const int kTickMs = 60;
const int kHalfTickMultiplier = 2;
class ChronoManager {
@@ -45,7 +49,6 @@ public:
void waitForKey();
bool _gameTick = false;
- bool _gameTickHalfSpeed = false;
long _textTtl = 0;
};
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index 9a1dc5894e0..fa431089d42 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -115,7 +115,7 @@ int LargeFont::getCharWidth(uint32 chr) const {
void LargeFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
chr -= 32; // Adjust for font starting at ASCII 32
- if (!_fontData || chr > 96 || chr < 0) {
+ if (!_fontData || chr >= 96 || chr < 0) {
return;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 3e749204dc2..e26b4b157e7 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -112,19 +112,19 @@ Common::Error PelrockEngine::run() {
if (e.type == Common::EVENT_KEYDOWN) {
switch (e.kbd.keycode) {
case Common::KEYCODE_w:
- alfredState = ALFRED_WALKING;
+ alfredState.animState = ALFRED_WALKING;
break;
case Common::KEYCODE_t:
- alfredState = ALFRED_TALKING;
+ alfredState.animState = ALFRED_TALKING;
break;
case Common::KEYCODE_s:
- alfredState = ALFRED_IDLE;
+ alfredState.animState = ALFRED_IDLE;
break;
case Common::KEYCODE_c:
- alfredState = ALFRED_COMB;
+ alfredState.animState = ALFRED_COMB;
break;
case Common::KEYCODE_i:
- alfredState = ALFRED_INTERACTING;
+ alfredState.animState = ALFRED_INTERACTING;
break;
case Common::KEYCODE_z:
showShadows = !showShadows;
@@ -204,7 +204,7 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(0, 0);
+ setScreen(0, ALFRED_DOWN);
// setScreen(6, 0); // museum entrance
// setScreen(13, 1); // restaurants kitchen
// setScreen(2, 2); // hooker
@@ -326,89 +326,91 @@ void PelrockEngine::frames() {
AnimSet &animSet = _room->_currentRoomAnims[i];
drawNextFrame(&animSet);
}
-
- switch (alfredState) {
+ switch (alfredState.animState) {
case ALFRED_WALKING: {
MovementStep step = _currentContext.movement_buffer[_current_step];
if (step.distance_x > 0) {
if (step.flags & MOVE_RIGHT) {
- dirAlfred = 0;
- xAlfred += MIN((uint16_t)6, step.distance_x);
+ alfredState.direction = ALFRED_RIGHT;
+ alfredState.x += MIN(alfredState.movementSpeed, step.distance_x);
}
if (step.flags & MOVE_LEFT) {
- dirAlfred = 1;
- xAlfred -= MIN((uint16_t)6, step.distance_x);
+ alfredState.direction = ALFRED_LEFT;
+ alfredState.x -= MIN(alfredState.movementSpeed, step.distance_x);
}
}
if (step.distance_y > 0) {
if (step.flags & MOVE_DOWN) {
- dirAlfred = 2;
- yAlfred += MIN((uint16_t)6, step.distance_y);
+ alfredState.direction = ALFRED_DOWN;
+ alfredState.y += MIN(alfredState.movementSpeed, step.distance_y);
}
if (step.flags & MOVE_UP) {
- dirAlfred = 3;
- yAlfred -= MIN((uint16_t)6, step.distance_y);
+ alfredState.direction = ALFRED_UP;
+ alfredState.y -= MIN(alfredState.movementSpeed, step.distance_y);
}
}
if (step.distance_x > 0)
- step.distance_x -= MIN((uint16_t)6, step.distance_x);
+ step.distance_x -= MIN(alfredState.movementSpeed, step.distance_x);
if (step.distance_y > 0)
- step.distance_y -= MIN((uint16_t)6, step.distance_y);
+ step.distance_y -= MIN(alfredState.movementSpeed, step.distance_y);
if (step.distance_x <= 0 && step.distance_y <= 0) {
_current_step++;
if (_current_step >= _currentContext.movement_count) {
_current_step = 0;
- alfredState = ALFRED_IDLE;
+ alfredState.animState = ALFRED_IDLE;
}
} else {
_currentContext.movement_buffer[_current_step] = step;
}
- Exit *exit = isExitUnder(xAlfred, yAlfred);
+ Exit *exit = isExitUnder(alfredState.x, alfredState.y);
if (exit != nullptr) {
- xAlfred = exit->targetX;
- yAlfred = exit->targetY;
+ alfredState.x = exit->targetX;
+ alfredState.y = exit->targetY;
setScreen(exit->targetRoom, exit->dir);
}
- if (curAlfredFrame >= walkingAnimLengths[dirAlfred]) {
- curAlfredFrame = 0;
+ if (alfredState.curFrame >= walkingAnimLengths[alfredState.direction]) {
+ alfredState.curFrame = 0;
}
- drawAlfred(_res->alfredWalkFrames[dirAlfred][curAlfredFrame]);
- curAlfredFrame++;
+ drawAlfred(_res->alfredWalkFrames[alfredState.direction][alfredState.curFrame]);
+ // if(alfredFrameSkip) alfredState.curFrame++;
+ // alfredFrameSkip = !alfredFrameSkip;
+ alfredState.curFrame++;
break;
}
case ALFRED_TALKING:
- if (curAlfredFrame >= talkingAnimLengths[dirAlfred] - 1) {
- curAlfredFrame = 0;
+ if (alfredState.curFrame >= talkingAnimLengths[alfredState.direction] - 1) {
+ alfredState.curFrame = 0;
}
- drawAlfred(_res->alfredTalkFrames[dirAlfred][curAlfredFrame]);
- curAlfredFrame++;
+ drawAlfred(_res->alfredTalkFrames[alfredState.direction][alfredState.curFrame]);
+ alfredState.curFrame++;
break;
case ALFRED_COMB:
- if (curAlfredFrame >= 11) {
- curAlfredFrame = 0;
+ if (alfredState.curFrame >= 11) {
+ alfredState.curFrame = 0;
}
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[0][curAlfredFrame], xAlfred, yAlfred - kAlfredFrameHeight, 51, 102, 255);
- curAlfredFrame++;
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[0][alfredState.curFrame], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
+ alfredState.curFrame++;
break;
case ALFRED_INTERACTING:
- if (curAlfredFrame >= interactingAnimLength) {
- curAlfredFrame = 0;
+ if (alfredState.curFrame >= interactingAnimLength) {
+ alfredState.curFrame = 0;
}
- drawAlfred(_res->alfredInteractFrames[dirAlfred][curAlfredFrame]);
- curAlfredFrame++;
+ drawAlfred(_res->alfredInteractFrames[alfredState.direction][alfredState.curFrame]);
+ alfredState.curFrame++;
break;
default:
- drawAlfred(_res->alfredIdle[dirAlfred]);
+ drawAlfred(_res->alfredIdle[alfredState.direction]);
break;
}
+
if (_displayPopup) {
// byte *bgDialog = new byte[kBalloonWidth * kBalloonHeight];
@@ -438,7 +440,7 @@ void PelrockEngine::frames() {
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- if (alfredState != ALFRED_WALKING && !_currentTextPages.empty()) {
+ if (alfredState.animState != ALFRED_WALKING && !_currentTextPages.empty()) {
if (_chronoManager->_textTtl > 0) {
renderText(_currentTextPages[_currentTextPageIndex], _textColor, _textPos.x, _textPos.y);
} else if (_currentTextPageIndex < _currentTextPages.size() - 1) {
@@ -452,7 +454,7 @@ void PelrockEngine::frames() {
} else {
_currentTextPages.clear();
_currentTextPageIndex = 0;
- alfredState = ALFRED_IDLE;
+ alfredState.animState = ALFRED_IDLE;
isNPCATalking = false;
isNPCBTalking = false;
}
@@ -519,7 +521,7 @@ void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, i
void PelrockEngine::drawAlfred(byte *buf) {
- ScaleCalculation scale = calculateScaling(yAlfred, _room->_scaleParams);
+ ScaleCalculation scale = calculateScaling(alfredState.y, _room->_scaleParams);
int finalHeight = kAlfredFrameHeight - scale.scaleDown + scale.scaleUp;
if (finalHeight <= 0) {
@@ -542,8 +544,8 @@ void PelrockEngine::drawAlfred(byte *buf) {
// debug("lines to skip = %d, finalHeight = %d, finalWidth = %d for position (%d, %d)", linesToSkip, finalHeight, finalWidth, xAlfred, yAlfred);
- int shadowPos = yAlfred; // - finalHeight;
- bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + xAlfred] != 0xFF;
+ int shadowPos = alfredState.y; // - finalHeight;
+ bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + alfredState.x] != 0xFF;
byte *finalBuf = new byte[finalWidth * finalHeight];
@@ -623,7 +625,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
}
- drawSpriteToBuffer(_compositeBuffer, 640, finalBuf, xAlfred, yAlfred - finalHeight, finalWidth, finalHeight, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, finalBuf, alfredState.x, alfredState.y - finalHeight, finalWidth, finalHeight, 255);
delete[] finalBuf;
}
@@ -881,8 +883,8 @@ void PelrockEngine::drawTalkNPC(AnimSet *animSet) {
}
void PelrockEngine::walkTo(int x, int y) {
- alfredState = ALFRED_WALKING;
- curAlfredFrame = 0;
+ alfredState.animState = ALFRED_WALKING;
+ alfredState.curFrame = 0;
PathContext context = {NULL, NULL, NULL, 0, 0, 0};
@@ -934,8 +936,8 @@ bool PelrockEngine::pathFind(int x, int y, PathContext *context) {
context->movement_buffer = (MovementStep *)malloc(MAX_MOVEMENT_STEPS * sizeof(MovementStep));
}
- int startX = xAlfred;
- int startY = yAlfred;
+ int startX = alfredState.x;
+ int startY = alfredState.y;
Common::Point target = calculateWalkTarget(x, y);
x = target.x;
y = target.y;
@@ -1253,8 +1255,8 @@ void PelrockEngine::checkMouseClick(int x, int y) {
Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
if (exit != nullptr) {
- xAlfred = exit->targetX;
- yAlfred = exit->targetY;
+ alfredState.x = exit->targetX;
+ alfredState.y = exit->targetY;
debug("Placing character at %d, %d", exit->targetX, exit->targetY);
setScreen(exit->targetRoom, exit->dir);
@@ -1396,8 +1398,8 @@ void PelrockEngine::sayNPC(AnimSet *anim, Common::String text, byte color) {
}
void PelrockEngine::sayAlfred(Common::String text) {
- alfredState = ALFRED_TALKING;
- curAlfredFrame = 0;
+ alfredState.animState = ALFRED_TALKING;
+ alfredState.curFrame = 0;
debug("Alfred says: %s", text.c_str());
_currentTextPages = wordWrap(text);
_textColor = 13;
@@ -1405,7 +1407,7 @@ void PelrockEngine::sayAlfred(Common::String text) {
for (int i = 0; i < _currentTextPages[0].size(); i++) {
totalChars += _currentTextPages[0][i].size();
}
- _textPos = Common::Point(xAlfred, yAlfred - kAlfredFrameHeight - 10);
+ _textPos = Common::Point(alfredState.x, alfredState.y - kAlfredFrameHeight - 10);
_chronoManager->_textTtl = totalChars * kTextCharDisplayTime;
}
@@ -1523,7 +1525,7 @@ Common::Array<Common::Array<Common::String>> wordWrap(Common::String text) {
return pages;
}
-void PelrockEngine::setScreen(int number, int dir) {
+void PelrockEngine::setScreen(int number, AlfredDirection dir) {
Common::File roomFile;
debug("Loading room %s number %d", _room->getRoomName(number).c_str(), number);
@@ -1531,11 +1533,11 @@ void PelrockEngine::setScreen(int number, int dir) {
error("Could not open ALFRED.1");
return;
}
- dirAlfred = dir;
- alfredState = ALFRED_IDLE;
+ alfredState.direction = dir;
+ alfredState.animState = ALFRED_IDLE;
_current_step = 0;
int roomOffset = number * kRoomStructSize;
- curAlfredFrame = 0;
+ alfredState.curFrame = 0;
byte *palette = new byte[256 * 3];
_room->getPalette(&roomFile, roomOffset, palette);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 6b1ac2a4e02..6c46e2c8686 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -58,8 +58,7 @@ private:
ResourceManager *_res = nullptr;
void init();
- void setScreen(int s, int dir);
- void setScreenJava(int s, int dir);
+ void setScreen(int s, AlfredDirection dir);
void loadAnims();
void walkTo(int x, int y);
@@ -121,12 +120,7 @@ private:
int _currentTextPageIndex = 0;
// Alfred
- // int xAlfred = 319;
- // int yAlfred = 302;
- int xAlfred = 264;
- int yAlfred = 394;
- int dirAlfred = 0;
- int curAlfredFrame = 0;
+ bool alfredFrameSkip = false;
uint16 mouseX = 0;
uint16 mouseY = 0;
@@ -173,7 +167,7 @@ protected:
public:
Graphics::Screen *_screen = nullptr;
- AlfredState alfredState = ALFRED_IDLE;
+ AlfredState alfredState;
ChronoManager *_chronoManager = nullptr;
VideoManager *_videoManager = nullptr;
SoundManager *_soundManager = nullptr;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index f8ffb32b25f..ef15b1258ae 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -111,7 +111,26 @@ Common::Array<Exit> RoomManager::loadExits(Common::File *roomFile, int roomOffse
exit.targetX = roomFile->readUint16LE();
exit.targetY = roomFile->readUint16LE();
- exit.dir = roomFile->readByte();
+ byte dir = roomFile->readByte();
+ switch (dir)
+ {
+ case ALFRED_RIGHT:
+ exit.dir = ALFRED_RIGHT;
+ break;
+ case ALFRED_LEFT:
+ exit.dir = ALFRED_LEFT;
+ break;
+ case ALFRED_DOWN:
+ exit.dir = ALFRED_DOWN;
+ break;
+ case ALFRED_UP:
+ exit.dir = ALFRED_UP;
+ break;
+ default:
+ exit.dir = ALFRED_DOWN;
+ break;
+ }
+
exits.push_back(exit);
}
return exits;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 8f99d8917d1..83fe1f8676d 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -68,13 +68,6 @@ const int kAlfredFrameHeight = 102;
const int kChoiceHeight = 16; // Height of each choice line in pixels
-enum AlfredState {
- ALFRED_IDLE,
- ALFRED_WALKING,
- ALFRED_TALKING,
- ALFRED_INTERACTING,
- ALFRED_COMB
-};
// Direction flags (bit-packed)
#define MOVE_RIGHT 0x01 // Move right (positive X)
@@ -101,6 +94,32 @@ enum AlfredState {
#define ALFRED_COLOR 0x0D
+
+
+enum AlfredAnimState {
+ ALFRED_IDLE,
+ ALFRED_WALKING,
+ ALFRED_TALKING,
+ ALFRED_INTERACTING,
+ ALFRED_COMB
+};
+
+enum AlfredDirection {
+ ALFRED_RIGHT = 0,
+ ALFRED_LEFT = 1,
+ ALFRED_DOWN = 2,
+ ALFRED_UP = 3
+};
+
+struct AlfredState {
+ AlfredAnimState animState = ALFRED_IDLE;
+ AlfredDirection direction = ALFRED_DOWN;
+ int curFrame = 0;
+ uint16 movementSpeed = 6; // pixels per frame
+ uint16 x = 319;
+ uint16 y = 302;
+};
+
typedef struct {
uint8_t flags; /* Direction flags (see MOVE_* constants) */
uint16_t distance_x; // Horizontal distance to move
@@ -142,7 +161,7 @@ struct Exit {
uint16 targetX;
uint16 targetY;
uint16 targetDir;
- byte dir;
+ AlfredDirection dir;
byte flags;
};
@@ -284,7 +303,6 @@ enum GameState {
INTRO = 106,
};
-
} // End of namespace Pelrock
#endif
Commit: 4e21a273c66309872ccd4223ddbfe5abedc4c802
https://github.com/scummvm/scummvm/commit/4e21a273c66309872ccd4223ddbfe5abedc4c802
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:16+02:00
Commit Message:
PELROCK: Rudimentary ambient sound generation
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index e26b4b157e7..ede51df431b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -318,6 +318,12 @@ void PelrockEngine::frames() {
if (_chronoManager->_gameTick) {
+ int soundIndex = _soundManager->tick();
+ if(soundIndex >= 0 && soundIndex < _room->_roomSfx.size()) {
+ debug("Playing SFX index %d", soundIndex);
+ _soundManager->playSound(_room->_roomSfx[3 + soundIndex]);
+ }
+
memcpy(_compositeBuffer, _currentBackground, 640 * 400);
// debug("Game tick!");
@@ -1526,7 +1532,7 @@ Common::Array<Common::Array<Common::String>> wordWrap(Common::String text) {
}
void PelrockEngine::setScreen(int number, AlfredDirection dir) {
-
+ _soundManager->stopAllSounds();
Common::File roomFile;
debug("Loading room %s number %d", _room->getRoomName(number).c_str(), number);
if (!roomFile.open(Common::Path("ALFRED.1"))) {
@@ -1566,10 +1572,10 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
else {
_soundManager->stopMusic();
}
- for (int i = 0; i < kNumSfxPerRoom; i++) {
- if (_room->_roomSfx[i])
- _soundManager->playSound(_room->_roomSfx[i]);
- }
+ // for (int i = 0; i < kNumSfxPerRoom; i++) {
+ // if (_room->_roomSfx[i])
+ // _soundManager->playSound(_room->_roomSfx[i]);
+ // }
_screen->markAllDirty();
roomFile.close();
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 4501b869086..52bb901e52b 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -31,6 +31,7 @@
#include "common/memstream.h"
#include "common/scummsys.h"
+#include "pelrock/pelrock.h"
#include "pelrock/sound.h"
#include "sound.h"
@@ -220,7 +221,7 @@ void SoundManager::playMusicTrack(int trackNumber) {
#endif
}
-void Pelrock::SoundManager::loadSoundIndex() {
+void SoundManager::loadSoundIndex() {
Common::File sonidosFile;
if (!sonidosFile.open(Common::Path("SONIDOS.DAT"))) {
@@ -249,4 +250,26 @@ void Pelrock::SoundManager::loadSoundIndex() {
sonidosFile.close();
}
+
+int gerRandomNumber() {
+
+
+}
+
+int SoundManager::tick() {
+
+ soundFrameCounter++;
+ uint32 random = g_engine->getRandomNumber(1);
+ if(!random) {
+ return -1;
+ }
+ if((soundFrameCounter & COUNTER_MASK) != COUNTER_MASK){
+
+ return -1;
+ }
+ soundFrameCounter = 0;
+ uint32 slot = g_engine->getRandomNumber(4);
+ return slot;
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 362b22e511d..c2a4372a35f 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -150,6 +150,8 @@ struct SoundData {
uint32 size;
};
+static const uint COUNTER_MASK = 0x1F;
+
const int kMaxChannels = 15;
class SoundManager {
@@ -169,6 +171,8 @@ public:
}
void loadSoundIndex();
+ int tick();
+
private:
void playSound(SonidoFile sound, int volume = 255);
SoundFormat detectFormat(byte *data, uint32 size);
@@ -183,7 +187,7 @@ private:
byte _currentMusicTrack = 0;
Audio::SoundHandle _musicHandle;
Audio::SoundHandle _sfxHandles[kMaxChannels];
-
+ int soundFrameCounter = 0;
Common::HashMap<Common::String, SonidoFile> _soundMap;
};
Commit: 9c95c808593920d13c72d0c550db8cf76196a5af
https://github.com/scummvm/scummvm/commit/9c95c808593920d13c72d0c550db8cf76196a5af
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:17+02:00
Commit Message:
PELROCK: Sprite movements (left/right and top/down)
Changed paths:
engines/pelrock/console.cpp
engines/pelrock/console.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/types.h
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index 1964cb5e3f6..cfa96283d8b 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -19,20 +19,32 @@
*
*/
+#include "console.h"
+
#include "pelrock/console.h"
+#include "pelrock/types.h"
namespace Pelrock {
-Console::Console() : GUI::Debugger() {
- registerCmd("test", WRAP_METHOD(Console, Cmd_test));
+PelrockConsole::PelrockConsole(PelrockEngine *engine) : GUI::Debugger(), _engine(engine) {
+ registerCmd("setScreen", WRAP_METHOD(PelrockConsole, cmdLoadRoom));
}
-Console::~Console() {
+PelrockConsole::~PelrockConsole() {
}
-bool Console::Cmd_test(int argc, const char **argv) {
- debugPrintf("Test\n");
+
+bool PelrockConsole::cmdLoadRoom(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Usage: setScreen <roomNumber>");
+ return true;
+ }
+
+ int roomNumber = atoi(argv[1]);
+ g_engine->setScreen(roomNumber, ALFRED_DOWN);
+ debugPrintf("Loaded room %d", roomNumber);
return true;
}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/console.h b/engines/pelrock/console.h
index f17d71e587e..29bb09747c0 100644
--- a/engines/pelrock/console.h
+++ b/engines/pelrock/console.h
@@ -24,15 +24,19 @@
#define PELROCK_CONSOLE_H
#include "gui/debugger.h"
+#include "pelrock/pelrock.h"
namespace Pelrock {
-class Console : public GUI::Debugger {
+class PelrockConsole : public GUI::Debugger {
private:
- bool Cmd_test(int argc, const char **argv);
+ PelrockEngine *_engine;
+ bool cmdLoadRoom(int argc, const char **argv);
+ bool cmdTest(int argc, const char **argv);
+
public:
- Console();
- ~Console() override;
+ PelrockConsole(PelrockEngine *engine);
+ ~PelrockConsole() override;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index ede51df431b..4095abd9f89 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -86,7 +86,7 @@ Common::Error PelrockEngine::run() {
_soundManager = new SoundManager(_mixer);
// Set the engine's debugger console
- setDebugger(new Console());
+ setDebugger(new PelrockConsole(this));
// If a savegame was selected from the launcher, load it
int saveSlot = ConfMan.getInt("save_slot");
@@ -220,7 +220,7 @@ void PelrockEngine::talk(byte object) {
if (_room->_currentRoomConversations.size() == 0)
return;
- AnimSet *animSet;
+ Sprite *animSet;
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].extra == object) {
animSet = &_room->_currentRoomAnims[i];
@@ -329,7 +329,7 @@ void PelrockEngine::frames() {
// debug("Game tick!");
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
// debug("Processing animation set %d, numAnims %d", num, i->numAnims);
- AnimSet &animSet = _room->_currentRoomAnims[i];
+ Sprite &animSet = _room->_currentRoomAnims[i];
drawNextFrame(&animSet);
}
switch (alfredState.animState) {
@@ -495,7 +495,7 @@ void PelrockEngine::frames() {
if (showShadows) {
memcpy(_screen->getPixels(), _room->_pixelsShadows, 640 * 400);
}
-
+ _smallFont->drawString(_screen, Common::String::format("Room number: %d",_room->_currentRoomNumber), 0, 4, 640, 13);
_screen->markAllDirty();
// _screen->update();
@@ -635,16 +635,52 @@ void PelrockEngine::drawAlfred(byte *buf) {
delete[] finalBuf;
}
-void PelrockEngine::drawNextFrame(AnimSet *animSet) {
- Anim &animData = animSet->animData[animSet->curAnimIndex];
- int x = animData.x;
- int y = animData.y;
+
+void applyMovement(int16_t *x, int16_t *y, /*int8_t *z,*/ uint16_t flags) {
+ // X-axis movement
+ if (flags & 0x10) { // Bit 4: X movement enabled
+ int amount = flags & 0x07; // Bits 0-2: pixels per frame
+ if (flags & 0x08) { // Bit 3: direction
+ *x += amount; // 1 = right (add)
+ } else {
+ *x -= amount; // 0 = left (subtract)
+ }
+ }
+
+ // Y-axis movement
+ if (flags & 0x200) { // Bit 9: Y movement enabled
+ int amount = (flags >> 5) & 0x07; // Bits 5-7: pixels per frame
+ if (flags & 0x100) { // Bit 8: direction
+ *y += amount; // 1 = down (add)
+ } else {
+ *y -= amount; // 0 = up (subtract)
+ }
+ }
+
+ // // Z-axis movement
+ // if (flags & 0x4000) { // Bit 14: Z movement enabled
+ // int amount = (flags >> 10) & 0x07; // Bits 10-12: amount
+ // if (flags & 0x2000) { // Bit 13: direction
+ // *z += amount; // 1 = forward (add)
+ // } else {
+ // *z -= amount; // 0 = back (subtract)
+ // }
+ // }
+}
+
+
+void PelrockEngine::drawNextFrame(Sprite *sprite) {
+ Anim &animData = sprite->animData[sprite->curAnimIndex];
+
+
+ applyMovement(&(sprite->x), &(sprite->y), animData.movementFlags);
+ int x = sprite->x;
+ int y = sprite->y;
int w = animData.w;
int h = animData.h;
- int extra = animSet->extra;
-
+ int extra = sprite->extra;
if (whichNPCTalking == extra) {
- drawTalkNPC(animSet);
+ drawTalkNPC(sprite);
return;
}
@@ -653,7 +689,7 @@ void PelrockEngine::drawNextFrame(AnimSet *animSet) {
byte *frame = new byte[frameSize];
extractSingleFrame(animData.animData, frame, curFrame, animData.w, animData.h);
- drawSpriteToBuffer(_compositeBuffer, 640, frame, animSet->x, animSet->y, animSet->w, animSet->h, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, frame, sprite->x, sprite->y, sprite->w, sprite->h, 255);
if (animData.elpapsedFrames == animData.speed) {
animData.elpapsedFrames = 0;
@@ -666,10 +702,10 @@ void PelrockEngine::drawNextFrame(AnimSet *animSet) {
} else {
animData.curFrame = 0;
animData.curLoop = 0;
- if (animSet->curAnimIndex < animSet->numAnims - 1) {
- animSet->curAnimIndex++;
+ if (sprite->curAnimIndex < sprite->numAnims - 1) {
+ sprite->curAnimIndex++;
} else {
- animSet->curAnimIndex = 0;
+ sprite->curAnimIndex = 0;
}
}
}
@@ -861,7 +897,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
}
-void PelrockEngine::drawTalkNPC(AnimSet *animSet) {
+void PelrockEngine::drawTalkNPC(Sprite *animSet) {
// Change with the right index
int index = animSet->index;
@@ -893,44 +929,8 @@ void PelrockEngine::walkTo(int x, int y) {
alfredState.curFrame = 0;
PathContext context = {NULL, NULL, NULL, 0, 0, 0};
-
pathFind(x, y, &context);
- // debug("\nPath Information:\n");
- // debug("================\n");
-
- // debug("Walkbox path (%d boxes): ", context.path_length);
-
- // debug("Movement steps (%d steps):\n", context.movement_count);
- for (int i = 0; i < context.movement_count; i++) {
- MovementStep *step = &context.movement_buffer[i];
- // debug(" Step %d: ", i);
-
- // if (step->flags & MOVE_RIGHT)
- // debug("RIGHT ");
- // if (step->flags & MOVE_LEFT)
- // debug("LEFT ");
- // if (step->flags & MOVE_DOWN)
- // debug("DOWN ");
- // if (step->flags & MOVE_UP)
- // debug("UP ");
-
- // debug("(dx=%d, dy=%d)\n", step->distance_x, step->distance_y);
- }
-
- // debug("\nCompressed path (%d bytes): ", context.compressed_length);
-
- // if (x > xAlfred) {
- // dirAlfred = RIGHT;
- // } else if (x < xAlfred) {
- // dirAlfred = LEFT;
- // } else if (y < yAlfred) {
- // dirAlfred = UP;
- // } else if (y > yAlfred) {
- // dirAlfred = DOWN;
- // }
- // debug("Setting Alfred to walk towards (%d, %d) from (%d, %d) in direction %d", x, y, xAlfred, yAlfred, dirAlfred);
_currentContext = context;
- // debug("Path find complete, movement count: %d", _currentContext.movement_count);
}
bool PelrockEngine::pathFind(int x, int y, PathContext *context) {
@@ -1389,7 +1389,7 @@ void PelrockEngine::drawText(Common::String text, int x, int y, int w, byte colo
_largeFont->drawString(_screen, text.c_str(), x, y, w, color, Graphics::kTextAlignCenter);
}
-void PelrockEngine::sayNPC(AnimSet *anim, Common::String text, byte color) {
+void PelrockEngine::sayNPC(Sprite *anim, Common::String text, byte color) {
isNPCATalking = true;
whichNPCTalking = anim->extra;
debug("NPC says %s, color = %d", text.c_str(), color);
@@ -1577,6 +1577,7 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
// _soundManager->playSound(_room->_roomSfx[i]);
// }
+ _room->_currentRoomNumber = number;
_screen->markAllDirty();
roomFile.close();
delete[] background;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 6c46e2c8686..0529e446045 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -58,7 +58,6 @@ private:
ResourceManager *_res = nullptr;
void init();
- void setScreen(int s, AlfredDirection dir);
void loadAnims();
void walkTo(int x, int y);
@@ -85,19 +84,19 @@ private:
void drawText(Common::String text, int x, int y, int w, byte color);
void sayAlfred(Common::String text);
- void sayNPC(AnimSet *anim, Common::String text, byte color);
+ void sayNPC(Sprite *anim, Common::String text, byte color);
void frames();
void doAction(byte action, byte object);
void renderText(Common::Array<Common::String> lines, int color, int x, int y);
void drawAlfred(byte *buf);
- void drawNextFrame(AnimSet *animSet);
+ void drawNextFrame(Sprite *animSet);
void changeCursor(Cursor cursor);
int isHotspotUnder(int x, int y);
Exit *isExitUnder(int x, int y);
- AnimSet *isSpriteUnder(int x, int y);
+ Sprite *isSpriteUnder(int x, int y);
void showActionBalloon(int posx, int posy, int curFrame);
- void drawTalkNPC(AnimSet *animSet);
+ void drawTalkNPC(Sprite *animSet);
void checkMouseHover();
void checkMouseClick(int x, int y);
@@ -217,6 +216,9 @@ public:
Common::Serializer s(stream, nullptr);
return syncGame(s);
}
+
+
+ void setScreen(int s, AlfredDirection dir);
};
extern PelrockEngine *g_engine;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index ef15b1258ae..ba3372913a5 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -180,7 +180,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
}
_currentRoomConversations = roots;
- Common::Array<AnimSet> anims = loadRoomAnimations(roomFile, roomOffset);
+ Common::Array<Sprite> anims = loadRoomAnimations(roomFile, roomOffset);
Common::Array<HotSpot> hotspots;
for (int i = 0; i < anims.size(); i++) {
@@ -234,7 +234,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
}
}
-Common::Array<AnimSet> RoomManager::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
+Common::Array<Sprite> RoomManager::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
uint32_t pair_offset = roomOffset + (8 * 8);
// debug("Sprite pair offset position: %d", pair_offset);
roomFile->seek(pair_offset, SEEK_SET);
@@ -249,9 +249,9 @@ Common::Array<AnimSet> RoomManager::loadRoomAnimations(Common::File *roomFile, i
if (offset > 0 && size > 0) {
rleDecompress(data, size, 0, size, &pic, true);
} else {
- return Common::Array<AnimSet>();
+ return Common::Array<Sprite>();
}
- Common::Array<AnimSet> anims = Common::Array<AnimSet>();
+ Common::Array<Sprite> anims = Common::Array<Sprite>();
uint32_t spriteEnd = offset + size;
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
@@ -262,52 +262,55 @@ Common::Array<AnimSet> RoomManager::loadRoomAnimations(Common::File *roomFile, i
byte *animData = new byte[44];
roomFile->seek(animOffset, SEEK_SET);
roomFile->read(animData, 44);
- AnimSet animSet;
- animSet.index = i;
- animSet.x = animData[0] | (animData[1] << 8);
- animSet.y = animData[2] | (animData[3] << 8);
- animSet.w = animData[4];
- animSet.h = animData[5];
- animSet.extra = animData[6];
+ Sprite sprite;
+ sprite.index = i;
+ sprite.x = animData[0] | (animData[1] << 8);
+ sprite.y = animData[2] | (animData[3] << 8);
+ sprite.w = animData[4];
+ sprite.h = animData[5];
+ sprite.extra = animData[6];
// roomFile->skip(1); // reserved
- animSet.numAnims = animData[8];
- animSet.spriteType = animData[33];
- animSet.actionFlags = animData[34];
- animSet.isDisabled = animData[38];
- if (animSet.numAnims == 0) {
+ sprite.numAnims = animData[8];
+ sprite.zOrder = animData[23];
+ sprite.spriteType = animData[33];
+ sprite.actionFlags = animData[34];
+ sprite.isDisabled = animData[38];
+ if (sprite.numAnims == 0) {
break;
}
- animSet.animData = new Anim[animSet.numAnims];
+ sprite.animData = new Anim[sprite.numAnims];
// debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
int subAnimOffset = 10;
- for (int j = 0; j < animSet.numAnims; j++) {
+ for (int j = 0; j < sprite.numAnims; j++) {
Anim anim;
- anim.x = animSet.x;
- anim.y = animSet.y;
- anim.w = animSet.w;
- anim.h = animSet.h;
+ anim.x = sprite.x;
+ anim.y = sprite.y;
+ anim.w = sprite.w;
+ anim.h = sprite.h;
anim.curFrame = 0;
anim.nframes = animData[subAnimOffset + j];
anim.loopCount = animData[subAnimOffset + 4 + j];
anim.speed = animData[subAnimOffset + 8 + j];
+ anim.movementFlags = animData[subAnimOffset + 14 + (j*2)] | (animData[subAnimOffset + 14 + (j*2) + 1] << 8);
anim.animData = new byte[anim.nframes];
if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
uint32_t needed = anim.w * anim.h * anim.nframes;
anim.animData = new byte[needed];
Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
- animSet.animData[j] = anim;
- // debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
+ sprite.animData[j] = anim;
+ debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
+ debug(" Movement flags: 0x%04X", anim.movementFlags);
picOffset += needed;
} else {
continue;
debug("Anim %d-%d: invalid dimensions, skipping", i, j);
}
- animSet.animData[j] = anim;
+ sprite.animData[j] = anim;
}
- anims.push_back(animSet);
+ anims.push_back(sprite);
}
return anims;
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 3ec5fbf4ad1..2d081c21e2e 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -47,7 +47,7 @@ public:
}
Common::Array<HotSpot> _currentRoomHotspots;
- Common::Array<AnimSet> _currentRoomAnims;
+ Common::Array<Sprite> _currentRoomAnims;
Common::Array<Exit> _currentRoomExits;
Common::Array<WalkBox> _currentRoomWalkboxes;
Common::Array<Description> _currentRoomDescriptions;
@@ -61,9 +61,10 @@ public:
Common::StringArray _roomNames;
byte _musicTrack = 0;
Common::Array<byte> _roomSfx;
+ byte _currentRoomNumber = 0;
private:
- Common::Array<AnimSet> loadRoomAnimations(Common::File *roomFile, int roomOffset);
+ Common::Array<Sprite> loadRoomAnimations(Common::File *roomFile, int roomOffset);
Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
Common::Array<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::Array<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 52bb901e52b..f5531cd98de 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -37,6 +37,8 @@
namespace Pelrock {
+
+
SoundManager::SoundManager(Audio::Mixer *mixer)
: _mixer(mixer), _currentVolume(255), _musicFile(nullptr) {
// TODO: Initialize sound manager
@@ -250,26 +252,31 @@ void SoundManager::loadSoundIndex() {
sonidosFile.close();
}
-
-int gerRandomNumber() {
-
-
-}
+int RANDOM_THRESHOLD = 0x4000;
int SoundManager::tick() {
soundFrameCounter++;
- uint32 random = g_engine->getRandomNumber(1);
- if(!random) {
+
+ uint16 rand1 = _rng.nextRandom();
+ // uint32 random = g_engine->getRandomNumber(1);
+ if(rand1 <= RANDOM_THRESHOLD){
+ // debug("No SFX this tick due to 50% random");
return -1;
}
- if((soundFrameCounter & COUNTER_MASK) != COUNTER_MASK){
+ if((soundFrameCounter & COUNTER_MASK) != COUNTER_MASK){
+ // debug("No SFX this tick due to counter mask (counter = %d)", soundFrameCounter);
return -1;
}
+
+ uint16 rand2 = _rng.nextRandom();
+ int slot = rand2 & 3;
+ debug("Slot = %d (rand2 = %u)", slot, rand2);
+
soundFrameCounter = 0;
- uint32 slot = g_engine->getRandomNumber(4);
- return slot;
+ // uint32 slot = g_engine->getRandomNumber(4);
+ return slot + 1;
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index c2a4372a35f..3be968743ea 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -154,6 +154,36 @@ static const uint COUNTER_MASK = 0x1F;
const int kMaxChannels = 15;
+
+
+ class GameRNG {
+
+private:
+ uint32_t _state;
+public:
+ // LCG constants (from JUEGO.EXE @ 0x0002b12f)
+ static constexpr uint32_t MULTIPLIER = 0x41C64E6D; // 1103515245
+ static constexpr uint32_t INCREMENT = 0x3039; // 12345
+
+ GameRNG(uint32_t seed = 0) {
+ _state = seed & 0xFFFFFFFF;
+ }
+
+ // Generate next random number (0-32767)
+ uint16_t nextRandom() {
+ _state = (_state * MULTIPLIER + INCREMENT) & 0xFFFFFFFF;
+ return static_cast<uint16_t>((_state >> 16) & 0x7FFF);
+ }
+
+ uint32_t getState() const {
+ return _state;
+ }
+
+ void setState(uint32_t state) {
+ _state = state & 0xFFFFFFFF;
+ }
+};
+
class SoundManager {
public:
SoundManager(Audio::Mixer *mixer);
@@ -189,8 +219,12 @@ private:
Audio::SoundHandle _sfxHandles[kMaxChannels];
int soundFrameCounter = 0;
Common::HashMap<Common::String, SonidoFile> _soundMap;
+ GameRNG _rng = GameRNG(0);
};
+
+
+
} // End of namespace Pelrock
#endif // PELROCK_SOUND_H
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 83fe1f8676d..c832ba20afe 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -139,8 +139,8 @@ typedef struct {
} PathContext;
struct Anim {
- int x;
- int y;
+ int16 x;
+ int16 y;
int w;
int h;
int nframes;
@@ -150,31 +150,33 @@ struct Anim {
byte loopCount;
byte speed;
byte elpapsedFrames = 0;
+ uint16 movementFlags = 0;
};
struct Exit {
- uint16 x;
- uint16 y;
+ int16 x;
+ int16 y;
byte w;
byte h;
uint16 targetRoom;
- uint16 targetX;
- uint16 targetY;
+ int16 targetX;
+ int16 targetY;
uint16 targetDir;
AlfredDirection dir;
byte flags;
};
-struct AnimSet {
+struct Sprite {
int index; // number of the animation in the rooms
byte type;
- int x; // 0
- int y; // 2
+ int16 x; // 0
+ int16 y; // 2
int w; // 4
int h; // 5
byte extra; // 6
int numAnims; // 8
int curAnimIndex = 0;
+ byte zOrder;
byte spriteType; // 33
byte actionFlags; // 34
bool isDisabled; // 38
Commit: ea20c30125dbd44e78ea12ddc62a4323f0f43e5c
https://github.com/scummvm/scummvm/commit/ea20c30125dbd44e78ea12ddc62a4323f0f43e5c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:17+02:00
Commit Message:
PELROCK: Fixes walking algorithm
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/sound.cpp
engines/pelrock/types.h
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 4095abd9f89..871ee128675 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -129,6 +129,11 @@ Common::Error PelrockEngine::run() {
case Common::KEYCODE_z:
showShadows = !showShadows;
break;
+ case Common::KEYCODE_y:
+ alfredState.x = 193;
+ alfredState.y = 382;
+ walkTo(377, 318);
+ break;
default:
break;
}
@@ -320,7 +325,7 @@ void PelrockEngine::frames() {
int soundIndex = _soundManager->tick();
if(soundIndex >= 0 && soundIndex < _room->_roomSfx.size()) {
- debug("Playing SFX index %d", soundIndex);
+ // debug("Playing SFX index %d", soundIndex);
_soundManager->playSound(_room->_roomSfx[3 + soundIndex]);
}
@@ -334,7 +339,8 @@ void PelrockEngine::frames() {
}
switch (alfredState.animState) {
case ALFRED_WALKING: {
- MovementStep step = _currentContext.movement_buffer[_current_step];
+
+ MovementStep step = _currentContext.movementBuffer[_currentStep];
if (step.distance_x > 0) {
if (step.flags & MOVE_RIGHT) {
@@ -364,13 +370,13 @@ void PelrockEngine::frames() {
step.distance_y -= MIN(alfredState.movementSpeed, step.distance_y);
if (step.distance_x <= 0 && step.distance_y <= 0) {
- _current_step++;
- if (_current_step >= _currentContext.movement_count) {
- _current_step = 0;
+ _currentStep++;
+ if (_currentStep >= _currentContext.movementCount) {
+ _currentStep = 0;
alfredState.animState = ALFRED_IDLE;
}
} else {
- _currentContext.movement_buffer[_current_step] = step;
+ _currentContext.movementBuffer[_currentStep] = step;
}
Exit *exit = isExitUnder(alfredState.x, alfredState.y);
@@ -471,6 +477,7 @@ void PelrockEngine::frames() {
// debug("Drawing walkbox %d", i);
WalkBox box = _room->_currentRoomWalkboxes[i];
drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
+ _smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
}
if (_curWalkTarget.x < 640 && _curWalkTarget.y < 400 && _curWalkTarget.x >= 0 && _curWalkTarget.y >= 0) {
_screen->setPixel(_curWalkTarget.x, _curWalkTarget.y, 100);
@@ -671,7 +678,10 @@ void applyMovement(int16_t *x, int16_t *y, /*int8_t *z,*/ uint16_t flags) {
void PelrockEngine::drawNextFrame(Sprite *sprite) {
Anim &animData = sprite->animData[sprite->curAnimIndex];
-
+ if(sprite->zOrder == -1) {
+ // skips z0rder -1 sprites
+ return;
+ }
applyMovement(&(sprite->x), &(sprite->y), animData.movementFlags);
int x = sprite->x;
@@ -885,15 +895,15 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _res->_popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
Common::Array<VerbIcons> actions = availableActions(_currentHotspot);
- drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[LOOK], posx + 20, posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
+ // drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[LOOK], posx + 20, posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
// Graphics::Surface rects;
// rects.create(kVerbIconWidth, kVerbIconHeight, Graphics::PixelFormat::createFormatCLUT8());
- // drawRect(&rects, 0, 0, kVerbIconWidth, kVerbIconHeight, 255);
+ // drawRect(&rects, 0, 0, kVerbIconWidth, kVerbIconHeight, 1);
- // blitSurfaceToBuffer(&rects, _compositeBuffer, 640, 480, posx + ver, posy + 20);
for (int i = 0; i < actions.size(); i++) {
drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
+ // blitSurfaceToBuffer(&rects, _compositeBuffer, 640, 480, posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20);
}
}
@@ -925,81 +935,79 @@ void PelrockEngine::drawTalkNPC(Sprite *animSet) {
}
void PelrockEngine::walkTo(int x, int y) {
- alfredState.animState = ALFRED_WALKING;
- alfredState.curFrame = 0;
-
- PathContext context = {NULL, NULL, NULL, 0, 0, 0};
+ _currentStep = 0;
+ PathContext context = {nullptr, nullptr, nullptr, 0, 0, 0};
pathFind(x, y, &context);
_currentContext = context;
+ alfredState.animState = ALFRED_WALKING;
+ alfredState.curFrame = 0;
}
-bool PelrockEngine::pathFind(int x, int y, PathContext *context) {
+bool PelrockEngine::pathFind(int targetX, int targetY, PathContext *context) {
- if (context->path_buffer == NULL) {
- context->path_buffer = (uint8_t *)malloc(MAX_PATH_LENGTH);
+ if (context->pathBuffer == NULL) {
+ context->pathBuffer = (uint8_t *)malloc(MAX_PATH_LENGTH);
}
- if (context->movement_buffer == NULL) {
- context->movement_buffer = (MovementStep *)malloc(MAX_MOVEMENT_STEPS * sizeof(MovementStep));
+ if (context->movementBuffer == NULL) {
+ context->movementBuffer = (MovementStep *)malloc(MAX_MOVEMENT_STEPS * sizeof(MovementStep));
}
int startX = alfredState.x;
int startY = alfredState.y;
- Common::Point target = calculateWalkTarget(x, y);
- x = target.x;
- y = target.y;
- debug("Startx= %d, starty= %d, destx= %d, desty= %d", startX, startY, x, y);
+ Common::Point target = calculateWalkTarget(targetX, targetY);
+ targetX = target.x;
+ targetY = target.y;
+ debug("Startx= %d, starty= %d, destx= %d, desty= %d", startX, startY, targetX, targetY);
- uint8_t start_box = find_walkbox_for_point(startX, startY);
- uint8_t dest_box = find_walkbox_for_point(x, y);
+ uint8_t startBox = findWalkboxForPoint(startX, startY);
+ uint8_t destBox = findWalkboxForPoint(targetX, targetY);
- debug("Pathfinding from (%d, %d) in box %d to (%d, %d) in box %d\n",
- startX, startY, start_box,
- x, y, dest_box);
+ debug("Pathfinding from (%d, %d) in box %d to (%d, %d) in box %d\n", startX, startY, startBox, targetX, targetY, destBox);
// Check if both points are in valid walkboxes
- if (start_box == 0xFF || dest_box == 0xFF) {
+ if (startBox == 0xFF || destBox == 0xFF) {
debug("Error: Start or destination not in any walkbox\n");
return false;
}
// Special case: same walkbox
- if (start_box == dest_box) {
+ if (startBox == destBox) {
// Generate direct movement
MovementStep direct_step;
direct_step.flags = 0;
- if (startX < x) {
- direct_step.distance_x = x - startX;
+ if (startX < targetX) {
+ direct_step.distance_x = targetX - startX;
direct_step.flags |= MOVE_RIGHT;
} else {
- direct_step.distance_x = startX - x;
+ direct_step.distance_x = startX - targetX;
direct_step.flags |= MOVE_LEFT;
}
- if (startY < y) {
- direct_step.distance_y = y - startY;
+ if (startY < targetY) {
+ direct_step.distance_y = targetY - startY;
direct_step.flags |= MOVE_DOWN;
} else {
- direct_step.distance_y = startY - y;
+ direct_step.distance_y = startY - targetY;
direct_step.flags |= MOVE_UP;
}
- context->movement_buffer[0] = direct_step;
- context->movement_count = 1;
+ context->movementBuffer[0] = direct_step;
+ context->movementCount = 1;
} else {
// Build walkbox path
- context->path_length = build_walkbox_path(start_box, dest_box,
- context->path_buffer);
-
- if (context->path_length == 0) {
+ context->pathLength = buildWalkboxPath(startBox, destBox, context->pathBuffer);
+ debug("Walkbox path to point");
+ for(int i = 0; i < context->pathLength; i++) {
+ debug("Walkbox %d: %d", i, context->pathBuffer[i]);
+ }
+ if (context->pathLength == 0) {
debug("Error: No path found\n");
return false;
}
// Generate movement steps
- context->movement_count = generate_movement_steps(
- context->path_buffer,
- context->path_length,
- startX, startY,
- x, y,
- context->movement_buffer);
+ context->movementCount = generateMovementSteps(context->pathBuffer, context->pathLength, startX, startY, targetX, targetY, context->movementBuffer);
+ for(int i = 0; i < context->movementCount; i++) {
+ debug("Movement step %d: flags=\"%s\", dx=%d, dy=%d", i, printMovementFlags(context->movementBuffer[i].flags).c_str(), context->movementBuffer[i].distance_x, context->movementBuffer[i].distance_y);
+ }
}
return true;
}
@@ -1007,7 +1015,7 @@ bool PelrockEngine::pathFind(int x, int y, PathContext *context) {
/**
* Calculate movement needed to reach a target within a walkbox
*/
-void calculate_movement_to_target(uint16_t current_x, uint16_t current_y,
+void calculateMovementToTarget(uint16_t current_x, uint16_t current_y,
uint16_t target_x, uint16_t target_y,
WalkBox *box,
MovementStep *step) {
@@ -1042,39 +1050,37 @@ void calculate_movement_to_target(uint16_t current_x, uint16_t current_y,
* Generate movement steps from walkbox path
* Returns: number of movement steps generated
*/
-uint16_t PelrockEngine::generate_movement_steps(uint8_t *path_buffer,
- uint16_t path_length,
- uint16_t start_x, uint16_t start_y,
- uint16_t dest_x, uint16_t dest_y,
- MovementStep *movement_buffer) {
- uint16_t current_x = start_x;
- uint16_t current_y = start_y;
- uint16_t movement_index = 0;
+uint16_t PelrockEngine::generateMovementSteps(uint8_t *pathBuffer,
+ uint16_t pathLength,
+ uint16_t startX, uint16_t startY,
+ uint16_t destX, uint16_t destY,
+ MovementStep *movementBuffer) {
+ uint16_t currentX = startX;
+ uint16_t currentY = startY;
+ uint16_t movementIndex = 0;
// Generate movements for each walkbox in path
- for (uint16_t i = 0; i < path_length && path_buffer[i] != PATH_END; i++) {
- uint8_t box_index = path_buffer[i];
- WalkBox *box = &_room->_currentRoomWalkboxes[box_index];
+ for (uint16_t i = 0; i < pathLength && pathBuffer[i] != PATH_END; i++) {
+ uint8_t boxIndex = pathBuffer[i];
+ WalkBox *box = &_room->_currentRoomWalkboxes[boxIndex];
MovementStep step;
- calculate_movement_to_target(current_x, current_y,
- dest_x, dest_y,
- box, &step);
+ calculateMovementToTarget(currentX, currentY, destX, destY, box, &step);
if (step.distance_x > 0 || step.distance_y > 0) {
- movement_buffer[movement_index++] = step;
+ movementBuffer[movementIndex++] = step;
// Update current position
if (step.flags & MOVE_RIGHT) {
- current_x = box->x;
+ currentX = box->x;
} else if (step.flags & MOVE_LEFT) {
- current_x = box->x + box->w;
+ currentX = box->x + box->w;
}
if (step.flags & MOVE_DOWN) {
- current_y = box->y;
+ currentY = box->y;
} else if (step.flags & MOVE_UP) {
- current_y = box->y + box->h;
+ currentY = box->y + box->h;
}
}
}
@@ -1083,77 +1089,75 @@ uint16_t PelrockEngine::generate_movement_steps(uint8_t *path_buffer,
MovementStep final_step;
final_step.flags = 0;
- if (current_x < dest_x) {
- final_step.distance_x = dest_x - current_x;
+ if (currentX < destX) {
+ final_step.distance_x = destX - currentX;
final_step.flags |= MOVE_RIGHT;
- } else if (current_x > dest_x) {
- final_step.distance_x = current_x - dest_x;
+ } else if (currentX > destX) {
+ final_step.distance_x = currentX - destX;
final_step.flags |= MOVE_LEFT;
} else {
final_step.distance_x = 0;
}
- if (current_y < dest_y) {
- final_step.distance_y = dest_y - current_y;
+ if (currentY < destY) {
+ final_step.distance_y = destY - currentY;
final_step.flags |= MOVE_DOWN;
- } else if (current_y > dest_y) {
- final_step.distance_y = current_y - dest_y;
+ } else if (currentY > destY) {
+ final_step.distance_y = currentY - destY;
final_step.flags |= MOVE_UP;
} else {
final_step.distance_y = 0;
}
if (final_step.distance_x > 0 || final_step.distance_y > 0) {
- movement_buffer[movement_index++] = final_step;
+ movementBuffer[movementIndex++] = final_step;
}
- return movement_index;
+ return movementIndex;
}
-uint16_t PelrockEngine::build_walkbox_path(
- uint8_t start_box,
- uint8_t dest_box,
- uint8_t *path_buffer) {
- uint16_t path_index = 0;
- uint8_t current_box = start_box;
+uint16_t PelrockEngine::buildWalkboxPath(uint8_t startBox, uint8_t destBox, uint8_t *pathBuffer) {
+
+ uint16_t pathIndex = 0;
+ uint8_t currentBox = startBox;
// Initialize path with start walkbox
- path_buffer[path_index++] = start_box;
+ pathBuffer[pathIndex++] = startBox;
// Clear visited flags
- clear_visited_flags();
+ clearVisitedFlags();
// Breadth-first search through walkboxes
- while (current_box != dest_box && path_index < MAX_PATH_LENGTH - 1) {
- uint8_t next_box = get_adjacent_walkbox(current_box);
+ while (currentBox != destBox && pathIndex < MAX_PATH_LENGTH - 1) {
+ uint8_t nextBox = getAdjacentWalkbox(currentBox);
- if (next_box == 0xFF) {
+ if (nextBox == 0xFF) {
// Dead end - backtrack
- if (path_index > 1) {
- path_index--;
- current_box = path_buffer[path_index - 1];
+ if (pathIndex > 1) {
+ pathIndex--;
+ currentBox = pathBuffer[pathIndex - 1];
} else {
// No path exists
return 0;
}
- } else if (next_box == dest_box) {
+ } else if (nextBox == destBox) {
// Found destination
- path_buffer[path_index++] = dest_box;
+ pathBuffer[pathIndex++] = destBox;
break;
} else {
// Continue searching
- path_buffer[path_index++] = next_box;
- current_box = next_box;
+ pathBuffer[pathIndex++] = nextBox;
+ currentBox = nextBox;
}
}
// Terminate path
- path_buffer[path_index] = PATH_END;
+ pathBuffer[pathIndex] = PATH_END;
- return path_index;
+ return pathIndex;
}
-void PelrockEngine::clear_visited_flags() {
+void PelrockEngine::clearVisitedFlags() {
for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
_room->_currentRoomWalkboxes[i].flags = 0;
}
@@ -1162,31 +1166,31 @@ void PelrockEngine::clear_visited_flags() {
/**
* Check if two walkboxes overlap or touch (are adjacent)
*/
-bool walkboxes_adjacent(WalkBox *box1, WalkBox *box2) {
+bool areWalkboxesAdjacent(WalkBox *box1, WalkBox *box2) {
uint16_t box1_x_max = box1->x + box1->w;
uint16_t box1_y_max = box1->y + box1->h;
uint16_t box2_x_max = box2->x + box2->w;
uint16_t box2_y_max = box2->y + box2->h;
// Check if X ranges overlap
- bool x_overlap = (box1->x <= box2_x_max) && (box2->x <= box1_x_max);
+ bool xOverlap = (box1->x <= box2_x_max) && (box2->x <= box1_x_max);
// Check if Y ranges overlap
- bool y_overlap = (box1->y <= box2_y_max) && (box2->y <= box1_y_max);
+ bool yOverlap = (box1->y <= box2_y_max) && (box2->y <= box1_y_max);
- return x_overlap && y_overlap;
+ return xOverlap && yOverlap;
}
-uint8_t PelrockEngine::get_adjacent_walkbox(uint8_t current_box_index) {
- WalkBox *current_box = &_room->_currentRoomWalkboxes[current_box_index];
+uint8_t PelrockEngine::getAdjacentWalkbox(uint8_t currentBoxIndex) {
+ WalkBox *currentBox = &_room->_currentRoomWalkboxes[currentBoxIndex];
// Mark current walkbox as visited
- current_box->flags = 0x01;
+ currentBox->flags = 0x01;
// Search for adjacent unvisited walkbox
for (uint8_t i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
// Skip current walkbox
- if (i == current_box_index) {
+ if (i == currentBoxIndex) {
continue;
}
@@ -1196,7 +1200,7 @@ uint8_t PelrockEngine::get_adjacent_walkbox(uint8_t current_box_index) {
}
// Check if walkboxes are adjacent
- if (walkboxes_adjacent(current_box, &_room->_currentRoomWalkboxes[i])) {
+ if (areWalkboxesAdjacent(currentBox, &_room->_currentRoomWalkboxes[i])) {
return i;
}
}
@@ -1204,16 +1208,16 @@ uint8_t PelrockEngine::get_adjacent_walkbox(uint8_t current_box_index) {
return 0xFF; // No adjacent walkbox found
}
-bool PelrockEngine::point_in_walkbox(WalkBox *box, uint16_t x, uint16_t y) {
+bool PelrockEngine::isPointInWalkbox(WalkBox *box, uint16_t x, uint16_t y) {
return (x >= box->x &&
x <= box->x + box->w &&
y >= box->y &&
y <= box->y + box->h);
}
-uint8_t PelrockEngine::find_walkbox_for_point(uint16_t x, uint16_t y) {
+uint8_t PelrockEngine::findWalkboxForPoint(uint16_t x, uint16_t y) {
for (uint8_t i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
- if (point_in_walkbox(&_room->_currentRoomWalkboxes[i], x, y)) {
+ if (isPointInWalkbox(&_room->_currentRoomWalkboxes[i], x, y)) {
return i;
}
}
@@ -1238,10 +1242,9 @@ void PelrockEngine::checkMouseClick(int x, int y) {
}
for (int i = 1; i < actions.size(); i++) {
- int x = _popupX + 20 + (i * (kVerbIconWidth + 2));
- int y = _popupY + 20;
- Common::Rect actionRect = Common::Rect(x, y, x + kVerbIconWidth, y + kVerbIconHeight);
-
+ int actionX = _popupX + 20 + (i * (kVerbIconWidth + 2));
+ int actionY = _popupY + 20;
+ Common::Rect actionRect = Common::Rect(actionX, actionY, actionX + kVerbIconWidth, actionY + kVerbIconHeight);
if (actionRect.contains(x, y)) {
debug("Action %d clicked", actions[i]);
doAction(actions[i], _currentHotspot->extra);
@@ -1541,7 +1544,7 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
}
alfredState.direction = dir;
alfredState.animState = ALFRED_IDLE;
- _current_step = 0;
+ _currentStep = 0;
int roomOffset = number * kRoomStructSize;
alfredState.curFrame = 0;
byte *palette = new byte[256 * 3];
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 0529e446045..c2121a17301 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -62,12 +62,12 @@ private:
void walkTo(int x, int y);
bool pathFind(int x, int y, PathContext *context);
- uint8_t find_walkbox_for_point(uint16_t x, uint16_t y);
- bool point_in_walkbox(WalkBox *box, uint16_t x, uint16_t y);
- uint16_t build_walkbox_path(uint8_t start_box, uint8_t dest_box, uint8_t *path_buffer);
- uint8_t get_adjacent_walkbox(uint8_t current_box_index);
- void clear_visited_flags();
- uint16_t generate_movement_steps(uint8_t *path_buffer,
+ uint8_t findWalkboxForPoint(uint16_t x, uint16_t y);
+ bool isPointInWalkbox(WalkBox *box, uint16_t x, uint16_t y);
+ uint16_t buildWalkboxPath(uint8_t start_box, uint8_t dest_box, uint8_t *path_buffer);
+ uint8_t getAdjacentWalkbox(uint8_t current_box_index);
+ void clearVisitedFlags();
+ uint16_t generateMovementSteps(uint8_t *path_buffer,
uint16_t path_length,
uint16_t start_x, uint16_t start_y,
uint16_t dest_x, uint16_t dest_y,
@@ -109,7 +109,7 @@ private:
Common::Array<Common::Array<int>> _heightScalingTable;
// walking
- int _current_step = 0;
+ int _currentStep = 0;
PathContext _currentContext;
// text display
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index ba3372913a5..2c316012176 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -170,13 +170,13 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
int roomOffset = roomNumber * kRoomStructSize;
Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
- debug("After decsriptions, position is %d", outPos);
+ // debug("After decsriptions, position is %d", outPos);
Common::Array<ConversationNode> roots = loadConversations(roomFile, roomOffset, outPos);
for (int i = 0; i < roots.size(); i++) {
if (roots[i].text.empty()) {
continue;
}
- debug("Conversation %d: %s", i, roots[i].text.c_str());
+ // debug("Conversation %d: %s", i, roots[i].text.c_str());
}
_currentRoomConversations = roots;
@@ -202,7 +202,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
ScalingParams scalingParams = loadScalingParams(roomFile, roomOffset);
Common::Array<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
- debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
+ // debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
for (int i = 0; i < staticHotspots.size(); i++) {
HotSpot hotspot = staticHotspots[i];
hotspot.index = anims.size() + i;
@@ -300,12 +300,12 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(Common::File *roomFile, in
anim.animData = new byte[needed];
Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
sprite.animData[j] = anim;
- debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
- debug(" Movement flags: 0x%04X", anim.movementFlags);
+ // debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
+ // debug(" Movement flags: 0x%04X", anim.movementFlags);
picOffset += needed;
} else {
continue;
- debug("Anim %d-%d: invalid dimensions, skipping", i, j);
+ // debug("Anim %d-%d: invalid dimensions, skipping", i, j);
}
sprite.animData[j] = anim;
}
@@ -461,7 +461,7 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
talkFile.read(&talkHeader.unknown5, 2);
talkHeader.numFramesAnimB = talkFile.readByte();
talkFile.read(&talkHeader.unknown6, 29);
- debug("Talking anim header for room %d: spritePointer=%d, wA=%d, hA=%d, framesA=%d, wB=%d, hB=%d, framesB=%d", roomNumber, talkHeader.spritePointer, talkHeader.wAnimA, talkHeader.hAnimA, talkHeader.numFramesAnimA, talkHeader.wAnimB, talkHeader.hAnimB, talkHeader.numFramesAnimB);
+ // debug("Talking anim header for room %d: spritePointer=%d, wA=%d, hA=%d, framesA=%d, wB=%d, hB=%d, framesB=%d", roomNumber, talkHeader.spritePointer, talkHeader.wAnimA, talkHeader.hAnimA, talkHeader.numFramesAnimA, talkHeader.wAnimB, talkHeader.hAnimB, talkHeader.numFramesAnimB);
if (talkHeader.spritePointer == 0) {
debug("No talking animation for room %d", roomNumber);
@@ -960,7 +960,7 @@ byte RoomManager::loadMusicTrackForRoom(Common::File *roomFile, int roomOffset)
roomFile->seek(pair9_data_offset, SEEK_SET);
byte musicTrack = roomFile->readByte();
- debug("Music track for room at offset %d is %d", roomOffset, musicTrack);
+ // debug("Music track for room at offset %d is %d", roomOffset, musicTrack);
return musicTrack > 0 ? musicTrack + 1 : 0;
}
@@ -976,7 +976,7 @@ Common::Array<byte> RoomManager::loadRoomSfx(Common::File *roomFile, int roomOff
for (int i = 0; i < kNumSfxPerRoom; i++) {
byte sfx = roomFile->readByte();
roomSfx[i] = sfx;
- debug("SFX %d for room at offset %d is %d (%s)", i, roomOffset, sfx, SOUND_FILENAMES[sfx]);
+ // debug("SFX %d for room at offset %d is %d (%s)", i, roomOffset, sfx, SOUND_FILENAMES[sfx]);
}
return roomSfx;
}
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index f5531cd98de..22e41377808 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -50,7 +50,7 @@ SoundManager::~SoundManager() {
}
void SoundManager::playSound(byte index, int volume) {
- debug("Playing sound index %d (%s)", index, SOUND_FILENAMES[index]);
+ // debug("Playing sound index %d (%s)", index, SOUND_FILENAMES[index]);
auto it = _soundMap.find(SOUND_FILENAMES[index]);
if (it != _soundMap.end()) {
playSound(it->_value, volume);
@@ -272,7 +272,7 @@ int SoundManager::tick() {
uint16 rand2 = _rng.nextRandom();
int slot = rand2 & 3;
- debug("Slot = %d (rand2 = %u)", slot, rand2);
+ // debug("Slot = %d (rand2 = %u)", slot, rand2);
soundFrameCounter = 0;
// uint32 slot = g_engine->getRandomNumber(4);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index c832ba20afe..e212ae31c3a 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -130,11 +130,11 @@ typedef struct {
* Pathfinding context
*/
typedef struct {
- uint8_t *path_buffer; // Sequence of walkbox indices
- MovementStep *movement_buffer; // Array of movement steps
+ uint8_t *pathBuffer; // Sequence of walkbox indices
+ MovementStep *movementBuffer; // Array of movement steps
uint8_t *compressed_path; // Final compressed path
- uint16_t path_length;
- uint16_t movement_count;
+ uint16_t pathLength;
+ uint16_t movementCount;
uint16_t compressed_length;
} PathContext;
@@ -176,7 +176,7 @@ struct Sprite {
byte extra; // 6
int numAnims; // 8
int curAnimIndex = 0;
- byte zOrder;
+ int8 zOrder;
byte spriteType; // 33
byte actionFlags; // 34
bool isDisabled; // 38
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 46e3e532e4a..72e071f3256 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -20,8 +20,9 @@
*/
#include "common/stream.h"
-#include "pelrock/util.h"
#include "pelrock/types.h"
+#include "pelrock/util.h"
+#include "util.h"
namespace Pelrock {
@@ -34,21 +35,42 @@ void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byt
}
void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color) {
- // debug("Drawing rect at (%d,%d) w=%d h=%d color=%d", x, y, w, h, color);
surface->drawLine(x, y, x + w, y, color);
surface->drawLine(x, y + h, x + w, y + h, color);
surface->drawLine(x, y, x, y + h, color);
surface->drawLine(x + w, y, x + w, y + h, color);
}
+Common::String printMovementFlags(uint8_t flags) {
+ Common::String result;
+ if (flags & MOVE_HORIZ) {
+ result += "HORIZ ";
+ }
+ if (flags & MOVE_VERT) {
+ result += "VERT ";
+ }
+ if (flags & MOVE_DOWN) {
+ result += "DOWN ";
+ }
+ if (flags & MOVE_LEFT) {
+ result += "LEFT ";
+ }
+ if (flags & MOVE_UP) {
+ result += "UP ";
+ }
+ if (flags & MOVE_RIGHT) {
+ result += "RIGHT ";
+ }
+ return result;
+}
+
size_t rleDecompress(
const uint8_t *input,
size_t inputSize,
uint32_t offset,
uint32_t expectedSize,
uint8_t **out_data,
- bool untilBuda
-) {
+ bool untilBuda) {
// // Check for uncompressed markers
if (inputSize == 0x8000 || inputSize == 0x6800) {
*out_data = (uint8_t *)malloc(inputSize);
@@ -87,26 +109,26 @@ size_t rleDecompress(
uint8_t value = input[pos + 1];
for (int i = 0; i < count; i++) {
- // If in untilBuda mode, grow buffer as needed
- if (untilBuda && result_size >= bufferCapacity) {
- bufferCapacity *= 2;
- uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
- if (!newBuf) {
- free(*out_data);
- *out_data = nullptr;
- return 0;
- }
- *out_data = newBuf;
- }
+ // If in untilBuda mode, grow buffer as needed
+ if (untilBuda && result_size >= bufferCapacity) {
+ bufferCapacity *= 2;
+ uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
+ if (!newBuf) {
+ free(*out_data);
+ *out_data = nullptr;
+ return 0;
+ }
+ *out_data = newBuf;
+ }
// debug("Pos = %zu, writing value %02X", result_size, value);
(*out_data)[result_size++] = value;
}
pos += 2;
- // In fixed size mode, stop when we reach expected size
- if (!untilBuda && result_size >= expectedSize) {
- break;
- }
+ // In fixed size mode, stop when we reach expected size
+ if (!untilBuda && result_size >= expectedSize) {
+ break;
+ }
}
return result_size;
@@ -163,6 +185,22 @@ void drawSpriteToBuffer(byte *buffer, int bufferWidth,
}
}
+void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY) {
+ for (int y = 0; y < surface->h; y++) {
+ for (int x = 0; x < surface->w; x++) {
+ int px = destX + x;
+ int py = destY + y;
+ if (px >= 0 && px < bufferWidth && py >= 0 && py < bufferHeight) {
+
+ byte pixel = *((byte *)surface->getBasePtr(x, y));
+ if (pixel != 0) {
+ buffer[py * bufferWidth + px] = pixel;
+ }
+ }
+ }
+ }
+}
+
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight) {
for (int y = 0; y < frameHeight; y++) {
for (int x = 0; x < frameWidth; x++) {
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 44b61c094c5..8e3de21718f 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -41,6 +41,7 @@ void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWid
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight);
void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
+Common::String printMovementFlags(uint8_t flags);
Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
} // End of namespace Pelrock
#endif // PELROCK_UTIL_H
Commit: ac84939fbbb0149a4bfec740a71ee2599565377b
https://github.com/scummvm/scummvm/commit/ac84939fbbb0149a4bfec740a71ee2599565377b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:17+02:00
Commit Message:
PELROCK: Refactor actions
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 871ee128675..07daaf682f4 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -220,35 +220,6 @@ void PelrockEngine::loadAnims() {
_res->loadAlfredAnims();
}
-void PelrockEngine::talk(byte object) {
- debug("Talking to object %d", object);
- if (_room->_currentRoomConversations.size() == 0)
- return;
-
- Sprite *animSet;
- for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (_room->_currentRoomAnims[i].extra == object) {
- animSet = &_room->_currentRoomAnims[i];
- }
- }
-
- ConversationNode selectedNode = _room->_currentRoomConversations[0];
-
- bool isNPC = selectedNode.speakerId != 13;
- if (isNPC) {
- sayNPC(animSet, selectedNode.text, selectedNode.speakerId);
- }
- // for(int i= 0; i< _currentRoomConversations.size(); i++) {
- // _currentRoomConversations
- // }
-
- // showDescription(_currentRoomConversations[0].text, x, y, _currentRoomConversations[0].speakerId);
- // for(int i = 0; i < _currentRoomConversations[0].choices.size(); i++) {
- // int idx = _currentRoomConversations.size() - 1 - i;
- // _smallFont->drawString(_screen, _currentRoomConversations[0].choices[idx].text.c_str(), 0, 400 - ((i + 1) * 12), 640, 14);
- // }
-}
-
void PelrockEngine::displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer) {
int overlayHeight = choices.size() * kChoiceHeight + 2;
int overlayY = 400 - overlayHeight;
@@ -284,36 +255,32 @@ void PelrockEngine::putBackgroundSlice(int x, int y, int w, int h, byte *slice)
}
}
-Common::Array<VerbIcons> PelrockEngine::availableActions(HotSpot *hotspot) {
- Common::Array<VerbIcons> verbs;
+Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
+ if(hotspot == nullptr) {
+ return Common::Array<VerbIcon>();
+ }
+ Common::Array<VerbIcon> verbs;
verbs.push_back(LOOK);
if (hotspot->type & 1) {
- debug("Hotspot allows OPEN action");
verbs.push_back(OPEN);
}
if (hotspot->type & 2) {
- debug("Hotspot allows CLOSE action");
verbs.push_back(CLOSE);
}
if (hotspot->type & 4) {
- debug("Hotspot allows UNKNOWN action");
verbs.push_back(UNKNOWN);
}
if (hotspot->type & 8) {
- debug("Hotspot allows PICKUP action");
verbs.push_back(PICKUP);
}
if (hotspot->type & 16) {
- debug("Hotspot allows TALK action");
verbs.push_back(TALK);
}
if (hotspot->type & 32) {
- debug("Hotspot allows WALK action");
verbs.push_back(PUSH);
}
if (hotspot->type & 128) {
- debug("Hotspot allows PULL action");
verbs.push_back(PULL);
}
return verbs;
@@ -324,7 +291,7 @@ void PelrockEngine::frames() {
if (_chronoManager->_gameTick) {
int soundIndex = _soundManager->tick();
- if(soundIndex >= 0 && soundIndex < _room->_roomSfx.size()) {
+ if (soundIndex >= 0 && soundIndex < _room->_roomSfx.size()) {
// debug("Playing SFX index %d", soundIndex);
_soundManager->playSound(_room->_roomSfx[3 + soundIndex]);
}
@@ -337,6 +304,12 @@ void PelrockEngine::frames() {
Sprite &animSet = _room->_currentRoomAnims[i];
drawNextFrame(&animSet);
}
+ // if(alfredState.animState == ALFRED_IDLE && alfredState.nextState != ALFRED_IDLE) {
+ // alfredState.animState = alfredState.nextState;
+ // alfredState.nextState = ALFRED_IDLE;
+ // alfredState.curFrame = 0;
+ // }
+
switch (alfredState.animState) {
case ALFRED_WALKING: {
@@ -424,19 +397,6 @@ void PelrockEngine::frames() {
}
if (_displayPopup) {
-
- // byte *bgDialog = new byte[kBalloonWidth * kBalloonHeight];
- // for (int j = 0; j < kBalloonWidth; j++) {
- // for (int i = 0; i < kBalloonHeight; i++) {
- // int idx = i * kBalloonWidth + j;
- // if (_popupY + i < 400 && _popupX + j < 640) {
- // *(bgDialog + idx) = _currentBackground[(_popupY + i) * 640 + (_popupX + j)];
- // }
- // }
- // }
- // if (_bgPopupBalloon != nullptr) {
- // putBackgroundSlice(_popupX, _popupY, kBalloonWidth, kBalloonHeight, _bgPopupBalloon);
- // }
showActionBalloon(_popupX, _popupY, _currentPopupFrame);
if (_currentPopupFrame < 3) {
_currentPopupFrame++;
@@ -452,8 +412,9 @@ void PelrockEngine::frames() {
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- if (alfredState.animState != ALFRED_WALKING && !_currentTextPages.empty()) {
+ if (alfredState.animState == ALFRED_TALKING && !_currentTextPages.empty()) {
if (_chronoManager->_textTtl > 0) {
+ _textPos = Common::Point(alfredState.x, alfredState.y - kAlfredFrameHeight - 10);
renderText(_currentTextPages[_currentTextPageIndex], _textColor, _textPos.x, _textPos.y);
} else if (_currentTextPageIndex < _currentTextPages.size() - 1) {
_currentTextPageIndex++;
@@ -472,6 +433,13 @@ void PelrockEngine::frames() {
}
}
+ if(alfredState.animState == ALFRED_IDLE && alfredState.nextState != ALFRED_IDLE) {
+ // debug("Switching Alfred state from IDLE to %d", alfredState.nextState);
+ alfredState.animState = alfredState.nextState;
+ alfredState.nextState = ALFRED_IDLE;
+ alfredState.curFrame = 0;
+ }
+
// debug("Drawing walkboxes..., %d, _currentRoomWalkboxes.size()=%d", _currentRoomWalkboxes.size(), _currentRoomWalkboxes.size());
for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
// debug("Drawing walkbox %d", i);
@@ -502,17 +470,60 @@ void PelrockEngine::frames() {
if (showShadows) {
memcpy(_screen->getPixels(), _room->_pixelsShadows, 640 * 400);
}
- _smallFont->drawString(_screen, Common::String::format("Room number: %d",_room->_currentRoomNumber), 0, 4, 640, 13);
+ _smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
_screen->markAllDirty();
// _screen->update();
}
}
-void PelrockEngine::doAction(byte action, byte object) {
- if (action == TALK) {
- talk(object);
+void PelrockEngine::doAction(byte action, HotSpot *hotspot) {
+ switch (action) {
+ case LOOK:
+ lookAtHotspot(_currentHotspot);
+ break;
+ case TALK:
+ talkTo(_currentHotspot);
+ break;
+ default:
+ break;
+ }
+}
+
+void PelrockEngine::talkTo(HotSpot *hotspot) {
+ debug("Talking to object %d", hotspot->index);
+ if (_room->_currentRoomConversations.size() == 0)
+ return;
+
+ Sprite *animSet;
+ for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ if (i == hotspot->index) {
+ animSet = &_room->_currentRoomAnims[i];
+ }
+ }
+
+ ConversationNode selectedNode = _room->_currentRoomConversations[0];
+
+ bool isNPC = selectedNode.speakerId != 13;
+ if (isNPC) {
+ sayNPC(animSet, selectedNode.text, selectedNode.speakerId);
}
+ // for(int i= 0; i< _currentRoomConversations.size(); i++) {
+ // _currentRoomConversations
+ // }
+
+ // showDescription(_currentRoomConversations[0].text, x, y, _currentRoomConversations[0].speakerId);
+ // for(int i = 0; i < _currentRoomConversations[0].choices.size(); i++) {
+ // int idx = _currentRoomConversations.size() - 1 - i;
+ // _smallFont->drawString(_screen, _currentRoomConversations[0].choices[idx].text.c_str(), 0, 400 - ((i + 1) * 12), 640, 14);
+ // }
+}
+
+void PelrockEngine::lookAtHotspot(HotSpot *hotspot) {
+ debug("Look action clicked");
+ walkTo(_currentHotspot->x, _currentHotspot->y);
+ sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index].text);
+ _displayPopup = false;
}
void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, int baseX, int baseY) {
@@ -642,43 +653,41 @@ void PelrockEngine::drawAlfred(byte *buf) {
delete[] finalBuf;
}
-
void applyMovement(int16_t *x, int16_t *y, /*int8_t *z,*/ uint16_t flags) {
- // X-axis movement
- if (flags & 0x10) { // Bit 4: X movement enabled
- int amount = flags & 0x07; // Bits 0-2: pixels per frame
- if (flags & 0x08) { // Bit 3: direction
- *x += amount; // 1 = right (add)
- } else {
- *x -= amount; // 0 = left (subtract)
- }
- }
-
- // Y-axis movement
- if (flags & 0x200) { // Bit 9: Y movement enabled
- int amount = (flags >> 5) & 0x07; // Bits 5-7: pixels per frame
- if (flags & 0x100) { // Bit 8: direction
- *y += amount; // 1 = down (add)
- } else {
- *y -= amount; // 0 = up (subtract)
- }
- }
-
- // // Z-axis movement
- // if (flags & 0x4000) { // Bit 14: Z movement enabled
- // int amount = (flags >> 10) & 0x07; // Bits 10-12: amount
- // if (flags & 0x2000) { // Bit 13: direction
- // *z += amount; // 1 = forward (add)
- // } else {
- // *z -= amount; // 0 = back (subtract)
- // }
- // }
-}
+ // X-axis movement
+ if (flags & 0x10) { // Bit 4: X movement enabled
+ int amount = flags & 0x07; // Bits 0-2: pixels per frame
+ if (flags & 0x08) { // Bit 3: direction
+ *x += amount; // 1 = right (add)
+ } else {
+ *x -= amount; // 0 = left (subtract)
+ }
+ }
+ // Y-axis movement
+ if (flags & 0x200) { // Bit 9: Y movement enabled
+ int amount = (flags >> 5) & 0x07; // Bits 5-7: pixels per frame
+ if (flags & 0x100) { // Bit 8: direction
+ *y += amount; // 1 = down (add)
+ } else {
+ *y -= amount; // 0 = up (subtract)
+ }
+ }
+
+ // // Z-axis movement
+ // if (flags & 0x4000) { // Bit 14: Z movement enabled
+ // int amount = (flags >> 10) & 0x07; // Bits 10-12: amount
+ // if (flags & 0x2000) { // Bit 13: direction
+ // *z += amount; // 1 = forward (add)
+ // } else {
+ // *z -= amount; // 0 = back (subtract)
+ // }
+ // }
+}
void PelrockEngine::drawNextFrame(Sprite *sprite) {
Anim &animData = sprite->animData[sprite->curAnimIndex];
- if(sprite->zOrder == -1) {
+ if (sprite->zOrder == -1) {
// skips z0rder -1 sprites
return;
}
@@ -893,17 +902,16 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _res->_popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
- Common::Array<VerbIcons> actions = availableActions(_currentHotspot);
-
- // drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[LOOK], posx + 20, posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
- // Graphics::Surface rects;
- // rects.create(kVerbIconWidth, kVerbIconHeight, Graphics::PixelFormat::createFormatCLUT8());
- // drawRect(&rects, 0, 0, kVerbIconWidth, kVerbIconHeight, 1);
-
-
+ Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
+ VerbIcon icon = isActionUnder(mouseX, mouseY);
for (int i = 0; i < actions.size(); i++) {
+ if(icon == actions[i] && _iconBlink++ < kIconBlinkPeriod/2) {
+ continue;
+ }
+ if (_iconBlink > kIconBlinkPeriod) {
+ _iconBlink = 0;
+ }
drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
- // blitSurfaceToBuffer(&rects, _compositeBuffer, 640, 480, posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20);
}
}
@@ -995,7 +1003,7 @@ bool PelrockEngine::pathFind(int targetX, int targetY, PathContext *context) {
// Build walkbox path
context->pathLength = buildWalkboxPath(startBox, destBox, context->pathBuffer);
debug("Walkbox path to point");
- for(int i = 0; i < context->pathLength; i++) {
+ for (int i = 0; i < context->pathLength; i++) {
debug("Walkbox %d: %d", i, context->pathBuffer[i]);
}
if (context->pathLength == 0) {
@@ -1005,7 +1013,7 @@ bool PelrockEngine::pathFind(int targetX, int targetY, PathContext *context) {
// Generate movement steps
context->movementCount = generateMovementSteps(context->pathBuffer, context->pathLength, startX, startY, targetX, targetY, context->movementBuffer);
- for(int i = 0; i < context->movementCount; i++) {
+ for (int i = 0; i < context->movementCount; i++) {
debug("Movement step %d: flags=\"%s\", dx=%d, dy=%d", i, printMovementFlags(context->movementBuffer[i].flags).c_str(), context->movementBuffer[i].distance_x, context->movementBuffer[i].distance_y);
}
}
@@ -1016,9 +1024,9 @@ bool PelrockEngine::pathFind(int targetX, int targetY, PathContext *context) {
* Calculate movement needed to reach a target within a walkbox
*/
void calculateMovementToTarget(uint16_t current_x, uint16_t current_y,
- uint16_t target_x, uint16_t target_y,
- WalkBox *box,
- MovementStep *step) {
+ uint16_t target_x, uint16_t target_y,
+ WalkBox *box,
+ MovementStep *step) {
step->flags = 0;
step->distance_x = 0;
step->distance_y = 0;
@@ -1051,10 +1059,10 @@ void calculateMovementToTarget(uint16_t current_x, uint16_t current_y,
* Returns: number of movement steps generated
*/
uint16_t PelrockEngine::generateMovementSteps(uint8_t *pathBuffer,
- uint16_t pathLength,
- uint16_t startX, uint16_t startY,
- uint16_t destX, uint16_t destY,
- MovementStep *movementBuffer) {
+ uint16_t pathLength,
+ uint16_t startX, uint16_t startY,
+ uint16_t destX, uint16_t destY,
+ MovementStep *movementBuffer) {
uint16_t currentX = startX;
uint16_t currentY = startY;
uint16_t movementIndex = 0;
@@ -1224,34 +1232,34 @@ uint8_t PelrockEngine::findWalkboxForPoint(uint16_t x, uint16_t y) {
return 0xFF; // Not found
}
+VerbIcon PelrockEngine::isActionUnder(int x, int y) {
+ Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
+ for (int i = 0; i < actions.size(); i++) {
+ int actionX = _popupX + 20 + (i * (kVerbIconWidth + 2));
+ int actionY = _popupY + 20;
+ Common::Rect actionRect = Common::Rect(actionX, actionY, actionX + kVerbIconWidth, actionY + kVerbIconHeight);
+ if (actionRect.contains(x, y)) {
+
+ return actions[i];
+ }
+ }
+ return NO_ACTION;
+}
+
void PelrockEngine::checkMouseClick(int x, int y) {
if (whichNPCTalking)
whichNPCTalking = false;
if (_displayPopup) {
- Common::Array<VerbIcons> actions = availableActions(_currentHotspot);
-
- Common::Rect lookRect = Common::Rect(_popupX + 20, _popupY + 20, _popupX + 20 + kVerbIconWidth, _popupY + 20 + kVerbIconHeight);
- if (lookRect.contains(x, y)) {
- debug("Look action clicked");
- walkTo(_currentHotspot->x, _currentHotspot->y);
- sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index].text);
+ // Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
+ VerbIcon actionClicked = isActionUnder(x, y);
+ if (actionClicked != NO_ACTION) {
+ debug("Action %d clicked", actionClicked);
+ doAction(actionClicked, _currentHotspot);
_displayPopup = false;
return;
}
- for (int i = 1; i < actions.size(); i++) {
-
- int actionX = _popupX + 20 + (i * (kVerbIconWidth + 2));
- int actionY = _popupY + 20;
- Common::Rect actionRect = Common::Rect(actionX, actionY, actionX + kVerbIconWidth, actionY + kVerbIconHeight);
- if (actionRect.contains(x, y)) {
- debug("Action %d clicked", actions[i]);
- doAction(actions[i], _currentHotspot->extra);
- _displayPopup = false;
- return;
- }
- }
}
_displayPopup = false;
@@ -1298,6 +1306,10 @@ void PelrockEngine::checkMouseHover() {
isSomethingUnder = true;
}
+ if(isActionUnder(mouseX, mouseY) != NO_ACTION) {
+ isSomethingUnder = false;
+ }
+
if (isSomethingUnder && exitDetected) {
changeCursor(COMBINATION);
} else if (isSomethingUnder) {
@@ -1407,7 +1419,7 @@ void PelrockEngine::sayNPC(Sprite *anim, Common::String text, byte color) {
}
void PelrockEngine::sayAlfred(Common::String text) {
- alfredState.animState = ALFRED_TALKING;
+ alfredState.nextState = ALFRED_TALKING;
alfredState.curFrame = 0;
debug("Alfred says: %s", text.c_str());
_currentTextPages = wordWrap(text);
@@ -1416,7 +1428,6 @@ void PelrockEngine::sayAlfred(Common::String text) {
for (int i = 0; i < _currentTextPages[0].size(); i++) {
totalChars += _currentTextPages[0][i].size();
}
- _textPos = Common::Point(alfredState.x, alfredState.y - kAlfredFrameHeight - 10);
_chronoManager->_textTtl = totalChars * kTextCharDisplayTime;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index c2121a17301..a96242a7709 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -60,42 +60,44 @@ private:
void init();
void loadAnims();
+ /*
+ Walking alforithm
+ */
void walkTo(int x, int y);
bool pathFind(int x, int y, PathContext *context);
+ Common::Point calculateWalkTarget(int mouseX, int mouseY);
uint8_t findWalkboxForPoint(uint16_t x, uint16_t y);
bool isPointInWalkbox(WalkBox *box, uint16_t x, uint16_t y);
uint16_t buildWalkboxPath(uint8_t start_box, uint8_t dest_box, uint8_t *path_buffer);
uint8_t getAdjacentWalkbox(uint8_t current_box_index);
void clearVisitedFlags();
- uint16_t generateMovementSteps(uint8_t *path_buffer,
- uint16_t path_length,
- uint16_t start_x, uint16_t start_y,
- uint16_t dest_x, uint16_t dest_y,
- MovementStep *movement_buffer);
+ uint16_t generateMovementSteps(uint8_t *path_buffer, uint16_t path_length, uint16_t start_x, uint16_t start_y, uint16_t dest_x, uint16_t dest_y, MovementStep *movement_buffer);
void talk(byte object);
void displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer);
+ void sayAlfred(Common::String text);
+ void sayNPC(Sprite *anim, Common::String text, byte color);
byte *grabBackgroundSlice(int x, int y, int w, int h);
void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
- Common::Array<VerbIcons> availableActions(HotSpot *hotspot);
- Common::Point calculateWalkTarget(int mouseX, int mouseY);
- void drawText(Common::String text, int x, int y, int w, byte color);
+ Common::Array<VerbIcon> availableActions(HotSpot *hotspot);
+ VerbIcon isActionUnder(int x, int y);
+ int isHotspotUnder(int x, int y);
+ Exit *isExitUnder(int x, int y);
+ Sprite *isSpriteUnder(int x, int y);
+ void showActionBalloon(int posx, int posy, int curFrame);
- void sayAlfred(Common::String text);
- void sayNPC(Sprite *anim, Common::String text, byte color);
+ void drawText(Common::String text, int x, int y, int w, byte color);
void frames();
- void doAction(byte action, byte object);
+ void doAction(byte action, HotSpot *hotspot);
+ void talkTo(HotSpot *hotspot);
+ void lookAtHotspot(HotSpot *hotspot);
void renderText(Common::Array<Common::String> lines, int color, int x, int y);
void drawAlfred(byte *buf);
void drawNextFrame(Sprite *animSet);
void changeCursor(Cursor cursor);
- int isHotspotUnder(int x, int y);
- Exit *isExitUnder(int x, int y);
- Sprite *isSpriteUnder(int x, int y);
- void showActionBalloon(int posx, int posy, int curFrame);
void drawTalkNPC(Sprite *animSet);
void checkMouseHover();
@@ -120,6 +122,7 @@ private:
// Alfred
bool alfredFrameSkip = false;
+ bool isAlkfredWalking = false;
uint16 mouseX = 0;
uint16 mouseY = 0;
@@ -132,6 +135,7 @@ private:
byte *_compositeBuffer; // Working composition buffer
bool _displayPopup = false;
+ byte _iconBlink = 0;
int _popupX = 0;
int _popupY = 0;
int _currentPopupFrame = 0;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index e212ae31c3a..865ecb3ab1a 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -35,7 +35,7 @@ enum Cursor {
COMBINATION
};
-enum VerbIcons {
+enum VerbIcon {
PICKUP,
TALK,
WALK,
@@ -44,7 +44,8 @@ enum VerbIcons {
PULL,
OPEN,
CLOSE,
- UNKNOWN
+ UNKNOWN,
+ NO_ACTION
};
static const uint32 kLongClickDuration = 500; // 500ms for long click
@@ -94,7 +95,7 @@ const int kChoiceHeight = 16; // Height of each choice line in pixels
#define ALFRED_COLOR 0x0D
-
+const byte kIconBlinkPeriod = 4;
enum AlfredAnimState {
ALFRED_IDLE,
@@ -113,6 +114,7 @@ enum AlfredDirection {
struct AlfredState {
AlfredAnimState animState = ALFRED_IDLE;
+ AlfredAnimState nextState = ALFRED_IDLE;
AlfredDirection direction = ALFRED_DOWN;
int curFrame = 0;
uint16 movementSpeed = 6; // pixels per frame
Commit: a74e8c29047ace9ffa9964d18510bed32fba5e91
https://github.com/scummvm/scummvm/commit/a74e8c29047ace9ffa9964d18510bed32fba5e91
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:17+02:00
Commit Message:
PELROCK: Fixed walk before talk
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 07daaf682f4..e634eee11c0 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -412,9 +412,11 @@ void PelrockEngine::frames() {
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- if (alfredState.animState == ALFRED_TALKING && !_currentTextPages.empty()) {
+ if (alfredState.animState != ALFRED_WALKING && !_currentTextPages.empty()) {
if (_chronoManager->_textTtl > 0) {
- _textPos = Common::Point(alfredState.x, alfredState.y - kAlfredFrameHeight - 10);
+ if(alfredState.animState == ALFRED_TALKING) {
+ _textPos = Common::Point(alfredState.x, alfredState.y - kAlfredFrameHeight - 10);
+ }
renderText(_currentTextPages[_currentTextPageIndex], _textColor, _textPos.x, _textPos.y);
} else if (_currentTextPageIndex < _currentTextPages.size() - 1) {
_currentTextPageIndex++;
@@ -937,7 +939,7 @@ void PelrockEngine::drawTalkNPC(Sprite *animSet) {
curFrame = 0;
}
byte *frame = index ? animHeader->animB[curFrame] : animHeader->animA[curFrame];
- debug("Talking NPC frame %d/%d, x=%d, y=%d, w=%d, h=%d", curFrame, numFrames, x, y, w, h);
+ // debug("Talking NPC frame %d/%d, x=%d, y=%d, w=%d, h=%d", curFrame, numFrames, x, y, w, h);
drawSpriteToBuffer(_compositeBuffer, 640, frame, x, y, w, h, 255);
}
@@ -1414,7 +1416,8 @@ void PelrockEngine::sayNPC(Sprite *anim, Common::String text, byte color) {
for (int i = 0; i < _currentTextPages[0].size(); i++) {
totalChars += _currentTextPages[0][i].size();
}
- _textPos = Common::Point(anim->x, anim->y - anim->h - 10);
+ debug("Settijng textpos to %d, %d", anim->x, anim->y - 10);
+ _textPos = Common::Point(anim->x, anim->y - 10);
_chronoManager->_textTtl = totalChars * kTextCharDisplayTime;
}
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 2c316012176..b66578481f2 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -370,24 +370,20 @@ Common::Array<Description> RoomManager::loadRoomDescriptions(Common::File *roomF
pos += 3;
description.index = data[pos++];
description.text = "";
- // debug("Found description terminator");
+
while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
- // debug(" char: %c", data[pos]);
+
if (data[pos] != 0x00) {
- description.text.append(1, (char)data[pos]);
+ // debug("Description char byte: 0x%02X", data[pos]);
+ description.text.append(1, decodeCPByte((byte)data[pos]));
}
if (data[pos] == 0xF8) {
description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
- // debug("Found action trigger: %d", description.actionTrigger);
pos += 2;
break;
}
- // desc[desc_pos++] = (char)data[pos];
- // debug("Current desc: %s", desc);
pos++;
}
- // debug("Found description for item %d index %d, text: %s", description.itemId, description.index, description.text.c_str());
-
descriptions.push_back(description);
lastDescPos = pos;
}
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 72e071f3256..b42c8b58cb9 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -220,4 +220,7 @@ Common::String joinStrings(const Common::Array<Common::String> &strings, const C
}
return result;
}
+char32_t decodeCPByte(byte b) {
+ return cp437_to_unicode[b];
+}
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 8e3de21718f..b5c2ba328fc 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -43,5 +43,43 @@ void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byt
void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
Common::String printMovementFlags(uint8_t flags);
Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
+static const char32_t cp437_to_unicode[256] = {
+ // 0x00 - 0x7F: ASCII (unchanged)
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ // 0x80 - 0xFF: CP437 extended characters
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x03B2, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x00B7, 0x2022, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+char32_t decodeCPByte(byte b);
} // End of namespace Pelrock
#endif // PELROCK_UTIL_H
Commit: f345388fbc1c9ceab8c2978e649afff2052831fd
https://github.com/scummvm/scummvm/commit/f345388fbc1c9ceab8c2978e649afff2052831fd
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:18+02:00
Commit Message:
PELROCK: Debug position markers
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index e634eee11c0..89c661e58c1 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -223,13 +223,15 @@ void PelrockEngine::loadAnims() {
void PelrockEngine::displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer) {
int overlayHeight = choices.size() * kChoiceHeight + 2;
int overlayY = 400 - overlayHeight;
- // debug("Displaying choices overlay at y=%d, height=%d", overlayY, overlayHeight);
for (int x = 0; x < 640; x++) {
for (int y = overlayY; y < 400; y++) {
int index = y * 640 + x;
compositeBuffer[index] = _room->overlayRemap[compositeBuffer[index]];
}
}
+ for (int i = 0; i < choices.size(); i++) {
+ drawText(choices[i], 10, overlayY + 2 + i * kChoiceHeight, 620, 15);
+ }
}
byte *PelrockEngine::grabBackgroundSlice(int x, int y, int w, int h) {
@@ -304,11 +306,6 @@ void PelrockEngine::frames() {
Sprite &animSet = _room->_currentRoomAnims[i];
drawNextFrame(&animSet);
}
- // if(alfredState.animState == ALFRED_IDLE && alfredState.nextState != ALFRED_IDLE) {
- // alfredState.animState = alfredState.nextState;
- // alfredState.nextState = ALFRED_IDLE;
- // alfredState.curFrame = 0;
- // }
switch (alfredState.animState) {
case ALFRED_WALKING: {
@@ -449,25 +446,10 @@ void PelrockEngine::frames() {
drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
_smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
}
- if (_curWalkTarget.x < 640 && _curWalkTarget.y < 400 && _curWalkTarget.x >= 0 && _curWalkTarget.y >= 0) {
- _screen->setPixel(_curWalkTarget.x, _curWalkTarget.y, 100);
- if (_curWalkTarget.x - 1 > 0 && _curWalkTarget.y - 1 > 0)
- _screen->setPixel(_curWalkTarget.x - 1, _curWalkTarget.y - 1, 100);
- if (_curWalkTarget.x - 1 > 0 && _curWalkTarget.y + 1 < 400)
- _screen->setPixel(_curWalkTarget.x - 1, _curWalkTarget.y + 1, 100);
- if (_curWalkTarget.x + 1 < 640 && _curWalkTarget.y - 1 > 0)
- _screen->setPixel(_curWalkTarget.x + 1, _curWalkTarget.y - 1, 100);
- if (_curWalkTarget.x + 1 < 640 && _curWalkTarget.y + 1 < 400)
- _screen->setPixel(_curWalkTarget.x + 1, _curWalkTarget.y + 1, 100);
- if (_curWalkTarget.x - 2 > 0)
- _screen->setPixel(_curWalkTarget.x - 2, _curWalkTarget.y, 100);
- if (_curWalkTarget.x + 2 < 640)
- _screen->setPixel(_curWalkTarget.x + 2, _curWalkTarget.y, 100);
- if (_curWalkTarget.y - 2 > 0)
- _screen->setPixel(_curWalkTarget.x, _curWalkTarget.y - 2, 100);
- if (_curWalkTarget.y + 2 < 400)
- _screen->setPixel(_curWalkTarget.x, _curWalkTarget.y + 2, 100);
- }
+
+ drawPos(_screen, alfredState.x, alfredState.y, 13);
+ drawPos(_screen, _curWalkTarget.x, _curWalkTarget.y, 100);
+
if (showShadows) {
memcpy(_screen->getPixels(), _room->_pixelsShadows, 640 * 400);
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index b42c8b58cb9..5a3d2a5e64a 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -220,6 +220,14 @@ Common::String joinStrings(const Common::Array<Common::String> &strings, const C
}
return result;
}
+void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color) {
+ if (x < 640 && y < 400 && x >= 0 && y >= 0) {
+ surface->setPixel(x, y, 100);
+
+ surface->drawEllipse(x - 3, y - 3, x+3, y+3, color, true);
+ }
+}
+
char32_t decodeCPByte(byte b) {
return cp437_to_unicode[b];
}
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index b5c2ba328fc..38783d96ac4 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -43,6 +43,7 @@ void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byt
void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
Common::String printMovementFlags(uint8_t flags);
Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
+void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
static const char32_t cp437_to_unicode[256] = {
// 0x00 - 0x7F: ASCII (unchanged)
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
Commit: 5751f8c2d58747ebe8c7a85590df01b5eaa78de5
https://github.com/scummvm/scummvm/commit/5751f8c2d58747ebe8c7a85590df01b5eaa78de5
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:18+02:00
Commit Message:
PELROCK: Sprite order
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 89c661e58c1..08dc243de5b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -258,7 +258,7 @@ void PelrockEngine::putBackgroundSlice(int x, int y, int w, int h, byte *slice)
}
Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
- if(hotspot == nullptr) {
+ if (hotspot == nullptr) {
return Common::Array<VerbIcon>();
}
Common::Array<VerbIcon> verbs;
@@ -288,6 +288,20 @@ Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
return verbs;
}
+// Sort sprites by zOrder in-place using insertion sort (efficient for nearly-sorted data)
+void sortAnimsByZOrder(Common::Array<Sprite> &anims) {
+ for (size_t i = 1; i < anims.size(); ++i) {
+ Sprite key = anims[i];
+ int z = key.zOrder;
+ size_t j = i;
+ while (j > 0 && anims[j - 1].zOrder > z) {
+ anims[j] = anims[j - 1];
+ --j;
+ }
+ anims[j] = key;
+ }
+}
+
void PelrockEngine::frames() {
if (_chronoManager->_gameTick) {
@@ -298,101 +312,42 @@ void PelrockEngine::frames() {
_soundManager->playSound(_room->_roomSfx[3 + soundIndex]);
}
- memcpy(_compositeBuffer, _currentBackground, 640 * 400);
+ // Sort sprites by zOrder (persists in the array)
+ sortAnimsByZOrder(_room->_currentRoomAnims);
- // debug("Game tick!");
- for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
- // debug("Processing animation set %d, numAnims %d", num, i->numAnims);
- Sprite &animSet = _room->_currentRoomAnims[i];
- drawNextFrame(&animSet);
- }
-
- switch (alfredState.animState) {
- case ALFRED_WALKING: {
-
- MovementStep step = _currentContext.movementBuffer[_currentStep];
-
- if (step.distance_x > 0) {
- if (step.flags & MOVE_RIGHT) {
- alfredState.direction = ALFRED_RIGHT;
- alfredState.x += MIN(alfredState.movementSpeed, step.distance_x);
- }
- if (step.flags & MOVE_LEFT) {
- alfredState.direction = ALFRED_LEFT;
- alfredState.x -= MIN(alfredState.movementSpeed, step.distance_x);
- }
- }
- if (step.distance_y > 0) {
- if (step.flags & MOVE_DOWN) {
- alfredState.direction = ALFRED_DOWN;
- alfredState.y += MIN(alfredState.movementSpeed, step.distance_y);
- }
- if (step.flags & MOVE_UP) {
- alfredState.direction = ALFRED_UP;
- alfredState.y -= MIN(alfredState.movementSpeed, step.distance_y);
- }
- }
-
- if (step.distance_x > 0)
- step.distance_x -= MIN(alfredState.movementSpeed, step.distance_x);
+ memcpy(_compositeBuffer, _currentBackground, 640 * 400);
- if (step.distance_y > 0)
- step.distance_y -= MIN(alfredState.movementSpeed, step.distance_y);
+ // Create temporary render order partitioned by Alfred's Y position
+ Common::Array<Sprite *> renderOrder;
+ int alfredY = alfredState.y;
- if (step.distance_x <= 0 && step.distance_y <= 0) {
- _currentStep++;
- if (_currentStep >= _currentContext.movementCount) {
- _currentStep = 0;
- alfredState.animState = ALFRED_IDLE;
- }
- } else {
- _currentContext.movementBuffer[_currentStep] = step;
- }
-
- Exit *exit = isExitUnder(alfredState.x, alfredState.y);
+ // First pass: sprites behind Alfred (y <= alfredY)
+ for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ if (_room->_currentRoomAnims[i].y < (alfredY - kAlfredFrameHeight)) {
+ debug("Drawing sprite %d in front of Alfred at zOrder %d, pos (%d, %d)", i, _room->_currentRoomAnims[i].zOrder, _room->_currentRoomAnims[i].x, _room->_currentRoomAnims[i].y);
- if (exit != nullptr) {
- alfredState.x = exit->targetX;
- alfredState.y = exit->targetY;
- setScreen(exit->targetRoom, exit->dir);
+ // renderOrder.push_back(&_room->_currentRoomAnims[i]);
+ drawNextFrame(&_room->_currentRoomAnims[i]);
}
+ }
- if (alfredState.curFrame >= walkingAnimLengths[alfredState.direction]) {
- alfredState.curFrame = 0;
- }
+ // Draw Alfred here (you'll need to add this)
+ chooseAlfredStateAndDraw();
- drawAlfred(_res->alfredWalkFrames[alfredState.direction][alfredState.curFrame]);
- // if(alfredFrameSkip) alfredState.curFrame++;
- // alfredFrameSkip = !alfredFrameSkip;
- alfredState.curFrame++;
- break;
- }
- case ALFRED_TALKING:
- if (alfredState.curFrame >= talkingAnimLengths[alfredState.direction] - 1) {
- alfredState.curFrame = 0;
- }
- drawAlfred(_res->alfredTalkFrames[alfredState.direction][alfredState.curFrame]);
- alfredState.curFrame++;
- break;
- case ALFRED_COMB:
- if (alfredState.curFrame >= 11) {
- alfredState.curFrame = 0;
- }
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[0][alfredState.curFrame], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
- alfredState.curFrame++;
- break;
- case ALFRED_INTERACTING:
- if (alfredState.curFrame >= interactingAnimLength) {
- alfredState.curFrame = 0;
+ // Second pass: sprites in front of Alfred (y > alfredY)
+ for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ if (_room->_currentRoomAnims[i].y > (alfredY - kAlfredFrameHeight)) {
+ debug("Drawing sprite %d behind Alfred at zOrder %d, pos (%d, %d)", i, _room->_currentRoomAnims[i].zOrder, _room->_currentRoomAnims[i].x, _room->_currentRoomAnims[i].y);
+ drawNextFrame(&_room->_currentRoomAnims[i]);
+ // renderOrder.push_back(&_room->_currentRoomAnims[i]);
}
- drawAlfred(_res->alfredInteractFrames[alfredState.direction][alfredState.curFrame]);
- alfredState.curFrame++;
- break;
- default:
- drawAlfred(_res->alfredIdle[alfredState.direction]);
- break;
}
+ // // Render in the computed order
+ // for (int i = 0; i < renderOrder.size(); i++) {
+ // drawNextFrame(renderOrder[i]);
+ // }
+
if (_displayPopup) {
showActionBalloon(_popupX, _popupY, _currentPopupFrame);
if (_currentPopupFrame < 3) {
@@ -411,7 +366,7 @@ void PelrockEngine::frames() {
if (alfredState.animState != ALFRED_WALKING && !_currentTextPages.empty()) {
if (_chronoManager->_textTtl > 0) {
- if(alfredState.animState == ALFRED_TALKING) {
+ if (alfredState.animState == ALFRED_TALKING) {
_textPos = Common::Point(alfredState.x, alfredState.y - kAlfredFrameHeight - 10);
}
renderText(_currentTextPages[_currentTextPageIndex], _textColor, _textPos.x, _textPos.y);
@@ -432,7 +387,7 @@ void PelrockEngine::frames() {
}
}
- if(alfredState.animState == ALFRED_IDLE && alfredState.nextState != ALFRED_IDLE) {
+ if (alfredState.animState == ALFRED_IDLE && alfredState.nextState != ALFRED_IDLE) {
// debug("Switching Alfred state from IDLE to %d", alfredState.nextState);
alfredState.animState = alfredState.nextState;
alfredState.nextState = ALFRED_IDLE;
@@ -448,13 +403,14 @@ void PelrockEngine::frames() {
}
drawPos(_screen, alfredState.x, alfredState.y, 13);
+ drawPos(_screen, alfredState.x, alfredState.y - kAlfredFrameHeight, 13);
drawPos(_screen, _curWalkTarget.x, _curWalkTarget.y, 100);
-
if (showShadows) {
memcpy(_screen->getPixels(), _room->_pixelsShadows, 640 * 400);
}
_smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
+ _smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", alfredState.x, alfredState.y, alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
_screen->markAllDirty();
// _screen->update();
@@ -527,6 +483,94 @@ void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, i
}
}
+void PelrockEngine::chooseAlfredStateAndDraw() {
+ switch (alfredState.animState) {
+ case ALFRED_WALKING: {
+
+ MovementStep step = _currentContext.movementBuffer[_currentStep];
+
+ if (step.distance_x > 0) {
+ if (step.flags & MOVE_RIGHT) {
+ alfredState.direction = ALFRED_RIGHT;
+ alfredState.x += MIN(alfredState.movementSpeed, step.distance_x);
+ }
+ if (step.flags & MOVE_LEFT) {
+ alfredState.direction = ALFRED_LEFT;
+ alfredState.x -= MIN(alfredState.movementSpeed, step.distance_x);
+ }
+ }
+ if (step.distance_y > 0) {
+ if (step.flags & MOVE_DOWN) {
+ alfredState.direction = ALFRED_DOWN;
+ alfredState.y += MIN(alfredState.movementSpeed, step.distance_y);
+ }
+ if (step.flags & MOVE_UP) {
+ alfredState.direction = ALFRED_UP;
+ alfredState.y -= MIN(alfredState.movementSpeed, step.distance_y);
+ }
+ }
+
+ if (step.distance_x > 0)
+ step.distance_x -= MIN(alfredState.movementSpeed, step.distance_x);
+
+ if (step.distance_y > 0)
+ step.distance_y -= MIN(alfredState.movementSpeed, step.distance_y);
+
+ if (step.distance_x <= 0 && step.distance_y <= 0) {
+ _currentStep++;
+ if (_currentStep >= _currentContext.movementCount) {
+ _currentStep = 0;
+ alfredState.animState = ALFRED_IDLE;
+ }
+ } else {
+ _currentContext.movementBuffer[_currentStep] = step;
+ }
+
+ Exit *exit = isExitUnder(alfredState.x, alfredState.y);
+
+ if (exit != nullptr) {
+ alfredState.x = exit->targetX;
+ alfredState.y = exit->targetY;
+ setScreen(exit->targetRoom, exit->dir);
+ }
+
+ if (alfredState.curFrame >= walkingAnimLengths[alfredState.direction]) {
+ alfredState.curFrame = 0;
+ }
+
+ drawAlfred(_res->alfredWalkFrames[alfredState.direction][alfredState.curFrame]);
+ // if(alfredFrameSkip) alfredState.curFrame++;
+ // alfredFrameSkip = !alfredFrameSkip;
+ alfredState.curFrame++;
+ break;
+ }
+ case ALFRED_TALKING:
+ if (alfredState.curFrame >= talkingAnimLengths[alfredState.direction] - 1) {
+ alfredState.curFrame = 0;
+ }
+ drawAlfred(_res->alfredTalkFrames[alfredState.direction][alfredState.curFrame]);
+ alfredState.curFrame++;
+ break;
+ case ALFRED_COMB:
+ if (alfredState.curFrame >= 11) {
+ alfredState.curFrame = 0;
+ }
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[0][alfredState.curFrame], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
+ alfredState.curFrame++;
+ break;
+ case ALFRED_INTERACTING:
+ if (alfredState.curFrame >= interactingAnimLength) {
+ alfredState.curFrame = 0;
+ }
+ drawAlfred(_res->alfredInteractFrames[alfredState.direction][alfredState.curFrame]);
+ alfredState.curFrame++;
+ break;
+ default:
+ drawAlfred(_res->alfredIdle[alfredState.direction]);
+ break;
+ }
+}
+
void PelrockEngine::drawAlfred(byte *buf) {
ScaleCalculation scale = calculateScaling(alfredState.y, _room->_scaleParams);
@@ -889,7 +933,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
VerbIcon icon = isActionUnder(mouseX, mouseY);
for (int i = 0; i < actions.size(); i++) {
- if(icon == actions[i] && _iconBlink++ < kIconBlinkPeriod/2) {
+ if (icon == actions[i] && _iconBlink++ < kIconBlinkPeriod / 2) {
continue;
}
if (_iconBlink > kIconBlinkPeriod) {
@@ -1290,7 +1334,7 @@ void PelrockEngine::checkMouseHover() {
isSomethingUnder = true;
}
- if(isActionUnder(mouseX, mouseY) != NO_ACTION) {
+ if (isActionUnder(mouseX, mouseY) != NO_ACTION) {
isSomethingUnder = false;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index a96242a7709..37a530f65b4 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -95,6 +95,7 @@ private:
void talkTo(HotSpot *hotspot);
void lookAtHotspot(HotSpot *hotspot);
void renderText(Common::Array<Common::String> lines, int color, int x, int y);
+ void chooseAlfredStateAndDraw();
void drawAlfred(byte *buf);
void drawNextFrame(Sprite *animSet);
void changeCursor(Cursor cursor);
Commit: d64304311f1ec1262bb6fb76d9a620ed0522afd5
https://github.com/scummvm/scummvm/commit/d64304311f1ec1262bb6fb76d9a620ed0522afd5
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:18+02:00
Commit Message:
PELROCK: Sets temporary Alfred zorder
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 08dc243de5b..7ada651578d 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -323,7 +323,7 @@ void PelrockEngine::frames() {
// First pass: sprites behind Alfred (y <= alfredY)
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (_room->_currentRoomAnims[i].y < (alfredY - kAlfredFrameHeight)) {
+ if (_room->_currentRoomAnims[i].zOrder > 10) {
debug("Drawing sprite %d in front of Alfred at zOrder %d, pos (%d, %d)", i, _room->_currentRoomAnims[i].zOrder, _room->_currentRoomAnims[i].x, _room->_currentRoomAnims[i].y);
// renderOrder.push_back(&_room->_currentRoomAnims[i]);
@@ -336,7 +336,7 @@ void PelrockEngine::frames() {
// Second pass: sprites in front of Alfred (y > alfredY)
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (_room->_currentRoomAnims[i].y > (alfredY - kAlfredFrameHeight)) {
+ if (_room->_currentRoomAnims[i].zOrder <= 10) {
debug("Drawing sprite %d behind Alfred at zOrder %d, pos (%d, %d)", i, _room->_currentRoomAnims[i].zOrder, _room->_currentRoomAnims[i].x, _room->_currentRoomAnims[i].y);
drawNextFrame(&_room->_currentRoomAnims[i]);
// renderOrder.push_back(&_room->_currentRoomAnims[i]);
Commit: df8045d555a2966ebea3ba99e992a3facf91b9db
https://github.com/scummvm/scummvm/commit/df8045d555a2966ebea3ba99e992a3facf91b9db
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:19+02:00
Commit Message:
PELROCK: Fixes decompression script
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/util.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 7ada651578d..f7abb794a5c 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -191,7 +191,7 @@ Common::Error PelrockEngine::run() {
void PelrockEngine::init() {
_res->loadCursors();
_res->loadInteractionIcons();
- _res->loadSettingsMenu();
+ // _res->loadSettingsMenu();
_soundManager->loadSoundIndex();
calculateScalingMasks();
@@ -324,9 +324,6 @@ void PelrockEngine::frames() {
// First pass: sprites behind Alfred (y <= alfredY)
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].zOrder > 10) {
- debug("Drawing sprite %d in front of Alfred at zOrder %d, pos (%d, %d)", i, _room->_currentRoomAnims[i].zOrder, _room->_currentRoomAnims[i].x, _room->_currentRoomAnims[i].y);
-
- // renderOrder.push_back(&_room->_currentRoomAnims[i]);
drawNextFrame(&_room->_currentRoomAnims[i]);
}
}
@@ -337,17 +334,10 @@ void PelrockEngine::frames() {
// Second pass: sprites in front of Alfred (y > alfredY)
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].zOrder <= 10) {
- debug("Drawing sprite %d behind Alfred at zOrder %d, pos (%d, %d)", i, _room->_currentRoomAnims[i].zOrder, _room->_currentRoomAnims[i].x, _room->_currentRoomAnims[i].y);
drawNextFrame(&_room->_currentRoomAnims[i]);
- // renderOrder.push_back(&_room->_currentRoomAnims[i]);
}
}
- // // Render in the computed order
- // for (int i = 0; i < renderOrder.size(); i++) {
- // drawNextFrame(renderOrder[i]);
- // }
-
if (_displayPopup) {
showActionBalloon(_popupX, _popupY, _currentPopupFrame);
if (_currentPopupFrame < 3) {
@@ -356,11 +346,11 @@ void PelrockEngine::frames() {
_currentPopupFrame = 0;
}
- Common::Array<Common::String> testChoices;
- testChoices.push_back("First choice");
- testChoices.push_back("Second choice");
- testChoices.push_back("Third choice");
- displayChoices(testChoices, _compositeBuffer);
+ // Common::Array<Common::String> testChoices;
+ // testChoices.push_back("First choice");
+ // testChoices.push_back("Second choice");
+ // testChoices.push_back("Third choice");
+ // displayChoices(testChoices, _compositeBuffer);
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
@@ -566,6 +556,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.curFrame++;
break;
default:
+ debug("Drawing Alfred idle frame for direction %d", alfredState.direction);
drawAlfred(_res->alfredIdle[alfredState.direction]);
break;
}
@@ -591,7 +582,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
if (scaleIndex < 0) {
scaleIndex = 0;
}
- // debug("Scaling Alfred frame to final size (%d x %d) from scale factor %.2f", finalWidth, finalHeight, scaleFactor);
+ debug("Scaling Alfred frame to final size (%d x %d) from scale factor %.2f", finalWidth, finalHeight, scaleFactor);
int linesToSkip = kAlfredFrameHeight - finalHeight;
// debug("lines to skip = %d, finalHeight = %d, finalWidth = %d for position (%d, %d)", linesToSkip, finalHeight, finalWidth, xAlfred, yAlfred);
@@ -660,7 +651,12 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
int srcIndex = srcY * kAlfredFrameWidth + srcX;
int outIndex = outY * finalWidth + outX;
- finalBuf[outIndex] = buf[srcIndex];
+ debug("srcIndex = %d, outIndex = %d, original size = %d, outsize = %d", srcIndex, outIndex, kAlfredFrameWidth * kAlfredFrameHeight, finalWidth * finalHeight);
+ if(outIndex >= finalWidth * finalHeight || srcIndex >= kAlfredFrameWidth * kAlfredFrameHeight) {
+ debug("Index out of bounds!");
+ }
+ else
+ finalBuf[outIndex] = buf[srcIndex];
}
outY++;
}
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index b66578481f2..fa00202554b 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -75,16 +75,20 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
roomFile->seek(pair_offset, SEEK_SET);
uint32_t offset = roomFile->readUint32LE();
uint32_t size = roomFile->readUint32LE();
-
+ debug("Background pair %d: offset=%d size=%d", pair_idx, offset, size);
if (offset > 0 && size > 0 && offset < roomFile->size()) {
byte *data = new byte[size];
roomFile->seek(offset, SEEK_SET);
roomFile->read(data, size);
uint8_t *block_data = NULL;
size_t block_size = rleDecompress(data, size, 0, 640 * 400, &block_data);
-
+ debug(" Decompressed block size: %d, combined size: %d", block_size, combined_size + block_size);
+ if (block_size + combined_size > 640 * 400) {
+ debug(" Warning: decompressed background size exceeds buffer size!");
+ block_size = 640 * 400 - combined_size;
+ }
memcpy(background + combined_size, block_data, block_size);
- combined_size += block_size + 1;
+ combined_size += block_size;
free(block_data);
delete[] data;
}
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 5a3d2a5e64a..76091bf1943 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -65,73 +65,99 @@ Common::String printMovementFlags(uint8_t flags) {
}
size_t rleDecompress(
- const uint8_t *input,
- size_t inputSize,
- uint32_t offset,
- uint32_t expectedSize,
- uint8_t **out_data,
- bool untilBuda) {
- // // Check for uncompressed markers
- if (inputSize == 0x8000 || inputSize == 0x6800) {
- *out_data = (uint8_t *)malloc(inputSize);
- memcpy(*out_data, input + offset, inputSize);
- return inputSize;
- }
+ const uint8_t *input,
+ size_t inputSize,
+ uint32_t offset,
+ uint32_t expectedSize,
+ uint8_t **out_data,
+ bool untilBuda) {
+ // Check for uncompressed markers
+ if (inputSize == 0x8000 || inputSize == 0x6800) {
+ *out_data = (uint8_t *)malloc(inputSize);
+ if (!*out_data)
+ return 0;
+ memcpy(*out_data, input + offset, inputSize);
+ return inputSize;
+ }
- // RLE compressed
- size_t bufferCapacity;
- size_t result_size = 0;
- uint32_t pos = offset;
-
- if (untilBuda) {
- // Dynamic allocation mode - grow buffer as needed
- bufferCapacity = 4096;
- *out_data = (uint8_t *)malloc(bufferCapacity);
- if (!*out_data)
- return 0;
- } else {
- // Fixed size mode
- bufferCapacity = expectedSize;
- *out_data = (uint8_t *)malloc(expectedSize);
- if (!*out_data)
- return 0;
- }
+ // RLE compressed
+ size_t bufferCapacity;
+ size_t result_size = 0;
+ uint32_t pos = offset;
+ uint8_t last_value = 0;
- while (pos + 2 <= inputSize) {
- // Check for BUDA marker
- if (pos + 4 <= inputSize &&
- input[pos] == 'B' && input[pos + 1] == 'U' &&
- input[pos + 2] == 'D' && input[pos + 3] == 'A') {
- break;
- }
+ if (untilBuda || expectedSize == 0) {
+ // Dynamic allocation mode - grow buffer as needed
+ bufferCapacity = 4096;
+ *out_data = (uint8_t *)malloc(bufferCapacity);
+ if (!*out_data)
+ return 0;
+ } else {
+ // Fixed size mode
+ bufferCapacity = expectedSize;
+ *out_data = (uint8_t *)malloc(bufferCapacity);
+ if (!*out_data)
+ return 0;
+ }
- uint8_t count = input[pos];
- uint8_t value = input[pos + 1];
-
- for (int i = 0; i < count; i++) {
- // If in untilBuda mode, grow buffer as needed
- if (untilBuda && result_size >= bufferCapacity) {
- bufferCapacity *= 2;
- uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
- if (!newBuf) {
- free(*out_data);
- *out_data = nullptr;
- return 0;
- }
- *out_data = newBuf;
- }
- // debug("Pos = %zu, writing value %02X", result_size, value);
- (*out_data)[result_size++] = value;
- }
+ while (pos + 2 <= inputSize) {
+ // Read the RLE pair
+ uint8_t count = input[pos];
+ uint8_t value = input[pos + 1];
+ last_value = value;
- pos += 2;
- // In fixed size mode, stop when we reach expected size
- if (!untilBuda && result_size >= expectedSize) {
- break;
- }
- }
+ // Write pixels for this pair
+ for (int i = 0; i < count; i++) {
+ // Grow buffer if needed
+ if (result_size >= bufferCapacity) {
+ if (untilBuda || expectedSize == 0) {
+ bufferCapacity *= 2;
+ } else {
+ // In fixed mode, we've hit the limit - something is wrong
+ // but grow minimally to avoid crash
+ bufferCapacity += 256;
+ }
+ uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
+ if (!newBuf) {
+ free(*out_data);
+ *out_data = nullptr;
+ return 0;
+ }
+ *out_data = newBuf;
+ }
+ (*out_data)[result_size++] = value;
+ }
+
+ // Advance to next pair
+ pos += 2;
+
+ // Check for BUDA marker at new position
+ if (untilBuda && pos + 4 <= inputSize &&
+ input[pos] == 'B' && input[pos + 1] == 'U' &&
+ input[pos + 2] == 'D' && input[pos + 3] == 'A') {
+ // Game writes one final pixel after BUDA marker
+ // Grow buffer if needed
+ if (result_size >= bufferCapacity) {
+ bufferCapacity++;
+ uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
+ if (!newBuf) {
+ free(*out_data);
+ *out_data = nullptr;
+ return 0;
+ }
+ *out_data = newBuf;
+ }
+ (*out_data)[result_size++] = last_value;
+ break;
+ }
+
+ // In fixed size mode, stop when we reach expected size
+ if (!untilBuda && expectedSize > 0 && result_size >= expectedSize) {
+ break;
+ }
+ }
- return result_size;
+ return result_size;
}
void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize) {
Commit: 9f89aabd1af755af11320a5b77fa5be25474a9e9
https://github.com/scummvm/scummvm/commit/9f89aabd1af755af11320a5b77fa5be25474a9e9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:19+02:00
Commit Message:
PELROCK: Loads and renders inventory icons
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/types.h
engines/pelrock/util.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f7abb794a5c..21cd123dee1 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -170,9 +170,16 @@ Common::Error PelrockEngine::run() {
}
checkMouseHover();
if (stateGame == SETTINGS) {
-
- memcpy(_screen->getPixels(), _res->_mainMenu, 640 * 400);
g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
+
+ memcpy(_compositeBuffer, _res->_mainMenu, 640 * 400);
+
+ for (int i = 0; i < 4; i++) {
+ InventoryObject item = _res->getInventoryObject(i);
+ drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + i * 85, 110 - i * 5, 60, 60, 1);
+ }
+ memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+
g_engine->_screen->markAllDirty();
g_engine->_screen->update();
@@ -191,7 +198,8 @@ Common::Error PelrockEngine::run() {
void PelrockEngine::init() {
_res->loadCursors();
_res->loadInteractionIcons();
- // _res->loadSettingsMenu();
+ _res->loadInventoryIcons();
+ _res->loadSettingsMenu();
_soundManager->loadSoundIndex();
calculateScalingMasks();
@@ -556,7 +564,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.curFrame++;
break;
default:
- debug("Drawing Alfred idle frame for direction %d", alfredState.direction);
+ // debug("Drawing Alfred idle frame for direction %d", alfredState.direction);
drawAlfred(_res->alfredIdle[alfredState.direction]);
break;
}
@@ -582,7 +590,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
if (scaleIndex < 0) {
scaleIndex = 0;
}
- debug("Scaling Alfred frame to final size (%d x %d) from scale factor %.2f", finalWidth, finalHeight, scaleFactor);
+ // debug("Scaling Alfred frame to final size (%d x %d) from scale factor %.2f", finalWidth, finalHeight, scaleFactor);
int linesToSkip = kAlfredFrameHeight - finalHeight;
// debug("lines to skip = %d, finalHeight = %d, finalWidth = %d for position (%d, %d)", linesToSkip, finalHeight, finalWidth, xAlfred, yAlfred);
@@ -652,10 +660,9 @@ void PelrockEngine::drawAlfred(byte *buf) {
int srcIndex = srcY * kAlfredFrameWidth + srcX;
int outIndex = outY * finalWidth + outX;
debug("srcIndex = %d, outIndex = %d, original size = %d, outsize = %d", srcIndex, outIndex, kAlfredFrameWidth * kAlfredFrameHeight, finalWidth * finalHeight);
- if(outIndex >= finalWidth * finalHeight || srcIndex >= kAlfredFrameWidth * kAlfredFrameHeight) {
+ if (outIndex >= finalWidth * finalHeight || srcIndex >= kAlfredFrameWidth * kAlfredFrameHeight) {
debug("Index out of bounds!");
- }
- else
+ } else
finalBuf[outIndex] = buf[srcIndex];
}
outY++;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 193133af40c..0364fe8a04b 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -29,6 +29,7 @@
namespace Pelrock {
ResourceManager::ResourceManager(/* args */) {
+ _inventoryIcons = new InventoryObject[69];
}
ResourceManager::~ResourceManager() {
@@ -60,6 +61,7 @@ ResourceManager::~ResourceManager() {
delete[] alfredCombFrames[0];
delete[] alfredCombFrames[1];
delete _mainMenu;
+ delete[] _inventoryIcons;
}
void ResourceManager::loadCursors() {
@@ -213,6 +215,27 @@ void ResourceManager::loadAlfredAnims() {
free(alfredCombLeftRaw);
}
+void ResourceManager::loadInventoryIcons() {
+ Common::File alfred4File;
+ if (!alfred4File.open("ALFRED.4")) {
+ error("Couldnt find file ALFRED.4");
+ }
+ uint32 iconsSize = alfred4File.size() - 423656;
+ byte *iconData = new byte[iconsSize];
+ alfred4File.seek(42366, SEEK_SET);
+ alfred4File.read(iconData, iconsSize);
+
+ int iconSize = 60 * 60; // each icon has 30 bytes of header
+ for (int i = 0; i < 69; i++) {
+ _inventoryIcons[i].index = i;
+ extractSingleFrame(iconData, _inventoryIcons[i].iconData, i, 60, 60);
+ }
+ delete[] iconData;
+}
+
+InventoryObject ResourceManager::getInventoryObject(byte index) {
+ return _inventoryIcons[index];
+}
void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32 offset, int numBlocks, byte *outputBuffer) {
stream->seek(offset, SEEK_SET);
@@ -225,7 +248,7 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
uint8_t *block_data = nullptr;
size_t decompressedSize = rleDecompress(thisBlock, blockSize, 0, 640 * 400, &block_data, true);
memcpy(outputBuffer + combined_size, block_data, decompressedSize);
- combined_size += decompressedSize + 1;
+ combined_size += decompressedSize;
free(block_data);
free(thisBlock);
}
@@ -252,5 +275,4 @@ void ResourceManager::loadSettingsMenu() {
alfred7.close();
}
-
} // End of namespace Pelrock
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 6bed0e95310..4561e78e799 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -23,6 +23,7 @@
#include "common/scummsys.h"
#include "common/stream.h"
+#include "pelrock/types.h"
namespace Pelrock {
@@ -33,6 +34,7 @@ static const int interactingAnimLength = 2;
class ResourceManager {
private:
void mergeRleBlocks(Common::SeekableReadStream *stream, uint32 offset, int numBlocks, byte *outputBuffer);
+ InventoryObject *_inventoryIcons = nullptr;
public:
ResourceManager(/* args */);
~ResourceManager();
@@ -41,6 +43,8 @@ public:
void loadCursors();
void loadInteractionIcons();
void loadAlfredAnims();
+ void loadInventoryIcons();
+ InventoryObject getInventoryObject(byte index);
byte *loadExtra();
byte *alfredIdle[4] = {nullptr}; // 4 directions
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 865ecb3ab1a..31969c3f898 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -307,6 +307,12 @@ enum GameState {
INTRO = 106,
};
+struct InventoryObject {
+ byte index;
+ Common::String description;
+ byte iconData[60 * 60];
+};
+
} // End of namespace Pelrock
#endif
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 76091bf1943..f204188003b 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -65,99 +65,99 @@ Common::String printMovementFlags(uint8_t flags) {
}
size_t rleDecompress(
- const uint8_t *input,
- size_t inputSize,
- uint32_t offset,
- uint32_t expectedSize,
- uint8_t **out_data,
- bool untilBuda) {
- // Check for uncompressed markers
- if (inputSize == 0x8000 || inputSize == 0x6800) {
- *out_data = (uint8_t *)malloc(inputSize);
- if (!*out_data)
- return 0;
- memcpy(*out_data, input + offset, inputSize);
- return inputSize;
- }
+ const uint8_t *input,
+ size_t inputSize,
+ uint32_t offset,
+ uint32_t expectedSize,
+ uint8_t **out_data,
+ bool untilBuda) {
+ // Check for uncompressed markers
+ if (inputSize == 0x8000 || inputSize == 0x6800) {
+ *out_data = (uint8_t *)malloc(inputSize);
+ if (!*out_data)
+ return 0;
+ memcpy(*out_data, input + offset, inputSize);
+ return inputSize;
+ }
- // RLE compressed
- size_t bufferCapacity;
- size_t result_size = 0;
- uint32_t pos = offset;
- uint8_t last_value = 0;
+ // RLE compressed
+ size_t bufferCapacity;
+ size_t result_size = 0;
+ uint32_t pos = offset;
+ uint8_t last_value = 0;
- if (untilBuda || expectedSize == 0) {
- // Dynamic allocation mode - grow buffer as needed
- bufferCapacity = 4096;
- *out_data = (uint8_t *)malloc(bufferCapacity);
- if (!*out_data)
- return 0;
- } else {
- // Fixed size mode
- bufferCapacity = expectedSize;
- *out_data = (uint8_t *)malloc(bufferCapacity);
- if (!*out_data)
- return 0;
- }
+ if (untilBuda || expectedSize == 0) {
+ // Dynamic allocation mode - grow buffer as needed
+ bufferCapacity = 4096;
+ *out_data = (uint8_t *)malloc(bufferCapacity);
+ if (!*out_data)
+ return 0;
+ } else {
+ // Fixed size mode
+ bufferCapacity = expectedSize;
+ *out_data = (uint8_t *)malloc(bufferCapacity);
+ if (!*out_data)
+ return 0;
+ }
- while (pos + 2 <= inputSize) {
- // Read the RLE pair
- uint8_t count = input[pos];
- uint8_t value = input[pos + 1];
- last_value = value;
+ while (pos + 2 <= inputSize) {
+ // Read the RLE pair
+ uint8_t count = input[pos];
+ uint8_t value = input[pos + 1];
+ last_value = value;
- // Write pixels for this pair
- for (int i = 0; i < count; i++) {
- // Grow buffer if needed
- if (result_size >= bufferCapacity) {
- if (untilBuda || expectedSize == 0) {
- bufferCapacity *= 2;
- } else {
- // In fixed mode, we've hit the limit - something is wrong
- // but grow minimally to avoid crash
- bufferCapacity += 256;
- }
- uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
- if (!newBuf) {
- free(*out_data);
- *out_data = nullptr;
- return 0;
- }
- *out_data = newBuf;
- }
- (*out_data)[result_size++] = value;
- }
+ // Write pixels for this pair
+ for (int i = 0; i < count; i++) {
+ // Grow buffer if needed
+ if (result_size >= bufferCapacity) {
+ if (untilBuda || expectedSize == 0) {
+ bufferCapacity *= 2;
+ } else {
+ // In fixed mode, we've hit the limit - something is wrong
+ // but grow minimally to avoid crash
+ bufferCapacity += 256;
+ }
+ uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
+ if (!newBuf) {
+ free(*out_data);
+ *out_data = nullptr;
+ return 0;
+ }
+ *out_data = newBuf;
+ }
+ (*out_data)[result_size++] = value;
+ }
- // Advance to next pair
- pos += 2;
+ // Advance to next pair
+ pos += 2;
- // Check for BUDA marker at new position
- if (untilBuda && pos + 4 <= inputSize &&
- input[pos] == 'B' && input[pos + 1] == 'U' &&
- input[pos + 2] == 'D' && input[pos + 3] == 'A') {
- // Game writes one final pixel after BUDA marker
- // Grow buffer if needed
- if (result_size >= bufferCapacity) {
- bufferCapacity++;
- uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
- if (!newBuf) {
- free(*out_data);
- *out_data = nullptr;
- return 0;
- }
- *out_data = newBuf;
- }
- (*out_data)[result_size++] = last_value;
- break;
- }
+ // Check for BUDA marker at new position
+ if (untilBuda && pos + 4 <= inputSize &&
+ input[pos] == 'B' && input[pos + 1] == 'U' &&
+ input[pos + 2] == 'D' && input[pos + 3] == 'A') {
+ // Game writes one final pixel after BUDA marker
+ // Grow buffer if needed
+ if (result_size >= bufferCapacity) {
+ bufferCapacity++;
+ uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
+ if (!newBuf) {
+ free(*out_data);
+ *out_data = nullptr;
+ return 0;
+ }
+ *out_data = newBuf;
+ }
+ (*out_data)[result_size++] = last_value;
+ break;
+ }
- // In fixed size mode, stop when we reach expected size
- if (!untilBuda && expectedSize > 0 && result_size >= expectedSize) {
- break;
- }
- }
+ // In fixed size mode, stop when we reach expected size
+ if (!untilBuda && expectedSize > 0 && result_size >= expectedSize) {
+ break;
+ }
+ }
- return result_size;
+ return result_size;
}
void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize) {
@@ -189,10 +189,8 @@ void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *
}
// Helper function for transparent blitting
-void drawSpriteToBuffer(byte *buffer, int bufferWidth,
- byte *sprite, int x, int y,
- int width, int height,
- int transparentColor) {
+void drawSpriteToBuffer(byte *buffer, int bufferWidth, byte *sprite, int x, int y, int width, int height, int transparentColor) {
+
for (int py = 0; py < height; py++) {
for (int px = 0; px < width; px++) {
int srcIdx = py * width + px;
@@ -250,7 +248,7 @@ void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color) {
if (x < 640 && y < 400 && x >= 0 && y >= 0) {
surface->setPixel(x, y, 100);
- surface->drawEllipse(x - 3, y - 3, x+3, y+3, color, true);
+ surface->drawEllipse(x - 3, y - 3, x + 3, y + 3, color, true);
}
}
Commit: 8463665fa1e8daf7de0511df1240d502f80666b5
https://github.com/scummvm/scummvm/commit/8463665fa1e8daf7de0511df1240d502f80666b5
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:19+02:00
Commit Message:
PELROCK: Reads the right settings screen
Changed paths:
engines/pelrock/resources.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 0364fe8a04b..e01d52d552c 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -262,16 +262,50 @@ void ResourceManager::loadSettingsMenu() {
}
_mainMenu = new byte[640 * 400];
-
- alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
- alfred7.read(_mainMenuPalette, 768);
- for (int i = 0; i < 256; i++) {
- _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
- _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
- _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
+ for (int i = 0; i < 640 * 400; i++) {
+ _mainMenu[i] = 13;
}
- mergeRleBlocks(&alfred7, kSettingsMenuOffset, 8, _mainMenu);
+ alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
+ // alfred7.read(_mainMenuPalette, 768);
+ // for (int i = 0; i < 256; i++) {
+ // _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
+ // _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
+ // _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
+ // }
+
+ uint32 curPos = 0;
+ alfred7.seek(2405266, SEEK_SET);
+ alfred7.read(_mainMenu, 65536);
+
+ curPos += 65536;
+
+ byte *compressedPart1 = new byte[29418];
+ alfred7.read(compressedPart1, 29418);
+ byte *decompressedPart1 = nullptr;
+ size_t decompressedSize = rleDecompress(compressedPart1, 29418, 0, 0, &decompressedPart1, true);
+
+ memcpy(_mainMenu + curPos, decompressedPart1, decompressedSize);
+ curPos += decompressedSize;
+
+
+ delete[] compressedPart1;
+ delete[] decompressedPart1;
+ alfred7.seek(2500220, SEEK_SET);
+ alfred7.read(_mainMenu + curPos, 32768);
+ curPos += 32768;
+ byte *compressedPart2 = new byte[30288];
+ alfred7.read(compressedPart2, 30288);
+ byte *decompressedPart2 = nullptr;
+ decompressedSize = rleDecompress(compressedPart2, 30288, 0, 0, &decompressedPart2, true);
+
+ memcpy(_mainMenu + curPos, decompressedPart2, decompressedSize);
+ curPos += decompressedSize;
+ debug("Settings menu size loaded: %d, with last block %d", curPos, curPos + 92160);
+ delete[] compressedPart2;
+ delete[] decompressedPart2;
+ alfred7.seek(2563266, SEEK_SET);
+ alfred7.read(_mainMenu + curPos, 92160);
alfred7.close();
}
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 38783d96ac4..593aac4e2df 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -33,10 +33,7 @@ namespace Pelrock {
const int EXPECTED_SIZE = 640 * 400;
size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data, bool untilBuda = true);
void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize);
-void drawSpriteToBuffer(byte *buffer, int bufferWidth,
- byte *sprite, int x, int y,
- int width, int height,
- int transparentColor);
+void drawSpriteToBuffer(byte *buffer, int bufferWidth, byte *sprite, int x, int y, int width, int height, int transparentColor);
void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY);
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight);
void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
Commit: 4c4a20c93cd918b0d11b62ab5428f1f60565c935
https://github.com/scummvm/scummvm/commit/4c4a20c93cd918b0d11b62ab5428f1f60565c935
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:19+02:00
Commit Message:
PELROCK: Loads right palette for settings menu
Changed paths:
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index e69c4a34e87..0fafede4be0 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -39,8 +39,8 @@ namespace Pelrock {
static const uint32_t ALFRED7_ALFRED_COMB_R = 67768;
static const uint32_t ALFRED7_ALFRED_COMB_L = 88408;
- static const uint32_t kSettingsMenuOffset = 910097; // Placeholder offset
- static const uint32_t kSettingsPaletteOffset = 1038141; // 640 * 480
+
+ static const uint32_t kSettingsPaletteOffset = 0x2884c2; // 640 * 480
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 21cd123dee1..e9137e1cd23 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -152,8 +152,10 @@ Common::Error PelrockEngine::run() {
_displayPopup = false;
_longClick = false;
} else if (e.type == Common::EVENT_RBUTTONUP) {
- if (stateGame != SETTINGS)
+ if (stateGame != SETTINGS){
+ g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
stateGame = SETTINGS;
+ }
else {
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
stateGame = GAME;
@@ -170,8 +172,6 @@ Common::Error PelrockEngine::run() {
}
checkMouseHover();
if (stateGame == SETTINGS) {
- g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
-
memcpy(_compositeBuffer, _res->_mainMenu, 640 * 400);
for (int i = 0; i < 4; i++) {
@@ -339,6 +339,7 @@ void PelrockEngine::frames() {
// Draw Alfred here (you'll need to add this)
chooseAlfredStateAndDraw();
+
// Second pass: sprites in front of Alfred (y > alfredY)
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].zOrder <= 10) {
@@ -766,6 +767,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
void PelrockEngine::checkLongMouseClick(int x, int y) {
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
+
if (hotspotIndex != -1) {
_popupX = x - kBalloonWidth / 2;
@@ -1192,7 +1194,7 @@ uint16_t PelrockEngine::buildWalkboxPath(uint8_t startBox, uint8_t destBox, uint
// Terminate path
pathBuffer[pathIndex] = PATH_END;
-
+ debug("Built walkbox path of length %d", pathIndex);
return pathIndex;
}
@@ -1332,7 +1334,11 @@ void PelrockEngine::checkMouseHover() {
}
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
-
+ if(hotspotIndex != -1) {
+ debug("Hotspot under mouse: %d, %d (extra = %d)", _room->_currentRoomHotspots[hotspotIndex].x,
+ _room->_currentRoomHotspots[hotspotIndex].y,
+ hotspotIndex != -1 ? _room->_currentRoomHotspots[hotspotIndex].extra : -1);
+ }
if (hotspotIndex != -1) {
isSomethingUnder = true;
}
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index e01d52d552c..9bddb612599 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -267,12 +267,12 @@ void ResourceManager::loadSettingsMenu() {
}
alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
- // alfred7.read(_mainMenuPalette, 768);
- // for (int i = 0; i < 256; i++) {
- // _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
- // _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
- // _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
- // }
+ alfred7.read(_mainMenuPalette, 768);
+ for (int i = 0; i < 256; i++) {
+ _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
+ _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
+ _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
+ }
uint32 curPos = 0;
alfred7.seek(2405266, SEEK_SET);
Commit: c7ec5a2917a1f61c070f24b82a748f09df7c69b1
https://github.com/scummvm/scummvm/commit/c7ec5a2917a1f61c070f24b82a748f09df7c69b1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:20+02:00
Commit Message:
PELROCK: Splits menu and game event handling
Changed paths:
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 0fafede4be0..4719d02d333 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -39,8 +39,8 @@ namespace Pelrock {
static const uint32_t ALFRED7_ALFRED_COMB_R = 67768;
static const uint32_t ALFRED7_ALFRED_COMB_L = 88408;
-
- static const uint32_t kSettingsPaletteOffset = 0x2884c2; // 640 * 480
+ static const uint32_t kAlternateSettingsMenuOffset = 910097; // Placeholder offset
+ static const uint32_t kSettingsPaletteOffset = 1038141; // 640 * 480
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index e9137e1cd23..6a0c3344ec9 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -107,86 +107,11 @@ Common::Error PelrockEngine::run() {
init();
while (!shouldQuit()) {
- _chronoManager->updateChrono();
- while (g_system->getEventManager()->pollEvent(e)) {
- if (e.type == Common::EVENT_KEYDOWN) {
- switch (e.kbd.keycode) {
- case Common::KEYCODE_w:
- alfredState.animState = ALFRED_WALKING;
- break;
- case Common::KEYCODE_t:
- alfredState.animState = ALFRED_TALKING;
- break;
- case Common::KEYCODE_s:
- alfredState.animState = ALFRED_IDLE;
- break;
- case Common::KEYCODE_c:
- alfredState.animState = ALFRED_COMB;
- break;
- case Common::KEYCODE_i:
- alfredState.animState = ALFRED_INTERACTING;
- break;
- case Common::KEYCODE_z:
- showShadows = !showShadows;
- break;
- case Common::KEYCODE_y:
- alfredState.x = 193;
- alfredState.y = 382;
- walkTo(377, 318);
- break;
- default:
- break;
- }
- } else if (e.type == Common::EVENT_MOUSEMOVE) {
- mouseX = e.mouse.x;
- mouseY = e.mouse.y;
- // debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
- } else if (e.type == Common::EVENT_LBUTTONDOWN) {
- if (!_isMouseDown) {
- _mouseClickTime = g_system->getMillis();
- _isMouseDown = true;
- }
- } else if (e.type == Common::EVENT_LBUTTONUP) {
- _isMouseDown = false;
- checkMouseClick(e.mouse.x, e.mouse.y);
- _displayPopup = false;
- _longClick = false;
- } else if (e.type == Common::EVENT_RBUTTONUP) {
- if (stateGame != SETTINGS){
- g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
- stateGame = SETTINGS;
- }
- else {
- g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
- stateGame = GAME;
- }
- }
- }
- if (_isMouseDown) {
- if (g_system->getMillis() - _mouseClickTime >= kLongClickDuration) {
- debug("long click!");
- _longClick = true;
- _isMouseDown = false;
- checkLongMouseClick(e.mouse.x, e.mouse.y);
- }
- }
- checkMouseHover();
if (stateGame == SETTINGS) {
- memcpy(_compositeBuffer, _res->_mainMenu, 640 * 400);
-
- for (int i = 0; i < 4; i++) {
- InventoryObject item = _res->getInventoryObject(i);
- drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + i * 85, 110 - i * 5, 60, 60, 1);
- }
- memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
-
- g_engine->_screen->markAllDirty();
- g_engine->_screen->update();
-
+ menuLoop();
} else if (stateGame == GAME) {
- frames();
+ gameLoop();
}
-
_screen->update();
// limiter.delayBeforeSwap();
// limiter.startFrame();
@@ -339,7 +264,6 @@ void PelrockEngine::frames() {
// Draw Alfred here (you'll need to add this)
chooseAlfredStateAndDraw();
-
// Second pass: sprites in front of Alfred (y > alfredY)
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].zOrder <= 10) {
@@ -975,6 +899,96 @@ void PelrockEngine::drawTalkNPC(Sprite *animSet) {
drawSpriteToBuffer(_compositeBuffer, 640, frame, x, y, w, h, 255);
}
+void PelrockEngine::gameLoop() {
+ _chronoManager->updateChrono();
+ Common::Event e;
+ while (g_system->getEventManager()->pollEvent(e)) {
+ if (e.type == Common::EVENT_KEYDOWN) {
+ switch (e.kbd.keycode) {
+ case Common::KEYCODE_w:
+ alfredState.animState = ALFRED_WALKING;
+ break;
+ case Common::KEYCODE_t:
+ alfredState.animState = ALFRED_TALKING;
+ break;
+ case Common::KEYCODE_s:
+ alfredState.animState = ALFRED_IDLE;
+ break;
+ case Common::KEYCODE_c:
+ alfredState.animState = ALFRED_COMB;
+ break;
+ case Common::KEYCODE_i:
+ alfredState.animState = ALFRED_INTERACTING;
+ break;
+ case Common::KEYCODE_z:
+ showShadows = !showShadows;
+ break;
+ case Common::KEYCODE_y:
+ alfredState.x = 193;
+ alfredState.y = 382;
+ walkTo(377, 318);
+ break;
+ default:
+ break;
+ }
+ } else if (e.type == Common::EVENT_MOUSEMOVE) {
+ mouseX = e.mouse.x;
+ mouseY = e.mouse.y;
+ // debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
+ } else if (e.type == Common::EVENT_LBUTTONDOWN) {
+ if (!_isMouseDown) {
+ _mouseClickTime = g_system->getMillis();
+ _isMouseDown = true;
+ }
+ } else if (e.type == Common::EVENT_LBUTTONUP) {
+ _isMouseDown = false;
+ checkMouseClick(e.mouse.x, e.mouse.y);
+ _displayPopup = false;
+ _longClick = false;
+ } else if (e.type == Common::EVENT_RBUTTONUP) {
+ g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
+ stateGame = SETTINGS;
+ }
+ }
+ if (_isMouseDown) {
+ if (g_system->getMillis() - _mouseClickTime >= kLongClickDuration) {
+ debug("long click!");
+ _longClick = true;
+ _isMouseDown = false;
+ checkLongMouseClick(e.mouse.x, e.mouse.y);
+ }
+ }
+ checkMouseHover();
+ frames();
+}
+
+void PelrockEngine::menuLoop() {
+ Common::Event e;
+ while (g_system->getEventManager()->pollEvent(e)) {
+ if (e.type == Common::EVENT_LBUTTONUP) {
+ // _isMouseDown = false;
+ // checkMouseClick(e.mouse.x, e.mouse.y);
+ // _displayPopup = false;
+ // _longClick = false;
+ } else if (e.type == Common::EVENT_RBUTTONUP) {
+
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+ stateGame = GAME;
+ }
+ }
+
+ memcpy(_compositeBuffer, _res->_mainMenu, 640 * 400);
+
+ for (int i = 0; i < 4; i++) {
+ InventoryObject item = _res->getInventoryObject(i);
+ drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + i * 85, 110 - i * 5, 60, 60, 1);
+ }
+ memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+}
+
void PelrockEngine::walkTo(int x, int y) {
_currentStep = 0;
PathContext context = {nullptr, nullptr, nullptr, 0, 0, 0};
@@ -1334,10 +1348,10 @@ void PelrockEngine::checkMouseHover() {
}
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
- if(hotspotIndex != -1) {
- debug("Hotspot under mouse: %d, %d (extra = %d)", _room->_currentRoomHotspots[hotspotIndex].x,
- _room->_currentRoomHotspots[hotspotIndex].y,
- hotspotIndex != -1 ? _room->_currentRoomHotspots[hotspotIndex].extra : -1);
+ if (hotspotIndex != -1) {
+ debug("Hotspot under mouse: %d, %d (extra = %d)", _room->_currentRoomHotspots[hotspotIndex].x,
+ _room->_currentRoomHotspots[hotspotIndex].y,
+ hotspotIndex != -1 ? _room->_currentRoomHotspots[hotspotIndex].extra : -1);
}
if (hotspotIndex != -1) {
isSomethingUnder = true;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 37a530f65b4..f346eee6b8c 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -101,6 +101,9 @@ private:
void changeCursor(Cursor cursor);
void drawTalkNPC(Sprite *animSet);
+ void gameLoop();
+ void menuLoop();
+
void checkMouseHover();
void checkMouseClick(int x, int y);
void checkLongMouseClick(int x, int y);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 9bddb612599..67bd6ba1bbb 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -255,6 +255,8 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
}
void ResourceManager::loadSettingsMenu() {
+
+ bool alternateMenu = true;
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
error("Could not open ALFRED.7");
@@ -262,51 +264,68 @@ void ResourceManager::loadSettingsMenu() {
}
_mainMenu = new byte[640 * 400];
- for (int i = 0; i < 640 * 400; i++) {
- _mainMenu[i] = 13;
- }
- alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
- alfred7.read(_mainMenuPalette, 768);
- for (int i = 0; i < 256; i++) {
- _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
- _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
- _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
- }
+ if (!alternateMenu) {
+ alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
+ alfred7.read(_mainMenuPalette, 768);
+ for (int i = 0; i < 256; i++) {
+ _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
+ _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
+ _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
+ }
- uint32 curPos = 0;
- alfred7.seek(2405266, SEEK_SET);
- alfred7.read(_mainMenu, 65536);
-
- curPos += 65536;
-
- byte *compressedPart1 = new byte[29418];
- alfred7.read(compressedPart1, 29418);
- byte *decompressedPart1 = nullptr;
- size_t decompressedSize = rleDecompress(compressedPart1, 29418, 0, 0, &decompressedPart1, true);
-
- memcpy(_mainMenu + curPos, decompressedPart1, decompressedSize);
- curPos += decompressedSize;
-
-
- delete[] compressedPart1;
- delete[] decompressedPart1;
- alfred7.seek(2500220, SEEK_SET);
- alfred7.read(_mainMenu + curPos, 32768);
- curPos += 32768;
- byte *compressedPart2 = new byte[30288];
- alfred7.read(compressedPart2, 30288);
- byte *decompressedPart2 = nullptr;
- decompressedSize = rleDecompress(compressedPart2, 30288, 0, 0, &decompressedPart2, true);
-
- memcpy(_mainMenu + curPos, decompressedPart2, decompressedSize);
- curPos += decompressedSize;
- debug("Settings menu size loaded: %d, with last block %d", curPos, curPos + 92160);
- delete[] compressedPart2;
- delete[] decompressedPart2;
- alfred7.seek(2563266, SEEK_SET);
- alfred7.read(_mainMenu + curPos, 92160);
- alfred7.close();
+ uint32 curPos = 0;
+ alfred7.seek(2405266, SEEK_SET);
+ alfred7.read(_mainMenu, 65536);
+
+ curPos += 65536;
+
+ byte *compressedPart1 = new byte[29418];
+ alfred7.read(compressedPart1, 29418);
+ byte *decompressedPart1 = nullptr;
+ size_t decompressedSize = rleDecompress(compressedPart1, 29418, 0, 0, &decompressedPart1, true);
+
+ memcpy(_mainMenu + curPos, decompressedPart1, decompressedSize);
+ curPos += decompressedSize;
+
+ delete[] compressedPart1;
+ delete[] decompressedPart1;
+ alfred7.seek(2500220, SEEK_SET);
+ alfred7.read(_mainMenu + curPos, 32768);
+ curPos += 32768;
+ byte *compressedPart2 = new byte[30288];
+ alfred7.read(compressedPart2, 30288);
+ byte *decompressedPart2 = nullptr;
+ decompressedSize = rleDecompress(compressedPart2, 30288, 0, 0, &decompressedPart2, true);
+
+ memcpy(_mainMenu + curPos, decompressedPart2, decompressedSize);
+ curPos += decompressedSize;
+ debug("Settings menu size loaded: %d, with last block %d", curPos, curPos + 92160);
+ delete[] compressedPart2;
+ delete[] decompressedPart2;
+ alfred7.seek(2563266, SEEK_SET);
+ alfred7.read(_mainMenu + curPos, 92160);
+ alfred7.close();
+ } else {
+ Common::File alfred7;
+ if (!alfred7.open(Common::Path("ALFRED.7"))) {
+ error("Could not open ALFRED.7");
+ return;
+ }
+
+ _mainMenu = new byte[640 * 400];
+
+ alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
+ alfred7.read(_mainMenuPalette, 768);
+ for (int i = 0; i < 256; i++) {
+ _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
+ _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
+ _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
+ }
+
+ mergeRleBlocks(&alfred7, kAlternateSettingsMenuOffset, 8, _mainMenu);
+ alfred7.close();
+ }
}
} // End of namespace Pelrock
Commit: 15b0077a61493db6202e0ccfda8a56f6a6f9b71f
https://github.com/scummvm/scummvm/commit/15b0077a61493db6202e0ccfda8a56f6a6f9b71f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:20+02:00
Commit Message:
PELROCK: Remove g_engine references from engine
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 6a0c3344ec9..f229527dcda 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -185,7 +185,7 @@ void PelrockEngine::putBackgroundSlice(int x, int y, int w, int h, byte *slice)
for (int j = 0; j < h; j++) {
int index = (j * w + i);
if (x + i < 640 && y + j < 400)
- *(byte *)g_engine->_screen->getBasePtr(x + i, y + j) = slice[index];
+ *(byte *)_screen->getBasePtr(x + i, y + j) = slice[index];
}
}
}
@@ -985,8 +985,8 @@ void PelrockEngine::menuLoop() {
}
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- g_engine->_screen->markAllDirty();
- g_engine->_screen->update();
+ _screen->markAllDirty();
+ _screen->update();
}
void PelrockEngine::walkTo(int x, int y) {
Commit: 9a2c56321be123d02869dc19ba8bb8c1f87e109a
https://github.com/scummvm/scummvm/commit/9a2c56321be123d02869dc19ba8bb8c1f87e109a
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:20+02:00
Commit Message:
PELROCK: Loads inventory descriptions
Changed paths:
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/resources.h
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 4719d02d333..6719c50478b 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -25,25 +25,145 @@
namespace Pelrock {
- static const uint32_t cursor_offsets[5] = {
- 0x0FDDFD,
- 0x0FDCDD,
- 0x0FDF1D,
- 0x0FE33D,
- 0x367EF0
- };
+static const uint32_t cursor_offsets[5] = {
+ 0x0FDDFD,
+ 0x0FDCDD,
+ 0x0FDF1D,
+ 0x0FE33D,
+ 0x367EF0};
- static const uint32_t kBalloonFramesOffset = 2176936;
- static const uint32_t kBalloonFramesSize = 24950;
+static const uint32_t kBalloonFramesOffset = 2176936;
+static const uint32_t kBalloonFramesSize = 24950;
- static const uint32_t ALFRED7_ALFRED_COMB_R = 67768;
- static const uint32_t ALFRED7_ALFRED_COMB_L = 88408;
+static const uint32_t ALFRED7_ALFRED_COMB_R = 67768;
+static const uint32_t ALFRED7_ALFRED_COMB_L = 88408;
- static const uint32_t kAlternateSettingsMenuOffset = 910097; // Placeholder offset
- static const uint32_t kSettingsPaletteOffset = 1038141; // 640 * 480
+static const uint32_t kAlternateSettingsMenuOffset = 910097; // Placeholder offset
+static const uint32_t kSettingsPaletteOffset = 1038141; // 640 * 480
+#define DESCRIPTION_BASE_OFFSET 0x4715D
+#define NUM_DESCRIPTIONS 113
+static const uint32 kInventoryDescriptionsOffset = 0x4715D;
+static const uint32 kInventoryDescriptionsSize = 7868;
+
+
+// Description offsets relative to DESCRIPTION_BASE_OFFSET
+const uint16_t description_offsets[NUM_DESCRIPTIONS] = {
+ 0x0000, // Object 0: Historia de la Princesa Zenna y su amante insatisfecho
+ 0x0058, // Object 1: Nombre: Alfred Pelrock
+ 0x00C4, // Object 2: La tipica tarjeta por la que te sacan commisiones
+ 0x010E, // Object 3: Una pequeña foto de Alfred
+ 0x012C, // Object 4: Un ladrillo
+ 0x013B, // Object 5: 1000 pesetas
+ 0x014B, // Object 6: Una alargadera con un extremo suelto
+ 0x0173, // Object 7: Un amuleto egipcio con forma de escarabajo alado
+ 0x01A7, // Object 8: Dice: OM OM RASKAMAMOM
+ 0x01C1, // Object 9: Es una carta de la Asociacion Ra-Amoniana
+ 0x020A, // Object 10: Un carnet de biblioteca
+ 0x0247, // Object 11: Titulo: Canticos espirituales en formato *.zip
+ 0x02B3, // Object 12: Titulo: Pasion Flagrante
+ 0x0327, // Object 13: Titulo: El Valenciano en los comienzos del siglo XXI
+ 0x039E, // Object 14: Titulo: El sistema inmunologico de los cefalopodos (v.I)
+ 0x0412, // Object 15: Titulo: Dos y dos son 5
+ 0x0493, // Object 16: Titulo: La parte creativa
+ 0x057B, // Object 17: Titulo: 10 maneras de preparar fideos chinos
+ 0x065C, // Object 18: Titulo: Los Peces Gato del Rio Tajo
+ 0x06D8, // Object 19: Titulo: Gato por liebre
+ 0x0753, // Object 20: Titulo: Hiper-cocina para solteros
+ 0x07CE, // Object 21: Titulo: El camaleon humano
+ 0x084E, // Object 22: Titulo: Psiquiatria Avanzada (vol. 8)
+ 0x08CA, // Object 23: Titulo: Sistemas de alcantarillado en el siglo XV
+ 0x0949, // Object 24: Titulo: Cartas de amor de Pol Pot a su novia
+ 0x09CC, // Object 25: Titulo: El gran libro de las preposiciones
+ 0x0A50, // Object 26: Titulo: Corazon, vida y muerte de un tenista
+ 0x0ACC, // Object 27: Titulo: Analisis de la vida de los funcionarios
+ 0x0B4D, // Object 28: Titulo: Ensayos sobre la putrefaccion
+ 0x0BC9, // Object 29: Titulo: Cocinar bien es imposible
+ 0x0C49, // Object 30: Titulo: 1000 formas de hacer sonar un claxon
+ 0x0CC8, // Object 31: Titulo: El arte de la peluqueria
+ 0x0D3B, // Object 32: Titulo: Analisis de las tramas de las mejores telecomedias
+ 0x0DC7, // Object 33: Titulo: Tratado de las empanadillas
+ 0x0E40, // Object 34: Titulo: Misterios de los numeros
+ 0x0EBA, // Object 35: Titulo: Como vender mas
+ 0x0F31, // Object 36: Titulo: Todos podemos estar de moda
+ 0x0FAD, // Object 37: Titulo: La economia capitalista (Tomo VI)
+ 0x102E, // Object 38: Titulo: Aventuras con mis hemorrides
+ 0x10AB, // Object 39: Titulo: Automate. Tomo IV: Suicidio
+ 0x1128, // Object 40: Titulo: El cienpies azul
+ 0x11A1, // Object 41: Titulo: Guia sexual de la mosca
+ 0x121E, // Object 42: Titulo: La Oveja. El gran misterio
+ 0x1297, // Object 43: Titulo: Mi libro de cocina
+ 0x1309, // Object 44: Titulo: Ariel
+ 0x1377, // Object 45: Titulo: Matar cucarachas con la mirada
+ 0x13F4, // Object 46: Titulo: Telepatia: Caso practico
+ 0x1476, // Object 47: Titulo: Vida y obra de Paquirrin
+ 0x14F4, // Object 48: Titulo: Odas para aliviar el estrenimiento
+ 0x1577, // Object 49: Titulo: Mi vida en el gran mercado
+ 0x15F4, // Object 50: Titulo: Oda al tocino
+ 0x1669, // Object 51: Titulo: Como escribir una novela
+ 0x16E0, // Object 52: Titulo: Recogiendo oro en las cloacas
+ 0x175B, // Object 53: Titulo: Como comer bien. Tomo XXI. Entrantes
+ 0x17DD, // Object 54: Titulo: No tengo nada mejor que hacer
+ 0x185D, // Object 55: Titulo: Los Heraldos Negros
+ 0x18D1, // Object 56: Titulo: La Piedra Rosetta
+ 0x194A, // Object 57: Titulo: Fabulas de Ciencia Ficcion
+ 0x19C3, // Object 58: Titulo: Elogio de la pereza
+ 0x1A35, // Object 59: Un pequeño altavoz
+ 0x1A52, // Object 60: Un altavoz mediano
+ 0x1A70, // Object 61: Un altavoz grande
+ 0x1A8C, // Object 62: Un extintor
+ 0x1AA3, // Object 63: Parece un extintor, pero es un termo de cafe. De los de antes, de los grandes
+ 0x1B2D, // Object 64: Un termo con cafe
+ 0x1B53, // Object 65: Una cafetera expres para una taza
+ 0x1B8D, // Object 66: La tarjeta de acceso de Erika
+ 0x1BBE, // Object 67: Billetes de avion para salir por patas hacia Valencia
+ 0x1C26, // Object 68: Una bolsa de patatas fritas
+ 0x1C52, // Object 69: Llave de la habitacion de Lucy
+ 0x1C82, // Object 70: Llave de la habitacion de Erika
+ 0x1CB3, // Object 71: Un ordenador de sobremesa
+ 0x1CE1, // Object 72: Un cuadro
+ 0x1CF9, // Object 73: Una moto mega-retuneada
+ 0x1D24, // Object 74: Una lamparita
+ 0x1D3F, // Object 75: Un libro gordo
+ 0x1D5C, // Object 76: Un libro finito
+ 0x1D7A, // Object 77: Un poco de escayola vieja
+ 0x1DA3, // Object 78: Un cacho de ladrillo
+ 0x1DCC, // Object 79: Un boligrafo
+ 0x1DE5, // Object 80: Un radiocasete
+ 0x1E00, // Object 81: Es una pistola. (Real como la vida misma)
+ 0x1E49, // Object 82: Una pieza de fruta
+ 0x1E6B, // Object 83: Un frasco de pastillas para dormir
+ 0x1EA0, // Object 84: Una pulsera
+ 0x1EB9, // Object 85: Una estatua pequeña
+ 0x1EE0, // Object 86: Una jodida (disculpen las molestias) cinta de video
+ 0x1F4F, // Object 87: Una jodida (disculpen las molestias) cadena hifi
+ 0x1FBE, // Object 88: Una magdalena
+ 0x1FD8, // Object 89: Un poco de cecina
+ 0x1FFC, // Object 90: Un televisor portatil con forma de Mickey Mouse
+ 0x2053, // Object 91: Un destornillador
+ 0x2071, // Object 92: Alicates de electricista
+ 0x2097, // Object 93: Un cable
+ 0x20AE, // Object 94: Una linterna
+ 0x20C6, // Object 95: Unas pilas gigantes
+ 0x20E7, // Object 96: La bolsa de basura negra
+ 0x2116, // Object 97: Foto de un tal Gerardo (desconocido)
+ 0x2158, // Object 98: Una cinta de casete
+ 0x2179, // Object 99: Un walkman
+ 0x218F, // Object 100: Un papel con un telefono
+ 0x21BE, // Object 101: Una llave grande de metacrilato
+ 0x21F1, // Object 102: Una pequeña llave
+ 0x220E, // Object 103: Autenticas naranjas de Nules
+ 0x2236, // Object 104: No se haga el loco: Llameme !!!
+ 0x2285, // Object 105: Folletos explicativos sobre el SIDA
+ 0x22BE, // Object 106: Un pin que acredita mi sabiduria
+ 0x22E2, // Object 107: Una bayeta para frotar lamparas magicas
+ 0x2316, // Object 108: Parches ultra-fuertes
+ 0x2337, // Object 109: Pegamento que te cagas
+ 0x235A, // Object 110: Una replica de Alfred pinchada
+ 0x2383, // Object 111: Una cinta del Rey Elvis
+ 0x23A4, // Object 112: Una caja de condone
+};
} // End of namespace Pelrock
#endif
-
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f229527dcda..2ee4d77cc90 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -124,6 +124,7 @@ void PelrockEngine::init() {
_res->loadCursors();
_res->loadInteractionIcons();
_res->loadInventoryIcons();
+ _res->loadInventoryDescriptions();
_res->loadSettingsMenu();
_soundManager->loadSoundIndex();
@@ -1348,11 +1349,6 @@ void PelrockEngine::checkMouseHover() {
}
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
- if (hotspotIndex != -1) {
- debug("Hotspot under mouse: %d, %d (extra = %d)", _room->_currentRoomHotspots[hotspotIndex].x,
- _room->_currentRoomHotspots[hotspotIndex].y,
- hotspotIndex != -1 ? _room->_currentRoomHotspots[hotspotIndex].extra : -1);
- }
if (hotspotIndex != -1) {
isSomethingUnder = true;
}
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 67bd6ba1bbb..67916788d49 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -233,6 +233,44 @@ void ResourceManager::loadInventoryIcons() {
delete[] iconData;
}
+void ResourceManager::loadInventoryDescriptions() {
+ Common::File exe;
+ if (!exe.open("JUEGO.EXE")) {
+ error("Couldnt find file JUEGO.EXE");
+ }
+ byte *descBuffer = new byte[kInventoryDescriptionsSize];
+ exe.seek(kInventoryDescriptionsOffset, SEEK_SET);
+ exe.read(descBuffer, kInventoryDescriptionsSize);
+ int pos = 0;
+ Common::String desc = "";
+ while (pos < kInventoryDescriptionsSize) {
+ if (descBuffer[pos] == 0xFD) {
+ if (!desc.empty()) {
+ _inventoryDescriptions.push_back(desc);
+ desc = Common::String();
+ }
+ pos++;
+ continue;
+ }
+ if (descBuffer[pos] == 0x00) {
+ pos++;
+ continue;
+ }
+ if (descBuffer[pos] == 0x08) {
+ pos += 2;
+ continue;
+ }
+
+ desc.append(1, descBuffer[pos]);
+ if (pos + 1 == kInventoryDescriptionsSize) {
+ _inventoryDescriptions.push_back(desc);
+ }
+ pos++;
+ }
+ delete[] descBuffer;
+ exe.close();
+}
+
InventoryObject ResourceManager::getInventoryObject(byte index) {
return _inventoryIcons[index];
}
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 4561e78e799..dd7c0d0c148 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -44,6 +44,7 @@ public:
void loadInteractionIcons();
void loadAlfredAnims();
void loadInventoryIcons();
+ void loadInventoryDescriptions();
InventoryObject getInventoryObject(byte index);
byte *loadExtra();
@@ -62,6 +63,7 @@ public:
byte *_mainMenu = nullptr;
byte _mainMenuPalette[768] = {0};
+ Common::Array<Common::String> _inventoryDescriptions;
};
} // End of namespace Pelrock
Commit: 4ebec869e3ee6b5e1514a81fd51e63b659d6cc50
https://github.com/scummvm/scummvm/commit/4ebec869e3ee6b5e1514a81fd51e63b659d6cc50
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:21+02:00
Commit Message:
PELROCK: Associates descriptions to objects
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 2ee4d77cc90..17e1ba67501 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -123,8 +123,7 @@ Common::Error PelrockEngine::run() {
void PelrockEngine::init() {
_res->loadCursors();
_res->loadInteractionIcons();
- _res->loadInventoryIcons();
- _res->loadInventoryDescriptions();
+ _res->loadInventoryItems();
_res->loadSettingsMenu();
_soundManager->loadSoundIndex();
@@ -967,6 +966,9 @@ void PelrockEngine::menuLoop() {
Common::Event e;
while (g_system->getEventManager()->pollEvent(e)) {
if (e.type == Common::EVENT_LBUTTONUP) {
+
+ _menuText = _res->getInventoryObject(selectedInvIndex++).description;
+
// _isMouseDown = false;
// checkMouseClick(e.mouse.x, e.mouse.y);
// _displayPopup = false;
@@ -985,7 +987,7 @@ void PelrockEngine::menuLoop() {
drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + i * 85, 110 - i * 5, 60, 60, 1);
}
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
-
+ _smallFont->drawString(_screen, _menuText, 0, 0, 640, 0);
_screen->markAllDirty();
_screen->update();
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index f346eee6b8c..bf00459347b 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -156,6 +156,10 @@ private:
bool showShadows = false;
+ //Temporary
+ int selectedInvIndex = 0;
+ Common::String _menuText;
+
// JAVA
bool shouldPlayIntro = false;
GameState stateGame = INTRO;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 67916788d49..d33576d2deb 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -215,7 +215,8 @@ void ResourceManager::loadAlfredAnims() {
free(alfredCombLeftRaw);
}
-void ResourceManager::loadInventoryIcons() {
+void ResourceManager::loadInventoryItems() {
+ loadInventoryDescriptions();
Common::File alfred4File;
if (!alfred4File.open("ALFRED.4")) {
error("Couldnt find file ALFRED.4");
@@ -229,6 +230,7 @@ void ResourceManager::loadInventoryIcons() {
for (int i = 0; i < 69; i++) {
_inventoryIcons[i].index = i;
extractSingleFrame(iconData, _inventoryIcons[i].iconData, i, 60, 60);
+ _inventoryIcons[i].description = _inventoryDescriptions[i];
}
delete[] iconData;
}
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index dd7c0d0c148..9b54652f76f 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -34,6 +34,7 @@ static const int interactingAnimLength = 2;
class ResourceManager {
private:
void mergeRleBlocks(Common::SeekableReadStream *stream, uint32 offset, int numBlocks, byte *outputBuffer);
+ void loadInventoryDescriptions();
InventoryObject *_inventoryIcons = nullptr;
public:
ResourceManager(/* args */);
@@ -43,8 +44,7 @@ public:
void loadCursors();
void loadInteractionIcons();
void loadAlfredAnims();
- void loadInventoryIcons();
- void loadInventoryDescriptions();
+ void loadInventoryItems();
InventoryObject getInventoryObject(byte index);
byte *loadExtra();
Commit: c3300ba0c62e4ee1fbbe85c9aeb1e44edc78b98f
https://github.com/scummvm/scummvm/commit/c3300ba0c62e4ee1fbbe85c9aeb1e44edc78b98f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:21+02:00
Commit Message:
PELROCK: Fixes persistent text
Changed paths:
engines/pelrock/chrono.cpp
engines/pelrock/chrono.h
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index 131fd80ce85..cb1d1b33848 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -37,7 +37,7 @@ ChronoManager::~ChronoManager() {
void ChronoManager::updateChrono() {
uint32 currentTime = g_system->getMillis();
- if (_textTtl > 0 && g_engine->alfredState.animState == ALFRED_TALKING && g_engine->alfredState.animState != ALFRED_WALKING) {
+ if (_textTtl > 0 && countTextDown) {
_textTtl -= (currentTime - _lastTick);
if (_textTtl < 0)
_textTtl = 0;
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 03f10b010cf..37d096f4dbd 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -50,6 +50,7 @@ public:
bool _gameTick = false;
long _textTtl = 0;
+ bool countTextDown = false;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 17e1ba67501..86efba1e75e 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -288,6 +288,7 @@ void PelrockEngine::frames() {
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
if (alfredState.animState != ALFRED_WALKING && !_currentTextPages.empty()) {
+ _chronoManager->countTextDown = true;
if (_chronoManager->_textTtl > 0) {
if (alfredState.animState == ALFRED_TALKING) {
_textPos = Common::Point(alfredState.x, alfredState.y - kAlfredFrameHeight - 10);
@@ -307,6 +308,7 @@ void PelrockEngine::frames() {
alfredState.animState = ALFRED_IDLE;
isNPCATalking = false;
isNPCBTalking = false;
+ _chronoManager->countTextDown = false;
}
}
@@ -694,14 +696,14 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
if (hotspotIndex != -1) {
- _popupX = x - kBalloonWidth / 2;
+ _popupX = alfredState.x - kBalloonWidth / 2;
if (_popupX < 0)
_popupX = 0;
if (_popupX + kBalloonWidth > 640) {
_popupX -= 640 - (_popupX + kBalloonWidth);
}
- _popupY = y - kBalloonHeight;
+ _popupY = alfredState.y - kAlfredFrameHeight - kBalloonHeight;
if (_popupY < 0) {
_popupY = 0;
}
@@ -986,6 +988,7 @@ void PelrockEngine::menuLoop() {
InventoryObject item = _res->getInventoryObject(i);
drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + i * 85, 110 - i * 5, 60, 60, 1);
}
+
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
_smallFont->drawString(_screen, _menuText, 0, 0, 640, 0);
_screen->markAllDirty();
Commit: 47ba1000c9ff704c6a7eee1e2b334de40ab97426
https://github.com/scummvm/scummvm/commit/47ba1000c9ff704c6a7eee1e2b334de40ab97426
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:21+02:00
Commit Message:
PELROCK: Navigate through inventory icons
Changed paths:
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 6719c50478b..66a2578af49 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -38,8 +38,10 @@ static const uint32_t kBalloonFramesSize = 24950;
static const uint32_t ALFRED7_ALFRED_COMB_R = 67768;
static const uint32_t ALFRED7_ALFRED_COMB_L = 88408;
-static const uint32_t kAlternateSettingsMenuOffset = 910097; // Placeholder offset
-static const uint32_t kSettingsPaletteOffset = 1038141; // 640 * 480
+
+static const uint32_t kAlternateSettingsMenuOffset = 910097;
+static const uint32_t kAlternateSettingsPaletteOffset = 1038141; // 640 * 480
+static const uint32_t kSettingsPaletteOffset = 0x2884c2; // 640 * 480
#define DESCRIPTION_BASE_OFFSET 0x4715D
#define NUM_DESCRIPTIONS 113
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 86efba1e75e..7d5e49704c8 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -108,6 +108,7 @@ Common::Error PelrockEngine::run() {
while (!shouldQuit()) {
if (stateGame == SETTINGS) {
+ changeCursor(DEFAULT);
menuLoop();
} else if (stateGame == GAME) {
gameLoop();
@@ -714,6 +715,32 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
}
}
+void PelrockEngine::checkMouseClickOnSettings(int x, int y) {
+
+ bool selectedItem = false;
+ for(int i = 0; i < 4; i++) {
+ if(x >= 140 + (82 * i) && x <= 140 + (82 * i) + 64 &&
+ y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
+ selectedInvIndex = curInventoryPage * 4 + i;
+ _menuText = _res->getInventoryObject(selectedInvIndex).description;
+ debug("Selected inventory index: %d", selectedInvIndex);
+ selectedItem = true;
+ return;
+ }
+ }
+ if(!selectedItem) {
+ selectedInvIndex = -1;
+ _menuText = "";
+ }
+
+ if(x >= 471 && x <= 471 + 23 &&
+ y >= 87 && y <= 87 + 33) {
+ curInventoryPage++;
+ }
+
+
+}
+
void PelrockEngine::calculateScalingMasks() {
// for scale_factor in range(CHAR_WIDTH):
@@ -968,13 +995,8 @@ void PelrockEngine::menuLoop() {
Common::Event e;
while (g_system->getEventManager()->pollEvent(e)) {
if (e.type == Common::EVENT_LBUTTONUP) {
+ checkMouseClickOnSettings(e.mouse.x, e.mouse.y);
- _menuText = _res->getInventoryObject(selectedInvIndex++).description;
-
- // _isMouseDown = false;
- // checkMouseClick(e.mouse.x, e.mouse.y);
- // _displayPopup = false;
- // _longClick = false;
} else if (e.type == Common::EVENT_RBUTTONUP) {
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
@@ -984,13 +1006,15 @@ void PelrockEngine::menuLoop() {
memcpy(_compositeBuffer, _res->_mainMenu, 640 * 400);
- for (int i = 0; i < 4; i++) {
- InventoryObject item = _res->getInventoryObject(i);
- drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + i * 85, 110 - i * 5, 60, 60, 1);
+ for(int i = 0; i < 4; i++) {
+ int itemIndex = curInventoryPage * 4 + i;
+ InventoryObject item = _res->getInventoryObject(itemIndex);
+ drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
+ drawRect(_compositeBuffer, 140 + (82 * i) - 2, 115 - (8 * i) - 2, 64, 64, 255); // Draw border
}
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- _smallFont->drawString(_screen, _menuText, 0, 0, 640, 0);
+ _smallFont->drawString(_screen, _menuText, 230, 200, 200, 0);
_screen->markAllDirty();
_screen->update();
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index bf00459347b..5aa74d3fa86 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -107,6 +107,7 @@ private:
void checkMouseHover();
void checkMouseClick(int x, int y);
void checkLongMouseClick(int x, int y);
+ void checkMouseClickOnSettings(int x, int y);
void calculateScalingMasks();
ScaleCalculation calculateScaling(int yPos, ScalingParams scalingParams);
@@ -158,6 +159,7 @@ private:
//Temporary
int selectedInvIndex = 0;
+ int curInventoryPage = 0;
Common::String _menuText;
// JAVA
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index d33576d2deb..63834fc61bd 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -296,7 +296,7 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
void ResourceManager::loadSettingsMenu() {
- bool alternateMenu = true;
+ bool alternateMenu = false;
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
error("Could not open ALFRED.7");
@@ -355,7 +355,7 @@ void ResourceManager::loadSettingsMenu() {
_mainMenu = new byte[640 * 400];
- alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
+ alfred7.seek(kAlternateSettingsPaletteOffset, SEEK_SET);
alfred7.read(_mainMenuPalette, 768);
for (int i = 0; i < 256; i++) {
_mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index fa00202554b..3f8fc4436a9 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -75,14 +75,12 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
roomFile->seek(pair_offset, SEEK_SET);
uint32_t offset = roomFile->readUint32LE();
uint32_t size = roomFile->readUint32LE();
- debug("Background pair %d: offset=%d size=%d", pair_idx, offset, size);
if (offset > 0 && size > 0 && offset < roomFile->size()) {
byte *data = new byte[size];
roomFile->seek(offset, SEEK_SET);
roomFile->read(data, size);
uint8_t *block_data = NULL;
size_t block_size = rleDecompress(data, size, 0, 640 * 400, &block_data);
- debug(" Decompressed block size: %d, combined size: %d", block_size, combined_size + block_size);
if (block_size + combined_size > 640 * 400) {
debug(" Warning: decompressed background size exceeds buffer size!");
block_size = 640 * 400 - combined_size;
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index f204188003b..bc302a8ae7d 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -41,6 +41,22 @@ void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color
surface->drawLine(x + w, y, x + w, y + h, color);
}
+void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color) {
+ Graphics::Surface *surface = new Graphics::Surface();
+ surface->create(w, h, Graphics::PixelFormat::createFormatCLUT8());
+ drawRect(surface, 0, 0, w, h, color);
+
+ for (int py = 0; py < h; py++) {
+ for (int px = 0; px < w; px++) {
+ int destIdx = (y + py) * 640 + (x + px);
+ int srcIdx = py * w + px;
+ int color = *((byte *)surface->getBasePtr(px, py));
+ if(color != 0)
+ screenBuffer[destIdx] = color;
+ }
+ }
+}
+
Common::String printMovementFlags(uint8_t flags) {
Common::String result;
if (flags & MOVE_HORIZ) {
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 593aac4e2df..88fc9c67093 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -38,6 +38,7 @@ void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWid
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight);
void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
+void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color);
Common::String printMovementFlags(uint8_t flags);
Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
Commit: e3517058e65add29333806130dbcd11db8dc925c
https://github.com/scummvm/scummvm/commit/e3517058e65add29333806130dbcd11db8dc925c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:21+02:00
Commit Message:
PELROCK: Fixes decoding issues
Changed paths:
engines/pelrock/fonts/large_font.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index fa431089d42..f6aa4f12e7f 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -37,7 +37,7 @@ bool LargeFont::load(const Common::String &filename) {
}
file.seek(0x7DC8, SEEK_SET);
- const int numChars = 96;
+ const int numChars = 100;
const int charWidth = 12;
const int charHeight = 24;
const int pad = 1;
@@ -115,7 +115,7 @@ int LargeFont::getCharWidth(uint32 chr) const {
void LargeFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
chr -= 32; // Adjust for font starting at ASCII 32
- if (!_fontData || chr >= 96 || chr < 0) {
+ if (!_fontData || chr >= 100 || chr < 0) {
return;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 7d5e49704c8..54c925df455 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -587,7 +587,6 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
int srcIndex = srcY * kAlfredFrameWidth + srcX;
int outIndex = outY * finalWidth + outX;
- debug("srcIndex = %d, outIndex = %d, original size = %d, outsize = %d", srcIndex, outIndex, kAlfredFrameWidth * kAlfredFrameHeight, finalWidth * finalHeight);
if (outIndex >= finalWidth * finalHeight || srcIndex >= kAlfredFrameWidth * kAlfredFrameHeight) {
debug("Index out of bounds!");
} else
@@ -701,7 +700,7 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
if (_popupX < 0)
_popupX = 0;
if (_popupX + kBalloonWidth > 640) {
- _popupX -= 640 - (_popupX + kBalloonWidth);
+ _popupX = 640 - kBalloonWidth;
}
_popupY = alfredState.y - kAlfredFrameHeight - kBalloonHeight;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 63834fc61bd..c5da7da9312 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -262,8 +262,13 @@ void ResourceManager::loadInventoryDescriptions() {
pos += 2;
continue;
}
+ if(descBuffer[pos] == 0xC8) {
+ desc.append(1, '\n');
+ pos++;
+ continue;
+ }
- desc.append(1, descBuffer[pos]);
+ desc.append(1, decodeChar(descBuffer[pos]));
if (pos + 1 == kInventoryDescriptionsSize) {
_inventoryDescriptions.push_back(desc);
}
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 3f8fc4436a9..df4910da95c 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -376,8 +376,8 @@ Common::Array<Description> RoomManager::loadRoomDescriptions(Common::File *roomF
while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
if (data[pos] != 0x00) {
- // debug("Description char byte: 0x%02X", data[pos]);
- description.text.append(1, decodeCPByte((byte)data[pos]));
+ // debug("Adding char 0x%02X to description, decoded as %lc", data[pos], decodeChar((byte)data[pos]));
+ description.text.append(1, decodeChar((byte)data[pos]));
}
if (data[pos] == 0xF8) {
description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
@@ -400,35 +400,6 @@ Common::Array<Description> RoomManager::loadRoomDescriptions(Common::File *roomF
return descriptions;
}
-char32_t decodeByte(byte b) {
- if (b == 0x80) {
- return '\xA4';
- } else if (b == 0x81) {
- return '\xA1';
- } else if (b == 0x82) {
- return '\xAD';
- } else if (b == 0x83) {
- return '\xA8';
- } else if (b == 0x84) {
- return '\xA3';
- } else if (b == 0x7B) {
- return '\xA0';
- } else if (b == 0x7C) {
- return '\x82';
- } else if (b == 0x7D) {
- return '\xA1';
- } else if (b == 0x7E) {
- return '\xA2';
- } else if (b == 0x7F) {
- return '\xA3';
- } else if (b >= 0x20 && b <= 0x7A) {
- return (char)b;
- } else {
- // return string in format [XX]
- return '.';
- }
-}
-
void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
int headerIndex = roomNumber;
@@ -631,7 +602,7 @@ Common::Array<ConversationElement> RoomManager::parseConversationElements(const
convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
convData[pos] != 0xF0) {
- char32_t ch = decodeByte(convData[pos]);
+ char32_t ch = decodeChar(convData[pos]);
if (ch != '.') {
text += ch;
}
@@ -676,7 +647,7 @@ Common::Array<ConversationElement> RoomManager::parseConversationElements(const
convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
convData[pos] != 0xF0) {
- char32_t ch = decodeByte(convData[pos]);
+ char32_t ch = decodeChar(convData[pos]);
if (ch != '.') {
text += ch;
}
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index bc302a8ae7d..ac0efab9cf0 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -268,7 +268,20 @@ void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color) {
}
}
-char32_t decodeCPByte(byte b) {
- return cp437_to_unicode[b];
+byte decodeChar(byte b) {
+ switch (b) {
+ case 0x82: return special_chars[1];
+ case 0x83: return special_chars[0];
+
+ case 0x80: return special_chars[3]; // n tilde
+ case 0x7F: return special_chars[4];
+ case 0x7E: return special_chars[5];
+ case 0x7D: return special_chars[6];
+ case 0x7C: return special_chars[7];
+ case 0x7B: return special_chars[8];
+ default:
+ return b;
+ }
}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 88fc9c67093..82e78cc368c 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -42,43 +42,21 @@ void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color);
Common::String printMovementFlags(uint8_t flags);
Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
-static const char32_t cp437_to_unicode[256] = {
- // 0x00 - 0x7F: ASCII (unchanged)
- 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
- 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
- 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
- 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
- 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
- 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
- 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
- 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
- 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
- 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
- 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
- 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
- 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
- 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
- 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
- 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
- // 0x80 - 0xFF: CP437 extended characters
- 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
- 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
- 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
- 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
- 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
- 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
- 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
- 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
- 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
- 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
- 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
- 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
- 0x03B1, 0x03B2, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
- 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
- 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
- 0x00B0, 0x00B7, 0x2022, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+byte decodeChar(byte b);
+
+
+static const int special_chars[] = {
+ 131, // inverted ?
+ 130, // inverted !
+ 129, // capital N tilde
+ 128, // small n tilde
+ 127, // small u tilde
+ 126, // small o tilde
+ 125, // small i tilde
+ 124, // small e tilde
+ 123, // small a tilde
};
-char32_t decodeCPByte(byte b);
+
} // End of namespace Pelrock
#endif // PELROCK_UTIL_H
Commit: 9b14c946816ddddc7fdf5f0f1f4b66102e5b18b2
https://github.com/scummvm/scummvm/commit/9b14c946816ddddc7fdf5f0f1f4b66102e5b18b2
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:22+02:00
Commit Message:
PELROCK: Room 2 palette anim
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/sound.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 54c925df455..b53375245d9 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -337,6 +337,53 @@ void PelrockEngine::frames() {
}
_smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
_smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", alfredState.x, alfredState.y, alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
+
+ if (_paletteAnim != nullptr) {
+
+ // if (_paletteAnim->curFrameCount >= _paletteAnim->speed) {
+ _paletteAnim->curFrameCount = 0;
+ if (_paletteAnim->currentR >= _paletteAnim->maxR &&
+ _paletteAnim->currentG >= _paletteAnim->maxG &&
+ _paletteAnim->currentB >= _paletteAnim->maxB) {
+ _paletteAnim->downDirection = 0;
+ } else if (_paletteAnim->currentR <= _paletteAnim->minR &&
+ _paletteAnim->currentG <= _paletteAnim->minG &&
+ _paletteAnim->currentB <= _paletteAnim->minB) {
+ _paletteAnim->downDirection = 1;
+ }
+
+ if (_paletteAnim->downDirection) {
+ if (_paletteAnim->currentR < _paletteAnim->maxR) {
+ _paletteAnim->currentR += _paletteAnim->speed;
+ }
+ if (_paletteAnim->currentG < _paletteAnim->maxG) {
+ _paletteAnim->currentG += _paletteAnim->speed;
+ }
+ if (_paletteAnim->currentB < _paletteAnim->maxB) {
+ _paletteAnim->currentB += _paletteAnim->speed;
+ }
+ } else {
+ if (_paletteAnim->currentR > _paletteAnim->minR) {
+ _paletteAnim->currentR -= _paletteAnim->speed;
+ }
+ if (_paletteAnim->currentG > _paletteAnim->minG) {
+ _paletteAnim->currentG -= _paletteAnim->speed;
+ }
+ if (_paletteAnim->currentB > _paletteAnim->minB) {
+ _paletteAnim->currentB -= _paletteAnim->speed;
+ }
+ }
+
+ _room->_roomPalette[_paletteAnim->paletteIndex * 3] = _paletteAnim->currentR;
+ _room->_roomPalette[_paletteAnim->paletteIndex * 3 + 1] = _paletteAnim->currentG;
+ _room->_roomPalette[_paletteAnim->paletteIndex * 3 + 2] = _paletteAnim->currentB;
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+
+ // } else {
+ // _paletteAnim->curFrameCount++;
+ // }
+ }
+
_screen->markAllDirty();
// _screen->update();
@@ -717,9 +764,9 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
void PelrockEngine::checkMouseClickOnSettings(int x, int y) {
bool selectedItem = false;
- for(int i = 0; i < 4; i++) {
- if(x >= 140 + (82 * i) && x <= 140 + (82 * i) + 64 &&
- y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
+ for (int i = 0; i < 4; i++) {
+ if (x >= 140 + (82 * i) && x <= 140 + (82 * i) + 64 &&
+ y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
selectedInvIndex = curInventoryPage * 4 + i;
_menuText = _res->getInventoryObject(selectedInvIndex).description;
debug("Selected inventory index: %d", selectedInvIndex);
@@ -727,17 +774,15 @@ void PelrockEngine::checkMouseClickOnSettings(int x, int y) {
return;
}
}
- if(!selectedItem) {
+ if (!selectedItem) {
selectedInvIndex = -1;
_menuText = "";
}
- if(x >= 471 && x <= 471 + 23 &&
- y >= 87 && y <= 87 + 33) {
+ if (x >= 471 && x <= 471 + 23 &&
+ y >= 87 && y <= 87 + 33) {
curInventoryPage++;
}
-
-
}
void PelrockEngine::calculateScalingMasks() {
@@ -1005,7 +1050,7 @@ void PelrockEngine::menuLoop() {
memcpy(_compositeBuffer, _res->_mainMenu, 640 * 400);
- for(int i = 0; i < 4; i++) {
+ for (int i = 0; i < 4; i++) {
int itemIndex = curInventoryPage * 4 + i;
InventoryObject item = _res->getInventoryObject(itemIndex);
drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
@@ -1668,6 +1713,15 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
// }
_room->_currentRoomNumber = number;
+
+ if (number == 2 && _paletteAnim == nullptr) { // Pelrock Mansion
+ _paletteAnim = _room->paletteAnimRoom2();
+ } else {
+ if (_paletteAnim != nullptr)
+ free(_paletteAnim);
+ _paletteAnim = nullptr;
+ }
+
_screen->markAllDirty();
roomFile.close();
delete[] background;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 5aa74d3fa86..13dde45f0cd 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -162,11 +162,15 @@ private:
int curInventoryPage = 0;
Common::String _menuText;
+ PaletteAnimFade *_paletteAnim = nullptr;
+
// JAVA
bool shouldPlayIntro = false;
GameState stateGame = INTRO;
bool gameInitialized = false;
bool screenReady = false;
+
+
// int prevDirX = 0;
// int prevDirY = 0;
// Common::String objectToShow = "";
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index df4910da95c..96d9bad83ee 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -93,6 +93,40 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
}
}
+void RoomManager::paletteAnimRoom0() {
+
+}
+
+PaletteAnimFade *RoomManager::paletteAnimRoom2() {
+ Common::File exeFile;
+
+ if (!exeFile.open("JUEGO.EXE")) {
+ debug("Could not open JUEGO.EXE for palette animation!");
+ return nullptr;
+ }
+ exeFile.seek(0x0004B860, SEEK_SET);
+ PaletteAnimFade *anim = new PaletteAnimFade();
+ anim->paletteIndex = exeFile.readByte();
+ anim->paletteMode = exeFile.readByte();
+ anim->currentR = exeFile.readByte() << 2;
+ anim->currentG = exeFile.readByte() << 2;
+ anim->currentB = exeFile.readByte() << 2;
+ anim->minR = exeFile.readByte() << 2;
+ anim->minG = exeFile.readByte() << 2;
+ anim->minB = exeFile.readByte() << 2;
+ anim->maxR = exeFile.readByte() << 2;
+ anim->maxG = exeFile.readByte() << 2;
+ anim->maxB = exeFile.readByte() << 2;
+ byte flags = exeFile.readByte();
+ anim->curFrameCount = 0;
+
+
+ // lower 5 bits are speed, bit 6 is direction
+ anim->speed = flags & 0x3F;
+ anim->downDirection = (flags & 0x40);
+ return anim;
+}
+
Common::Array<Exit> RoomManager::loadExits(Common::File *roomFile, int roomOffset) {
Common::Array<Exit> exits;
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 2d081c21e2e..573d18292f1 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -39,6 +39,9 @@ public:
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
+ void paletteAnimRoom0();
+ PaletteAnimFade *paletteAnimRoom2();
+
Common::String getRoomName(int roomNumber) {
if (roomNumber >= 0 && roomNumber < _roomNames.size()) {
return _roomNames[roomNumber];
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 22e41377808..bbea25006be 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -100,10 +100,10 @@ void SoundManager::playSound(SonidoFile sound, int volume) {
return;
}
- if (stream) {
- int channel = findFreeChannel();
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
- }
+ // if (stream) {
+ // int channel = findFreeChannel();
+ // _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
+ // }
// TODO: Play sound file
}
@@ -193,34 +193,34 @@ void SoundManager::stopMusic() {
}
void SoundManager::playMusicTrack(int trackNumber) {
- if (_currentMusicTrack == trackNumber && _isMusicPlaying) {
- // Already playing this track
- return;
- }
- _currentMusicTrack = trackNumber;
- stopMusic();
- // Open the file
- _musicFile = new Common::File();
- Common::String filename = Common::String::format("music/track%d.mp3", trackNumber);
-
- if (!_musicFile->open(Common::Path(filename))) {
- delete _musicFile;
- _musicFile = nullptr;
- return;
- }
-#ifdef USE_MAD
- Audio::SeekableAudioStream *stream = Audio::makeMP3Stream(_musicFile, DisposeAfterUse::YES);
- if (!stream) {
- _musicFile->close();
- delete _musicFile;
- _musicFile = nullptr;
- return;
- }
- Audio::AudioStream *loopStream = Audio::makeLoopingAudioStream(stream, 0);
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, loopStream, -1, _currentVolume);
- _isMusicPlaying = true;
- _musicFile = nullptr;
-#endif
+// if (_currentMusicTrack == trackNumber && _isMusicPlaying) {
+// // Already playing this track
+// return;
+// }
+// _currentMusicTrack = trackNumber;
+// stopMusic();
+// // Open the file
+// _musicFile = new Common::File();
+// Common::String filename = Common::String::format("music/track%d.mp3", trackNumber);
+
+// if (!_musicFile->open(Common::Path(filename))) {
+// delete _musicFile;
+// _musicFile = nullptr;
+// return;
+// }
+// #ifdef USE_MAD
+// Audio::SeekableAudioStream *stream = Audio::makeMP3Stream(_musicFile, DisposeAfterUse::YES);
+// if (!stream) {
+// _musicFile->close();
+// delete _musicFile;
+// _musicFile = nullptr;
+// return;
+// }
+// Audio::AudioStream *loopStream = Audio::makeLoopingAudioStream(stream, 0);
+// _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, loopStream, -1, _currentVolume);
+// _isMusicPlaying = true;
+// _musicFile = nullptr;
+// #endif
}
void SoundManager::loadSoundIndex() {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 31969c3f898..c5ae3d7911c 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -313,6 +313,23 @@ struct InventoryObject {
byte iconData[60 * 60];
};
+struct PaletteAnimFade {
+ byte paletteIndex;
+ byte paletteMode;
+ byte currentR;
+ byte currentG;
+ byte currentB;
+ byte minR;
+ byte minG;
+ byte minB;
+ byte maxR;
+ byte maxG;
+ byte maxB;
+ byte speed;
+ bool downDirection;
+ byte curFrameCount = 0;
+};
+
} // End of namespace Pelrock
#endif
Commit: 7dd082958e8b9e92c460d5594c4fdb432e2bd5d9
https://github.com/scummvm/scummvm/commit/7dd082958e8b9e92c460d5594c4fdb432e2bd5d9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:22+02:00
Commit Message:
PELROCK: Palette anim from room 0
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b53375245d9..9f564bfa9ac 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -338,45 +338,45 @@ void PelrockEngine::frames() {
_smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
_smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", alfredState.x, alfredState.y, alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
- if (_paletteAnim != nullptr) {
+ if (_paletteFadeAnim != nullptr) {
// if (_paletteAnim->curFrameCount >= _paletteAnim->speed) {
- _paletteAnim->curFrameCount = 0;
- if (_paletteAnim->currentR >= _paletteAnim->maxR &&
- _paletteAnim->currentG >= _paletteAnim->maxG &&
- _paletteAnim->currentB >= _paletteAnim->maxB) {
- _paletteAnim->downDirection = 0;
- } else if (_paletteAnim->currentR <= _paletteAnim->minR &&
- _paletteAnim->currentG <= _paletteAnim->minG &&
- _paletteAnim->currentB <= _paletteAnim->minB) {
- _paletteAnim->downDirection = 1;
+ _paletteFadeAnim->curFrameCount = 0;
+ if (_paletteFadeAnim->currentR >= _paletteFadeAnim->maxR &&
+ _paletteFadeAnim->currentG >= _paletteFadeAnim->maxG &&
+ _paletteFadeAnim->currentB >= _paletteFadeAnim->maxB) {
+ _paletteFadeAnim->downDirection = 0;
+ } else if (_paletteFadeAnim->currentR <= _paletteFadeAnim->minR &&
+ _paletteFadeAnim->currentG <= _paletteFadeAnim->minG &&
+ _paletteFadeAnim->currentB <= _paletteFadeAnim->minB) {
+ _paletteFadeAnim->downDirection = 1;
}
- if (_paletteAnim->downDirection) {
- if (_paletteAnim->currentR < _paletteAnim->maxR) {
- _paletteAnim->currentR += _paletteAnim->speed;
+ if (_paletteFadeAnim->downDirection) {
+ if (_paletteFadeAnim->currentR < _paletteFadeAnim->maxR) {
+ _paletteFadeAnim->currentR += _paletteFadeAnim->speed;
}
- if (_paletteAnim->currentG < _paletteAnim->maxG) {
- _paletteAnim->currentG += _paletteAnim->speed;
+ if (_paletteFadeAnim->currentG < _paletteFadeAnim->maxG) {
+ _paletteFadeAnim->currentG += _paletteFadeAnim->speed;
}
- if (_paletteAnim->currentB < _paletteAnim->maxB) {
- _paletteAnim->currentB += _paletteAnim->speed;
+ if (_paletteFadeAnim->currentB < _paletteFadeAnim->maxB) {
+ _paletteFadeAnim->currentB += _paletteFadeAnim->speed;
}
} else {
- if (_paletteAnim->currentR > _paletteAnim->minR) {
- _paletteAnim->currentR -= _paletteAnim->speed;
+ if (_paletteFadeAnim->currentR > _paletteFadeAnim->minR) {
+ _paletteFadeAnim->currentR -= _paletteFadeAnim->speed;
}
- if (_paletteAnim->currentG > _paletteAnim->minG) {
- _paletteAnim->currentG -= _paletteAnim->speed;
+ if (_paletteFadeAnim->currentG > _paletteFadeAnim->minG) {
+ _paletteFadeAnim->currentG -= _paletteFadeAnim->speed;
}
- if (_paletteAnim->currentB > _paletteAnim->minB) {
- _paletteAnim->currentB -= _paletteAnim->speed;
+ if (_paletteFadeAnim->currentB > _paletteFadeAnim->minB) {
+ _paletteFadeAnim->currentB -= _paletteFadeAnim->speed;
}
}
- _room->_roomPalette[_paletteAnim->paletteIndex * 3] = _paletteAnim->currentR;
- _room->_roomPalette[_paletteAnim->paletteIndex * 3 + 1] = _paletteAnim->currentG;
- _room->_roomPalette[_paletteAnim->paletteIndex * 3 + 2] = _paletteAnim->currentB;
+ _room->_roomPalette[_paletteFadeAnim->paletteIndex * 3] = _paletteFadeAnim->currentR;
+ _room->_roomPalette[_paletteFadeAnim->paletteIndex * 3 + 1] = _paletteFadeAnim->currentG;
+ _room->_roomPalette[_paletteFadeAnim->paletteIndex * 3 + 2] = _paletteFadeAnim->currentB;
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
// } else {
@@ -384,6 +384,29 @@ void PelrockEngine::frames() {
// }
}
+ if (_paletteRotateAnim != nullptr) {
+ if (_paletteRotateAnim->curFrameCount >= _paletteRotateAnim->delay) {
+ _paletteRotateAnim->curFrameCount = 0;
+ int colors = _paletteRotateAnim->paletteMode;
+ byte *paletteValues = new byte[colors * 3];
+ for (int i = 0; i < colors; i++) {
+ paletteValues[i * 3] = _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3];
+ paletteValues[i * 3 + 1] = _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3 + 1];
+ paletteValues[i * 3 + 2] = _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3 + 2];
+ }
+ for (int i = 0; i < colors; i++) {
+ int srcIndex = (i + 1) % colors;
+ _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3] = paletteValues[srcIndex * 3];
+ _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3 + 1] = paletteValues[srcIndex * 3 + 1];
+ _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3 + 2] = paletteValues[srcIndex * 3 + 2];
+ }
+
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+
+ } else {
+ _paletteRotateAnim->curFrameCount++;
+ }
+ }
_screen->markAllDirty();
// _screen->update();
@@ -1714,12 +1737,17 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
_room->_currentRoomNumber = number;
- if (number == 2 && _paletteAnim == nullptr) { // Pelrock Mansion
- _paletteAnim = _room->paletteAnimRoom2();
+ if (number == 2 && _paletteFadeAnim == nullptr) { // Pelrock Mansion
+ _paletteFadeAnim = _room->paletteAnimRoom2();
+ } else if (number == 0 && _paletteRotateAnim == nullptr) {
+ _paletteRotateAnim = _room->paletteAnimRoom0();
} else {
- if (_paletteAnim != nullptr)
- free(_paletteAnim);
- _paletteAnim = nullptr;
+ if (_paletteFadeAnim != nullptr)
+ free(_paletteFadeAnim);
+ _paletteFadeAnim = nullptr;
+ if (_paletteRotateAnim != nullptr)
+ free(_paletteRotateAnim);
+ _paletteRotateAnim = nullptr;
}
_screen->markAllDirty();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 13dde45f0cd..d3ecbbd95e8 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -162,8 +162,8 @@ private:
int curInventoryPage = 0;
Common::String _menuText;
- PaletteAnimFade *_paletteAnim = nullptr;
-
+ PaletteAnimFade *_paletteFadeAnim = nullptr;
+ PaletteAnimRotate *_paletteRotateAnim = nullptr;
// JAVA
bool shouldPlayIntro = false;
GameState stateGame = INTRO;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 96d9bad83ee..75a2014e2fd 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -93,8 +93,23 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
}
}
-void RoomManager::paletteAnimRoom0() {
+PaletteAnimRotate *RoomManager::paletteAnimRoom0() {
+ Common::File exeFile;
+ if (!exeFile.open("JUEGO.EXE")) {
+ debug("Could not open JUEGO.EXE for palette animation!");
+ return nullptr;
+ }
+ exeFile.seek(0x0004B88C, SEEK_SET);
+ PaletteAnimRotate *anim = new PaletteAnimRotate();
+ anim->paletteStartIndex = exeFile.readByte();
+ anim->paletteMode = exeFile.readByte();
+ anim->unknown = exeFile.readByte();
+ anim->delay = exeFile.readByte();
+ exeFile.read(anim->unknownBytes, 7);
+ anim->flags = exeFile.readByte();
+ exeFile.close();
+ return anim;
}
PaletteAnimFade *RoomManager::paletteAnimRoom2() {
@@ -124,6 +139,7 @@ PaletteAnimFade *RoomManager::paletteAnimRoom2() {
// lower 5 bits are speed, bit 6 is direction
anim->speed = flags & 0x3F;
anim->downDirection = (flags & 0x40);
+ exeFile.close();
return anim;
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 573d18292f1..688038f8247 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -39,7 +39,7 @@ public:
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
- void paletteAnimRoom0();
+ PaletteAnimRotate *paletteAnimRoom0();
PaletteAnimFade *paletteAnimRoom2();
Common::String getRoomName(int roomNumber) {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index c5ae3d7911c..d4d89c46bac 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -330,6 +330,17 @@ struct PaletteAnimFade {
byte curFrameCount = 0;
};
+
+struct PaletteAnimRotate {
+ byte paletteStartIndex;
+ byte paletteMode;
+ byte unknown;
+ byte delay;
+ byte unknownBytes[7];
+ byte flags;
+ byte curFrameCount = 0;
+};
+
} // End of namespace Pelrock
#endif
Commit: 9fc45ddbca79db240dd203e6a194fef6c3f5a96b
https://github.com/scummvm/scummvm/commit/9fc45ddbca79db240dd203e6a194fef6c3f5a96b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:22+02:00
Commit Message:
PELROCK: Consolidate palette animations
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 9f564bfa9ac..2a0f2fc8fe3 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -338,78 +338,80 @@ void PelrockEngine::frames() {
_smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
_smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", alfredState.x, alfredState.y, alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
- if (_paletteFadeAnim != nullptr) {
-
- // if (_paletteAnim->curFrameCount >= _paletteAnim->speed) {
- _paletteFadeAnim->curFrameCount = 0;
- if (_paletteFadeAnim->currentR >= _paletteFadeAnim->maxR &&
- _paletteFadeAnim->currentG >= _paletteFadeAnim->maxG &&
- _paletteFadeAnim->currentB >= _paletteFadeAnim->maxB) {
- _paletteFadeAnim->downDirection = 0;
- } else if (_paletteFadeAnim->currentR <= _paletteFadeAnim->minR &&
- _paletteFadeAnim->currentG <= _paletteFadeAnim->minG &&
- _paletteFadeAnim->currentB <= _paletteFadeAnim->minB) {
- _paletteFadeAnim->downDirection = 1;
- }
-
- if (_paletteFadeAnim->downDirection) {
- if (_paletteFadeAnim->currentR < _paletteFadeAnim->maxR) {
- _paletteFadeAnim->currentR += _paletteFadeAnim->speed;
- }
- if (_paletteFadeAnim->currentG < _paletteFadeAnim->maxG) {
- _paletteFadeAnim->currentG += _paletteFadeAnim->speed;
- }
- if (_paletteFadeAnim->currentB < _paletteFadeAnim->maxB) {
- _paletteFadeAnim->currentB += _paletteFadeAnim->speed;
- }
+ if (_room->_currentPaletteAnim != nullptr) {
+ if (_room->_currentPaletteAnim->paletteMode == 1) {
+ animateFadePalette(_room->_currentPaletteAnim);
} else {
- if (_paletteFadeAnim->currentR > _paletteFadeAnim->minR) {
- _paletteFadeAnim->currentR -= _paletteFadeAnim->speed;
- }
- if (_paletteFadeAnim->currentG > _paletteFadeAnim->minG) {
- _paletteFadeAnim->currentG -= _paletteFadeAnim->speed;
- }
- if (_paletteFadeAnim->currentB > _paletteFadeAnim->minB) {
- _paletteFadeAnim->currentB -= _paletteFadeAnim->speed;
- }
+ animateRotatePalette(_room->_currentPaletteAnim);
}
+ }
- _room->_roomPalette[_paletteFadeAnim->paletteIndex * 3] = _paletteFadeAnim->currentR;
- _room->_roomPalette[_paletteFadeAnim->paletteIndex * 3 + 1] = _paletteFadeAnim->currentG;
- _room->_roomPalette[_paletteFadeAnim->paletteIndex * 3 + 2] = _paletteFadeAnim->currentB;
- g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+ _screen->markAllDirty();
+ }
+}
- // } else {
- // _paletteAnim->curFrameCount++;
- // }
- }
+void PelrockEngine::animateFadePalette(PaletteAnim *anim) {
- if (_paletteRotateAnim != nullptr) {
- if (_paletteRotateAnim->curFrameCount >= _paletteRotateAnim->delay) {
- _paletteRotateAnim->curFrameCount = 0;
- int colors = _paletteRotateAnim->paletteMode;
- byte *paletteValues = new byte[colors * 3];
- for (int i = 0; i < colors; i++) {
- paletteValues[i * 3] = _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3];
- paletteValues[i * 3 + 1] = _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3 + 1];
- paletteValues[i * 3 + 2] = _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3 + 2];
- }
- for (int i = 0; i < colors; i++) {
- int srcIndex = (i + 1) % colors;
- _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3] = paletteValues[srcIndex * 3];
- _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3 + 1] = paletteValues[srcIndex * 3 + 1];
- _room->_roomPalette[(_paletteRotateAnim->paletteStartIndex + i) * 3 + 2] = paletteValues[srcIndex * 3 + 2];
- }
+ // if (_paletteAnim->curFrameCount >= _paletteAnim->speed) {
+ if (anim->data[0] >= anim->data[6] &&
+ anim->data[1] >= anim->data[7] &&
+ anim->data[2] >= anim->data[8]) {
+ anim->data[10] = 0;
+ } else if (anim->data[0] <= anim->data[3] &&
+ anim->data[1] <= anim->data[4] &&
+ anim->data[2] <= anim->data[5]) {
+ anim->data[10] = 1;
+ }
+
+ if (anim->data[10]) {
+ if (anim->data[0] < anim->data[6]) {
+ anim->data[0] += anim->data[9];
+ }
+ if (anim->data[1] < anim->data[7]) {
+ anim->data[1] += anim->data[9];
+ }
+ if (anim->data[2] < anim->data[8]) {
+ anim->data[2] += anim->data[9];
+ }
+ } else {
+ if (anim->data[0] > anim->data[3]) {
+ anim->data[0] -= anim->data[9];
+ }
+ if (anim->data[1] > anim->data[4]) {
+ anim->data[1] -= anim->data[9];
+ }
+ if (anim->data[2] > anim->data[5]) {
+ anim->data[2] -= anim->data[9];
+ }
+ }
- g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+ _room->_roomPalette[anim->startIndex * 3] = anim->data[0];
+ _room->_roomPalette[anim->startIndex * 3 + 1] = anim->data[1];
+ _room->_roomPalette[anim->startIndex * 3 + 2] = anim->data[2];
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+}
- } else {
- _paletteRotateAnim->curFrameCount++;
- }
+void PelrockEngine::animateRotatePalette(PaletteAnim *anim) {
+ if (anim->curFrameCount >= anim->data[1]) {
+ anim->curFrameCount = 0;
+ int colors = anim->paletteMode;
+ byte *paletteValues = new byte[colors * 3];
+ for (int i = 0; i < colors; i++) {
+ paletteValues[i * 3] = _room->_roomPalette[(anim->startIndex + i) * 3];
+ paletteValues[i * 3 + 1] = _room->_roomPalette[(anim->startIndex + i) * 3 + 1];
+ paletteValues[i * 3 + 2] = _room->_roomPalette[(anim->startIndex + i) * 3 + 2];
}
- _screen->markAllDirty();
+ for (int i = 0; i < colors; i++) {
+ int srcIndex = (i + 1) % colors;
+ _room->_roomPalette[(anim->startIndex + i) * 3] = paletteValues[srcIndex * 3];
+ _room->_roomPalette[(anim->startIndex + i) * 3 + 1] = paletteValues[srcIndex * 3 + 1];
+ _room->_roomPalette[(anim->startIndex + i) * 3 + 2] = paletteValues[srcIndex * 3 + 2];
+ }
+
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
- // _screen->update();
+ } else {
+ anim->curFrameCount++;
}
}
@@ -1737,19 +1739,6 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
_room->_currentRoomNumber = number;
- if (number == 2 && _paletteFadeAnim == nullptr) { // Pelrock Mansion
- _paletteFadeAnim = _room->paletteAnimRoom2();
- } else if (number == 0 && _paletteRotateAnim == nullptr) {
- _paletteRotateAnim = _room->paletteAnimRoom0();
- } else {
- if (_paletteFadeAnim != nullptr)
- free(_paletteFadeAnim);
- _paletteFadeAnim = nullptr;
- if (_paletteRotateAnim != nullptr)
- free(_paletteRotateAnim);
- _paletteRotateAnim = nullptr;
- }
-
_screen->markAllDirty();
roomFile.close();
delete[] background;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index d3ecbbd95e8..30c6c3816d8 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -91,6 +91,8 @@ private:
void drawText(Common::String text, int x, int y, int w, byte color);
void frames();
+ void animateFadePalette(PaletteAnim *anim);
+ void animateRotatePalette(PaletteAnim *anim);
void doAction(byte action, HotSpot *hotspot);
void talkTo(HotSpot *hotspot);
void lookAtHotspot(HotSpot *hotspot);
@@ -157,20 +159,17 @@ private:
bool showShadows = false;
- //Temporary
+ // Temporary
int selectedInvIndex = 0;
int curInventoryPage = 0;
Common::String _menuText;
- PaletteAnimFade *_paletteFadeAnim = nullptr;
- PaletteAnimRotate *_paletteRotateAnim = nullptr;
// JAVA
bool shouldPlayIntro = false;
GameState stateGame = INTRO;
bool gameInitialized = false;
bool screenReady = false;
-
// int prevDirX = 0;
// int prevDirY = 0;
// Common::String objectToShow = "";
@@ -235,7 +234,6 @@ public:
return syncGame(s);
}
-
void setScreen(int s, AlfredDirection dir);
};
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 75a2014e2fd..f261859bca8 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -93,52 +93,37 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
}
}
-PaletteAnimRotate *RoomManager::paletteAnimRoom0() {
+PaletteAnim *RoomManager::getPaletteAnimForRoom(int roomNumber) {
Common::File exeFile;
if (!exeFile.open("JUEGO.EXE")) {
debug("Could not open JUEGO.EXE for palette animation!");
return nullptr;
}
- exeFile.seek(0x0004B88C, SEEK_SET);
- PaletteAnimRotate *anim = new PaletteAnimRotate();
- anim->paletteStartIndex = exeFile.readByte();
- anim->paletteMode = exeFile.readByte();
- anim->unknown = exeFile.readByte();
- anim->delay = exeFile.readByte();
- exeFile.read(anim->unknownBytes, 7);
- anim->flags = exeFile.readByte();
- exeFile.close();
- return anim;
-}
-
-PaletteAnimFade *RoomManager::paletteAnimRoom2() {
- Common::File exeFile;
-
- if (!exeFile.open("JUEGO.EXE")) {
- debug("Could not open JUEGO.EXE for palette animation!");
+ uint32_t offset = 0;
+ switch (roomNumber) {
+ case 0:
+ offset = 0x0004B88C;
+ break;
+ case 2:
+ offset = 0x0004B860;
+ break;
+ default:
+ exeFile.close();
return nullptr;
}
- exeFile.seek(0x0004B860, SEEK_SET);
- PaletteAnimFade *anim = new PaletteAnimFade();
- anim->paletteIndex = exeFile.readByte();
+
+ exeFile.seek(offset, SEEK_SET);
+ PaletteAnim *anim = new PaletteAnim();
+ anim->startIndex = exeFile.readByte();
anim->paletteMode = exeFile.readByte();
- anim->currentR = exeFile.readByte() << 2;
- anim->currentG = exeFile.readByte() << 2;
- anim->currentB = exeFile.readByte() << 2;
- anim->minR = exeFile.readByte() << 2;
- anim->minG = exeFile.readByte() << 2;
- anim->minB = exeFile.readByte() << 2;
- anim->maxR = exeFile.readByte() << 2;
- anim->maxG = exeFile.readByte() << 2;
- anim->maxB = exeFile.readByte() << 2;
- byte flags = exeFile.readByte();
- anim->curFrameCount = 0;
-
-
- // lower 5 bits are speed, bit 6 is direction
- anim->speed = flags & 0x3F;
- anim->downDirection = (flags & 0x40);
+ exeFile.read(anim->data, 10);
+ if (anim->paletteMode == 1) {
+ for (int i = 2; i < 10; i++) {
+ anim->data[i] = anim->data[i] << 2;
+ }
+ }
+
exeFile.close();
return anim;
}
@@ -164,8 +149,7 @@ Common::Array<Exit> RoomManager::loadExits(Common::File *roomFile, int roomOffse
exit.targetX = roomFile->readUint16LE();
exit.targetY = roomFile->readUint16LE();
byte dir = roomFile->readByte();
- switch (dir)
- {
+ switch (dir) {
case ALFRED_RIGHT:
exit.dir = ALFRED_RIGHT;
break;
@@ -284,6 +268,15 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
Exit exit = _currentRoomExits[i];
// drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
}
+ PaletteAnim *anim = getPaletteAnimForRoom(roomNumber);
+ if (anim != nullptr) {
+ if (_currentPaletteAnim != nullptr) {
+ delete _currentPaletteAnim;
+ }
+ _currentPaletteAnim = anim;
+ } else {
+ _currentPaletteAnim = nullptr;
+ }
}
Common::Array<Sprite> RoomManager::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
@@ -345,7 +338,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(Common::File *roomFile, in
anim.nframes = animData[subAnimOffset + j];
anim.loopCount = animData[subAnimOffset + 4 + j];
anim.speed = animData[subAnimOffset + 8 + j];
- anim.movementFlags = animData[subAnimOffset + 14 + (j*2)] | (animData[subAnimOffset + 14 + (j*2) + 1] << 8);
+ anim.movementFlags = animData[subAnimOffset + 14 + (j * 2)] | (animData[subAnimOffset + 14 + (j * 2) + 1] << 8);
anim.animData = new byte[anim.nframes];
if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
uint32_t needed = anim.w * anim.h * anim.nframes;
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 688038f8247..a73b94add24 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -39,8 +39,8 @@ public:
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
- PaletteAnimRotate *paletteAnimRoom0();
- PaletteAnimFade *paletteAnimRoom2();
+
+ PaletteAnim *getPaletteAnimForRoom(int roomNumber);
Common::String getRoomName(int roomNumber) {
if (roomNumber >= 0 && roomNumber < _roomNames.size()) {
@@ -65,6 +65,7 @@ public:
byte _musicTrack = 0;
Common::Array<byte> _roomSfx;
byte _currentRoomNumber = 0;
+ PaletteAnim *_currentPaletteAnim = nullptr;
private:
Common::Array<Sprite> loadRoomAnimations(Common::File *roomFile, int roomOffset);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index d4d89c46bac..3d98e38a4be 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -314,7 +314,7 @@ struct InventoryObject {
};
struct PaletteAnimFade {
- byte paletteIndex;
+ byte startIndex;
byte paletteMode;
byte currentR;
byte currentG;
@@ -332,7 +332,7 @@ struct PaletteAnimFade {
struct PaletteAnimRotate {
- byte paletteStartIndex;
+ byte startIndex;
byte paletteMode;
byte unknown;
byte delay;
@@ -341,6 +341,13 @@ struct PaletteAnimRotate {
byte curFrameCount = 0;
};
+struct PaletteAnim {
+ byte startIndex;
+ byte paletteMode;
+ byte data[10]; // Based on mode its a rotate or fade
+ byte curFrameCount = 0;
+};
+
} // End of namespace Pelrock
#endif
Commit: e20590b5bd01ca5f159a030688c1ca5da7f5a956
https://github.com/scummvm/scummvm/commit/e20590b5bd01ca5f159a030688c1ca5da7f5a956
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:23+02:00
Commit Message:
PELROCK: Loads stickers
Changed paths:
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 66a2578af49..03311b8295c 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -50,6 +50,27 @@ static const uint32 kInventoryDescriptionsOffset = 0x4715D;
static const uint32 kInventoryDescriptionsSize = 7868;
+const uint32_t pegatina_offsets[137] = {
+ 0x000000, 0x00005B, 0x0000B6, 0x000298, 0x00047A, 0x0023C8, 0x004316, 0x004376,
+ 0x005119, 0x005EBC, 0x0083ED, 0x008529, 0x0092C4, 0x00A3AA, 0x00B490, 0x00B6A6,
+ 0x00C05A, 0x00CA0E, 0x00D3D0, 0x00D46E, 0x00F036, 0x00FB8F, 0x00FC55, 0x0119D7,
+ 0x013759, 0x01391F, 0x014A9D, 0x015C1B, 0x017601, 0x018FE7, 0x019048, 0x0190A9,
+ 0x01910A, 0x0197F4, 0x019EDE, 0x01A7EC, 0x01B0FA, 0x01B8C4, 0x01C644, 0x01D83A,
+ 0x01E104, 0x01E8C6, 0x01F45D, 0x01FBBB, 0x02011D, 0x02052F, 0x020A95, 0x020E5B,
+ 0x0210B3, 0x0216E6, 0x021D5E, 0x0233A3, 0x0249E8, 0x025777, 0x026506, 0x028E2B,
+ 0x02B82F, 0x02C9D7, 0x02E4CA, 0x02FFBD, 0x03234A, 0x0346D7, 0x036A83, 0x038E2F,
+ 0x03B18D, 0x03D4EB, 0x03DEC9, 0x03F813, 0x04115D, 0x045303, 0x0494A9, 0x04955F,
+ 0x049615, 0x0496CB, 0x0499E1, 0x049EC7, 0x04A023, 0x04A447, 0x04BA6D, 0x04BFA1,
+ 0x04CE33, 0x04CF09, 0x04DB3B, 0x052885, 0x0575CF, 0x05775B, 0x057D79, 0x058397,
+ 0x058969, 0x058F50, 0x05A9DB, 0x05C561, 0x05C72E, 0x05C8FB, 0x05EAC1, 0x060C87,
+ 0x060D19, 0x060E62, 0x061039, 0x0613C2, 0x061764, 0x061847, 0x062535, 0x062D4B,
+ 0x064F11, 0x0670D7, 0x067381, 0x0675A9, 0x0677EF, 0x067A98, 0x067DDE, 0x068115,
+ 0x0684E3, 0x068A76, 0x068F30, 0x0693C8, 0x0696AD, 0x06C2C9, 0x06C84D, 0x07095D,
+ 0x071854, 0x07274B, 0x073642, 0x074539, 0x075454, 0x0791DA, 0x07CF60, 0x07E4AB,
+ 0x07ECED, 0x07F52F, 0x07FD71, 0x080591, 0x080B24, 0x080B84, 0x080F39, 0x0812F5,
+ 0x0816B1
+};
+
// Description offsets relative to DESCRIPTION_BASE_OFFSET
const uint16_t description_offsets[NUM_DESCRIPTIONS] = {
0x0000, // Object 0: Historia de la Princesa Zenna y su amante insatisfecho
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 2a0f2fc8fe3..93c03eb230b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -418,10 +418,13 @@ void PelrockEngine::animateRotatePalette(PaletteAnim *anim) {
void PelrockEngine::doAction(byte action, HotSpot *hotspot) {
switch (action) {
case LOOK:
- lookAtHotspot(_currentHotspot);
+ lookAt(hotspot);
break;
case TALK:
- talkTo(_currentHotspot);
+ talkTo(hotspot);
+ break;
+ case OPEN:
+ open(hotspot);
break;
default:
break;
@@ -457,13 +460,25 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
// }
}
-void PelrockEngine::lookAtHotspot(HotSpot *hotspot) {
+void PelrockEngine::lookAt(HotSpot *hotspot) {
debug("Look action clicked");
walkTo(_currentHotspot->x, _currentHotspot->y);
sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index].text);
_displayPopup = false;
}
+void PelrockEngine::open(HotSpot *hotspot) {
+ switch (hotspot->extra)
+ {
+ case 261:
+ _room->placeSticker(_res->getSticker(91), _currentBackground);
+ break;
+
+ default:
+ break;
+ }
+}
+
void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, int baseX, int baseY) {
int maxW = 0;
@@ -782,7 +797,7 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
_displayPopup = true;
_currentPopupFrame = 0;
_currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
- debug("Current hotspot type: %d", _currentHotspot->type);
+ debug("Current hotspot (x=%d, y=%d) with extra = %d type: %d, desc= %s", _currentHotspot->x, _currentHotspot->y, _currentHotspot->extra, _currentHotspot->type, _room->_currentRoomDescriptions[_currentHotspot->index].text.c_str());
}
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 30c6c3816d8..83f23136b46 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -95,7 +95,8 @@ private:
void animateRotatePalette(PaletteAnim *anim);
void doAction(byte action, HotSpot *hotspot);
void talkTo(HotSpot *hotspot);
- void lookAtHotspot(HotSpot *hotspot);
+ void lookAt(HotSpot *hotspot);
+ void open(HotSpot *hotspot);
void renderText(Common::Array<Common::String> lines, int color, int x, int y);
void chooseAlfredStateAndDraw();
void drawAlfred(byte *buf);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index c5da7da9312..b79af08c68d 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -235,6 +235,25 @@ void ResourceManager::loadInventoryItems() {
delete[] iconData;
}
+Pelrock::Sticker ResourceManager::getSticker(int stickerIndex) {
+ Common::File alfred6File;
+ if (!alfred6File.open("ALFRED.6")) {
+ error("Couldnt find file ALFRED.6");
+ }
+
+ uint32 stickerOffset = pegatina_offsets[stickerIndex];
+ alfred6File.seek(stickerOffset, SEEK_SET);
+ Sticker sticker;
+ sticker.x = alfred6File.readUint16LE();
+ sticker.y = alfred6File.readUint16LE();
+ sticker.w = alfred6File.readByte();
+ sticker.h = alfred6File.readByte();
+ sticker.stickerData = new byte[sticker.w * sticker.h];
+ alfred6File.read(sticker.stickerData, sticker.w * sticker.h);
+ alfred6File.close();
+ return sticker;
+}
+
void ResourceManager::loadInventoryDescriptions() {
Common::File exe;
if (!exe.open("JUEGO.EXE")) {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 9b54652f76f..dc7d70c7602 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -45,6 +45,7 @@ public:
void loadInteractionIcons();
void loadAlfredAnims();
void loadInventoryItems();
+ Sticker getSticker(int stickerIndex);
InventoryObject getInventoryObject(byte index);
byte *loadExtra();
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index f261859bca8..103d4189ee5 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -93,6 +93,21 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
}
}
+void RoomManager::placeSticker(Sticker sticker, byte *background) {
+ for (int y = 0; y < sticker.h; y++) {
+ for (int x = 0; x < sticker.w; x++) {
+ byte pixel = sticker.stickerData[y * sticker.w + x];
+ if (pixel != 0) {
+ int bgX = sticker.x + x;
+ int bgY = sticker.y + y;
+ if (bgX >= 0 && bgX < 640 && bgY >= 0 && bgY < 400) {
+ background[bgY * 640 + bgX] = pixel;
+ }
+ }
+ }
+ }
+}
+
PaletteAnim *RoomManager::getPaletteAnimForRoom(int roomNumber) {
Common::File exeFile;
@@ -174,7 +189,7 @@ Common::Array<Exit> RoomManager::loadExits(Common::File *roomFile, int roomOffse
Common::Array<HotSpot> RoomManager::loadHotspots(Common::File *roomFile, int roomOffset) {
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- // debug("Hotspot(10) pair offset position: %d", pair10_offset_pos);
+
roomFile->seek(pair10_offset_pos, SEEK_SET);
uint32_t pair10_data_offset = roomFile->readUint32LE();
uint32_t pair10_size = roomFile->readUint32LE();
@@ -193,17 +208,15 @@ Common::Array<HotSpot> RoomManager::loadHotspots(Common::File *roomFile, int roo
spot.w = roomFile->readByte();
spot.h = roomFile->readByte();
spot.extra = roomFile->readUint16LE();
- // debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
+ debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
hotspots.push_back(spot);
}
return hotspots;
- // uint32_t hover_areas_start = pair10_data_offset + 0x1BE;
- // roomFile->seek(hover_areas_start, SEEK_SET);
}
void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
uint32_t outPos = 0;
-
+ _currentRoomStickers.clear();
int roomOffset = roomNumber * kRoomStructSize;
Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
// debug("After decsriptions, position is %d", outPos);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index a73b94add24..c2552e87866 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -39,7 +39,7 @@ public:
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
-
+ void placeSticker(Sticker sticker, byte *background);
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
Common::String getRoomName(int roomNumber) {
@@ -66,6 +66,7 @@ public:
Common::Array<byte> _roomSfx;
byte _currentRoomNumber = 0;
PaletteAnim *_currentPaletteAnim = nullptr;
+ Common::Array<Sticker> _currentRoomStickers;
private:
Common::Array<Sprite> loadRoomAnimations(Common::File *roomFile, int roomOffset);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 3d98e38a4be..4bc5ffce333 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -330,6 +330,15 @@ struct PaletteAnimFade {
byte curFrameCount = 0;
};
+struct Sticker
+{
+ uint16 x;
+ uint16 y;
+ byte w;
+ byte h;
+ byte *stickerData;
+};
+
struct PaletteAnimRotate {
byte startIndex;
Commit: a3fb1e4e1cf47390a3d3f198d25e18ad63e85956
https://github.com/scummvm/scummvm/commit/a3fb1e4e1cf47390a3d3f198d25e18ad63e85956
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:23+02:00
Commit Message:
PELROCK: Refactor pathfinding into its own module
Changed paths:
A engines/pelrock/pathfinding.cpp
A engines/pelrock/pathfinding.h
engines/pelrock/chrono.cpp
engines/pelrock/chrono.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index cb1d1b33848..1538240f90b 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -37,12 +37,6 @@ ChronoManager::~ChronoManager() {
void ChronoManager::updateChrono() {
uint32 currentTime = g_system->getMillis();
- if (_textTtl > 0 && countTextDown) {
- _textTtl -= (currentTime - _lastTick);
- if (_textTtl < 0)
- _textTtl = 0;
- }
-
if ((currentTime - _lastTick) >= kTickMs / _speedMultiplier) {
_gameTick = true;
_tickCount++;
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 37d096f4dbd..649ab9a0391 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -49,7 +49,6 @@ public:
void waitForKey();
bool _gameTick = false;
- long _textTtl = 0;
bool countTextDown = false;
};
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index f6b1579cff6..f919cdf363f 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -11,7 +11,8 @@ MODULE_OBJS = \
util.o \
resources.o\
sound.o \
- video/video.o
+ video/video.o \
+ pathfinding.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
new file mode 100644
index 00000000000..32254c551d3
--- /dev/null
+++ b/engines/pelrock/pathfinding.cpp
@@ -0,0 +1,394 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "common/debug.h"
+#include "common/scummsys.h"
+
+#include "pelrock/pathfinding.h"
+#include "pelrock/util.h"
+
+namespace Pelrock {
+
+Common::String printMovementFlags(uint8_t flags) {
+ Common::String result;
+ if (flags & MOVE_HORIZ) {
+ result += "HORIZ ";
+ }
+ if (flags & MOVE_VERT) {
+ result += "VERT ";
+ }
+ if (flags & MOVE_DOWN) {
+ result += "DOWN ";
+ }
+ if (flags & MOVE_LEFT) {
+ result += "LEFT ";
+ }
+ if (flags & MOVE_UP) {
+ result += "UP ";
+ }
+ if (flags & MOVE_RIGHT) {
+ result += "RIGHT ";
+ }
+ return result;
+}
+
+bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<WalkBox> &walkboxes, PathContext *context) {
+
+ if (context->pathBuffer == NULL) {
+ context->pathBuffer = (uint8_t *)malloc(MAX_PATH_LENGTH);
+ }
+ if (context->movementBuffer == NULL) {
+ context->movementBuffer = (MovementStep *)malloc(MAX_MOVEMENT_STEPS * sizeof(MovementStep));
+ }
+
+ int startX = sourceX;
+ int startY = sourceY;
+ Common::Point target = calculateWalkTarget(walkboxes, targetX, targetY);
+ targetX = target.x;
+ targetY = target.y;
+ debug("Startx= %d, starty= %d, destx= %d, desty= %d", startX, startY, targetX, targetY);
+
+ uint8_t startBox = findWalkboxForPoint(walkboxes, startX, startY);
+ uint8_t destBox = findWalkboxForPoint(walkboxes, targetX, targetY);
+
+ debug("Pathfinding from (%d, %d) in box %d to (%d, %d) in box %d\n", startX, startY, startBox, targetX, targetY, destBox);
+ // Check if both points are in valid walkboxes
+ if (startBox == 0xFF || destBox == 0xFF) {
+ debug("Error: Start or destination not in any walkbox\n");
+ return false;
+ }
+ // Special case: same walkbox
+ if (startBox == destBox) {
+ // Generate direct movement
+ MovementStep direct_step;
+ direct_step.flags = 0;
+ if (startX < targetX) {
+ direct_step.distanceX = targetX - startX;
+ direct_step.flags |= MOVE_RIGHT;
+ } else {
+ direct_step.distanceX = startX - targetX;
+ direct_step.flags |= MOVE_LEFT;
+ }
+
+ if (startY < targetY) {
+ direct_step.distanceY = targetY - startY;
+ direct_step.flags |= MOVE_DOWN;
+ } else {
+ direct_step.distanceY = startY - targetY;
+ direct_step.flags |= MOVE_UP;
+ }
+
+ context->movementBuffer[0] = direct_step;
+ context->movementCount = 1;
+ } else {
+ // Build walkbox path
+ context->pathLength = buildWalkboxPath(walkboxes, startBox, destBox, context->pathBuffer);
+ debug("Walkbox path to point");
+ for (int i = 0; i < context->pathLength; i++) {
+ debug("Walkbox %d: %d", i, context->pathBuffer[i]);
+ }
+ if (context->pathLength == 0) {
+ debug("Error: No path found\n");
+ return false;
+ }
+
+ // Generate movement steps
+ context->movementCount = generateMovementSteps(walkboxes, context->pathBuffer, context->pathLength, startX, startY, targetX, targetY, context->movementBuffer);
+ // for (int i = 0; i < context->movementCount; i++) {
+ // debug("Movement step %d: flags=\"%s\", dx=%d, dy=%d", i, printMovementFlags(context->movementBuffer[i].flags).c_str(), context->movementBuffer[i].distanceX, context->movementBuffer[i].distanceY);
+ // }
+ }
+ return true;
+}
+
+Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes, int x, int y) {
+ // Starting point for pathfinding
+ int sourceX = x;
+ int sourceY = y;
+
+ // TODO: If hovering over a sprite/hotspot, adjust source point to sprite center
+ // For now, just use mouse position
+
+ // Find nearest walkable point in walkboxes
+ uint32 minDistance = 0xFFFFFFFF;
+ Common::Point bestTarget(sourceX, sourceY);
+
+ for (size_t i = 0; i < walkboxes.size(); i++) {
+
+ // Calculate distance from source point to this walkbox (Manhattan distance)
+ int dx = 0;
+ int dy = 0;
+
+ // Calculate horizontal distance
+ if (sourceX < walkboxes[i].x) {
+ dx = walkboxes[i].x - sourceX;
+ } else if (sourceX > walkboxes[i].x + walkboxes[i].w) {
+ dx = sourceX - (walkboxes[i].x + walkboxes[i].w);
+ }
+ // else: sourceX is inside walkbox horizontally, dx = 0
+
+ // Calculate vertical distance
+ if (sourceY < walkboxes[i].y) {
+ dy = walkboxes[i].y - sourceY;
+ } else if (sourceY > walkboxes[i].y + walkboxes[i].h) {
+ dy = sourceY - (walkboxes[i].y + walkboxes[i].h);
+ }
+ // else: sourceY is inside walkbox vertically, dy = 0
+
+ uint32 distance = dx + dy;
+
+ if (distance < minDistance) {
+ minDistance = distance;
+
+ // Calculate target point (nearest point on walkbox to source)
+ int targetX = sourceX;
+ int targetY = sourceY;
+
+ if (sourceX < walkboxes[i].x) {
+ targetX = walkboxes[i].x;
+ } else if (sourceX > walkboxes[i].x + walkboxes[i].w) {
+ targetX = walkboxes[i].x + walkboxes[i].w;
+ }
+
+ if (sourceY < walkboxes[i].y) {
+ targetY = walkboxes[i].y;
+ } else if (sourceY > walkboxes[i].y + walkboxes[i].h) {
+ targetY = walkboxes[i].y + walkboxes[i].h;
+ }
+
+ bestTarget.x = targetX;
+ bestTarget.y = targetY;
+ }
+ }
+
+ return bestTarget;
+}
+
+uint8_t findWalkboxForPoint(Common::Array<WalkBox> &walkboxes, uint16_t x, uint16_t y) {
+ for (uint8_t i = 0; i < walkboxes.size(); i++) {
+ if (isPointInWalkbox(&walkboxes[i], x, y)) {
+ return i;
+ }
+ }
+ return 0xFF; // Not found
+}
+
+bool isPointInWalkbox(WalkBox *box, uint16_t x, uint16_t y) {
+ return (x >= box->x &&
+ x <= box->x + box->w &&
+ y >= box->y &&
+ y <= box->y + box->h);
+}
+
+/**
+ * Check if two walkboxes overlap or touch (are adjacent)
+ */
+bool areWalkboxesAdjacent(WalkBox *box1, WalkBox *box2) {
+ uint16_t box1_x_max = box1->x + box1->w;
+ uint16_t box1_y_max = box1->y + box1->h;
+ uint16_t box2_x_max = box2->x + box2->w;
+ uint16_t box2_y_max = box2->y + box2->h;
+
+ // Check if X ranges overlap
+ bool xOverlap = (box1->x <= box2_x_max) && (box2->x <= box1_x_max);
+
+ // Check if Y ranges overlap
+ bool yOverlap = (box1->y <= box2_y_max) && (box2->y <= box1_y_max);
+
+ return xOverlap && yOverlap;
+}
+
+uint8_t getAdjacentWalkbox(Common::Array<WalkBox> &walkboxes, uint8_t currentBoxIndex) {
+ WalkBox *currentBox = &walkboxes[currentBoxIndex];
+
+ // Mark current walkbox as visited
+ currentBox->flags = 0x01;
+
+ // Search for adjacent unvisited walkbox
+ for (uint8_t i = 0; i < walkboxes.size(); i++) {
+ // Skip current walkbox
+ if (i == currentBoxIndex) {
+ continue;
+ }
+
+ // Skip already visited walkboxes
+ if (walkboxes[i].flags == 0x01) {
+ continue;
+ }
+
+ // Check if walkboxes are adjacent
+ if (areWalkboxesAdjacent(currentBox, &walkboxes[i])) {
+ return i;
+ }
+ }
+
+ return 0xFF; // No adjacent walkbox found
+}
+
+void clearVisitedFlags(Common::Array<WalkBox> &walkboxes) {
+ for (int i = 0; i < walkboxes.size(); i++) {
+ walkboxes[i].flags = 0;
+ }
+}
+
+uint16_t buildWalkboxPath(Common::Array<WalkBox> &walkboxes, uint8_t startBox, uint8_t destBox, uint8_t *pathBuffer) {
+
+ uint16_t pathIndex = 0;
+ uint8_t currentBox = startBox;
+
+ // Initialize path with start walkbox
+ pathBuffer[pathIndex++] = startBox;
+
+ // Clear visited flags
+ clearVisitedFlags(walkboxes);
+
+ // Breadth-first search through walkboxes
+ while (currentBox != destBox && pathIndex < MAX_PATH_LENGTH - 1) {
+ uint8_t nextBox = getAdjacentWalkbox(walkboxes, currentBox);
+
+ if (nextBox == 0xFF) {
+ // Dead end - backtrack
+ if (pathIndex > 1) {
+ pathIndex--;
+ currentBox = pathBuffer[pathIndex - 1];
+ } else {
+ // No path exists
+ return 0;
+ }
+ } else if (nextBox == destBox) {
+ // Found destination
+ pathBuffer[pathIndex++] = destBox;
+ break;
+ } else {
+ // Continue searching
+ pathBuffer[pathIndex++] = nextBox;
+ currentBox = nextBox;
+ }
+ }
+
+ // Terminate path
+ pathBuffer[pathIndex] = PATH_END;
+ debug("Built walkbox path of length %d", pathIndex);
+ return pathIndex;
+}
+
+/**
+ * Calculate movement needed to reach a target within a walkbox
+ */
+void calculateMovementToTarget(uint16_t currentX, uint16_t currentY, uint16_t targetX, uint16_t targetY, WalkBox *box, MovementStep *step) {
+ step->flags = 0;
+ step->distanceX = 0;
+ step->distanceY = 0;
+
+ // Calculate horizontal movement
+ if (currentX < box->x) {
+ // Need to move right to enter walkbox
+ step->distanceX = box->x - currentX;
+ step->flags |= MOVE_RIGHT;
+ } else if (currentX > box->x + box->w) {
+ // Need to move left to enter walkbox
+ step->distanceX = currentX - (box->x + box->w);
+ step->flags |= MOVE_LEFT;
+ }
+
+ // Calculate vertical movement
+ if (currentY < box->y) {
+ // Need to move down to enter walkbox
+ step->distanceY = box->y - currentY;
+ step->flags |= MOVE_DOWN;
+ } else if (currentY > box->y + box->h) {
+ // Need to move up to enter walkbox
+ step->distanceY = currentY - (box->y + box->h);
+ step->flags |= MOVE_UP;
+ }
+}
+
+/**
+ * Generate movement steps from walkbox path
+ * Returns: number of movement steps generated
+ */
+uint16_t generateMovementSteps(Common::Array<WalkBox> &walkboxes,
+ uint8_t *pathBuffer,
+ uint16_t pathLength,
+ uint16_t startX, uint16_t startY,
+ uint16_t destX, uint16_t destY,
+ MovementStep *movementBuffer) {
+ uint16_t currentX = startX;
+ uint16_t currentY = startY;
+ uint16_t movementIndex = 0;
+
+ // Generate movements for each walkbox in path
+ for (uint16_t i = 0; i < pathLength && pathBuffer[i] != PATH_END; i++) {
+ uint8_t boxIndex = pathBuffer[i];
+ WalkBox *box = &walkboxes[boxIndex];
+
+ MovementStep step;
+ calculateMovementToTarget(currentX, currentY, destX, destY, box, &step);
+
+ if (step.distanceX > 0 || step.distanceY > 0) {
+ movementBuffer[movementIndex++] = step;
+
+ // Update current position
+ if (step.flags & MOVE_RIGHT) {
+ currentX = box->x;
+ } else if (step.flags & MOVE_LEFT) {
+ currentX = box->x + box->w;
+ }
+
+ if (step.flags & MOVE_DOWN) {
+ currentY = box->y;
+ } else if (step.flags & MOVE_UP) {
+ currentY = box->y + box->h;
+ }
+ }
+ }
+
+ // Final movement to exact destination
+ MovementStep final_step;
+ final_step.flags = 0;
+
+ if (currentX < destX) {
+ final_step.distanceX = destX - currentX;
+ final_step.flags |= MOVE_RIGHT;
+ } else if (currentX > destX) {
+ final_step.distanceX = currentX - destX;
+ final_step.flags |= MOVE_LEFT;
+ } else {
+ final_step.distanceX = 0;
+ }
+
+ if (currentY < destY) {
+ final_step.distanceY = destY - currentY;
+ final_step.flags |= MOVE_DOWN;
+ } else if (currentY > destY) {
+ final_step.distanceY = currentY - destY;
+ final_step.flags |= MOVE_UP;
+ } else {
+ final_step.distanceY = 0;
+ }
+
+ if (final_step.distanceX > 0 || final_step.distanceY > 0) {
+ movementBuffer[movementIndex++] = final_step;
+ }
+
+ return movementIndex;
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/pathfinding.h b/engines/pelrock/pathfinding.h
new file mode 100644
index 00000000000..cb33de23d29
--- /dev/null
+++ b/engines/pelrock/pathfinding.h
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_PATHFINDING_H
+#define PELROCK_PATHFINDING_H
+
+#include "common/scummsys.h"
+#include "graphics/screen.h"
+
+#include "pelrock/types.h"
+
+namespace Pelrock {
+bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<WalkBox> &walkboxes, PathContext *context);
+
+Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes, int x, int y);
+uint8_t findWalkboxForPoint(Common::Array<WalkBox> &walkboxes, uint16_t x, uint16_t y);
+uint8_t getAdjacentWalkbox(Common::Array<WalkBox> &walkboxes, uint8_t current_box_index);
+uint16_t buildWalkboxPath(Common::Array<WalkBox> &walkboxes, uint8_t start_box, uint8_t dest_box, uint8_t *path_buffer);
+uint16_t generateMovementSteps(Common::Array<WalkBox> &walkboxes, uint8_t *path_buffer, uint16_t path_length, uint16_t start_x, uint16_t start_y, uint16_t dest_x, uint16_t dest_y, MovementStep *movement_buffer);
+bool isPointInWalkbox(WalkBox *box, uint16_t x, uint16_t y);
+void clearVisitedFlags(Common::Array<WalkBox> &walkboxes);
+
+} // End of namespace Pelrock
+
+#endif // PELROCK_PATHFINDING_H
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 93c03eb230b..099a8108744 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -40,6 +40,7 @@
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
+#include "pelrock/pathfinding.h"
namespace Pelrock {
@@ -107,6 +108,7 @@ Common::Error PelrockEngine::run() {
init();
while (!shouldQuit()) {
+
if (stateGame == SETTINGS) {
changeCursor(DEFAULT);
menuLoop();
@@ -236,7 +238,7 @@ void sortAnimsByZOrder(Common::Array<Sprite> &anims) {
}
}
-void PelrockEngine::frames() {
+void PelrockEngine::renderScene() {
if (_chronoManager->_gameTick) {
@@ -290,7 +292,7 @@ void PelrockEngine::frames() {
if (alfredState.animState != ALFRED_WALKING && !_currentTextPages.empty()) {
_chronoManager->countTextDown = true;
- if (_chronoManager->_textTtl > 0) {
+ if (_textDurationFrames-- > 0) {
if (alfredState.animState == ALFRED_TALKING) {
_textPos = Common::Point(alfredState.x, alfredState.y - kAlfredFrameHeight - 10);
}
@@ -302,7 +304,7 @@ void PelrockEngine::frames() {
for (int i = 0; i < _currentTextPages[_currentTextPageIndex].size(); i++) {
totalChars += _currentTextPages[_currentTextPageIndex][i].size();
}
- _chronoManager->_textTtl = totalChars * kTextCharDisplayTime;
+ _textDurationFrames = totalChars / 2;
} else {
_currentTextPages.clear();
_currentTextPageIndex = 0;
@@ -502,34 +504,34 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
MovementStep step = _currentContext.movementBuffer[_currentStep];
- if (step.distance_x > 0) {
+ if (step.distanceX > 0) {
if (step.flags & MOVE_RIGHT) {
alfredState.direction = ALFRED_RIGHT;
- alfredState.x += MIN(alfredState.movementSpeed, step.distance_x);
+ alfredState.x += MIN(alfredState.movementSpeed, step.distanceX);
}
if (step.flags & MOVE_LEFT) {
alfredState.direction = ALFRED_LEFT;
- alfredState.x -= MIN(alfredState.movementSpeed, step.distance_x);
+ alfredState.x -= MIN(alfredState.movementSpeed, step.distanceX);
}
}
- if (step.distance_y > 0) {
+ if (step.distanceY > 0) {
if (step.flags & MOVE_DOWN) {
alfredState.direction = ALFRED_DOWN;
- alfredState.y += MIN(alfredState.movementSpeed, step.distance_y);
+ alfredState.y += MIN(alfredState.movementSpeed, step.distanceY);
}
if (step.flags & MOVE_UP) {
alfredState.direction = ALFRED_UP;
- alfredState.y -= MIN(alfredState.movementSpeed, step.distance_y);
+ alfredState.y -= MIN(alfredState.movementSpeed, step.distanceY);
}
}
- if (step.distance_x > 0)
- step.distance_x -= MIN(alfredState.movementSpeed, step.distance_x);
+ if (step.distanceX > 0)
+ step.distanceX -= MIN(alfredState.movementSpeed, step.distanceX);
- if (step.distance_y > 0)
- step.distance_y -= MIN(alfredState.movementSpeed, step.distance_y);
+ if (step.distanceY > 0)
+ step.distanceY -= MIN(alfredState.movementSpeed, step.distanceY);
- if (step.distance_x <= 0 && step.distance_y <= 0) {
+ if (step.distanceX <= 0 && step.distanceY <= 0) {
_currentStep++;
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
@@ -1012,6 +1014,12 @@ void PelrockEngine::drawTalkNPC(Sprite *animSet) {
drawSpriteToBuffer(_compositeBuffer, 640, frame, x, y, w, h, 255);
}
+void PelrockEngine::conversationLoop() {
+ while(inConversation) {
+
+ }
+}
+
void PelrockEngine::gameLoop() {
_chronoManager->updateChrono();
Common::Event e;
@@ -1072,7 +1080,12 @@ void PelrockEngine::gameLoop() {
}
}
checkMouseHover();
- frames();
+
+ if(inConversation) {
+ conversationLoop();
+ } else {
+ renderScene();
+ }
}
void PelrockEngine::menuLoop() {
@@ -1106,293 +1119,12 @@ void PelrockEngine::menuLoop() {
void PelrockEngine::walkTo(int x, int y) {
_currentStep = 0;
PathContext context = {nullptr, nullptr, nullptr, 0, 0, 0};
- pathFind(x, y, &context);
+ findPath(alfredState.x, alfredState.y, x, y, _room->_currentRoomWalkboxes, &context);
_currentContext = context;
alfredState.animState = ALFRED_WALKING;
alfredState.curFrame = 0;
}
-bool PelrockEngine::pathFind(int targetX, int targetY, PathContext *context) {
-
- if (context->pathBuffer == NULL) {
- context->pathBuffer = (uint8_t *)malloc(MAX_PATH_LENGTH);
- }
- if (context->movementBuffer == NULL) {
- context->movementBuffer = (MovementStep *)malloc(MAX_MOVEMENT_STEPS * sizeof(MovementStep));
- }
-
- int startX = alfredState.x;
- int startY = alfredState.y;
- Common::Point target = calculateWalkTarget(targetX, targetY);
- targetX = target.x;
- targetY = target.y;
- debug("Startx= %d, starty= %d, destx= %d, desty= %d", startX, startY, targetX, targetY);
-
- uint8_t startBox = findWalkboxForPoint(startX, startY);
- uint8_t destBox = findWalkboxForPoint(targetX, targetY);
-
- debug("Pathfinding from (%d, %d) in box %d to (%d, %d) in box %d\n", startX, startY, startBox, targetX, targetY, destBox);
- // Check if both points are in valid walkboxes
- if (startBox == 0xFF || destBox == 0xFF) {
- debug("Error: Start or destination not in any walkbox\n");
- return false;
- }
- // Special case: same walkbox
- if (startBox == destBox) {
- // Generate direct movement
- MovementStep direct_step;
- direct_step.flags = 0;
- if (startX < targetX) {
- direct_step.distance_x = targetX - startX;
- direct_step.flags |= MOVE_RIGHT;
- } else {
- direct_step.distance_x = startX - targetX;
- direct_step.flags |= MOVE_LEFT;
- }
-
- if (startY < targetY) {
- direct_step.distance_y = targetY - startY;
- direct_step.flags |= MOVE_DOWN;
- } else {
- direct_step.distance_y = startY - targetY;
- direct_step.flags |= MOVE_UP;
- }
-
- context->movementBuffer[0] = direct_step;
- context->movementCount = 1;
- } else {
- // Build walkbox path
- context->pathLength = buildWalkboxPath(startBox, destBox, context->pathBuffer);
- debug("Walkbox path to point");
- for (int i = 0; i < context->pathLength; i++) {
- debug("Walkbox %d: %d", i, context->pathBuffer[i]);
- }
- if (context->pathLength == 0) {
- debug("Error: No path found\n");
- return false;
- }
-
- // Generate movement steps
- context->movementCount = generateMovementSteps(context->pathBuffer, context->pathLength, startX, startY, targetX, targetY, context->movementBuffer);
- for (int i = 0; i < context->movementCount; i++) {
- debug("Movement step %d: flags=\"%s\", dx=%d, dy=%d", i, printMovementFlags(context->movementBuffer[i].flags).c_str(), context->movementBuffer[i].distance_x, context->movementBuffer[i].distance_y);
- }
- }
- return true;
-}
-
-/**
- * Calculate movement needed to reach a target within a walkbox
- */
-void calculateMovementToTarget(uint16_t current_x, uint16_t current_y,
- uint16_t target_x, uint16_t target_y,
- WalkBox *box,
- MovementStep *step) {
- step->flags = 0;
- step->distance_x = 0;
- step->distance_y = 0;
-
- // Calculate horizontal movement
- if (current_x < box->x) {
- // Need to move right to enter walkbox
- step->distance_x = box->x - current_x;
- step->flags |= MOVE_RIGHT;
- } else if (current_x > box->x + box->w) {
- // Need to move left to enter walkbox
- step->distance_x = current_x - (box->x + box->w);
- step->flags |= MOVE_LEFT;
- }
-
- // Calculate vertical movement
- if (current_y < box->y) {
- // Need to move down to enter walkbox
- step->distance_y = box->y - current_y;
- step->flags |= MOVE_DOWN;
- } else if (current_y > box->y + box->h) {
- // Need to move up to enter walkbox
- step->distance_y = current_y - (box->y + box->h);
- step->flags |= MOVE_UP;
- }
-}
-
-/**
- * Generate movement steps from walkbox path
- * Returns: number of movement steps generated
- */
-uint16_t PelrockEngine::generateMovementSteps(uint8_t *pathBuffer,
- uint16_t pathLength,
- uint16_t startX, uint16_t startY,
- uint16_t destX, uint16_t destY,
- MovementStep *movementBuffer) {
- uint16_t currentX = startX;
- uint16_t currentY = startY;
- uint16_t movementIndex = 0;
-
- // Generate movements for each walkbox in path
- for (uint16_t i = 0; i < pathLength && pathBuffer[i] != PATH_END; i++) {
- uint8_t boxIndex = pathBuffer[i];
- WalkBox *box = &_room->_currentRoomWalkboxes[boxIndex];
-
- MovementStep step;
- calculateMovementToTarget(currentX, currentY, destX, destY, box, &step);
-
- if (step.distance_x > 0 || step.distance_y > 0) {
- movementBuffer[movementIndex++] = step;
-
- // Update current position
- if (step.flags & MOVE_RIGHT) {
- currentX = box->x;
- } else if (step.flags & MOVE_LEFT) {
- currentX = box->x + box->w;
- }
-
- if (step.flags & MOVE_DOWN) {
- currentY = box->y;
- } else if (step.flags & MOVE_UP) {
- currentY = box->y + box->h;
- }
- }
- }
-
- // Final movement to exact destination
- MovementStep final_step;
- final_step.flags = 0;
-
- if (currentX < destX) {
- final_step.distance_x = destX - currentX;
- final_step.flags |= MOVE_RIGHT;
- } else if (currentX > destX) {
- final_step.distance_x = currentX - destX;
- final_step.flags |= MOVE_LEFT;
- } else {
- final_step.distance_x = 0;
- }
-
- if (currentY < destY) {
- final_step.distance_y = destY - currentY;
- final_step.flags |= MOVE_DOWN;
- } else if (currentY > destY) {
- final_step.distance_y = currentY - destY;
- final_step.flags |= MOVE_UP;
- } else {
- final_step.distance_y = 0;
- }
-
- if (final_step.distance_x > 0 || final_step.distance_y > 0) {
- movementBuffer[movementIndex++] = final_step;
- }
-
- return movementIndex;
-}
-
-uint16_t PelrockEngine::buildWalkboxPath(uint8_t startBox, uint8_t destBox, uint8_t *pathBuffer) {
-
- uint16_t pathIndex = 0;
- uint8_t currentBox = startBox;
-
- // Initialize path with start walkbox
- pathBuffer[pathIndex++] = startBox;
-
- // Clear visited flags
- clearVisitedFlags();
-
- // Breadth-first search through walkboxes
- while (currentBox != destBox && pathIndex < MAX_PATH_LENGTH - 1) {
- uint8_t nextBox = getAdjacentWalkbox(currentBox);
-
- if (nextBox == 0xFF) {
- // Dead end - backtrack
- if (pathIndex > 1) {
- pathIndex--;
- currentBox = pathBuffer[pathIndex - 1];
- } else {
- // No path exists
- return 0;
- }
- } else if (nextBox == destBox) {
- // Found destination
- pathBuffer[pathIndex++] = destBox;
- break;
- } else {
- // Continue searching
- pathBuffer[pathIndex++] = nextBox;
- currentBox = nextBox;
- }
- }
-
- // Terminate path
- pathBuffer[pathIndex] = PATH_END;
- debug("Built walkbox path of length %d", pathIndex);
- return pathIndex;
-}
-
-void PelrockEngine::clearVisitedFlags() {
- for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
- _room->_currentRoomWalkboxes[i].flags = 0;
- }
-}
-
-/**
- * Check if two walkboxes overlap or touch (are adjacent)
- */
-bool areWalkboxesAdjacent(WalkBox *box1, WalkBox *box2) {
- uint16_t box1_x_max = box1->x + box1->w;
- uint16_t box1_y_max = box1->y + box1->h;
- uint16_t box2_x_max = box2->x + box2->w;
- uint16_t box2_y_max = box2->y + box2->h;
-
- // Check if X ranges overlap
- bool xOverlap = (box1->x <= box2_x_max) && (box2->x <= box1_x_max);
-
- // Check if Y ranges overlap
- bool yOverlap = (box1->y <= box2_y_max) && (box2->y <= box1_y_max);
-
- return xOverlap && yOverlap;
-}
-
-uint8_t PelrockEngine::getAdjacentWalkbox(uint8_t currentBoxIndex) {
- WalkBox *currentBox = &_room->_currentRoomWalkboxes[currentBoxIndex];
-
- // Mark current walkbox as visited
- currentBox->flags = 0x01;
-
- // Search for adjacent unvisited walkbox
- for (uint8_t i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
- // Skip current walkbox
- if (i == currentBoxIndex) {
- continue;
- }
-
- // Skip already visited walkboxes
- if (_room->_currentRoomWalkboxes[i].flags == 0x01) {
- continue;
- }
-
- // Check if walkboxes are adjacent
- if (areWalkboxesAdjacent(currentBox, &_room->_currentRoomWalkboxes[i])) {
- return i;
- }
- }
-
- return 0xFF; // No adjacent walkbox found
-}
-
-bool PelrockEngine::isPointInWalkbox(WalkBox *box, uint16_t x, uint16_t y) {
- return (x >= box->x &&
- x <= box->x + box->w &&
- y >= box->y &&
- y <= box->y + box->h);
-}
-
-uint8_t PelrockEngine::findWalkboxForPoint(uint16_t x, uint16_t y) {
- for (uint8_t i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
- if (isPointInWalkbox(&_room->_currentRoomWalkboxes[i], x, y)) {
- return i;
- }
- }
- return 0xFF; // Not found
-}
-
VerbIcon PelrockEngine::isActionUnder(int x, int y) {
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
for (int i = 0; i < actions.size(); i++) {
@@ -1407,6 +1139,20 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
return NO_ACTION;
}
+bool PelrockEngine::isAlfredUnder(int x, int y) {
+ //TODO: Account for scaling
+ int alfredX = alfredState.x;
+ int alfredY = alfredState.y;
+ int alfredW = kAlfredFrameWidth;
+ int alfredH = kAlfredFrameHeight;
+
+ if(alfredY - alfredH > y || alfredY < y || alfredX > x || alfredX + alfredW < x) {
+ return false;
+ }
+ return true;
+}
+
+
void PelrockEngine::checkMouseClick(int x, int y) {
if (whichNPCTalking)
@@ -1426,7 +1172,7 @@ void PelrockEngine::checkMouseClick(int x, int y) {
_displayPopup = false;
_currentHotspot = nullptr;
- Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
+ Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, mouseX, mouseY);
_curWalkTarget = walkTarget;
{ // For quick room navigation
@@ -1449,10 +1195,10 @@ void PelrockEngine::changeCursor(Cursor cursor) {
}
void PelrockEngine::checkMouseHover() {
- bool isSomethingUnder = false;
+ bool hotspotDetected = false;
// Calculate walk target first (before checking anything else)
- Common::Point walkTarget = calculateWalkTarget(mouseX, mouseY);
+ Common::Point walkTarget = calculateWalkTarget( _room->_currentRoomWalkboxes, mouseX, mouseY);
// Check if walk target hits any exit
bool exitDetected = false;
@@ -1463,88 +1209,96 @@ void PelrockEngine::checkMouseHover() {
int hotspotIndex = isHotspotUnder(mouseX, mouseY);
if (hotspotIndex != -1) {
- isSomethingUnder = true;
+ hotspotDetected = true;
}
if (isActionUnder(mouseX, mouseY) != NO_ACTION) {
- isSomethingUnder = false;
+ hotspotDetected = false;
+ }
+
+ bool alfredDetected = false;
+ if(isAlfredUnder(mouseX, mouseY)) {
+ alfredDetected = true;
}
- if (isSomethingUnder && exitDetected) {
+ if(alfredDetected) {
+ changeCursor(ALFRED);
+ } else if (hotspotDetected && exitDetected) {
changeCursor(COMBINATION);
- } else if (isSomethingUnder) {
+ } else if (hotspotDetected) {
changeCursor(HOTSPOT);
} else if (exitDetected) {
changeCursor(EXIT);
- } else {
+ }
+ else {
changeCursor(DEFAULT);
}
}
-Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
- // Starting point for pathfinding
- int sourceX = mouseX;
- int sourceY = mouseY;
-
- // TODO: If hovering over a sprite/hotspot, adjust source point to sprite center
- // For now, just use mouse position
-
- // Find nearest walkable point in walkboxes
- uint32 minDistance = 0xFFFFFFFF;
- Common::Point bestTarget(sourceX, sourceY);
-
- // for (Common::List<WalkBox>::iterator it = _currentRoomWalkboxes.begin();
- // it != _currentRoomWalkboxes.end(); ++it) {
- for (size_t i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
-
- // Calculate distance from source point to this walkbox (Manhattan distance)
- int dx = 0;
- int dy = 0;
-
- // Calculate horizontal distance
- if (sourceX < _room->_currentRoomWalkboxes[i].x) {
- dx = _room->_currentRoomWalkboxes[i].x - sourceX;
- } else if (sourceX > _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w) {
- dx = sourceX - (_room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w);
- }
- // else: sourceX is inside walkbox horizontally, dx = 0
-
- // Calculate vertical distance
- if (sourceY < _room->_currentRoomWalkboxes[i].y) {
- dy = _room->_currentRoomWalkboxes[i].y - sourceY;
- } else if (sourceY > _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h) {
- dy = sourceY - (_room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h);
- }
- // else: sourceY is inside walkbox vertically, dy = 0
-
- uint32 distance = dx + dy;
-
- if (distance < minDistance) {
- minDistance = distance;
-
- // Calculate target point (nearest point on walkbox to source)
- int targetX = sourceX;
- int targetY = sourceY;
-
- if (sourceX < _room->_currentRoomWalkboxes[i].x) {
- targetX = _room->_currentRoomWalkboxes[i].x;
- } else if (sourceX > _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w) {
- targetX = _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w;
- }
-
- if (sourceY < _room->_currentRoomWalkboxes[i].y) {
- targetY = _room->_currentRoomWalkboxes[i].y;
- } else if (sourceY > _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h) {
- targetY = _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h;
- }
-
- bestTarget.x = targetX;
- bestTarget.y = targetY;
- }
- }
-
- return bestTarget;
-}
+// Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
+// // Starting point for pathfinding
+// int sourceX = mouseX;
+// int sourceY = mouseY;
+
+// // TODO: If hovering over a sprite/hotspot, adjust source point to sprite center
+// // For now, just use mouse position
+
+// // Find nearest walkable point in walkboxes
+// uint32 minDistance = 0xFFFFFFFF;
+// Common::Point bestTarget(sourceX, sourceY);
+
+// // for (Common::List<WalkBox>::iterator it = _currentRoomWalkboxes.begin();
+// // it != _currentRoomWalkboxes.end(); ++it) {
+// for (size_t i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
+
+// // Calculate distance from source point to this walkbox (Manhattan distance)
+// int dx = 0;
+// int dy = 0;
+
+// // Calculate horizontal distance
+// if (sourceX < _room->_currentRoomWalkboxes[i].x) {
+// dx = _room->_currentRoomWalkboxes[i].x - sourceX;
+// } else if (sourceX > _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w) {
+// dx = sourceX - (_room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w);
+// }
+// // else: sourceX is inside walkbox horizontally, dx = 0
+
+// // Calculate vertical distance
+// if (sourceY < _room->_currentRoomWalkboxes[i].y) {
+// dy = _room->_currentRoomWalkboxes[i].y - sourceY;
+// } else if (sourceY > _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h) {
+// dy = sourceY - (_room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h);
+// }
+// // else: sourceY is inside walkbox vertically, dy = 0
+
+// uint32 distance = dx + dy;
+
+// if (distance < minDistance) {
+// minDistance = distance;
+
+// // Calculate target point (nearest point on walkbox to source)
+// int targetX = sourceX;
+// int targetY = sourceY;
+
+// if (sourceX < _room->_currentRoomWalkboxes[i].x) {
+// targetX = _room->_currentRoomWalkboxes[i].x;
+// } else if (sourceX > _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w) {
+// targetX = _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w;
+// }
+
+// if (sourceY < _room->_currentRoomWalkboxes[i].y) {
+// targetY = _room->_currentRoomWalkboxes[i].y;
+// } else if (sourceY > _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h) {
+// targetY = _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h;
+// }
+
+// bestTarget.x = targetX;
+// bestTarget.y = targetY;
+// }
+// }
+
+// return bestTarget;
+// }
void PelrockEngine::drawText(Common::String text, int x, int y, int w, byte color) {
Common::Rect rect = _largeFont->getBoundingBox(text.c_str());
@@ -1576,7 +1330,7 @@ void PelrockEngine::sayNPC(Sprite *anim, Common::String text, byte color) {
}
debug("Settijng textpos to %d, %d", anim->x, anim->y - 10);
_textPos = Common::Point(anim->x, anim->y - 10);
- _chronoManager->_textTtl = totalChars * kTextCharDisplayTime;
+ _textDurationFrames = totalChars / 2;
}
void PelrockEngine::sayAlfred(Common::String text) {
@@ -1589,7 +1343,7 @@ void PelrockEngine::sayAlfred(Common::String text) {
for (int i = 0; i < _currentTextPages[0].size(); i++) {
totalChars += _currentTextPages[0][i].size();
}
- _chronoManager->_textTtl = totalChars * kTextCharDisplayTime;
+ _textDurationFrames = totalChars / 2;
}
bool isEndMarker(char char_byte) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 83f23136b46..0fbf0148874 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -64,14 +64,6 @@ private:
Walking alforithm
*/
void walkTo(int x, int y);
- bool pathFind(int x, int y, PathContext *context);
- Common::Point calculateWalkTarget(int mouseX, int mouseY);
- uint8_t findWalkboxForPoint(uint16_t x, uint16_t y);
- bool isPointInWalkbox(WalkBox *box, uint16_t x, uint16_t y);
- uint16_t buildWalkboxPath(uint8_t start_box, uint8_t dest_box, uint8_t *path_buffer);
- uint8_t getAdjacentWalkbox(uint8_t current_box_index);
- void clearVisitedFlags();
- uint16_t generateMovementSteps(uint8_t *path_buffer, uint16_t path_length, uint16_t start_x, uint16_t start_y, uint16_t dest_x, uint16_t dest_y, MovementStep *movement_buffer);
void talk(byte object);
void displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer);
@@ -83,6 +75,7 @@ private:
Common::Array<VerbIcon> availableActions(HotSpot *hotspot);
VerbIcon isActionUnder(int x, int y);
+ bool isAlfredUnder(int x, int y);
int isHotspotUnder(int x, int y);
Exit *isExitUnder(int x, int y);
Sprite *isSpriteUnder(int x, int y);
@@ -90,7 +83,7 @@ private:
void drawText(Common::String text, int x, int y, int w, byte color);
- void frames();
+ void renderScene();
void animateFadePalette(PaletteAnim *anim);
void animateRotatePalette(PaletteAnim *anim);
void doAction(byte action, HotSpot *hotspot);
@@ -103,6 +96,7 @@ private:
void drawNextFrame(Sprite *animSet);
void changeCursor(Cursor cursor);
void drawTalkNPC(Sprite *animSet);
+ void conversationLoop();
void gameLoop();
void menuLoop();
@@ -125,6 +119,7 @@ private:
// text display
byte _textColor = 0;
Common::Point _textPos;
+ int _textDurationFrames = 0;
Common::Array<Common::Array<Common::String>> _currentTextPages = Common::Array<Common::Array<Common::String>>();
int _currentTextPageIndex = 0;
@@ -168,6 +163,7 @@ private:
// JAVA
bool shouldPlayIntro = false;
GameState stateGame = INTRO;
+ bool inConversation = false;
bool gameInitialized = false;
bool screenReady = false;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 4bc5ffce333..aa8e4f9edb8 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -124,8 +124,8 @@ struct AlfredState {
typedef struct {
uint8_t flags; /* Direction flags (see MOVE_* constants) */
- uint16_t distance_x; // Horizontal distance to move
- uint16_t distance_y; // Vertical distance to move
+ uint16_t distanceX; // Horizontal distance to move
+ uint16_t distanceY; // Vertical distance to move
} MovementStep;
/**
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index ac0efab9cf0..33713fbce43 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -57,29 +57,6 @@ void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color) {
}
}
-Common::String printMovementFlags(uint8_t flags) {
- Common::String result;
- if (flags & MOVE_HORIZ) {
- result += "HORIZ ";
- }
- if (flags & MOVE_VERT) {
- result += "VERT ";
- }
- if (flags & MOVE_DOWN) {
- result += "DOWN ";
- }
- if (flags & MOVE_LEFT) {
- result += "LEFT ";
- }
- if (flags & MOVE_UP) {
- result += "UP ";
- }
- if (flags & MOVE_RIGHT) {
- result += "RIGHT ";
- }
- return result;
-}
-
size_t rleDecompress(
const uint8_t *input,
size_t inputSize,
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 82e78cc368c..1d0aec0a740 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -39,7 +39,6 @@ void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth
void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color);
-Common::String printMovementFlags(uint8_t flags);
Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
byte decodeChar(byte b);
Commit: 7bc6fce6fc6f49ac5a3a4a294c58f29b8e93f941
https://github.com/scummvm/scummvm/commit/7bc6fce6fc6f49ac5a3a4a294c58f29b8e93f941
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:23+02:00
Commit Message:
PELROCK: Restructuring of renderloop
Changed paths:
A engines/pelrock/dialog.cpp
A engines/pelrock/dialog.h
A engines/pelrock/graphics.cpp
A engines/pelrock/graphics.h
engines/pelrock/chrono.cpp
engines/pelrock/chrono.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/sound.cpp
engines/pelrock/sound.h
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index 1538240f90b..d5c3e3655e5 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -39,7 +39,7 @@ void ChronoManager::updateChrono() {
if ((currentTime - _lastTick) >= kTickMs / _speedMultiplier) {
_gameTick = true;
- _tickCount++;
+ _frameCount++;
_lastTick = currentTime;
} else {
_gameTick = false;
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 649ab9a0391..67f8ced785f 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -37,8 +37,8 @@ const int kHalfTickMultiplier = 2;
class ChronoManager {
private:
uint32 _lastTick = 0;
- byte _tickCount = 0;
byte _speedMultiplier = 1;
+ uint32 _frameCount = 0;
public:
ChronoManager();
@@ -47,6 +47,9 @@ public:
void changeSpeed();
void delay(uint32 ms);
void waitForKey();
+ uint32 getFrameCount() const {
+ return _frameCount;
+ }
bool _gameTick = false;
bool countTextDown = false;
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
new file mode 100644
index 00000000000..fb5db72f960
--- /dev/null
+++ b/engines/pelrock/dialog.cpp
@@ -0,0 +1,36 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "pelrock/dialog.h"
+#include "dialog.h"
+
+namespace Pelrock {
+
+DialogManager::DialogManager(/* args */) {
+}
+
+DialogManager::~DialogManager() {
+}
+
+void DialogManager::startConversation(ConversationNode &root) {
+
+}
+} // namespace Pelrock
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
new file mode 100644
index 00000000000..ae1b032c04f
--- /dev/null
+++ b/engines/pelrock/dialog.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_DIALOG_H
+#define PELROCK_DIALOG_H
+
+#include "common/array.h"
+#include "common/scummsys.h"
+
+#include "pelrock/pelrock.h"
+#include "pelrock/types.h"
+namespace Pelrock {
+
+class DialogManager
+{
+private:
+ /* data */
+public:
+ DialogManager(/* args */);
+ ~DialogManager();
+
+ void startConversation(ConversationNode &root);
+};
+
+} // End of namespace Pelrock
+#endif // PELROCK_DIALOG_H
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
new file mode 100644
index 00000000000..69c05b16b4f
--- /dev/null
+++ b/engines/pelrock/graphics.cpp
@@ -0,0 +1,35 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/scummsys.h"
+
+#include "pelrock/graphics.h"
+
+namespace Pelrock {
+
+GraphicsManager::GraphicsManager() {
+}
+
+GraphicsManager::~GraphicsManager() {
+}
+
+} // End of namespace Pelrock
+
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
new file mode 100644
index 00000000000..a4718e50624
--- /dev/null
+++ b/engines/pelrock/graphics.h
@@ -0,0 +1,38 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_GRAPHICS_H
+#define PELROCK_GRAPHICS_H
+
+#include "common/scummsys.h"
+
+namespace Pelrock {
+
+class GraphicsManager {
+
+public:
+ GraphicsManager();
+ ~GraphicsManager();
+
+ void renderScene(bool showDialogOverlay);
+};
+
+} // End of namespace Pelrock
+#endif // PELROCK_GRAPHICS_H
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 099a8108744..b5cb852c6cb 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -38,9 +38,9 @@
#include "pelrock/detection.h"
#include "pelrock/fonts/small_font.h"
#include "pelrock/offsets.h"
+#include "pelrock/pathfinding.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
-#include "pelrock/pathfinding.h"
namespace Pelrock {
@@ -156,6 +156,30 @@ void PelrockEngine::loadAnims() {
_res->loadAlfredAnims();
}
+void PelrockEngine::talkLoop() {
+ while (inConversation) {
+
+ // // Display and advance through text
+ // while (/*moresegments*/ 1) {
+
+ // // Show each segment with animation
+ // while (!time_expired && !click) {
+ // â INNER LOOP
+
+ // wait_or_process_input();
+ // setup_alfred_frame_from_state();
+
+ // render_scene(0);
+ // â CALLS FULL ANIMATION CODE
+ // â update_npc_sprite_animations() â HERE !-Increment frame counters - Advance animation frames - Process movement - Apply sprite changes
+
+ // process_game_state(1);
+
+ // } // End animation loop
+ // }
+ }
+}
+
void PelrockEngine::displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer) {
int overlayHeight = choices.size() * kChoiceHeight + 2;
int overlayY = 400 - overlayHeight;
@@ -238,118 +262,141 @@ void sortAnimsByZOrder(Common::Array<Sprite> &anims) {
}
}
-void PelrockEngine::renderScene() {
-
- if (_chronoManager->_gameTick) {
-
- int soundIndex = _soundManager->tick();
- if (soundIndex >= 0 && soundIndex < _room->_roomSfx.size()) {
- // debug("Playing SFX index %d", soundIndex);
- _soundManager->playSound(_room->_roomSfx[3 + soundIndex]);
- }
-
- // Sort sprites by zOrder (persists in the array)
- sortAnimsByZOrder(_room->_currentRoomAnims);
+void PelrockEngine::playSoundIfNeeded() {
- memcpy(_compositeBuffer, _currentBackground, 640 * 400);
+ int soundIndex = _soundManager->tick(_chronoManager->getFrameCount());
+ if (soundIndex >= 0 && soundIndex < _room->_roomSfx.size()) {
+ debug("Playing SFX index %d", soundIndex);
+ _soundManager->playSound(_room->_roomSfx[3 + soundIndex]);
+ }
+}
- // Create temporary render order partitioned by Alfred's Y position
- Common::Array<Sprite *> renderOrder;
- int alfredY = alfredState.y;
+void PelrockEngine::renderScene(bool showTextOverlay) {
- // First pass: sprites behind Alfred (y <= alfredY)
- for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (_room->_currentRoomAnims[i].zOrder > 10) {
- drawNextFrame(&_room->_currentRoomAnims[i]);
- }
- }
+ if (_chronoManager->_gameTick) {
+ playSoundIfNeeded();
+
+ copyBackgroundToBuffer();
+ updateAnimations();
+
+ if (showTextOverlay) {
+ displayChoices(_currentTextPages[_currentTextPageIndex], _compositeBuffer);
+ }
+
+ presentFrame();
+ updatePaletteAnimations();
+
+ // if (alfredState.animState != ALFRED_WALKING && !_currentTextPages.empty()) {
+ // _chronoManager->countTextDown = true;
+ // if (_textDurationFrames-- > 0) {
+ // if (alfredState.animState == ALFRED_TALKING) {
+ // _textPos = Common::Point(alfredState.x, alfredState.y - kAlfredFrameHeight - 10);
+ // }
+ // renderText(_currentTextPages[_currentTextPageIndex], _textColor, _textPos.x, _textPos.y);
+ // } else if (_currentTextPageIndex < _currentTextPages.size() - 1) {
+ // _currentTextPageIndex++;
+
+ // int totalChars = 0;
+ // for (int i = 0; i < _currentTextPages[_currentTextPageIndex].size(); i++) {
+ // totalChars += _currentTextPages[_currentTextPageIndex][i].size();
+ // }
+ // _textDurationFrames = totalChars / 2;
+ // } else {
+ // _currentTextPages.clear();
+ // _currentTextPageIndex = 0;
+ // alfredState.animState = ALFRED_IDLE;
+ // isNPCATalking = false;
+ // isNPCBTalking = false;
+ // _chronoManager->countTextDown = false;
+ // }
+ // }
- // Draw Alfred here (you'll need to add this)
- chooseAlfredStateAndDraw();
+ // if (alfredState.animState == ALFRED_IDLE && alfredState.nextState != ALFRED_IDLE) {
+ // // debug("Switching Alfred state from IDLE to %d", alfredState.nextState);
+ // alfredState.animState = alfredState.nextState;
+ // alfredState.nextState = ALFRED_IDLE;
+ // alfredState.curFrame = 0;
+ // }
- // Second pass: sprites in front of Alfred (y > alfredY)
- for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (_room->_currentRoomAnims[i].zOrder <= 10) {
- drawNextFrame(&_room->_currentRoomAnims[i]);
- }
- }
+ // debug("Drawing walkboxes..., %d, _currentRoomWalkboxes.size()=%d", _currentRoomWalkboxes.size(), _currentRoomWalkboxes.size());
- if (_displayPopup) {
- showActionBalloon(_popupX, _popupY, _currentPopupFrame);
- if (_currentPopupFrame < 3) {
- _currentPopupFrame++;
- } else
- _currentPopupFrame = 0;
- }
+ _screen->markAllDirty();
+ }
+}
- // Common::Array<Common::String> testChoices;
- // testChoices.push_back("First choice");
- // testChoices.push_back("Second choice");
- // testChoices.push_back("Third choice");
- // displayChoices(testChoices, _compositeBuffer);
+void PelrockEngine::copyBackgroundToBuffer() {
+ // copy background to buffer
+ memcpy(_compositeBuffer, _currentBackground, 640 * 400);
+}
- memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+void PelrockEngine::updateAnimations() {
+ // Sort sprites by zOrder (persists in the array)
+ sortAnimsByZOrder(_room->_currentRoomAnims);
- if (alfredState.animState != ALFRED_WALKING && !_currentTextPages.empty()) {
- _chronoManager->countTextDown = true;
- if (_textDurationFrames-- > 0) {
- if (alfredState.animState == ALFRED_TALKING) {
- _textPos = Common::Point(alfredState.x, alfredState.y - kAlfredFrameHeight - 10);
- }
- renderText(_currentTextPages[_currentTextPageIndex], _textColor, _textPos.x, _textPos.y);
- } else if (_currentTextPageIndex < _currentTextPages.size() - 1) {
- _currentTextPageIndex++;
+ // Create temporary render order partitioned by Alfred's Y position
+ Common::Array<Sprite *> renderOrder;
+ int alfredY = alfredState.y;
- int totalChars = 0;
- for (int i = 0; i < _currentTextPages[_currentTextPageIndex].size(); i++) {
- totalChars += _currentTextPages[_currentTextPageIndex][i].size();
- }
- _textDurationFrames = totalChars / 2;
- } else {
- _currentTextPages.clear();
- _currentTextPageIndex = 0;
- alfredState.animState = ALFRED_IDLE;
- isNPCATalking = false;
- isNPCBTalking = false;
- _chronoManager->countTextDown = false;
- }
+ // First pass: sprites behind Alfred (y <= alfredY)
+ for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ if (_room->_currentRoomAnims[i].zOrder > 10) {
+ drawNextFrame(&_room->_currentRoomAnims[i]);
}
+ }
- if (alfredState.animState == ALFRED_IDLE && alfredState.nextState != ALFRED_IDLE) {
- // debug("Switching Alfred state from IDLE to %d", alfredState.nextState);
- alfredState.animState = alfredState.nextState;
- alfredState.nextState = ALFRED_IDLE;
- alfredState.curFrame = 0;
- }
+ // Draw Alfred here (you'll need to add this)
+ chooseAlfredStateAndDraw();
- // debug("Drawing walkboxes..., %d, _currentRoomWalkboxes.size()=%d", _currentRoomWalkboxes.size(), _currentRoomWalkboxes.size());
- for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
- // debug("Drawing walkbox %d", i);
- WalkBox box = _room->_currentRoomWalkboxes[i];
- drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
- _smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
+ // Second pass: sprites in front of Alfred (y > alfredY)
+ for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ if (_room->_currentRoomAnims[i].zOrder <= 10) {
+ drawNextFrame(&_room->_currentRoomAnims[i]);
}
+ }
- drawPos(_screen, alfredState.x, alfredState.y, 13);
- drawPos(_screen, alfredState.x, alfredState.y - kAlfredFrameHeight, 13);
- drawPos(_screen, _curWalkTarget.x, _curWalkTarget.y, 100);
+ if (_displayPopup) {
+ showActionBalloon(_popupX, _popupY, _currentPopupFrame);
+ if (_currentPopupFrame < 3) {
+ _currentPopupFrame++;
+ } else
+ _currentPopupFrame = 0;
+ }
+}
- if (showShadows) {
- memcpy(_screen->getPixels(), _room->_pixelsShadows, 640 * 400);
- }
- _smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
- _smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", alfredState.x, alfredState.y, alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
+void PelrockEngine::presentFrame() {
+ memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+ paintDebugLayer();
+ _screen->markAllDirty();
+}
- if (_room->_currentPaletteAnim != nullptr) {
- if (_room->_currentPaletteAnim->paletteMode == 1) {
- animateFadePalette(_room->_currentPaletteAnim);
- } else {
- animateRotatePalette(_room->_currentPaletteAnim);
- }
+void PelrockEngine::updatePaletteAnimations() {
+ if (_room->_currentPaletteAnim != nullptr) {
+ if (_room->_currentPaletteAnim->paletteMode == 1) {
+ animateFadePalette(_room->_currentPaletteAnim);
+ } else {
+ animateRotatePalette(_room->_currentPaletteAnim);
}
+ }
+}
- _screen->markAllDirty();
+void PelrockEngine::paintDebugLayer() {
+ for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
+ // debug("Drawing walkbox %d", i);
+ WalkBox box = _room->_currentRoomWalkboxes[i];
+ drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
+ _smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
+ }
+
+ drawPos(_screen, alfredState.x, alfredState.y, 13);
+ drawPos(_screen, alfredState.x, alfredState.y - kAlfredFrameHeight, 13);
+ drawPos(_screen, _curWalkTarget.x, _curWalkTarget.y, 100);
+
+ if (showShadows) {
+ memcpy(_screen->getPixels(), _room->_pixelsShadows, 640 * 400);
}
+ _smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
+ _smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", alfredState.x, alfredState.y, alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
+ _smallFont->drawString(_screen, Common::String::format("Frame number: %d", _chronoManager->getFrameCount()), 0, 30, 640, 13);
}
void PelrockEngine::animateFadePalette(PaletteAnim *anim) {
@@ -470,8 +517,7 @@ void PelrockEngine::lookAt(HotSpot *hotspot) {
}
void PelrockEngine::open(HotSpot *hotspot) {
- switch (hotspot->extra)
- {
+ switch (hotspot->extra) {
case 261:
_room->placeSticker(_res->getSticker(91), _currentBackground);
break;
@@ -1015,8 +1061,7 @@ void PelrockEngine::drawTalkNPC(Sprite *animSet) {
}
void PelrockEngine::conversationLoop() {
- while(inConversation) {
-
+ while (inConversation) {
}
}
@@ -1081,7 +1126,7 @@ void PelrockEngine::gameLoop() {
}
checkMouseHover();
- if(inConversation) {
+ if (inConversation) {
conversationLoop();
} else {
renderScene();
@@ -1140,19 +1185,18 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
}
bool PelrockEngine::isAlfredUnder(int x, int y) {
- //TODO: Account for scaling
+ // TODO: Account for scaling
int alfredX = alfredState.x;
int alfredY = alfredState.y;
int alfredW = kAlfredFrameWidth;
int alfredH = kAlfredFrameHeight;
- if(alfredY - alfredH > y || alfredY < y || alfredX > x || alfredX + alfredW < x) {
+ if (alfredY - alfredH > y || alfredY < y || alfredX > x || alfredX + alfredW < x) {
return false;
}
return true;
}
-
void PelrockEngine::checkMouseClick(int x, int y) {
if (whichNPCTalking)
@@ -1198,7 +1242,7 @@ void PelrockEngine::checkMouseHover() {
bool hotspotDetected = false;
// Calculate walk target first (before checking anything else)
- Common::Point walkTarget = calculateWalkTarget( _room->_currentRoomWalkboxes, mouseX, mouseY);
+ Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, mouseX, mouseY);
// Check if walk target hits any exit
bool exitDetected = false;
@@ -1217,11 +1261,11 @@ void PelrockEngine::checkMouseHover() {
}
bool alfredDetected = false;
- if(isAlfredUnder(mouseX, mouseY)) {
+ if (isAlfredUnder(mouseX, mouseY)) {
alfredDetected = true;
}
- if(alfredDetected) {
+ if (alfredDetected) {
changeCursor(ALFRED);
} else if (hotspotDetected && exitDetected) {
changeCursor(COMBINATION);
@@ -1229,8 +1273,7 @@ void PelrockEngine::checkMouseHover() {
changeCursor(HOTSPOT);
} else if (exitDetected) {
changeCursor(EXIT);
- }
- else {
+ } else {
changeCursor(DEFAULT);
}
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 0fbf0148874..109e9f07793 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -66,6 +66,7 @@ private:
void walkTo(int x, int y);
void talk(byte object);
+ void talkLoop();
void displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer);
void sayAlfred(Common::String text);
void sayNPC(Sprite *anim, Common::String text, byte color);
@@ -83,7 +84,14 @@ private:
void drawText(Common::String text, int x, int y, int w, byte color);
- void renderScene();
+ void renderScene(bool showTextOverlay = false);
+ void copyBackgroundToBuffer();
+ void updateAnimations();
+ void presentFrame();
+ void updatePaletteAnimations();
+ void paintDebugLayer();
+
+
void animateFadePalette(PaletteAnim *anim);
void animateRotatePalette(PaletteAnim *anim);
void doAction(byte action, HotSpot *hotspot);
@@ -96,8 +104,9 @@ private:
void drawNextFrame(Sprite *animSet);
void changeCursor(Cursor cursor);
void drawTalkNPC(Sprite *animSet);
- void conversationLoop();
+ void playSoundIfNeeded();
+ void conversationLoop();
void gameLoop();
void menuLoop();
@@ -180,10 +189,10 @@ protected:
public:
Graphics::Screen *_screen = nullptr;
- AlfredState alfredState;
ChronoManager *_chronoManager = nullptr;
VideoManager *_videoManager = nullptr;
SoundManager *_soundManager = nullptr;
+ AlfredState alfredState;
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index bbea25006be..1c08df8579e 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -104,7 +104,6 @@ void SoundManager::playSound(SonidoFile sound, int volume) {
// int channel = findFreeChannel();
// _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
// }
- // TODO: Play sound file
}
SoundFormat SoundManager::detectFormat(byte *data, uint32 size) {
@@ -254,9 +253,8 @@ void SoundManager::loadSoundIndex() {
int RANDOM_THRESHOLD = 0x4000;
-int SoundManager::tick() {
+int SoundManager::tick(uint32 frameCount) {
- soundFrameCounter++;
uint16 rand1 = _rng.nextRandom();
// uint32 random = g_engine->getRandomNumber(1);
@@ -265,7 +263,7 @@ int SoundManager::tick() {
return -1;
}
- if((soundFrameCounter & COUNTER_MASK) != COUNTER_MASK){
+ if((frameCount & COUNTER_MASK) != COUNTER_MASK){
// debug("No SFX this tick due to counter mask (counter = %d)", soundFrameCounter);
return -1;
}
@@ -273,8 +271,6 @@ int SoundManager::tick() {
uint16 rand2 = _rng.nextRandom();
int slot = rand2 & 3;
// debug("Slot = %d (rand2 = %u)", slot, rand2);
-
- soundFrameCounter = 0;
// uint32 slot = g_engine->getRandomNumber(4);
return slot + 1;
}
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 3be968743ea..9a22bdfa099 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -201,7 +201,7 @@ public:
}
void loadSoundIndex();
- int tick();
+ int tick(uint32 frameCount);
private:
void playSound(SonidoFile sound, int volume = 255);
@@ -217,7 +217,6 @@ private:
byte _currentMusicTrack = 0;
Audio::SoundHandle _musicHandle;
Audio::SoundHandle _sfxHandles[kMaxChannels];
- int soundFrameCounter = 0;
Common::HashMap<Common::String, SonidoFile> _soundMap;
GameRNG _rng = GameRNG(0);
};
Commit: b58ca4248cd62962c4c7633146530283f366b8ac
https://github.com/scummvm/scummvm/commit/b58ca4248cd62962c4c7633146530283f366b8ac
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:23+02:00
Commit Message:
PELROCK: Create EventManager
Changed paths:
A engines/pelrock/events.cpp
A engines/pelrock/events.h
engines/pelrock/chrono.cpp
engines/pelrock/chrono.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index d5c3e3655e5..db0f7d8c10a 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -65,19 +65,4 @@ void ChronoManager::delay(uint32 ms) {
}
}
-void ChronoManager::waitForKey() {
- bool waitForKey = false;
- Common::Event e;
- debug("Waiting for key!");
- while (!waitForKey && !g_engine->shouldQuit()) {
- while (g_system->getEventManager()->pollEvent(e)) {
- if (e.type == Common::EVENT_KEYDOWN) {
- waitForKey = true;
- }
- }
-
- g_engine->_screen->update();
- g_system->delayMillis(10);
- }
-}
} // End of namespace Pelrock
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 67f8ced785f..f7f67229545 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -46,7 +46,6 @@ public:
void updateChrono();
void changeSpeed();
void delay(uint32 ms);
- void waitForKey();
uint32 getFrameCount() const {
return _frameCount;
}
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
new file mode 100644
index 00000000000..bc81829f64b
--- /dev/null
+++ b/engines/pelrock/events.cpp
@@ -0,0 +1,120 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "common/events.h"
+
+#include "pelrock/events.h"
+#include "pelrock/pelrock.h"
+
+namespace Pelrock {
+
+PelrockEventManager::PelrockEventManager() {
+}
+
+void PelrockEventManager::pollEvent() {
+
+ Common::EventManager *eventMan = g_engine->_system->getEventManager();
+ while (eventMan->pollEvent(_event)) {
+ if (isMouseEvent(_event)) {
+ _mouseX = _event.mouse.x;
+ _mouseY = _event.mouse.y;
+ }
+ switch (_event.type) {
+ case Common::EVENT_QUIT:
+ case Common::EVENT_RETURN_TO_LAUNCHER:
+ return;
+
+ // case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
+ // // handle action
+ // handleKey(_event);
+ // break;
+
+ // case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
+ // break;
+ // case Common::EVENT_KEYDOWN:
+ // changeGameSpeed(_event);
+ // _keyPressed = true;
+ // _lastKeyEvent = _event;
+ // return;
+ // case Common::EVENT_KEYUP:
+ // return;
+ case Common::EVENT_LBUTTONDOWN:
+ if (_leftMouseButton == 0) {
+ _clickTime = g_system->getMillis();
+ }
+ _leftMouseButton = 1;
+ break;
+ case Common::EVENT_LBUTTONUP:
+ if (_leftMouseButton == 1) {
+ _leftMouseClicked = true;
+ _mouseClickX = _event.mouse.x;
+ _mouseClickY = _event.mouse.y;
+ _longClicked = false;
+ } else {
+ _leftMouseClicked = false;
+ }
+ _longClicked = false;
+ _leftMouseButton = 0;
+ _clickTime = 0;
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ _rightMouseButton = 1;
+ debug("Right mouse button down");
+ break;
+ case Common::EVENT_RBUTTONUP:
+ if (_rightMouseButton == 1) {
+ debug("Right mouse clicked");
+ _rightMouseClicked = true;
+ } else {
+ _rightMouseClicked = false;
+ }
+ _rightMouseButton = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (_leftMouseButton) {
+ uint32 elapsedLongClick = g_system->getMillis() - _clickTime;
+ if (elapsedLongClick >= kDoubleClickDelay) {
+ elapsedLongClick = 0;
+ _longClicked = true;
+ _leftMouseButton = 0;
+ }
+ }
+}
+
+void PelrockEventManager::waitForKey() {
+ bool waitForKey = false;
+ Common::Event e;
+ debug("Waiting for key!");
+ while (!waitForKey && !g_engine->shouldQuit()) {
+ while (g_system->getEventManager()->pollEvent(e)) {
+ if (e.type == Common::EVENT_KEYDOWN) {
+ waitForKey = true;
+ }
+ }
+
+ g_engine->_screen->update();
+ g_system->delayMillis(10);
+ }
+}
+} // namespace Pelrock
diff --git a/engines/pelrock/events.h b/engines/pelrock/events.h
new file mode 100644
index 00000000000..ddea8935c8b
--- /dev/null
+++ b/engines/pelrock/events.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_EVENTS_H
+#define PELROCK_EVENTS_H
+
+#include "common/events.h"
+#include "common/scummsys.h"
+
+namespace Pelrock {
+static const int kDoubleClickDelay = 300; // in milliseconds
+class PelrockEventManager {
+private:
+ Common::Event _event;
+ bool _leftMouseButton = 0;
+ bool _rightMouseButton = 0;
+ uint32 _clickTime = 0;
+public:
+ int16 _mouseX = 0;
+ int16 _mouseY = 0;
+ int16 _mouseClickX = 0;
+ int16 _mouseClickY = 0;
+ bool _leftMouseClicked = false;
+ bool _longClicked = false;
+ bool _rightMouseClicked = false;
+ Common::Event _lastKeyEvent;
+ PelrockEventManager();
+ void pollEvent();
+ void waitForKey();
+};
+
+} // End of namespace Pelrock
+#endif
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index f919cdf363f..d935e5fa27f 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -12,7 +12,8 @@ MODULE_OBJS = \
resources.o\
sound.o \
video/video.o \
- pathfinding.o
+ pathfinding.o \
+ events.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b5cb852c6cb..fc471ab0c36 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -49,22 +49,24 @@ PelrockEngine *g_engine;
PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst),
_gameDescription(gameDesc), _randomSource("Pelrock") {
g_engine = this;
- _chronoManager = new ChronoManager();
+ _chrono = new ChronoManager();
+ _events = new PelrockEventManager();
}
PelrockEngine::~PelrockEngine() {
delete[] _compositeBuffer;
delete[] _currentBackground;
delete _largeFont;
+ delete _smallFont;
delete _screen;
- delete _chronoManager;
+ delete _chrono;
delete _videoManager;
- delete _soundManager;
+ delete _sound;
delete _room;
delete _res;
+ delete _events;
// if (_bgPopupBalloon)
// delete[] _bgPopupBalloon;
- delete _smallFont;
}
uint32 PelrockEngine::getFeatures() const {
@@ -81,10 +83,10 @@ Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
initGraphics(640, 400);
_screen = new Graphics::Screen();
- _videoManager = new VideoManager(_screen);
+ _videoManager = new VideoManager(_screen, _events);
_room = new RoomManager();
_res = new ResourceManager();
- _soundManager = new SoundManager(_mixer);
+ _sound = new SoundManager(_mixer);
// Set the engine's debugger console
setDebugger(new PelrockConsole(this));
@@ -95,7 +97,6 @@ Common::Error PelrockEngine::run() {
(void)loadGameState(saveSlot);
// Simple event handling loop
- Common::Event e;
Graphics::FrameLimiter limiter(g_system, 60);
if (shouldPlayIntro == false) {
@@ -128,7 +129,7 @@ void PelrockEngine::init() {
_res->loadInteractionIcons();
_res->loadInventoryItems();
_res->loadSettingsMenu();
- _soundManager->loadSoundIndex();
+ _sound->loadSoundIndex();
calculateScalingMasks();
_compositeBuffer = new byte[640 * 400];
@@ -146,9 +147,6 @@ void PelrockEngine::init() {
gameInitialized = true;
loadAnims();
setScreen(0, ALFRED_DOWN);
- // setScreen(6, 0); // museum entrance
- // setScreen(13, 1); // restaurants kitchen
- // setScreen(2, 2); // hooker
}
}
@@ -156,30 +154,6 @@ void PelrockEngine::loadAnims() {
_res->loadAlfredAnims();
}
-void PelrockEngine::talkLoop() {
- while (inConversation) {
-
- // // Display and advance through text
- // while (/*moresegments*/ 1) {
-
- // // Show each segment with animation
- // while (!time_expired && !click) {
- // â INNER LOOP
-
- // wait_or_process_input();
- // setup_alfred_frame_from_state();
-
- // render_scene(0);
- // â CALLS FULL ANIMATION CODE
- // â update_npc_sprite_animations() â HERE !-Increment frame counters - Advance animation frames - Process movement - Apply sprite changes
-
- // process_game_state(1);
-
- // } // End animation loop
- // }
- }
-}
-
void PelrockEngine::displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer) {
int overlayHeight = choices.size() * kChoiceHeight + 2;
int overlayY = 400 - overlayHeight;
@@ -264,16 +238,16 @@ void sortAnimsByZOrder(Common::Array<Sprite> &anims) {
void PelrockEngine::playSoundIfNeeded() {
- int soundIndex = _soundManager->tick(_chronoManager->getFrameCount());
+ int soundIndex = _sound->tick(_chrono->getFrameCount());
if (soundIndex >= 0 && soundIndex < _room->_roomSfx.size()) {
debug("Playing SFX index %d", soundIndex);
- _soundManager->playSound(_room->_roomSfx[3 + soundIndex]);
+ _sound->playSound(_room->_roomSfx[3 + soundIndex]);
}
}
void PelrockEngine::renderScene(bool showTextOverlay) {
- if (_chronoManager->_gameTick) {
+ if (_chrono->_gameTick) {
playSoundIfNeeded();
copyBackgroundToBuffer();
@@ -283,6 +257,8 @@ void PelrockEngine::renderScene(bool showTextOverlay) {
displayChoices(_currentTextPages[_currentTextPageIndex], _compositeBuffer);
}
+ checkMouse();
+
presentFrame();
updatePaletteAnimations();
@@ -324,6 +300,55 @@ void PelrockEngine::renderScene(bool showTextOverlay) {
}
}
+void PelrockEngine::checkMouse() {
+ if(_events->_leftMouseClicked) {
+ checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
+ _events->_leftMouseClicked = false;
+ _displayPopup = false;
+ }
+ else if(_events->_longClicked) {
+ checkLongMouseClick(_events->_mouseClickX, _events->_mouseClickY);
+ _events->_longClicked = false;
+ }
+ else if(_events->_rightMouseClicked) {
+ debug("Right mouse clicked - entering settings menu");
+ g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
+ _events->_rightMouseClicked = false;
+ stateGame = SETTINGS;
+ }
+ checkMouseHover();
+
+//else if (e.type == Common::EVENT_MOUSEMOVE) {
+ // mouseX = e.mouse.x;
+ // mouseY = e.mouse.y;
+ // // debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
+ // } else if (e.type == Common::EVENT_LBUTTONDOWN) {
+ // if (!_isMouseDown) {
+ // _mouseClickTime = g_system->getMillis();
+ // _isMouseDown = true;
+ // }
+ // } else if (e.type == Common::EVENT_LBUTTONUP) {
+ // _isMouseDown = false;
+ // checkMouseClick(e.mouse.x, e.mouse.y);
+ // _displayPopup = false;
+ // _longClick = false;
+ // } else if (e.type == Common::EVENT_RBUTTONUP) {
+ // g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
+ // stateGame = SETTINGS;
+ // }
+ // }
+ // if (_isMouseDown) {
+ // if (g_system->getMillis() - _mouseClickTime >= kLongClickDuration) {
+ // debug("long click!");
+ // _longClick = true;
+ // _isMouseDown = false;
+ // checkLongMouseClick(e.mouse.x, e.mouse.y);
+ // }
+ // }
+ // checkMouseHover();
+
+}
+
void PelrockEngine::copyBackgroundToBuffer() {
// copy background to buffer
memcpy(_compositeBuffer, _currentBackground, 640 * 400);
@@ -396,12 +421,12 @@ void PelrockEngine::paintDebugLayer() {
}
_smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
_smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", alfredState.x, alfredState.y, alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
- _smallFont->drawString(_screen, Common::String::format("Frame number: %d", _chronoManager->getFrameCount()), 0, 30, 640, 13);
+ _smallFont->drawString(_screen, Common::String::format("Frame number: %d", _chrono->getFrameCount()), 0, 30, 640, 13);
}
void PelrockEngine::animateFadePalette(PaletteAnim *anim) {
- // if (_paletteAnim->curFrameCount >= _paletteAnim->speed) {
+
if (anim->data[0] >= anim->data[6] &&
anim->data[1] >= anim->data[7] &&
anim->data[2] >= anim->data[8]) {
@@ -800,7 +825,6 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
int curFrame = animData.curFrame;
byte *frame = new byte[frameSize];
extractSingleFrame(animData.animData, frame, curFrame, animData.w, animData.h);
-
drawSpriteToBuffer(_compositeBuffer, 640, frame, sprite->x, sprite->y, sprite->w, sprite->h, 255);
if (animData.elpapsedFrames == animData.speed) {
@@ -827,7 +851,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
}
void PelrockEngine::checkLongMouseClick(int x, int y) {
- int hotspotIndex = isHotspotUnder(mouseX, mouseY);
+ int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
if (hotspotIndex != -1) {
@@ -998,8 +1022,8 @@ int PelrockEngine::isHotspotUnder(int x, int y) {
for (size_t i = 0; i < _room->_currentRoomHotspots.size(); i++) {
HotSpot hotspot = _room->_currentRoomHotspots[i];
if (hotspot.isEnabled &&
- mouseX >= hotspot.x && mouseX <= (hotspot.x + hotspot.w) &&
- mouseY >= hotspot.y && mouseY <= (hotspot.y + hotspot.h)) {
+ x >= hotspot.x && x <= (hotspot.x + hotspot.w) &&
+ y >= hotspot.y && y <= (hotspot.y + hotspot.h)) {
return i;
}
}
@@ -1021,7 +1045,8 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _res->_popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
- VerbIcon icon = isActionUnder(mouseX, mouseY);
+
+ VerbIcon icon = isActionUnder(_events->_mouseX, _events->_mouseY);
for (int i = 0; i < actions.size(); i++) {
if (icon == actions[i] && _iconBlink++ < kIconBlinkPeriod / 2) {
continue;
@@ -1062,69 +1087,70 @@ void PelrockEngine::drawTalkNPC(Sprite *animSet) {
void PelrockEngine::conversationLoop() {
while (inConversation) {
+
}
}
void PelrockEngine::gameLoop() {
- _chronoManager->updateChrono();
- Common::Event e;
- while (g_system->getEventManager()->pollEvent(e)) {
- if (e.type == Common::EVENT_KEYDOWN) {
- switch (e.kbd.keycode) {
- case Common::KEYCODE_w:
- alfredState.animState = ALFRED_WALKING;
- break;
- case Common::KEYCODE_t:
- alfredState.animState = ALFRED_TALKING;
- break;
- case Common::KEYCODE_s:
- alfredState.animState = ALFRED_IDLE;
- break;
- case Common::KEYCODE_c:
- alfredState.animState = ALFRED_COMB;
- break;
- case Common::KEYCODE_i:
- alfredState.animState = ALFRED_INTERACTING;
- break;
- case Common::KEYCODE_z:
- showShadows = !showShadows;
- break;
- case Common::KEYCODE_y:
- alfredState.x = 193;
- alfredState.y = 382;
- walkTo(377, 318);
- break;
- default:
- break;
- }
- } else if (e.type == Common::EVENT_MOUSEMOVE) {
- mouseX = e.mouse.x;
- mouseY = e.mouse.y;
- // debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
- } else if (e.type == Common::EVENT_LBUTTONDOWN) {
- if (!_isMouseDown) {
- _mouseClickTime = g_system->getMillis();
- _isMouseDown = true;
- }
- } else if (e.type == Common::EVENT_LBUTTONUP) {
- _isMouseDown = false;
- checkMouseClick(e.mouse.x, e.mouse.y);
- _displayPopup = false;
- _longClick = false;
- } else if (e.type == Common::EVENT_RBUTTONUP) {
- g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
- stateGame = SETTINGS;
- }
- }
- if (_isMouseDown) {
- if (g_system->getMillis() - _mouseClickTime >= kLongClickDuration) {
- debug("long click!");
- _longClick = true;
- _isMouseDown = false;
- checkLongMouseClick(e.mouse.x, e.mouse.y);
- }
- }
- checkMouseHover();
+ _chrono->updateChrono();
+ _events->pollEvent();
+ // while (g_system->getEventManager()->pollEvent(e)) {
+ // if (e.type == Common::EVENT_KEYDOWN) {
+ // switch (e.kbd.keycode) {
+ // case Common::KEYCODE_w:
+ // alfredState.animState = ALFRED_WALKING;
+ // break;
+ // case Common::KEYCODE_t:
+ // alfredState.animState = ALFRED_TALKING;
+ // break;
+ // case Common::KEYCODE_s:
+ // alfredState.animState = ALFRED_IDLE;
+ // break;
+ // case Common::KEYCODE_c:
+ // alfredState.animState = ALFRED_COMB;
+ // break;
+ // case Common::KEYCODE_i:
+ // alfredState.animState = ALFRED_INTERACTING;
+ // break;
+ // case Common::KEYCODE_z:
+ // showShadows = !showShadows;
+ // break;
+ // case Common::KEYCODE_y:
+ // alfredState.x = 193;
+ // alfredState.y = 382;
+ // walkTo(377, 318);
+ // break;
+ // default:
+ // break;
+ // }
+ // } else if (e.type == Common::EVENT_MOUSEMOVE) {
+ // mouseX = e.mouse.x;
+ // mouseY = e.mouse.y;
+ // // debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
+ // } else if (e.type == Common::EVENT_LBUTTONDOWN) {
+ // if (!_isMouseDown) {
+ // _mouseClickTime = g_system->getMillis();
+ // _isMouseDown = true;
+ // }
+ // } else if (e.type == Common::EVENT_LBUTTONUP) {
+ // _isMouseDown = false;
+ // checkMouseClick(e.mouse.x, e.mouse.y);
+ // _displayPopup = false;
+ // _longClick = false;
+ // } else if (e.type == Common::EVENT_RBUTTONUP) {
+ // g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
+ // stateGame = SETTINGS;
+ // }
+ // }
+ // if (_isMouseDown) {
+ // if (g_system->getMillis() - _mouseClickTime >= kLongClickDuration) {
+ // debug("long click!");
+ // _longClick = true;
+ // _isMouseDown = false;
+ // checkLongMouseClick(e.mouse.x, e.mouse.y);
+ // }
+ // }
+ // checkMouseHover();
if (inConversation) {
conversationLoop();
@@ -1134,16 +1160,16 @@ void PelrockEngine::gameLoop() {
}
void PelrockEngine::menuLoop() {
- Common::Event e;
- while (g_system->getEventManager()->pollEvent(e)) {
- if (e.type == Common::EVENT_LBUTTONUP) {
- checkMouseClickOnSettings(e.mouse.x, e.mouse.y);
+ _events->pollEvent();
- } else if (e.type == Common::EVENT_RBUTTONUP) {
-
- g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
- stateGame = GAME;
- }
+ if(_events->_leftMouseClicked) {
+ _events->_leftMouseClicked = false;
+ checkMouseClickOnSettings(_events->_mouseX, _events->_mouseY);
+ }
+ else if (_events->_rightMouseClicked) {
+ _events->_rightMouseClicked = false;
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+ stateGame = GAME;
}
memcpy(_compositeBuffer, _res->_mainMenu, 640 * 400);
@@ -1216,7 +1242,7 @@ void PelrockEngine::checkMouseClick(int x, int y) {
_displayPopup = false;
_currentHotspot = nullptr;
- Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, mouseX, mouseY);
+ Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY);
_curWalkTarget = walkTarget;
{ // For quick room navigation
@@ -1242,7 +1268,7 @@ void PelrockEngine::checkMouseHover() {
bool hotspotDetected = false;
// Calculate walk target first (before checking anything else)
- Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, mouseX, mouseY);
+ Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY);
// Check if walk target hits any exit
bool exitDetected = false;
@@ -1251,17 +1277,17 @@ void PelrockEngine::checkMouseHover() {
exitDetected = true;
}
- int hotspotIndex = isHotspotUnder(mouseX, mouseY);
+ int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
if (hotspotIndex != -1) {
hotspotDetected = true;
}
- if (isActionUnder(mouseX, mouseY) != NO_ACTION) {
+ if (isActionUnder(_events->_mouseX, _events->_mouseY) != NO_ACTION) {
hotspotDetected = false;
}
bool alfredDetected = false;
- if (isAlfredUnder(mouseX, mouseY)) {
+ if (isAlfredUnder(_events->_mouseX, _events->_mouseY)) {
alfredDetected = true;
}
@@ -1504,7 +1530,7 @@ Common::Array<Common::Array<Common::String>> wordWrap(Common::String text) {
}
void PelrockEngine::setScreen(int number, AlfredDirection dir) {
- _soundManager->stopAllSounds();
+ _sound->stopAllSounds();
Common::File roomFile;
debug("Loading room %s number %d", _room->getRoomName(number).c_str(), number);
if (!roomFile.open(Common::Path("ALFRED.1"))) {
@@ -1540,14 +1566,10 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
_room->loadRoomMetadata(&roomFile, number);
_room->loadRoomTalkingAnimations(number);
if (_room->_musicTrack > 0)
- _soundManager->playMusicTrack(_room->_musicTrack);
+ _sound->playMusicTrack(_room->_musicTrack);
else {
- _soundManager->stopMusic();
+ _sound->stopMusic();
}
- // for (int i = 0; i < kNumSfxPerRoom; i++) {
- // if (_room->_roomSfx[i])
- // _soundManager->playSound(_room->_roomSfx[i]);
- // }
_room->_currentRoomNumber = number;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 109e9f07793..b19d94498c1 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -38,6 +38,7 @@
#include "pelrock/chrono.h"
#include "pelrock/detection.h"
+#include "pelrock/events.h"
#include "pelrock/fonts/large_font.h"
#include "pelrock/fonts/small_font.h"
#include "pelrock/resources.h"
@@ -56,6 +57,10 @@ private:
Common::RandomSource _randomSource;
RoomManager *_room = nullptr;
ResourceManager *_res = nullptr;
+ ChronoManager *_chrono = nullptr;
+ VideoManager *_videoManager = nullptr;
+ SoundManager *_sound = nullptr;
+ PelrockEventManager *_events = nullptr;
void init();
void loadAnims();
@@ -66,7 +71,6 @@ private:
void walkTo(int x, int y);
void talk(byte object);
- void talkLoop();
void displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer);
void sayAlfred(Common::String text);
void sayNPC(Sprite *anim, Common::String text, byte color);
@@ -85,6 +89,7 @@ private:
void drawText(Common::String text, int x, int y, int w, byte color);
void renderScene(bool showTextOverlay = false);
+ void checkMouse();
void copyBackgroundToBuffer();
void updateAnimations();
void presentFrame();
@@ -136,13 +141,6 @@ private:
bool alfredFrameSkip = false;
bool isAlkfredWalking = false;
- uint16 mouseX = 0;
- uint16 mouseY = 0;
- bool _lMouseDown = false;
- uint32 _mouseClickTime;
- bool _isMouseDown = false;
- bool _longClick = false;
-
byte *_currentBackground = nullptr; // Clean background - NEVER modified
byte *_compositeBuffer; // Working composition buffer
@@ -189,9 +187,6 @@ protected:
public:
Graphics::Screen *_screen = nullptr;
- ChronoManager *_chronoManager = nullptr;
- VideoManager *_videoManager = nullptr;
- SoundManager *_soundManager = nullptr;
AlfredState alfredState;
public:
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 93c5fd4a17e..03b78936d1b 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -29,7 +29,7 @@
namespace Pelrock {
-VideoManager::VideoManager(Graphics::Screen *screen) : _screen(screen) {
+VideoManager::VideoManager(Graphics::Screen *screen, PelrockEventManager *events) : _screen(screen), _events(events) {
}
VideoManager::~VideoManager() {
@@ -56,7 +56,7 @@ void VideoManager::playIntro() {
_screen->markAllDirty();
_screen->update();
delete[] chunk0;
- g_engine->_chronoManager->waitForKey();
+ _events->waitForKey();
size_t chunk1Size = chunkSize * 6;
byte chunk1_data[chunk1Size];
@@ -75,7 +75,7 @@ void VideoManager::playIntro() {
}
_screen->markAllDirty();
_screen->update();
- g_engine->_chronoManager->waitForKey();
+ _events->waitForKey();
for (size_t i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
byte *chunk = new byte[chunkSize];
@@ -94,9 +94,9 @@ void VideoManager::playIntro() {
delete[] chunk;
_screen->markAllDirty();
_screen->update();
- g_engine->_chronoManager->waitForKey();
+ _events->waitForKey();
}
- g_engine->_chronoManager->waitForKey();
+ _events->waitForKey();
videoFile.close();
}
void VideoManager::loadPalette(Common::SeekableReadStream &stream) {
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index f9ac45b3a2e..405c52b06b2 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -22,6 +22,8 @@
#ifndef PELROCK_VIDEO_H
#define PELROCK_VIDEO_H
+#include "pelrock/events.h"
+
namespace Pelrock {
static const uint32 frame0offset = 0x5000;
@@ -39,12 +41,13 @@ static const uint32 offsets[] = {
class VideoManager {
public:
- VideoManager(Graphics::Screen *screen);
+ VideoManager(Graphics::Screen *screen, PelrockEventManager *events);
~VideoManager();
void playIntro();
private:
Graphics::Screen *_screen;
+ PelrockEventManager *_events;
void loadPalette(Common::SeekableReadStream &stream);
byte *decodeCopyBlock(byte *data, uint32 offset);
byte *decodeRLE(byte *data, size_t size, uint32 offset);
Commit: e6ad7d5ed4119626befdd26a1271d5b82aeaa569
https://github.com/scummvm/scummvm/commit/e6ad7d5ed4119626befdd26a1271d5b82aeaa569
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:24+02:00
Commit Message:
PELROCK: First attempt at conversation flow
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index fb5db72f960..99bb129661f 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -21,16 +21,517 @@
#include "pelrock/dialog.h"
#include "dialog.h"
+#include "pelrock/pelrock.h"
+#include "pelrock/util.h"
+
+// Control character codes (negative values in signed char)
+#define CHAR_SPACE 0x20 /* ' ' */
+#define CHAR_END_MARKER_1 0xFD /* -3 (end of text marker) */
+#define CHAR_END_MARKER_2 0xF4 /* -0xC (alternate end marker) */
+#define CHAR_END_MARKER_3 0xF8 /* -8 (another end marker) */
+#define CHAR_END_MARKER_4 0xF0 /* -0x10 (another end marker) */
+#define CHAR_NEWLINE 0xF6 /* -10 (newline marker) */
+#define CHAR_PAGE_BREAK 0xF9 /* marker inserted when switching pages */
+
+// Conversation control bytes
+#define CTRL_SPEAKER_ID 0x08 /* Next byte is speaker ID (color) */
+#define CTRL_END_TEXT 0xFD /* End of text segment */
+#define CTRL_TEXT_TERMINATOR 0xFC /* Text terminator */
+#define CTRL_DIALOGUE_MARKER 0xFB /* Choice marker */
+#define CTRL_DISABLED_CHOICE 0xFA /* Disabled choice marker */
+#define CTRL_PAGE_BREAK_CONV 0xF9 /* Page break in conversation */
+#define CTRL_ACTION_TRIGGER 0xF8 /* Action trigger */
+#define CTRL_END_BRANCH 0xF7 /* End of branch */
+#define CTRL_LINE_CONTINUE 0xF6 /* Line continue/newline */
+#define CTRL_ALT_END_MARKER_1 0xF5 /* Alt end marker */
+#define CTRL_END_CONVERSATION 0xF4 /* End conversation */
+#define CTRL_DIALOGUE_MARKER_2 0xF1 /* Alt choice marker */
+#define CTRL_GO_BACK 0xF0 /* Go back in conversation */
+#define CTRL_ALT_END_MARKER_2 0xEB /* Alt end marker 2 */
+#define CTRL_ALT_END_MARKER_3 0xFE /* Alt end marker 3 */
namespace Pelrock {
-DialogManager::DialogManager(/* args */) {
+DialogManager::DialogManager(Graphics::Screen *screen, PelrockEventManager *events,
+ LargeFont *largeFont, SmallFont *smallFont)
+ : _screen(screen), _events(events),
+ _largeFont(largeFont), _smallFont(smallFont) {
}
DialogManager::~DialogManager() {
+ delete _currentChoices;
+ _currentChoices = nullptr;
+}
+
+uint32 DialogManager::readTextBlock(
+ const byte *data,
+ uint32 dataSize,
+ uint32 startPos,
+ Common::String &outText,
+ byte &outSpeakerId) {
+ uint32 pos = startPos;
+ outSpeakerId = ALFRED_COLOR; // Default to Alfred's color
+ outText = "";
+
+ // Skip control bytes at start
+ while (pos < dataSize &&
+ (data[pos] == CTRL_ALT_END_MARKER_1 || data[pos] == CTRL_ALT_END_MARKER_2 ||
+ data[pos] == CTRL_ALT_END_MARKER_3 || data[pos] == CTRL_TEXT_TERMINATOR ||
+ data[pos] == CTRL_GO_BACK)) {
+ pos++;
+ }
+
+ if (pos >= dataSize) {
+ return pos;
+ }
+
+ // Check for speaker ID marker
+ if (data[pos] == CTRL_SPEAKER_ID) {
+ pos++;
+ if (pos < dataSize) {
+ outSpeakerId = data[pos];
+ pos++;
+ }
+ }
+ // Check for dialogue marker (choice text)
+ else if (data[pos] == CTRL_DIALOGUE_MARKER || data[pos] == CTRL_DIALOGUE_MARKER_2) {
+ pos++; // Skip marker
+
+ // Skip choice index
+ if (pos < dataSize) {
+ pos++;
+ }
+
+ // Skip 2 bytes after choice index (speaker marker bytes)
+ if (pos < dataSize) {
+ pos++;
+ }
+ if (pos < dataSize) {
+ pos++;
+ }
+
+ // Choice text is always spoken by ALFRED
+ outSpeakerId = ALFRED_COLOR;
+ }
+
+ // Read text until control byte
+ while (pos < dataSize) {
+ byte b = data[pos];
+
+ // End markers - stop reading text
+ if (b == CTRL_END_TEXT || b == CTRL_END_CONVERSATION || b == CTRL_ACTION_TRIGGER ||
+ b == CTRL_END_BRANCH || b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_2 ||
+ b == CTRL_TEXT_TERMINATOR || b == CTRL_ALT_END_MARKER_1 || b == CTRL_ALT_END_MARKER_2 ||
+ b == CTRL_ALT_END_MARKER_3 || b == CTRL_GO_BACK || b == CTRL_SPEAKER_ID) {
+ break;
+ }
+
+ if (b == CTRL_LINE_CONTINUE || b == CTRL_PAGE_BREAK_CONV) {
+ outText += ' ';
+ pos++;
+ continue;
+ }
+
+ if (b == 0x0A || b == 0x0B || b == 0x00) {
+ debug("Skipping byte 0x%02X at pos %u", b, pos);
+ pos++; // Skip nulls and line feeds
+ continue;
+ }
+
+ // Regular text - decode the character
+ if (b >= 0x20 && b <= 0x7A) {
+ outText += decodeChar(b);
+ } else {
+ // Try to decode special characters
+ byte decoded = decodeChar(b);
+ if (decoded != b || (decoded >= 0x20 && decoded <= 0x83)) {
+ outText += (char)decoded;
+ }
+ }
+ pos++;
+ }
+
+ return pos;
+}
+
+void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer) {
+ int overlayHeight = choices->size() * kChoiceHeight + 2;
+ int overlayY = 400 - overlayHeight;
+ for (int x = 0; x < 640; x++) {
+ for (int y = overlayY; y < 400; y++) {
+ int index = y * 640 + x;
+ compositeBuffer[index] = g_engine->_room->overlayRemap[compositeBuffer[index]];
+ }
+ }
+ for (int i = 0; i < choices->size(); i++) {
+ drawText(compositeBuffer, g_engine->_smallFont, (*choices)[i].text, 10, overlayY + 2 + i * kChoiceHeight, 620, 9);
+ }
+}
+
+/**
+ * Display dialogue text and wait for click to advance
+ * @param text The text to display
+ * @param speakerId The speaker ID which is used as color
+ */
+void DialogManager::displayDialogue(const Common::String &text, byte speakerId) {
+ if (text.empty() || text.size() <= 1) {
+ return;
+ }
+
+ // Clear any existing click state
+ _events->_leftMouseClicked = false;
+
+ // Render loop - display text and wait for click
+ while (!g_engine->shouldQuit()) {
+ _events->pollEvent();
+
+ // Render the scene (keeps animations going)
+ g_engine->renderScene(false);
+
+ // Draw the dialogue text on top using speaker ID as color
+ drawText(g_engine->_largeFont, text, _curSprite->x, _curSprite->y - 10, 640, speakerId);
+ // drawText(g_engine->_largeFont, "Hola", 10, 10, 640, speakerId);
+
+ // Present to screen
+ _screen->markAllDirty();
+ _screen->update();
+
+ if (_events->_leftMouseClicked) {
+ _events->_leftMouseClicked = false;
+ break;
+ }
+ g_system->delayMillis(10);
+ }
+}
+
+/**
+ * Select a choice from displayed options
+ * Returns the index of the selected choice in the choices array
+ */
+int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer) {
+ // Clear any existing click state
+ _events->_leftMouseClicked = false;
+
+ int overlayHeight = choices.size() * kChoiceHeight + 2;
+ int overlayY = 400 - overlayHeight;
+
+ while (!g_engine->shouldQuit()) {
+ _events->pollEvent();
+
+ // Render the scene with choices overlay
+ g_engine->renderScene(true);
+
+ if (_events->_leftMouseClicked) {
+ _events->_leftMouseClicked = false;
+
+ // Check if click is in the choices area
+ if (_events->_mouseClickY >= overlayY) {
+ int selectedIndex = (_events->_mouseClickY - overlayY - 2) / kChoiceHeight;
+ if (selectedIndex >= 0 && selectedIndex < (int)choices.size()) {
+ return selectedIndex;
+ }
+ }
+ }
+ g_engine->_screen->update();
+ g_system->delayMillis(10);
+ }
+
+ return 0;
+}
+
+/**
+ * Parse conversation choices from the data
+ * @param data The conversation data
+ * @param dataSize Size of data
+ * @param startPos Starting position
+ * @param outChoices Output: array of choice options
+ * @return The position after parsing choices
+ */
+uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 startPos,
+ Common::Array<ChoiceOption> &outChoices) {
+ uint32 pos = startPos;
+ outChoices.clear();
+ int firstChoiceIndex = -1;
+ int choiceCount = 0;
+
+ // Find first choice marker
+ while (pos < dataSize) {
+ byte b = data[pos];
+
+ // Stop at end markers
+ if (b == CTRL_ALT_END_MARKER_1 || b == CTRL_END_BRANCH || b == CTRL_ALT_END_MARKER_3) {
+ break;
+ }
+
+ // Found first choice marker
+ if (b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_2) {
+ if (pos + 1 < dataSize) {
+ firstChoiceIndex = data[pos + 1];
+ ChoiceOption opt;
+ opt.index = firstChoiceIndex;
+ opt.dataOffset = pos;
+ opt.isDisabled = false;
+
+ // Parse the choice text
+ uint32 textPos = pos + 4; // Skip marker + index + 2 speaker bytes
+ while (textPos < dataSize) {
+ byte tb = data[textPos];
+ if (tb == CTRL_END_TEXT || tb == CTRL_DIALOGUE_MARKER ||
+ tb == CTRL_DIALOGUE_MARKER_2 || tb == CTRL_END_BRANCH ||
+ tb == CTRL_ALT_END_MARKER_1) {
+ break;
+ }
+
+ if (b == 0x0A || b == 0x0B || b == 0x00) {
+ debug("Skipping byte 0x%02X at pos %u", b, pos);
+ pos++; // Skip nulls and line feeds
+ continue;
+ }
+
+ if (tb >= 0x20 && tb <= 0x7A) {
+ opt.text += (char)tb;
+ } else {
+ byte decoded = decodeChar(tb);
+ if (decoded != tb || (decoded >= 0x20 && decoded <= 0x83)) {
+ opt.text += (char)decoded;
+ }
+ }
+ textPos++;
+ }
+
+ outChoices.push_back(opt);
+ choiceCount = 1;
+ pos++;
+ break;
+ }
+ }
+
+ pos++;
+ }
+
+ // Scan for additional choices with SAME index
+ while (pos < dataSize) {
+ byte b = data[pos];
+
+ // Stop at end markers
+ if (b == CTRL_ALT_END_MARKER_1 || b == CTRL_END_BRANCH || b == CTRL_ALT_END_MARKER_3) {
+ break;
+ }
+
+ // Found a dialogue marker
+ if (b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_2) {
+ if (pos + 1 < dataSize) {
+ int choiceIndex = data[pos + 1];
+
+ // Only collect choices with same index
+ if (choiceIndex == firstChoiceIndex) {
+ // Check if disabled
+ bool isDisabled = (b == CTRL_DISABLED_CHOICE);
+
+ ChoiceOption opt;
+ opt.index = choiceIndex;
+ opt.dataOffset = pos;
+ opt.isDisabled = isDisabled;
+
+ // Parse the choice text
+ uint32 textPos = pos + 4;
+ while (textPos < dataSize) {
+ byte tb = data[textPos];
+ if (tb == CTRL_END_TEXT || tb == CTRL_DIALOGUE_MARKER ||
+ tb == CTRL_DIALOGUE_MARKER_2 || tb == CTRL_END_BRANCH ||
+ tb == CTRL_ALT_END_MARKER_1) {
+ break;
+ }
+
+ if (b == 0x0A || b == 0x0B || b == 0x00) {
+ debug("Skipping byte 0x%02X at pos %u", b, pos);
+ pos++; // Skip nulls and line feeds
+ continue;
+ }
+
+ if (tb >= 0x20 && tb <= 0x7A) {
+ opt.text += (char)tb;
+ } else {
+ byte decoded = decodeChar(tb);
+ if (decoded != tb || (decoded >= 0x20 && decoded <= 0x83)) {
+ opt.text += (char)decoded;
+ }
+ }
+ textPos++;
+ }
+
+ outChoices.push_back(opt);
+ choiceCount++;
+ } else if (choiceIndex < firstChoiceIndex) {
+ // Different choice index - stop scanning
+ break;
+ }
+ }
+ }
+
+ pos++;
+ }
+
+ return pos;
}
-void DialogManager::startConversation(ConversationNode &root) {
+void DialogManager::startConversation(const byte *conversationData, uint32 dataSize, Sprite *animSet) {
+ if (!conversationData || dataSize == 0) {
+ debug("startConversation: No conversation data");
+ return;
+ }
+ _curSprite = animSet;
+
+ debug("Starting conversation with %u bytes of data", dataSize);
+
+ uint32 position = 0;
+
+ // Skip any junk at start until we find a speaker marker or choice marker
+ while (position < dataSize &&
+ conversationData[position] != CTRL_SPEAKER_ID &&
+ conversationData[position] != CTRL_DIALOGUE_MARKER &&
+ conversationData[position] != CTRL_DIALOGUE_MARKER_2) {
+ position++;
+ }
+
+ // OUTER LOOP: Continue until conversation ends
+ while (position < dataSize && !g_engine->shouldQuit()) {
+ // Skip control bytes that should be ignored
+ while (position < dataSize &&
+ (conversationData[position] == CTRL_ALT_END_MARKER_1 ||
+ conversationData[position] == CTRL_ALT_END_MARKER_2 ||
+ conversationData[position] == CTRL_ALT_END_MARKER_3 ||
+ conversationData[position] == CTRL_TEXT_TERMINATOR ||
+ conversationData[position] == CTRL_GO_BACK)) {
+ position++;
+ }
+
+ if (position >= dataSize) {
+ debug("Reached end of data while skipping control bytes");
+ break;
+ }
+
+ // 1. Read and display current dialogue
+ Common::String text;
+ byte speakerId;
+ uint32 endPos = readTextBlock(conversationData, dataSize, position, text, speakerId);
+
+ // Skip spurious single character artifacts
+ if (!text.empty() && text.size() > 1) {
+ debug("Dialogue: \"%s\" (Speaker ID: %u)", text.c_str(), speakerId);
+ displayDialogue(text, speakerId);
+ }
+
+ // Move to end of text
+ position = endPos;
+
+ // 2. Check for end of conversation
+ if (position >= dataSize) {
+ debug("Reached end of data after reading dialogue");
+ break;
+ }
+
+ byte controlByte = conversationData[position];
+
+ if (controlByte == CTRL_END_CONVERSATION) {
+ debug("End of conversation marker found");
+ break;
+ }
+
+ // Move past control byte
+ if (controlByte == CTRL_END_TEXT || controlByte == CTRL_ACTION_TRIGGER) {
+ position++;
+ if (position >= dataSize) {
+ debug("Reached end of data after moving past control byte");
+ break;
+ }
+ }
+
+ // 3. Before parsing choices, check if we're at a choice marker
+ // Skip control bytes to peek at next meaningful byte
+ uint32 peekPos = position;
+ while (peekPos < dataSize &&
+ (conversationData[peekPos] == CTRL_ALT_END_MARKER_1 ||
+ conversationData[peekPos] == CTRL_ALT_END_MARKER_2 ||
+ conversationData[peekPos] == CTRL_ALT_END_MARKER_3 ||
+ conversationData[peekPos] == CTRL_TEXT_TERMINATOR ||
+ conversationData[peekPos] == CTRL_GO_BACK)) {
+ peekPos++;
+ }
+
+ // If not at a choice marker, there's more dialogue to read
+ if (peekPos < dataSize &&
+ conversationData[peekPos] != CTRL_DIALOGUE_MARKER &&
+ conversationData[peekPos] != CTRL_DIALOGUE_MARKER_2 &&
+ conversationData[peekPos] != CTRL_END_CONVERSATION) {
+ continue;
+ }
+
+ // 4. Parse choices
+ debug("Parsing choices at pos %u", position);
+ Common::Array<ChoiceOption> choices;
+ parseChoices(conversationData, dataSize, position, choices);
+ debug("Parsed %u choices", choices.size());
+ for (uint i = 0; i < choices.size(); i++) {
+ debug(" Choice %u: \"%s\" (Disabled: %s)", i, choices[i].text.c_str(),
+ choices[i].isDisabled ? "Yes" : "No");
+ }
+ if (choices.empty()) {
+ // No choices, continue reading dialogue
+ position = peekPos;
+ continue;
+ }
+
+ // 5. Display choices and get selection
+ int selectedIndex = 0;
+
+ // Check if this is auto-dialogue (only one choice)
+ if (choices.size() == 1) {
+ // Auto-dialogue: display it automatically
+ displayDialogue(choices[0].text, ALFRED_COLOR);
+ selectedIndex = 0;
+ } else {
+ // Real choice: show menu and wait for selection
+ Common::Array<Common::String> choiceTexts;
+ for (uint i = 0; i < choices.size(); i++) {
+ if (choices[i].isDisabled) {
+ choiceTexts.push_back("[DISABLED] " + choices[i].text);
+ } else {
+ choiceTexts.push_back(choices[i].text);
+ }
+ }
+ _currentChoices = &choices;
+ // Use displayChoices to show and select
+ selectedIndex = selectChoice(choiceTexts, g_engine->_compositeBuffer);
+ }
+
+ // 6. Move position to after the selected choice
+ if (selectedIndex >= 0 && selectedIndex < (int)choices.size()) {
+ position = choices[selectedIndex].dataOffset;
+
+ // Read and display the selected choice as dialogue
+ Common::String choiceText;
+ byte choiceSpeakerId;
+ endPos = readTextBlock(conversationData, dataSize, position, choiceText, choiceSpeakerId);
+
+ if (!choiceText.empty() && choiceText.size() > 1) {
+ displayDialogue(choiceText, ALFRED_COLOR);
+ }
+
+ position = endPos;
+
+ // Skip past end marker
+ if (position < dataSize) {
+ byte endByte = conversationData[position];
+ if (endByte == CTRL_END_TEXT || endByte == CTRL_END_BRANCH ||
+ endByte == CTRL_ACTION_TRIGGER) {
+ position++;
+ }
+ }
+ }
+ }
+ debug("Conversation ended");
+ // Note: The caller should set inConversation = false after this returns
}
} // namespace Pelrock
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index ae1b032c04f..816d9f32dab 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -21,22 +21,53 @@
#ifndef PELROCK_DIALOG_H
#define PELROCK_DIALOG_H
-#include "common/array.h"
#include "common/scummsys.h"
+#include "graphics/screen.h"
-#include "pelrock/pelrock.h"
+#include "pelrock/events.h"
+#include "pelrock/fonts/large_font.h"
+#include "pelrock/fonts/small_font.h"
#include "pelrock/types.h"
+
namespace Pelrock {
+/**
+ * Structure to hold a parsed choice option
+ */
+struct ChoiceOption {
+ int index;
+ Common::String text;
+ bool isDisabled;
+ uint32 dataOffset;
+
+ ChoiceOption() : index(-1), isDisabled(false), dataOffset(0) {}
+};
-class DialogManager
-{
+class DialogManager {
private:
- /* data */
+ Graphics::Screen *_screen = nullptr;
+ PelrockEventManager *_events = nullptr;
+ LargeFont *_largeFont = nullptr;
+ SmallFont *_smallFont = nullptr;
+ Sprite *_curSprite = nullptr;
+
+ // Private helper functions for conversation parsing
+ void displayDialogue(const Common::String &text, byte speakerId);
+ uint32 readTextBlock(const byte *data, uint32 dataSize, uint32 startPos,
+ Common::String &outText, byte &outSpeakerId);
+ uint32 parseChoices(const byte *data, uint32 dataSize, uint32 startPos, Common::Array<ChoiceOption> &outChoices);
+
+ void checkMouse();
+
public:
- DialogManager(/* args */);
- ~DialogManager();
+ DialogManager(Graphics::Screen *screen, PelrockEventManager *events,
+ LargeFont *largeFont, SmallFont *smallFont);
+ ~DialogManager();
+
+ void displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer);
+ int selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer);
+ void startConversation(const byte *conversationData, uint32 dataSize, Sprite *alfredAnimSet = nullptr);
- void startConversation(ConversationNode &root);
+ Common::Array<ChoiceOption> *_currentChoices = nullptr;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index d935e5fa27f..942fcb31b5e 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -13,7 +13,8 @@ MODULE_OBJS = \
sound.o \
video/video.o \
pathfinding.o \
- events.o
+ events.o \
+ dialog.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index fc471ab0c36..d9a7c8da098 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -20,7 +20,6 @@
*/
#include "common/config-manager.h"
-#include "common/debug-channels.h"
#include "common/endian.h"
#include "common/events.h"
#include "common/file.h"
@@ -77,7 +76,7 @@ Common::String PelrockEngine::getGameId() const {
return _gameDescription->gameId;
}
-Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
+// Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
@@ -87,6 +86,7 @@ Common::Error PelrockEngine::run() {
_room = new RoomManager();
_res = new ResourceManager();
_sound = new SoundManager(_mixer);
+ _dialog = new DialogManager(_screen, _events, _largeFont, _smallFont);
// Set the engine's debugger console
setDebugger(new PelrockConsole(this));
@@ -154,20 +154,6 @@ void PelrockEngine::loadAnims() {
_res->loadAlfredAnims();
}
-void PelrockEngine::displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer) {
- int overlayHeight = choices.size() * kChoiceHeight + 2;
- int overlayY = 400 - overlayHeight;
- for (int x = 0; x < 640; x++) {
- for (int y = overlayY; y < 400; y++) {
- int index = y * 640 + x;
- compositeBuffer[index] = _room->overlayRemap[compositeBuffer[index]];
- }
- }
- for (int i = 0; i < choices.size(); i++) {
- drawText(choices[i], 10, overlayY + 2 + i * kChoiceHeight, 620, 15);
- }
-}
-
byte *PelrockEngine::grabBackgroundSlice(int x, int y, int w, int h) {
byte *bg = new byte[w * h];
for (int j = 0; j < w; j++) {
@@ -240,13 +226,13 @@ void PelrockEngine::playSoundIfNeeded() {
int soundIndex = _sound->tick(_chrono->getFrameCount());
if (soundIndex >= 0 && soundIndex < _room->_roomSfx.size()) {
- debug("Playing SFX index %d", soundIndex);
_sound->playSound(_room->_roomSfx[3 + soundIndex]);
}
}
void PelrockEngine::renderScene(bool showTextOverlay) {
+ _chrono->updateChrono();
if (_chrono->_gameTick) {
playSoundIfNeeded();
@@ -254,11 +240,9 @@ void PelrockEngine::renderScene(bool showTextOverlay) {
updateAnimations();
if (showTextOverlay) {
- displayChoices(_currentTextPages[_currentTextPageIndex], _compositeBuffer);
+ _dialog->displayChoices(_dialog->_currentChoices, _compositeBuffer);
}
- checkMouse();
-
presentFrame();
updatePaletteAnimations();
@@ -288,13 +272,11 @@ void PelrockEngine::renderScene(bool showTextOverlay) {
// }
// if (alfredState.animState == ALFRED_IDLE && alfredState.nextState != ALFRED_IDLE) {
- // // debug("Switching Alfred state from IDLE to %d", alfredState.nextState);
// alfredState.animState = alfredState.nextState;
// alfredState.nextState = ALFRED_IDLE;
// alfredState.curFrame = 0;
// }
- // debug("Drawing walkboxes..., %d, _currentRoomWalkboxes.size()=%d", _currentRoomWalkboxes.size(), _currentRoomWalkboxes.size());
_screen->markAllDirty();
}
@@ -311,7 +293,6 @@ void PelrockEngine::checkMouse() {
_events->_longClicked = false;
}
else if(_events->_rightMouseClicked) {
- debug("Right mouse clicked - entering settings menu");
g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
_events->_rightMouseClicked = false;
stateGame = SETTINGS;
@@ -321,7 +302,6 @@ void PelrockEngine::checkMouse() {
//else if (e.type == Common::EVENT_MOUSEMOVE) {
// mouseX = e.mouse.x;
// mouseY = e.mouse.y;
- // // debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
// } else if (e.type == Common::EVENT_LBUTTONDOWN) {
// if (!_isMouseDown) {
// _mouseClickTime = g_system->getMillis();
@@ -339,7 +319,6 @@ void PelrockEngine::checkMouse() {
// }
// if (_isMouseDown) {
// if (g_system->getMillis() - _mouseClickTime >= kLongClickDuration) {
- // debug("long click!");
// _longClick = true;
// _isMouseDown = false;
// checkLongMouseClick(e.mouse.x, e.mouse.y);
@@ -406,7 +385,6 @@ void PelrockEngine::updatePaletteAnimations() {
void PelrockEngine::paintDebugLayer() {
for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
- // debug("Drawing walkbox %d", i);
WalkBox box = _room->_currentRoomWalkboxes[i];
drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
_smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
@@ -506,38 +484,20 @@ void PelrockEngine::doAction(byte action, HotSpot *hotspot) {
}
void PelrockEngine::talkTo(HotSpot *hotspot) {
- debug("Talking to object %d", hotspot->index);
- if (_room->_currentRoomConversations.size() == 0)
- return;
-
Sprite *animSet;
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (i == hotspot->index) {
animSet = &_room->_currentRoomAnims[i];
+ break;
}
}
-
- ConversationNode selectedNode = _room->_currentRoomConversations[0];
-
- bool isNPC = selectedNode.speakerId != 13;
- if (isNPC) {
- sayNPC(animSet, selectedNode.text, selectedNode.speakerId);
- }
- // for(int i= 0; i< _currentRoomConversations.size(); i++) {
- // _currentRoomConversations
- // }
-
- // showDescription(_currentRoomConversations[0].text, x, y, _currentRoomConversations[0].speakerId);
- // for(int i = 0; i < _currentRoomConversations[0].choices.size(); i++) {
- // int idx = _currentRoomConversations.size() - 1 - i;
- // _smallFont->drawString(_screen, _currentRoomConversations[0].choices[idx].text.c_str(), 0, 400 - ((i + 1) * 12), 640, 14);
- // }
+ debug("Starting conversation with hotspot %d, animSet pos %d", hotspot->index, animSet->x);
+ _dialog->startConversation(_room->_conversationData, _room->_conversationDataSize, animSet);
}
void PelrockEngine::lookAt(HotSpot *hotspot) {
- debug("Look action clicked");
walkTo(_currentHotspot->x, _currentHotspot->y);
- sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index].text);
+ // sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index].text);
_displayPopup = false;
}
@@ -565,7 +525,7 @@ void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, i
for (size_t i = 0; i < lines.size(); i++) {
int textX = baseX - (maxW / 2);
int textY = baseY - (lineSize * 25) + (i * 25);
- drawText(lines[i], textX, textY, maxW, color);
+ drawText(_largeFont, lines[i], textX, textY, maxW, color);
}
}
@@ -652,7 +612,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.curFrame++;
break;
default:
- // debug("Drawing Alfred idle frame for direction %d", alfredState.direction);
drawAlfred(_res->alfredIdle[alfredState.direction]);
break;
}
@@ -678,10 +637,8 @@ void PelrockEngine::drawAlfred(byte *buf) {
if (scaleIndex < 0) {
scaleIndex = 0;
}
- // debug("Scaling Alfred frame to final size (%d x %d) from scale factor %.2f", finalWidth, finalHeight, scaleFactor);
int linesToSkip = kAlfredFrameHeight - finalHeight;
- // debug("lines to skip = %d, finalHeight = %d, finalWidth = %d for position (%d, %d)", linesToSkip, finalHeight, finalWidth, xAlfred, yAlfred);
int shadowPos = alfredState.y; // - finalHeight;
bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + alfredState.x] != 0xFF;
@@ -696,7 +653,6 @@ void PelrockEngine::drawAlfred(byte *buf) {
idealSkipPositions.push_back(idealPos);
}
- // debug("Height scaling table size =%d", _heightScalingTable.size());
Common::Array<int> tableSkipPositions;
for (int scanline = 0; scanline < kAlfredFrameHeight; scanline++) {
if (_heightScalingTable[scaleIndex][scanline] != 0) {
@@ -704,9 +660,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
}
- // debug("Table skip positions:");
// for (size_t i = 0; i < tableSkipPositions.size(); i++) {
- // debug(" %d", tableSkipPositions[i]);
// }
Common::Array<int> skipTheseLines;
@@ -748,7 +702,6 @@ void PelrockEngine::drawAlfred(byte *buf) {
int srcIndex = srcY * kAlfredFrameWidth + srcX;
int outIndex = outY * finalWidth + outX;
if (outIndex >= finalWidth * finalHeight || srcIndex >= kAlfredFrameWidth * kAlfredFrameHeight) {
- debug("Index out of bounds!");
} else
finalBuf[outIndex] = buf[srcIndex];
}
@@ -869,7 +822,6 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
_displayPopup = true;
_currentPopupFrame = 0;
_currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
- debug("Current hotspot (x=%d, y=%d) with extra = %d type: %d, desc= %s", _currentHotspot->x, _currentHotspot->y, _currentHotspot->extra, _currentHotspot->type, _room->_currentRoomDescriptions[_currentHotspot->index].text.c_str());
}
}
@@ -881,7 +833,6 @@ void PelrockEngine::checkMouseClickOnSettings(int x, int y) {
y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
selectedInvIndex = curInventoryPage * 4 + i;
_menuText = _res->getInventoryObject(selectedInvIndex).description;
- debug("Selected inventory index: %d", selectedInvIndex);
selectedItem = true;
return;
}
@@ -1080,19 +1031,11 @@ void PelrockEngine::drawTalkNPC(Sprite *animSet) {
curFrame = 0;
}
byte *frame = index ? animHeader->animB[curFrame] : animHeader->animA[curFrame];
- // debug("Talking NPC frame %d/%d, x=%d, y=%d, w=%d, h=%d", curFrame, numFrames, x, y, w, h);
drawSpriteToBuffer(_compositeBuffer, 640, frame, x, y, w, h, 255);
}
-void PelrockEngine::conversationLoop() {
- while (inConversation) {
-
- }
-}
-
void PelrockEngine::gameLoop() {
- _chrono->updateChrono();
_events->pollEvent();
// while (g_system->getEventManager()->pollEvent(e)) {
// if (e.type == Common::EVENT_KEYDOWN) {
@@ -1115,46 +1058,18 @@ void PelrockEngine::gameLoop() {
// case Common::KEYCODE_z:
// showShadows = !showShadows;
// break;
- // case Common::KEYCODE_y:
- // alfredState.x = 193;
- // alfredState.y = 382;
- // walkTo(377, 318);
- // break;
// default:
// break;
// }
- // } else if (e.type == Common::EVENT_MOUSEMOVE) {
- // mouseX = e.mouse.x;
- // mouseY = e.mouse.y;
- // // debug(3, "Mouse moved to (%d,%d)", mouseX, mouseY);
- // } else if (e.type == Common::EVENT_LBUTTONDOWN) {
- // if (!_isMouseDown) {
- // _mouseClickTime = g_system->getMillis();
- // _isMouseDown = true;
- // }
- // } else if (e.type == Common::EVENT_LBUTTONUP) {
- // _isMouseDown = false;
- // checkMouseClick(e.mouse.x, e.mouse.y);
- // _displayPopup = false;
- // _longClick = false;
- // } else if (e.type == Common::EVENT_RBUTTONUP) {
- // g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
- // stateGame = SETTINGS;
- // }
- // }
- // if (_isMouseDown) {
- // if (g_system->getMillis() - _mouseClickTime >= kLongClickDuration) {
- // debug("long click!");
- // _longClick = true;
- // _isMouseDown = false;
- // checkLongMouseClick(e.mouse.x, e.mouse.y);
// }
- // }
- // checkMouseHover();
if (inConversation) {
- conversationLoop();
+ // TODO: Pass actual conversation data from room
+ // For now, using nullptr to disable - actual data needs to be loaded
+ _dialog->startConversation(nullptr, 0);
+ inConversation = false;
} else {
+ checkMouse();
renderScene();
}
}
@@ -1232,7 +1147,6 @@ void PelrockEngine::checkMouseClick(int x, int y) {
// Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
VerbIcon actionClicked = isActionUnder(x, y);
if (actionClicked != NO_ACTION) {
- debug("Action %d clicked", actionClicked);
doAction(actionClicked, _currentHotspot);
_displayPopup = false;
return;
@@ -1252,7 +1166,6 @@ void PelrockEngine::checkMouseClick(int x, int y) {
alfredState.x = exit->targetX;
alfredState.y = exit->targetY;
- debug("Placing character at %d, %d", exit->targetX, exit->targetY);
setScreen(exit->targetRoom, exit->dir);
} else {
walkTo(walkTarget.x, walkTarget.y);
@@ -1304,235 +1217,141 @@ void PelrockEngine::checkMouseHover() {
}
}
-// Common::Point PelrockEngine::calculateWalkTarget(int mouseX, int mouseY) {
-// // Starting point for pathfinding
-// int sourceX = mouseX;
-// int sourceY = mouseY;
-
-// // TODO: If hovering over a sprite/hotspot, adjust source point to sprite center
-// // For now, just use mouse position
-
-// // Find nearest walkable point in walkboxes
-// uint32 minDistance = 0xFFFFFFFF;
-// Common::Point bestTarget(sourceX, sourceY);
-
-// // for (Common::List<WalkBox>::iterator it = _currentRoomWalkboxes.begin();
-// // it != _currentRoomWalkboxes.end(); ++it) {
-// for (size_t i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
+// void PelrockEngine::sayNPC(Sprite *anim, Common::String text, byte color) {
+// isNPCATalking = true;
+// whichNPCTalking = anim->extra;
+// _currentTextPages = wordWrap(text);
+// _textColor = color;
+// int totalChars = 0;
+// for (int i = 0; i < _currentTextPages[0].size(); i++) {
+// totalChars += _currentTextPages[0][i].size();
+// }
+// _textPos = Common::Point(anim->x, anim->y - 10);
+// _textDurationFrames = totalChars / 2;
+// }
-// // Calculate distance from source point to this walkbox (Manhattan distance)
-// int dx = 0;
-// int dy = 0;
+// void PelrockEngine::sayAlfred(Common::String text) {
+// alfredState.nextState = ALFRED_TALKING;
+// alfredState.curFrame = 0;
+// _currentTextPages = wordWrap(text);
+// _textColor = 13;
+// int totalChars = 0;
+// for (int i = 0; i < _currentTextPages[0].size(); i++) {
+// totalChars += _currentTextPages[0][i].size();
+// }
+// _textDurationFrames = totalChars / 2;
+// }
-// // Calculate horizontal distance
-// if (sourceX < _room->_currentRoomWalkboxes[i].x) {
-// dx = _room->_currentRoomWalkboxes[i].x - sourceX;
-// } else if (sourceX > _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w) {
-// dx = sourceX - (_room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w);
+// int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
+// // return word_length, is_end
+// int wordLength = 0;
+// int pos = startPos;
+// while (pos < text.size()) {
+// char char_byte = text[pos];
+// if (char_byte == CHAR_SPACE || isEndMarker(char_byte)) {
+// break;
// }
-// // else: sourceX is inside walkbox horizontally, dx = 0
-
-// // Calculate vertical distance
-// if (sourceY < _room->_currentRoomWalkboxes[i].y) {
-// dy = _room->_currentRoomWalkboxes[i].y - sourceY;
-// } else if (sourceY > _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h) {
-// dy = sourceY - (_room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h);
+// wordLength++;
+// pos++;
+// }
+// // Check if we hit an end marker
+// if (pos < text.size() && isEndMarker(text[pos])) {
+// isEnd = true;
+// }
+// // Count ALL trailing spaces as part of this word
+// if (pos < text.size() && !isEnd) {
+// if (text[pos] == CHAR_END_MARKER_3) { // 0xF8 (-8) special case
+// wordLength += 3;
+// } else {
+// // Count all consecutive spaces
+// while (pos < text.size() && text[pos] == CHAR_SPACE) {
+// wordLength++;
+// pos++;
+// }
// }
-// // else: sourceY is inside walkbox vertically, dy = 0
-
-// uint32 distance = dx + dy;
-
-// if (distance < minDistance) {
-// minDistance = distance;
-
-// // Calculate target point (nearest point on walkbox to source)
-// int targetX = sourceX;
-// int targetY = sourceY;
+// }
+// return wordLength;
+// }
-// if (sourceX < _room->_currentRoomWalkboxes[i].x) {
-// targetX = _room->_currentRoomWalkboxes[i].x;
-// } else if (sourceX > _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w) {
-// targetX = _room->_currentRoomWalkboxes[i].x + _room->_currentRoomWalkboxes[i].w;
+// Common::Array<Common::Array<Common::String>> wordWrap(Common::String text) {
+
+// Common::Array<Common::Array<Common::String>> pages;
+// Common::Array<Common::String> currentPage;
+// Common::Array<Common::String> currentLine;
+// int charsRemaining = MAX_CHARS_PER_LINE;
+// int position = 0;
+// int currentLineNum = 0;
+// while (position < text.size()) {
+// bool isEnd = false;
+// int wordLength = calculateWordLength(text, position, isEnd);
+// // # Extract the word (including trailing spaces)
+// // word = text[position:position + word_length].decode('latin-1', errors='replace')
+// Common::String word = text.substr(position, wordLength).decode(Common::kLatin1);
+// // # Key decision: if word_length > chars_remaining, wrap to next line
+// if (wordLength > charsRemaining) {
+// // Word is longer than the entire line - need to split
+// currentPage.push_back(joinStrings(currentLine, ""));
+// currentLine.clear();
+// charsRemaining = MAX_CHARS_PER_LINE;
+// currentLineNum++;
+
+// if (currentLineNum >= MAX_LINES) {
+// pages.push_back(currentPage);
+// currentPage.clear();
+// currentLineNum = 0;
// }
-
-// if (sourceY < _room->_currentRoomWalkboxes[i].y) {
-// targetY = _room->_currentRoomWalkboxes[i].y;
-// } else if (sourceY > _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h) {
-// targetY = _room->_currentRoomWalkboxes[i].y + _room->_currentRoomWalkboxes[i].h;
+// }
+// // Add word to current line
+// currentLine.push_back(word);
+// charsRemaining -= wordLength;
+
+// if (charsRemaining == 0 && isEnd) {
+// Common::String lineText = joinStrings(currentLine, "");
+// while (lineText.lastChar() == CHAR_SPACE) {
+// lineText = lineText.substr(0, lineText.size() - 1);
+// }
+// int trailingSpaces = currentLine.size() - lineText.size();
+// if (trailingSpaces > 0) {
+// currentPage.push_back(lineText);
+// // current_line = [' ' * trailing_spaces]
+// Common::String currentLine(trailingSpaces, ' ');
+// charsRemaining = MAX_CHARS_PER_LINE - trailingSpaces;
+// currentLineNum += 1;
+
+// if (currentLineNum >= MAX_LINES) {
+// pages.push_back(currentPage);
+// currentPage.clear();
+// currentLineNum = 0;
+// }
// }
+// }
-// bestTarget.x = targetX;
-// bestTarget.y = targetY;
+// position += wordLength;
+// if (isEnd) {
+// // End of sentence/paragraph/page
+// break;
// }
// }
-
-// return bestTarget;
+// if (currentLine.empty() == false) {
+// Common::String lineText = joinStrings(currentLine, "");
+// while (lineText.lastChar() == CHAR_SPACE) {
+// lineText = lineText.substr(0, lineText.size() - 1);
+// }
+// currentPage.push_back(lineText);
+// }
+// if (currentPage.empty() == false) {
+// pages.push_back(currentPage);
+// }
+// for (int i = 0; i < pages.size(); i++) {
+// for (int j = 0; j < pages[i].size(); j++) {
+// }
+// }
+// return pages;
// }
-void PelrockEngine::drawText(Common::String text, int x, int y, int w, byte color) {
- Common::Rect rect = _largeFont->getBoundingBox(text.c_str());
- if (x + rect.width() > 640) {
- x = 640 - rect.width() - 2;
- }
- if (y + rect.height() > 400) {
- y = 400 - rect.height();
- }
- if (x < 0) {
- x = 0;
- }
- if (y < 0) {
- y = 0;
- }
- // Draw main text on top
- _largeFont->drawString(_screen, text.c_str(), x, y, w, color, Graphics::kTextAlignCenter);
-}
-
-void PelrockEngine::sayNPC(Sprite *anim, Common::String text, byte color) {
- isNPCATalking = true;
- whichNPCTalking = anim->extra;
- debug("NPC says %s, color = %d", text.c_str(), color);
- _currentTextPages = wordWrap(text);
- _textColor = color;
- int totalChars = 0;
- for (int i = 0; i < _currentTextPages[0].size(); i++) {
- totalChars += _currentTextPages[0][i].size();
- }
- debug("Settijng textpos to %d, %d", anim->x, anim->y - 10);
- _textPos = Common::Point(anim->x, anim->y - 10);
- _textDurationFrames = totalChars / 2;
-}
-
-void PelrockEngine::sayAlfred(Common::String text) {
- alfredState.nextState = ALFRED_TALKING;
- alfredState.curFrame = 0;
- debug("Alfred says: %s", text.c_str());
- _currentTextPages = wordWrap(text);
- _textColor = 13;
- int totalChars = 0;
- for (int i = 0; i < _currentTextPages[0].size(); i++) {
- totalChars += _currentTextPages[0][i].size();
- }
- _textDurationFrames = totalChars / 2;
-}
-
-bool isEndMarker(char char_byte) {
- return char_byte == CHAR_END_MARKER_1 || char_byte == CHAR_END_MARKER_2 || char_byte == CHAR_END_MARKER_3 || char_byte == CHAR_END_MARKER_4;
-}
-
-int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
- // return word_length, is_end
- int wordLength = 0;
- int pos = startPos;
- while (pos < text.size()) {
- char char_byte = text[pos];
- if (char_byte == CHAR_SPACE || isEndMarker(char_byte)) {
- break;
- }
- wordLength++;
- pos++;
- }
- // Check if we hit an end marker
- if (pos < text.size() && isEndMarker(text[pos])) {
- isEnd = true;
- }
- // Count ALL trailing spaces as part of this word
- if (pos < text.size() && !isEnd) {
- if (text[pos] == CHAR_END_MARKER_3) { // 0xF8 (-8) special case
- wordLength += 3;
- } else {
- // Count all consecutive spaces
- while (pos < text.size() && text[pos] == CHAR_SPACE) {
- wordLength++;
- pos++;
- }
- }
- }
- return wordLength;
-}
-
-Common::Array<Common::Array<Common::String>> wordWrap(Common::String text) {
-
- Common::Array<Common::Array<Common::String>> pages;
- Common::Array<Common::String> currentPage;
- Common::Array<Common::String> currentLine;
- int charsRemaining = MAX_CHARS_PER_LINE;
- int position = 0;
- int currentLineNum = 0;
- while (position < text.size()) {
- bool isEnd = false;
- int wordLength = calculateWordLength(text, position, isEnd);
- // # Extract the word (including trailing spaces)
- // word = text[position:position + word_length].decode('latin-1', errors='replace')
- Common::String word = text.substr(position, wordLength).decode(Common::kLatin1);
- // # Key decision: if word_length > chars_remaining, wrap to next line
- if (wordLength > charsRemaining) {
- // Word is longer than the entire line - need to split
- currentPage.push_back(joinStrings(currentLine, ""));
- currentLine.clear();
- charsRemaining = MAX_CHARS_PER_LINE;
- currentLineNum++;
-
- if (currentLineNum >= MAX_LINES) {
- pages.push_back(currentPage);
- currentPage.clear();
- currentLineNum = 0;
- }
- }
- // Add word to current line
- currentLine.push_back(word);
- charsRemaining -= wordLength;
-
- if (charsRemaining == 0 && isEnd) {
- Common::String lineText = joinStrings(currentLine, "");
- while (lineText.lastChar() == CHAR_SPACE) {
- lineText = lineText.substr(0, lineText.size() - 1);
- }
- int trailingSpaces = currentLine.size() - lineText.size();
- if (trailingSpaces > 0) {
- currentPage.push_back(lineText);
- // current_line = [' ' * trailing_spaces]
- Common::String currentLine(trailingSpaces, ' ');
- charsRemaining = MAX_CHARS_PER_LINE - trailingSpaces;
- currentLineNum += 1;
-
- if (currentLineNum >= MAX_LINES) {
- pages.push_back(currentPage);
- currentPage.clear();
- currentLineNum = 0;
- }
- }
- }
-
- position += wordLength;
- if (isEnd) {
- // End of sentence/paragraph/page
- break;
- }
- }
- if (currentLine.empty() == false) {
- Common::String lineText = joinStrings(currentLine, "");
- while (lineText.lastChar() == CHAR_SPACE) {
- lineText = lineText.substr(0, lineText.size() - 1);
- }
- currentPage.push_back(lineText);
- }
- if (currentPage.empty() == false) {
- pages.push_back(currentPage);
- }
- debug("Word wrap produced %d pages", pages.size());
- for (int i = 0; i < pages.size(); i++) {
- debug(" Page %d:", i);
- for (int j = 0; j < pages[i].size(); j++) {
- debug(" Line %d: %s", j, pages[i][j].c_str());
- }
- }
- return pages;
-}
-
void PelrockEngine::setScreen(int number, AlfredDirection dir) {
_sound->stopAllSounds();
Common::File roomFile;
- debug("Loading room %s number %d", _room->getRoomName(number).c_str(), number);
if (!roomFile.open(Common::Path("ALFRED.1"))) {
error("Could not open ALFRED.1");
return;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index b19d94498c1..8fdf33ee2a4 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -38,6 +38,7 @@
#include "pelrock/chrono.h"
#include "pelrock/detection.h"
+#include "pelrock/dialog.h"
#include "pelrock/events.h"
#include "pelrock/fonts/large_font.h"
#include "pelrock/fonts/small_font.h"
@@ -55,12 +56,12 @@ class PelrockEngine : public Engine {
private:
const ADGameDescription *_gameDescription;
Common::RandomSource _randomSource;
- RoomManager *_room = nullptr;
ResourceManager *_res = nullptr;
ChronoManager *_chrono = nullptr;
VideoManager *_videoManager = nullptr;
SoundManager *_sound = nullptr;
PelrockEventManager *_events = nullptr;
+ DialogManager *_dialog = nullptr;
void init();
void loadAnims();
@@ -71,7 +72,6 @@ private:
void walkTo(int x, int y);
void talk(byte object);
- void displayChoices(Common::Array<Common::String> choices, byte *compositeBuffer);
void sayAlfred(Common::String text);
void sayNPC(Sprite *anim, Common::String text, byte color);
@@ -86,9 +86,6 @@ private:
Sprite *isSpriteUnder(int x, int y);
void showActionBalloon(int posx, int posy, int curFrame);
- void drawText(Common::String text, int x, int y, int w, byte color);
-
- void renderScene(bool showTextOverlay = false);
void checkMouse();
void copyBackgroundToBuffer();
void updateAnimations();
@@ -111,7 +108,6 @@ private:
void drawTalkNPC(Sprite *animSet);
void playSoundIfNeeded();
- void conversationLoop();
void gameLoop();
void menuLoop();
@@ -142,7 +138,6 @@ private:
bool isAlkfredWalking = false;
byte *_currentBackground = nullptr; // Clean background - NEVER modified
- byte *_compositeBuffer; // Working composition buffer
bool _displayPopup = false;
byte _iconBlink = 0;
@@ -152,8 +147,6 @@ private:
HotSpot *_currentHotspot = nullptr;
- SmallFont *_smallFont = nullptr;
- LargeFont *_largeFont = nullptr;
Common::Point _curWalkTarget;
bool isNPCATalking = false;
@@ -187,7 +180,13 @@ protected:
public:
Graphics::Screen *_screen = nullptr;
+ RoomManager *_room = nullptr;
AlfredState alfredState;
+ byte *_compositeBuffer; // Working composition buffer
+
+ SmallFont *_smallFont = nullptr;
+ LargeFont *_largeFont = nullptr;
+ void renderScene(bool showTextOverlay = false);
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 103d4189ee5..a705bd009b5 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -218,17 +218,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
uint32_t outPos = 0;
_currentRoomStickers.clear();
int roomOffset = roomNumber * kRoomStructSize;
- Common::Array<Description> descriptions = loadRoomDescriptions(roomFile, roomOffset, outPos);
- // debug("After decsriptions, position is %d", outPos);
- Common::Array<ConversationNode> roots = loadConversations(roomFile, roomOffset, outPos);
- for (int i = 0; i < roots.size(); i++) {
- if (roots[i].text.empty()) {
- continue;
- }
- // debug("Conversation %d: %s", i, roots[i].text.c_str());
- }
- _currentRoomConversations = roots;
-
+ Common::Array<Description> descriptions = loadRoomTexts(roomFile, roomOffset);
Common::Array<Sprite> anims = loadRoomAnimations(roomFile, roomOffset);
Common::Array<HotSpot> hotspots;
@@ -407,7 +397,7 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(Common::File *roomFile, int ro
return walkboxes;
}
-Common::Array<Description> RoomManager::loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos) {
+Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, int roomOffset) {
uint32_t pair12_offset_pos = roomOffset + (12 * 8);
roomFile->seek(pair12_offset_pos, SEEK_SET);
// roomFile->skip(4);
@@ -448,7 +438,14 @@ Common::Array<Description> RoomManager::loadRoomDescriptions(Common::File *roomF
pos++;
}
// debug("End of descriptions at position %d", pos);
- outPos = lastDescPos + 1;
+ size_t conversationStart = lastDescPos + 1;
+ _conversationDataSize = pair12_size - conversationStart;
+ if(_conversationData != nullptr) {
+ delete[] _conversationData;
+ }
+ _conversationData = new byte[_conversationDataSize];
+ Common::copy(data + conversationStart, data + conversationStart + _conversationDataSize, _conversationData);
+
delete[] data;
// for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
// debug("Room description: %s", i->c_str());
@@ -530,361 +527,6 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
talkFile.close();
}
-Common::String RoomManager::getControlName(byte b) {
- switch (b) {
- case 0xFD:
- return "END_LINE";
- case 0xFC:
- return "TEXT_TERM";
- case 0xFB:
- return "CHOICE";
- case 0xFA:
- return "SKIP";
- case 0xF9:
- return "PAGE_BREAK";
- case 0xF8:
- return "ACTION";
- case 0xF7:
- return "END_BRANCH";
- case 0xF6:
- return "LINE_CONT";
- case 0xF5:
- return "END_BRANCH_2";
- case 0xF4:
- return "END_CONV";
- case 0xF1:
- return "CHOICE_ALT";
- case 0xF0:
- return "GO_BACK";
- case 0xFE:
- return "END_BRANCH_3";
- case 0xEB:
- return "END_ALT";
- case 0xFF:
- return "DESC_START";
- case 0x08:
- return "SPEAKER";
- default:
- return Common::String::format("UNKNOWN(0x%02X)", b);
- }
-}
-
-Common::String RoomManager::cleanText(const Common::String &text) {
- Common::String cleaned = text;
-
- // Trim leading/trailing whitespace
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- while (!cleaned.empty() && Common::isSpace(cleaned.lastChar())) {
- cleaned.deleteLastChar();
- }
-
- // Remove leading [XX][00] patterns
- while (!cleaned.empty() && cleaned.contains('[')) {
- uint idx = 0;
- for (uint i = 0; i < cleaned.size() && i < 15; i++) {
- if (cleaned[i] == '[') {
- idx = i;
- break;
- }
- }
-
- if (idx < 10) {
- int endIdx = -1;
- for (uint i = idx; i < cleaned.size() && i < idx + 10; i++) {
- if (cleaned[i] == ']') {
- endIdx = i;
- break;
- }
- }
-
- if (endIdx > (int)idx && endIdx < (int)idx + 10) {
- cleaned = cleaned.c_str() + endIdx + 1;
- // Trim leading whitespace again
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- // Remove single leading control characters
- if (cleaned.size() > 1) {
- byte first = (byte)cleaned[0];
- byte second = (byte)cleaned[1];
-
- if ((first == 'A' || first == 'H') &&
- (Common::isUpper(second) || second == 0x83 || second == 0x82 || second == '[')) {
- cleaned.deleteChar(0);
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- } else if (strchr("#%')!+,.-\"*&$(/", first)) {
- cleaned.deleteChar(0);
- while (!cleaned.empty() && Common::isSpace(cleaned.firstChar())) {
- cleaned.deleteChar(0);
- }
- }
- }
-
- return cleaned;
-}
-
-Common::Array<ConversationElement> RoomManager::parseConversationElements(const byte *convData, uint32 size) {
- Common::Array<ConversationElement> elements;
- Common::HashMap<int, int> choiceIndices; // Track choice index occurrences
- uint32 pos = 0;
-
- // First pass: parse elements and track choice indices
- while (pos < size) {
- byte b = convData[pos];
-
- if (b == 0x08) { // SPEAKER
- pos++;
- if (pos < size) {
- byte speakerId = convData[pos];
- Common::String speaker = (speakerId == 0x0D) ? "ALFRED" : "NPC";
- pos++;
-
- // Read text
- Common::String text;
- while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
- convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
- convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
- convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
- convData[pos] != 0xF0) {
- char32_t ch = decodeChar(convData[pos]);
- if (ch != '.') {
- text += ch;
- }
- pos++;
- }
-
- text = cleanText(text);
- if (!text.empty()) {
- ConversationElement elem;
- elem.type = ConversationElement::DIALOGUE;
- elem.speakerId = speakerId;
- elem.speaker = speaker;
- elem.text = text;
- elem.choiceIndex = -1;
- elements.push_back(elem);
- }
- }
- } else if (b == 0xFB || b == 0xF1) { // CHOICE marker
- pos++;
- int choiceIndex = -1;
- if (pos < size) {
- choiceIndex = convData[pos];
- // Track this choice index
- if (choiceIndices.contains(choiceIndex)) {
- choiceIndices[choiceIndex]++;
- } else {
- choiceIndices[choiceIndex] = 1;
- }
- pos++;
- }
-
- // Skip next 2 bytes (speaker marker)
- if (pos < size)
- pos++;
- if (pos < size)
- pos++;
-
- // Read text
- Common::String text;
- while (pos < size && convData[pos] != 0x08 && convData[pos] != 0xFB &&
- convData[pos] != 0xF1 && convData[pos] != 0xF8 && convData[pos] != 0xFD &&
- convData[pos] != 0xFC && convData[pos] != 0xF4 && convData[pos] != 0xF7 &&
- convData[pos] != 0xF5 && convData[pos] != 0xFE && convData[pos] != 0xEB &&
- convData[pos] != 0xF0) {
- char32_t ch = decodeChar(convData[pos]);
- if (ch != '.') {
- text += ch;
- }
- pos++;
- }
-
- text = cleanText(text);
- if (!text.empty()) {
- ConversationElement elem;
- elem.type = ConversationElement::CHOICE_MARKER;
- elem.text = text;
- elem.choiceIndex = choiceIndex;
- elements.push_back(elem);
- }
- } else if (b == 0xF8) { // ACTION
- pos += 3;
- } else if (b == 0xF4) { // END_CONV
- ConversationElement elem;
- elem.type = ConversationElement::END_CONV;
- elements.push_back(elem);
- pos++;
- } else if (b == 0xF7) { // END_BRANCH
- ConversationElement elem;
- elem.type = ConversationElement::END_BRANCH;
- elements.push_back(elem);
- pos++;
- } else if (b == 0xFD || b == 0xFC || b == 0xF5 || b == 0xFE || b == 0xEB || b == 0xF0) {
- pos++;
- } else {
- pos++;
- }
- }
-
- // Second pass: mark which indices are actual choices (appear multiple times)
- for (uint i = 0; i < elements.size(); i++) {
- if (elements[i].choiceIndex >= 0) {
- elements[i].isRealChoice = (choiceIndices[elements[i].choiceIndex] > 1);
- }
- }
-
- return elements;
-}
-
-Common::Array<ConversationNode> RoomManager::buildTreeStructure(const Common::Array<ConversationElement> &elements) {
- Common::Array<ConversationNode> roots;
- Common::Array<StackEntry> stack;
- ConversationNode *currentRoot = nullptr;
- uint i = 0;
-
- while (i < elements.size()) {
- const ConversationElement &elem = elements[i];
-
- if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "NPC") {
- if (stack.empty()) {
- // New root conversation
- ConversationNode root;
- root.type = ConversationNode::ROOT;
- root.text = elem.text;
- root.speaker = "NPC";
- root.speakerId = elem.speakerId;
- roots.push_back(root);
- currentRoot = &roots[roots.size() - 1];
- } else {
- // NPC response within a branch
- ConversationNode *parent = stack[stack.size() - 1].node;
- ConversationNode response;
- response.type = ConversationNode::RESPONSE;
- response.speaker = "NPC";
- response.speakerId = elem.speakerId;
- response.text = elem.text;
- parent->responses.push_back(response);
- }
- i++;
-
- } else if (elem.type == ConversationElement::CHOICE_MARKER) {
- if (elem.isRealChoice) {
- // Real choice - player selects from menu
- ConversationNode choiceNode;
- choiceNode.type = ConversationNode::CHOICE;
- choiceNode.text = elem.text;
- choiceNode.speaker = "ALFRED";
- choiceNode.speakerId = 0x0D; // Player
- choiceNode.choiceIndex = elem.choiceIndex;
-
- // Find where to attach this choice
- while (!stack.empty() && stack[stack.size() - 1].index >= elem.choiceIndex) {
- stack.pop_back();
- }
-
- if (!stack.empty()) {
- ConversationNode *parent = stack[stack.size() - 1].node;
- parent->subchoices.push_back(choiceNode);
-
- // Get pointer to the newly added choice
- ConversationNode *newChoice = &parent->subchoices[parent->subchoices.size() - 1];
-
- StackEntry entry;
- entry.node = newChoice;
- entry.index = elem.choiceIndex;
- stack.push_back(entry);
- } else {
- if (currentRoot) {
- currentRoot->choices.push_back(choiceNode);
-
- // Get pointer to the newly added choice
- ConversationNode *newChoice = ¤tRoot->choices[currentRoot->choices.size() - 1];
-
- StackEntry entry;
- entry.node = newChoice;
- entry.index = elem.choiceIndex;
- stack.push_back(entry);
- }
- }
- } else {
- // Auto-dialogue - ALFRED just speaks
- if (!stack.empty()) {
- ConversationNode *parent = stack[stack.size() - 1].node;
- ConversationNode response;
- response.type = ConversationNode::RESPONSE;
- response.speaker = "ALFRED";
- response.speakerId = 0x0D;
- response.text = elem.text;
- parent->responses.push_back(response);
- }
- }
- i++;
-
- } else if (elem.type == ConversationElement::DIALOGUE && elem.speaker == "ALFRED") {
- if (!stack.empty()) {
- ConversationNode *parent = stack[stack.size() - 1].node;
- ConversationNode response;
- response.type = ConversationNode::RESPONSE;
- response.speaker = "ALFRED";
- response.text = elem.text;
- response.speakerId = 0x0D;
- parent->responses.push_back(response);
- }
- i++;
-
- } else if (elem.type == ConversationElement::END_CONV) {
- if (!stack.empty()) {
- stack[stack.size() - 1].node->terminated = true;
- stack.pop_back();
- }
- i++;
-
- } else if (elem.type == ConversationElement::END_BRANCH) {
- stack.clear();
- currentRoot = nullptr;
- i++;
-
- } else {
- i++;
- }
- }
-
- return roots;
-}
-
-Common::Array<ConversationNode> RoomManager::loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos) {
-
- debug("Loading conversations starting at position %d", startPos);
-
- uint32_t pair12_offset_pos = roomOffset + (12 * 8);
- roomFile->seek(pair12_offset_pos, SEEK_SET);
- uint32_t pair12_data_offset = roomFile->readUint32LE();
- uint32_t pair12_size = roomFile->readUint32LE();
-
- // startPos += 2;
- uint32_t conversation_start = pair12_data_offset + startPos;
- uint32_t conversation_size = pair12_size - startPos;
-
- roomFile->seek(conversation_start, SEEK_SET);
- byte *data = new byte[conversation_size];
- roomFile->read(data, conversation_size);
-
- Common::Array<ConversationElement> elements = parseConversationElements(data, conversation_size);
- Common::Array<ConversationNode> roots = buildTreeStructure(elements);
- return roots;
-}
-
ScalingParams RoomManager::loadScalingParams(Common::File *roomFile, int roomOffset) {
uint32_t pair10_offset_pos = roomOffset + (10 * 8);
roomFile->seek(pair10_offset_pos, SEEK_SET);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index c2552e87866..c0a3c0f0419 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -49,43 +49,41 @@ public:
return "Unknown Room";
}
+ byte _currentRoomNumber = 0;
Common::Array<HotSpot> _currentRoomHotspots;
Common::Array<Sprite> _currentRoomAnims;
Common::Array<Exit> _currentRoomExits;
Common::Array<WalkBox> _currentRoomWalkboxes;
Common::Array<Description> _currentRoomDescriptions;
- Common::Array<ConversationNode> _currentRoomConversations;
+
TalkingAnimHeader _talkingAnimHeader;
ScalingParams _scaleParams;
byte *_pixelsShadows = nullptr;
byte _roomPalette[768];
byte alfredRemap[256];
byte overlayRemap[256];
- Common::StringArray _roomNames;
byte _musicTrack = 0;
Common::Array<byte> _roomSfx;
- byte _currentRoomNumber = 0;
PaletteAnim *_currentPaletteAnim = nullptr;
Common::Array<Sticker> _currentRoomStickers;
+ byte *_conversationData = nullptr;
+ size_t _conversationDataSize = 0;
private:
Common::Array<Sprite> loadRoomAnimations(Common::File *roomFile, int roomOffset);
Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
Common::Array<Exit> loadExits(Common::File *roomFile, int roomOffset);
Common::Array<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
- Common::Array<Description> loadRoomDescriptions(Common::File *roomFile, int roomOffset, uint32_t &outPos);
+ Common::Array<Description> loadRoomTexts(Common::File *roomFile, int roomOffset);
- Common::String getControlName(byte b);
- Common::String cleanText(const Common::String &text);
- Common::Array<ConversationElement> parseConversationElements(const byte *convData, uint32 size);
- Common::Array<ConversationNode> buildTreeStructure(const Common::Array<ConversationElement> &elements);
- Common::Array<ConversationNode> loadConversations(Common::File *roomFile, int roomOffset, uint32_t startPos);
ScalingParams loadScalingParams(Common::File *roomFile, int roomOffset);
byte *loadShadowMap(int roomNumber);
void loadRemaps(int roomNumber);
Common::StringArray loadRoomNames();
byte loadMusicTrackForRoom(Common::File *roomFile, int roomOffset);
Common::Array<byte> loadRoomSfx(Common::File *roomFile, int roomOffset);
+
+ Common::StringArray _roomNames;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index aa8e4f9edb8..ae9fec2be54 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -84,15 +84,6 @@ const int kChoiceHeight = 16; // Height of each choice line in pixels
#define MAX_CHARS_PER_LINE 0x2F // 47 characters
#define MAX_LINES 5 // Maximum number of lines per page (0-indexed check against 4)
-// Control character codes (negative values in signed char)
-#define CHAR_SPACE 0x20 /* ' ' */
-#define CHAR_END_MARKER_1 0xFD /* -3 (end of text marker) */
-#define CHAR_END_MARKER_2 0xF4 /* -0xC (alternate end marker) */
-#define CHAR_END_MARKER_3 0xF8 /* -8 (another end marker) */
-#define CHAR_END_MARKER_4 0xF0 /* -0x10 (another end marker) */
-#define CHAR_NEWLINE 0xF6 /* -10 (newline marker) */
-#define CHAR_PAGE_BREAK 0xF9 /* marker inserted when switching pages */
-
#define ALFRED_COLOR 0x0D
const byte kIconBlinkPeriod = 4;
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 33713fbce43..87fb010963b 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -19,7 +19,9 @@
*
*/
#include "common/stream.h"
+#include "graphics/font.h"
+#include "pelrock/pelrock.h"
#include "pelrock/types.h"
#include "pelrock/util.h"
#include "util.h"
@@ -50,13 +52,66 @@ void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color) {
for (int px = 0; px < w; px++) {
int destIdx = (y + py) * 640 + (x + px);
int srcIdx = py * w + px;
- int color = *((byte *)surface->getBasePtr(px, py));
- if(color != 0)
- screenBuffer[destIdx] = color;
+ int color = *((byte *)surface->getBasePtr(px, py));
+ if (color != 0)
+ screenBuffer[destIdx] = color;
}
}
}
+void drawText(byte *screenBuffer, Graphics::Font *font, Common::String text, int x, int y, int w, byte color, Graphics::TextAlign align) {
+ Common::Rect rect = font->getBoundingBox(text.c_str());
+ Graphics::Surface *surface = new Graphics::Surface();
+ int bboxW = rect.width();
+ int bboxH = rect.height();
+
+ surface->create(bboxW, bboxH, Graphics::PixelFormat::createFormatCLUT8());
+
+ if (x + bboxW > 640) {
+ x = 640 - bboxW - 2;
+ }
+ if (y + bboxH > 400) {
+ y = 400 - bboxH - 2;
+ }
+ if (x < 0) {
+ x = 0;
+ }
+ if (y < 0) {
+ y = 0;
+ }
+
+ // Draw main text on top
+ font->drawString(surface, text.c_str(), 0, 0, bboxW, color, align);
+ drawRect(surface, 0, 0, bboxW - 1, bboxH - 1, color);
+ for (int py = 0; py < bboxH; py++) {
+ for (int px = 0; px < bboxW; px++) {
+ int destIdx = (y + py) * 640 + (x + px);
+ int srcIdx = py * bboxW + px;
+ int color = *((byte *)surface->getBasePtr(px, py));
+ if (color != 0)
+ screenBuffer[destIdx] = color;
+ }
+ }
+}
+
+void drawText(Graphics::Font *font, Common::String text, int x, int y, int w, byte color) {
+ Common::Rect rect = font->getBoundingBox(text.c_str());
+ if (x + rect.width() > 640) {
+ x = 640 - rect.width() - 2;
+ }
+ if (y + rect.height() > 400) {
+ y = 400 - rect.height();
+ }
+ if (x < 0) {
+ x = 0;
+ }
+ if (y < 0) {
+ y = 0;
+ }
+ // Draw main text on top
+ font->drawString(g_engine->_screen, text.c_str(), x, y, w, color, Graphics::kTextAlignCenter);
+}
+
size_t rleDecompress(
const uint8_t *input,
size_t inputSize,
@@ -246,19 +301,29 @@ void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color) {
}
byte decodeChar(byte b) {
+ byte returnedChar = 0;
switch (b) {
- case 0x82: return special_chars[1];
- case 0x83: return special_chars[0];
-
- case 0x80: return special_chars[3]; // n tilde
- case 0x7F: return special_chars[4];
- case 0x7E: return special_chars[5];
- case 0x7D: return special_chars[6];
- case 0x7C: return special_chars[7];
- case 0x7B: return special_chars[8];
- default:
- return b;
+ case 0x82:
+ returnedChar = special_chars[1];
+ case 0x83:
+ returnedChar = special_chars[0];
+
+ case 0x80:
+ returnedChar = special_chars[3]; // n tilde
+ case 0x7F:
+ returnedChar = special_chars[4];
+ case 0x7E:
+ returnedChar = special_chars[5];
+ case 0x7D:
+ returnedChar = special_chars[6];
+ case 0x7C:
+ returnedChar = special_chars[7];
+ case 0x7B:
+ returnedChar = special_chars[8];
+ default:
+ return returnedChar = b;
}
+ return returnedChar;
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 1d0aec0a740..aaa7d96af16 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -21,13 +21,12 @@
#ifndef PELROCK_UTIL_H
#define PELROCK_UTIL_H
-#include "common/array.h"
#include "common/stream.h"
#include "common/types.h"
+#include "graphics/font.h"
#include "graphics/managed_surface.h"
#include "graphics/surface.h"
-
namespace Pelrock {
const int EXPECTED_SIZE = 640 * 400;
@@ -39,23 +38,23 @@ void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth
void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color);
+void drawText(byte *screenBuffer, Graphics::Font *font, Common::String text, int x, int y, int w, byte color, Graphics::TextAlign align = Graphics::kTextAlignLeft);
+void drawText(Graphics::Font *font, Common::String text, int x, int y, int w, byte color);
Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
byte decodeChar(byte b);
-
static const int special_chars[] = {
- 131, // inverted ?
- 130, // inverted !
- 129, // capital N tilde
- 128, // small n tilde
- 127, // small u tilde
- 126, // small o tilde
- 125, // small i tilde
- 124, // small e tilde
- 123, // small a tilde
+ 131, // inverted ?
+ 130, // inverted !
+ 129, // capital N tilde
+ 128, // small n tilde
+ 127, // small u tilde
+ 126, // small o tilde
+ 125, // small i tilde
+ 124, // small e tilde
+ 123, // small a tilde
};
-
} // End of namespace Pelrock
#endif // PELROCK_UTIL_H
Commit: 4a16eee238c654f20d73cc054d214a2f4a5d075e
https://github.com/scummvm/scummvm/commit/4a16eee238c654f20d73cc054d214a2f4a5d075e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:24+02:00
Commit Message:
PELROCK: Creates double font
Changed paths:
A engines/pelrock/fonts/small_font_double.cpp
A engines/pelrock/fonts/small_font_double.h
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/fonts/small_font.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/util.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 99bb129661f..55ab3822263 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -52,10 +52,8 @@
namespace Pelrock {
-DialogManager::DialogManager(Graphics::Screen *screen, PelrockEventManager *events,
- LargeFont *largeFont, SmallFont *smallFont)
- : _screen(screen), _events(events),
- _largeFont(largeFont), _smallFont(smallFont) {
+DialogManager::DialogManager(Graphics::Screen *screen, PelrockEventManager *events)
+ : _screen(screen), _events(events) {
}
DialogManager::~DialogManager() {
@@ -164,7 +162,7 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *c
}
}
for (int i = 0; i < choices->size(); i++) {
- drawText(compositeBuffer, g_engine->_smallFont, (*choices)[i].text, 10, overlayY + 2 + i * kChoiceHeight, 620, 9);
+ drawText(compositeBuffer, g_engine->_doubleSmallFont, (*choices)[i].text, 10, overlayY + 2 + i * kChoiceHeight, 620, 9);
}
}
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 816d9f32dab..bf78fb658b6 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -46,8 +46,6 @@ class DialogManager {
private:
Graphics::Screen *_screen = nullptr;
PelrockEventManager *_events = nullptr;
- LargeFont *_largeFont = nullptr;
- SmallFont *_smallFont = nullptr;
Sprite *_curSprite = nullptr;
// Private helper functions for conversation parsing
@@ -59,8 +57,7 @@ private:
void checkMouse();
public:
- DialogManager(Graphics::Screen *screen, PelrockEventManager *events,
- LargeFont *largeFont, SmallFont *smallFont);
+ DialogManager(Graphics::Screen *screen, PelrockEventManager *events);
~DialogManager();
void displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer);
diff --git a/engines/pelrock/fonts/small_font.h b/engines/pelrock/fonts/small_font.h
index f1fb165503a..08432320f98 100644
--- a/engines/pelrock/fonts/small_font.h
+++ b/engines/pelrock/fonts/small_font.h
@@ -39,11 +39,12 @@ public:
int getMaxCharWidth() const override { return CHAR_WIDTH; }
int getCharWidth(uint32 chr) const override;
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
+protected:
+ byte *_fontData;
private:
static const int CHAR_WIDTH = 8;
static const int CHAR_HEIGHT = 8;
- byte *_fontData;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/fonts/small_font_double.cpp b/engines/pelrock/fonts/small_font_double.cpp
new file mode 100644
index 00000000000..ef483eaf9c0
--- /dev/null
+++ b/engines/pelrock/fonts/small_font_double.cpp
@@ -0,0 +1,89 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "pelrock/fonts/small_font_double.h"
+
+namespace Pelrock {
+
+DoubleSmallFont::DoubleSmallFont() : SmallFont() {
+}
+
+DoubleSmallFont::~DoubleSmallFont() {
+}
+
+// void DoubleSmallFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
+// if (!_fontData || chr > 255) {
+// return;
+// }
+
+// int charOffset = chr * 8;
+
+// for (int i = 0; i < 8; i++) {
+// byte rowByte = _fontData[charOffset + i];
+// for (int bit = 0; bit < 8; bit++) {
+// bool pixelOn = (rowByte & (0x80 >> bit)) != 0;
+// if (pixelOn) {
+// if ((x + bit) < dst->w && (y + i) < dst->h) {
+// *((byte *)dst->getBasePtr(x + bit, y + i)) = color;
+// }
+// }
+// }
+// }
+// }
+
+void DoubleSmallFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
+ if (!_fontData || chr > 255) {
+ return;
+ }
+
+ int charOffset = chr * 8;
+
+ for (int i = 0; i < 8; i++) {
+ byte rowByte = _fontData[charOffset + i];
+ for (int bit = 0; bit < 8; bit++) {
+ bool pixelOn = (rowByte & (0x80 >> bit)) != 0;
+ int yPos = y + (i * 2);
+ // int yPos
+ if (pixelOn) {
+ if ((x + bit) < dst->w && (y + yPos + 1) < dst->h) {
+ *((byte *)dst->getBasePtr(x + bit, yPos)) = color;
+ *((byte *)dst->getBasePtr(x + bit, yPos + 1)) = color;
+ // *((byte *)dst->getBasePtr(x + bit, y + yPos + 1)) = color;
+ }
+ }
+ }
+ }
+
+ // for (int i = 0; i < 8; i++) {
+ // byte rowByte = _fontData[charOffset + i];
+ // for (int bit = 0; bit < 8; bit++) {
+ // bool pixelOn = (rowByte & (0x80 >> bit)) != 0;
+ // if (pixelOn) {
+ // if ((x + bit) < dst->w && (y + i) < dst->h) {
+ // *((byte *)dst->getBasePtr(x + bit, y + i)) = color;
+ // }
+ // }
+ // }
+ // }
+
+}
+
+} // namespace Pelrock
diff --git a/engines/pelrock/fonts/small_font_double.h b/engines/pelrock/fonts/small_font_double.h
new file mode 100644
index 00000000000..6cbe30d4884
--- /dev/null
+++ b/engines/pelrock/fonts/small_font_double.h
@@ -0,0 +1,47 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_SMALLFONTDOUBLE_H
+#define PELROCK_SMALLFONTDOUBLE_H
+
+#include "common/file.h"
+#include "common/str.h"
+#include "graphics/font.h"
+#include "graphics/surface.h"
+
+#include "pelrock/fonts/small_font.h"
+
+namespace Pelrock {
+class DoubleSmallFont : public SmallFont {
+public:
+ DoubleSmallFont();
+ ~DoubleSmallFont();
+
+ // Required Font interface methods
+ int getFontHeight() const override { return CHAR_HEIGHT; };
+ void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
+
+private:
+ static const int CHAR_HEIGHT = 16;
+};
+
+} // End of namespace Pelrock
+#endif
+
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index 942fcb31b5e..427fcc99c03 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -8,6 +8,7 @@ MODULE_OBJS = \
room.o \
fonts/small_font.o \
fonts/large_font.o \
+ fonts/small_font_double.o \
util.o \
resources.o\
sound.o \
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index d9a7c8da098..2a82af31a9c 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -57,6 +57,7 @@ PelrockEngine::~PelrockEngine() {
delete[] _currentBackground;
delete _largeFont;
delete _smallFont;
+ delete _doubleSmallFont;
delete _screen;
delete _chrono;
delete _videoManager;
@@ -86,7 +87,7 @@ Common::Error PelrockEngine::run() {
_room = new RoomManager();
_res = new ResourceManager();
_sound = new SoundManager(_mixer);
- _dialog = new DialogManager(_screen, _events, _largeFont, _smallFont);
+ _dialog = new DialogManager(_screen, _events);
// Set the engine's debugger console
setDebugger(new PelrockConsole(this));
@@ -139,6 +140,8 @@ void PelrockEngine::init() {
_smallFont->load("ALFRED.4");
_largeFont = new LargeFont();
_largeFont->load("ALFRED.7");
+ _doubleSmallFont = new DoubleSmallFont();
+ _doubleSmallFont->load("ALFRED.4");
changeCursor(DEFAULT);
CursorMan.showMouse(true);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 8fdf33ee2a4..407afeed780 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -42,6 +42,7 @@
#include "pelrock/events.h"
#include "pelrock/fonts/large_font.h"
#include "pelrock/fonts/small_font.h"
+#include "pelrock/fonts/small_font_double.h"
#include "pelrock/resources.h"
#include "pelrock/room.h"
#include "pelrock/sound.h"
@@ -186,6 +187,7 @@ public:
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
+ DoubleSmallFont *_doubleSmallFont = nullptr;
void renderScene(bool showTextOverlay = false);
public:
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 87fb010963b..5725ab54109 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -82,7 +82,7 @@ void drawText(byte *screenBuffer, Graphics::Font *font, Common::String text, int
// Draw main text on top
font->drawString(surface, text.c_str(), 0, 0, bboxW, color, align);
- drawRect(surface, 0, 0, bboxW - 1, bboxH - 1, color);
+ // drawRect(surface, 0, 0, bboxW - 1, bboxH - 1, color);
for (int py = 0; py < bboxH; py++) {
for (int px = 0; px < bboxW; px++) {
int destIdx = (y + py) * 640 + (x + px);
Commit: 105ea475b050794e410ebca753ebdcb4502e0bc1
https://github.com/scummvm/scummvm/commit/105ea475b050794e410ebca753ebdcb4502e0bc1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:24+02:00
Commit Message:
PELROCK: Implements double height font
Changed paths:
engines/pelrock/fonts/small_font.cpp
engines/pelrock/fonts/small_font.h
engines/pelrock/fonts/small_font_double.cpp
engines/pelrock/fonts/small_font_double.h
diff --git a/engines/pelrock/fonts/small_font.cpp b/engines/pelrock/fonts/small_font.cpp
index 9ab959e3bcb..9dff0d694e2 100644
--- a/engines/pelrock/fonts/small_font.cpp
+++ b/engines/pelrock/fonts/small_font.cpp
@@ -38,8 +38,8 @@ bool SmallFont::load(const Common::String &filename) {
file.seek(0x8F32, SEEK_SET);
- // const int dataSize = 256 * 8 * 8; // 256 characters, 8x8 pixels
- const int dataSize = 2048; // 256 characters, 8x8 pixels
+ const int dataSize = kNumChars * 8; // 256 characters, 8x8 pixels
+ debug("SmallFont::load: Loading font data of size %d from %s", dataSize, filename.c_str());
_fontData = new byte[dataSize];
file.read(_fontData, dataSize);
file.close();
@@ -52,7 +52,7 @@ int SmallFont::getCharWidth(uint32 chr) const {
}
void SmallFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
- if (!_fontData || chr > 255) {
+ if (!_fontData || chr > kNumChars - 1) {
return;
}
diff --git a/engines/pelrock/fonts/small_font.h b/engines/pelrock/fonts/small_font.h
index 08432320f98..cd80c690a1b 100644
--- a/engines/pelrock/fonts/small_font.h
+++ b/engines/pelrock/fonts/small_font.h
@@ -27,6 +27,9 @@
#include "graphics/surface.h"
namespace Pelrock {
+
+static const int kNumChars = 256;
+
class SmallFont : public Graphics::Font {
public:
SmallFont();
@@ -39,8 +42,9 @@ public:
int getMaxCharWidth() const override { return CHAR_WIDTH; }
int getCharWidth(uint32 chr) const override;
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
-protected:
+
byte *_fontData;
+protected:
private:
static const int CHAR_WIDTH = 8;
diff --git a/engines/pelrock/fonts/small_font_double.cpp b/engines/pelrock/fonts/small_font_double.cpp
index ef483eaf9c0..19fb92645cf 100644
--- a/engines/pelrock/fonts/small_font_double.cpp
+++ b/engines/pelrock/fonts/small_font_double.cpp
@@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
-
+#include "common/debug.h"
#include "pelrock/fonts/small_font_double.h"
namespace Pelrock {
@@ -29,61 +29,26 @@ DoubleSmallFont::DoubleSmallFont() : SmallFont() {
DoubleSmallFont::~DoubleSmallFont() {
}
-// void DoubleSmallFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
-// if (!_fontData || chr > 255) {
-// return;
-// }
-
-// int charOffset = chr * 8;
-
-// for (int i = 0; i < 8; i++) {
-// byte rowByte = _fontData[charOffset + i];
-// for (int bit = 0; bit < 8; bit++) {
-// bool pixelOn = (rowByte & (0x80 >> bit)) != 0;
-// if (pixelOn) {
-// if ((x + bit) < dst->w && (y + i) < dst->h) {
-// *((byte *)dst->getBasePtr(x + bit, y + i)) = color;
-// }
-// }
-// }
-// }
-// }
-
void DoubleSmallFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
- if (!_fontData || chr > 255) {
+ if (!_fontData || chr > kNumChars - 1) {
+ // debug("DoubleSmallFont::drawChar: Invalid char %d", chr);
return;
}
-
int charOffset = chr * 8;
for (int i = 0; i < 8; i++) {
byte rowByte = _fontData[charOffset + i];
for (int bit = 0; bit < 8; bit++) {
bool pixelOn = (rowByte & (0x80 >> bit)) != 0;
- int yPos = y + (i * 2);
- // int yPos
+ int yPos = y + (i * 2);
if (pixelOn) {
- if ((x + bit) < dst->w && (y + yPos + 1) < dst->h) {
+ if ((x + bit) < dst->w && (yPos + 1) < dst->h) {
*((byte *)dst->getBasePtr(x + bit, yPos)) = color;
- *((byte *)dst->getBasePtr(x + bit, yPos + 1)) = color;
- // *((byte *)dst->getBasePtr(x + bit, y + yPos + 1)) = color;
+ *((byte *)dst->getBasePtr(x + bit, yPos + 1)) = color;
}
}
}
}
-
- // for (int i = 0; i < 8; i++) {
- // byte rowByte = _fontData[charOffset + i];
- // for (int bit = 0; bit < 8; bit++) {
- // bool pixelOn = (rowByte & (0x80 >> bit)) != 0;
- // if (pixelOn) {
- // if ((x + bit) < dst->w && (y + i) < dst->h) {
- // *((byte *)dst->getBasePtr(x + bit, y + i)) = color;
- // }
- // }
- // }
- // }
-
}
} // namespace Pelrock
diff --git a/engines/pelrock/fonts/small_font_double.h b/engines/pelrock/fonts/small_font_double.h
index 6cbe30d4884..5bf265ca0fa 100644
--- a/engines/pelrock/fonts/small_font_double.h
+++ b/engines/pelrock/fonts/small_font_double.h
@@ -34,7 +34,7 @@ public:
DoubleSmallFont();
~DoubleSmallFont();
- // Required Font interface methods
+
int getFontHeight() const override { return CHAR_HEIGHT; };
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
Commit: f5a9d2bcf28d159daeb7e1fdc9bc0c63329a132f
https://github.com/scummvm/scummvm/commit/f5a9d2bcf28d159daeb7e1fdc9bc0c63329a132f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:25+02:00
Commit Message:
PELROCK: Decodes text bytes properly
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 55ab3822263..8bf85f49a2f 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -112,6 +112,7 @@ uint32 DialogManager::readTextBlock(
outSpeakerId = ALFRED_COLOR;
}
+ pos += 2; // Skip line count and blank
// Read text until control byte
while (pos < dataSize) {
byte b = data[pos];
@@ -130,22 +131,8 @@ uint32 DialogManager::readTextBlock(
continue;
}
- if (b == 0x0A || b == 0x0B || b == 0x00) {
- debug("Skipping byte 0x%02X at pos %u", b, pos);
- pos++; // Skip nulls and line feeds
- continue;
- }
-
- // Regular text - decode the character
- if (b >= 0x20 && b <= 0x7A) {
- outText += decodeChar(b);
- } else {
- // Try to decode special characters
- byte decoded = decodeChar(b);
- if (decoded != b || (decoded >= 0x20 && decoded <= 0x83)) {
- outText += (char)decoded;
- }
- }
+ // Regular text - does not need decoding
+ outText += b;
pos++;
}
@@ -272,6 +259,7 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
// Parse the choice text
uint32 textPos = pos + 4; // Skip marker + index + 2 speaker bytes
+ textPos += 2;
while (textPos < dataSize) {
byte tb = data[textPos];
if (tb == CTRL_END_TEXT || tb == CTRL_DIALOGUE_MARKER ||
@@ -280,17 +268,12 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
break;
}
- if (b == 0x0A || b == 0x0B || b == 0x00) {
- debug("Skipping byte 0x%02X at pos %u", b, pos);
- pos++; // Skip nulls and line feeds
- continue;
- }
-
- if (tb >= 0x20 && tb <= 0x7A) {
+ if (tb >= 0x20 && tb < 0x7A) {
opt.text += (char)tb;
} else {
byte decoded = decodeChar(tb);
- if (decoded != tb || (decoded >= 0x20 && decoded <= 0x83)) {
+ debug("Parsing choice char: 0x%02X, decoded: 0x%02X", tb, decoded);
+ if (decoded != tb || (decoded >= 0x20 && decoded <= 0xB4)) {
opt.text += (char)decoded;
}
}
@@ -333,6 +316,7 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
// Parse the choice text
uint32 textPos = pos + 4;
+ textPos += 2; // Skip marker + index + 2 speaker bytes
while (textPos < dataSize) {
byte tb = data[textPos];
if (tb == CTRL_END_TEXT || tb == CTRL_DIALOGUE_MARKER ||
@@ -341,17 +325,12 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
break;
}
- if (b == 0x0A || b == 0x0B || b == 0x00) {
- debug("Skipping byte 0x%02X at pos %u", b, pos);
- pos++; // Skip nulls and line feeds
- continue;
- }
-
if (tb >= 0x20 && tb <= 0x7A) {
opt.text += (char)tb;
} else {
byte decoded = decodeChar(tb);
- if (decoded != tb || (decoded >= 0x20 && decoded <= 0x83)) {
+ debug("Parsing choice char: 0x%02X, decoded: 0x%02X", tb, decoded);
+ if (decoded != tb || (decoded >= 0x20 && decoded <= 0xB4)) {
opt.text += (char)decoded;
}
}
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 5725ab54109..de6c4f3b2b6 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -301,29 +301,27 @@ void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color) {
}
byte decodeChar(byte b) {
- byte returnedChar = 0;
+
switch (b) {
case 0x82:
- returnedChar = special_chars[1];
+ return special_chars[1];
case 0x83:
- returnedChar = special_chars[0];
-
+ return special_chars[0];
case 0x80:
- returnedChar = special_chars[3]; // n tilde
+ return special_chars[3]; // n tilde
case 0x7F:
- returnedChar = special_chars[4];
+ return special_chars[4];
case 0x7E:
- returnedChar = special_chars[5];
+ return special_chars[5];
case 0x7D:
- returnedChar = special_chars[6];
+ return special_chars[6];
case 0x7C:
- returnedChar = special_chars[7];
+ return special_chars[7];
case 0x7B:
- returnedChar = special_chars[8];
+ return special_chars[8];
default:
- return returnedChar = b;
+ return b;
}
- return returnedChar;
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index aaa7d96af16..2a31bfbcd81 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -45,15 +45,15 @@ void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
byte decodeChar(byte b);
static const int special_chars[] = {
- 131, // inverted ?
- 130, // inverted !
- 129, // capital N tilde
- 128, // small n tilde
- 127, // small u tilde
- 126, // small o tilde
- 125, // small i tilde
- 124, // small e tilde
- 123, // small a tilde
+ 168, // inverted ?
+ 173, // inverted !
+ 165, // capital N tilde
+ 164, // small n tilde
+ 163, // small u tilde
+ 162, // small o tilde
+ 161, // small i tilde
+ 132, // small e tilde
+ 160, // small a tilde
};
} // End of namespace Pelrock
Commit: deb08538828e0c6ecf31a1def5092a376e75a1ad
https://github.com/scummvm/scummvm/commit/deb08538828e0c6ecf31a1def5092a376e75a1ad
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:25+02:00
Commit Message:
PELROCK: Fixes responses during conversations
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 8bf85f49a2f..41a02d418ac 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -112,7 +112,7 @@ uint32 DialogManager::readTextBlock(
outSpeakerId = ALFRED_COLOR;
}
- pos += 2; // Skip line count and blank
+ // pos += 2; // Skip line count and blank
// Read text until control byte
while (pos < dataSize) {
byte b = data[pos];
@@ -132,7 +132,9 @@ uint32 DialogManager::readTextBlock(
}
// Regular text - does not need decoding
- outText += b;
+ if (b >= 0x20 && b <= 0x83) {
+ outText += b;
+ }
pos++;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 2a82af31a9c..44ccb7788ec 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -302,33 +302,6 @@ void PelrockEngine::checkMouse() {
}
checkMouseHover();
-//else if (e.type == Common::EVENT_MOUSEMOVE) {
- // mouseX = e.mouse.x;
- // mouseY = e.mouse.y;
- // } else if (e.type == Common::EVENT_LBUTTONDOWN) {
- // if (!_isMouseDown) {
- // _mouseClickTime = g_system->getMillis();
- // _isMouseDown = true;
- // }
- // } else if (e.type == Common::EVENT_LBUTTONUP) {
- // _isMouseDown = false;
- // checkMouseClick(e.mouse.x, e.mouse.y);
- // _displayPopup = false;
- // _longClick = false;
- // } else if (e.type == Common::EVENT_RBUTTONUP) {
- // g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
- // stateGame = SETTINGS;
- // }
- // }
- // if (_isMouseDown) {
- // if (g_system->getMillis() - _mouseClickTime >= kLongClickDuration) {
- // _longClick = true;
- // _isMouseDown = false;
- // checkLongMouseClick(e.mouse.x, e.mouse.y);
- // }
- // }
- // checkMouseHover();
-
}
void PelrockEngine::copyBackgroundToBuffer() {
Commit: 318b7f345f858133bd0a6b0d8c7d994143c8e7c4
https://github.com/scummvm/scummvm/commit/318b7f345f858133bd0a6b0d8c7d994143c8e7c4
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:25+02:00
Commit Message:
PELROCK: Initial attempt at word wrapping algorithm
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 41a02d418ac..c4accf5dea1 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -160,14 +160,14 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *c
* @param text The text to display
* @param speakerId The speaker ID which is used as color
*/
-void DialogManager::displayDialogue(const Common::String &text, byte speakerId) {
- if (text.empty() || text.size() <= 1) {
+void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>> dialogueLines, byte speakerId) {
+ if (dialogueLines.empty()) {
return;
}
// Clear any existing click state
_events->_leftMouseClicked = false;
-
+ int curPage = 0;
// Render loop - display text and wait for click
while (!g_engine->shouldQuit()) {
_events->pollEvent();
@@ -175,9 +175,13 @@ void DialogManager::displayDialogue(const Common::String &text, byte speakerId)
// Render the scene (keeps animations going)
g_engine->renderScene(false);
+
// Draw the dialogue text on top using speaker ID as color
- drawText(g_engine->_largeFont, text, _curSprite->x, _curSprite->y - 10, 640, speakerId);
- // drawText(g_engine->_largeFont, "Hola", 10, 10, 640, speakerId);
+ Common::Array<Common::String> textLines = dialogueLines[curPage];
+ for(int i = 0; i < textLines.size(); i++) {
+ int yPos = 400 - (textLines.size() - i) * 20 - 10; // Adjust Y position based on line count
+ drawText(g_engine->_largeFont, textLines[i], 10, yPos, 620, speakerId);
+ }
// Present to screen
_screen->markAllDirty();
@@ -185,12 +189,21 @@ void DialogManager::displayDialogue(const Common::String &text, byte speakerId)
if (_events->_leftMouseClicked) {
_events->_leftMouseClicked = false;
+ if(curPage < (int)dialogueLines.size() - 1) {
+ curPage++;
+ } else {
+ break; // Exit dialogue on last page click
+ }
break;
}
g_system->delayMillis(10);
}
}
+void DialogManager::displayDialogue(Common::String text, byte speakerId) {
+ displayDialogue(wordWrap(text), speakerId);
+}
+
/**
* Select a choice from displayed options
* Returns the index of the selected choice in the choices array
@@ -395,10 +408,13 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
byte speakerId;
uint32 endPos = readTextBlock(conversationData, dataSize, position, text, speakerId);
+
+ Common::Array<Common::Array<Common::String>> wrappedText = wordWrap(text);
+
// Skip spurious single character artifacts
if (!text.empty() && text.size() > 1) {
debug("Dialogue: \"%s\" (Speaker ID: %u)", text.c_str(), speakerId);
- displayDialogue(text, speakerId);
+ displayDialogue(wrappedText, speakerId);
}
// Move to end of text
@@ -513,4 +529,117 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
debug("Conversation ended");
// Note: The caller should set inConversation = false after this returns
}
+
+bool isEndMarker(char char_byte) {
+ return char_byte == CHAR_END_MARKER_1 || char_byte == CHAR_END_MARKER_2 || char_byte == CHAR_END_MARKER_3 || char_byte == CHAR_END_MARKER_4;
+}
+
+
+int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
+ // return word_length, is_end
+ int wordLength = 0;
+ int pos = startPos;
+ while (pos < text.size()) {
+ char char_byte = text[pos];
+ if (char_byte == CHAR_SPACE || isEndMarker(char_byte)) {
+ break;
+ }
+ wordLength++;
+ pos++;
+ }
+ // Check if we hit an end marker
+ if (pos < text.size() && isEndMarker(text[pos])) {
+ isEnd = true;
+ }
+ // Count ALL trailing spaces as part of this word
+ if (pos < text.size() && !isEnd) {
+ if (text[pos] == CHAR_END_MARKER_3) { // 0xF8 (-8) special case
+ wordLength += 3;
+ } else {
+ // Count all consecutive spaces
+ while (pos < text.size() && text[pos] == CHAR_SPACE) {
+ wordLength++;
+ pos++;
+ }
+ }
+ }
+ return wordLength;
+}
+
+Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::String text) {
+
+ Common::Array<Common::Array<Common::String>> pages;
+ Common::Array<Common::String> currentPage;
+ Common::Array<Common::String> currentLine;
+ int charsRemaining = MAX_CHARS_PER_LINE;
+ int position = 0;
+ int currentLineNum = 0;
+ while (position < text.size()) {
+ bool isEnd = false;
+ int wordLength = calculateWordLength(text, position, isEnd);
+ // # Extract the word (including trailing spaces)
+ // word = text[position:position + word_length].decode('latin-1', errors='replace')
+ Common::String word = text.substr(position, wordLength).decode(Common::kLatin1);
+ // # Key decision: if word_length > chars_remaining, wrap to next line
+ if (wordLength > charsRemaining) {
+ // Word is longer than the entire line - need to split
+ currentPage.push_back(joinStrings(currentLine, ""));
+ currentLine.clear();
+ charsRemaining = MAX_CHARS_PER_LINE;
+ currentLineNum++;
+
+ if (currentLineNum >= MAX_LINES) {
+ pages.push_back(currentPage);
+ currentPage.clear();
+ currentLineNum = 0;
+ }
+ }
+ // Add word to current line
+ currentLine.push_back(word);
+ charsRemaining -= wordLength;
+
+ if (charsRemaining == 0 && isEnd) {
+ Common::String lineText = joinStrings(currentLine, "");
+ while (lineText.lastChar() == CHAR_SPACE) {
+ lineText = lineText.substr(0, lineText.size() - 1);
+ }
+ int trailingSpaces = currentLine.size() - lineText.size();
+ if (trailingSpaces > 0) {
+ currentPage.push_back(lineText);
+ // current_line = [' ' * trailing_spaces]
+ Common::String currentLine(trailingSpaces, ' ');
+ charsRemaining = MAX_CHARS_PER_LINE - trailingSpaces;
+ currentLineNum += 1;
+
+ if (currentLineNum >= MAX_LINES) {
+ pages.push_back(currentPage);
+ currentPage.clear();
+ currentLineNum = 0;
+ }
+ }
+ }
+
+ position += wordLength;
+ if (isEnd) {
+ // End of sentence/paragraph/page
+ break;
+ }
+ }
+ if (currentLine.empty() == false) {
+ Common::String lineText = joinStrings(currentLine, "");
+ while (lineText.lastChar() == CHAR_SPACE) {
+ lineText = lineText.substr(0, lineText.size() - 1);
+ }
+ currentPage.push_back(lineText);
+ }
+ if (currentPage.empty() == false) {
+ pages.push_back(currentPage);
+ }
+ for (int i = 0; i < pages.size(); i++) {
+ for (int j = 0; j < pages[i].size(); j++) {
+ }
+ }
+ return pages;
+}
+
} // namespace Pelrock
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index bf78fb658b6..f3b7e055ebe 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -49,7 +49,8 @@ private:
Sprite *_curSprite = nullptr;
// Private helper functions for conversation parsing
- void displayDialogue(const Common::String &text, byte speakerId);
+ void displayDialogue(Common::Array<Common::Array<Common::String>> dialogueLines, byte speakerId);
+ void displayDialogue(Common::String text, byte speakerId);
uint32 readTextBlock(const byte *data, uint32 dataSize, uint32 startPos,
Common::String &outText, byte &outSpeakerId);
uint32 parseChoices(const byte *data, uint32 dataSize, uint32 startPos, Common::Array<ChoiceOption> &outChoices);
@@ -63,7 +64,7 @@ public:
void displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer);
int selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer);
void startConversation(const byte *conversationData, uint32 dataSize, Sprite *alfredAnimSet = nullptr);
-
+ Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
Common::Array<ChoiceOption> *_currentChoices = nullptr;
};
Commit: 570547df397964c7c49fb3b343092b2a25b49230
https://github.com/scummvm/scummvm/commit/570547df397964c7c49fb3b343092b2a25b49230
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:26+02:00
Commit Message:
PELROCK: Center text above character
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index c4accf5dea1..6ca9bfaea52 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -175,21 +175,61 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
// Render the scene (keeps animations going)
g_engine->renderScene(false);
-
// Draw the dialogue text on top using speaker ID as color
Common::Array<Common::String> textLines = dialogueLines[curPage];
- for(int i = 0; i < textLines.size(); i++) {
- int yPos = 400 - (textLines.size() - i) * 20 - 10; // Adjust Y position based on line count
- drawText(g_engine->_largeFont, textLines[i], 10, yPos, 620, speakerId);
+
+ int maxWidth = 0;
+ int height = textLines.size() * 20;
+ for (int i = 0; i < textLines.size(); i++) {
+ maxWidth = MAX(maxWidth, g_engine->_largeFont->getStringWidth(textLines[i]));
+ }
+
+ Graphics::Surface s;
+ s.create(maxWidth, height, Graphics::PixelFormat::createFormatCLUT8());
+ s.drawRoundRect(Common::Rect(0, 0, s.getRect().width(), s.getRect().height()), 2, 13, false);
+ int xPos = 0;
+ int yPos = 0;
+
+ if (speakerId == ALFRED_COLOR) {
+ // Offset X position for Alfred to avoid overlapping with his sprite
+ xPos = g_engine->alfredState.x + kAlfredFrameWidth / 2 - maxWidth / 2;
+ yPos = g_engine->alfredState.y - kAlfredFrameHeight - 30; // Above sprite, adjust for line
+ } else {
+ xPos = _curSprite->x + _curSprite->w / 2 - maxWidth / 2;
+ yPos = _curSprite->y - 30 - height; // Above sprite, adjust for line
+ }
+
+ for (int i = 0; i < textLines.size(); i++) {
+
+ int xPos = 0;
+ int yPos = i * 20; // Above sprite, adjust for line
+
+ debug("Drawing dialogue line %s at (%d, %d), speaker =%d, maxWidth = %d", textLines[i].c_str(), xPos, yPos, speakerId, maxWidth);
+ g_engine->_largeFont->drawString(&s, textLines[i], xPos, yPos, maxWidth, speakerId, Graphics::kTextAlignCenter);
+
}
+ if (xPos + s.getRect().width() > 640) {
+ xPos = 640 - s.getRect().width() - 2;
+ }
+ if (yPos + s.getRect().height() > 400) {
+ yPos = 400 - s.getRect().height();
+ }
+ if (xPos < 0) {
+ xPos = 0;
+ }
+ if (yPos < 0) {
+ yPos = 0;
+ }
+
+ _screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos));
// Present to screen
_screen->markAllDirty();
_screen->update();
if (_events->_leftMouseClicked) {
_events->_leftMouseClicked = false;
- if(curPage < (int)dialogueLines.size() - 1) {
+ if (curPage < (int)dialogueLines.size() - 1) {
curPage++;
} else {
break; // Exit dialogue on last page click
@@ -408,7 +448,6 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
byte speakerId;
uint32 endPos = readTextBlock(conversationData, dataSize, position, text, speakerId);
-
Common::Array<Common::Array<Common::String>> wrappedText = wordWrap(text);
// Skip spurious single character artifacts
@@ -534,7 +573,6 @@ bool isEndMarker(char char_byte) {
return char_byte == CHAR_END_MARKER_1 || char_byte == CHAR_END_MARKER_2 || char_byte == CHAR_END_MARKER_3 || char_byte == CHAR_END_MARKER_4;
}
-
int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
// return word_length, is_end
int wordLength = 0;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 44ccb7788ec..51859bc238f 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -462,12 +462,11 @@ void PelrockEngine::doAction(byte action, HotSpot *hotspot) {
void PelrockEngine::talkTo(HotSpot *hotspot) {
Sprite *animSet;
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (i == hotspot->index) {
+ if (_room->_currentRoomAnims[i].index == hotspot->index) {
animSet = &_room->_currentRoomAnims[i];
break;
}
}
- debug("Starting conversation with hotspot %d, animSet pos %d", hotspot->index, animSet->x);
_dialog->startConversation(_room->_conversationData, _room->_conversationDataSize, animSet);
}
Commit: dce198bd6e3472486179872589af1c6f2e141a44
https://github.com/scummvm/scummvm/commit/dce198bd6e3472486179872589af1c6f2e141a44
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:26+02:00
Commit Message:
PELROCK: Enable talking animations
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 6ca9bfaea52..e4300e1347e 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -191,12 +191,16 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int yPos = 0;
if (speakerId == ALFRED_COLOR) {
+ g_engine->alfredState.animState = ALFRED_TALKING;
+ _curSprite->isTalking = false;
// Offset X position for Alfred to avoid overlapping with his sprite
xPos = g_engine->alfredState.x + kAlfredFrameWidth / 2 - maxWidth / 2;
- yPos = g_engine->alfredState.y - kAlfredFrameHeight - 30; // Above sprite, adjust for line
+ yPos = g_engine->alfredState.y - kAlfredFrameHeight - height; // Above sprite, adjust for line
} else {
+ g_engine->alfredState.animState = ALFRED_IDLE;
+ _curSprite->isTalking = true;
xPos = _curSprite->x + _curSprite->w / 2 - maxWidth / 2;
- yPos = _curSprite->y - 30 - height; // Above sprite, adjust for line
+ yPos = _curSprite->y - height; // Above sprite, adjust for line
}
for (int i = 0; i < textLines.size(); i++) {
@@ -204,7 +208,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int xPos = 0;
int yPos = i * 20; // Above sprite, adjust for line
- debug("Drawing dialogue line %s at (%d, %d), speaker =%d, maxWidth = %d", textLines[i].c_str(), xPos, yPos, speakerId, maxWidth);
+ debug("Drawing dialogue line %s at (%d, %d), speaker =%d, maxWidth = %d, isNPC talking=%d", textLines[i].c_str(), xPos, yPos, speakerId, maxWidth, _curSprite->isTalking ? 1 : 0);
g_engine->_largeFont->drawString(&s, textLines[i], xPos, yPos, maxWidth, speakerId, Graphics::kTextAlignCenter);
}
@@ -238,6 +242,8 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
}
g_system->delayMillis(10);
}
+ _curSprite->isTalking = false;
+ g_engine->alfredState.animState = ALFRED_IDLE;
}
void DialogManager::displayDialogue(Common::String text, byte speakerId) {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 51859bc238f..977d44fe5e6 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -464,6 +464,7 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].index == hotspot->index) {
animSet = &_room->_currentRoomAnims[i];
+ animSet->isTalking = true;
break;
}
}
@@ -743,8 +744,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
int y = sprite->y;
int w = animData.w;
int h = animData.h;
- int extra = sprite->extra;
- if (whichNPCTalking == extra) {
+ if (sprite->isTalking) {
drawTalkNPC(sprite);
return;
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index ae9fec2be54..3aa7fe81cfc 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -173,6 +173,7 @@ struct Sprite {
byte spriteType; // 33
byte actionFlags; // 34
bool isDisabled; // 38
+ bool isTalking = false;
Anim *animData;
};
Commit: 97e87afd0978de7c2edb11a1830e553af9d6606f
https://github.com/scummvm/scummvm/commit/97e87afd0978de7c2edb11a1830e553af9d6606f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:26+02:00
Commit Message:
PELROCK: Highlighting of conversation choices
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index e4300e1347e..3ef603438e1 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -151,7 +151,15 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *c
}
}
for (int i = 0; i < choices->size(); i++) {
- drawText(compositeBuffer, g_engine->_doubleSmallFont, (*choices)[i].text, 10, overlayY + 2 + i * kChoiceHeight, 620, 9);
+ ChoiceOption choice = (*choices)[i];
+ int choicePadding = 32;
+ int width = g_engine->_doubleSmallFont->getStringWidth(choice.text);
+ Common::Rect bbox(0, overlayY + i * kChoiceHeight, width + choicePadding * 2, overlayY + i * kChoiceHeight + kChoiceHeight);
+ int color = 14;
+ if (bbox.contains(_events->_mouseX, _events->_mouseY)) {
+ color = 15;
+ }
+ drawText(compositeBuffer, g_engine->_doubleSmallFont, choice.text, choicePadding, overlayY + 2 + i * kChoiceHeight, 620, color);
}
}
@@ -179,13 +187,14 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
Common::Array<Common::String> textLines = dialogueLines[curPage];
int maxWidth = 0;
- int height = textLines.size() * 20;
+ int height = textLines.size() * 24;
for (int i = 0; i < textLines.size(); i++) {
maxWidth = MAX(maxWidth, g_engine->_largeFont->getStringWidth(textLines[i]));
}
Graphics::Surface s;
s.create(maxWidth, height, Graphics::PixelFormat::createFormatCLUT8());
+ s.fillRect(s.getRect(), 255); // Clear surface
s.drawRoundRect(Common::Rect(0, 0, s.getRect().width(), s.getRect().height()), 2, 13, false);
int xPos = 0;
int yPos = 0;
@@ -208,9 +217,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int xPos = 0;
int yPos = i * 20; // Above sprite, adjust for line
- debug("Drawing dialogue line %s at (%d, %d), speaker =%d, maxWidth = %d, isNPC talking=%d", textLines[i].c_str(), xPos, yPos, speakerId, maxWidth, _curSprite->isTalking ? 1 : 0);
g_engine->_largeFont->drawString(&s, textLines[i], xPos, yPos, maxWidth, speakerId, Graphics::kTextAlignCenter);
-
}
if (xPos + s.getRect().width() > 640) {
@@ -226,7 +233,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
yPos = 0;
}
- _screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos));
+ _screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos), 255);
// Present to screen
_screen->markAllDirty();
_screen->update();
@@ -453,12 +460,10 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
Common::String text;
byte speakerId;
uint32 endPos = readTextBlock(conversationData, dataSize, position, text, speakerId);
-
Common::Array<Common::Array<Common::String>> wrappedText = wordWrap(text);
// Skip spurious single character artifacts
if (!text.empty() && text.size() > 1) {
- debug("Dialogue: \"%s\" (Speaker ID: %u)", text.c_str(), speakerId);
displayDialogue(wrappedText, speakerId);
}
@@ -508,7 +513,6 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
// 4. Parse choices
- debug("Parsing choices at pos %u", position);
Common::Array<ChoiceOption> choices;
parseChoices(conversationData, dataSize, position, choices);
debug("Parsed %u choices", choices.size());
@@ -528,7 +532,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// Check if this is auto-dialogue (only one choice)
if (choices.size() == 1) {
// Auto-dialogue: display it automatically
- displayDialogue(choices[0].text, ALFRED_COLOR);
+ debug("Auto-selecting single choice: \"%s\"", choices[0].text.c_str());
selectedIndex = 0;
} else {
// Real choice: show menu and wait for selection
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 977d44fe5e6..6d0a94103cd 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -149,7 +149,10 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(0, ALFRED_DOWN);
+ // setScreen(0, ALFRED_DOWN);
+ setScreen(2, ALFRED_LEFT);
+ alfredState.x = 576;
+ alfredState.y = 374;
}
}
@@ -508,9 +511,7 @@ void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, i
void PelrockEngine::chooseAlfredStateAndDraw() {
switch (alfredState.animState) {
case ALFRED_WALKING: {
-
MovementStep step = _currentContext.movementBuffer[_currentStep];
-
if (step.distanceX > 0) {
if (step.flags & MOVE_RIGHT) {
alfredState.direction = ALFRED_RIGHT;
@@ -571,7 +572,9 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.curFrame = 0;
}
drawAlfred(_res->alfredTalkFrames[alfredState.direction][alfredState.curFrame]);
- alfredState.curFrame++;
+ if(_chrono->getFrameCount() % 2 == 0) {
+ alfredState.curFrame++;
+ }
break;
case ALFRED_COMB:
if (alfredState.curFrame >= 11) {
Commit: 2c4d6eb2908d224b6fd94282eb7edbcbbc03860c
https://github.com/scummvm/scummvm/commit/2c4d6eb2908d224b6fd94282eb7edbcbbc03860c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:26+02:00
Commit Message:
PELROCK: Fixes word wrap rendering
Changed paths:
engines/pelrock/dialog.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 3ef603438e1..e61661ab0db 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -240,12 +240,12 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (_events->_leftMouseClicked) {
_events->_leftMouseClicked = false;
+ debug("Dialogue click to advance, current page: %d, totalPages: %d", curPage, (int)dialogueLines.size());
if (curPage < (int)dialogueLines.size() - 1) {
curPage++;
} else {
break; // Exit dialogue on last page click
}
- break;
}
g_system->delayMillis(10);
}
@@ -461,7 +461,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
byte speakerId;
uint32 endPos = readTextBlock(conversationData, dataSize, position, text, speakerId);
Common::Array<Common::Array<Common::String>> wrappedText = wordWrap(text);
-
+ debug("Word wrapping %s produces %d pages", text.c_str(), wrappedText.size());
// Skip spurious single character artifacts
if (!text.empty() && text.size() > 1) {
displayDialogue(wrappedText, speakerId);
Commit: d5fd802816b0731b7e703669496bd642eceb15b1
https://github.com/scummvm/scummvm/commit/d5fd802816b0731b7e703669496bd642eceb15b1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:27+02:00
Commit Message:
PELROCK: Stop conversation when no more choices are available.
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index e61661ab0db..da445446bc9 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -24,32 +24,6 @@
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
-// Control character codes (negative values in signed char)
-#define CHAR_SPACE 0x20 /* ' ' */
-#define CHAR_END_MARKER_1 0xFD /* -3 (end of text marker) */
-#define CHAR_END_MARKER_2 0xF4 /* -0xC (alternate end marker) */
-#define CHAR_END_MARKER_3 0xF8 /* -8 (another end marker) */
-#define CHAR_END_MARKER_4 0xF0 /* -0x10 (another end marker) */
-#define CHAR_NEWLINE 0xF6 /* -10 (newline marker) */
-#define CHAR_PAGE_BREAK 0xF9 /* marker inserted when switching pages */
-
-// Conversation control bytes
-#define CTRL_SPEAKER_ID 0x08 /* Next byte is speaker ID (color) */
-#define CTRL_END_TEXT 0xFD /* End of text segment */
-#define CTRL_TEXT_TERMINATOR 0xFC /* Text terminator */
-#define CTRL_DIALOGUE_MARKER 0xFB /* Choice marker */
-#define CTRL_DISABLED_CHOICE 0xFA /* Disabled choice marker */
-#define CTRL_PAGE_BREAK_CONV 0xF9 /* Page break in conversation */
-#define CTRL_ACTION_TRIGGER 0xF8 /* Action trigger */
-#define CTRL_END_BRANCH 0xF7 /* End of branch */
-#define CTRL_LINE_CONTINUE 0xF6 /* Line continue/newline */
-#define CTRL_ALT_END_MARKER_1 0xF5 /* Alt end marker */
-#define CTRL_END_CONVERSATION 0xF4 /* End conversation */
-#define CTRL_DIALOGUE_MARKER_2 0xF1 /* Alt choice marker */
-#define CTRL_GO_BACK 0xF0 /* Go back in conversation */
-#define CTRL_ALT_END_MARKER_2 0xEB /* Alt end marker 2 */
-#define CTRL_ALT_END_MARKER_3 0xFE /* Alt end marker 3 */
-
namespace Pelrock {
DialogManager::DialogManager(Graphics::Screen *screen, PelrockEventManager *events)
@@ -430,6 +404,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
debug("Starting conversation with %u bytes of data", dataSize);
uint32 position = 0;
+ int currentChoiceLevel = -1; // Track the current choice level
// Skip any junk at start until we find a speaker marker or choice marker
while (position < dataSize &&
@@ -517,7 +492,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
parseChoices(conversationData, dataSize, position, choices);
debug("Parsed %u choices", choices.size());
for (uint i = 0; i < choices.size(); i++) {
- debug(" Choice %u: \"%s\" (Disabled: %s)", i, choices[i].text.c_str(),
+ debug(" Choice %u (index %d): \"%s\" (Disabled: %s)", i, choices[i].index, choices[i].text.c_str(),
choices[i].isDisabled ? "Yes" : "No");
}
if (choices.empty()) {
@@ -526,6 +501,23 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
continue;
}
+ // Check if we have a currentChoiceLevel and if these choices are at the next level
+ if (currentChoiceLevel >= 0) {
+ // We've already made a choice, check if the current choices are at the next level
+ bool foundNextLevel = false;
+ for (uint i = 0; i < choices.size(); i++) {
+ if (choices[i].index == currentChoiceLevel + 1) {
+ foundNextLevel = true;
+ break;
+ }
+ }
+
+ if (!foundNextLevel) {
+ debug("No choices found at level %d (current is %d), ending conversation", currentChoiceLevel + 1, currentChoiceLevel);
+ break;
+ }
+ }
+
// 5. Display choices and get selection
int selectedIndex = 0;
@@ -552,6 +544,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// 6. Move position to after the selected choice
if (selectedIndex >= 0 && selectedIndex < (int)choices.size()) {
position = choices[selectedIndex].dataOffset;
+ currentChoiceLevel = choices[selectedIndex].index;
// Read and display the selected choice as dialogue
Common::String choiceText;
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index f3b7e055ebe..68dddfe8941 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -30,6 +30,33 @@
#include "pelrock/types.h"
namespace Pelrock {
+
+// Control character codes (negative values in signed char)
+#define CHAR_SPACE 0x20 /* ' ' */
+#define CHAR_END_MARKER_1 0xFD /* -3 (end of text marker) */
+#define CHAR_END_MARKER_2 0xF4 /* -0xC (alternate end marker) */
+#define CHAR_END_MARKER_3 0xF8 /* -8 (another end marker) */
+#define CHAR_END_MARKER_4 0xF0 /* -0x10 (another end marker) */
+#define CHAR_NEWLINE 0xF6 /* -10 (newline marker) */
+#define CHAR_PAGE_BREAK 0xF9 /* marker inserted when switching pages */
+
+// Conversation control bytes
+#define CTRL_SPEAKER_ID 0x08 /* Next byte is speaker ID (color) */
+#define CTRL_END_TEXT 0xFD /* End of text segment */
+#define CTRL_TEXT_TERMINATOR 0xFC /* Text terminator */
+#define CTRL_DIALOGUE_MARKER 0xFB /* Choice marker */
+#define CTRL_DISABLED_CHOICE 0xFA /* Disabled choice marker */
+#define CTRL_PAGE_BREAK_CONV 0xF9 /* Page break in conversation */
+#define CTRL_ACTION_TRIGGER 0xF8 /* Action trigger */
+#define CTRL_END_BRANCH 0xF7 /* End of branch */
+#define CTRL_LINE_CONTINUE 0xF6 /* Line continue/newline */
+#define CTRL_ALT_END_MARKER_1 0xF5 /* Alt end marker - do nothing */
+#define CTRL_END_CONVERSATION 0xF4 /* End conversation and disable option */
+#define CTRL_DIALOGUE_MARKER_2 0xF1 /* Alt choice marker that disappears */
+#define CTRL_GO_BACK 0xF0 /* Go back in conversation */
+#define CTRL_ALT_END_MARKER_2 0xEB /* Alt end marker 2 */
+#define CTRL_ALT_END_MARKER_3 0xFE /* Alt end marker 3 */
+
/**
* Structure to hold a parsed choice option
*/
@@ -51,8 +78,7 @@ private:
// Private helper functions for conversation parsing
void displayDialogue(Common::Array<Common::Array<Common::String>> dialogueLines, byte speakerId);
void displayDialogue(Common::String text, byte speakerId);
- uint32 readTextBlock(const byte *data, uint32 dataSize, uint32 startPos,
- Common::String &outText, byte &outSpeakerId);
+ uint32 readTextBlock(const byte *data, uint32 dataSize, uint32 startPos, Common::String &outText, byte &outSpeakerId);
uint32 parseChoices(const byte *data, uint32 dataSize, uint32 startPos, Common::Array<ChoiceOption> &outChoices);
void checkMouse();
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 6d0a94103cd..445f90ed1c2 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1125,8 +1125,8 @@ void PelrockEngine::checkMouseClick(int x, int y) {
// Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
VerbIcon actionClicked = isActionUnder(x, y);
if (actionClicked != NO_ACTION) {
- doAction(actionClicked, _currentHotspot);
_displayPopup = false;
+ doAction(actionClicked, _currentHotspot);
return;
}
}
Commit: 1d9b7dc63b2ceb713b75d0e35a09b096d07dde3e
https://github.com/scummvm/scummvm/commit/1d9b7dc63b2ceb713b75d0e35a09b096d07dde3e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:27+02:00
Commit Message:
PELROCK: Applies z-movement to sprites
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 445f90ed1c2..700ce52f4f0 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -703,7 +703,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
delete[] finalBuf;
}
-void applyMovement(int16_t *x, int16_t *y, /*int8_t *z,*/ uint16_t flags) {
+void applyMovement(int16_t *x, int16_t *y, int8_t *z, uint16_t flags) {
// X-axis movement
if (flags & 0x10) { // Bit 4: X movement enabled
int amount = flags & 0x07; // Bits 0-2: pixels per frame
@@ -724,15 +724,15 @@ void applyMovement(int16_t *x, int16_t *y, /*int8_t *z,*/ uint16_t flags) {
}
}
- // // Z-axis movement
- // if (flags & 0x4000) { // Bit 14: Z movement enabled
- // int amount = (flags >> 10) & 0x07; // Bits 10-12: amount
- // if (flags & 0x2000) { // Bit 13: direction
- // *z += amount; // 1 = forward (add)
- // } else {
- // *z -= amount; // 0 = back (subtract)
- // }
- // }
+ // Z-axis movement
+ if (flags & 0x4000) { // Bit 14: Z movement enabled
+ int amount = (flags >> 10) & 0x07; // Bits 10-12: amount
+ if (flags & 0x2000) { // Bit 13: direction
+ *z += amount; // 1 = forward (add)
+ } else {
+ *z -= amount; // 0 = back (subtract)
+ }
+ }
}
void PelrockEngine::drawNextFrame(Sprite *sprite) {
@@ -742,7 +742,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
return;
}
- applyMovement(&(sprite->x), &(sprite->y), animData.movementFlags);
+ applyMovement(&(sprite->x), &(sprite->y), &(sprite->zOrder), animData.movementFlags);
int x = sprite->x;
int y = sprite->y;
int w = animData.w;
@@ -758,7 +758,8 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
extractSingleFrame(animData.animData, frame, curFrame, animData.w, animData.h);
drawSpriteToBuffer(_compositeBuffer, 640, frame, sprite->x, sprite->y, sprite->w, sprite->h, 255);
- if (animData.elpapsedFrames == animData.speed) {
+ // if (animData.elpapsedFrames == animData.speed) {
+ if(_chrono->getFrameCount() % animData.speed == 0) {
animData.elpapsedFrames = 0;
if (animData.curFrame < animData.nframes - 1) {
animData.curFrame++;
Commit: d0f1be8645d909ddc21d10e5d01c4ca1cd8b0c3d
https://github.com/scummvm/scummvm/commit/d0f1be8645d909ddc21d10e5d01c4ca1cd8b0c3d
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:27+02:00
Commit Message:
PELROCK: Animation speeds for talking
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 700ce52f4f0..edc3733c2ef 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -562,8 +562,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
}
drawAlfred(_res->alfredWalkFrames[alfredState.direction][alfredState.curFrame]);
- // if(alfredFrameSkip) alfredState.curFrame++;
- // alfredFrameSkip = !alfredFrameSkip;
alfredState.curFrame++;
break;
}
@@ -572,7 +570,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.curFrame = 0;
}
drawAlfred(_res->alfredTalkFrames[alfredState.direction][alfredState.curFrame]);
- if(_chrono->getFrameCount() % 2 == 0) {
+ if(_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
alfredState.curFrame++;
}
break;
@@ -1000,7 +998,17 @@ void PelrockEngine::drawTalkNPC(Sprite *animSet) {
int w = index ? animHeader->wAnimB : animHeader->wAnimA;
int h = index ? animHeader->hAnimB : animHeader->hAnimA;
int numFrames = index ? animHeader->numFramesAnimB : animHeader->numFramesAnimA;
- int curFrame = index ? animHeader->currentFrameAnimB++ : animHeader->currentFrameAnimA++;
+
+ if(_chrono->getFrameCount() % kTalkAnimationSpeed == 0) {
+ if (index) {
+ animHeader->currentFrameAnimB++;
+ } else {
+ animHeader->currentFrameAnimA++;
+ }
+ }
+
+ byte curFrame = index ? animHeader->currentFrameAnimB : animHeader->currentFrameAnimA;
+
if (curFrame >= numFrames) {
if (index) {
animHeader->currentFrameAnimB = 0;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 3aa7fe81cfc..e2529d55dd4 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -69,6 +69,9 @@ const int kAlfredFrameHeight = 102;
const int kChoiceHeight = 16; // Height of each choice line in pixels
+const int kTalkAnimationSpeed = 2; // Frames per update
+const int kAlfredAnimationSpeed = 2; // Frames per update
+
// Direction flags (bit-packed)
#define MOVE_RIGHT 0x01 // Move right (positive X)
@@ -111,6 +114,7 @@ struct AlfredState {
uint16 movementSpeed = 6; // pixels per frame
uint16 x = 319;
uint16 y = 302;
+ float currentScale = 1.0f;
};
typedef struct {
Commit: 60d73a5f1c1332cc6d8b0363333eeeac4036e313
https://github.com/scummvm/scummvm/commit/60d73a5f1c1332cc6d8b0363333eeeac4036e313
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:28+02:00
Commit Message:
PELROCK: Fixes incorrect zorder drawing
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index edc3733c2ef..ab2ea96cafd 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -314,15 +314,11 @@ void PelrockEngine::copyBackgroundToBuffer() {
void PelrockEngine::updateAnimations() {
// Sort sprites by zOrder (persists in the array)
- sortAnimsByZOrder(_room->_currentRoomAnims);
-
- // Create temporary render order partitioned by Alfred's Y position
- Common::Array<Sprite *> renderOrder;
- int alfredY = alfredState.y;
+ sortAnimsByZOrder(_room->_currentRoomAnims);
// First pass: sprites behind Alfred (y <= alfredY)
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (_room->_currentRoomAnims[i].zOrder > 10) {
+ if (_room->_currentRoomAnims[i].zOrder > 10 || _room->_currentRoomAnims[i].zOrder < 0) {
drawNextFrame(&_room->_currentRoomAnims[i]);
}
}
@@ -332,7 +328,7 @@ void PelrockEngine::updateAnimations() {
// Second pass: sprites in front of Alfred (y > alfredY)
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (_room->_currentRoomAnims[i].zOrder <= 10) {
+ if (_room->_currentRoomAnims[i].zOrder <= 10 && _room->_currentRoomAnims[i].zOrder >= 0) {
drawNextFrame(&_room->_currentRoomAnims[i]);
}
}
Commit: 2326250c3d599713ee0efcb5300317e0282f8b15
https://github.com/scummvm/scummvm/commit/2326250c3d599713ee0efcb5300317e0282f8b15
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:28+02:00
Commit Message:
PELROCK: Moves menu handling into its own class
Changed paths:
A engines/pelrock/menu.cpp
A engines/pelrock/menu.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
new file mode 100644
index 00000000000..5d51fc887d8
--- /dev/null
+++ b/engines/pelrock/menu.cpp
@@ -0,0 +1,226 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/file.h"
+#include "graphics/paletteman.h"
+
+#include "pelrock/menu.h"
+#include "pelrock/offsets.h"
+#include "pelrock/pelrock.h"
+#include "pelrock/util.h"
+#include "menu.h"
+
+namespace Pelrock {
+
+Pelrock::MenuManager::MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res) : _screen(screen), _events(events), _res(res) {
+
+}
+
+
+void MenuManager::checkMouseClick(int x, int y) {
+
+ bool selectedItem = false;
+ for (int i = 0; i < 4; i++) {
+ if (x >= 140 + (82 * i) && x <= 140 + (82 * i) + 64 &&
+ y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
+ _selectedInvIndex = _curInventoryPage * 4 + i;
+ _menuText = _inventoryDescriptions[_selectedInvIndex];
+ selectedItem = true;
+ return;
+ }
+ }
+ if (!selectedItem) {
+ _selectedInvIndex = -1;
+ _menuText = "";
+ }
+
+ if (x >= 471 && x <= 471 + 23 &&
+ y >= 87 && y <= 87 + 33) {
+ _curInventoryPage++;
+ }
+}
+
+
+void MenuManager::menuLoop() {
+ _events->pollEvent();
+
+ if(_events->_leftMouseClicked) {
+ _events->_leftMouseClicked = false;
+ checkMouseClick(_events->_mouseX, _events->_mouseY);
+ }
+ else if (_events->_rightMouseClicked) {
+ _events->_rightMouseClicked = false;
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+ g_engine->stateGame = GAME;
+ tearDown();
+ }
+
+ memcpy(_compositeBuffer, _mainMenu, 640 * 400);
+
+ for (int i = 0; i < 4; i++) {
+ int itemIndex = _curInventoryPage * 4 + i;
+ InventoryObject item = _res->getInventoryObject(itemIndex);
+ drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
+ drawRect(_compositeBuffer, 140 + (82 * i) - 2, 115 - (8 * i) - 2, 64, 64, 255); // Draw border
+ }
+
+ memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+ g_engine->_smallFont->drawString(_screen, _menuText, 230, 200, 200, 255);
+ _screen->markAllDirty();
+ _screen->update();
+}
+
+void MenuManager::loadMenu() {
+
+ bool alternateMenu = false;
+ Common::File alfred7;
+ if (!alfred7.open(Common::Path("ALFRED.7"))) {
+ error("Could not open ALFRED.7");
+ return;
+ }
+
+ _compositeBuffer = new byte[640 * 400];
+ _mainMenu = new byte[640 * 400];
+ loadInventoryDescriptions();
+ if (!alternateMenu) {
+ alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
+ alfred7.read(_mainMenuPalette, 768);
+ for (int i = 0; i < 256; i++) {
+ _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
+ _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
+ _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
+ }
+
+ uint32 curPos = 0;
+ alfred7.seek(2405266, SEEK_SET);
+ alfred7.read(_mainMenu, 65536);
+
+ curPos += 65536;
+
+ byte *compressedPart1 = new byte[29418];
+ alfred7.read(compressedPart1, 29418);
+ byte *decompressedPart1 = nullptr;
+ size_t decompressedSize = rleDecompress(compressedPart1, 29418, 0, 0, &decompressedPart1, true);
+
+ memcpy(_mainMenu + curPos, decompressedPart1, decompressedSize);
+ curPos += decompressedSize;
+
+ delete[] compressedPart1;
+ delete[] decompressedPart1;
+ alfred7.seek(2500220, SEEK_SET);
+ alfred7.read(_mainMenu + curPos, 32768);
+ curPos += 32768;
+ byte *compressedPart2 = new byte[30288];
+ alfred7.read(compressedPart2, 30288);
+ byte *decompressedPart2 = nullptr;
+ decompressedSize = rleDecompress(compressedPart2, 30288, 0, 0, &decompressedPart2, true);
+
+ memcpy(_mainMenu + curPos, decompressedPart2, decompressedSize);
+ curPos += decompressedSize;
+ debug("Settings menu size loaded: %d, with last block %d", curPos, curPos + 92160);
+ delete[] compressedPart2;
+ delete[] decompressedPart2;
+ alfred7.seek(2563266, SEEK_SET);
+ alfred7.read(_mainMenu + curPos, 92160);
+ alfred7.close();
+ } else {
+ Common::File alfred7;
+ if (!alfred7.open(Common::Path("ALFRED.7"))) {
+ error("Could not open ALFRED.7");
+ return;
+ }
+
+ _mainMenu = new byte[640 * 400];
+
+ alfred7.seek(kAlternateSettingsPaletteOffset, SEEK_SET);
+ alfred7.read(_mainMenuPalette, 768);
+ for (int i = 0; i < 256; i++) {
+ _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
+ _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
+ _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
+ }
+
+ g_engine->_res->mergeRleBlocks(&alfred7, kAlternateSettingsMenuOffset, 8, _mainMenu);
+ alfred7.close();
+ }
+}
+
+void MenuManager::loadInventoryDescriptions() {
+
+ Common::File exe;
+ if (!exe.open("JUEGO.EXE")) {
+ error("Couldnt find file JUEGO.EXE");
+ }
+ byte *descBuffer = new byte[kInventoryDescriptionsSize];
+ exe.seek(kInventoryDescriptionsOffset, SEEK_SET);
+ exe.read(descBuffer, kInventoryDescriptionsSize);
+ int pos = 0;
+ Common::String desc = "";
+ while (pos < kInventoryDescriptionsSize) {
+ if (descBuffer[pos] == 0xFD) {
+ if (!desc.empty()) {
+ _inventoryDescriptions.push_back(desc);
+ desc = Common::String();
+ }
+ pos++;
+ continue;
+ }
+ if (descBuffer[pos] == 0x00) {
+ pos++;
+ continue;
+ }
+ if (descBuffer[pos] == 0x08) {
+ pos += 2;
+ continue;
+ }
+ if (descBuffer[pos] == 0xC8) {
+ desc.append(1, '\n');
+ pos++;
+ continue;
+ }
+
+ desc.append(1, decodeChar(descBuffer[pos]));
+ if (pos + 1 == kInventoryDescriptionsSize) {
+ _inventoryDescriptions.push_back(desc);
+ }
+ pos++;
+ }
+ delete[] descBuffer;
+
+ exe.seek(0x49209, SEEK_SET);
+
+
+ _defaultText = exe.readString(0xFD, 35);
+ _menuText = _defaultText;
+
+ exe.close();
+}
+
+void MenuManager::tearDown() {
+
+}
+
+Pelrock::MenuManager::~MenuManager() {
+ delete[] _mainMenu;
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
new file mode 100644
index 00000000000..ba7f44e8859
--- /dev/null
+++ b/engines/pelrock/menu.h
@@ -0,0 +1,56 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_MENU_H
+#define PELROCK_MENU_H
+
+#include "graphics/screen.h"
+
+#include "pelrock/events.h"
+#include "pelrock/resources.h"
+
+namespace Pelrock {
+
+class MenuManager {
+public:
+ MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res);
+ ~MenuManager();
+ void menuLoop();
+ void loadMenu();
+ byte _mainMenuPalette[768] = {0};
+private:
+ void checkMouseClick(int x, int y);
+ void loadInventoryDescriptions();
+ void tearDown();
+ Graphics::Screen *_screen = nullptr;
+ PelrockEventManager *_events = nullptr;
+ ResourceManager *_res = nullptr;
+ byte *_mainMenu = nullptr;
+ byte *_compositeBuffer = nullptr;
+ Common::String _defaultText;
+ // Temporary
+ int _selectedInvIndex = 0;
+ int _curInventoryPage = 0;
+ Common::String _menuText;
+ Common::Array<Common::String> _inventoryDescriptions;
+};
+
+} // End of namespace Pelrock
+#endif // PELROCK_MENU_H
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index 427fcc99c03..0fd85abbf06 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -15,7 +15,8 @@ MODULE_OBJS = \
video/video.o \
pathfinding.o \
events.o \
- dialog.o
+ dialog.o \
+ menu.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index ab2ea96cafd..f94fa27cc51 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -65,6 +65,8 @@ PelrockEngine::~PelrockEngine() {
delete _room;
delete _res;
delete _events;
+ delete _dialog;
+ delete _menu;
// if (_bgPopupBalloon)
// delete[] _bgPopupBalloon;
}
@@ -88,6 +90,7 @@ Common::Error PelrockEngine::run() {
_res = new ResourceManager();
_sound = new SoundManager(_mixer);
_dialog = new DialogManager(_screen, _events);
+ _menu = new MenuManager(_screen, _events, _res);
// Set the engine's debugger console
setDebugger(new PelrockConsole(this));
@@ -113,7 +116,7 @@ Common::Error PelrockEngine::run() {
if (stateGame == SETTINGS) {
changeCursor(DEFAULT);
- menuLoop();
+ _menu->menuLoop();
} else if (stateGame == GAME) {
gameLoop();
}
@@ -129,8 +132,8 @@ void PelrockEngine::init() {
_res->loadCursors();
_res->loadInteractionIcons();
_res->loadInventoryItems();
- _res->loadSettingsMenu();
_sound->loadSoundIndex();
+ _menu->loadMenu();
calculateScalingMasks();
_compositeBuffer = new byte[640 * 400];
@@ -299,7 +302,8 @@ void PelrockEngine::checkMouse() {
_events->_longClicked = false;
}
else if(_events->_rightMouseClicked) {
- g_system->getPaletteManager()->setPalette(_res->_mainMenuPalette, 0, 256);
+
+ g_system->getPaletteManager()->setPalette(_menu->_mainMenuPalette, 0, 256);
_events->_rightMouseClicked = false;
stateGame = SETTINGS;
}
@@ -798,29 +802,6 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
}
}
-void PelrockEngine::checkMouseClickOnSettings(int x, int y) {
-
- bool selectedItem = false;
- for (int i = 0; i < 4; i++) {
- if (x >= 140 + (82 * i) && x <= 140 + (82 * i) + 64 &&
- y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
- selectedInvIndex = curInventoryPage * 4 + i;
- _menuText = _res->getInventoryObject(selectedInvIndex).description;
- selectedItem = true;
- return;
- }
- }
- if (!selectedItem) {
- selectedInvIndex = -1;
- _menuText = "";
- }
-
- if (x >= 471 && x <= 471 + 23 &&
- y >= 87 && y <= 87 + 33) {
- curInventoryPage++;
- }
-}
-
void PelrockEngine::calculateScalingMasks() {
// for scale_factor in range(CHAR_WIDTH):
@@ -1057,33 +1038,33 @@ void PelrockEngine::gameLoop() {
}
}
-void PelrockEngine::menuLoop() {
- _events->pollEvent();
+// void PelrockEngine::menuLoop() {
+// _events->pollEvent();
- if(_events->_leftMouseClicked) {
- _events->_leftMouseClicked = false;
- checkMouseClickOnSettings(_events->_mouseX, _events->_mouseY);
- }
- else if (_events->_rightMouseClicked) {
- _events->_rightMouseClicked = false;
- g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
- stateGame = GAME;
- }
+// if(_events->_leftMouseClicked) {
+// _events->_leftMouseClicked = false;
+// checkMouseClickOnSettings(_events->_mouseX, _events->_mouseY);
+// }
+// else if (_events->_rightMouseClicked) {
+// _events->_rightMouseClicked = false;
+// g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+// stateGame = GAME;
+// }
- memcpy(_compositeBuffer, _res->_mainMenu, 640 * 400);
+// memcpy(_compositeBuffer, _res->_mainMenu, 640 * 400);
- for (int i = 0; i < 4; i++) {
- int itemIndex = curInventoryPage * 4 + i;
- InventoryObject item = _res->getInventoryObject(itemIndex);
- drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
- drawRect(_compositeBuffer, 140 + (82 * i) - 2, 115 - (8 * i) - 2, 64, 64, 255); // Draw border
- }
+// for (int i = 0; i < 4; i++) {
+// int itemIndex = curInventoryPage * 4 + i;
+// InventoryObject item = _res->getInventoryObject(itemIndex);
+// drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
+// drawRect(_compositeBuffer, 140 + (82 * i) - 2, 115 - (8 * i) - 2, 64, 64, 255); // Draw border
+// }
- memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- _smallFont->drawString(_screen, _menuText, 230, 200, 200, 0);
- _screen->markAllDirty();
- _screen->update();
-}
+// memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+// _smallFont->drawString(_screen, _menuText, 230, 200, 200, 0);
+// _screen->markAllDirty();
+// _screen->update();
+// }
void PelrockEngine::walkTo(int x, int y) {
_currentStep = 0;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 407afeed780..a4a0ef2508a 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -48,6 +48,7 @@
#include "pelrock/sound.h"
#include "pelrock/types.h"
#include "pelrock/video/video.h"
+#include "pelrock/menu.h"
namespace Pelrock {
@@ -57,12 +58,12 @@ class PelrockEngine : public Engine {
private:
const ADGameDescription *_gameDescription;
Common::RandomSource _randomSource;
- ResourceManager *_res = nullptr;
ChronoManager *_chrono = nullptr;
VideoManager *_videoManager = nullptr;
SoundManager *_sound = nullptr;
PelrockEventManager *_events = nullptr;
DialogManager *_dialog = nullptr;
+ MenuManager *_menu = nullptr;
void init();
void loadAnims();
@@ -115,7 +116,6 @@ private:
void checkMouseHover();
void checkMouseClick(int x, int y);
void checkLongMouseClick(int x, int y);
- void checkMouseClickOnSettings(int x, int y);
void calculateScalingMasks();
ScaleCalculation calculateScaling(int yPos, ScalingParams scalingParams);
@@ -156,14 +156,8 @@ private:
bool showShadows = false;
- // Temporary
- int selectedInvIndex = 0;
- int curInventoryPage = 0;
- Common::String _menuText;
-
// JAVA
bool shouldPlayIntro = false;
- GameState stateGame = INTRO;
bool inConversation = false;
bool gameInitialized = false;
bool screenReady = false;
@@ -181,9 +175,11 @@ protected:
public:
Graphics::Screen *_screen = nullptr;
+ ResourceManager *_res = nullptr;
RoomManager *_room = nullptr;
AlfredState alfredState;
byte *_compositeBuffer; // Working composition buffer
+ GameState stateGame = INTRO;
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index b79af08c68d..3c61c31c45e 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -60,7 +60,6 @@ ResourceManager::~ResourceManager() {
delete[] alfredCombFrames[0];
delete[] alfredCombFrames[1];
- delete _mainMenu;
delete[] _inventoryIcons;
}
@@ -216,7 +215,7 @@ void ResourceManager::loadAlfredAnims() {
}
void ResourceManager::loadInventoryItems() {
- loadInventoryDescriptions();
+ // loadInventoryDescriptions();
Common::File alfred4File;
if (!alfred4File.open("ALFRED.4")) {
error("Couldnt find file ALFRED.4");
@@ -230,7 +229,7 @@ void ResourceManager::loadInventoryItems() {
for (int i = 0; i < 69; i++) {
_inventoryIcons[i].index = i;
extractSingleFrame(iconData, _inventoryIcons[i].iconData, i, 60, 60);
- _inventoryIcons[i].description = _inventoryDescriptions[i];
+ // _inventoryIcons[i].description = _inventoryDescriptions[i];
}
delete[] iconData;
}
@@ -254,49 +253,6 @@ Pelrock::Sticker ResourceManager::getSticker(int stickerIndex) {
return sticker;
}
-void ResourceManager::loadInventoryDescriptions() {
- Common::File exe;
- if (!exe.open("JUEGO.EXE")) {
- error("Couldnt find file JUEGO.EXE");
- }
- byte *descBuffer = new byte[kInventoryDescriptionsSize];
- exe.seek(kInventoryDescriptionsOffset, SEEK_SET);
- exe.read(descBuffer, kInventoryDescriptionsSize);
- int pos = 0;
- Common::String desc = "";
- while (pos < kInventoryDescriptionsSize) {
- if (descBuffer[pos] == 0xFD) {
- if (!desc.empty()) {
- _inventoryDescriptions.push_back(desc);
- desc = Common::String();
- }
- pos++;
- continue;
- }
- if (descBuffer[pos] == 0x00) {
- pos++;
- continue;
- }
- if (descBuffer[pos] == 0x08) {
- pos += 2;
- continue;
- }
- if(descBuffer[pos] == 0xC8) {
- desc.append(1, '\n');
- pos++;
- continue;
- }
-
- desc.append(1, decodeChar(descBuffer[pos]));
- if (pos + 1 == kInventoryDescriptionsSize) {
- _inventoryDescriptions.push_back(desc);
- }
- pos++;
- }
- delete[] descBuffer;
- exe.close();
-}
-
InventoryObject ResourceManager::getInventoryObject(byte index) {
return _inventoryIcons[index];
}
@@ -318,78 +274,4 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
}
}
-void ResourceManager::loadSettingsMenu() {
-
- bool alternateMenu = false;
- Common::File alfred7;
- if (!alfred7.open(Common::Path("ALFRED.7"))) {
- error("Could not open ALFRED.7");
- return;
- }
-
- _mainMenu = new byte[640 * 400];
-
- if (!alternateMenu) {
- alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
- alfred7.read(_mainMenuPalette, 768);
- for (int i = 0; i < 256; i++) {
- _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
- _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
- _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
- }
-
- uint32 curPos = 0;
- alfred7.seek(2405266, SEEK_SET);
- alfred7.read(_mainMenu, 65536);
-
- curPos += 65536;
-
- byte *compressedPart1 = new byte[29418];
- alfred7.read(compressedPart1, 29418);
- byte *decompressedPart1 = nullptr;
- size_t decompressedSize = rleDecompress(compressedPart1, 29418, 0, 0, &decompressedPart1, true);
-
- memcpy(_mainMenu + curPos, decompressedPart1, decompressedSize);
- curPos += decompressedSize;
-
- delete[] compressedPart1;
- delete[] decompressedPart1;
- alfred7.seek(2500220, SEEK_SET);
- alfred7.read(_mainMenu + curPos, 32768);
- curPos += 32768;
- byte *compressedPart2 = new byte[30288];
- alfred7.read(compressedPart2, 30288);
- byte *decompressedPart2 = nullptr;
- decompressedSize = rleDecompress(compressedPart2, 30288, 0, 0, &decompressedPart2, true);
-
- memcpy(_mainMenu + curPos, decompressedPart2, decompressedSize);
- curPos += decompressedSize;
- debug("Settings menu size loaded: %d, with last block %d", curPos, curPos + 92160);
- delete[] compressedPart2;
- delete[] decompressedPart2;
- alfred7.seek(2563266, SEEK_SET);
- alfred7.read(_mainMenu + curPos, 92160);
- alfred7.close();
- } else {
- Common::File alfred7;
- if (!alfred7.open(Common::Path("ALFRED.7"))) {
- error("Could not open ALFRED.7");
- return;
- }
-
- _mainMenu = new byte[640 * 400];
-
- alfred7.seek(kAlternateSettingsPaletteOffset, SEEK_SET);
- alfred7.read(_mainMenuPalette, 768);
- for (int i = 0; i < 256; i++) {
- _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
- _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
- _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
- }
-
- mergeRleBlocks(&alfred7, kAlternateSettingsMenuOffset, 8, _mainMenu);
- alfred7.close();
- }
-}
-
} // End of namespace Pelrock
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index dc7d70c7602..2f774dee09e 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -33,13 +33,13 @@ static const int interactingAnimLength = 2;
class ResourceManager {
private:
- void mergeRleBlocks(Common::SeekableReadStream *stream, uint32 offset, int numBlocks, byte *outputBuffer);
- void loadInventoryDescriptions();
InventoryObject *_inventoryIcons = nullptr;
+
public:
ResourceManager(/* args */);
~ResourceManager();
+ void mergeRleBlocks(Common::SeekableReadStream *stream, uint32 offset, int numBlocks, byte *outputBuffer);
void loadSettingsMenu();
void loadCursors();
void loadInteractionIcons();
@@ -61,10 +61,6 @@ public:
byte *_cursorMasks[5] = {nullptr};
byte *_verbIcons[9] = {nullptr};
byte *_popUpBalloon = nullptr;
-
- byte *_mainMenu = nullptr;
- byte _mainMenuPalette[768] = {0};
- Common::Array<Common::String> _inventoryDescriptions;
};
} // End of namespace Pelrock
Commit: 567ff2ce419769bd67f7044647b7c938deb2d7f6
https://github.com/scummvm/scummvm/commit/567ff2ce419769bd67f7044647b7c938deb2d7f6
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:28+02:00
Commit Message:
PELROCK: Loads menu texts
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 5d51fc887d8..84a86b3c4f8 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -205,12 +205,43 @@ void MenuManager::loadInventoryDescriptions() {
pos++;
}
delete[] descBuffer;
+ desc = "";
+ byte *textBuffer = new byte[230];
+ exe.seek(0x49203, SEEK_SET);
+ exe.read(textBuffer, 230);
+ pos = 0;
+ while (pos < 230) {
+ if (textBuffer[pos] == 0xFD) {
+ if (!desc.empty()) {
+ _menuTexts.push_back(desc);
+ desc = Common::String();
+ }
+ pos++;
+ continue;
+ }
+ if (textBuffer[pos] == 0x00) {
+ pos++;
+ continue;
+ }
+ if (textBuffer[pos] == 0x08) {
+ pos += 2;
+ continue;
+ }
+ if (textBuffer[pos] == 0xC8) {
+ desc.append(1, '\n');
+ pos++;
+ continue;
+ }
- exe.seek(0x49209, SEEK_SET);
-
+ desc.append(1, decodeChar(textBuffer[pos]));
+ if (pos + 1 == 230) {
+ _menuTexts.push_back(desc);
+ }
+ pos++;
+ }
- _defaultText = exe.readString(0xFD, 35);
- _menuText = _defaultText;
+ _menuText = _menuTexts[0];
+ delete[] textBuffer;
exe.close();
}
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index ba7f44e8859..f4a162b8731 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -38,18 +38,19 @@ public:
private:
void checkMouseClick(int x, int y);
void loadInventoryDescriptions();
+ void loadMenuTexts();
void tearDown();
Graphics::Screen *_screen = nullptr;
PelrockEventManager *_events = nullptr;
ResourceManager *_res = nullptr;
byte *_mainMenu = nullptr;
byte *_compositeBuffer = nullptr;
- Common::String _defaultText;
+ Common::StringArray _menuTexts;
// Temporary
int _selectedInvIndex = 0;
int _curInventoryPage = 0;
Common::String _menuText;
- Common::Array<Common::String> _inventoryDescriptions;
+ Common::StringArray _inventoryDescriptions;
};
} // End of namespace Pelrock
Commit: ae7169c6f8806b08cb5f1d912a8504d48f286bd7
https://github.com/scummvm/scummvm/commit/ae7169c6f8806b08cb5f1d912a8504d48f286bd7
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:28+02:00
Commit Message:
PELROCK: Processes new line commands
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 84a86b3c4f8..9dffd67665d 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -50,7 +50,7 @@ void MenuManager::checkMouseClick(int x, int y) {
}
if (!selectedItem) {
_selectedInvIndex = -1;
- _menuText = "";
+ _menuText = _menuTexts[0];
}
if (x >= 471 && x <= 471 + 23 &&
@@ -84,7 +84,10 @@ void MenuManager::menuLoop() {
}
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- g_engine->_smallFont->drawString(_screen, _menuText, 230, 200, 200, 255);
+ for(int i = 0; _menuText.size() > i; i++) {
+ g_engine->_smallFont->drawString(_screen, _menuText[i], 230, 200 + (i * 10), 200, 255);
+ }
+
_screen->markAllDirty();
_screen->update();
}
@@ -175,10 +178,14 @@ void MenuManager::loadInventoryDescriptions() {
exe.read(descBuffer, kInventoryDescriptionsSize);
int pos = 0;
Common::String desc = "";
+ Common::StringArray objLines;
while (pos < kInventoryDescriptionsSize) {
if (descBuffer[pos] == 0xFD) {
if (!desc.empty()) {
- _inventoryDescriptions.push_back(desc);
+
+ objLines.push_back(desc);
+ _inventoryDescriptions.push_back(objLines);
+ objLines.clear();
desc = Common::String();
}
pos++;
@@ -193,14 +200,16 @@ void MenuManager::loadInventoryDescriptions() {
continue;
}
if (descBuffer[pos] == 0xC8) {
- desc.append(1, '\n');
+ objLines.push_back(desc);
+ desc = Common::String();
pos++;
continue;
}
desc.append(1, decodeChar(descBuffer[pos]));
if (pos + 1 == kInventoryDescriptionsSize) {
- _inventoryDescriptions.push_back(desc);
+ objLines.push_back(desc);
+ _inventoryDescriptions.push_back(objLines);
}
pos++;
}
@@ -210,10 +219,13 @@ void MenuManager::loadInventoryDescriptions() {
exe.seek(0x49203, SEEK_SET);
exe.read(textBuffer, 230);
pos = 0;
+ Common::StringArray textLines;
while (pos < 230) {
if (textBuffer[pos] == 0xFD) {
if (!desc.empty()) {
- _menuTexts.push_back(desc);
+ textLines.push_back(desc);
+ _menuTexts.push_back(textLines);
+ textLines.clear();
desc = Common::String();
}
pos++;
@@ -228,14 +240,16 @@ void MenuManager::loadInventoryDescriptions() {
continue;
}
if (textBuffer[pos] == 0xC8) {
- desc.append(1, '\n');
+ textLines.push_back(desc);
+ desc = Common::String();
pos++;
continue;
}
desc.append(1, decodeChar(textBuffer[pos]));
if (pos + 1 == 230) {
- _menuTexts.push_back(desc);
+ textLines.push_back(desc);
+ _menuTexts.push_back(textLines);
}
pos++;
}
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index f4a162b8731..1a429f5b7fe 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -45,12 +45,12 @@ private:
ResourceManager *_res = nullptr;
byte *_mainMenu = nullptr;
byte *_compositeBuffer = nullptr;
- Common::StringArray _menuTexts;
+ Common::Array<Common::StringArray> _menuTexts;
// Temporary
int _selectedInvIndex = 0;
int _curInventoryPage = 0;
- Common::String _menuText;
- Common::StringArray _inventoryDescriptions;
+ Common::StringArray _menuText;
+ Common::Array<Common::StringArray> _inventoryDescriptions;
};
} // End of namespace Pelrock
Commit: fcb23865fd95e000017cdd617909eaed30976150
https://github.com/scummvm/scummvm/commit/fcb23865fd95e000017cdd617909eaed30976150
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:29+02:00
Commit Message:
PELROCK: Process colored text
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 9dffd67665d..43576882dc5 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -35,6 +35,31 @@ Pelrock::MenuManager::MenuManager(Graphics::Screen *screen, PelrockEventManager
}
+void MenuManager::drawColoredText(Graphics::ManagedSurface *screen, const Common::String &text, int x, int y, int w, Graphics::Font *font) {
+ int currentX = x;
+ uint32 currentColor = 255;
+
+ Common::String segment;
+ for (uint i = 0; i < text.size(); i++) {
+ if (text[i] == '@' && i + 1 < text.size()) {
+ // Draw accumulated segment
+ if (!segment.empty()) {
+ font->drawString(screen, segment, currentX, y, w, currentColor);
+ currentX += font->getStringWidth(segment);
+ segment.clear();
+ }
+ currentColor = text[i + 1];
+ i++; // skip color code
+ } else {
+ segment += text[i];
+ }
+ }
+
+ // Draw remaining segment
+ if (!segment.empty()) {
+ font->drawString(screen, segment, currentX, y, w, currentColor);
+ }
+}
void MenuManager::checkMouseClick(int x, int y) {
@@ -61,7 +86,7 @@ void MenuManager::checkMouseClick(int x, int y) {
void MenuManager::menuLoop() {
- _events->pollEvent();
+ _events->pollEvent();
if(_events->_leftMouseClicked) {
_events->_leftMouseClicked = false;
@@ -71,7 +96,7 @@ void MenuManager::menuLoop() {
_events->_rightMouseClicked = false;
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
g_engine->stateGame = GAME;
- tearDown();
+ tearDown();
}
memcpy(_compositeBuffer, _mainMenu, 640 * 400);
@@ -80,13 +105,12 @@ void MenuManager::menuLoop() {
int itemIndex = _curInventoryPage * 4 + i;
InventoryObject item = _res->getInventoryObject(itemIndex);
drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
- drawRect(_compositeBuffer, 140 + (82 * i) - 2, 115 - (8 * i) - 2, 64, 64, 255); // Draw border
}
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- for(int i = 0; _menuText.size() > i; i++) {
- g_engine->_smallFont->drawString(_screen, _menuText[i], 230, 200 + (i * 10), 200, 255);
- }
+ for(int i = 0; _menuText.size() > i; i++) {
+ drawColoredText(_screen, _menuText[i], 230, 200 + (i * 10), 200, g_engine->_smallFont);
+ }
_screen->markAllDirty();
_screen->update();
@@ -103,7 +127,7 @@ void MenuManager::loadMenu() {
_compositeBuffer = new byte[640 * 400];
_mainMenu = new byte[640 * 400];
- loadInventoryDescriptions();
+ loadMenuTexts();
if (!alternateMenu) {
alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
alfred7.read(_mainMenuPalette, 768);
@@ -167,95 +191,71 @@ void MenuManager::loadMenu() {
}
}
-void MenuManager::loadInventoryDescriptions() {
-
- Common::File exe;
- if (!exe.open("JUEGO.EXE")) {
- error("Couldnt find file JUEGO.EXE");
- }
- byte *descBuffer = new byte[kInventoryDescriptionsSize];
- exe.seek(kInventoryDescriptionsOffset, SEEK_SET);
- exe.read(descBuffer, kInventoryDescriptionsSize);
+Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size) {
int pos = 0;
Common::String desc = "";
- Common::StringArray objLines;
- while (pos < kInventoryDescriptionsSize) {
- if (descBuffer[pos] == 0xFD) {
+ Common::StringArray lines;
+ Common::Array<Common::Array<Common::String>> texts;
+ while (pos < size) {
+ if (data[pos] == 0xFD) {
if (!desc.empty()) {
- objLines.push_back(desc);
- _inventoryDescriptions.push_back(objLines);
- objLines.clear();
+ lines.push_back(desc);
+ texts.push_back(lines);
+ lines.clear();
desc = Common::String();
}
pos++;
continue;
}
- if (descBuffer[pos] == 0x00) {
+ if (data[pos] == 0x00) {
pos++;
continue;
}
- if (descBuffer[pos] == 0x08) {
+ if (data[pos] == 0x08) {
+ byte color = data[pos + 1];
+ desc.append(1, '@');
+ desc.append(1, color);
pos += 2;
continue;
}
- if (descBuffer[pos] == 0xC8) {
- objLines.push_back(desc);
- desc = Common::String();
+ if (data[pos] == 0xC8) {
+ lines.push_back(desc);
+ desc = Common::String();
pos++;
continue;
}
- desc.append(1, decodeChar(descBuffer[pos]));
- if (pos + 1 == kInventoryDescriptionsSize) {
- objLines.push_back(desc);
- _inventoryDescriptions.push_back(objLines);
+ desc.append(1, decodeChar(data[pos]));
+ if (pos + 1 == size) {
+ lines.push_back(desc);
+ texts.push_back(lines);
}
pos++;
}
- delete[] descBuffer;
- desc = "";
- byte *textBuffer = new byte[230];
- exe.seek(0x49203, SEEK_SET);
- exe.read(textBuffer, 230);
- pos = 0;
- Common::StringArray textLines;
- while (pos < 230) {
- if (textBuffer[pos] == 0xFD) {
- if (!desc.empty()) {
- textLines.push_back(desc);
- _menuTexts.push_back(textLines);
- textLines.clear();
- desc = Common::String();
- }
- pos++;
- continue;
- }
- if (textBuffer[pos] == 0x00) {
- pos++;
- continue;
- }
- if (textBuffer[pos] == 0x08) {
- pos += 2;
- continue;
- }
- if (textBuffer[pos] == 0xC8) {
- textLines.push_back(desc);
- desc = Common::String();
- pos++;
- continue;
- }
+ return texts;
+}
- desc.append(1, decodeChar(textBuffer[pos]));
- if (pos + 1 == 230) {
- textLines.push_back(desc);
- _menuTexts.push_back(textLines);
- }
- pos++;
+void MenuManager::loadMenuTexts() {
+
+ Common::File exe;
+ if (!exe.open("JUEGO.EXE")) {
+ error("Couldnt find file JUEGO.EXE");
}
+ byte *descBuffer = new byte[kInventoryDescriptionsSize];
+ exe.seek(kInventoryDescriptionsOffset, SEEK_SET);
+ exe.read(descBuffer, kInventoryDescriptionsSize);
+ _inventoryDescriptions = processTextData(descBuffer, kInventoryDescriptionsSize);
+ delete[] descBuffer;
+
+ Common::String desc = "";
+ byte *textBuffer = new byte[230];
+ exe.seek(0x49203, SEEK_SET);
+ exe.read(textBuffer, 230);
+ _menuTexts = processTextData(textBuffer, 230);
- _menuText = _menuTexts[0];
- delete[] textBuffer;
+ _menuText = _menuTexts[0];
+ delete[] textBuffer;
exe.close();
}
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 1a429f5b7fe..77d5d39b5b6 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -22,6 +22,7 @@
#define PELROCK_MENU_H
#include "graphics/screen.h"
+#include "graphics/font.h"
#include "pelrock/events.h"
#include "pelrock/resources.h"
@@ -30,22 +31,22 @@ namespace Pelrock {
class MenuManager {
public:
- MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res);
- ~MenuManager();
- void menuLoop();
- void loadMenu();
+ MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res);
+ ~MenuManager();
+ void menuLoop();
+ void loadMenu();
byte _mainMenuPalette[768] = {0};
private:
void checkMouseClick(int x, int y);
- void loadInventoryDescriptions();
- void loadMenuTexts();
- void tearDown();
- Graphics::Screen *_screen = nullptr;
- PelrockEventManager *_events = nullptr;
- ResourceManager *_res = nullptr;
+ void loadMenuTexts();
+ void tearDown();
+ void drawColoredText(Graphics::ManagedSurface *surface, const Common::String &text, int x, int y, int w, Graphics::Font *font);
+ Graphics::Screen *_screen = nullptr;
+ PelrockEventManager *_events = nullptr;
+ ResourceManager *_res = nullptr;
byte *_mainMenu = nullptr;
- byte *_compositeBuffer = nullptr;
- Common::Array<Common::StringArray> _menuTexts;
+ byte *_compositeBuffer = nullptr;
+ Common::Array<Common::StringArray> _menuTexts;
// Temporary
int _selectedInvIndex = 0;
int _curInventoryPage = 0;
Commit: c45bf2369c5219f9157a5a633cbc7a86b26c5fb9
https://github.com/scummvm/scummvm/commit/c45bf2369c5219f9157a5a633cbc7a86b26c5fb9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:29+02:00
Commit Message:
PELROCK: Add and remove Stickers
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 43576882dc5..497f7db4a92 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -191,51 +191,6 @@ void MenuManager::loadMenu() {
}
}
-Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size) {
- int pos = 0;
- Common::String desc = "";
- Common::StringArray lines;
- Common::Array<Common::Array<Common::String>> texts;
- while (pos < size) {
- if (data[pos] == 0xFD) {
- if (!desc.empty()) {
-
- lines.push_back(desc);
- texts.push_back(lines);
- lines.clear();
- desc = Common::String();
- }
- pos++;
- continue;
- }
- if (data[pos] == 0x00) {
- pos++;
- continue;
- }
- if (data[pos] == 0x08) {
- byte color = data[pos + 1];
- desc.append(1, '@');
- desc.append(1, color);
- pos += 2;
- continue;
- }
- if (data[pos] == 0xC8) {
- lines.push_back(desc);
- desc = Common::String();
- pos++;
- continue;
- }
-
- desc.append(1, decodeChar(data[pos]));
- if (pos + 1 == size) {
- lines.push_back(desc);
- texts.push_back(lines);
- }
- pos++;
- }
- return texts;
-}
-
void MenuManager::loadMenuTexts() {
Common::File exe;
@@ -245,14 +200,14 @@ void MenuManager::loadMenuTexts() {
byte *descBuffer = new byte[kInventoryDescriptionsSize];
exe.seek(kInventoryDescriptionsOffset, SEEK_SET);
exe.read(descBuffer, kInventoryDescriptionsSize);
- _inventoryDescriptions = processTextData(descBuffer, kInventoryDescriptionsSize);
+ _inventoryDescriptions = _res->processTextData(descBuffer, kInventoryDescriptionsSize);
delete[] descBuffer;
Common::String desc = "";
- byte *textBuffer = new byte[230];
- exe.seek(0x49203, SEEK_SET);
- exe.read(textBuffer, 230);
- _menuTexts = processTextData(textBuffer, 230);
+ byte *textBuffer = new byte[kMenuTextSize];
+ exe.seek(kMenuTextOffset, SEEK_SET);
+ exe.read(textBuffer, kMenuTextSize);
+ _menuTexts = _res->processTextData(textBuffer, kMenuTextSize);
_menuText = _menuTexts[0];
delete[] textBuffer;
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 03311b8295c..6b939b13e28 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -38,37 +38,85 @@ static const uint32_t kBalloonFramesSize = 24950;
static const uint32_t ALFRED7_ALFRED_COMB_R = 67768;
static const uint32_t ALFRED7_ALFRED_COMB_L = 88408;
-
static const uint32_t kAlternateSettingsMenuOffset = 910097;
-static const uint32_t kAlternateSettingsPaletteOffset = 1038141; // 640 * 480
-static const uint32_t kSettingsPaletteOffset = 0x2884c2; // 640 * 480
+static const uint32_t kAlternateSettingsPaletteOffset = 1038141; // 640 * 480
+static const uint32_t kSettingsPaletteOffset = 0x2884c2; // 640 * 480
#define DESCRIPTION_BASE_OFFSET 0x4715D
#define NUM_DESCRIPTIONS 113
static const uint32 kInventoryDescriptionsOffset = 0x4715D;
static const uint32 kInventoryDescriptionsSize = 7868;
-
+static const uint32 kMenuTextOffset = 0x49203;
+static const uint32 kMenuTextSize = 230;
+static const uint32 kAlfredResponsesOffset = 0x441DC;
+static const uint32 kAlfredResponsesSize = 12163;
+static const uint32 kCreditsOffset = 0x49F60;
+static const uint32 kCreditsSize = 2540;
const uint32_t pegatina_offsets[137] = {
0x000000, 0x00005B, 0x0000B6, 0x000298, 0x00047A, 0x0023C8, 0x004316, 0x004376,
- 0x005119, 0x005EBC, 0x0083ED, 0x008529, 0x0092C4, 0x00A3AA, 0x00B490, 0x00B6A6,
- 0x00C05A, 0x00CA0E, 0x00D3D0, 0x00D46E, 0x00F036, 0x00FB8F, 0x00FC55, 0x0119D7,
- 0x013759, 0x01391F, 0x014A9D, 0x015C1B, 0x017601, 0x018FE7, 0x019048, 0x0190A9,
- 0x01910A, 0x0197F4, 0x019EDE, 0x01A7EC, 0x01B0FA, 0x01B8C4, 0x01C644, 0x01D83A,
- 0x01E104, 0x01E8C6, 0x01F45D, 0x01FBBB, 0x02011D, 0x02052F, 0x020A95, 0x020E5B,
- 0x0210B3, 0x0216E6, 0x021D5E, 0x0233A3, 0x0249E8, 0x025777, 0x026506, 0x028E2B,
- 0x02B82F, 0x02C9D7, 0x02E4CA, 0x02FFBD, 0x03234A, 0x0346D7, 0x036A83, 0x038E2F,
- 0x03B18D, 0x03D4EB, 0x03DEC9, 0x03F813, 0x04115D, 0x045303, 0x0494A9, 0x04955F,
- 0x049615, 0x0496CB, 0x0499E1, 0x049EC7, 0x04A023, 0x04A447, 0x04BA6D, 0x04BFA1,
- 0x04CE33, 0x04CF09, 0x04DB3B, 0x052885, 0x0575CF, 0x05775B, 0x057D79, 0x058397,
- 0x058969, 0x058F50, 0x05A9DB, 0x05C561, 0x05C72E, 0x05C8FB, 0x05EAC1, 0x060C87,
- 0x060D19, 0x060E62, 0x061039, 0x0613C2, 0x061764, 0x061847, 0x062535, 0x062D4B,
- 0x064F11, 0x0670D7, 0x067381, 0x0675A9, 0x0677EF, 0x067A98, 0x067DDE, 0x068115,
- 0x0684E3, 0x068A76, 0x068F30, 0x0693C8, 0x0696AD, 0x06C2C9, 0x06C84D, 0x07095D,
- 0x071854, 0x07274B, 0x073642, 0x074539, 0x075454, 0x0791DA, 0x07CF60, 0x07E4AB,
- 0x07ECED, 0x07F52F, 0x07FD71, 0x080591, 0x080B24, 0x080B84, 0x080F39, 0x0812F5,
- 0x0816B1
+ 0x005119, 0x005EBC, 0x0083ED, 0x008529, 0x0092C4, 0x00A3AA, 0x00B490, 0x00B6A6,
+ 0x00C05A, 0x00CA0E, 0x00D3D0, 0x00D46E, 0x00F036, 0x00FB8F, 0x00FC55, 0x0119D7,
+ 0x013759, 0x01391F, 0x014A9D, 0x015C1B, 0x017601, 0x018FE7, 0x019048, 0x0190A9,
+ 0x01910A, 0x0197F4, 0x019EDE, 0x01A7EC, 0x01B0FA, 0x01B8C4, 0x01C644, 0x01D83A,
+ 0x01E104, 0x01E8C6, 0x01F45D, 0x01FBBB, 0x02011D, 0x02052F, 0x020A95, 0x020E5B,
+ 0x0210B3, 0x0216E6, 0x021D5E, 0x0233A3, 0x0249E8, 0x025777, 0x026506, 0x028E2B,
+ 0x02B82F, 0x02C9D7, 0x02E4CA, 0x02FFBD, 0x03234A, 0x0346D7, 0x036A83, 0x038E2F,
+ 0x03B18D, 0x03D4EB, 0x03DEC9, 0x03F813, 0x04115D, 0x045303, 0x0494A9, 0x04955F,
+ 0x049615, 0x0496CB, 0x0499E1, 0x049EC7, 0x04A023, 0x04A447, 0x04BA6D, 0x04BFA1,
+ 0x04CE33, 0x04CF09, 0x04DB3B, 0x052885, 0x0575CF, 0x05775B, 0x057D79, 0x058397,
+ 0x058969, 0x058F50, 0x05A9DB, 0x05C561, 0x05C72E, 0x05C8FB, 0x05EAC1, 0x060C87,
+ 0x060D19, 0x060E62, 0x061039, 0x0613C2, 0x061764, 0x061847, 0x062535, 0x062D4B,
+ 0x064F11, 0x0670D7, 0x067381, 0x0675A9, 0x0677EF, 0x067A98, 0x067DDE, 0x068115,
+ 0x0684E3, 0x068A76, 0x068F30, 0x0693C8, 0x0696AD, 0x06C2C9, 0x06C84D, 0x07095D,
+ 0x071854, 0x07274B, 0x073642, 0x074539, 0x075454, 0x0791DA, 0x07CF60, 0x07E4AB,
+ 0x07ECED, 0x07F52F, 0x07FD71, 0x080591, 0x080B24, 0x080B84, 0x080F39, 0x0812F5,
+ 0x0816B1};
+
+const byte pegatina_rooms[140] = {
+ 0, 0, 0, 0, 0, 0, 0, // Sprites 0-6: Room 0
+ 2, 2, // Sprites 7-8: Room 2
+ 3, 3, 3, 3, 3, 3, 3, 3, // Sprites 9-16: Room 3
+ 4, 4, 4, 4, 4, // Sprites 17-21: Room 4
+ 5, 5, // Sprites 22-23: Room 5
+ 7, // Sprite 24: Room 7
+ 8, 8, // Sprites 25-26: Room 8
+ 9, 9, 9, 9, 9, // Sprites 27-31: Room 9
+ 12, 12, // Sprites 32-33: Room 12
+ 13, 13, 13, // Sprites 34-36: Room 13
+ 12, // Sprite 37: Room 12
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, // Sprites 38-49: Room 15
+ 16, 16, // Sprites 50-51: Room 16
+ 17, 17, // Sprites 52-53: Room 17
+ 19, 19, 19, 19, 19, // Sprites 54-58: Room 19
+
+ 0, 0, 0, 0, 0, 0, 0, // Sprites 59-65: Room 0
+ 33, 33, // Sprites 66-67: Room 33
+ 29, 29, // Sprites 68-69: Room 29
+ 0, 0, 0, // Sprites 70-72: Room 0
+
+ 34, 35, 31, 25, // Sprites 73-76: Various rooms
+ 31, // Sprite 77: Room 31
+ 32, // Sprite 78: Room 32
+ 21, 25, // Sprites 79-80: Rooms 21, 25
+ 0, // Sprite 81: Room 0
+ 0, 0, 0, 0, 0, // Sprites 82-86: Room 0
+ 4, 4, 4, 4, // Sprites 87-90: Room 4
+ 0, 0, 0, 0, // Sprites 91-94: Room 0
+ 0, 0, 0, 0, 0, 0, // Sprites 95-100: Room 0
+ 33, 33, // Sprites 101-102: Room 33
+ 47, 47, // Sprites 103-104: Room 47
+ 52, 52, 52, 52, 52, // Sprites 105-109: Room 52
+ 52, 52, 52, 52, 52, 52, // Sprites 110-115: Room 52
+ 41, // Sprite 116: Room 41
+ 0, // Sprite 117: Room 0
+ 30, // Sprite 118: Room 30
+ 44, 44, 44, 44, // Sprites 119-122: Room 44
+ 31, // Sprite 123: Room 31
+ 46, 46, // Sprites 124-125: Room 46
+ 31, // Sprite 126: Room 31
+ 51, 52, 53, 54 // Sprites 127-130: Various rooms
};
// Description offsets relative to DESCRIPTION_BASE_OFFSET
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f94fa27cc51..826b4cd3c2e 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -132,6 +132,8 @@ void PelrockEngine::init() {
_res->loadCursors();
_res->loadInteractionIcons();
_res->loadInventoryItems();
+ _res->loadAlfredResponses();
+
_sound->loadSoundIndex();
_menu->loadMenu();
@@ -246,6 +248,8 @@ void PelrockEngine::renderScene(bool showTextOverlay) {
playSoundIfNeeded();
copyBackgroundToBuffer();
+
+ placeStickers();
updateAnimations();
if (showTextOverlay) {
@@ -286,29 +290,25 @@ void PelrockEngine::renderScene(bool showTextOverlay) {
// alfredState.curFrame = 0;
// }
-
_screen->markAllDirty();
}
}
void PelrockEngine::checkMouse() {
- if(_events->_leftMouseClicked) {
+ if (_events->_leftMouseClicked) {
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_leftMouseClicked = false;
_displayPopup = false;
- }
- else if(_events->_longClicked) {
+ } else if (_events->_longClicked) {
checkLongMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_longClicked = false;
- }
- else if(_events->_rightMouseClicked) {
+ } else if (_events->_rightMouseClicked) {
g_system->getPaletteManager()->setPalette(_menu->_mainMenuPalette, 0, 256);
_events->_rightMouseClicked = false;
stateGame = SETTINGS;
}
checkMouseHover();
-
}
void PelrockEngine::copyBackgroundToBuffer() {
@@ -381,8 +381,31 @@ void PelrockEngine::paintDebugLayer() {
_smallFont->drawString(_screen, Common::String::format("Frame number: %d", _chrono->getFrameCount()), 0, 30, 640, 13);
}
-void PelrockEngine::animateFadePalette(PaletteAnim *anim) {
+void PelrockEngine::placeStickers() {
+ for (int i = 0; i < _room->_currentRoomStickers.size(); i++) {
+ Sticker sticker = _room->_currentRoomStickers[i];
+ if (sticker.roomNumber == _room->_currentRoomNumber) {
+ placeSticker(sticker);
+ }
+ }
+}
+
+void PelrockEngine::placeSticker(Sticker sticker) {
+ for (int y = 0; y < sticker.h; y++) {
+ for (int x = 0; x < sticker.w; x++) {
+ byte pixel = sticker.stickerData[y * sticker.w + x];
+ if (pixel != 0) {
+ int bgX = sticker.x + x;
+ int bgY = sticker.y + y;
+ if (bgX >= 0 && bgX < 640 && bgY >= 0 && bgY < 400) {
+ _compositeBuffer[bgY * 640 + bgX] = pixel;
+ }
+ }
+ }
+ }
+}
+void PelrockEngine::animateFadePalette(PaletteAnim *anim) {
if (anim->data[0] >= anim->data[6] &&
anim->data[1] >= anim->data[7] &&
@@ -457,6 +480,9 @@ void PelrockEngine::doAction(byte action, HotSpot *hotspot) {
case OPEN:
open(hotspot);
break;
+ case CLOSE:
+ close(hotspot);
+ break;
default:
break;
}
@@ -483,10 +509,23 @@ void PelrockEngine::lookAt(HotSpot *hotspot) {
void PelrockEngine::open(HotSpot *hotspot) {
switch (hotspot->extra) {
case 261:
- _room->placeSticker(_res->getSticker(91), _currentBackground);
+ _room->addSticker(_res->getSticker(91));
+ break;
+
+ default:
+
+ break;
+ }
+}
+
+void PelrockEngine::close(HotSpot *hotspot) {
+ switch (hotspot->extra) {
+ case 261:
+ _room->removeSticker(91);
break;
default:
+
break;
}
}
@@ -570,7 +609,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.curFrame = 0;
}
drawAlfred(_res->alfredTalkFrames[alfredState.direction][alfredState.curFrame]);
- if(_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
+ if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
alfredState.curFrame++;
}
break;
@@ -616,7 +655,6 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
int linesToSkip = kAlfredFrameHeight - finalHeight;
-
int shadowPos = alfredState.y; // - finalHeight;
bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + alfredState.x] != 0xFF;
@@ -723,13 +761,13 @@ void applyMovement(int16_t *x, int16_t *y, int8_t *z, uint16_t flags) {
}
// Z-axis movement
- if (flags & 0x4000) { // Bit 14: Z movement enabled
- int amount = (flags >> 10) & 0x07; // Bits 10-12: amount
- if (flags & 0x2000) { // Bit 13: direction
- *z += amount; // 1 = forward (add)
- } else {
- *z -= amount; // 0 = back (subtract)
- }
+ if (flags & 0x4000) { // Bit 14: Z movement enabled
+ int amount = (flags >> 10) & 0x07; // Bits 10-12: amount
+ if (flags & 0x2000) { // Bit 13: direction
+ *z += amount; // 1 = forward (add)
+ } else {
+ *z -= amount; // 0 = back (subtract)
+ }
}
}
@@ -757,7 +795,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
drawSpriteToBuffer(_compositeBuffer, 640, frame, sprite->x, sprite->y, sprite->w, sprite->h, 255);
// if (animData.elpapsedFrames == animData.speed) {
- if(_chrono->getFrameCount() % animData.speed == 0) {
+ if (_chrono->getFrameCount() % animData.speed == 0) {
animData.elpapsedFrames = 0;
if (animData.curFrame < animData.nframes - 1) {
animData.curFrame++;
@@ -953,12 +991,9 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
VerbIcon icon = isActionUnder(_events->_mouseX, _events->_mouseY);
for (int i = 0; i < actions.size(); i++) {
- if (icon == actions[i] && _iconBlink++ < kIconBlinkPeriod / 2) {
+ if (icon == actions[i] && _chrono->getFrameCount() % kIconBlinkPeriod == 0) {
continue;
}
- if (_iconBlink > kIconBlinkPeriod) {
- _iconBlink = 0;
- }
drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
}
@@ -976,7 +1011,7 @@ void PelrockEngine::drawTalkNPC(Sprite *animSet) {
int h = index ? animHeader->hAnimB : animHeader->hAnimA;
int numFrames = index ? animHeader->numFramesAnimB : animHeader->numFramesAnimA;
- if(_chrono->getFrameCount() % kTalkAnimationSpeed == 0) {
+ if (_chrono->getFrameCount() % kTalkAnimationSpeed == 0) {
if (index) {
animHeader->currentFrameAnimB++;
} else {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index a4a0ef2508a..476809f6e49 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -43,12 +43,12 @@
#include "pelrock/fonts/large_font.h"
#include "pelrock/fonts/small_font.h"
#include "pelrock/fonts/small_font_double.h"
+#include "pelrock/menu.h"
#include "pelrock/resources.h"
#include "pelrock/room.h"
#include "pelrock/sound.h"
#include "pelrock/types.h"
#include "pelrock/video/video.h"
-#include "pelrock/menu.h"
namespace Pelrock {
@@ -94,7 +94,8 @@ private:
void presentFrame();
void updatePaletteAnimations();
void paintDebugLayer();
-
+ void placeStickers();
+ void placeSticker(Sticker sticker);
void animateFadePalette(PaletteAnim *anim);
void animateRotatePalette(PaletteAnim *anim);
@@ -102,6 +103,7 @@ private:
void talkTo(HotSpot *hotspot);
void lookAt(HotSpot *hotspot);
void open(HotSpot *hotspot);
+ void close(HotSpot *hotspot);
void renderText(Common::Array<Common::String> lines, int color, int x, int y);
void chooseAlfredStateAndDraw();
void drawAlfred(byte *buf);
@@ -141,14 +143,12 @@ private:
byte *_currentBackground = nullptr; // Clean background - NEVER modified
bool _displayPopup = false;
- byte _iconBlink = 0;
int _popupX = 0;
int _popupY = 0;
int _currentPopupFrame = 0;
HotSpot *_currentHotspot = nullptr;
-
Common::Point _curWalkTarget;
bool isNPCATalking = false;
uint16 whichNPCTalking = 0;
@@ -178,7 +178,7 @@ public:
ResourceManager *_res = nullptr;
RoomManager *_room = nullptr;
AlfredState alfredState;
- byte *_compositeBuffer; // Working composition buffer
+ byte *_compositeBuffer; // Working composition buffer
GameState stateGame = INTRO;
SmallFont *_smallFont = nullptr;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 3c61c31c45e..7262f3028fe 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -234,6 +234,79 @@ void ResourceManager::loadInventoryItems() {
delete[] iconData;
}
+void ResourceManager::loadAlfredResponses() {
+
+ Common::File exe;
+ if (!exe.open("JUEGO.EXE")) {
+ error("Couldnt find file JUEGO.EXE");
+ }
+ byte *descBuffer = new byte[kAlfredResponsesSize];
+ exe.seek(kAlfredResponsesOffset, SEEK_SET);
+ exe.read(descBuffer, kAlfredResponsesSize);
+ _alfredResponses = processTextData(descBuffer, kAlfredResponsesSize);
+ delete[] descBuffer;
+ exe.close();
+}
+
+Common::Array<Common::StringArray> ResourceManager::getCredits() {
+ Common::File exe;
+ if (!exe.open("JUEGO.EXE")) {
+ error("Couldnt find file JUEGO.EXE");
+ }
+ byte *descBuffer = new byte[kCreditsSize];
+ exe.seek(kCreditsOffset, SEEK_SET);
+ exe.read(descBuffer, kCreditsSize);
+ Common::Array<Common::StringArray> credits = processTextData(descBuffer, kCreditsSize);
+ delete[] descBuffer;
+ exe.close();
+ return credits;
+}
+
+Common::Array<Common::Array<Common::String>> ResourceManager::processTextData(byte *data, size_t size) {
+ int pos = 0;
+ Common::String desc = "";
+ Common::StringArray lines;
+ Common::Array<Common::Array<Common::String>> texts;
+ while (pos < size) {
+ if (data[pos] == 0xFD) {
+ if (!desc.empty()) {
+
+ lines.push_back(desc);
+ texts.push_back(lines);
+ lines.clear();
+ desc = Common::String();
+ }
+ pos++;
+ continue;
+ }
+ if (data[pos] == 0x00) {
+ pos++;
+ continue;
+ }
+ if (data[pos] == 0x08) {
+ byte color = data[pos + 1];
+ desc.append(1, '@');
+ desc.append(1, color);
+ pos += 2;
+ continue;
+ }
+ if (data[pos] == 0xC8) {
+ lines.push_back(desc);
+ desc = Common::String();
+ pos++;
+ continue;
+ }
+
+ desc.append(1, decodeChar(data[pos]));
+ if (pos + 1 == size) {
+ lines.push_back(desc);
+ texts.push_back(lines);
+ }
+ pos++;
+ }
+ return texts;
+}
+
Pelrock::Sticker ResourceManager::getSticker(int stickerIndex) {
Common::File alfred6File;
if (!alfred6File.open("ALFRED.6")) {
@@ -247,6 +320,8 @@ Pelrock::Sticker ResourceManager::getSticker(int stickerIndex) {
sticker.y = alfred6File.readUint16LE();
sticker.w = alfred6File.readByte();
sticker.h = alfred6File.readByte();
+ sticker.roomNumber = pegatina_rooms[stickerIndex];
+ sticker.stickerIndex = stickerIndex;
sticker.stickerData = new byte[sticker.w * sticker.h];
alfred6File.read(sticker.stickerData, sticker.w * sticker.h);
alfred6File.close();
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 2f774dee09e..77535265e62 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -45,6 +45,9 @@ public:
void loadInteractionIcons();
void loadAlfredAnims();
void loadInventoryItems();
+ void loadAlfredResponses();
+ Common::Array<Common::StringArray> getCredits();
+ Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size);
Sticker getSticker(int stickerIndex);
InventoryObject getInventoryObject(byte index);
byte *loadExtra();
@@ -61,6 +64,7 @@ public:
byte *_cursorMasks[5] = {nullptr};
byte *_verbIcons[9] = {nullptr};
byte *_popUpBalloon = nullptr;
+ Common::Array<Common::StringArray> _alfredResponses;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index a705bd009b5..f7cedd90832 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -93,19 +93,20 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
}
}
-void RoomManager::placeSticker(Sticker sticker, byte *background) {
- for (int y = 0; y < sticker.h; y++) {
- for (int x = 0; x < sticker.w; x++) {
- byte pixel = sticker.stickerData[y * sticker.w + x];
- if (pixel != 0) {
- int bgX = sticker.x + x;
- int bgY = sticker.y + y;
- if (bgX >= 0 && bgX < 640 && bgY >= 0 && bgY < 400) {
- background[bgY * 640 + bgX] = pixel;
- }
- }
+void RoomManager::addSticker(Sticker sticker) {
+ _currentRoomStickers.push_back(sticker);
+}
+
+void RoomManager::removeSticker(int stickerIndex) {
+ int index = -1;
+ for (int i = 0; i < _currentRoomStickers.size(); i++) {
+ if (_currentRoomStickers[i].stickerIndex == stickerIndex) {
+ index = i;
+ break;
}
}
+ if (index != -1 && index < _currentRoomStickers.size())
+ _currentRoomStickers.remove_at(index);
}
PaletteAnim *RoomManager::getPaletteAnimForRoom(int roomNumber) {
@@ -440,7 +441,7 @@ Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, in
// debug("End of descriptions at position %d", pos);
size_t conversationStart = lastDescPos + 1;
_conversationDataSize = pair12_size - conversationStart;
- if(_conversationData != nullptr) {
+ if (_conversationData != nullptr) {
delete[] _conversationData;
}
_conversationData = new byte[_conversationDataSize];
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index c0a3c0f0419..f9018d89d84 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -39,7 +39,8 @@ public:
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
- void placeSticker(Sticker sticker, byte *background);
+ void addSticker(Sticker sticker);
+ void removeSticker(int index);
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
Common::String getRoomName(int roomNumber) {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index e2529d55dd4..0ca599f4ffe 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -69,10 +69,9 @@ const int kAlfredFrameHeight = 102;
const int kChoiceHeight = 16; // Height of each choice line in pixels
-const int kTalkAnimationSpeed = 2; // Frames per update
+const int kTalkAnimationSpeed = 2; // Frames per update
const int kAlfredAnimationSpeed = 2; // Frames per update
-
// Direction flags (bit-packed)
#define MOVE_RIGHT 0x01 // Move right (positive X)
#define MOVE_LEFT 0x02 // Move left (negative X)
@@ -118,7 +117,7 @@ struct AlfredState {
};
typedef struct {
- uint8_t flags; /* Direction flags (see MOVE_* constants) */
+ uint8_t flags; /* Direction flags (see MOVE_* constants) */
uint16_t distanceX; // Horizontal distance to move
uint16_t distanceY; // Vertical distance to move
} MovementStep;
@@ -129,7 +128,7 @@ typedef struct {
typedef struct {
uint8_t *pathBuffer; // Sequence of walkbox indices
MovementStep *movementBuffer; // Array of movement steps
- uint8_t *compressed_path; // Final compressed path
+ uint8_t *compressed_path; // Final compressed path
uint16_t pathLength;
uint16_t movementCount;
uint16_t compressed_length;
@@ -166,8 +165,8 @@ struct Exit {
struct Sprite {
int index; // number of the animation in the rooms
byte type;
- int16 x; // 0
- int16 y; // 2
+ int16 x; // 0
+ int16 y; // 2
int w; // 4
int h; // 5
byte extra; // 6
@@ -326,8 +325,9 @@ struct PaletteAnimFade {
byte curFrameCount = 0;
};
-struct Sticker
-{
+struct Sticker {
+ int roomNumber;
+ int stickerIndex;
uint16 x;
uint16 y;
byte w;
@@ -335,7 +335,6 @@ struct Sticker
byte *stickerData;
};
-
struct PaletteAnimRotate {
byte startIndex;
byte paletteMode;
Commit: 69fc6068593e8914c6eeb78625f8d4dc6927a310
https://github.com/scummvm/scummvm/commit/69fc6068593e8914c6eeb78625f8d4dc6927a310
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:29+02:00
Commit Message:
PELROCK: Opens/Closes door and enables exit
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 826b4cd3c2e..22e2834a108 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -511,7 +511,10 @@ void PelrockEngine::open(HotSpot *hotspot) {
case 261:
_room->addSticker(_res->getSticker(91));
break;
-
+ case 268:
+ _room->addSticker(_res->getSticker(93));
+ _room->_currentRoomExits[0].isEnabled = true;
+ break;
default:
break;
@@ -523,7 +526,10 @@ void PelrockEngine::close(HotSpot *hotspot) {
case 261:
_room->removeSticker(91);
break;
-
+ case 268:
+ _room->removeSticker(93);
+ _room->_currentRoomExits[0].isEnabled = false;
+ break;
default:
break;
@@ -977,7 +983,9 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
for (int i = 0; i < _room->_currentRoomExits.size(); i++) {
Exit exit = _room->_currentRoomExits[i];
if (x >= exit.x && x <= (exit.x + exit.w) &&
- y >= exit.y && y <= (exit.y + exit.h)) {
+ y >= exit.y && y <= (exit.y + exit.h)
+ // && exit.isEnabled
+ ) {
return &(_room->_currentRoomExits[i]);
}
}
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index f7cedd90832..6e3a8db6ba9 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -156,7 +156,7 @@ Common::Array<Exit> RoomManager::loadExits(Common::File *roomFile, int roomOffse
for (int i = 0; i < exit_count; i++) {
Exit exit;
exit.targetRoom = roomFile->readUint16LE();
- exit.flags = roomFile->readByte();
+ exit.isEnabled = roomFile->readByte();
exit.x = roomFile->readUint16LE();
exit.y = roomFile->readUint16LE();
exit.w = roomFile->readByte();
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 0ca599f4ffe..24179d1cabb 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -159,7 +159,7 @@ struct Exit {
int16 targetY;
uint16 targetDir;
AlfredDirection dir;
- byte flags;
+ byte isEnabled;
};
struct Sprite {
Commit: 1ea95983098c9f25b0cd1b6f0ab20d6158e42b58
https://github.com/scummvm/scummvm/commit/1ea95983098c9f25b0cd1b6f0ab20d6158e42b58
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:30+02:00
Commit Message:
PELROCK: Refactor popup state
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index da445446bc9..00893a9041a 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -31,8 +31,10 @@ DialogManager::DialogManager(Graphics::Screen *screen, PelrockEventManager *even
}
DialogManager::~DialogManager() {
- delete _currentChoices;
- _currentChoices = nullptr;
+ if( _currentChoices ) {
+ delete _currentChoices;
+ _currentChoices = nullptr;
+ }
}
uint32 DialogManager::readTextBlock(
@@ -274,10 +276,9 @@ int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *co
* @param outChoices Output: array of choice options
* @return The position after parsing choices
*/
-uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 startPos,
- Common::Array<ChoiceOption> &outChoices) {
+uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 startPos, Common::Array<ChoiceOption> *outChoices) {
uint32 pos = startPos;
- outChoices.clear();
+ outChoices->clear();
int firstChoiceIndex = -1;
int choiceCount = 0;
@@ -322,7 +323,7 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
textPos++;
}
- outChoices.push_back(opt);
+ outChoices->push_back(opt);
choiceCount = 1;
pos++;
break;
@@ -379,7 +380,7 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
textPos++;
}
- outChoices.push_back(opt);
+ outChoices->push_back(opt);
choiceCount++;
} else if (choiceIndex < firstChoiceIndex) {
// Different choice index - stop scanning
@@ -488,14 +489,14 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
// 4. Parse choices
- Common::Array<ChoiceOption> choices;
+ Common::Array<ChoiceOption> *choices = new Common::Array<ChoiceOption>();
parseChoices(conversationData, dataSize, position, choices);
- debug("Parsed %u choices", choices.size());
- for (uint i = 0; i < choices.size(); i++) {
- debug(" Choice %u (index %d): \"%s\" (Disabled: %s)", i, choices[i].index, choices[i].text.c_str(),
- choices[i].isDisabled ? "Yes" : "No");
+ debug("Parsed %u choices", choices->size());
+ for (uint i = 0; i < choices->size(); i++) {
+ debug(" Choice %u (index %d): \"%s\" (Disabled: %s)", i, (*choices)[i].index, (*choices)[i].text.c_str(),
+ (*choices)[i].isDisabled ? "Yes" : "No");
}
- if (choices.empty()) {
+ if (choices->empty()) {
// No choices, continue reading dialogue
position = peekPos;
continue;
@@ -505,8 +506,8 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
if (currentChoiceLevel >= 0) {
// We've already made a choice, check if the current choices are at the next level
bool foundNextLevel = false;
- for (uint i = 0; i < choices.size(); i++) {
- if (choices[i].index == currentChoiceLevel + 1) {
+ for (uint i = 0; i < choices->size(); i++) {
+ if ((*choices)[i].index == currentChoiceLevel + 1) {
foundNextLevel = true;
break;
}
@@ -522,29 +523,34 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
int selectedIndex = 0;
// Check if this is auto-dialogue (only one choice)
- if (choices.size() == 1) {
+ if (choices->size() == 1) {
// Auto-dialogue: display it automatically
- debug("Auto-selecting single choice: \"%s\"", choices[0].text.c_str());
+ debug("Auto-selecting single choice: \"%s\"", (*choices)[0].text.c_str());
selectedIndex = 0;
} else {
// Real choice: show menu and wait for selection
Common::Array<Common::String> choiceTexts;
- for (uint i = 0; i < choices.size(); i++) {
- if (choices[i].isDisabled) {
- choiceTexts.push_back("[DISABLED] " + choices[i].text);
+ for (uint i = 0; i < choices->size(); i++) {
+ if ((*choices)[i].isDisabled) {
+ choiceTexts.push_back("[DISABLED] " + (*choices)[i].text);
} else {
- choiceTexts.push_back(choices[i].text);
+ choiceTexts.push_back((*choices)[i].text);
}
}
- _currentChoices = &choices;
+
+ if(_currentChoices) {
+ delete _currentChoices;
+ _currentChoices = nullptr;
+ }
+ _currentChoices = choices;
// Use displayChoices to show and select
selectedIndex = selectChoice(choiceTexts, g_engine->_compositeBuffer);
}
// 6. Move position to after the selected choice
- if (selectedIndex >= 0 && selectedIndex < (int)choices.size()) {
- position = choices[selectedIndex].dataOffset;
- currentChoiceLevel = choices[selectedIndex].index;
+ if (selectedIndex >= 0 && selectedIndex < (int)choices->size()) {
+ position = (*choices)[selectedIndex].dataOffset;
+ currentChoiceLevel = (*choices)[selectedIndex].index;
// Read and display the selected choice as dialogue
Common::String choiceText;
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 68dddfe8941..55111b95f01 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -79,7 +79,7 @@ private:
void displayDialogue(Common::Array<Common::Array<Common::String>> dialogueLines, byte speakerId);
void displayDialogue(Common::String text, byte speakerId);
uint32 readTextBlock(const byte *data, uint32 dataSize, uint32 startPos, Common::String &outText, byte &outSpeakerId);
- uint32 parseChoices(const byte *data, uint32 dataSize, uint32 startPos, Common::Array<ChoiceOption> &outChoices);
+ uint32 parseChoices(const byte *data, uint32 dataSize, uint32 startPos, Common::Array<ChoiceOption> *outChoices);
void checkMouse();
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 22e2834a108..ca19c39b00e 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -298,7 +298,7 @@ void PelrockEngine::checkMouse() {
if (_events->_leftMouseClicked) {
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_leftMouseClicked = false;
- _displayPopup = false;
+ _actionPopupState.isActive = false;
} else if (_events->_longClicked) {
checkLongMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_longClicked = false;
@@ -337,12 +337,12 @@ void PelrockEngine::updateAnimations() {
}
}
- if (_displayPopup) {
- showActionBalloon(_popupX, _popupY, _currentPopupFrame);
- if (_currentPopupFrame < 3) {
- _currentPopupFrame++;
+ if (_actionPopupState.isActive) {
+ showActionBalloon(_actionPopupState.x, _actionPopupState.y, _actionPopupState.curFrame);
+ if (_actionPopupState.curFrame < 3) {
+ _actionPopupState.curFrame++;
} else
- _currentPopupFrame = 0;
+ _actionPopupState.curFrame = 0;
}
}
@@ -503,7 +503,7 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
void PelrockEngine::lookAt(HotSpot *hotspot) {
walkTo(_currentHotspot->x, _currentHotspot->y);
// sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index].text);
- _displayPopup = false;
+ _actionPopupState.isActive = false;
}
void PelrockEngine::open(HotSpot *hotspot) {
@@ -790,7 +790,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
int w = animData.w;
int h = animData.h;
if (sprite->isTalking) {
- drawTalkNPC(sprite);
+ animateTalkingNPC(sprite);
return;
}
@@ -829,19 +829,19 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
if (hotspotIndex != -1) {
- _popupX = alfredState.x - kBalloonWidth / 2;
- if (_popupX < 0)
- _popupX = 0;
- if (_popupX + kBalloonWidth > 640) {
- _popupX = 640 - kBalloonWidth;
+ _actionPopupState.x = alfredState.x - kBalloonWidth / 2;
+ if (_actionPopupState.x < 0)
+ _actionPopupState.x = 0;
+ if (_actionPopupState.x + kBalloonWidth > 640) {
+ _actionPopupState.x = 640 - kBalloonWidth;
}
- _popupY = alfredState.y - kAlfredFrameHeight - kBalloonHeight;
- if (_popupY < 0) {
- _popupY = 0;
+ _actionPopupState.y = alfredState.y - kAlfredFrameHeight - kBalloonHeight;
+ if (_actionPopupState.y < 0) {
+ _actionPopupState.y = 0;
}
- _displayPopup = true;
- _currentPopupFrame = 0;
+ _actionPopupState.isActive = true;
+ _actionPopupState.curFrame = 0;
_currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
}
}
@@ -1006,7 +1006,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
}
-void PelrockEngine::drawTalkNPC(Sprite *animSet) {
+void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
// Change with the right index
int index = animSet->index;
@@ -1121,8 +1121,8 @@ void PelrockEngine::walkTo(int x, int y) {
VerbIcon PelrockEngine::isActionUnder(int x, int y) {
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
for (int i = 0; i < actions.size(); i++) {
- int actionX = _popupX + 20 + (i * (kVerbIconWidth + 2));
- int actionY = _popupY + 20;
+ int actionX = _actionPopupState.x + 20 + (i * (kVerbIconWidth + 2));
+ int actionY = _actionPopupState.y + 20;
Common::Rect actionRect = Common::Rect(actionX, actionY, actionX + kVerbIconWidth, actionY + kVerbIconHeight);
if (actionRect.contains(x, y)) {
@@ -1150,17 +1150,17 @@ void PelrockEngine::checkMouseClick(int x, int y) {
if (whichNPCTalking)
whichNPCTalking = false;
- if (_displayPopup) {
+ if (_actionPopupState.isActive) {
// Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
VerbIcon actionClicked = isActionUnder(x, y);
if (actionClicked != NO_ACTION) {
- _displayPopup = false;
+ _actionPopupState.isActive = false;
doAction(actionClicked, _currentHotspot);
return;
}
}
- _displayPopup = false;
+ _actionPopupState.isActive = false;
_currentHotspot = nullptr;
Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 476809f6e49..8e2201d200d 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -109,7 +109,7 @@ private:
void drawAlfred(byte *buf);
void drawNextFrame(Sprite *animSet);
void changeCursor(Cursor cursor);
- void drawTalkNPC(Sprite *animSet);
+ void animateTalkingNPC(Sprite *animSet);
void playSoundIfNeeded();
void gameLoop();
@@ -142,10 +142,7 @@ private:
byte *_currentBackground = nullptr; // Clean background - NEVER modified
- bool _displayPopup = false;
- int _popupX = 0;
- int _popupY = 0;
- int _currentPopupFrame = 0;
+ ActionPopupState _actionPopupState;
HotSpot *_currentHotspot = nullptr;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 24179d1cabb..1e782187187 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -105,6 +105,14 @@ enum AlfredDirection {
ALFRED_UP = 3
};
+struct ActionPopupState {
+ bool isActive = false;
+ int curFrame = 0;
+ int x = 0;
+ int y = 0;
+ int displayTime = 0;
+};
+
struct AlfredState {
AlfredAnimState animState = ALFRED_IDLE;
AlfredAnimState nextState = ALFRED_IDLE;
Commit: 0d4a8eee0a0cf9ffd155049cc2ad652bae045704
https://github.com/scummvm/scummvm/commit/0d4a8eee0a0cf9ffd155049cc2ad652bae045704
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:30+02:00
Commit Message:
PELROCK: Loads extra screens
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 00893a9041a..8321f6a03e5 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -177,7 +177,9 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (speakerId == ALFRED_COLOR) {
g_engine->alfredState.animState = ALFRED_TALKING;
- _curSprite->isTalking = false;
+ if(_curSprite != nullptr) {
+ _curSprite->isTalking = false;
+ }
// Offset X position for Alfred to avoid overlapping with his sprite
xPos = g_engine->alfredState.x + kAlfredFrameWidth / 2 - maxWidth / 2;
yPos = g_engine->alfredState.y - kAlfredFrameHeight - height; // Above sprite, adjust for line
@@ -225,7 +227,9 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
}
g_system->delayMillis(10);
}
- _curSprite->isTalking = false;
+ if(_curSprite != nullptr) {
+ _curSprite->isTalking = false;
+ }
g_engine->alfredState.animState = ALFRED_IDLE;
}
@@ -578,6 +582,23 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// Note: The caller should set inConversation = false after this returns
}
+void DialogManager::sayAlfred(Common::String text) {
+ g_engine->alfredState.nextState = ALFRED_TALKING;
+ g_engine->alfredState.curFrame = 0;
+
+ Common::Array<Common::Array<Common::String>> textLines = wordWrap(text);
+
+ displayDialogue(textLines, ALFRED_COLOR);
+
+}
+
+void DialogManager::sayAlfred(Description description) {
+ sayAlfred(description.text);
+ if( description.isAction) {
+ g_engine->performActionTrigger(description.actionTrigger);
+ }
+}
+
bool isEndMarker(char char_byte) {
return char_byte == CHAR_END_MARKER_1 || char_byte == CHAR_END_MARKER_2 || char_byte == CHAR_END_MARKER_3 || char_byte == CHAR_END_MARKER_4;
}
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 55111b95f01..ffadb6ab073 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -90,6 +90,9 @@ public:
void displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer);
int selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer);
void startConversation(const byte *conversationData, uint32 dataSize, Sprite *alfredAnimSet = nullptr);
+ void sayAlfred(Common::String text);
+ void sayAlfred(Description description);
+
Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
Common::Array<ChoiceOption> *_currentChoices = nullptr;
};
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 6b939b13e28..fa80338d70f 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -236,5 +236,64 @@ const uint16_t description_offsets[NUM_DESCRIPTIONS] = {
0x23A4, // Object 112: Una caja de condone
};
+struct ExtraImages {
+ uint32 offset;
+ uint32 paletteOffset;
+ byte numChunks;
+};
+
+const ExtraImages extraScreens[] = {
+ {
+ 0x00, // Portrait above bed
+ 0x7984,
+ 8
+ },
+ {
+ 0x1A9EE, // Computer screen
+ 0x305A2,
+ 8
+ },
+ {
+ 0x647C3, // Alfred circle
+ 0x7B6B1,
+ 4
+ },
+ {
+ 0x6FBC9, // Recipe
+ 0x7B6B1,
+ 8
+ },
+ {
+ 0x7BA11, // Newspaper
+ 0x88745,
+ 8
+ },
+ {
+ 0x9237B, // tablet
+ 0xB0EE7,
+ 8
+ },
+ {
+ 0xB11ED, // map
+ 0xDE011,
+ 8
+ },
+ {
+ 0xFFC47, // girl book
+ 0x1180C9,
+ 8
+ },
+ {
+ 0x1183C5, // book
+ 0x1358F3,
+ 8
+ },
+ {
+ 0x152A88, // portrait
+ 0x15BFC8,
+ 8
+ },
+};
+
} // End of namespace Pelrock
#endif
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index ca19c39b00e..5cbfca2a5f9 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -294,6 +294,26 @@ void PelrockEngine::renderScene(bool showTextOverlay) {
}
}
+void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
+ debug("Performing action trigger: %d", actionTrigger);
+ switch (actionTrigger) {
+ case 257:
+ byte *palette = new byte[768];
+ if (_extraScreen == nullptr) {
+ _extraScreen = new byte[640 * 400];
+ }
+ _res->getExtraScreen(9, _extraScreen, palette);
+
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+ showExtraScreen();
+
+ _dialog->sayAlfred(_res->_alfredResponses[0][0]); // "I found something interesting!");
+
+ delete[] palette;
+ break;
+ }
+}
+
void PelrockEngine::checkMouse() {
if (_events->_leftMouseClicked) {
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
@@ -502,7 +522,7 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
void PelrockEngine::lookAt(HotSpot *hotspot) {
walkTo(_currentHotspot->x, _currentHotspot->y);
- // sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index].text);
+ _dialog->sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index]);
_actionPopupState.isActive = false;
}
@@ -1081,33 +1101,24 @@ void PelrockEngine::gameLoop() {
}
}
-// void PelrockEngine::menuLoop() {
-// _events->pollEvent();
-
-// if(_events->_leftMouseClicked) {
-// _events->_leftMouseClicked = false;
-// checkMouseClickOnSettings(_events->_mouseX, _events->_mouseY);
-// }
-// else if (_events->_rightMouseClicked) {
-// _events->_rightMouseClicked = false;
-// g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
-// stateGame = GAME;
-// }
-
-// memcpy(_compositeBuffer, _res->_mainMenu, 640 * 400);
+void PelrockEngine::showExtraScreen() {
+ memcpy(_screen->getPixels(), _extraScreen, 640 * 400);
+ _screen->markAllDirty();
+ _screen->update();
+ while (!shouldQuit()) {
+ _events->pollEvent();
-// for (int i = 0; i < 4; i++) {
-// int itemIndex = curInventoryPage * 4 + i;
-// InventoryObject item = _res->getInventoryObject(itemIndex);
-// drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
-// drawRect(_compositeBuffer, 140 + (82 * i) - 2, 115 - (8 * i) - 2, 64, 64, 255); // Draw border
-// }
+ if (_events->_leftMouseClicked) {
+ _events->_leftMouseClicked = false;
+ break;
+ }
+ g_system->delayMillis(10);
+ }
-// memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
-// _smallFont->drawString(_screen, _menuText, 230, 200, 200, 0);
-// _screen->markAllDirty();
-// _screen->update();
-// }
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+ free(_extraScreen);
+ _extraScreen = nullptr;
+}
void PelrockEngine::walkTo(int x, int y) {
_currentStep = 0;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 8e2201d200d..13668978b52 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -74,7 +74,6 @@ private:
void walkTo(int x, int y);
void talk(byte object);
- void sayAlfred(Common::String text);
void sayNPC(Sprite *anim, Common::String text, byte color);
byte *grabBackgroundSlice(int x, int y, int w, int h);
@@ -114,6 +113,7 @@ private:
void gameLoop();
void menuLoop();
+ void showExtraScreen();
void checkMouseHover();
void checkMouseClick(int x, int y);
@@ -141,7 +141,7 @@ private:
bool isAlkfredWalking = false;
byte *_currentBackground = nullptr; // Clean background - NEVER modified
-
+ byte *_extraScreen = nullptr;
ActionPopupState _actionPopupState;
HotSpot *_currentHotspot = nullptr;
@@ -182,6 +182,7 @@ public:
LargeFont *_largeFont = nullptr;
DoubleSmallFont *_doubleSmallFont = nullptr;
void renderScene(bool showTextOverlay = false);
+ void performActionTrigger(uint16 actionTrigger);
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 7262f3028fe..95123581d55 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -248,6 +248,23 @@ void ResourceManager::loadAlfredResponses() {
exe.close();
}
+void ResourceManager::getExtraScreen(int screenIndex, byte *screenBuf, byte *palette) {
+ Common::File alfred7;
+ if (!alfred7.open("ALFRED.7")) {
+ error("Couldnt find file ALFRED.7");
+ }
+ ExtraImages screen = extraScreens[screenIndex];
+ mergeRleBlocks(&alfred7, screen.offset, 8, screenBuf);
+ alfred7.seek(screen.paletteOffset, SEEK_SET);
+ alfred7.read(palette, 768);
+ for (int i = 0; i < 256; i++) {
+ palette[i * 3] = palette[i * 3] << 2;
+ palette[i * 3 + 1] = palette[i * 3 + 1] << 2;
+ palette[i * 3 + 2] = palette[i * 3 + 2] << 2;
+ }
+ alfred7.close();
+}
+
Common::Array<Common::StringArray> ResourceManager::getCredits() {
Common::File exe;
if (!exe.open("JUEGO.EXE")) {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 77535265e62..e026f15813f 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -46,6 +46,7 @@ public:
void loadAlfredAnims();
void loadInventoryItems();
void loadAlfredResponses();
+ void getExtraScreen(int screenIndex, byte *screenBuf, byte *palette);
Common::Array<Common::StringArray> getCredits();
Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size);
Sticker getSticker(int stickerIndex);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 6e3a8db6ba9..1dc41fdbe3a 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -428,6 +428,9 @@ Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, in
}
if (data[pos] == 0xF8) {
description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
+ if( description.actionTrigger != 0 ) {
+ description.isAction = true;
+ }
pos += 2;
break;
}
Commit: eb5618572cb745969e8ce81738468fc792d6d064
https://github.com/scummvm/scummvm/commit/eb5618572cb745969e8ce81738468fc792d6d064
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:30+02:00
Commit Message:
PELROCK: Queued actions
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 5cbfca2a5f9..f2c6dc3e25d 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -521,7 +521,6 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
}
void PelrockEngine::lookAt(HotSpot *hotspot) {
- walkTo(_currentHotspot->x, _currentHotspot->y);
_dialog->sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index]);
_actionPopupState.isActive = false;
}
@@ -608,6 +607,10 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_currentStep++;
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
+ if(_queuedAction.isQueued) {
+ doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
+ _queuedAction.isQueued = false;
+ }
alfredState.animState = ALFRED_IDLE;
}
} else {
@@ -1136,7 +1139,6 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
int actionY = _actionPopupState.y + 20;
Common::Rect actionRect = Common::Rect(actionX, actionY, actionX + kVerbIconWidth, actionY + kVerbIconHeight);
if (actionRect.contains(x, y)) {
-
return actions[i];
}
}
@@ -1158,19 +1160,21 @@ bool PelrockEngine::isAlfredUnder(int x, int y) {
void PelrockEngine::checkMouseClick(int x, int y) {
- if (whichNPCTalking)
- whichNPCTalking = false;
-
if (_actionPopupState.isActive) {
// Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
VerbIcon actionClicked = isActionUnder(x, y);
if (actionClicked != NO_ACTION) {
_actionPopupState.isActive = false;
- doAction(actionClicked, _currentHotspot);
- return;
+ if(_currentHotspot != nullptr) {
+ walkTo(_currentHotspot->x + _currentHotspot->w / 2, _currentHotspot->y + _currentHotspot->h);
+ _queuedAction = QueuedAction{actionClicked, _currentHotspot->index, true};
+ return;
+ }
}
}
+ _queuedAction = QueuedAction{NO_ACTION, -1, false};
+
_actionPopupState.isActive = false;
_currentHotspot = nullptr;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 13668978b52..8c0cc2def13 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -147,9 +147,7 @@ private:
HotSpot *_currentHotspot = nullptr;
Common::Point _curWalkTarget;
- bool isNPCATalking = false;
- uint16 whichNPCTalking = 0;
- bool isNPCBTalking = false;
+ QueuedAction _queuedAction;
bool showShadows = false;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 1e782187187..330a5696b69 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -287,6 +287,12 @@ struct WalkBox {
byte flags;
};
+struct QueuedAction {
+ VerbIcon verb;
+ int hotspotIndex;
+ bool isQueued;
+};
+
struct ScalingParams {
int16 yThreshold;
byte scaleDivisor;
Commit: 7728e3ea128699585f80485ce4d05f6e3b297dee
https://github.com/scummvm/scummvm/commit/7728e3ea128699585f80485ce4d05f6e3b297dee
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:30+02:00
Commit Message:
PELROCK: Improve exit calculation
Changed paths:
engines/pelrock/pathfinding.cpp
engines/pelrock/pathfinding.h
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
index 32254c551d3..bc78b4c68ea 100644
--- a/engines/pelrock/pathfinding.cpp
+++ b/engines/pelrock/pathfinding.cpp
@@ -22,6 +22,7 @@
#include "common/scummsys.h"
#include "pelrock/pathfinding.h"
+#include "pelrock/types.h"
#include "pelrock/util.h"
namespace Pelrock {
@@ -60,7 +61,7 @@ bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<
int startX = sourceX;
int startY = sourceY;
- Common::Point target = calculateWalkTarget(walkboxes, targetX, targetY);
+ Common::Point target = calculateWalkTarget(walkboxes, targetX, targetY, false, nullptr);
targetX = target.x;
targetY = target.y;
debug("Startx= %d, starty= %d, destx= %d, desty= %d", startX, startY, targetX, targetY);
@@ -118,67 +119,97 @@ bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<
return true;
}
-Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes, int x, int y) {
- // Starting point for pathfinding
- int sourceX = x;
- int sourceY = y;
+Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes,
+ int sourceX, int sourceY,
+ bool mouseHoverState,
+ HotSpot *hotspot) {
+
+ // // Step 1: Determine actual source point
+ // if (mouseHoverState == 1) {
+ // // Hovering over sprite - check if it has action flags or is animated
+ // Sprite *sprite = getSprite(hotspotSpriteIndex);
+ // if (sprite->actionFlags != 0 || sprite->frameCount != 1) {
+ // sourceX = sprite->x + sprite->width / 2;
+ // sourceY = sprite->y + sprite->height;
+ // }
+ // }
+ // else if (mouseHoverState == 2) {
+ // // Hovering over hotspot - use hotspot center-bottom
+ // Hotspot *hotspot = getHotspot(hotspotSpriteIndex);
+ // sourceX = hotspot->x + hotspot->width / 2;
+ // sourceY = hotspot->y + hotspot->height;
+ // }
+
+ if (mouseHoverState == 1) {
+ // Hovering over hotspot - use hotspot center-bottom
+ sourceX = hotspot->x + hotspot->w / 2;
+ sourceY = hotspot->y + hotspot->h;
+ }
- // TODO: If hovering over a sprite/hotspot, adjust source point to sprite center
- // For now, just use mouse position
+ // else: use sourceX, sourceY as passed (mouse position)
- // Find nearest walkable point in walkboxes
- uint32 minDistance = 0xFFFFFFFF;
- Common::Point bestTarget(sourceX, sourceY);
+ // Step 2: Find nearest walkbox
+ uint32 minDistance = 0xFFFF;
+ int bestXDistance = 0;
+ int bestYDistance = 0;
+ int bestXDirection = 0; // 0 = left/subtract, 1 = right/add
+ int bestYDirection = 0; // 0 = up/subtract, 1 = down/add
for (size_t i = 0; i < walkboxes.size(); i++) {
+ int xDistance = 0;
+ int xDirection = 0;
+ int yDistance = 0;
+ int yDirection = 0;
- // Calculate distance from source point to this walkbox (Manhattan distance)
- int dx = 0;
- int dy = 0;
-
- // Calculate horizontal distance
+ // Calculate X distance with direction
if (sourceX < walkboxes[i].x) {
- dx = walkboxes[i].x - sourceX;
+ xDistance = walkboxes[i].x - sourceX;
+ xDirection = 1; // RIGHT
} else if (sourceX > walkboxes[i].x + walkboxes[i].w) {
- dx = sourceX - (walkboxes[i].x + walkboxes[i].w);
+ // KEY: subtract 1 from right edge
+ xDistance = sourceX - (walkboxes[i].x + walkboxes[i].w - 1);
+ xDirection = 0; // LEFT
}
- // else: sourceX is inside walkbox horizontally, dx = 0
+ // else: sourceX is inside, xDistance = 0
- // Calculate vertical distance
+ // Calculate Y distance with direction
if (sourceY < walkboxes[i].y) {
- dy = walkboxes[i].y - sourceY;
+ yDistance = walkboxes[i].y - sourceY;
+ yDirection = 1; // DOWN
} else if (sourceY > walkboxes[i].y + walkboxes[i].h) {
- dy = sourceY - (walkboxes[i].y + walkboxes[i].h);
+ // KEY: subtract 1 from bottom edge
+ yDistance = sourceY - (walkboxes[i].y + walkboxes[i].h - 1);
+ yDirection = 0; // UP
}
- // else: sourceY is inside walkbox vertically, dy = 0
-
- uint32 distance = dx + dy;
+ // else: sourceY is inside, yDistance = 0
- if (distance < minDistance) {
- minDistance = distance;
+ uint32 totalDistance = xDistance + yDistance;
- // Calculate target point (nearest point on walkbox to source)
- int targetX = sourceX;
- int targetY = sourceY;
+ if (totalDistance < minDistance) {
+ minDistance = totalDistance;
+ bestXDistance = xDistance;
+ bestYDistance = yDistance;
+ bestXDirection = xDirection;
+ bestYDirection = yDirection;
+ }
+ }
- if (sourceX < walkboxes[i].x) {
- targetX = walkboxes[i].x;
- } else if (sourceX > walkboxes[i].x + walkboxes[i].w) {
- targetX = walkboxes[i].x + walkboxes[i].w;
- }
+ // Step 3: Calculate final target point
+ Common::Point target;
- if (sourceY < walkboxes[i].y) {
- targetY = walkboxes[i].y;
- } else if (sourceY > walkboxes[i].y + walkboxes[i].h) {
- targetY = walkboxes[i].y + walkboxes[i].h;
- }
+ if (bestXDirection == 1) {
+ target.x = sourceX + bestXDistance;
+ } else {
+ target.x = sourceX - bestXDistance;
+ }
- bestTarget.x = targetX;
- bestTarget.y = targetY;
- }
+ if (bestYDirection == 1) {
+ target.y = sourceY + bestYDistance;
+ } else {
+ target.y = sourceY - bestYDistance;
}
- return bestTarget;
+ return target;
}
uint8_t findWalkboxForPoint(Common::Array<WalkBox> &walkboxes, uint16_t x, uint16_t y) {
diff --git a/engines/pelrock/pathfinding.h b/engines/pelrock/pathfinding.h
index cb33de23d29..8f02b0e814b 100644
--- a/engines/pelrock/pathfinding.h
+++ b/engines/pelrock/pathfinding.h
@@ -29,7 +29,7 @@
namespace Pelrock {
bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<WalkBox> &walkboxes, PathContext *context);
-Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes, int x, int y);
+Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes, int sourceX, int sourceY, bool mouseHoverState, HotSpot *hotspot);
uint8_t findWalkboxForPoint(Common::Array<WalkBox> &walkboxes, uint16_t x, uint16_t y);
uint8_t getAdjacentWalkbox(Common::Array<WalkBox> &walkboxes, uint8_t current_box_index);
uint16_t buildWalkboxPath(Common::Array<WalkBox> &walkboxes, uint8_t start_box, uint8_t dest_box, uint8_t *path_buffer);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f2c6dc3e25d..90510cc501e 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -607,7 +607,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_currentStep++;
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
- if(_queuedAction.isQueued) {
+ if (_queuedAction.isQueued) {
doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
_queuedAction.isQueued = false;
}
@@ -1165,7 +1165,7 @@ void PelrockEngine::checkMouseClick(int x, int y) {
VerbIcon actionClicked = isActionUnder(x, y);
if (actionClicked != NO_ACTION) {
_actionPopupState.isActive = false;
- if(_currentHotspot != nullptr) {
+ if (_currentHotspot != nullptr) {
walkTo(_currentHotspot->x + _currentHotspot->w / 2, _currentHotspot->y + _currentHotspot->h);
_queuedAction = QueuedAction{actionClicked, _currentHotspot->index, true};
return;
@@ -1178,21 +1178,34 @@ void PelrockEngine::checkMouseClick(int x, int y) {
_actionPopupState.isActive = false;
_currentHotspot = nullptr;
- Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY);
+ int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
+ bool isHotspotUnder = false;
+ if(hotspotIndex != -1) {
+ isHotspotUnder = true;
+ }
+
+ Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, isHotspotUnder, isHotspotUnder ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
_curWalkTarget = walkTarget;
- { // For quick room navigation
- Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
+ // if (hotspotIndex != -1) {
+ // _currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
+ // walkTarget.x = _currentHotspot->x + _currentHotspot->w / 2;
+ // walkTarget.y = _currentHotspot->y + _currentHotspot->h;
+ // }
- if (exit != nullptr) {
- alfredState.x = exit->targetX;
- alfredState.y = exit->targetY;
+ walkTo(walkTarget.x, walkTarget.y);
- setScreen(exit->targetRoom, exit->dir);
- } else {
- walkTo(walkTarget.x, walkTarget.y);
- }
- }
+ // { // For quick room navigation
+ // Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
+
+ // if (exit != nullptr) {
+ // alfredState.x = exit->targetX;
+ // alfredState.y = exit->targetY;
+
+ // setScreen(exit->targetRoom, exit->dir);
+ // } else {
+ // }
+ // }
}
void PelrockEngine::changeCursor(Cursor cursor) {
@@ -1202,16 +1215,6 @@ void PelrockEngine::changeCursor(Cursor cursor) {
void PelrockEngine::checkMouseHover() {
bool hotspotDetected = false;
- // Calculate walk target first (before checking anything else)
- Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY);
-
- // Check if walk target hits any exit
- bool exitDetected = false;
- Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
- if (exit != nullptr) {
- exitDetected = true;
- }
-
int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
if (hotspotIndex != -1) {
hotspotDetected = true;
@@ -1225,6 +1228,15 @@ void PelrockEngine::checkMouseHover() {
if (isAlfredUnder(_events->_mouseX, _events->_mouseY)) {
alfredDetected = true;
}
+ // Calculate walk target first (before checking anything else)
+ Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, hotspotDetected, hotspotDetected ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
+
+ // Check if walk target hits any exit
+ bool exitDetected = false;
+ Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
+ if (exit != nullptr) {
+ exitDetected = true;
+ }
if (alfredDetected) {
changeCursor(ALFRED);
@@ -1239,138 +1251,6 @@ void PelrockEngine::checkMouseHover() {
}
}
-// void PelrockEngine::sayNPC(Sprite *anim, Common::String text, byte color) {
-// isNPCATalking = true;
-// whichNPCTalking = anim->extra;
-// _currentTextPages = wordWrap(text);
-// _textColor = color;
-// int totalChars = 0;
-// for (int i = 0; i < _currentTextPages[0].size(); i++) {
-// totalChars += _currentTextPages[0][i].size();
-// }
-// _textPos = Common::Point(anim->x, anim->y - 10);
-// _textDurationFrames = totalChars / 2;
-// }
-
-// void PelrockEngine::sayAlfred(Common::String text) {
-// alfredState.nextState = ALFRED_TALKING;
-// alfredState.curFrame = 0;
-// _currentTextPages = wordWrap(text);
-// _textColor = 13;
-// int totalChars = 0;
-// for (int i = 0; i < _currentTextPages[0].size(); i++) {
-// totalChars += _currentTextPages[0][i].size();
-// }
-// _textDurationFrames = totalChars / 2;
-// }
-
-// int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
-// // return word_length, is_end
-// int wordLength = 0;
-// int pos = startPos;
-// while (pos < text.size()) {
-// char char_byte = text[pos];
-// if (char_byte == CHAR_SPACE || isEndMarker(char_byte)) {
-// break;
-// }
-// wordLength++;
-// pos++;
-// }
-// // Check if we hit an end marker
-// if (pos < text.size() && isEndMarker(text[pos])) {
-// isEnd = true;
-// }
-// // Count ALL trailing spaces as part of this word
-// if (pos < text.size() && !isEnd) {
-// if (text[pos] == CHAR_END_MARKER_3) { // 0xF8 (-8) special case
-// wordLength += 3;
-// } else {
-// // Count all consecutive spaces
-// while (pos < text.size() && text[pos] == CHAR_SPACE) {
-// wordLength++;
-// pos++;
-// }
-// }
-// }
-// return wordLength;
-// }
-
-// Common::Array<Common::Array<Common::String>> wordWrap(Common::String text) {
-
-// Common::Array<Common::Array<Common::String>> pages;
-// Common::Array<Common::String> currentPage;
-// Common::Array<Common::String> currentLine;
-// int charsRemaining = MAX_CHARS_PER_LINE;
-// int position = 0;
-// int currentLineNum = 0;
-// while (position < text.size()) {
-// bool isEnd = false;
-// int wordLength = calculateWordLength(text, position, isEnd);
-// // # Extract the word (including trailing spaces)
-// // word = text[position:position + word_length].decode('latin-1', errors='replace')
-// Common::String word = text.substr(position, wordLength).decode(Common::kLatin1);
-// // # Key decision: if word_length > chars_remaining, wrap to next line
-// if (wordLength > charsRemaining) {
-// // Word is longer than the entire line - need to split
-// currentPage.push_back(joinStrings(currentLine, ""));
-// currentLine.clear();
-// charsRemaining = MAX_CHARS_PER_LINE;
-// currentLineNum++;
-
-// if (currentLineNum >= MAX_LINES) {
-// pages.push_back(currentPage);
-// currentPage.clear();
-// currentLineNum = 0;
-// }
-// }
-// // Add word to current line
-// currentLine.push_back(word);
-// charsRemaining -= wordLength;
-
-// if (charsRemaining == 0 && isEnd) {
-// Common::String lineText = joinStrings(currentLine, "");
-// while (lineText.lastChar() == CHAR_SPACE) {
-// lineText = lineText.substr(0, lineText.size() - 1);
-// }
-// int trailingSpaces = currentLine.size() - lineText.size();
-// if (trailingSpaces > 0) {
-// currentPage.push_back(lineText);
-// // current_line = [' ' * trailing_spaces]
-// Common::String currentLine(trailingSpaces, ' ');
-// charsRemaining = MAX_CHARS_PER_LINE - trailingSpaces;
-// currentLineNum += 1;
-
-// if (currentLineNum >= MAX_LINES) {
-// pages.push_back(currentPage);
-// currentPage.clear();
-// currentLineNum = 0;
-// }
-// }
-// }
-
-// position += wordLength;
-// if (isEnd) {
-// // End of sentence/paragraph/page
-// break;
-// }
-// }
-// if (currentLine.empty() == false) {
-// Common::String lineText = joinStrings(currentLine, "");
-// while (lineText.lastChar() == CHAR_SPACE) {
-// lineText = lineText.substr(0, lineText.size() - 1);
-// }
-// currentPage.push_back(lineText);
-// }
-// if (currentPage.empty() == false) {
-// pages.push_back(currentPage);
-// }
-// for (int i = 0; i < pages.size(); i++) {
-// for (int j = 0; j < pages[i].size(); j++) {
-// }
-// }
-// return pages;
-// }
-
void PelrockEngine::setScreen(int number, AlfredDirection dir) {
_sound->stopAllSounds();
Common::File roomFile;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 1dc41fdbe3a..9f85bdc1906 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -386,7 +386,7 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(Common::File *roomFile, int ro
int16 w = roomFile->readSint16LE();
int16 h = roomFile->readSint16LE();
byte flags = roomFile->readByte();
- // debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+ debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
WalkBox box;
box.x = x1;
box.y = y1;
Commit: ed2e14da575a2d2c208b221fb019080b657f39a1
https://github.com/scummvm/scummvm/commit/ed2e14da575a2d2c208b221fb019080b657f39a1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:31+02:00
Commit Message:
PELROCK: Simple inventory management
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 497f7db4a92..6384c358000 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -67,7 +67,7 @@ void MenuManager::checkMouseClick(int x, int y) {
for (int i = 0; i < 4; i++) {
if (x >= 140 + (82 * i) && x <= 140 + (82 * i) + 64 &&
y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
- _selectedInvIndex = _curInventoryPage * 4 + i;
+ _selectedInvIndex = g_engine->_inventoryItems[_curInventoryPage * 4 + i];
_menuText = _inventoryDescriptions[_selectedInvIndex];
selectedItem = true;
return;
@@ -101,9 +101,12 @@ void MenuManager::menuLoop() {
memcpy(_compositeBuffer, _mainMenu, 640 * 400);
+
for (int i = 0; i < 4; i++) {
int itemIndex = _curInventoryPage * 4 + i;
- InventoryObject item = _res->getInventoryObject(itemIndex);
+ if(g_engine->_inventoryItems.size() <= itemIndex)
+ continue;
+ InventoryObject item = g_engine->_res->getInventoryObject(g_engine->_inventoryItems[itemIndex]);
drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 90510cc501e..2dcbaf73857 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -503,6 +503,9 @@ void PelrockEngine::doAction(byte action, HotSpot *hotspot) {
case CLOSE:
close(hotspot);
break;
+ case PICKUP:
+ pick(hotspot);
+ break;
default:
break;
}
@@ -529,6 +532,7 @@ void PelrockEngine::open(HotSpot *hotspot) {
switch (hotspot->extra) {
case 261:
_room->addSticker(_res->getSticker(91));
+ _room->_currentRoomHotspots[hotspot->index].isEnabled = false;
break;
case 268:
_room->addSticker(_res->getSticker(93));
@@ -555,6 +559,25 @@ void PelrockEngine::close(HotSpot *hotspot) {
}
}
+void PelrockEngine::pick(HotSpot *hotspot) {
+ _inventoryItems.push_back(hotspot->extra);
+ switch (hotspot->extra)
+ {
+ case 0:
+ case 1:
+ case 2:
+ _room->_currentRoomHotspots[hotspot->index].isEnabled = false;
+ break;
+ case 4:
+ _room->addSticker(_res->getSticker(95));
+ /* code */
+ break;
+
+ default:
+ break;
+ }
+}
+
void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, int baseX, int baseY) {
int maxW = 0;
@@ -1158,6 +1181,7 @@ bool PelrockEngine::isAlfredUnder(int x, int y) {
return true;
}
+
void PelrockEngine::checkMouseClick(int x, int y) {
if (_actionPopupState.isActive) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 8c0cc2def13..b9a47c1beef 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -103,6 +103,7 @@ private:
void lookAt(HotSpot *hotspot);
void open(HotSpot *hotspot);
void close(HotSpot *hotspot);
+ void pick(HotSpot *hotspot);
void renderText(Common::Array<Common::String> lines, int color, int x, int y);
void chooseAlfredStateAndDraw();
void drawAlfred(byte *buf);
@@ -179,8 +180,10 @@ public:
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
DoubleSmallFont *_doubleSmallFont = nullptr;
- void renderScene(bool showTextOverlay = false);
- void performActionTrigger(uint16 actionTrigger);
+
+ Common::Array<int> _inventoryItems;
+ int _selectedInventoryItem = -1;
+
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
@@ -229,6 +232,8 @@ public:
}
void setScreen(int s, AlfredDirection dir);
+ void renderScene(bool showTextOverlay = false);
+ void performActionTrigger(uint16 actionTrigger);
};
extern PelrockEngine *g_engine;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 9f85bdc1906..3fd7bf5faf3 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -424,7 +424,7 @@ Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, in
if (data[pos] != 0x00) {
// debug("Adding char 0x%02X to description, decoded as %lc", data[pos], decodeChar((byte)data[pos]));
- description.text.append(1, decodeChar((byte)data[pos]));
+ description.text.append(1, (char)data[pos]);
}
if (data[pos] == 0xF8) {
description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
@@ -449,11 +449,7 @@ Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, in
}
_conversationData = new byte[_conversationDataSize];
Common::copy(data + conversationStart, data + conversationStart + _conversationDataSize, _conversationData);
-
delete[] data;
- // for (Common::List<Common::String>::iterator i = descriptions.begin(); i != descriptions.end(); i++) {
- // debug("Room description: %s", i->c_str());
- // }
return descriptions;
}
Commit: b533f0ac91b90db89b9e97a352bf56f48f39c55c
https://github.com/scummvm/scummvm/commit/b533f0ac91b90db89b9e97a352bf56f48f39c55c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:31+02:00
Commit Message:
PELROCK: Remove debug artifacts
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 8321f6a03e5..cf52a246d5e 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -171,7 +171,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
Graphics::Surface s;
s.create(maxWidth, height, Graphics::PixelFormat::createFormatCLUT8());
s.fillRect(s.getRect(), 255); // Clear surface
- s.drawRoundRect(Common::Rect(0, 0, s.getRect().width(), s.getRect().height()), 2, 13, false);
+ // s.drawRoundRect(Common::Rect(0, 0, s.getRect().width(), s.getRect().height()), 2, 13, false);
int xPos = 0;
int yPos = 0;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 2dcbaf73857..7495aa9c7d7 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -368,7 +368,7 @@ void PelrockEngine::updateAnimations() {
void PelrockEngine::presentFrame() {
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- paintDebugLayer();
+ // paintDebugLayer();
_screen->markAllDirty();
}
Commit: 558c76b6d58b5ff5bfbba6f578fb39583e2c21a9
https://github.com/scummvm/scummvm/commit/558c76b6d58b5ff5bfbba6f578fb39583e2c21a9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:31+02:00
Commit Message:
PELROCK: Idle animation
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 7495aa9c7d7..774796d04df 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -317,13 +317,15 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
void PelrockEngine::checkMouse() {
if (_events->_leftMouseClicked) {
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
+ alfredState.idleFrameCounter = 0;
_events->_leftMouseClicked = false;
_actionPopupState.isActive = false;
} else if (_events->_longClicked) {
+ alfredState.idleFrameCounter = 0;
checkLongMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_longClicked = false;
} else if (_events->_rightMouseClicked) {
-
+ alfredState.idleFrameCounter = 0;
g_system->getPaletteManager()->setPalette(_menu->_mainMenuPalette, 0, 256);
_events->_rightMouseClicked = false;
stateGame = SETTINGS;
@@ -596,6 +598,14 @@ void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, i
}
void PelrockEngine::chooseAlfredStateAndDraw() {
+ if(alfredState.idleFrameCounter++ >= kAlfredIdleAnimationFrameCount &&
+ alfredState.animState == ALFRED_IDLE &&
+ (alfredState.direction == ALFRED_LEFT || alfredState.direction == ALFRED_RIGHT)
+ ) {
+ alfredState.idleFrameCounter = 0;
+ alfredState.curFrame = 0;
+ alfredState.animState = ALFRED_COMB;
+ }
switch (alfredState.animState) {
case ALFRED_WALKING: {
MovementStep step = _currentContext.movementBuffer[_currentStep];
@@ -667,9 +677,12 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
break;
case ALFRED_COMB:
if (alfredState.curFrame >= 11) {
+ alfredState.animState = ALFRED_IDLE;
alfredState.curFrame = 0;
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredIdle[alfredState.direction], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
+ break;
}
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[0][alfredState.curFrame], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[alfredState.direction][alfredState.curFrame], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
alfredState.curFrame++;
break;
case ALFRED_INTERACTING:
@@ -1090,31 +1103,6 @@ void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
void PelrockEngine::gameLoop() {
_events->pollEvent();
- // while (g_system->getEventManager()->pollEvent(e)) {
- // if (e.type == Common::EVENT_KEYDOWN) {
- // switch (e.kbd.keycode) {
- // case Common::KEYCODE_w:
- // alfredState.animState = ALFRED_WALKING;
- // break;
- // case Common::KEYCODE_t:
- // alfredState.animState = ALFRED_TALKING;
- // break;
- // case Common::KEYCODE_s:
- // alfredState.animState = ALFRED_IDLE;
- // break;
- // case Common::KEYCODE_c:
- // alfredState.animState = ALFRED_COMB;
- // break;
- // case Common::KEYCODE_i:
- // alfredState.animState = ALFRED_INTERACTING;
- // break;
- // case Common::KEYCODE_z:
- // showShadows = !showShadows;
- // break;
- // default:
- // break;
- // }
- // }
if (inConversation) {
// TODO: Pass actual conversation data from room
@@ -1276,37 +1264,34 @@ void PelrockEngine::checkMouseHover() {
}
void PelrockEngine::setScreen(int number, AlfredDirection dir) {
- _sound->stopAllSounds();
+
Common::File roomFile;
if (!roomFile.open(Common::Path("ALFRED.1"))) {
error("Could not open ALFRED.1");
return;
}
+ _sound->stopAllSounds();
alfredState.direction = dir;
alfredState.animState = ALFRED_IDLE;
_currentStep = 0;
int roomOffset = number * kRoomStructSize;
alfredState.curFrame = 0;
+
byte *palette = new byte[256 * 3];
_room->getPalette(&roomFile, roomOffset, palette);
- int paletteOffset = roomOffset + (11 * 8);
- roomFile.seek(paletteOffset, SEEK_SET);
- uint32 offset = roomFile.readUint32LE();
-
- g_system->getPaletteManager()->setPalette(palette, 0, 256);
byte *background = new byte[640 * 400];
_room->getBackground(&roomFile, roomOffset, background);
- if (_currentBackground != nullptr)
- delete[] _currentBackground;
- _currentBackground = new byte[640 * 400];
+
+ _screen->clear();
+ _screen->markAllDirty();
+ _screen->update();
+
+
Common::copy(background, background + 640 * 400, _currentBackground);
- for (int i = 0; i < 640; i++) {
- for (int j = 0; j < 400; j++) {
- _screen->setPixel(i, j, background[j * 640 + i]);
- }
- }
+ copyBackgroundToBuffer();
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
_room->loadRoomMetadata(&roomFile, number);
_room->loadRoomTalkingAnimations(number);
@@ -1319,6 +1304,7 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
_room->_currentRoomNumber = number;
_screen->markAllDirty();
+ _screen->update();
roomFile.close();
delete[] background;
delete[] palette;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 330a5696b69..0a738eaa141 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -71,6 +71,7 @@ const int kChoiceHeight = 16; // Height of each choice line in pixels
const int kTalkAnimationSpeed = 2; // Frames per update
const int kAlfredAnimationSpeed = 2; // Frames per update
+const int kAlfredIdleAnimationFrameCount = 300;
// Direction flags (bit-packed)
#define MOVE_RIGHT 0x01 // Move right (positive X)
@@ -122,6 +123,7 @@ struct AlfredState {
uint16 x = 319;
uint16 y = 302;
float currentScale = 1.0f;
+ int idleFrameCounter = 0;
};
typedef struct {
Commit: cf4d609cdaea99fd4289ef2639f230938887fed0
https://github.com/scummvm/scummvm/commit/cf4d609cdaea99fd4289ef2639f230938887fed0
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:32+02:00
Commit Message:
PELROCK: Fixes text processing
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/resources.cpp
engines/pelrock/resources.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 6384c358000..8398d028e70 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -203,14 +203,14 @@ void MenuManager::loadMenuTexts() {
byte *descBuffer = new byte[kInventoryDescriptionsSize];
exe.seek(kInventoryDescriptionsOffset, SEEK_SET);
exe.read(descBuffer, kInventoryDescriptionsSize);
- _inventoryDescriptions = _res->processTextData(descBuffer, kInventoryDescriptionsSize);
+ _inventoryDescriptions = _res->processTextData(descBuffer, kInventoryDescriptionsSize, true);
delete[] descBuffer;
Common::String desc = "";
byte *textBuffer = new byte[kMenuTextSize];
exe.seek(kMenuTextOffset, SEEK_SET);
exe.read(textBuffer, kMenuTextSize);
- _menuTexts = _res->processTextData(textBuffer, kMenuTextSize);
+ _menuTexts = _res->processTextData(textBuffer, kMenuTextSize, true);
_menuText = _menuTexts[0];
delete[] textBuffer;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 95123581d55..98757d03414 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -279,7 +279,7 @@ Common::Array<Common::StringArray> ResourceManager::getCredits() {
return credits;
}
-Common::Array<Common::Array<Common::String>> ResourceManager::processTextData(byte *data, size_t size) {
+Common::Array<Common::Array<Common::String>> ResourceManager::processTextData(byte *data, size_t size, bool decode) {
int pos = 0;
Common::String desc = "";
Common::StringArray lines;
@@ -313,8 +313,10 @@ Common::Array<Common::Array<Common::String>> ResourceManager::processTextData(by
pos++;
continue;
}
-
- desc.append(1, decodeChar(data[pos]));
+ if( decode )
+ desc.append(1, decodeChar(data[pos]));
+ else
+ desc.append(1, data[pos]);
if (pos + 1 == size) {
lines.push_back(desc);
texts.push_back(lines);
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index e026f15813f..042c9bf82a4 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -48,7 +48,7 @@ public:
void loadAlfredResponses();
void getExtraScreen(int screenIndex, byte *screenBuf, byte *palette);
Common::Array<Common::StringArray> getCredits();
- Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size);
+ Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size, bool decode = false);
Sticker getSticker(int stickerIndex);
InventoryObject getInventoryObject(byte index);
byte *loadExtra();
Commit: 441230ed99a0b499471325b05aea1d8b94206328
https://github.com/scummvm/scummvm/commit/441230ed99a0b499471325b05aea1d8b94206328
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:32+02:00
Commit Message:
PELROCK: Action Handler
Changed paths:
A engines/pelrock/actions.cpp
A engines/pelrock/actions.h
engines/pelrock/dialog.cpp
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
new file mode 100644
index 00000000000..b5efbf0709a
--- /dev/null
+++ b/engines/pelrock/actions.cpp
@@ -0,0 +1,82 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "pelrock/actions.h"
+#include "pelrock/pelrock.h"
+
+namespace Pelrock {
+
+const ActionEntry actionTable[] = {
+ // Room 0
+ { 261, OPEN, &PelrockEngine::openDrawer },
+ { 261, CLOSE, &PelrockEngine::closeDrawer },
+ { 268, OPEN, &PelrockEngine::openDoor },
+ { 268, CLOSE, &PelrockEngine::closeDoor },
+ { 3, PICKUP, &PelrockEngine::pickUpPhoto },
+
+ // Generic handlers
+ { WILDCARD, PICKUP, &PelrockEngine::noOp }, // Generic pickup action
+ { WILDCARD, TALK, &PelrockEngine::noOp }, // Generic talk action
+ { WILDCARD, WALK, &PelrockEngine::noOp }, // Generic walk action
+ { WILDCARD, LOOK, &PelrockEngine::noOp }, // Generic look action
+ { WILDCARD, PUSH, &PelrockEngine::noOp }, // Generic push action
+ { WILDCARD, PULL, &PelrockEngine::noOp }, // Generic pull action
+ { WILDCARD, OPEN, &PelrockEngine::noOp }, // Generic open action
+ { WILDCARD, CLOSE, &PelrockEngine::noOp }, // Generic close action
+
+ // End marker
+ { WILDCARD, NO_ACTION, nullptr }
+};
+
+// Handler implementations
+void PelrockEngine::openDrawer(HotSpot *hotspot) {
+ _room->addSticker(_res->getSticker(91));
+ hotspot->isEnabled = false;
+}
+
+void PelrockEngine::closeDrawer(HotSpot *hotspot) {
+ _room->removeSticker(91);
+ hotspot->isEnabled = true;
+}
+
+void PelrockEngine::openDoor(HotSpot *hotspot) {
+ _room->addSticker(_res->getSticker(93));
+ _room->_currentRoomExits[0].isEnabled = true;
+}
+
+void PelrockEngine::closeDoor(HotSpot *hotspot) {
+ _room->removeSticker(93);
+ _room->_currentRoomExits[0].isEnabled = false;
+}
+
+void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
+ _inventoryItems.push_back(hotspot->extra);
+ hotspot->isEnabled = false;
+}
+
+void PelrockEngine::pickUpPhoto(HotSpot *hotspot) {
+ _room->findHotspotByExtra(261)->isEnabled = true;
+}
+void PelrockEngine::noOp(HotSpot *hotspot) {
+ // Do nothing
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/actions.h b/engines/pelrock/actions.h
new file mode 100644
index 00000000000..73305bc21de
--- /dev/null
+++ b/engines/pelrock/actions.h
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_ACTIONS_H
+#define PELROCK_ACTIONS_H
+
+#include "pelrock/types.h"
+#include "pelrock/pelrock.h"
+
+namespace Pelrock {
+
+const int WILDCARD = -1;
+
+struct ActionEntry {
+ int hotspotExtra;
+ VerbIcon action;
+ void (PelrockEngine::*handler)(HotSpot *);
+};
+
+// Action table for all rooms
+extern const ActionEntry actionTable[];
+
+} // End of namespace Pelrock
+#endif // PELROCK_ACTIONS_H
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index cf52a246d5e..0c9e688f39e 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -586,10 +586,9 @@ void DialogManager::sayAlfred(Common::String text) {
g_engine->alfredState.nextState = ALFRED_TALKING;
g_engine->alfredState.curFrame = 0;
+ _curSprite = nullptr;
Common::Array<Common::Array<Common::String>> textLines = wordWrap(text);
-
displayDialogue(textLines, ALFRED_COLOR);
-
}
void DialogManager::sayAlfred(Description description) {
@@ -604,7 +603,6 @@ bool isEndMarker(char char_byte) {
}
int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
- // return word_length, is_end
int wordLength = 0;
int pos = startPos;
while (pos < text.size()) {
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index 0fd85abbf06..c577cd7abe3 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -2,6 +2,7 @@ MODULE := engines/pelrock
MODULE_OBJS = \
pelrock.o \
+ actions.o \
chrono.o \
console.o \
metaengine.o \
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 774796d04df..0c9c36659ed 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -33,6 +33,7 @@
#include "image/png.h"
#include "pelrock.h"
+#include "pelrock/actions.h"
#include "pelrock/console.h"
#include "pelrock/detection.h"
#include "pelrock/fonts/small_font.h"
@@ -67,8 +68,6 @@ PelrockEngine::~PelrockEngine() {
delete _events;
delete _dialog;
delete _menu;
- // if (_bgPopupBalloon)
- // delete[] _bgPopupBalloon;
}
uint32 PelrockEngine::getFeatures() const {
@@ -195,25 +194,25 @@ Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
Common::Array<VerbIcon> verbs;
verbs.push_back(LOOK);
- if (hotspot->type & 1) {
+ if (hotspot->actionFlags & 1) {
verbs.push_back(OPEN);
}
- if (hotspot->type & 2) {
+ if (hotspot->actionFlags & 2) {
verbs.push_back(CLOSE);
}
- if (hotspot->type & 4) {
+ if (hotspot->actionFlags & 4) {
verbs.push_back(UNKNOWN);
}
- if (hotspot->type & 8) {
+ if (hotspot->actionFlags & 8) {
verbs.push_back(PICKUP);
}
- if (hotspot->type & 16) {
+ if (hotspot->actionFlags & 16) {
verbs.push_back(TALK);
}
- if (hotspot->type & 32) {
+ if (hotspot->actionFlags & 32) {
verbs.push_back(PUSH);
}
- if (hotspot->type & 128) {
+ if (hotspot->actionFlags & 128) {
verbs.push_back(PULL);
}
return verbs;
@@ -259,37 +258,6 @@ void PelrockEngine::renderScene(bool showTextOverlay) {
presentFrame();
updatePaletteAnimations();
- // if (alfredState.animState != ALFRED_WALKING && !_currentTextPages.empty()) {
- // _chronoManager->countTextDown = true;
- // if (_textDurationFrames-- > 0) {
- // if (alfredState.animState == ALFRED_TALKING) {
- // _textPos = Common::Point(alfredState.x, alfredState.y - kAlfredFrameHeight - 10);
- // }
- // renderText(_currentTextPages[_currentTextPageIndex], _textColor, _textPos.x, _textPos.y);
- // } else if (_currentTextPageIndex < _currentTextPages.size() - 1) {
- // _currentTextPageIndex++;
-
- // int totalChars = 0;
- // for (int i = 0; i < _currentTextPages[_currentTextPageIndex].size(); i++) {
- // totalChars += _currentTextPages[_currentTextPageIndex][i].size();
- // }
- // _textDurationFrames = totalChars / 2;
- // } else {
- // _currentTextPages.clear();
- // _currentTextPageIndex = 0;
- // alfredState.animState = ALFRED_IDLE;
- // isNPCATalking = false;
- // isNPCBTalking = false;
- // _chronoManager->countTextDown = false;
- // }
- // }
-
- // if (alfredState.animState == ALFRED_IDLE && alfredState.nextState != ALFRED_IDLE) {
- // alfredState.animState = alfredState.nextState;
- // alfredState.nextState = ALFRED_IDLE;
- // alfredState.curFrame = 0;
- // }
-
_screen->markAllDirty();
}
}
@@ -314,6 +282,27 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
}
}
+void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
+ for (const ActionEntry *entry = actionTable; entry->handler != nullptr; entry++) {
+ if (entry->action == action && entry->hotspotExtra == hotspot->extra) {
+ // Found exact match - call the handler
+ (this->*(entry->handler))(hotspot);
+ return;
+ }
+ }
+
+ // Try wildcard match (hotspotExtra == 0 means "any hotspot")
+ for (const ActionEntry *entry = actionTable; entry->handler != nullptr; ++entry) {
+ if (entry->action == action && entry->hotspotExtra == WILDCARD) {
+ (this->*(entry->handler))(hotspot);
+ return;
+ }
+ }
+
+ // No handler found
+ warning("No handler for hotspot %d with action %d", hotspot->extra, action);
+}
+
void PelrockEngine::checkMouse() {
if (_events->_leftMouseClicked) {
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
@@ -491,7 +480,7 @@ void PelrockEngine::animateRotatePalette(PaletteAnim *anim) {
}
}
-void PelrockEngine::doAction(byte action, HotSpot *hotspot) {
+void PelrockEngine::doAction(VerbIcon action, HotSpot *hotspot) {
switch (action) {
case LOOK:
lookAt(hotspot);
@@ -499,16 +488,12 @@ void PelrockEngine::doAction(byte action, HotSpot *hotspot) {
case TALK:
talkTo(hotspot);
break;
- case OPEN:
- open(hotspot);
- break;
- case CLOSE:
- close(hotspot);
- break;
case PICKUP:
- pick(hotspot);
+ pickUpAndDisable(hotspot);
+ executeAction(PICKUP, hotspot);
break;
default:
+ executeAction(action, hotspot);
break;
}
}
@@ -530,56 +515,6 @@ void PelrockEngine::lookAt(HotSpot *hotspot) {
_actionPopupState.isActive = false;
}
-void PelrockEngine::open(HotSpot *hotspot) {
- switch (hotspot->extra) {
- case 261:
- _room->addSticker(_res->getSticker(91));
- _room->_currentRoomHotspots[hotspot->index].isEnabled = false;
- break;
- case 268:
- _room->addSticker(_res->getSticker(93));
- _room->_currentRoomExits[0].isEnabled = true;
- break;
- default:
-
- break;
- }
-}
-
-void PelrockEngine::close(HotSpot *hotspot) {
- switch (hotspot->extra) {
- case 261:
- _room->removeSticker(91);
- break;
- case 268:
- _room->removeSticker(93);
- _room->_currentRoomExits[0].isEnabled = false;
- break;
- default:
-
- break;
- }
-}
-
-void PelrockEngine::pick(HotSpot *hotspot) {
- _inventoryItems.push_back(hotspot->extra);
- switch (hotspot->extra)
- {
- case 0:
- case 1:
- case 2:
- _room->_currentRoomHotspots[hotspot->index].isEnabled = false;
- break;
- case 4:
- _room->addSticker(_res->getSticker(95));
- /* code */
- break;
-
- default:
- break;
- }
-}
-
void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, int baseX, int baseY) {
int maxW = 0;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index b9a47c1beef..d73b420734a 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -98,12 +98,10 @@ private:
void animateFadePalette(PaletteAnim *anim);
void animateRotatePalette(PaletteAnim *anim);
- void doAction(byte action, HotSpot *hotspot);
+ void doAction(VerbIcon action, HotSpot *hotspot);
void talkTo(HotSpot *hotspot);
void lookAt(HotSpot *hotspot);
- void open(HotSpot *hotspot);
- void close(HotSpot *hotspot);
- void pick(HotSpot *hotspot);
+
void renderText(Common::Array<Common::String> lines, int color, int x, int y);
void chooseAlfredStateAndDraw();
void drawAlfred(byte *buf);
@@ -234,6 +232,17 @@ public:
void setScreen(int s, AlfredDirection dir);
void renderScene(bool showTextOverlay = false);
void performActionTrigger(uint16 actionTrigger);
+
+ void executeAction(VerbIcon action, HotSpot *hotspot);
+
+ void openDrawer(HotSpot *hotspot);
+ void closeDrawer(HotSpot *hotspot);
+ void openDoor(HotSpot *hotspot);
+ void closeDoor(HotSpot *hotspot);
+ void pickUpAndDisable(HotSpot *hotspot);
+ void pickUpPhoto(HotSpot *hotspot);
+ void noOp(HotSpot *hotspot);
+
};
extern PelrockEngine *g_engine;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 3fd7bf5faf3..f7a78196fcc 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -109,6 +109,15 @@ void RoomManager::removeSticker(int stickerIndex) {
_currentRoomStickers.remove_at(index);
}
+HotSpot *RoomManager::findHotspotByExtra(uint16 extra) {
+ for (int i = 0; i < _currentRoomHotspots.size(); i++) {
+ if (_currentRoomHotspots[i].extra == extra) {
+ return &_currentRoomHotspots[i];
+ }
+ }
+ return nullptr;
+}
+
PaletteAnim *RoomManager::getPaletteAnimForRoom(int roomNumber) {
Common::File exeFile;
@@ -203,13 +212,13 @@ Common::Array<HotSpot> RoomManager::loadHotspots(Common::File *roomFile, int roo
uint32_t obj_offset = hotspot_data_start + i * 9;
roomFile->seek(obj_offset, SEEK_SET);
HotSpot spot;
- spot.type = roomFile->readByte();
- spot.x = roomFile->readUint16LE();
- spot.y = roomFile->readUint16LE();
+ spot.actionFlags = roomFile->readByte();
+ spot.x = roomFile->readSint16LE();
+ spot.y = roomFile->readSint16LE();
spot.w = roomFile->readByte();
spot.h = roomFile->readByte();
- spot.extra = roomFile->readUint16LE();
- debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.type, spot.x, spot.y, spot.w, spot.h, spot.extra);
+ spot.extra = roomFile->readSint16LE();
+ debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra);
hotspots.push_back(spot);
}
return hotspots;
@@ -232,7 +241,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
thisHotspot.w = anims[i].w;
thisHotspot.h = anims[i].h;
thisHotspot.extra = anims[i].extra;
- thisHotspot.type = anims[i].actionFlags;
+ thisHotspot.actionFlags = anims[i].actionFlags;
thisHotspot.isEnabled = !anims[i].isDisabled;
hotspots.push_back(thisHotspot);
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index f9018d89d84..0f2e78fb400 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -41,6 +41,7 @@ public:
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
void addSticker(Sticker sticker);
void removeSticker(int index);
+ HotSpot * findHotspotByExtra(uint16 extra);
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
Common::String getRoomName(int roomNumber) {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 0a738eaa141..e1a11da6dd7 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -193,12 +193,12 @@ struct Sprite {
struct HotSpot {
int index;
int id;
- int x;
- int y;
+ int16 x;
+ int16 y;
int w;
int h;
- byte type;
- int extra;
+ byte actionFlags;
+ int16 extra;
bool isEnabled = true;
};
Commit: 3566f40b75dcc2d0f0e8507be9832c576b5ef8ac
https://github.com/scummvm/scummvm/commit/3566f40b75dcc2d0f0e8507be9832c576b5ef8ac
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:32+02:00
Commit Message:
PELROCK: Adds item to action popup
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index b5efbf0709a..aeaa5727aa6 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -68,7 +68,11 @@ void PelrockEngine::closeDoor(HotSpot *hotspot) {
}
void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
+ if(_inventoryItems.size() == 0) {
+ _selectedInventoryItem = hotspot->extra;
+ }
_inventoryItems.push_back(hotspot->extra);
+
hotspot->isEnabled = false;
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 0c9e688f39e..88f0043a266 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -118,6 +118,7 @@ uint32 DialogManager::readTextBlock(
}
void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer) {
+
int overlayHeight = choices->size() * kChoiceHeight + 2;
int overlayY = 400 - overlayHeight;
for (int x = 0; x < 640; x++) {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 0c9c36659ed..8d583aceb2d 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -153,10 +153,10 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- // setScreen(0, ALFRED_DOWN);
- setScreen(2, ALFRED_LEFT);
- alfredState.x = 576;
- alfredState.y = 374;
+ setScreen(0, ALFRED_DOWN);
+ // setScreen(2, ALFRED_LEFT);
+ // alfredState.x = 576;
+ // alfredState.y = 374;
}
}
@@ -992,12 +992,22 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
VerbIcon icon = isActionUnder(_events->_mouseX, _events->_mouseY);
+ bool shouldBlink = _chrono->getFrameCount() % kIconBlinkPeriod == 0;
for (int i = 0; i < actions.size(); i++) {
- if (icon == actions[i] && _chrono->getFrameCount() % kIconBlinkPeriod == 0) {
+ if (icon == actions[i] && shouldBlink) {
continue;
}
drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
+
+ }
+ bool itemUnder = isItemUnder(_events->_mouseX, _events->_mouseY);
+ if(_selectedInventoryItem != -1) {
+ if(itemUnder && shouldBlink) {
+ return;
+ }
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->getInventoryObject(_selectedInventoryItem).iconData, posx + 20 + (actions.size() * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
+
}
void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
@@ -1091,6 +1101,17 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
return NO_ACTION;
}
+bool PelrockEngine::isItemUnder(int x, int y) {
+ Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
+ Common::Rect itemRect = Common::Rect(_actionPopupState.x + 20 + (actions.size() * (kVerbIconWidth + 2)), _actionPopupState.y + 20,
+ _actionPopupState.x + 20 + (actions.size() * (kVerbIconWidth + 2)) + kVerbIconWidth,
+ _actionPopupState.y + 20 + kVerbIconHeight);
+ if (itemRect.contains(x, y)) {
+ return true;
+ }
+ return false;
+}
+
bool PelrockEngine::isAlfredUnder(int x, int y) {
// TODO: Account for scaling
int alfredX = alfredState.x;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index d73b420734a..77578522f2e 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -81,6 +81,7 @@ private:
Common::Array<VerbIcon> availableActions(HotSpot *hotspot);
VerbIcon isActionUnder(int x, int y);
+ bool isItemUnder(int x, int y);
bool isAlfredUnder(int x, int y);
int isHotspotUnder(int x, int y);
Exit *isExitUnder(int x, int y);
@@ -108,8 +109,8 @@ private:
void drawNextFrame(Sprite *animSet);
void changeCursor(Cursor cursor);
void animateTalkingNPC(Sprite *animSet);
- void playSoundIfNeeded();
+ void playSoundIfNeeded();
void gameLoop();
void menuLoop();
void showExtraScreen();
Commit: b4f04b9518fd99dd9e2f52fa9186145ab97a0b25
https://github.com/scummvm/scummvm/commit/b4f04b9518fd99dd9e2f52fa9186145ab97a0b25
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:32+02:00
Commit Message:
PELROCK: Additional text processing
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index aeaa5727aa6..f6a90bd9893 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -21,64 +21,74 @@
#include "pelrock/actions.h"
#include "pelrock/pelrock.h"
+#include "pelrock/offsets.h"
namespace Pelrock {
const ActionEntry actionTable[] = {
- // Room 0
- { 261, OPEN, &PelrockEngine::openDrawer },
- { 261, CLOSE, &PelrockEngine::closeDrawer },
- { 268, OPEN, &PelrockEngine::openDoor },
- { 268, CLOSE, &PelrockEngine::closeDoor },
- { 3, PICKUP, &PelrockEngine::pickUpPhoto },
+ // Room 0
+ {261, OPEN, &PelrockEngine::openDrawer},
+ {261, CLOSE, &PelrockEngine::closeDrawer},
+ {268, OPEN, &PelrockEngine::openDoor},
+ {268, CLOSE, &PelrockEngine::closeDoor},
+ {3, PICKUP, &PelrockEngine::pickUpPhoto},
+ {0, PICKUP, &PelrockEngine::pickYellowBook}, // Generic pickup for other items
- // Generic handlers
- { WILDCARD, PICKUP, &PelrockEngine::noOp }, // Generic pickup action
- { WILDCARD, TALK, &PelrockEngine::noOp }, // Generic talk action
- { WILDCARD, WALK, &PelrockEngine::noOp }, // Generic walk action
- { WILDCARD, LOOK, &PelrockEngine::noOp }, // Generic look action
- { WILDCARD, PUSH, &PelrockEngine::noOp }, // Generic push action
- { WILDCARD, PULL, &PelrockEngine::noOp }, // Generic pull action
- { WILDCARD, OPEN, &PelrockEngine::noOp }, // Generic open action
- { WILDCARD, CLOSE, &PelrockEngine::noOp }, // Generic close action
+ // Generic handlers
+ {WILDCARD, PICKUP, &PelrockEngine::noOp}, // Generic pickup action
+ {WILDCARD, TALK, &PelrockEngine::noOp}, // Generic talk action
+ {WILDCARD, WALK, &PelrockEngine::noOp}, // Generic walk action
+ {WILDCARD, LOOK, &PelrockEngine::noOp}, // Generic look action
+ {WILDCARD, PUSH, &PelrockEngine::noOp}, // Generic push action
+ {WILDCARD, PULL, &PelrockEngine::noOp}, // Generic pull action
+ {WILDCARD, OPEN, &PelrockEngine::noOp}, // Generic open action
+ {WILDCARD, CLOSE, &PelrockEngine::noOp}, // Generic close action
- // End marker
- { WILDCARD, NO_ACTION, nullptr }
-};
+ // End marker
+ {WILDCARD, NO_ACTION, nullptr}};
// Handler implementations
void PelrockEngine::openDrawer(HotSpot *hotspot) {
- _room->addSticker(_res->getSticker(91));
- hotspot->isEnabled = false;
+ if (_room->hasSticker(91)) {
+ _dialog->say(_res->_ingameTexts[ALREADY_OPENED_M]);
+ return;
+ }
+ _room->addSticker(_res->getSticker(91));
+ hotspot->isEnabled = false;
}
void PelrockEngine::closeDrawer(HotSpot *hotspot) {
- _room->removeSticker(91);
- hotspot->isEnabled = true;
+ _room->removeSticker(91);
+ hotspot->isEnabled = true;
}
void PelrockEngine::openDoor(HotSpot *hotspot) {
- _room->addSticker(_res->getSticker(93));
- _room->_currentRoomExits[0].isEnabled = true;
+ _room->addSticker(_res->getSticker(93));
+ _room->_currentRoomExits[0].isEnabled = true;
}
void PelrockEngine::closeDoor(HotSpot *hotspot) {
- _room->removeSticker(93);
- _room->_currentRoomExits[0].isEnabled = false;
+ _room->removeSticker(93);
+ _room->_currentRoomExits[0].isEnabled = false;
}
void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
- if(_inventoryItems.size() == 0) {
- _selectedInventoryItem = hotspot->extra;
- }
- _inventoryItems.push_back(hotspot->extra);
+ if (_inventoryItems.size() == 0) {
+ _selectedInventoryItem = hotspot->extra;
+ }
+ _inventoryItems.push_back(hotspot->extra);
- hotspot->isEnabled = false;
+ hotspot->isEnabled = false;
}
void PelrockEngine::pickUpPhoto(HotSpot *hotspot) {
- _room->findHotspotByExtra(261)->isEnabled = true;
+ _room->findHotspotByExtra(261)->isEnabled = true;
}
+
+void PelrockEngine::pickYellowBook(HotSpot *hotspot) {
+ _room->addSticker(_res->getSticker(95));
+}
+
void PelrockEngine::noOp(HotSpot *hotspot) {
// Do nothing
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 88f0043a266..ad33710ce02 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -400,12 +400,31 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
return pos;
}
+void DialogManager::setCurSprite(int index) {
+ // Set current sprite based on index
+ if (g_engine->_room == nullptr) {
+ _curSprite = nullptr;
+ return;
+ }
+
+ for (uint i = 0; i < g_engine->_room->_currentRoomAnims.size(); i++) {
+ Sprite *sprite = &g_engine->_room->_currentRoomAnims[i];
+ if (sprite->index == index) {
+ _curSprite = sprite;
+ return;
+ }
+ }
+
+ _curSprite = nullptr;
+}
+
void DialogManager::startConversation(const byte *conversationData, uint32 dataSize, Sprite *animSet) {
if (!conversationData || dataSize == 0) {
debug("startConversation: No conversation data");
return;
}
- _curSprite = animSet;
+ setCurSprite(animSet ? animSet->index : -1);
+ // _curSprite = animSet;
debug("Starting conversation with %u bytes of data", dataSize);
@@ -583,22 +602,61 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// Note: The caller should set inConversation = false after this returns
}
-void DialogManager::sayAlfred(Common::String text) {
+void DialogManager::sayAlfred(Common::StringArray texts) {
g_engine->alfredState.nextState = ALFRED_TALKING;
g_engine->alfredState.curFrame = 0;
_curSprite = nullptr;
- Common::Array<Common::Array<Common::String>> textLines = wordWrap(text);
+ Common::Array<Common::StringArray> textLines = wordWrap(texts);
displayDialogue(textLines, ALFRED_COLOR);
}
void DialogManager::sayAlfred(Description description) {
- sayAlfred(description.text);
+ Common::StringArray texts;
+ texts.push_back(description.text);
+
+ sayAlfred(texts);
if( description.isAction) {
g_engine->performActionTrigger(description.actionTrigger);
}
}
+void DialogManager::say(Common::StringArray texts) {
+ if(texts.empty()) {
+ return;
+ }
+ int speakerMarker = texts[0][0];
+ int color = texts[0][1];
+
+ if(speakerMarker == '@') {
+
+ for(int i = 0; i < texts.size(); i++) {
+ // Remove first two marker bytes
+ if(texts[i].size() > 2) {
+ texts[i] = texts[i].substr(2);
+ if(texts[i][0] == 0x78 && texts[i][1] == 0x78) { // Remove additional control chars
+ texts[i] = texts[i].substr(2);
+ }
+ } else {
+ texts[i] = "";
+ }
+ }
+
+ if(color == ALFRED_COLOR) {
+ sayAlfred(texts);
+ return;
+ }
+ else {
+ setCurSprite(0);
+ Common::Array<Common::StringArray> textLines = wordWrap(texts);
+ displayDialogue(textLines, color);
+ }
+ }
+ else {
+ sayAlfred(texts);
+ }
+}
+
bool isEndMarker(char char_byte) {
return char_byte == CHAR_END_MARKER_1 || char_byte == CHAR_END_MARKER_2 || char_byte == CHAR_END_MARKER_3 || char_byte == CHAR_END_MARKER_4;
}
@@ -709,4 +767,15 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
return pages;
}
+Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::StringArray texts) {
+ Common::Array<Common::Array<Common::String>> allWrappedLines;
+ for(int i = 0; i < texts.size(); i++) {
+ Common::Array<Common::Array<Common::String>> wrapped = wordWrap(texts[i]);
+ for(int j = 0; j < wrapped.size(); j++) {
+ allWrappedLines.push_back(wrapped[j]);
+ }
+ }
+ return allWrappedLines;
+}
+
} // namespace Pelrock
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index ffadb6ab073..104d319bc0c 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -80,8 +80,9 @@ private:
void displayDialogue(Common::String text, byte speakerId);
uint32 readTextBlock(const byte *data, uint32 dataSize, uint32 startPos, Common::String &outText, byte &outSpeakerId);
uint32 parseChoices(const byte *data, uint32 dataSize, uint32 startPos, Common::Array<ChoiceOption> *outChoices);
-
+ void setCurSprite(int index);
void checkMouse();
+ void sayAlfred(Common::StringArray texts);
public:
DialogManager(Graphics::Screen *screen, PelrockEventManager *events);
@@ -90,10 +91,11 @@ public:
void displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer);
int selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer);
void startConversation(const byte *conversationData, uint32 dataSize, Sprite *alfredAnimSet = nullptr);
- void sayAlfred(Common::String text);
void sayAlfred(Description description);
+ void say(Common::StringArray texts);
Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
+ Common::Array<Common::Array<Common::String>> wordWrap(Common::StringArray texts);
Common::Array<ChoiceOption> *_currentChoices = nullptr;
};
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index fa80338d70f..aed6086615e 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -119,6 +119,43 @@ const byte pegatina_rooms[140] = {
51, 52, 53, 54 // Sprites 127-130: Various rooms
};
+enum TextIndices {
+ THEYRE_CLOSED,
+ NOTAVAILABLE_TODAY,
+ ALREADY_OPENED_M,
+ ALREADY_CLOSED_M,
+ ALREADY_OPENED_F,
+ ALREADY_CLOSED_F,
+ ICECREAM_CLOSED,
+ IMPOOR,
+ SOHOT,
+ GREENBUTTON_REDBUTTON,
+ ENTERCARD,
+ NOMONEY_LEFT,
+ STUNGAGAIN,
+ WHATWASTHAT,
+ WHOS_THERE,
+ IMOFF,
+ SHOP_CLOSED,
+ SHE_WOULDNT_NOTICE,
+ GOTTA_OPEN_FIRST,
+ LETHISFATHER_PICKTHEM,
+ BRIBEME,
+ VERYGOOD,
+ WHENHEASKS,
+ OKAY,
+ I_NEED_ID,
+ WHAT_DO_I_GET_IN_RETURN,
+ THATSNOTENOUGH,
+ STOP,
+ THATSOBVIOUSLYNOTENOUGH,
+ WHATFOR,
+ NOTSTONE_ICE,
+ HEY_DONTSTART,
+ HOTONE_MOCKING,
+ SHUTUP,
+};
+
// Description offsets relative to DESCRIPTION_BASE_OFFSET
const uint16_t description_offsets[NUM_DESCRIPTIONS] = {
0x0000, // Object 0: Historia de la Princesa Zenna y su amante insatisfecho
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 8d583aceb2d..dc7c0b9f2cb 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -273,9 +273,11 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
_res->getExtraScreen(9, _extraScreen, palette);
g_system->getPaletteManager()->setPalette(palette, 0, 256);
- showExtraScreen();
+ extraScreenLoop();
- _dialog->sayAlfred(_res->_alfredResponses[0][0]); // "I found something interesting!");
+ _dialog->say(_res->_ingameTexts[SOHOT]);
+ _screen->markAllDirty();
+ _screen->update();
delete[] palette;
break;
@@ -283,24 +285,24 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
}
void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
- for (const ActionEntry *entry = actionTable; entry->handler != nullptr; entry++) {
- if (entry->action == action && entry->hotspotExtra == hotspot->extra) {
- // Found exact match - call the handler
- (this->*(entry->handler))(hotspot);
- return;
- }
- }
-
- // Try wildcard match (hotspotExtra == 0 means "any hotspot")
- for (const ActionEntry *entry = actionTable; entry->handler != nullptr; ++entry) {
- if (entry->action == action && entry->hotspotExtra == WILDCARD) {
- (this->*(entry->handler))(hotspot);
- return;
- }
- }
-
- // No handler found
- warning("No handler for hotspot %d with action %d", hotspot->extra, action);
+ for (const ActionEntry *entry = actionTable; entry->handler != nullptr; entry++) {
+ if (entry->action == action && entry->hotspotExtra == hotspot->extra) {
+ // Found exact match - call the handler
+ (this->*(entry->handler))(hotspot);
+ return;
+ }
+ }
+
+ // Try wildcard match (hotspotExtra == 0 means "any hotspot")
+ for (const ActionEntry *entry = actionTable; entry->handler != nullptr; ++entry) {
+ if (entry->action == action && entry->hotspotExtra == WILDCARD) {
+ (this->*(entry->handler))(hotspot);
+ return;
+ }
+ }
+
+ // No handler found
+ warning("No handler for hotspot %d with action %d", hotspot->extra, action);
}
void PelrockEngine::checkMouse() {
@@ -533,10 +535,9 @@ void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, i
}
void PelrockEngine::chooseAlfredStateAndDraw() {
- if(alfredState.idleFrameCounter++ >= kAlfredIdleAnimationFrameCount &&
- alfredState.animState == ALFRED_IDLE &&
- (alfredState.direction == ALFRED_LEFT || alfredState.direction == ALFRED_RIGHT)
- ) {
+ if (alfredState.idleFrameCounter++ >= kAlfredIdleAnimationFrameCount &&
+ alfredState.animState == ALFRED_IDLE &&
+ (alfredState.direction == ALFRED_LEFT || alfredState.direction == ALFRED_RIGHT)) {
alfredState.idleFrameCounter = 0;
alfredState.curFrame = 0;
alfredState.animState = ALFRED_COMB;
@@ -998,16 +999,14 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
continue;
}
drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
-
}
bool itemUnder = isItemUnder(_events->_mouseX, _events->_mouseY);
- if(_selectedInventoryItem != -1) {
- if(itemUnder && shouldBlink) {
+ if (_selectedInventoryItem != -1) {
+ if (itemUnder && shouldBlink) {
return;
}
drawSpriteToBuffer(_compositeBuffer, 640, _res->getInventoryObject(_selectedInventoryItem).iconData, posx + 20 + (actions.size() * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
-
}
void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
@@ -1060,10 +1059,9 @@ void PelrockEngine::gameLoop() {
}
}
-void PelrockEngine::showExtraScreen() {
+void PelrockEngine::extraScreenLoop() {
memcpy(_screen->getPixels(), _extraScreen, 640 * 400);
- _screen->markAllDirty();
- _screen->update();
+
while (!shouldQuit()) {
_events->pollEvent();
@@ -1072,6 +1070,8 @@ void PelrockEngine::showExtraScreen() {
break;
}
g_system->delayMillis(10);
+ _screen->markAllDirty();
+ _screen->update();
}
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
@@ -1104,8 +1104,8 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
bool PelrockEngine::isItemUnder(int x, int y) {
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
Common::Rect itemRect = Common::Rect(_actionPopupState.x + 20 + (actions.size() * (kVerbIconWidth + 2)), _actionPopupState.y + 20,
- _actionPopupState.x + 20 + (actions.size() * (kVerbIconWidth + 2)) + kVerbIconWidth,
- _actionPopupState.y + 20 + kVerbIconHeight);
+ _actionPopupState.x + 20 + (actions.size() * (kVerbIconWidth + 2)) + kVerbIconWidth,
+ _actionPopupState.y + 20 + kVerbIconHeight);
if (itemRect.contains(x, y)) {
return true;
}
@@ -1125,7 +1125,6 @@ bool PelrockEngine::isAlfredUnder(int x, int y) {
return true;
}
-
void PelrockEngine::checkMouseClick(int x, int y) {
if (_actionPopupState.isActive) {
@@ -1148,7 +1147,7 @@ void PelrockEngine::checkMouseClick(int x, int y) {
int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
bool isHotspotUnder = false;
- if(hotspotIndex != -1) {
+ if (hotspotIndex != -1) {
isHotspotUnder = true;
}
@@ -1236,7 +1235,6 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
byte *palette = new byte[256 * 3];
_room->getPalette(&roomFile, roomOffset, palette);
-
byte *background = new byte[640 * 400];
_room->getBackground(&roomFile, roomOffset, background);
@@ -1244,7 +1242,6 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
_screen->markAllDirty();
_screen->update();
-
Common::copy(background, background + 640 * 400, _currentBackground);
copyBackgroundToBuffer();
g_system->getPaletteManager()->setPalette(palette, 0, 256);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 77578522f2e..cbb0b9dd401 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -113,7 +113,7 @@ private:
void playSoundIfNeeded();
void gameLoop();
void menuLoop();
- void showExtraScreen();
+ void extraScreenLoop();
void checkMouseHover();
void checkMouseClick(int x, int y);
@@ -242,6 +242,7 @@ public:
void closeDoor(HotSpot *hotspot);
void pickUpAndDisable(HotSpot *hotspot);
void pickUpPhoto(HotSpot *hotspot);
+ void pickYellowBook(HotSpot *hotspot);
void noOp(HotSpot *hotspot);
};
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 98757d03414..18c79aac5d9 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -243,7 +243,7 @@ void ResourceManager::loadAlfredResponses() {
byte *descBuffer = new byte[kAlfredResponsesSize];
exe.seek(kAlfredResponsesOffset, SEEK_SET);
exe.read(descBuffer, kAlfredResponsesSize);
- _alfredResponses = processTextData(descBuffer, kAlfredResponsesSize);
+ _ingameTexts = processTextData(descBuffer, kAlfredResponsesSize);
delete[] descBuffer;
exe.close();
}
@@ -305,6 +305,7 @@ Common::Array<Common::Array<Common::String>> ResourceManager::processTextData(by
desc.append(1, '@');
desc.append(1, color);
pos += 2;
+
continue;
}
if (data[pos] == 0xC8) {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 042c9bf82a4..19faa3bdd63 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -65,7 +65,7 @@ public:
byte *_cursorMasks[5] = {nullptr};
byte *_verbIcons[9] = {nullptr};
byte *_popUpBalloon = nullptr;
- Common::Array<Common::StringArray> _alfredResponses;
+ Common::Array<Common::StringArray> _ingameTexts;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index f7a78196fcc..25aed624a85 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -109,6 +109,15 @@ void RoomManager::removeSticker(int stickerIndex) {
_currentRoomStickers.remove_at(index);
}
+bool RoomManager::hasSticker(int index) {
+ for(int i = 0; i < _currentRoomStickers.size(); i++) {
+ if (_currentRoomStickers[i].stickerIndex == index) {
+ return true;
+ }
+ }
+ return false;
+}
+
HotSpot *RoomManager::findHotspotByExtra(uint16 extra) {
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
if (_currentRoomHotspots[i].extra == extra) {
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 0f2e78fb400..b529cf83fac 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -41,6 +41,7 @@ public:
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
void addSticker(Sticker sticker);
void removeSticker(int index);
+ bool hasSticker(int index);
HotSpot * findHotspotByExtra(uint16 extra);
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
Commit: fedc0a9a10604b6f04684ff3f1b2ff2054c3a567
https://github.com/scummvm/scummvm/commit/fedc0a9a10604b6f04684ff3f1b2ff2054c3a567
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:33+02:00
Commit Message:
PELROCK: Inventory icon flashes when picked up
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/actions.h
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/events.h
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/sound.h
engines/pelrock/types.h
engines/pelrock/util.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index f6a90bd9893..3693cb5daf5 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -20,8 +20,9 @@
*/
#include "pelrock/actions.h"
-#include "pelrock/pelrock.h"
#include "pelrock/offsets.h"
+#include "pelrock/pelrock.h"
+#include "pelrock/util.h"
namespace Pelrock {
@@ -50,7 +51,7 @@ const ActionEntry actionTable[] = {
// Handler implementations
void PelrockEngine::openDrawer(HotSpot *hotspot) {
if (_room->hasSticker(91)) {
- _dialog->say(_res->_ingameTexts[ALREADY_OPENED_M]);
+ _dialog->say(_res->_ingameTexts[ALREADY_OPENED_M]);
return;
}
_room->addSticker(_res->getSticker(91));
@@ -76,8 +77,18 @@ void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
if (_inventoryItems.size() == 0) {
_selectedInventoryItem = hotspot->extra;
}
- _inventoryItems.push_back(hotspot->extra);
+ int frameCounter = 0;
+ while (frameCounter < kIconFlashDuration) {
+ _events->pollEvent();
+ bool didRender = renderScene(OVERLAY_PICKUP_ICON);
+ _screen->update();
+ if (didRender) {
+ frameCounter++;
+ }
+ g_system->delayMillis(10);
+ }
+ _inventoryItems.push_back(hotspot->extra);
hotspot->isEnabled = false;
}
diff --git a/engines/pelrock/actions.h b/engines/pelrock/actions.h
index 73305bc21de..5bd70abe8e4 100644
--- a/engines/pelrock/actions.h
+++ b/engines/pelrock/actions.h
@@ -21,17 +21,18 @@
#ifndef PELROCK_ACTIONS_H
#define PELROCK_ACTIONS_H
-#include "pelrock/types.h"
#include "pelrock/pelrock.h"
+#include "pelrock/types.h"
namespace Pelrock {
const int WILDCARD = -1;
+const int kIconFlashDuration = 15; // frames
struct ActionEntry {
- int hotspotExtra;
- VerbIcon action;
- void (PelrockEngine::*handler)(HotSpot *);
+ int hotspotExtra;
+ VerbIcon action;
+ void (PelrockEngine::*handler)(HotSpot *);
};
// Action table for all rooms
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index ad33710ce02..c1cbc8a3fdf 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -26,12 +26,12 @@
namespace Pelrock {
-DialogManager::DialogManager(Graphics::Screen *screen, PelrockEventManager *events)
- : _screen(screen), _events(events) {
+DialogManager::DialogManager(Graphics::Screen *screen, PelrockEventManager *events, GraphicsManager *graphics)
+ : _screen(screen), _events(events), _graphics(graphics) {
}
DialogManager::~DialogManager() {
- if( _currentChoices ) {
+ if (_currentChoices) {
delete _currentChoices;
_currentChoices = nullptr;
}
@@ -120,23 +120,17 @@ uint32 DialogManager::readTextBlock(
void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer) {
int overlayHeight = choices->size() * kChoiceHeight + 2;
- int overlayY = 400 - overlayHeight;
- for (int x = 0; x < 640; x++) {
- for (int y = overlayY; y < 400; y++) {
- int index = y * 640 + x;
- compositeBuffer[index] = g_engine->_room->overlayRemap[compositeBuffer[index]];
- }
- }
+ Common::Point overlayPos = _graphics->showOverlay(overlayHeight, compositeBuffer);
for (int i = 0; i < choices->size(); i++) {
ChoiceOption choice = (*choices)[i];
int choicePadding = 32;
int width = g_engine->_doubleSmallFont->getStringWidth(choice.text);
- Common::Rect bbox(0, overlayY + i * kChoiceHeight, width + choicePadding * 2, overlayY + i * kChoiceHeight + kChoiceHeight);
+ Common::Rect bbox(0, overlayPos.y + i * kChoiceHeight, width + choicePadding * 2, overlayPos.y + i * kChoiceHeight + kChoiceHeight);
int color = 14;
if (bbox.contains(_events->_mouseX, _events->_mouseY)) {
color = 15;
}
- drawText(compositeBuffer, g_engine->_doubleSmallFont, choice.text, choicePadding, overlayY + 2 + i * kChoiceHeight, 620, color);
+ drawText(compositeBuffer, g_engine->_doubleSmallFont, choice.text, choicePadding, overlayPos.y + 2 + i * kChoiceHeight, 620, color);
}
}
@@ -158,7 +152,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_events->pollEvent();
// Render the scene (keeps animations going)
- g_engine->renderScene(false);
+ g_engine->renderScene(OVERLAY_NONE);
// Draw the dialogue text on top using speaker ID as color
Common::Array<Common::String> textLines = dialogueLines[curPage];
@@ -178,7 +172,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (speakerId == ALFRED_COLOR) {
g_engine->alfredState.animState = ALFRED_TALKING;
- if(_curSprite != nullptr) {
+ if (_curSprite != nullptr) {
_curSprite->isTalking = false;
}
// Offset X position for Alfred to avoid overlapping with his sprite
@@ -228,7 +222,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
}
g_system->delayMillis(10);
}
- if(_curSprite != nullptr) {
+ if (_curSprite != nullptr) {
_curSprite->isTalking = false;
}
g_engine->alfredState.animState = ALFRED_IDLE;
@@ -253,7 +247,7 @@ int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *co
_events->pollEvent();
// Render the scene with choices overlay
- g_engine->renderScene(true);
+ g_engine->renderScene(OVERLAY_CHOICES);
if (_events->_leftMouseClicked) {
_events->_leftMouseClicked = false;
@@ -562,7 +556,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
}
- if(_currentChoices) {
+ if (_currentChoices) {
delete _currentChoices;
_currentChoices = nullptr;
}
@@ -616,25 +610,25 @@ void DialogManager::sayAlfred(Description description) {
texts.push_back(description.text);
sayAlfred(texts);
- if( description.isAction) {
+ if (description.isAction) {
g_engine->performActionTrigger(description.actionTrigger);
}
}
void DialogManager::say(Common::StringArray texts) {
- if(texts.empty()) {
+ if (texts.empty()) {
return;
}
int speakerMarker = texts[0][0];
int color = texts[0][1];
- if(speakerMarker == '@') {
+ if (speakerMarker == '@') {
- for(int i = 0; i < texts.size(); i++) {
+ for (int i = 0; i < texts.size(); i++) {
// Remove first two marker bytes
- if(texts[i].size() > 2) {
+ if (texts[i].size() > 2) {
texts[i] = texts[i].substr(2);
- if(texts[i][0] == 0x78 && texts[i][1] == 0x78) { // Remove additional control chars
+ if (texts[i][0] == 0x78 && texts[i][1] == 0x78) { // Remove additional control chars
texts[i] = texts[i].substr(2);
}
} else {
@@ -642,17 +636,15 @@ void DialogManager::say(Common::StringArray texts) {
}
}
- if(color == ALFRED_COLOR) {
+ if (color == ALFRED_COLOR) {
sayAlfred(texts);
return;
- }
- else {
+ } else {
setCurSprite(0);
Common::Array<Common::StringArray> textLines = wordWrap(texts);
displayDialogue(textLines, color);
}
- }
- else {
+ } else {
sayAlfred(texts);
}
}
@@ -769,9 +761,9 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::StringArray texts) {
Common::Array<Common::Array<Common::String>> allWrappedLines;
- for(int i = 0; i < texts.size(); i++) {
+ for (int i = 0; i < texts.size(); i++) {
Common::Array<Common::Array<Common::String>> wrapped = wordWrap(texts[i]);
- for(int j = 0; j < wrapped.size(); j++) {
+ for (int j = 0; j < wrapped.size(); j++) {
allWrappedLines.push_back(wrapped[j]);
}
}
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 104d319bc0c..d9b4e82a192 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -27,6 +27,7 @@
#include "pelrock/events.h"
#include "pelrock/fonts/large_font.h"
#include "pelrock/fonts/small_font.h"
+#include "pelrock/graphics.h"
#include "pelrock/types.h"
namespace Pelrock {
@@ -73,6 +74,7 @@ class DialogManager {
private:
Graphics::Screen *_screen = nullptr;
PelrockEventManager *_events = nullptr;
+ GraphicsManager *_graphics = nullptr;
Sprite *_curSprite = nullptr;
// Private helper functions for conversation parsing
@@ -85,7 +87,7 @@ private:
void sayAlfred(Common::StringArray texts);
public:
- DialogManager(Graphics::Screen *screen, PelrockEventManager *events);
+ DialogManager(Graphics::Screen *screen, PelrockEventManager *events, GraphicsManager *graphics);
~DialogManager();
void displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer);
diff --git a/engines/pelrock/events.h b/engines/pelrock/events.h
index ddea8935c8b..d25fb456cdd 100644
--- a/engines/pelrock/events.h
+++ b/engines/pelrock/events.h
@@ -32,6 +32,7 @@ private:
bool _leftMouseButton = 0;
bool _rightMouseButton = 0;
uint32 _clickTime = 0;
+
public:
int16 _mouseX = 0;
int16 _mouseY = 0;
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 69c05b16b4f..8a1743bbff7 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -22,6 +22,7 @@
#include "common/scummsys.h"
#include "pelrock/graphics.h"
+#include "pelrock/pelrock.h"
namespace Pelrock {
@@ -31,5 +32,16 @@ GraphicsManager::GraphicsManager() {
GraphicsManager::~GraphicsManager() {
}
-} // End of namespace Pelrock
+Common::Point GraphicsManager::showOverlay(int height, byte *buf) {
+ int overlayY = 400 - height;
+ int overlayX = 0;
+ for (int x = 0; x < 640; x++) {
+ for (int y = overlayY; y < 400; y++) {
+ int index = y * 640 + x;
+ buf[index] = g_engine->_room->overlayRemap[buf[index]];
+ }
+ }
+ return Common::Point(overlayX, overlayY);
+}
+} // End of namespace Pelrock
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index a4718e50624..a6c607706a3 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -22,16 +22,16 @@
#define PELROCK_GRAPHICS_H
#include "common/scummsys.h"
+#include "graphics/screen.h"
namespace Pelrock {
class GraphicsManager {
-
public:
GraphicsManager();
~GraphicsManager();
- void renderScene(bool showDialogOverlay);
+ Common::Point showOverlay(int height, byte *buf);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 8398d028e70..da6d1cdc761 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -23,16 +23,15 @@
#include "common/file.h"
#include "graphics/paletteman.h"
+#include "menu.h"
#include "pelrock/menu.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
-#include "menu.h"
namespace Pelrock {
Pelrock::MenuManager::MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res) : _screen(screen), _events(events), _res(res) {
-
}
void MenuManager::drawColoredText(Graphics::ManagedSurface *screen, const Common::String &text, int x, int y, int w, Graphics::Font *font) {
@@ -84,15 +83,13 @@ void MenuManager::checkMouseClick(int x, int y) {
}
}
-
void MenuManager::menuLoop() {
_events->pollEvent();
- if(_events->_leftMouseClicked) {
+ if (_events->_leftMouseClicked) {
_events->_leftMouseClicked = false;
checkMouseClick(_events->_mouseX, _events->_mouseY);
- }
- else if (_events->_rightMouseClicked) {
+ } else if (_events->_rightMouseClicked) {
_events->_rightMouseClicked = false;
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
g_engine->stateGame = GAME;
@@ -101,17 +98,16 @@ void MenuManager::menuLoop() {
memcpy(_compositeBuffer, _mainMenu, 640 * 400);
-
for (int i = 0; i < 4; i++) {
int itemIndex = _curInventoryPage * 4 + i;
- if(g_engine->_inventoryItems.size() <= itemIndex)
+ if (g_engine->_inventoryItems.size() <= itemIndex)
continue;
InventoryObject item = g_engine->_res->getInventoryObject(g_engine->_inventoryItems[itemIndex]);
drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
}
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- for(int i = 0; _menuText.size() > i; i++) {
+ for (int i = 0; _menuText.size() > i; i++) {
drawColoredText(_screen, _menuText[i], 230, 200 + (i * 10), 200, g_engine->_smallFont);
}
@@ -219,7 +215,6 @@ void MenuManager::loadMenuTexts() {
}
void MenuManager::tearDown() {
-
}
Pelrock::MenuManager::~MenuManager() {
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 77d5d39b5b6..b9d3e87f463 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -21,8 +21,8 @@
#ifndef PELROCK_MENU_H
#define PELROCK_MENU_H
-#include "graphics/screen.h"
#include "graphics/font.h"
+#include "graphics/screen.h"
#include "pelrock/events.h"
#include "pelrock/resources.h"
@@ -36,6 +36,7 @@ public:
void menuLoop();
void loadMenu();
byte _mainMenuPalette[768] = {0};
+
private:
void checkMouseClick(int x, int y);
void loadMenuTexts();
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index c577cd7abe3..a01a7d58cc9 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -17,7 +17,8 @@ MODULE_OBJS = \
pathfinding.o \
events.o \
dialog.o \
- menu.o
+ menu.o \
+ graphics.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index dc7c0b9f2cb..c4c888786b4 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -68,6 +68,7 @@ PelrockEngine::~PelrockEngine() {
delete _events;
delete _dialog;
delete _menu;
+ delete _graphics;
}
uint32 PelrockEngine::getFeatures() const {
@@ -85,12 +86,12 @@ Common::Error PelrockEngine::run() {
initGraphics(640, 400);
_screen = new Graphics::Screen();
_videoManager = new VideoManager(_screen, _events);
+ _graphics = new GraphicsManager();
_room = new RoomManager();
_res = new ResourceManager();
_sound = new SoundManager(_mixer);
- _dialog = new DialogManager(_screen, _events);
+ _dialog = new DialogManager(_screen, _events, _graphics);
_menu = new MenuManager(_screen, _events, _res);
-
// Set the engine's debugger console
setDebugger(new PelrockConsole(this));
@@ -240,7 +241,7 @@ void PelrockEngine::playSoundIfNeeded() {
}
}
-void PelrockEngine::renderScene(bool showTextOverlay) {
+bool PelrockEngine::renderScene(int overlayMode) {
_chrono->updateChrono();
if (_chrono->_gameTick) {
@@ -251,15 +252,19 @@ void PelrockEngine::renderScene(bool showTextOverlay) {
placeStickers();
updateAnimations();
- if (showTextOverlay) {
+ if (overlayMode == 1) {
_dialog->displayChoices(_dialog->_currentChoices, _compositeBuffer);
+ } else if (overlayMode == 2) {
+ pickupIconFlash();
}
presentFrame();
updatePaletteAnimations();
_screen->markAllDirty();
+ return true;
}
+ return false;
}
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
@@ -576,11 +581,11 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_currentStep++;
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
+ alfredState.animState = ALFRED_IDLE;
if (_queuedAction.isQueued) {
doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
_queuedAction.isQueued = false;
}
- alfredState.animState = ALFRED_IDLE;
}
} else {
_currentContext.movementBuffer[_currentStep] = step;
@@ -1045,6 +1050,14 @@ void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
drawSpriteToBuffer(_compositeBuffer, 640, frame, x, y, w, h, 255);
}
+void PelrockEngine::pickupIconFlash() {
+ _graphics->showOverlay(65, _compositeBuffer);
+ InventoryObject item = _res->getInventoryObject(_currentHotspot->extra);
+ if (_chrono->getFrameCount() % kIconBlinkPeriod == 0) {
+ drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 5, 400 - 60 - 5, 60, 60, 1);
+ }
+}
+
void PelrockEngine::gameLoop() {
_events->pollEvent();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index cbb0b9dd401..86b11252531 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -43,6 +43,7 @@
#include "pelrock/fonts/large_font.h"
#include "pelrock/fonts/small_font.h"
#include "pelrock/fonts/small_font_double.h"
+#include "pelrock/graphics.h"
#include "pelrock/menu.h"
#include "pelrock/resources.h"
#include "pelrock/room.h"
@@ -64,6 +65,7 @@ private:
PelrockEventManager *_events = nullptr;
DialogManager *_dialog = nullptr;
MenuManager *_menu = nullptr;
+ GraphicsManager *_graphics = nullptr;
void init();
void loadAnims();
@@ -109,6 +111,7 @@ private:
void drawNextFrame(Sprite *animSet);
void changeCursor(Cursor cursor);
void animateTalkingNPC(Sprite *animSet);
+ void pickupIconFlash();
void playSoundIfNeeded();
void gameLoop();
@@ -183,7 +186,6 @@ public:
Common::Array<int> _inventoryItems;
int _selectedInventoryItem = -1;
-
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
~PelrockEngine() override;
@@ -231,20 +233,19 @@ public:
}
void setScreen(int s, AlfredDirection dir);
- void renderScene(bool showTextOverlay = false);
+ bool renderScene(int overlayMode = OVERLAY_NONE);
void performActionTrigger(uint16 actionTrigger);
- void executeAction(VerbIcon action, HotSpot *hotspot);
+ void executeAction(VerbIcon action, HotSpot *hotspot);
- void openDrawer(HotSpot *hotspot);
- void closeDrawer(HotSpot *hotspot);
- void openDoor(HotSpot *hotspot);
- void closeDoor(HotSpot *hotspot);
- void pickUpAndDisable(HotSpot *hotspot);
+ void openDrawer(HotSpot *hotspot);
+ void closeDrawer(HotSpot *hotspot);
+ void openDoor(HotSpot *hotspot);
+ void closeDoor(HotSpot *hotspot);
+ void pickUpAndDisable(HotSpot *hotspot);
void pickUpPhoto(HotSpot *hotspot);
void pickYellowBook(HotSpot *hotspot);
void noOp(HotSpot *hotspot);
-
};
extern PelrockEngine *g_engine;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 18c79aac5d9..4a9f1000d2c 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -314,7 +314,7 @@ Common::Array<Common::Array<Common::String>> ResourceManager::processTextData(by
pos++;
continue;
}
- if( decode )
+ if (decode)
desc.append(1, decodeChar(data[pos]));
else
desc.append(1, data[pos]);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 25aed624a85..79d46904824 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -110,7 +110,7 @@ void RoomManager::removeSticker(int stickerIndex) {
}
bool RoomManager::hasSticker(int index) {
- for(int i = 0; i < _currentRoomStickers.size(); i++) {
+ for (int i = 0; i < _currentRoomStickers.size(); i++) {
if (_currentRoomStickers[i].stickerIndex == index) {
return true;
}
@@ -446,7 +446,7 @@ Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, in
}
if (data[pos] == 0xF8) {
description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
- if( description.actionTrigger != 0 ) {
+ if (description.actionTrigger != 0) {
description.isAction = true;
}
pos += 2;
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index b529cf83fac..74b86f15d0b 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -42,7 +42,7 @@ public:
void addSticker(Sticker sticker);
void removeSticker(int index);
bool hasSticker(int index);
- HotSpot * findHotspotByExtra(uint16 extra);
+ HotSpot *findHotspotByExtra(uint16 extra);
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
Common::String getRoomName(int roomNumber) {
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 9a22bdfa099..e354a8d452e 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -154,34 +154,33 @@ static const uint COUNTER_MASK = 0x1F;
const int kMaxChannels = 15;
-
-
- class GameRNG {
+class GameRNG {
private:
- uint32_t _state;
+ uint32_t _state;
+
public:
- // LCG constants (from JUEGO.EXE @ 0x0002b12f)
- static constexpr uint32_t MULTIPLIER = 0x41C64E6D; // 1103515245
- static constexpr uint32_t INCREMENT = 0x3039; // 12345
-
- GameRNG(uint32_t seed = 0) {
- _state = seed & 0xFFFFFFFF;
- }
-
- // Generate next random number (0-32767)
- uint16_t nextRandom() {
- _state = (_state * MULTIPLIER + INCREMENT) & 0xFFFFFFFF;
- return static_cast<uint16_t>((_state >> 16) & 0x7FFF);
- }
-
- uint32_t getState() const {
- return _state;
- }
-
- void setState(uint32_t state) {
- _state = state & 0xFFFFFFFF;
- }
+ // LCG constants (from JUEGO.EXE @ 0x0002b12f)
+ static constexpr uint32_t MULTIPLIER = 0x41C64E6D; // 1103515245
+ static constexpr uint32_t INCREMENT = 0x3039; // 12345
+
+ GameRNG(uint32_t seed = 0) {
+ _state = seed & 0xFFFFFFFF;
+ }
+
+ // Generate next random number (0-32767)
+ uint16_t nextRandom() {
+ _state = (_state * MULTIPLIER + INCREMENT) & 0xFFFFFFFF;
+ return static_cast<uint16_t>((_state >> 16) & 0x7FFF);
+ }
+
+ uint32_t getState() const {
+ return _state;
+ }
+
+ void setState(uint32_t state) {
+ _state = state & 0xFFFFFFFF;
+ }
};
class SoundManager {
@@ -221,9 +220,6 @@ private:
GameRNG _rng = GameRNG(0);
};
-
-
-
} // End of namespace Pelrock
#endif // PELROCK_SOUND_H
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index e1a11da6dd7..b99c1aa5eb9 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -89,6 +89,10 @@ const int kAlfredIdleAnimationFrameCount = 300;
#define ALFRED_COLOR 0x0D
+#define OVERLAY_NONE 0
+#define OVERLAY_CHOICES 1
+#define OVERLAY_PICKUP_ICON 2
+
const byte kIconBlinkPeriod = 4;
enum AlfredAnimState {
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index de6c4f3b2b6..5fa4e5ad68d 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -308,7 +308,7 @@ byte decodeChar(byte b) {
case 0x83:
return special_chars[0];
case 0x80:
- return special_chars[3]; // n tilde
+ return special_chars[3]; // n tilde
case 0x7F:
return special_chars[4];
case 0x7E:
Commit: 2e4bbe82e602964acf73837f68e6de2ebf5ac768
https://github.com/scummvm/scummvm/commit/2e4bbe82e602964acf73837f68e6de2ebf5ac768
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:33+02:00
Commit Message:
PELROCK: Cleanup of pelrock engine class
Changed paths:
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 8a1743bbff7..355b773e5f9 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -44,4 +44,29 @@ Common::Point GraphicsManager::showOverlay(int height, byte *buf) {
return Common::Point(overlayX, overlayY);
}
+byte *GraphicsManager::grabBackgroundSlice(byte *buf, int x, int y, int w, int h) {
+ byte *bg = new byte[w * h];
+ for (int j = 0; j < w; j++) {
+ for (int i = 0; i < h; i++) {
+ int idx = i * w + j;
+ if (y + i < 400 && x + j < 640) {
+ *(bg + idx) = buf[(y + i) * 640 + (x + j)];
+ }
+ }
+ }
+ return bg;
+}
+
+void GraphicsManager::putBackgroundSlice(byte *buf, int x, int y, int w, int h, byte *slice) {
+ for (int i = 0; i < w; i++) {
+ for (int j = 0; j < h; j++) {
+ int index = (j * w + i);
+ if (x + i < 640 && y + j < 400) {
+ buf[(y + j) * 640 + (x + i)] = slice[index];
+ // *(byte *)_screen->getBasePtr(x + i, y + j) = slice[index];
+ }
+ }
+ }
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index a6c607706a3..ab604a63d56 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -32,6 +32,9 @@ public:
~GraphicsManager();
Common::Point showOverlay(int height, byte *buf);
+ byte *grabBackgroundSlice(byte *buf, int x, int y, int w, int h);
+ void putBackgroundSlice(byte *buf, int x, int y, int w, int h, byte *slice);
+
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index c4c888786b4..dc43e6ab911 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -165,28 +165,6 @@ void PelrockEngine::loadAnims() {
_res->loadAlfredAnims();
}
-byte *PelrockEngine::grabBackgroundSlice(int x, int y, int w, int h) {
- byte *bg = new byte[w * h];
- for (int j = 0; j < w; j++) {
- for (int i = 0; i < h; i++) {
- int idx = i * w + j;
- if (y + i < 400 && x + j < 640) {
- *(bg + idx) = _currentBackground[(y + i) * 640 + (x + j)];
- }
- }
- }
- return bg;
-}
-
-void PelrockEngine::putBackgroundSlice(int x, int y, int w, int h, byte *slice) {
- for (int i = 0; i < w; i++) {
- for (int j = 0; j < h; j++) {
- int index = (j * w + i);
- if (x + i < 640 && y + j < 400)
- *(byte *)_screen->getBasePtr(x + i, y + j) = slice[index];
- }
- }
-}
Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
if (hotspot == nullptr) {
@@ -522,23 +500,6 @@ void PelrockEngine::lookAt(HotSpot *hotspot) {
_actionPopupState.isActive = false;
}
-void PelrockEngine::renderText(Common::Array<Common::String> lines, int color, int baseX, int baseY) {
-
- int maxW = 0;
- for (size_t i = 0; i < lines.size(); i++) {
- Common::Rect r = _largeFont->getBoundingBox(lines[i]);
- if (r.width() > maxW) {
- maxW = r.width();
- }
- }
- int lineSize = lines.size();
- for (size_t i = 0; i < lines.size(); i++) {
- int textX = baseX - (maxW / 2);
- int textY = baseY - (lineSize * 25) + (i * 25);
- drawText(_largeFont, lines[i], textX, textY, maxW, color);
- }
-}
-
void PelrockEngine::chooseAlfredStateAndDraw() {
if (alfredState.idleFrameCounter++ >= kAlfredIdleAnimationFrameCount &&
alfredState.animState == ALFRED_IDLE &&
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 86b11252531..797f6ce40ca 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -75,12 +75,6 @@ private:
*/
void walkTo(int x, int y);
- void talk(byte object);
- void sayNPC(Sprite *anim, Common::String text, byte color);
-
- byte *grabBackgroundSlice(int x, int y, int w, int h);
- void putBackgroundSlice(int x, int y, int w, int h, byte *slice);
-
Common::Array<VerbIcon> availableActions(HotSpot *hotspot);
VerbIcon isActionUnder(int x, int y);
bool isItemUnder(int x, int y);
@@ -88,6 +82,7 @@ private:
int isHotspotUnder(int x, int y);
Exit *isExitUnder(int x, int y);
Sprite *isSpriteUnder(int x, int y);
+
void showActionBalloon(int posx, int posy, int curFrame);
void checkMouse();
@@ -105,7 +100,6 @@ private:
void talkTo(HotSpot *hotspot);
void lookAt(HotSpot *hotspot);
- void renderText(Common::Array<Common::String> lines, int color, int x, int y);
void chooseAlfredStateAndDraw();
void drawAlfred(byte *buf);
void drawNextFrame(Sprite *animSet);
@@ -114,8 +108,8 @@ private:
void pickupIconFlash();
void playSoundIfNeeded();
+
void gameLoop();
- void menuLoop();
void extraScreenLoop();
void checkMouseHover();
@@ -125,6 +119,7 @@ private:
void calculateScalingMasks();
ScaleCalculation calculateScaling(int yPos, ScalingParams scalingParams);
+
Common::Array<Common::Array<int>> _widthScalingTable;
Common::Array<Common::Array<int>> _heightScalingTable;
@@ -132,24 +127,15 @@ private:
int _currentStep = 0;
PathContext _currentContext;
- // text display
- byte _textColor = 0;
- Common::Point _textPos;
- int _textDurationFrames = 0;
- Common::Array<Common::Array<Common::String>> _currentTextPages = Common::Array<Common::Array<Common::String>>();
- int _currentTextPageIndex = 0;
-
- // Alfred
- bool alfredFrameSkip = false;
- bool isAlkfredWalking = false;
-
byte *_currentBackground = nullptr; // Clean background - NEVER modified
byte *_extraScreen = nullptr;
+
ActionPopupState _actionPopupState;
HotSpot *_currentHotspot = nullptr;
Common::Point _curWalkTarget;
+
QueuedAction _queuedAction;
bool showShadows = false;
@@ -186,6 +172,7 @@ public:
Common::Array<int> _inventoryItems;
int _selectedInventoryItem = -1;
+
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
~PelrockEngine() override;
@@ -234,15 +221,16 @@ public:
void setScreen(int s, AlfredDirection dir);
bool renderScene(int overlayMode = OVERLAY_NONE);
+
+ // Actions
void performActionTrigger(uint16 actionTrigger);
void executeAction(VerbIcon action, HotSpot *hotspot);
-
- void openDrawer(HotSpot *hotspot);
- void closeDrawer(HotSpot *hotspot);
- void openDoor(HotSpot *hotspot);
- void closeDoor(HotSpot *hotspot);
- void pickUpAndDisable(HotSpot *hotspot);
+ void openDrawer(HotSpot *hotspot);
+ void closeDrawer(HotSpot *hotspot);
+ void openDoor(HotSpot *hotspot);
+ void closeDoor(HotSpot *hotspot);
+ void pickUpAndDisable(HotSpot *hotspot);
void pickUpPhoto(HotSpot *hotspot);
void pickYellowBook(HotSpot *hotspot);
void noOp(HotSpot *hotspot);
Commit: 149fd0a54e1def62ce14d67ecd4ca309db4d572b
https://github.com/scummvm/scummvm/commit/149fd0a54e1def62ce14d67ecd4ca309db4d572b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:33+02:00
Commit Message:
PELROCK: Better handling of mouse events
Changed paths:
engines/pelrock/events.cpp
engines/pelrock/events.h
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
index bc81829f64b..766dfccc1f8 100644
--- a/engines/pelrock/events.cpp
+++ b/engines/pelrock/events.cpp
@@ -63,7 +63,10 @@ void PelrockEventManager::pollEvent() {
break;
case Common::EVENT_LBUTTONUP:
if (_leftMouseButton == 1) {
- _leftMouseClicked = true;
+ // Don't treat as regular click if we're in popup selection mode
+ if (!_popupSelectionMode) {
+ _leftMouseClicked = true;
+ }
_mouseClickX = _event.mouse.x;
_mouseClickY = _event.mouse.y;
_longClicked = false;
@@ -97,7 +100,7 @@ void PelrockEventManager::pollEvent() {
if (elapsedLongClick >= kDoubleClickDelay) {
elapsedLongClick = 0;
_longClicked = true;
- _leftMouseButton = 0;
+ _popupSelectionMode = true;
}
}
}
diff --git a/engines/pelrock/events.h b/engines/pelrock/events.h
index d25fb456cdd..f39ab56cfb5 100644
--- a/engines/pelrock/events.h
+++ b/engines/pelrock/events.h
@@ -29,8 +29,6 @@ static const int kDoubleClickDelay = 300; // in milliseconds
class PelrockEventManager {
private:
Common::Event _event;
- bool _leftMouseButton = 0;
- bool _rightMouseButton = 0;
uint32 _clickTime = 0;
public:
@@ -41,6 +39,9 @@ public:
bool _leftMouseClicked = false;
bool _longClicked = false;
bool _rightMouseClicked = false;
+ bool _popupSelectionMode = false;
+ bool _leftMouseButton = 0;
+ bool _rightMouseButton = 0;
Common::Event _lastKeyEvent;
PelrockEventManager();
void pollEvent();
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index dc43e6ab911..1c27602a347 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -165,7 +165,6 @@ void PelrockEngine::loadAnims() {
_res->loadAlfredAnims();
}
-
Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
if (hotspot == nullptr) {
return Common::Array<VerbIcon>();
@@ -230,9 +229,9 @@ bool PelrockEngine::renderScene(int overlayMode) {
placeStickers();
updateAnimations();
- if (overlayMode == 1) {
+ if (overlayMode == OVERLAY_CHOICES) {
_dialog->displayChoices(_dialog->_currentChoices, _compositeBuffer);
- } else if (overlayMode == 2) {
+ } else if (overlayMode == OVERLAY_PICKUP_ICON) {
pickupIconFlash();
}
@@ -289,7 +288,31 @@ void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
}
void PelrockEngine::checkMouse() {
- if (_events->_leftMouseClicked) {
+
+ // Cancel walking animation on mouse click
+ if(_events->_leftMouseButton) {
+ alfredState.curFrame = 0;
+ alfredState.animState = ALFRED_IDLE;
+ }
+
+ // Handle mouse release after long press (popup selection mode)
+ if (_events->_popupSelectionMode && !_events->_leftMouseButton) {
+ // Mouse was released while popup is active
+ VerbIcon actionClicked = isActionUnder(_events->_mouseX, _events->_mouseY);
+ if (actionClicked != NO_ACTION && _currentHotspot != nullptr) {
+ // Action was selected - queue it
+ walkTo(_currentHotspot->x + _currentHotspot->w / 2, _currentHotspot->y + _currentHotspot->h);
+ _queuedAction = QueuedAction{actionClicked, _currentHotspot->index, true};
+ } else {
+ // Released outside popup - just close it
+ _queuedAction = QueuedAction{NO_ACTION, -1, false};
+ _currentHotspot = nullptr;
+ }
+ _actionPopupState.isActive = false;
+ _events->_popupSelectionMode = false;
+ alfredState.idleFrameCounter = 0;
+ } else if (_events->_leftMouseClicked) {
+ // Regular click (not during popup mode)
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
alfredState.idleFrameCounter = 0;
_events->_leftMouseClicked = false;
@@ -788,9 +811,9 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
void PelrockEngine::checkLongMouseClick(int x, int y) {
int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
- if (hotspotIndex != -1) {
+ if (hotspotIndex != -1 && !_actionPopupState.isActive) {
- _actionPopupState.x = alfredState.x - kBalloonWidth / 2;
+ _actionPopupState.x = alfredState.x + kAlfredFrameWidth/2 - kBalloonWidth / 2;
if (_actionPopupState.x < 0)
_actionPopupState.x = 0;
if (_actionPopupState.x + kBalloonWidth > 640) {
@@ -1100,22 +1123,8 @@ bool PelrockEngine::isAlfredUnder(int x, int y) {
}
void PelrockEngine::checkMouseClick(int x, int y) {
-
- if (_actionPopupState.isActive) {
- // Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
- VerbIcon actionClicked = isActionUnder(x, y);
- if (actionClicked != NO_ACTION) {
- _actionPopupState.isActive = false;
- if (_currentHotspot != nullptr) {
- walkTo(_currentHotspot->x + _currentHotspot->w / 2, _currentHotspot->y + _currentHotspot->h);
- _queuedAction = QueuedAction{actionClicked, _currentHotspot->index, true};
- return;
- }
- }
- }
-
+ // This handles regular clicks (not popup selection)
_queuedAction = QueuedAction{NO_ACTION, -1, false};
-
_actionPopupState.isActive = false;
_currentHotspot = nullptr;
Commit: 70b784d2d0c0b4a740dbacecfe4432f798afebe4
https://github.com/scummvm/scummvm/commit/70b784d2d0c0b4a740dbacecfe4432f798afebe4
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:34+02:00
Commit Message:
PELROCK: Calculate facing direction
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1c27602a347..13189d3da44 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -233,6 +233,8 @@ bool PelrockEngine::renderScene(int overlayMode) {
_dialog->displayChoices(_dialog->_currentChoices, _compositeBuffer);
} else if (overlayMode == OVERLAY_PICKUP_ICON) {
pickupIconFlash();
+ } else if (overlayMode == OVERLAY_ACTION) {
+ showActionBalloon(_actionPopupState.x, _actionPopupState.y, _actionPopupState.curFrame);
}
presentFrame();
@@ -290,8 +292,9 @@ void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
void PelrockEngine::checkMouse() {
// Cancel walking animation on mouse click
- if(_events->_leftMouseButton) {
+ if (_events->_leftMouseButton) {
alfredState.curFrame = 0;
+ alfredState.idleFrameCounter = 0;
alfredState.animState = ALFRED_IDLE;
}
@@ -310,19 +313,15 @@ void PelrockEngine::checkMouse() {
}
_actionPopupState.isActive = false;
_events->_popupSelectionMode = false;
- alfredState.idleFrameCounter = 0;
} else if (_events->_leftMouseClicked) {
// Regular click (not during popup mode)
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
- alfredState.idleFrameCounter = 0;
_events->_leftMouseClicked = false;
_actionPopupState.isActive = false;
} else if (_events->_longClicked) {
- alfredState.idleFrameCounter = 0;
checkLongMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_longClicked = false;
} else if (_events->_rightMouseClicked) {
- alfredState.idleFrameCounter = 0;
g_system->getPaletteManager()->setPalette(_menu->_mainMenuPalette, 0, 256);
_events->_rightMouseClicked = false;
stateGame = SETTINGS;
@@ -367,7 +366,7 @@ void PelrockEngine::updateAnimations() {
void PelrockEngine::presentFrame() {
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- // paintDebugLayer();
+ paintDebugLayer();
_screen->markAllDirty();
}
@@ -566,6 +565,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
alfredState.animState = ALFRED_IDLE;
+ alfredState.direction = calculateAlfredsDirection(_currentHotspot);
if (_queuedAction.isQueued) {
doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
_queuedAction.isQueued = false;
@@ -608,7 +608,8 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
break;
}
drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[alfredState.direction][alfredState.curFrame], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
- alfredState.curFrame++;
+ if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
+ alfredState.curFrame++;
break;
case ALFRED_INTERACTING:
if (alfredState.curFrame >= interactingAnimLength) {
@@ -813,7 +814,7 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
if (hotspotIndex != -1 && !_actionPopupState.isActive) {
- _actionPopupState.x = alfredState.x + kAlfredFrameWidth/2 - kBalloonWidth / 2;
+ _actionPopupState.x = alfredState.x + kAlfredFrameWidth / 2 - kBalloonWidth / 2;
if (_actionPopupState.x < 0)
_actionPopupState.x = 0;
if (_actionPopupState.x + kBalloonWidth > 640) {
@@ -977,7 +978,6 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
}
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
-
drawSpriteToBuffer(_compositeBuffer, 640, _res->_popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
@@ -996,6 +996,11 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
drawSpriteToBuffer(_compositeBuffer, 640, _res->getInventoryObject(_selectedInventoryItem).iconData, posx + 20 + (actions.size() * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
+ if (_actionPopupState.curFrame < 3) {
+ _actionPopupState.curFrame++;
+ } else {
+ _actionPopupState.curFrame = 0;
+ }
}
void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
@@ -1044,16 +1049,8 @@ void PelrockEngine::pickupIconFlash() {
void PelrockEngine::gameLoop() {
_events->pollEvent();
-
- if (inConversation) {
- // TODO: Pass actual conversation data from room
- // For now, using nullptr to disable - actual data needs to be loaded
- _dialog->startConversation(nullptr, 0);
- inConversation = false;
- } else {
- checkMouse();
- renderScene();
- }
+ checkMouse();
+ renderScene();
}
void PelrockEngine::extraScreenLoop() {
@@ -1085,6 +1082,50 @@ void PelrockEngine::walkTo(int x, int y) {
alfredState.curFrame = 0;
}
+AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
+
+ AlfredDirection calculatedDirection = ALFRED_DOWN;
+ if (hotspot->isSprite) {
+ // Check if Alfred's left edge is past sprite's right edge
+ if (hotspot->x + hotspot->w < alfredState.x) {
+ calculatedDirection = ALFRED_LEFT; // Face LEFT
+ }
+ // Check if Alfred's right edge is before sprite's left edge
+ else if ((alfredState.x + kAlfredFrameWidth - alfredState.scaledX) < hotspot->x) {
+ calculatedDirection = ALFRED_RIGHT; // Face RIGHT
+ }
+ // Alfred is horizontally overlapping with sprite
+ else {
+ // Check if Alfred's top is above sprite's bottom OR Alfred is within sprite's Y range
+ if (((alfredState.y + kAlfredFrameHeight - alfredState.scaledY) < hotspot->y) ||
+ (alfredState.y <= hotspot->y + hotspot->h &&
+ hotspot->zOrder <= ((399 - alfredState.y) / 2) + 10)) {
+ calculatedDirection = ALFRED_DOWN; // Face DOWN
+ } else {
+ calculatedDirection = ALFRED_UP; // Face UP
+ }
+ }
+ } else {
+ // Check if Alfred's left edge is past hotspot's right edge
+ if (hotspot->x + hotspot->w < alfredState.x) {
+ calculatedDirection = ALFRED_LEFT; // Face LEFT
+ }
+ // Check if Alfred's right edge is before hotspot's left edge
+ else if ((alfredState.x + kAlfredFrameWidth - alfredState.scaledX) < hotspot->x) {
+ calculatedDirection = ALFRED_RIGHT; // Face RIGHT
+ }
+ // Check vertical positioning
+ else if (((alfredState.y + kAlfredFrameHeight - alfredState.scaledY) < hotspot->y) ||
+ (alfredState.y <= hotspot->y + hotspot->h &&
+ (hotspot->actionFlags & 0x80) == 0x80)) {
+ calculatedDirection = ALFRED_DOWN; // Face DOWN
+ } else {
+ calculatedDirection = ALFRED_UP; // Face UP
+ }
+ }
+ return calculatedDirection;
+}
+
VerbIcon PelrockEngine::isActionUnder(int x, int y) {
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
for (int i = 0; i < actions.size(); i++) {
@@ -1137,11 +1178,14 @@ void PelrockEngine::checkMouseClick(int x, int y) {
Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, isHotspotUnder, isHotspotUnder ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
_curWalkTarget = walkTarget;
- // if (hotspotIndex != -1) {
- // _currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
- // walkTarget.x = _currentHotspot->x + _currentHotspot->w / 2;
- // walkTarget.y = _currentHotspot->y + _currentHotspot->h;
- // }
+ if (hotspotIndex != -1) {
+ _currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
+ walkTarget.x = _currentHotspot->x + _currentHotspot->w / 2;
+ walkTarget.y = _currentHotspot->y + _currentHotspot->h;
+ }
+ else {
+ _currentHotspot = nullptr;
+ }
walkTo(walkTarget.x, walkTarget.y);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 797f6ce40ca..a700fdd9719 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -74,6 +74,7 @@ private:
Walking alforithm
*/
void walkTo(int x, int y);
+ AlfredDirection calculateAlfredsDirection(HotSpot *hotspot);
Common::Array<VerbIcon> availableActions(HotSpot *hotspot);
VerbIcon isActionUnder(int x, int y);
@@ -142,7 +143,6 @@ private:
// JAVA
bool shouldPlayIntro = false;
- bool inConversation = false;
bool gameInitialized = false;
bool screenReady = false;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 79d46904824..4d5065a42f2 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -226,6 +226,7 @@ Common::Array<HotSpot> RoomManager::loadHotspots(Common::File *roomFile, int roo
spot.y = roomFile->readSint16LE();
spot.w = roomFile->readByte();
spot.h = roomFile->readByte();
+ spot.isSprite = false;
spot.extra = roomFile->readSint16LE();
debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra);
hotspots.push_back(spot);
@@ -252,6 +253,8 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
thisHotspot.extra = anims[i].extra;
thisHotspot.actionFlags = anims[i].actionFlags;
thisHotspot.isEnabled = !anims[i].isDisabled;
+ thisHotspot.isSprite = true;
+ thisHotspot.zOrder = anims[i].zOrder;
hotspots.push_back(thisHotspot);
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index b99c1aa5eb9..e2266ec0ac6 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -92,6 +92,7 @@ const int kAlfredIdleAnimationFrameCount = 300;
#define OVERLAY_NONE 0
#define OVERLAY_CHOICES 1
#define OVERLAY_PICKUP_ICON 2
+#define OVERLAY_ACTION 3
const byte kIconBlinkPeriod = 4;
@@ -126,7 +127,8 @@ struct AlfredState {
uint16 movementSpeed = 6; // pixels per frame
uint16 x = 319;
uint16 y = 302;
- float currentScale = 1.0f;
+ uint16 scaledX = 0;
+ uint16 scaledY = 0;
int idleFrameCounter = 0;
};
@@ -204,6 +206,8 @@ struct HotSpot {
byte actionFlags;
int16 extra;
bool isEnabled = true;
+ bool isSprite = false;
+ byte zOrder = 0;
};
struct TalkingAnimHeader {
Commit: 262ec696c5f9b4bd84394f4af63f6a9f059945a0
https://github.com/scummvm/scummvm/commit/262ec696c5f9b4bd84394f4af63f6a9f059945a0
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:34+02:00
Commit Message:
PELROCK: Fixes crash with non-existing hotspot
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 13189d3da44..b59af0a0d04 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -565,7 +565,8 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
alfredState.animState = ALFRED_IDLE;
- alfredState.direction = calculateAlfredsDirection(_currentHotspot);
+ if(_currentHotspot != nullptr)
+ alfredState.direction = calculateAlfredsDirection(_currentHotspot);
if (_queuedAction.isQueued) {
doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
_queuedAction.isQueued = false;
@@ -1127,6 +1128,9 @@ AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
}
VerbIcon PelrockEngine::isActionUnder(int x, int y) {
+ if (_currentHotspot == nullptr) {
+ return NO_ACTION;
+ }
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
for (int i = 0; i < actions.size(); i++) {
int actionX = _actionPopupState.x + 20 + (i * (kVerbIconWidth + 2));
@@ -1174,19 +1178,10 @@ void PelrockEngine::checkMouseClick(int x, int y) {
if (hotspotIndex != -1) {
isHotspotUnder = true;
}
-
- Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, isHotspotUnder, isHotspotUnder ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
+ _currentHotspot = isHotspotUnder ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr;
+ Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, isHotspotUnder, _currentHotspot);
_curWalkTarget = walkTarget;
- if (hotspotIndex != -1) {
- _currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
- walkTarget.x = _currentHotspot->x + _currentHotspot->w / 2;
- walkTarget.y = _currentHotspot->y + _currentHotspot->h;
- }
- else {
- _currentHotspot = nullptr;
- }
-
walkTo(walkTarget.x, walkTarget.y);
// { // For quick room navigation
@@ -1253,6 +1248,7 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
return;
}
_sound->stopAllSounds();
+ _currentHotspot = nullptr;
alfredState.direction = dir;
alfredState.animState = ALFRED_IDLE;
_currentStep = 0;
Commit: 86f6b84e837694f74a01aedf8f1273ed160a13ac
https://github.com/scummvm/scummvm/commit/86f6b84e837694f74a01aedf8f1273ed160a13ac
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:34+02:00
Commit Message:
PELROCK: Pickup animation
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pathfinding.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 3693cb5daf5..69724377a5f 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -23,6 +23,7 @@
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
+#include "pelrock.h"
namespace Pelrock {
@@ -34,6 +35,7 @@ const ActionEntry actionTable[] = {
{268, CLOSE, &PelrockEngine::closeDoor},
{3, PICKUP, &PelrockEngine::pickUpPhoto},
{0, PICKUP, &PelrockEngine::pickYellowBook}, // Generic pickup for other items
+ {4, PICKUP, &PelrockEngine::pickUpBrick}, // Brick
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOp}, // Generic pickup action
@@ -100,6 +102,10 @@ void PelrockEngine::pickYellowBook(HotSpot *hotspot) {
_room->addSticker(_res->getSticker(95));
}
+void PelrockEngine::pickUpBrick(HotSpot *hotspot) {
+ _room->addSticker(_res->getSticker(133));
+}
+
void PelrockEngine::noOp(HotSpot *hotspot) {
// Do nothing
}
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
index bc78b4c68ea..c6538d91273 100644
--- a/engines/pelrock/pathfinding.cpp
+++ b/engines/pelrock/pathfinding.cpp
@@ -144,6 +144,7 @@ Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes,
// Hovering over hotspot - use hotspot center-bottom
sourceX = hotspot->x + hotspot->w / 2;
sourceY = hotspot->y + hotspot->h;
+
}
// else: use sourceX, sourceY as passed (mouse position)
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b59af0a0d04..b710156c738 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -387,6 +387,12 @@ void PelrockEngine::paintDebugLayer() {
_smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
}
+ for(int i = 0; i< _room->_currentRoomExits.size(); i++) {
+ Exit exit = _room->_currentRoomExits[i];
+ drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 200 + i);
+ _smallFont->drawString(_screen, Common::String::format("Exit %d -> Room %d", i, exit.targetRoom), exit.x + 2, exit.y + 2, 640, 14);
+ }
+
drawPos(_screen, alfredState.x, alfredState.y, 13);
drawPos(_screen, alfredState.x, alfredState.y - kAlfredFrameHeight, 13);
drawPos(_screen, _curWalkTarget.x, _curWalkTarget.y, 100);
@@ -402,9 +408,7 @@ void PelrockEngine::paintDebugLayer() {
void PelrockEngine::placeStickers() {
for (int i = 0; i < _room->_currentRoomStickers.size(); i++) {
Sticker sticker = _room->_currentRoomStickers[i];
- if (sticker.roomNumber == _room->_currentRoomNumber) {
- placeSticker(sticker);
- }
+ placeSticker(sticker);
}
}
@@ -496,6 +500,8 @@ void PelrockEngine::doAction(VerbIcon action, HotSpot *hotspot) {
talkTo(hotspot);
break;
case PICKUP:
+ alfredState.animState = ALFRED_INTERACTING;
+ alfredState.curFrame = 0;
pickUpAndDisable(hotspot);
executeAction(PICKUP, hotspot);
break;
@@ -530,6 +536,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.curFrame = 0;
alfredState.animState = ALFRED_COMB;
}
+ debug("Alfred state: %d, pos (%d, %d) curFrame %d", alfredState.animState, alfredState.x, alfredState.y, alfredState.curFrame);
switch (alfredState.animState) {
case ALFRED_WALKING: {
MovementStep step = _currentContext.movementBuffer[_currentStep];
@@ -565,11 +572,14 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
alfredState.animState = ALFRED_IDLE;
+ alfredState.curFrame = 0;
if(_currentHotspot != nullptr)
alfredState.direction = calculateAlfredsDirection(_currentHotspot);
+
if (_queuedAction.isQueued) {
doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
_queuedAction.isQueued = false;
+ break;
}
}
} else {
@@ -615,9 +625,11 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
case ALFRED_INTERACTING:
if (alfredState.curFrame >= interactingAnimLength) {
alfredState.curFrame = 0;
+ alfredState.animState = ALFRED_IDLE;
}
drawAlfred(_res->alfredInteractFrames[alfredState.direction][alfredState.curFrame]);
- alfredState.curFrame++;
+ if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
+ alfredState.curFrame++;
break;
default:
drawAlfred(_res->alfredIdle[alfredState.direction]);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index a700fdd9719..77ecb0cb53f 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -233,6 +233,7 @@ public:
void pickUpAndDisable(HotSpot *hotspot);
void pickUpPhoto(HotSpot *hotspot);
void pickYellowBook(HotSpot *hotspot);
+ void pickUpBrick(HotSpot *hotspot);
void noOp(HotSpot *hotspot);
};
Commit: e960d138d9a73eea979373bf76d60b9eec13b2d8
https://github.com/scummvm/scummvm/commit/e960d138d9a73eea979373bf76d60b9eec13b2d8
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:34+02:00
Commit Message:
PELROCK: State change through function
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index c1cbc8a3fdf..566d9e1b667 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -171,7 +171,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int yPos = 0;
if (speakerId == ALFRED_COLOR) {
- g_engine->alfredState.animState = ALFRED_TALKING;
+ g_engine->alfredState.setState(ALFRED_TALKING);
if (_curSprite != nullptr) {
_curSprite->isTalking = false;
}
@@ -179,7 +179,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
xPos = g_engine->alfredState.x + kAlfredFrameWidth / 2 - maxWidth / 2;
yPos = g_engine->alfredState.y - kAlfredFrameHeight - height; // Above sprite, adjust for line
} else {
- g_engine->alfredState.animState = ALFRED_IDLE;
+ g_engine->alfredState.setState(ALFRED_IDLE);
_curSprite->isTalking = true;
xPos = _curSprite->x + _curSprite->w / 2 - maxWidth / 2;
yPos = _curSprite->y - height; // Above sprite, adjust for line
@@ -225,7 +225,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (_curSprite != nullptr) {
_curSprite->isTalking = false;
}
- g_engine->alfredState.animState = ALFRED_IDLE;
+ g_engine->alfredState.setState(ALFRED_IDLE);
}
void DialogManager::displayDialogue(Common::String text, byte speakerId) {
@@ -597,8 +597,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
void DialogManager::sayAlfred(Common::StringArray texts) {
- g_engine->alfredState.nextState = ALFRED_TALKING;
- g_engine->alfredState.curFrame = 0;
+ g_engine->alfredState.setState(ALFRED_TALKING);
_curSprite = nullptr;
Common::Array<Common::StringArray> textLines = wordWrap(texts);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b710156c738..130f156749c 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -294,8 +294,7 @@ void PelrockEngine::checkMouse() {
// Cancel walking animation on mouse click
if (_events->_leftMouseButton) {
alfredState.curFrame = 0;
- alfredState.idleFrameCounter = 0;
- alfredState.animState = ALFRED_IDLE;
+ alfredState.setState(ALFRED_IDLE);
}
// Handle mouse release after long press (popup selection mode)
@@ -387,7 +386,7 @@ void PelrockEngine::paintDebugLayer() {
_smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
}
- for(int i = 0; i< _room->_currentRoomExits.size(); i++) {
+ for (int i = 0; i < _room->_currentRoomExits.size(); i++) {
Exit exit = _room->_currentRoomExits[i];
drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 200 + i);
_smallFont->drawString(_screen, Common::String::format("Exit %d -> Room %d", i, exit.targetRoom), exit.x + 2, exit.y + 2, 640, 14);
@@ -500,8 +499,7 @@ void PelrockEngine::doAction(VerbIcon action, HotSpot *hotspot) {
talkTo(hotspot);
break;
case PICKUP:
- alfredState.animState = ALFRED_INTERACTING;
- alfredState.curFrame = 0;
+ alfredState.setState(ALFRED_INTERACTING);
pickUpAndDisable(hotspot);
executeAction(PICKUP, hotspot);
break;
@@ -533,8 +531,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.animState == ALFRED_IDLE &&
(alfredState.direction == ALFRED_LEFT || alfredState.direction == ALFRED_RIGHT)) {
alfredState.idleFrameCounter = 0;
- alfredState.curFrame = 0;
- alfredState.animState = ALFRED_COMB;
+ alfredState.setState(ALFRED_COMB);
}
debug("Alfred state: %d, pos (%d, %d) curFrame %d", alfredState.animState, alfredState.x, alfredState.y, alfredState.curFrame);
switch (alfredState.animState) {
@@ -571,9 +568,8 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_currentStep++;
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
- alfredState.animState = ALFRED_IDLE;
- alfredState.curFrame = 0;
- if(_currentHotspot != nullptr)
+ alfredState.setState(ALFRED_IDLE);
+ if (_currentHotspot != nullptr)
alfredState.direction = calculateAlfredsDirection(_currentHotspot);
if (_queuedAction.isQueued) {
@@ -613,8 +609,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
break;
case ALFRED_COMB:
if (alfredState.curFrame >= 11) {
- alfredState.animState = ALFRED_IDLE;
- alfredState.curFrame = 0;
+ alfredState.setState(ALFRED_IDLE);
drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredIdle[alfredState.direction], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
break;
}
@@ -623,13 +618,15 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.curFrame++;
break;
case ALFRED_INTERACTING:
- if (alfredState.curFrame >= interactingAnimLength) {
- alfredState.curFrame = 0;
- alfredState.animState = ALFRED_IDLE;
+ if (alfredState.curFrame > interactingAnimLength) {
+ alfredState.setState(ALFRED_IDLE);
+ drawAlfred(_res->alfredInteractFrames[alfredState.direction][alfredState.curFrame]);
+ break;
}
drawAlfred(_res->alfredInteractFrames[alfredState.direction][alfredState.curFrame]);
- if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
+ if (_chrono->getFrameCount() % 15 == 0) {
alfredState.curFrame++;
+ }
break;
default:
drawAlfred(_res->alfredIdle[alfredState.direction]);
@@ -1091,8 +1088,7 @@ void PelrockEngine::walkTo(int x, int y) {
PathContext context = {nullptr, nullptr, nullptr, 0, 0, 0};
findPath(alfredState.x, alfredState.y, x, y, _room->_currentRoomWalkboxes, &context);
_currentContext = context;
- alfredState.animState = ALFRED_WALKING;
- alfredState.curFrame = 0;
+ alfredState.setState(ALFRED_WALKING);
}
AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
@@ -1262,7 +1258,7 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
_sound->stopAllSounds();
_currentHotspot = nullptr;
alfredState.direction = dir;
- alfredState.animState = ALFRED_IDLE;
+ alfredState.setState(ALFRED_IDLE);
_currentStep = 0;
int roomOffset = number * kRoomStructSize;
alfredState.curFrame = 0;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index e2266ec0ac6..4a6767ebc38 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -121,7 +121,6 @@ struct ActionPopupState {
struct AlfredState {
AlfredAnimState animState = ALFRED_IDLE;
- AlfredAnimState nextState = ALFRED_IDLE;
AlfredDirection direction = ALFRED_DOWN;
int curFrame = 0;
uint16 movementSpeed = 6; // pixels per frame
@@ -130,6 +129,11 @@ struct AlfredState {
uint16 scaledX = 0;
uint16 scaledY = 0;
int idleFrameCounter = 0;
+
+ void setState(AlfredAnimState nextState) {
+ animState = nextState;
+ curFrame = 0;
+ }
};
typedef struct {
Commit: ae72e1d66ee19901e76432b988536b0647947b0a
https://github.com/scummvm/scummvm/commit/ae72e1d66ee19901e76432b988536b0647947b0a
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:35+02:00
Commit Message:
PELROCK: Fixes redundant frame when changing alfred state
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 130f156749c..5e491352366 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -611,26 +611,26 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (alfredState.curFrame >= 11) {
alfredState.setState(ALFRED_IDLE);
drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredIdle[alfredState.direction], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
- break;
+ } else {
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[alfredState.direction][alfredState.curFrame], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
+ if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
+ alfredState.curFrame++;
}
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[alfredState.direction][alfredState.curFrame], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
- if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
- alfredState.curFrame++;
break;
case ALFRED_INTERACTING:
- if (alfredState.curFrame > interactingAnimLength) {
+ if (alfredState.curFrame >= interactingAnimLength) {
alfredState.setState(ALFRED_IDLE);
+ } else {
drawAlfred(_res->alfredInteractFrames[alfredState.direction][alfredState.curFrame]);
- break;
- }
- drawAlfred(_res->alfredInteractFrames[alfredState.direction][alfredState.curFrame]);
- if (_chrono->getFrameCount() % 15 == 0) {
- alfredState.curFrame++;
+ if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
+ alfredState.curFrame++;
+ }
}
break;
- default:
+ }
+ // This if is needed to draw Alfred when idle, when the switch case results in a state change
+ if (alfredState.animState == ALFRED_IDLE) {
drawAlfred(_res->alfredIdle[alfredState.direction]);
- break;
}
}
Commit: b8398b86dc9f6745bd27e17fc2b29cdab0c95e27
https://github.com/scummvm/scummvm/commit/b8398b86dc9f6745bd27e17fc2b29cdab0c95e27
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:35+02:00
Commit Message:
PELROCK: Implements menu buttons
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index da6d1cdc761..becf7ca81a3 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -60,6 +60,24 @@ void MenuManager::drawColoredText(Graphics::ManagedSurface *screen, const Common
}
}
+MenuButton MenuManager::isButtonClicked(int x, int y) {
+ Common::Rect questionMarkRect(Common::Point(kQuestionMarkPosX, kQuestionMarkPosY), kQuestionMarkWidth, kQuestionMarkHeight);
+ if (questionMarkRect.contains(x, y)) {
+ return QUESTION_MARK_BUTTON;
+ }
+ Common::Rect invPrevRect(Common::Point(469, 87), kInventoryArrowWidth, kInventoryArrowHeight);
+ if (invPrevRect.contains(x, y)) {
+ return INVENTORY_PREV_BUTTON;
+ }
+ Common::Rect invNextRect(Common::Point(459, 140), kInventoryArrowWidth, kInventoryArrowHeight);
+ if (invNextRect.contains(x, y)) {
+ return INVENTORY_NEXT_BUTTON;
+ }
+
+ return NO_BUTTON; // Default fallback
+
+}
+
void MenuManager::checkMouseClick(int x, int y) {
bool selectedItem = false;
@@ -77,26 +95,42 @@ void MenuManager::checkMouseClick(int x, int y) {
_menuText = _menuTexts[0];
}
- if (x >= 471 && x <= 471 + 23 &&
- y >= 87 && y <= 87 + 33) {
- _curInventoryPage++;
+ MenuButton button = isButtonClicked(x, y);
+ switch (button) {
+ case QUESTION_MARK_BUTTON:
+ debug("Show credits");
+ break;
+ case INVENTORY_PREV_BUTTON:
+ if (_curInventoryPage > 0)
+ _curInventoryPage--;
+ break;
+ case INVENTORY_NEXT_BUTTON:
+ if ((_curInventoryPage + 1) * 4 < g_engine->_inventoryItems.size())
+ _curInventoryPage++;
+ break;
+ default:
+ break;
}
+
}
+
+
void MenuManager::menuLoop() {
_events->pollEvent();
if (_events->_leftMouseClicked) {
- _events->_leftMouseClicked = false;
checkMouseClick(_events->_mouseX, _events->_mouseY);
+ _events->_leftMouseClicked = false;
} else if (_events->_rightMouseClicked) {
- _events->_rightMouseClicked = false;
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
g_engine->stateGame = GAME;
+ _events->_rightMouseClicked = false;
tearDown();
}
memcpy(_compositeBuffer, _mainMenu, 640 * 400);
+ drawButtons();
for (int i = 0; i < 4; i++) {
int itemIndex = _curInventoryPage * 4 + i;
@@ -111,6 +145,7 @@ void MenuManager::menuLoop() {
drawColoredText(_screen, _menuText[i], 230, 200 + (i * 10), 200, g_engine->_smallFont);
}
+ drawText(g_engine->_smallFont, Common::String::format("%d,%d", _events->_mouseX, _events->_mouseY), 0, 0, 640, 13);
_screen->markAllDirty();
_screen->update();
}
@@ -167,7 +202,6 @@ void MenuManager::loadMenu() {
delete[] decompressedPart2;
alfred7.seek(2563266, SEEK_SET);
alfred7.read(_mainMenu + curPos, 92160);
- alfred7.close();
} else {
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
@@ -186,8 +220,41 @@ void MenuManager::loadMenu() {
}
g_engine->_res->mergeRleBlocks(&alfred7, kAlternateSettingsMenuOffset, 8, _mainMenu);
- alfred7.close();
}
+
+
+ // question mark
+ byte *questionMarks = new byte[kQuestionMarkStride * 2];
+
+ alfred7.seek(3214046, SEEK_SET);
+ alfred7.read(questionMarks, kQuestionMarkStride * 2);
+
+ _questionMark[0] = new byte[kQuestionMarkStride];
+ _questionMark[1] = new byte[kQuestionMarkStride];
+ extractSingleFrame(questionMarks, _questionMark[0], 0, kQuestionMarkWidth, kQuestionMarkHeight);
+ extractSingleFrame(questionMarks, _questionMark[1], 1, kQuestionMarkWidth, kQuestionMarkHeight);
+ delete[] questionMarks;
+
+ //Inventory arrows
+ byte *arrows = new byte[kInventoryArrowStride * 2];
+ alfred7.seek(kInvLeftArrowOffset, SEEK_SET);
+ alfred7.read(arrows, kInventoryArrowStride * 2);
+ _inventoryLeftArrow[0] = new byte[kInventoryArrowStride];
+ _inventoryLeftArrow[1] = new byte[kInventoryArrowStride];
+ extractSingleFrame(arrows, _inventoryLeftArrow[0], 0, kInventoryArrowWidth, kInventoryArrowHeight);
+ extractSingleFrame(arrows, _inventoryLeftArrow[1], 1, kInventoryArrowWidth, kInventoryArrowHeight);
+
+ alfred7.seek(kInvLeftArrowOffset + (kInventoryArrowStride * 2), SEEK_SET);
+ alfred7.read(arrows, kInventoryArrowStride * 2);
+ _inventoryRightArrow[0] = new byte[kInventoryArrowStride];
+ _inventoryRightArrow[1] = new byte[kInventoryArrowStride];
+ extractSingleFrame(arrows, _inventoryRightArrow[0], 0, kInventoryArrowWidth, kInventoryArrowHeight);
+ extractSingleFrame(arrows, _inventoryRightArrow[1], 1, kInventoryArrowWidth, kInventoryArrowHeight);
+
+ delete[] arrows;
+
+
+ alfred7.close();
}
void MenuManager::loadMenuTexts() {
@@ -217,8 +284,32 @@ void MenuManager::loadMenuTexts() {
void MenuManager::tearDown() {
}
+void MenuManager::drawButtons() {
+ MenuButton button = NO_BUTTON;
+ if(_events->_leftMouseButton != 0) {
+ button = isButtonClicked(_events->_mouseX, _events->_mouseY);
+ }
+ //Question mark
+ byte *buf = button == QUESTION_MARK_BUTTON ? _questionMark[1] : _questionMark[0];
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, kQuestionMarkPosX, kQuestionMarkPosY, kQuestionMarkWidth, kQuestionMarkHeight, 255);
+
+ buf = button == INVENTORY_PREV_BUTTON ? _inventoryLeftArrow[1] : _inventoryLeftArrow[0];
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, 469, 87, kInventoryArrowWidth, kInventoryArrowHeight, 255);
+
+ buf = button == INVENTORY_NEXT_BUTTON ? _inventoryRightArrow[1] : _inventoryRightArrow[0];
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, 463, 133, kInventoryArrowWidth, kInventoryArrowHeight, 255);
+
+}
+
Pelrock::MenuManager::~MenuManager() {
delete[] _mainMenu;
+ delete[] _compositeBuffer;
+ delete[] _questionMark[0];
+ delete[] _questionMark[1];
+ delete[] _inventoryLeftArrow[0];
+ delete[] _inventoryLeftArrow[1];
+ delete[] _inventoryRightArrow[0];
+ delete[] _inventoryRightArrow[1];
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index b9d3e87f463..edcd02ee101 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -29,6 +29,32 @@
namespace Pelrock {
+const int kQuestionMarkOffset = 3214046;
+const int kInvLeftArrowOffset = 3215906;
+
+const int kQuestionMarkPosX = 217;
+const int kQuestionMarkPosY = 293;
+const int kQuestionMarkWidth = 31;
+const int kQuestionMarkHeight = 30;
+const int kQuestionMarkStride = 30 * 31;
+
+const int kInventoryArrowWidth = 26;
+const int kInventoryArrowHeight = 37;
+const int kInventoryArrowStride = kInventoryArrowWidth * kInventoryArrowHeight;
+
+enum MenuButton {
+ QUESTION_MARK_BUTTON,
+ INVENTORY_PREV_BUTTON,
+ INVENTORY_NEXT_BUTTON,
+ SAVEGAME_PREV_BUTTON,
+ SAVEGAME_NEXT_BUTTON,
+ EXIT_MENU_BUTTON,
+ SAVE_GAME_BUTTON,
+ LOAD_GAME_BUTTON,
+ SOUNDS_BUTTON,
+ NO_BUTTON
+};
+
class MenuManager {
public:
MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res);
@@ -41,12 +67,18 @@ private:
void checkMouseClick(int x, int y);
void loadMenuTexts();
void tearDown();
+ void drawButtons();
void drawColoredText(Graphics::ManagedSurface *surface, const Common::String &text, int x, int y, int w, Graphics::Font *font);
+ MenuButton isButtonClicked(int x, int y);
Graphics::Screen *_screen = nullptr;
PelrockEventManager *_events = nullptr;
ResourceManager *_res = nullptr;
byte *_mainMenu = nullptr;
byte *_compositeBuffer = nullptr;
+ byte *_inventoryLeftArrow[2] = { nullptr };
+ byte *_inventoryRightArrow[2] = { nullptr };
+ byte *_savesArrows[2] = { nullptr };
+ byte *_questionMark[2] = {nullptr};
Common::Array<Common::StringArray> _menuTexts;
// Temporary
int _selectedInvIndex = 0;
Commit: 0a5f0560a5f6c0c72a9853bb0a97b10226c00c57
https://github.com/scummvm/scummvm/commit/0a5f0560a5f6c0c72a9853bb0a97b10226c00c57
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:35+02:00
Commit Message:
PELROCK: Refactor button resource reading
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index becf7ca81a3..6d669408866 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -61,19 +61,27 @@ void MenuManager::drawColoredText(Graphics::ManagedSurface *screen, const Common
}
MenuButton MenuManager::isButtonClicked(int x, int y) {
- Common::Rect questionMarkRect(Common::Point(kQuestionMarkPosX, kQuestionMarkPosY), kQuestionMarkWidth, kQuestionMarkHeight);
- if (questionMarkRect.contains(x, y)) {
+ if (_questionMarkRect.contains(x, y)) {
return QUESTION_MARK_BUTTON;
}
- Common::Rect invPrevRect(Common::Point(469, 87), kInventoryArrowWidth, kInventoryArrowHeight);
- if (invPrevRect.contains(x, y)) {
+ if (_invLeft.contains(x, y)) {
return INVENTORY_PREV_BUTTON;
}
- Common::Rect invNextRect(Common::Point(459, 140), kInventoryArrowWidth, kInventoryArrowHeight);
- if (invNextRect.contains(x, y)) {
+ if (_invRight.contains(x, y)) {
return INVENTORY_NEXT_BUTTON;
}
-
+ if( _saveGameRect.contains(x, y)) {
+ return SAVE_GAME_BUTTON;
+ }
+ if( _loadGameRect.contains(x, y)) {
+ return LOAD_GAME_BUTTON;
+ }
+ if( _soundsRect.contains(x, y)) {
+ return SOUNDS_BUTTON;
+ }
+ if( _exitToDosRect.contains(x, y)) {
+ return EXIT_MENU_BUTTON;
+ }
return NO_BUTTON; // Default fallback
}
@@ -222,41 +230,30 @@ void MenuManager::loadMenu() {
g_engine->_res->mergeRleBlocks(&alfred7, kAlternateSettingsMenuOffset, 8, _mainMenu);
}
+ readButton(alfred7, 3193376, _saveButtons, _saveGameRect);
+ readButton(alfred7, alfred7.pos(), _loadButtons, _loadGameRect);
+ readButton(alfred7, alfred7.pos(), _soundsButtons, _soundsRect);
+ readButton(alfred7, kInvLeftArrowOffset, _inventoryLeftArrow, _invLeft);
+ readButton(alfred7, alfred7.pos(), _inventoryRightArrow, _invRight);
+ readButton(alfred7, 3214046, _questionMark, _questionMarkRect);
- // question mark
- byte *questionMarks = new byte[kQuestionMarkStride * 2];
-
- alfred7.seek(3214046, SEEK_SET);
- alfred7.read(questionMarks, kQuestionMarkStride * 2);
-
- _questionMark[0] = new byte[kQuestionMarkStride];
- _questionMark[1] = new byte[kQuestionMarkStride];
- extractSingleFrame(questionMarks, _questionMark[0], 0, kQuestionMarkWidth, kQuestionMarkHeight);
- extractSingleFrame(questionMarks, _questionMark[1], 1, kQuestionMarkWidth, kQuestionMarkHeight);
- delete[] questionMarks;
-
- //Inventory arrows
- byte *arrows = new byte[kInventoryArrowStride * 2];
- alfred7.seek(kInvLeftArrowOffset, SEEK_SET);
- alfred7.read(arrows, kInventoryArrowStride * 2);
- _inventoryLeftArrow[0] = new byte[kInventoryArrowStride];
- _inventoryLeftArrow[1] = new byte[kInventoryArrowStride];
- extractSingleFrame(arrows, _inventoryLeftArrow[0], 0, kInventoryArrowWidth, kInventoryArrowHeight);
- extractSingleFrame(arrows, _inventoryLeftArrow[1], 1, kInventoryArrowWidth, kInventoryArrowHeight);
-
- alfred7.seek(kInvLeftArrowOffset + (kInventoryArrowStride * 2), SEEK_SET);
- alfred7.read(arrows, kInventoryArrowStride * 2);
- _inventoryRightArrow[0] = new byte[kInventoryArrowStride];
- _inventoryRightArrow[1] = new byte[kInventoryArrowStride];
- extractSingleFrame(arrows, _inventoryRightArrow[0], 0, kInventoryArrowWidth, kInventoryArrowHeight);
- extractSingleFrame(arrows, _inventoryRightArrow[1], 1, kInventoryArrowWidth, kInventoryArrowHeight);
+ alfred7.close();
+}
- delete[] arrows;
- alfred7.close();
+void MenuManager::readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect) {
+ alfred7.seek(offset, SEEK_SET);
+ byte *buttonData = new byte[rect.width() * rect.height() * 2];
+ alfred7.read(buttonData, rect.width() * rect.height() * 2);
+ outBuffer[0] = new byte[rect.width() * rect.height()];
+ outBuffer[1] = new byte[rect.width() * rect.height()];
+ extractSingleFrame(buttonData, outBuffer[0], 0, rect.width(), rect.height());
+ extractSingleFrame(buttonData, outBuffer[1], 1 , rect.width(), rect.height());
+ delete[] buttonData;
}
+
void MenuManager::loadMenuTexts() {
Common::File exe;
@@ -289,16 +286,26 @@ void MenuManager::drawButtons() {
if(_events->_leftMouseButton != 0) {
button = isButtonClicked(_events->_mouseX, _events->_mouseY);
}
- //Question mark
byte *buf = button == QUESTION_MARK_BUTTON ? _questionMark[1] : _questionMark[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, kQuestionMarkPosX, kQuestionMarkPosY, kQuestionMarkWidth, kQuestionMarkHeight, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _questionMarkRect.left, _questionMarkRect.top, _questionMarkRect.width(), _questionMarkRect.height(), 255);
buf = button == INVENTORY_PREV_BUTTON ? _inventoryLeftArrow[1] : _inventoryLeftArrow[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, 469, 87, kInventoryArrowWidth, kInventoryArrowHeight, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _invLeft.left, _invLeft.top, _invLeft.width(), _invLeft.height(), 255);
buf = button == INVENTORY_NEXT_BUTTON ? _inventoryRightArrow[1] : _inventoryRightArrow[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, 463, 133, kInventoryArrowWidth, kInventoryArrowHeight, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _invRight.left, _invRight.top, _invRight.width(), _invRight.height(), 255);
+
+ buf = button == SAVE_GAME_BUTTON ? _saveButtons[1] : _saveButtons[0];
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _saveGameRect.left, _saveGameRect.top, _saveGameRect.width(), _saveGameRect.height(), 255);
+
+ buf = button == LOAD_GAME_BUTTON ? _loadButtons[1] : _loadButtons[0];
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _loadGameRect.left, _loadGameRect.top, _loadGameRect.width(), _loadGameRect.height(), 255);
+
+ buf = button == LOAD_GAME_BUTTON ? _loadButtons[1] : _loadButtons[0];
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _loadGameRect.left, _loadGameRect.top, _loadGameRect.width(), _loadGameRect.height(), 255);
+ buf = button == SOUNDS_BUTTON ? _soundsButtons[1] : _soundsButtons[0];
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _soundsRect.left, _soundsRect.top, _soundsRect.width(), _soundsRect.height(), 255);
}
Pelrock::MenuManager::~MenuManager() {
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index edcd02ee101..099b8897018 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -32,16 +32,6 @@ namespace Pelrock {
const int kQuestionMarkOffset = 3214046;
const int kInvLeftArrowOffset = 3215906;
-const int kQuestionMarkPosX = 217;
-const int kQuestionMarkPosY = 293;
-const int kQuestionMarkWidth = 31;
-const int kQuestionMarkHeight = 30;
-const int kQuestionMarkStride = 30 * 31;
-
-const int kInventoryArrowWidth = 26;
-const int kInventoryArrowHeight = 37;
-const int kInventoryArrowStride = kInventoryArrowWidth * kInventoryArrowHeight;
-
enum MenuButton {
QUESTION_MARK_BUTTON,
INVENTORY_PREV_BUTTON,
@@ -69,16 +59,42 @@ private:
void tearDown();
void drawButtons();
void drawColoredText(Graphics::ManagedSurface *surface, const Common::String &text, int x, int y, int w, Graphics::Font *font);
+ void readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect);
MenuButton isButtonClicked(int x, int y);
Graphics::Screen *_screen = nullptr;
PelrockEventManager *_events = nullptr;
ResourceManager *_res = nullptr;
byte *_mainMenu = nullptr;
byte *_compositeBuffer = nullptr;
+
+ Common::Rect _saveGameRect = Common::Rect(Common::Point(130, 184), 81, 34);
+ byte *_saveButtons[2] = { nullptr };
+
+ Common::Rect _loadGameRect = Common::Rect(Common::Point(130, 221), 80, 31);
+ byte *_loadButtons[2] = { nullptr };
+
+ Common::Rect _soundsRect = Common::Rect(Common::Point(137, 260), 77, 30);
+ byte *_soundsButtons[2] = { nullptr };
+
+ Common::Rect _exitToDosRect = Common::Rect(Common::Point(220, 270), 81, 30);
+ byte *_exitToDosButtons[2] = { nullptr };
+
+
+ Common::Rect _invLeft = Common::Rect(Common::Point(469, 87), 26, 37);
byte *_inventoryLeftArrow[2] = { nullptr };
+
+ Common::Rect _invRight = Common::Rect(Common::Point(463, 130), 26, 37);
byte *_inventoryRightArrow[2] = { nullptr };
- byte *_savesArrows[2] = { nullptr };
+
+ Common::Rect _savesUp = Common::Rect(Common::Point(320, 150), 16, 16);
+ byte *_savesUpArrows[2] = { nullptr };
+
+ Common::Rect _savesDown = Common::Rect(Common::Point(385, 150), 16, 16);
+ byte *_savesDownArrows[2] = { nullptr };
+
+ Common::Rect _questionMarkRect = Common::Rect(Common::Point(217, 293), 31, 30);
byte *_questionMark[2] = {nullptr};
+
Common::Array<Common::StringArray> _menuTexts;
// Temporary
int _selectedInvIndex = 0;
Commit: f5a3133cb41bd1320453a1dfbf77176506b47879
https://github.com/scummvm/scummvm/commit/f5a3133cb41bd1320453a1dfbf77176506b47879
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:36+02:00
Commit Message:
PELROCK: Properly place all menu buttons
Changed paths:
engines/pelrock/events.cpp
engines/pelrock/events.h
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
index 766dfccc1f8..37f46927342 100644
--- a/engines/pelrock/events.cpp
+++ b/engines/pelrock/events.cpp
@@ -48,10 +48,11 @@ void PelrockEventManager::pollEvent() {
// case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
// break;
- // case Common::EVENT_KEYDOWN:
+ case Common::EVENT_KEYDOWN:
// changeGameSpeed(_event);
- // _keyPressed = true;
- // _lastKeyEvent = _event;
+ // _keyPressed = true;
+ _lastKeyEvent = _event.kbd.keycode;
+ break;
// return;
// case Common::EVENT_KEYUP:
// return;
diff --git a/engines/pelrock/events.h b/engines/pelrock/events.h
index f39ab56cfb5..defe1392f9c 100644
--- a/engines/pelrock/events.h
+++ b/engines/pelrock/events.h
@@ -42,7 +42,7 @@ public:
bool _popupSelectionMode = false;
bool _leftMouseButton = 0;
bool _rightMouseButton = 0;
- Common::Event _lastKeyEvent;
+ Common::KeyCode _lastKeyEvent = Common::KEYCODE_INVALID;
PelrockEventManager();
void pollEvent();
void waitForKey();
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 6d669408866..a04c840df59 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -70,20 +70,25 @@ MenuButton MenuManager::isButtonClicked(int x, int y) {
if (_invRight.contains(x, y)) {
return INVENTORY_NEXT_BUTTON;
}
- if( _saveGameRect.contains(x, y)) {
+ if (_saveGameRect.contains(x, y)) {
return SAVE_GAME_BUTTON;
}
- if( _loadGameRect.contains(x, y)) {
+ if (_loadGameRect.contains(x, y)) {
return LOAD_GAME_BUTTON;
}
- if( _soundsRect.contains(x, y)) {
+ if (_soundsRect.contains(x, y)) {
return SOUNDS_BUTTON;
}
- if( _exitToDosRect.contains(x, y)) {
+ if (_exitToDosRect.contains(x, y)) {
return EXIT_MENU_BUTTON;
}
+ if (_savesUp.contains(x, y)) {
+ return SAVEGAME_PREV_BUTTON;
+ }
+ if (_savesDown.contains(x, y)) {
+ return SAVEGAME_NEXT_BUTTON;
+ }
return NO_BUTTON; // Default fallback
-
}
void MenuManager::checkMouseClick(int x, int y) {
@@ -119,11 +124,8 @@ void MenuManager::checkMouseClick(int x, int y) {
default:
break;
}
-
}
-
-
void MenuManager::menuLoop() {
_events->pollEvent();
@@ -135,10 +137,20 @@ void MenuManager::menuLoop() {
g_engine->stateGame = GAME;
_events->_rightMouseClicked = false;
tearDown();
+ } else {
+ if (_events->_lastKeyEvent == Common::KEYCODE_b) {
+ // g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+ // g_engine->stateGame = GAME;
+ showButtons = !showButtons;
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ // tearDown();
+ }
}
memcpy(_compositeBuffer, _mainMenu, 640 * 400);
- drawButtons();
+ // memset(_compositeBuffer, 0, 640 * 400);
+ if (showButtons)
+ drawButtons();
for (int i = 0; i < 4; i++) {
int itemIndex = _curInventoryPage * 4 + i;
@@ -233,15 +245,16 @@ void MenuManager::loadMenu() {
readButton(alfred7, 3193376, _saveButtons, _saveGameRect);
readButton(alfred7, alfred7.pos(), _loadButtons, _loadGameRect);
readButton(alfred7, alfred7.pos(), _soundsButtons, _soundsRect);
+ readButton(alfred7, alfred7.pos(), _exitToDosButtons, _exitToDosRect);
readButton(alfred7, kInvLeftArrowOffset, _inventoryLeftArrow, _invLeft);
readButton(alfred7, alfred7.pos(), _inventoryRightArrow, _invRight);
+ readButton(alfred7, alfred7.pos(), _savesUpArrows, _savesUp);
+ readButton(alfred7, alfred7.pos(), _savesDownArrows, _savesDown);
readButton(alfred7, 3214046, _questionMark, _questionMarkRect);
alfred7.close();
}
-
-
void MenuManager::readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect) {
alfred7.seek(offset, SEEK_SET);
byte *buttonData = new byte[rect.width() * rect.height() * 2];
@@ -249,11 +262,10 @@ void MenuManager::readButton(Common::File &alfred7, uint32 offset, byte *outBuff
outBuffer[0] = new byte[rect.width() * rect.height()];
outBuffer[1] = new byte[rect.width() * rect.height()];
extractSingleFrame(buttonData, outBuffer[0], 0, rect.width(), rect.height());
- extractSingleFrame(buttonData, outBuffer[1], 1 , rect.width(), rect.height());
+ extractSingleFrame(buttonData, outBuffer[1], 1, rect.width(), rect.height());
delete[] buttonData;
}
-
void MenuManager::loadMenuTexts() {
Common::File exe;
@@ -283,29 +295,38 @@ void MenuManager::tearDown() {
void MenuManager::drawButtons() {
MenuButton button = NO_BUTTON;
- if(_events->_leftMouseButton != 0) {
+ if (_events->_leftMouseButton != 0) {
button = isButtonClicked(_events->_mouseX, _events->_mouseY);
}
byte *buf = button == QUESTION_MARK_BUTTON ? _questionMark[1] : _questionMark[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _questionMarkRect.left, _questionMarkRect.top, _questionMarkRect.width(), _questionMarkRect.height(), 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _questionMarkRect.left, _questionMarkRect.top, _questionMarkRect.width(), _questionMarkRect.height(), kTransparentColor);
buf = button == INVENTORY_PREV_BUTTON ? _inventoryLeftArrow[1] : _inventoryLeftArrow[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _invLeft.left, _invLeft.top, _invLeft.width(), _invLeft.height(), 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _invLeft.left, _invLeft.top, _invLeft.width(), _invLeft.height(), kTransparentColor);
buf = button == INVENTORY_NEXT_BUTTON ? _inventoryRightArrow[1] : _inventoryRightArrow[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _invRight.left, _invRight.top, _invRight.width(), _invRight.height(), 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _invRight.left, _invRight.top, _invRight.width(), _invRight.height(), kTransparentColor);
buf = button == SAVE_GAME_BUTTON ? _saveButtons[1] : _saveButtons[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _saveGameRect.left, _saveGameRect.top, _saveGameRect.width(), _saveGameRect.height(), 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _saveGameRect.left, _saveGameRect.top, _saveGameRect.width(), _saveGameRect.height(), kTransparentColor);
buf = button == LOAD_GAME_BUTTON ? _loadButtons[1] : _loadButtons[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _loadGameRect.left, _loadGameRect.top, _loadGameRect.width(), _loadGameRect.height(), 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _loadGameRect.left, _loadGameRect.top, _loadGameRect.width(), _loadGameRect.height(), kTransparentColor);
buf = button == LOAD_GAME_BUTTON ? _loadButtons[1] : _loadButtons[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _loadGameRect.left, _loadGameRect.top, _loadGameRect.width(), _loadGameRect.height(), 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _loadGameRect.left, _loadGameRect.top, _loadGameRect.width(), _loadGameRect.height(), kTransparentColor);
buf = button == SOUNDS_BUTTON ? _soundsButtons[1] : _soundsButtons[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _soundsRect.left, _soundsRect.top, _soundsRect.width(), _soundsRect.height(), 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _soundsRect.left, _soundsRect.top, _soundsRect.width(), _soundsRect.height(), kTransparentColor);
+
+ buf = button == EXIT_MENU_BUTTON ? _exitToDosButtons[1] : _exitToDosButtons[0];
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _exitToDosRect.left, _exitToDosRect.top, _exitToDosRect.width(), _exitToDosRect.height(), kTransparentColor);
+
+ buf = button == SAVEGAME_PREV_BUTTON ? _savesUpArrows[1] : _savesUpArrows[0];
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _savesUp.left, _savesUp.top, _savesUp.width(), _savesUp.height(), kTransparentColor);
+
+ buf = button == SAVEGAME_NEXT_BUTTON ? _savesDownArrows[1] : _savesDownArrows[0];
+ drawSpriteToBuffer(_compositeBuffer, 640, buf, _savesDown.left, _savesDown.top, _savesDown.width(), _savesDown.height(), kTransparentColor);
}
Pelrock::MenuManager::~MenuManager() {
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 099b8897018..9d1fae248dd 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -31,6 +31,7 @@ namespace Pelrock {
const int kQuestionMarkOffset = 3214046;
const int kInvLeftArrowOffset = 3215906;
+const int kTransparentColor = 15;
enum MenuButton {
QUESTION_MARK_BUTTON,
@@ -67,30 +68,29 @@ private:
byte *_mainMenu = nullptr;
byte *_compositeBuffer = nullptr;
- Common::Rect _saveGameRect = Common::Rect(Common::Point(130, 184), 81, 34);
- byte *_saveButtons[2] = { nullptr };
+ Common::Rect _saveGameRect = Common::Rect(Common::Point(132, 186), 81, 34);
+ byte *_saveButtons[2] = {nullptr};
- Common::Rect _loadGameRect = Common::Rect(Common::Point(130, 221), 80, 31);
- byte *_loadButtons[2] = { nullptr };
+ Common::Rect _loadGameRect = Common::Rect(Common::Point(133, 222), 80, 33);
+ byte *_loadButtons[2] = {nullptr};
- Common::Rect _soundsRect = Common::Rect(Common::Point(137, 260), 77, 30);
- byte *_soundsButtons[2] = { nullptr };
+ Common::Rect _soundsRect = Common::Rect(Common::Point(134, 258), 77, 33);
+ byte *_soundsButtons[2] = {nullptr};
- Common::Rect _exitToDosRect = Common::Rect(Common::Point(220, 270), 81, 30);
- byte *_exitToDosButtons[2] = { nullptr };
+ Common::Rect _exitToDosRect = Common::Rect(Common::Point(134, 293), 75, 30);
+ byte *_exitToDosButtons[2] = {nullptr};
+ Common::Rect _invLeft = Common::Rect(Common::Point(469, 88), 26, 37);
+ byte *_inventoryLeftArrow[2] = {nullptr};
- Common::Rect _invLeft = Common::Rect(Common::Point(469, 87), 26, 37);
- byte *_inventoryLeftArrow[2] = { nullptr };
+ Common::Rect _invRight = Common::Rect(Common::Point(463, 132), 26, 37);
+ byte *_inventoryRightArrow[2] = {nullptr};
- Common::Rect _invRight = Common::Rect(Common::Point(463, 130), 26, 37);
- byte *_inventoryRightArrow[2] = { nullptr };
+ Common::Rect _savesUp = Common::Rect(Common::Point(457, 189), 26, 24);
+ byte *_savesUpArrows[2] = {nullptr};
- Common::Rect _savesUp = Common::Rect(Common::Point(320, 150), 16, 16);
- byte *_savesUpArrows[2] = { nullptr };
-
- Common::Rect _savesDown = Common::Rect(Common::Point(385, 150), 16, 16);
- byte *_savesDownArrows[2] = { nullptr };
+ Common::Rect _savesDown = Common::Rect(Common::Point(450, 278), 26, 24);
+ byte *_savesDownArrows[2] = {nullptr};
Common::Rect _questionMarkRect = Common::Rect(Common::Point(217, 293), 31, 30);
byte *_questionMark[2] = {nullptr};
@@ -101,6 +101,8 @@ private:
int _curInventoryPage = 0;
Common::StringArray _menuText;
Common::Array<Common::StringArray> _inventoryDescriptions;
+
+ bool showButtons = true;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 5e491352366..563789e4f89 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -105,6 +105,7 @@ Common::Error PelrockEngine::run() {
if (shouldPlayIntro == false) {
stateGame = GAME;
+ // stateGame = SETTINGS;
} else {
stateGame = INTRO;
_videoManager->playIntro();
Commit: ce313b205643b446101e0da3362c2a59ae2e2ac7
https://github.com/scummvm/scummvm/commit/ce313b205643b446101e0da3362c2a59ae2e2ac7
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:36+02:00
Commit Message:
PELROCK: Plays entire intro video
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index a04c840df59..6d1aa8f7b3e 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -99,6 +99,7 @@ void MenuManager::checkMouseClick(int x, int y) {
y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
_selectedInvIndex = g_engine->_inventoryItems[_curInventoryPage * 4 + i];
_menuText = _inventoryDescriptions[_selectedInvIndex];
+ g_engine->_selectedInventoryItem = _selectedInvIndex;
selectedItem = true;
return;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 563789e4f89..ec35dfc84d2 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -54,8 +54,10 @@ PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) :
}
PelrockEngine::~PelrockEngine() {
- delete[] _compositeBuffer;
- delete[] _currentBackground;
+ if(_compositeBuffer)
+ delete[] _compositeBuffer;
+ if(_currentBackground)
+ delete[] _currentBackground;
delete _largeFont;
delete _smallFont;
delete _doubleSmallFont;
@@ -85,13 +87,13 @@ Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
initGraphics(640, 400);
_screen = new Graphics::Screen();
- _videoManager = new VideoManager(_screen, _events);
_graphics = new GraphicsManager();
_room = new RoomManager();
_res = new ResourceManager();
_sound = new SoundManager(_mixer);
_dialog = new DialogManager(_screen, _events, _graphics);
_menu = new MenuManager(_screen, _events, _res);
+ _videoManager = new VideoManager(_screen, _events, _chrono);
// Set the engine's debugger console
setDebugger(new PelrockConsole(this));
@@ -111,7 +113,8 @@ Common::Error PelrockEngine::run() {
_videoManager->playIntro();
stateGame = GAME;
}
- init();
+ if(!shouldQuit())
+ init();
while (!shouldQuit()) {
@@ -534,7 +537,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.idleFrameCounter = 0;
alfredState.setState(ALFRED_COMB);
}
- debug("Alfred state: %d, pos (%d, %d) curFrame %d", alfredState.animState, alfredState.x, alfredState.y, alfredState.curFrame);
switch (alfredState.animState) {
case ALFRED_WALKING: {
MovementStep step = _currentContext.movementBuffer[_currentStep];
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 77ecb0cb53f..63c46b11290 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -141,8 +141,7 @@ private:
bool showShadows = false;
- // JAVA
- bool shouldPlayIntro = false;
+ bool shouldPlayIntro = true;
bool gameInitialized = false;
bool screenReady = false;
@@ -162,7 +161,7 @@ public:
ResourceManager *_res = nullptr;
RoomManager *_room = nullptr;
AlfredState alfredState;
- byte *_compositeBuffer; // Working composition buffer
+ byte *_compositeBuffer = nullptr; // Working composition buffer
GameState stateGame = INTRO;
SmallFont *_smallFont = nullptr;
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 03b78936d1b..3bb59706f49 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -21,6 +21,7 @@
#include "common/file.h"
#include "graphics/screen.h"
+#include "graphics/paletteman.h"
#include "pelrock/chrono.h"
#include "pelrock/pelrock.h"
@@ -29,7 +30,7 @@
namespace Pelrock {
-VideoManager::VideoManager(Graphics::Screen *screen, PelrockEventManager *events) : _screen(screen), _events(events) {
+VideoManager::VideoManager(Graphics::Screen *screen, PelrockEventManager *events, ChronoManager *chrono) : _screen(screen), _events(events), _chrono(chrono) {
}
VideoManager::~VideoManager() {
@@ -42,63 +43,46 @@ void VideoManager::playIntro() {
return;
}
loadPalette(videoFile);
- videoFile.seek(frame0offset, SEEK_SET);
- size_t firstChunkSize = chunkSize * 13;
- byte *chunk0 = new byte[firstChunkSize];
- videoFile.read(chunk0, firstChunkSize);
- byte *background = decodeCopyBlock(chunk0, 0);
-
- for (int i = 0; i < 640; i++) {
- for (int j = 0; j < 400; j++) {
- _screen->setPixel(i, j, background[j * 640 + i]);
- }
- }
- _screen->markAllDirty();
- _screen->update();
- delete[] chunk0;
- _events->waitForKey();
-
- size_t chunk1Size = chunkSize * 6;
- byte chunk1_data[chunk1Size];
- videoFile.seek(frame1offset, SEEK_SET);
- videoFile.read(chunk1_data, chunk1Size);
-
- byte *delta1 = decodeRLE(chunk1_data, chunk1Size, 0x0D);
- for (int j = 0; j < 256000; j++) {
- background[j] ^= delta1[j];
- }
- delete[] delta1;
- for (int x = 0; x < 640; x++) {
- for (int y = 0; y < 400; y++) {
- _screen->setPixel(x, y, background[y * 640 + x]);
- }
- }
- _screen->markAllDirty();
- _screen->update();
- _events->waitForKey();
-
- for (size_t i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
- byte *chunk = new byte[chunkSize];
- videoFile.seek(offsets[i], SEEK_SET);
- videoFile.read(chunk, chunkSize);
- byte *delta = decodeCopyBlock(chunk, 0);
- for (int j = 0; j < 256000; j++) {
- background[j] ^= delta[j];
- }
- delete[] delta;
- for (int x = 0; x < 640; x++) {
- for (int y = 0; y < 400; y++) {
- _screen->setPixel(x, y, background[y * 640 + x]);
+ videoFile.seek(0, SEEK_SET);
+
+ memset(_currentKeyFrame, 0, 256000);
+ for (int sequence = 0; sequence < 1; sequence++) {
+ int frameCounter = 0;
+ int chunksInBuffer = 0;
+ bool videoExitFlag = false;
+
+ while (!videoExitFlag && !g_engine->shouldQuit()) {
+ _chrono->updateChrono();
+ _events->pollEvent();
+
+ if(_chrono->_gameTick) {
+ ChunkHeader chunk;
+ readChunk(videoFile, chunk);
+
+ switch (chunk.chunkType) {
+ case 1:
+ case 2:
+ processFrame(chunk, frameCounter++);
+ break;
+ case 3:
+ videoExitFlag = true;
+ break;
+ case 4:
+ loadPalette(chunk);
+ break;
+ default:
+ debug("Unknown chunk type %d encountered", chunk.chunkType);
+ break;
+ }
+ presentFrame();
}
+ g_system->delayMillis(10);
}
- delete[] chunk;
- _screen->markAllDirty();
- _screen->update();
- _events->waitForKey();
}
- _events->waitForKey();
+
videoFile.close();
}
+
void VideoManager::loadPalette(Common::SeekableReadStream &stream) {
byte paletteData[768];
@@ -113,11 +97,21 @@ void VideoManager::loadPalette(Common::SeekableReadStream &stream) {
_screen->setPalette(palette);
}
+void VideoManager::loadPalette(ChunkHeader &chunk) {
+ byte palette[768];
+ for (int i = 0; i < 256; i++) {
+ palette[i * 3 + 0] = chunk.data[i * 3 + 0] << 2;
+ palette[i * 3 + 1] = chunk.data[i * 3 + 1] << 2;
+ palette[i * 3 + 2] = chunk.data[i * 3 + 2] << 2;
+ }
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+}
+
byte *VideoManager::decodeCopyBlock(byte *data, uint32 offset) {
byte *buf = new byte[256000];
memset(buf, 0, 256000);
- uint32 pos = offset + 0x0D;
+ uint32 pos = offset + 0x04;
// frames are encoded so that each block copy has a 5-byte header
// the first 3 bytes are the offset within the screen to which to
// copy the bytes. The 5th byte is the length of the block to copy.
@@ -139,7 +133,7 @@ byte *VideoManager::decodeCopyBlock(byte *data, uint32 offset) {
pos += length;
}
- return buf; // Placeholder
+ return buf;
}
byte *VideoManager::decodeRLE(byte *data, size_t size, uint32 offset) {
@@ -169,4 +163,42 @@ byte *VideoManager::decodeRLE(byte *data, size_t size, uint32 offset) {
}
return buf;
}
+
+void VideoManager::readChunk(Common::SeekableReadStream &stream, ChunkHeader &chunk) {
+ chunk.blockCount = stream.readUint32LE();
+ chunk.dataOffset = stream.readUint32LE();
+ chunk.chunkType = stream.readByte();
+
+ chunk.data = new byte[chunk.blockCount * chunkSize + 9];
+ stream.read(chunk.data, chunk.blockCount * chunkSize - 9);
+}
+
+void VideoManager::processFrame(ChunkHeader &chunk, const int frameCount) {
+ byte *frameData = nullptr;
+ if(chunk.chunkType == 1) {
+ // Video data chunk
+ frameData = decodeRLE(chunk.data, chunk.blockCount * chunkSize, 0x04);
+ } else if (chunk.chunkType == 2) {
+ // Block copy chunk
+ frameData = decodeCopyBlock(chunk.data, 0);
+ }
+
+ if(frameCount == 0) {
+ memcpy(_currentKeyFrame, frameData, 256000);
+ } else {
+ // Subsequent frames, XOR with previous frame
+ for (int i = 0; i < 256000; i++) {
+ _currentKeyFrame[i] ^= frameData[i];
+ }
+ }
+ delete[] frameData;
+
+}
+
+void VideoManager::presentFrame() {
+ memcpy(_screen->getPixels(), _currentKeyFrame, 640 * 400);
+ _screen->markAllDirty();
+ _screen->update();
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index 405c52b06b2..82354cbb833 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -26,31 +26,35 @@
namespace Pelrock {
-static const uint32 frame0offset = 0x5000;
-static const uint32 frame1offset = 0x46000;
+struct ChunkHeader {
+ uint32_t blockCount; // +0x00: Number of 0x5000-byte blocks
+ uint32_t dataOffset; // +0x04: Varies by chunk type
+ uint8_t chunkType; // +0x08: 1=RLE, 2=BlockCopy, 3=End, 4=Palette, 6=Special
+ // +0x0D: Frame data begins
+ byte *data;
+};
+
static const uint32 chunkSize = 0x5000;
-static const uint32 offsets[] = {
- 0x64000,
- 0x69000,
- 0x6E000,
- 0x73000,
- 0x78000,
- 0x7D000,
- 0x82000,
- 0x87000};
class VideoManager {
public:
- VideoManager(Graphics::Screen *screen, PelrockEventManager *events);
+ VideoManager(Graphics::Screen *screen, PelrockEventManager *events, ChronoManager *chrono);
~VideoManager();
void playIntro();
private:
Graphics::Screen *_screen;
PelrockEventManager *_events;
+ ChronoManager *_chrono;
void loadPalette(Common::SeekableReadStream &stream);
+ void loadPalette(ChunkHeader &chunk);
byte *decodeCopyBlock(byte *data, uint32 offset);
byte *decodeRLE(byte *data, size_t size, uint32 offset);
+ void readChunk(Common::SeekableReadStream &stream, ChunkHeader &chunk);
+ void processFrame(ChunkHeader &chunk, const int frameCount);
+ void presentFrame();
+ byte *_currentKeyFrame = new byte[640 * 400];
+ Common::Array<ChunkHeader> _chunkBuffer;
};
} // End of namespace Pelrock
Commit: 33afb68090be03f4ab70dfca1d8c79424e56e25c
https://github.com/scummvm/scummvm/commit/33afb68090be03f4ab70dfca1d8c79424e56e25c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:36+02:00
Commit Message:
PELROCK: Fix missing alfred frame on queued actions
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index ec35dfc84d2..0391b38a0c9 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -507,6 +507,9 @@ void PelrockEngine::doAction(VerbIcon action, HotSpot *hotspot) {
pickUpAndDisable(hotspot);
executeAction(PICKUP, hotspot);
break;
+ case OPEN:
+ case CLOSE:
+ alfredState.setState(ALFRED_INTERACTING);
default:
executeAction(action, hotspot);
break;
@@ -572,8 +575,10 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
alfredState.setState(ALFRED_IDLE);
+
if (_currentHotspot != nullptr)
alfredState.direction = calculateAlfredsDirection(_currentHotspot);
+ drawAlfred(_res->alfredIdle[alfredState.direction]);
if (_queuedAction.isQueued) {
doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 63c46b11290..691b6808d08 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -141,7 +141,7 @@ private:
bool showShadows = false;
- bool shouldPlayIntro = true;
+ bool shouldPlayIntro = false;
bool gameInitialized = false;
bool screenReady = false;
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 3bb59706f49..2eac7bc4f4a 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -31,9 +31,11 @@
namespace Pelrock {
VideoManager::VideoManager(Graphics::Screen *screen, PelrockEventManager *events, ChronoManager *chrono) : _screen(screen), _events(events), _chrono(chrono) {
+ _screenSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
}
VideoManager::~VideoManager() {
+ _screenSurface.free();
}
void VideoManager::playIntro() {
@@ -42,10 +44,9 @@ void VideoManager::playIntro() {
error("Could not open ESCENAX.SSN");
return;
}
- loadPalette(videoFile);
videoFile.seek(0, SEEK_SET);
- memset(_currentKeyFrame, 0, 256000);
+ _screenSurface.fillRect(Common::Rect(0, 0, 640, 400), 0);
for (int sequence = 0; sequence < 1; sequence++) {
int frameCounter = 0;
int chunksInBuffer = 0;
@@ -83,20 +84,6 @@ void VideoManager::playIntro() {
videoFile.close();
}
-void VideoManager::loadPalette(Common::SeekableReadStream &stream) {
-
- byte paletteData[768];
- stream.seek(0x0009, SEEK_SET);
- stream.read(paletteData, 768);
- byte palette[768];
- for (int i = 0; i < 256; i++) {
- palette[i * 3 + 0] = paletteData[i * 3 + 0] << 2;
- palette[i * 3 + 1] = paletteData[i * 3 + 1] << 2;
- palette[i * 3 + 2] = paletteData[i * 3 + 2] << 2;
- }
- _screen->setPalette(palette);
-}
-
void VideoManager::loadPalette(ChunkHeader &chunk) {
byte palette[768];
for (int i = 0; i < 256; i++) {
@@ -183,12 +170,13 @@ void VideoManager::processFrame(ChunkHeader &chunk, const int frameCount) {
frameData = decodeCopyBlock(chunk.data, 0);
}
+ byte *surfacePixels = (byte *)_screenSurface.getPixels();
if(frameCount == 0) {
- memcpy(_currentKeyFrame, frameData, 256000);
+ memcpy(surfacePixels, frameData, 256000);
} else {
// Subsequent frames, XOR with previous frame
for (int i = 0; i < 256000; i++) {
- _currentKeyFrame[i] ^= frameData[i];
+ surfacePixels[i] ^= frameData[i];
}
}
delete[] frameData;
@@ -196,7 +184,7 @@ void VideoManager::processFrame(ChunkHeader &chunk, const int frameCount) {
}
void VideoManager::presentFrame() {
- memcpy(_screen->getPixels(), _currentKeyFrame, 640 * 400);
+ _screen->blitFrom(_screenSurface);
_screen->markAllDirty();
_screen->update();
}
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index 82354cbb833..f46c8068229 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -22,6 +22,8 @@
#ifndef PELROCK_VIDEO_H
#define PELROCK_VIDEO_H
+#include "graphics/surface.h"
+
#include "pelrock/events.h"
namespace Pelrock {
@@ -46,14 +48,13 @@ private:
Graphics::Screen *_screen;
PelrockEventManager *_events;
ChronoManager *_chrono;
- void loadPalette(Common::SeekableReadStream &stream);
void loadPalette(ChunkHeader &chunk);
byte *decodeCopyBlock(byte *data, uint32 offset);
byte *decodeRLE(byte *data, size_t size, uint32 offset);
void readChunk(Common::SeekableReadStream &stream, ChunkHeader &chunk);
void processFrame(ChunkHeader &chunk, const int frameCount);
void presentFrame();
- byte *_currentKeyFrame = new byte[640 * 400];
+ Graphics::Surface _screenSurface = Graphics::Surface();
Common::Array<ChunkHeader> _chunkBuffer;
};
Commit: 4f3db805075f3acd338c02ccef054975533f27e4
https://github.com/scummvm/scummvm/commit/4f3db805075f3acd338c02ccef054975533f27e4
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:36+02:00
Commit Message:
PELROCK: Switch to using AudioCDManager
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 0391b38a0c9..fda6a07e787 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -32,6 +32,8 @@
#include "image/pcx.h"
#include "image/png.h"
+#include "backends/audiocd/audiocd.h"
+
#include "pelrock.h"
#include "pelrock/actions.h"
#include "pelrock/console.h"
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 1c08df8579e..47c82d82cb8 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -20,28 +20,28 @@
*/
#include "audio/audiostream.h"
-#include "audio/decoders/mp3.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/wave.h"
-
#include "audio/mixer.h"
+
#include "common/debug.h"
#include "common/endian.h"
#include "common/file.h"
#include "common/memstream.h"
#include "common/scummsys.h"
+#include "backends/audiocd/audiocd.h"
+
#include "pelrock/pelrock.h"
#include "pelrock/sound.h"
#include "sound.h"
namespace Pelrock {
-
-
SoundManager::SoundManager(Audio::Mixer *mixer)
: _mixer(mixer), _currentVolume(255), _musicFile(nullptr) {
// TODO: Initialize sound manager
+ g_system->getAudioCDManager()->open();
}
SoundManager::~SoundManager() {
@@ -184,42 +184,21 @@ bool SoundManager::isPlaying(int channel) const {
}
void SoundManager::stopMusic() {
- if (_isMusicPlaying) {
- debug("Stopping music");
- _mixer->stopHandle(_musicHandle);
- _isMusicPlaying = false;
- }
+ g_system->getAudioCDManager()->stop();
+}
+
+bool SoundManager::isMusicPlaying() {
+ return g_system->getAudioCDManager()->isPlaying();
}
void SoundManager::playMusicTrack(int trackNumber) {
-// if (_currentMusicTrack == trackNumber && _isMusicPlaying) {
-// // Already playing this track
-// return;
-// }
-// _currentMusicTrack = trackNumber;
-// stopMusic();
-// // Open the file
-// _musicFile = new Common::File();
-// Common::String filename = Common::String::format("music/track%d.mp3", trackNumber);
-
-// if (!_musicFile->open(Common::Path(filename))) {
-// delete _musicFile;
-// _musicFile = nullptr;
-// return;
-// }
-// #ifdef USE_MAD
-// Audio::SeekableAudioStream *stream = Audio::makeMP3Stream(_musicFile, DisposeAfterUse::YES);
-// if (!stream) {
-// _musicFile->close();
-// delete _musicFile;
-// _musicFile = nullptr;
-// return;
-// }
-// Audio::AudioStream *loopStream = Audio::makeLoopingAudioStream(stream, 0);
-// _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, loopStream, -1, _currentVolume);
-// _isMusicPlaying = true;
-// _musicFile = nullptr;
-// #endif
+ if (_currentMusicTrack == trackNumber && isMusicPlaying()) {
+ // Already playing this track
+ return;
+ }
+ _currentMusicTrack = trackNumber;
+ g_system->getAudioCDManager()->stop();
+ g_system->getAudioCDManager()->play(trackNumber, -1, 0, 0);
}
void SoundManager::loadSoundIndex() {
@@ -255,15 +234,14 @@ int RANDOM_THRESHOLD = 0x4000;
int SoundManager::tick(uint32 frameCount) {
-
uint16 rand1 = _rng.nextRandom();
// uint32 random = g_engine->getRandomNumber(1);
- if(rand1 <= RANDOM_THRESHOLD){
+ if (rand1 <= RANDOM_THRESHOLD) {
// debug("No SFX this tick due to 50% random");
return -1;
}
- if((frameCount & COUNTER_MASK) != COUNTER_MASK){
+ if ((frameCount & COUNTER_MASK) != COUNTER_MASK) {
// debug("No SFX this tick due to counter mask (counter = %d)", soundFrameCounter);
return -1;
}
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index e354a8d452e..d47d39559a8 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -191,6 +191,7 @@ public:
void stopAllSounds();
void stopSound(int channel);
void stopMusic();
+ bool isMusicPlaying();
void setVolume(int volume);
bool isPlaying() const;
bool isPlaying(int channel) const;
Commit: 62b56b6c36b87b6cd9ce570024327827c35b931e
https://github.com/scummvm/scummvm/commit/62b56b6c36b87b6cd9ce570024327827c35b931e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:37+02:00
Commit Message:
PELROCK: Renders subtitles on intro video
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index fda6a07e787..5e3b6e3391d 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -95,7 +95,14 @@ Common::Error PelrockEngine::run() {
_sound = new SoundManager(_mixer);
_dialog = new DialogManager(_screen, _events, _graphics);
_menu = new MenuManager(_screen, _events, _res);
- _videoManager = new VideoManager(_screen, _events, _chrono);
+ _smallFont = new SmallFont();
+ _smallFont->load("ALFRED.4");
+ _largeFont = new LargeFont();
+ _largeFont->load("ALFRED.7");
+ _doubleSmallFont = new DoubleSmallFont();
+ _doubleSmallFont->load("ALFRED.4");
+ _videoManager = new VideoManager(_screen, _events, _chrono, _largeFont);
+
// Set the engine's debugger console
setDebugger(new PelrockConsole(this));
@@ -147,13 +154,6 @@ void PelrockEngine::init() {
_compositeBuffer = new byte[640 * 400];
_currentBackground = new byte[640 * 400];
- _smallFont = new SmallFont();
- _smallFont->load("ALFRED.4");
- _largeFont = new LargeFont();
- _largeFont->load("ALFRED.7");
- _doubleSmallFont = new DoubleSmallFont();
- _doubleSmallFont->load("ALFRED.4");
-
changeCursor(DEFAULT);
CursorMan.showMouse(true);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 691b6808d08..63c46b11290 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -141,7 +141,7 @@ private:
bool showShadows = false;
- bool shouldPlayIntro = false;
+ bool shouldPlayIntro = true;
bool gameInitialized = false;
bool screenReady = false;
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 2eac7bc4f4a..f25a3e71820 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -20,8 +20,8 @@
*/
#include "common/file.h"
-#include "graphics/screen.h"
#include "graphics/paletteman.h"
+#include "graphics/screen.h"
#include "pelrock/chrono.h"
#include "pelrock/pelrock.h"
@@ -30,15 +30,17 @@
namespace Pelrock {
-VideoManager::VideoManager(Graphics::Screen *screen, PelrockEventManager *events, ChronoManager *chrono) : _screen(screen), _events(events), _chrono(chrono) {
- _screenSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+VideoManager::VideoManager(Graphics::Screen *screen, PelrockEventManager *events, ChronoManager *chrono, LargeFont *largeFont) : _screen(screen), _events(events), _chrono(chrono), _largeFont(largeFont) {
+ _videoSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+ _textSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
}
VideoManager::~VideoManager() {
- _screenSurface.free();
+ _videoSurface.free();
}
void VideoManager::playIntro() {
+ initMetadata();
Common::File videoFile;
if (!videoFile.open("ESCENAX.SSN")) {
error("Could not open ESCENAX.SSN");
@@ -46,7 +48,8 @@ void VideoManager::playIntro() {
}
videoFile.seek(0, SEEK_SET);
- _screenSurface.fillRect(Common::Rect(0, 0, 640, 400), 0);
+ _videoSurface.fillRect(Common::Rect(0, 0, 640, 400), 0);
+ _textSurface.fillRect(Common::Rect(0, 0, 640, 400), 255);
for (int sequence = 0; sequence < 1; sequence++) {
int frameCounter = 0;
int chunksInBuffer = 0;
@@ -56,7 +59,7 @@ void VideoManager::playIntro() {
_chrono->updateChrono();
_events->pollEvent();
- if(_chrono->_gameTick) {
+ if (_chrono->_gameTick && _chrono->getFrameCount() % 2 == 0) {
ChunkHeader chunk;
readChunk(videoFile, chunk);
@@ -75,12 +78,18 @@ void VideoManager::playIntro() {
debug("Unknown chunk type %d encountered", chunk.chunkType);
break;
}
+
+ Subtitle *subtitle = getSubtitleForFrame(frameCounter);
+ if (subtitle != nullptr) {
+ _largeFont->drawString(&_textSurface, subtitle->text, subtitle->x, subtitle->y, 640, 13);
+ }
+
presentFrame();
}
g_system->delayMillis(10);
}
+ debug("Total frames played: %d", frameCounter);
}
-
videoFile.close();
}
@@ -162,7 +171,7 @@ void VideoManager::readChunk(Common::SeekableReadStream &stream, ChunkHeader &ch
void VideoManager::processFrame(ChunkHeader &chunk, const int frameCount) {
byte *frameData = nullptr;
- if(chunk.chunkType == 1) {
+ if (chunk.chunkType == 1) {
// Video data chunk
frameData = decodeRLE(chunk.data, chunk.blockCount * chunkSize, 0x04);
} else if (chunk.chunkType == 2) {
@@ -170,8 +179,8 @@ void VideoManager::processFrame(ChunkHeader &chunk, const int frameCount) {
frameData = decodeCopyBlock(chunk.data, 0);
}
- byte *surfacePixels = (byte *)_screenSurface.getPixels();
- if(frameCount == 0) {
+ byte *surfacePixels = (byte *)_videoSurface.getPixels();
+ if (frameCount == 0) {
memcpy(surfacePixels, frameData, 256000);
} else {
// Subsequent frames, XOR with previous frame
@@ -180,13 +189,115 @@ void VideoManager::processFrame(ChunkHeader &chunk, const int frameCount) {
}
}
delete[] frameData;
-
}
void VideoManager::presentFrame() {
- _screen->blitFrom(_screenSurface);
+ _screen->blitFrom(_videoSurface);
+ _screen->transBlitFrom(_textSurface, 255);
_screen->markAllDirty();
_screen->update();
}
+void VideoManager::initMetadata() {
+ Common::File metadataFile;
+ if (!metadataFile.open("ESCENAX.SCR")) {
+ error("Could not open ESCENAX.SCR");
+ return;
+ }
+
+ while (metadataFile.eos() == false) {
+ char curChar = metadataFile.readByte();
+ if (curChar == '/') {
+ char nextChar = metadataFile.readByte();
+ if (nextChar == 't') { // subtitle
+ Subtitle subtitle;
+ Common::String buffer;
+ int values[4];
+ int valueIndex = 0;
+
+ // Skip spaces after "/t"
+ while (!metadataFile.eos() && metadataFile.readByte() == ' ')
+ ;
+ metadataFile.seek(-1, SEEK_CUR); // Step back one byte
+
+ // Parse 4 space-delimited numbers
+ while (!metadataFile.eos() && valueIndex < 4) {
+ char c = metadataFile.readByte();
+
+ if (c == ' ') {
+ if (!buffer.empty()) {
+ values[valueIndex++] = atoi(buffer.c_str());
+ buffer.clear();
+ }
+ } else if (c >= '0' && c <= '9') {
+ buffer += c;
+ } else if (c == 0x08) {
+ // End of numbers, start of text
+ if (!buffer.empty()) {
+ values[valueIndex++] = atoi(buffer.c_str());
+ }
+ break;
+ }
+ }
+
+ if (valueIndex == 4) {
+ subtitle.startFrame = values[0];
+ subtitle.endFrame = values[1];
+ subtitle.x = values[2];
+ subtitle.y = values[3];
+
+ // Read text until CRLF (0x0D 0x0A)
+ subtitle.text.clear();
+ while (!metadataFile.eos()) {
+ char c = metadataFile.readByte();
+
+ if (c == 0x0D) {
+ char next = metadataFile.readByte();
+ if (next == 0x0A) {
+ break;
+ } else {
+ subtitle.text += c;
+ subtitle.text += next;
+ }
+ } else {
+ subtitle.text += c;
+ }
+ }
+ _subtitles.push_back(subtitle);
+ }
+ }
+ }
+ }
+
+ debug("Loaded %d subtitles", _subtitles.size());
+ debug("Loaded %d audio effects", _audioEffect.size());
+
+ metadataFile.close();
+}
+
+Subtitle *VideoManager::getSubtitleForFrame(uint16 frameCounter) {
+ // Check if current subtitle is still active
+ if (_currentSubtitleIndex < _subtitles.size()) {
+ Subtitle &sub = _subtitles[_currentSubtitleIndex];
+
+ if (frameCounter >= sub.startFrame && frameCounter <= sub.endFrame) {
+ return ⊂ // Still showing this subtitle
+ }
+
+ if (frameCounter > sub.endFrame) {
+ _currentSubtitleIndex++; // Move to next subtitle
+ _textSurface.fillRect(Common::Rect(0, 0, 640, 400), 255);
+ // Check if new subtitle should be active
+ if (_currentSubtitleIndex < _subtitles.size()) {
+ Subtitle &nextSub = _subtitles[_currentSubtitleIndex];
+ if (frameCounter >= nextSub.startFrame && frameCounter <= nextSub.endFrame) {
+ return &nextSub;
+ }
+ }
+ }
+ }
+
+ return nullptr; // No active subtitle
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index f46c8068229..61ee9256e3a 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -25,6 +25,7 @@
#include "graphics/surface.h"
#include "pelrock/events.h"
+#include "pelrock/fonts/large_font.h"
namespace Pelrock {
@@ -36,11 +37,38 @@ struct ChunkHeader {
byte *data;
};
+struct Effect {
+ uint16 startFrame;
+};
+
+struct AudioEffect : Effect {
+};
+
+struct Subtitle : Effect {
+ uint16 startFrame;
+ uint16 endFrame;
+ uint16 x;
+ uint16 y;
+ Common::String text;
+};
+
+struct Voice : AudioEffect {
+ char filename[12];
+};
+
+struct Sfx : AudioEffect {
+ uint32 soundId;
+};
+
+struct ExtraSound : AudioEffect {
+ char filename[12];
+};
+
static const uint32 chunkSize = 0x5000;
class VideoManager {
public:
- VideoManager(Graphics::Screen *screen, PelrockEventManager *events, ChronoManager *chrono);
+ VideoManager(Graphics::Screen *screen, PelrockEventManager *events, ChronoManager *chrono, LargeFont *largeFont);
~VideoManager();
void playIntro();
@@ -48,14 +76,21 @@ private:
Graphics::Screen *_screen;
PelrockEventManager *_events;
ChronoManager *_chrono;
+ LargeFont *_largeFont;
void loadPalette(ChunkHeader &chunk);
byte *decodeCopyBlock(byte *data, uint32 offset);
byte *decodeRLE(byte *data, size_t size, uint32 offset);
void readChunk(Common::SeekableReadStream &stream, ChunkHeader &chunk);
void processFrame(ChunkHeader &chunk, const int frameCount);
void presentFrame();
- Graphics::Surface _screenSurface = Graphics::Surface();
+ void initMetadata();
+ Subtitle *getSubtitleForFrame(uint16 frameNumber);
+ int _currentSubtitleIndex = 0;
+ Graphics::Surface _videoSurface = Graphics::Surface();
+ Graphics::Surface _textSurface = Graphics::Surface();
Common::Array<ChunkHeader> _chunkBuffer;
+ Common::Array<Subtitle> _subtitles;
+ Common::Array<AudioEffect> _audioEffect;
};
} // End of namespace Pelrock
Commit: 291103f79bec1ca43a3f5c7d9c797ac701860098
https://github.com/scummvm/scummvm/commit/291103f79bec1ca43a3f5c7d9c797ac701860098
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:37+02:00
Commit Message:
PELROCK: Proper colors in video subtitles
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 566d9e1b667..80601605cdd 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -618,36 +618,44 @@ void DialogManager::say(Common::StringArray texts) {
if (texts.empty()) {
return;
}
- int speakerMarker = texts[0][0];
- int color = texts[0][1];
+ byte speakerId;
+ bool wasProcessed = processColorAndTrim(texts, speakerId);
- if (speakerMarker == '@') {
-
- for (int i = 0; i < texts.size(); i++) {
- // Remove first two marker bytes
- if (texts[i].size() > 2) {
- texts[i] = texts[i].substr(2);
- if (texts[i][0] == 0x78 && texts[i][1] == 0x78) { // Remove additional control chars
- texts[i] = texts[i].substr(2);
- }
- } else {
- texts[i] = "";
- }
- }
-
- if (color == ALFRED_COLOR) {
+ if (wasProcessed) {
+ if (speakerId == ALFRED_COLOR) {
sayAlfred(texts);
return;
} else {
setCurSprite(0);
Common::Array<Common::StringArray> textLines = wordWrap(texts);
- displayDialogue(textLines, color);
+ displayDialogue(textLines, speakerId);
}
} else {
sayAlfred(texts);
}
}
+bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speakerId) {
+ int speakerMarker = lines[0][0];
+ speakerId = lines[0][1];
+ if (speakerMarker == '@') {
+
+ for (int i = 0; i < lines.size(); i++) {
+ // Remove first two marker bytes
+ if (lines[i].size() > 2) {
+ lines[i] = lines[i].substr(2);
+ if (lines[i][0] == 0x78 && lines[i][1] == 0x78) { // Remove additional control chars
+ lines[i] = lines[i].substr(2);
+ }
+ } else {
+ lines[i] = "";
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
bool isEndMarker(char char_byte) {
return char_byte == CHAR_END_MARKER_1 || char_byte == CHAR_END_MARKER_2 || char_byte == CHAR_END_MARKER_3 || char_byte == CHAR_END_MARKER_4;
}
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index d9b4e82a192..0b9b59504ae 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -95,6 +95,7 @@ public:
void startConversation(const byte *conversationData, uint32 dataSize, Sprite *alfredAnimSet = nullptr);
void sayAlfred(Description description);
void say(Common::StringArray texts);
+ bool processColorAndTrim(Common::StringArray &lines, byte &speakerId);
Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
Common::Array<Common::Array<Common::String>> wordWrap(Common::StringArray texts);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 5e3b6e3391d..d1623192ffc 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -101,7 +101,7 @@ Common::Error PelrockEngine::run() {
_largeFont->load("ALFRED.7");
_doubleSmallFont = new DoubleSmallFont();
_doubleSmallFont->load("ALFRED.4");
- _videoManager = new VideoManager(_screen, _events, _chrono, _largeFont);
+ _videoManager = new VideoManager(_screen, _events, _chrono, _largeFont, _dialog);
// Set the engine's debugger console
setDebugger(new PelrockConsole(this));
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index f25a3e71820..4552c1a799d 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -30,7 +30,10 @@
namespace Pelrock {
-VideoManager::VideoManager(Graphics::Screen *screen, PelrockEventManager *events, ChronoManager *chrono, LargeFont *largeFont) : _screen(screen), _events(events), _chrono(chrono), _largeFont(largeFont) {
+VideoManager::VideoManager(
+ Graphics::Screen *screen,
+ PelrockEventManager *events,
+ ChronoManager *chrono, LargeFont *largeFont, DialogManager *dialog) : _screen(screen), _events(events), _chrono(chrono), _largeFont(largeFont), _dialog(dialog) {
_videoSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
_textSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
}
@@ -79,9 +82,15 @@ void VideoManager::playIntro() {
break;
}
+
Subtitle *subtitle = getSubtitleForFrame(frameCounter);
if (subtitle != nullptr) {
- _largeFont->drawString(&_textSurface, subtitle->text, subtitle->x, subtitle->y, 640, 13);
+ Common::StringArray lines;
+ lines.push_back(subtitle->text);
+ byte color;
+ _dialog->processColorAndTrim(lines, color);
+ debug("Displaying subtitle: %s with color %d", subtitle->text.c_str(), color);
+ _largeFont->drawString(&_textSurface, subtitle->text, subtitle->x, subtitle->y, 640, color);
}
presentFrame();
@@ -239,7 +248,7 @@ void VideoManager::initMetadata() {
break;
}
}
-
+ metadataFile.skip(1); // Skip the extra space
if (valueIndex == 4) {
subtitle.startFrame = values[0];
subtitle.endFrame = values[1];
@@ -260,7 +269,10 @@ void VideoManager::initMetadata() {
subtitle.text += next;
}
} else {
- subtitle.text += c;
+ if(c == 0x08)
+ subtitle.text += '@';
+ else
+ subtitle.text += c;
}
}
_subtitles.push_back(subtitle);
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index 61ee9256e3a..64e618b309f 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -68,7 +68,13 @@ static const uint32 chunkSize = 0x5000;
class VideoManager {
public:
- VideoManager(Graphics::Screen *screen, PelrockEventManager *events, ChronoManager *chrono, LargeFont *largeFont);
+ VideoManager(
+ Graphics::Screen *screen,
+ PelrockEventManager *events,
+ ChronoManager *chrono,
+ LargeFont *largeFont,
+ DialogManager *dialog
+ );
~VideoManager();
void playIntro();
@@ -77,6 +83,7 @@ private:
PelrockEventManager *_events;
ChronoManager *_chrono;
LargeFont *_largeFont;
+ DialogManager *_dialog;
void loadPalette(ChunkHeader &chunk);
byte *decodeCopyBlock(byte *data, uint32 offset);
byte *decodeRLE(byte *data, size_t size, uint32 offset);
Commit: 07706d32616f565a74be9f37a642f64c9bf389e2
https://github.com/scummvm/scummvm/commit/07706d32616f565a74be9f37a642f64c9bf389e2
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:37+02:00
Commit Message:
PELROCK: Word wraps subtitles
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 80601605cdd..e90f09189dc 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -134,6 +134,28 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *c
}
}
+Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId) {
+
+ int maxWidth = 0;
+ int height = dialogueLines.size() * 24;
+ for (int i = 0; i < dialogueLines.size(); i++) {
+ maxWidth = MAX(maxWidth, g_engine->_largeFont->getStringWidth(dialogueLines[i]));
+ }
+
+ Graphics::Surface s;
+ s.create(maxWidth, height, Graphics::PixelFormat::createFormatCLUT8());
+ s.fillRect(s.getRect(), 255); // Clear surface
+
+ for (int i = 0; i < dialogueLines.size(); i++) {
+
+ int xPos = 0;
+ int yPos = i * 20; // Above sprite, adjust for line
+
+ g_engine->_largeFont->drawString(&s, dialogueLines[i], xPos, yPos, maxWidth, speakerId, Graphics::kTextAlignCenter);
+ }
+
+ return s;
+}
/**
* Display dialogue text and wait for click to advance
* @param text The text to display
@@ -162,11 +184,6 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
for (int i = 0; i < textLines.size(); i++) {
maxWidth = MAX(maxWidth, g_engine->_largeFont->getStringWidth(textLines[i]));
}
-
- Graphics::Surface s;
- s.create(maxWidth, height, Graphics::PixelFormat::createFormatCLUT8());
- s.fillRect(s.getRect(), 255); // Clear surface
- // s.drawRoundRect(Common::Rect(0, 0, s.getRect().width(), s.getRect().height()), 2, 13, false);
int xPos = 0;
int yPos = 0;
@@ -185,13 +202,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
yPos = _curSprite->y - height; // Above sprite, adjust for line
}
- for (int i = 0; i < textLines.size(); i++) {
-
- int xPos = 0;
- int yPos = i * 20; // Above sprite, adjust for line
-
- g_engine->_largeFont->drawString(&s, textLines[i], xPos, yPos, maxWidth, speakerId, Graphics::kTextAlignCenter);
- }
+ Graphics::Surface s = getDialogueSurface(textLines, speakerId);
if (xPos + s.getRect().width() > 640) {
xPos = 640 - s.getRect().width() - 2;
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 0b9b59504ae..0812eddef57 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -96,6 +96,7 @@ public:
void sayAlfred(Description description);
void say(Common::StringArray texts);
bool processColorAndTrim(Common::StringArray &lines, byte &speakerId);
+ Graphics::Surface getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId);
Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
Common::Array<Common::Array<Common::String>> wordWrap(Common::StringArray texts);
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 4552c1a799d..67f19ea5d99 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -58,7 +58,7 @@ void VideoManager::playIntro() {
int chunksInBuffer = 0;
bool videoExitFlag = false;
- while (!videoExitFlag && !g_engine->shouldQuit()) {
+ while (!videoExitFlag && !g_engine->shouldQuit() && _events->_lastKeyEvent != Common::KEYCODE_ESCAPE) {
_chrono->updateChrono();
_events->pollEvent();
@@ -82,15 +82,13 @@ void VideoManager::playIntro() {
break;
}
-
Subtitle *subtitle = getSubtitleForFrame(frameCounter);
if (subtitle != nullptr) {
- Common::StringArray lines;
- lines.push_back(subtitle->text);
+ Common::StringArray lines = _dialog->wordWrap(subtitle->text)[0];
+
byte color;
_dialog->processColorAndTrim(lines, color);
- debug("Displaying subtitle: %s with color %d", subtitle->text.c_str(), color);
- _largeFont->drawString(&_textSurface, subtitle->text, subtitle->x, subtitle->y, 640, color);
+ _textSurface.transBlitFrom(_dialog->getDialogueSurface(lines, color), Common::Point(subtitle->x, subtitle->y), 255);
}
presentFrame();
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index 64e618b309f..801e720b00a 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -94,7 +94,7 @@ private:
Subtitle *getSubtitleForFrame(uint16 frameNumber);
int _currentSubtitleIndex = 0;
Graphics::Surface _videoSurface = Graphics::Surface();
- Graphics::Surface _textSurface = Graphics::Surface();
+ Graphics::ManagedSurface _textSurface = Graphics::ManagedSurface();
Common::Array<ChunkHeader> _chunkBuffer;
Common::Array<Subtitle> _subtitles;
Common::Array<AudioEffect> _audioEffect;
Commit: 476564d9826583b2200d12b0e19f021d1cf026fd
https://github.com/scummvm/scummvm/commit/476564d9826583b2200d12b0e19f021d1cf026fd
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:38+02:00
Commit Message:
PELROCK: Improvements on text positioning
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/util.cpp
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index e90f09189dc..c739a04932b 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -149,8 +149,7 @@ Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String
for (int i = 0; i < dialogueLines.size(); i++) {
int xPos = 0;
- int yPos = i * 20; // Above sprite, adjust for line
-
+ int yPos = i * 25; // Above sprite, adjust for line
g_engine->_largeFont->drawString(&s, dialogueLines[i], xPos, yPos, maxWidth, speakerId, Graphics::kTextAlignCenter);
}
@@ -188,7 +187,9 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int yPos = 0;
if (speakerId == ALFRED_COLOR) {
- g_engine->alfredState.setState(ALFRED_TALKING);
+ if(g_engine->alfredState.animState != ALFRED_TALKING) {
+ g_engine->alfredState.setState(ALFRED_TALKING);
+ }
if (_curSprite != nullptr) {
_curSprite->isTalking = false;
}
@@ -198,14 +199,14 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
} else {
g_engine->alfredState.setState(ALFRED_IDLE);
_curSprite->isTalking = true;
- xPos = _curSprite->x + _curSprite->w / 2 - maxWidth / 2;
+ xPos = _curSprite->x + _curSprite->w / 2;
yPos = _curSprite->y - height; // Above sprite, adjust for line
}
Graphics::Surface s = getDialogueSurface(textLines, speakerId);
if (xPos + s.getRect().width() > 640) {
- xPos = 640 - s.getRect().width() - 2;
+ xPos = 640 - s.getRect().width();
}
if (yPos + s.getRect().height() > 400) {
yPos = 400 - s.getRect().height();
@@ -216,8 +217,11 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (yPos < 0) {
yPos = 0;
}
-
_screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos), 255);
+ drawPos(_screen, xPos, yPos, speakerId);
+ drawRect(_screen, xPos, yPos,
+ s.getRect().width(),
+ s.getRect().height(), speakerId);
// Present to screen
_screen->markAllDirty();
_screen->update();
@@ -617,8 +621,8 @@ void DialogManager::sayAlfred(Common::StringArray texts) {
void DialogManager::sayAlfred(Description description) {
Common::StringArray texts;
- texts.push_back(description.text);
+ texts.push_back(description.text);
sayAlfred(texts);
if (description.isAction) {
g_engine->performActionTrigger(description.actionTrigger);
@@ -649,12 +653,14 @@ void DialogManager::say(Common::StringArray texts) {
bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speakerId) {
int speakerMarker = lines[0][0];
speakerId = lines[0][1];
+
if (speakerMarker == '@') {
for (int i = 0; i < lines.size(); i++) {
// Remove first two marker bytes
if (lines[i].size() > 2) {
lines[i] = lines[i].substr(2);
+
if (lines[i][0] == 0x78 && lines[i][1] == 0x78) { // Remove additional control chars
lines[i] = lines[i].substr(2);
}
@@ -713,8 +719,7 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
bool isEnd = false;
int wordLength = calculateWordLength(text, position, isEnd);
// # Extract the word (including trailing spaces)
- // word = text[position:position + word_length].decode('latin-1', errors='replace')
- Common::String word = text.substr(position, wordLength).decode(Common::kLatin1);
+ Common::String word = text.substr(position, wordLength);
// # Key decision: if word_length > chars_remaining, wrap to next line
if (wordLength > charsRemaining) {
// Word is longer than the entire line - need to split
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 0812eddef57..230dfa135ae 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -70,6 +70,18 @@ struct ChoiceOption {
ChoiceOption() : index(-1), isDisabled(false), dataOffset(0) {}
};
+static void debugHexString(const Common::String &str, const char *label = nullptr) {
+ if (label) {
+ debug("%s:", label);
+ }
+
+ Common::String hexOutput;
+ for (uint i = 0; i < str.size(); i++) {
+ hexOutput += Common::String::format("%02X ", (unsigned char)str[i]);
+ }
+ debug("%s", hexOutput.c_str());
+}
+
class DialogManager {
private:
Graphics::Screen *_screen = nullptr;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index d1623192ffc..1e13810181a 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -594,7 +594,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
Exit *exit = isExitUnder(alfredState.x, alfredState.y);
- if (exit != nullptr) {
+ if (exit != nullptr && exit->isEnabled) {
alfredState.x = exit->targetX;
alfredState.y = exit->targetY;
setScreen(exit->targetRoom, exit->dir);
@@ -604,7 +604,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.curFrame = 0;
}
- drawAlfred(_res->alfredWalkFrames[alfredState.direction][alfredState.curFrame]);
+ drawAlfred(_res->alfredWalkFrames[alfredState.direction][alfredState.curFrame]);
alfredState.curFrame++;
break;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 63c46b11290..691b6808d08 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -141,7 +141,7 @@ private:
bool showShadows = false;
- bool shouldPlayIntro = true;
+ bool shouldPlayIntro = false;
bool gameInitialized = false;
bool screenReady = false;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 4d5065a42f2..e06a144542f 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -436,15 +436,15 @@ Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, in
int desc_pos = 0;
if (data[pos] == 0xFF) {
Description description;
+
description.itemId = data[pos + 1];
- pos += 3;
+ pos += 4;
description.index = data[pos++];
description.text = "";
while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
if (data[pos] != 0x00) {
- // debug("Adding char 0x%02X to description, decoded as %lc", data[pos], decodeChar((byte)data[pos]));
description.text.append(1, (char)data[pos]);
}
if (data[pos] == 0xF8) {
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 5fa4e5ad68d..cf2503cd5aa 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -295,7 +295,6 @@ Common::String joinStrings(const Common::Array<Common::String> &strings, const C
void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color) {
if (x < 640 && y < 400 && x >= 0 && y >= 0) {
surface->setPixel(x, y, 100);
-
surface->drawEllipse(x - 3, y - 3, x + 3, y + 3, color, true);
}
}
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 67f19ea5d99..46e7bc7f7da 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -26,7 +26,7 @@
#include "pelrock/chrono.h"
#include "pelrock/pelrock.h"
#include "pelrock/video/video.h"
-#include "video.h"
+#include "pelrock/util.h"
namespace Pelrock {
@@ -88,7 +88,13 @@ void VideoManager::playIntro() {
byte color;
_dialog->processColorAndTrim(lines, color);
- _textSurface.transBlitFrom(_dialog->getDialogueSurface(lines, color), Common::Point(subtitle->x, subtitle->y), 255);
+ Graphics::Surface s = _dialog->getDialogueSurface(lines, color);
+ _textSurface.transBlitFrom(s, Common::Point(subtitle->x, subtitle->y), 255);
+
+ drawPos(&_textSurface, subtitle->x, subtitle->y, color);
+ drawRect(&_textSurface, subtitle->x, subtitle->y,
+ s.getRect().width(),
+ s.getRect().height(), color);
}
presentFrame();
@@ -270,7 +276,7 @@ void VideoManager::initMetadata() {
if(c == 0x08)
subtitle.text += '@';
else
- subtitle.text += c;
+ subtitle.text += decodeChar(c);
}
}
_subtitles.push_back(subtitle);
@@ -285,6 +291,30 @@ void VideoManager::initMetadata() {
metadataFile.close();
}
+char VideoManager::decodeChar(byte c) {
+
+ switch (c) {
+ case 0xAD:
+ return video_special_chars[1];
+ case 0xA8:
+ return video_special_chars[0];
+ case 0xA4:
+ return video_special_chars[3]; // n tilde
+ case 0xA3:
+ return video_special_chars[4];
+ case 0xA2:
+ return video_special_chars[5];
+ case 0xA1:
+ return video_special_chars[6];
+ case 0x82:
+ return video_special_chars[7];
+ case 0xA0:
+ return video_special_chars[8];
+ default:
+ return c;
+ }
+}
+
Subtitle *VideoManager::getSubtitleForFrame(uint16 frameCounter) {
// Check if current subtitle is still active
if (_currentSubtitleIndex < _subtitles.size()) {
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index 801e720b00a..37ca542c6a0 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -66,6 +66,18 @@ struct ExtraSound : AudioEffect {
static const uint32 chunkSize = 0x5000;
+static const int video_special_chars[] = {
+ 0x83, // inverted ?
+ 0x82, // inverted !
+ 165, // capital N tilde
+ 0x80, // small n tilde
+ 0x7F, // small u tilde
+ 0x7E, // small o tilde
+ 0x7D, // small i tilde
+ 0x7C, // small e tilde
+ 0x7B, // small a tilde
+};
+
class VideoManager {
public:
VideoManager(
@@ -91,6 +103,7 @@ private:
void processFrame(ChunkHeader &chunk, const int frameCount);
void presentFrame();
void initMetadata();
+ char decodeChar(byte c);
Subtitle *getSubtitleForFrame(uint16 frameNumber);
int _currentSubtitleIndex = 0;
Graphics::Surface _videoSurface = Graphics::Surface();
Commit: 0a3c9e5e6e003b53290d036af7b9b02b9a9cd176
https://github.com/scummvm/scummvm/commit/0a3c9e5e6e003b53290d036af7b9b02b9a9cd176
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:38+02:00
Commit Message:
PELROCK: Improvements on text positioning
Changed paths:
engines/pelrock/dialog.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index c739a04932b..e5429d4c61f 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -194,7 +194,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_curSprite->isTalking = false;
}
// Offset X position for Alfred to avoid overlapping with his sprite
- xPos = g_engine->alfredState.x + kAlfredFrameWidth / 2 - maxWidth / 2;
+ xPos = g_engine->alfredState.x - maxWidth / 2; //+ kAlfredFrameWidth / 2 - maxWidth / 2;
yPos = g_engine->alfredState.y - kAlfredFrameHeight - height; // Above sprite, adjust for line
} else {
g_engine->alfredState.setState(ALFRED_IDLE);
Commit: a527041b51cfd2ba428a440ef481d7f6ba8e4fe6
https://github.com/scummvm/scummvm/commit/a527041b51cfd2ba428a440ef481d7f6ba8e4fe6
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:38+02:00
Commit Message:
PELROCK: Checks mouse hover against sprite pixel masks
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1e13810181a..09d72217160 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -56,9 +56,9 @@ PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) :
}
PelrockEngine::~PelrockEngine() {
- if(_compositeBuffer)
+ if (_compositeBuffer)
delete[] _compositeBuffer;
- if(_currentBackground)
+ if (_currentBackground)
delete[] _currentBackground;
delete _largeFont;
delete _smallFont;
@@ -122,7 +122,7 @@ Common::Error PelrockEngine::run() {
_videoManager->playIntro();
stateGame = GAME;
}
- if(!shouldQuit())
+ if (!shouldQuit())
init();
while (!shouldQuit()) {
@@ -604,7 +604,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
alfredState.curFrame = 0;
}
- drawAlfred(_res->alfredWalkFrames[alfredState.direction][alfredState.curFrame]);
+ drawAlfred(_res->alfredWalkFrames[alfredState.direction][alfredState.curFrame]);
alfredState.curFrame++;
break;
}
@@ -978,6 +978,19 @@ int PelrockEngine::isHotspotUnder(int x, int y) {
if (hotspot.isEnabled &&
x >= hotspot.x && x <= (hotspot.x + hotspot.w) &&
y >= hotspot.y && y <= (hotspot.y + hotspot.h)) {
+ // Check against sprite frame
+ if (hotspot.isSprite) {
+ Sprite *sprite = nullptr;
+ for (size_t j = 0; j < _room->_currentRoomAnims.size(); j++) {
+ if (_room->_currentRoomAnims[j].index == hotspot.index) {
+ sprite = &(_room->_currentRoomAnims[j]);
+ break;
+ }
+ }
+ bool spriteUnder = isSpriteUnder(sprite, x, y);
+ return spriteUnder ? i : -1;
+ }
+
return i;
}
}
@@ -997,6 +1010,28 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
return nullptr;
}
+/**
+ * Checks if the given position is actually frame data or transparent pixel
+ */
+bool PelrockEngine::isSpriteUnder(Sprite *sprite, int x, int y) {
+ Anim &animData = sprite->animData[sprite->curAnimIndex];
+ int frameSize = animData.w * animData.h;
+ int curFrame = animData.curFrame;
+ byte *frame = new byte[frameSize];
+ extractSingleFrame(animData.animData, frame, curFrame, animData.w, animData.h);
+ int localX = x - animData.x;
+ int localY = y - animData.y;
+ if (localX >= 0 && localX < animData.w && localY >= 0 && localY < animData.h) {
+ byte pixel = frame[localY * animData.w + localX];
+ if (pixel != 255) {
+ delete[] frame;
+ return true;
+ }
+ }
+ delete[] frame;
+ return false;
+}
+
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _res->_popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 691b6808d08..9484d292a29 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -82,7 +82,7 @@ private:
bool isAlfredUnder(int x, int y);
int isHotspotUnder(int x, int y);
Exit *isExitUnder(int x, int y);
- Sprite *isSpriteUnder(int x, int y);
+ bool isSpriteUnder(Sprite *sprite, int x, int y);
void showActionBalloon(int posx, int posy, int curFrame);
Commit: a13abbc63c4041323cbc8cf1df750d6ddaa0ce9c
https://github.com/scummvm/scummvm/commit/a13abbc63c4041323cbc8cf1df750d6ddaa0ce9c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:38+02:00
Commit Message:
PELROCK: Refactor sprite data to preprocess animations
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 09d72217160..1ca4f04a638 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -802,8 +802,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
int frameSize = animData.w * animData.h;
int curFrame = animData.curFrame;
byte *frame = new byte[frameSize];
- extractSingleFrame(animData.animData, frame, curFrame, animData.w, animData.h);
- drawSpriteToBuffer(_compositeBuffer, 640, frame, sprite->x, sprite->y, sprite->w, sprite->h, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, animData.animData[curFrame], sprite->x, sprite->y, sprite->w, sprite->h, 255);
// if (animData.elpapsedFrames == animData.speed) {
if (_chrono->getFrameCount() % animData.speed == 0) {
@@ -1002,7 +1001,7 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
Exit exit = _room->_currentRoomExits[i];
if (x >= exit.x && x <= (exit.x + exit.w) &&
y >= exit.y && y <= (exit.y + exit.h)
- // && exit.isEnabled
+ && exit.isEnabled
) {
return &(_room->_currentRoomExits[i]);
}
@@ -1017,18 +1016,15 @@ bool PelrockEngine::isSpriteUnder(Sprite *sprite, int x, int y) {
Anim &animData = sprite->animData[sprite->curAnimIndex];
int frameSize = animData.w * animData.h;
int curFrame = animData.curFrame;
- byte *frame = new byte[frameSize];
- extractSingleFrame(animData.animData, frame, curFrame, animData.w, animData.h);
+
int localX = x - animData.x;
int localY = y - animData.y;
if (localX >= 0 && localX < animData.w && localY >= 0 && localY < animData.h) {
- byte pixel = frame[localY * animData.w + localX];
+ byte pixel = animData.animData[curFrame][localY * animData.w + localX];
if (pixel != 255) {
- delete[] frame;
return true;
}
}
- delete[] frame;
return false;
}
@@ -1062,7 +1058,7 @@ void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
// Change with the right index
int index = animSet->index;
- TalkingAnimHeader *animHeader = &_room->_talkingAnimHeader;
+ TalkingAnims *animHeader = &_room->_talkingAnimHeader;
int x = animSet->x + (index ? animHeader->offsetXAnimB : animHeader->offsetXAnimA);
int y = animSet->y + (index ? animHeader->offsetYAnimB : animHeader->offsetYAnimA);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index e06a144542f..c682155bd5c 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -339,7 +339,6 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(Common::File *roomFile, in
sprite.w = animData[4];
sprite.h = animData[5];
sprite.extra = animData[6];
- // roomFile->skip(1); // reserved
sprite.numAnims = animData[8];
sprite.zOrder = animData[23];
sprite.spriteType = animData[33];
@@ -364,11 +363,14 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(Common::File *roomFile, in
anim.loopCount = animData[subAnimOffset + 4 + j];
anim.speed = animData[subAnimOffset + 8 + j];
anim.movementFlags = animData[subAnimOffset + 14 + (j * 2)] | (animData[subAnimOffset + 14 + (j * 2) + 1] << 8);
- anim.animData = new byte[anim.nframes];
+
+ anim.animData = new byte *[anim.nframes];
if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
uint32_t needed = anim.w * anim.h * anim.nframes;
- anim.animData = new byte[needed];
- Common::copy(pic + picOffset, pic + picOffset + needed, anim.animData);
+ for(int i = 0; i < anim.nframes; i++) {
+ anim.animData[i] = new byte[anim.w * anim.h];
+ extractSingleFrame(pic + picOffset, anim.animData[i], i, anim.w, anim.h);
+ }
sprite.animData[j] = anim;
// debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
// debug(" Movement flags: 0x%04X", anim.movementFlags);
@@ -479,7 +481,7 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
int headerIndex = roomNumber;
uint32 offset = kTalkingAnimHeaderSize * headerIndex;
- TalkingAnimHeader talkHeader;
+ TalkingAnims talkHeader;
Common::File talkFile;
if (!talkFile.open("ALFRED.2")) {
error("Couldnt find file ALFRED.2");
@@ -512,10 +514,6 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
return;
}
- // if(talkHeader.animA != nullptr) {
- // delete[] talkHeader.animA;
- // talkHeader.animA = nullptr;
- // }
talkHeader.animA = new byte *[talkHeader.numFramesAnimA];
byte *data = nullptr;
@@ -532,10 +530,6 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
}
if (talkHeader.numFramesAnimB > 0) {
- // if(talkHeader.animA != nullptr) {
- // delete[] talkHeader.animA;
- // talkHeader.animA = nullptr;
- // }
talkHeader.animB = new byte *[talkHeader.numFramesAnimB];
for (int i = 0; i < talkHeader.numFramesAnimB; i++) {
talkHeader.animB[i] = new byte[talkHeader.wAnimB * talkHeader.hAnimB];
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 74b86f15d0b..8809aaeddb2 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -59,7 +59,7 @@ public:
Common::Array<WalkBox> _currentRoomWalkboxes;
Common::Array<Description> _currentRoomDescriptions;
- TalkingAnimHeader _talkingAnimHeader;
+ TalkingAnims _talkingAnimHeader;
ScalingParams _scaleParams;
byte *_pixelsShadows = nullptr;
byte _roomPalette[768];
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 4a6767ebc38..d53fa540694 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -162,7 +162,7 @@ struct Anim {
int nframes;
int curFrame = 0;
int curLoop = 0;
- byte *animData;
+ byte **animData;
byte loopCount;
byte speed;
byte elpapsedFrames = 0;
@@ -214,7 +214,7 @@ struct HotSpot {
byte zOrder = 0;
};
-struct TalkingAnimHeader {
+struct TalkingAnims {
uint32 spritePointer;
byte unknown2[3];
Commit: 65a66c21d00a8feaed5ff50d5128eb842d7103ab
https://github.com/scummvm/scummvm/commit/65a66c21d00a8feaed5ff50d5128eb842d7103ab
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:39+02:00
Commit Message:
PELROCK: Reads voice files
Changed paths:
engines/pelrock/pelrock.h
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 9484d292a29..a4a87c51f1f 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -141,7 +141,7 @@ private:
bool showShadows = false;
- bool shouldPlayIntro = false;
+ bool shouldPlayIntro = true;
bool gameInitialized = false;
bool screenReady = false;
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 46e7bc7f7da..97d55bd2c16 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -25,8 +25,9 @@
#include "pelrock/chrono.h"
#include "pelrock/pelrock.h"
-#include "pelrock/video/video.h"
#include "pelrock/util.h"
+#include "pelrock/video/video.h"
+#include "video.h"
namespace Pelrock {
@@ -36,10 +37,14 @@ VideoManager::VideoManager(
ChronoManager *chrono, LargeFont *largeFont, DialogManager *dialog) : _screen(screen), _events(events), _chrono(chrono), _largeFont(largeFont), _dialog(dialog) {
_videoSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
_textSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+ if (!_introSndFile.open("introsnd.dat")) {
+ error("Could not open introsnd.dat");
+ }
}
VideoManager::~VideoManager() {
_videoSurface.free();
+ _introSndFile.close();
}
void VideoManager::playIntro() {
@@ -93,8 +98,8 @@ void VideoManager::playIntro() {
drawPos(&_textSurface, subtitle->x, subtitle->y, color);
drawRect(&_textSurface, subtitle->x, subtitle->y,
- s.getRect().width(),
- s.getRect().height(), color);
+ s.getRect().width(),
+ s.getRect().height(), color);
}
presentFrame();
@@ -218,69 +223,36 @@ void VideoManager::initMetadata() {
return;
}
+ // 1. Read the file allocation table from introsnd.dat
+ if (_introSndFile.isOpen()) {
+ _introSndFile.seek(0, SEEK_SET);
+ char signature[5] = {0};
+ _introSndFile.read(signature, 4);
+ if (strcmp(signature, "PACK") == 0) {
+ uint32_t numFiles = _introSndFile.readUint32LE();
+ for (uint32_t i = 0; i < numFiles; ++i) {
+ VoiceData sound;
+ Common::String filename = _introSndFile.readString();
+ // _introSndFile.skip(1);
+ sound.offset = _introSndFile.readUint32LE();
+ sound.length = _introSndFile.readUint32LE();
+ _sounds[filename] = sound;
+ }
+ }
+ debug("Loaded %d sound entries", _sounds.size());
+ }
+
while (metadataFile.eos() == false) {
char curChar = metadataFile.readByte();
if (curChar == '/') {
char nextChar = metadataFile.readByte();
if (nextChar == 't') { // subtitle
- Subtitle subtitle;
- Common::String buffer;
- int values[4];
- int valueIndex = 0;
-
- // Skip spaces after "/t"
- while (!metadataFile.eos() && metadataFile.readByte() == ' ')
- ;
- metadataFile.seek(-1, SEEK_CUR); // Step back one byte
-
- // Parse 4 space-delimited numbers
- while (!metadataFile.eos() && valueIndex < 4) {
- char c = metadataFile.readByte();
-
- if (c == ' ') {
- if (!buffer.empty()) {
- values[valueIndex++] = atoi(buffer.c_str());
- buffer.clear();
- }
- } else if (c >= '0' && c <= '9') {
- buffer += c;
- } else if (c == 0x08) {
- // End of numbers, start of text
- if (!buffer.empty()) {
- values[valueIndex++] = atoi(buffer.c_str());
- }
- break;
- }
- }
- metadataFile.skip(1); // Skip the extra space
- if (valueIndex == 4) {
- subtitle.startFrame = values[0];
- subtitle.endFrame = values[1];
- subtitle.x = values[2];
- subtitle.y = values[3];
-
- // Read text until CRLF (0x0D 0x0A)
- subtitle.text.clear();
- while (!metadataFile.eos()) {
- char c = metadataFile.readByte();
-
- if (c == 0x0D) {
- char next = metadataFile.readByte();
- if (next == 0x0A) {
- break;
- } else {
- subtitle.text += c;
- subtitle.text += next;
- }
- } else {
- if(c == 0x08)
- subtitle.text += '@';
- else
- subtitle.text += decodeChar(c);
- }
- }
- _subtitles.push_back(subtitle);
- }
+ Subtitle subtitle = readSubtitle(metadataFile);
+ _subtitles.push_back(subtitle);
+ } else if (nextChar == 'x') {
+ Voice voice = readVoice(metadataFile);
+ // Read filename (up to 12 bytes, null-terminated)
+ _audioEffect.push_back(voice);
}
}
}
@@ -291,6 +263,95 @@ void VideoManager::initMetadata() {
metadataFile.close();
}
+Voice VideoManager::readVoice(Common::File &metadataFile) {
+ Voice voice;
+ Common::String buffer;
+
+ // Skip spaces after "/x"
+ while (!metadataFile.eos() && metadataFile.readByte() == ' ')
+ ;
+ metadataFile.seek(-1, SEEK_CUR); // Step back one byte
+
+ bool frameCountRead = false;
+ while (!metadataFile.eos()) {
+ char c = metadataFile.readByte();
+ if (c == ' ') {
+ if (!buffer.empty() && !frameCountRead) {
+ voice.startFrame = atoi(buffer.c_str());
+ buffer.clear();
+ frameCountRead = true;
+ }
+ } else if (c == 0x0D || c == 0x0A) {
+ break;
+ } else {
+ buffer += c;
+ }
+ }
+ voice.filename = buffer;
+ debug("Loaded voice: frame %d, file '%s'", voice.startFrame, voice.filename.c_str());
+ return voice;
+}
+
+Subtitle VideoManager::readSubtitle(Common::File &metadataFile) {
+ Subtitle subtitle;
+ Common::String buffer;
+ int values[4];
+ int valueIndex = 0;
+
+ // Skip spaces after "/t"
+ while (!metadataFile.eos() && metadataFile.readByte() == ' ')
+ ;
+ metadataFile.seek(-1, SEEK_CUR); // Step back one byte
+
+ // Parse 4 space-delimited numbers
+ while (!metadataFile.eos() && valueIndex < 4) {
+ char c = metadataFile.readByte();
+
+ if (c == ' ') {
+ if (!buffer.empty()) {
+ values[valueIndex++] = atoi(buffer.c_str());
+ buffer.clear();
+ }
+ } else if (c >= '0' && c <= '9') {
+ buffer += c;
+ } else if (c == 0x08) {
+ // End of numbers, start of text
+ if (!buffer.empty()) {
+ values[valueIndex++] = atoi(buffer.c_str());
+ }
+ break;
+ }
+ }
+ metadataFile.skip(1); // Skip the extra space
+
+ subtitle.startFrame = values[0];
+ subtitle.endFrame = values[1];
+ subtitle.x = values[2];
+ subtitle.y = values[3];
+
+ // Read text until CRLF (0x0D 0x0A)
+ subtitle.text.clear();
+ while (!metadataFile.eos()) {
+ char c = metadataFile.readByte();
+
+ if (c == 0x0D) {
+ char next = metadataFile.readByte();
+ if (next == 0x0A) {
+ break;
+ } else {
+ subtitle.text += c;
+ subtitle.text += next;
+ }
+ } else {
+ if (c == 0x08)
+ subtitle.text += '@';
+ else
+ subtitle.text += decodeChar(c);
+ }
+ }
+ return subtitle;
+}
+
char VideoManager::decodeChar(byte c) {
switch (c) {
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index 37ca542c6a0..a3597ee71c3 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -53,7 +53,7 @@ struct Subtitle : Effect {
};
struct Voice : AudioEffect {
- char filename[12];
+ Common::String filename;
};
struct Sfx : AudioEffect {
@@ -61,7 +61,12 @@ struct Sfx : AudioEffect {
};
struct ExtraSound : AudioEffect {
- char filename[12];
+ Common::String filename;
+};
+
+struct VoiceData {
+ uint32 offset;
+ uint32 length;
};
static const uint32 chunkSize = 0x5000;
@@ -103,6 +108,9 @@ private:
void processFrame(ChunkHeader &chunk, const int frameCount);
void presentFrame();
void initMetadata();
+ void readSubtitle(Common::File &metadataFile, Pelrock::Subtitle &subtitle);
+ Subtitle readSubtitle(Common::File &metadataFile);
+ Voice readVoice(Common::File &metadataFile);
char decodeChar(byte c);
Subtitle *getSubtitleForFrame(uint16 frameNumber);
int _currentSubtitleIndex = 0;
@@ -111,6 +119,8 @@ private:
Common::Array<ChunkHeader> _chunkBuffer;
Common::Array<Subtitle> _subtitles;
Common::Array<AudioEffect> _audioEffect;
+ Common::HashMap<Common::String, VoiceData> _sounds;
+ Common::File _introSndFile;
};
} // End of namespace Pelrock
Commit: 22ff6faa73d3290864dabd5e30f7bc10664bbf19
https://github.com/scummvm/scummvm/commit/22ff6faa73d3290864dabd5e30f7bc10664bbf19
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:39+02:00
Commit Message:
PELROCK: Plays intro speech
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1ca4f04a638..b6bcfeccc17 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -101,7 +101,7 @@ Common::Error PelrockEngine::run() {
_largeFont->load("ALFRED.7");
_doubleSmallFont = new DoubleSmallFont();
_doubleSmallFont->load("ALFRED.4");
- _videoManager = new VideoManager(_screen, _events, _chrono, _largeFont, _dialog);
+ _videoManager = new VideoManager(_screen, _events, _chrono, _largeFont, _dialog, _sound);
// Set the engine's debugger console
setDebugger(new PelrockConsole(this));
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 47c82d82cb8..281ba6d9304 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -100,10 +100,14 @@ void SoundManager::playSound(SonidoFile sound, int volume) {
return;
}
- // if (stream) {
- // int channel = findFreeChannel();
- // _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
- // }
+}
+
+void SoundManager::playSound(byte *soundData, uint32 size,int volume) {
+ Audio::AudioStream *stream = Audio::makeRawStream(soundData, size, 11025, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
+ if (stream) {
+ int channel = findFreeChannel();
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
+ }
}
SoundFormat SoundManager::detectFormat(byte *data, uint32 size) {
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index d47d39559a8..ee305f6a20d 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -188,6 +188,7 @@ public:
SoundManager(Audio::Mixer *mixer);
~SoundManager();
void playSound(byte index, int volume = 255);
+ void playSound(byte *soundData, uint32 size, int volume = 255);
void stopAllSounds();
void stopSound(int channel);
void stopMusic();
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 97d55bd2c16..a0ad426faa9 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -34,7 +34,10 @@ namespace Pelrock {
VideoManager::VideoManager(
Graphics::Screen *screen,
PelrockEventManager *events,
- ChronoManager *chrono, LargeFont *largeFont, DialogManager *dialog) : _screen(screen), _events(events), _chrono(chrono), _largeFont(largeFont), _dialog(dialog) {
+ ChronoManager *chrono,
+ LargeFont *largeFont,
+ DialogManager *dialog,
+ SoundManager *sound) : _screen(screen), _events(events), _chrono(chrono), _largeFont(largeFont), _dialog(dialog), _sound(sound) {
_videoSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
_textSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
if (!_introSndFile.open("introsnd.dat")) {
@@ -59,7 +62,7 @@ void VideoManager::playIntro() {
_videoSurface.fillRect(Common::Rect(0, 0, 640, 400), 0);
_textSurface.fillRect(Common::Rect(0, 0, 640, 400), 255);
for (int sequence = 0; sequence < 1; sequence++) {
- int frameCounter = 0;
+ uint16 frameCounter = 0;
int chunksInBuffer = 0;
bool videoExitFlag = false;
@@ -87,6 +90,18 @@ void VideoManager::playIntro() {
break;
}
+ if (_voiceEffect.contains(frameCounter)) {
+ Voice voice = _voiceEffect[frameCounter];
+ debug("Playing voice effect: '%s'", voice.filename.c_str());
+ VoiceData voiceData = _sounds[voice.filename];
+ _introSndFile.seek(voiceData.offset, SEEK_SET);
+ byte *voiceBuffer = new byte[voiceData.length];
+ _introSndFile.read(voiceBuffer, voiceData.length);
+ _sound->playSound(voiceBuffer, voiceData.length);
+ // g_system->getSoundManager()->playSoundBuffer(voiceBuffer, voiceData.length, SOUND_FORMAT_PCM8, 11025);
+ // delete[] voiceBuffer;
+ }
+
Subtitle *subtitle = getSubtitleForFrame(frameCounter);
if (subtitle != nullptr) {
Common::StringArray lines = _dialog->wordWrap(subtitle->text)[0];
@@ -223,7 +238,6 @@ void VideoManager::initMetadata() {
return;
}
- // 1. Read the file allocation table from introsnd.dat
if (_introSndFile.isOpen()) {
_introSndFile.seek(0, SEEK_SET);
char signature[5] = {0};
@@ -237,8 +251,10 @@ void VideoManager::initMetadata() {
sound.offset = _introSndFile.readUint32LE();
sound.length = _introSndFile.readUint32LE();
_sounds[filename] = sound;
+ debug("Loaded sound: '%s' (offset: %u, length: %u)", filename.c_str(), sound.offset, sound.length);
}
}
+
debug("Loaded %d sound entries", _sounds.size());
}
@@ -252,13 +268,13 @@ void VideoManager::initMetadata() {
} else if (nextChar == 'x') {
Voice voice = readVoice(metadataFile);
// Read filename (up to 12 bytes, null-terminated)
- _audioEffect.push_back(voice);
+ _voiceEffect[voice.startFrame] = voice;
}
}
}
debug("Loaded %d subtitles", _subtitles.size());
- debug("Loaded %d audio effects", _audioEffect.size());
+ debug("Loaded %d audio effects", _voiceEffect.size());
metadataFile.close();
}
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index a3597ee71c3..064a0c7b7ae 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -90,7 +90,8 @@ public:
PelrockEventManager *events,
ChronoManager *chrono,
LargeFont *largeFont,
- DialogManager *dialog
+ DialogManager *dialog,
+ SoundManager *sound
);
~VideoManager();
void playIntro();
@@ -101,6 +102,7 @@ private:
ChronoManager *_chrono;
LargeFont *_largeFont;
DialogManager *_dialog;
+ SoundManager *_sound;
void loadPalette(ChunkHeader &chunk);
byte *decodeCopyBlock(byte *data, uint32 offset);
byte *decodeRLE(byte *data, size_t size, uint32 offset);
@@ -118,7 +120,7 @@ private:
Graphics::ManagedSurface _textSurface = Graphics::ManagedSurface();
Common::Array<ChunkHeader> _chunkBuffer;
Common::Array<Subtitle> _subtitles;
- Common::Array<AudioEffect> _audioEffect;
+ Common::HashMap<uint16, Voice> _voiceEffect;
Common::HashMap<Common::String, VoiceData> _sounds;
Common::File _introSndFile;
};
Commit: 828e6d9b84e85cfa3ec904c0b0bbf6a680e7999e
https://github.com/scummvm/scummvm/commit/828e6d9b84e85cfa3ec904c0b0bbf6a680e7999e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:39+02:00
Commit Message:
PELROCK: Read metadata parameters from byte buffer
Changed paths:
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/sound.cpp
engines/pelrock/video/video.cpp
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index a4a87c51f1f..9484d292a29 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -141,7 +141,7 @@ private:
bool showShadows = false;
- bool shouldPlayIntro = true;
+ bool shouldPlayIntro = false;
bool gameInitialized = false;
bool screenReady = false;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index c682155bd5c..4d1397a181e 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -162,27 +162,24 @@ PaletteAnim *RoomManager::getPaletteAnimForRoom(int roomNumber) {
return anim;
}
-Common::Array<Exit> RoomManager::loadExits(Common::File *roomFile, int roomOffset) {
+Common::Array<Exit> RoomManager::loadExits(byte *data, size_t size) {
Common::Array<Exit> exits;
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- roomFile->seek(pair10_offset_pos, SEEK_SET);
- uint32_t pair10_data_offset = roomFile->readUint32LE();
- uint32_t pair10_size = roomFile->readUint32LE();
- roomFile->seek(pair10_data_offset + 0x1BE, SEEK_SET);
- int exit_count = roomFile->readByte();
- roomFile->seek(pair10_data_offset + 0x1BF, SEEK_SET);
- for (int i = 0; i < exit_count; i++) {
+ int exitCountOffset = 0x1BE;
+ byte exitCount = data[exitCountOffset];
+ int exitDataOffset = 0x1BF;
+ for (int i = 0; i < exitCount; i++) {
+ int exitOffset = exitDataOffset + i * 14;
Exit exit;
- exit.targetRoom = roomFile->readUint16LE();
- exit.isEnabled = roomFile->readByte();
- exit.x = roomFile->readUint16LE();
- exit.y = roomFile->readUint16LE();
- exit.w = roomFile->readByte();
- exit.h = roomFile->readByte();
-
- exit.targetX = roomFile->readUint16LE();
- exit.targetY = roomFile->readUint16LE();
- byte dir = roomFile->readByte();
+ exit.targetRoom = READ_LE_INT16(data + exitOffset);
+ exit.isEnabled = data[exitOffset + 2];
+ exit.x = READ_LE_INT16(data + exitOffset + 3);
+ exit.y = READ_LE_INT16(data + exitOffset + 5);
+ exit.w = data[exitOffset + 7];
+ exit.h = data[exitOffset + 8];
+
+ exit.targetX = READ_LE_INT16(data + exitOffset + 9);
+ exit.targetY = READ_LE_INT16(data + exitOffset + 11);
+ byte dir = data[exitOffset + 13];
switch (dir) {
case ALFRED_RIGHT:
exit.dir = ALFRED_RIGHT;
@@ -202,32 +199,30 @@ Common::Array<Exit> RoomManager::loadExits(Common::File *roomFile, int roomOffse
}
exits.push_back(exit);
+ debug("Exit %d: targetRoom=%d isEnabled=%d x=%d y=%d w=%d h=%d targetX=%d targetY=%d dir=%d",
+ i, exit.targetRoom, exit.isEnabled, exit.x, exit.y, exit.w, exit.h,
+ exit.targetX, exit.targetY, exit.dir);
}
return exits;
}
-Common::Array<HotSpot> RoomManager::loadHotspots(Common::File *roomFile, int roomOffset) {
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
+Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
+ int pair10StartingPos = 0x47a;
- roomFile->seek(pair10_offset_pos, SEEK_SET);
- uint32_t pair10_data_offset = roomFile->readUint32LE();
- uint32_t pair10_size = roomFile->readUint32LE();
- uint32_t count_offset = pair10_data_offset + 0x47a;
- roomFile->seek(count_offset, SEEK_SET);
- byte hotspot_count = roomFile->readByte();
- uint32_t hotspot_data_start = pair10_data_offset + 0x47c;
+
+ byte hotspot_count = data[pair10StartingPos];
+ int hotspotsDataStart = pair10StartingPos + 2;
Common::Array<HotSpot> hotspots;
for (int i = 0; i < hotspot_count; i++) {
- uint32_t obj_offset = hotspot_data_start + i * 9;
- roomFile->seek(obj_offset, SEEK_SET);
+ int hotspotOffset = hotspotsDataStart + i * 9;
HotSpot spot;
- spot.actionFlags = roomFile->readByte();
- spot.x = roomFile->readSint16LE();
- spot.y = roomFile->readSint16LE();
- spot.w = roomFile->readByte();
- spot.h = roomFile->readByte();
+ spot.actionFlags = data[hotspotOffset];
+ spot.x = READ_LE_INT16(data + hotspotOffset + 1);
+ spot.y = READ_LE_INT16(data + hotspotOffset + 3);
+ spot.w = data[hotspotOffset + 5];
+ spot.h = data[hotspotOffset + 6];
spot.isSprite = false;
- spot.extra = roomFile->readSint16LE();
+ spot.extra = READ_LE_INT16(data + hotspotOffset + 7);
debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra);
hotspots.push_back(spot);
}
@@ -238,9 +233,33 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
uint32_t outPos = 0;
_currentRoomStickers.clear();
int roomOffset = roomNumber * kRoomStructSize;
- Common::Array<Description> descriptions = loadRoomTexts(roomFile, roomOffset);
- Common::Array<Sprite> anims = loadRoomAnimations(roomFile, roomOffset);
+ uint32_t pair10offset = roomOffset + (10 * 8);
+ roomFile->seek(pair10offset, SEEK_SET);
+ // roomFile->skip(4);
+ uint32_t pair10dataOffset = roomFile->readUint32LE();
+ uint32_t pair10size = roomFile->readUint32LE();
+
+ byte *pair10 = new byte[pair10size];
+ roomFile->seek(pair10dataOffset, SEEK_SET);
+ roomFile->read(pair10, pair10size);
+
+ // The user's game can be in any state so we reset to defaults first
+ resetRoomDefaults(pair10, pair10size);
+
+
+ byte *pic = nullptr;
+ size_t pixelDataSize = 0;
+ loadAnimationPixelData(roomFile, roomOffset, pic, pixelDataSize);
+
+ Common::Array<Sprite> anims = loadRoomAnimations(pic, pixelDataSize, pair10, pair10size);
+ Common::Array<HotSpot> staticHotspots = loadHotspots(pair10, pair10size);
+ Common::Array<WalkBox> walkboxes = loadWalkboxes(pair10, pair10size);
+ Common::Array<Exit> exits = loadExits(pair10, pair10size);
+ ScalingParams scalingParams = loadScalingParams(pair10, pair10size);
+
+
+ Common::Array<Description> descriptions = loadRoomTexts(roomFile, roomOffset);
Common::Array<HotSpot> hotspots;
for (int i = 0; i < anims.size(); i++) {
@@ -258,11 +277,6 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
hotspots.push_back(thisHotspot);
}
- Common::Array<HotSpot> staticHotspots = loadHotspots(roomFile, roomOffset);
- Common::Array<Exit> exits = loadExits(roomFile, roomOffset);
- ScalingParams scalingParams = loadScalingParams(roomFile, roomOffset);
- Common::Array<WalkBox> walkboxes = loadWalkboxes(roomFile, roomOffset);
-
// debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
for (int i = 0; i < staticHotspots.size(); i++) {
HotSpot hotspot = staticHotspots[i];
@@ -302,54 +316,52 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
} else {
_currentPaletteAnim = nullptr;
}
+
+ delete[] pair10;
}
-Common::Array<Sprite> RoomManager::loadRoomAnimations(Common::File *roomFile, int roomOffset) {
+void RoomManager::loadAnimationPixelData(Common::File *roomFile, int roomOffset, byte *&buffer, size_t &outSize) {
uint32_t pair_offset = roomOffset + (8 * 8);
- // debug("Sprite pair offset position: %d", pair_offset);
roomFile->seek(pair_offset, SEEK_SET);
uint32_t offset = roomFile->readUint32LE();
uint32_t size = roomFile->readUint32LE();
- byte *data = new byte[size];
+ byte *pixelData = new byte[size];
roomFile->seek(offset, SEEK_SET);
- roomFile->read(data, size);
-
- unsigned char *pic = nullptr;
+ roomFile->read(pixelData, size);
if (offset > 0 && size > 0) {
- rleDecompress(data, size, 0, size, &pic, true);
- } else {
- return Common::Array<Sprite>();
+ outSize = rleDecompress(pixelData, size, 0, size, &buffer, true);
}
- Common::Array<Sprite> anims = Common::Array<Sprite>();
- uint32_t spriteEnd = offset + size;
+}
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- uint32_t metadata_start = spriteEnd + 108;
+Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size) {
+
+ Common::Array<Sprite> anims = Common::Array<Sprite>();
+ uint32_t spriteCountPos = 5;
+ byte spriteCount = data[spriteCountPos] - 2;
+ debug("Sprite count: %d", spriteCount);
+ uint32_t metadata_start = spriteCountPos + (44 * 2 + 5);
uint32_t picOffset = 0;
- for (int i = 0; i < 7; i++) {
+ for (int i = 0; i < spriteCount; i++) {
uint32_t animOffset = metadata_start + (i * 44);
- byte *animData = new byte[44];
- roomFile->seek(animOffset, SEEK_SET);
- roomFile->read(animData, 44);
Sprite sprite;
sprite.index = i;
- sprite.x = animData[0] | (animData[1] << 8);
- sprite.y = animData[2] | (animData[3] << 8);
- sprite.w = animData[4];
- sprite.h = animData[5];
- sprite.extra = animData[6];
- sprite.numAnims = animData[8];
- sprite.zOrder = animData[23];
- sprite.spriteType = animData[33];
- sprite.actionFlags = animData[34];
- sprite.isDisabled = animData[38];
+ sprite.x = READ_LE_INT16(data + animOffset + 0);
+ sprite.y = READ_LE_INT16(data + animOffset + 2);
+ sprite.w = data[animOffset + 4];
+ sprite.h = data[animOffset + 5];
+ sprite.extra = data[animOffset + 6];
+ sprite.numAnims = data[animOffset + 8];
+ sprite.zOrder = data[animOffset + 23];
+ sprite.spriteType = data[animOffset + 33];
+ sprite.actionFlags = data[animOffset + 34];
+ sprite.isDisabled = data[animOffset + 38];
if (sprite.numAnims == 0) {
break;
}
sprite.animData = new Anim[sprite.numAnims];
// debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
- int subAnimOffset = 10;
+ int subAnimOffset = animOffset + 10;
for (int j = 0; j < sprite.numAnims; j++) {
Anim anim;
@@ -359,17 +371,17 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(Common::File *roomFile, in
anim.h = sprite.h;
anim.curFrame = 0;
- anim.nframes = animData[subAnimOffset + j];
- anim.loopCount = animData[subAnimOffset + 4 + j];
- anim.speed = animData[subAnimOffset + 8 + j];
- anim.movementFlags = animData[subAnimOffset + 14 + (j * 2)] | (animData[subAnimOffset + 14 + (j * 2) + 1] << 8);
+ anim.nframes = data[subAnimOffset + j];
+ anim.loopCount = data[subAnimOffset + 4 + j];
+ anim.speed = data[subAnimOffset + 8 + j];
+ anim.movementFlags = data[subAnimOffset + 14 + (j * 2)] | (data[subAnimOffset + 14 + (j * 2) + 1] << 8);
anim.animData = new byte *[anim.nframes];
if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
uint32_t needed = anim.w * anim.h * anim.nframes;
for(int i = 0; i < anim.nframes; i++) {
anim.animData[i] = new byte[anim.w * anim.h];
- extractSingleFrame(pic + picOffset, anim.animData[i], i, anim.w, anim.h);
+ extractSingleFrame(pixelData + picOffset, anim.animData[i], i, anim.w, anim.h);
}
sprite.animData[j] = anim;
// debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
@@ -387,28 +399,21 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(Common::File *roomFile, in
return anims;
}
-Common::Array<WalkBox> RoomManager::loadWalkboxes(Common::File *roomFile, int roomOffset) {
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- roomFile->seek(pair10_offset_pos, SEEK_SET);
- // roomFile->skip(4);
- uint32_t pair10_data_offset = roomFile->readUint32LE();
- uint32_t pair10_size = roomFile->readUint32LE();
+Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
- uint32_t walkbox_countOffset = pair10_data_offset + 0x213;
- roomFile->seek(walkbox_countOffset, SEEK_SET);
- byte walkbox_count = roomFile->readByte();
+ int walkboxCountOffset = 0x213;
+ byte walkboxCount = data[walkboxCountOffset];
// debug("Walkbox count: %d", walkbox_count);
- uint32_t walkbox_offset = pair10_data_offset + 0x218;
+ uint32_t walkboxOffset = 0x218;
Common::Array<WalkBox> walkboxes;
- for (int i = 0; i < walkbox_count; i++) {
- uint32_t box_offset = walkbox_offset + i * 9;
- roomFile->seek(box_offset, SEEK_SET);
- int16 x1 = roomFile->readSint16LE();
- int16 y1 = roomFile->readSint16LE();
- int16 w = roomFile->readSint16LE();
- int16 h = roomFile->readSint16LE();
- byte flags = roomFile->readByte();
+ for (int i = 0; i < walkboxCount; i++) {
+ uint32_t boxOffset = walkboxOffset + i * 9;
+ int16 x1 = READ_LE_INT16(data + boxOffset);
+ int16 y1 = READ_LE_INT16(data + boxOffset + 2);
+ int16 w = READ_LE_INT16(data + boxOffset + 4);
+ int16 h = READ_LE_INT16(data + boxOffset + 6);
+ byte flags = data[boxOffset + 8];
debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
WalkBox box;
box.x = x1;
@@ -424,7 +429,6 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(Common::File *roomFile, int ro
Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, int roomOffset) {
uint32_t pair12_offset_pos = roomOffset + (12 * 8);
roomFile->seek(pair12_offset_pos, SEEK_SET);
- // roomFile->skip(4);
uint32_t pair12_data_offset = roomFile->readUint32LE();
uint32_t pair12_size = roomFile->readUint32LE();
@@ -476,6 +480,10 @@ Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, in
return descriptions;
}
+void RoomManager::resetRoomDefaults(byte *data, size_t size) {
+
+}
+
void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
int headerIndex = roomNumber;
@@ -542,19 +550,14 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
talkFile.close();
}
-ScalingParams RoomManager::loadScalingParams(Common::File *roomFile, int roomOffset) {
- uint32_t pair10_offset_pos = roomOffset + (10 * 8);
- roomFile->seek(pair10_offset_pos, SEEK_SET);
- // roomFile->skip(4);
- uint32_t pair10_data_offset = roomFile->readUint32LE();
- uint32_t pair10_size = roomFile->readUint32LE();
- uint32_t scalingParamsOffset = pair10_data_offset + 0x214;
+ScalingParams RoomManager::loadScalingParams(byte *data, size_t size) {
+
+ uint32_t scalingParamsOffset = 0x214;
- roomFile->seek(scalingParamsOffset, SEEK_SET);
ScalingParams scalingParams;
- scalingParams.yThreshold = roomFile->readSint16LE();
- scalingParams.scaleDivisor = roomFile->readByte();
- scalingParams.scaleMode = roomFile->readByte();
+ scalingParams.yThreshold = READ_LE_INT16(data + scalingParamsOffset);
+ scalingParams.scaleDivisor = data[scalingParamsOffset + 2];
+ scalingParams.scaleMode = data[scalingParamsOffset + 3];
return scalingParams;
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 8809aaeddb2..462f0e96279 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -73,13 +73,16 @@ public:
size_t _conversationDataSize = 0;
private:
- Common::Array<Sprite> loadRoomAnimations(Common::File *roomFile, int roomOffset);
- Common::Array<HotSpot> loadHotspots(Common::File *roomFile, int roomOffset);
- Common::Array<Exit> loadExits(Common::File *roomFile, int roomOffset);
- Common::Array<WalkBox> loadWalkboxes(Common::File *roomFile, int roomOffset);
+ void loadAnimationPixelData(Common::File *roomFile, int roomOffset, byte *&buffer, size_t &outSize);
+ Common::Array<Sprite> loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size);
+ Common::Array<HotSpot> loadHotspots(byte *data, size_t size);
+ Common::Array<Exit> loadExits(byte *data, size_t size);
+ ScalingParams loadScalingParams(byte *data, size_t size);
+ Common::Array<WalkBox> loadWalkboxes(byte *data, size_t size);
Common::Array<Description> loadRoomTexts(Common::File *roomFile, int roomOffset);
- ScalingParams loadScalingParams(Common::File *roomFile, int roomOffset);
+ void resetRoomDefaults(byte *data, size_t size);
+
byte *loadShadowMap(int roomNumber);
void loadRemaps(int roomNumber);
Common::StringArray loadRoomNames();
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 281ba6d9304..604dae90c47 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -99,12 +99,11 @@ void SoundManager::playSound(SonidoFile sound, int volume) {
delete[] data;
return;
}
-
}
-void SoundManager::playSound(byte *soundData, uint32 size,int volume) {
+void SoundManager::playSound(byte *soundData, uint32 size, int volume) {
Audio::AudioStream *stream = Audio::makeRawStream(soundData, size, 11025, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
- if (stream) {
+ if (stream) {
int channel = findFreeChannel();
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
}
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index a0ad426faa9..8564be3c1ee 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -73,7 +73,7 @@ void VideoManager::playIntro() {
if (_chrono->_gameTick && _chrono->getFrameCount() % 2 == 0) {
ChunkHeader chunk;
readChunk(videoFile, chunk);
-
+ debug("Read chunk type %d at frame %d", chunk.chunkType, frameCounter);
switch (chunk.chunkType) {
case 1:
case 2:
@@ -98,8 +98,6 @@ void VideoManager::playIntro() {
byte *voiceBuffer = new byte[voiceData.length];
_introSndFile.read(voiceBuffer, voiceData.length);
_sound->playSound(voiceBuffer, voiceData.length);
- // g_system->getSoundManager()->playSoundBuffer(voiceBuffer, voiceData.length, SOUND_FORMAT_PCM8, 11025);
- // delete[] voiceBuffer;
}
Subtitle *subtitle = getSubtitleForFrame(frameCounter);
Commit: bd027e3ecf98f75c8456553de6ca128a0b0ac41c
https://github.com/scummvm/scummvm/commit/bd027e3ecf98f75c8456553de6ca128a0b0ac41c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:40+02:00
Commit Message:
PELROCK: Reset room states before loading
Changed paths:
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 4d1397a181e..fccc5533045 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -43,6 +43,7 @@ RoomManager::~RoomManager() {
delete[] _pixelsShadows;
_pixelsShadows = nullptr;
}
+ delete[] _resetData;
}
void RoomManager::getPalette(Common::File *roomFile, int roomOffset, byte *palette) {
@@ -209,7 +210,6 @@ Common::Array<Exit> RoomManager::loadExits(byte *data, size_t size) {
Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
int pair10StartingPos = 0x47a;
-
byte hotspot_count = data[pair10StartingPos];
int hotspotsDataStart = pair10StartingPos + 2;
Common::Array<HotSpot> hotspots;
@@ -245,8 +245,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
roomFile->read(pair10, pair10size);
// The user's game can be in any state so we reset to defaults first
- resetRoomDefaults(pair10, pair10size);
-
+ resetRoomDefaults(roomNumber, pair10, pair10size);
byte *pic = nullptr;
size_t pixelDataSize = 0;
@@ -258,7 +257,6 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
Common::Array<Exit> exits = loadExits(pair10, pair10size);
ScalingParams scalingParams = loadScalingParams(pair10, pair10size);
-
Common::Array<Description> descriptions = loadRoomTexts(roomFile, roomOffset);
Common::Array<HotSpot> hotspots;
for (int i = 0; i < anims.size(); i++) {
@@ -320,13 +318,24 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
delete[] pair10;
}
+void RoomManager::init() {
+ Common::File alfred8;
+ if (!alfred8.open("ALFRED.8")) {
+ error("Couldnt find file ALFRED.8");
+ }
+ // _resetDataSize = alfred8.size();
+ // _resetData = new byte[_resetDataSize];
+ // alfred8.read(_resetData, _resetDataSize);
+ // alfred8.close();
+}
+
void RoomManager::loadAnimationPixelData(Common::File *roomFile, int roomOffset, byte *&buffer, size_t &outSize) {
uint32_t pair_offset = roomOffset + (8 * 8);
roomFile->seek(pair_offset, SEEK_SET);
uint32_t offset = roomFile->readUint32LE();
uint32_t size = roomFile->readUint32LE();
- byte *pixelData = new byte[size];
+ byte *pixelData = new byte[size];
roomFile->seek(offset, SEEK_SET);
roomFile->read(pixelData, size);
if (offset > 0 && size > 0) {
@@ -379,7 +388,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
anim.animData = new byte *[anim.nframes];
if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
uint32_t needed = anim.w * anim.h * anim.nframes;
- for(int i = 0; i < anim.nframes; i++) {
+ for (int i = 0; i < anim.nframes; i++) {
anim.animData[i] = new byte[anim.w * anim.h];
extractSingleFrame(pixelData + picOffset, anim.animData[i], i, anim.w, anim.h);
}
@@ -480,8 +489,33 @@ Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, in
return descriptions;
}
-void RoomManager::resetRoomDefaults(byte *data, size_t size) {
-
+void RoomManager::resetRoomDefaults(byte room, byte *&data, size_t size) {
+ Common::File alfred8;
+ if (!alfred8.open("ALFRED.8")) {
+ error("Couldnt find file ALFRED.8");
+ }
+ bool roomDone = false;
+ while (!alfred8.eos() && !roomDone) {
+ ResetEntry entry;
+ entry.room = alfred8.readUint16LE();
+ entry.offset = alfred8.readUint16LE();
+ entry.dataSize = alfred8.readByte();
+ entry.data = new byte[entry.dataSize];
+ alfred8.read(entry.data, entry.dataSize);
+ if (room < entry.room) {
+ // We've passed the room we care about
+ roomDone = true;
+ break;
+ }
+ if (room > entry.room) {
+ // Not the room we care about, skip
+ continue;
+ }
+ debug("Resetting room %d data at offset %d, size %d", entry.room, entry.offset, entry.dataSize);
+ Common::copy(entry.data, entry.data + entry.dataSize, data + entry.offset);
+ // delete[] entry.data;
+ }
+ alfred8.close();
}
void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 462f0e96279..5da0a7b0659 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -31,6 +31,20 @@ namespace Pelrock {
static const int kNumSfxPerRoom = 8;
+struct ResetEntry {
+ uint16 room;
+ uint16 offset;
+ byte dataSize;
+ byte *data = nullptr;
+
+ ~ResetEntry() {
+ if (data != nullptr) {
+ delete[] data;
+ data = nullptr;
+ }
+ }
+};
+
class RoomManager {
public:
RoomManager();
@@ -73,6 +87,7 @@ public:
size_t _conversationDataSize = 0;
private:
+ void init();
void loadAnimationPixelData(Common::File *roomFile, int roomOffset, byte *&buffer, size_t &outSize);
Common::Array<Sprite> loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size);
Common::Array<HotSpot> loadHotspots(byte *data, size_t size);
@@ -81,7 +96,7 @@ private:
Common::Array<WalkBox> loadWalkboxes(byte *data, size_t size);
Common::Array<Description> loadRoomTexts(Common::File *roomFile, int roomOffset);
- void resetRoomDefaults(byte *data, size_t size);
+ void resetRoomDefaults(byte room, byte *&data, size_t size);
byte *loadShadowMap(int roomNumber);
void loadRemaps(int roomNumber);
@@ -90,6 +105,7 @@ private:
Common::Array<byte> loadRoomSfx(Common::File *roomFile, int roomOffset);
Common::StringArray _roomNames;
+ byte *_resetData = nullptr;
};
} // End of namespace Pelrock
Commit: 67b294ed5b2a2d45417eb71c7fa9c261dab5585e
https://github.com/scummvm/scummvm/commit/67b294ed5b2a2d45417eb71c7fa9c261dab5585e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:40+02:00
Commit Message:
PELROCK: Video timing
Changed paths:
engines/pelrock/video/video.cpp
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 8564be3c1ee..a4f726a8478 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -69,8 +69,9 @@ void VideoManager::playIntro() {
while (!videoExitFlag && !g_engine->shouldQuit() && _events->_lastKeyEvent != Common::KEYCODE_ESCAPE) {
_chrono->updateChrono();
_events->pollEvent();
-
- if (_chrono->_gameTick && _chrono->getFrameCount() % 2 == 0) {
+ Subtitle *subtitle = getSubtitleForFrame(frameCounter);
+ int frameSkip = subtitle != nullptr ? 4 : 2;
+ if (_chrono->_gameTick && _chrono->getFrameCount() % frameSkip == 0) {
ChunkHeader chunk;
readChunk(videoFile, chunk);
debug("Read chunk type %d at frame %d", chunk.chunkType, frameCounter);
@@ -91,6 +92,14 @@ void VideoManager::playIntro() {
}
if (_voiceEffect.contains(frameCounter)) {
+ // Wait for any playing voice to finish before starting new one
+ while (_sound->isPlaying()) {
+ _events->pollEvent();
+ g_system->delayMillis(10);
+ if (g_engine->shouldQuit() || _events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
+ break;
+ }
+ }
Voice voice = _voiceEffect[frameCounter];
debug("Playing voice effect: '%s'", voice.filename.c_str());
VoiceData voiceData = _sounds[voice.filename];
@@ -100,7 +109,7 @@ void VideoManager::playIntro() {
_sound->playSound(voiceBuffer, voiceData.length);
}
- Subtitle *subtitle = getSubtitleForFrame(frameCounter);
+
if (subtitle != nullptr) {
Common::StringArray lines = _dialog->wordWrap(subtitle->text)[0];
Commit: fc798c1b53046915de74bdd3ff7bf415aee9fc1b
https://github.com/scummvm/scummvm/commit/fc798c1b53046915de74bdd3ff7bf415aee9fc1b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:40+02:00
Commit Message:
PELROCK: Saves room changes in memory gamestate
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 69724377a5f..5582eef7204 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -20,10 +20,10 @@
*/
#include "pelrock/actions.h"
+#include "pelrock.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
-#include "pelrock.h"
namespace Pelrock {
@@ -35,7 +35,7 @@ const ActionEntry actionTable[] = {
{268, CLOSE, &PelrockEngine::closeDoor},
{3, PICKUP, &PelrockEngine::pickUpPhoto},
{0, PICKUP, &PelrockEngine::pickYellowBook}, // Generic pickup for other items
- {4, PICKUP, &PelrockEngine::pickUpBrick}, // Brick
+ {4, PICKUP, &PelrockEngine::pickUpBrick}, // Brick
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOp}, // Generic pickup action
@@ -57,16 +57,17 @@ void PelrockEngine::openDrawer(HotSpot *hotspot) {
return;
}
_room->addSticker(_res->getSticker(91));
- hotspot->isEnabled = false;
+ // TODO: Check if we need to disable the hotspot
+ _room->disableHotspot(hotspot);
}
void PelrockEngine::closeDrawer(HotSpot *hotspot) {
_room->removeSticker(91);
- hotspot->isEnabled = true;
+ _room->enableHotspot(hotspot);
}
void PelrockEngine::openDoor(HotSpot *hotspot) {
- _room->addSticker(_res->getSticker(93));
+ _room->addSticker(_res->getSticker(93), false);
_room->_currentRoomExits[0].isEnabled = true;
}
@@ -91,11 +92,11 @@ void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
g_system->delayMillis(10);
}
_inventoryItems.push_back(hotspot->extra);
- hotspot->isEnabled = false;
+ _room->disableHotspot(hotspot);
}
void PelrockEngine::pickUpPhoto(HotSpot *hotspot) {
- _room->findHotspotByExtra(261)->isEnabled = true;
+ _room->enableHotspot(_room->findHotspotByExtra(261));
}
void PelrockEngine::pickYellowBook(HotSpot *hotspot) {
@@ -103,7 +104,7 @@ void PelrockEngine::pickYellowBook(HotSpot *hotspot) {
}
void PelrockEngine::pickUpBrick(HotSpot *hotspot) {
- _room->addSticker(_res->getSticker(133));
+ _room->addSticker(_res->getSticker(133));
}
void PelrockEngine::noOp(HotSpot *hotspot) {
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 6d1aa8f7b3e..78db638a13d 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -135,7 +135,7 @@ void MenuManager::menuLoop() {
_events->_leftMouseClicked = false;
} else if (_events->_rightMouseClicked) {
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
- g_engine->stateGame = GAME;
+ g_engine->_state.stateGame = GAME;
_events->_rightMouseClicked = false;
tearDown();
} else {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b6bcfeccc17..a2f259e6424 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -115,22 +115,22 @@ Common::Error PelrockEngine::run() {
Graphics::FrameLimiter limiter(g_system, 60);
if (shouldPlayIntro == false) {
- stateGame = GAME;
+ _state.stateGame = GAME;
// stateGame = SETTINGS;
} else {
- stateGame = INTRO;
+ _state.stateGame = INTRO;
_videoManager->playIntro();
- stateGame = GAME;
+ _state.stateGame = GAME;
}
if (!shouldQuit())
init();
while (!shouldQuit()) {
- if (stateGame == SETTINGS) {
+ if (_state.stateGame == SETTINGS) {
changeCursor(DEFAULT);
_menu->menuLoop();
- } else if (stateGame == GAME) {
+ } else if (_state.stateGame == GAME) {
gameLoop();
}
_screen->update();
@@ -329,7 +329,7 @@ void PelrockEngine::checkMouse() {
} else if (_events->_rightMouseClicked) {
g_system->getPaletteManager()->setPalette(_menu->_mainMenuPalette, 0, 256);
_events->_rightMouseClicked = false;
- stateGame = SETTINGS;
+ _state.stateGame = SETTINGS;
}
checkMouseHover();
}
@@ -411,8 +411,13 @@ void PelrockEngine::paintDebugLayer() {
}
void PelrockEngine::placeStickers() {
- for (int i = 0; i < _room->_currentRoomStickers.size(); i++) {
- Sticker sticker = _room->_currentRoomStickers[i];
+ for (int i = 0; i < _state.roomStickers[_room->_currentRoomNumber].size(); i++) {
+ Sticker sticker = _state.roomStickers[_room->_currentRoomNumber][i];
+ placeSticker(sticker);
+ }
+ // also place temporary stickers
+ for (int i = 0; i < _room->_transientStickers.size(); i++) {
+ Sticker sticker = _room->_transientStickers[i];
placeSticker(sticker);
}
}
@@ -830,7 +835,6 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
void PelrockEngine::checkLongMouseClick(int x, int y) {
int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
-
if (hotspotIndex != -1 && !_actionPopupState.isActive) {
_actionPopupState.x = alfredState.x + kAlfredFrameWidth / 2 - kBalloonWidth / 2;
@@ -990,7 +994,7 @@ int PelrockEngine::isHotspotUnder(int x, int y) {
return spriteUnder ? i : -1;
}
- return i;
+ return hotspot.index;
}
}
return -1;
@@ -1000,9 +1004,7 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
for (int i = 0; i < _room->_currentRoomExits.size(); i++) {
Exit exit = _room->_currentRoomExits[i];
if (x >= exit.x && x <= (exit.x + exit.w) &&
- y >= exit.y && y <= (exit.y + exit.h)
- && exit.isEnabled
- ) {
+ y >= exit.y && y <= (exit.y + exit.h) && exit.isEnabled) {
return &(_room->_currentRoomExits[i]);
}
}
@@ -1326,8 +1328,6 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
_sound->stopMusic();
}
- _room->_currentRoomNumber = number;
-
_screen->markAllDirty();
_screen->update();
roomFile.close();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 9484d292a29..74ac6c087ea 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -145,6 +145,7 @@ private:
bool gameInitialized = false;
bool screenReady = false;
+
// int prevDirX = 0;
// int prevDirY = 0;
// Common::String objectToShow = "";
@@ -162,7 +163,8 @@ public:
RoomManager *_room = nullptr;
AlfredState alfredState;
byte *_compositeBuffer = nullptr; // Working composition buffer
- GameState stateGame = INTRO;
+
+ GameStateData _state;
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index fccc5533045..c64d7394728 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -94,31 +94,64 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
}
}
-void RoomManager::addSticker(Sticker sticker) {
- _currentRoomStickers.push_back(sticker);
+void RoomManager::addSticker(Sticker sticker, bool persist) {
+ if (persist)
+ g_engine->_state.roomStickers[_currentRoomNumber].push_back(sticker);
+ else
+ _transientStickers.push_back(sticker);
}
void RoomManager::removeSticker(int stickerIndex) {
int index = -1;
- for (int i = 0; i < _currentRoomStickers.size(); i++) {
- if (_currentRoomStickers[i].stickerIndex == stickerIndex) {
+ for (int i = 0; i < g_engine->_state.roomStickers[_currentRoomNumber].size(); i++) {
+ if (g_engine->_state.roomStickers[_currentRoomNumber][i].stickerIndex == stickerIndex) {
index = i;
break;
}
}
- if (index != -1 && index < _currentRoomStickers.size())
- _currentRoomStickers.remove_at(index);
+ if (index != -1 && index < g_engine->_state.roomStickers[_currentRoomNumber].size())
+ g_engine->_state.roomStickers[_currentRoomNumber].remove_at(index);
}
bool RoomManager::hasSticker(int index) {
- for (int i = 0; i < _currentRoomStickers.size(); i++) {
- if (_currentRoomStickers[i].stickerIndex == index) {
+ for (int i = 0; i < g_engine->_state.roomStickers[_currentRoomNumber].size(); i++) {
+ if (g_engine->_state.roomStickers[_currentRoomNumber][i].stickerIndex == index) {
return true;
}
}
return false;
}
+void RoomManager::changeExit(Exit exit) {
+ g_engine->_state.roomExitChanges[_currentRoomNumber].push_back({_currentRoomNumber, exit.index, exit});
+}
+
+void RoomManager::changeWalkBox(WalkBox walkbox) {
+ g_engine->_state.roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
+}
+
+void RoomManager::changeHotSpot(HotSpot hotspot) {
+ g_engine->_state.roomHotSpotChanges[_currentRoomNumber].push_back({_currentRoomNumber, hotspot.innerIndex, hotspot});
+}
+
+void RoomManager::enableHotspot(HotSpot *hotspot, bool persist) {
+ hotspot->isEnabled = true;
+ if (persist) {
+ changeHotSpot(*hotspot);
+ }
+}
+
+void RoomManager::disableHotspot(HotSpot *hotspot, bool persist) {
+ hotspot->isEnabled = false;
+ if (persist) {
+ changeHotSpot(*hotspot);
+ }
+}
+
+void RoomManager::addWalkbox(WalkBox walkbox) {
+ g_engine->_state.roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
+}
+
HotSpot *RoomManager::findHotspotByExtra(uint16 extra) {
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
if (_currentRoomHotspots[i].extra == extra) {
@@ -170,7 +203,23 @@ Common::Array<Exit> RoomManager::loadExits(byte *data, size_t size) {
int exitDataOffset = 0x1BF;
for (int i = 0; i < exitCount; i++) {
int exitOffset = exitDataOffset + i * 14;
+ bool isChanged = false;
+ if (g_engine->_state.roomExitChanges.contains(_currentRoomNumber)) {
+ // if the exit has been changed, load the changed version
+ for (int j = 0; j < g_engine->_state.roomExitChanges[_currentRoomNumber].size(); j++) {
+ if (g_engine->_state.roomExitChanges[_currentRoomNumber][j].exitIndex == i) {
+ exits.push_back(g_engine->_state.roomExitChanges[_currentRoomNumber][j].exit);
+ isChanged = true;
+ break;
+ }
+ }
+ }
+
+ if (isChanged)
+ continue;
+
Exit exit;
+ exit.index = i;
exit.targetRoom = READ_LE_INT16(data + exitOffset);
exit.isEnabled = data[exitOffset + 2];
exit.x = READ_LE_INT16(data + exitOffset + 3);
@@ -200,9 +249,9 @@ Common::Array<Exit> RoomManager::loadExits(byte *data, size_t size) {
}
exits.push_back(exit);
- debug("Exit %d: targetRoom=%d isEnabled=%d x=%d y=%d w=%d h=%d targetX=%d targetY=%d dir=%d",
- i, exit.targetRoom, exit.isEnabled, exit.x, exit.y, exit.w, exit.h,
- exit.targetX, exit.targetY, exit.dir);
+ // debug("Exit %d: targetRoom=%d isEnabled=%d x=%d y=%d w=%d h=%d targetX=%d targetY=%d dir=%d",
+ // i, exit.targetRoom, exit.isEnabled, exit.x, exit.y, exit.w, exit.h,
+ // exit.targetX, exit.targetY, exit.dir);
}
return exits;
}
@@ -216,6 +265,21 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
for (int i = 0; i < hotspot_count; i++) {
int hotspotOffset = hotspotsDataStart + i * 9;
HotSpot spot;
+ spot.innerIndex = i;
+ spot.index = i;
+ bool isChanged = false;
+ if (g_engine->_state.roomHotSpotChanges.contains(_currentRoomNumber)) {
+ // if the hotspot has been changed, load the changed version
+ for (int j = 0; j < g_engine->_state.roomHotSpotChanges[_currentRoomNumber].size(); j++) {
+ if (g_engine->_state.roomHotSpotChanges[_currentRoomNumber][j].hotspotIndex == spot.innerIndex) {
+ hotspots.push_back(g_engine->_state.roomHotSpotChanges[_currentRoomNumber][j].hotspot);
+ isChanged = true;
+ break;
+ }
+ }
+ }
+ if (isChanged)
+ continue;
spot.actionFlags = data[hotspotOffset];
spot.x = READ_LE_INT16(data + hotspotOffset + 1);
spot.y = READ_LE_INT16(data + hotspotOffset + 3);
@@ -223,15 +287,18 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
spot.h = data[hotspotOffset + 6];
spot.isSprite = false;
spot.extra = READ_LE_INT16(data + hotspotOffset + 7);
- debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d", i, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra);
+ debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d, isEnabled=%d", spot.innerIndex, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra, spot.isEnabled);
hotspots.push_back(spot);
}
+
return hotspots;
}
void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
+
uint32_t outPos = 0;
- _currentRoomStickers.clear();
+ _transientStickers.clear();
+ _currentRoomNumber = roomNumber;
int roomOffset = roomNumber * kRoomStructSize;
uint32_t pair10offset = roomOffset + (10 * 8);
@@ -423,8 +490,22 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
int16 w = READ_LE_INT16(data + boxOffset + 4);
int16 h = READ_LE_INT16(data + boxOffset + 6);
byte flags = data[boxOffset + 8];
- debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+ // debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
WalkBox box;
+ box.index = i;
+ bool isChanged = false;
+ if (g_engine->_state.roomWalkBoxChanges.contains(_currentRoomNumber)) {
+ // if the walkbox has been changed, load the changed version
+ for (int j = 0; j < g_engine->_state.roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
+ if (g_engine->_state.roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == i) {
+ walkboxes.push_back(g_engine->_state.roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
+ isChanged = true;
+ break;
+ }
+ }
+ }
+ if (isChanged)
+ continue;
box.x = x1;
box.y = y1;
box.w = w;
@@ -432,6 +513,23 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
box.flags = flags;
walkboxes.push_back(box);
}
+
+ if (g_engine->_state.roomWalkBoxChanges.contains(_currentRoomNumber)) {
+ // Add any new walkboxes that were added
+ for (int j = 0; j < g_engine->_state.roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
+ bool found = false;
+ for (int i = 0; i < walkboxes.size(); i++) {
+ if (g_engine->_state.roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == walkboxes[i].index) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ walkboxes.push_back(g_engine->_state.roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
+ }
+ }
+ }
+
return walkboxes;
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 5da0a7b0659..c3f2b9ed8e8 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -53,9 +53,19 @@ public:
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
- void addSticker(Sticker sticker);
+ void addSticker(Sticker sticker, bool persist = true);
void removeSticker(int index);
bool hasSticker(int index);
+ void changeExit(Exit exit);
+ void changeWalkBox(WalkBox walkbox);
+ void changeHotSpot(HotSpot hotspot);
+ /**
+ * Utility function to enable or disable a hotspot, with an option to persist the change.
+ */
+ void enableHotspot(HotSpot *hotspot, bool persist = true);
+ void disableHotspot(HotSpot *hotspot, bool persist = true);
+ void addWalkbox(WalkBox walkbox);
+
HotSpot *findHotspotByExtra(uint16 extra);
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
@@ -82,13 +92,13 @@ public:
byte _musicTrack = 0;
Common::Array<byte> _roomSfx;
PaletteAnim *_currentPaletteAnim = nullptr;
- Common::Array<Sticker> _currentRoomStickers;
byte *_conversationData = nullptr;
size_t _conversationDataSize = 0;
+ Common::Array<Sticker> _transientStickers;
private:
void init();
- void loadAnimationPixelData(Common::File *roomFile, int roomOffset, byte *&buffer, size_t &outSize);
+ void loadAnimationPixelData(Common::File *roomFile, int roomOffset, byte *&buffer, size_t &outSize);
Common::Array<Sprite> loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size);
Common::Array<HotSpot> loadHotspots(byte *data, size_t size);
Common::Array<Exit> loadExits(byte *data, size_t size);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index d53fa540694..dcea3d58394 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -170,6 +170,7 @@ struct Anim {
};
struct Exit {
+ byte index;
int16 x;
int16 y;
byte w;
@@ -183,7 +184,7 @@ struct Exit {
};
struct Sprite {
- int index; // number of the animation in the rooms
+ byte index; // number of the animation in the rooms
byte type;
int16 x; // 0
int16 y; // 2
@@ -201,7 +202,8 @@ struct Sprite {
};
struct HotSpot {
- int index;
+ byte index;
+ byte innerIndex;
int id;
int16 x;
int16 y;
@@ -243,48 +245,6 @@ struct TalkingAnims {
byte **animB = nullptr;
};
-struct ConversationElement {
- enum Type {
- DIALOGUE,
- CHOICE_MARKER,
- END_CONV,
- END_BRANCH
- } type;
-
- Common::String speaker;
- byte speakerId;
- Common::String text;
- int choiceIndex;
- bool isRealChoice;
-
- ConversationElement() : type(DIALOGUE), choiceIndex(-1), isRealChoice(false) {}
-};
-
-struct ConversationNode {
- enum NodeType {
- ROOT,
- CHOICE,
- RESPONSE
- } type;
-
- Common::String text;
- Common::String speaker;
- byte speakerId;
- int choiceIndex;
- bool terminated;
-
- Common::Array<ConversationNode> choices;
- Common::Array<ConversationNode> responses;
- Common::Array<ConversationNode> subchoices;
-
- ConversationNode() : type(ROOT), choiceIndex(-1), terminated(false) {}
-};
-
-struct StackEntry {
- ConversationNode *node;
- int index;
-};
-
struct Description {
byte itemId;
byte index;
@@ -294,6 +254,7 @@ struct Description {
};
struct WalkBox {
+ byte index;
int16 x;
int16 y;
int16 w;
@@ -330,6 +291,24 @@ enum GameState {
INTRO = 106,
};
+struct HotSpotChange {
+ byte roomNumber;
+ byte hotspotIndex;
+ HotSpot hotspot;
+};
+
+struct ExitChange {
+ byte roomNumber;
+ byte exitIndex;
+ Exit exit;
+};
+
+struct WalkBoxChange {
+ byte roomNumber;
+ byte walkboxIndex;
+ WalkBox walkbox;
+};
+
struct InventoryObject {
byte index;
Common::String description;
@@ -380,6 +359,15 @@ struct PaletteAnim {
byte curFrameCount = 0;
};
+
+struct GameStateData {
+ GameState stateGame = INTRO;
+ Common::HashMap<byte, Common::Array<Sticker>> roomStickers;
+ Common::HashMap<byte, Common::Array<ExitChange>> roomExitChanges;
+ Common::HashMap<byte, Common::Array<WalkBoxChange>> roomWalkBoxChanges;
+ Common::HashMap<byte, Common::Array<HotSpotChange>> roomHotSpotChanges;
+};
+
} // End of namespace Pelrock
#endif
Commit: 6da8f84da294b7de54eb99bdd7bdc049f439bf38
https://github.com/scummvm/scummvm/commit/6da8f84da294b7de54eb99bdd7bdc049f439bf38
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:41+02:00
Commit Message:
PELROCK: Refactor dialog handler, reset and skip disabled conversations
Changed paths:
A engines/pelrock/saveload.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/graphics.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index e5429d4c61f..046bf05eac2 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -108,7 +108,7 @@ uint32 DialogManager::readTextBlock(
}
// Regular text - does not need decoding
- if (b >= 0x20 && b <= 0x83) {
+ if (b >= CHAR_SPACE && b <= 0x83) {
outText += b;
}
pos++;
@@ -187,14 +187,14 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int yPos = 0;
if (speakerId == ALFRED_COLOR) {
- if(g_engine->alfredState.animState != ALFRED_TALKING) {
+ if (g_engine->alfredState.animState != ALFRED_TALKING) {
g_engine->alfredState.setState(ALFRED_TALKING);
}
if (_curSprite != nullptr) {
_curSprite->isTalking = false;
}
// Offset X position for Alfred to avoid overlapping with his sprite
- xPos = g_engine->alfredState.x - maxWidth / 2; //+ kAlfredFrameWidth / 2 - maxWidth / 2;
+ xPos = g_engine->alfredState.x - maxWidth / 2; //+ kAlfredFrameWidth / 2 - maxWidth / 2;
yPos = g_engine->alfredState.y - kAlfredFrameHeight - height; // Above sprite, adjust for line
} else {
g_engine->alfredState.setState(ALFRED_IDLE);
@@ -220,8 +220,8 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos), 255);
drawPos(_screen, xPos, yPos, speakerId);
drawRect(_screen, xPos, yPos,
- s.getRect().width(),
- s.getRect().height(), speakerId);
+ s.getRect().width(),
+ s.getRect().height(), speakerId);
// Present to screen
_screen->markAllDirty();
_screen->update();
@@ -294,58 +294,6 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
uint32 pos = startPos;
outChoices->clear();
int firstChoiceIndex = -1;
- int choiceCount = 0;
-
- // Find first choice marker
- while (pos < dataSize) {
- byte b = data[pos];
-
- // Stop at end markers
- if (b == CTRL_ALT_END_MARKER_1 || b == CTRL_END_BRANCH || b == CTRL_ALT_END_MARKER_3) {
- break;
- }
-
- // Found first choice marker
- if (b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_2) {
- if (pos + 1 < dataSize) {
- firstChoiceIndex = data[pos + 1];
- ChoiceOption opt;
- opt.index = firstChoiceIndex;
- opt.dataOffset = pos;
- opt.isDisabled = false;
-
- // Parse the choice text
- uint32 textPos = pos + 4; // Skip marker + index + 2 speaker bytes
- textPos += 2;
- while (textPos < dataSize) {
- byte tb = data[textPos];
- if (tb == CTRL_END_TEXT || tb == CTRL_DIALOGUE_MARKER ||
- tb == CTRL_DIALOGUE_MARKER_2 || tb == CTRL_END_BRANCH ||
- tb == CTRL_ALT_END_MARKER_1) {
- break;
- }
-
- if (tb >= 0x20 && tb < 0x7A) {
- opt.text += (char)tb;
- } else {
- byte decoded = decodeChar(tb);
- debug("Parsing choice char: 0x%02X, decoded: 0x%02X", tb, decoded);
- if (decoded != tb || (decoded >= 0x20 && decoded <= 0xB4)) {
- opt.text += (char)decoded;
- }
- }
- textPos++;
- }
-
- outChoices->push_back(opt);
- choiceCount = 1;
- pos++;
- break;
- }
- }
-
- pos++;
- }
// Scan for additional choices with SAME index
while (pos < dataSize) {
@@ -359,21 +307,25 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
// Found a dialogue marker
if (b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_2) {
if (pos + 1 < dataSize) {
+ if (firstChoiceIndex == -1) {
+ firstChoiceIndex = data[pos + 1];
+ }
int choiceIndex = data[pos + 1];
// Only collect choices with same index
if (choiceIndex == firstChoiceIndex) {
// Check if disabled
- bool isDisabled = (b == CTRL_DISABLED_CHOICE);
ChoiceOption opt;
opt.index = choiceIndex;
opt.dataOffset = pos;
- opt.isDisabled = isDisabled;
-
+ pos += 2; // Move past marker + index
+ if (data[pos] == CTRL_DISABLED_CHOICE) {
+ opt.isDisabled = true;
+ }
// Parse the choice text
uint32 textPos = pos + 4;
- textPos += 2; // Skip marker + index + 2 speaker bytes
+ // textPos += 2; // Skip marker + index + 2 speaker bytes
while (textPos < dataSize) {
byte tb = data[textPos];
if (tb == CTRL_END_TEXT || tb == CTRL_DIALOGUE_MARKER ||
@@ -393,9 +345,8 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
}
textPos++;
}
-
- outChoices->push_back(opt);
- choiceCount++;
+ if (!opt.isDisabled)
+ outChoices->push_back(opt);
} else if (choiceIndex < firstChoiceIndex) {
// Different choice index - stop scanning
break;
@@ -674,7 +625,7 @@ bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speake
}
bool isEndMarker(char char_byte) {
- return char_byte == CHAR_END_MARKER_1 || char_byte == CHAR_END_MARKER_2 || char_byte == CHAR_END_MARKER_3 || char_byte == CHAR_END_MARKER_4;
+ return char_byte == CTRL_END_TEXT || char_byte == CTRL_END_CONVERSATION || char_byte == CTRL_ACTION_TRIGGER || char_byte == CTRL_GO_BACK;
}
int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
@@ -694,7 +645,7 @@ int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
}
// Count ALL trailing spaces as part of this word
if (pos < text.size() && !isEnd) {
- if (text[pos] == CHAR_END_MARKER_3) { // 0xF8 (-8) special case
+ if (text[pos] == CTRL_ACTION_TRIGGER) { // 0xF8 (-8) special case
wordLength += 3;
} else {
// Count all consecutive spaces
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 230dfa135ae..3113a1c6a68 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -34,18 +34,10 @@ namespace Pelrock {
// Control character codes (negative values in signed char)
#define CHAR_SPACE 0x20 /* ' ' */
-#define CHAR_END_MARKER_1 0xFD /* -3 (end of text marker) */
-#define CHAR_END_MARKER_2 0xF4 /* -0xC (alternate end marker) */
-#define CHAR_END_MARKER_3 0xF8 /* -8 (another end marker) */
-#define CHAR_END_MARKER_4 0xF0 /* -0x10 (another end marker) */
-#define CHAR_NEWLINE 0xF6 /* -10 (newline marker) */
-#define CHAR_PAGE_BREAK 0xF9 /* marker inserted when switching pages */
-
-// Conversation control bytes
#define CTRL_SPEAKER_ID 0x08 /* Next byte is speaker ID (color) */
#define CTRL_END_TEXT 0xFD /* End of text segment */
#define CTRL_TEXT_TERMINATOR 0xFC /* Text terminator */
-#define CTRL_DIALOGUE_MARKER 0xFB /* Choice marker */
+#define CTRL_DIALOGUE_MARKER 0xF1 /* Choice marker that sticks */
#define CTRL_DISABLED_CHOICE 0xFA /* Disabled choice marker */
#define CTRL_PAGE_BREAK_CONV 0xF9 /* Page break in conversation */
#define CTRL_ACTION_TRIGGER 0xF8 /* Action trigger */
@@ -53,7 +45,7 @@ namespace Pelrock {
#define CTRL_LINE_CONTINUE 0xF6 /* Line continue/newline */
#define CTRL_ALT_END_MARKER_1 0xF5 /* Alt end marker - do nothing */
#define CTRL_END_CONVERSATION 0xF4 /* End conversation and disable option */
-#define CTRL_DIALOGUE_MARKER_2 0xF1 /* Alt choice marker that disappears */
+#define CTRL_DIALOGUE_MARKER_2 0xFB /* Alt choice marker that disappears */
#define CTRL_GO_BACK 0xF0 /* Go back in conversation */
#define CTRL_ALT_END_MARKER_2 0xEB /* Alt end marker 2 */
#define CTRL_ALT_END_MARKER_3 0xFE /* Alt end marker 3 */
@@ -66,6 +58,7 @@ struct ChoiceOption {
Common::String text;
bool isDisabled;
uint32 dataOffset;
+ bool shouldDisableOnSelect = false;
ChoiceOption() : index(-1), isDisabled(false), dataOffset(0) {}
};
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 355b773e5f9..218e52b9e39 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -38,7 +38,7 @@ Common::Point GraphicsManager::showOverlay(int height, byte *buf) {
for (int x = 0; x < 640; x++) {
for (int y = overlayY; y < 400; y++) {
int index = y * 640 + x;
- buf[index] = g_engine->_room->overlayRemap[buf[index]];
+ buf[index] = g_engine->_room->paletteRemaps[1][buf[index]];
}
}
return Common::Point(overlayX, overlayY);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a2f259e6424..bb0548d69b7 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -746,7 +746,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
if (shadeCharacter) {
for (int i = 0; i < finalWidth * finalHeight; i++) {
if (finalBuf[i] != 255) {
- finalBuf[i] = _room->alfredRemap[finalBuf[i]];
+ finalBuf[i] = _room->paletteRemaps[0][finalBuf[i]];
}
}
}
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 4a9f1000d2c..781ecd6ea59 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -285,7 +285,7 @@ Common::Array<Common::Array<Common::String>> ResourceManager::processTextData(by
Common::StringArray lines;
Common::Array<Common::Array<Common::String>> texts;
while (pos < size) {
- if (data[pos] == 0xFD) {
+ if (data[pos] == CTRL_END_TEXT) {
if (!desc.empty()) {
lines.push_back(desc);
@@ -300,7 +300,7 @@ Common::Array<Common::Array<Common::String>> ResourceManager::processTextData(by
pos++;
continue;
}
- if (data[pos] == 0x08) {
+ if (data[pos] == CTRL_SPEAKER_ID) {
byte color = data[pos + 1];
desc.append(1, '@');
desc.append(1, color);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index c64d7394728..478d7d15089 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -33,12 +33,6 @@ RoomManager::RoomManager() {
}
RoomManager::~RoomManager() {
- // delete[] _currentRoomHotspots;
- // delete[] _currentRoomAnims;
- // delete[] _currentRoomExits;
- // delete[] _currentRoomWalkboxes;
- // delete[] _currentRoomDescriptions;
- // delete[] _currentRoomConversations;
if (_pixelsShadows != nullptr) {
delete[] _pixelsShadows;
_pixelsShadows = nullptr;
@@ -294,6 +288,36 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
return hotspots;
}
+void RoomManager::resetConversationStates(byte roomNumber, byte *conversationData, size_t conversationDataSize) {
+ Common::File alfredB;
+ if (!alfredB.open("ALFRED.B")) {
+ debug("Could not open ALFRED.B to reset conversation states!");
+ return;
+ }
+ bool roomDone = false;
+ while (!alfredB.eos() && !roomDone) {
+ ResetEntry entry;
+ entry.room = alfredB.readUint16LE();
+ entry.offset = alfredB.readUint16LE();
+ entry.dataSize = alfredB.readByte();
+ entry.data = new byte[entry.dataSize];
+ alfredB.read(entry.data, entry.dataSize);
+ if (roomNumber < entry.room) {
+ // We've passed the room we care about
+ roomDone = true;
+ break;
+ }
+ if (roomNumber > entry.room) {
+ // Not the room we care about, skip
+ continue;
+ }
+ debug("Resetting room %d conversation data at offset %d, size %d", entry.room, entry.offset, entry.dataSize);
+ Common::copy(entry.data, entry.data + entry.dataSize, conversationData + entry.offset);
+ // delete[] entry.data;
+ }
+ alfredB.close();
+}
+
void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
uint32_t outPos = 0;
@@ -301,9 +325,20 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
_currentRoomNumber = roomNumber;
int roomOffset = roomNumber * kRoomStructSize;
+ // Pairs 0-7 are background data, already loaded
+
+ // Pair 8 - Animation Pixel Data
+ byte *pic = nullptr;
+ size_t pixelDataSize = 0;
+ loadAnimationPixelData(roomFile, roomOffset, pic, pixelDataSize);
+
+ // Pair 9 - Music and sound
+ _musicTrack = loadMusicTrackForRoom(roomFile, roomOffset);
+ _roomSfx = loadRoomSfx(roomFile, roomOffset);
+
+ // Pair 10
uint32_t pair10offset = roomOffset + (10 * 8);
roomFile->seek(pair10offset, SEEK_SET);
- // roomFile->skip(4);
uint32_t pair10dataOffset = roomFile->readUint32LE();
uint32_t pair10size = roomFile->readUint32LE();
@@ -312,56 +347,38 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
roomFile->read(pair10, pair10size);
// The user's game can be in any state so we reset to defaults first
- resetRoomDefaults(roomNumber, pair10, pair10size);
-
- byte *pic = nullptr;
- size_t pixelDataSize = 0;
- loadAnimationPixelData(roomFile, roomOffset, pic, pixelDataSize);
+ resetMetadataDefaults(roomNumber, pair10, pair10size);
- Common::Array<Sprite> anims = loadRoomAnimations(pic, pixelDataSize, pair10, pair10size);
+ Common::Array<Sprite> sprites = loadRoomAnimations(pic, pixelDataSize, pair10, pair10size);
Common::Array<HotSpot> staticHotspots = loadHotspots(pair10, pair10size);
- Common::Array<WalkBox> walkboxes = loadWalkboxes(pair10, pair10size);
- Common::Array<Exit> exits = loadExits(pair10, pair10size);
- ScalingParams scalingParams = loadScalingParams(pair10, pair10size);
- Common::Array<Description> descriptions = loadRoomTexts(roomFile, roomOffset);
- Common::Array<HotSpot> hotspots;
- for (int i = 0; i < anims.size(); i++) {
+ _currentRoomAnims = sprites;
+ _currentRoomHotspots = unifyHotspots(sprites, staticHotspots);
+ _currentRoomExits = loadExits(pair10, pair10size);
+ _currentRoomWalkboxes = loadWalkboxes(pair10, pair10size);
+ _scaleParams = loadScalingParams(pair10, pair10size);
- HotSpot thisHotspot;
- thisHotspot.index = i;
- thisHotspot.x = anims[i].x;
- thisHotspot.y = anims[i].y;
- thisHotspot.w = anims[i].w;
- thisHotspot.h = anims[i].h;
- thisHotspot.extra = anims[i].extra;
- thisHotspot.actionFlags = anims[i].actionFlags;
- thisHotspot.isEnabled = !anims[i].isDisabled;
- thisHotspot.isSprite = true;
- thisHotspot.zOrder = anims[i].zOrder;
- hotspots.push_back(thisHotspot);
- }
+ // Pair 11 is the palette, already loaded
- // debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
- for (int i = 0; i < staticHotspots.size(); i++) {
- HotSpot hotspot = staticHotspots[i];
- hotspot.index = anims.size() + i;
- hotspots.push_back(hotspot);
- }
+ // Pair 12 - Room Texts
+ uint32_t pair12offset = roomOffset + (12 * 8);
+ roomFile->seek(pair12offset, SEEK_SET);
+ uint32_t pair12dataOffset = roomFile->readUint32LE();
+ uint32_t pair12size = roomFile->readUint32LE();
- byte *shadows = loadShadowMap(roomNumber);
- loadRemaps(roomNumber);
+ byte *pair12 = new byte[pair12size];
+ roomFile->seek(pair12dataOffset, SEEK_SET);
+ roomFile->read(pair12, pair12size);
- int walkboxCount = 0;
- _currentRoomAnims = anims;
- _currentRoomHotspots = hotspots;
- _currentRoomExits = exits;
- _currentRoomWalkboxes = walkboxes;
- _currentRoomDescriptions = descriptions;
- _scaleParams = scalingParams;
- Common::copy(shadows, shadows + (640 * 400), _pixelsShadows);
- _musicTrack = loadMusicTrackForRoom(roomFile, roomOffset);
- _roomSfx = loadRoomSfx(roomFile, roomOffset);
+ resetConversationStates(roomNumber, pair12, pair12size);
+ uint32 lastDescPos = loadDescriptions(pair12, pair12size, _currentRoomDescriptions);
+ loadConversationData(pair12, pair12size, lastDescPos, _conversationDataSize, _conversationData);
+
+ if (_pixelsShadows != nullptr)
+ delete[] _pixelsShadows;
+ _pixelsShadows = loadShadowMap(roomNumber);
+
+ loadRemaps(roomNumber);
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
@@ -370,8 +387,8 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
for (int i = 0; i < _currentRoomExits.size(); i++) {
Exit exit = _currentRoomExits[i];
- // drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 100 + i);
}
+
PaletteAnim *anim = getPaletteAnimForRoom(roomNumber);
if (anim != nullptr) {
if (_currentPaletteAnim != nullptr) {
@@ -383,6 +400,33 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
}
delete[] pair10;
+ delete[] pair12;
+}
+
+Common::Array<HotSpot> RoomManager::unifyHotspots(Common::Array<Pelrock::Sprite> &anims, Common::Array<Pelrock::HotSpot> &staticHotspots) {
+ Common::Array<HotSpot> unifiedHotspots;
+ for (int i = 0; i < anims.size(); i++) {
+ HotSpot thisHotspot;
+ thisHotspot.index = i;
+ thisHotspot.x = anims[i].x;
+ thisHotspot.y = anims[i].y;
+ thisHotspot.w = anims[i].w;
+ thisHotspot.h = anims[i].h;
+ thisHotspot.extra = anims[i].extra;
+ thisHotspot.actionFlags = anims[i].actionFlags;
+ thisHotspot.isEnabled = !anims[i].isDisabled;
+ thisHotspot.isSprite = true;
+ thisHotspot.zOrder = anims[i].zOrder;
+ unifiedHotspots.push_back(thisHotspot);
+ }
+
+ // debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
+ for (int i = 0; i < staticHotspots.size(); i++) {
+ HotSpot hotspot = staticHotspots[i];
+ hotspot.index = anims.size() + i;
+ unifiedHotspots.push_back(hotspot);
+ }
+ return unifiedHotspots;
}
void RoomManager::init() {
@@ -533,35 +577,26 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
return walkboxes;
}
-Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, int roomOffset) {
- uint32_t pair12_offset_pos = roomOffset + (12 * 8);
- roomFile->seek(pair12_offset_pos, SEEK_SET);
- uint32_t pair12_data_offset = roomFile->readUint32LE();
- uint32_t pair12_size = roomFile->readUint32LE();
-
- roomFile->seek(pair12_data_offset, SEEK_SET);
- byte *data = new byte[pair12_size];
- roomFile->read(data, pair12_size);
- Common::Array<Description> descriptions;
+uint32 RoomManager::loadDescriptions(byte *pair12data, size_t pair12size, Common::Array<Description> &outDescriptions) {
uint32_t pos = 0;
uint32_t lastDescPos = 0;
- while (pos < (pair12_size)) {
+ while (pos < (pair12size)) {
int desc_pos = 0;
- if (data[pos] == 0xFF) {
+ if (pair12data[pos] == 0xFF) {
Description description;
- description.itemId = data[pos + 1];
+ description.itemId = pair12data[pos + 1];
pos += 4;
- description.index = data[pos++];
+ description.index = pair12data[pos++];
description.text = "";
- while (pos < (pair12_size) && data[pos] != 0xFD && pos < (pair12_size)) {
+ while (pos < (pair12size) && pair12data[pos] != 0xFD && pos < (pair12size)) {
- if (data[pos] != 0x00) {
- description.text.append(1, (char)data[pos]);
+ if (pair12data[pos] != 0x00) {
+ description.text.append(1, (char)pair12data[pos]);
}
- if (data[pos] == 0xF8) {
- description.actionTrigger = data[pos + 1] | data[pos + 2] << 8;
+ if (pair12data[pos] == 0xF8) {
+ description.actionTrigger = pair12data[pos + 1] | pair12data[pos + 2] << 8;
if (description.actionTrigger != 0) {
description.isAction = true;
}
@@ -570,24 +605,25 @@ Common::Array<Description> RoomManager::loadRoomTexts(Common::File *roomFile, in
}
pos++;
}
- descriptions.push_back(description);
+ outDescriptions.push_back(description);
lastDescPos = pos;
}
pos++;
}
- // debug("End of descriptions at position %d", pos);
- size_t conversationStart = lastDescPos + 1;
- _conversationDataSize = pair12_size - conversationStart;
- if (_conversationData != nullptr) {
- delete[] _conversationData;
+ return lastDescPos + 1;
+}
+
+void RoomManager::loadConversationData(byte *pair12data, size_t pair12size, uint32 startPos, size_t &outConversationDataSize, byte *&outConversationData) {
+ size_t conversationStart = startPos;
+ outConversationDataSize = pair12size - conversationStart;
+ if (outConversationData != nullptr) {
+ delete[] outConversationData;
}
- _conversationData = new byte[_conversationDataSize];
- Common::copy(data + conversationStart, data + conversationStart + _conversationDataSize, _conversationData);
- delete[] data;
- return descriptions;
+ outConversationData = new byte[outConversationDataSize];
+ Common::copy(pair12data + conversationStart, pair12data + conversationStart + outConversationDataSize, outConversationData);
}
-void RoomManager::resetRoomDefaults(byte room, byte *&data, size_t size) {
+void RoomManager::resetMetadataDefaults(byte room, byte *&data, size_t size) {
Common::File alfred8;
if (!alfred8.open("ALFRED.8")) {
error("Couldnt find file ALFRED.8");
@@ -609,7 +645,7 @@ void RoomManager::resetRoomDefaults(byte room, byte *&data, size_t size) {
// Not the room we care about, skip
continue;
}
- debug("Resetting room %d data at offset %d, size %d", entry.room, entry.offset, entry.dataSize);
+ debug("Resetting room %d metadata at offset %d, size %d", entry.room, entry.offset, entry.dataSize);
Common::copy(entry.data, entry.data + entry.dataSize, data + entry.offset);
// delete[] entry.data;
}
@@ -731,8 +767,10 @@ void RoomManager::loadRemaps(int roomNumber) {
uint32 remapOffset = 0x200 + (roomNumber * 1024);
remapFile.seek(remapOffset, SEEK_SET);
- remapFile.read(alfredRemap, 256);
- remapFile.read(overlayRemap, 256);
+ remapFile.read(paletteRemaps[0], 256);
+ remapFile.read(paletteRemaps[1], 256);
+ remapFile.read(paletteRemaps[2], 256);
+ remapFile.read(paletteRemaps[3], 256);
remapFile.close();
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index c3f2b9ed8e8..15d4b5c59c5 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -50,6 +50,7 @@ public:
RoomManager();
~RoomManager();
void loadRoomMetadata(Common::File *roomFile, int roomNumber);
+ Common::Array<HotSpot> unifyHotspots(Common::Array<Pelrock::Sprite> &anims, Common::Array<Pelrock::HotSpot> &staticHotspots);
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
@@ -87,8 +88,7 @@ public:
ScalingParams _scaleParams;
byte *_pixelsShadows = nullptr;
byte _roomPalette[768];
- byte alfredRemap[256];
- byte overlayRemap[256];
+ byte paletteRemaps[4][256];
byte _musicTrack = 0;
Common::Array<byte> _roomSfx;
PaletteAnim *_currentPaletteAnim = nullptr;
@@ -104,9 +104,10 @@ private:
Common::Array<Exit> loadExits(byte *data, size_t size);
ScalingParams loadScalingParams(byte *data, size_t size);
Common::Array<WalkBox> loadWalkboxes(byte *data, size_t size);
- Common::Array<Description> loadRoomTexts(Common::File *roomFile, int roomOffset);
-
- void resetRoomDefaults(byte room, byte *&data, size_t size);
+ uint32 loadDescriptions(byte *pair12data, size_t pair12size, Common::Array<Description> &outDescriptions);
+ void loadConversationData(byte *pair12data, size_t pair12size, uint32 startPos, size_t &outConversationDataSize, byte *&outConversationData);
+ void resetConversationStates(byte roomNumber, byte *conversationData, size_t conversationDataSize);
+ void resetMetadataDefaults(byte room, byte *&data, size_t size);
byte *loadShadowMap(int roomNumber);
void loadRemaps(int roomNumber);
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
new file mode 100644
index 00000000000..87e3e6cabff
--- /dev/null
+++ b/engines/pelrock/saveload.cpp
@@ -0,0 +1,25 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+ namespace Pelrock {
+
+
+ } // End of namespace Pelrock
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index dcea3d58394..6467a007c0b 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -366,6 +366,15 @@ struct GameStateData {
Common::HashMap<byte, Common::Array<ExitChange>> roomExitChanges;
Common::HashMap<byte, Common::Array<WalkBoxChange>> roomWalkBoxChanges;
Common::HashMap<byte, Common::Array<HotSpotChange>> roomHotSpotChanges;
+ byte *conversationBranchState = new byte[4 * 56];
+
+ bool getBranchDisabledState(byte room, byte branch) const {
+ return (conversationBranchState[room * 4 + branch] != 0);
+ }
+
+ void setBranchDisabledState(byte room, byte branch, bool disabled) {
+ conversationBranchState[room * 4 + branch] = disabled ? 1 : 0;
+ }
};
} // End of namespace Pelrock
Commit: 40001b9ba5f96232b5e0437328fcfa1494c7ad30
https://github.com/scummvm/scummvm/commit/40001b9ba5f96232b5e0437328fcfa1494c7ad30
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:41+02:00
Commit Message:
PELROCK: Saves state of disabled conversation choices
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 5582eef7204..e8d76a2aaf3 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -111,4 +111,11 @@ void PelrockEngine::noOp(HotSpot *hotspot) {
// Do nothing
}
+void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex) {
+ if(actionTrigger == 328) {
+ debug("Disabling root %d in room %d", rootIndex, room);
+ _state.setRootDisabledState(room, rootIndex, true);
+ }
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 046bf05eac2..d8de2caa6f3 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -68,7 +68,7 @@ uint32 DialogManager::readTextBlock(
}
}
// Check for dialogue marker (choice text)
- else if (data[pos] == CTRL_DIALOGUE_MARKER || data[pos] == CTRL_DIALOGUE_MARKER_2) {
+ else if (data[pos] == CTRL_DIALOGUE_MARKER || data[pos] == CTRL_DIALOGUE_MARKER_ONEOFF) {
pos++; // Skip marker
// Skip choice index
@@ -95,7 +95,7 @@ uint32 DialogManager::readTextBlock(
// End markers - stop reading text
if (b == CTRL_END_TEXT || b == CTRL_END_CONVERSATION || b == CTRL_ACTION_TRIGGER ||
- b == CTRL_END_BRANCH || b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_2 ||
+ b == CTRL_END_BRANCH || b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_ONEOFF ||
b == CTRL_TEXT_TERMINATOR || b == CTRL_ALT_END_MARKER_1 || b == CTRL_ALT_END_MARKER_2 ||
b == CTRL_ALT_END_MARKER_3 || b == CTRL_GO_BACK || b == CTRL_SPEAKER_ID) {
break;
@@ -305,7 +305,7 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
}
// Found a dialogue marker
- if (b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_2) {
+ if (b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_ONEOFF) {
if (pos + 1 < dataSize) {
if (firstChoiceIndex == -1) {
firstChoiceIndex = data[pos + 1];
@@ -317,7 +317,9 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
// Check if disabled
ChoiceOption opt;
- opt.index = choiceIndex;
+ opt.room = g_engine->_room->_currentRoomNumber;
+ opt.shouldDisableOnSelect = b == CTRL_DIALOGUE_MARKER_ONEOFF;
+ opt.choiceIndex = choiceIndex;
opt.dataOffset = pos;
pos += 2; // Move past marker + index
if (data[pos] == CTRL_DISABLED_CHOICE) {
@@ -329,7 +331,7 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
while (textPos < dataSize) {
byte tb = data[textPos];
if (tb == CTRL_END_TEXT || tb == CTRL_DIALOGUE_MARKER ||
- tb == CTRL_DIALOGUE_MARKER_2 || tb == CTRL_END_BRANCH ||
+ tb == CTRL_DIALOGUE_MARKER_ONEOFF || tb == CTRL_END_BRANCH ||
tb == CTRL_ALT_END_MARKER_1) {
break;
}
@@ -338,7 +340,6 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
opt.text += (char)tb;
} else {
byte decoded = decodeChar(tb);
- debug("Parsing choice char: 0x%02X, decoded: 0x%02X", tb, decoded);
if (decoded != tb || (decoded >= 0x20 && decoded <= 0xB4)) {
opt.text += (char)decoded;
}
@@ -395,7 +396,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
while (position < dataSize &&
conversationData[position] != CTRL_SPEAKER_ID &&
conversationData[position] != CTRL_DIALOGUE_MARKER &&
- conversationData[position] != CTRL_DIALOGUE_MARKER_2) {
+ conversationData[position] != CTRL_DIALOGUE_MARKER_ONEOFF) {
position++;
}
@@ -443,6 +444,16 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
break;
}
+ if(controlByte == CTRL_ACTION_TRIGGER) {
+ uint16 actionCode = conversationData[position + 1] | (conversationData[position + 2] << 8);
+ debug("Action trigger %d encountered!", actionCode);
+ g_engine->dialogActionTrigger(
+ actionCode,
+ g_engine->_room->_currentRoomNumber,
+ g_engine->_room->getCurrentConversationRootIndex()
+ );
+ }
+
// Move past control byte
if (controlByte == CTRL_END_TEXT || controlByte == CTRL_ACTION_TRIGGER) {
position++;
@@ -467,7 +478,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// If not at a choice marker, there's more dialogue to read
if (peekPos < dataSize &&
conversationData[peekPos] != CTRL_DIALOGUE_MARKER &&
- conversationData[peekPos] != CTRL_DIALOGUE_MARKER_2 &&
+ conversationData[peekPos] != CTRL_DIALOGUE_MARKER_ONEOFF &&
conversationData[peekPos] != CTRL_END_CONVERSATION) {
continue;
}
@@ -477,7 +488,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
parseChoices(conversationData, dataSize, position, choices);
debug("Parsed %u choices", choices->size());
for (uint i = 0; i < choices->size(); i++) {
- debug(" Choice %u (index %d): \"%s\" (Disabled: %s)", i, (*choices)[i].index, (*choices)[i].text.c_str(),
+ debug(" Choice %u (index %d): \"%s\" (Disabled: %s)", i, (*choices)[i].choiceIndex, (*choices)[i].text.c_str(),
(*choices)[i].isDisabled ? "Yes" : "No");
}
if (choices->empty()) {
@@ -491,7 +502,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// We've already made a choice, check if the current choices are at the next level
bool foundNextLevel = false;
for (uint i = 0; i < choices->size(); i++) {
- if ((*choices)[i].index == currentChoiceLevel + 1) {
+ if ((*choices)[i].choiceIndex == currentChoiceLevel + 1) {
foundNextLevel = true;
break;
}
@@ -515,11 +526,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// Real choice: show menu and wait for selection
Common::Array<Common::String> choiceTexts;
for (uint i = 0; i < choices->size(); i++) {
- if ((*choices)[i].isDisabled) {
- choiceTexts.push_back("[DISABLED] " + (*choices)[i].text);
- } else {
- choiceTexts.push_back((*choices)[i].text);
- }
+ choiceTexts.push_back((*choices)[i].text);
}
if (_currentChoices) {
@@ -534,7 +541,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// 6. Move position to after the selected choice
if (selectedIndex >= 0 && selectedIndex < (int)choices->size()) {
position = (*choices)[selectedIndex].dataOffset;
- currentChoiceLevel = (*choices)[selectedIndex].index;
+ currentChoiceLevel = (*choices)[selectedIndex].choiceIndex;
// Read and display the selected choice as dialogue
Common::String choiceText;
@@ -543,6 +550,9 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
if (!choiceText.empty() && choiceText.size() > 1) {
displayDialogue(choiceText, ALFRED_COLOR);
+ if ((*choices)[selectedIndex].shouldDisableOnSelect) {
+ g_engine->_room->addDisabledChoice((*choices)[selectedIndex]);
+ }
}
position = endPos;
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 3113a1c6a68..16df8d811d1 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -33,35 +33,22 @@
namespace Pelrock {
// Control character codes (negative values in signed char)
-#define CHAR_SPACE 0x20 /* ' ' */
-#define CTRL_SPEAKER_ID 0x08 /* Next byte is speaker ID (color) */
-#define CTRL_END_TEXT 0xFD /* End of text segment */
-#define CTRL_TEXT_TERMINATOR 0xFC /* Text terminator */
-#define CTRL_DIALOGUE_MARKER 0xF1 /* Choice marker that sticks */
-#define CTRL_DISABLED_CHOICE 0xFA /* Disabled choice marker */
-#define CTRL_PAGE_BREAK_CONV 0xF9 /* Page break in conversation */
-#define CTRL_ACTION_TRIGGER 0xF8 /* Action trigger */
-#define CTRL_END_BRANCH 0xF7 /* End of branch */
-#define CTRL_LINE_CONTINUE 0xF6 /* Line continue/newline */
-#define CTRL_ALT_END_MARKER_1 0xF5 /* Alt end marker - do nothing */
-#define CTRL_END_CONVERSATION 0xF4 /* End conversation and disable option */
-#define CTRL_DIALOGUE_MARKER_2 0xFB /* Alt choice marker that disappears */
-#define CTRL_GO_BACK 0xF0 /* Go back in conversation */
-#define CTRL_ALT_END_MARKER_2 0xEB /* Alt end marker 2 */
-#define CTRL_ALT_END_MARKER_3 0xFE /* Alt end marker 3 */
-
-/**
- * Structure to hold a parsed choice option
- */
-struct ChoiceOption {
- int index;
- Common::String text;
- bool isDisabled;
- uint32 dataOffset;
- bool shouldDisableOnSelect = false;
-
- ChoiceOption() : index(-1), isDisabled(false), dataOffset(0) {}
-};
+#define CHAR_SPACE 0x20 /* ' ' */
+#define CTRL_SPEAKER_ID 0x08 /* Next byte is speaker ID (color) */
+#define CTRL_END_TEXT 0xFD /* End of text segment */
+#define CTRL_TEXT_TERMINATOR 0xFC /* Text terminator */
+#define CTRL_DIALOGUE_MARKER 0xF1 /* Choice marker that sticks */
+#define CTRL_DISABLED_CHOICE 0xFA /* Disabled choice marker */
+#define CTRL_PAGE_BREAK_CONV 0xF9 /* Page break in conversation */
+#define CTRL_ACTION_TRIGGER 0xF8 /* Action trigger */
+#define CTRL_END_BRANCH 0xF7 /* End of branch */
+#define CTRL_LINE_CONTINUE 0xF6 /* Line continue/newline */
+#define CTRL_ALT_END_MARKER_1 0xF5 /* Alt end marker - do nothing */
+#define CTRL_END_CONVERSATION 0xF4 /* End conversation and disable option */
+#define CTRL_DIALOGUE_MARKER_ONEOFF 0xFB /* Alt choice marker that disappears */
+#define CTRL_GO_BACK 0xF0 /* Go back in conversation */
+#define CTRL_ALT_END_MARKER_2 0xEB /* Alt end marker 2 */
+#define CTRL_ALT_END_MARKER_3 0xFE /* Alt end marker 3 */
static void debugHexString(const Common::String &str, const char *label = nullptr) {
if (label) {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index bb0548d69b7..994b6b4d7fb 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -274,6 +274,7 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
}
}
+
void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
for (const ActionEntry *entry = actionTable; entry->handler != nullptr; entry++) {
if (entry->action == action && entry->hotspotExtra == hotspot->extra) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 74ac6c087ea..4d60d09973a 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -120,7 +120,6 @@ private:
void calculateScalingMasks();
ScaleCalculation calculateScaling(int yPos, ScalingParams scalingParams);
-
Common::Array<Common::Array<int>> _widthScalingTable;
Common::Array<Common::Array<int>> _heightScalingTable;
@@ -145,7 +144,6 @@ private:
bool gameInitialized = false;
bool screenReady = false;
-
// int prevDirX = 0;
// int prevDirY = 0;
// Common::String objectToShow = "";
@@ -173,7 +171,6 @@ public:
Common::Array<int> _inventoryItems;
int _selectedInventoryItem = -1;
-
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
~PelrockEngine() override;
@@ -225,13 +222,14 @@ public:
// Actions
void performActionTrigger(uint16 actionTrigger);
+ void dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex);
void executeAction(VerbIcon action, HotSpot *hotspot);
- void openDrawer(HotSpot *hotspot);
- void closeDrawer(HotSpot *hotspot);
- void openDoor(HotSpot *hotspot);
- void closeDoor(HotSpot *hotspot);
- void pickUpAndDisable(HotSpot *hotspot);
+ void openDrawer(HotSpot *hotspot);
+ void closeDrawer(HotSpot *hotspot);
+ void openDoor(HotSpot *hotspot);
+ void closeDoor(HotSpot *hotspot);
+ void pickUpAndDisable(HotSpot *hotspot);
void pickUpPhoto(HotSpot *hotspot);
void pickYellowBook(HotSpot *hotspot);
void pickUpBrick(HotSpot *hotspot);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 478d7d15089..3a6e1a67bda 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -371,8 +371,8 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
roomFile->read(pair12, pair12size);
resetConversationStates(roomNumber, pair12, pair12size);
- uint32 lastDescPos = loadDescriptions(pair12, pair12size, _currentRoomDescriptions);
- loadConversationData(pair12, pair12size, lastDescPos, _conversationDataSize, _conversationData);
+ _conversationOffset = loadDescriptions(pair12, pair12size, _currentRoomDescriptions);
+ loadConversationData(pair12, pair12size, _conversationOffset, _conversationDataSize, _conversationData);
if (_pixelsShadows != nullptr)
delete[] _pixelsShadows;
@@ -621,6 +621,39 @@ void RoomManager::loadConversationData(byte *pair12data, size_t pair12size, uint
}
outConversationData = new byte[outConversationDataSize];
Common::copy(pair12data + conversationStart, pair12data + conversationStart + outConversationDataSize, outConversationData);
+ if (g_engine->_state.disabledBranches.contains(_currentRoomNumber)) {
+ applyDisabledChoices(_currentRoomNumber, outConversationData, outConversationDataSize);
+ }
+}
+
+void RoomManager::applyDisabledChoices(int roomNumber, byte *conversationData, size_t conversationDataSize) {
+ Common::Array<ResetEntry> disabledBranches = g_engine->_state.disabledBranches[roomNumber];
+ if (disabledBranches.size() == 0) {
+ return;
+ }
+ debug("Disabling %d conversation branches for room %d", disabledBranches.size(), roomNumber);
+ for (int i = 0; i < disabledBranches.size(); i++) {
+ ResetEntry resetEntry = disabledBranches[i];
+ applyDisabledChoice(resetEntry, conversationData, conversationDataSize);
+ }
+}
+
+void RoomManager::applyDisabledChoice(ResetEntry entry, byte *conversationData, size_t conversationDataSize) {
+ Common::copy(entry.data, entry.data + entry.dataSize, conversationData + entry.offset);
+}
+
+void RoomManager::addDisabledChoice(ChoiceOption choice) {
+ debug("Adding disabled branch for room %d at offset %d", choice.room, choice.dataOffset);
+ ResetEntry resetEntry = ResetEntry();
+ resetEntry.room = choice.room;
+ resetEntry.offset = choice.dataOffset;
+ resetEntry.dataSize = 1;
+ resetEntry.data = new byte[1];
+ resetEntry.data[0] = 0xFA; // Disabled
+ // Apply immediately
+ applyDisabledChoice(resetEntry, _conversationData, _conversationDataSize);
+ // Store for future loads
+ g_engine->_state.addDisabledBranch(resetEntry);
}
void RoomManager::resetMetadataDefaults(byte room, byte *&data, size_t size) {
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 15d4b5c59c5..2a3ace33404 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -31,20 +31,6 @@ namespace Pelrock {
static const int kNumSfxPerRoom = 8;
-struct ResetEntry {
- uint16 room;
- uint16 offset;
- byte dataSize;
- byte *data = nullptr;
-
- ~ResetEntry() {
- if (data != nullptr) {
- delete[] data;
- data = nullptr;
- }
- }
-};
-
class RoomManager {
public:
RoomManager();
@@ -54,6 +40,8 @@ public:
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
+
+ /** Methods to modify room data at runtime **/
void addSticker(Sticker sticker, bool persist = true);
void removeSticker(int index);
bool hasSticker(int index);
@@ -66,6 +54,9 @@ public:
void enableHotspot(HotSpot *hotspot, bool persist = true);
void disableHotspot(HotSpot *hotspot, bool persist = true);
void addWalkbox(WalkBox walkbox);
+ void applyDisabledChoices(int roomNumber, byte *conversationData, size_t conversationDataSize);
+ void applyDisabledChoice(ResetEntry entry, byte *conversationData, size_t conversationDataSize);
+ void addDisabledChoice(ChoiceOption choice);
HotSpot *findHotspotByExtra(uint16 extra);
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
@@ -95,6 +86,7 @@ public:
byte *_conversationData = nullptr;
size_t _conversationDataSize = 0;
Common::Array<Sticker> _transientStickers;
+ uint32 _conversationOffset;
private:
void init();
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 6467a007c0b..4e5f5b44e19 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -359,6 +359,26 @@ struct PaletteAnim {
byte curFrameCount = 0;
};
+/**
+ * Structure to hold a parsed choice option
+ */
+struct ChoiceOption {
+ byte room;
+ int choiceIndex;
+ Common::String text;
+ uint32 dataOffset;
+ bool isDisabled;
+ bool shouldDisableOnSelect = false;
+
+ ChoiceOption() : choiceIndex(-1), isDisabled(false), dataOffset(0) {}
+};
+
+struct ResetEntry {
+ uint16 room;
+ uint16 offset;
+ byte dataSize;
+ byte *data = nullptr;
+};
struct GameStateData {
GameState stateGame = INTRO;
@@ -366,14 +386,21 @@ struct GameStateData {
Common::HashMap<byte, Common::Array<ExitChange>> roomExitChanges;
Common::HashMap<byte, Common::Array<WalkBoxChange>> roomWalkBoxChanges;
Common::HashMap<byte, Common::Array<HotSpotChange>> roomHotSpotChanges;
- byte *conversationBranchState = new byte[4 * 56];
- bool getBranchDisabledState(byte room, byte branch) const {
- return (conversationBranchState[room * 4 + branch] != 0);
+ Common::HashMap<byte, Common::Array<ResetEntry>> disabledBranches;
+
+ void addDisabledBranch(ResetEntry entry) {
+ disabledBranches[entry.room].push_back(entry);
+ }
+
+ byte *conversationRootsState = new byte[4 * 56];
+
+ bool getRootDisabledState(byte room, byte root) const {
+ return (conversationRootsState[room * 4 + root] != 0);
}
- void setBranchDisabledState(byte room, byte branch, bool disabled) {
- conversationBranchState[room * 4 + branch] = disabled ? 1 : 0;
+ void setRootDisabledState(byte room, byte root, bool disabled) {
+ conversationRootsState[room * 4 + root] = disabled ? 1 : 0;
}
};
Commit: 8b077e1e0215397c5eb9488a7c7334064643ec47
https://github.com/scummvm/scummvm/commit/8b077e1e0215397c5eb9488a7c7334064643ec47
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:41+02:00
Commit Message:
PELROCK: Selects correct conversation when multiple npcs exist
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index d8de2caa6f3..2c9cc81730e 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -50,7 +50,7 @@ uint32 DialogManager::readTextBlock(
// Skip control bytes at start
while (pos < dataSize &&
(data[pos] == CTRL_ALT_END_MARKER_1 || data[pos] == CTRL_ALT_END_MARKER_2 ||
- data[pos] == CTRL_ALT_END_MARKER_3 || data[pos] == CTRL_TEXT_TERMINATOR ||
+ data[pos] == CTRL_TEXT_TERMINATOR ||
data[pos] == CTRL_GO_BACK)) {
pos++;
}
@@ -97,7 +97,7 @@ uint32 DialogManager::readTextBlock(
if (b == CTRL_END_TEXT || b == CTRL_END_CONVERSATION || b == CTRL_ACTION_TRIGGER ||
b == CTRL_END_BRANCH || b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_ONEOFF ||
b == CTRL_TEXT_TERMINATOR || b == CTRL_ALT_END_MARKER_1 || b == CTRL_ALT_END_MARKER_2 ||
- b == CTRL_ALT_END_MARKER_3 || b == CTRL_GO_BACK || b == CTRL_SPEAKER_ID) {
+ b == CTRL_GO_BACK || b == CTRL_SPEAKER_ID) {
break;
}
@@ -300,7 +300,7 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
byte b = data[pos];
// Stop at end markers
- if (b == CTRL_ALT_END_MARKER_1 || b == CTRL_END_BRANCH || b == CTRL_ALT_END_MARKER_3) {
+ if (b == CTRL_ALT_END_MARKER_1 || b == CTRL_END_BRANCH) {
break;
}
@@ -379,7 +379,7 @@ void DialogManager::setCurSprite(int index) {
_curSprite = nullptr;
}
-void DialogManager::startConversation(const byte *conversationData, uint32 dataSize, Sprite *animSet) {
+void DialogManager::startConversation(const byte *conversationData, uint32 dataSize, byte npcIndex, Sprite *animSet) {
if (!conversationData || dataSize == 0) {
debug("startConversation: No conversation data");
return;
@@ -387,11 +387,24 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
setCurSprite(animSet ? animSet->index : -1);
// _curSprite = animSet;
- debug("Starting conversation with %u bytes of data", dataSize);
+ debug("Starting conversation with %u bytes of data, for npc %u", dataSize, npcIndex);
uint32 position = 0;
int currentChoiceLevel = -1; // Track the current choice level
+ bool speakerRootOffsetFound = false;
+ int currentRoot = npcIndex + 1;
+ while(position < dataSize && !speakerRootOffsetFound) {
+ if(conversationData[position] == CTRL_ALT_SPEAKER_ROOT && conversationData[position + 1] == currentRoot) {
+ speakerRootOffsetFound = true;
+ position += 2; // Move past the speaker root marker and npc index
+ } else {
+ position++;
+ }
+ }
+
+
+
// Skip any junk at start until we find a speaker marker or choice marker
while (position < dataSize &&
conversationData[position] != CTRL_SPEAKER_ID &&
@@ -406,7 +419,6 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
while (position < dataSize &&
(conversationData[position] == CTRL_ALT_END_MARKER_1 ||
conversationData[position] == CTRL_ALT_END_MARKER_2 ||
- conversationData[position] == CTRL_ALT_END_MARKER_3 ||
conversationData[position] == CTRL_TEXT_TERMINATOR ||
conversationData[position] == CTRL_GO_BACK)) {
position++;
@@ -450,7 +462,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
g_engine->dialogActionTrigger(
actionCode,
g_engine->_room->_currentRoomNumber,
- g_engine->_room->getCurrentConversationRootIndex()
+ 0 //FIXME: Pass NPC index?
);
}
@@ -469,7 +481,6 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
while (peekPos < dataSize &&
(conversationData[peekPos] == CTRL_ALT_END_MARKER_1 ||
conversationData[peekPos] == CTRL_ALT_END_MARKER_2 ||
- conversationData[peekPos] == CTRL_ALT_END_MARKER_3 ||
conversationData[peekPos] == CTRL_TEXT_TERMINATOR ||
conversationData[peekPos] == CTRL_GO_BACK)) {
peekPos++;
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 16df8d811d1..66a34b94c8b 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -48,7 +48,7 @@ namespace Pelrock {
#define CTRL_DIALOGUE_MARKER_ONEOFF 0xFB /* Alt choice marker that disappears */
#define CTRL_GO_BACK 0xF0 /* Go back in conversation */
#define CTRL_ALT_END_MARKER_2 0xEB /* Alt end marker 2 */
-#define CTRL_ALT_END_MARKER_3 0xFE /* Alt end marker 3 */
+#define CTRL_ALT_SPEAKER_ROOT 0xFE /* Separates conversations from different speakers */
static void debugHexString(const Common::String &str, const char *label = nullptr) {
if (label) {
@@ -84,7 +84,7 @@ public:
void displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer);
int selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer);
- void startConversation(const byte *conversationData, uint32 dataSize, Sprite *alfredAnimSet = nullptr);
+ void startConversation(const byte *conversationData, uint32 dataSize, byte npcIndex, Sprite *alfredAnimSet = nullptr);
void sayAlfred(Description description);
void say(Common::StringArray texts);
bool processColorAndTrim(Common::StringArray &lines, byte &speakerId);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 994b6b4d7fb..e8ea2498395 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -533,7 +533,7 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
break;
}
}
- _dialog->startConversation(_room->_conversationData, _room->_conversationDataSize, animSet);
+ _dialog->startConversation(_room->_conversationData, _room->_conversationDataSize, hotspot->index, animSet);
}
void PelrockEngine::lookAt(HotSpot *hotspot) {
Commit: 89d26fe2a93fcf8ee5371dc712d0f65d117ef69b
https://github.com/scummvm/scummvm/commit/89d26fe2a93fcf8ee5371dc712d0f65d117ef69b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:41+02:00
Commit Message:
PELROCK: Fixes descriptions not being cleared
Changed paths:
engines/pelrock/room.cpp
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 3a6e1a67bda..9cc6a11d670 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -371,6 +371,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
roomFile->read(pair12, pair12size);
resetConversationStates(roomNumber, pair12, pair12size);
+
_conversationOffset = loadDescriptions(pair12, pair12size, _currentRoomDescriptions);
loadConversationData(pair12, pair12size, _conversationOffset, _conversationDataSize, _conversationData);
@@ -580,6 +581,7 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
uint32 RoomManager::loadDescriptions(byte *pair12data, size_t pair12size, Common::Array<Description> &outDescriptions) {
uint32_t pos = 0;
uint32_t lastDescPos = 0;
+ outDescriptions.clear();
while (pos < (pair12size)) {
int desc_pos = 0;
if (pair12data[pos] == 0xFF) {
Commit: 3622f07b3df0d399fb277c9e2c01b93a63259d29
https://github.com/scummvm/scummvm/commit/3622f07b3df0d399fb277c9e2c01b93a63259d29
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:42+02:00
Commit Message:
PELROCK: Disables conversation roots
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 2c9cc81730e..a433e5378ca 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -392,18 +392,30 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
uint32 position = 0;
int currentChoiceLevel = -1; // Track the current choice level
- bool speakerRootOffsetFound = false;
- int currentRoot = npcIndex + 1;
- while(position < dataSize && !speakerRootOffsetFound) {
- if(conversationData[position] == CTRL_ALT_SPEAKER_ROOT && conversationData[position + 1] == currentRoot) {
- speakerRootOffsetFound = true;
- position += 2; // Move past the speaker root marker and npc index
+ // Find the speaker tree for this NPC; they are marked by 0xFE 0xXX where XX is NPC index + 1
+ bool speakerTreeOffsetFound = false;
+ int currentConversationTree = npcIndex + 1;
+ while(position < dataSize && !speakerTreeOffsetFound) {
+ if(conversationData[position] == CTRL_ALT_SPEAKER_ROOT && conversationData[position + 1] == currentConversationTree) {
+ speakerTreeOffsetFound = true;
+ position += 2; // Move past the speaker tree marker and npc index
} else {
position++;
}
}
-
-
+ // Right after the speaker conversation tree, we are in branch 0
+ int currentRoot = 0;
+ while(g_engine->_state.getRootDisabledState(g_engine->_room->_currentRoomNumber, currentRoot)) {
+ // This root is disabled, skip to next
+ while(position < dataSize) {
+ if(conversationData[position] == CTRL_END_BRANCH) {
+ position++; // Move past end branch marker
+ currentRoot++;
+ break;
+ }
+ position++;
+ }
+ }
// Skip any junk at start until we find a speaker marker or choice marker
while (position < dataSize &&
@@ -462,7 +474,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
g_engine->dialogActionTrigger(
actionCode,
g_engine->_room->_currentRoomNumber,
- 0 //FIXME: Pass NPC index?
+ currentRoot
);
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index e8ea2498395..523797ae087 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -160,10 +160,10 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(0, ALFRED_DOWN);
- // setScreen(2, ALFRED_LEFT);
- // alfredState.x = 576;
- // alfredState.y = 374;
+ // setScreen(0, ALFRED_DOWN);
+ setScreen(2, ALFRED_LEFT);
+ alfredState.x = 576;
+ alfredState.y = 374;
}
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 4e5f5b44e19..4df597b3717 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -389,6 +389,15 @@ struct GameStateData {
Common::HashMap<byte, Common::Array<ResetEntry>> disabledBranches;
+ GameStateData() {
+ memset(conversationRootsState, 0, 4 * 56);
+ }
+
+ ~GameStateData() {
+ delete[] conversationRootsState;
+ conversationRootsState = nullptr;
+ }
+
void addDisabledBranch(ResetEntry entry) {
disabledBranches[entry.room].push_back(entry);
}
Commit: 19c6f7bc1a7a81c9b6185e79c3516658a004790d
https://github.com/scummvm/scummvm/commit/19c6f7bc1a7a81c9b6185e79c3516658a004790d
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:42+02:00
Commit Message:
PELROCK: Fixes dialog lines being read incorrectly
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index a433e5378ca..6e4b20352f1 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -43,16 +43,14 @@ uint32 DialogManager::readTextBlock(
uint32 startPos,
Common::String &outText,
byte &outSpeakerId) {
+
uint32 pos = startPos;
outSpeakerId = ALFRED_COLOR; // Default to Alfred's color
outText = "";
// Skip control bytes at start
- while (pos < dataSize &&
- (data[pos] == CTRL_ALT_END_MARKER_1 || data[pos] == CTRL_ALT_END_MARKER_2 ||
- data[pos] == CTRL_TEXT_TERMINATOR ||
- data[pos] == CTRL_GO_BACK)) {
- pos++;
+ if(data[pos] == CTRL_TEXT_TERMINATOR) {
+ pos+=2;
}
if (pos >= dataSize) {
@@ -64,7 +62,6 @@ uint32 DialogManager::readTextBlock(
pos++;
if (pos < dataSize) {
outSpeakerId = data[pos];
- pos++;
}
}
// Check for dialogue marker (choice text)
@@ -75,20 +72,14 @@ uint32 DialogManager::readTextBlock(
if (pos < dataSize) {
pos++;
}
-
- // Skip 2 bytes after choice index (speaker marker bytes)
- if (pos < dataSize) {
- pos++;
- }
- if (pos < dataSize) {
- pos++;
- }
-
// Choice text is always spoken by ALFRED
outSpeakerId = ALFRED_COLOR;
+ pos+=2;
}
- // pos += 2; // Skip line count and blank
+ int lineIndex = data[++pos];
+ pos++; //blank
+ debug("Reading text block starting at pos %u, line index %d, speaker ID %d", startPos, lineIndex, outSpeakerId);
// Read text until control byte
while (pos < dataSize) {
byte b = data[pos];
@@ -102,6 +93,7 @@ uint32 DialogManager::readTextBlock(
}
if (b == CTRL_LINE_CONTINUE || b == CTRL_PAGE_BREAK_CONV) {
+ warning("Found unexpected line/page break control code in readTextBlock at pos %u", pos);
outText += ' ';
pos++;
continue;
@@ -431,7 +423,6 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
while (position < dataSize &&
(conversationData[position] == CTRL_ALT_END_MARKER_1 ||
conversationData[position] == CTRL_ALT_END_MARKER_2 ||
- conversationData[position] == CTRL_TEXT_TERMINATOR ||
conversationData[position] == CTRL_GO_BACK)) {
position++;
}
@@ -476,6 +467,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
g_engine->_room->_currentRoomNumber,
currentRoot
);
+ break;
}
// Move past control byte
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 2a31bfbcd81..59ae1fb4687 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -52,7 +52,7 @@ static const int special_chars[] = {
163, // small u tilde
162, // small o tilde
161, // small i tilde
- 132, // small e tilde
+ 130, // small e tilde
160, // small a tilde
};
Commit: eafad6d16d1a5a23247f1bcea5bceaf562805bcc
https://github.com/scummvm/scummvm/commit/eafad6d16d1a5a23247f1bcea5bceaf562805bcc
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:42+02:00
Commit Message:
PELROCK: Fix text positioning for NPCs
Changed paths:
engines/pelrock/dialog.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 6e4b20352f1..b3313729fe5 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -191,24 +191,18 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
} else {
g_engine->alfredState.setState(ALFRED_IDLE);
_curSprite->isTalking = true;
- xPos = _curSprite->x + _curSprite->w / 2;
+ xPos = _curSprite->x + _curSprite->w / 2 - maxWidth / 2;
yPos = _curSprite->y - height; // Above sprite, adjust for line
}
Graphics::Surface s = getDialogueSurface(textLines, speakerId);
- if (xPos + s.getRect().width() > 640) {
- xPos = 640 - s.getRect().width();
- }
- if (yPos + s.getRect().height() > 400) {
- yPos = 400 - s.getRect().height();
- }
- if (xPos < 0) {
- xPos = 0;
- }
- if (yPos < 0) {
- yPos = 0;
- }
+
+
+ // Clamp to screen bounds
+ xPos = CLIP(xPos, 0, 640 - maxWidth);
+ yPos = CLIP(yPos, 0, 400 - s.getRect().height());
+
_screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos), 255);
drawPos(_screen, xPos, yPos, speakerId);
drawRect(_screen, xPos, yPos,
Commit: b1034e8745a1ee6e42ac16382aa5f89b60f1b91c
https://github.com/scummvm/scummvm/commit/b1034e8745a1ee6e42ac16382aa5f89b60f1b91c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:43+02:00
Commit Message:
PELROCK: Initial save/load implementation
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/menu.cpp
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/saveload.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index e8d76a2aaf3..30127b279fe 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -77,8 +77,8 @@ void PelrockEngine::closeDoor(HotSpot *hotspot) {
}
void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
- if (_inventoryItems.size() == 0) {
- _selectedInventoryItem = hotspot->extra;
+ if (_state.inventoryItems.size() == 0) {
+ _state.selectedInventoryItem = hotspot->extra;
}
int frameCounter = 0;
while (frameCounter < kIconFlashDuration) {
@@ -91,7 +91,7 @@ void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
}
g_system->delayMillis(10);
}
- _inventoryItems.push_back(hotspot->extra);
+ _state.inventoryItems.push_back(hotspot->extra);
_room->disableHotspot(hotspot);
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index b3313729fe5..110a1c16632 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -179,17 +179,17 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int yPos = 0;
if (speakerId == ALFRED_COLOR) {
- if (g_engine->alfredState.animState != ALFRED_TALKING) {
- g_engine->alfredState.setState(ALFRED_TALKING);
+ if (g_engine->_alfredState.animState != ALFRED_TALKING) {
+ g_engine->_alfredState.setState(ALFRED_TALKING);
}
if (_curSprite != nullptr) {
_curSprite->isTalking = false;
}
// Offset X position for Alfred to avoid overlapping with his sprite
- xPos = g_engine->alfredState.x - maxWidth / 2; //+ kAlfredFrameWidth / 2 - maxWidth / 2;
- yPos = g_engine->alfredState.y - kAlfredFrameHeight - height; // Above sprite, adjust for line
+ xPos = g_engine->_alfredState.x - maxWidth / 2; //+ kAlfredFrameWidth / 2 - maxWidth / 2;
+ yPos = g_engine->_alfredState.y - kAlfredFrameHeight - height; // Above sprite, adjust for line
} else {
- g_engine->alfredState.setState(ALFRED_IDLE);
+ g_engine->_alfredState.setState(ALFRED_IDLE);
_curSprite->isTalking = true;
xPos = _curSprite->x + _curSprite->w / 2 - maxWidth / 2;
yPos = _curSprite->y - height; // Above sprite, adjust for line
@@ -226,7 +226,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (_curSprite != nullptr) {
_curSprite->isTalking = false;
}
- g_engine->alfredState.setState(ALFRED_IDLE);
+ g_engine->_alfredState.setState(ALFRED_IDLE);
}
void DialogManager::displayDialogue(Common::String text, byte speakerId) {
@@ -582,7 +582,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
void DialogManager::sayAlfred(Common::StringArray texts) {
- g_engine->alfredState.setState(ALFRED_TALKING);
+ g_engine->_alfredState.setState(ALFRED_TALKING);
_curSprite = nullptr;
Common::Array<Common::StringArray> textLines = wordWrap(texts);
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 78db638a13d..39442d50c0c 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -97,9 +97,9 @@ void MenuManager::checkMouseClick(int x, int y) {
for (int i = 0; i < 4; i++) {
if (x >= 140 + (82 * i) && x <= 140 + (82 * i) + 64 &&
y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
- _selectedInvIndex = g_engine->_inventoryItems[_curInventoryPage * 4 + i];
+ _selectedInvIndex = g_engine->_state.inventoryItems[_curInventoryPage * 4 + i];
_menuText = _inventoryDescriptions[_selectedInvIndex];
- g_engine->_selectedInventoryItem = _selectedInvIndex;
+ g_engine->_state.selectedInventoryItem = _selectedInvIndex;
selectedItem = true;
return;
}
@@ -119,9 +119,15 @@ void MenuManager::checkMouseClick(int x, int y) {
_curInventoryPage--;
break;
case INVENTORY_NEXT_BUTTON:
- if ((_curInventoryPage + 1) * 4 < g_engine->_inventoryItems.size())
+ if ((_curInventoryPage + 1) * 4 < g_engine->_state.inventoryItems.size())
_curInventoryPage++;
break;
+ case SAVE_GAME_BUTTON:
+ g_engine->saveGameDialog();
+ break;
+ case LOAD_GAME_BUTTON:
+ g_engine->loadGameDialog();
+ break;
default:
break;
}
@@ -155,9 +161,9 @@ void MenuManager::menuLoop() {
for (int i = 0; i < 4; i++) {
int itemIndex = _curInventoryPage * 4 + i;
- if (g_engine->_inventoryItems.size() <= itemIndex)
+ if (g_engine->_state.inventoryItems.size() <= itemIndex)
continue;
- InventoryObject item = g_engine->_res->getInventoryObject(g_engine->_inventoryItems[itemIndex]);
+ InventoryObject item = g_engine->_res->getInventoryObject(g_engine->_state.inventoryItems[itemIndex]);
drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
}
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index a01a7d58cc9..fc5b879566f 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -18,7 +18,8 @@ MODULE_OBJS = \
events.o \
dialog.o \
menu.o \
- graphics.o
+ graphics.o \
+ saveload.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 523797ae087..bebdd59fd74 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -160,10 +160,10 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- // setScreen(0, ALFRED_DOWN);
- setScreen(2, ALFRED_LEFT);
- alfredState.x = 576;
- alfredState.y = 374;
+ setScreen(0, ALFRED_DOWN);
+ // setScreen(2, ALFRED_LEFT);
+ // alfredState.x = 576;
+ // alfredState.y = 374;
}
}
@@ -300,8 +300,8 @@ void PelrockEngine::checkMouse() {
// Cancel walking animation on mouse click
if (_events->_leftMouseButton) {
- alfredState.curFrame = 0;
- alfredState.setState(ALFRED_IDLE);
+ _alfredState.curFrame = 0;
+ _alfredState.setState(ALFRED_IDLE);
}
// Handle mouse release after long press (popup selection mode)
@@ -399,15 +399,15 @@ void PelrockEngine::paintDebugLayer() {
_smallFont->drawString(_screen, Common::String::format("Exit %d -> Room %d", i, exit.targetRoom), exit.x + 2, exit.y + 2, 640, 14);
}
- drawPos(_screen, alfredState.x, alfredState.y, 13);
- drawPos(_screen, alfredState.x, alfredState.y - kAlfredFrameHeight, 13);
+ drawPos(_screen, _alfredState.x, _alfredState.y, 13);
+ drawPos(_screen, _alfredState.x, _alfredState.y - kAlfredFrameHeight, 13);
drawPos(_screen, _curWalkTarget.x, _curWalkTarget.y, 100);
if (showShadows) {
memcpy(_screen->getPixels(), _room->_pixelsShadows, 640 * 400);
}
_smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
- _smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", alfredState.x, alfredState.y, alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
+ _smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", _alfredState.x, _alfredState.y, _alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
_smallFont->drawString(_screen, Common::String::format("Frame number: %d", _chrono->getFrameCount()), 0, 30, 640, 13);
}
@@ -511,13 +511,13 @@ void PelrockEngine::doAction(VerbIcon action, HotSpot *hotspot) {
talkTo(hotspot);
break;
case PICKUP:
- alfredState.setState(ALFRED_INTERACTING);
+ _alfredState.setState(ALFRED_INTERACTING);
pickUpAndDisable(hotspot);
executeAction(PICKUP, hotspot);
break;
case OPEN:
case CLOSE:
- alfredState.setState(ALFRED_INTERACTING);
+ _alfredState.setState(ALFRED_INTERACTING);
default:
executeAction(action, hotspot);
break;
@@ -542,51 +542,51 @@ void PelrockEngine::lookAt(HotSpot *hotspot) {
}
void PelrockEngine::chooseAlfredStateAndDraw() {
- if (alfredState.idleFrameCounter++ >= kAlfredIdleAnimationFrameCount &&
- alfredState.animState == ALFRED_IDLE &&
- (alfredState.direction == ALFRED_LEFT || alfredState.direction == ALFRED_RIGHT)) {
- alfredState.idleFrameCounter = 0;
- alfredState.setState(ALFRED_COMB);
+ if (_alfredState.idleFrameCounter++ >= kAlfredIdleAnimationFrameCount &&
+ _alfredState.animState == ALFRED_IDLE &&
+ (_alfredState.direction == ALFRED_LEFT || _alfredState.direction == ALFRED_RIGHT)) {
+ _alfredState.idleFrameCounter = 0;
+ _alfredState.setState(ALFRED_COMB);
}
- switch (alfredState.animState) {
+ switch (_alfredState.animState) {
case ALFRED_WALKING: {
MovementStep step = _currentContext.movementBuffer[_currentStep];
if (step.distanceX > 0) {
if (step.flags & MOVE_RIGHT) {
- alfredState.direction = ALFRED_RIGHT;
- alfredState.x += MIN(alfredState.movementSpeed, step.distanceX);
+ _alfredState.direction = ALFRED_RIGHT;
+ _alfredState.x += MIN(_alfredState.movementSpeed, step.distanceX);
}
if (step.flags & MOVE_LEFT) {
- alfredState.direction = ALFRED_LEFT;
- alfredState.x -= MIN(alfredState.movementSpeed, step.distanceX);
+ _alfredState.direction = ALFRED_LEFT;
+ _alfredState.x -= MIN(_alfredState.movementSpeed, step.distanceX);
}
}
if (step.distanceY > 0) {
if (step.flags & MOVE_DOWN) {
- alfredState.direction = ALFRED_DOWN;
- alfredState.y += MIN(alfredState.movementSpeed, step.distanceY);
+ _alfredState.direction = ALFRED_DOWN;
+ _alfredState.y += MIN(_alfredState.movementSpeed, step.distanceY);
}
if (step.flags & MOVE_UP) {
- alfredState.direction = ALFRED_UP;
- alfredState.y -= MIN(alfredState.movementSpeed, step.distanceY);
+ _alfredState.direction = ALFRED_UP;
+ _alfredState.y -= MIN(_alfredState.movementSpeed, step.distanceY);
}
}
if (step.distanceX > 0)
- step.distanceX -= MIN(alfredState.movementSpeed, step.distanceX);
+ step.distanceX -= MIN(_alfredState.movementSpeed, step.distanceX);
if (step.distanceY > 0)
- step.distanceY -= MIN(alfredState.movementSpeed, step.distanceY);
+ step.distanceY -= MIN(_alfredState.movementSpeed, step.distanceY);
if (step.distanceX <= 0 && step.distanceY <= 0) {
_currentStep++;
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
- alfredState.setState(ALFRED_IDLE);
+ _alfredState.setState(ALFRED_IDLE);
if (_currentHotspot != nullptr)
- alfredState.direction = calculateAlfredsDirection(_currentHotspot);
- drawAlfred(_res->alfredIdle[alfredState.direction]);
+ _alfredState.direction = calculateAlfredsDirection(_currentHotspot);
+ drawAlfred(_res->alfredIdle[_alfredState.direction]);
if (_queuedAction.isQueued) {
doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
@@ -598,61 +598,61 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_currentContext.movementBuffer[_currentStep] = step;
}
- Exit *exit = isExitUnder(alfredState.x, alfredState.y);
+ Exit *exit = isExitUnder(_alfredState.x, _alfredState.y);
if (exit != nullptr && exit->isEnabled) {
- alfredState.x = exit->targetX;
- alfredState.y = exit->targetY;
+ _alfredState.x = exit->targetX;
+ _alfredState.y = exit->targetY;
setScreen(exit->targetRoom, exit->dir);
}
- if (alfredState.curFrame >= walkingAnimLengths[alfredState.direction]) {
- alfredState.curFrame = 0;
+ if (_alfredState.curFrame >= walkingAnimLengths[_alfredState.direction]) {
+ _alfredState.curFrame = 0;
}
- drawAlfred(_res->alfredWalkFrames[alfredState.direction][alfredState.curFrame]);
- alfredState.curFrame++;
+ drawAlfred(_res->alfredWalkFrames[_alfredState.direction][_alfredState.curFrame]);
+ _alfredState.curFrame++;
break;
}
case ALFRED_TALKING:
- if (alfredState.curFrame >= talkingAnimLengths[alfredState.direction] - 1) {
- alfredState.curFrame = 0;
+ if (_alfredState.curFrame >= talkingAnimLengths[_alfredState.direction] - 1) {
+ _alfredState.curFrame = 0;
}
- drawAlfred(_res->alfredTalkFrames[alfredState.direction][alfredState.curFrame]);
+ drawAlfred(_res->alfredTalkFrames[_alfredState.direction][_alfredState.curFrame]);
if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
- alfredState.curFrame++;
+ _alfredState.curFrame++;
}
break;
case ALFRED_COMB:
- if (alfredState.curFrame >= 11) {
- alfredState.setState(ALFRED_IDLE);
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredIdle[alfredState.direction], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
+ if (_alfredState.curFrame >= 11) {
+ _alfredState.setState(ALFRED_IDLE);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredIdle[_alfredState.direction], _alfredState.x, _alfredState.y - kAlfredFrameHeight, 51, 102, 255);
} else {
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[alfredState.direction][alfredState.curFrame], alfredState.x, alfredState.y - kAlfredFrameHeight, 51, 102, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[_alfredState.direction][_alfredState.curFrame], _alfredState.x, _alfredState.y - kAlfredFrameHeight, 51, 102, 255);
if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
- alfredState.curFrame++;
+ _alfredState.curFrame++;
}
break;
case ALFRED_INTERACTING:
- if (alfredState.curFrame >= interactingAnimLength) {
- alfredState.setState(ALFRED_IDLE);
+ if (_alfredState.curFrame >= interactingAnimLength) {
+ _alfredState.setState(ALFRED_IDLE);
} else {
- drawAlfred(_res->alfredInteractFrames[alfredState.direction][alfredState.curFrame]);
+ drawAlfred(_res->alfredInteractFrames[_alfredState.direction][_alfredState.curFrame]);
if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
- alfredState.curFrame++;
+ _alfredState.curFrame++;
}
}
break;
}
// This if is needed to draw Alfred when idle, when the switch case results in a state change
- if (alfredState.animState == ALFRED_IDLE) {
- drawAlfred(_res->alfredIdle[alfredState.direction]);
+ if (_alfredState.animState == ALFRED_IDLE) {
+ drawAlfred(_res->alfredIdle[_alfredState.direction]);
}
}
void PelrockEngine::drawAlfred(byte *buf) {
- ScaleCalculation scale = calculateScaling(alfredState.y, _room->_scaleParams);
+ ScaleCalculation scale = calculateScaling(_alfredState.y, _room->_scaleParams);
int finalHeight = kAlfredFrameHeight - scale.scaleDown + scale.scaleUp;
if (finalHeight <= 0) {
@@ -672,8 +672,8 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
int linesToSkip = kAlfredFrameHeight - finalHeight;
- int shadowPos = alfredState.y; // - finalHeight;
- bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + alfredState.x] != 0xFF;
+ int shadowPos = _alfredState.y; // - finalHeight;
+ bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + _alfredState.x] != 0xFF;
byte *finalBuf = new byte[finalWidth * finalHeight];
@@ -752,7 +752,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
}
- drawSpriteToBuffer(_compositeBuffer, 640, finalBuf, alfredState.x, alfredState.y - finalHeight, finalWidth, finalHeight, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, finalBuf, _alfredState.x, _alfredState.y - finalHeight, finalWidth, finalHeight, 255);
delete[] finalBuf;
}
@@ -838,14 +838,14 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
if (hotspotIndex != -1 && !_actionPopupState.isActive) {
- _actionPopupState.x = alfredState.x + kAlfredFrameWidth / 2 - kBalloonWidth / 2;
+ _actionPopupState.x = _alfredState.x + kAlfredFrameWidth / 2 - kBalloonWidth / 2;
if (_actionPopupState.x < 0)
_actionPopupState.x = 0;
if (_actionPopupState.x + kBalloonWidth > 640) {
_actionPopupState.x = 640 - kBalloonWidth;
}
- _actionPopupState.y = alfredState.y - kAlfredFrameHeight - kBalloonHeight;
+ _actionPopupState.y = _alfredState.y - kAlfredFrameHeight - kBalloonHeight;
if (_actionPopupState.y < 0) {
_actionPopupState.y = 0;
}
@@ -1044,11 +1044,11 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
bool itemUnder = isItemUnder(_events->_mouseX, _events->_mouseY);
- if (_selectedInventoryItem != -1) {
+ if (_state.selectedInventoryItem != -1) {
if (itemUnder && shouldBlink) {
return;
}
- drawSpriteToBuffer(_compositeBuffer, 640, _res->getInventoryObject(_selectedInventoryItem).iconData, posx + 20 + (actions.size() * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->getInventoryObject(_state.selectedInventoryItem).iconData, posx + 20 + (actions.size() * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
if (_actionPopupState.curFrame < 3) {
_actionPopupState.curFrame++;
@@ -1130,9 +1130,9 @@ void PelrockEngine::extraScreenLoop() {
void PelrockEngine::walkTo(int x, int y) {
_currentStep = 0;
PathContext context = {nullptr, nullptr, nullptr, 0, 0, 0};
- findPath(alfredState.x, alfredState.y, x, y, _room->_currentRoomWalkboxes, &context);
+ findPath(_alfredState.x, _alfredState.y, x, y, _room->_currentRoomWalkboxes, &context);
_currentContext = context;
- alfredState.setState(ALFRED_WALKING);
+ _alfredState.setState(ALFRED_WALKING);
}
AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
@@ -1140,19 +1140,19 @@ AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
AlfredDirection calculatedDirection = ALFRED_DOWN;
if (hotspot->isSprite) {
// Check if Alfred's left edge is past sprite's right edge
- if (hotspot->x + hotspot->w < alfredState.x) {
+ if (hotspot->x + hotspot->w < _alfredState.x) {
calculatedDirection = ALFRED_LEFT; // Face LEFT
}
// Check if Alfred's right edge is before sprite's left edge
- else if ((alfredState.x + kAlfredFrameWidth - alfredState.scaledX) < hotspot->x) {
+ else if ((_alfredState.x + kAlfredFrameWidth - _alfredState.scaledX) < hotspot->x) {
calculatedDirection = ALFRED_RIGHT; // Face RIGHT
}
// Alfred is horizontally overlapping with sprite
else {
// Check if Alfred's top is above sprite's bottom OR Alfred is within sprite's Y range
- if (((alfredState.y + kAlfredFrameHeight - alfredState.scaledY) < hotspot->y) ||
- (alfredState.y <= hotspot->y + hotspot->h &&
- hotspot->zOrder <= ((399 - alfredState.y) / 2) + 10)) {
+ if (((_alfredState.y + kAlfredFrameHeight - _alfredState.scaledY) < hotspot->y) ||
+ (_alfredState.y <= hotspot->y + hotspot->h &&
+ hotspot->zOrder <= ((399 - _alfredState.y) / 2) + 10)) {
calculatedDirection = ALFRED_DOWN; // Face DOWN
} else {
calculatedDirection = ALFRED_UP; // Face UP
@@ -1160,16 +1160,16 @@ AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
}
} else {
// Check if Alfred's left edge is past hotspot's right edge
- if (hotspot->x + hotspot->w < alfredState.x) {
+ if (hotspot->x + hotspot->w < _alfredState.x) {
calculatedDirection = ALFRED_LEFT; // Face LEFT
}
// Check if Alfred's right edge is before hotspot's left edge
- else if ((alfredState.x + kAlfredFrameWidth - alfredState.scaledX) < hotspot->x) {
+ else if ((_alfredState.x + kAlfredFrameWidth - _alfredState.scaledX) < hotspot->x) {
calculatedDirection = ALFRED_RIGHT; // Face RIGHT
}
// Check vertical positioning
- else if (((alfredState.y + kAlfredFrameHeight - alfredState.scaledY) < hotspot->y) ||
- (alfredState.y <= hotspot->y + hotspot->h &&
+ else if (((_alfredState.y + kAlfredFrameHeight - _alfredState.scaledY) < hotspot->y) ||
+ (_alfredState.y <= hotspot->y + hotspot->h &&
(hotspot->actionFlags & 0x80) == 0x80)) {
calculatedDirection = ALFRED_DOWN; // Face DOWN
} else {
@@ -1208,8 +1208,8 @@ bool PelrockEngine::isItemUnder(int x, int y) {
bool PelrockEngine::isAlfredUnder(int x, int y) {
// TODO: Account for scaling
- int alfredX = alfredState.x;
- int alfredY = alfredState.y;
+ int alfredX = _alfredState.x;
+ int alfredY = _alfredState.y;
int alfredW = kAlfredFrameWidth;
int alfredH = kAlfredFrameHeight;
@@ -1301,11 +1301,11 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
}
_sound->stopAllSounds();
_currentHotspot = nullptr;
- alfredState.direction = dir;
- alfredState.setState(ALFRED_IDLE);
+ _alfredState.direction = dir;
+ _alfredState.setState(ALFRED_IDLE);
_currentStep = 0;
int roomOffset = number * kRoomStructSize;
- alfredState.curFrame = 0;
+ _alfredState.curFrame = 0;
byte *palette = new byte[256 * 3];
_room->getPalette(&roomFile, roomOffset, palette);
@@ -1336,15 +1336,4 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
delete[] palette;
}
-Common::Error PelrockEngine::syncGame(Common::Serializer &s) {
- // The Serializer has methods isLoading() and isSaving()
- // if you need to specific steps; for example setting
- // an array size after reading it's length, whereas
- // for saving it would write the existing array's length
- int dummy = 0;
- s.syncAsUint32LE(dummy);
-
- return Common::kNoError;
-}
-
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 4d60d09973a..50d1affcc74 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -159,7 +159,7 @@ public:
Graphics::Screen *_screen = nullptr;
ResourceManager *_res = nullptr;
RoomManager *_room = nullptr;
- AlfredState alfredState;
+ AlfredState _alfredState;
byte *_compositeBuffer = nullptr; // Working composition buffer
GameStateData _state;
@@ -168,8 +168,6 @@ public:
LargeFont *_largeFont = nullptr;
DoubleSmallFont *_doubleSmallFont = nullptr;
- Common::Array<int> _inventoryItems;
- int _selectedInventoryItem = -1;
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
@@ -208,6 +206,10 @@ public:
*/
Common::Error syncGame(Common::Serializer &s);
+ void loadGame(SaveGameData &saveGame);
+
+ SaveGameData *createSaveGameData() const;
+
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override {
Common::Serializer s(nullptr, stream);
return syncGame(s);
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index 87e3e6cabff..dff98e24e5b 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -18,8 +18,338 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+#include "common/savefile.h"
- namespace Pelrock {
+#include "pelrock.h"
+#include "pelrock/pelrock.h"
+#include "pelrock/types.h"
+namespace Pelrock {
- } // End of namespace Pelrock
+#define SAVEGAME_CURRENT_VERSION 1
+
+// Helper functions for syncing structs
+void syncSticker(Common::Serializer &s, Sticker &sticker) {
+ s.syncAsSint32LE(sticker.stickerIndex);
+ // if(s.isLoading()) {
+
+ // }
+ // s.syncAsSint32LE(sticker.roomNumber);
+
+ // if(s.isLoading()) {
+ // sticker.stickerData = new byte[sticker.w * sticker.h];
+ // }
+ // s.syncAsUint16LE(sticker.x);
+ // s.syncAsUint16LE(sticker.y);
+ // s.syncAsByte(sticker.w);
+ // s.syncAsByte(sticker.h);
+ // // Note: stickerData pointer not serialized - must be reconstructed on load
+}
+
+void syncExit(Common::Serializer &s, Exit &exit) {
+ s.syncAsByte(exit.index);
+ s.syncAsSint16LE(exit.x);
+ s.syncAsSint16LE(exit.y);
+ s.syncAsByte(exit.w);
+ s.syncAsByte(exit.h);
+ s.syncAsUint16LE(exit.targetRoom);
+ s.syncAsSint16LE(exit.targetX);
+ s.syncAsSint16LE(exit.targetY);
+ s.syncAsUint16LE(exit.targetDir);
+ s.syncAsByte((byte &)exit.dir);
+ s.syncAsByte(exit.isEnabled);
+}
+
+void syncExitChange(Common::Serializer &s, ExitChange &change) {
+ s.syncAsByte(change.roomNumber);
+ s.syncAsByte(change.exitIndex);
+ syncExit(s, change.exit);
+}
+
+void syncWalkBox(Common::Serializer &s, WalkBox &walkbox) {
+ s.syncAsSint16LE(walkbox.x);
+ s.syncAsSint16LE(walkbox.y);
+ s.syncAsSint16LE(walkbox.w);
+ s.syncAsSint16LE(walkbox.h);
+ s.syncAsByte(walkbox.flags);
+}
+
+void syncWalkBoxChange(Common::Serializer &s, WalkBoxChange &change) {
+ s.syncAsByte(change.roomNumber);
+ s.syncAsByte(change.walkboxIndex);
+ syncWalkBox(s, change.walkbox);
+}
+
+void syncHotSpot(Common::Serializer &s, HotSpot &hotspot) {
+ s.syncAsByte(hotspot.index);
+ s.syncAsByte(hotspot.innerIndex);
+ s.syncAsSint32LE(hotspot.id);
+ s.syncAsSint16LE(hotspot.x);
+ s.syncAsSint16LE(hotspot.y);
+ s.syncAsSint16LE(hotspot.w);
+ s.syncAsSint16LE(hotspot.h);
+ s.syncAsByte(hotspot.actionFlags);
+ s.syncAsByte(hotspot.extra);
+ s.syncAsByte((byte &)hotspot.isEnabled);
+ s.syncAsByte((byte &)hotspot.isSprite);
+ s.syncAsByte(hotspot.zOrder);
+}
+
+void syncHotSpotChange(Common::Serializer &s, HotSpotChange &change) {
+ s.syncAsByte(change.roomNumber);
+ s.syncAsByte(change.hotspotIndex);
+ syncHotSpot(s, change.hotspot);
+}
+
+void syncResetEntry(Common::Serializer &s, ResetEntry &entry) {
+ s.syncAsUint16LE(entry.room);
+ s.syncAsUint16LE(entry.offset);
+ s.syncAsByte(entry.dataSize);
+ if (s.isLoading()) {
+ entry.data = new byte[entry.dataSize];
+ }
+ for (int j = 0; j < entry.dataSize; ++j) {
+ s.syncAsByte(entry.data[j]);
+ }
+}
+
+bool syncGeneralData(Common::Serializer &s, SaveGameData *game) {
+ // Byte
+ s.syncAsByte(game->currentRoom);
+ // Uint16
+ s.syncAsUint16LE(game->alfredX);
+ s.syncAsUint16LE(game->alfredY);
+ s.syncAsByte(game->alfredDir);
+
+ return !s.err();
+}
+
+bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
+ // GameState
+ s.syncAsUint32LE((uint32 &)gameState->stateGame);
+
+ // Inventory items
+ uint16 inventorySize = (uint16)gameState->inventoryItems.size();
+ s.syncAsUint16LE(inventorySize);
+ if (s.isLoading()) {
+ gameState->inventoryItems.resize(inventorySize);
+ }
+ for (uint16 i = 0; i < inventorySize; ++i) {
+ s.syncAsByte(gameState->inventoryItems[i]);
+ }
+ // Selected inventory item
+ s.syncAsSint16LE(gameState->selectedInventoryItem);
+
+ // Room stickers
+ uint16 stickersSize = (uint16)gameState->roomStickers.size();
+ s.syncAsUint16LE(stickersSize);
+ if (s.isSaving()) {
+ for (const auto &pair : gameState->roomStickers) {
+ byte roomNumber = pair._key;
+ s.syncAsByte(roomNumber);
+ const Common::Array<Sticker> &stickers = pair._value;
+ uint16 numStickers = (uint16)stickers.size();
+ s.syncAsUint16LE(numStickers);
+ for (uint16 i = 0; i < numStickers; ++i) {
+ Sticker sticker = stickers[i];
+ syncSticker(s, sticker);
+ }
+ }
+ } else {
+ gameState->roomStickers.clear();
+ for (uint16 idx = 0; idx < stickersSize; ++idx) {
+ byte roomNumber;
+ s.syncAsByte(roomNumber);
+ uint16 numStickers;
+ s.syncAsUint16LE(numStickers);
+ Common::Array<Sticker> stickers;
+ for (uint16 i = 0; i < numStickers; ++i) {
+ int stickerIndex = 0;
+ s.syncAsSint32LE(stickerIndex);
+ stickers.push_back(g_engine->_res->getSticker(stickerIndex));
+ }
+ gameState->roomStickers[roomNumber] = stickers;
+ }
+ }
+
+ // Room exit changes
+ uint16 numExits = (uint16)gameState->roomExitChanges.size();
+ s.syncAsUint16LE(numExits);
+ if (s.isSaving()) {
+ for (const auto &exitPair : gameState->roomExitChanges) {
+ byte roomNumber = exitPair._key;
+ s.syncAsByte(roomNumber);
+ const Common::Array<ExitChange> &exits = exitPair._value;
+ uint16 numExitsInRoom = (uint16)exits.size();
+ s.syncAsUint16LE(numExitsInRoom);
+ for (uint16 i = 0; i < numExitsInRoom; ++i) {
+ ExitChange change = exits[i];
+ syncExitChange(s, change);
+ }
+ }
+ } else {
+ gameState->roomExitChanges.clear();
+ for (uint16 idx = 0; idx < numExits; ++idx) {
+ byte roomNumber;
+ s.syncAsByte(roomNumber);
+ uint16 numExitsInRoom;
+ s.syncAsUint16LE(numExitsInRoom);
+ Common::Array<ExitChange> exits;
+ for (uint16 i = 0; i < numExitsInRoom; ++i) {
+ ExitChange change;
+ syncExitChange(s, change);
+ exits.push_back(change);
+ }
+ gameState->roomExitChanges[roomNumber] = exits;
+ }
+ }
+
+ // Room walkbox changes
+ uint16 numWalkBoxes = (uint16)gameState->roomWalkBoxChanges.size();
+ s.syncAsUint16LE(numWalkBoxes);
+ if (s.isSaving()) {
+ for (const auto &walkBoxPair : gameState->roomWalkBoxChanges) {
+ byte roomNumber = walkBoxPair._key;
+ s.syncAsByte(roomNumber);
+ const Common::Array<WalkBoxChange> &walkBoxes = walkBoxPair._value;
+ uint16 numWalkBoxesInRoom = (uint16)walkBoxes.size();
+ s.syncAsUint16LE(numWalkBoxesInRoom);
+ for (uint16 i = 0; i < numWalkBoxesInRoom; ++i) {
+ WalkBoxChange change = walkBoxes[i];
+ syncWalkBoxChange(s, change);
+ }
+ }
+ } else {
+ gameState->roomWalkBoxChanges.clear();
+ for (uint16 idx = 0; idx < numWalkBoxes; ++idx) {
+ byte roomNumber;
+ s.syncAsByte(roomNumber);
+ uint16 numWalkBoxesInRoom;
+ s.syncAsUint16LE(numWalkBoxesInRoom);
+ Common::Array<WalkBoxChange> walkBoxes;
+ for (uint16 i = 0; i < numWalkBoxesInRoom; ++i) {
+ WalkBoxChange change;
+ syncWalkBoxChange(s, change);
+ walkBoxes.push_back(change);
+ }
+ gameState->roomWalkBoxChanges[roomNumber] = walkBoxes;
+ }
+ }
+
+ // Room hotspot changes
+ uint16 hotSpotChangesSize = (uint16)gameState->roomHotSpotChanges.size();
+ s.syncAsUint16LE(hotSpotChangesSize);
+ if (s.isSaving()) {
+ for (const auto &hotSpotPair : gameState->roomHotSpotChanges) {
+ byte roomNumber = hotSpotPair._key;
+ s.syncAsByte(roomNumber);
+ const Common::Array<HotSpotChange> &hotSpots = hotSpotPair._value;
+ uint16 numHotSpots = (uint16)hotSpots.size();
+ s.syncAsUint16LE(numHotSpots);
+ for (uint16 i = 0; i < numHotSpots; ++i) {
+ HotSpotChange change = hotSpots[i];
+ syncHotSpotChange(s, change);
+ }
+ }
+ } else {
+ gameState->roomHotSpotChanges.clear();
+ for (uint16 idx = 0; idx < hotSpotChangesSize; ++idx) {
+ byte roomNumber;
+ s.syncAsByte(roomNumber);
+ uint16 numHotSpots;
+ s.syncAsUint16LE(numHotSpots);
+ Common::Array<HotSpotChange> hotSpots;
+ for (uint16 i = 0; i < numHotSpots; ++i) {
+ HotSpotChange change;
+ syncHotSpotChange(s, change);
+ hotSpots.push_back(change);
+ }
+ gameState->roomHotSpotChanges[roomNumber] = hotSpots;
+ }
+ }
+
+ // Disabled branches
+ uint16 disabledBranchesSize = (uint16)gameState->disabledBranches.size();
+ s.syncAsUint16LE(disabledBranchesSize);
+ if (s.isSaving()) {
+ for (const auto &branchPair : gameState->disabledBranches) {
+ byte roomNumber = branchPair._key;
+ s.syncAsByte(roomNumber);
+ const Common::Array<ResetEntry> &branches = branchPair._value;
+ uint16 numBranches = (uint16)branches.size();
+ s.syncAsUint16LE(numBranches);
+ for (uint16 i = 0; i < numBranches; ++i) {
+ ResetEntry entry = branches[i];
+ syncResetEntry(s, entry);
+ }
+ }
+ } else {
+ gameState->disabledBranches.clear();
+ for (uint16 idx = 0; idx < disabledBranchesSize; ++idx) {
+ byte roomNumber;
+ s.syncAsByte(roomNumber);
+ uint16 numBranches;
+ s.syncAsUint16LE(numBranches);
+ Common::Array<ResetEntry> branches;
+ for (uint16 i = 0; i < numBranches; ++i) {
+ ResetEntry entry;
+ syncResetEntry(s, entry);
+ branches.push_back(entry);
+ }
+ gameState->disabledBranches[roomNumber] = branches;
+ }
+ }
+
+ // Conversation roots state
+ s.syncBytes(gameState->conversationRootsState, 4 * 56);
+ return !s.err();
+}
+
+Common::Error syncSaveData(Common::Serializer &s, SaveGameData *gameState) {
+ if (!syncGeneralData(s, gameState))
+ return Common::Error(Common::kUnknownError, "Failed to sync general save game data.");
+
+ if (!syncGameStateData(s, gameState->gameState))
+ return Common::Error(Common::kUnknownError, "Failed to sync game state data.");
+
+ return Common::kNoError;
+}
+
+Common::Error PelrockEngine::syncGame(Common::Serializer &s) {
+ Common::Error result;
+
+ if (s.isLoading()) {
+ SaveGameData saveGame;
+ if (saveGame.gameState != nullptr)
+ delete saveGame.gameState;
+ saveGame.gameState = new GameStateData();
+ result = syncSaveData(s, &(saveGame));
+ loadGame(saveGame);
+ } else {
+ SaveGameData *saveGame = createSaveGameData();
+ result = syncSaveData(s, saveGame);
+ }
+ return result;
+}
+
+void PelrockEngine::loadGame(SaveGameData &saveGame) {
+ _alfredState.x = saveGame.alfredX;
+ _alfredState.y = saveGame.alfredY;
+ _alfredState.direction = (AlfredDirection)saveGame.alfredDir;
+ _state = *(saveGame.gameState);
+
+ setScreen(saveGame.currentRoom, _alfredState.direction);
+ _state.stateGame = GAME;
+}
+
+SaveGameData *PelrockEngine::createSaveGameData() const {
+ SaveGameData *saveGame = new SaveGameData();
+ saveGame->gameState = &g_engine->_state;
+ saveGame->currentRoom = _room->_currentRoomNumber;
+ saveGame->alfredX = _alfredState.x;
+ saveGame->alfredY = _alfredState.y;
+ saveGame->alfredDir = _alfredState.direction;
+ return saveGame;
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 4df597b3717..a3e54267b8a 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -380,13 +380,16 @@ struct ResetEntry {
byte *data = nullptr;
};
+
struct GameStateData {
GameState stateGame = INTRO;
+
+ Common::Array<byte> inventoryItems;
+ int16 selectedInventoryItem = -1;
Common::HashMap<byte, Common::Array<Sticker>> roomStickers;
Common::HashMap<byte, Common::Array<ExitChange>> roomExitChanges;
Common::HashMap<byte, Common::Array<WalkBoxChange>> roomWalkBoxChanges;
Common::HashMap<byte, Common::Array<HotSpotChange>> roomHotSpotChanges;
-
Common::HashMap<byte, Common::Array<ResetEntry>> disabledBranches;
GameStateData() {
@@ -413,6 +416,14 @@ struct GameStateData {
}
};
+struct SaveGameData {
+ byte currentRoom = 0;
+ uint16 alfredX = 0;
+ uint16 alfredY = 0;
+ AlfredDirection alfredDir = ALFRED_DOWN;
+ GameStateData *gameState = nullptr;
+};
+
} // End of namespace Pelrock
#endif
Commit: b0044c74d6ee1da608624ab3f20d99fe31dee5ab
https://github.com/scummvm/scummvm/commit/b0044c74d6ee1da608624ab3f20d99fe31dee5ab
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:43+02:00
Commit Message:
PELROCK: Fix extra Alfred being show when clicking on target object
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index bebdd59fd74..04b9c98ef08 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -609,9 +609,10 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (_alfredState.curFrame >= walkingAnimLengths[_alfredState.direction]) {
_alfredState.curFrame = 0;
}
-
- drawAlfred(_res->alfredWalkFrames[_alfredState.direction][_alfredState.curFrame]);
- _alfredState.curFrame++;
+ if(_alfredState.animState == ALFRED_WALKING) {// in case it changed to idle above
+ drawAlfred(_res->alfredWalkFrames[_alfredState.direction][_alfredState.curFrame]);
+ _alfredState.curFrame++;
+ }
break;
}
case ALFRED_TALKING:
Commit: 33b640a79e1c3f2442135bd0f5aa7112703110ec
https://github.com/scummvm/scummvm/commit/33b640a79e1c3f2442135bd0f5aa7112703110ec
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:43+02:00
Commit Message:
PELROCK: Swap palette remaps
Changed paths:
engines/pelrock/graphics.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 218e52b9e39..e52fbf92f29 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -38,7 +38,7 @@ Common::Point GraphicsManager::showOverlay(int height, byte *buf) {
for (int x = 0; x < 640; x++) {
for (int y = overlayY; y < 400; y++) {
int index = y * 640 + x;
- buf[index] = g_engine->_room->paletteRemaps[1][buf[index]];
+ buf[index] = g_engine->_room->paletteRemaps[0][buf[index]];
}
}
return Common::Point(overlayX, overlayY);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 04b9c98ef08..54277f017a6 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -748,7 +748,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
if (shadeCharacter) {
for (int i = 0; i < finalWidth * finalHeight; i++) {
if (finalBuf[i] != 255) {
- finalBuf[i] = _room->paletteRemaps[0][finalBuf[i]];
+ finalBuf[i] = _room->paletteRemaps[1][finalBuf[i]];
}
}
}
Commit: 7701be0918f256afb67d8a58319a6691ca1d500d
https://github.com/scummvm/scummvm/commit/7701be0918f256afb67d8a58319a6691ca1d500d
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:43+02:00
Commit Message:
PELROCK: Walk to center of hotspots
Changed paths:
engines/pelrock/pathfinding.cpp
engines/pelrock/pathfinding.h
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
index c6538d91273..af0bfb8681c 100644
--- a/engines/pelrock/pathfinding.cpp
+++ b/engines/pelrock/pathfinding.cpp
@@ -50,7 +50,7 @@ Common::String printMovementFlags(uint8_t flags) {
return result;
}
-bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<WalkBox> &walkboxes, PathContext *context) {
+bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<WalkBox> &walkboxes, PathContext *context, HotSpot *hotspot) {
if (context->pathBuffer == NULL) {
context->pathBuffer = (uint8_t *)malloc(MAX_PATH_LENGTH);
@@ -61,7 +61,7 @@ bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<
int startX = sourceX;
int startY = sourceY;
- Common::Point target = calculateWalkTarget(walkboxes, targetX, targetY, false, nullptr);
+ Common::Point target = calculateWalkTarget(walkboxes, targetX, targetY, 2, nullptr);
targetX = target.x;
targetY = target.y;
debug("Startx= %d, starty= %d, destx= %d, desty= %d", startX, startY, targetX, targetY);
@@ -140,13 +140,15 @@ Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes,
// sourceY = hotspot->y + hotspot->height;
// }
- if (mouseHoverState == 1) {
+ // if (mouseHoverState == 1) {
// Hovering over hotspot - use hotspot center-bottom
+ if(hotspot != nullptr) {
sourceX = hotspot->x + hotspot->w / 2;
sourceY = hotspot->y + hotspot->h;
-
}
+ // }
+
// else: use sourceX, sourceY as passed (mouse position)
// Step 2: Find nearest walkbox
diff --git a/engines/pelrock/pathfinding.h b/engines/pelrock/pathfinding.h
index 8f02b0e814b..6b7a3a628ef 100644
--- a/engines/pelrock/pathfinding.h
+++ b/engines/pelrock/pathfinding.h
@@ -27,8 +27,17 @@
#include "pelrock/types.h"
namespace Pelrock {
-bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<WalkBox> &walkboxes, PathContext *context);
+bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<WalkBox> &walkboxes, PathContext *context, HotSpot *hotspot = nullptr);
+/**
+ * Calculate the walk target point based on source coordinates and mouse hover state.
+ * @param walkboxes Array of walkboxes in the current room.
+ * @param sourceX X coordinate of the source point (e.g., mouse position).
+ * @param sourceY Y coordinate of the source point (e.g., mouse position).
+ * @param mouseHoverState State indicating what the mouse is hovering over (0 = nothing, 1 = hotspot hover, 2 = hotspot click).
+ * @param hotspot Pointer to the hotspot being hovered over (if applicable).
+ * @return Calculated walk target point.
+ */
Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes, int sourceX, int sourceY, bool mouseHoverState, HotSpot *hotspot);
uint8_t findWalkboxForPoint(Common::Array<WalkBox> &walkboxes, uint16_t x, uint16_t y);
uint8_t getAdjacentWalkbox(Common::Array<WalkBox> &walkboxes, uint8_t current_box_index);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 54277f017a6..aab309f1e0e 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1131,7 +1131,7 @@ void PelrockEngine::extraScreenLoop() {
void PelrockEngine::walkTo(int x, int y) {
_currentStep = 0;
PathContext context = {nullptr, nullptr, nullptr, 0, 0, 0};
- findPath(_alfredState.x, _alfredState.y, x, y, _room->_currentRoomWalkboxes, &context);
+ findPath(_alfredState.x, _alfredState.y, x, y, _room->_currentRoomWalkboxes, &context, _currentHotspot);
_currentContext = context;
_alfredState.setState(ALFRED_WALKING);
}
Commit: c80e1a25bc49f46143c7b061be5f1542cf861390
https://github.com/scummvm/scummvm/commit/c80e1a25bc49f46143c7b061be5f1542cf861390
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:44+02:00
Commit Message:
PELROCK: Use inventory item with hotspot
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/actions.h
engines/pelrock/offsets.h
engines/pelrock/pathfinding.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 30127b279fe..b61f620fca4 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -19,6 +19,8 @@
*
*/
+#include "graphics/paletteman.h"
+
#include "pelrock/actions.h"
#include "pelrock.h"
#include "pelrock/offsets.h"
@@ -38,27 +40,60 @@ const ActionEntry actionTable[] = {
{4, PICKUP, &PelrockEngine::pickUpBrick}, // Brick
// Generic handlers
- {WILDCARD, PICKUP, &PelrockEngine::noOp}, // Generic pickup action
- {WILDCARD, TALK, &PelrockEngine::noOp}, // Generic talk action
- {WILDCARD, WALK, &PelrockEngine::noOp}, // Generic walk action
- {WILDCARD, LOOK, &PelrockEngine::noOp}, // Generic look action
- {WILDCARD, PUSH, &PelrockEngine::noOp}, // Generic push action
- {WILDCARD, PULL, &PelrockEngine::noOp}, // Generic pull action
- {WILDCARD, OPEN, &PelrockEngine::noOp}, // Generic open action
- {WILDCARD, CLOSE, &PelrockEngine::noOp}, // Generic close action
+ {WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
+ {WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
+ {WILDCARD, WALK, &PelrockEngine::noOpAction}, // Generic walk action
+ {WILDCARD, LOOK, &PelrockEngine::noOpAction}, // Generic look action
+ {WILDCARD, PUSH, &PelrockEngine::noOpAction}, // Generic push action
+ {WILDCARD, PULL, &PelrockEngine::noOpAction}, // Generic pull action
+ {WILDCARD, OPEN, &PelrockEngine::noOpAction}, // Generic open action
+ {WILDCARD, CLOSE, &PelrockEngine::noOpAction}, // Generic close action
// End marker
{WILDCARD, NO_ACTION, nullptr}};
-// Handler implementations
+
+const CombinationEntry combinationTable[] = {
+ {2, 281, &PelrockEngine::useCardWithATM}, // Use ATM Card with ATM
+ // End marker
+ {WILDCARD, WILDCARD, nullptr}
+};
+
+ // Handler implementations
+void PelrockEngine::openDoor(HotSpot *hotspot) {
+ _room->addSticker(_res->getSticker(93), false);
+ _room->enableExit(0, false);
+}
+
void PelrockEngine::openDrawer(HotSpot *hotspot) {
if (_room->hasSticker(91)) {
- _dialog->say(_res->_ingameTexts[ALREADY_OPENED_M]);
+ _dialog->say(_res->_ingameTexts[YA_ABIERTO_M]);
return;
}
_room->addSticker(_res->getSticker(91));
// TODO: Check if we need to disable the hotspot
- _room->disableHotspot(hotspot);
+ if(_room->findHotspotByExtra(1)->isEnabled &&
+ _room->findHotspotByExtra(2)->isEnabled &&
+ _room->findHotspotByExtra(3)->isEnabled) {
+ _room->disableHotspot(hotspot);
+ }
+}
+
+void PelrockEngine::closeDoor(HotSpot *hotspot) {
+ _room->removeSticker(93);
+ _room->disableExit(0, false);
+}
+
+void PelrockEngine::pickUpPhoto(HotSpot *hotspot) {
+ _room->enableHotspot(_room->findHotspotByExtra(261));
+}
+
+void PelrockEngine::pickYellowBook(HotSpot *hotspot) {
+ _room->addSticker(_res->getSticker(95));
+}
+
+void PelrockEngine::pickUpBrick(HotSpot *hotspot) {
+ _room->addSticker(_res->getSticker(133));
}
void PelrockEngine::closeDrawer(HotSpot *hotspot) {
@@ -66,20 +101,41 @@ void PelrockEngine::closeDrawer(HotSpot *hotspot) {
_room->enableHotspot(hotspot);
}
-void PelrockEngine::openDoor(HotSpot *hotspot) {
- _room->addSticker(_res->getSticker(93), false);
- _room->_currentRoomExits[0].isEnabled = true;
-}
-void PelrockEngine::closeDoor(HotSpot *hotspot) {
- _room->removeSticker(93);
- _room->_currentRoomExits[0].isEnabled = false;
+void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
+ debug("Withdrawing money from ATM using card (inv obj %d)", inventoryObject);
+ if(_state.JEFE_INGRESA_PASTA) {
+ _state.JEFE_INGRESA_PASTA = 0;
+ addInventoryItem(75);
+ }
+ else {
+ int billCount = 0;
+ for(int i = 0; i < _state.inventoryItems.size(); i++) {
+ if(_state.inventoryItems[i] == 5) {
+ billCount++;
+ }
+ }
+ if(billCount < 13) {
+ addInventoryItem(5); // 1000 pesetas bill
+ _dialog->say(_res->_ingameTexts[109]);
+ }
+ else {
+ _dialog->say(_res->_ingameTexts[NOMONEY_LEFT]);
+ }
+
+ }
}
void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
+ addInventoryItem(hotspot->extra);
+ _room->disableHotspot(hotspot);
+}
+
+void PelrockEngine::addInventoryItem(int item) {
if (_state.inventoryItems.size() == 0) {
- _state.selectedInventoryItem = hotspot->extra;
+ _state.selectedInventoryItem = item;
}
+ _flashingIcon = item;
int frameCounter = 0;
while (frameCounter < kIconFlashDuration) {
_events->pollEvent();
@@ -91,31 +147,47 @@ void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
}
g_system->delayMillis(10);
}
- _state.inventoryItems.push_back(hotspot->extra);
- _room->disableHotspot(hotspot);
+ _state.addInventoryItem(item);
}
-void PelrockEngine::pickUpPhoto(HotSpot *hotspot) {
- _room->enableHotspot(_room->findHotspotByExtra(261));
-}
-void PelrockEngine::pickYellowBook(HotSpot *hotspot) {
- _room->addSticker(_res->getSticker(95));
+void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex) {
+ if(actionTrigger == 328) {
+ debug("Disabling root %d in room %d", rootIndex, room);
+ _state.setRootDisabledState(room, rootIndex, true);
+ }
}
-void PelrockEngine::pickUpBrick(HotSpot *hotspot) {
- _room->addSticker(_res->getSticker(133));
+void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
+ debug("Performing action trigger: %d", actionTrigger);
+ switch (actionTrigger) {
+ case 257:
+ byte *palette = new byte[768];
+ if (_extraScreen == nullptr) {
+ _extraScreen = new byte[640 * 400];
+ }
+ _res->getExtraScreen(9, _extraScreen, palette);
+
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+ extraScreenLoop();
+
+ _dialog->say(_res->_ingameTexts[SOHOT]);
+ _screen->markAllDirty();
+ _screen->update();
+
+ delete[] palette;
+ break;
+ }
}
-void PelrockEngine::noOp(HotSpot *hotspot) {
+
+void PelrockEngine::noOpAction(HotSpot *hotspot) {
// Do nothing
}
-void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex) {
- if(actionTrigger == 328) {
- debug("Disabling root %d in room %d", rootIndex, room);
- _state.setRootDisabledState(room, rootIndex, true);
- }
+
+void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
+ // Do nothing
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/actions.h b/engines/pelrock/actions.h
index 5bd70abe8e4..a5eb7a62804 100644
--- a/engines/pelrock/actions.h
+++ b/engines/pelrock/actions.h
@@ -35,8 +35,15 @@ struct ActionEntry {
void (PelrockEngine::*handler)(HotSpot *);
};
+struct CombinationEntry {
+ int inventoryObject;
+ int hotspotExtra;
+ void (PelrockEngine::*handler)(int, HotSpot *);
+};
+
// Action table for all rooms
extern const ActionEntry actionTable[];
+extern const CombinationEntry combinationTable[];
} // End of namespace Pelrock
#endif // PELROCK_ACTIONS_H
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index aed6086615e..a76ad6cb5f5 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -120,9 +120,9 @@ const byte pegatina_rooms[140] = {
};
enum TextIndices {
- THEYRE_CLOSED,
- NOTAVAILABLE_TODAY,
- ALREADY_OPENED_M,
+ ESTAN_CERRADOS,
+ HOY_NO_DISPONIBLES,
+ YA_ABIERTO_M,
ALREADY_CLOSED_M,
ALREADY_OPENED_F,
ALREADY_CLOSED_F,
@@ -154,6 +154,29 @@ enum TextIndices {
HEY_DONTSTART,
HOTONE_MOCKING,
SHUTUP,
+ NO_YOU,
+ TOO_MUCH_CANT_THINK,
+ A_LITTLE_RESPECT,
+ NO_THEY_MAKEYOU_FAT,
+ CLOCK_CHANGED,
+ CORRESPONDENCIA_AJENA,
+ ANDA,
+ TUCREES,
+ NOESAMIAQUIENDEBES,
+ AQUIENENTONCES,
+ LIBROSSECRETOS,
+ VENGA_ACA,
+ TODOS,
+ EL_LIBRO_NOESTA_AQUI,
+ TENDRE_DEJAR_LIBRO,
+ TRABAJARIA_MEJOR_SI_NO_ME_MOLESTARA,
+ REGALO_LIBRO_RECETAS,
+ YSI_METIRA_MAQUINA,
+ QUITA_ESAS_MANOS,
+ QUEASCO,
+ QUESESTO_RECETA,
+ YAESTA_ABIERTO,
+
};
// Description offsets relative to DESCRIPTION_BASE_OFFSET
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
index af0bfb8681c..efe1a28e600 100644
--- a/engines/pelrock/pathfinding.cpp
+++ b/engines/pelrock/pathfinding.cpp
@@ -142,10 +142,10 @@ Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes,
// if (mouseHoverState == 1) {
// Hovering over hotspot - use hotspot center-bottom
- if(hotspot != nullptr) {
- sourceX = hotspot->x + hotspot->w / 2;
- sourceY = hotspot->y + hotspot->h;
- }
+ // if(hotspot != nullptr) {
+ // sourceX = hotspot->x + hotspot->w / 2;
+ // sourceY = hotspot->y + hotspot->h;
+ // }
// }
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index aab309f1e0e..19f6a47d676 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -252,30 +252,22 @@ bool PelrockEngine::renderScene(int overlayMode) {
return false;
}
-void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
- debug("Performing action trigger: %d", actionTrigger);
- switch (actionTrigger) {
- case 257:
- byte *palette = new byte[768];
- if (_extraScreen == nullptr) {
- _extraScreen = new byte[640 * 400];
- }
- _res->getExtraScreen(9, _extraScreen, palette);
-
- g_system->getPaletteManager()->setPalette(palette, 0, 256);
- extraScreenLoop();
-
- _dialog->say(_res->_ingameTexts[SOHOT]);
- _screen->markAllDirty();
- _screen->update();
+void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
- delete[] palette;
- break;
+ if(action == ITEM) {
+ int inventoryObject = _state.selectedInventoryItem;
+ for (const CombinationEntry *entry = combinationTable; entry->handler != nullptr; entry++) {
+ if (entry->inventoryObject == inventoryObject && entry->hotspotExtra == hotspot->extra) {
+ (this->*(entry->handler))(inventoryObject, hotspot);
+ return;
+ }
+ }
+ warning("No handler for using inventory object %d with hotspot %d", inventoryObject, hotspot->extra);
+ return;
}
-}
-void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
+
for (const ActionEntry *entry = actionTable; entry->handler != nullptr; entry++) {
if (entry->action == action && entry->hotspotExtra == hotspot->extra) {
// Found exact match - call the handler
@@ -284,7 +276,7 @@ void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
}
}
- // Try wildcard match (hotspotExtra == 0 means "any hotspot")
+ // Try wildcard match (hotspotExtra == -1 means "any hotspot")
for (const ActionEntry *entry = actionTable; entry->handler != nullptr; ++entry) {
if (entry->action == action && entry->hotspotExtra == WILDCARD) {
(this->*(entry->handler))(hotspot);
@@ -1096,7 +1088,7 @@ void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
void PelrockEngine::pickupIconFlash() {
_graphics->showOverlay(65, _compositeBuffer);
- InventoryObject item = _res->getInventoryObject(_currentHotspot->extra);
+ InventoryObject item = _res->getInventoryObject(_flashingIcon);
if (_chrono->getFrameCount() % kIconBlinkPeriod == 0) {
drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 5, 400 - 60 - 5, 60, 60, 1);
}
@@ -1185,11 +1177,19 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
return NO_ACTION;
}
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
- for (int i = 0; i < actions.size(); i++) {
+ int loopEnd = _state.selectedInventoryItem != -1 ? actions.size() + 1 : actions.size();
+ for (int i = 0; i < loopEnd; i++) {
int actionX = _actionPopupState.x + 20 + (i * (kVerbIconWidth + 2));
int actionY = _actionPopupState.y + 20;
Common::Rect actionRect = Common::Rect(actionX, actionY, actionX + kVerbIconWidth, actionY + kVerbIconHeight);
- if (actionRect.contains(x, y)) {
+
+ if(i == actions.size()) {
+ // Check inventory item
+ if (actionRect.contains(x, y)) {
+ return ITEM;
+ }
+ }
+ else if (actionRect.contains(x, y)) {
return actions[i];
}
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 50d1affcc74..b1427cf4677 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -133,9 +133,9 @@ private:
ActionPopupState _actionPopupState;
HotSpot *_currentHotspot = nullptr;
+ int _flashingIcon = -1;
Common::Point _curWalkTarget;
-
QueuedAction _queuedAction;
bool showShadows = false;
@@ -222,6 +222,7 @@ public:
void setScreen(int s, AlfredDirection dir);
bool renderScene(int overlayMode = OVERLAY_NONE);
+ void addInventoryItem(int item);
// Actions
void performActionTrigger(uint16 actionTrigger);
void dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex);
@@ -235,7 +236,9 @@ public:
void pickUpPhoto(HotSpot *hotspot);
void pickYellowBook(HotSpot *hotspot);
void pickUpBrick(HotSpot *hotspot);
- void noOp(HotSpot *hotspot);
+ void noOpAction(HotSpot *hotspot);
+ void noOpItem(int item, HotSpot *hotspot);
+ void useCardWithATM(int inventoryObject, HotSpot *hotspot);
};
extern PelrockEngine *g_engine;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 9cc6a11d670..555cdabe24c 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -116,8 +116,18 @@ bool RoomManager::hasSticker(int index) {
return false;
}
-void RoomManager::changeExit(Exit exit) {
- g_engine->_state.roomExitChanges[_currentRoomNumber].push_back({_currentRoomNumber, exit.index, exit});
+void RoomManager::changeExit(int index, bool enabled, bool persist) {
+ _currentRoomExits[index].isEnabled = enabled;
+ if(persist)
+ g_engine->_state.roomExitChanges[_currentRoomNumber].push_back({_currentRoomNumber, _currentRoomExits[index].index, _currentRoomExits[index]});
+}
+
+void RoomManager::disableExit(int index, bool persist) {
+ changeExit(index, false, persist);
+}
+
+void RoomManager::enableExit(int index, bool persist) {
+ changeExit(index, true, persist);
}
void RoomManager::changeWalkBox(WalkBox walkbox) {
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 2a3ace33404..6814dad01aa 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -45,7 +45,9 @@ public:
void addSticker(Sticker sticker, bool persist = true);
void removeSticker(int index);
bool hasSticker(int index);
- void changeExit(Exit exit);
+ void changeExit(int index, bool enabled, bool persist = true);
+ void disableExit(int index, bool persist);
+ void enableExit(int index, bool persist);
void changeWalkBox(WalkBox walkbox);
void changeHotSpot(HotSpot hotspot);
/**
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index a3e54267b8a..bdfbf28aeaf 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -44,6 +44,7 @@ enum VerbIcon {
PULL,
OPEN,
CLOSE,
+ ITEM,
UNKNOWN,
NO_ACTION
};
@@ -382,6 +383,8 @@ struct ResetEntry {
struct GameStateData {
+ bool JEFE_INGRESA_PASTA = false;
+
GameState stateGame = INTRO;
Common::Array<byte> inventoryItems;
@@ -405,6 +408,18 @@ struct GameStateData {
disabledBranches[entry.room].push_back(entry);
}
+ void addInventoryItem(int id) {
+ inventoryItems.push_back(id);
+ }
+ void removeInventoyItem(int id) {
+ for(int i = 0; i < inventoryItems.size(); i++) {
+ if (inventoryItems[i] == id) {
+ inventoryItems.remove_at(i);
+ return;
+ }
+ }
+ }
+
byte *conversationRootsState = new byte[4 * 56];
bool getRootDisabledState(byte room, byte root) const {
Commit: d8d5873eee038cc505826cad57fcd8fb00ebcec5
https://github.com/scummvm/scummvm/commit/d8d5873eee038cc505826cad57fcd8fb00ebcec5
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:44+02:00
Commit Message:
PELROCK: Wrong combination responses
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index b61f620fca4..abbcb8f1825 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -59,7 +59,6 @@ const CombinationEntry combinationTable[] = {
{WILDCARD, WILDCARD, nullptr}
};
- // Handler implementations
void PelrockEngine::openDoor(HotSpot *hotspot) {
_room->addSticker(_res->getSticker(93), false);
_room->enableExit(0, false);
@@ -117,12 +116,11 @@ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
}
if(billCount < 13) {
addInventoryItem(5); // 1000 pesetas bill
- _dialog->say(_res->_ingameTexts[109]);
+ _dialog->say(_res->_ingameTexts[TEAPETECE_BUENRATO]);
}
else {
_dialog->say(_res->_ingameTexts[NOMONEY_LEFT]);
}
-
}
}
@@ -182,12 +180,14 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
void PelrockEngine::noOpAction(HotSpot *hotspot) {
- // Do nothing
}
void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
- // Do nothing
+ //154 to 169
+ debug("No-op item %d with hotspot %d", item, hotspot->extra);
+ byte response = (byte)getRandomNumber(12);
+ _dialog->say(_res->_ingameTexts[154 + response]);
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index a76ad6cb5f5..f6343fa48d1 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -176,7 +176,145 @@ enum TextIndices {
QUEASCO,
QUESESTO_RECETA,
YAESTA_ABIERTO,
-
+ VAESTAR_POCOFUERTE,
+ CUENTOPARECIDO,
+ COSASAPRENDIDO,
+ PERIODICOSENSACIONALISTA,
+ HOJAENTREPAGINAS,
+ NOENTIENDONADA,
+ NOTENGODINERO,
+ CUESTA1000,
+ AQUITIENE,
+ MUYBIEN,
+ YASEEGIPCIO,
+ QUELASTIMA_NOSEEGIPCIO,
+ FORMULAVIAJETIEMPO,
+ PARECECERRADO,
+ NOVIO2METROS,
+ GRANIDEA,
+ SELORECOMIENDO,
+ OIGAUSTED,
+ ESAMI,
+ VENGAAHORAMISMO,
+ CUIDADOIMPRUDENTE,
+ QUEOSCUROESTAESTO,
+ MENUDAAVENTURA,
+ NECESITOGASOLINA,
+ YANOSEHACEONCOMOANTES,
+ NADIELOHAVISTO,
+ AYAYAY,
+ OIGAUSTED2,
+ LEESTOYVIGILANDO,
+ OIGA,
+ CAPITULOPARADOJAS,
+ HAYQUECELEBRARLO,
+ PESADEMASIADO,
+ NINGUNATEMAAPROPIADO,
+ PARAQUECOGERBARRO,
+ BUENOCOGEREUNPOCO,
+ ABSOLUTAMENTECERRADO,
+ NOSETEOCURRAACERCARTE,
+ PUERTAAUTENTICA_IZQUIERDA,
+ OHMISALVADOR,
+ VOYPORTI_PRINCESA,
+ AMISBRAZOS,
+ DIOSMIOQUEESESTO,
+ QUEPASA,
+ OLVIDECERRARTRAMPILLA,
+ NOTEPREOCUPES_VOLVERE,
+ ALACONUSTED,
+ MEMEO,
+ POR5MINUTOS,
+ TALUEGOLUCAS,
+ SISUPIERA_COMBINACION,
+ PARECE_COMBINACION_CAJAFUERTE,
+ GRANCANTIDAD_DINERO,
+ TEAPETECE_BUENRATO,
+ YLOSCONDONES,
+ QUEASCO_CASIMEMEA,
+ HECHOELPRIMO,
+ MEHANTOMADO_EL_PELO,
+ PESADO_UNRATO,
+ TRAIDOR,
+ TUTIA,
+ LATUYA,
+ GORDO,
+ FIDEO,
+ LIMPIACULO,
+ CONTUTURBANTE,
+ OSO,
+ COMADREJA,
+ CABEZON,
+ TUABUELO,
+ TUMUJER,
+ PERDEDOR,
+ SOYMEJORQUETU,
+ TRAMPOSO,
+ MALPERDEDOR,
+ PARAUNAVEZ,
+ MEJORMELARGO,
+ NOTENGOPARCHES,
+ NOTENGOPEGAMENTO,
+ MUNECO_ARREGLADO,
+ MAREDEDEU,
+ PROBARLIBRO,
+ PRACTICAR_MAS,
+ AQUI_NO_NECESITO,
+ DIOSHALCON,
+ OHGRANOSIRIS,
+ HEMEAQUI,
+ OHSOBEK,
+ OHTOTH,
+ TODOSLASCOSAS,
+ HELLEGADOPURO,
+ DIOSDELATURBULENCIA,
+ OHANUBIS,
+ HEVENIDO,
+ HELLEGADOATI,
+ OHPTHA,
+ LASPUERTASDELCIELO,
+ VAYASUENHO,
+ PARAQUE,
+ YESO,
+ UNPOCODESESPERADO,
+ COMBINACIONESMEJORES,
+ NOSEQUEPRETENDES_CONESO,
+ COMO,
+ MUCHOSENTIDO,
+ PORPROBAR,
+ NOLOENTIENDO,
+ PARAESONOSIRVE,
+ PRUEBAOTRACOSA,
+ SIHOMBREQUEMAS,
+ NOSEQUEPRETENDES,
+ COSASRARAS,
+ ARTE_O_LOCURA,
+ UTILIDADES,
+ TITULOJUEGO,
+ MENSAJEOTRAEPOCA,
+ NOERAAUTENTICO,
+ PRIMERINGREDIENTE,
+ DOSINGREDIENTES,
+ TRESINGREDIENTES,
+ CUATROINGREDIENTES,
+ DEACUERDO,
+ GAMBERROS,
+ QUIENYO,
+ PINTA_BUENAPERSONA,
+ DEMO_FINAL,
+ DIOSHALCON_2,
+ GRANOSIRIS,
+ HEMEAQUI_ISIS,
+ OHSOBEK_2,
+ OHTOTH_2,
+ PROTEGEN_MI_CUERPO,
+ HELLEGADO_PURO,
+ DIOSDELATURBULENCIA_2,
+ OHANUBIS_2,
+ HEVENIDO_2,
+ HELLEGADO_ATI,
+ OHPTHA_2,
+ LASPUERTAS_DELCIELO,
};
// Description offsets relative to DESCRIPTION_BASE_OFFSET
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 19f6a47d676..80b49229074 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -262,6 +262,7 @@ void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
return;
}
}
+ noOpItem(inventoryObject, hotspot);
warning("No handler for using inventory object %d with hotspot %d", inventoryObject, hotspot->extra);
return;
}
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index cf2503cd5aa..7ead6a86730 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -323,4 +323,8 @@ byte decodeChar(byte b) {
}
}
+Common::StringArray arrayOf(Common::String str) {
+ return Common::StringArray(1, str);
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 59ae1fb4687..62a70260476 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -43,6 +43,7 @@ void drawText(Graphics::Font *font, Common::String text, int x, int y, int w, by
Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
byte decodeChar(byte b);
+Common::StringArray arrayOf(Common::String str);
static const int special_chars[] = {
168, // inverted ?
Commit: 1481f311477a2bb44b9b6d4a518254e927784a8c
https://github.com/scummvm/scummvm/commit/1481f311477a2bb44b9b6d4a518254e927784a8c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:44+02:00
Commit Message:
PELROCK: Pickup sauces
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index abbcb8f1825..2a391eae874 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -37,7 +37,14 @@ const ActionEntry actionTable[] = {
{268, CLOSE, &PelrockEngine::closeDoor},
{3, PICKUP, &PelrockEngine::pickUpPhoto},
{0, PICKUP, &PelrockEngine::pickYellowBook}, // Generic pickup for other items
+ // Room 1
{4, PICKUP, &PelrockEngine::pickUpBrick}, // Brick
+ // Room 2
+ {282, OPEN, &PelrockEngine::openMcDoor},
+ {282, CLOSE, &PelrockEngine::closeMcDoor},
+ {60, PICKUP, &PelrockEngine::grabKetchup},
+ {61, PICKUP, &PelrockEngine::grabMustard},
+ {62, PICKUP, &PelrockEngine::grabSpicey},
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
@@ -60,7 +67,7 @@ const CombinationEntry combinationTable[] = {
};
void PelrockEngine::openDoor(HotSpot *hotspot) {
- _room->addSticker(_res->getSticker(93), false);
+ _room->addSticker(93, false);
_room->enableExit(0, false);
}
@@ -69,7 +76,7 @@ void PelrockEngine::openDrawer(HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[YA_ABIERTO_M]);
return;
}
- _room->addSticker(_res->getSticker(91));
+ _room->addSticker(91);
// TODO: Check if we need to disable the hotspot
if(_room->findHotspotByExtra(1)->isEnabled &&
_room->findHotspotByExtra(2)->isEnabled &&
@@ -88,11 +95,11 @@ void PelrockEngine::pickUpPhoto(HotSpot *hotspot) {
}
void PelrockEngine::pickYellowBook(HotSpot *hotspot) {
- _room->addSticker(_res->getSticker(95));
+ _room->addSticker(95);
}
void PelrockEngine::pickUpBrick(HotSpot *hotspot) {
- _room->addSticker(_res->getSticker(133));
+ _room->addSticker(133);
}
void PelrockEngine::closeDrawer(HotSpot *hotspot) {
@@ -100,7 +107,6 @@ void PelrockEngine::closeDrawer(HotSpot *hotspot) {
_room->enableHotspot(hotspot);
}
-
void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
debug("Withdrawing money from ATM using card (inv obj %d)", inventoryObject);
if(_state.JEFE_INGRESA_PASTA) {
@@ -124,11 +130,41 @@ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
}
}
+void PelrockEngine::openMcDoor(HotSpot *hotspot) {
+ if( _room->hasSticker(7)) {
+ _dialog->say(_res->_ingameTexts[ALREADY_OPENED_F]);
+ return;
+ }
+ _room->enableExit(2);
+ _room->addSticker(7);
+}
+
+void PelrockEngine::closeMcDoor(HotSpot *hotspot) {
+ if( !_room->hasSticker(7)) {
+ _dialog->say(_res->_ingameTexts[ALREADY_CLOSED_F]);
+ return;
+ }
+ _room->disableExit(2);
+ _room->removeSticker(7);
+}
+
void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
addInventoryItem(hotspot->extra);
_room->disableHotspot(hotspot);
}
+void PelrockEngine::grabKetchup(HotSpot *hotspot) {
+ _room->addSticker(70);
+}
+
+void PelrockEngine::grabMustard(HotSpot *hotspot) {
+ _room->addSticker(72);
+}
+
+void PelrockEngine::grabSpicey(HotSpot *hotspot) {
+ _room->addSticker(71);
+}
+
void PelrockEngine::addInventoryItem(int item) {
if (_state.inventoryItems.size() == 0) {
_state.selectedInventoryItem = item;
@@ -186,6 +222,7 @@ void PelrockEngine::noOpAction(HotSpot *hotspot) {
void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
//154 to 169
debug("No-op item %d with hotspot %d", item, hotspot->extra);
+ _alfredState.direction = ALFRED_DOWN;
byte response = (byte)getRandomNumber(12);
_dialog->say(_res->_ingameTexts[154 + response]);
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 80b49229074..796bbaf4723 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -530,6 +530,7 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
}
void PelrockEngine::lookAt(HotSpot *hotspot) {
+ debug("Looking at hotspot %d with extra %d", hotspot->index, hotspot->extra);
_dialog->sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index]);
_actionPopupState.isActive = false;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index b1427cf4677..29cbab2fd12 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -233,12 +233,17 @@ public:
void openDoor(HotSpot *hotspot);
void closeDoor(HotSpot *hotspot);
void pickUpAndDisable(HotSpot *hotspot);
+ void grabKetchup(HotSpot *hotspot);
+ void grabMustard(HotSpot *hotspot);
+ void grabSpicey(HotSpot *hotspot);
void pickUpPhoto(HotSpot *hotspot);
void pickYellowBook(HotSpot *hotspot);
void pickUpBrick(HotSpot *hotspot);
void noOpAction(HotSpot *hotspot);
void noOpItem(int item, HotSpot *hotspot);
void useCardWithATM(int inventoryObject, HotSpot *hotspot);
+ void openMcDoor(HotSpot *hotspot);
+ void closeMcDoor(HotSpot *hotspot);
};
extern PelrockEngine *g_engine;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 555cdabe24c..6eef9f6742c 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -88,7 +88,8 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
}
}
-void RoomManager::addSticker(Sticker sticker, bool persist) {
+void RoomManager::addSticker(int stickerId, bool persist) {
+ Sticker sticker = g_engine->_res->getSticker(stickerId);
if (persist)
g_engine->_state.roomStickers[_currentRoomNumber].push_back(sticker);
else
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 6814dad01aa..719a251db63 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -42,12 +42,12 @@ public:
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
/** Methods to modify room data at runtime **/
- void addSticker(Sticker sticker, bool persist = true);
+ void addSticker(int stickerId, bool persist = true);
void removeSticker(int index);
bool hasSticker(int index);
void changeExit(int index, bool enabled, bool persist = true);
- void disableExit(int index, bool persist);
- void enableExit(int index, bool persist);
+ void disableExit(int index, bool persist = true);
+ void enableExit(int index, bool persist = true);
void changeWalkBox(WalkBox walkbox);
void changeHotSpot(HotSpot hotspot);
/**
Commit: dec2e69b73fc0dbc19aaa2f97f0b7d424af54122
https://github.com/scummvm/scummvm/commit/dec2e69b73fc0dbc19aaa2f97f0b7d424af54122
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:45+02:00
Commit Message:
PELROCK: open/close doors
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 2a391eae874..77d5aeac3cf 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -21,14 +21,17 @@
#include "graphics/paletteman.h"
-#include "pelrock/actions.h"
#include "pelrock.h"
+#include "pelrock/actions.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
namespace Pelrock {
+#define MASCULINE true
+#define FEMININE false
+
const ActionEntry actionTable[] = {
// Room 0
{261, OPEN, &PelrockEngine::openDrawer},
@@ -38,13 +41,17 @@ const ActionEntry actionTable[] = {
{3, PICKUP, &PelrockEngine::pickUpPhoto},
{0, PICKUP, &PelrockEngine::pickYellowBook}, // Generic pickup for other items
// Room 1
- {4, PICKUP, &PelrockEngine::pickUpBrick}, // Brick
+ {4, PICKUP, &PelrockEngine::pickUpBrick}, // Brick
// Room 2
{282, OPEN, &PelrockEngine::openMcDoor},
{282, CLOSE, &PelrockEngine::closeMcDoor},
+
+ // Room 12
{60, PICKUP, &PelrockEngine::grabKetchup},
{61, PICKUP, &PelrockEngine::grabMustard},
{62, PICKUP, &PelrockEngine::grabSpicey},
+ {370, OPEN, &PelrockEngine::openKitchenDoor},
+ {370, CLOSE, &PelrockEngine::closeKitchenDoor},
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
@@ -59,16 +66,13 @@ const ActionEntry actionTable[] = {
// End marker
{WILDCARD, NO_ACTION, nullptr}};
-
const CombinationEntry combinationTable[] = {
{2, 281, &PelrockEngine::useCardWithATM}, // Use ATM Card with ATM
// End marker
- {WILDCARD, WILDCARD, nullptr}
-};
+ {WILDCARD, WILDCARD, nullptr}};
void PelrockEngine::openDoor(HotSpot *hotspot) {
- _room->addSticker(93, false);
- _room->enableExit(0, false);
+ openDoor(hotspot, 0, 93, FEMININE, true);
}
void PelrockEngine::openDrawer(HotSpot *hotspot) {
@@ -78,16 +82,15 @@ void PelrockEngine::openDrawer(HotSpot *hotspot) {
}
_room->addSticker(91);
// TODO: Check if we need to disable the hotspot
- if(_room->findHotspotByExtra(1)->isEnabled &&
- _room->findHotspotByExtra(2)->isEnabled &&
- _room->findHotspotByExtra(3)->isEnabled) {
- _room->disableHotspot(hotspot);
+ if (_room->findHotspotByExtra(1)->isEnabled &&
+ _room->findHotspotByExtra(2)->isEnabled &&
+ _room->findHotspotByExtra(3)->isEnabled) {
+ _room->disableHotspot(hotspot);
}
}
void PelrockEngine::closeDoor(HotSpot *hotspot) {
- _room->removeSticker(93);
- _room->disableExit(0, false);
+ closeDoor(hotspot, 0, 93, FEMININE, true);
}
void PelrockEngine::pickUpPhoto(HotSpot *hotspot) {
@@ -109,29 +112,27 @@ void PelrockEngine::closeDrawer(HotSpot *hotspot) {
void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
debug("Withdrawing money from ATM using card (inv obj %d)", inventoryObject);
- if(_state.JEFE_INGRESA_PASTA) {
+ if (_state.JEFE_INGRESA_PASTA) {
_state.JEFE_INGRESA_PASTA = 0;
addInventoryItem(75);
- }
- else {
+ } else {
int billCount = 0;
- for(int i = 0; i < _state.inventoryItems.size(); i++) {
- if(_state.inventoryItems[i] == 5) {
+ for (int i = 0; i < _state.inventoryItems.size(); i++) {
+ if (_state.inventoryItems[i] == 5) {
billCount++;
}
}
- if(billCount < 13) {
+ if (billCount < 13) {
addInventoryItem(5); // 1000 pesetas bill
_dialog->say(_res->_ingameTexts[TEAPETECE_BUENRATO]);
- }
- else {
+ } else {
_dialog->say(_res->_ingameTexts[NOMONEY_LEFT]);
}
}
}
void PelrockEngine::openMcDoor(HotSpot *hotspot) {
- if( _room->hasSticker(7)) {
+ if (_room->hasSticker(7)) {
_dialog->say(_res->_ingameTexts[ALREADY_OPENED_F]);
return;
}
@@ -140,7 +141,8 @@ void PelrockEngine::openMcDoor(HotSpot *hotspot) {
}
void PelrockEngine::closeMcDoor(HotSpot *hotspot) {
- if( !_room->hasSticker(7)) {
+ closeDoor(hotspot, 2, 7, FEMININE, true);
+ if (!_room->hasSticker(7)) {
_dialog->say(_res->_ingameTexts[ALREADY_CLOSED_F]);
return;
}
@@ -162,9 +164,38 @@ void PelrockEngine::grabMustard(HotSpot *hotspot) {
}
void PelrockEngine::grabSpicey(HotSpot *hotspot) {
+
_room->addSticker(71);
}
+void PelrockEngine::openKitchenDoor(HotSpot *hotspot) {
+ openDoor(hotspot, 1, 32, MASCULINE, true);
+}
+
+void PelrockEngine::closeKitchenDoor(HotSpot *HotSpot) {
+ closeDoor(HotSpot, 1, 32, MASCULINE, true);
+}
+
+void PelrockEngine::openDoor(HotSpot *hotspot, int doorIndex, int sticker, bool masculine, bool stayClosed) {
+ if (_room->hasSticker(sticker)) {
+ int text = masculine == MASCULINE ? YA_ABIERTO_M : ALREADY_OPENED_F;
+ _dialog->say(_res->_ingameTexts[text]);
+ return;
+ }
+ _room->enableExit(doorIndex, !stayClosed);
+ _room->addSticker(sticker, !stayClosed);
+}
+
+void PelrockEngine::closeDoor(HotSpot *hotspot, int doorIndex, int sticker, bool masculine, bool stayOpen) {
+ if (!_room->hasSticker(sticker)) {
+ int text = masculine == MASCULINE ? ALREADY_CLOSED_M : ALREADY_CLOSED_F;
+ _dialog->say(_res->_ingameTexts[text]);
+ return;
+ }
+ _room->disableExit(doorIndex, !stayOpen);
+ _room->removeSticker(sticker);
+}
+
void PelrockEngine::addInventoryItem(int item) {
if (_state.inventoryItems.size() == 0) {
_state.selectedInventoryItem = item;
@@ -184,9 +215,8 @@ void PelrockEngine::addInventoryItem(int item) {
_state.addInventoryItem(item);
}
-
void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex) {
- if(actionTrigger == 328) {
+ if (actionTrigger == 328) {
debug("Disabling root %d in room %d", rootIndex, room);
_state.setRootDisabledState(room, rootIndex, true);
}
@@ -214,13 +244,11 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
}
}
-
void PelrockEngine::noOpAction(HotSpot *hotspot) {
}
-
void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
- //154 to 169
+ // 154 to 169
debug("No-op item %d with hotspot %d", item, hotspot->extra);
_alfredState.direction = ALFRED_DOWN;
byte response = (byte)getRandomNumber(12);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 29cbab2fd12..bdc641ed837 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -236,6 +236,10 @@ public:
void grabKetchup(HotSpot *hotspot);
void grabMustard(HotSpot *hotspot);
void grabSpicey(HotSpot *hotspot);
+ void openKitchenDoor(HotSpot *hotspot);
+ void closeKitchenDoor(HotSpot *HotSpot);
+ void openDoor(HotSpot *hotspot, int doorIndex, int sticker, bool masculine, bool stayClosed);
+ void closeDoor(HotSpot *hotspot, int doorIndex, int sticker, bool masculine, bool stayOpen);
void pickUpPhoto(HotSpot *hotspot);
void pickYellowBook(HotSpot *hotspot);
void pickUpBrick(HotSpot *hotspot);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 6eef9f6742c..bad8be22e6d 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -98,12 +98,24 @@ void RoomManager::addSticker(int stickerId, bool persist) {
void RoomManager::removeSticker(int stickerIndex) {
int index = -1;
+ if (index == -1) {
+ for (int i = 0; i < _transientStickers.size(); i++) {
+ if (_transientStickers[i].stickerIndex == stickerIndex) {
+ index = i;
+ _transientStickers.remove_at(index);
+ return;
+ }
+ }
+ }
+
for (int i = 0; i < g_engine->_state.roomStickers[_currentRoomNumber].size(); i++) {
if (g_engine->_state.roomStickers[_currentRoomNumber][i].stickerIndex == stickerIndex) {
index = i;
+ g_engine->_state.roomStickers[_currentRoomNumber].remove_at(index);
break;
}
}
+
if (index != -1 && index < g_engine->_state.roomStickers[_currentRoomNumber].size())
g_engine->_state.roomStickers[_currentRoomNumber].remove_at(index);
}
@@ -114,12 +126,19 @@ bool RoomManager::hasSticker(int index) {
return true;
}
}
+
+ for (int i = 0; i < _transientStickers.size(); i++) {
+ if (_transientStickers[i].stickerIndex == index) {
+ return true;
+ }
+ }
+
return false;
}
void RoomManager::changeExit(int index, bool enabled, bool persist) {
_currentRoomExits[index].isEnabled = enabled;
- if(persist)
+ if (persist)
g_engine->_state.roomExitChanges[_currentRoomNumber].push_back({_currentRoomNumber, _currentRoomExits[index].index, _currentRoomExits[index]});
}
Commit: 16ebb316a209547f5f39625236a60ae4fe64279d
https://github.com/scummvm/scummvm/commit/16ebb316a209547f5f39625236a60ae4fe64279d
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:45+02:00
Commit Message:
PELROCK: Triggers side effects in other rooms
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/saveload.cpp
engines/pelrock/sound.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 77d5aeac3cf..d71120b29eb 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -34,10 +34,10 @@ namespace Pelrock {
const ActionEntry actionTable[] = {
// Room 0
- {261, OPEN, &PelrockEngine::openDrawer},
- {261, CLOSE, &PelrockEngine::closeDrawer},
- {268, OPEN, &PelrockEngine::openDoor},
- {268, CLOSE, &PelrockEngine::closeDoor},
+ {261, OPEN, &PelrockEngine::openRoomDrawer},
+ {261, CLOSE, &PelrockEngine::closeRoomDrawer},
+ {268, OPEN, &PelrockEngine::openRoomDoor},
+ {268, CLOSE, &PelrockEngine::closeRoomDoor},
{3, PICKUP, &PelrockEngine::pickUpPhoto},
{0, PICKUP, &PelrockEngine::pickYellowBook}, // Generic pickup for other items
// Room 1
@@ -53,6 +53,10 @@ const ActionEntry actionTable[] = {
{370, OPEN, &PelrockEngine::openKitchenDoor},
{370, CLOSE, &PelrockEngine::closeKitchenDoor},
+ // Room 13
+ {375, OPEN, &PelrockEngine::openKitchenDrawer},
+ {374, OPEN, &PelrockEngine::openKitchenDoorFromInside},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -68,14 +72,15 @@ const ActionEntry actionTable[] = {
const CombinationEntry combinationTable[] = {
{2, 281, &PelrockEngine::useCardWithATM}, // Use ATM Card with ATM
+ {62, 185, &PelrockEngine::useSpicySauceWithBurger}, // Use Spicy Sauce with Burger
// End marker
{WILDCARD, WILDCARD, nullptr}};
-void PelrockEngine::openDoor(HotSpot *hotspot) {
+void PelrockEngine::openRoomDoor(HotSpot *hotspot) {
openDoor(hotspot, 0, 93, FEMININE, true);
}
-void PelrockEngine::openDrawer(HotSpot *hotspot) {
+void PelrockEngine::openRoomDrawer(HotSpot *hotspot) {
if (_room->hasSticker(91)) {
_dialog->say(_res->_ingameTexts[YA_ABIERTO_M]);
return;
@@ -89,7 +94,7 @@ void PelrockEngine::openDrawer(HotSpot *hotspot) {
}
}
-void PelrockEngine::closeDoor(HotSpot *hotspot) {
+void PelrockEngine::closeRoomDoor(HotSpot *hotspot) {
closeDoor(hotspot, 0, 93, FEMININE, true);
}
@@ -105,7 +110,7 @@ void PelrockEngine::pickUpBrick(HotSpot *hotspot) {
_room->addSticker(133);
}
-void PelrockEngine::closeDrawer(HotSpot *hotspot) {
+void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
_room->removeSticker(91);
_room->enableHotspot(hotspot);
}
@@ -132,22 +137,12 @@ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::openMcDoor(HotSpot *hotspot) {
- if (_room->hasSticker(7)) {
- _dialog->say(_res->_ingameTexts[ALREADY_OPENED_F]);
- return;
- }
- _room->enableExit(2);
- _room->addSticker(7);
+ openDoor(hotspot, 2, 7, FEMININE, false);
}
void PelrockEngine::closeMcDoor(HotSpot *hotspot) {
- closeDoor(hotspot, 2, 7, FEMININE, true);
- if (!_room->hasSticker(7)) {
- _dialog->say(_res->_ingameTexts[ALREADY_CLOSED_F]);
- return;
- }
- _room->disableExit(2);
- _room->removeSticker(7);
+ //FIXME: Impossible to close right now
+ closeDoor(hotspot, 2, 7, FEMININE, false);
}
void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
@@ -164,7 +159,6 @@ void PelrockEngine::grabMustard(HotSpot *hotspot) {
}
void PelrockEngine::grabSpicey(HotSpot *hotspot) {
-
_room->addSticker(71);
}
@@ -176,23 +170,42 @@ void PelrockEngine::closeKitchenDoor(HotSpot *HotSpot) {
closeDoor(HotSpot, 1, 32, MASCULINE, true);
}
-void PelrockEngine::openDoor(HotSpot *hotspot, int doorIndex, int sticker, bool masculine, bool stayClosed) {
+void PelrockEngine::openKitchenDrawer(HotSpot *hotspot) {
+ if(_state.JEFE_ENCARCELADO == false) {
+ _dialog->say(_res->_ingameTexts[QUITA_ESAS_MANOS]);
+ }
+ else {
+ _room->addSticker(36);
+ _room->disableHotspot(hotspot);
+ }
+}
+
+void PelrockEngine::openKitchenDoorFromInside(HotSpot *hotspot) {
+ openDoor(hotspot, 0, 34, MASCULINE, true);
+}
+
+void PelrockEngine::useSpicySauceWithBurger(int inventoryObject, HotSpot *hotspot) {
+ _state.PUESTA_SALSA_PICANTE = true;
+ _dialog->say(_res->_ingameTexts[VAESTAR_POCOFUERTE]);
+}
+
+void PelrockEngine::openDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayClosed) {
if (_room->hasSticker(sticker)) {
int text = masculine == MASCULINE ? YA_ABIERTO_M : ALREADY_OPENED_F;
_dialog->say(_res->_ingameTexts[text]);
return;
}
- _room->enableExit(doorIndex, !stayClosed);
+ _room->enableExit(exitIndex, !stayClosed);
_room->addSticker(sticker, !stayClosed);
}
-void PelrockEngine::closeDoor(HotSpot *hotspot, int doorIndex, int sticker, bool masculine, bool stayOpen) {
+void PelrockEngine::closeDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayOpen) {
if (!_room->hasSticker(sticker)) {
int text = masculine == MASCULINE ? ALREADY_CLOSED_M : ALREADY_CLOSED_F;
_dialog->say(_res->_ingameTexts[text]);
return;
}
- _room->disableExit(doorIndex, !stayOpen);
+ _room->disableExit(exitIndex, !stayOpen);
_room->removeSticker(sticker);
}
@@ -233,6 +246,7 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
_res->getExtraScreen(9, _extraScreen, palette);
g_system->getPaletteManager()->setPalette(palette, 0, 256);
+ _sound->playMusicTrack(25);
extraScreenLoop();
_dialog->say(_res->_ingameTexts[SOHOT]);
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 39442d50c0c..4dec3ef8cd5 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -101,6 +101,7 @@ void MenuManager::checkMouseClick(int x, int y) {
_menuText = _inventoryDescriptions[_selectedInvIndex];
g_engine->_state.selectedInventoryItem = _selectedInvIndex;
selectedItem = true;
+ debug("Selected inventory item %d", _selectedInvIndex);
return;
}
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 796bbaf4723..063812a4681 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -641,6 +641,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
}
// This if is needed to draw Alfred when idle, when the switch case results in a state change
if (_alfredState.animState == ALFRED_IDLE) {
+ debug("Drawing Alfred idle frame, direction %d", _alfredState.direction);
drawAlfred(_res->alfredIdle[_alfredState.direction]);
}
}
@@ -1331,7 +1332,7 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
else {
_sound->stopMusic();
}
-
+ doExtraActions(number);
_screen->markAllDirty();
_screen->update();
roomFile.close();
@@ -1339,4 +1340,32 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
delete[] palette;
}
+void PelrockEngine::doExtraActions(int roomNumber) {
+switch (roomNumber)
+{
+case 4:
+ if(_state.PUESTA_SALSA_PICANTE && !_state.JEFE_ENCARCELADO) {
+ _state.JEFE_ENCARCELADO = true;
+ _room->disableSprite(13, 0, true); // Disable Jefe hotspot
+ byte *palette = new byte[768];
+ if (_extraScreen == nullptr) {
+ _extraScreen = new byte[640 * 400];
+ }
+ _res->getExtraScreen(4, _extraScreen, palette);
+
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+ extraScreenLoop();
+
+ _screen->markAllDirty();
+ _screen->update();
+
+ }
+ break;
+
+default:
+ break;
+}
+
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index bdc641ed837..267b64e1e12 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -220,6 +220,7 @@ public:
}
void setScreen(int s, AlfredDirection dir);
+ void doExtraActions(int roomNumber);
bool renderScene(int overlayMode = OVERLAY_NONE);
void addInventoryItem(int item);
@@ -228,16 +229,19 @@ public:
void dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex);
void executeAction(VerbIcon action, HotSpot *hotspot);
- void openDrawer(HotSpot *hotspot);
- void closeDrawer(HotSpot *hotspot);
- void openDoor(HotSpot *hotspot);
- void closeDoor(HotSpot *hotspot);
+ void openRoomDrawer(HotSpot *hotspot);
+ void closeRoomDrawer(HotSpot *hotspot);
+ void openRoomDoor(HotSpot *hotspot);
+ void closeRoomDoor(HotSpot *hotspot);
void pickUpAndDisable(HotSpot *hotspot);
void grabKetchup(HotSpot *hotspot);
void grabMustard(HotSpot *hotspot);
void grabSpicey(HotSpot *hotspot);
void openKitchenDoor(HotSpot *hotspot);
void closeKitchenDoor(HotSpot *HotSpot);
+ void openKitchenDrawer(HotSpot *hotspot);
+ void openKitchenDoorFromInside(HotSpot *hotspot);
+ void useSpicySauceWithBurger(int inventoryObject, HotSpot *hotspot);
void openDoor(HotSpot *hotspot, int doorIndex, int sticker, bool masculine, bool stayClosed);
void closeDoor(HotSpot *hotspot, int doorIndex, int sticker, bool masculine, bool stayOpen);
void pickUpPhoto(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 781ecd6ea59..d9ddd65087e 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -30,6 +30,9 @@ namespace Pelrock {
ResourceManager::ResourceManager(/* args */) {
_inventoryIcons = new InventoryObject[69];
+ for (int i = 0; i < 4; i++) {
+ alfredIdle[i] = nullptr;
+ }
}
ResourceManager::~ResourceManager() {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 19faa3bdd63..852dc741c9a 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -53,7 +53,7 @@ public:
InventoryObject getInventoryObject(byte index);
byte *loadExtra();
- byte *alfredIdle[4] = {nullptr}; // 4 directions
+ byte *alfredIdle[4]; // 4 directions
byte **alfredWalkFrames[4]; // 4 arrays of arrays
@@ -62,8 +62,8 @@ public:
byte **alfredCombFrames[2];
byte **alfredInteractFrames[4];
- byte *_cursorMasks[5] = {nullptr};
- byte *_verbIcons[9] = {nullptr};
+ byte *_cursorMasks[5];
+ byte *_verbIcons[9];
byte *_popUpBalloon = nullptr;
Common::Array<Common::StringArray> _ingameTexts;
};
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index bad8be22e6d..00f16d8af42 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -158,6 +158,17 @@ void RoomManager::changeHotSpot(HotSpot hotspot) {
g_engine->_state.roomHotSpotChanges[_currentRoomNumber].push_back({_currentRoomNumber, hotspot.innerIndex, hotspot});
}
+void RoomManager::disableSprite(int roomNumber, int spriteIndex, bool persist) {
+ if(roomNumber == _currentRoomNumber) {
+ _currentRoomAnims[spriteIndex].zOrder = 255;
+ }
+ g_engine->_state.disabledSprites[roomNumber].push_back(spriteIndex);
+}
+
+void RoomManager::enableSprite(int spriteIndex, int zOrder, bool persist) {
+ // _currentRoomAnims[spriteIndex].zOrder = zOrder;
+}
+
void RoomManager::enableHotspot(HotSpot *hotspot, bool persist) {
hotspot->isEnabled = true;
if (persist) {
@@ -445,7 +456,7 @@ Common::Array<HotSpot> RoomManager::unifyHotspots(Common::Array<Pelrock::Sprite>
thisHotspot.h = anims[i].h;
thisHotspot.extra = anims[i].extra;
thisHotspot.actionFlags = anims[i].actionFlags;
- thisHotspot.isEnabled = !anims[i].isDisabled;
+ thisHotspot.isEnabled = !anims[i].isHotspotDisabled;
thisHotspot.isSprite = true;
thisHotspot.zOrder = anims[i].zOrder;
unifiedHotspots.push_back(thisHotspot);
@@ -493,6 +504,9 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
debug("Sprite count: %d", spriteCount);
uint32_t metadata_start = spriteCountPos + (44 * 2 + 5);
uint32_t picOffset = 0;
+
+ Common::Array<int> disabledSprites = g_engine->_state.disabledSprites[_currentRoomNumber];
+
for (int i = 0; i < spriteCount; i++) {
uint32_t animOffset = metadata_start + (i * 44);
Sprite sprite;
@@ -504,9 +518,15 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
sprite.extra = data[animOffset + 6];
sprite.numAnims = data[animOffset + 8];
sprite.zOrder = data[animOffset + 23];
+ for(int i = 0; i < disabledSprites.size(); i++) {
+ if (disabledSprites[i] == sprite.index) {
+ sprite.zOrder = 255;
+ break;
+ }
+ }
sprite.spriteType = data[animOffset + 33];
sprite.actionFlags = data[animOffset + 34];
- sprite.isDisabled = data[animOffset + 38];
+ sprite.isHotspotDisabled = data[animOffset + 38];
if (sprite.numAnims == 0) {
break;
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 719a251db63..cd0354871e4 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -50,6 +50,8 @@ public:
void enableExit(int index, bool persist = true);
void changeWalkBox(WalkBox walkbox);
void changeHotSpot(HotSpot hotspot);
+ void disableSprite(int roomNumber, int spriteIndex, bool persist = true);
+ void enableSprite(int spriteIndex, int zOrder, bool persist = true);
/**
* Utility function to enable or disable a hotspot, with an option to persist the change.
*/
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index dff98e24e5b..259a1c74735 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -268,6 +268,37 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
}
}
+ uint16 disabledSpritesSize = (uint16)gameState->disabledSprites.size();
+ s.syncAsUint16LE(disabledSpritesSize);
+ if (s.isSaving()) {
+ for (const auto &spritePair : gameState->disabledSprites) {
+ byte roomNumber = spritePair._key;
+ s.syncAsByte(roomNumber);
+ const Common::Array<int> &sprites = spritePair._value;
+ uint16 numSprites = (uint16)sprites.size();
+ s.syncAsUint16LE(numSprites);
+ for (uint16 i = 0; i < numSprites; ++i) {
+ int spriteIndex = sprites[i];
+ s.syncAsSint32LE(spriteIndex);
+ }
+ }
+ } else {
+ gameState->disabledSprites.clear();
+ for (uint16 idx = 0; idx < disabledSpritesSize; ++idx) {
+ byte roomNumber;
+ s.syncAsByte(roomNumber);
+ uint16 numSprites;
+ s.syncAsUint16LE(numSprites);
+ Common::Array<int> sprites;
+ for (uint16 i = 0; i < numSprites; ++i) {
+ int spriteIndex;
+ s.syncAsSint32LE(spriteIndex);
+ sprites.push_back(spriteIndex);
+ }
+ gameState->disabledSprites[roomNumber] = sprites;
+ }
+ }
+
// Disabled branches
uint16 disabledBranchesSize = (uint16)gameState->disabledBranches.size();
s.syncAsUint16LE(disabledBranchesSize);
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 604dae90c47..cba53b03780 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -92,13 +92,17 @@ void SoundManager::playSound(SonidoFile sound, int volume) {
delete[] data;
// Create raw audio stream (8-bit unsigned mono is common for old games)
- stream = Audio::makeRawStream(pcmData, pcmSize, sampleRate,
- Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
+ stream = Audio::makeRawStream(pcmData, pcmSize, sampleRate, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
} else {
debug("Unknown sound format");
delete[] data;
return;
}
+
+ if (stream) {
+ int channel = findFreeChannel();
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
+ }
}
void SoundManager::playSound(byte *soundData, uint32 size, int volume) {
@@ -201,7 +205,7 @@ void SoundManager::playMusicTrack(int trackNumber) {
}
_currentMusicTrack = trackNumber;
g_system->getAudioCDManager()->stop();
- g_system->getAudioCDManager()->play(trackNumber, -1, 0, 0);
+ // g_system->getAudioCDManager()->play(trackNumber, -1, 0, 0);
}
void SoundManager::loadSoundIndex() {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index bdfbf28aeaf..3175c3080ca 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -197,7 +197,7 @@ struct Sprite {
int8 zOrder;
byte spriteType; // 33
byte actionFlags; // 34
- bool isDisabled; // 38
+ bool isHotspotDisabled; // 38
bool isTalking = false;
Anim *animData;
};
@@ -384,6 +384,8 @@ struct ResetEntry {
struct GameStateData {
bool JEFE_INGRESA_PASTA = false;
+ bool JEFE_ENCARCELADO = false;
+ bool PUESTA_SALSA_PICANTE = false;
GameState stateGame = INTRO;
@@ -394,6 +396,7 @@ struct GameStateData {
Common::HashMap<byte, Common::Array<WalkBoxChange>> roomWalkBoxChanges;
Common::HashMap<byte, Common::Array<HotSpotChange>> roomHotSpotChanges;
Common::HashMap<byte, Common::Array<ResetEntry>> disabledBranches;
+ Common::HashMap<byte, Common::Array<int>> disabledSprites;
GameStateData() {
memset(conversationRootsState, 0, 4 * 56);
Commit: 5140ab1362da08bfc565bf39f851886fb9b00f76
https://github.com/scummvm/scummvm/commit/5140ab1362da08bfc565bf39f851886fb9b00f76
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:45+02:00
Commit Message:
PELROCK: Shows action popup over alfred, fixes hover priority, mouse position capture
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/events.cpp
engines/pelrock/events.h
engines/pelrock/menu.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
engines/pelrock/saveload.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/types.h
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index d71120b29eb..17d229c94cb 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -72,7 +72,7 @@ const ActionEntry actionTable[] = {
const CombinationEntry combinationTable[] = {
{2, 281, &PelrockEngine::useCardWithATM}, // Use ATM Card with ATM
- {62, 185, &PelrockEngine::useSpicySauceWithBurger}, // Use Spicy Sauce with Burger
+ {62, 117, &PelrockEngine::useSpicySauceWithBurger}, // Use Spicy Sauce with Burger
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -117,13 +117,13 @@ void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
debug("Withdrawing money from ATM using card (inv obj %d)", inventoryObject);
- if (_state.JEFE_INGRESA_PASTA) {
- _state.JEFE_INGRESA_PASTA = 0;
+ if (_state->JEFE_INGRESA_PASTA) {
+ _state->JEFE_INGRESA_PASTA = 0;
addInventoryItem(75);
} else {
int billCount = 0;
- for (int i = 0; i < _state.inventoryItems.size(); i++) {
- if (_state.inventoryItems[i] == 5) {
+ for (int i = 0; i < _state->inventoryItems.size(); i++) {
+ if (_state->inventoryItems[i] == 5) {
billCount++;
}
}
@@ -171,12 +171,13 @@ void PelrockEngine::closeKitchenDoor(HotSpot *HotSpot) {
}
void PelrockEngine::openKitchenDrawer(HotSpot *hotspot) {
- if(_state.JEFE_ENCARCELADO == false) {
+ if(_state->JEFE_ENCARCELADO == false) {
_dialog->say(_res->_ingameTexts[QUITA_ESAS_MANOS]);
}
else {
_room->addSticker(36);
- _room->disableHotspot(hotspot);
+ addInventoryItem(73); // Add recipe
+ _dialog->say(_res->_ingameTexts[QUESESTO_RECETA]);
}
}
@@ -185,7 +186,7 @@ void PelrockEngine::openKitchenDoorFromInside(HotSpot *hotspot) {
}
void PelrockEngine::useSpicySauceWithBurger(int inventoryObject, HotSpot *hotspot) {
- _state.PUESTA_SALSA_PICANTE = true;
+ _state->PUESTA_SALSA_PICANTE = true;
_dialog->say(_res->_ingameTexts[VAESTAR_POCOFUERTE]);
}
@@ -210,8 +211,8 @@ void PelrockEngine::closeDoor(HotSpot *hotspot, int exitIndex, int sticker, bool
}
void PelrockEngine::addInventoryItem(int item) {
- if (_state.inventoryItems.size() == 0) {
- _state.selectedInventoryItem = item;
+ if (_state->inventoryItems.size() == 0) {
+ _state->selectedInventoryItem = item;
}
_flashingIcon = item;
int frameCounter = 0;
@@ -225,13 +226,13 @@ void PelrockEngine::addInventoryItem(int item) {
}
g_system->delayMillis(10);
}
- _state.addInventoryItem(item);
+ _state->addInventoryItem(item);
}
void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex) {
if (actionTrigger == 328) {
debug("Disabling root %d in room %d", rootIndex, room);
- _state.setRootDisabledState(room, rootIndex, true);
+ _state->setRootDisabledState(room, rootIndex, true);
}
}
@@ -239,21 +240,11 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
case 257:
- byte *palette = new byte[768];
- if (_extraScreen == nullptr) {
- _extraScreen = new byte[640 * 400];
- }
- _res->getExtraScreen(9, _extraScreen, palette);
-
- g_system->getPaletteManager()->setPalette(palette, 0, 256);
_sound->playMusicTrack(25);
- extraScreenLoop();
-
+ loadExtraScreenAndPresent(9);
_dialog->say(_res->_ingameTexts[SOHOT]);
_screen->markAllDirty();
_screen->update();
-
- delete[] palette;
break;
}
}
@@ -269,4 +260,21 @@ void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[154 + response]);
}
+void PelrockEngine::useOnAlfred(int inventoryObject) {
+
+ debug("Using item %d on Alfred", inventoryObject);
+ switch (inventoryObject)
+ {
+ case 73: // Recipe book
+ _res->loadAlfredSpecialAnim(0);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ loadExtraScreenAndPresent(3);
+ _dialog->say(_res->_ingameTexts[QUEASCO]);
+ break;
+
+ default:
+ break;
+ }
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 110a1c16632..1abead0b84a 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -391,7 +391,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
// Right after the speaker conversation tree, we are in branch 0
int currentRoot = 0;
- while(g_engine->_state.getRootDisabledState(g_engine->_room->_currentRoomNumber, currentRoot)) {
+ while(g_engine->_state->getRootDisabledState(g_engine->_room->_currentRoomNumber, currentRoot)) {
// This root is disabled, skip to next
while(position < dataSize) {
if(conversationData[position] == CTRL_END_BRANCH) {
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
index 37f46927342..1b0f4c4ff8a 100644
--- a/engines/pelrock/events.cpp
+++ b/engines/pelrock/events.cpp
@@ -22,6 +22,7 @@
#include "pelrock/events.h"
#include "pelrock/pelrock.h"
+#include "pelrock/util.h"
namespace Pelrock {
@@ -49,7 +50,7 @@ void PelrockEventManager::pollEvent() {
// case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
// break;
case Common::EVENT_KEYDOWN:
- // changeGameSpeed(_event);
+ changeGameSpeed(_event);
// _keyPressed = true;
_lastKeyEvent = _event.kbd.keycode;
break;
@@ -61,6 +62,8 @@ void PelrockEventManager::pollEvent() {
_clickTime = g_system->getMillis();
}
_leftMouseButton = 1;
+ _mouseClickX = _event.mouse.x;
+ _mouseClickY = _event.mouse.y;
break;
case Common::EVENT_LBUTTONUP:
if (_leftMouseButton == 1) {
@@ -68,8 +71,8 @@ void PelrockEventManager::pollEvent() {
if (!_popupSelectionMode) {
_leftMouseClicked = true;
}
- _mouseClickX = _event.mouse.x;
- _mouseClickY = _event.mouse.y;
+ _releaseX = _event.mouse.x;
+ _releaseY = _event.mouse.y;
_longClicked = false;
} else {
_leftMouseClicked = false;
diff --git a/engines/pelrock/events.h b/engines/pelrock/events.h
index defe1392f9c..046e38dc8ec 100644
--- a/engines/pelrock/events.h
+++ b/engines/pelrock/events.h
@@ -36,6 +36,8 @@ public:
int16 _mouseY = 0;
int16 _mouseClickX = 0;
int16 _mouseClickY = 0;
+ int16 _releaseX = 0;
+ int16 _releaseY = 0;
bool _leftMouseClicked = false;
bool _longClicked = false;
bool _rightMouseClicked = false;
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 4dec3ef8cd5..ad74822092b 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -97,9 +97,9 @@ void MenuManager::checkMouseClick(int x, int y) {
for (int i = 0; i < 4; i++) {
if (x >= 140 + (82 * i) && x <= 140 + (82 * i) + 64 &&
y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
- _selectedInvIndex = g_engine->_state.inventoryItems[_curInventoryPage * 4 + i];
+ _selectedInvIndex = g_engine->_state->inventoryItems[_curInventoryPage * 4 + i];
_menuText = _inventoryDescriptions[_selectedInvIndex];
- g_engine->_state.selectedInventoryItem = _selectedInvIndex;
+ g_engine->_state->selectedInventoryItem = _selectedInvIndex;
selectedItem = true;
debug("Selected inventory item %d", _selectedInvIndex);
return;
@@ -120,7 +120,7 @@ void MenuManager::checkMouseClick(int x, int y) {
_curInventoryPage--;
break;
case INVENTORY_NEXT_BUTTON:
- if ((_curInventoryPage + 1) * 4 < g_engine->_state.inventoryItems.size())
+ if ((_curInventoryPage + 1) * 4 < g_engine->_state->inventoryItems.size())
_curInventoryPage++;
break;
case SAVE_GAME_BUTTON:
@@ -142,7 +142,7 @@ void MenuManager::menuLoop() {
_events->_leftMouseClicked = false;
} else if (_events->_rightMouseClicked) {
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
- g_engine->_state.stateGame = GAME;
+ g_engine->_state->stateGame = GAME;
_events->_rightMouseClicked = false;
tearDown();
} else {
@@ -162,9 +162,9 @@ void MenuManager::menuLoop() {
for (int i = 0; i < 4; i++) {
int itemIndex = _curInventoryPage * 4 + i;
- if (g_engine->_state.inventoryItems.size() <= itemIndex)
+ if (g_engine->_state->inventoryItems.size() <= itemIndex)
continue;
- InventoryObject item = g_engine->_res->getInventoryObject(g_engine->_state.inventoryItems[itemIndex]);
+ InventoryObject item = g_engine->_res->getIconForObject(g_engine->_state->inventoryItems[itemIndex]);
drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
}
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index f6343fa48d1..b63745f9d22 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -441,56 +441,56 @@ struct ExtraImages {
};
const ExtraImages extraScreens[] = {
- {
- 0x00, // Portrait above bed
- 0x7984,
- 8
- },
- {
- 0x1A9EE, // Computer screen
- 0x305A2,
- 8
- },
- {
- 0x647C3, // Alfred circle
- 0x7B6B1,
- 4
- },
- {
- 0x6FBC9, // Recipe
- 0x7B6B1,
- 8
- },
- {
- 0x7BA11, // Newspaper
- 0x88745,
- 8
- },
- {
- 0x9237B, // tablet
- 0xB0EE7,
- 8
- },
- {
- 0xB11ED, // map
- 0xDE011,
- 8
- },
- {
- 0xFFC47, // girl book
- 0x1180C9,
- 8
- },
- {
- 0x1183C5, // book
- 0x1358F3,
- 8
- },
- {
- 0x152A88, // portrait
- 0x15BFC8,
- 8
- },
+ {0x00, // Portrait above bed
+ 0x7984,
+ 8},
+ {0x1A9EE, // Computer screen
+ 0x305A2,
+ 8},
+ {0x647C3, // Alfred circle
+ 0x7B6B1,
+ 4},
+ {0x6FBC9, // Recipe
+ 0x7B6B1,
+ 8},
+ {0x7BA11, // Newspaper
+ 0x88745,
+ 8},
+ {0x9237B, // tablet
+ 0xB0EE7,
+ 8},
+ {0xB11ED, // map
+ 0xDE011,
+ 8},
+ {0xFFC47, // girl book
+ 0x1180C9,
+ 8},
+ {0x1183C5, // book
+ 0x1358F3,
+ 8},
+ {0x152A88, // portrait
+ 0x15BFC8,
+ 8},
+};
+
+struct AlfredSpecialAnimOffset {
+ int numFrames = 0;
+ int w = 0;
+ int h = 0;
+ int numBudas;
+ uint32 offset;
+ int stride = 0;
+
+ AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, uint32 off)
+ : numFrames(nF), w(width), h(height), numBudas(nBudas), offset(off) {
+ stride = w * h;
+ }
+ AlfredSpecialAnimOffset() {
+ }
+};
+
+const AlfredSpecialAnimOffset alfredSpecialAnims[] = {
+ {20, 51, 102, 2, 559681}, // READ
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 063812a4681..b367960b160 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -115,22 +115,22 @@ Common::Error PelrockEngine::run() {
Graphics::FrameLimiter limiter(g_system, 60);
if (shouldPlayIntro == false) {
- _state.stateGame = GAME;
+ _state->stateGame = GAME;
// stateGame = SETTINGS;
} else {
- _state.stateGame = INTRO;
+ _state->stateGame = INTRO;
_videoManager->playIntro();
- _state.stateGame = GAME;
+ _state->stateGame = GAME;
}
if (!shouldQuit())
init();
while (!shouldQuit()) {
- if (_state.stateGame == SETTINGS) {
+ if (_state->stateGame == SETTINGS) {
changeCursor(DEFAULT);
_menu->menuLoop();
- } else if (_state.stateGame == GAME) {
+ } else if (_state->stateGame == GAME) {
gameLoop();
}
_screen->update();
@@ -254,8 +254,8 @@ bool PelrockEngine::renderScene(int overlayMode) {
void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
- if(action == ITEM) {
- int inventoryObject = _state.selectedInventoryItem;
+ if (action == ITEM) {
+ int inventoryObject = _state->selectedInventoryItem;
for (const CombinationEntry *entry = combinationTable; entry->handler != nullptr; entry++) {
if (entry->inventoryObject == inventoryObject && entry->hotspotExtra == hotspot->extra) {
(this->*(entry->handler))(inventoryObject, hotspot);
@@ -267,8 +267,6 @@ void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
return;
}
-
-
for (const ActionEntry *entry = actionTable; entry->handler != nullptr; entry++) {
if (entry->action == action && entry->hotspotExtra == hotspot->extra) {
// Found exact match - call the handler
@@ -300,8 +298,11 @@ void PelrockEngine::checkMouse() {
// Handle mouse release after long press (popup selection mode)
if (_events->_popupSelectionMode && !_events->_leftMouseButton) {
// Mouse was released while popup is active
- VerbIcon actionClicked = isActionUnder(_events->_mouseX, _events->_mouseY);
- if (actionClicked != NO_ACTION && _currentHotspot != nullptr) {
+ VerbIcon actionClicked = isActionUnder(_events->_releaseX, _events->_releaseY);
+ if (_actionPopupState.isAlfredUnder) {
+ debug("Using item on Alfred");
+ useOnAlfred(_state->selectedInventoryItem);
+ } else if (actionClicked != NO_ACTION && _currentHotspot != nullptr) {
// Action was selected - queue it
walkTo(_currentHotspot->x + _currentHotspot->w / 2, _currentHotspot->y + _currentHotspot->h);
_queuedAction = QueuedAction{actionClicked, _currentHotspot->index, true};
@@ -323,7 +324,7 @@ void PelrockEngine::checkMouse() {
} else if (_events->_rightMouseClicked) {
g_system->getPaletteManager()->setPalette(_menu->_mainMenuPalette, 0, 256);
_events->_rightMouseClicked = false;
- _state.stateGame = SETTINGS;
+ _state->stateGame = SETTINGS;
}
checkMouseHover();
}
@@ -405,8 +406,8 @@ void PelrockEngine::paintDebugLayer() {
}
void PelrockEngine::placeStickers() {
- for (int i = 0; i < _state.roomStickers[_room->_currentRoomNumber].size(); i++) {
- Sticker sticker = _state.roomStickers[_room->_currentRoomNumber][i];
+ for (int i = 0; i < _state->roomStickers[_room->_currentRoomNumber].size(); i++) {
+ Sticker sticker = _state->roomStickers[_room->_currentRoomNumber][i];
placeSticker(sticker);
}
// also place temporary stickers
@@ -603,13 +604,13 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (_alfredState.curFrame >= walkingAnimLengths[_alfredState.direction]) {
_alfredState.curFrame = 0;
}
- if(_alfredState.animState == ALFRED_WALKING) {// in case it changed to idle above
+ if (_alfredState.animState == ALFRED_WALKING) { // in case it changed to idle above
drawAlfred(_res->alfredWalkFrames[_alfredState.direction][_alfredState.curFrame]);
_alfredState.curFrame++;
}
break;
}
- case ALFRED_TALKING:
+ case ALFRED_TALKING: {
if (_alfredState.curFrame >= talkingAnimLengths[_alfredState.direction] - 1) {
_alfredState.curFrame = 0;
}
@@ -618,7 +619,8 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.curFrame++;
}
break;
- case ALFRED_COMB:
+ }
+ case ALFRED_COMB: {
if (_alfredState.curFrame >= 11) {
_alfredState.setState(ALFRED_IDLE);
drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredIdle[_alfredState.direction], _alfredState.x, _alfredState.y - kAlfredFrameHeight, 51, 102, 255);
@@ -628,7 +630,8 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.curFrame++;
}
break;
- case ALFRED_INTERACTING:
+ }
+ case ALFRED_INTERACTING: {
if (_alfredState.curFrame >= interactingAnimLength) {
_alfredState.setState(ALFRED_IDLE);
} else {
@@ -639,9 +642,34 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
}
break;
}
+ case ALFRED_SPECIAL_ANIM: {
+ if (_res->_specialAnimCurFrame > _res->_curSpecialAnim.numFrames) {
+ _res->clearSpecialAnim();
+ _alfredState.setState(ALFRED_IDLE);
+ } else {
+ byte *frame = new byte[_res->_curSpecialAnim.stride * _res->_curSpecialAnim.numFrames];
+ extractSingleFrame(_res->_specialAnimData,
+ frame,
+ _res->_specialAnimCurFrame,
+ _res->_curSpecialAnim.w,
+ _res->_curSpecialAnim.h);
+ drawSpriteToBuffer(_compositeBuffer,
+ 640,
+ frame,
+ _alfredState.x,
+ _alfredState.y - _res->_curSpecialAnim.h,
+ _res->_curSpecialAnim.w,
+ _res->_curSpecialAnim.h,
+ 255);
+ if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
+ _res->_specialAnimCurFrame++;
+ }
+ delete[] frame;
+ }
+ }
+ }
// This if is needed to draw Alfred when idle, when the switch case results in a state change
if (_alfredState.animState == ALFRED_IDLE) {
- debug("Drawing Alfred idle frame, direction %d", _alfredState.direction);
drawAlfred(_res->alfredIdle[_alfredState.direction]);
}
}
@@ -801,10 +829,10 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
return;
}
- int frameSize = animData.w * animData.h;
+ int frameSize = sprite->stride;
int curFrame = animData.curFrame;
byte *frame = new byte[frameSize];
- drawSpriteToBuffer(_compositeBuffer, 640, animData.animData[curFrame], sprite->x, sprite->y, sprite->w, sprite->h, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, animData.animData[curFrame], x, y, w, h, 255);
// if (animData.elpapsedFrames == animData.speed) {
if (_chrono->getFrameCount() % animData.speed == 0) {
@@ -831,8 +859,9 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
}
void PelrockEngine::checkLongMouseClick(int x, int y) {
- int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
- if (hotspotIndex != -1 && !_actionPopupState.isActive) {
+ int hotspotIndex = isHotspotUnder(x, y);
+ bool alfredUnder = isAlfredUnder(x, y);
+ if ((hotspotIndex != -1 || alfredUnder) && !_actionPopupState.isActive) {
_actionPopupState.x = _alfredState.x + kAlfredFrameWidth / 2 - kBalloonWidth / 2;
if (_actionPopupState.x < 0)
@@ -847,7 +876,11 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
}
_actionPopupState.isActive = true;
_actionPopupState.curFrame = 0;
- _currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
+
+ if (hotspotIndex != -1) {
+ _actionPopupState.isAlfredUnder = alfredUnder;
+ _currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
+ }
}
}
@@ -1040,11 +1073,11 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
bool itemUnder = isItemUnder(_events->_mouseX, _events->_mouseY);
- if (_state.selectedInventoryItem != -1) {
+ if (_state->selectedInventoryItem != -1) {
if (itemUnder && shouldBlink) {
return;
}
- drawSpriteToBuffer(_compositeBuffer, 640, _res->getInventoryObject(_state.selectedInventoryItem).iconData, posx + 20 + (actions.size() * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->selectedInventoryItem).iconData, posx + 20 + (actions.size() * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
if (_actionPopupState.curFrame < 3) {
_actionPopupState.curFrame++;
@@ -1091,7 +1124,10 @@ void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
void PelrockEngine::pickupIconFlash() {
_graphics->showOverlay(65, _compositeBuffer);
- InventoryObject item = _res->getInventoryObject(_flashingIcon);
+ if(_flashingIcon == -1)
+ return;
+ debug("Flashing icon %d", _flashingIcon);
+ InventoryObject item = _res->getIconForObject(_flashingIcon);
if (_chrono->getFrameCount() % kIconBlinkPeriod == 0) {
drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 5, 400 - 60 - 5, 60, 60, 1);
}
@@ -1180,19 +1216,18 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
return NO_ACTION;
}
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
- int loopEnd = _state.selectedInventoryItem != -1 ? actions.size() + 1 : actions.size();
+ int loopEnd = _state->selectedInventoryItem != -1 ? actions.size() + 1 : actions.size();
for (int i = 0; i < loopEnd; i++) {
int actionX = _actionPopupState.x + 20 + (i * (kVerbIconWidth + 2));
int actionY = _actionPopupState.y + 20;
Common::Rect actionRect = Common::Rect(actionX, actionY, actionX + kVerbIconWidth, actionY + kVerbIconHeight);
- if(i == actions.size()) {
+ if (i == actions.size()) {
// Check inventory item
if (actionRect.contains(x, y)) {
return ITEM;
}
- }
- else if (actionRect.contains(x, y)) {
+ } else if (actionRect.contains(x, y)) {
return actions[i];
}
}
@@ -1283,14 +1318,14 @@ void PelrockEngine::checkMouseHover() {
exitDetected = true;
}
- if (alfredDetected) {
- changeCursor(ALFRED);
- } else if (hotspotDetected && exitDetected) {
+ if (hotspotDetected && exitDetected) {
changeCursor(COMBINATION);
} else if (hotspotDetected) {
changeCursor(HOTSPOT);
} else if (exitDetected) {
changeCursor(EXIT);
+ } else if (alfredDetected) {
+ changeCursor(ALFRED);
} else {
changeCursor(DEFAULT);
}
@@ -1340,32 +1375,36 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
delete[] palette;
}
-void PelrockEngine::doExtraActions(int roomNumber) {
-switch (roomNumber)
-{
-case 4:
- if(_state.PUESTA_SALSA_PICANTE && !_state.JEFE_ENCARCELADO) {
- _state.JEFE_ENCARCELADO = true;
- _room->disableSprite(13, 0, true); // Disable Jefe hotspot
- byte *palette = new byte[768];
- if (_extraScreen == nullptr) {
- _extraScreen = new byte[640 * 400];
- }
- _res->getExtraScreen(4, _extraScreen, palette);
-
- g_system->getPaletteManager()->setPalette(palette, 0, 256);
- extraScreenLoop();
-
- _screen->markAllDirty();
- _screen->update();
-
+void PelrockEngine::loadExtraScreenAndPresent(int screenIndex) {
+ byte *palette = new byte[768];
+ if (_extraScreen == nullptr) {
+ _extraScreen = new byte[640 * 400];
}
- break;
+ _res->getExtraScreen(screenIndex, _extraScreen, palette);
-default:
- break;
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+ extraScreenLoop();
+ delete[] _extraScreen;
+ delete[] palette;
+ _screen->markAllDirty();
+ _screen->update();
}
+void PelrockEngine::doExtraActions(int roomNumber) {
+ switch (roomNumber) {
+ case 4:
+ if (_state->PUESTA_SALSA_PICANTE && !_state->JEFE_ENCARCELADO) {
+ _state->JEFE_ENCARCELADO = true;
+ _room->disableSprite(13, 0, true);
+ loadExtraScreenAndPresent(4);
+ _screen->markAllDirty();
+ _screen->update();
+ }
+ break;
+
+ default:
+ break;
+ }
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 267b64e1e12..b38ba69a017 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -59,7 +59,6 @@ class PelrockEngine : public Engine {
private:
const ADGameDescription *_gameDescription;
Common::RandomSource _randomSource;
- ChronoManager *_chrono = nullptr;
VideoManager *_videoManager = nullptr;
SoundManager *_sound = nullptr;
PelrockEventManager *_events = nullptr;
@@ -159,10 +158,11 @@ public:
Graphics::Screen *_screen = nullptr;
ResourceManager *_res = nullptr;
RoomManager *_room = nullptr;
+ ChronoManager *_chrono = nullptr;
AlfredState _alfredState;
byte *_compositeBuffer = nullptr; // Working composition buffer
- GameStateData _state;
+ GameStateData *_state = new GameStateData();
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
@@ -220,6 +220,7 @@ public:
}
void setScreen(int s, AlfredDirection dir);
+ void loadExtraScreenAndPresent(int screenIndex);
void doExtraActions(int roomNumber);
bool renderScene(int overlayMode = OVERLAY_NONE);
@@ -249,6 +250,7 @@ public:
void pickUpBrick(HotSpot *hotspot);
void noOpAction(HotSpot *hotspot);
void noOpItem(int item, HotSpot *hotspot);
+ void useOnAlfred(int inventoryObject);
void useCardWithATM(int inventoryObject, HotSpot *hotspot);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index d9ddd65087e..1c95c4abf24 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -217,6 +217,27 @@ void ResourceManager::loadAlfredAnims() {
free(alfredCombLeftRaw);
}
+void ResourceManager::loadAlfredSpecialAnim(int numAnim) {
+ _curSpecialAnim = alfredSpecialAnims[numAnim];
+ Common::File alfred7;
+ if (!alfred7.open(Common::Path("ALFRED.7"))) {
+ error("Could not open ALFRED.7");
+ return;
+ }
+
+ alfred7.seek(_curSpecialAnim.offset, SEEK_SET);
+ _specialAnimData = new byte[_curSpecialAnim.numFrames * _curSpecialAnim.w * _curSpecialAnim.h];
+ mergeRleBlocks(&alfred7, _curSpecialAnim.offset, 2, _specialAnimData);
+ _specialAnimCurFrame = 0;
+ alfred7.close();
+}
+
+void ResourceManager::clearSpecialAnim() {
+ delete[] _specialAnimData;
+ _specialAnimData = nullptr;
+ _specialAnimCurFrame = 0;
+}
+
void ResourceManager::loadInventoryItems() {
// loadInventoryDescriptions();
Common::File alfred4File;
@@ -351,8 +372,18 @@ Pelrock::Sticker ResourceManager::getSticker(int stickerIndex) {
return sticker;
}
-InventoryObject ResourceManager::getInventoryObject(byte index) {
- return _inventoryIcons[index];
+InventoryObject ResourceManager::getIconForObject(byte objectIndex) {
+ byte iconIndex = 0;
+ if (objectIndex < 59) {
+ if (11 < objectIndex < 59) {
+ iconIndex = ((objectIndex - 11) & 3) + 11; // Books cycle through icons 11-14
+ } else {
+ iconIndex = objectIndex; // Direct mapping for IDs 0-11
+ }
+ } else {
+ iconIndex = objectIndex - 44; // Offset for high IDs (59+)
+ }
+ return _inventoryIcons[iconIndex];
}
void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32 offset, int numBlocks, byte *outputBuffer) {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 852dc741c9a..1288d3d6af7 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -24,6 +24,7 @@
#include "common/scummsys.h"
#include "common/stream.h"
#include "pelrock/types.h"
+#include "pelrock/offsets.h"
namespace Pelrock {
@@ -44,13 +45,15 @@ public:
void loadCursors();
void loadInteractionIcons();
void loadAlfredAnims();
+ void loadAlfredSpecialAnim(int numAnim);
+ void clearSpecialAnim();
void loadInventoryItems();
void loadAlfredResponses();
void getExtraScreen(int screenIndex, byte *screenBuf, byte *palette);
Common::Array<Common::StringArray> getCredits();
Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size, bool decode = false);
Sticker getSticker(int stickerIndex);
- InventoryObject getInventoryObject(byte index);
+ InventoryObject getIconForObject(byte index);
byte *loadExtra();
byte *alfredIdle[4]; // 4 directions
@@ -66,6 +69,11 @@ public:
byte *_verbIcons[9];
byte *_popUpBalloon = nullptr;
Common::Array<Common::StringArray> _ingameTexts;
+
+ //Special anims
+ byte *_specialAnimData = nullptr;
+ int _specialAnimCurFrame = 0;
+ AlfredSpecialAnimOffset _curSpecialAnim;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 00f16d8af42..265396014b4 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -91,7 +91,7 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
void RoomManager::addSticker(int stickerId, bool persist) {
Sticker sticker = g_engine->_res->getSticker(stickerId);
if (persist)
- g_engine->_state.roomStickers[_currentRoomNumber].push_back(sticker);
+ g_engine->_state->roomStickers[_currentRoomNumber].push_back(sticker);
else
_transientStickers.push_back(sticker);
}
@@ -108,21 +108,21 @@ void RoomManager::removeSticker(int stickerIndex) {
}
}
- for (int i = 0; i < g_engine->_state.roomStickers[_currentRoomNumber].size(); i++) {
- if (g_engine->_state.roomStickers[_currentRoomNumber][i].stickerIndex == stickerIndex) {
+ for (int i = 0; i < g_engine->_state->roomStickers[_currentRoomNumber].size(); i++) {
+ if (g_engine->_state->roomStickers[_currentRoomNumber][i].stickerIndex == stickerIndex) {
index = i;
- g_engine->_state.roomStickers[_currentRoomNumber].remove_at(index);
+ g_engine->_state->roomStickers[_currentRoomNumber].remove_at(index);
break;
}
}
- if (index != -1 && index < g_engine->_state.roomStickers[_currentRoomNumber].size())
- g_engine->_state.roomStickers[_currentRoomNumber].remove_at(index);
+ if (index != -1 && index < g_engine->_state->roomStickers[_currentRoomNumber].size())
+ g_engine->_state->roomStickers[_currentRoomNumber].remove_at(index);
}
bool RoomManager::hasSticker(int index) {
- for (int i = 0; i < g_engine->_state.roomStickers[_currentRoomNumber].size(); i++) {
- if (g_engine->_state.roomStickers[_currentRoomNumber][i].stickerIndex == index) {
+ for (int i = 0; i < g_engine->_state->roomStickers[_currentRoomNumber].size(); i++) {
+ if (g_engine->_state->roomStickers[_currentRoomNumber][i].stickerIndex == index) {
return true;
}
}
@@ -139,7 +139,7 @@ bool RoomManager::hasSticker(int index) {
void RoomManager::changeExit(int index, bool enabled, bool persist) {
_currentRoomExits[index].isEnabled = enabled;
if (persist)
- g_engine->_state.roomExitChanges[_currentRoomNumber].push_back({_currentRoomNumber, _currentRoomExits[index].index, _currentRoomExits[index]});
+ g_engine->_state->roomExitChanges[_currentRoomNumber].push_back({_currentRoomNumber, _currentRoomExits[index].index, _currentRoomExits[index]});
}
void RoomManager::disableExit(int index, bool persist) {
@@ -151,18 +151,18 @@ void RoomManager::enableExit(int index, bool persist) {
}
void RoomManager::changeWalkBox(WalkBox walkbox) {
- g_engine->_state.roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
+ g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
}
void RoomManager::changeHotSpot(HotSpot hotspot) {
- g_engine->_state.roomHotSpotChanges[_currentRoomNumber].push_back({_currentRoomNumber, hotspot.innerIndex, hotspot});
+ g_engine->_state->roomHotSpotChanges[_currentRoomNumber].push_back({_currentRoomNumber, hotspot.innerIndex, hotspot});
}
void RoomManager::disableSprite(int roomNumber, int spriteIndex, bool persist) {
if(roomNumber == _currentRoomNumber) {
_currentRoomAnims[spriteIndex].zOrder = 255;
}
- g_engine->_state.disabledSprites[roomNumber].push_back(spriteIndex);
+ g_engine->_state->disabledSprites[roomNumber].push_back(spriteIndex);
}
void RoomManager::enableSprite(int spriteIndex, int zOrder, bool persist) {
@@ -184,7 +184,7 @@ void RoomManager::disableHotspot(HotSpot *hotspot, bool persist) {
}
void RoomManager::addWalkbox(WalkBox walkbox) {
- g_engine->_state.roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
+ g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
}
HotSpot *RoomManager::findHotspotByExtra(uint16 extra) {
@@ -239,11 +239,11 @@ Common::Array<Exit> RoomManager::loadExits(byte *data, size_t size) {
for (int i = 0; i < exitCount; i++) {
int exitOffset = exitDataOffset + i * 14;
bool isChanged = false;
- if (g_engine->_state.roomExitChanges.contains(_currentRoomNumber)) {
+ if (g_engine->_state->roomExitChanges.contains(_currentRoomNumber)) {
// if the exit has been changed, load the changed version
- for (int j = 0; j < g_engine->_state.roomExitChanges[_currentRoomNumber].size(); j++) {
- if (g_engine->_state.roomExitChanges[_currentRoomNumber][j].exitIndex == i) {
- exits.push_back(g_engine->_state.roomExitChanges[_currentRoomNumber][j].exit);
+ for (int j = 0; j < g_engine->_state->roomExitChanges[_currentRoomNumber].size(); j++) {
+ if (g_engine->_state->roomExitChanges[_currentRoomNumber][j].exitIndex == i) {
+ exits.push_back(g_engine->_state->roomExitChanges[_currentRoomNumber][j].exit);
isChanged = true;
break;
}
@@ -303,11 +303,11 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
spot.innerIndex = i;
spot.index = i;
bool isChanged = false;
- if (g_engine->_state.roomHotSpotChanges.contains(_currentRoomNumber)) {
+ if (g_engine->_state->roomHotSpotChanges.contains(_currentRoomNumber)) {
// if the hotspot has been changed, load the changed version
- for (int j = 0; j < g_engine->_state.roomHotSpotChanges[_currentRoomNumber].size(); j++) {
- if (g_engine->_state.roomHotSpotChanges[_currentRoomNumber][j].hotspotIndex == spot.innerIndex) {
- hotspots.push_back(g_engine->_state.roomHotSpotChanges[_currentRoomNumber][j].hotspot);
+ for (int j = 0; j < g_engine->_state->roomHotSpotChanges[_currentRoomNumber].size(); j++) {
+ if (g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspotIndex == spot.innerIndex) {
+ hotspots.push_back(g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot);
isChanged = true;
break;
}
@@ -352,7 +352,6 @@ void RoomManager::resetConversationStates(byte roomNumber, byte *conversationDat
// Not the room we care about, skip
continue;
}
- debug("Resetting room %d conversation data at offset %d, size %d", entry.room, entry.offset, entry.dataSize);
Common::copy(entry.data, entry.data + entry.dataSize, conversationData + entry.offset);
// delete[] entry.data;
}
@@ -505,7 +504,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
uint32_t metadata_start = spriteCountPos + (44 * 2 + 5);
uint32_t picOffset = 0;
- Common::Array<int> disabledSprites = g_engine->_state.disabledSprites[_currentRoomNumber];
+ Common::Array<int> disabledSprites = g_engine->_state->disabledSprites[_currentRoomNumber];
for (int i = 0; i < spriteCount; i++) {
uint32_t animOffset = metadata_start + (i * 44);
@@ -515,18 +514,20 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
sprite.y = READ_LE_INT16(data + animOffset + 2);
sprite.w = data[animOffset + 4];
sprite.h = data[animOffset + 5];
- sprite.extra = data[animOffset + 6];
+ sprite.stride = READ_LE_INT16(data + animOffset + 6);
sprite.numAnims = data[animOffset + 8];
sprite.zOrder = data[animOffset + 23];
+ sprite.extra = data[animOffset + 32];
+ sprite.spriteType = data[animOffset + 33];
+ sprite.actionFlags = data[animOffset + 34];
+ sprite.isHotspotDisabled = data[animOffset + 38];
for(int i = 0; i < disabledSprites.size(); i++) {
if (disabledSprites[i] == sprite.index) {
sprite.zOrder = 255;
+ sprite.isHotspotDisabled = 1;
break;
}
}
- sprite.spriteType = data[animOffset + 33];
- sprite.actionFlags = data[animOffset + 34];
- sprite.isHotspotDisabled = data[animOffset + 38];
if (sprite.numAnims == 0) {
break;
}
@@ -589,11 +590,11 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
WalkBox box;
box.index = i;
bool isChanged = false;
- if (g_engine->_state.roomWalkBoxChanges.contains(_currentRoomNumber)) {
+ if (g_engine->_state->roomWalkBoxChanges.contains(_currentRoomNumber)) {
// if the walkbox has been changed, load the changed version
- for (int j = 0; j < g_engine->_state.roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
- if (g_engine->_state.roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == i) {
- walkboxes.push_back(g_engine->_state.roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
+ for (int j = 0; j < g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
+ if (g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == i) {
+ walkboxes.push_back(g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
isChanged = true;
break;
}
@@ -609,18 +610,18 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
walkboxes.push_back(box);
}
- if (g_engine->_state.roomWalkBoxChanges.contains(_currentRoomNumber)) {
+ if (g_engine->_state->roomWalkBoxChanges.contains(_currentRoomNumber)) {
// Add any new walkboxes that were added
- for (int j = 0; j < g_engine->_state.roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
+ for (int j = 0; j < g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
bool found = false;
for (int i = 0; i < walkboxes.size(); i++) {
- if (g_engine->_state.roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == walkboxes[i].index) {
+ if (g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == walkboxes[i].index) {
found = true;
break;
}
}
if (!found) {
- walkboxes.push_back(g_engine->_state.roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
+ walkboxes.push_back(g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
}
}
}
@@ -673,13 +674,13 @@ void RoomManager::loadConversationData(byte *pair12data, size_t pair12size, uint
}
outConversationData = new byte[outConversationDataSize];
Common::copy(pair12data + conversationStart, pair12data + conversationStart + outConversationDataSize, outConversationData);
- if (g_engine->_state.disabledBranches.contains(_currentRoomNumber)) {
+ if (g_engine->_state->disabledBranches.contains(_currentRoomNumber)) {
applyDisabledChoices(_currentRoomNumber, outConversationData, outConversationDataSize);
}
}
void RoomManager::applyDisabledChoices(int roomNumber, byte *conversationData, size_t conversationDataSize) {
- Common::Array<ResetEntry> disabledBranches = g_engine->_state.disabledBranches[roomNumber];
+ Common::Array<ResetEntry> disabledBranches = g_engine->_state->disabledBranches[roomNumber];
if (disabledBranches.size() == 0) {
return;
}
@@ -705,7 +706,7 @@ void RoomManager::addDisabledChoice(ChoiceOption choice) {
// Apply immediately
applyDisabledChoice(resetEntry, _conversationData, _conversationDataSize);
// Store for future loads
- g_engine->_state.addDisabledBranch(resetEntry);
+ g_engine->_state->addDisabledBranch(resetEntry);
}
void RoomManager::resetMetadataDefaults(byte room, byte *&data, size_t size) {
@@ -730,7 +731,6 @@ void RoomManager::resetMetadataDefaults(byte room, byte *&data, size_t size) {
// Not the room we care about, skip
continue;
}
- debug("Resetting room %d metadata at offset %d, size %d", entry.room, entry.offset, entry.dataSize);
Common::copy(entry.data, entry.data + entry.dataSize, data + entry.offset);
// delete[] entry.data;
}
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index 259a1c74735..63184033f7f 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -31,19 +31,6 @@ namespace Pelrock {
// Helper functions for syncing structs
void syncSticker(Common::Serializer &s, Sticker &sticker) {
s.syncAsSint32LE(sticker.stickerIndex);
- // if(s.isLoading()) {
-
- // }
- // s.syncAsSint32LE(sticker.roomNumber);
-
- // if(s.isLoading()) {
- // sticker.stickerData = new byte[sticker.w * sticker.h];
- // }
- // s.syncAsUint16LE(sticker.x);
- // s.syncAsUint16LE(sticker.y);
- // s.syncAsByte(sticker.w);
- // s.syncAsByte(sticker.h);
- // // Note: stickerData pointer not serialized - must be reconstructed on load
}
void syncExit(Common::Serializer &s, Exit &exit) {
@@ -119,7 +106,13 @@ bool syncGeneralData(Common::Serializer &s, SaveGameData *game) {
// Uint16
s.syncAsUint16LE(game->alfredX);
s.syncAsUint16LE(game->alfredY);
- s.syncAsByte(game->alfredDir);
+ s.syncAsByte((byte &)game->alfredDir);
+
+ if (s.isLoading()) {
+ debug("LOAD: room=%d, x=%d, y=%d, dir=%d", game->currentRoom, game->alfredX, game->alfredY, game->alfredDir);
+ } else {
+ debug("SAVE: room=%d, x=%d, y=%d, dir=%d", game->currentRoom, game->alfredX, game->alfredY, game->alfredDir);
+ }
return !s.err();
}
@@ -279,7 +272,7 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
s.syncAsUint16LE(numSprites);
for (uint16 i = 0; i < numSprites; ++i) {
int spriteIndex = sprites[i];
- s.syncAsSint32LE(spriteIndex);
+ s.syncAsByte(spriteIndex);
}
}
} else {
@@ -292,7 +285,7 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
Common::Array<int> sprites;
for (uint16 i = 0; i < numSprites; ++i) {
int spriteIndex;
- s.syncAsSint32LE(spriteIndex);
+ s.syncAsByte(spriteIndex);
sprites.push_back(spriteIndex);
}
gameState->disabledSprites[roomNumber] = sprites;
@@ -367,19 +360,19 @@ void PelrockEngine::loadGame(SaveGameData &saveGame) {
_alfredState.x = saveGame.alfredX;
_alfredState.y = saveGame.alfredY;
_alfredState.direction = (AlfredDirection)saveGame.alfredDir;
- _state = *(saveGame.gameState);
+ _state = saveGame.gameState;
setScreen(saveGame.currentRoom, _alfredState.direction);
- _state.stateGame = GAME;
+ _state->stateGame = GAME;
}
SaveGameData *PelrockEngine::createSaveGameData() const {
SaveGameData *saveGame = new SaveGameData();
- saveGame->gameState = &g_engine->_state;
saveGame->currentRoom = _room->_currentRoomNumber;
saveGame->alfredX = _alfredState.x;
saveGame->alfredY = _alfredState.y;
saveGame->alfredDir = _alfredState.direction;
+ saveGame->gameState = g_engine->_state;
return saveGame;
}
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index cba53b03780..31bfa59f5ad 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -198,14 +198,14 @@ bool SoundManager::isMusicPlaying() {
return g_system->getAudioCDManager()->isPlaying();
}
-void SoundManager::playMusicTrack(int trackNumber) {
+void SoundManager::playMusicTrack(int trackNumber, bool loop) {
if (_currentMusicTrack == trackNumber && isMusicPlaying()) {
// Already playing this track
return;
}
_currentMusicTrack = trackNumber;
g_system->getAudioCDManager()->stop();
- // g_system->getAudioCDManager()->play(trackNumber, -1, 0, 0);
+ // g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 0, 0, 0);
}
void SoundManager::loadSoundIndex() {
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index ee305f6a20d..d2733e83e7a 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -196,7 +196,7 @@ public:
void setVolume(int volume);
bool isPlaying() const;
bool isPlaying(int channel) const;
- void playMusicTrack(int trackNumber);
+ void playMusicTrack(int trackNumber, bool loop = true);
bool isMusicPlaying() const {
return _isMusicPlaying;
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 3175c3080ca..e2d0a2bf59c 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -102,7 +102,8 @@ enum AlfredAnimState {
ALFRED_WALKING,
ALFRED_TALKING,
ALFRED_INTERACTING,
- ALFRED_COMB
+ ALFRED_COMB,
+ ALFRED_SPECIAL_ANIM
};
enum AlfredDirection {
@@ -118,6 +119,7 @@ struct ActionPopupState {
int x = 0;
int y = 0;
int displayTime = 0;
+ bool isAlfredUnder = false;
};
struct AlfredState {
@@ -191,7 +193,7 @@ struct Sprite {
int16 y; // 2
int w; // 4
int h; // 5
- byte extra; // 6
+ uint16 stride; // 6-7
int numAnims; // 8
int curAnimIndex = 0;
int8 zOrder;
@@ -200,6 +202,7 @@ struct Sprite {
bool isHotspotDisabled; // 38
bool isTalking = false;
Anim *animData;
+ byte extra;
};
struct HotSpot {
@@ -381,17 +384,63 @@ struct ResetEntry {
byte *data = nullptr;
};
-
struct GameStateData {
bool JEFE_INGRESA_PASTA = false;
bool JEFE_ENCARCELADO = false;
bool PUESTA_SALSA_PICANTE = false;
+ bool CRISTAL_ROTO = false;
+ bool ENTRA_EN_TIENDA_PRIMERA_VEZ = false;
+ bool ELECTROCUTACION = false;
+ bool CABLES_PUESTOS = false;
+ bool SOBORNO_PORTERO = false;
+ bool MEMORIZA_LIBRO = false;
+ bool ALFRED_INTELIGENTE = false;
+ bool ALFRED_SABE_EGIPCIO = false;
+ bool VENDEDOR_DEJA_DE_JODER = false;
+ bool VIAJE_A_EGIPTO = false;
+ bool PARADOJA_RESUELTA = false;
+ bool CROCODILLO_ENCENDIDO = false;
+ bool MIRA_SIMBOLO_FUERA_MUSEO = false;
+ bool PUERTA_SECRETA_ABIERTA = false;
+ bool ROBA_PELO_PRINCESA = false;
+ bool A_LA_CARCEL = false;
+ bool CLAVE_CAJA_FUERTE = false;
+ bool SE_HA_PUESTO_EL_MUNECO = false;
+ bool VIGILANTE_BEBE_AGUA = false;
+ bool VIGILANTE_MEANDO = false;
+ bool PIRAMIDE_JODIDA = false;
+ bool PIRAMIDE_JODIDA2 = false;
+ bool VIGILANTE_PAJEANDOSE = false;
+ bool FORMULA_MAGICA = false;
+ bool VIAJA_AL_PASADO = false;
+ bool APARECE_EUNUCO = false;
+ bool AL_FARAON = false;
+ bool A_CURRAR = false;
+ bool DA_PIEDRA = false;
+ byte NUMERO_DE_COPAS = false;
+ bool PIEDRAS_COGIDAS = false;
+ bool GUARDIAS_BORRACHOS = false;
+ bool PIEDRA_FAKE_MOJADA = false;
+ bool PUERTA_BUENA = false;
+ bool TRAMPILLA_ABIERTA = false;
+ bool HABITACION_PRINCESA = false;
+ bool A_POR_LA_PRINCESA = false;
+ bool VUELTA_A_EMPEZAR = false;
+ bool A_LOS_PASILLOS = false;
+ bool COMO_ESTAN_LOS_DIOSES = false;
+ bool END_OF_GAME = false;
+ bool FROM_INTRO = false;
+ byte INGREDIENTES_CONSEGUIDOS = 0;
+ bool HE_TIRADO_PIEDRA = false;
+ bool HA_USADO_AGUA = false;
GameState stateGame = INTRO;
Common::Array<byte> inventoryItems;
int16 selectedInventoryItem = -1;
+
Common::HashMap<byte, Common::Array<Sticker>> roomStickers;
+ // Common::HashMap<byte, ResetEntry> roomExitChanges;
Common::HashMap<byte, Common::Array<ExitChange>> roomExitChanges;
Common::HashMap<byte, Common::Array<WalkBoxChange>> roomWalkBoxChanges;
Common::HashMap<byte, Common::Array<HotSpotChange>> roomHotSpotChanges;
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 7ead6a86730..05f9d9e231d 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -323,6 +323,17 @@ byte decodeChar(byte b) {
}
}
+
+void changeGameSpeed(Common::Event e) {
+ if (e.type == Common::EVENT_KEYDOWN) {
+ if (e.kbd.hasFlags(Common::KBD_CTRL)) {
+ if (e.kbd.keycode == Common::KEYCODE_f) {
+ g_engine->_chrono->changeSpeed();
+ }
+ }
+ }
+}
+
Common::StringArray arrayOf(Common::String str) {
return Common::StringArray(1, str);
}
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 62a70260476..9af486dbe51 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -21,8 +21,10 @@
#ifndef PELROCK_UTIL_H
#define PELROCK_UTIL_H
+#include "common/events.h"
#include "common/stream.h"
#include "common/types.h"
+
#include "graphics/font.h"
#include "graphics/managed_surface.h"
#include "graphics/surface.h"
@@ -43,6 +45,7 @@ void drawText(Graphics::Font *font, Common::String text, int x, int y, int w, by
Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
byte decodeChar(byte b);
+void changeGameSpeed(Common::Event e);
Common::StringArray arrayOf(Common::String str);
static const int special_chars[] = {
Commit: d3db3eff4809f43408fae182b8413183bbc42951
https://github.com/scummvm/scummvm/commit/d3db3eff4809f43408fae182b8413183bbc42951
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:45+02:00
Commit Message:
PELROCK: Use stuff with Alfred
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/saveload.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 17d229c94cb..0db963320e8 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -117,8 +117,8 @@ void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
debug("Withdrawing money from ATM using card (inv obj %d)", inventoryObject);
- if (_state->JEFE_INGRESA_PASTA) {
- _state->JEFE_INGRESA_PASTA = 0;
+ if (_state->flagIsSet(FLAG_JEFE_INGRESA_PASTA)) {
+ _state->setFlag(FLAG_JEFE_INGRESA_PASTA, false);
addInventoryItem(75);
} else {
int billCount = 0;
@@ -171,12 +171,12 @@ void PelrockEngine::closeKitchenDoor(HotSpot *HotSpot) {
}
void PelrockEngine::openKitchenDrawer(HotSpot *hotspot) {
- if(_state->JEFE_ENCARCELADO == false) {
+ if(!_state->flagIsSet(FLAG_JEFE_ENCARCELADO)) {
_dialog->say(_res->_ingameTexts[QUITA_ESAS_MANOS]);
}
else {
_room->addSticker(36);
- addInventoryItem(73); // Add recipe
+ addInventoryItem(63); // Add recipe
_dialog->say(_res->_ingameTexts[QUESESTO_RECETA]);
}
}
@@ -186,7 +186,7 @@ void PelrockEngine::openKitchenDoorFromInside(HotSpot *hotspot) {
}
void PelrockEngine::useSpicySauceWithBurger(int inventoryObject, HotSpot *hotspot) {
- _state->PUESTA_SALSA_PICANTE = true;
+ _state->setFlag(FLAG_PUESTA_SALSA_PICANTE, true);
_dialog->say(_res->_ingameTexts[VAESTAR_POCOFUERTE]);
}
@@ -265,11 +265,11 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
debug("Using item %d on Alfred", inventoryObject);
switch (inventoryObject)
{
- case 73: // Recipe book
+ case 63: // Recipe book
_res->loadAlfredSpecialAnim(0);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
loadExtraScreenAndPresent(3);
- _dialog->say(_res->_ingameTexts[QUEASCO]);
+ // _dialog->say(_res->_ingameTexts[QUEASCO]);
break;
default:
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b367960b160..7438fdbc8f6 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -877,8 +877,8 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
_actionPopupState.isActive = true;
_actionPopupState.curFrame = 0;
+ _actionPopupState.isAlfredUnder = alfredUnder;
if (hotspotIndex != -1) {
- _actionPopupState.isAlfredUnder = alfredUnder;
_currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
}
}
@@ -1381,9 +1381,10 @@ void PelrockEngine::loadExtraScreenAndPresent(int screenIndex) {
_extraScreen = new byte[640 * 400];
}
_res->getExtraScreen(screenIndex, _extraScreen, palette);
-
+ CursorMan.showMouse(false);
g_system->getPaletteManager()->setPalette(palette, 0, 256);
extraScreenLoop();
+ CursorMan.showMouse(true);
delete[] _extraScreen;
delete[] palette;
_screen->markAllDirty();
@@ -1393,8 +1394,8 @@ void PelrockEngine::loadExtraScreenAndPresent(int screenIndex) {
void PelrockEngine::doExtraActions(int roomNumber) {
switch (roomNumber) {
case 4:
- if (_state->PUESTA_SALSA_PICANTE && !_state->JEFE_ENCARCELADO) {
- _state->JEFE_ENCARCELADO = true;
+ if (_state->flagIsSet(FLAG_PUESTA_SALSA_PICANTE) && !_state->flagIsSet(FLAG_JEFE_ENCARCELADO)) {
+ _state->setFlag(FLAG_JEFE_ENCARCELADO, true);
_room->disableSprite(13, 0, true);
loadExtraScreenAndPresent(4);
_screen->markAllDirty();
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index 63184033f7f..4f92d03b297 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -121,6 +121,10 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
// GameState
s.syncAsUint32LE((uint32 &)gameState->stateGame);
+ // Flags
+ for (int i = 0; i < 46; ++i) {
+ s.syncAsByte((byte &)gameState->flags[i]);
+ }
// Inventory items
uint16 inventorySize = (uint16)gameState->inventoryItems.size();
s.syncAsUint16LE(inventorySize);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index e2d0a2bf59c..93d477a02d7 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -189,17 +189,17 @@ struct Exit {
struct Sprite {
byte index; // number of the animation in the rooms
byte type;
- int16 x; // 0
- int16 y; // 2
- int w; // 4
- int h; // 5
+ int16 x; // 0
+ int16 y; // 2
+ int w; // 4
+ int h; // 5
uint16 stride; // 6-7
- int numAnims; // 8
+ int numAnims; // 8
int curAnimIndex = 0;
int8 zOrder;
- byte spriteType; // 33
- byte actionFlags; // 34
- bool isHotspotDisabled; // 38
+ byte spriteType; // 33
+ byte actionFlags; // 34
+ bool isHotspotDisabled; // 38
bool isTalking = false;
Anim *animData;
byte extra;
@@ -384,55 +384,58 @@ struct ResetEntry {
byte *data = nullptr;
};
+#define FLAG_JEFE_INGRESA_PASTA 0
+#define FLAG_JEFE_ENCARCELADO 1
+#define FLAG_PUESTA_SALSA_PICANTE 2
+#define FLAG_CRISTAL_ROTO 3
+#define FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ 4
+#define FLAG_ELECTROCUTACION 5
+#define FLAG_CABLES_PUESTOS 6
+#define FLAG_SOBORNO_PORTERO 7
+#define FLAG_MEMORIZA_LIBRO 8
+#define FLAG_ALFRED_INTELIGENTE 9
+#define FLAG_ALFRED_SABE_EGIPCIO 10
+#define FLAG_VENDEDOR_DEJA_DE_JODER 11
+#define FLAG_VIAJE_A_EGIPTO 12
+#define FLAG_PARADOJA_RESUELTA 13
+#define FLAG_CROCODILLO_ENCENDIDO 14
+#define FLAG_MIRA_SIMBOLO_FUERA_MUSEO 15
+#define FLAG_PUERTA_SECRETA_ABIERTA 16
+#define FLAG_ROBA_PELO_PRINCESA 17
+#define FLAG_A_LA_CARCEL 18
+#define FLAG_CLAVE_CAJA_FUERTE 19
+#define FLAG_SE_HA_PUESTO_EL_MUNECO 20
+#define FLAG_VIGILANTE_BEBE_AGUA 21
+#define FLAG_VIGILANTE_MEANDO 22
+#define FLAG_PIRAMIDE_JODIDA 23
+#define FLAG_PIRAMIDE_JODIDA2 24
+#define FLAG_VIGILANTE_PAJEANDOSE 25
+#define FLAG_FORMULA_MAGICA 26
+#define FLAG_VIAJA_AL_PASADO 27
+#define FLAG_APARECE_EUNUCO 28
+#define FLAG_AL_FARAON 29
+#define FLAG_A_CURRAR 30
+#define FLAG_DA_PIEDRA 31
+#define FLAG_PIEDRAS_COGIDAS 32
+#define FLAG_GUARDIAS_BORRACHOS 33
+#define FLAG_PIEDRA_FAKE_MOJADA 34
+#define FLAG_PUERTA_BUENA 35
+#define FLAG_TRAMPILLA_ABIERTA 36
+#define FLAG_HABITACION_PRINCESA 37
+#define FLAG_A_POR_LA_PRINCESA 38
+#define FLAG_VUELTA_A_EMPEZAR 39
+#define FLAG_A_LOS_PASILLOS 40
+#define FLAG_COMO_ESTAN_LOS_DIOSES 41
+#define FLAG_END_OF_GAME 42
+#define FLAG_FROM_INTRO 43
+#define FLAG_HE_TIRADO_PIEDRA 44
+#define FLAG_HA_USADO_AGUA 45
+
struct GameStateData {
- bool JEFE_INGRESA_PASTA = false;
- bool JEFE_ENCARCELADO = false;
- bool PUESTA_SALSA_PICANTE = false;
- bool CRISTAL_ROTO = false;
- bool ENTRA_EN_TIENDA_PRIMERA_VEZ = false;
- bool ELECTROCUTACION = false;
- bool CABLES_PUESTOS = false;
- bool SOBORNO_PORTERO = false;
- bool MEMORIZA_LIBRO = false;
- bool ALFRED_INTELIGENTE = false;
- bool ALFRED_SABE_EGIPCIO = false;
- bool VENDEDOR_DEJA_DE_JODER = false;
- bool VIAJE_A_EGIPTO = false;
- bool PARADOJA_RESUELTA = false;
- bool CROCODILLO_ENCENDIDO = false;
- bool MIRA_SIMBOLO_FUERA_MUSEO = false;
- bool PUERTA_SECRETA_ABIERTA = false;
- bool ROBA_PELO_PRINCESA = false;
- bool A_LA_CARCEL = false;
- bool CLAVE_CAJA_FUERTE = false;
- bool SE_HA_PUESTO_EL_MUNECO = false;
- bool VIGILANTE_BEBE_AGUA = false;
- bool VIGILANTE_MEANDO = false;
- bool PIRAMIDE_JODIDA = false;
- bool PIRAMIDE_JODIDA2 = false;
- bool VIGILANTE_PAJEANDOSE = false;
- bool FORMULA_MAGICA = false;
- bool VIAJA_AL_PASADO = false;
- bool APARECE_EUNUCO = false;
- bool AL_FARAON = false;
- bool A_CURRAR = false;
- bool DA_PIEDRA = false;
+ bool flags[46];
+
byte NUMERO_DE_COPAS = false;
- bool PIEDRAS_COGIDAS = false;
- bool GUARDIAS_BORRACHOS = false;
- bool PIEDRA_FAKE_MOJADA = false;
- bool PUERTA_BUENA = false;
- bool TRAMPILLA_ABIERTA = false;
- bool HABITACION_PRINCESA = false;
- bool A_POR_LA_PRINCESA = false;
- bool VUELTA_A_EMPEZAR = false;
- bool A_LOS_PASILLOS = false;
- bool COMO_ESTAN_LOS_DIOSES = false;
- bool END_OF_GAME = false;
- bool FROM_INTRO = false;
byte INGREDIENTES_CONSEGUIDOS = 0;
- bool HE_TIRADO_PIEDRA = false;
- bool HA_USADO_AGUA = false;
GameState stateGame = INTRO;
@@ -460,11 +463,23 @@ struct GameStateData {
disabledBranches[entry.room].push_back(entry);
}
+ bool flagIsSet(int flagIndex) const {
+ if (flagIndex < 0 || flagIndex >= 46)
+ return false;
+ return flags[flagIndex];
+ }
+
+ void setFlag(int flagIndex, bool value) {
+ if (flagIndex < 0 || flagIndex >= 46)
+ return;
+ flags[flagIndex] = value;
+ }
+
void addInventoryItem(int id) {
inventoryItems.push_back(id);
}
void removeInventoyItem(int id) {
- for(int i = 0; i < inventoryItems.size(); i++) {
+ for (int i = 0; i < inventoryItems.size(); i++) {
if (inventoryItems[i] == id) {
inventoryItems.remove_at(i);
return;
Commit: 8f89c446f2062c7dcdbcda5102a75934395ed38c
https://github.com/scummvm/scummvm/commit/8f89c446f2062c7dcdbcda5102a75934395ed38c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:46+02:00
Commit Message:
PELROCK: Reading recipe
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/events.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 0db963320e8..cf0dc9853a4 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -71,7 +71,7 @@ const ActionEntry actionTable[] = {
{WILDCARD, NO_ACTION, nullptr}};
const CombinationEntry combinationTable[] = {
- {2, 281, &PelrockEngine::useCardWithATM}, // Use ATM Card with ATM
+ {2, 281, &PelrockEngine::useCardWithATM}, // Use ATM Card with ATM
{62, 117, &PelrockEngine::useSpicySauceWithBurger}, // Use Spicy Sauce with Burger
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -141,7 +141,7 @@ void PelrockEngine::openMcDoor(HotSpot *hotspot) {
}
void PelrockEngine::closeMcDoor(HotSpot *hotspot) {
- //FIXME: Impossible to close right now
+ // FIXME: Impossible to close right now
closeDoor(hotspot, 2, 7, FEMININE, false);
}
@@ -171,10 +171,9 @@ void PelrockEngine::closeKitchenDoor(HotSpot *HotSpot) {
}
void PelrockEngine::openKitchenDrawer(HotSpot *hotspot) {
- if(!_state->flagIsSet(FLAG_JEFE_ENCARCELADO)) {
+ if (!_state->flagIsSet(FLAG_JEFE_ENCARCELADO)) {
_dialog->say(_res->_ingameTexts[QUITA_ESAS_MANOS]);
- }
- else {
+ } else {
_room->addSticker(36);
addInventoryItem(63); // Add recipe
_dialog->say(_res->_ingameTexts[QUESESTO_RECETA]);
@@ -263,13 +262,15 @@ void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
void PelrockEngine::useOnAlfred(int inventoryObject) {
debug("Using item %d on Alfred", inventoryObject);
- switch (inventoryObject)
- {
+ switch (inventoryObject) {
case 63: // Recipe book
- _res->loadAlfredSpecialAnim(0);
+ _res->loadAlfredSpecialAnim(1);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ debug("After special anim");
loadExtraScreenAndPresent(3);
- // _dialog->say(_res->_ingameTexts[QUEASCO]);
+ debug("After extra screen");
+ _dialog->say(_res->_ingameTexts[QUEASCO]);
break;
default:
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
index 1b0f4c4ff8a..63bf81876ef 100644
--- a/engines/pelrock/events.cpp
+++ b/engines/pelrock/events.cpp
@@ -83,11 +83,9 @@ void PelrockEventManager::pollEvent() {
break;
case Common::EVENT_RBUTTONDOWN:
_rightMouseButton = 1;
- debug("Right mouse button down");
break;
case Common::EVENT_RBUTTONUP:
if (_rightMouseButton == 1) {
- debug("Right mouse clicked");
_rightMouseClicked = true;
} else {
_rightMouseClicked = false;
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index b63745f9d22..03cb71fcdab 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -450,7 +450,7 @@ const ExtraImages extraScreens[] = {
{0x647C3, // Alfred circle
0x7B6B1,
4},
- {0x6FBC9, // Recipe
+ {0x6FBCD, // Recipe
0x7B6B1,
8},
{0x7BA11, // Newspaper
@@ -478,11 +478,12 @@ struct AlfredSpecialAnimOffset {
int w = 0;
int h = 0;
int numBudas;
+ int loops;
uint32 offset;
int stride = 0;
- AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, uint32 off)
- : numFrames(nF), w(width), h(height), numBudas(nBudas), offset(off) {
+ AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, uint32 off, int loops)
+ : numFrames(nF), w(width), h(height), numBudas(nBudas), offset(off), loops(loops) {
stride = w * h;
}
AlfredSpecialAnimOffset() {
@@ -490,7 +491,8 @@ struct AlfredSpecialAnimOffset {
};
const AlfredSpecialAnimOffset alfredSpecialAnims[] = {
- {20, 51, 102, 2, 559681}, // READ
+ {10, 51, 102, 1, 559685, 1}, // READ BOOK
+ {10, 51, 102, 1, 578943, 1}, // READ RECIPE
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 7438fdbc8f6..e2794bf23fb 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -297,6 +297,10 @@ void PelrockEngine::checkMouse() {
// Handle mouse release after long press (popup selection mode)
if (_events->_popupSelectionMode && !_events->_leftMouseButton) {
+ _events->_leftMouseButton = false;
+ _events->_leftMouseClicked = false;
+ _events->_popupSelectionMode = false;
+ _actionPopupState.isActive = false;
// Mouse was released while popup is active
VerbIcon actionClicked = isActionUnder(_events->_releaseX, _events->_releaseY);
if (_actionPopupState.isAlfredUnder) {
@@ -311,8 +315,6 @@ void PelrockEngine::checkMouse() {
_queuedAction = QueuedAction{NO_ACTION, -1, false};
_currentHotspot = nullptr;
}
- _actionPopupState.isActive = false;
- _events->_popupSelectionMode = false;
} else if (_events->_leftMouseClicked) {
// Regular click (not during popup mode)
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
@@ -643,9 +645,15 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
break;
}
case ALFRED_SPECIAL_ANIM: {
- if (_res->_specialAnimCurFrame > _res->_curSpecialAnim.numFrames) {
- _res->clearSpecialAnim();
- _alfredState.setState(ALFRED_IDLE);
+ if (_res->_specialAnimCurFrame >= _res->_curSpecialAnim.numFrames) {
+ if (_res->_speciaAnimLoopCount < _res->_curSpecialAnim.loops) {
+ _res->_speciaAnimLoopCount++;
+ _res->_specialAnimCurFrame = 0;
+ } else {
+ _res->clearSpecialAnim();
+ _alfredState.setState(ALFRED_IDLE);
+ _res->_isSpecialAnimFinished = true;
+ }
} else {
byte *frame = new byte[_res->_curSpecialAnim.stride * _res->_curSpecialAnim.numFrames];
extractSingleFrame(_res->_specialAnimData,
@@ -1124,9 +1132,8 @@ void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
void PelrockEngine::pickupIconFlash() {
_graphics->showOverlay(65, _compositeBuffer);
- if(_flashingIcon == -1)
+ if (_flashingIcon == -1)
return;
- debug("Flashing icon %d", _flashingIcon);
InventoryObject item = _res->getIconForObject(_flashingIcon);
if (_chrono->getFrameCount() % kIconBlinkPeriod == 0) {
drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 5, 400 - 60 - 5, 60, 60, 1);
@@ -1141,7 +1148,6 @@ void PelrockEngine::gameLoop() {
void PelrockEngine::extraScreenLoop() {
memcpy(_screen->getPixels(), _extraScreen, 640 * 400);
-
while (!shouldQuit()) {
_events->pollEvent();
@@ -1391,6 +1397,15 @@ void PelrockEngine::loadExtraScreenAndPresent(int screenIndex) {
_screen->update();
}
+void PelrockEngine::waitForSpecialAnimation() {
+ while (!g_engine->shouldQuit() && !_res->_isSpecialAnimFinished) {
+ _events->pollEvent();
+ renderScene(OVERLAY_NONE);
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+}
+
void PelrockEngine::doExtraActions(int roomNumber) {
switch (roomNumber) {
case 4:
@@ -1398,8 +1413,6 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_state->setFlag(FLAG_JEFE_ENCARCELADO, true);
_room->disableSprite(13, 0, true);
loadExtraScreenAndPresent(4);
- _screen->markAllDirty();
- _screen->update();
}
break;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index b38ba69a017..4e0eeb9f5a5 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -221,6 +221,7 @@ public:
void setScreen(int s, AlfredDirection dir);
void loadExtraScreenAndPresent(int screenIndex);
+ void waitForSpecialAnimation();
void doExtraActions(int roomNumber);
bool renderScene(int overlayMode = OVERLAY_NONE);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 1c95c4abf24..d951cca7771 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -227,8 +227,10 @@ void ResourceManager::loadAlfredSpecialAnim(int numAnim) {
alfred7.seek(_curSpecialAnim.offset, SEEK_SET);
_specialAnimData = new byte[_curSpecialAnim.numFrames * _curSpecialAnim.w * _curSpecialAnim.h];
- mergeRleBlocks(&alfred7, _curSpecialAnim.offset, 2, _specialAnimData);
+ debug("Special anim buffer size: %d", _curSpecialAnim.numFrames * _curSpecialAnim.w * _curSpecialAnim.h);
+ mergeRleBlocks(&alfred7, _curSpecialAnim.offset, _curSpecialAnim.numBudas, _specialAnimData);
_specialAnimCurFrame = 0;
+ _isSpecialAnimFinished = false;
alfred7.close();
}
@@ -236,6 +238,7 @@ void ResourceManager::clearSpecialAnim() {
delete[] _specialAnimData;
_specialAnimData = nullptr;
_specialAnimCurFrame = 0;
+ _speciaAnimLoopCount = 0;
}
void ResourceManager::loadInventoryItems() {
@@ -393,6 +396,7 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
for (int i = 0; i < numBlocks; i++) {
byte *thisBlock = nullptr;
size_t blockSize = 0;
+ uint32 pos = stream->pos();
readUntilBuda(stream, stream->pos(), thisBlock, blockSize);
uint8_t *block_data = nullptr;
size_t decompressedSize = rleDecompress(thisBlock, blockSize, 0, 640 * 400, &block_data, true);
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 1288d3d6af7..3b1690ed34e 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -23,8 +23,8 @@
#include "common/scummsys.h"
#include "common/stream.h"
-#include "pelrock/types.h"
#include "pelrock/offsets.h"
+#include "pelrock/types.h"
namespace Pelrock {
@@ -70,10 +70,12 @@ public:
byte *_popUpBalloon = nullptr;
Common::Array<Common::StringArray> _ingameTexts;
- //Special anims
+ // Special anims
byte *_specialAnimData = nullptr;
int _specialAnimCurFrame = 0;
+ int _speciaAnimLoopCount = 0;
AlfredSpecialAnimOffset _curSpecialAnim;
+ bool _isSpecialAnimFinished = false;
};
} // End of namespace Pelrock
Commit: e78e9488e07982b57c909cbd1c0ee2ef4f38422e
https://github.com/scummvm/scummvm/commit/e78e9488e07982b57c909cbd1c0ee2ef4f38422e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:46+02:00
Commit Message:
PELROCK: Fixes timing issues in sprites, walking speed and palette animations
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index e2794bf23fb..4cb895350c3 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -435,36 +435,47 @@ void PelrockEngine::placeSticker(Sticker sticker) {
}
void PelrockEngine::animateFadePalette(PaletteAnim *anim) {
-
- if (anim->data[0] >= anim->data[6] &&
- anim->data[1] >= anim->data[7] &&
- anim->data[2] >= anim->data[8]) {
- anim->data[10] = 0;
- } else if (anim->data[0] <= anim->data[3] &&
- anim->data[1] <= anim->data[4] &&
- anim->data[2] <= anim->data[5]) {
- anim->data[10] = 1;
- }
-
- if (anim->data[10]) {
- if (anim->data[0] < anim->data[6]) {
- anim->data[0] += anim->data[9];
- }
- if (anim->data[1] < anim->data[7]) {
- anim->data[1] += anim->data[9];
- }
- if (anim->data[2] < anim->data[8]) {
- anim->data[2] += anim->data[9];
+ // FADE palette animation - cycles a single palette entry between min/max RGB values
+ // Data layout (after loading from EXE):
+ // data[0] = current R
+ // data[1] = current G
+ // data[2] = current B
+ // data[3] = min R
+ // data[4] = min G
+ // data[5] = min B
+ // data[6] = max R
+ // data[7] = max G
+ // data[8] = max B
+ // data[9] = flags byte:
+ // bits 0-1: R increment
+ // bits 2-3: G increment
+ // bits 4-5: B increment
+ // bit 6: direction (0=decreasing toward min, 1=increasing toward max)
+
+ byte flags = anim->data[9];
+ // Increments are scaled by 4 (<<2) to match the shifted RGB values
+ byte rInc = (flags & 0x03) << 2;
+ byte gInc = ((flags >> 2) & 0x03) << 2;
+ byte bInc = ((flags >> 4) & 0x03) << 2;
+ bool increasing = (flags & 0x40) != 0;
+
+ if (increasing) {
+ // Increasing toward max values
+ anim->data[0] += rInc;
+ anim->data[1] += gInc;
+ anim->data[2] += bInc;
+ // Check if R reached max, then reverse direction
+ if (anim->data[0] >= anim->data[6]) {
+ anim->data[9] &= ~0x40; // Clear direction bit
}
} else {
- if (anim->data[0] > anim->data[3]) {
- anim->data[0] -= anim->data[9];
- }
- if (anim->data[1] > anim->data[4]) {
- anim->data[1] -= anim->data[9];
- }
- if (anim->data[2] > anim->data[5]) {
- anim->data[2] -= anim->data[9];
+ // Decreasing toward min values
+ anim->data[0] -= rInc;
+ anim->data[1] -= gInc;
+ anim->data[2] -= bInc;
+ // Check if R reached min, then reverse direction
+ if (anim->data[0] <= anim->data[3]) {
+ anim->data[9] |= 0x40; // Set direction bit
}
}
@@ -475,8 +486,9 @@ void PelrockEngine::animateFadePalette(PaletteAnim *anim) {
}
void PelrockEngine::animateRotatePalette(PaletteAnim *anim) {
- if (anim->curFrameCount >= anim->data[1]) {
- anim->curFrameCount = 0;
+
+ if (anim->curFrame >= anim->data[1]) {
+ anim->curFrame = 0;
int colors = anim->paletteMode;
byte *paletteValues = new byte[colors * 3];
for (int i = 0; i < colors; i++) {
@@ -494,7 +506,7 @@ void PelrockEngine::animateRotatePalette(PaletteAnim *anim) {
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
} else {
- anim->curFrameCount++;
+ anim->curFrame++;
}
}
@@ -551,29 +563,29 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (step.distanceX > 0) {
if (step.flags & MOVE_RIGHT) {
_alfredState.direction = ALFRED_RIGHT;
- _alfredState.x += MIN(_alfredState.movementSpeed, step.distanceX);
+ _alfredState.x += MIN(_alfredState.movementSpeedX, step.distanceX);
}
if (step.flags & MOVE_LEFT) {
_alfredState.direction = ALFRED_LEFT;
- _alfredState.x -= MIN(_alfredState.movementSpeed, step.distanceX);
+ _alfredState.x -= MIN(_alfredState.movementSpeedX, step.distanceX);
}
}
if (step.distanceY > 0) {
if (step.flags & MOVE_DOWN) {
_alfredState.direction = ALFRED_DOWN;
- _alfredState.y += MIN(_alfredState.movementSpeed, step.distanceY);
+ _alfredState.y += MIN(_alfredState.movementSpeedY, step.distanceY);
}
if (step.flags & MOVE_UP) {
_alfredState.direction = ALFRED_UP;
- _alfredState.y -= MIN(_alfredState.movementSpeed, step.distanceY);
+ _alfredState.y -= MIN(_alfredState.movementSpeedY, step.distanceY);
}
}
if (step.distanceX > 0)
- step.distanceX -= MIN(_alfredState.movementSpeed, step.distanceX);
+ step.distanceX -= MIN(_alfredState.movementSpeedX, step.distanceX);
if (step.distanceY > 0)
- step.distanceY -= MIN(_alfredState.movementSpeed, step.distanceY);
+ step.distanceY -= MIN(_alfredState.movementSpeedY, step.distanceY);
if (step.distanceX <= 0 && step.distanceY <= 0) {
_currentStep++;
@@ -617,9 +629,9 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.curFrame = 0;
}
drawAlfred(_res->alfredTalkFrames[_alfredState.direction][_alfredState.curFrame]);
- if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
+ // if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
_alfredState.curFrame++;
- }
+ // }
break;
}
case ALFRED_COMB: {
@@ -628,7 +640,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredIdle[_alfredState.direction], _alfredState.x, _alfredState.y - kAlfredFrameHeight, 51, 102, 255);
} else {
drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[_alfredState.direction][_alfredState.curFrame], _alfredState.x, _alfredState.y - kAlfredFrameHeight, 51, 102, 255);
- if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
+ // if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
_alfredState.curFrame++;
}
break;
@@ -638,9 +650,9 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.setState(ALFRED_IDLE);
} else {
drawAlfred(_res->alfredInteractFrames[_alfredState.direction][_alfredState.curFrame]);
- if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
+ // if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
_alfredState.curFrame++;
- }
+ // }
}
break;
}
@@ -669,9 +681,9 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_res->_curSpecialAnim.w,
_res->_curSpecialAnim.h,
255);
- if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
+ // if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
_res->_specialAnimCurFrame++;
- }
+ // }
delete[] frame;
}
}
@@ -842,8 +854,9 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
byte *frame = new byte[frameSize];
drawSpriteToBuffer(_compositeBuffer, 640, animData.animData[curFrame], x, y, w, h, 255);
- // if (animData.elpapsedFrames == animData.speed) {
- if (_chrono->getFrameCount() % animData.speed == 0) {
+ // Original in the game: increment FIRST, then check (not check-then-increment)
+ animData.elpapsedFrames++;
+ if (animData.elpapsedFrames >= animData.speed) {
animData.elpapsedFrames = 0;
if (animData.curFrame < animData.nframes - 1) {
animData.curFrame++;
@@ -861,8 +874,6 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
}
}
}
- } else {
- animData.elpapsedFrames++;
}
}
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 265396014b4..8143c9938fb 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -222,7 +222,12 @@ PaletteAnim *RoomManager::getPaletteAnimForRoom(int roomNumber) {
anim->paletteMode = exeFile.readByte();
exeFile.read(anim->data, 10);
if (anim->paletteMode == 1) {
- for (int i = 2; i < 10; i++) {
+ // FADE mode: shift RGB values to convert from 6-bit VGA to 8-bit
+ // data[0-2] = current R,G,B
+ // data[3-5] = min R,G,B
+ // data[6-8] = max R,G,B
+ // data[9] = flags (R/G/B increments + direction) - NOT shifted
+ for (int i = 0; i < 9; i++) {
anim->data[i] = anim->data[i] << 2;
}
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 93d477a02d7..09af2584325 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -71,7 +71,7 @@ const int kAlfredFrameHeight = 102;
const int kChoiceHeight = 16; // Height of each choice line in pixels
const int kTalkAnimationSpeed = 2; // Frames per update
-const int kAlfredAnimationSpeed = 2; // Frames per update
+
const int kAlfredIdleAnimationFrameCount = 300;
// Direction flags (bit-packed)
@@ -126,7 +126,8 @@ struct AlfredState {
AlfredAnimState animState = ALFRED_IDLE;
AlfredDirection direction = ALFRED_DOWN;
int curFrame = 0;
- uint16 movementSpeed = 6; // pixels per frame
+ uint16 movementSpeedX = 6; // pixels per frame
+ uint16 movementSpeedY = 5; // pixels per frame
uint16 x = 319;
uint16 y = 302;
uint16 scaledX = 0;
@@ -360,7 +361,8 @@ struct PaletteAnim {
byte startIndex;
byte paletteMode;
byte data[10]; // Based on mode its a rotate or fade
- byte curFrameCount = 0;
+ byte curFrame = 0;
+ byte tickCount = 0;
};
/**
Commit: b4f94c59fc715c9d644ec764f657d5582de8954c
https://github.com/scummvm/scummvm/commit/b4f94c59fc715c9d644ec764f657d5582de8954c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:46+02:00
Commit Message:
PELROCK: Scaling improvements
Changed paths:
engines/pelrock/pathfinding.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/sound.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
index efe1a28e600..a89d9cee7ad 100644
--- a/engines/pelrock/pathfinding.cpp
+++ b/engines/pelrock/pathfinding.cpp
@@ -124,34 +124,12 @@ Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes,
bool mouseHoverState,
HotSpot *hotspot) {
- // // Step 1: Determine actual source point
- // if (mouseHoverState == 1) {
- // // Hovering over sprite - check if it has action flags or is animated
- // Sprite *sprite = getSprite(hotspotSpriteIndex);
- // if (sprite->actionFlags != 0 || sprite->frameCount != 1) {
- // sourceX = sprite->x + sprite->width / 2;
- // sourceY = sprite->y + sprite->height;
- // }
- // }
- // else if (mouseHoverState == 2) {
- // // Hovering over hotspot - use hotspot center-bottom
- // Hotspot *hotspot = getHotspot(hotspotSpriteIndex);
- // sourceX = hotspot->x + hotspot->width / 2;
- // sourceY = hotspot->y + hotspot->height;
- // }
-
- // if (mouseHoverState == 1) {
- // Hovering over hotspot - use hotspot center-bottom
- // if(hotspot != nullptr) {
- // sourceX = hotspot->x + hotspot->w / 2;
- // sourceY = hotspot->y + hotspot->h;
- // }
-
- // }
-
- // else: use sourceX, sourceY as passed (mouse position)
-
- // Step 2: Find nearest walkbox
+ if(hotspot != nullptr) {
+ sourceX = hotspot->x + hotspot->w / 2;
+ sourceY = hotspot->y + hotspot->h;
+ }
+
+ // Find nearest walkbox
uint32 minDistance = 0xFFFF;
int bestXDistance = 0;
int bestYDistance = 0;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 4cb895350c3..18b3e968c36 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -629,19 +629,17 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.curFrame = 0;
}
drawAlfred(_res->alfredTalkFrames[_alfredState.direction][_alfredState.curFrame]);
- // if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
- _alfredState.curFrame++;
+ _alfredState.curFrame++;
// }
break;
}
case ALFRED_COMB: {
if (_alfredState.curFrame >= 11) {
_alfredState.setState(ALFRED_IDLE);
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredIdle[_alfredState.direction], _alfredState.x, _alfredState.y - kAlfredFrameHeight, 51, 102, 255);
+ drawAlfred(_res->alfredIdle[_alfredState.direction]);
} else {
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCombFrames[_alfredState.direction][_alfredState.curFrame], _alfredState.x, _alfredState.y - kAlfredFrameHeight, 51, 102, 255);
- // if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
- _alfredState.curFrame++;
+ drawAlfred(_res->alfredCombFrames[_alfredState.direction][_alfredState.curFrame]);
+ _alfredState.curFrame++;
}
break;
}
@@ -650,9 +648,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.setState(ALFRED_IDLE);
} else {
drawAlfred(_res->alfredInteractFrames[_alfredState.direction][_alfredState.curFrame]);
- // if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
- _alfredState.curFrame++;
- // }
+ _alfredState.curFrame++;
}
break;
}
@@ -673,17 +669,16 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_res->_specialAnimCurFrame,
_res->_curSpecialAnim.w,
_res->_curSpecialAnim.h);
- drawSpriteToBuffer(_compositeBuffer,
- 640,
- frame,
- _alfredState.x,
- _alfredState.y - _res->_curSpecialAnim.h,
- _res->_curSpecialAnim.w,
- _res->_curSpecialAnim.h,
- 255);
- // if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
- _res->_specialAnimCurFrame++;
- // }
+ drawAlfred(frame);
+ // drawSpriteToBuffer(_compositeBuffer,
+ // 640,
+ // frame,
+ // _alfredState.x,
+ // _alfredState.y - _res->_curSpecialAnim.h,
+ // _res->_curSpecialAnim.w,
+ // _res->_curSpecialAnim.h,
+ // 255);
+ _res->_specialAnimCurFrame++;
delete[] frame;
}
}
@@ -698,17 +693,19 @@ void PelrockEngine::drawAlfred(byte *buf) {
ScaleCalculation scale = calculateScaling(_alfredState.y, _room->_scaleParams);
- int finalHeight = kAlfredFrameHeight - scale.scaleDown + scale.scaleUp;
+ // Use the pre-calculated scaled dimensions from calculateScaling
+ int finalHeight = scale.scaledHeight;
+ int finalWidth = scale.scaledWidth;
+
if (finalHeight <= 0) {
finalHeight = 1;
}
- float scaleFactor = static_cast<float>(finalHeight) / static_cast<float>(kAlfredFrameHeight);
- int finalWidth = static_cast<int>(kAlfredFrameWidth * scaleFactor);
if (finalWidth <= 0) {
finalWidth = 1;
}
+
int scaleIndex = finalHeight - 1;
- if (scaleIndex >= _heightScalingTable.size()) {
+ if (scaleIndex >= (int)_heightScalingTable.size()) {
scaleIndex = _heightScalingTable.size() - 1;
}
if (scaleIndex < 0) {
@@ -981,45 +978,52 @@ void PelrockEngine::calculateScalingMasks() {
}
ScaleCalculation PelrockEngine::calculateScaling(int yPos, ScalingParams scalingParams) {
- int scaleDown = 0;
- int scaleUp = 0;
+ // scaleY = amount to subtract from height (94 max for 0xFF mode)
+ // scaleX = amount to subtract from width (47 max for 0xFF mode, = scaleY/2)
+ int scaleY = 0;
+ int scaleX = 0;
if (scalingParams.scaleMode == 0xFF) {
- scaleDown = 0x5e;
- scaleUp = 0x2f;
+ // Maximum scaling - character is very small (used for bird's eye view maps)
+ scaleY = 0x5e; // 94
+ scaleX = 0x2f; // 47
} else if (scalingParams.scaleMode == 0xFE) {
- scaleDown = 0;
- scaleUp = 0;
+ // No scaling - full size character
+ scaleY = 0;
+ scaleX = 0;
} else if (scalingParams.scaleMode == 0) {
+ // Dynamic scaling based on Y position
if (scalingParams.yThreshold < yPos) {
- scaleDown = 0;
- scaleUp = 0;
+ // Below threshold - no scaling
+ scaleY = 0;
+ scaleX = 0;
} else {
if (scalingParams.scaleDivisor != 0) {
- scaleDown = (scalingParams.yThreshold - yPos) / scalingParams.scaleDivisor;
- scaleUp = scaleDown / 2;
+ scaleY = (scalingParams.yThreshold - yPos) / scalingParams.scaleDivisor;
+ scaleX = scaleY / 2;
} else {
- scaleDown = 0;
- scaleUp = 0;
+ scaleY = 0;
+ scaleX = 0;
}
}
} else {
- scaleDown = 0;
- scaleUp = 0;
+ scaleY = 0;
+ scaleX = 0;
}
- int finalHeight = kAlfredFrameHeight - scaleDown + scaleUp;
+ // Original game formula: actual dimensions = base - scale amount
+ int finalHeight = kAlfredFrameHeight - scaleY;
if (finalHeight < 1)
finalHeight = 1;
- int finalWidth = kAlfredFrameWidth * (finalHeight / kAlfredFrameHeight);
+ int finalWidth = kAlfredFrameWidth - scaleX;
if (finalWidth < 1)
finalWidth = 1;
ScaleCalculation scaleCalc;
scaleCalc.scaledHeight = finalHeight;
scaleCalc.scaledWidth = finalWidth;
- scaleCalc.scaleDown = scaleDown;
- scaleCalc.scaleUp = scaleUp;
+ scaleCalc.scaleY = scaleY;
+ scaleCalc.scaleX = scaleX;
return scaleCalc;
}
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 31bfa59f5ad..50ec43216a4 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -94,7 +94,7 @@ void SoundManager::playSound(SonidoFile sound, int volume) {
// Create raw audio stream (8-bit unsigned mono is common for old games)
stream = Audio::makeRawStream(pcmData, pcmSize, sampleRate, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
} else {
- debug("Unknown sound format");
+ debug("Unknown sound format at offset %d, with size %d", sound.offset, sound.size);
delete[] data;
return;
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 09af2584325..75b32123f00 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -282,8 +282,8 @@ struct ScalingParams {
struct ScaleCalculation {
int scaledWidth;
int scaledHeight;
- int scaleUp;
- int scaleDown;
+ int scaleX; // Amount to subtract from width (was scaleUp)
+ int scaleY; // Amount to subtract from height (was scaleDown)
};
enum GameState {
Commit: 8e6c8b01a45051e42992509d81d6495784b14cda
https://github.com/scummvm/scummvm/commit/8e6c8b01a45051e42992509d81d6495784b14cda
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:47+02:00
Commit Message:
PELROCK: Additional debugging capabilities
Changed paths:
engines/pelrock/console.cpp
engines/pelrock/console.h
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/types.h
engines/pelrock/util.cpp
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index cfa96283d8b..04cf59c1dea 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -28,12 +28,12 @@ namespace Pelrock {
PelrockConsole::PelrockConsole(PelrockEngine *engine) : GUI::Debugger(), _engine(engine) {
registerCmd("setScreen", WRAP_METHOD(PelrockConsole, cmdLoadRoom));
+ registerCmd("give", WRAP_METHOD(PelrockConsole, cmdGiveItems));
}
PelrockConsole::~PelrockConsole() {
}
-
bool PelrockConsole::cmdLoadRoom(int argc, const char **argv) {
if (argc < 2) {
debugPrintf("Usage: setScreen <roomNumber>");
@@ -42,9 +42,24 @@ bool PelrockConsole::cmdLoadRoom(int argc, const char **argv) {
int roomNumber = atoi(argv[1]);
g_engine->setScreen(roomNumber, ALFRED_DOWN);
+ const WalkBox w = g_engine->_room->_currentRoomWalkboxes[0];
+ g_engine->_alfredState.x = w.x;
+ g_engine->_alfredState.y = w.y;
debugPrintf("Loaded room %d", roomNumber);
return true;
}
+bool PelrockConsole::cmdGiveItems(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Usage: giveItems <itemId> [itemId] ...");
+ return true;
+ }
+ for (int i = 1; i < argc; i++) {
+ int itemId = atoi(argv[i]);
+ g_engine->_state->addInventoryItem(itemId);
+ debugPrintf("Gave item %d\n", itemId);
+ }
+ return true;
+}
} // End of namespace Pelrock
diff --git a/engines/pelrock/console.h b/engines/pelrock/console.h
index 29bb09747c0..41b007da25c 100644
--- a/engines/pelrock/console.h
+++ b/engines/pelrock/console.h
@@ -32,6 +32,7 @@ class PelrockConsole : public GUI::Debugger {
private:
PelrockEngine *_engine;
bool cmdLoadRoom(int argc, const char **argv);
+ bool cmdGiveItems(int argc, const char **argv);
bool cmdTest(int argc, const char **argv);
public:
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index ad74822092b..488255a310d 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -160,13 +160,7 @@ void MenuManager::menuLoop() {
if (showButtons)
drawButtons();
- for (int i = 0; i < 4; i++) {
- int itemIndex = _curInventoryPage * 4 + i;
- if (g_engine->_state->inventoryItems.size() <= itemIndex)
- continue;
- InventoryObject item = g_engine->_res->getIconForObject(g_engine->_state->inventoryItems[itemIndex]);
- drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
- }
+ drawInventoryIcons();
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
for (int i = 0; _menuText.size() > i; i++) {
@@ -178,6 +172,21 @@ void MenuManager::menuLoop() {
_screen->update();
}
+void MenuManager::drawInventoryIcons() {
+ bool debugIcons = true;
+ for (int i = 0; i < 4; i++) {
+ int itemIndex = _curInventoryPage * 4 + i;
+ if (g_engine->_state->inventoryItems.size() <= itemIndex)
+ continue;
+ InventoryObject item = g_engine->_res->getIconForObject(g_engine->_state->inventoryItems[itemIndex]);
+ drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
+ if (debugIcons) {
+ drawRect(_compositeBuffer, 140 + (82 * i), 115 - (8 * i), 60, 60, 13);
+ drawText(_compositeBuffer, g_engine->_smallFont, Common::String::format("ID %d", g_engine->_state->inventoryItems[itemIndex]), 140 + (82 * i) + 2, 115 - (8 * i) + 2, 640, 13);
+ }
+ }
+}
+
void MenuManager::loadMenu() {
bool alternateMenu = false;
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 9d1fae248dd..3de2bc10f92 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -51,6 +51,7 @@ public:
MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res);
~MenuManager();
void menuLoop();
+ void drawInventoryIcons();
void loadMenu();
byte _mainMenuPalette[768] = {0};
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 18b3e968c36..aee08282f69 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -383,16 +383,35 @@ void PelrockEngine::updatePaletteAnimations() {
}
void PelrockEngine::paintDebugLayer() {
- for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
- WalkBox box = _room->_currentRoomWalkboxes[i];
- drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
- _smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
+ bool showWalkboxes = false;
+
+ if (showWalkboxes) {
+ for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
+ WalkBox box = _room->_currentRoomWalkboxes[i];
+ drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
+ _smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
+ }
}
- for (int i = 0; i < _room->_currentRoomExits.size(); i++) {
- Exit exit = _room->_currentRoomExits[i];
- drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 200 + i);
- _smallFont->drawString(_screen, Common::String::format("Exit %d -> Room %d", i, exit.targetRoom), exit.x + 2, exit.y + 2, 640, 14);
+ bool showHotspots = true;
+ if (showHotspots) {
+ for (int i = 0; i < _room->_currentRoomHotspots.size(); i++) {
+ HotSpot hotspot = _room->_currentRoomHotspots[i];
+ if (!hotspot.isEnabled)
+ continue;
+ drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 180 + i);
+ _smallFont->drawString(_screen, Common::String::format("HS %d", i), hotspot.x + 2, hotspot.y + 2, 640, 14);
+ _smallFont->drawString(_screen, Common::String::format("x=%d", hotspot.extra), hotspot.x + 2, hotspot.y + 2 + 14, 640, 14);
+ }
+ }
+
+ bool showExits = true;
+ if (showExits) {
+ for (int i = 0; i < _room->_currentRoomExits.size(); i++) {
+ Exit exit = _room->_currentRoomExits[i];
+ drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 200 + i);
+ _smallFont->drawString(_screen, Common::String::format("Exit %d -> Room %d", i, exit.targetRoom), exit.x + 2, exit.y + 2, 640, 14);
+ }
}
drawPos(_screen, _alfredState.x, _alfredState.y, 13);
@@ -670,14 +689,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_res->_curSpecialAnim.w,
_res->_curSpecialAnim.h);
drawAlfred(frame);
- // drawSpriteToBuffer(_compositeBuffer,
- // 640,
- // frame,
- // _alfredState.x,
- // _alfredState.y - _res->_curSpecialAnim.h,
- // _res->_curSpecialAnim.w,
- // _res->_curSpecialAnim.h,
- // 255);
_res->_specialAnimCurFrame++;
delete[] frame;
}
@@ -689,6 +700,9 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
}
}
+/**
+ * Scales and shades alfred sprite and draws it to the composite buffer
+ */
void PelrockEngine::drawAlfred(byte *buf) {
ScaleCalculation scale = calculateScaling(_alfredState.y, _room->_scaleParams);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index d951cca7771..eda93599d47 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -378,7 +378,7 @@ Pelrock::Sticker ResourceManager::getSticker(int stickerIndex) {
InventoryObject ResourceManager::getIconForObject(byte objectIndex) {
byte iconIndex = 0;
if (objectIndex < 59) {
- if (11 < objectIndex < 59) {
+ if (objectIndex >= 11 && objectIndex < 59) {
iconIndex = ((objectIndex - 11) & 3) + 11; // Books cycle through icons 11-14
} else {
iconIndex = objectIndex; // Direct mapping for IDs 0-11
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 8143c9938fb..24969dc6711 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -159,7 +159,7 @@ void RoomManager::changeHotSpot(HotSpot hotspot) {
}
void RoomManager::disableSprite(int roomNumber, int spriteIndex, bool persist) {
- if(roomNumber == _currentRoomNumber) {
+ if (roomNumber == _currentRoomNumber) {
_currentRoomAnims[spriteIndex].zOrder = 255;
}
g_engine->_state->disabledSprites[roomNumber].push_back(spriteIndex);
@@ -526,7 +526,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
sprite.spriteType = data[animOffset + 33];
sprite.actionFlags = data[animOffset + 34];
sprite.isHotspotDisabled = data[animOffset + 38];
- for(int i = 0; i < disabledSprites.size(); i++) {
+ for (int i = 0; i < disabledSprites.size(); i++) {
if (disabledSprites[i] == sprite.index) {
sprite.zOrder = 255;
sprite.isHotspotDisabled = 1;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 75b32123f00..4970659abec 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -70,7 +70,7 @@ const int kAlfredFrameHeight = 102;
const int kChoiceHeight = 16; // Height of each choice line in pixels
-const int kTalkAnimationSpeed = 2; // Frames per update
+const int kTalkAnimationSpeed = 2; // Frames per update
const int kAlfredIdleAnimationFrameCount = 300;
@@ -282,8 +282,8 @@ struct ScalingParams {
struct ScaleCalculation {
int scaledWidth;
int scaledHeight;
- int scaleX; // Amount to subtract from width (was scaleUp)
- int scaleY; // Amount to subtract from height (was scaleDown)
+ int scaleX; // Amount to subtract from width (was scaleUp)
+ int scaleY; // Amount to subtract from height (was scaleDown)
};
enum GameState {
@@ -480,6 +480,7 @@ struct GameStateData {
void addInventoryItem(int id) {
inventoryItems.push_back(id);
}
+
void removeInventoyItem(int id) {
for (int i = 0; i < inventoryItems.size(); i++) {
if (inventoryItems[i] == id) {
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 05f9d9e231d..e4b8c5d370f 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -323,7 +323,6 @@ byte decodeChar(byte b) {
}
}
-
void changeGameSpeed(Common::Event e) {
if (e.type == Common::EVENT_KEYDOWN) {
if (e.kbd.hasFlags(Common::KBD_CTRL)) {
Commit: 37add58b128ca8e5497e89dd9ed90bd41626973c
https://github.com/scummvm/scummvm/commit/37add58b128ca8e5497e89dd9ed90bd41626973c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:47+02:00
Commit Message:
PELROCK: Implement all palette animations
Changed paths:
engines/pelrock/room.cpp
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 24969dc6711..f858fac530c 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -211,6 +211,39 @@ PaletteAnim *RoomManager::getPaletteAnimForRoom(int roomNumber) {
case 2:
offset = 0x0004B860;
break;
+ case 9:
+ offset = 0x0004B874;
+ break;
+ case 17:
+ offset = 0x0004B86C;
+ break;
+ case 18:
+ offset = 0x0004B870;
+ break;
+ case 19:
+ offset = 0x0004B878;
+ break;
+ case 21:
+ offset = 0x0004B884;
+ break;
+ case 25:
+ offset = 0x0004B890;
+ break;
+ case 32:
+ offset = 0x0004B898;
+ break;
+ case 33:
+ offset = 0x0004B89C;
+ break;
+ case 38:
+ offset = 0x0004B894;
+ break;
+ case 39:
+ offset = 0x0004B888;
+ break;
+ case 46:
+ offset = 0x0004B8A0;
+ break;
default:
exeFile.close();
return nullptr;
Commit: 7f740aff3cdc355075a7915e9bafbee12a57312a
https://github.com/scummvm/scummvm/commit/7f740aff3cdc355075a7915e9bafbee12a57312a
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:47+02:00
Commit Message:
PELROCK: Better sound management
Changed paths:
engines/pelrock/sound.cpp
engines/pelrock/sound.h
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 50ec43216a4..530a7c934c6 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -237,27 +237,23 @@ void SoundManager::loadSoundIndex() {
sonidosFile.close();
}
-int RANDOM_THRESHOLD = 0x4000;
+static const uint kAmbientCounterMask = 0x1F; // Trigger when (counter & mask) == mask
-int SoundManager::tick(uint32 frameCount) {
-
- uint16 rand1 = _rng.nextRandom();
- // uint32 random = g_engine->getRandomNumber(1);
- if (rand1 <= RANDOM_THRESHOLD) {
- // debug("No SFX this tick due to 50% random");
+int SoundManager::tickAmbientSound(uint32 frameCount) {
+ // Counter gate: only trigger every 32 frames when (counter & 0x1F) == 0x1F
+ if ((frameCount & kAmbientCounterMask) != kAmbientCounterMask) {
return -1;
}
- if ((frameCount & COUNTER_MASK) != COUNTER_MASK) {
- // debug("No SFX this tick due to counter mask (counter = %d)", soundFrameCounter);
+ // 50% probability gate using ScummVM's random source
+ if (g_engine->getRandomNumber(1) == 0) {
return -1;
}
- uint16 rand2 = _rng.nextRandom();
- int slot = rand2 & 3;
- // debug("Slot = %d (rand2 = %u)", slot, rand2);
- // uint32 slot = g_engine->getRandomNumber(4);
- return slot + 1;
+ // Pick random ambient slot 0-3 (corresponds to room sound indices 4-7)
+ int ambientSlotOffset = g_engine->getRandomNumber(3);
+
+ return ambientSlotOffset; // Caller adds 4 to get room sound index
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index d2733e83e7a..45d882fa1a3 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -150,38 +150,9 @@ struct SoundData {
uint32 size;
};
-static const uint COUNTER_MASK = 0x1F;
const int kMaxChannels = 15;
-
-class GameRNG {
-
-private:
- uint32_t _state;
-
-public:
- // LCG constants (from JUEGO.EXE @ 0x0002b12f)
- static constexpr uint32_t MULTIPLIER = 0x41C64E6D; // 1103515245
- static constexpr uint32_t INCREMENT = 0x3039; // 12345
-
- GameRNG(uint32_t seed = 0) {
- _state = seed & 0xFFFFFFFF;
- }
-
- // Generate next random number (0-32767)
- uint16_t nextRandom() {
- _state = (_state * MULTIPLIER + INCREMENT) & 0xFFFFFFFF;
- return static_cast<uint16_t>((_state >> 16) & 0x7FFF);
- }
-
- uint32_t getState() const {
- return _state;
- }
-
- void setState(uint32_t state) {
- _state = state & 0xFFFFFFFF;
- }
-};
+const int kAmbientSoundSlotBase = 4; // Room sound indices 4-7 are ambient sounds
class SoundManager {
public:
@@ -202,7 +173,13 @@ public:
}
void loadSoundIndex();
- int tick(uint32 frameCount);
+ /**
+ * Check if ambient sound should play this frame.
+ * @param frameCount Current game frame counter
+ * @return Ambient slot offset (0-3) to play, or -1 if no sound this frame
+ * Add kAmbientSoundSlotBase (4) to get room sound index
+ */
+ int tickAmbientSound(uint32 frameCount);
private:
void playSound(SonidoFile sound, int volume = 255);
@@ -219,7 +196,6 @@ private:
Audio::SoundHandle _musicHandle;
Audio::SoundHandle _sfxHandles[kMaxChannels];
Common::HashMap<Common::String, SonidoFile> _soundMap;
- GameRNG _rng = GameRNG(0);
};
} // End of namespace Pelrock
Commit: c8c2995f9efd2aaa19fbe5619d5534106936ff90
https://github.com/scummvm/scummvm/commit/c8c2995f9efd2aaa19fbe5619d5534106936ff90
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:48+02:00
Commit Message:
PELROCK: Add actions for room 3
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/events.cpp
engines/pelrock/events.h
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/saveload.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index cf0dc9853a4..aeb70e48c20 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -57,6 +57,11 @@ const ActionEntry actionTable[] = {
{375, OPEN, &PelrockEngine::openKitchenDrawer},
{374, OPEN, &PelrockEngine::openKitchenDoorFromInside},
+ // Room 3
+ {290, OPEN, &PelrockEngine::openShopDoor},
+ {290, CLOSE, &PelrockEngine::closeShopDoor},
+ {32, OPEN, &PelrockEngine::openLamppost},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -73,6 +78,7 @@ const ActionEntry actionTable[] = {
const CombinationEntry combinationTable[] = {
{2, 281, &PelrockEngine::useCardWithATM}, // Use ATM Card with ATM
{62, 117, &PelrockEngine::useSpicySauceWithBurger}, // Use Spicy Sauce with Burger
+ {4, 294, &PelrockEngine::useBrickWithWindow}, // Use Brick with Window (Room 3)
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -131,7 +137,7 @@ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
addInventoryItem(5); // 1000 pesetas bill
_dialog->say(_res->_ingameTexts[TEAPETECE_BUENRATO]);
} else {
- _dialog->say(_res->_ingameTexts[NOMONEY_LEFT]);
+ _dialog->say(_res->_ingameTexts[NOTENGOMASDINERO]);
}
}
}
@@ -189,9 +195,90 @@ void PelrockEngine::useSpicySauceWithBurger(int inventoryObject, HotSpot *hotspo
_dialog->say(_res->_ingameTexts[VAESTAR_POCOFUERTE]);
}
+void PelrockEngine::openShopDoor(HotSpot *hotspot) {
+ if (!_state->flagIsSet(FLAG_TIENDA_ABIERTA)) {
+ _dialog->say(_res->_ingameTexts[TIENDA_CERRADA]);
+ return;
+ } else {
+ openDoor(hotspot, 0, 13, MASCULINE, false);
+ }
+}
+
+void PelrockEngine::closeShopDoor(HotSpot *hotspot) {
+ closeDoor(hotspot, 0, 13, MASCULINE, false);
+}
+
+void PelrockEngine::openLamppost(HotSpot *hotspot) {
+ debug("Opening lamppost");
+ _room->addSticker(14);
+}
+
+void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
+ debug("Using brick with window - sticker 11 will be added");
+
+ // Check if window is already broken
+ if (_room->hasSticker(11)) {
+ // Window already broken, say something generic
+ _alfredState.direction = ALFRED_UP;
+ _dialog->say(_res->_ingameTexts[YA_ABIERTO_M]); // "It's already open/broken"
+ return;
+ }
+
+ // TODO: Play Alfred's throwing animation
+ // This would require adding a new special animation entry
+ // _res->loadAlfredSpecialAnim(BRICK_THROW_ANIM);
+ // _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ // waitForSpecialAnimation();
+
+ // TODO: Animate sprite 8 (brick projectile) moving to window
+ Sprite *brickSprite = _room->findSpriteByIndex(7);
+ HotSpot *windowHotspot = _room->findHotspotByExtra(294);
+ brickSprite->x = _alfredState.x - brickSprite->w / 2;
+ brickSprite->y = _alfredState.y - kAlfredFrameHeight;
+ brickSprite->zOrder = 20; // Make it visible
+ int target = windowHotspot->y + windowHotspot->h / 2;
+ while (!shouldQuit()) {
+ _events->pollEvent();
+ renderScene(OVERLAY_NONE);
+ if (_chrono->_gameTick) {
+ _room->findSpriteByIndex(7)->y -= 40;
+ if (_room->findSpriteByIndex(7)->y < target) {
+ _room->findSpriteByIndex(7)->zOrder = -1;
+ break;
+ }
+ }
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+ // This would involve loading and animating the room sprite
+
+ // Add the broken window sticker
+ _room->addSticker(11);
+ _sound->playSound(_room->_roomSfx[2]); // Play glass breaking sound
+
+ // Remove brick from inventory
+ _state->removeInventoryItem(4);
+
+ int16 x = 639; // put at the very edge of the screen
+ int16 y = windowHotspot->y;
+ // Play the NPC dialog sequence
+ int16 dialog1y = y + 22;
+ int16 dialog2y = dialog1y + 10 + _largeFont->getFontHeight();
+ _dialog->say(_res->_ingameTexts[QUEHASIDOESO], x, dialog1y);
+ _dialog->say(_res->_ingameTexts[QUIENANDAAHI], x, dialog2y);
+ _dialog->say(_res->_ingameTexts[YOMEVOY]);
+
+ _state->setFlag(FLAG_TIENDA_ABIERTA, true);
+ _room->onlyPersistSticker(_room->_currentRoomNumber, 9);
+ _room->onlyPersistSticker(_room->_currentRoomNumber, 10);
+ _room->disableHotspot(_room->findHotspotByExtra(295)); // Disable storefront hotspot
+ _room->disableHotspot(_room->findHotspotByExtra(294)); // Disable window hotspot
+ walkTo(639, _alfredState.y);
+}
+
void PelrockEngine::openDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayClosed) {
if (_room->hasSticker(sticker)) {
- int text = masculine == MASCULINE ? YA_ABIERTO_M : ALREADY_OPENED_F;
+ int text = masculine == MASCULINE ? YA_ABIERTO_M : YA_ABIERTA_F;
_dialog->say(_res->_ingameTexts[text]);
return;
}
@@ -201,7 +288,7 @@ void PelrockEngine::openDoor(HotSpot *hotspot, int exitIndex, int sticker, bool
void PelrockEngine::closeDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayOpen) {
if (!_room->hasSticker(sticker)) {
- int text = masculine == MASCULINE ? ALREADY_CLOSED_M : ALREADY_CLOSED_F;
+ int text = masculine == MASCULINE ? YA_CERRADO_M : YA_CERRADA_F;
_dialog->say(_res->_ingameTexts[text]);
return;
}
@@ -241,7 +328,7 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
case 257:
_sound->playMusicTrack(25);
loadExtraScreenAndPresent(9);
- _dialog->say(_res->_ingameTexts[SOHOT]);
+ _dialog->say(_res->_ingameTexts[QUEBUENA_ESTA]);
_screen->markAllDirty();
_screen->update();
break;
@@ -267,12 +354,17 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_res->loadAlfredSpecialAnim(1);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
waitForSpecialAnimation();
- debug("After special anim");
+
loadExtraScreenAndPresent(3);
debug("After extra screen");
_dialog->say(_res->_ingameTexts[QUEASCO]);
break;
-
+ case 0: // yellow book
+ _res->loadAlfredSpecialAnim(2);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _dialog->say(_res->_ingameTexts[CUENTOPARECIDO]);
+ break;
default:
break;
}
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index 04cf59c1dea..0f1b2f0f967 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -42,9 +42,6 @@ bool PelrockConsole::cmdLoadRoom(int argc, const char **argv) {
int roomNumber = atoi(argv[1]);
g_engine->setScreen(roomNumber, ALFRED_DOWN);
- const WalkBox w = g_engine->_room->_currentRoomWalkboxes[0];
- g_engine->_alfredState.x = w.x;
- g_engine->_alfredState.y = w.y;
debugPrintf("Loaded room %d", roomNumber);
return true;
}
@@ -56,7 +53,11 @@ bool PelrockConsole::cmdGiveItems(int argc, const char **argv) {
}
for (int i = 1; i < argc; i++) {
int itemId = atoi(argv[i]);
+ bool markAsSelected = g_engine->_state->inventoryItems.empty();
g_engine->_state->addInventoryItem(itemId);
+ if (markAsSelected)
+ g_engine->_state->selectedInventoryItem = itemId;
+
debugPrintf("Gave item %d\n", itemId);
}
return true;
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 1abead0b84a..c5233f6275d 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -49,8 +49,8 @@ uint32 DialogManager::readTextBlock(
outText = "";
// Skip control bytes at start
- if(data[pos] == CTRL_TEXT_TERMINATOR) {
- pos+=2;
+ if (data[pos] == CTRL_TEXT_TERMINATOR) {
+ pos += 2;
}
if (pos >= dataSize) {
@@ -74,11 +74,11 @@ uint32 DialogManager::readTextBlock(
}
// Choice text is always spoken by ALFRED
outSpeakerId = ALFRED_COLOR;
- pos+=2;
+ pos += 2;
}
int lineIndex = data[++pos];
- pos++; //blank
+ pos++; // blank
debug("Reading text block starting at pos %u, line index %d, speaker ID %d", startPos, lineIndex, outSpeakerId);
// Read text until control byte
while (pos < dataSize) {
@@ -147,12 +147,37 @@ Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String
return s;
}
+
+void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>> dialogueLines, byte speakerId) {
+ int16 xBasePos = 0;
+ int16 yBasePos = 0;
+ if (speakerId == ALFRED_COLOR) {
+ if (g_engine->_alfredState.animState != ALFRED_TALKING) {
+ g_engine->_alfredState.setState(ALFRED_TALKING);
+ }
+ if (_curSprite != nullptr) {
+ _curSprite->isTalking = false;
+ }
+ // Offset X position for Alfred to avoid overlapping with his sprite
+ xBasePos = g_engine->_alfredState.x; //+ kAlfredFrameWidth / 2 - maxWidth / 2;
+ yBasePos = g_engine->_alfredState.y - kAlfredFrameHeight; // Above sprite, adjust for line
+ } else {
+ g_engine->_alfredState.setState(ALFRED_IDLE);
+ if (_curSprite != nullptr) {
+ _curSprite->isTalking = true;
+ xBasePos = _curSprite->x + _curSprite->w / 2;
+ yBasePos = _curSprite->y; // Above sprite, adjust for line
+ }
+ }
+ displayDialogue(dialogueLines, speakerId, xBasePos, yBasePos); // Default position
+}
+
/**
* Display dialogue text and wait for click to advance
* @param text The text to display
* @param speakerId The speaker ID which is used as color
*/
-void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>> dialogueLines, byte speakerId) {
+void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>> dialogueLines, byte speakerId, int xBasePos, int yBasePos) {
if (dialogueLines.empty()) {
return;
}
@@ -160,6 +185,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
// Clear any existing click state
_events->_leftMouseClicked = false;
int curPage = 0;
+
// Render loop - display text and wait for click
while (!g_engine->shouldQuit()) {
_events->pollEvent();
@@ -175,30 +201,12 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
for (int i = 0; i < textLines.size(); i++) {
maxWidth = MAX(maxWidth, g_engine->_largeFont->getStringWidth(textLines[i]));
}
- int xPos = 0;
- int yPos = 0;
- if (speakerId == ALFRED_COLOR) {
- if (g_engine->_alfredState.animState != ALFRED_TALKING) {
- g_engine->_alfredState.setState(ALFRED_TALKING);
- }
- if (_curSprite != nullptr) {
- _curSprite->isTalking = false;
- }
- // Offset X position for Alfred to avoid overlapping with his sprite
- xPos = g_engine->_alfredState.x - maxWidth / 2; //+ kAlfredFrameWidth / 2 - maxWidth / 2;
- yPos = g_engine->_alfredState.y - kAlfredFrameHeight - height; // Above sprite, adjust for line
- } else {
- g_engine->_alfredState.setState(ALFRED_IDLE);
- _curSprite->isTalking = true;
- xPos = _curSprite->x + _curSprite->w / 2 - maxWidth / 2;
- yPos = _curSprite->y - height; // Above sprite, adjust for line
- }
+ int xPos = xBasePos - maxWidth / 2;
+ int yPos = yBasePos - height;
Graphics::Surface s = getDialogueSurface(textLines, speakerId);
-
-
// Clamp to screen bounds
xPos = CLIP(xPos, 0, 640 - maxWidth);
yPos = CLIP(yPos, 0, 400 - s.getRect().height());
@@ -356,7 +364,7 @@ void DialogManager::setCurSprite(int index) {
for (uint i = 0; i < g_engine->_room->_currentRoomAnims.size(); i++) {
Sprite *sprite = &g_engine->_room->_currentRoomAnims[i];
- if (sprite->index == index) {
+ if (sprite->index == index && (sprite->actionFlags & 16)) {
_curSprite = sprite;
return;
}
@@ -381,8 +389,8 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// Find the speaker tree for this NPC; they are marked by 0xFE 0xXX where XX is NPC index + 1
bool speakerTreeOffsetFound = false;
int currentConversationTree = npcIndex + 1;
- while(position < dataSize && !speakerTreeOffsetFound) {
- if(conversationData[position] == CTRL_ALT_SPEAKER_ROOT && conversationData[position + 1] == currentConversationTree) {
+ while (position < dataSize && !speakerTreeOffsetFound) {
+ if (conversationData[position] == CTRL_ALT_SPEAKER_ROOT && conversationData[position + 1] == currentConversationTree) {
speakerTreeOffsetFound = true;
position += 2; // Move past the speaker tree marker and npc index
} else {
@@ -391,10 +399,10 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
// Right after the speaker conversation tree, we are in branch 0
int currentRoot = 0;
- while(g_engine->_state->getRootDisabledState(g_engine->_room->_currentRoomNumber, currentRoot)) {
+ while (g_engine->_state->getRootDisabledState(g_engine->_room->_currentRoomNumber, currentRoot)) {
// This root is disabled, skip to next
- while(position < dataSize) {
- if(conversationData[position] == CTRL_END_BRANCH) {
+ while (position < dataSize) {
+ if (conversationData[position] == CTRL_END_BRANCH) {
position++; // Move past end branch marker
currentRoot++;
break;
@@ -453,14 +461,13 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
break;
}
- if(controlByte == CTRL_ACTION_TRIGGER) {
+ if (controlByte == CTRL_ACTION_TRIGGER) {
uint16 actionCode = conversationData[position + 1] | (conversationData[position + 2] << 8);
debug("Action trigger %d encountered!", actionCode);
g_engine->dialogActionTrigger(
actionCode,
g_engine->_room->_currentRoomNumber,
- currentRoot
- );
+ currentRoot);
break;
}
@@ -620,6 +627,23 @@ void DialogManager::say(Common::StringArray texts) {
}
}
+void DialogManager::say(Common::StringArray texts, int16 x, int16 y) {
+ if (texts.empty()) {
+ return;
+ }
+ byte speakerId;
+ bool wasProcessed = processColorAndTrim(texts, speakerId);
+
+ if (wasProcessed) {
+ // Create a temporary sprite at the specified position
+ Common::Array<Common::StringArray> textLines = wordWrap(texts);
+ displayDialogue(textLines, speakerId, x, y);
+ } else {
+ sayAlfred(texts);
+ }
+
+}
+
bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speakerId) {
int speakerMarker = lines[0][0];
speakerId = lines[0][1];
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 66a34b94c8b..b543de68855 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -71,6 +71,7 @@ private:
// Private helper functions for conversation parsing
void displayDialogue(Common::Array<Common::Array<Common::String>> dialogueLines, byte speakerId);
+ void displayDialogue(Common::Array<Common::Array<Common::String>> dialogueLines, byte speakerId, int xBasePos, int yBasePos);
void displayDialogue(Common::String text, byte speakerId);
uint32 readTextBlock(const byte *data, uint32 dataSize, uint32 startPos, Common::String &outText, byte &outSpeakerId);
uint32 parseChoices(const byte *data, uint32 dataSize, uint32 startPos, Common::Array<ChoiceOption> *outChoices);
@@ -87,6 +88,7 @@ public:
void startConversation(const byte *conversationData, uint32 dataSize, byte npcIndex, Sprite *alfredAnimSet = nullptr);
void sayAlfred(Description description);
void say(Common::StringArray texts);
+ void say(Common::StringArray texts, int16 x, int16 y);
bool processColorAndTrim(Common::StringArray &lines, byte &speakerId);
Graphics::Surface getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId);
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
index 63bf81876ef..da4b41a7e87 100644
--- a/engines/pelrock/events.cpp
+++ b/engines/pelrock/events.cpp
@@ -23,6 +23,7 @@
#include "pelrock/events.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
+#include "events.h"
namespace Pelrock {
@@ -58,6 +59,7 @@ void PelrockEventManager::pollEvent() {
// case Common::EVENT_KEYUP:
// return;
case Common::EVENT_LBUTTONDOWN:
+
if (_leftMouseButton == 0) {
_clickTime = g_system->getMillis();
}
@@ -122,4 +124,5 @@ void PelrockEventManager::waitForKey() {
g_system->delayMillis(10);
}
}
+
} // namespace Pelrock
diff --git a/engines/pelrock/events.h b/engines/pelrock/events.h
index 046e38dc8ec..fe25ba04382 100644
--- a/engines/pelrock/events.h
+++ b/engines/pelrock/events.h
@@ -30,7 +30,6 @@ class PelrockEventManager {
private:
Common::Event _event;
uint32 _clickTime = 0;
-
public:
int16 _mouseX = 0;
int16 _mouseY = 0;
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 03cb71fcdab..9f14fc77506 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -123,34 +123,34 @@ enum TextIndices {
ESTAN_CERRADOS,
HOY_NO_DISPONIBLES,
YA_ABIERTO_M,
- ALREADY_CLOSED_M,
- ALREADY_OPENED_F,
- ALREADY_CLOSED_F,
- ICECREAM_CLOSED,
- IMPOOR,
- SOHOT,
- GREENBUTTON_REDBUTTON,
- ENTERCARD,
- NOMONEY_LEFT,
- STUNGAGAIN,
- WHATWASTHAT,
- WHOS_THERE,
- IMOFF,
- SHOP_CLOSED,
- SHE_WOULDNT_NOTICE,
- GOTTA_OPEN_FIRST,
- LETHISFATHER_PICKTHEM,
- BRIBEME,
- VERYGOOD,
- WHENHEASKS,
- OKAY,
- I_NEED_ID,
- WHAT_DO_I_GET_IN_RETURN,
- THATSNOTENOUGH,
- STOP,
- THATSOBVIOUSLYNOTENOUGH,
- WHATFOR,
- NOTSTONE_ICE,
+ YA_CERRADO_M,
+ YA_ABIERTA_F,
+ YA_CERRADA_F,
+ HELADERIA_CERRADA,
+ POBRE_PERO_NO_HE_LLEGADO_A_ESO,
+ QUEBUENA_ESTA,
+ BOTONVERDEPARASACAR_BOTONVERDEPARACANCELAR,
+ PRIMEROMETA_TARJETA,
+ NOTENGOMASDINERO,
+ MEHEVUELTOAPINCHAR,
+ QUEHASIDOESO,
+ QUIENANDAAHI,
+ YOMEVOY,
+ TIENDA_CERRADA,
+ NOSE_ENTERARIA,
+ PRIMERO_ABRIRLO,
+ QUELOSCOJA_SUPADRE,
+ PRETENDEUSTED_SOBORNARME,
+ MUYBIEN_1,
+ CUANDOMELOPIDA,
+ DEACUERDO,
+ NECESITODNI,
+ QUE_RECIBO_ACAMBIO,
+ ESPOCO,
+ ALTO,
+ NIPARAEMPEZAR,
+ PARAQUE,
+ DEPIEDRANO_DEHIELO,
HEY_DONTSTART,
HOTONE_MOCKING,
SHUTUP,
@@ -274,7 +274,7 @@ enum TextIndices {
OHPTHA,
LASPUERTASDELCIELO,
VAYASUENHO,
- PARAQUE,
+ PARAQUE_2,
YESO,
UNPOCODESESPERADO,
COMBINACIONESMEJORES,
@@ -297,7 +297,7 @@ enum TextIndices {
DOSINGREDIENTES,
TRESINGREDIENTES,
CUATROINGREDIENTES,
- DEACUERDO,
+ DEACUERDO_2,
GAMBERROS,
QUIENYO,
PINTA_BUENAPERSONA,
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index aee08282f69..bb8f7e68ec1 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -160,7 +160,9 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(0, ALFRED_DOWN);
+ // setScreen(0, ALFRED_DOWN);
+ setScreen(3, ALFRED_RIGHT);
+ // setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
// alfredState.y = 374;
@@ -217,10 +219,17 @@ void sortAnimsByZOrder(Common::Array<Sprite> &anims) {
}
void PelrockEngine::playSoundIfNeeded() {
-
- int soundIndex = _sound->tick(_chrono->getFrameCount());
- if (soundIndex >= 0 && soundIndex < _room->_roomSfx.size()) {
- _sound->playSound(_room->_roomSfx[3 + soundIndex]);
+ // Get ambient slot offset (0-3) or -1 if no sound this frame
+ int ambientSlotOffset = _sound->tickAmbientSound(_chrono->getFrameCount());
+ if (ambientSlotOffset >= 0) {
+ // Convert to room sound index: slots 12-15 = room indices 4-7
+ int roomSoundIndex = kAmbientSoundSlotBase + ambientSlotOffset;
+ if (roomSoundIndex < _room->_roomSfx.size()) {
+ byte soundFileIndex = _room->_roomSfx[roomSoundIndex];
+ if (soundFileIndex != 0) { // 0 = NO_SOUND.SMP (disabled)
+ _sound->playSound(soundFileIndex);
+ }
+ }
}
}
@@ -234,6 +243,15 @@ bool PelrockEngine::renderScene(int overlayMode) {
placeStickers();
updateAnimations();
+ // Some stickers need to be placed AFTER sprites, hardcoded in the original
+ if (_room->_currentRoomNumber == 3) {
+ for (int i = 0; i < _state->stickersPerRoom[3].size(); i++) {
+ if (_state->stickersPerRoom[3][i].stickerIndex == 14) {
+ placeSticker(_state->stickersPerRoom[3][i]);
+ break;
+ }
+ }
+ }
if (overlayMode == OVERLAY_CHOICES) {
_dialog->displayChoices(_dialog->_currentChoices, _compositeBuffer);
@@ -253,7 +271,7 @@ bool PelrockEngine::renderScene(int overlayMode) {
}
void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
-
+ debug("Executing action %d on hotspot %d", action, hotspot->extra);
if (action == ITEM) {
int inventoryObject = _state->selectedInventoryItem;
for (const CombinationEntry *entry = combinationTable; entry->handler != nullptr; entry++) {
@@ -389,7 +407,16 @@ void PelrockEngine::paintDebugLayer() {
for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
WalkBox box = _room->_currentRoomWalkboxes[i];
drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
- _smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
+ // _smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
+ }
+ }
+
+ bool showSprites = true;
+ if (showSprites) {
+ for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ Sprite sprite = _room->_currentRoomAnims[i];
+ drawRect(_screen, sprite.x, sprite.y, sprite.animData->w, sprite.animData->h, 14);
+ _smallFont->drawString(_screen, Common::String::format("S %d", sprite.index), sprite.x + 2, sprite.y, 640, 14);
}
}
@@ -397,11 +424,11 @@ void PelrockEngine::paintDebugLayer() {
if (showHotspots) {
for (int i = 0; i < _room->_currentRoomHotspots.size(); i++) {
HotSpot hotspot = _room->_currentRoomHotspots[i];
- if (!hotspot.isEnabled)
+ if (!hotspot.isEnabled || hotspot.isSprite)
continue;
- drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 180 + i);
- _smallFont->drawString(_screen, Common::String::format("HS %d", i), hotspot.x + 2, hotspot.y + 2, 640, 14);
- _smallFont->drawString(_screen, Common::String::format("x=%d", hotspot.extra), hotspot.x + 2, hotspot.y + 2 + 14, 640, 14);
+ drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 12);
+ _smallFont->drawString(_screen, Common::String::format("HS %d", hotspot.index - _room->_currentRoomAnims.size()), hotspot.x + 2, hotspot.y + 2, 640, 12);
+ // _smallFont->drawString(_screen, Common::String::format("x=%d", hotspot.extra), hotspot.x + 2, hotspot.y + 2 + 14, 640, 14);
}
}
@@ -427,13 +454,9 @@ void PelrockEngine::paintDebugLayer() {
}
void PelrockEngine::placeStickers() {
- for (int i = 0; i < _state->roomStickers[_room->_currentRoomNumber].size(); i++) {
- Sticker sticker = _state->roomStickers[_room->_currentRoomNumber][i];
- placeSticker(sticker);
- }
// also place temporary stickers
- for (int i = 0; i < _room->_transientStickers.size(); i++) {
- Sticker sticker = _room->_transientStickers[i];
+ for (int i = 0; i < _room->_roomStickers.size(); i++) {
+ Sticker sticker = _room->_roomStickers[i];
placeSticker(sticker);
}
}
@@ -564,7 +587,7 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
}
void PelrockEngine::lookAt(HotSpot *hotspot) {
- debug("Looking at hotspot %d with extra %d", hotspot->index, hotspot->extra);
+ debug("Looking at hotspot %d (%d) with extra %d", hotspot->index, hotspot->isSprite? hotspot->index : hotspot->index - _room->_currentRoomAnims.size(), hotspot->extra);
_dialog->sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index]);
_actionPopupState.isActive = false;
}
@@ -628,7 +651,8 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
Exit *exit = isExitUnder(_alfredState.x, _alfredState.y);
- if (exit != nullptr && exit->isEnabled) {
+ if (exit != nullptr /*&& exit->isEnabled*/) {
+ debug("Using exit to room %d", exit->targetRoom);
_alfredState.x = exit->targetX;
_alfredState.y = exit->targetY;
setScreen(exit->targetRoom, exit->dir);
@@ -1049,7 +1073,9 @@ int PelrockEngine::isHotspotUnder(int x, int y) {
x >= hotspot.x && x <= (hotspot.x + hotspot.w) &&
y >= hotspot.y && y <= (hotspot.y + hotspot.h)) {
// Check against sprite frame
- if (hotspot.isSprite) {
+ if (!hotspot.isSprite) {
+ return hotspot.index;
+ } else {
Sprite *sprite = nullptr;
for (size_t j = 0; j < _room->_currentRoomAnims.size(); j++) {
if (_room->_currentRoomAnims[j].index == hotspot.index) {
@@ -1058,10 +1084,10 @@ int PelrockEngine::isHotspotUnder(int x, int y) {
}
}
bool spriteUnder = isSpriteUnder(sprite, x, y);
- return spriteUnder ? i : -1;
+ if(spriteUnder)
+ return i;
+ else continue;
}
-
- return hotspot.index;
}
}
return -1;
@@ -1110,7 +1136,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
bool itemUnder = isItemUnder(_events->_mouseX, _events->_mouseY);
- if (_state->selectedInventoryItem != -1) {
+ if (_state->selectedInventoryItem >= 0 && !_state->inventoryItems.empty()) {
if (itemUnder && shouldBlink) {
return;
}
@@ -1366,7 +1392,7 @@ void PelrockEngine::checkMouseHover() {
}
}
-void PelrockEngine::setScreen(int number, AlfredDirection dir) {
+void PelrockEngine::setScreen(int roomNumber, AlfredDirection dir) {
Common::File roomFile;
if (!roomFile.open(Common::Path("ALFRED.1"))) {
@@ -1378,7 +1404,7 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
_alfredState.direction = dir;
_alfredState.setState(ALFRED_IDLE);
_currentStep = 0;
- int roomOffset = number * kRoomStructSize;
+ int roomOffset = roomNumber * kRoomStructSize;
_alfredState.curFrame = 0;
byte *palette = new byte[256 * 3];
@@ -1395,16 +1421,25 @@ void PelrockEngine::setScreen(int number, AlfredDirection dir) {
copyBackgroundToBuffer();
g_system->getPaletteManager()->setPalette(palette, 0, 256);
- _room->loadRoomMetadata(&roomFile, number);
- _room->loadRoomTalkingAnimations(number);
+ _room->loadRoomMetadata(&roomFile, roomNumber);
+ _room->loadRoomTalkingAnimations(roomNumber);
if (_room->_musicTrack > 0)
_sound->playMusicTrack(_room->_musicTrack);
else {
_sound->stopMusic();
}
- doExtraActions(number);
+
+ if (findWalkboxForPoint(_room->_currentRoomWalkboxes, _alfredState.x, _alfredState.y) == 0xFF) {
+ const WalkBox w = _room->_currentRoomWalkboxes[0];
+ _alfredState.x = w.x;
+ _alfredState.y = w.y;
+ }
+
_screen->markAllDirty();
_screen->update();
+
+
+ doExtraActions(roomNumber);
roomFile.close();
delete[] background;
delete[] palette;
@@ -1444,6 +1479,13 @@ void PelrockEngine::doExtraActions(int roomNumber) {
loadExtraScreenAndPresent(4);
}
break;
+ case 15:
+ if(_state->flagIsSet(FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ)) {
+ _state->setFlag(FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ, false);
+ _dialog->say(_res->_ingameTexts[GAMBERROS]);
+ _dialog->say(_res->_ingameTexts[QUIENYO]);
+ _dialog->say(_res->_ingameTexts[PINTA_BUENAPERSONA]);
+ }
default:
break;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 4e0eeb9f5a5..7b0a8452448 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -244,6 +244,9 @@ public:
void openKitchenDrawer(HotSpot *hotspot);
void openKitchenDoorFromInside(HotSpot *hotspot);
void useSpicySauceWithBurger(int inventoryObject, HotSpot *hotspot);
+ void openShopDoor(HotSpot *hotspot);
+ void closeShopDoor(HotSpot *hotspot);
+ void openLamppost(HotSpot *hotspot);
void openDoor(HotSpot *hotspot, int doorIndex, int sticker, bool masculine, bool stayClosed);
void closeDoor(HotSpot *hotspot, int doorIndex, int sticker, bool masculine, bool stayOpen);
void pickUpPhoto(HotSpot *hotspot);
@@ -253,6 +256,7 @@ public:
void noOpItem(int item, HotSpot *hotspot);
void useOnAlfred(int inventoryObject);
void useCardWithATM(int inventoryObject, HotSpot *hotspot);
+ void useBrickWithWindow(int inventoryObject, HotSpot *hotspot);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
};
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index f858fac530c..5211fea94d8 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -90,45 +90,49 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
void RoomManager::addSticker(int stickerId, bool persist) {
Sticker sticker = g_engine->_res->getSticker(stickerId);
+ _roomStickers.push_back(sticker);
if (persist)
- g_engine->_state->roomStickers[_currentRoomNumber].push_back(sticker);
- else
- _transientStickers.push_back(sticker);
+ g_engine->_state->stickersPerRoom[_currentRoomNumber].push_back(sticker);
+}
+
+void RoomManager::onlyPersistSticker(byte room, int stickerId) {
+ Sticker sticker = g_engine->_res->getSticker(stickerId);
+ g_engine->_state->stickersPerRoom[room].push_back(sticker);
}
void RoomManager::removeSticker(int stickerIndex) {
int index = -1;
if (index == -1) {
- for (int i = 0; i < _transientStickers.size(); i++) {
- if (_transientStickers[i].stickerIndex == stickerIndex) {
+ for (int i = 0; i < _roomStickers.size(); i++) {
+ if (_roomStickers[i].stickerIndex == stickerIndex) {
index = i;
- _transientStickers.remove_at(index);
+ _roomStickers.remove_at(index);
return;
}
}
}
- for (int i = 0; i < g_engine->_state->roomStickers[_currentRoomNumber].size(); i++) {
- if (g_engine->_state->roomStickers[_currentRoomNumber][i].stickerIndex == stickerIndex) {
+ for (int i = 0; i < g_engine->_state->stickersPerRoom[_currentRoomNumber].size(); i++) {
+ if (g_engine->_state->stickersPerRoom[_currentRoomNumber][i].stickerIndex == stickerIndex) {
index = i;
- g_engine->_state->roomStickers[_currentRoomNumber].remove_at(index);
+ g_engine->_state->stickersPerRoom[_currentRoomNumber].remove_at(index);
break;
}
}
- if (index != -1 && index < g_engine->_state->roomStickers[_currentRoomNumber].size())
- g_engine->_state->roomStickers[_currentRoomNumber].remove_at(index);
+ if (index != -1 && index < g_engine->_state->stickersPerRoom[_currentRoomNumber].size())
+ g_engine->_state->stickersPerRoom[_currentRoomNumber].remove_at(index);
}
bool RoomManager::hasSticker(int index) {
- for (int i = 0; i < g_engine->_state->roomStickers[_currentRoomNumber].size(); i++) {
- if (g_engine->_state->roomStickers[_currentRoomNumber][i].stickerIndex == index) {
+ for (int i = 0; i < g_engine->_state->stickersPerRoom[_currentRoomNumber].size(); i++) {
+ if (g_engine->_state->stickersPerRoom[_currentRoomNumber][i].stickerIndex == index) {
return true;
}
}
- for (int i = 0; i < _transientStickers.size(); i++) {
- if (_transientStickers[i].stickerIndex == index) {
+ for (int i = 0; i < _roomStickers.size(); i++) {
+ if (_roomStickers[i].stickerIndex == index) {
return true;
}
}
@@ -166,7 +170,7 @@ void RoomManager::disableSprite(int roomNumber, int spriteIndex, bool persist) {
}
void RoomManager::enableSprite(int spriteIndex, int zOrder, bool persist) {
- // _currentRoomAnims[spriteIndex].zOrder = zOrder;
+ _currentRoomAnims[spriteIndex].zOrder = zOrder;
}
void RoomManager::enableHotspot(HotSpot *hotspot, bool persist) {
@@ -187,6 +191,24 @@ void RoomManager::addWalkbox(WalkBox walkbox) {
g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
}
+Sprite *RoomManager::findSpriteByIndex(byte index) {
+ for (int i = 0; i < _currentRoomAnims.size(); i++) {
+ if (_currentRoomAnims[i].index == index) {
+ return &_currentRoomAnims[i];
+ }
+ }
+ return nullptr;
+}
+
+HotSpot *RoomManager::findHotspotByIndex(byte index) {
+ for (int i = 0; i < _currentRoomHotspots.size(); i++) {
+ if (!_currentRoomHotspots[i].isSprite && _currentRoomHotspots[i].innerIndex == index) {
+ return &_currentRoomHotspots[i];
+ }
+ }
+ return nullptr;
+}
+
HotSpot *RoomManager::findHotspotByExtra(uint16 extra) {
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
if (_currentRoomHotspots[i].extra == extra) {
@@ -360,7 +382,7 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
spot.h = data[hotspotOffset + 6];
spot.isSprite = false;
spot.extra = READ_LE_INT16(data + hotspotOffset + 7);
- debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d, isEnabled=%d", spot.innerIndex, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra, spot.isEnabled);
+ // debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d, isEnabled=%d", spot.innerIndex, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra, spot.isEnabled);
hotspots.push_back(spot);
}
@@ -399,7 +421,7 @@ void RoomManager::resetConversationStates(byte roomNumber, byte *conversationDat
void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
uint32_t outPos = 0;
- _transientStickers.clear();
+ _roomStickers.clear();
_currentRoomNumber = roomNumber;
int roomOffset = roomNumber * kRoomStructSize;
@@ -435,7 +457,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
_currentRoomExits = loadExits(pair10, pair10size);
_currentRoomWalkboxes = loadWalkboxes(pair10, pair10size);
_scaleParams = loadScalingParams(pair10, pair10size);
-
+ _roomStickers = g_engine->_state->stickersPerRoom[roomNumber];
// Pair 11 is the palette, already loaded
// Pair 12 - Room Texts
@@ -570,7 +592,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
break;
}
sprite.animData = new Anim[sprite.numAnims];
- // debug("AnimSet %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, animSet.numAnims, animSet.spriteType, animSet.actionFlags, animSet.isDisabled);
+ // debug("Sprite %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, sprite.numAnims, sprite.spriteType, sprite.actionFlags, sprite.isHotspotDisabled);
int subAnimOffset = animOffset + 10;
for (int j = 0; j < sprite.numAnims; j++) {
@@ -696,11 +718,16 @@ uint32 RoomManager::loadDescriptions(byte *pair12data, size_t pair12size, Common
}
pos++;
}
+ // Hardcoded fix in the original!
+ if(_currentRoomNumber == 3 && description.text.size() == 1 && description.text[0] == 0x2D) {
+ outDescriptions.push_back(description);
+ }
outDescriptions.push_back(description);
lastDescPos = pos;
}
pos++;
}
+
return lastDescPos + 1;
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index cd0354871e4..7f5d18184cc 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -43,6 +43,7 @@ public:
/** Methods to modify room data at runtime **/
void addSticker(int stickerId, bool persist = true);
+ void onlyPersistSticker(byte room, int stickerId);
void removeSticker(int index);
bool hasSticker(int index);
void changeExit(int index, bool enabled, bool persist = true);
@@ -62,6 +63,8 @@ public:
void applyDisabledChoice(ResetEntry entry, byte *conversationData, size_t conversationDataSize);
void addDisabledChoice(ChoiceOption choice);
+ Sprite *findSpriteByIndex(byte index);
+ HotSpot *findHotspotByIndex(byte index);
HotSpot *findHotspotByExtra(uint16 extra);
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
@@ -89,7 +92,7 @@ public:
PaletteAnim *_currentPaletteAnim = nullptr;
byte *_conversationData = nullptr;
size_t _conversationDataSize = 0;
- Common::Array<Sticker> _transientStickers;
+ Common::Array<Sticker> _roomStickers;
uint32 _conversationOffset;
private:
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index 4f92d03b297..51066a03da5 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -122,7 +122,7 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
s.syncAsUint32LE((uint32 &)gameState->stateGame);
// Flags
- for (int i = 0; i < 46; ++i) {
+ for (int i = 0; i < kNumGameFlags; ++i) {
s.syncAsByte((byte &)gameState->flags[i]);
}
// Inventory items
@@ -138,10 +138,10 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
s.syncAsSint16LE(gameState->selectedInventoryItem);
// Room stickers
- uint16 stickersSize = (uint16)gameState->roomStickers.size();
+ uint16 stickersSize = (uint16)gameState->stickersPerRoom.size();
s.syncAsUint16LE(stickersSize);
if (s.isSaving()) {
- for (const auto &pair : gameState->roomStickers) {
+ for (const auto &pair : gameState->stickersPerRoom) {
byte roomNumber = pair._key;
s.syncAsByte(roomNumber);
const Common::Array<Sticker> &stickers = pair._value;
@@ -153,7 +153,7 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
}
}
} else {
- gameState->roomStickers.clear();
+ gameState->stickersPerRoom.clear();
for (uint16 idx = 0; idx < stickersSize; ++idx) {
byte roomNumber;
s.syncAsByte(roomNumber);
@@ -165,7 +165,7 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
s.syncAsSint32LE(stickerIndex);
stickers.push_back(g_engine->_res->getSticker(stickerIndex));
}
- gameState->roomStickers[roomNumber] = stickers;
+ gameState->stickersPerRoom[roomNumber] = stickers;
}
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 4970659abec..9714e9ae6ad 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -432,9 +432,12 @@ struct ResetEntry {
#define FLAG_FROM_INTRO 43
#define FLAG_HE_TIRADO_PIEDRA 44
#define FLAG_HA_USADO_AGUA 45
+#define FLAG_TIENDA_ABIERTA 46
+
+const int kNumGameFlags = 47;
struct GameStateData {
- bool flags[46];
+ bool flags[kNumGameFlags];
byte NUMERO_DE_COPAS = false;
byte INGREDIENTES_CONSEGUIDOS = 0;
@@ -442,9 +445,9 @@ struct GameStateData {
GameState stateGame = INTRO;
Common::Array<byte> inventoryItems;
- int16 selectedInventoryItem = -1;
+ int16 selectedInventoryItem = 0;
- Common::HashMap<byte, Common::Array<Sticker>> roomStickers;
+ Common::HashMap<byte, Common::Array<Sticker>> stickersPerRoom;
// Common::HashMap<byte, ResetEntry> roomExitChanges;
Common::HashMap<byte, Common::Array<ExitChange>> roomExitChanges;
Common::HashMap<byte, Common::Array<WalkBoxChange>> roomWalkBoxChanges;
@@ -454,6 +457,7 @@ struct GameStateData {
GameStateData() {
memset(conversationRootsState, 0, 4 * 56);
+ flags[FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ] = true;
}
~GameStateData() {
@@ -481,7 +485,7 @@ struct GameStateData {
inventoryItems.push_back(id);
}
- void removeInventoyItem(int id) {
+ void removeInventoryItem(int id) {
for (int i = 0; i < inventoryItems.size(); i++) {
if (inventoryItems[i] == id) {
inventoryItems.remove_at(i);
Commit: b3e454c6ff98d176a0182a3af67da23507d2dfc8
https://github.com/scummvm/scummvm/commit/b3e454c6ff98d176a0182a3af67da23507d2dfc8
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:48+02:00
Commit Message:
PELROCK: Implements Room 15
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/pathfinding.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index aeb70e48c20..cbcf6042c0c 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -61,6 +61,21 @@ const ActionEntry actionTable[] = {
{290, OPEN, &PelrockEngine::openShopDoor},
{290, CLOSE, &PelrockEngine::closeShopDoor},
{32, OPEN, &PelrockEngine::openLamppost},
+ {308, PICKUP, &PelrockEngine::moveCable}, // Lamppost cable
+
+ // Room 15
+ {65, PICKUP, &PelrockEngine::pickGuitar},
+ {66, PICKUP, &PelrockEngine::pickFish},
+ {67, PICKUP, &PelrockEngine::pickTeddyBear},
+ {68, PICKUP, &PelrockEngine::pickDiscs},
+ {69, PICKUP, &PelrockEngine::pickMonkeyBrain},
+ {70, PICKUP, &PelrockEngine::pickBooks},
+ {71, PICKUP, &PelrockEngine::pickPalette},
+ {72, PICKUP, &PelrockEngine::pickCandy},
+ {73, PICKUP, &PelrockEngine::pickConch},
+ {74, PICKUP, &PelrockEngine::pickHat},
+ {6, PICKUP, &PelrockEngine::pickCord},
+ {7, PICKUP, &PelrockEngine::pickAmulet},
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
@@ -79,6 +94,7 @@ const CombinationEntry combinationTable[] = {
{2, 281, &PelrockEngine::useCardWithATM}, // Use ATM Card with ATM
{62, 117, &PelrockEngine::useSpicySauceWithBurger}, // Use Spicy Sauce with Burger
{4, 294, &PelrockEngine::useBrickWithWindow}, // Use Brick with Window (Room 3)
+ {4, 295, &PelrockEngine::useBrickWithShopWindow},
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -211,18 +227,10 @@ void PelrockEngine::closeShopDoor(HotSpot *hotspot) {
void PelrockEngine::openLamppost(HotSpot *hotspot) {
debug("Opening lamppost");
_room->addSticker(14);
+ _room->moveHotspot(_room->findHotspotByExtra(308), 519, 363);
}
void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
- debug("Using brick with window - sticker 11 will be added");
-
- // Check if window is already broken
- if (_room->hasSticker(11)) {
- // Window already broken, say something generic
- _alfredState.direction = ALFRED_UP;
- _dialog->say(_res->_ingameTexts[YA_ABIERTO_M]); // "It's already open/broken"
- return;
- }
// TODO: Play Alfred's throwing animation
// This would require adding a new special animation entry
@@ -259,7 +267,7 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
// Remove brick from inventory
_state->removeInventoryItem(4);
- int16 x = 639; // put at the very edge of the screen
+ int16 x = 639; // put at the very edge of the screen so it gets adjusted
int16 y = windowHotspot->y;
// Play the NPC dialog sequence
int16 dialog1y = y + 22;
@@ -276,6 +284,66 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
walkTo(639, _alfredState.y);
}
+void PelrockEngine::moveCable(HotSpot *hotspot) {
+ _room->addSticker(15);
+ _room->addSticker(16);
+ _room->addSticker(17);
+ _room->addStickerToRoom(4, 20); // Room 4, sticker 20
+ _state->setFlag(FLAG_CABLES_PUESTOS, true);
+}
+
+void PelrockEngine::useBrickWithShopWindow(int inventoryObject, HotSpot *hotspot) {
+ _dialog->say(_res->_ingameTexts[NOSE_ENTERARIA]);
+}
+
+void PelrockEngine::pickGuitar(HotSpot *hotspot) {
+ buyFromStore(hotspot, 38);
+}
+
+void PelrockEngine::pickFish(HotSpot *hotspot) {
+ buyFromStore(hotspot, 39);
+}
+
+void PelrockEngine::pickTeddyBear(HotSpot *hotspot) {
+ buyFromStore(hotspot, 40);
+}
+
+void PelrockEngine::pickDiscs(HotSpot *hotspot) {
+ buyFromStore(hotspot, 41);
+}
+
+void PelrockEngine::pickMonkeyBrain(HotSpot *hotspot) {
+ buyFromStore(hotspot, 42);
+}
+
+void PelrockEngine::pickBooks(HotSpot *hotspot) {
+ buyFromStore(hotspot, 43);
+}
+
+void PelrockEngine::pickPalette(HotSpot *hotspot) {
+ buyFromStore(hotspot, 44);
+}
+
+void PelrockEngine::pickCandy(HotSpot *hotspot) {
+ buyFromStore(hotspot, 45);
+}
+
+void PelrockEngine::pickConch(HotSpot *hotspot) {
+ buyFromStore(hotspot, 46);
+}
+
+void PelrockEngine::pickHat(HotSpot *hotspot) {
+ buyFromStore(hotspot, 47);
+}
+
+void PelrockEngine::pickCord(HotSpot *hotspot) {
+ buyFromStore(hotspot, 48);
+}
+
+void PelrockEngine::pickAmulet(HotSpot *hotspot) {
+ buyFromStore(hotspot, 49);
+}
+
void PelrockEngine::openDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayClosed) {
if (_room->hasSticker(sticker)) {
int text = masculine == MASCULINE ? YA_ABIERTO_M : YA_ABIERTA_F;
@@ -284,6 +352,7 @@ void PelrockEngine::openDoor(HotSpot *hotspot, int exitIndex, int sticker, bool
}
_room->enableExit(exitIndex, !stayClosed);
_room->addSticker(sticker, !stayClosed);
+ _sound->playSound(_room->_roomSfx[0]);
}
void PelrockEngine::closeDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayOpen) {
@@ -294,6 +363,7 @@ void PelrockEngine::closeDoor(HotSpot *hotspot, int exitIndex, int sticker, bool
}
_room->disableExit(exitIndex, !stayOpen);
_room->removeSticker(sticker);
+ _sound->playSound(_room->_roomSfx[1]);
}
void PelrockEngine::addInventoryItem(int item) {
@@ -315,6 +385,27 @@ void PelrockEngine::addInventoryItem(int item) {
_state->addInventoryItem(item);
}
+void PelrockEngine::buyFromStore(HotSpot *hotspot, int stickerId) {
+ if(_state->hasInventoryItem(5) == false)
+ {
+ _dialog->say(_res->_ingameTexts[NOTENGODINERO]);
+ return;
+ }
+ else {
+ _room->addSticker(stickerId);
+ _room->disableHotspot(hotspot);
+ _state->addInventoryItem(hotspot->extra);
+ _currentHotspot = nullptr;
+ walkLoop(224, 283, ALFRED_LEFT);
+ _dialog->say(_res->_ingameTexts[CUESTA1000]);
+ _dialog->say(_res->_ingameTexts[AQUITIENE]);
+ _dialog->say(_res->_ingameTexts[MUYBIEN]);
+ _state->removeInventoryItem(5); // Remove 1000 pesetas bill
+ }
+}
+
+
+
void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex) {
if (actionTrigger == 328) {
debug("Disabling root %d in room %d", rootIndex, room);
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 9f14fc77506..85268139a93 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -297,6 +297,7 @@ enum TextIndices {
DOSINGREDIENTES,
TRESINGREDIENTES,
CUATROINGREDIENTES,
+ LIBRO_ABURRIDO,
DEACUERDO_2,
GAMBERROS,
QUIENYO,
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
index a89d9cee7ad..d141bb3af21 100644
--- a/engines/pelrock/pathfinding.cpp
+++ b/engines/pelrock/pathfinding.cpp
@@ -64,12 +64,12 @@ bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<
Common::Point target = calculateWalkTarget(walkboxes, targetX, targetY, 2, nullptr);
targetX = target.x;
targetY = target.y;
- debug("Startx= %d, starty= %d, destx= %d, desty= %d", startX, startY, targetX, targetY);
+ // debug("Startx= %d, starty= %d, destx= %d, desty= %d", startX, startY, targetX, targetY);
uint8_t startBox = findWalkboxForPoint(walkboxes, startX, startY);
uint8_t destBox = findWalkboxForPoint(walkboxes, targetX, targetY);
- debug("Pathfinding from (%d, %d) in box %d to (%d, %d) in box %d\n", startX, startY, startBox, targetX, targetY, destBox);
+ // debug("Pathfinding from (%d, %d) in box %d to (%d, %d) in box %d\n", startX, startY, startBox, targetX, targetY, destBox);
// Check if both points are in valid walkboxes
if (startBox == 0xFF || destBox == 0xFF) {
debug("Error: Start or destination not in any walkbox\n");
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index bb8f7e68ec1..0193577b6f6 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -161,7 +161,7 @@ void PelrockEngine::init() {
gameInitialized = true;
loadAnims();
// setScreen(0, ALFRED_DOWN);
- setScreen(3, ALFRED_RIGHT);
+ setScreen(15, ALFRED_RIGHT);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -237,7 +237,7 @@ bool PelrockEngine::renderScene(int overlayMode) {
_chrono->updateChrono();
if (_chrono->_gameTick) {
- playSoundIfNeeded();
+ // playSoundIfNeeded();
copyBackgroundToBuffer();
@@ -427,7 +427,7 @@ void PelrockEngine::paintDebugLayer() {
if (!hotspot.isEnabled || hotspot.isSprite)
continue;
drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 12);
- _smallFont->drawString(_screen, Common::String::format("HS %d", hotspot.index - _room->_currentRoomAnims.size()), hotspot.x + 2, hotspot.y + 2, 640, 12);
+ _smallFont->drawString(_screen, Common::String::format("HS %d - %d", hotspot.index - _room->_currentRoomAnims.size(), hotspot.extra), hotspot.x + 2, hotspot.y + 2, 640, 12);
// _smallFont->drawString(_screen, Common::String::format("x=%d", hotspot.extra), hotspot.x + 2, hotspot.y + 2 + 14, 640, 14);
}
}
@@ -562,7 +562,9 @@ void PelrockEngine::doAction(VerbIcon action, HotSpot *hotspot) {
break;
case PICKUP:
_alfredState.setState(ALFRED_INTERACTING);
- pickUpAndDisable(hotspot);
+ if(_room->isPickableByExtra(hotspot->extra)) {
+ pickUpAndDisable(hotspot);
+ }
executeAction(PICKUP, hotspot);
break;
case OPEN:
@@ -633,6 +635,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_currentStep++;
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
+ debug("Finished walking to target");
_alfredState.setState(ALFRED_IDLE);
if (_currentHotspot != nullptr)
@@ -640,8 +643,8 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
drawAlfred(_res->alfredIdle[_alfredState.direction]);
if (_queuedAction.isQueued) {
- doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
_queuedAction.isQueued = false;
+ doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
break;
}
}
@@ -931,10 +934,13 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
_actionPopupState.isActive = true;
_actionPopupState.curFrame = 0;
- _actionPopupState.isAlfredUnder = alfredUnder;
if (hotspotIndex != -1) {
_currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
}
+ else {
+ _actionPopupState.isAlfredUnder = alfredUnder;
+ _currentHotspot = nullptr;
+ }
}
}
@@ -1220,6 +1226,19 @@ void PelrockEngine::extraScreenLoop() {
_extraScreen = nullptr;
}
+void PelrockEngine::walkLoop(int16 x, int16 y, AlfredDirection direction) {
+
+ _alfredState.direction = direction;
+ walkTo(x, y);
+ while(!shouldQuit() && _alfredState.animState == ALFRED_WALKING) {
+ _events->pollEvent();
+ renderScene();
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+ debug("Walk loop ended");
+}
+
void PelrockEngine::walkTo(int x, int y) {
_currentStep = 0;
PathContext context = {nullptr, nullptr, nullptr, 0, 0, 0};
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 7b0a8452448..8350fb76227 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -111,6 +111,7 @@ private:
void gameLoop();
void extraScreenLoop();
+ void walkLoop(int16 x, int16 y, AlfredDirection direction);
void checkMouseHover();
void checkMouseClick(int x, int y);
@@ -226,6 +227,7 @@ public:
bool renderScene(int overlayMode = OVERLAY_NONE);
void addInventoryItem(int item);
+ void buyFromStore(HotSpot *hotspot, int stickerId);
// Actions
void performActionTrigger(uint16 actionTrigger);
void dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex);
@@ -257,6 +259,20 @@ public:
void useOnAlfred(int inventoryObject);
void useCardWithATM(int inventoryObject, HotSpot *hotspot);
void useBrickWithWindow(int inventoryObject, HotSpot *hotspot);
+ void moveCable(HotSpot *hotspot);
+ void useBrickWithShopWindow(int inventoryObject, HotSpot *hotspot);
+ void pickGuitar(HotSpot *hotspot);
+ void pickFish(HotSpot *hotspot);
+ void pickTeddyBear(HotSpot *hotspot);
+ void pickDiscs(HotSpot *hotspot);
+ void pickMonkeyBrain(HotSpot *hotspot);
+ void pickBooks(HotSpot *hotspot);
+ void pickPalette(HotSpot *hotspot);
+ void pickCandy(HotSpot *hotspot);
+ void pickConch(HotSpot *hotspot);
+ void pickHat(HotSpot *hotspot);
+ void pickCord(HotSpot *hotspot);
+ void pickAmulet(HotSpot *hotspot);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
};
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 5211fea94d8..04d86740812 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -91,8 +91,12 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
void RoomManager::addSticker(int stickerId, bool persist) {
Sticker sticker = g_engine->_res->getSticker(stickerId);
_roomStickers.push_back(sticker);
- if (persist)
- g_engine->_state->stickersPerRoom[_currentRoomNumber].push_back(sticker);
+ addStickerToRoom(_currentRoomNumber, stickerId);
+}
+
+void RoomManager::addStickerToRoom(byte room, int stickerId) {
+ Sticker sticker = g_engine->_res->getSticker(stickerId);
+ g_engine->_state->stickersPerRoom[room].push_back(sticker);
}
void RoomManager::onlyPersistSticker(byte room, int stickerId) {
@@ -162,7 +166,7 @@ void RoomManager::changeHotSpot(HotSpot hotspot) {
g_engine->_state->roomHotSpotChanges[_currentRoomNumber].push_back({_currentRoomNumber, hotspot.innerIndex, hotspot});
}
-void RoomManager::disableSprite(int roomNumber, int spriteIndex, bool persist) {
+void RoomManager::disableSprite(byte roomNumber, int spriteIndex, bool persist) {
if (roomNumber == _currentRoomNumber) {
_currentRoomAnims[spriteIndex].zOrder = 255;
}
@@ -187,6 +191,14 @@ void RoomManager::disableHotspot(HotSpot *hotspot, bool persist) {
}
}
+void RoomManager::moveHotspot(HotSpot *hotspot, int16 newX, int16 newY, bool persist) {
+ hotspot->x = newX;
+ hotspot->y = newY;
+ if (persist) {
+ changeHotSpot(*hotspot);
+ }
+}
+
void RoomManager::addWalkbox(WalkBox walkbox) {
g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
}
@@ -382,7 +394,7 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
spot.h = data[hotspotOffset + 6];
spot.isSprite = false;
spot.extra = READ_LE_INT16(data + hotspotOffset + 7);
- // debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d, isEnabled=%d", spot.innerIndex, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra, spot.isEnabled);
+ debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d, isEnabled=%d", spot.innerIndex, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra, spot.isEnabled);
hotspots.push_back(spot);
}
@@ -744,7 +756,7 @@ void RoomManager::loadConversationData(byte *pair12data, size_t pair12size, uint
}
}
-void RoomManager::applyDisabledChoices(int roomNumber, byte *conversationData, size_t conversationDataSize) {
+void RoomManager::applyDisabledChoices(byte roomNumber, byte *conversationData, size_t conversationDataSize) {
Common::Array<ResetEntry> disabledBranches = g_engine->_state->disabledBranches[roomNumber];
if (disabledBranches.size() == 0) {
return;
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 7f5d18184cc..eb624d32b35 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -30,6 +30,21 @@
namespace Pelrock {
static const int kNumSfxPerRoom = 8;
+static const int unpickableHotspotExtras[] = {
+ 308, // lamppost cable
+ 65, // objects in shop
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 6,
+ 7
+};
class RoomManager {
public:
@@ -43,26 +58,46 @@ public:
/** Methods to modify room data at runtime **/
void addSticker(int stickerId, bool persist = true);
+ void addStickerToRoom(byte room, int stickerId);
void onlyPersistSticker(byte room, int stickerId);
void removeSticker(int index);
+ void removeSticker(byte room, int index);
bool hasSticker(int index);
+ bool hasSticker(byte room, int index);
void changeExit(int index, bool enabled, bool persist = true);
+ void changeExit(byte room, int index, bool enabled, bool persist = true);
void disableExit(int index, bool persist = true);
+ void disableExit(byte room, int index, bool persist = true);
void enableExit(int index, bool persist = true);
+ void enableExit(byte room, int index, bool persist = true);
void changeWalkBox(WalkBox walkbox);
+ void changeWalkbox(byte room, WalkBox walkbox);
void changeHotSpot(HotSpot hotspot);
- void disableSprite(int roomNumber, int spriteIndex, bool persist = true);
+ void changeHotspot(byte room, HotSpot hotspot);
+ void disableSprite(byte roomNumber, int spriteIndex, bool persist = true);
void enableSprite(int spriteIndex, int zOrder, bool persist = true);
+ void enableSprite(byte roomNumber,int spriteIndex, int zOrder, bool persist = true);
/**
* Utility function to enable or disable a hotspot, with an option to persist the change.
*/
void enableHotspot(HotSpot *hotspot, bool persist = true);
+ void enableHotspot(byte room, HotSpot *hotspot, bool persist = true);
void disableHotspot(HotSpot *hotspot, bool persist = true);
+ void disableHotspot(byte room, HotSpot *hotspot, bool persist = true);
+ void moveHotspot(HotSpot *hotspot, int16 newX, int16 newY, bool persist = true);
+ void moveHotspot(byte room, HotSpot *hotspot, int16 newX, int16 newY, bool persist = true);
void addWalkbox(WalkBox walkbox);
- void applyDisabledChoices(int roomNumber, byte *conversationData, size_t conversationDataSize);
+ void addWalkbox(byte room, WalkBox walkbox);
+ void applyDisabledChoices(byte roomNumber, byte *conversationData, size_t conversationDataSize);
void applyDisabledChoice(ResetEntry entry, byte *conversationData, size_t conversationDataSize);
void addDisabledChoice(ChoiceOption choice);
-
+ bool isPickableByExtra(uint16 extra) {
+ for(int i = 0; i < sizeof(unpickableHotspotExtras); i++) {
+ if (extra == unpickableHotspotExtras[i])
+ return false;
+ }
+ return true;
+ }
Sprite *findSpriteByIndex(byte index);
HotSpot *findHotspotByIndex(byte index);
HotSpot *findHotspotByExtra(uint16 extra);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 9714e9ae6ad..a307e46697e 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -470,13 +470,13 @@ struct GameStateData {
}
bool flagIsSet(int flagIndex) const {
- if (flagIndex < 0 || flagIndex >= 46)
+ if (flagIndex < 0 || flagIndex >= kNumGameFlags)
return false;
return flags[flagIndex];
}
void setFlag(int flagIndex, bool value) {
- if (flagIndex < 0 || flagIndex >= 46)
+ if (flagIndex < 0 || flagIndex >= kNumGameFlags)
return;
flags[flagIndex] = value;
}
@@ -494,6 +494,15 @@ struct GameStateData {
}
}
+ bool hasInventoryItem(int id) const {
+ for (int i = 0; i < inventoryItems.size(); i++) {
+ if (inventoryItems[i] == id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
byte *conversationRootsState = new byte[4 * 56];
bool getRootDisabledState(byte room, byte root) const {
Commit: 0078df575bbd9e91e4de12efffc68bee09eece4e
https://github.com/scummvm/scummvm/commit/0078df575bbd9e91e4de12efffc68bee09eece4e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:48+02:00
Commit Message:
PELROCK: Implements actions on Room 4
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/menu.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index cbcf6042c0c..2af488824fa 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -77,6 +77,10 @@ const ActionEntry actionTable[] = {
{6, PICKUP, &PelrockEngine::pickCord},
{7, PICKUP, &PelrockEngine::pickAmulet},
+ // Room 4
+ {315, OPEN, &PelrockEngine::openPlug},
+ {316, PICKUP, &PelrockEngine::pickCables},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -95,9 +99,89 @@ const CombinationEntry combinationTable[] = {
{62, 117, &PelrockEngine::useSpicySauceWithBurger}, // Use Spicy Sauce with Burger
{4, 294, &PelrockEngine::useBrickWithWindow}, // Use Brick with Window (Room 3)
{4, 295, &PelrockEngine::useBrickWithShopWindow},
+ {6, 315, &PelrockEngine::useCordWithPlug},
// End marker
{WILDCARD, WILDCARD, nullptr}};
+void PelrockEngine::openDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayClosed) {
+ if (_room->hasSticker(sticker)) {
+ int text = masculine == MASCULINE ? YA_ABIERTO_M : YA_ABIERTA_F;
+ _dialog->say(_res->_ingameTexts[text]);
+ return;
+ }
+ _room->enableExit(exitIndex, !stayClosed);
+ _room->addSticker(sticker, !stayClosed);
+ _sound->playSound(_room->_roomSfx[0]);
+}
+
+void PelrockEngine::closeDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayOpen) {
+ if (!_room->hasSticker(sticker)) {
+ int text = masculine == MASCULINE ? YA_CERRADO_M : YA_CERRADA_F;
+ _dialog->say(_res->_ingameTexts[text]);
+ return;
+ }
+ _room->disableExit(exitIndex, !stayOpen);
+ _room->removeSticker(sticker);
+ _sound->playSound(_room->_roomSfx[1]);
+}
+
+void PelrockEngine::addInventoryItem(int item) {
+ if (_state->inventoryItems.size() == 0) {
+ _state->selectedInventoryItem = item;
+ }
+ _flashingIcon = item;
+ int frameCounter = 0;
+ while (frameCounter < kIconFlashDuration) {
+ _events->pollEvent();
+
+ bool didRender = renderScene(OVERLAY_PICKUP_ICON);
+ _screen->update();
+ if (didRender) {
+ frameCounter++;
+ }
+ g_system->delayMillis(10);
+ }
+ _state->addInventoryItem(item);
+}
+
+void PelrockEngine::buyFromStore(HotSpot *hotspot, int stickerId) {
+ if (_state->hasInventoryItem(5) == false) {
+ _dialog->say(_res->_ingameTexts[NOTENGODINERO]);
+ return;
+ } else {
+ _room->addSticker(stickerId);
+ _room->disableHotspot(hotspot);
+ if (hotspot->extra == 69) {
+ _room->disableSprite(15, 3); // Disable monkey brain sprite
+ }
+ _state->addInventoryItem(hotspot->extra);
+ _currentHotspot = nullptr;
+ walkLoop(224, 283, ALFRED_LEFT);
+ _dialog->say(_res->_ingameTexts[CUESTA1000]);
+ _dialog->say(_res->_ingameTexts[AQUITIENE]);
+ _dialog->say(_res->_ingameTexts[MUYBIEN]);
+ _state->removeInventoryItem(5); // Remove 1000 pesetas bill
+ }
+}
+
+void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex) {
+ if (actionTrigger == 328) {
+ debug("Disabling root %d in room %d", rootIndex, room);
+ _state->setRootDisabledState(room, rootIndex, true);
+ }
+}
+
+void PelrockEngine::noOpAction(HotSpot *hotspot) {
+}
+
+void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
+ // 154 to 169
+ debug("No-op item %d with hotspot %d", item, hotspot->extra);
+ _alfredState.direction = ALFRED_DOWN;
+ byte response = (byte)getRandomNumber(12);
+ _dialog->say(_res->_ingameTexts[154 + response]);
+}
+
void PelrockEngine::openRoomDoor(HotSpot *hotspot) {
openDoor(hotspot, 0, 93, FEMININE, true);
}
@@ -139,7 +223,7 @@ void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
debug("Withdrawing money from ATM using card (inv obj %d)", inventoryObject);
- if (_state->flagIsSet(FLAG_JEFE_INGRESA_PASTA)) {
+ if (_state->getFlag(FLAG_JEFE_INGRESA_PASTA)) {
_state->setFlag(FLAG_JEFE_INGRESA_PASTA, false);
addInventoryItem(75);
} else {
@@ -193,7 +277,7 @@ void PelrockEngine::closeKitchenDoor(HotSpot *HotSpot) {
}
void PelrockEngine::openKitchenDrawer(HotSpot *hotspot) {
- if (!_state->flagIsSet(FLAG_JEFE_ENCARCELADO)) {
+ if (!_state->getFlag(FLAG_JEFE_ENCARCELADO)) {
_dialog->say(_res->_ingameTexts[QUITA_ESAS_MANOS]);
} else {
_room->addSticker(36);
@@ -212,7 +296,7 @@ void PelrockEngine::useSpicySauceWithBurger(int inventoryObject, HotSpot *hotspo
}
void PelrockEngine::openShopDoor(HotSpot *hotspot) {
- if (!_state->flagIsSet(FLAG_TIENDA_ABIERTA)) {
+ if (!_state->getFlag(FLAG_TIENDA_ABIERTA)) {
_dialog->say(_res->_ingameTexts[TIENDA_CERRADA]);
return;
} else {
@@ -344,73 +428,43 @@ void PelrockEngine::pickAmulet(HotSpot *hotspot) {
buyFromStore(hotspot, 49);
}
-void PelrockEngine::openDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayClosed) {
- if (_room->hasSticker(sticker)) {
- int text = masculine == MASCULINE ? YA_ABIERTO_M : YA_ABIERTA_F;
- _dialog->say(_res->_ingameTexts[text]);
- return;
- }
- _room->enableExit(exitIndex, !stayClosed);
- _room->addSticker(sticker, !stayClosed);
- _sound->playSound(_room->_roomSfx[0]);
-}
-
-void PelrockEngine::closeDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayOpen) {
- if (!_room->hasSticker(sticker)) {
- int text = masculine == MASCULINE ? YA_CERRADO_M : YA_CERRADA_F;
- _dialog->say(_res->_ingameTexts[text]);
- return;
- }
- _room->disableExit(exitIndex, !stayOpen);
- _room->removeSticker(sticker);
- _sound->playSound(_room->_roomSfx[1]);
+void PelrockEngine::openPlug(HotSpot *hotspot) {
+ _room->addSticker(18);
}
-void PelrockEngine::addInventoryItem(int item) {
- if (_state->inventoryItems.size() == 0) {
- _state->selectedInventoryItem = item;
- }
- _flashingIcon = item;
- int frameCounter = 0;
- while (frameCounter < kIconFlashDuration) {
- _events->pollEvent();
-
- bool didRender = renderScene(OVERLAY_PICKUP_ICON);
- _screen->update();
- if (didRender) {
- frameCounter++;
+void PelrockEngine::useCordWithPlug(int inventoryObject, HotSpot *hotspot) {
+ if (!_room->hasSticker(18)) {
+ _dialog->say(_res->_ingameTexts[PRIMERO_ABRIRLO]);
+ } else {
+ debug("Flag is %d", _state->getFlag(FLAG_CABLES_PUESTOS));
+ if (_state->getFlag(FLAG_CABLES_PUESTOS)) {
+ _room->addSticker(19);
+ _room->moveHotspot(_room->findHotspotByIndex(6), 391, 381);
}
- g_system->delayMillis(10);
}
- _state->addInventoryItem(item);
}
-void PelrockEngine::buyFromStore(HotSpot *hotspot, int stickerId) {
- if(_state->hasInventoryItem(5) == false)
- {
- _dialog->say(_res->_ingameTexts[NOTENGODINERO]);
- return;
- }
- else {
- _room->addSticker(stickerId);
- _room->disableHotspot(hotspot);
- _state->addInventoryItem(hotspot->extra);
- _currentHotspot = nullptr;
- walkLoop(224, 283, ALFRED_LEFT);
- _dialog->say(_res->_ingameTexts[CUESTA1000]);
- _dialog->say(_res->_ingameTexts[AQUITIENE]);
- _dialog->say(_res->_ingameTexts[MUYBIEN]);
- _state->removeInventoryItem(5); // Remove 1000 pesetas bill
- }
-}
+void PelrockEngine::pickCables(HotSpot *hotspot) {
+ // Duck to pick cables
+ _res->loadAlfredSpecialAnim(2);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ // electric shock
+ int prevX = _alfredState.x;
+ _alfredState.x -= 20;
+ _res->loadAlfredSpecialAnim(3);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _alfredState.x = prevX;
+ // Stand up (reverse of duck)
+ _res->loadAlfredSpecialAnim(2, true);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _room->addSticker(21);
-void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex) {
- if (actionTrigger == 328) {
- debug("Disabling root %d in room %d", rootIndex, room);
- _state->setRootDisabledState(room, rootIndex, true);
- }
+ _dialog->say(_res->_ingameTexts[RELOJ_HA_CAMBIADO]);
}
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
@@ -426,17 +480,6 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
}
}
-void PelrockEngine::noOpAction(HotSpot *hotspot) {
-}
-
-void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
- // 154 to 169
- debug("No-op item %d with hotspot %d", item, hotspot->extra);
- _alfredState.direction = ALFRED_DOWN;
- byte response = (byte)getRandomNumber(12);
- _dialog->say(_res->_ingameTexts[154 + response]);
-}
-
void PelrockEngine::useOnAlfred(int inventoryObject) {
debug("Using item %d on Alfred", inventoryObject);
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 488255a310d..b8da093fb03 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -269,6 +269,7 @@ void MenuManager::loadMenu() {
readButton(alfred7, alfred7.pos(), _savesDownArrows, _savesDown);
readButton(alfred7, 3214046, _questionMark, _questionMarkRect);
+ _menuText = _menuTexts[0];
alfred7.close();
}
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 85268139a93..3e2a1d88b4a 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -158,7 +158,7 @@ enum TextIndices {
TOO_MUCH_CANT_THINK,
A_LITTLE_RESPECT,
NO_THEY_MAKEYOU_FAT,
- CLOCK_CHANGED,
+ RELOJ_HA_CAMBIADO,
CORRESPONDENCIA_AJENA,
ANDA,
TUCREES,
@@ -494,6 +494,8 @@ struct AlfredSpecialAnimOffset {
const AlfredSpecialAnimOffset alfredSpecialAnims[] = {
{10, 51, 102, 1, 559685, 1}, // READ BOOK
{10, 51, 102, 1, 578943, 1}, // READ RECIPE
+ {3, 45, 87, 0, 37000, 1}, // ELECTRIC SHOCK 1
+ {2, 82, 58, 0, 53106, 20}, // ELECTRIC SHOCK 3
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 0193577b6f6..20904e8fc80 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -161,7 +161,8 @@ void PelrockEngine::init() {
gameInitialized = true;
loadAnims();
// setScreen(0, ALFRED_DOWN);
- setScreen(15, ALFRED_RIGHT);
+ // setScreen(3, ALFRED_RIGHT);
+ setScreen(4, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -561,15 +562,13 @@ void PelrockEngine::doAction(VerbIcon action, HotSpot *hotspot) {
talkTo(hotspot);
break;
case PICKUP:
- _alfredState.setState(ALFRED_INTERACTING);
- if(_room->isPickableByExtra(hotspot->extra)) {
+ if (_room->isPickableByExtra(hotspot->extra)) {
pickUpAndDisable(hotspot);
}
executeAction(PICKUP, hotspot);
break;
case OPEN:
case CLOSE:
- _alfredState.setState(ALFRED_INTERACTING);
default:
executeAction(action, hotspot);
break;
@@ -589,7 +588,7 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
}
void PelrockEngine::lookAt(HotSpot *hotspot) {
- debug("Looking at hotspot %d (%d) with extra %d", hotspot->index, hotspot->isSprite? hotspot->index : hotspot->index - _room->_currentRoomAnims.size(), hotspot->extra);
+ debug("Looking at hotspot %d (%d) with extra %d", hotspot->index, hotspot->isSprite ? hotspot->index : hotspot->index - _room->_currentRoomAnims.size(), hotspot->extra);
_dialog->sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index]);
_actionPopupState.isActive = false;
}
@@ -601,7 +600,12 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.idleFrameCounter = 0;
_alfredState.setState(ALFRED_COMB);
}
+
switch (_alfredState.animState) {
+ case ALFRED_IDLE: {
+ drawAlfred(_res->alfredIdle[_alfredState.direction]);
+ break;
+ }
case ALFRED_WALKING: {
MovementStep step = _currentContext.movementBuffer[_currentStep];
if (step.distanceX > 0) {
@@ -641,11 +645,14 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (_currentHotspot != nullptr)
_alfredState.direction = calculateAlfredsDirection(_currentHotspot);
drawAlfred(_res->alfredIdle[_alfredState.direction]);
-
if (_queuedAction.isQueued) {
- _queuedAction.isQueued = false;
- doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
- break;
+ // look and talk execute immediately, others need interaction animation first
+ if (_queuedAction.verb == TALK || _queuedAction.verb == LOOK) {
+ _queuedAction.isQueued = false;
+ doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
+ break;
+ }
+ _alfredState.setState(ALFRED_INTERACTING);
}
}
} else {
@@ -671,60 +678,74 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
break;
}
case ALFRED_TALKING: {
+ drawAlfred(_res->alfredTalkFrames[_alfredState.direction][_alfredState.curFrame]);
+ if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
+ _alfredState.curFrame++;
if (_alfredState.curFrame >= talkingAnimLengths[_alfredState.direction] - 1) {
_alfredState.curFrame = 0;
}
- drawAlfred(_res->alfredTalkFrames[_alfredState.direction][_alfredState.curFrame]);
- _alfredState.curFrame++;
- // }
break;
}
case ALFRED_COMB: {
+
+ drawAlfred(_res->alfredCombFrames[_alfredState.direction][_alfredState.curFrame]);
+ _alfredState.curFrame++;
if (_alfredState.curFrame >= 11) {
_alfredState.setState(ALFRED_IDLE);
- drawAlfred(_res->alfredIdle[_alfredState.direction]);
- } else {
- drawAlfred(_res->alfredCombFrames[_alfredState.direction][_alfredState.curFrame]);
- _alfredState.curFrame++;
}
break;
}
case ALFRED_INTERACTING: {
+ drawAlfred(_res->alfredInteractFrames[_alfredState.direction][_alfredState.curFrame]);
+ _alfredState.curFrame++;
if (_alfredState.curFrame >= interactingAnimLength) {
+ if (_queuedAction.isQueued) {
+ _queuedAction.isQueued = false;
+ doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
+ break;
+ }
_alfredState.setState(ALFRED_IDLE);
- } else {
- drawAlfred(_res->alfredInteractFrames[_alfredState.direction][_alfredState.curFrame]);
- _alfredState.curFrame++;
}
break;
}
case ALFRED_SPECIAL_ANIM: {
- if (_res->_specialAnimCurFrame >= _res->_curSpecialAnim.numFrames) {
- if (_res->_speciaAnimLoopCount < _res->_curSpecialAnim.loops) {
- _res->_speciaAnimLoopCount++;
- _res->_specialAnimCurFrame = 0;
- } else {
- _res->clearSpecialAnim();
- _alfredState.setState(ALFRED_IDLE);
- _res->_isSpecialAnimFinished = true;
- }
- } else {
- byte *frame = new byte[_res->_curSpecialAnim.stride * _res->_curSpecialAnim.numFrames];
- extractSingleFrame(_res->_specialAnimData,
- frame,
- _res->_specialAnimCurFrame,
- _res->_curSpecialAnim.w,
- _res->_curSpecialAnim.h);
+
+ byte *frame = new byte[_res->_currentSpecialAnim->stride * _res->_currentSpecialAnim->numFrames];
+ debug("Drawing special anim frame %d/%d", _res->_currentSpecialAnim->curFrame, _res->_currentSpecialAnim->numFrames);
+ extractSingleFrame(_res->_currentSpecialAnim->animData,
+ frame,
+ _res->_currentSpecialAnim->curFrame,
+ _res->_currentSpecialAnim->w,
+ _res->_currentSpecialAnim->h);
+ if (_res->_currentSpecialAnim->w == kAlfredFrameWidth && _res->_currentSpecialAnim->h == kAlfredFrameHeight) {
drawAlfred(frame);
- _res->_specialAnimCurFrame++;
- delete[] frame;
+ } else {
+ // Scale special anim frame to Alfred size before drawing
+ drawSpriteToBuffer(_compositeBuffer, 640, frame, _alfredState.x, _alfredState.y - _res->_currentSpecialAnim->h, _res->_currentSpecialAnim->w, _res->_currentSpecialAnim->h, 255);
}
+ if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
+ _res->_currentSpecialAnim->curFrame++;
+
+ if (_res->_currentSpecialAnim->curFrame >= _res->_currentSpecialAnim->numFrames) {
+ if (_res->_currentSpecialAnim->curLoop < _res->_currentSpecialAnim->loopCount - 1) {
+ _res->_currentSpecialAnim->curLoop++;
+ _res->_currentSpecialAnim->curFrame = 0;
+ } else {
+ _alfredState.setState(ALFRED_IDLE);
+ _res->clearSpecialAnim();
+ _res->_isSpecialAnimFinished = true;
+ }
+ }
+ }
+
+ delete[] frame;
+ break;
}
}
- // This if is needed to draw Alfred when idle, when the switch case results in a state change
- if (_alfredState.animState == ALFRED_IDLE) {
- drawAlfred(_res->alfredIdle[_alfredState.direction]);
- }
+ // // This if is needed to draw Alfred when idle, when the switch case results in a state change
+ // if (_alfredState.animState == ALFRED_IDLE) {
+ // drawAlfred(_res->alfredIdle[_alfredState.direction]);
+ // }
}
/**
@@ -734,6 +755,10 @@ void PelrockEngine::drawAlfred(byte *buf) {
ScaleCalculation scale = calculateScaling(_alfredState.y, _room->_scaleParams);
+ // Update Alfred's scale state for use by other functions
+ _alfredState.scaledX = scale.scaleX;
+ _alfredState.scaledY = scale.scaleY;
+
// Use the pre-calculated scaled dimensions from calculateScaling
int finalHeight = scale.scaledHeight;
int finalWidth = scale.scaledWidth;
@@ -745,7 +770,8 @@ void PelrockEngine::drawAlfred(byte *buf) {
finalWidth = 1;
}
- int scaleIndex = finalHeight - 1;
+ // The scaling table is indexed by how many scanlines to skip (scaleY), not by final height
+ int scaleIndex = scale.scaleY;
if (scaleIndex >= (int)_heightScalingTable.size()) {
scaleIndex = _heightScalingTable.size() - 1;
}
@@ -916,6 +942,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
}
void PelrockEngine::checkLongMouseClick(int x, int y) {
+ _alfredState.idleFrameCounter = 0;
int hotspotIndex = isHotspotUnder(x, y);
bool alfredUnder = isAlfredUnder(x, y);
if ((hotspotIndex != -1 || alfredUnder) && !_actionPopupState.isActive) {
@@ -933,12 +960,11 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
}
_actionPopupState.isActive = true;
_actionPopupState.curFrame = 0;
-
+ debug("Setting alfred under popup: %d", alfredUnder);
+ _actionPopupState.isAlfredUnder = alfredUnder;
if (hotspotIndex != -1) {
_currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
- }
- else {
- _actionPopupState.isAlfredUnder = alfredUnder;
+ } else {
_currentHotspot = nullptr;
}
}
@@ -1090,9 +1116,10 @@ int PelrockEngine::isHotspotUnder(int x, int y) {
}
}
bool spriteUnder = isSpriteUnder(sprite, x, y);
- if(spriteUnder)
+ if (spriteUnder)
return i;
- else continue;
+ else
+ continue;
}
}
}
@@ -1230,7 +1257,7 @@ void PelrockEngine::walkLoop(int16 x, int16 y, AlfredDirection direction) {
_alfredState.direction = direction;
walkTo(x, y);
- while(!shouldQuit() && _alfredState.animState == ALFRED_WALKING) {
+ while (!shouldQuit() && _alfredState.animState == ALFRED_WALKING) {
_events->pollEvent();
renderScene();
_screen->update();
@@ -1326,11 +1353,11 @@ bool PelrockEngine::isItemUnder(int x, int y) {
}
bool PelrockEngine::isAlfredUnder(int x, int y) {
- // TODO: Account for scaling
int alfredX = _alfredState.x;
int alfredY = _alfredState.y;
- int alfredW = kAlfredFrameWidth;
- int alfredH = kAlfredFrameHeight;
+ // Use scaled dimensions (width - scaleX, height - scaleY)
+ int alfredW = kAlfredFrameWidth - _alfredState.scaledX;
+ int alfredH = kAlfredFrameHeight - _alfredState.scaledY;
if (alfredY - alfredH > y || alfredY < y || alfredX > x || alfredX + alfredW < x) {
return false;
@@ -1343,7 +1370,7 @@ void PelrockEngine::checkMouseClick(int x, int y) {
_queuedAction = QueuedAction{NO_ACTION, -1, false};
_actionPopupState.isActive = false;
_currentHotspot = nullptr;
-
+ _alfredState.idleFrameCounter = 0;
int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
bool isHotspotUnder = false;
if (hotspotIndex != -1) {
@@ -1457,7 +1484,6 @@ void PelrockEngine::setScreen(int roomNumber, AlfredDirection dir) {
_screen->markAllDirty();
_screen->update();
-
doExtraActions(roomNumber);
roomFile.close();
delete[] background;
@@ -1492,14 +1518,14 @@ void PelrockEngine::waitForSpecialAnimation() {
void PelrockEngine::doExtraActions(int roomNumber) {
switch (roomNumber) {
case 4:
- if (_state->flagIsSet(FLAG_PUESTA_SALSA_PICANTE) && !_state->flagIsSet(FLAG_JEFE_ENCARCELADO)) {
+ if (_state->getFlag(FLAG_PUESTA_SALSA_PICANTE) && !_state->getFlag(FLAG_JEFE_ENCARCELADO)) {
_state->setFlag(FLAG_JEFE_ENCARCELADO, true);
_room->disableSprite(13, 0, true);
loadExtraScreenAndPresent(4);
}
break;
case 15:
- if(_state->flagIsSet(FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ)) {
+ if (_state->getFlag(FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ)) {
_state->setFlag(FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ, false);
_dialog->say(_res->_ingameTexts[GAMBERROS]);
_dialog->say(_res->_ingameTexts[QUIENYO]);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 8350fb76227..1d9970cab01 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -273,6 +273,9 @@ public:
void pickHat(HotSpot *hotspot);
void pickCord(HotSpot *hotspot);
void pickAmulet(HotSpot *hotspot);
+ void openPlug(HotSpot *hotspot);
+ void useCordWithPlug(int inventoryObject, HotSpot *hotspot);
+ void pickCables(HotSpot *hotspot);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
};
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index eda93599d47..ff01637d04b 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -217,28 +217,46 @@ void ResourceManager::loadAlfredAnims() {
free(alfredCombLeftRaw);
}
-void ResourceManager::loadAlfredSpecialAnim(int numAnim) {
- _curSpecialAnim = alfredSpecialAnims[numAnim];
+void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
+ AlfredSpecialAnimOffset offset = alfredSpecialAnims[numAnim];
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
error("Could not open ALFRED.7");
return;
}
- alfred7.seek(_curSpecialAnim.offset, SEEK_SET);
- _specialAnimData = new byte[_curSpecialAnim.numFrames * _curSpecialAnim.w * _curSpecialAnim.h];
- debug("Special anim buffer size: %d", _curSpecialAnim.numFrames * _curSpecialAnim.w * _curSpecialAnim.h);
- mergeRleBlocks(&alfred7, _curSpecialAnim.offset, _curSpecialAnim.numBudas, _specialAnimData);
- _specialAnimCurFrame = 0;
+ alfred7.seek(offset.offset, SEEK_SET);
+ if(_currentSpecialAnim)
+ delete _currentSpecialAnim;
+ _currentSpecialAnim = new AlfredSpecialAnim(offset.numFrames, offset.w, offset.h, offset.numBudas, offset.offset, offset.loops);
+ _currentSpecialAnim->animData = new byte[offset.numFrames * offset.w * offset.h];
+ if(offset.numBudas > 0) {
+ mergeRleBlocks(&alfred7, offset.offset, offset.numBudas, _currentSpecialAnim->animData);
+ }
+ else {
+ alfred7.read(_currentSpecialAnim->animData, offset.numFrames * offset.w * offset.h);
+ }
+ if(reverse) {
+ // reverse frames for testing
+ byte *reversedData = new byte[offset.numFrames * offset.w * offset.h];
+ for(int i = 0; i < offset.numFrames; i++) {
+ extractSingleFrame(_currentSpecialAnim->animData,
+ &reversedData[i * offset.w * offset.h],
+ offset.numFrames - 1 - i,
+ offset.w,
+ offset.h);
+ }
+ delete[] _currentSpecialAnim->animData;
+ _currentSpecialAnim->animData = reversedData;
+ }
+
_isSpecialAnimFinished = false;
alfred7.close();
}
void ResourceManager::clearSpecialAnim() {
- delete[] _specialAnimData;
- _specialAnimData = nullptr;
- _specialAnimCurFrame = 0;
- _speciaAnimLoopCount = 0;
+ delete _currentSpecialAnim;
+ _currentSpecialAnim = nullptr;
}
void ResourceManager::loadInventoryItems() {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 3b1690ed34e..f91386e2f37 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -45,7 +45,7 @@ public:
void loadCursors();
void loadInteractionIcons();
void loadAlfredAnims();
- void loadAlfredSpecialAnim(int numAnim);
+ void loadAlfredSpecialAnim(int numAnim, bool reverse = false);
void clearSpecialAnim();
void loadInventoryItems();
void loadAlfredResponses();
@@ -71,10 +71,11 @@ public:
Common::Array<Common::StringArray> _ingameTexts;
// Special anims
- byte *_specialAnimData = nullptr;
- int _specialAnimCurFrame = 0;
- int _speciaAnimLoopCount = 0;
- AlfredSpecialAnimOffset _curSpecialAnim;
+ AlfredSpecialAnim *_currentSpecialAnim = nullptr;
+ // byte *_specialAnimData = nullptr;
+ // int _specialAnimCurFrame = 0;
+ // int _speciaAnimLoopCount = 0;
+ // AlfredSpecialAnimOffset _curSpecialAnim;
bool _isSpecialAnimFinished = false;
};
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 04d86740812..61981dac738 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -215,6 +215,7 @@ Sprite *RoomManager::findSpriteByIndex(byte index) {
HotSpot *RoomManager::findHotspotByIndex(byte index) {
for (int i = 0; i < _currentRoomHotspots.size(); i++) {
if (!_currentRoomHotspots[i].isSprite && _currentRoomHotspots[i].innerIndex == index) {
+ debug("Found hotspot %d at index %d, extra = %d", index, i, _currentRoomHotspots[i].extra);
return &_currentRoomHotspots[i];
}
}
@@ -379,6 +380,7 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
// if the hotspot has been changed, load the changed version
for (int j = 0; j < g_engine->_state->roomHotSpotChanges[_currentRoomNumber].size(); j++) {
if (g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspotIndex == spot.innerIndex) {
+ debug("Hotspot %d has been changed, loading changed version, Hotspot x=%d, y = %d, extra = %d", spot.innerIndex, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.x, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.y, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.extra);
hotspots.push_back(g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot);
isChanged = true;
break;
@@ -394,7 +396,7 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
spot.h = data[hotspotOffset + 6];
spot.isSprite = false;
spot.extra = READ_LE_INT16(data + hotspotOffset + 7);
- debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d, isEnabled=%d", spot.innerIndex, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra, spot.isEnabled);
+ debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d, index =%d, isEnabled=%d", spot.innerIndex, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra, spot.innerIndex, spot.isEnabled);
hotspots.push_back(spot);
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index eb624d32b35..e16941f4d9a 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -92,7 +92,8 @@ public:
void applyDisabledChoice(ResetEntry entry, byte *conversationData, size_t conversationDataSize);
void addDisabledChoice(ChoiceOption choice);
bool isPickableByExtra(uint16 extra) {
- for(int i = 0; i < sizeof(unpickableHotspotExtras); i++) {
+ int size = sizeof(unpickableHotspotExtras) / sizeof(unpickableHotspotExtras[0]);
+ for(int i = 0; i < size; i++) {
if (extra == unpickableHotspotExtras[i])
return false;
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index a307e46697e..65b9ea944b4 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -71,6 +71,8 @@ const int kAlfredFrameHeight = 102;
const int kChoiceHeight = 16; // Height of each choice line in pixels
const int kTalkAnimationSpeed = 2; // Frames per update
+const int kAlfredAnimationSpeed = 2; // Frames per update
+
const int kAlfredIdleAnimationFrameCount = 300;
@@ -113,6 +115,27 @@ enum AlfredDirection {
ALFRED_UP = 3
};
+struct AlfredSpecialAnim {
+ byte *animData = nullptr;
+ int w = 0;
+ int h = 0;
+ int numFrames = 0;
+ int loopCount = 0;
+ uint32 stride = 0;
+ int curFrame = 0;
+ int curLoop = 0;
+ AlfredSpecialAnim(int nF, int width, int height, int nBudas, uint32 off, int loopCount)
+ : numFrames(nF), w(width), h(height), loopCount(loopCount) {
+ stride = w * h;
+ }
+ ~AlfredSpecialAnim() {
+ if (animData) {
+ delete[] animData;
+ animData = nullptr;
+ }
+ }
+};
+
struct ActionPopupState {
bool isActive = false;
int curFrame = 0;
@@ -433,19 +456,18 @@ struct ResetEntry {
#define FLAG_HE_TIRADO_PIEDRA 44
#define FLAG_HA_USADO_AGUA 45
#define FLAG_TIENDA_ABIERTA 46
+#define FLAG_NUMERO_DE_COPAS 47
+#define FLAG_INGREDIENTES_CONSEGUIDOS 48
-const int kNumGameFlags = 47;
+const int kNumGameFlags = 49;
struct GameStateData {
- bool flags[kNumGameFlags];
-
- byte NUMERO_DE_COPAS = false;
- byte INGREDIENTES_CONSEGUIDOS = 0;
+ byte flags[kNumGameFlags];
GameState stateGame = INTRO;
Common::Array<byte> inventoryItems;
- int16 selectedInventoryItem = 0;
+ int16 selectedInventoryItem = -1;
Common::HashMap<byte, Common::Array<Sticker>> stickersPerRoom;
// Common::HashMap<byte, ResetEntry> roomExitChanges;
@@ -457,6 +479,8 @@ struct GameStateData {
GameStateData() {
memset(conversationRootsState, 0, 4 * 56);
+ for (int i = 0; i < kNumGameFlags; i++)
+ flags[i] = 0;
flags[FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ] = true;
}
@@ -469,13 +493,13 @@ struct GameStateData {
disabledBranches[entry.room].push_back(entry);
}
- bool flagIsSet(int flagIndex) const {
+ byte getFlag(int flagIndex) const {
if (flagIndex < 0 || flagIndex >= kNumGameFlags)
return false;
return flags[flagIndex];
}
- void setFlag(int flagIndex, bool value) {
+ void setFlag(int flagIndex, byte value) {
if (flagIndex < 0 || flagIndex >= kNumGameFlags)
return;
flags[flagIndex] = value;
Commit: fa5ee4b021436bfa67df6dfc003504f06dfdfb97
https://github.com/scummvm/scummvm/commit/fa5ee4b021436bfa67df6dfc003504f06dfdfb97
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:48+02:00
Commit Message:
PELROCK: Improvements on dialog handling
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index c5233f6275d..9342c10df73 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -355,6 +355,53 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
return pos;
}
+/**
+ * Check if all sub-branches of the current choice level are exhausted.
+ * Based on Ghidra code at LAB_00018c2d in handle_conversation_tree.
+ *
+ * Returns true if we should disable the current choice, which happens when:
+ * - There are no FB sub-branches at higher indices, OR
+ * - All FB sub-branches at higher indices already have FA (are disabled)
+ *
+ * F1 markers (repeatable) don't block disabling - they never get disabled.
+ */
+bool DialogManager::checkAllSubBranchesExhausted(const byte *data, uint32 dataSize, uint32 startPos, int currentChoiceLevel) {
+ uint32 pos = startPos;
+
+ while (pos < dataSize) {
+ byte b = data[pos];
+
+ // Stop at branch/conversation end markers (0xF5, 0xF7, 0xFE, 0xF4)
+ if (b == CTRL_ALT_END_MARKER_1 || b == CTRL_END_BRANCH ||
+ b == CTRL_ALT_SPEAKER_ROOT || b == CTRL_END_CONVERSATION) {
+ break;
+ }
+
+ // Found FB (one-time choice marker)
+ if (b == CTRL_DIALOGUE_MARKER_ONEOFF && pos + 2 < dataSize) {
+ byte choiceIdx = data[pos + 1];
+
+ // Only check sub-branches (higher index = deeper level)
+ if (choiceIdx > currentChoiceLevel) {
+ // Check if NOT disabled (no FA at pos+2)
+ if (data[pos + 2] != CTRL_DISABLED_CHOICE) {
+ debug("checkAllSubBranchesExhausted: Active FB at pos %u, idx %d (current %d) - NOT exhausted",
+ pos, choiceIdx, currentChoiceLevel);
+ return false; // Don't disable parent
+ }
+ } else if (choiceIdx <= currentChoiceLevel) {
+ // Hit choice at same or lower level - stop
+ break;
+ }
+ }
+
+ pos++;
+ }
+
+ debug("checkAllSubBranchesExhausted: All sub-branches exhausted at level %d", currentChoiceLevel);
+ return true;
+}
+
void DialogManager::setCurSprite(int index) {
// Set current sprite based on index
if (g_engine->_room == nullptr) {
@@ -373,6 +420,14 @@ void DialogManager::setCurSprite(int index) {
_curSprite = nullptr;
}
+bool isRootDisabled(byte room, int root) {
+
+ if(g_engine->_state->getRootDisabledState(room, root)) {
+ return true;
+ }
+ return false;
+}
+
void DialogManager::startConversation(const byte *conversationData, uint32 dataSize, byte npcIndex, Sprite *animSet) {
if (!conversationData || dataSize == 0) {
debug("startConversation: No conversation data");
@@ -472,7 +527,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
// Move past control byte
- if (controlByte == CTRL_END_TEXT || controlByte == CTRL_ACTION_TRIGGER) {
+ if (controlByte == CTRL_END_TEXT) {
position++;
if (position >= dataSize) {
debug("Reached end of data after moving past control byte");
@@ -495,7 +550,8 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
if (peekPos < dataSize &&
conversationData[peekPos] != CTRL_DIALOGUE_MARKER &&
conversationData[peekPos] != CTRL_DIALOGUE_MARKER_ONEOFF &&
- conversationData[peekPos] != CTRL_END_CONVERSATION) {
+ conversationData[peekPos] != CTRL_END_CONVERSATION &&
+ conversationData[peekPos] != CTRL_DISABLED_CHOICE) {
continue;
}
@@ -566,8 +622,13 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
if (!choiceText.empty() && choiceText.size() > 1) {
displayDialogue(choiceText, ALFRED_COLOR);
+ // Only disable FB choice if all sub-branches are exhausted (Ghidra LAB_00018c2d)
if ((*choices)[selectedIndex].shouldDisableOnSelect) {
- g_engine->_room->addDisabledChoice((*choices)[selectedIndex]);
+ bool shouldDisable = checkAllSubBranchesExhausted(
+ conversationData, dataSize, endPos, currentChoiceLevel);
+ if (shouldDisable) {
+ g_engine->_room->addDisabledChoice((*choices)[selectedIndex]);
+ }
}
}
@@ -686,7 +747,6 @@ int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
if (pos < text.size() && isEndMarker(text[pos])) {
isEnd = true;
}
- // Count ALL trailing spaces as part of this word
if (pos < text.size() && !isEnd) {
if (text[pos] == CTRL_ACTION_TRIGGER) { // 0xF8 (-8) special case
wordLength += 3;
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index b543de68855..8a47379ccec 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -78,6 +78,7 @@ private:
void setCurSprite(int index);
void checkMouse();
void sayAlfred(Common::StringArray texts);
+ bool checkAllSubBranchesExhausted(const byte *data, uint32 dataSize, uint32 startPos, int currentChoiceLevel);
public:
DialogManager(Graphics::Screen *screen, PelrockEventManager *events, GraphicsManager *graphics);
Commit: aeae414a3e39ce76ab5957c47764d09facc9f653
https://github.com/scummvm/scummvm/commit/aeae414a3e39ce76ab5957c47764d09facc9f653
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:49+02:00
Commit Message:
PELROCK: Room 4 conversation marker
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 2af488824fa..383e04ee7b8 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -445,6 +445,10 @@ void PelrockEngine::useCordWithPlug(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::pickCables(HotSpot *hotspot) {
+ if(_room->hasSticker(21)) {
+ _dialog->say(_res->_ingameTexts[QUELOSCOJA_SUPADRE]);
+ return;
+ }
// Duck to pick cables
_res->loadAlfredSpecialAnim(2);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
@@ -465,6 +469,7 @@ void PelrockEngine::pickCables(HotSpot *hotspot) {
_room->addSticker(21);
_dialog->say(_res->_ingameTexts[RELOJ_HA_CAMBIADO]);
+ _state->setRootDisabledState(4, 0, true);
}
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 9342c10df73..020414d7a5a 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -357,13 +357,12 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
/**
* Check if all sub-branches of the current choice level are exhausted.
- * Based on Ghidra code at LAB_00018c2d in handle_conversation_tree.
*
* Returns true if we should disable the current choice, which happens when:
* - There are no FB sub-branches at higher indices, OR
* - All FB sub-branches at higher indices already have FA (are disabled)
*
- * F1 markers (repeatable) don't block disabling - they never get disabled.
+ * F1 markers (repeatable) never get disabled.
*/
bool DialogManager::checkAllSubBranchesExhausted(const byte *data, uint32 dataSize, uint32 startPos, int currentChoiceLevel) {
uint32 pos = startPos;
@@ -440,6 +439,9 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
uint32 position = 0;
int currentChoiceLevel = -1; // Track the current choice level
+ uint32 lastChoiceMenuPosition = 0; // Track where we last showed a choice menu
+ ChoiceOption lastSelectedChoice; // Track the last choice we selected
+ bool skipToChoices = false; // After F0, skip directly to choice parsing
// Find the speaker tree for this NPC; they are marked by 0xFE 0xXX where XX is NPC index + 1
bool speakerTreeOffsetFound = false;
@@ -476,86 +478,114 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// OUTER LOOP: Continue until conversation ends
while (position < dataSize && !g_engine->shouldQuit()) {
- // Skip control bytes that should be ignored
+ // Skip control bytes that should be ignored (but handle F0 specially)
while (position < dataSize &&
(conversationData[position] == CTRL_ALT_END_MARKER_1 ||
- conversationData[position] == CTRL_ALT_END_MARKER_2 ||
- conversationData[position] == CTRL_GO_BACK)) {
+ conversationData[position] == CTRL_ALT_END_MARKER_2)) {
position++;
}
- if (position >= dataSize) {
- debug("Reached end of data while skipping control bytes");
- break;
- }
+ // Handle F0 "Go Back" - return to the last choice menu position
+ // Disable the choice that led us here before rewinding
+ if (position < dataSize && conversationData[position] == CTRL_GO_BACK) {
+ debug("F0 Go Back at position %u, rewinding to lastChoiceMenuPosition %u", position, lastChoiceMenuPosition);
- // 1. Read and display current dialogue
- Common::String text;
- byte speakerId;
- uint32 endPos = readTextBlock(conversationData, dataSize, position, text, speakerId);
- Common::Array<Common::Array<Common::String>> wrappedText = wordWrap(text);
- debug("Word wrapping %s produces %d pages", text.c_str(), wrappedText.size());
- // Skip spurious single character artifacts
- if (!text.empty() && text.size() > 1) {
- displayDialogue(wrappedText, speakerId);
+ if (lastChoiceMenuPosition > 0) {
+ // Disable the choice that led to this F0
+ if (lastSelectedChoice.dataOffset > 0) {
+ debug("F0: Disabling choice that led here at offset %u", lastSelectedChoice.dataOffset);
+ g_engine->_room->addDisabledChoice(lastSelectedChoice);
+ }
+ position = lastChoiceMenuPosition;
+ skipToChoices = true; // Skip directly to choice parsing
+ // Jump directly to choice parsing section
+ // Don't continue - let it fall through
+ } else {
+ debug("F0: No previous choice menu, ending conversation");
+ break;
+ }
}
- // Move to end of text
- position = endPos;
-
- // 2. Check for end of conversation
if (position >= dataSize) {
- debug("Reached end of data after reading dialogue");
+ debug("Reached end of data while skipping control bytes");
break;
}
- byte controlByte = conversationData[position];
-
- if (controlByte == CTRL_END_CONVERSATION) {
- debug("End of conversation marker found");
- break;
- }
+ // 1. Read and display current dialogue (unless skipping to choices)
+ uint32 endPos = position; // Declare outside the if block
+ if (!skipToChoices) {
+ Common::String text;
+ byte speakerId;
+ endPos = readTextBlock(conversationData, dataSize, position, text, speakerId);
+ Common::Array<Common::Array<Common::String>> wrappedText = wordWrap(text);
+ debug("Word wrapping %s produces %d pages", text.c_str(), wrappedText.size());
+ // Skip spurious single character artifacts
+ if (!text.empty() && text.size() > 1) {
+ displayDialogue(wrappedText, speakerId);
+ }
- if (controlByte == CTRL_ACTION_TRIGGER) {
- uint16 actionCode = conversationData[position + 1] | (conversationData[position + 2] << 8);
- debug("Action trigger %d encountered!", actionCode);
- g_engine->dialogActionTrigger(
- actionCode,
- g_engine->_room->_currentRoomNumber,
- currentRoot);
- break;
+ // Move to end of text
+ position = endPos;
}
- // Move past control byte
- if (controlByte == CTRL_END_TEXT) {
- position++;
+ // 2. Check for end of conversation (skip if going directly to choices)
+ if (!skipToChoices) {
if (position >= dataSize) {
- debug("Reached end of data after moving past control byte");
+ debug("Reached end of data after reading dialogue");
+ break;
+ }
+
+ byte controlByte = conversationData[position];
+
+ if (controlByte == CTRL_END_CONVERSATION) {
+ debug("End of conversation marker found");
+ break;
+ }
+
+ if (controlByte == CTRL_ACTION_TRIGGER) {
+ uint16 actionCode = conversationData[position + 1] | (conversationData[position + 2] << 8);
+ debug("Action trigger %d encountered!", actionCode);
+ g_engine->dialogActionTrigger(
+ actionCode,
+ g_engine->_room->_currentRoomNumber,
+ currentRoot);
break;
}
+
+ // Move past control byte
+ if (controlByte == CTRL_END_TEXT) {
+ position++;
+ if (position >= dataSize) {
+ debug("Reached end of data after moving past control byte");
+ break;
+ }
+ }
}
// 3. Before parsing choices, check if we're at a choice marker
// Skip control bytes to peek at next meaningful byte
uint32 peekPos = position;
- while (peekPos < dataSize &&
- (conversationData[peekPos] == CTRL_ALT_END_MARKER_1 ||
- conversationData[peekPos] == CTRL_ALT_END_MARKER_2 ||
- conversationData[peekPos] == CTRL_TEXT_TERMINATOR ||
- conversationData[peekPos] == CTRL_GO_BACK)) {
- peekPos++;
- }
-
- // If not at a choice marker, there's more dialogue to read
- if (peekPos < dataSize &&
- conversationData[peekPos] != CTRL_DIALOGUE_MARKER &&
- conversationData[peekPos] != CTRL_DIALOGUE_MARKER_ONEOFF &&
- conversationData[peekPos] != CTRL_END_CONVERSATION &&
- conversationData[peekPos] != CTRL_DISABLED_CHOICE) {
- continue;
+ if (!skipToChoices) {
+ while (peekPos < dataSize &&
+ (conversationData[peekPos] == CTRL_ALT_END_MARKER_1 ||
+ conversationData[peekPos] == CTRL_ALT_END_MARKER_2 ||
+ conversationData[peekPos] == CTRL_TEXT_TERMINATOR)) {
+ peekPos++;
+ }
+
+ // If not at a choice marker, there's more dialogue to read
+ if (peekPos < dataSize &&
+ conversationData[peekPos] != CTRL_DIALOGUE_MARKER &&
+ conversationData[peekPos] != CTRL_DIALOGUE_MARKER_ONEOFF &&
+ conversationData[peekPos] != CTRL_END_CONVERSATION &&
+ conversationData[peekPos] != CTRL_DISABLED_CHOICE) {
+ continue;
+ }
}
- // 4. Parse choices
+ // 4. Parse choices - save position for F0 "go back"
+ skipToChoices = false; // Reset flag
+ lastChoiceMenuPosition = position;
Common::Array<ChoiceOption> *choices = new Common::Array<ChoiceOption>();
parseChoices(conversationData, dataSize, position, choices);
debug("Parsed %u choices", choices->size());
@@ -569,19 +599,23 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
continue;
}
- // Check if we have a currentChoiceLevel and if these choices are at the next level
+ // Check if we have a currentChoiceLevel and if these choices are at the expected level
if (currentChoiceLevel >= 0) {
- // We've already made a choice, check if the current choices are at the next level
- bool foundNextLevel = false;
+ // After F0, we expect choices at the SAME level (currentChoiceLevel)
+ // Otherwise, we expect choices at the NEXT level (currentChoiceLevel + 1)
+ bool foundExpectedLevel = false;
for (uint i = 0; i < choices->size(); i++) {
- if ((*choices)[i].choiceIndex == currentChoiceLevel + 1) {
- foundNextLevel = true;
+ if ((*choices)[i].choiceIndex == currentChoiceLevel ||
+ (*choices)[i].choiceIndex == currentChoiceLevel + 1) {
+ foundExpectedLevel = true;
+ // Update currentChoiceLevel to match what we found
+ currentChoiceLevel = (*choices)[i].choiceIndex;
break;
}
}
- if (!foundNextLevel) {
- debug("No choices found at level %d (current is %d), ending conversation", currentChoiceLevel + 1, currentChoiceLevel);
+ if (!foundExpectedLevel) {
+ debug("No choices found at level %d or %d, ending conversation", currentChoiceLevel, currentChoiceLevel + 1);
break;
}
}
@@ -612,6 +646,8 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// 6. Move position to after the selected choice
if (selectedIndex >= 0 && selectedIndex < (int)choices->size()) {
+ // Save this choice in case we hit F0 and need to disable it
+ lastSelectedChoice = (*choices)[selectedIndex];
position = (*choices)[selectedIndex].dataOffset;
currentChoiceLevel = (*choices)[selectedIndex].choiceIndex;
@@ -624,8 +660,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
displayDialogue(choiceText, ALFRED_COLOR);
// Only disable FB choice if all sub-branches are exhausted (Ghidra LAB_00018c2d)
if ((*choices)[selectedIndex].shouldDisableOnSelect) {
- bool shouldDisable = checkAllSubBranchesExhausted(
- conversationData, dataSize, endPos, currentChoiceLevel);
+ bool shouldDisable = checkAllSubBranchesExhausted(conversationData, dataSize, endPos, currentChoiceLevel);
if (shouldDisable) {
g_engine->_room->addDisabledChoice((*choices)[selectedIndex]);
}
@@ -728,7 +763,7 @@ bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speake
return false;
}
-bool isEndMarker(char char_byte) {
+bool isEndMarker(unsigned char char_byte) {
return char_byte == CTRL_END_TEXT || char_byte == CTRL_END_CONVERSATION || char_byte == CTRL_ACTION_TRIGGER || char_byte == CTRL_GO_BACK;
}
@@ -801,7 +836,7 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
if (trailingSpaces > 0) {
currentPage.push_back(lineText);
// current_line = [' ' * trailing_spaces]
- Common::String currentLine(trailingSpaces, ' ');
+ Common::String current_line(trailingSpaces, ' ');
charsRemaining = MAX_CHARS_PER_LINE - trailingSpaces;
currentLineNum += 1;
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 8a47379ccec..0f8d078af3b 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -50,17 +50,17 @@ namespace Pelrock {
#define CTRL_ALT_END_MARKER_2 0xEB /* Alt end marker 2 */
#define CTRL_ALT_SPEAKER_ROOT 0xFE /* Separates conversations from different speakers */
-static void debugHexString(const Common::String &str, const char *label = nullptr) {
- if (label) {
- debug("%s:", label);
- }
+// static void debugHexString(const Common::String &str, const char *label = nullptr) {
+// if (label) {
+// debug("%s:", label);
+// }
- Common::String hexOutput;
- for (uint i = 0; i < str.size(); i++) {
- hexOutput += Common::String::format("%02X ", (unsigned char)str[i]);
- }
- debug("%s", hexOutput.c_str());
-}
+// Common::String hexOutput;
+// for (uint i = 0; i < str.size(); i++) {
+// hexOutput += Common::String::format("%02X ", (unsigned char)str[i]);
+// }
+// debug("%s", hexOutput.c_str());
+// }
class DialogManager {
private:
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 3e2a1d88b4a..bdd14778c95 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -491,7 +491,7 @@ struct AlfredSpecialAnimOffset {
}
};
-const AlfredSpecialAnimOffset alfredSpecialAnims[] = {
+static const AlfredSpecialAnimOffset alfredSpecialAnims[] = {
{10, 51, 102, 1, 559685, 1}, // READ BOOK
{10, 51, 102, 1, 578943, 1}, // READ RECIPE
{3, 45, 87, 0, 37000, 1}, // ELECTRIC SHOCK 1
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 20904e8fc80..28ce2b527de 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -576,7 +576,7 @@ void PelrockEngine::doAction(VerbIcon action, HotSpot *hotspot) {
}
void PelrockEngine::talkTo(HotSpot *hotspot) {
- Sprite *animSet;
+ Sprite *animSet = nullptr;
for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].index == hotspot->index) {
animSet = &_room->_currentRoomAnims[i];
@@ -696,22 +696,22 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
break;
}
case ALFRED_INTERACTING: {
+ debug("Alfred interacting frame %d/%d, direction %d", _alfredState.curFrame, interactingAnimLength, _alfredState.direction);
drawAlfred(_res->alfredInteractFrames[_alfredState.direction][_alfredState.curFrame]);
_alfredState.curFrame++;
if (_alfredState.curFrame >= interactingAnimLength) {
if (_queuedAction.isQueued) {
_queuedAction.isQueued = false;
+ _alfredState.setState(ALFRED_IDLE);
doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
break;
}
- _alfredState.setState(ALFRED_IDLE);
}
break;
}
case ALFRED_SPECIAL_ANIM: {
byte *frame = new byte[_res->_currentSpecialAnim->stride * _res->_currentSpecialAnim->numFrames];
- debug("Drawing special anim frame %d/%d", _res->_currentSpecialAnim->curFrame, _res->_currentSpecialAnim->numFrames);
extractSingleFrame(_res->_currentSpecialAnim->animData,
frame,
_res->_currentSpecialAnim->curFrame,
@@ -915,7 +915,6 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
int frameSize = sprite->stride;
int curFrame = animData.curFrame;
- byte *frame = new byte[frameSize];
drawSpriteToBuffer(_compositeBuffer, 640, animData.animData[curFrame], x, y, w, h, 255);
// Original in the game: increment FIRST, then check (not check-then-increment)
@@ -1142,7 +1141,6 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
*/
bool PelrockEngine::isSpriteUnder(Sprite *sprite, int x, int y) {
Anim &animData = sprite->animData[sprite->curAnimIndex];
- int frameSize = animData.w * animData.h;
int curFrame = animData.curFrame;
int localX = x - animData.x;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 61981dac738..9e7a1e7efd5 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -434,7 +434,6 @@ void RoomManager::resetConversationStates(byte roomNumber, byte *conversationDat
void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
- uint32_t outPos = 0;
_roomStickers.clear();
_currentRoomNumber = roomNumber;
int roomOffset = roomNumber * kRoomStructSize;
@@ -500,10 +499,6 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
drawRect(g_engine->_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
}
- for (int i = 0; i < _currentRoomExits.size(); i++) {
- Exit exit = _currentRoomExits[i];
- }
-
PaletteAnim *anim = getPaletteAnimForRoom(roomNumber);
if (anim != nullptr) {
if (_currentPaletteAnim != nullptr) {
@@ -595,8 +590,8 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
sprite.spriteType = data[animOffset + 33];
sprite.actionFlags = data[animOffset + 34];
sprite.isHotspotDisabled = data[animOffset + 38];
- for (int i = 0; i < disabledSprites.size(); i++) {
- if (disabledSprites[i] == sprite.index) {
+ for (int j = 0; j < disabledSprites.size(); j++) {
+ if (disabledSprites[j] == sprite.index) {
sprite.zOrder = 255;
sprite.isHotspotDisabled = 1;
break;
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index e16941f4d9a..3feb2b25913 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -43,7 +43,8 @@ static const int unpickableHotspotExtras[] = {
73,
74,
6,
- 7
+ 7,
+ 316, // wires
};
class RoomManager {
Commit: bc0118e1717cca86458d71898dcadeb20687b480
https://github.com/scummvm/scummvm/commit/bc0118e1717cca86458d71898dcadeb20687b480
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:49+02:00
Commit Message:
PELROCK: Implements computer on room 9
Changed paths:
A engines/pelrock/computer.cpp
A engines/pelrock/computer.h
A engines/pelrock/library_books.h
engines/pelrock/actions.cpp
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
engines/pelrock/util.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 383e04ee7b8..1b18c8f46d1 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -482,6 +482,13 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
_screen->markAllDirty();
_screen->update();
break;
+ case 271:
+ _dialog->say(_res->_ingameTexts[TRABAJARIA_MEJOR_SI_NO_ME_MOLESTARA]);
+ break;
+ case 270:
+ // loadExtraScreenAndPresent(9);
+ _state->stateGame = COMPUTER;
+ break;
}
}
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
new file mode 100644
index 00000000000..3b60c673edf
--- /dev/null
+++ b/engines/pelrock/computer.cpp
@@ -0,0 +1,294 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/events.h"
+#include "common/system.h"
+#include "graphics/paletteman.h"
+
+#include "pelrock/computer.h"
+#include "pelrock/library_books.h"
+#include "pelrock/pelrock.h"
+
+namespace Pelrock {
+
+Computer::Computer(PelrockEventManager *eventMan)
+ : _backgroundScreen(nullptr),
+ _palette(nullptr),
+ _state(STATE_MAIN_MENU),
+ _searchLetter(0),
+ _searchType(0),
+ _currentResult(0),
+ _memorizedBookIndex(-1),
+ _events(eventMan) {
+
+ // Initialize UI strings (Spanish - original game language)
+ _menuTitle = "MENU PRINCIPAL";
+ _menuOption1 = "1 CONSULTAR POR TITULO";
+ _menuOption2 = "2 CONSULTAR POR AUTOR";
+ _menuOption3 = "3 CANCELAR";
+ _promptLetter = "Teclea una letra (A-Z):";
+ _labelTitle = "Titulo : ";
+ _labelAuthor = "Autor : ";
+ _labelGenre = "Genero : ";
+ _labelSituacion = "Situacion : ";
+ _statusPhysical = "Estante %c, fila %d";
+ _statusCatalogOnly = "Solo en catalogo";
+ _optMemorizar = "(M)emorizar";
+ _optSeguir = "(S)eguir";
+ _optCancelar = "(C)ancelar";
+ _noResults = "No se encontraron libros";
+ _memorizedMsg = "Bueno... Tendre que buscar en la estanteria de la %c";
+}
+
+Computer::~Computer() {
+ cleanup();
+}
+
+void Computer::loadBackground() {
+ _palette = new byte[768];
+ _backgroundScreen = new byte[640 * 400];
+
+ g_engine->_res->getExtraScreen(1, _backgroundScreen, _palette);
+ g_system->getPaletteManager()->setPalette(_palette, 0, 256);
+}
+
+void Computer::cleanup() {
+ if (_backgroundScreen) {
+ delete[] _backgroundScreen;
+ _backgroundScreen = nullptr;
+ }
+ if (_palette) {
+ // Restore room palette
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+ delete[] _palette;
+ _palette = nullptr;
+ }
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+}
+
+int Computer::run() {
+ loadBackground();
+ _state = STATE_MAIN_MENU;
+
+ while (!g_engine->shouldQuit() && _state != STATE_EXIT) {
+ _events->pollEvent();
+ drawScreen();
+
+ switch (_state) {
+ case STATE_MAIN_MENU:
+ handleMainMenu();
+ break;
+
+ case STATE_SEARCH_BY_TITLE:
+ case STATE_SEARCH_BY_AUTHOR:
+ handleSearchInput();
+ break;
+
+ case STATE_SHOW_RESULTS:
+ handleResultsDisplay();
+ break;
+
+ case STATE_EXIT:
+ break;
+ }
+
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+ g_system->delayMillis(10);
+ }
+ cleanup();
+ return _memorizedBookIndex;
+}
+
+void Computer::drawScreen() {
+ // Clear to background
+ memcpy(g_engine->_screen->getPixels(), _backgroundScreen, 640 * 400);
+
+ int textY = 100;
+ int textX = 180;
+
+ switch (_state) {
+ case STATE_MAIN_MENU:
+ g_engine->_smallFont->drawString(g_engine->_screen, _menuTitle, textX, textY, 280, 15, Graphics::kTextAlignCenter);
+ g_engine->_smallFont->drawString(g_engine->_screen, _menuOption1, textX, textY + 40, 280, 14);
+ g_engine->_smallFont->drawString(g_engine->_screen, _menuOption2, textX, textY + 60, 280, 14);
+ g_engine->_smallFont->drawString(g_engine->_screen, _menuOption3, textX, textY + 80, 280, 14);
+ break;
+
+ case STATE_SEARCH_BY_TITLE:
+ case STATE_SEARCH_BY_AUTHOR:
+ g_engine->_smallFont->drawString(g_engine->_screen,
+ _searchType == 0 ? "CONSULTAR POR TITULO" : "CONSULTAR POR AUTOR",
+ textX, textY, 280, 15, Graphics::kTextAlignCenter);
+ g_engine->_smallFont->drawString(g_engine->_screen, _promptLetter, textX, textY + 40, 280, 14);
+ break;
+
+ case STATE_SHOW_RESULTS:
+ {
+ Common::String header = Common::String::format(
+ "Consulta de %s, letra %c",
+ _searchType == 0 ? "TITULO" : "AUTOR",
+ _searchLetter);
+ g_engine->_smallFont->drawString(g_engine->_screen, header, textX, textY, 280, 15, Graphics::kTextAlignCenter);
+
+ if (_searchResults.empty()) {
+ g_engine->_smallFont->drawString(g_engine->_screen, _noResults, textX, textY + 50, 280, 14);
+ } else {
+ // Display current book
+ int bookIdx = _searchResults[_currentResult];
+ const LibraryBook &book = kLibraryBooks[bookIdx];
+
+ // Title (may be long, truncate if needed)
+ Common::String titleLine = Common::String::format("%s%s", _labelTitle, book.title);
+ g_engine->_smallFont->drawString(g_engine->_screen, titleLine, textX - 50, textY + 40, 340, 14);
+
+ // Author
+ Common::String authorLine = Common::String::format("%s%s", _labelAuthor, book.author);
+ g_engine->_smallFont->drawString(g_engine->_screen, authorLine, textX - 50, textY + 60, 340, 14);
+
+ // Genre
+ Common::String genreLine = Common::String::format("%s%s", _labelGenre, book.genre);
+ g_engine->_smallFont->drawString(g_engine->_screen, genreLine, textX - 50, textY + 80, 340, 14);
+
+ // Situacion (location/availability)
+ Common::String situacionLine;
+ if (book.available) {
+ situacionLine = Common::String::format("%sEstante %c, fila %d",
+ _labelSituacion, book.shelfLetter, book.shelfRow);
+ } else {
+ situacionLine = Common::String::format("%s%s",
+ _labelSituacion, _statusCatalogOnly);
+ }
+ g_engine->_smallFont->drawString(g_engine->_screen, situacionLine, textX - 50, textY + 100, 340,
+ book.available ? 10 : 8); // Green if physical, gray if catalog-only
+
+ // Show result counter
+ Common::String counter = Common::String::format("Libro %d de %d",
+ _currentResult + 1, (int)_searchResults.size());
+ g_engine->_smallFont->drawString(g_engine->_screen, counter, textX, textY + 130, 280, 14, Graphics::kTextAlignCenter);
+
+ // Show navigation options
+ Common::String navOptions;
+ if (book.available) {
+ navOptions = Common::String::format("%s %s %s", _optMemorizar, _optSeguir, _optCancelar);
+ } else {
+ navOptions = Common::String::format("%s %s", _optSeguir, _optCancelar);
+ }
+ g_engine->_smallFont->drawString(g_engine->_screen, navOptions, textX, textY + 160, 280, 8, Graphics::kTextAlignCenter);
+ }
+ }
+ break;
+
+ case STATE_EXIT:
+ break;
+ }
+}
+
+void Computer::handleMainMenu() {
+ if (_events->_lastKeyEvent == Common::KEYCODE_1) {
+ _searchType = 0;
+ _state = STATE_SEARCH_BY_TITLE;
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ } else if (_events->_lastKeyEvent == Common::KEYCODE_2) {
+ _searchType = 1;
+ _state = STATE_SEARCH_BY_AUTHOR;
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ } else if (_events->_lastKeyEvent == Common::KEYCODE_3) {
+ _state = STATE_EXIT;
+ }
+}
+
+void Computer::handleSearchInput() {
+ if (_events->_lastKeyEvent >= Common::KEYCODE_a &&
+ _events->_lastKeyEvent <= Common::KEYCODE_z) {
+ _searchLetter = 'A' + (_events->_lastKeyEvent - Common::KEYCODE_a);
+ performSearch();
+ _currentResult = 0;
+ _state = STATE_SHOW_RESULTS;
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ } else if (_events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
+ _state = STATE_MAIN_MENU;
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ }
+}
+
+void Computer::handleResultsDisplay() {
+ if (_events->_lastKeyEvent == Common::KEYCODE_s) {
+ if (!_searchResults.empty()) {
+ _currentResult = (_currentResult + 1) % _searchResults.size();
+ }
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ }
+ else if (_events->_lastKeyEvent == Common::KEYCODE_m) {
+ if (!_searchResults.empty()) {
+ int bookIdx = _searchResults[_currentResult];
+ const LibraryBook &book = kLibraryBooks[bookIdx];
+ if (book.available) {
+ memorizeBook(bookIdx);
+ }
+ }
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ }
+ // C key or ESC - Cancel (return to main menu)
+ else if (_events->_lastKeyEvent == Common::KEYCODE_c ||
+ _events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
+ _state = STATE_MAIN_MENU;
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ }
+}
+
+void Computer::memorizeBook(int bookIndex) {
+ const LibraryBook &book = kLibraryBooks[bookIndex];
+
+ // Store the memorized book for later pickup from the shelf
+ _memorizedBookIndex = bookIndex;
+
+ // In the original game, Alfred says "Bueno... Tendre que buscar en la estanteria de la X"
+ // where X is the shelf letter
+ // TODO: Play the dialog and set a game flag so the book can be picked up from the shelf
+
+ // For now, just exit the computer interface
+ // The game state should be updated to allow picking up this book from shelf X
+ _state = STATE_EXIT;
+
+ debug(1, "Memorized book '%s' at shelf %c, row %d", book.title, book.shelfLetter, book.shelfRow);
+}
+
+void Computer::performSearch() {
+ _searchResults.clear();
+
+ for (int i = 0; i < kLibraryBookCount; i++) {
+ const char *searchField = _searchType == 0 ?
+ kLibraryBooks[i].title : kLibraryBooks[i].author;
+
+ // Check if first letter matches (case-insensitive)
+ char firstChar = searchField[0];
+ if (firstChar >= 'a' && firstChar <= 'z')
+ firstChar = firstChar - 'a' + 'A';
+
+ if (firstChar == _searchLetter) {
+ _searchResults.push_back(i);
+ }
+ }
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/computer.h b/engines/pelrock/computer.h
new file mode 100644
index 00000000000..a9c3f7e1e00
--- /dev/null
+++ b/engines/pelrock/computer.h
@@ -0,0 +1,94 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PELROCK_COMPUTER_H
+#define PELROCK_COMPUTER_H
+
+#include "common/array.h"
+#include "common/str.h"
+
+#include "pelrock/events.h"
+
+namespace Pelrock {
+
+class PelrockEngine;
+
+class Computer {
+public:
+ Computer(PelrockEventManager *eventMan);
+ ~Computer();
+
+ /**
+ * @return Book index if a book was memorized, -1 otherwise
+ */
+ int run();
+
+private:
+ enum ComputerState {
+ STATE_MAIN_MENU,
+ STATE_SEARCH_BY_TITLE,
+ STATE_SEARCH_BY_AUTHOR,
+ STATE_SHOW_RESULTS,
+ STATE_EXIT
+ };
+
+ PelrockEventManager *_events;
+ byte *_backgroundScreen;
+ byte *_palette;
+
+ // State variables
+ ComputerState _state;
+ char _searchLetter;
+ int _searchType; // 0 = title, 1 = author
+ Common::Array<int> _searchResults;
+ int _currentResult;
+ int _memorizedBookIndex; // Index of book that was memorized (-1 if none)
+
+ const char *_menuTitle;
+ const char *_menuOption1; // "CONSULTAR POR TITULO"
+ const char *_menuOption2; // "CONSULTAR POR AUTOR"
+ const char *_menuOption3; // "CANCELAR"
+ const char *_promptLetter; // "Teclea una letra (A-Z):"
+ const char *_labelTitle; // "Titulo : "
+ const char *_labelAuthor; // "Autor : "
+ const char *_labelGenre; // "Genero : "
+ const char *_labelSituacion; // "Situacion : "
+ const char *_statusPhysical; // "Estante %c, fila %d"
+ const char *_statusCatalogOnly; // "Solo en catalogo"
+ const char *_optMemorizar; // "(M)emorizar"
+ const char *_optSeguir; // "(S)eguir"
+ const char *_optCancelar; // "(C)ancelar"
+ const char *_noResults; // "No se encontraron libros"
+ const char *_memorizedMsg; // "Bueno... Tendre que buscar en la estanteria de la %c"
+
+ void loadBackground();
+ void cleanup();
+ void handleMainMenu();
+ void handleSearchInput();
+ void handleResultsDisplay();
+ void performSearch();
+ void drawScreen();
+ void memorizeBook(int bookIndex);
+};
+
+} // End of namespace Pelrock
+
+#endif
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index e52fbf92f29..59a540cf077 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -69,4 +69,8 @@ void GraphicsManager::putBackgroundSlice(byte *buf, int x, int y, int w, int h,
}
}
+void GraphicsManager::clearScreen() {
+ memset(g_engine->_screen->getPixels(), 0, g_engine->_screen->pitch * g_engine->_screen->h);
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index ab604a63d56..caa28e18f4c 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -34,7 +34,7 @@ public:
Common::Point showOverlay(int height, byte *buf);
byte *grabBackgroundSlice(byte *buf, int x, int y, int w, int h);
void putBackgroundSlice(byte *buf, int x, int y, int w, int h, byte *slice);
-
+ void clearScreen();
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/library_books.h b/engines/pelrock/library_books.h
new file mode 100644
index 00000000000..a86a990948e
--- /dev/null
+++ b/engines/pelrock/library_books.h
@@ -0,0 +1,305 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * Alfred Pelrock Library Book Database
+ * Extracted from ALFRED.7 offset 0x309E0 to 0x33F05
+ *
+ * This file was auto-generated by extract_alfred7_books_full.py
+ * DO NOT EDIT MANUALLY
+ *
+ * Book format in ALFRED.7 (108 bytes per entry):
+ * - Title: 55 bytes (space-padded)
+ * - Author: 30 bytes (space-padded)
+ * - Genre: 20 bytes (space-padded)
+ * - Shelf Letter: 1 byte (A-Z or space if catalog-only)
+ * - Shelf Row: 1 byte (1-3 or space)
+ * - Status: 1 byte (0x01=catalog only, 0x02=physical copy)
+ */
+
+#ifndef PELROCK_LIBRARY_BOOKS_H
+#define PELROCK_LIBRARY_BOOKS_H
+
+#include "common/scummsys.h"
+
+namespace Pelrock {
+
+// Book data location in ALFRED.7
+static const uint32 kBookDataOffset = 0x309E0;
+static const uint32 kBookDataEnd = 0x33F05;
+static const int kBookEntrySize = 108; // 55 + 30 + 20 + 1 + 1 + 1
+
+// Field sizes
+static const int kBookTitleSize = 55;
+static const int kBookAuthorSize = 30;
+static const int kBookGenreSize = 20;
+
+// Status byte values
+static const byte kBookStatusCatalogOnly = 0x01; // No physical copy
+static const byte kBookStatusPhysical = 0x02; // Has physical copy on shelf
+
+struct LibraryBook {
+ const char *title;
+ const char *author;
+ const char *genre;
+ char shelfLetter; // A-Z for shelf location, space if catalog-only
+ byte shelfRow; // 1-3 for row number, 0 if catalog-only
+ bool available; // true = can be found on shelf, false = catalog only
+};
+
+static const int kLibraryBookCount = 125;
+
+static const LibraryBook kLibraryBooks[] = {
+ // Book 1: Los hombres: ¡ Como caparlos !
+ {"Los hombres: ¡ Como caparlos !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
+ // Book 2: Mujeres del mundo: ¡ No os depileis las ...
+ {"Mujeres del mundo: ¡ No os depileis las axilas !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
+ // Book 3: Gato por liebre
+ {"Gato por liebre", "Karlos Arguiñano", "Cocina", 'I', 1, true},
+ // Book 4: Hamlet
+ {"Hamlet", "William Shakespeare", "Teatro", ' ', 0, false},
+ // Book 5: Fausto
+ {"Fausto", "Goethe", "Novela", ' ', 0, false},
+ // Book 6: Enrique de Ofterdingen
+ {"Enrique de Ofterdingen", "Novalis", "Novela", 'J', 1, true},
+ // Book 7: Guia de desobediencia civica
+ {"Guia de desobediencia civica", "Azagra", "Ensayo", ' ', 0, false},
+ // Book 8: Literatura en la edad de piedra: cuestio...
+ {"Literatura en la edad de piedra: cuestion de fuerza", "Profesor Cebollo", "Ensayo", ' ', 0, false},
+ // Book 9: Turbo C ++ con Intratex
+ {"Turbo C ++ con Intratex", "Programadores reunidos", "Informatica", ' ', 0, false},
+ // Book 10: Codigo Maquina a pelo
+ {"Codigo Maquina a pelo", "Programadores reunidos", "Informatica", 'K', 1, true},
+ // Book 11: Asesino por vocacion
+ {"Asesino por vocacion", "Chema Ton", "Novela negra", ' ', 0, false},
+ // Book 12: Poemas rebuscados
+ {"Poemas rebuscados", "Ramon Rodriguez", "Poesia", ' ', 0, false},
+ // Book 13: El parto de las tortugas: Un proceso len...
+ {"El parto de las tortugas: Un proceso lento", "Profesor Lorin Colorado", "Biologia", ' ', 0, false},
+ // Book 14: Te parto la cara ¡ Capuyo !
+ {"Te parto la cara ¡ Capuyo !", "Jhonny Rapper", "Critica Social", 'L', 3, true},
+ // Book 15: En los tugurios del Himalaya
+ {"En los tugurios del Himalaya", "Coronel Tapioca", "Aventuras", ' ', 0, false},
+ // Book 16: En las callejuelas del amazonas
+ {"En las callejuelas del amazonas", "Coronel Tapioca", "Aventuras", ' ', 0, false},
+ // Book 17: En las selvas de Londres
+ {"En las selvas de Londres", "Coronel Tapioca", "Aventuras", 'M', 1, true},
+ // Book 18: Sueños binarios
+ {"Sueños binarios", "Doctor Chip", "Ciencia ficcion", ' ', 0, false},
+ // Book 19: Cien cuentos cortisimos
+ {"Cien cuentos cortisimos", "Billi el rapido", "Novela", ' ', 0, false},
+ // Book 20: Teoria de la relatividad
+ {"Teoria de la relatividad", "Alfred Einstein", "Ciencia", ' ', 0, false},
+ // Book 21: El ultimo paso para la cuadratura del ci...
+ {"El ultimo paso para la cuadratura del circulo", "Anonimo", "Filosofia", 'N', 1, true},
+ // Book 22: Correlacion entre el sentido de los colo...
+ {"Correlacion entre el sentido de los colores y sonidos", "Anonimo", "Filosofia", ' ', 0, false},
+ // Book 23: Los cuatro evangelios: Interpretados por...
+ {"Los cuatro evangelios: Interpretados por ordenador", "Doctor Chip", "Teologia", ' ', 0, false},
+ // Book 24: Enciclopedia de bolsillo
+ {"Enciclopedia de bolsillo", "Profesor Lumbreras", "Enciclopedia", 'O', 1, true},
+ // Book 25: Sigueme y revienta
+ {"Sigueme y revienta", "M. Indurain", "Deporte", 'P', 3, true},
+ // Book 26: Me duele too...
+ {"Me duele too...", "Carmen Opausica", "Ensayo", ' ', 0, false},
+ // Book 27: El Perro de Sam Rocker si tiene rabo
+ {"El Perro de Sam Rocker si tiene rabo", "El Perro de Sam Rocker", "Biografia", ' ', 0, false},
+ // Book 28: Donde estara mi carro ?
+ {"Donde estara mi carro ?", "Manolo Escobar", "Aventuras", ' ', 0, false},
+ // Book 29: Oh tu, bella flor del jardin
+ {"Oh tu, bella flor del jardin", "La abeja Maya", "Poesia", 'Q', 2, true},
+ // Book 30: Yogui, ¡ Bajate de esa motoneta !
+ {"Yogui, ¡ Bajate de esa motoneta !", "Bubu", "Filosofia", ' ', 0, false},
+ // Book 31: Odio a muerte a loh mardito rohedore !
+ {"Odio a muerte a loh mardito rohedore !", "Er gato Yin", "Zoologia", ' ', 0, false},
+ // Book 32: Pissi, Dissi, ¡ Sargan de su aguhero !
+ {"Pissi, Dissi, ¡ Sargan de su aguhero !", "Er gato Yin", "Zoologia", ' ', 0, false},
+ // Book 33: Mardito sea ... ¡ Er queso !
+ {"Mardito sea ... ¡ Er queso !", "Er gato Yin", "Zoologia", ' ', 0, false},
+ // Book 34: La mate porque era mia
+ {"La mate porque era mia", "Loquillo", "Novela", ' ', 0, false},
+ // Book 35: Los gallos: Esos desconocidos
+ {"Los gallos: Esos desconocidos", "Paco rico", "Zoologia", ' ', 0, false},
+ // Book 36: Cuentos corrientes
+ {"Cuentos corrientes", "Pepe Lopez", "Novela", 'R', 1, true},
+ // Book 37: Mas madera
+ {"Mas madera", "R. Gepetto", "Bricolage", 'S', 2, true},
+ // Book 38: Cuentos del Lejano Oriente
+ {"Cuentos del Lejano Oriente", "Jhonny Mc. Dowall", "Novela", ' ', 0, false},
+ // Book 39: Saca el guiski cheli
+ {"Saca el guiski cheli", "Manolo lailo", "Cronica Social", ' ', 0, false},
+ // Book 40: Ta totao !
+ {"Ta totao !", "Lao Tse", "Filosofia", ' ', 0, false},
+ // Book 41: Mis conversaciones con el señor Roca
+ {"Mis conversaciones con el señor Roca", "Francisca Gando", "Epistolar", 'T', 2, true},
+ // Book 42: Guia para la supervivencia
+ {"Guia para la supervivencia", "Robinson Crusoe", "Manual", ' ', 0, false},
+ // Book 43: No esperes a ser la segunda: ¡ Engaña a ...
+ {"No esperes a ser la segunda: ¡ Engaña a tu marido !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
+ // Book 44: Yoga Sutras
+ {"Yoga Sutras", "Patanjali", "Filosofia", 'X', 3, true},
+ // Book 45: El juego de los Abalorios
+ {"El juego de los Abalorios", "Herman Hesse", "Novela", ' ', 0, false},
+ // Book 46: Tienes suerte de ser tan pequeño, ¡ mard...
+ {"Tienes suerte de ser tan pequeño, ¡ mardito roedo !", "Er gato Yin", "Novela", ' ', 0, false},
+ // Book 47: Como hacerse rico en diez minutos
+ {"Como hacerse rico en diez minutos", "El Dioni", "Manual", 'Y', 1, true},
+ // Book 48: Te querre a pesar de tu madre
+ {"Te querre a pesar de tu madre", "Corin Tellado", "Novela rosa", ' ', 0, false},
+ // Book 49: Hasta que el mando a distancia nos separ...
+ {"Hasta que el mando a distancia nos separe", "Corin Tellado", "Novela rosa", ' ', 0, false},
+ // Book 50: Una pasion ostentorea
+ {"Una pasion ostentorea", "Corin Tellado y Jesus Gil", "Novela rosa", 'Z', 3, true},
+ // Book 51: Por mi, como si te la machacas
+ {"Por mi, como si te la machacas", "Seneca", "Filosofia", ' ', 0, false},
+ // Book 52: Conversaciones con mi caballo
+ {"Conversaciones con mi caballo", "Jesus Gil", "Humor", ' ', 0, false},
+ // Book 53: El poder curativo de la mierda comun
+ {"El poder curativo de la mierda comun", "Sri Ramachrinaraska", "Esoterismo", ' ', 1, true},
+ // Book 54: La liberacion mediante la eneriga de los...
+ {"La liberacion mediante la eneriga de los pedos", "Sri Ramachrinaraska", "Esoterismo", ' ', 0, false},
+ // Book 55: Sobre la imperceptibilidad de lo imperce...
+ {"Sobre la imperceptibilidad de lo imperceptible", "Perogrullo", "Ensayo", ' ', 0, false},
+ // Book 56: Piojos; como educarlos sin traumas
+ {"Piojos; como educarlos sin traumas", "Franz Franzfrenz", "Psicologia", ' ', 0, false},
+ // Book 57: I Ching
+ {"I Ching", "Richard Willem", "Filosofia", ' ', 0, false},
+ // Book 58: No se nada, ni me importa
+ {"No se nada, ni me importa", "Socrates", "Filosofia", 'U', 2, true},
+ // Book 59: No he sido yo, ¡ Lo juro !
+ {"No he sido yo, ¡ Lo juro !", "Juan Jose Gil", "Biografia", ' ', 0, false},
+ // Book 60: Relatos cortos
+ {"Relatos cortos", "Tachenko", "Novela de ficcion", 'V', 3, true},
+ // Book 61: El martillo como elemento cognitivo
+ {"El martillo como elemento cognitivo", "Friedrich Nietzsche", "Filosofia", ' ', 0, false},
+ // Book 62: La maravillosa vida del escarabajo pelot...
+ {"La maravillosa vida del escarabajo pelotero (v. I)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
+ // Book 63: La maravillosa vida del escarabajo pelot...
+ {"La maravillosa vida del escarabajo pelotero (v. II)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
+ // Book 64: La maravillosa vida del escarabajo pelot...
+ {"La maravillosa vida del escarabajo pelotero (v. III)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
+ // Book 65: La maravillosa vida del escarabajo pelot...
+ {"La maravillosa vida del escarabajo pelotero (v. IV)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
+ // Book 66: La maravillosa vida del escarabajo pelot...
+ {"La maravillosa vida del escarabajo pelotero (v. V)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
+ // Book 67: Tu eliges: Tu madre o yo
+ {"Tu eliges: Tu madre o yo", "Anonimo", "Psicologia aplicada", 'W', 3, true},
+ // Book 68: Mi lucha
+ {"Mi lucha", "Adolf Hitler", "Humor negro", ' ', 0, false},
+ // Book 69: Cuentos de amor y desidia
+ {"Cuentos de amor y desidia", "Jardiel Poncela", "Teatro", ' ', 1, true},
+ // Book 70: Nuevas andanzas de Zaratustra
+ {"Nuevas andanzas de Zaratustra", "Anonimo", "Aventuras", ' ', 2, true},
+ // Book 71: Me se cuadre ¡ Coño !
+ {"Me se cuadre ¡ Coño !", "Sargento Cienfuegos", "Etica militar", ' ', 2, true},
+ // Book 72: Gatos: solos o con Ketchup
+ {"Gatos: solos o con Ketchup", "El perro de Sam Rocker", "Cocina", ' ', 1, true},
+ // Book 73: Querida Adelaida: mi marido NO ha dejado...
+ {"Querida Adelaida: mi marido NO ha dejado de roncar", "Maruja Mones", "Epistolar", ' ', 0, false},
+ // Book 74: Sobre el papel de El Lepe en el nuevo Or...
+ {"Sobre el papel de El Lepe en el nuevo Orden Mundial", "General Sintacha", "Estrategia", ' ', 0, false},
+ // Book 75: Aqui no hay nadie que se acueste sin cen...
+ {"Aqui no hay nadie que se acueste sin cenar (v. I)", "Fidel Castro", "Politica", ' ', 1, true},
+ // Book 76: Aqui no hay nadie que se acueste sin cen...
+ {"Aqui no hay nadie que se acueste sin cenar (v. II)", "Fidel Castro", "Politica", ' ', 0, false},
+ // Book 77: Aqui no hay nadie que se acueste sin cen...
+ {"Aqui no hay nadie que se acueste sin cenar (v. III)", "Fidel Castro", "Politica", ' ', 0, false},
+ // Book 78: Aqui no hay nadie que se acueste sin cen...
+ {"Aqui no hay nadie que se acueste sin cenar (v. IV)", "Fidel Castro", "Politica", ' ', 0, false},
+ // Book 79: Aqui no hay nadie que se acueste sin cen...
+ {"Aqui no hay nadie que se acueste sin cenar (v. V)", "Fidel Castro", "Politica", ' ', 0, false},
+ // Book 80: Domine la metafisica en 5 dias
+ {"Domine la metafisica en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
+ // Book 81: Domine el ensamblador en 5 dias
+ {"Domine el ensamblador en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
+ // Book 82: Dominese a si mismo en 5 dias
+ {"Dominese a si mismo en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
+ // Book 83: Piernas de Ciertopelo
+ {"Piernas de Ciertopelo", "Chichi Mondongo", "Erotica", ' ', 2, true},
+ // Book 84: Otra vuelta de tuerca
+ {"Otra vuelta de tuerca", "Pepe, el fontanero", "Bricolage", ' ', 2, true},
+ // Book 85: La Tierra: ¡ Planeta limpio !
+ {"La Tierra: ¡ Planeta limpio !", "Juan, el basurero", "Ciencia Ficcion", ' ', 2, true},
+ // Book 86: Liberad a Brian !
+ {"Liberad a Brian !", "Roger Rabitt", "Historica", ' ', 2, true},
+ // Book 87: La vida es una mierda
+ {"La vida es una mierda", "Juanjo Dido", "Ensayo", ' ', 2, true},
+ // Book 88: No era eso lo que yo di a entender
+ {"No era eso lo que yo di a entender", "Jesus de Nazaret", "Religion", ' ', 2, true},
+ // Book 89: Castigos a Piratas Informaticos
+ {"Castigos a Piratas Informaticos", "Torquemada", "Inquisicion", ' ', 1, true},
+ // Book 90: Confiesa, bruja asquerosa
+ {"Confiesa, bruja asquerosa", "Troquemada", "Inquisicion", ' ', 1, true},
+ // Book 91: El cocherito lere
+ {"El cocherito lere", "Paco costas", "Automovilismo", ' ', 1, true},
+ // Book 92: La musica amansa a las fieras
+ {"La musica amansa a las fieras", "Wagner", "Musica", ' ', 2, true},
+ // Book 93: Pinocho en el Parlamento
+ {"Pinocho en el Parlamento", "Carmen Tirosa", "Cronica Social", ' ', 0, false},
+ // Book 94: Hagase famoso gracias a la energia de la...
+ {"Hagase famoso gracias a la energia de las petunias", "Carmelo Cuelo", "Esoterismo", ' ', 0, false},
+ // Book 95: Dios mio, ¡ Que cruz !
+ {"Dios mio, ¡ Que cruz !", "Jesus de Nazaret", "Autobiografia", ' ', 0, false},
+ // Book 96: Psicologia de la motivacion inmotivada
+ {"Psicologia de la motivacion inmotivada", "Dr. Chemi", "Psicologia", ' ', 2, true},
+ // Book 97: Magia rosa para iniciados
+ {"Magia rosa para iniciados", "Manolo Lailo", "Esoterismo", ' ', 0, false},
+ // Book 98: Un mundo Feliz
+ {"Un mundo Feliz", "Aldous Huxley", "Novela", ' ', 0, false},
+ // Book 99: Sexo oral y por escrito
+ {"Sexo oral y por escrito", "Franz Masturmann", "Sexologia", ' ', 3, true},
+ // Book 100: El contrato social de aprendizaje
+ {"El contrato social de aprendizaje", "Rousseau", "Ensayo", ' ', 1, true},
+ // Book 101: Vida sexual del escarabajo de la Patagon...
+ {"Vida sexual del escarabajo de la Patagonia", "Dr. Tedio Plomez", "Botanica", ' ', 3, true},
+ // Book 102: Manual del necrofago
+ {"Manual del necrofago", "Jesus Gil", "Manual", ' ', 0, false},
+ // Book 103: Canticos espirituales en formato *.ZIP
+ {"Canticos espirituales en formato *.ZIP", "Doctor Chip", "Poesia", 'B', 1, true},
+ // Book 104: Novela erotica en formato *.MAS
+ {"Novela erotica en formato *.MAS", "Doctor Chip", "Erotica", ' ', 0, false},
+ // Book 105: Plopuestas colelacionales en coyuntulas ...
+ {"Plopuestas colelacionales en coyuntulas bilatelales", "Senadol Chan Chu Yo", "Politica", ' ', 0, false},
+ // Book 106: Ereh un fistro
+ {"Ereh un fistro", "Chiquito de la casa", "Humor", ' ', 0, false},
+ // Book 107: El hacedor de la Lluvia
+ {"El hacedor de la Lluvia", "Herman Hesse", "Cuentos", ' ', 0, false},
+ // Book 108: Pasiones recalcitrantes
+ {"Pasiones recalcitrantes", "Corin Tellado", "Novela rosa", 'C', 2, true},
+ // Book 109: No me mates con tomate
+ {"No me mates con tomate", "Karlos Arguiñano", "Cocina", ' ', 0, false},
+ // Book 110: El valenciano en los albores del siglo X...
+ {"El valenciano en los albores del siglo XXI", "Jaume i Pascual", "Nacionalismo", 'D', 1, true},
+ // Book 111: El valenciano es la lengua del futuro
+ {"El valenciano es la lengua del futuro", "Jaume i Pascual", "Nacionalismo", ' ', 0, false},
+ // Book 112: Valencia: mes que mai
+ {"Valencia: mes que mai", "Jaume i Pascual", "Nacionalismo", ' ', 0, false},
+ // Book 113: Sistema inmunitario de los cefalopodos (...
+ {"Sistema inmunitario de los cefalopodos (v. I)", "Dr. Tedio Plomez", "Biologia", 'E', 3, true},
+ // Book 114: Sistema inmunitario de los cefalopodos (...
+ {"Sistema inmunitario de los cefalopodos (v. II)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
+ // Book 115: Sistema inmunitario de los cefalopodos (...
+ {"Sistema inmunitario de los cefalopodos (v. III)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
+ // Book 116: Sistema inmunitario de los cefalopodos (...
+ {"Sistema inmunitario de los cefalopodos (v. IV)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
+ // Book 117: Sistema inmunitario de los cefalopodos (...
+ {"Sistema inmunitario de los cefalopodos (v. V)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
+ // Book 118: Dos mas dos son cinco
+ {"Dos mas dos son cinco", "Joan Josep Climent Colomer", "Matematicas", 'F', 1, true},
+ // Book 119: El algebra es la base de la programacion
+ {"El algebra es la base de la programacion", "Joan Josep Climent Colomer", "Humor absurdo", ' ', 0, false},
+ // Book 120: Autobiografia de una miseria humana
+ {"Autobiografia de una miseria humana", "Joan Josep Climent Colomer", "Esperpento", ' ', 0, false},
+ // Book 121: El arte mundial antes y despues de mi
+ {"El arte mundial antes y despues de mi", "Nacho Taulet Perman", "Arte", ' ', 0, false},
+ // Book 122: La parte Creativa
+ {"La parte Creativa", "Nacho Taulet Perman", "Arte", 'G', 2, true},
+ // Book 123: Llamame cuando se muera tu abuelo
+ {"Llamame cuando se muera tu abuelo", "Jose Bart Carrion", "Teatro", ' ', 0, false},
+ // Book 124: Soy un incomprendido
+ {"Soy un incomprendido", "Jose Bart Carrion", "Autobiografia", ' ', 0, false},
+ // Book 125: El arte de limpiar botijos por dentro
+ {"El arte de limpiar botijos por dentro", "Varios autores", "Manualidades", ' ', 0, false},
+};
+
+} // namespace Pelrock
+
+#endif // PELROCK_LIBRARY_BOOKS_H
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index b8da093fb03..a2bea00e420 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -135,26 +135,29 @@ void MenuManager::checkMouseClick(int x, int y) {
}
void MenuManager::menuLoop() {
- _events->pollEvent();
-
- if (_events->_leftMouseClicked) {
- checkMouseClick(_events->_mouseX, _events->_mouseY);
- _events->_leftMouseClicked = false;
- } else if (_events->_rightMouseClicked) {
- g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
- g_engine->_state->stateGame = GAME;
- _events->_rightMouseClicked = false;
- tearDown();
- } else {
- if (_events->_lastKeyEvent == Common::KEYCODE_b) {
- // g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
- // g_engine->stateGame = GAME;
- showButtons = !showButtons;
- _events->_lastKeyEvent = Common::KEYCODE_INVALID;
- // tearDown();
+
+ g_engine->changeCursor(DEFAULT);
+ while (!g_engine->shouldQuit() && !_events->_rightMouseClicked) {
+
+ _events->pollEvent();
+
+ if (_events->_leftMouseClicked) {
+ checkMouseClick(_events->_mouseX, _events->_mouseY);
+ _events->_leftMouseClicked = false;
}
+
+ drawScreen();
+ _screen->markAllDirty();
+ _screen->update();
+ g_system->delayMillis(10);
}
+ g_engine->_graphics->clearScreen();
+ _events->_rightMouseClicked = false;
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+ cleanUp();
+}
+void MenuManager::drawScreen() {
memcpy(_compositeBuffer, _mainMenu, 640 * 400);
// memset(_compositeBuffer, 0, 640 * 400);
if (showButtons)
@@ -168,8 +171,6 @@ void MenuManager::menuLoop() {
}
drawText(g_engine->_smallFont, Common::String::format("%d,%d", _events->_mouseX, _events->_mouseY), 0, 0, 640, 13);
- _screen->markAllDirty();
- _screen->update();
}
void MenuManager::drawInventoryIcons() {
@@ -308,7 +309,7 @@ void MenuManager::loadMenuTexts() {
exe.close();
}
-void MenuManager::tearDown() {
+void MenuManager::cleanUp() {
}
void MenuManager::drawButtons() {
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 3de2bc10f92..32b0b14505d 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -51,6 +51,7 @@ public:
MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res);
~MenuManager();
void menuLoop();
+ void drawScreen();
void drawInventoryIcons();
void loadMenu();
byte _mainMenuPalette[768] = {0};
@@ -58,7 +59,7 @@ public:
private:
void checkMouseClick(int x, int y);
void loadMenuTexts();
- void tearDown();
+ void cleanUp();
void drawButtons();
void drawColoredText(Graphics::ManagedSurface *surface, const Common::String &text, int x, int y, int w, Graphics::Font *font);
void readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect);
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index fc5b879566f..5a295a952b0 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -4,6 +4,7 @@ MODULE_OBJS = \
pelrock.o \
actions.o \
chrono.o \
+ computer.o \
console.o \
metaengine.o \
room.o \
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 28ce2b527de..f9d1b13e358 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -36,6 +36,7 @@
#include "pelrock.h"
#include "pelrock/actions.h"
+#include "pelrock/computer.h"
#include "pelrock/console.h"
#include "pelrock/detection.h"
#include "pelrock/fonts/small_font.h"
@@ -111,31 +112,24 @@ Common::Error PelrockEngine::run() {
if (saveSlot != -1)
(void)loadGameState(saveSlot);
- // Simple event handling loop
- Graphics::FrameLimiter limiter(g_system, 60);
-
- if (shouldPlayIntro == false) {
- _state->stateGame = GAME;
- // stateGame = SETTINGS;
- } else {
- _state->stateGame = INTRO;
- _videoManager->playIntro();
- _state->stateGame = GAME;
- }
- if (!shouldQuit())
- init();
+ _state->stateGame = shouldPlayIntro ? INTRO : GAME;
+ init();
while (!shouldQuit()) {
-
if (_state->stateGame == SETTINGS) {
- changeCursor(DEFAULT);
_menu->menuLoop();
+ _state->stateGame = GAME;
} else if (_state->stateGame == GAME) {
gameLoop();
}
- _screen->update();
- // limiter.delayBeforeSwap();
- // limiter.startFrame();
+ else if (_state->stateGame == INTRO) {
+ _videoManager->playIntro();
+ _state->stateGame = GAME;
+ }
+ else if (_state->stateGame == COMPUTER) {
+ computerLoop();
+ _state->stateGame = GAME;
+ }
}
return Common::kNoError;
@@ -1227,9 +1221,16 @@ void PelrockEngine::pickupIconFlash() {
}
void PelrockEngine::gameLoop() {
- _events->pollEvent();
- checkMouse();
- renderScene();
+
+ _events->pollEvent();
+ checkMouse();
+ renderScene();
+ _screen->update();
+}
+
+void PelrockEngine::computerLoop() {
+ Computer computer(_events);
+ computer.run();
}
void PelrockEngine::extraScreenLoop() {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 1d9970cab01..3edb3a915b8 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -61,10 +61,8 @@ private:
Common::RandomSource _randomSource;
VideoManager *_videoManager = nullptr;
SoundManager *_sound = nullptr;
- PelrockEventManager *_events = nullptr;
DialogManager *_dialog = nullptr;
MenuManager *_menu = nullptr;
- GraphicsManager *_graphics = nullptr;
void init();
void loadAnims();
@@ -103,13 +101,13 @@ private:
void chooseAlfredStateAndDraw();
void drawAlfred(byte *buf);
void drawNextFrame(Sprite *animSet);
- void changeCursor(Cursor cursor);
void animateTalkingNPC(Sprite *animSet);
void pickupIconFlash();
void playSoundIfNeeded();
void gameLoop();
+ void computerLoop();
void extraScreenLoop();
void walkLoop(int16 x, int16 y, AlfredDirection direction);
@@ -156,10 +154,12 @@ protected:
Common::Error run() override;
public:
+ GraphicsManager *_graphics = nullptr;
Graphics::Screen *_screen = nullptr;
ResourceManager *_res = nullptr;
RoomManager *_room = nullptr;
ChronoManager *_chrono = nullptr;
+ PelrockEventManager *_events = nullptr;
AlfredState _alfredState;
byte *_compositeBuffer = nullptr; // Working composition buffer
@@ -223,12 +223,14 @@ public:
void setScreen(int s, AlfredDirection dir);
void loadExtraScreenAndPresent(int screenIndex);
void waitForSpecialAnimation();
- void doExtraActions(int roomNumber);
bool renderScene(int overlayMode = OVERLAY_NONE);
+ void changeCursor(Cursor cursor);
+
+ // Actions
+ void doExtraActions(int roomNumber);
void addInventoryItem(int item);
void buyFromStore(HotSpot *hotspot, int stickerId);
- // Actions
void performActionTrigger(uint16 actionTrigger);
void dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 65b9ea944b4..db0570ea3bd 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -311,12 +311,10 @@ struct ScaleCalculation {
enum GameState {
GAME = 100,
- MENU = 101,
- CREDITS = 102,
- SAVELOAD = 103,
- SETTINGS = 104,
- EXTRA_SCREEN = 105,
- INTRO = 106,
+ CREDITS = 101,
+ SETTINGS = 102,
+ INTRO = 103,
+ COMPUTER = 104
};
struct HotSpotChange {
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index e4b8c5d370f..e105ca50e73 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -19,12 +19,13 @@
*
*/
#include "common/stream.h"
+
+#include "graphics/cursorman.h"
#include "graphics/font.h"
#include "pelrock/pelrock.h"
#include "pelrock/types.h"
#include "pelrock/util.h"
-#include "util.h"
namespace Pelrock {
Commit: 463759106ffac067400fa8aee679a4a5bcb4f2a6
https://github.com/scummvm/scummvm/commit/463759106ffac067400fa8aee679a4a5bcb4f2a6
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:49+02:00
Commit Message:
PELROCK: Cleanup
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/sound.cpp
engines/pelrock/types.h
engines/pelrock/util.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 1b18c8f46d1..633e2e1f318 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -21,7 +21,6 @@
#include "graphics/paletteman.h"
-#include "pelrock.h"
#include "pelrock/actions.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
@@ -126,7 +125,7 @@ void PelrockEngine::closeDoor(HotSpot *hotspot, int exitIndex, int sticker, bool
}
void PelrockEngine::addInventoryItem(int item) {
- if (_state->inventoryItems.size() == 0) {
+ if (_state->inventoryItems.empty()) {
_state->selectedInventoryItem = item;
}
_flashingIcon = item;
@@ -228,7 +227,7 @@ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
addInventoryItem(75);
} else {
int billCount = 0;
- for (int i = 0; i < _state->inventoryItems.size(); i++) {
+ for (uint i = 0; i < _state->inventoryItems.size(); i++) {
if (_state->inventoryItems[i] == 5) {
billCount++;
}
@@ -445,7 +444,7 @@ void PelrockEngine::useCordWithPlug(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::pickCables(HotSpot *hotspot) {
- if(_room->hasSticker(21)) {
+ if (_room->hasSticker(21)) {
_dialog->say(_res->_ingameTexts[QUELOSCOJA_SUPADRE]);
return;
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 020414d7a5a..3e2bebb996a 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -20,7 +20,6 @@
*/
#include "pelrock/dialog.h"
-#include "dialog.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
@@ -113,7 +112,7 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *c
int overlayHeight = choices->size() * kChoiceHeight + 2;
Common::Point overlayPos = _graphics->showOverlay(overlayHeight, compositeBuffer);
- for (int i = 0; i < choices->size(); i++) {
+ for (uint i = 0; i < choices->size(); i++) {
ChoiceOption choice = (*choices)[i];
int choicePadding = 32;
int width = g_engine->_doubleSmallFont->getStringWidth(choice.text);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f9d1b13e358..4002e663f55 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -121,12 +121,10 @@ Common::Error PelrockEngine::run() {
_state->stateGame = GAME;
} else if (_state->stateGame == GAME) {
gameLoop();
- }
- else if (_state->stateGame == INTRO) {
+ } else if (_state->stateGame == INTRO) {
_videoManager->playIntro();
_state->stateGame = GAME;
- }
- else if (_state->stateGame == COMPUTER) {
+ } else if (_state->stateGame == COMPUTER) {
computerLoop();
_state->stateGame = GAME;
}
@@ -240,7 +238,7 @@ bool PelrockEngine::renderScene(int overlayMode) {
updateAnimations();
// Some stickers need to be placed AFTER sprites, hardcoded in the original
if (_room->_currentRoomNumber == 3) {
- for (int i = 0; i < _state->stickersPerRoom[3].size(); i++) {
+ for (uint i = 0; i < _state->stickersPerRoom[3].size(); i++) {
if (_state->stickersPerRoom[3][i].stickerIndex == 14) {
placeSticker(_state->stickersPerRoom[3][i]);
break;
@@ -354,7 +352,7 @@ void PelrockEngine::updateAnimations() {
sortAnimsByZOrder(_room->_currentRoomAnims);
// First pass: sprites behind Alfred (y <= alfredY)
- for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].zOrder > 10 || _room->_currentRoomAnims[i].zOrder < 0) {
drawNextFrame(&_room->_currentRoomAnims[i]);
}
@@ -364,7 +362,7 @@ void PelrockEngine::updateAnimations() {
chooseAlfredStateAndDraw();
// Second pass: sprites in front of Alfred (y > alfredY)
- for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].zOrder <= 10 && _room->_currentRoomAnims[i].zOrder >= 0) {
drawNextFrame(&_room->_currentRoomAnims[i]);
}
@@ -399,7 +397,7 @@ void PelrockEngine::paintDebugLayer() {
bool showWalkboxes = false;
if (showWalkboxes) {
- for (int i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
+ for (uint i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
WalkBox box = _room->_currentRoomWalkboxes[i];
drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
// _smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
@@ -408,7 +406,7 @@ void PelrockEngine::paintDebugLayer() {
bool showSprites = true;
if (showSprites) {
- for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
Sprite sprite = _room->_currentRoomAnims[i];
drawRect(_screen, sprite.x, sprite.y, sprite.animData->w, sprite.animData->h, 14);
_smallFont->drawString(_screen, Common::String::format("S %d", sprite.index), sprite.x + 2, sprite.y, 640, 14);
@@ -417,7 +415,7 @@ void PelrockEngine::paintDebugLayer() {
bool showHotspots = true;
if (showHotspots) {
- for (int i = 0; i < _room->_currentRoomHotspots.size(); i++) {
+ for (uint i = 0; i < _room->_currentRoomHotspots.size(); i++) {
HotSpot hotspot = _room->_currentRoomHotspots[i];
if (!hotspot.isEnabled || hotspot.isSprite)
continue;
@@ -429,7 +427,7 @@ void PelrockEngine::paintDebugLayer() {
bool showExits = true;
if (showExits) {
- for (int i = 0; i < _room->_currentRoomExits.size(); i++) {
+ for (uint i = 0; i < _room->_currentRoomExits.size(); i++) {
Exit exit = _room->_currentRoomExits[i];
drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 200 + i);
_smallFont->drawString(_screen, Common::String::format("Exit %d -> Room %d", i, exit.targetRoom), exit.x + 2, exit.y + 2, 640, 14);
@@ -450,7 +448,7 @@ void PelrockEngine::paintDebugLayer() {
void PelrockEngine::placeStickers() {
// also place temporary stickers
- for (int i = 0; i < _room->_roomStickers.size(); i++) {
+ for (uint i = 0; i < _room->_roomStickers.size(); i++) {
Sticker sticker = _room->_roomStickers[i];
placeSticker(sticker);
}
@@ -539,6 +537,7 @@ void PelrockEngine::animateRotatePalette(PaletteAnim *anim) {
_room->_roomPalette[(anim->startIndex + i) * 3 + 1] = paletteValues[srcIndex * 3 + 1];
_room->_roomPalette[(anim->startIndex + i) * 3 + 2] = paletteValues[srcIndex * 3 + 2];
}
+ delete[] paletteValues;
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
@@ -571,7 +570,7 @@ void PelrockEngine::doAction(VerbIcon action, HotSpot *hotspot) {
void PelrockEngine::talkTo(HotSpot *hotspot) {
Sprite *animSet = nullptr;
- for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].index == hotspot->index) {
animSet = &_room->_currentRoomAnims[i];
animSet->isTalking = true;
@@ -1120,7 +1119,7 @@ int PelrockEngine::isHotspotUnder(int x, int y) {
}
Exit *PelrockEngine::isExitUnder(int x, int y) {
- for (int i = 0; i < _room->_currentRoomExits.size(); i++) {
+ for (uint i = 0; i < _room->_currentRoomExits.size(); i++) {
Exit exit = _room->_currentRoomExits[i];
if (x >= exit.x && x <= (exit.x + exit.w) &&
y >= exit.y && y <= (exit.y + exit.h) && exit.isEnabled) {
@@ -1134,6 +1133,9 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
* Checks if the given position is actually frame data or transparent pixel
*/
bool PelrockEngine::isSpriteUnder(Sprite *sprite, int x, int y) {
+ if (sprite == nullptr) {
+ return false;
+ }
Anim &animData = sprite->animData[sprite->curAnimIndex];
int curFrame = animData.curFrame;
@@ -1154,7 +1156,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
VerbIcon icon = isActionUnder(_events->_mouseX, _events->_mouseY);
bool shouldBlink = _chrono->getFrameCount() % kIconBlinkPeriod == 0;
- for (int i = 0; i < actions.size(); i++) {
+ for (uint i = 0; i < actions.size(); i++) {
if (icon == actions[i] && shouldBlink) {
continue;
}
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index ff01637d04b..8a47740db83 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -22,9 +22,8 @@
#include "pelrock/resources.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
+#include "pelrock/room.h"
#include "pelrock/util.h"
-#include "resources.h"
-#include "room.h"
namespace Pelrock {
@@ -226,20 +225,19 @@ void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
}
alfred7.seek(offset.offset, SEEK_SET);
- if(_currentSpecialAnim)
+ if (_currentSpecialAnim)
delete _currentSpecialAnim;
_currentSpecialAnim = new AlfredSpecialAnim(offset.numFrames, offset.w, offset.h, offset.numBudas, offset.offset, offset.loops);
_currentSpecialAnim->animData = new byte[offset.numFrames * offset.w * offset.h];
- if(offset.numBudas > 0) {
+ if (offset.numBudas > 0) {
mergeRleBlocks(&alfred7, offset.offset, offset.numBudas, _currentSpecialAnim->animData);
- }
- else {
+ } else {
alfred7.read(_currentSpecialAnim->animData, offset.numFrames * offset.w * offset.h);
}
- if(reverse) {
+ if (reverse) {
// reverse frames for testing
byte *reversedData = new byte[offset.numFrames * offset.w * offset.h];
- for(int i = 0; i < offset.numFrames; i++) {
+ for (int i = 0; i < offset.numFrames; i++) {
extractSingleFrame(_currentSpecialAnim->animData,
&reversedData[i * offset.w * offset.h],
offset.numFrames - 1 - i,
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 9e7a1e7efd5..d0fb17c4754 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -23,7 +23,6 @@
#include "pelrock/pelrock.h"
#include "pelrock/room.h"
#include "pelrock/util.h"
-#include "room.h"
namespace Pelrock {
@@ -105,37 +104,31 @@ void RoomManager::onlyPersistSticker(byte room, int stickerId) {
}
void RoomManager::removeSticker(int stickerIndex) {
- int index = -1;
- if (index == -1) {
- for (int i = 0; i < _roomStickers.size(); i++) {
- if (_roomStickers[i].stickerIndex == stickerIndex) {
- index = i;
- _roomStickers.remove_at(index);
- return;
- }
+ // First check and remove from room stickers
+ for (uint i = 0; i < _roomStickers.size(); i++) {
+ if (_roomStickers[i].stickerIndex == stickerIndex) {
+ _roomStickers.remove_at(i);
+ return;
}
}
- for (int i = 0; i < g_engine->_state->stickersPerRoom[_currentRoomNumber].size(); i++) {
+ // Then check and remove from persisted stickers
+ for (uint i = 0; i < g_engine->_state->stickersPerRoom[_currentRoomNumber].size(); i++) {
if (g_engine->_state->stickersPerRoom[_currentRoomNumber][i].stickerIndex == stickerIndex) {
- index = i;
- g_engine->_state->stickersPerRoom[_currentRoomNumber].remove_at(index);
- break;
+ g_engine->_state->stickersPerRoom[_currentRoomNumber].remove_at(i);
+ return;
}
}
-
- if (index != -1 && index < g_engine->_state->stickersPerRoom[_currentRoomNumber].size())
- g_engine->_state->stickersPerRoom[_currentRoomNumber].remove_at(index);
}
bool RoomManager::hasSticker(int index) {
- for (int i = 0; i < g_engine->_state->stickersPerRoom[_currentRoomNumber].size(); i++) {
+ for (uint i = 0; i < g_engine->_state->stickersPerRoom[_currentRoomNumber].size(); i++) {
if (g_engine->_state->stickersPerRoom[_currentRoomNumber][i].stickerIndex == index) {
return true;
}
}
- for (int i = 0; i < _roomStickers.size(); i++) {
+ for (uint i = 0; i < _roomStickers.size(); i++) {
if (_roomStickers[i].stickerIndex == index) {
return true;
}
@@ -204,7 +197,7 @@ void RoomManager::addWalkbox(WalkBox walkbox) {
}
Sprite *RoomManager::findSpriteByIndex(byte index) {
- for (int i = 0; i < _currentRoomAnims.size(); i++) {
+ for (uint i = 0; i < _currentRoomAnims.size(); i++) {
if (_currentRoomAnims[i].index == index) {
return &_currentRoomAnims[i];
}
@@ -213,7 +206,7 @@ Sprite *RoomManager::findSpriteByIndex(byte index) {
}
HotSpot *RoomManager::findHotspotByIndex(byte index) {
- for (int i = 0; i < _currentRoomHotspots.size(); i++) {
+ for (uint i = 0; i < _currentRoomHotspots.size(); i++) {
if (!_currentRoomHotspots[i].isSprite && _currentRoomHotspots[i].innerIndex == index) {
debug("Found hotspot %d at index %d, extra = %d", index, i, _currentRoomHotspots[i].extra);
return &_currentRoomHotspots[i];
@@ -223,7 +216,7 @@ HotSpot *RoomManager::findHotspotByIndex(byte index) {
}
HotSpot *RoomManager::findHotspotByExtra(uint16 extra) {
- for (int i = 0; i < _currentRoomHotspots.size(); i++) {
+ for (uint i = 0; i < _currentRoomHotspots.size(); i++) {
if (_currentRoomHotspots[i].extra == extra) {
return &_currentRoomHotspots[i];
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 3feb2b25913..cb676dbabd6 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -77,7 +77,7 @@ public:
void changeHotspot(byte room, HotSpot hotspot);
void disableSprite(byte roomNumber, int spriteIndex, bool persist = true);
void enableSprite(int spriteIndex, int zOrder, bool persist = true);
- void enableSprite(byte roomNumber,int spriteIndex, int zOrder, bool persist = true);
+ void enableSprite(byte roomNumber, int spriteIndex, int zOrder, bool persist = true);
/**
* Utility function to enable or disable a hotspot, with an option to persist the change.
*/
@@ -92,9 +92,9 @@ public:
void applyDisabledChoices(byte roomNumber, byte *conversationData, size_t conversationDataSize);
void applyDisabledChoice(ResetEntry entry, byte *conversationData, size_t conversationDataSize);
void addDisabledChoice(ChoiceOption choice);
- bool isPickableByExtra(uint16 extra) {
+ bool isPickableByExtra(uint16 extra) {
int size = sizeof(unpickableHotspotExtras) / sizeof(unpickableHotspotExtras[0]);
- for(int i = 0; i < size; i++) {
+ for (int i = 0; i < size; i++) {
if (extra == unpickableHotspotExtras[i])
return false;
}
@@ -106,7 +106,7 @@ public:
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
Common::String getRoomName(int roomNumber) {
- if (roomNumber >= 0 && roomNumber < _roomNames.size()) {
+ if (roomNumber >= 0 && (uint)roomNumber < _roomNames.size()) {
return _roomNames[roomNumber];
}
return "Unknown Room";
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 530a7c934c6..deea925d318 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -34,7 +34,6 @@
#include "pelrock/pelrock.h"
#include "pelrock/sound.h"
-#include "sound.h"
namespace Pelrock {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index db0570ea3bd..72ecc35def2 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -508,7 +508,7 @@ struct GameStateData {
}
void removeInventoryItem(int id) {
- for (int i = 0; i < inventoryItems.size(); i++) {
+ for (uint i = 0; i < inventoryItems.size(); i++) {
if (inventoryItems[i] == id) {
inventoryItems.remove_at(i);
return;
@@ -517,7 +517,7 @@ struct GameStateData {
}
bool hasInventoryItem(int id) const {
- for (int i = 0; i < inventoryItems.size(); i++) {
+ for (uint i = 0; i < inventoryItems.size(); i++) {
if (inventoryItems[i] == id) {
return true;
}
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index e105ca50e73..e4c5aa39f10 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -45,28 +45,28 @@ void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color
}
void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color) {
- Graphics::Surface *surface = new Graphics::Surface();
- surface->create(w, h, Graphics::PixelFormat::createFormatCLUT8());
- drawRect(surface, 0, 0, w, h, color);
+ Graphics::Surface surface;
+ surface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
+ drawRect(&surface, 0, 0, w, h, color);
for (int py = 0; py < h; py++) {
for (int px = 0; px < w; px++) {
int destIdx = (y + py) * 640 + (x + px);
- int srcIdx = py * w + px;
- int color = *((byte *)surface->getBasePtr(px, py));
- if (color != 0)
- screenBuffer[destIdx] = color;
+ int pixelColor = *((byte *)surface.getBasePtr(px, py));
+ if (pixelColor != 0)
+ screenBuffer[destIdx] = pixelColor;
}
}
+ surface.free();
}
void drawText(byte *screenBuffer, Graphics::Font *font, Common::String text, int x, int y, int w, byte color, Graphics::TextAlign align) {
Common::Rect rect = font->getBoundingBox(text.c_str());
- Graphics::Surface *surface = new Graphics::Surface();
+ Graphics::Surface surface;
int bboxW = rect.width();
int bboxH = rect.height();
- surface->create(bboxW, bboxH, Graphics::PixelFormat::createFormatCLUT8());
+ surface.create(bboxW, bboxH, Graphics::PixelFormat::createFormatCLUT8());
if (x + bboxW > 640) {
x = 640 - bboxW - 2;
@@ -82,17 +82,17 @@ void drawText(byte *screenBuffer, Graphics::Font *font, Common::String text, int
}
// Draw main text on top
- font->drawString(surface, text.c_str(), 0, 0, bboxW, color, align);
+ font->drawString(&surface, text.c_str(), 0, 0, bboxW, color, align);
// drawRect(surface, 0, 0, bboxW - 1, bboxH - 1, color);
for (int py = 0; py < bboxH; py++) {
for (int px = 0; px < bboxW; px++) {
int destIdx = (y + py) * 640 + (x + px);
- int srcIdx = py * bboxW + px;
- int color = *((byte *)surface->getBasePtr(px, py));
- if (color != 0)
- screenBuffer[destIdx] = color;
+ int pixelColor = *((byte *)surface.getBasePtr(px, py));
+ if (pixelColor != 0)
+ screenBuffer[destIdx] = pixelColor;
}
}
+ surface.free();
}
void drawText(Graphics::Font *font, Common::String text, int x, int y, int w, byte color) {
Commit: 451919142ac6d28c15fbacb21dd672aa39b7223b
https://github.com/scummvm/scummvm/commit/451919142ac6d28c15fbacb21dd672aa39b7223b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:50+02:00
Commit Message:
PELROCK: Finish room 4
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 633e2e1f318..6e48f7358c3 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -21,6 +21,7 @@
#include "graphics/paletteman.h"
+#include "pelrock.h"
#include "pelrock/actions.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
@@ -41,6 +42,7 @@ const ActionEntry actionTable[] = {
{0, PICKUP, &PelrockEngine::pickYellowBook}, // Generic pickup for other items
// Room 1
{4, PICKUP, &PelrockEngine::pickUpBrick}, // Brick
+ {277, OPEN, &PelrockEngine::openIceCreamShopDoor},
// Room 2
{282, OPEN, &PelrockEngine::openMcDoor},
{282, CLOSE, &PelrockEngine::closeMcDoor},
@@ -79,6 +81,7 @@ const ActionEntry actionTable[] = {
// Room 4
{315, OPEN, &PelrockEngine::openPlug},
{316, PICKUP, &PelrockEngine::pickCables},
+ {312, OPEN, &PelrockEngine::openMuseumDoor},
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
@@ -99,6 +102,8 @@ const CombinationEntry combinationTable[] = {
{4, 294, &PelrockEngine::useBrickWithWindow}, // Use Brick with Window (Room 3)
{4, 295, &PelrockEngine::useBrickWithShopWindow},
{6, 315, &PelrockEngine::useCordWithPlug},
+ {1, 53, &PelrockEngine::giveIdToGuard}, // Give ID to Guard
+ {5, 53, &PelrockEngine::giveMoneyToGuard}, // Give Money to Guard
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -167,6 +172,11 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
if (actionTrigger == 328) {
debug("Disabling root %d in room %d", rootIndex, room);
_state->setRootDisabledState(room, rootIndex, true);
+ } else if (actionTrigger == 258) {
+ _state->setFlag(FLAG_GUARDIA_PIDECOSAS, true);
+ _state->setRootDisabledState(4, 1, true);
+ } else {
+ debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
}
}
@@ -215,6 +225,10 @@ void PelrockEngine::pickUpBrick(HotSpot *hotspot) {
_room->addSticker(133);
}
+void PelrockEngine::openIceCreamShopDoor(HotSpot *hotspot) {
+ _dialog->say(_res->_ingameTexts[HELADERIA_CERRADA]);
+}
+
void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
_room->removeSticker(91);
_room->enableHotspot(hotspot);
@@ -471,6 +485,52 @@ void PelrockEngine::pickCables(HotSpot *hotspot) {
_state->setRootDisabledState(4, 0, true);
}
+void PelrockEngine::giveIdToGuard(int inventoryObject, HotSpot *hotspot) {
+ if (!_state->getFlag(FLAG_GUARDIA_PIDECOSAS)) {
+ _dialog->say(_res->_ingameTexts[CUANDOMELOPIDA]);
+ return;
+ }
+
+ if (!_state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
+ _state->setFlag(FLAG_GUARDIA_DNI_ENTREGADO, true);
+ _dialog->say(_res->_ingameTexts[DEACUERDO]);
+ return;
+ }
+ if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
+ _state->setRootDisabledState(4, 2, true);
+ return;
+ }
+}
+
+void PelrockEngine::giveMoneyToGuard(int inventoryObject, HotSpot *hotspot) {
+ if (!_state->getFlag(FLAG_GUARDIA_PIDECOSAS)) {
+ _dialog->say(_res->_ingameTexts[PRETENDEUSTED_SOBORNARME]);
+ return;
+ } else if (!_state->getFlag(FLAG_SOBORNO_PORTERO)) {
+ _state->setFlag(FLAG_SOBORNO_PORTERO, true);
+ _dialog->say(_res->_ingameTexts[MUYBIEN]);
+ _state->removeInventoryItem(5); // Remove 1000 pesetas bill
+ return;
+ }
+ if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
+ _state->setRootDisabledState(4, 2, true);
+ return;
+ }
+}
+
+void PelrockEngine::openMuseumDoor(HotSpot *hotspot) {
+ if (!_state->getFlag(FLAG_GUARDIA_PIDECOSAS)) {
+ _dialog->say(_res->_ingameTexts[ALTO]);
+ return;
+ } else if (!_state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
+ _dialog->say(_res->_ingameTexts[NECESITODNI]);
+ } else if (!_state->getFlag(FLAG_SOBORNO_PORTERO)) {
+ _dialog->say(_res->_ingameTexts[QUE_RECIBO_ACAMBIO]);
+ } else {
+ openDoor(hotspot, 1, 22, FEMININE, false);
+ }
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 3edb3a915b8..915b68ed8a8 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -256,6 +256,7 @@ public:
void pickUpPhoto(HotSpot *hotspot);
void pickYellowBook(HotSpot *hotspot);
void pickUpBrick(HotSpot *hotspot);
+ void openIceCreamShopDoor(HotSpot *hotspot);
void noOpAction(HotSpot *hotspot);
void noOpItem(int item, HotSpot *hotspot);
void useOnAlfred(int inventoryObject);
@@ -278,6 +279,9 @@ public:
void openPlug(HotSpot *hotspot);
void useCordWithPlug(int inventoryObject, HotSpot *hotspot);
void pickCables(HotSpot *hotspot);
+ void giveIdToGuard(int inventoryObject, HotSpot *hotspot);
+ void giveMoneyToGuard(int inventoryObject, HotSpot *hotspot);
+ void openMuseumDoor(HotSpot *hotspot);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
};
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index d0fb17c4754..b78f88ec381 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -122,14 +122,13 @@ void RoomManager::removeSticker(int stickerIndex) {
}
bool RoomManager::hasSticker(int index) {
- for (uint i = 0; i < g_engine->_state->stickersPerRoom[_currentRoomNumber].size(); i++) {
- if (g_engine->_state->stickersPerRoom[_currentRoomNumber][i].stickerIndex == index) {
+ for (uint i = 0; i < _roomStickers.size(); i++) {
+ if (_roomStickers[i].stickerIndex == index) {
return true;
}
}
-
- for (uint i = 0; i < _roomStickers.size(); i++) {
- if (_roomStickers[i].stickerIndex == index) {
+ for (uint i = 0; i < g_engine->_state->stickersPerRoom[_currentRoomNumber].size(); i++) {
+ if (g_engine->_state->stickersPerRoom[_currentRoomNumber][i].stickerIndex == index) {
return true;
}
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 72ecc35def2..0bd87050257 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -456,8 +456,10 @@ struct ResetEntry {
#define FLAG_TIENDA_ABIERTA 46
#define FLAG_NUMERO_DE_COPAS 47
#define FLAG_INGREDIENTES_CONSEGUIDOS 48
+#define FLAG_GUARDIA_PIDECOSAS 49
+#define FLAG_GUARDIA_DNI_ENTREGADO 50
-const int kNumGameFlags = 49;
+const int kNumGameFlags = 51;
struct GameStateData {
byte flags[kNumGameFlags];
Commit: 9379385a8e1f649ab6863671edf33ec5825a42fe
https://github.com/scummvm/scummvm/commit/9379385a8e1f649ab6863671edf33ec5825a42fe
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:50+02:00
Commit Message:
PELROCK: Adds forced terminator to conversations
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/types.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 3e2bebb996a..ce472641f2c 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -20,6 +20,7 @@
*/
#include "pelrock/dialog.h"
+#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
@@ -326,6 +327,24 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
if (tb == CTRL_END_TEXT || tb == CTRL_DIALOGUE_MARKER ||
tb == CTRL_DIALOGUE_MARKER_ONEOFF || tb == CTRL_END_BRANCH ||
tb == CTRL_ALT_END_MARKER_1) {
+ // Check if there is a terminator (F4 or F8) at the end of this choice's response
+ // Scan forward but stop at another choice marker or branch end
+ uint32 scanPos = textPos;
+ while (scanPos < dataSize) {
+ byte sb = data[scanPos];
+ // Stop scanning at another choice marker or branch boundaries
+ if (sb == CTRL_DIALOGUE_MARKER || sb == CTRL_DIALOGUE_MARKER_ONEOFF ||
+ sb == CTRL_END_BRANCH || sb == CTRL_ALT_END_MARKER_1 ||
+ sb == CTRL_ALT_SPEAKER_ROOT) {
+ break;
+ }
+ // Found a conversation terminator - this choice ends the conversation
+ if (sb == CTRL_END_CONVERSATION || sb == CTRL_ACTION_TRIGGER) {
+ opt.hasConversationEndMarker = true;
+ break;
+ }
+ scanPos++;
+ }
break;
}
@@ -385,7 +404,7 @@ bool DialogManager::checkAllSubBranchesExhausted(const byte *data, uint32 dataSi
if (data[pos + 2] != CTRL_DISABLED_CHOICE) {
debug("checkAllSubBranchesExhausted: Active FB at pos %u, idx %d (current %d) - NOT exhausted",
pos, choiceIdx, currentChoiceLevel);
- return false; // Don't disable parent
+ return false; // Don't disable parent
}
} else if (choiceIdx <= currentChoiceLevel) {
// Hit choice at same or lower level - stop
@@ -420,7 +439,7 @@ void DialogManager::setCurSprite(int index) {
bool isRootDisabled(byte room, int root) {
- if(g_engine->_state->getRootDisabledState(room, root)) {
+ if (g_engine->_state->getRootDisabledState(room, root)) {
return true;
}
return false;
@@ -437,10 +456,10 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
debug("Starting conversation with %u bytes of data, for npc %u", dataSize, npcIndex);
uint32 position = 0;
- int currentChoiceLevel = -1; // Track the current choice level
+ int currentChoiceLevel = -1; // Track the current choice level
uint32 lastChoiceMenuPosition = 0; // Track where we last showed a choice menu
- ChoiceOption lastSelectedChoice; // Track the last choice we selected
- bool skipToChoices = false; // After F0, skip directly to choice parsing
+ ChoiceOption lastSelectedChoice; // Track the last choice we selected
+ bool skipToChoices = false; // After F0, skip directly to choice parsing
// Find the speaker tree for this NPC; they are marked by 0xFE 0xXX where XX is NPC index + 1
bool speakerTreeOffsetFound = false;
@@ -497,8 +516,8 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
position = lastChoiceMenuPosition;
skipToChoices = true; // Skip directly to choice parsing
- // Jump directly to choice parsing section
- // Don't continue - let it fall through
+ // Jump directly to choice parsing section
+ // Don't continue - let it fall through
} else {
debug("F0: No previous choice menu, ending conversation");
break;
@@ -587,6 +606,28 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
lastChoiceMenuPosition = position;
Common::Array<ChoiceOption> *choices = new Common::Array<ChoiceOption>();
parseChoices(conversationData, dataSize, position, choices);
+
+ // Check if ANY choice has a conversation terminator (F4 or F8)
+ // If so, there's already a way to exit - don't add goodbye option
+ // Only add goodbye if NO choices terminate the conversation naturally
+ bool anyChoiceTerminatesConversation = false;
+ for (uint i = 0; i < choices->size(); i++) {
+ if ((*choices)[i].hasConversationEndMarker) {
+ anyChoiceTerminatesConversation = true;
+ break;
+ }
+ }
+ if (!anyChoiceTerminatesConversation && choices->size() > 0) {
+ // No choice ends the conversation, so add the goodbye option
+ ChoiceOption termChoice;
+ termChoice.choiceIndex = currentChoiceLevel;
+ termChoice.isTerminator = true;
+ termChoice.isDisabled = false;
+ termChoice.shouldDisableOnSelect = false;
+ termChoice.text = g_engine->_res->_conversationTerminator;
+ choices->push_back(termChoice);
+ }
+
debug("Parsed %u choices", choices->size());
for (uint i = 0; i < choices->size(); i++) {
debug(" Choice %u (index %d): \"%s\" (Disabled: %s)", i, (*choices)[i].choiceIndex, (*choices)[i].text.c_str(),
@@ -645,8 +686,13 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// 6. Move position to after the selected choice
if (selectedIndex >= 0 && selectedIndex < (int)choices->size()) {
+
// Save this choice in case we hit F0 and need to disable it
lastSelectedChoice = (*choices)[selectedIndex];
+ if (lastSelectedChoice.isTerminator) {
+ displayDialogue(lastSelectedChoice.text, ALFRED_COLOR);
+ break;
+ }
position = (*choices)[selectedIndex].dataOffset;
currentChoiceLevel = (*choices)[selectedIndex].choiceIndex;
@@ -657,7 +703,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
if (!choiceText.empty() && choiceText.size() > 1) {
displayDialogue(choiceText, ALFRED_COLOR);
- // Only disable FB choice if all sub-branches are exhausted (Ghidra LAB_00018c2d)
+ // Only disable FB choice if all sub-branches are exhausted
if ((*choices)[selectedIndex].shouldDisableOnSelect) {
bool shouldDisable = checkAllSubBranchesExhausted(conversationData, dataSize, endPos, currentChoiceLevel);
if (shouldDisable) {
@@ -736,7 +782,6 @@ void DialogManager::say(Common::StringArray texts, int16 x, int16 y) {
} else {
sayAlfred(texts);
}
-
}
bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speakerId) {
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 0f8d078af3b..dc3e24dc03e 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -50,18 +50,6 @@ namespace Pelrock {
#define CTRL_ALT_END_MARKER_2 0xEB /* Alt end marker 2 */
#define CTRL_ALT_SPEAKER_ROOT 0xFE /* Separates conversations from different speakers */
-// static void debugHexString(const Common::String &str, const char *label = nullptr) {
-// if (label) {
-// debug("%s:", label);
-// }
-
-// Common::String hexOutput;
-// for (uint i = 0; i < str.size(); i++) {
-// hexOutput += Common::String::format("%02X ", (unsigned char)str[i]);
-// }
-// debug("%s", hexOutput.c_str());
-// }
-
class DialogManager {
private:
Graphics::Screen *_screen = nullptr;
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index bdd14778c95..9f53a168279 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -50,6 +50,7 @@ static const uint32 kInventoryDescriptionsSize = 7868;
static const uint32 kMenuTextOffset = 0x49203;
static const uint32 kMenuTextSize = 230;
static const uint32 kAlfredResponsesOffset = 0x441DC;
+static const uint32 kConversationTerminatorOffset = 0x0492EE;
static const uint32 kAlfredResponsesSize = 12163;
static const uint32 kCreditsOffset = 0x49F60;
static const uint32 kCreditsSize = 2540;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 4002e663f55..cfeb4f748ee 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -137,7 +137,7 @@ void PelrockEngine::init() {
_res->loadCursors();
_res->loadInteractionIcons();
_res->loadInventoryItems();
- _res->loadAlfredResponses();
+ _res->loadHardcodedText();
_sound->loadSoundIndex();
_menu->loadMenu();
@@ -314,6 +314,7 @@ void PelrockEngine::checkMouse() {
_actionPopupState.isActive = false;
// Mouse was released while popup is active
VerbIcon actionClicked = isActionUnder(_events->_releaseX, _events->_releaseY);
+ debug("Popup action clicked: %d, is alfredunder %d", actionClicked, _actionPopupState.isAlfredUnder);
if (_actionPopupState.isAlfredUnder) {
debug("Using item on Alfred");
useOnAlfred(_state->selectedInventoryItem);
@@ -937,6 +938,7 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
_alfredState.idleFrameCounter = 0;
int hotspotIndex = isHotspotUnder(x, y);
bool alfredUnder = isAlfredUnder(x, y);
+ debug("Long click at %d,%d - hotspot %d, alfred under %d", x, y, hotspotIndex, alfredUnder);
if ((hotspotIndex != -1 || alfredUnder) && !_actionPopupState.isActive) {
_actionPopupState.x = _alfredState.x + kAlfredFrameWidth / 2 - kBalloonWidth / 2;
@@ -1224,10 +1226,10 @@ void PelrockEngine::pickupIconFlash() {
void PelrockEngine::gameLoop() {
- _events->pollEvent();
- checkMouse();
- renderScene();
- _screen->update();
+ _events->pollEvent();
+ checkMouse();
+ renderScene();
+ _screen->update();
}
void PelrockEngine::computerLoop() {
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 8a47740db83..08af8c0331c 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -234,7 +234,7 @@ void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
} else {
alfred7.read(_currentSpecialAnim->animData, offset.numFrames * offset.w * offset.h);
}
- if (reverse) {
+ if (reverse) {
// reverse frames for testing
byte *reversedData = new byte[offset.numFrames * offset.w * offset.h];
for (int i = 0; i < offset.numFrames; i++) {
@@ -277,7 +277,7 @@ void ResourceManager::loadInventoryItems() {
delete[] iconData;
}
-void ResourceManager::loadAlfredResponses() {
+void ResourceManager::loadHardcodedText() {
Common::File exe;
if (!exe.open("JUEGO.EXE")) {
@@ -287,6 +287,10 @@ void ResourceManager::loadAlfredResponses() {
exe.seek(kAlfredResponsesOffset, SEEK_SET);
exe.read(descBuffer, kAlfredResponsesSize);
_ingameTexts = processTextData(descBuffer, kAlfredResponsesSize);
+ byte *terminatorBuffer = new byte[39];
+ exe.seek(kConversationTerminatorOffset, SEEK_SET);
+ exe.read(terminatorBuffer, 39);
+ _conversationTerminator = Common::String((const char *)terminatorBuffer, 39);
delete[] descBuffer;
exe.close();
}
@@ -322,11 +326,11 @@ Common::Array<Common::StringArray> ResourceManager::getCredits() {
return credits;
}
-Common::Array<Common::Array<Common::String>> ResourceManager::processTextData(byte *data, size_t size, bool decode) {
+Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data, size_t size, bool decode) {
int pos = 0;
Common::String desc = "";
Common::StringArray lines;
- Common::Array<Common::Array<Common::String>> texts;
+ Common::Array<Common::StringArray> texts;
while (pos < size) {
if (data[pos] == CTRL_END_TEXT) {
if (!desc.empty()) {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index f91386e2f37..22aec4820cb 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -48,7 +48,7 @@ public:
void loadAlfredSpecialAnim(int numAnim, bool reverse = false);
void clearSpecialAnim();
void loadInventoryItems();
- void loadAlfredResponses();
+ void loadHardcodedText();
void getExtraScreen(int screenIndex, byte *screenBuf, byte *palette);
Common::Array<Common::StringArray> getCredits();
Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size, bool decode = false);
@@ -69,13 +69,10 @@ public:
byte *_verbIcons[9];
byte *_popUpBalloon = nullptr;
Common::Array<Common::StringArray> _ingameTexts;
+ Common::String _conversationTerminator;
// Special anims
AlfredSpecialAnim *_currentSpecialAnim = nullptr;
- // byte *_specialAnimData = nullptr;
- // int _specialAnimCurFrame = 0;
- // int _speciaAnimLoopCount = 0;
- // AlfredSpecialAnimOffset _curSpecialAnim;
bool _isSpecialAnimFinished = false;
};
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 0bd87050257..6203cf64bdb 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -394,10 +394,12 @@ struct ChoiceOption {
int choiceIndex;
Common::String text;
uint32 dataOffset;
- bool isDisabled;
+ bool isDisabled = false;
bool shouldDisableOnSelect = false;
+ bool hasConversationEndMarker = false;
+ bool isTerminator = false;
- ChoiceOption() : choiceIndex(-1), isDisabled(false), dataOffset(0) {}
+ ChoiceOption() : choiceIndex(-1), dataOffset(0) {}
};
struct ResetEntry {
Commit: acdc0fd107646aac28f01a8e21d62f08b36b21cd
https://github.com/scummvm/scummvm/commit/acdc0fd107646aac28f01a8e21d62f08b36b21cd
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:50+02:00
Commit Message:
PELROCK: Dialog in room 5
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/events.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 6e48f7358c3..761945ed49a 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -83,6 +83,9 @@ const ActionEntry actionTable[] = {
{316, PICKUP, &PelrockEngine::pickCables},
{312, OPEN, &PelrockEngine::openMuseumDoor},
+ // Room 5
+ {},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -172,9 +175,22 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
if (actionTrigger == 328) {
debug("Disabling root %d in room %d", rootIndex, room);
_state->setRootDisabledState(room, rootIndex, true);
+ } else if (actionTrigger == 329) {
+ debug("Would now enable X easter egg");
} else if (actionTrigger == 258) {
_state->setFlag(FLAG_GUARDIA_PIDECOSAS, true);
_state->setRootDisabledState(4, 1, true);
+ } else if (actionTrigger == 259) {
+ _dialog->say(_res->_ingameTexts[NO_EMPECEMOS]);
+ } else if (actionTrigger == 260) {
+ _dialog->say(_res->_ingameTexts[CUERPO_DANONE], 1);
+ _dialog->say(_res->_ingameTexts[CABEZA_HUECA]);
+ } else if (actionTrigger == 261) {
+ _dialog->say(_res->_ingameTexts[ESO_LO_SERAS_TU], 1);
+ } else if (actionTrigger == 262) {
+ _dialog->say(_res->_ingameTexts[DEMASIADO_NO_PUEDO_PENSAR], 1);
+ } else if (actionTrigger == 263) {
+ _dialog->say(_res->_ingameTexts[UN_POCO_RESPETO]);
} else {
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index ce472641f2c..2ce7ca94221 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -289,27 +289,30 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
outChoices->clear();
int firstChoiceIndex = -1;
- // Scan for additional choices with SAME index
+ // Scan for choices with SAME index
+ // The key insight: choices at the same level may be scattered throughout the data,
+ // separated by deeper-level sub-branches. We must scan past higher-index choices
+ // to find all choices at our level, but stop when we hit a LOWER index.
while (pos < dataSize) {
byte b = data[pos];
// Stop at end markers
- if (b == CTRL_ALT_END_MARKER_1 || b == CTRL_END_BRANCH) {
+ if (b == CTRL_ALT_END_MARKER_1 || b == CTRL_END_BRANCH || b == CTRL_ALT_SPEAKER_ROOT) {
break;
}
// Found a dialogue marker
if (b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_ONEOFF) {
if (pos + 1 < dataSize) {
+ int choiceIndex = data[pos + 1];
+
+ // Set firstChoiceIndex from first non-disabled choice, or first choice if all disabled
if (firstChoiceIndex == -1) {
- firstChoiceIndex = data[pos + 1];
+ firstChoiceIndex = choiceIndex;
}
- int choiceIndex = data[pos + 1];
- // Only collect choices with same index
+ // Only collect choices with same index as the first one we found
if (choiceIndex == firstChoiceIndex) {
- // Check if disabled
-
ChoiceOption opt;
opt.room = g_engine->_room->_currentRoomNumber;
opt.shouldDisableOnSelect = b == CTRL_DIALOGUE_MARKER_ONEOFF;
@@ -321,7 +324,6 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
}
// Parse the choice text
uint32 textPos = pos + 4;
- // textPos += 2; // Skip marker + index + 2 speaker bytes
while (textPos < dataSize) {
byte tb = data[textPos];
if (tb == CTRL_END_TEXT || tb == CTRL_DIALOGUE_MARKER ||
@@ -361,9 +363,12 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
if (!opt.isDisabled)
outChoices->push_back(opt);
} else if (choiceIndex < firstChoiceIndex) {
- // Different choice index - stop scanning
+ // Hit a choice at a LOWER level - stop scanning
+ // This means we've gone past all choices at our level
break;
}
+ // If choiceIndex > firstChoiceIndex, we're in a deeper sub-branch
+ // Continue scanning to find more choices at our level
}
}
@@ -388,9 +393,12 @@ bool DialogManager::checkAllSubBranchesExhausted(const byte *data, uint32 dataSi
while (pos < dataSize) {
byte b = data[pos];
- // Stop at branch/conversation end markers (0xF5, 0xF7, 0xFE, 0xF4)
+ // Stop at TRUE branch boundary markers (0xF5, 0xF7, 0xFE)
+ // NOTE: Do NOT stop at F4 (CTRL_END_CONVERSATION) - F4 markers appear between
+ // choices as terminators for each choice's response path. We need to scan
+ // past them to find all choices at the target level.
if (b == CTRL_ALT_END_MARKER_1 || b == CTRL_END_BRANCH ||
- b == CTRL_ALT_SPEAKER_ROOT || b == CTRL_END_CONVERSATION) {
+ b == CTRL_ALT_SPEAKER_ROOT) {
break;
}
@@ -407,7 +415,8 @@ bool DialogManager::checkAllSubBranchesExhausted(const byte *data, uint32 dataSi
return false; // Don't disable parent
}
} else if (choiceIdx <= currentChoiceLevel) {
- // Hit choice at same or lower level - stop
+ // Hit choice at same or lower level - stop scanning
+ // All choices at higher levels before this point have been checked
break;
}
}
@@ -536,7 +545,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
byte speakerId;
endPos = readTextBlock(conversationData, dataSize, position, text, speakerId);
Common::Array<Common::Array<Common::String>> wrappedText = wordWrap(text);
- debug("Word wrapping %s produces %d pages", text.c_str(), wrappedText.size());
+ // debug("Word wrapping %s produces %d pages", text.c_str(), wrappedText.size());
// Skip spurious single character artifacts
if (!text.empty() && text.size() > 1) {
displayDialogue(wrappedText, speakerId);
@@ -707,6 +716,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
if ((*choices)[selectedIndex].shouldDisableOnSelect) {
bool shouldDisable = checkAllSubBranchesExhausted(conversationData, dataSize, endPos, currentChoiceLevel);
if (shouldDisable) {
+ debug("Disabling one-time choice at index %d after selection", selectedIndex);
g_engine->_room->addDisabledChoice((*choices)[selectedIndex]);
}
}
@@ -747,7 +757,7 @@ void DialogManager::sayAlfred(Description description) {
}
}
-void DialogManager::say(Common::StringArray texts) {
+void DialogManager::say(Common::StringArray texts, byte spriteIndex) {
if (texts.empty()) {
return;
}
@@ -759,7 +769,7 @@ void DialogManager::say(Common::StringArray texts) {
sayAlfred(texts);
return;
} else {
- setCurSprite(0);
+ setCurSprite(spriteIndex);
Common::Array<Common::StringArray> textLines = wordWrap(texts);
displayDialogue(textLines, speakerId);
}
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index dc3e24dc03e..7719110b719 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -76,7 +76,7 @@ public:
int selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer);
void startConversation(const byte *conversationData, uint32 dataSize, byte npcIndex, Sprite *alfredAnimSet = nullptr);
void sayAlfred(Description description);
- void say(Common::StringArray texts);
+ void say(Common::StringArray texts, byte spriteIndex = 0);
void say(Common::StringArray texts, int16 x, int16 y);
bool processColorAndTrim(Common::StringArray &lines, byte &speakerId);
Graphics::Surface getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId);
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
index da4b41a7e87..c90705e7c06 100644
--- a/engines/pelrock/events.cpp
+++ b/engines/pelrock/events.cpp
@@ -59,7 +59,6 @@ void PelrockEventManager::pollEvent() {
// case Common::EVENT_KEYUP:
// return;
case Common::EVENT_LBUTTONDOWN:
-
if (_leftMouseButton == 0) {
_clickTime = g_system->getMillis();
}
@@ -70,9 +69,9 @@ void PelrockEventManager::pollEvent() {
case Common::EVENT_LBUTTONUP:
if (_leftMouseButton == 1) {
// Don't treat as regular click if we're in popup selection mode
- if (!_popupSelectionMode) {
- _leftMouseClicked = true;
- }
+ // if (!_popupSelectionMode) {
+ _leftMouseClicked = true;
+ // }
_releaseX = _event.mouse.x;
_releaseY = _event.mouse.y;
_longClicked = false;
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 9f53a168279..1d80751bdc3 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -152,12 +152,12 @@ enum TextIndices {
NIPARAEMPEZAR,
PARAQUE,
DEPIEDRANO_DEHIELO,
- HEY_DONTSTART,
- HOTONE_MOCKING,
- SHUTUP,
- NO_YOU,
- TOO_MUCH_CANT_THINK,
- A_LITTLE_RESPECT,
+ NO_EMPECEMOS,
+ CUERPO_DANONE,
+ CABEZA_HUECA,
+ ESO_LO_SERAS_TU,
+ DEMASIADO_NO_PUEDO_PENSAR,
+ UN_POCO_RESPETO,
NO_THEY_MAKEYOU_FAT,
RELOJ_HA_CAMBIADO,
CORRESPONDENCIA_AJENA,
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index cfeb4f748ee..5561005b206 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -154,7 +154,7 @@ void PelrockEngine::init() {
loadAnims();
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
- setScreen(4, ALFRED_DOWN);
+ setScreen(5, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -578,6 +578,7 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
break;
}
}
+ changeCursor(DEFAULT);
_dialog->startConversation(_room->_conversationData, _room->_conversationDataSize, hotspot->index, animSet);
}
@@ -938,7 +939,6 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
_alfredState.idleFrameCounter = 0;
int hotspotIndex = isHotspotUnder(x, y);
bool alfredUnder = isAlfredUnder(x, y);
- debug("Long click at %d,%d - hotspot %d, alfred under %d", x, y, hotspotIndex, alfredUnder);
if ((hotspotIndex != -1 || alfredUnder) && !_actionPopupState.isActive) {
_actionPopupState.x = _alfredState.x + kAlfredFrameWidth / 2 - kBalloonWidth / 2;
@@ -1403,6 +1403,7 @@ void PelrockEngine::changeCursor(Cursor cursor) {
}
void PelrockEngine::checkMouseHover() {
+
bool hotspotDetected = false;
int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
@@ -1410,17 +1411,19 @@ void PelrockEngine::checkMouseHover() {
hotspotDetected = true;
}
+
if (isActionUnder(_events->_mouseX, _events->_mouseY) != NO_ACTION) {
hotspotDetected = false;
}
+ // Calculate walk target first (before checking anything else)
+ Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, hotspotDetected, hotspotDetected ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
+
+
bool alfredDetected = false;
if (isAlfredUnder(_events->_mouseX, _events->_mouseY)) {
alfredDetected = true;
}
- // Calculate walk target first (before checking anything else)
- Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, hotspotDetected, hotspotDetected ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
-
// Check if walk target hits any exit
bool exitDetected = false;
Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index b78f88ec381..8917eb03092 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -762,13 +762,17 @@ void RoomManager::applyDisabledChoice(ResetEntry entry, byte *conversationData,
}
void RoomManager::addDisabledChoice(ChoiceOption choice) {
- debug("Adding disabled branch for room %d at offset %d", choice.room, choice.dataOffset);
+ // Write 0xFA at offset+2 (after FB/F1 marker and level byte)
+ // This marks the choice as disabled without destroying the marker structure
+ uint32 disableOffset = choice.dataOffset + 2;
+ debug("Adding disabled branch for room %d at offset %d (FA written at %d)",
+ choice.room, choice.dataOffset, disableOffset);
ResetEntry resetEntry = ResetEntry();
resetEntry.room = choice.room;
- resetEntry.offset = choice.dataOffset;
+ resetEntry.offset = disableOffset;
resetEntry.dataSize = 1;
resetEntry.data = new byte[1];
- resetEntry.data[0] = 0xFA; // Disabled
+ resetEntry.data[0] = 0xFA; // Disabled marker
// Apply immediately
applyDisabledChoice(resetEntry, _conversationData, _conversationDataSize);
// Store for future loads
Commit: 08d7b47d4d4f669fe64effc452dc0197a574ed50
https://github.com/scummvm/scummvm/commit/08d7b47d4d4f669fe64effc452dc0197a574ed50
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:51+02:00
Commit Message:
PELROCK: Fixes dialog in room 7, fixes zorder
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 761945ed49a..f24b3924856 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -191,6 +191,10 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_dialog->say(_res->_ingameTexts[DEMASIADO_NO_PUEDO_PENSAR], 1);
} else if (actionTrigger == 263) {
_dialog->say(_res->_ingameTexts[UN_POCO_RESPETO]);
+ } else if (actionTrigger == 264) {
+ //disables the two first roots, the second one will be enabled later!
+ _state->setRootDisabledState(room, rootIndex, true);
+ _state->setRootDisabledState(room, rootIndex + 1, true);
} else {
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
}
@@ -550,14 +554,17 @@ void PelrockEngine::openMuseumDoor(HotSpot *hotspot) {
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
- case 257:
+ case 257: // look portrait
_sound->playMusicTrack(25);
loadExtraScreenAndPresent(9);
_dialog->say(_res->_ingameTexts[QUEBUENA_ESTA]);
_screen->markAllDirty();
_screen->update();
break;
- case 271:
+ case 268: // look at statue
+ _dialog->say(_res->_ingameTexts[TUCREES]);
+ break;
+ case 271: // look at librarian
_dialog->say(_res->_ingameTexts[TRABAJARIA_MEJOR_SI_NO_ME_MOLESTARA]);
break;
case 270:
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 2ce7ca94221..aa39d3e9116 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -616,25 +616,31 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
Common::Array<ChoiceOption> *choices = new Common::Array<ChoiceOption>();
parseChoices(conversationData, dataSize, position, choices);
- // Check if ANY choice has a conversation terminator (F4 or F8)
- // If so, there's already a way to exit - don't add goodbye option
- // Only add goodbye if NO choices terminate the conversation naturally
- bool anyChoiceTerminatesConversation = false;
- for (uint i = 0; i < choices->size(); i++) {
- if ((*choices)[i].hasConversationEndMarker) {
- anyChoiceTerminatesConversation = true;
- break;
+ // Store original choice count before potentially adding goodbye
+ uint originalChoiceCount = choices->size();
+
+ // Only consider adding goodbye if there are MULTIPLE choices
+ // If there's only 1 choice, it's auto-dialogue and should not have goodbye
+ if (originalChoiceCount > 1) {
+ // Check if ANY choice has a conversation terminator (F4 or F8)
+ // If so, there's already a way to exit - don't add goodbye option
+ bool anyChoiceTerminatesConversation = false;
+ for (uint i = 0; i < choices->size(); i++) {
+ if ((*choices)[i].hasConversationEndMarker) {
+ anyChoiceTerminatesConversation = true;
+ break;
+ }
+ }
+ if (!anyChoiceTerminatesConversation) {
+ // No choice ends the conversation, so add the goodbye option
+ ChoiceOption termChoice;
+ termChoice.choiceIndex = currentChoiceLevel;
+ termChoice.isTerminator = true;
+ termChoice.isDisabled = false;
+ termChoice.shouldDisableOnSelect = false;
+ termChoice.text = g_engine->_res->_conversationTerminator;
+ choices->push_back(termChoice);
}
- }
- if (!anyChoiceTerminatesConversation && choices->size() > 0) {
- // No choice ends the conversation, so add the goodbye option
- ChoiceOption termChoice;
- termChoice.choiceIndex = currentChoiceLevel;
- termChoice.isTerminator = true;
- termChoice.isDisabled = false;
- termChoice.shouldDisableOnSelect = false;
- termChoice.text = g_engine->_res->_conversationTerminator;
- choices->push_back(termChoice);
}
debug("Parsed %u choices", choices->size());
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 5561005b206..8084547e28f 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -348,23 +348,32 @@ void PelrockEngine::copyBackgroundToBuffer() {
memcpy(_compositeBuffer, _currentBackground, 640 * 400);
}
-void PelrockEngine::updateAnimations() {
- // Sort sprites by zOrder (persists in the array)
+// Calculate Alfred's z-order based on Y position
+// At Y=399 (bottom of screen): z = 10 (foreground)
+// At Y=0 (top of screen): z = 209 (background)
+static int calculateAlfredZOrder(int alfredY) {
+ return ((399 - alfredY) & 0xFFFE) / 2 + 10;
+}
+void PelrockEngine::updateAnimations() {
+ // Sort sprites by zOrder (ascending: low z = back, rendered first)
sortAnimsByZOrder(_room->_currentRoomAnims);
- // First pass: sprites behind Alfred (y <= alfredY)
+
+ int alfredZOrder = calculateAlfredZOrder(_alfredState.y);
+
+ // First pass: sprites behind Alfred (sprite zOrder > alfredZOrder)
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (_room->_currentRoomAnims[i].zOrder > 10 || _room->_currentRoomAnims[i].zOrder < 0) {
+ if (_room->_currentRoomAnims[i].zOrder > alfredZOrder || _room->_currentRoomAnims[i].zOrder < 0) {
drawNextFrame(&_room->_currentRoomAnims[i]);
}
}
- // Draw Alfred here (you'll need to add this)
+ // Draw Alfred
chooseAlfredStateAndDraw();
- // Second pass: sprites in front of Alfred (y > alfredY)
+ // Second pass: sprites in front of Alfred (sprite zOrder <= alfredZOrder)
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (_room->_currentRoomAnims[i].zOrder <= 10 && _room->_currentRoomAnims[i].zOrder >= 0) {
+ if (_room->_currentRoomAnims[i].zOrder <= alfredZOrder && _room->_currentRoomAnims[i].zOrder >= 0) {
drawNextFrame(&_room->_currentRoomAnims[i]);
}
}
Commit: c6066f17073a4fcfede01176148b634c62c8083e
https://github.com/scummvm/scummvm/commit/c6066f17073a4fcfede01176148b634c62c8083e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:51+02:00
Commit Message:
PELROCK: WIP mouse movement in room 9
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/chrono.h
engines/pelrock/console.cpp
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index f24b3924856..5cc6b2a9517 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -83,8 +83,20 @@ const ActionEntry actionTable[] = {
{316, PICKUP, &PelrockEngine::pickCables},
{312, OPEN, &PelrockEngine::openMuseumDoor},
- // Room 5
- {},
+ // // Room 5
+ // {},
+
+ // // Room 7
+ // {},
+
+ // Room 8
+ {355, OPEN, &PelrockEngine::openLibraryOutdoorsDoor},
+ {355, CLOSE, &PelrockEngine::closeLibraryOutdoorsDoor},
+ {357, PICKUP, &PelrockEngine::pickUpLetter},
+
+ // Room 9
+ {363, OPEN, &PelrockEngine::openLibraryIndoorsDoor},
+ {363, CLOSE, &PelrockEngine::closeLibraryIndoorsDoor},
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
@@ -100,13 +112,14 @@ const ActionEntry actionTable[] = {
{WILDCARD, NO_ACTION, nullptr}};
const CombinationEntry combinationTable[] = {
- {2, 281, &PelrockEngine::useCardWithATM}, // Use ATM Card with ATM
- {62, 117, &PelrockEngine::useSpicySauceWithBurger}, // Use Spicy Sauce with Burger
- {4, 294, &PelrockEngine::useBrickWithWindow}, // Use Brick with Window (Room 3)
+ {2, 281, &PelrockEngine::useCardWithATM},
+ {62, 117, &PelrockEngine::useSpicySauceWithBurger},
+ {4, 294, &PelrockEngine::useBrickWithWindow},
{4, 295, &PelrockEngine::useBrickWithShopWindow},
{6, 315, &PelrockEngine::useCordWithPlug},
- {1, 53, &PelrockEngine::giveIdToGuard}, // Give ID to Guard
- {5, 53, &PelrockEngine::giveMoneyToGuard}, // Give Money to Guard
+ {1, 53, &PelrockEngine::giveIdToGuard},
+ {5, 53, &PelrockEngine::giveMoneyToGuard},
+ {7, 353, &PelrockEngine::useAmuletWithStatue},
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -551,6 +564,46 @@ void PelrockEngine::openMuseumDoor(HotSpot *hotspot) {
}
}
+void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
+
+ if (!_room->hasSticker(24)) {
+ _room->addSticker(24);
+ _state->removeInventoryItem(7);
+ _state->setRootDisabledState(7, 0, true);
+ _state->setRootDisabledState(7, 1, false);
+ _state->setRootDisabledState(7, 2, true);
+ // TODO: Palette anim
+ HotSpot *statueHotspot = _room->findHotspotByExtra(91);
+ _currentHotspot = statueHotspot;
+
+ walkAndAction(statueHotspot, TALK);
+ _state->setRootDisabledState(7, 1, true);
+
+ // TODO: Undo palette anim!
+ }
+}
+
+void PelrockEngine::pickUpLetter(HotSpot *hotspot) {
+ addInventoryItem(9);
+ _room->setActionMask(hotspot, ACTION_MASK_NONE); // Disable hotspot
+}
+
+void PelrockEngine::openLibraryOutdoorsDoor(HotSpot *hotspot) {
+ openDoor(hotspot, 0, 26, FEMININE, false);
+}
+
+void PelrockEngine::closeLibraryOutdoorsDoor(HotSpot *hotspot) {
+ closeDoor(hotspot, 0, 26, FEMININE, false);
+}
+
+void PelrockEngine::openLibraryIndoorsDoor(HotSpot *hotspot) {
+ openDoor(hotspot, 0, 28, FEMININE, false);
+}
+
+void PelrockEngine::closeLibraryIndoorsDoor(HotSpot *hotspot) {
+ closeDoor(hotspot, 0, 28, FEMININE, false);
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index f7f67229545..295157816f2 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -30,7 +30,8 @@ namespace Pelrock {
// const int kTickMs = 15;
// const int kTickMs = 33;
// const int kTickMs = 38;
-const int kTickMs = 55;
+// const int kTickMs = 55;
+const int kTickMs = 200;
// const int kTickMs = 60;
const int kHalfTickMultiplier = 2;
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index 0f1b2f0f967..3b5a7c327b5 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -27,7 +27,7 @@
namespace Pelrock {
PelrockConsole::PelrockConsole(PelrockEngine *engine) : GUI::Debugger(), _engine(engine) {
- registerCmd("setScreen", WRAP_METHOD(PelrockConsole, cmdLoadRoom));
+ registerCmd("room", WRAP_METHOD(PelrockConsole, cmdLoadRoom));
registerCmd("give", WRAP_METHOD(PelrockConsole, cmdGiveItems));
}
@@ -36,7 +36,7 @@ PelrockConsole::~PelrockConsole() {
bool PelrockConsole::cmdLoadRoom(int argc, const char **argv) {
if (argc < 2) {
- debugPrintf("Usage: setScreen <roomNumber>");
+ debugPrintf("Usage: room <roomNumber>");
return true;
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index aa39d3e9116..7dc5629975f 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -305,7 +305,7 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
if (b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_ONEOFF) {
if (pos + 1 < dataSize) {
int choiceIndex = data[pos + 1];
-
+
// Set firstChoiceIndex from first non-disabled choice, or first choice if all disabled
if (firstChoiceIndex == -1) {
firstChoiceIndex = choiceIndex;
@@ -462,7 +462,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
setCurSprite(animSet ? animSet->index : -1);
// _curSprite = animSet;
- debug("Starting conversation with %u bytes of data, for npc %u", dataSize, npcIndex);
+ debug("Starting conversation with %d bytes of data, for npc %d, hotspot %d", dataSize, npcIndex, animSet ? animSet->index : -1);
uint32 position = 0;
int currentChoiceLevel = -1; // Track the current choice level
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 8084547e28f..5b45e3d5b31 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -154,7 +154,8 @@ void PelrockEngine::init() {
loadAnims();
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
- setScreen(5, ALFRED_DOWN);
+ // setScreen(5, ALFRED_DOWN);
+ setScreen(9, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -173,25 +174,25 @@ Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
Common::Array<VerbIcon> verbs;
verbs.push_back(LOOK);
- if (hotspot->actionFlags & 1) {
+ if (hotspot->actionFlags & ACTION_MASK_OPEN) {
verbs.push_back(OPEN);
}
- if (hotspot->actionFlags & 2) {
+ if (hotspot->actionFlags & ACTION_MASK_CLOSE) {
verbs.push_back(CLOSE);
}
- if (hotspot->actionFlags & 4) {
+ if (hotspot->actionFlags & ACTION_MASK_UNKNOWN) {
verbs.push_back(UNKNOWN);
}
- if (hotspot->actionFlags & 8) {
+ if (hotspot->actionFlags & ACTION_MASK_PICKUP) {
verbs.push_back(PICKUP);
}
- if (hotspot->actionFlags & 16) {
+ if (hotspot->actionFlags & ACTION_MASK_TALK) {
verbs.push_back(TALK);
}
- if (hotspot->actionFlags & 32) {
+ if (hotspot->actionFlags & ACTION_MASK_PUSH) {
verbs.push_back(PUSH);
}
- if (hotspot->actionFlags & 128) {
+ if (hotspot->actionFlags & ACTION_MASK_PULL) {
verbs.push_back(PULL);
}
return verbs;
@@ -230,29 +231,16 @@ bool PelrockEngine::renderScene(int overlayMode) {
_chrono->updateChrono();
if (_chrono->_gameTick) {
- // playSoundIfNeeded();
+ frameTriggers();
+
+ playSoundIfNeeded();
copyBackgroundToBuffer();
- placeStickers();
+ placeStickersFirstPass();
updateAnimations();
- // Some stickers need to be placed AFTER sprites, hardcoded in the original
- if (_room->_currentRoomNumber == 3) {
- for (uint i = 0; i < _state->stickersPerRoom[3].size(); i++) {
- if (_state->stickersPerRoom[3][i].stickerIndex == 14) {
- placeSticker(_state->stickersPerRoom[3][i]);
- break;
- }
- }
- }
- if (overlayMode == OVERLAY_CHOICES) {
- _dialog->displayChoices(_dialog->_currentChoices, _compositeBuffer);
- } else if (overlayMode == OVERLAY_PICKUP_ICON) {
- pickupIconFlash();
- } else if (overlayMode == OVERLAY_ACTION) {
- showActionBalloon(_actionPopupState.x, _actionPopupState.y, _actionPopupState.curFrame);
- }
+ renderOverlay(overlayMode);
presentFrame();
updatePaletteAnimations();
@@ -263,6 +251,55 @@ bool PelrockEngine::renderScene(int overlayMode) {
return false;
}
+const int kPasserbyTriggerFrameInterval = 30;
+
+void PelrockEngine::frameTriggers() {
+ if ((_chrono->getFrameCount() & kPasserbyTriggerFrameInterval) == kPasserbyTriggerFrameInterval) {
+ debug("Would trigger passer-by");
+ switch (_room->_currentRoomNumber)
+ {
+ case 9: {
+ Sprite *mouse = _room->findSpriteByIndex(2);
+ mouse->zOrder = 3;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if(_room->_currentRoomNumber == 9) {
+ Sprite *mouse = _room->findSpriteByIndex(2);
+ if (mouse) {
+ if(mouse->x > 130 && mouse->x < 200) {
+ debug("Moving mouse right and down");
+ if(mouse->curAnimIndex == 0)
+ mouse->curAnimIndex = 1;
+ mouse->y += 2;
+ mouse->x += 6;
+ }
+ else if(mouse->x > 200 && mouse->x < 340) {
+ debug("Moving mouse right");
+ if(mouse->curAnimIndex == 1)
+ mouse->curAnimIndex = 2;
+ mouse->x += 6;
+ }
+ else if(mouse->x > 340) {
+ debug("Moving mouse down");
+ if(mouse->curAnimIndex == 2)
+ mouse->curAnimIndex = 1;
+ mouse->y += 2;
+ }
+ if(mouse->x > 355) {
+ mouse->x = 82;
+ mouse->y = 315;
+ mouse->zOrder = 255;
+ mouse->curAnimIndex = 0;
+ }
+ }
+ }
+}
+
void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
debug("Executing action %d on hotspot %d", action, hotspot->extra);
if (action == ITEM) {
@@ -320,8 +357,7 @@ void PelrockEngine::checkMouse() {
useOnAlfred(_state->selectedInventoryItem);
} else if (actionClicked != NO_ACTION && _currentHotspot != nullptr) {
// Action was selected - queue it
- walkTo(_currentHotspot->x + _currentHotspot->w / 2, _currentHotspot->y + _currentHotspot->h);
- _queuedAction = QueuedAction{actionClicked, _currentHotspot->index, true};
+ walkAndAction(_currentHotspot, actionClicked);
} else {
// Released outside popup - just close it
_queuedAction = QueuedAction{NO_ACTION, -1, false};
@@ -456,7 +492,7 @@ void PelrockEngine::paintDebugLayer() {
_smallFont->drawString(_screen, Common::String::format("Frame number: %d", _chrono->getFrameCount()), 0, 30, 640, 13);
}
-void PelrockEngine::placeStickers() {
+void PelrockEngine::placeStickersFirstPass() {
// also place temporary stickers
for (uint i = 0; i < _room->_roomStickers.size(); i++) {
Sticker sticker = _room->_roomStickers[i];
@@ -464,6 +500,18 @@ void PelrockEngine::placeStickers() {
}
}
+void PelrockEngine::placeStickersSecondPass() {
+ // Some stickers need to be placed AFTER sprites, hardcoded in the original
+ if (_room->_currentRoomNumber == 3) {
+ for (uint i = 0; i < _state->stickersPerRoom[3].size(); i++) {
+ if (_state->stickersPerRoom[3][i].stickerIndex == 14) {
+ placeSticker(_state->stickersPerRoom[3][i]);
+ break;
+ }
+ }
+ }
+}
+
void PelrockEngine::placeSticker(Sticker sticker) {
for (int y = 0; y < sticker.h; y++) {
for (int x = 0; x < sticker.w; x++) {
@@ -479,6 +527,16 @@ void PelrockEngine::placeSticker(Sticker sticker) {
}
}
+void PelrockEngine::renderOverlay(int overlayMode) {
+ if (overlayMode == OVERLAY_CHOICES) {
+ _dialog->displayChoices(_dialog->_currentChoices, _compositeBuffer);
+ } else if (overlayMode == OVERLAY_PICKUP_ICON) {
+ pickupIconFlash();
+ } else if (overlayMode == OVERLAY_ACTION) {
+ showActionBalloon(_actionPopupState.x, _actionPopupState.y, _actionPopupState.curFrame);
+ }
+}
+
void PelrockEngine::animateFadePalette(PaletteAnim *anim) {
// FADE palette animation - cycles a single palette entry between min/max RGB values
// Data layout (after loading from EXE):
@@ -588,6 +646,7 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
}
}
changeCursor(DEFAULT);
+ debug("Talking to hotspot %d (%d) with extra %d", hotspot->index, hotspot->isSprite ? hotspot->index : hotspot->index - _room->_currentRoomAnims.size(), hotspot->extra);
_dialog->startConversation(_room->_conversationData, _room->_conversationDataSize, hotspot->index, animSet);
}
@@ -901,6 +960,8 @@ void applyMovement(int16_t *x, int16_t *y, int8_t *z, uint16_t flags) {
}
void PelrockEngine::drawNextFrame(Sprite *sprite) {
+ if(sprite->index == 2)
+ debug("Drawing sprite %d at (%d,%d) zOrder %d, anim %d frame %d, movementFlags %d", sprite->index, sprite->x, sprite->y, sprite->zOrder, sprite->curAnimIndex, sprite->animData[sprite->curAnimIndex].curFrame, sprite->animData[sprite->curAnimIndex].movementFlags);
Anim &animData = sprite->animData[sprite->curAnimIndex];
if (sprite->zOrder == -1) {
// skips z0rder -1 sprites
@@ -936,6 +997,14 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
animData.curLoop = 0;
if (sprite->curAnimIndex < sprite->numAnims - 1) {
sprite->curAnimIndex++;
+
+ // Trigger ring on phone on every start of animation 2
+ if (_room->_currentRoomNumber == 9 && sprite->index == 3) {
+ if (sprite->curAnimIndex == 1 && animData.curLoop == 0) {
+ byte soundFileIndex = _room->_roomSfx[2];
+ _sound->playSound(soundFileIndex, 2);
+ }
+ }
} else {
sprite->curAnimIndex = 0;
}
@@ -1286,6 +1355,12 @@ void PelrockEngine::walkTo(int x, int y) {
_alfredState.setState(ALFRED_WALKING);
}
+void PelrockEngine::walkAndAction(HotSpot *hotspot, VerbIcon action) {
+ walkTo(hotspot->x + hotspot->w / 2, hotspot->y + hotspot->h);
+
+ _queuedAction = QueuedAction{action, hotspot->index, true};
+}
+
AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
AlfredDirection calculatedDirection = ALFRED_DOWN;
@@ -1420,7 +1495,6 @@ void PelrockEngine::checkMouseHover() {
hotspotDetected = true;
}
-
if (isActionUnder(_events->_mouseX, _events->_mouseY) != NO_ACTION) {
hotspotDetected = false;
}
@@ -1428,7 +1502,6 @@ void PelrockEngine::checkMouseHover() {
// Calculate walk target first (before checking anything else)
Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, hotspotDetected, hotspotDetected ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
-
bool alfredDetected = false;
if (isAlfredUnder(_events->_mouseX, _events->_mouseY)) {
alfredDetected = true;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 915b68ed8a8..c5927739af8 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -71,6 +71,7 @@ private:
Walking alforithm
*/
void walkTo(int x, int y);
+ void walkAndAction(HotSpot *hotspot, VerbIcon action);
AlfredDirection calculateAlfredsDirection(HotSpot *hotspot);
Common::Array<VerbIcon> availableActions(HotSpot *hotspot);
@@ -89,8 +90,10 @@ private:
void presentFrame();
void updatePaletteAnimations();
void paintDebugLayer();
- void placeStickers();
+ void placeStickersFirstPass();
+ void placeStickersSecondPass();
void placeSticker(Sticker sticker);
+ void renderOverlay(int overlayMode);
void animateFadePalette(PaletteAnim *anim);
void animateRotatePalette(PaletteAnim *anim);
@@ -224,6 +227,7 @@ public:
void loadExtraScreenAndPresent(int screenIndex);
void waitForSpecialAnimation();
bool renderScene(int overlayMode = OVERLAY_NONE);
+ void frameTriggers();
void changeCursor(Cursor cursor);
@@ -282,6 +286,12 @@ public:
void giveIdToGuard(int inventoryObject, HotSpot *hotspot);
void giveMoneyToGuard(int inventoryObject, HotSpot *hotspot);
void openMuseumDoor(HotSpot *hotspot);
+ void useAmuletWithStatue(int inventoryObject, HotSpot *hotspot);
+ void pickUpLetter(HotSpot *hotspot);
+ void openLibraryOutdoorsDoor(HotSpot *hotspot);
+ void closeLibraryOutdoorsDoor(HotSpot *hotspot);
+ void openLibraryIndoorsDoor(HotSpot *hotspot);
+ void closeLibraryIndoorsDoor(HotSpot *hotspot);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
};
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 8917eb03092..e6641fb8712 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -23,6 +23,7 @@
#include "pelrock/pelrock.h"
#include "pelrock/room.h"
#include "pelrock/util.h"
+#include "room.h"
namespace Pelrock {
@@ -191,6 +192,11 @@ void RoomManager::moveHotspot(HotSpot *hotspot, int16 newX, int16 newY, bool per
}
}
+void RoomManager::setActionMask(HotSpot *hotspot, byte actionMask) {
+ hotspot->actionFlags = actionMask;
+ changeHotSpot(*hotspot);
+}
+
void RoomManager::addWalkbox(WalkBox walkbox) {
g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
}
@@ -765,7 +771,7 @@ void RoomManager::addDisabledChoice(ChoiceOption choice) {
// Write 0xFA at offset+2 (after FB/F1 marker and level byte)
// This marks the choice as disabled without destroying the marker structure
uint32 disableOffset = choice.dataOffset + 2;
- debug("Adding disabled branch for room %d at offset %d (FA written at %d)",
+ debug("Adding disabled branch for room %d at offset %d (FA written at %d)",
choice.room, choice.dataOffset, disableOffset);
ResetEntry resetEntry = ResetEntry();
resetEntry.room = choice.room;
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index cb676dbabd6..e837fe45a2d 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -45,6 +45,7 @@ static const int unpickableHotspotExtras[] = {
6,
7,
316, // wires
+ 357, // mailbox should pick a different hotspot
};
class RoomManager {
@@ -86,6 +87,7 @@ public:
void disableHotspot(HotSpot *hotspot, bool persist = true);
void disableHotspot(byte room, HotSpot *hotspot, bool persist = true);
void moveHotspot(HotSpot *hotspot, int16 newX, int16 newY, bool persist = true);
+ void setActionMask(HotSpot *hotspot, byte actionMask);
void moveHotspot(byte room, HotSpot *hotspot, int16 newX, int16 newY, bool persist = true);
void addWalkbox(WalkBox walkbox);
void addWalkbox(byte room, WalkBox walkbox);
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index deea925d318..98f57125cc9 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -48,7 +48,7 @@ SoundManager::~SoundManager() {
stopMusic();
}
-void SoundManager::playSound(byte index, int volume) {
+void SoundManager::playSound(byte index, int volume, int channel) {
// debug("Playing sound index %d (%s)", index, SOUND_FILENAMES[index]);
auto it = _soundMap.find(SOUND_FILENAMES[index]);
if (it != _soundMap.end()) {
@@ -58,7 +58,7 @@ void SoundManager::playSound(byte index, int volume) {
}
}
-void SoundManager::playSound(SonidoFile sound, int volume) {
+void SoundManager::playSound(SonidoFile sound, int volume, int channel) {
Common::File sonidosFile;
if (!sonidosFile.open(Common::Path("SONIDOS.DAT"))) {
debug("Failed to open SONIDOS.DAT");
@@ -99,7 +99,15 @@ void SoundManager::playSound(SonidoFile sound, int volume) {
}
if (stream) {
- int channel = findFreeChannel();
+ if(channel == -1) {
+ // Find a free channel
+ channel = findFreeChannel();
+ }
+ else {
+ if(_mixer->isSoundHandleActive(_sfxHandles[channel])) {
+ _mixer->stopHandle(_sfxHandles[channel]);
+ }
+ }
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
}
}
@@ -149,7 +157,8 @@ int SoundManager::getSampleRate(byte *data, SoundFormat format) {
}
int SoundManager::findFreeChannel() {
- for (int i = 0; i < kMaxChannels; i++) {
+ //Reserve first 3 channels for one-off sounds
+ for (int i = 3; i < kMaxChannels; i++) {
if (!_mixer->isSoundHandleActive(_sfxHandles[i])) {
return i;
}
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 45d882fa1a3..5f0f90c895e 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -158,7 +158,7 @@ class SoundManager {
public:
SoundManager(Audio::Mixer *mixer);
~SoundManager();
- void playSound(byte index, int volume = 255);
+ void playSound(byte index, int volume = 255, int channel = -1);
void playSound(byte *soundData, uint32 size, int volume = 255);
void stopAllSounds();
void stopSound(int channel);
@@ -182,7 +182,7 @@ public:
int tickAmbientSound(uint32 frameCount);
private:
- void playSound(SonidoFile sound, int volume = 255);
+ void playSound(SonidoFile sound, int volume = 255, int channel = -1);
SoundFormat detectFormat(byte *data, uint32 size);
int getSampleRate(byte *data, SoundFormat format);
int findFreeChannel();
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 6203cf64bdb..424c4f005d2 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -35,6 +35,15 @@ enum Cursor {
COMBINATION
};
+#define ACTION_MASK_NONE 0
+#define ACTION_MASK_OPEN 1
+#define ACTION_MASK_CLOSE 2
+#define ACTION_MASK_UNKNOWN 4
+#define ACTION_MASK_PICKUP 8
+#define ACTION_MASK_TALK 16
+#define ACTION_MASK_PUSH 32
+#define ACTION_MASK_PULL 128
+
enum VerbIcon {
PICKUP,
TALK,
@@ -471,8 +480,8 @@ struct GameStateData {
Common::Array<byte> inventoryItems;
int16 selectedInventoryItem = -1;
+ int libraryShelf = -1;
Common::HashMap<byte, Common::Array<Sticker>> stickersPerRoom;
- // Common::HashMap<byte, ResetEntry> roomExitChanges;
Common::HashMap<byte, Common::Array<ExitChange>> roomExitChanges;
Common::HashMap<byte, Common::Array<WalkBoxChange>> roomWalkBoxChanges;
Common::HashMap<byte, Common::Array<HotSpotChange>> roomHotSpotChanges;
Commit: 8fde0bac53520e097456df6ddbcaa1076bfa2cbb
https://github.com/scummvm/scummvm/commit/8fde0bac53520e097456df6ddbcaa1076bfa2cbb
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:51+02:00
Commit Message:
PELROCK: Implements library mouse (pass-by animations)
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/chrono.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 5cc6b2a9517..f43d0d57aa2 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -97,6 +97,9 @@ const ActionEntry actionTable[] = {
// Room 9
{363, OPEN, &PelrockEngine::openLibraryIndoorsDoor},
{363, CLOSE, &PelrockEngine::closeLibraryIndoorsDoor},
+ {360, PICKUP, &PelrockEngine::pickBooksFromShelf1},
+ {361, PICKUP, &PelrockEngine::pickBooksFromShelf2},
+ {362, PICKUP, &PelrockEngine::pickBooksFromShelf3},
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
@@ -205,7 +208,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
} else if (actionTrigger == 263) {
_dialog->say(_res->_ingameTexts[UN_POCO_RESPETO]);
} else if (actionTrigger == 264) {
- //disables the two first roots, the second one will be enabled later!
+ // disables the two first roots, the second one will be enabled later!
_state->setRootDisabledState(room, rootIndex, true);
_state->setRootDisabledState(room, rootIndex + 1, true);
} else {
@@ -604,6 +607,67 @@ void PelrockEngine::closeLibraryIndoorsDoor(HotSpot *hotspot) {
closeDoor(hotspot, 0, 28, FEMININE, false);
}
+void PelrockEngine::pickBooksFromShelf1(HotSpot *hotspot) {
+ pickUpBook(0);
+}
+
+void PelrockEngine::pickBooksFromShelf2(HotSpot *hotspot) {
+ pickUpBook(1);
+}
+
+void PelrockEngine::pickBooksFromShelf3(HotSpot *hotspot) {
+ pickUpBook(2);
+}
+
+void PelrockEngine::pickUpBook(int i) {
+ if (!_state->hasInventoryItem(10)) {
+ _dialog->say(_res->_ingameTexts[VENGA_ACA]);
+ _state->setRootDisabledState(9, 0, true);
+ _alfredState.isWalkingCancelable = false;
+ walkAndAction(_room->findHotspotByExtra(102), TALK);
+ } else {
+ if (_state->libraryShelf == -1) {
+ _dialog->say(_res->_ingameTexts[TODOS]);
+ } else if (_state->libraryShelf != i) {
+ _dialog->say(_res->_ingameTexts[EL_LIBRO_NOESTA_AQUI]);
+ } else {
+ _state->libraryShelf = -1;
+ }
+ }
+ // if (AlfredActivity.stanteriaABuscar == -1)// no ha memorizado
+ // // ninguno
+ // AlfredActivity.myMovingAlfredThread
+ // .saySomething(AlfredActivity.extraThingsToTranslate[54]);
+ // else
+ // {
+ // if (AlfredActivity.stanteriaABuscar != i)// estanteria
+ // // equivocada
+ // AlfredActivity.myMovingAlfredThread
+ // .saySomething(AlfredActivity.extraThingsToTranslate[66]);
+ // else
+ // // coge el libro
+ // {
+
+ // AlfredActivity.stanteriaABuscar = -1;
+
+ // int hml = howManyLibrosTengo();
+
+ // if (hml == 3)
+ // {
+ // int in = getFirstBook();
+ // if (in != -1)
+ // AlfredActivity.removeUsingObject(in);
+
+ // AlfredActivity.myMovingAlfredThread
+ // .saySomething(AlfredActivity.extraThingsToTranslate[67]);
+ // }
+
+ // AlfredActivity
+ // .addInventoryItem(11 + AlfredActivity.newShowLibro.index);
+ // }
+ // }
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 295157816f2..f7f67229545 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -30,8 +30,7 @@ namespace Pelrock {
// const int kTickMs = 15;
// const int kTickMs = 33;
// const int kTickMs = 38;
-// const int kTickMs = 55;
-const int kTickMs = 200;
+const int kTickMs = 55;
// const int kTickMs = 60;
const int kHalfTickMultiplier = 2;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 5b45e3d5b31..29676cdef92 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -251,16 +251,22 @@ bool PelrockEngine::renderScene(int overlayMode) {
return false;
}
-const int kPasserbyTriggerFrameInterval = 30;
+const int kPasserbyTriggerFrameInterval = 0x3FF;
void PelrockEngine::frameTriggers() {
if ((_chrono->getFrameCount() & kPasserbyTriggerFrameInterval) == kPasserbyTriggerFrameInterval) {
debug("Would trigger passer-by");
- switch (_room->_currentRoomNumber)
- {
+ switch (_room->_currentRoomNumber) {
case 9: {
Sprite *mouse = _room->findSpriteByIndex(2);
- mouse->zOrder = 3;
+ mouse->zOrder = 1;
+ mouse->animData[0].loopCount = 3;
+ mouse->animData[1].loopCount = 1;
+ mouse->animData[1].movementFlags = 0x3FF;
+ mouse->animData[2].loopCount = 1;
+ mouse->animData[2].movementFlags = 0x801F;
+ mouse->animData[3].loopCount = 3;
+ mouse->animData[3].movementFlags = 0x3E0;
break;
}
default:
@@ -268,29 +274,11 @@ void PelrockEngine::frameTriggers() {
}
}
- if(_room->_currentRoomNumber == 9) {
+ if (_room->_currentRoomNumber == 9) {
+ // Mouse animation on library
Sprite *mouse = _room->findSpriteByIndex(2);
if (mouse) {
- if(mouse->x > 130 && mouse->x < 200) {
- debug("Moving mouse right and down");
- if(mouse->curAnimIndex == 0)
- mouse->curAnimIndex = 1;
- mouse->y += 2;
- mouse->x += 6;
- }
- else if(mouse->x > 200 && mouse->x < 340) {
- debug("Moving mouse right");
- if(mouse->curAnimIndex == 1)
- mouse->curAnimIndex = 2;
- mouse->x += 6;
- }
- else if(mouse->x > 340) {
- debug("Moving mouse down");
- if(mouse->curAnimIndex == 2)
- mouse->curAnimIndex = 1;
- mouse->y += 2;
- }
- if(mouse->x > 355) {
+ if (mouse->y > 355) {
mouse->x = 82;
mouse->y = 315;
mouse->zOrder = 255;
@@ -337,6 +325,14 @@ void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
void PelrockEngine::checkMouse() {
+ checkMouseHover();
+ if (_alfredState.animState == ALFRED_WALKING && !_alfredState.isWalkingCancelable) {
+ // Ignore clicks while Alfred is walking
+ _events->_leftMouseClicked = false;
+ debug("Ignoring mouse click while Alfred is walking");
+ return;
+ }
+
// Cancel walking animation on mouse click
if (_events->_leftMouseButton) {
_alfredState.curFrame = 0;
@@ -364,6 +360,7 @@ void PelrockEngine::checkMouse() {
_currentHotspot = nullptr;
}
} else if (_events->_leftMouseClicked) {
+
// Regular click (not during popup mode)
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_leftMouseClicked = false;
@@ -376,7 +373,6 @@ void PelrockEngine::checkMouse() {
_events->_rightMouseClicked = false;
_state->stateGame = SETTINGS;
}
- checkMouseHover();
}
void PelrockEngine::copyBackgroundToBuffer() {
@@ -704,6 +700,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_currentStep = 0;
debug("Finished walking to target");
_alfredState.setState(ALFRED_IDLE);
+ _alfredState.isWalkingCancelable = true;
if (_currentHotspot != nullptr)
_alfredState.direction = calculateAlfredsDirection(_currentHotspot);
@@ -960,8 +957,6 @@ void applyMovement(int16_t *x, int16_t *y, int8_t *z, uint16_t flags) {
}
void PelrockEngine::drawNextFrame(Sprite *sprite) {
- if(sprite->index == 2)
- debug("Drawing sprite %d at (%d,%d) zOrder %d, anim %d frame %d, movementFlags %d", sprite->index, sprite->x, sprite->y, sprite->zOrder, sprite->curAnimIndex, sprite->animData[sprite->curAnimIndex].curFrame, sprite->animData[sprite->curAnimIndex].movementFlags);
Anim &animData = sprite->animData[sprite->curAnimIndex];
if (sprite->zOrder == -1) {
// skips z0rder -1 sprites
@@ -1357,7 +1352,6 @@ void PelrockEngine::walkTo(int x, int y) {
void PelrockEngine::walkAndAction(HotSpot *hotspot, VerbIcon action) {
walkTo(hotspot->x + hotspot->w / 2, hotspot->y + hotspot->h);
-
_queuedAction = QueuedAction{action, hotspot->index, true};
}
@@ -1453,6 +1447,7 @@ bool PelrockEngine::isAlfredUnder(int x, int y) {
}
void PelrockEngine::checkMouseClick(int x, int y) {
+
// This handles regular clicks (not popup selection)
_queuedAction = QueuedAction{NO_ACTION, -1, false};
_actionPopupState.isActive = false;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index c5927739af8..052b418c668 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -166,6 +166,7 @@ public:
AlfredState _alfredState;
byte *_compositeBuffer = nullptr; // Working composition buffer
+ bool _mouseDisabled = false;
GameStateData *_state = new GameStateData();
SmallFont *_smallFont = nullptr;
@@ -292,6 +293,10 @@ public:
void closeLibraryOutdoorsDoor(HotSpot *hotspot);
void openLibraryIndoorsDoor(HotSpot *hotspot);
void closeLibraryIndoorsDoor(HotSpot *hotspot);
+ void pickBooksFromShelf1(HotSpot *hotspot);
+ void pickBooksFromShelf2(HotSpot *hotspot);
+ void pickBooksFromShelf3(HotSpot *hotspot);
+ void pickUpBook(int i);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
};
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index e837fe45a2d..00d231976f7 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -45,7 +45,10 @@ static const int unpickableHotspotExtras[] = {
6,
7,
316, // wires
- 357, // mailbox should pick a different hotspot
+ 357, // mailbox should pick a different hotspot,
+ 360, // library shelves
+ 361,
+ 362,
};
class RoomManager {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 424c4f005d2..329190948f9 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -165,6 +165,7 @@ struct AlfredState {
uint16 scaledX = 0;
uint16 scaledY = 0;
int idleFrameCounter = 0;
+ bool isWalkingCancelable = true;
void setState(AlfredAnimState nextState) {
animState = nextState;
Commit: 83b8fb17e9e678bf9c0019d6608349fbfdbb9165
https://github.com/scummvm/scummvm/commit/83b8fb17e9e678bf9c0019d6608349fbfdbb9165
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:51+02:00
Commit Message:
PELROCK: Computer-book logic
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/computer.cpp
engines/pelrock/computer.h
engines/pelrock/dialog.h
engines/pelrock/library_books.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index f43d0d57aa2..ab4c33c2d88 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -608,15 +608,15 @@ void PelrockEngine::closeLibraryIndoorsDoor(HotSpot *hotspot) {
}
void PelrockEngine::pickBooksFromShelf1(HotSpot *hotspot) {
- pickUpBook(0);
+ pickUpBook(1);
}
void PelrockEngine::pickBooksFromShelf2(HotSpot *hotspot) {
- pickUpBook(1);
+ pickUpBook(2);
}
void PelrockEngine::pickBooksFromShelf3(HotSpot *hotspot) {
- pickUpBook(2);
+ pickUpBook(3);
}
void PelrockEngine::pickUpBook(int i) {
@@ -632,40 +632,17 @@ void PelrockEngine::pickUpBook(int i) {
_dialog->say(_res->_ingameTexts[EL_LIBRO_NOESTA_AQUI]);
} else {
_state->libraryShelf = -1;
+ int booksInInventory = _state->booksInInventory();
+ if (booksInInventory == 3) {
+ int firstBook = _state->findFirstBookIndex();
+ if(firstBook != -1)
+ _state->removeInventoryItem(firstBook);
+ _dialog->say(_res->_ingameTexts[TENDRE_DEJAR_LIBRO]);
+ }
+ _state->addInventoryItem(_state->selectedBookIndex);
+ _state->selectedBookIndex = -1;
}
}
- // if (AlfredActivity.stanteriaABuscar == -1)// no ha memorizado
- // // ninguno
- // AlfredActivity.myMovingAlfredThread
- // .saySomething(AlfredActivity.extraThingsToTranslate[54]);
- // else
- // {
- // if (AlfredActivity.stanteriaABuscar != i)// estanteria
- // // equivocada
- // AlfredActivity.myMovingAlfredThread
- // .saySomething(AlfredActivity.extraThingsToTranslate[66]);
- // else
- // // coge el libro
- // {
-
- // AlfredActivity.stanteriaABuscar = -1;
-
- // int hml = howManyLibrosTengo();
-
- // if (hml == 3)
- // {
- // int in = getFirstBook();
- // if (in != -1)
- // AlfredActivity.removeUsingObject(in);
-
- // AlfredActivity.myMovingAlfredThread
- // .saySomething(AlfredActivity.extraThingsToTranslate[67]);
- // }
-
- // AlfredActivity
- // .addInventoryItem(11 + AlfredActivity.newShowLibro.index);
- // }
- // }
}
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index 3b60c673edf..4b675b82dec 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -23,6 +23,7 @@
#include "common/system.h"
#include "graphics/paletteman.h"
+#include "computer.h"
#include "pelrock/computer.h"
#include "pelrock/library_books.h"
#include "pelrock/pelrock.h"
@@ -56,8 +57,51 @@ Computer::Computer(PelrockEventManager *eventMan)
_optCancelar = "(C)ancelar";
_noResults = "No se encontraron libros";
_memorizedMsg = "Bueno... Tendre que buscar en la estanteria de la %c";
+
+ init();
}
+void Computer::init() {
+ Common::File alfred7File;
+ if (!alfred7File.open("ALFRED.7")) {
+ error("Could not open ALFRED.7");
+ return;
+ }
+
+ alfred7File.seek(kBookDataOffset, SEEK_SET);
+ int index = 0;
+ int index2 = 0;
+ while (alfred7File.pos() < kBookDataEnd) {
+ LibraryBook book;
+
+ book.title = alfred7File.readString(0, kBookTitleSize);
+ book.author = alfred7File.readString(0, kBookAuthorSize);
+ book.genre = alfred7File.readString(0, kBookGenreSize);
+ book.title.trim();
+ book.author.trim();
+ book.genre.trim();
+ book.inventoryIndex = alfred7File.readByte() - 55;
+ book.shelf = alfred7File.readByte();
+ book.available = alfred7File.readByte() == 2;
+ // book.index = book.available ? index++ : -1;
+ // book.index2 = index2++;
+ _libraryBooks.push_back(book);
+ }
+
+ for(int i = 0; i < _libraryBooks.size(); i++) {
+ const LibraryBook &book = _libraryBooks[i];
+ debug("Loaded book: title='%s', author='%s', genre='%s', unknown=%d, shelf=%d, available=%d",
+ book.title.c_str(), book.author.c_str(), book.genre.c_str(),
+ book.inventoryIndex, book.shelf, book.available);
+ }
+
+ _searchResults.clear();
+ _currentResult = 0;
+ _searchLetter = 0;
+ _memorizedBookIndex = -1;
+}
+
+
Computer::~Computer() {
cleanup();
}
@@ -137,66 +181,64 @@ void Computer::drawScreen() {
case STATE_SEARCH_BY_TITLE:
case STATE_SEARCH_BY_AUTHOR:
g_engine->_smallFont->drawString(g_engine->_screen,
- _searchType == 0 ? "CONSULTAR POR TITULO" : "CONSULTAR POR AUTOR",
- textX, textY, 280, 15, Graphics::kTextAlignCenter);
+ _searchType == 0 ? "CONSULTAR POR TITULO" : "CONSULTAR POR AUTOR",
+ textX, textY, 280, 15, Graphics::kTextAlignCenter);
g_engine->_smallFont->drawString(g_engine->_screen, _promptLetter, textX, textY + 40, 280, 14);
break;
- case STATE_SHOW_RESULTS:
- {
- Common::String header = Common::String::format(
- "Consulta de %s, letra %c",
- _searchType == 0 ? "TITULO" : "AUTOR",
- _searchLetter);
- g_engine->_smallFont->drawString(g_engine->_screen, header, textX, textY, 280, 15, Graphics::kTextAlignCenter);
+ case STATE_SHOW_RESULTS: {
+ Common::String header = Common::String::format(
+ "Consulta de %s, letra %c",
+ _searchType == 0 ? "TITULO" : "AUTOR",
+ _searchLetter);
+ g_engine->_smallFont->drawString(g_engine->_screen, header, textX, textY, 280, 15, Graphics::kTextAlignCenter);
+
+ if (_searchResults.empty()) {
+ g_engine->_smallFont->drawString(g_engine->_screen, _noResults, textX, textY + 50, 280, 14);
+ } else {
+ // Display current book
+ int bookIdx = _searchResults[_currentResult];
+ const LibraryBook &book = _libraryBooks[bookIdx];
+
+ // Title (may be long, truncate if needed)
+ Common::String titleLine = Common::String::format("%s%s", _labelTitle, book.title.c_str());
+ g_engine->_smallFont->drawString(g_engine->_screen, titleLine, textX - 50, textY + 40, 340, 14);
- if (_searchResults.empty()) {
- g_engine->_smallFont->drawString(g_engine->_screen, _noResults, textX, textY + 50, 280, 14);
+ // Author
+ Common::String authorLine = Common::String::format("%s%s", _labelAuthor, book.author.c_str());
+ g_engine->_smallFont->drawString(g_engine->_screen, authorLine, textX - 50, textY + 60, 340, 14);
+
+ // Genre
+ Common::String genreLine = Common::String::format("%s%s", _labelGenre, book.genre.c_str());
+ g_engine->_smallFont->drawString(g_engine->_screen, genreLine, textX - 50, textY + 80, 340, 14);
+
+ // Situacion (location/availability)
+ Common::String situacionLine;
+ if (book.available) {
+ situacionLine = Common::String::format("%s Estanteria %d",
+ _labelSituacion, book.shelf);
+ } else {
+ situacionLine = Common::String::format("%s%s",
+ _labelSituacion, _statusCatalogOnly);
+ }
+ g_engine->_smallFont->drawString(g_engine->_screen, situacionLine, textX - 50, textY + 100, 340,
+ book.available ? 10 : 8); // Green if physical, gray if catalog-only
+
+ // Show result counter
+ Common::String counter = Common::String::format("Libro %d de %d",
+ _currentResult + 1, (int)_searchResults.size());
+ g_engine->_smallFont->drawString(g_engine->_screen, counter, textX, textY + 130, 280, 14, Graphics::kTextAlignCenter);
+
+ // Show navigation options
+ Common::String navOptions;
+ if (book.available) {
+ navOptions = Common::String::format("%s %s %s", _optMemorizar, _optSeguir, _optCancelar);
} else {
- // Display current book
- int bookIdx = _searchResults[_currentResult];
- const LibraryBook &book = kLibraryBooks[bookIdx];
-
- // Title (may be long, truncate if needed)
- Common::String titleLine = Common::String::format("%s%s", _labelTitle, book.title);
- g_engine->_smallFont->drawString(g_engine->_screen, titleLine, textX - 50, textY + 40, 340, 14);
-
- // Author
- Common::String authorLine = Common::String::format("%s%s", _labelAuthor, book.author);
- g_engine->_smallFont->drawString(g_engine->_screen, authorLine, textX - 50, textY + 60, 340, 14);
-
- // Genre
- Common::String genreLine = Common::String::format("%s%s", _labelGenre, book.genre);
- g_engine->_smallFont->drawString(g_engine->_screen, genreLine, textX - 50, textY + 80, 340, 14);
-
- // Situacion (location/availability)
- Common::String situacionLine;
- if (book.available) {
- situacionLine = Common::String::format("%sEstante %c, fila %d",
- _labelSituacion, book.shelfLetter, book.shelfRow);
- } else {
- situacionLine = Common::String::format("%s%s",
- _labelSituacion, _statusCatalogOnly);
- }
- g_engine->_smallFont->drawString(g_engine->_screen, situacionLine, textX - 50, textY + 100, 340,
- book.available ? 10 : 8); // Green if physical, gray if catalog-only
-
- // Show result counter
- Common::String counter = Common::String::format("Libro %d de %d",
- _currentResult + 1, (int)_searchResults.size());
- g_engine->_smallFont->drawString(g_engine->_screen, counter, textX, textY + 130, 280, 14, Graphics::kTextAlignCenter);
-
- // Show navigation options
- Common::String navOptions;
- if (book.available) {
- navOptions = Common::String::format("%s %s %s", _optMemorizar, _optSeguir, _optCancelar);
- } else {
- navOptions = Common::String::format("%s %s", _optSeguir, _optCancelar);
- }
- g_engine->_smallFont->drawString(g_engine->_screen, navOptions, textX, textY + 160, 280, 8, Graphics::kTextAlignCenter);
+ navOptions = Common::String::format("%s %s", _optSeguir, _optCancelar);
}
+ g_engine->_smallFont->drawString(g_engine->_screen, navOptions, textX, textY + 160, 280, 8, Graphics::kTextAlignCenter);
}
- break;
+ } break;
case STATE_EXIT:
break;
@@ -219,7 +261,7 @@ void Computer::handleMainMenu() {
void Computer::handleSearchInput() {
if (_events->_lastKeyEvent >= Common::KEYCODE_a &&
- _events->_lastKeyEvent <= Common::KEYCODE_z) {
+ _events->_lastKeyEvent <= Common::KEYCODE_z) {
_searchLetter = 'A' + (_events->_lastKeyEvent - Common::KEYCODE_a);
performSearch();
_currentResult = 0;
@@ -237,11 +279,10 @@ void Computer::handleResultsDisplay() {
_currentResult = (_currentResult + 1) % _searchResults.size();
}
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
- }
- else if (_events->_lastKeyEvent == Common::KEYCODE_m) {
+ } else if (_events->_lastKeyEvent == Common::KEYCODE_m) {
if (!_searchResults.empty()) {
int bookIdx = _searchResults[_currentResult];
- const LibraryBook &book = kLibraryBooks[bookIdx];
+ const LibraryBook &book = _libraryBooks[bookIdx];
if (book.available) {
memorizeBook(bookIdx);
}
@@ -250,35 +291,35 @@ void Computer::handleResultsDisplay() {
}
// C key or ESC - Cancel (return to main menu)
else if (_events->_lastKeyEvent == Common::KEYCODE_c ||
- _events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
+ _events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
_state = STATE_MAIN_MENU;
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ g_engine->_state->libraryShelf = -1; // 0-based shelf index
+ g_engine->_state->selectedBookIndex = -1;
+ g_engine->_state->bookLetter = '\0';
}
}
void Computer::memorizeBook(int bookIndex) {
- const LibraryBook &book = kLibraryBooks[bookIndex];
+ const LibraryBook &book = _libraryBooks[bookIndex];
// Store the memorized book for later pickup from the shelf
_memorizedBookIndex = bookIndex;
- // In the original game, Alfred says "Bueno... Tendre que buscar en la estanteria de la X"
- // where X is the shelf letter
- // TODO: Play the dialog and set a game flag so the book can be picked up from the shelf
-
- // For now, just exit the computer interface
- // The game state should be updated to allow picking up this book from shelf X
_state = STATE_EXIT;
- debug(1, "Memorized book '%s' at shelf %c, row %d", book.title, book.shelfLetter, book.shelfRow);
+ g_engine->_state->libraryShelf = book.shelf; // 0-based shelf index
+ g_engine->_state->selectedBookIndex = book.inventoryIndex;
+ g_engine->_state->bookLetter = book.title[0];
+
+ debug("Memorized book '%s' with index %d, shelf %d, letter %c", book.title.c_str(), g_engine->_state->selectedBookIndex, g_engine->_state->libraryShelf, g_engine->_state->bookLetter);
}
void Computer::performSearch() {
_searchResults.clear();
- for (int i = 0; i < kLibraryBookCount; i++) {
- const char *searchField = _searchType == 0 ?
- kLibraryBooks[i].title : kLibraryBooks[i].author;
+ for (int i = 0; i < _libraryBooks.size(); i++) {
+ Common::String searchField = _searchType == 0 ? _libraryBooks[i].title : _libraryBooks[i].author;
// Check if first letter matches (case-insensitive)
char firstChar = searchField[0];
diff --git a/engines/pelrock/computer.h b/engines/pelrock/computer.h
index a9c3f7e1e00..7f0117c9f4c 100644
--- a/engines/pelrock/computer.h
+++ b/engines/pelrock/computer.h
@@ -26,6 +26,7 @@
#include "common/str.h"
#include "pelrock/events.h"
+#include "pelrock/library_books.h"
namespace Pelrock {
@@ -34,12 +35,14 @@ class PelrockEngine;
class Computer {
public:
Computer(PelrockEventManager *eventMan);
+
~Computer();
/**
* @return Book index if a book was memorized, -1 otherwise
*/
int run();
+ const char *_memorizedMsg; // "Bueno... Tendre que buscar en la estanteria de la %c"
private:
enum ComputerState {
@@ -59,6 +62,7 @@ private:
char _searchLetter;
int _searchType; // 0 = title, 1 = author
Common::Array<int> _searchResults;
+ Common::Array<LibraryBook> _libraryBooks;
int _currentResult;
int _memorizedBookIndex; // Index of book that was memorized (-1 if none)
@@ -77,7 +81,6 @@ private:
const char *_optSeguir; // "(S)eguir"
const char *_optCancelar; // "(C)ancelar"
const char *_noResults; // "No se encontraron libros"
- const char *_memorizedMsg; // "Bueno... Tendre que buscar en la estanteria de la %c"
void loadBackground();
void cleanup();
@@ -87,6 +90,7 @@ private:
void performSearch();
void drawScreen();
void memorizeBook(int bookIndex);
+ void init();
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 7719110b719..03c578ca35e 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -65,7 +65,6 @@ private:
uint32 parseChoices(const byte *data, uint32 dataSize, uint32 startPos, Common::Array<ChoiceOption> *outChoices);
void setCurSprite(int index);
void checkMouse();
- void sayAlfred(Common::StringArray texts);
bool checkAllSubBranchesExhausted(const byte *data, uint32 dataSize, uint32 startPos, int currentChoiceLevel);
public:
@@ -76,6 +75,7 @@ public:
int selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer);
void startConversation(const byte *conversationData, uint32 dataSize, byte npcIndex, Sprite *alfredAnimSet = nullptr);
void sayAlfred(Description description);
+ void sayAlfred(Common::StringArray texts);
void say(Common::StringArray texts, byte spriteIndex = 0);
void say(Common::StringArray texts, int16 x, int16 y);
bool processColorAndTrim(Common::StringArray &lines, byte &speakerId);
diff --git a/engines/pelrock/library_books.h b/engines/pelrock/library_books.h
index a86a990948e..15a6491b98e 100644
--- a/engines/pelrock/library_books.h
+++ b/engines/pelrock/library_books.h
@@ -37,268 +37,271 @@ static const byte kBookStatusCatalogOnly = 0x01; // No physical copy
static const byte kBookStatusPhysical = 0x02; // Has physical copy on shelf
struct LibraryBook {
- const char *title;
- const char *author;
- const char *genre;
- char shelfLetter; // A-Z for shelf location, space if catalog-only
- byte shelfRow; // 1-3 for row number, 0 if catalog-only
+ Common::String title; //55 bytes for title
+ Common::String author; //30 bytes for author
+ Common::String genre; //20 bytes for genre
+ byte inventoryIndex;
+ byte shelf; // 1-3 for row number, 0 if catalog-only
bool available; // true = can be found on shelf, false = catalog only
};
-static const int kLibraryBookCount = 125;
+const LibraryBook noBook = {"", "", "", 0, 0, false};
-static const LibraryBook kLibraryBooks[] = {
- // Book 1: Los hombres: ¡ Como caparlos !
- {"Los hombres: ¡ Como caparlos !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
- // Book 2: Mujeres del mundo: ¡ No os depileis las ...
- {"Mujeres del mundo: ¡ No os depileis las axilas !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
- // Book 3: Gato por liebre
- {"Gato por liebre", "Karlos Arguiñano", "Cocina", 'I', 1, true},
- // Book 4: Hamlet
- {"Hamlet", "William Shakespeare", "Teatro", ' ', 0, false},
- // Book 5: Fausto
- {"Fausto", "Goethe", "Novela", ' ', 0, false},
- // Book 6: Enrique de Ofterdingen
- {"Enrique de Ofterdingen", "Novalis", "Novela", 'J', 1, true},
- // Book 7: Guia de desobediencia civica
- {"Guia de desobediencia civica", "Azagra", "Ensayo", ' ', 0, false},
- // Book 8: Literatura en la edad de piedra: cuestio...
- {"Literatura en la edad de piedra: cuestion de fuerza", "Profesor Cebollo", "Ensayo", ' ', 0, false},
- // Book 9: Turbo C ++ con Intratex
- {"Turbo C ++ con Intratex", "Programadores reunidos", "Informatica", ' ', 0, false},
- // Book 10: Codigo Maquina a pelo
- {"Codigo Maquina a pelo", "Programadores reunidos", "Informatica", 'K', 1, true},
- // Book 11: Asesino por vocacion
- {"Asesino por vocacion", "Chema Ton", "Novela negra", ' ', 0, false},
- // Book 12: Poemas rebuscados
- {"Poemas rebuscados", "Ramon Rodriguez", "Poesia", ' ', 0, false},
- // Book 13: El parto de las tortugas: Un proceso len...
- {"El parto de las tortugas: Un proceso lento", "Profesor Lorin Colorado", "Biologia", ' ', 0, false},
- // Book 14: Te parto la cara ¡ Capuyo !
- {"Te parto la cara ¡ Capuyo !", "Jhonny Rapper", "Critica Social", 'L', 3, true},
- // Book 15: En los tugurios del Himalaya
- {"En los tugurios del Himalaya", "Coronel Tapioca", "Aventuras", ' ', 0, false},
- // Book 16: En las callejuelas del amazonas
- {"En las callejuelas del amazonas", "Coronel Tapioca", "Aventuras", ' ', 0, false},
- // Book 17: En las selvas de Londres
- {"En las selvas de Londres", "Coronel Tapioca", "Aventuras", 'M', 1, true},
- // Book 18: Sueños binarios
- {"Sueños binarios", "Doctor Chip", "Ciencia ficcion", ' ', 0, false},
- // Book 19: Cien cuentos cortisimos
- {"Cien cuentos cortisimos", "Billi el rapido", "Novela", ' ', 0, false},
- // Book 20: Teoria de la relatividad
- {"Teoria de la relatividad", "Alfred Einstein", "Ciencia", ' ', 0, false},
- // Book 21: El ultimo paso para la cuadratura del ci...
- {"El ultimo paso para la cuadratura del circulo", "Anonimo", "Filosofia", 'N', 1, true},
- // Book 22: Correlacion entre el sentido de los colo...
- {"Correlacion entre el sentido de los colores y sonidos", "Anonimo", "Filosofia", ' ', 0, false},
- // Book 23: Los cuatro evangelios: Interpretados por...
- {"Los cuatro evangelios: Interpretados por ordenador", "Doctor Chip", "Teologia", ' ', 0, false},
- // Book 24: Enciclopedia de bolsillo
- {"Enciclopedia de bolsillo", "Profesor Lumbreras", "Enciclopedia", 'O', 1, true},
- // Book 25: Sigueme y revienta
- {"Sigueme y revienta", "M. Indurain", "Deporte", 'P', 3, true},
- // Book 26: Me duele too...
- {"Me duele too...", "Carmen Opausica", "Ensayo", ' ', 0, false},
- // Book 27: El Perro de Sam Rocker si tiene rabo
- {"El Perro de Sam Rocker si tiene rabo", "El Perro de Sam Rocker", "Biografia", ' ', 0, false},
- // Book 28: Donde estara mi carro ?
- {"Donde estara mi carro ?", "Manolo Escobar", "Aventuras", ' ', 0, false},
- // Book 29: Oh tu, bella flor del jardin
- {"Oh tu, bella flor del jardin", "La abeja Maya", "Poesia", 'Q', 2, true},
- // Book 30: Yogui, ¡ Bajate de esa motoneta !
- {"Yogui, ¡ Bajate de esa motoneta !", "Bubu", "Filosofia", ' ', 0, false},
- // Book 31: Odio a muerte a loh mardito rohedore !
- {"Odio a muerte a loh mardito rohedore !", "Er gato Yin", "Zoologia", ' ', 0, false},
- // Book 32: Pissi, Dissi, ¡ Sargan de su aguhero !
- {"Pissi, Dissi, ¡ Sargan de su aguhero !", "Er gato Yin", "Zoologia", ' ', 0, false},
- // Book 33: Mardito sea ... ¡ Er queso !
- {"Mardito sea ... ¡ Er queso !", "Er gato Yin", "Zoologia", ' ', 0, false},
- // Book 34: La mate porque era mia
- {"La mate porque era mia", "Loquillo", "Novela", ' ', 0, false},
- // Book 35: Los gallos: Esos desconocidos
- {"Los gallos: Esos desconocidos", "Paco rico", "Zoologia", ' ', 0, false},
- // Book 36: Cuentos corrientes
- {"Cuentos corrientes", "Pepe Lopez", "Novela", 'R', 1, true},
- // Book 37: Mas madera
- {"Mas madera", "R. Gepetto", "Bricolage", 'S', 2, true},
- // Book 38: Cuentos del Lejano Oriente
- {"Cuentos del Lejano Oriente", "Jhonny Mc. Dowall", "Novela", ' ', 0, false},
- // Book 39: Saca el guiski cheli
- {"Saca el guiski cheli", "Manolo lailo", "Cronica Social", ' ', 0, false},
- // Book 40: Ta totao !
- {"Ta totao !", "Lao Tse", "Filosofia", ' ', 0, false},
- // Book 41: Mis conversaciones con el señor Roca
- {"Mis conversaciones con el señor Roca", "Francisca Gando", "Epistolar", 'T', 2, true},
- // Book 42: Guia para la supervivencia
- {"Guia para la supervivencia", "Robinson Crusoe", "Manual", ' ', 0, false},
- // Book 43: No esperes a ser la segunda: ¡ Engaña a ...
- {"No esperes a ser la segunda: ¡ Engaña a tu marido !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
- // Book 44: Yoga Sutras
- {"Yoga Sutras", "Patanjali", "Filosofia", 'X', 3, true},
- // Book 45: El juego de los Abalorios
- {"El juego de los Abalorios", "Herman Hesse", "Novela", ' ', 0, false},
- // Book 46: Tienes suerte de ser tan pequeño, ¡ mard...
- {"Tienes suerte de ser tan pequeño, ¡ mardito roedo !", "Er gato Yin", "Novela", ' ', 0, false},
- // Book 47: Como hacerse rico en diez minutos
- {"Como hacerse rico en diez minutos", "El Dioni", "Manual", 'Y', 1, true},
- // Book 48: Te querre a pesar de tu madre
- {"Te querre a pesar de tu madre", "Corin Tellado", "Novela rosa", ' ', 0, false},
- // Book 49: Hasta que el mando a distancia nos separ...
- {"Hasta que el mando a distancia nos separe", "Corin Tellado", "Novela rosa", ' ', 0, false},
- // Book 50: Una pasion ostentorea
- {"Una pasion ostentorea", "Corin Tellado y Jesus Gil", "Novela rosa", 'Z', 3, true},
- // Book 51: Por mi, como si te la machacas
- {"Por mi, como si te la machacas", "Seneca", "Filosofia", ' ', 0, false},
- // Book 52: Conversaciones con mi caballo
- {"Conversaciones con mi caballo", "Jesus Gil", "Humor", ' ', 0, false},
- // Book 53: El poder curativo de la mierda comun
- {"El poder curativo de la mierda comun", "Sri Ramachrinaraska", "Esoterismo", ' ', 1, true},
- // Book 54: La liberacion mediante la eneriga de los...
- {"La liberacion mediante la eneriga de los pedos", "Sri Ramachrinaraska", "Esoterismo", ' ', 0, false},
- // Book 55: Sobre la imperceptibilidad de lo imperce...
- {"Sobre la imperceptibilidad de lo imperceptible", "Perogrullo", "Ensayo", ' ', 0, false},
- // Book 56: Piojos; como educarlos sin traumas
- {"Piojos; como educarlos sin traumas", "Franz Franzfrenz", "Psicologia", ' ', 0, false},
- // Book 57: I Ching
- {"I Ching", "Richard Willem", "Filosofia", ' ', 0, false},
- // Book 58: No se nada, ni me importa
- {"No se nada, ni me importa", "Socrates", "Filosofia", 'U', 2, true},
- // Book 59: No he sido yo, ¡ Lo juro !
- {"No he sido yo, ¡ Lo juro !", "Juan Jose Gil", "Biografia", ' ', 0, false},
- // Book 60: Relatos cortos
- {"Relatos cortos", "Tachenko", "Novela de ficcion", 'V', 3, true},
- // Book 61: El martillo como elemento cognitivo
- {"El martillo como elemento cognitivo", "Friedrich Nietzsche", "Filosofia", ' ', 0, false},
- // Book 62: La maravillosa vida del escarabajo pelot...
- {"La maravillosa vida del escarabajo pelotero (v. I)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
- // Book 63: La maravillosa vida del escarabajo pelot...
- {"La maravillosa vida del escarabajo pelotero (v. II)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
- // Book 64: La maravillosa vida del escarabajo pelot...
- {"La maravillosa vida del escarabajo pelotero (v. III)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
- // Book 65: La maravillosa vida del escarabajo pelot...
- {"La maravillosa vida del escarabajo pelotero (v. IV)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
- // Book 66: La maravillosa vida del escarabajo pelot...
- {"La maravillosa vida del escarabajo pelotero (v. V)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
- // Book 67: Tu eliges: Tu madre o yo
- {"Tu eliges: Tu madre o yo", "Anonimo", "Psicologia aplicada", 'W', 3, true},
- // Book 68: Mi lucha
- {"Mi lucha", "Adolf Hitler", "Humor negro", ' ', 0, false},
- // Book 69: Cuentos de amor y desidia
- {"Cuentos de amor y desidia", "Jardiel Poncela", "Teatro", ' ', 1, true},
- // Book 70: Nuevas andanzas de Zaratustra
- {"Nuevas andanzas de Zaratustra", "Anonimo", "Aventuras", ' ', 2, true},
- // Book 71: Me se cuadre ¡ Coño !
- {"Me se cuadre ¡ Coño !", "Sargento Cienfuegos", "Etica militar", ' ', 2, true},
- // Book 72: Gatos: solos o con Ketchup
- {"Gatos: solos o con Ketchup", "El perro de Sam Rocker", "Cocina", ' ', 1, true},
- // Book 73: Querida Adelaida: mi marido NO ha dejado...
- {"Querida Adelaida: mi marido NO ha dejado de roncar", "Maruja Mones", "Epistolar", ' ', 0, false},
- // Book 74: Sobre el papel de El Lepe en el nuevo Or...
- {"Sobre el papel de El Lepe en el nuevo Orden Mundial", "General Sintacha", "Estrategia", ' ', 0, false},
- // Book 75: Aqui no hay nadie que se acueste sin cen...
- {"Aqui no hay nadie que se acueste sin cenar (v. I)", "Fidel Castro", "Politica", ' ', 1, true},
- // Book 76: Aqui no hay nadie que se acueste sin cen...
- {"Aqui no hay nadie que se acueste sin cenar (v. II)", "Fidel Castro", "Politica", ' ', 0, false},
- // Book 77: Aqui no hay nadie que se acueste sin cen...
- {"Aqui no hay nadie que se acueste sin cenar (v. III)", "Fidel Castro", "Politica", ' ', 0, false},
- // Book 78: Aqui no hay nadie que se acueste sin cen...
- {"Aqui no hay nadie que se acueste sin cenar (v. IV)", "Fidel Castro", "Politica", ' ', 0, false},
- // Book 79: Aqui no hay nadie que se acueste sin cen...
- {"Aqui no hay nadie que se acueste sin cenar (v. V)", "Fidel Castro", "Politica", ' ', 0, false},
- // Book 80: Domine la metafisica en 5 dias
- {"Domine la metafisica en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
- // Book 81: Domine el ensamblador en 5 dias
- {"Domine el ensamblador en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
- // Book 82: Dominese a si mismo en 5 dias
- {"Dominese a si mismo en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
- // Book 83: Piernas de Ciertopelo
- {"Piernas de Ciertopelo", "Chichi Mondongo", "Erotica", ' ', 2, true},
- // Book 84: Otra vuelta de tuerca
- {"Otra vuelta de tuerca", "Pepe, el fontanero", "Bricolage", ' ', 2, true},
- // Book 85: La Tierra: ¡ Planeta limpio !
- {"La Tierra: ¡ Planeta limpio !", "Juan, el basurero", "Ciencia Ficcion", ' ', 2, true},
- // Book 86: Liberad a Brian !
- {"Liberad a Brian !", "Roger Rabitt", "Historica", ' ', 2, true},
- // Book 87: La vida es una mierda
- {"La vida es una mierda", "Juanjo Dido", "Ensayo", ' ', 2, true},
- // Book 88: No era eso lo que yo di a entender
- {"No era eso lo que yo di a entender", "Jesus de Nazaret", "Religion", ' ', 2, true},
- // Book 89: Castigos a Piratas Informaticos
- {"Castigos a Piratas Informaticos", "Torquemada", "Inquisicion", ' ', 1, true},
- // Book 90: Confiesa, bruja asquerosa
- {"Confiesa, bruja asquerosa", "Troquemada", "Inquisicion", ' ', 1, true},
- // Book 91: El cocherito lere
- {"El cocherito lere", "Paco costas", "Automovilismo", ' ', 1, true},
- // Book 92: La musica amansa a las fieras
- {"La musica amansa a las fieras", "Wagner", "Musica", ' ', 2, true},
- // Book 93: Pinocho en el Parlamento
- {"Pinocho en el Parlamento", "Carmen Tirosa", "Cronica Social", ' ', 0, false},
- // Book 94: Hagase famoso gracias a la energia de la...
- {"Hagase famoso gracias a la energia de las petunias", "Carmelo Cuelo", "Esoterismo", ' ', 0, false},
- // Book 95: Dios mio, ¡ Que cruz !
- {"Dios mio, ¡ Que cruz !", "Jesus de Nazaret", "Autobiografia", ' ', 0, false},
- // Book 96: Psicologia de la motivacion inmotivada
- {"Psicologia de la motivacion inmotivada", "Dr. Chemi", "Psicologia", ' ', 2, true},
- // Book 97: Magia rosa para iniciados
- {"Magia rosa para iniciados", "Manolo Lailo", "Esoterismo", ' ', 0, false},
- // Book 98: Un mundo Feliz
- {"Un mundo Feliz", "Aldous Huxley", "Novela", ' ', 0, false},
- // Book 99: Sexo oral y por escrito
- {"Sexo oral y por escrito", "Franz Masturmann", "Sexologia", ' ', 3, true},
- // Book 100: El contrato social de aprendizaje
- {"El contrato social de aprendizaje", "Rousseau", "Ensayo", ' ', 1, true},
- // Book 101: Vida sexual del escarabajo de la Patagon...
- {"Vida sexual del escarabajo de la Patagonia", "Dr. Tedio Plomez", "Botanica", ' ', 3, true},
- // Book 102: Manual del necrofago
- {"Manual del necrofago", "Jesus Gil", "Manual", ' ', 0, false},
- // Book 103: Canticos espirituales en formato *.ZIP
- {"Canticos espirituales en formato *.ZIP", "Doctor Chip", "Poesia", 'B', 1, true},
- // Book 104: Novela erotica en formato *.MAS
- {"Novela erotica en formato *.MAS", "Doctor Chip", "Erotica", ' ', 0, false},
- // Book 105: Plopuestas colelacionales en coyuntulas ...
- {"Plopuestas colelacionales en coyuntulas bilatelales", "Senadol Chan Chu Yo", "Politica", ' ', 0, false},
- // Book 106: Ereh un fistro
- {"Ereh un fistro", "Chiquito de la casa", "Humor", ' ', 0, false},
- // Book 107: El hacedor de la Lluvia
- {"El hacedor de la Lluvia", "Herman Hesse", "Cuentos", ' ', 0, false},
- // Book 108: Pasiones recalcitrantes
- {"Pasiones recalcitrantes", "Corin Tellado", "Novela rosa", 'C', 2, true},
- // Book 109: No me mates con tomate
- {"No me mates con tomate", "Karlos Arguiñano", "Cocina", ' ', 0, false},
- // Book 110: El valenciano en los albores del siglo X...
- {"El valenciano en los albores del siglo XXI", "Jaume i Pascual", "Nacionalismo", 'D', 1, true},
- // Book 111: El valenciano es la lengua del futuro
- {"El valenciano es la lengua del futuro", "Jaume i Pascual", "Nacionalismo", ' ', 0, false},
- // Book 112: Valencia: mes que mai
- {"Valencia: mes que mai", "Jaume i Pascual", "Nacionalismo", ' ', 0, false},
- // Book 113: Sistema inmunitario de los cefalopodos (...
- {"Sistema inmunitario de los cefalopodos (v. I)", "Dr. Tedio Plomez", "Biologia", 'E', 3, true},
- // Book 114: Sistema inmunitario de los cefalopodos (...
- {"Sistema inmunitario de los cefalopodos (v. II)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
- // Book 115: Sistema inmunitario de los cefalopodos (...
- {"Sistema inmunitario de los cefalopodos (v. III)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
- // Book 116: Sistema inmunitario de los cefalopodos (...
- {"Sistema inmunitario de los cefalopodos (v. IV)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
- // Book 117: Sistema inmunitario de los cefalopodos (...
- {"Sistema inmunitario de los cefalopodos (v. V)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
- // Book 118: Dos mas dos son cinco
- {"Dos mas dos son cinco", "Joan Josep Climent Colomer", "Matematicas", 'F', 1, true},
- // Book 119: El algebra es la base de la programacion
- {"El algebra es la base de la programacion", "Joan Josep Climent Colomer", "Humor absurdo", ' ', 0, false},
- // Book 120: Autobiografia de una miseria humana
- {"Autobiografia de una miseria humana", "Joan Josep Climent Colomer", "Esperpento", ' ', 0, false},
- // Book 121: El arte mundial antes y despues de mi
- {"El arte mundial antes y despues de mi", "Nacho Taulet Perman", "Arte", ' ', 0, false},
- // Book 122: La parte Creativa
- {"La parte Creativa", "Nacho Taulet Perman", "Arte", 'G', 2, true},
- // Book 123: Llamame cuando se muera tu abuelo
- {"Llamame cuando se muera tu abuelo", "Jose Bart Carrion", "Teatro", ' ', 0, false},
- // Book 124: Soy un incomprendido
- {"Soy un incomprendido", "Jose Bart Carrion", "Autobiografia", ' ', 0, false},
- // Book 125: El arte de limpiar botijos por dentro
- {"El arte de limpiar botijos por dentro", "Varios autores", "Manualidades", ' ', 0, false},
-};
+
+// static const int kLibraryBookCount = 125;
+
+// static const LibraryBook kLibraryBooks[] = {
+// // Book 1: Los hombres: ¡ Como caparlos !
+// {"Los hombres: ¡ Como caparlos !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
+// // Book 2: Mujeres del mundo: ¡ No os depileis las ...
+// {"Mujeres del mundo: ¡ No os depileis las axilas !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
+// // Book 3: Gato por liebre
+// {"Gato por liebre", "Karlos Arguiñano", "Cocina", 'I', 1, true},
+// // Book 4: Hamlet
+// {"Hamlet", "William Shakespeare", "Teatro", ' ', 0, false},
+// // Book 5: Fausto
+// {"Fausto", "Goethe", "Novela", ' ', 0, false},
+// // Book 6: Enrique de Ofterdingen
+// {"Enrique de Ofterdingen", "Novalis", "Novela", 'J', 1, true},
+// // Book 7: Guia de desobediencia civica
+// {"Guia de desobediencia civica", "Azagra", "Ensayo", ' ', 0, false},
+// // Book 8: Literatura en la edad de piedra: cuestio...
+// {"Literatura en la edad de piedra: cuestion de fuerza", "Profesor Cebollo", "Ensayo", ' ', 0, false},
+// // Book 9: Turbo C ++ con Intratex
+// {"Turbo C ++ con Intratex", "Programadores reunidos", "Informatica", ' ', 0, false},
+// // Book 10: Codigo Maquina a pelo
+// {"Codigo Maquina a pelo", "Programadores reunidos", "Informatica", 'K', 1, true},
+// // Book 11: Asesino por vocacion
+// {"Asesino por vocacion", "Chema Ton", "Novela negra", ' ', 0, false},
+// // Book 12: Poemas rebuscados
+// {"Poemas rebuscados", "Ramon Rodriguez", "Poesia", ' ', 0, false},
+// // Book 13: El parto de las tortugas: Un proceso len...
+// {"El parto de las tortugas: Un proceso lento", "Profesor Lorin Colorado", "Biologia", ' ', 0, false},
+// // Book 14: Te parto la cara ¡ Capuyo !
+// {"Te parto la cara ¡ Capuyo !", "Jhonny Rapper", "Critica Social", 'L', 3, true},
+// // Book 15: En los tugurios del Himalaya
+// {"En los tugurios del Himalaya", "Coronel Tapioca", "Aventuras", ' ', 0, false},
+// // Book 16: En las callejuelas del amazonas
+// {"En las callejuelas del amazonas", "Coronel Tapioca", "Aventuras", ' ', 0, false},
+// // Book 17: En las selvas de Londres
+// {"En las selvas de Londres", "Coronel Tapioca", "Aventuras", 'M', 1, true},
+// // Book 18: Sueños binarios
+// {"Sueños binarios", "Doctor Chip", "Ciencia ficcion", ' ', 0, false},
+// // Book 19: Cien cuentos cortisimos
+// {"Cien cuentos cortisimos", "Billi el rapido", "Novela", ' ', 0, false},
+// // Book 20: Teoria de la relatividad
+// {"Teoria de la relatividad", "Alfred Einstein", "Ciencia", ' ', 0, false},
+// // Book 21: El ultimo paso para la cuadratura del ci...
+// {"El ultimo paso para la cuadratura del circulo", "Anonimo", "Filosofia", 'N', 1, true},
+// // Book 22: Correlacion entre el sentido de los colo...
+// {"Correlacion entre el sentido de los colores y sonidos", "Anonimo", "Filosofia", ' ', 0, false},
+// // Book 23: Los cuatro evangelios: Interpretados por...
+// {"Los cuatro evangelios: Interpretados por ordenador", "Doctor Chip", "Teologia", ' ', 0, false},
+// // Book 24: Enciclopedia de bolsillo
+// {"Enciclopedia de bolsillo", "Profesor Lumbreras", "Enciclopedia", 'O', 1, true},
+// // Book 25: Sigueme y revienta
+// {"Sigueme y revienta", "M. Indurain", "Deporte", 'P', 3, true},
+// // Book 26: Me duele too...
+// {"Me duele too...", "Carmen Opausica", "Ensayo", ' ', 0, false},
+// // Book 27: El Perro de Sam Rocker si tiene rabo
+// {"El Perro de Sam Rocker si tiene rabo", "El Perro de Sam Rocker", "Biografia", ' ', 0, false},
+// // Book 28: Donde estara mi carro ?
+// {"Donde estara mi carro ?", "Manolo Escobar", "Aventuras", ' ', 0, false},
+// // Book 29: Oh tu, bella flor del jardin
+// {"Oh tu, bella flor del jardin", "La abeja Maya", "Poesia", 'Q', 2, true},
+// // Book 30: Yogui, ¡ Bajate de esa motoneta !
+// {"Yogui, ¡ Bajate de esa motoneta !", "Bubu", "Filosofia", ' ', 0, false},
+// // Book 31: Odio a muerte a loh mardito rohedore !
+// {"Odio a muerte a loh mardito rohedore !", "Er gato Yin", "Zoologia", ' ', 0, false},
+// // Book 32: Pissi, Dissi, ¡ Sargan de su aguhero !
+// {"Pissi, Dissi, ¡ Sargan de su aguhero !", "Er gato Yin", "Zoologia", ' ', 0, false},
+// // Book 33: Mardito sea ... ¡ Er queso !
+// {"Mardito sea ... ¡ Er queso !", "Er gato Yin", "Zoologia", ' ', 0, false},
+// // Book 34: La mate porque era mia
+// {"La mate porque era mia", "Loquillo", "Novela", ' ', 0, false},
+// // Book 35: Los gallos: Esos desconocidos
+// {"Los gallos: Esos desconocidos", "Paco rico", "Zoologia", ' ', 0, false},
+// // Book 36: Cuentos corrientes
+// {"Cuentos corrientes", "Pepe Lopez", "Novela", 'R', 1, true},
+// // Book 37: Mas madera
+// {"Mas madera", "R. Gepetto", "Bricolage", 'S', 2, true},
+// // Book 38: Cuentos del Lejano Oriente
+// {"Cuentos del Lejano Oriente", "Jhonny Mc. Dowall", "Novela", ' ', 0, false},
+// // Book 39: Saca el guiski cheli
+// {"Saca el guiski cheli", "Manolo lailo", "Cronica Social", ' ', 0, false},
+// // Book 40: Ta totao !
+// {"Ta totao !", "Lao Tse", "Filosofia", ' ', 0, false},
+// // Book 41: Mis conversaciones con el señor Roca
+// {"Mis conversaciones con el señor Roca", "Francisca Gando", "Epistolar", 'T', 2, true},
+// // Book 42: Guia para la supervivencia
+// {"Guia para la supervivencia", "Robinson Crusoe", "Manual", ' ', 0, false},
+// // Book 43: No esperes a ser la segunda: ¡ Engaña a ...
+// {"No esperes a ser la segunda: ¡ Engaña a tu marido !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
+// // Book 44: Yoga Sutras
+// {"Yoga Sutras", "Patanjali", "Filosofia", 'X', 3, true},
+// // Book 45: El juego de los Abalorios
+// {"El juego de los Abalorios", "Herman Hesse", "Novela", ' ', 0, false},
+// // Book 46: Tienes suerte de ser tan pequeño, ¡ mard...
+// {"Tienes suerte de ser tan pequeño, ¡ mardito roedo !", "Er gato Yin", "Novela", ' ', 0, false},
+// // Book 47: Como hacerse rico en diez minutos
+// {"Como hacerse rico en diez minutos", "El Dioni", "Manual", 'Y', 1, true},
+// // Book 48: Te querre a pesar de tu madre
+// {"Te querre a pesar de tu madre", "Corin Tellado", "Novela rosa", ' ', 0, false},
+// // Book 49: Hasta que el mando a distancia nos separ...
+// {"Hasta que el mando a distancia nos separe", "Corin Tellado", "Novela rosa", ' ', 0, false},
+// // Book 50: Una pasion ostentorea
+// {"Una pasion ostentorea", "Corin Tellado y Jesus Gil", "Novela rosa", 'Z', 3, true},
+// // Book 51: Por mi, como si te la machacas
+// {"Por mi, como si te la machacas", "Seneca", "Filosofia", ' ', 0, false},
+// // Book 52: Conversaciones con mi caballo
+// {"Conversaciones con mi caballo", "Jesus Gil", "Humor", ' ', 0, false},
+// // Book 53: El poder curativo de la mierda comun
+// {"El poder curativo de la mierda comun", "Sri Ramachrinaraska", "Esoterismo", ' ', 1, true},
+// // Book 54: La liberacion mediante la eneriga de los...
+// {"La liberacion mediante la eneriga de los pedos", "Sri Ramachrinaraska", "Esoterismo", ' ', 0, false},
+// // Book 55: Sobre la imperceptibilidad de lo imperce...
+// {"Sobre la imperceptibilidad de lo imperceptible", "Perogrullo", "Ensayo", ' ', 0, false},
+// // Book 56: Piojos; como educarlos sin traumas
+// {"Piojos; como educarlos sin traumas", "Franz Franzfrenz", "Psicologia", ' ', 0, false},
+// // Book 57: I Ching
+// {"I Ching", "Richard Willem", "Filosofia", ' ', 0, false},
+// // Book 58: No se nada, ni me importa
+// {"No se nada, ni me importa", "Socrates", "Filosofia", 'U', 2, true},
+// // Book 59: No he sido yo, ¡ Lo juro !
+// {"No he sido yo, ¡ Lo juro !", "Juan Jose Gil", "Biografia", ' ', 0, false},
+// // Book 60: Relatos cortos
+// {"Relatos cortos", "Tachenko", "Novela de ficcion", 'V', 3, true},
+// // Book 61: El martillo como elemento cognitivo
+// {"El martillo como elemento cognitivo", "Friedrich Nietzsche", "Filosofia", ' ', 0, false},
+// // Book 62: La maravillosa vida del escarabajo pelot...
+// {"La maravillosa vida del escarabajo pelotero (v. I)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
+// // Book 63: La maravillosa vida del escarabajo pelot...
+// {"La maravillosa vida del escarabajo pelotero (v. II)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
+// // Book 64: La maravillosa vida del escarabajo pelot...
+// {"La maravillosa vida del escarabajo pelotero (v. III)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
+// // Book 65: La maravillosa vida del escarabajo pelot...
+// {"La maravillosa vida del escarabajo pelotero (v. IV)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
+// // Book 66: La maravillosa vida del escarabajo pelot...
+// {"La maravillosa vida del escarabajo pelotero (v. V)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
+// // Book 67: Tu eliges: Tu madre o yo
+// {"Tu eliges: Tu madre o yo", "Anonimo", "Psicologia aplicada", 'W', 3, true},
+// // Book 68: Mi lucha
+// {"Mi lucha", "Adolf Hitler", "Humor negro", ' ', 0, false},
+// // Book 69: Cuentos de amor y desidia
+// {"Cuentos de amor y desidia", "Jardiel Poncela", "Teatro", ' ', 1, true},
+// // Book 70: Nuevas andanzas de Zaratustra
+// {"Nuevas andanzas de Zaratustra", "Anonimo", "Aventuras", ' ', 2, true},
+// // Book 71: Me se cuadre ¡ Coño !
+// {"Me se cuadre ¡ Coño !", "Sargento Cienfuegos", "Etica militar", ' ', 2, true},
+// // Book 72: Gatos: solos o con Ketchup
+// {"Gatos: solos o con Ketchup", "El perro de Sam Rocker", "Cocina", ' ', 1, true},
+// // Book 73: Querida Adelaida: mi marido NO ha dejado...
+// {"Querida Adelaida: mi marido NO ha dejado de roncar", "Maruja Mones", "Epistolar", ' ', 0, false},
+// // Book 74: Sobre el papel de El Lepe en el nuevo Or...
+// {"Sobre el papel de El Lepe en el nuevo Orden Mundial", "General Sintacha", "Estrategia", ' ', 0, false},
+// // Book 75: Aqui no hay nadie que se acueste sin cen...
+// {"Aqui no hay nadie que se acueste sin cenar (v. I)", "Fidel Castro", "Politica", ' ', 1, true},
+// // Book 76: Aqui no hay nadie que se acueste sin cen...
+// {"Aqui no hay nadie que se acueste sin cenar (v. II)", "Fidel Castro", "Politica", ' ', 0, false},
+// // Book 77: Aqui no hay nadie que se acueste sin cen...
+// {"Aqui no hay nadie que se acueste sin cenar (v. III)", "Fidel Castro", "Politica", ' ', 0, false},
+// // Book 78: Aqui no hay nadie que se acueste sin cen...
+// {"Aqui no hay nadie que se acueste sin cenar (v. IV)", "Fidel Castro", "Politica", ' ', 0, false},
+// // Book 79: Aqui no hay nadie que se acueste sin cen...
+// {"Aqui no hay nadie que se acueste sin cenar (v. V)", "Fidel Castro", "Politica", ' ', 0, false},
+// // Book 80: Domine la metafisica en 5 dias
+// {"Domine la metafisica en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
+// // Book 81: Domine el ensamblador en 5 dias
+// {"Domine el ensamblador en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
+// // Book 82: Dominese a si mismo en 5 dias
+// {"Dominese a si mismo en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
+// // Book 83: Piernas de Ciertopelo
+// {"Piernas de Ciertopelo", "Chichi Mondongo", "Erotica", ' ', 2, true},
+// // Book 84: Otra vuelta de tuerca
+// {"Otra vuelta de tuerca", "Pepe, el fontanero", "Bricolage", ' ', 2, true},
+// // Book 85: La Tierra: ¡ Planeta limpio !
+// {"La Tierra: ¡ Planeta limpio !", "Juan, el basurero", "Ciencia Ficcion", ' ', 2, true},
+// // Book 86: Liberad a Brian !
+// {"Liberad a Brian !", "Roger Rabitt", "Historica", ' ', 2, true},
+// // Book 87: La vida es una mierda
+// {"La vida es una mierda", "Juanjo Dido", "Ensayo", ' ', 2, true},
+// // Book 88: No era eso lo que yo di a entender
+// {"No era eso lo que yo di a entender", "Jesus de Nazaret", "Religion", ' ', 2, true},
+// // Book 89: Castigos a Piratas Informaticos
+// {"Castigos a Piratas Informaticos", "Torquemada", "Inquisicion", ' ', 1, true},
+// // Book 90: Confiesa, bruja asquerosa
+// {"Confiesa, bruja asquerosa", "Troquemada", "Inquisicion", ' ', 1, true},
+// // Book 91: El cocherito lere
+// {"El cocherito lere", "Paco costas", "Automovilismo", ' ', 1, true},
+// // Book 92: La musica amansa a las fieras
+// {"La musica amansa a las fieras", "Wagner", "Musica", ' ', 2, true},
+// // Book 93: Pinocho en el Parlamento
+// {"Pinocho en el Parlamento", "Carmen Tirosa", "Cronica Social", ' ', 0, false},
+// // Book 94: Hagase famoso gracias a la energia de la...
+// {"Hagase famoso gracias a la energia de las petunias", "Carmelo Cuelo", "Esoterismo", ' ', 0, false},
+// // Book 95: Dios mio, ¡ Que cruz !
+// {"Dios mio, ¡ Que cruz !", "Jesus de Nazaret", "Autobiografia", ' ', 0, false},
+// // Book 96: Psicologia de la motivacion inmotivada
+// {"Psicologia de la motivacion inmotivada", "Dr. Chemi", "Psicologia", ' ', 2, true},
+// // Book 97: Magia rosa para iniciados
+// {"Magia rosa para iniciados", "Manolo Lailo", "Esoterismo", ' ', 0, false},
+// // Book 98: Un mundo Feliz
+// {"Un mundo Feliz", "Aldous Huxley", "Novela", ' ', 0, false},
+// // Book 99: Sexo oral y por escrito
+// {"Sexo oral y por escrito", "Franz Masturmann", "Sexologia", ' ', 3, true},
+// // Book 100: El contrato social de aprendizaje
+// {"El contrato social de aprendizaje", "Rousseau", "Ensayo", ' ', 1, true},
+// // Book 101: Vida sexual del escarabajo de la Patagon...
+// {"Vida sexual del escarabajo de la Patagonia", "Dr. Tedio Plomez", "Botanica", ' ', 3, true},
+// // Book 102: Manual del necrofago
+// {"Manual del necrofago", "Jesus Gil", "Manual", ' ', 0, false},
+// // Book 103: Canticos espirituales en formato *.ZIP
+// {"Canticos espirituales en formato *.ZIP", "Doctor Chip", "Poesia", 'B', 1, true},
+// // Book 104: Novela erotica en formato *.MAS
+// {"Novela erotica en formato *.MAS", "Doctor Chip", "Erotica", ' ', 0, false},
+// // Book 105: Plopuestas colelacionales en coyuntulas ...
+// {"Plopuestas colelacionales en coyuntulas bilatelales", "Senadol Chan Chu Yo", "Politica", ' ', 0, false},
+// // Book 106: Ereh un fistro
+// {"Ereh un fistro", "Chiquito de la casa", "Humor", ' ', 0, false},
+// // Book 107: El hacedor de la Lluvia
+// {"El hacedor de la Lluvia", "Herman Hesse", "Cuentos", ' ', 0, false},
+// // Book 108: Pasiones recalcitrantes
+// {"Pasiones recalcitrantes", "Corin Tellado", "Novela rosa", 'C', 2, true},
+// // Book 109: No me mates con tomate
+// {"No me mates con tomate", "Karlos Arguiñano", "Cocina", ' ', 0, false},
+// // Book 110: El valenciano en los albores del siglo X...
+// {"El valenciano en los albores del siglo XXI", "Jaume i Pascual", "Nacionalismo", 'D', 1, true},
+// // Book 111: El valenciano es la lengua del futuro
+// {"El valenciano es la lengua del futuro", "Jaume i Pascual", "Nacionalismo", ' ', 0, false},
+// // Book 112: Valencia: mes que mai
+// {"Valencia: mes que mai", "Jaume i Pascual", "Nacionalismo", ' ', 0, false},
+// // Book 113: Sistema inmunitario de los cefalopodos (...
+// {"Sistema inmunitario de los cefalopodos (v. I)", "Dr. Tedio Plomez", "Biologia", 'E', 3, true},
+// // Book 114: Sistema inmunitario de los cefalopodos (...
+// {"Sistema inmunitario de los cefalopodos (v. II)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
+// // Book 115: Sistema inmunitario de los cefalopodos (...
+// {"Sistema inmunitario de los cefalopodos (v. III)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
+// // Book 116: Sistema inmunitario de los cefalopodos (...
+// {"Sistema inmunitario de los cefalopodos (v. IV)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
+// // Book 117: Sistema inmunitario de los cefalopodos (...
+// {"Sistema inmunitario de los cefalopodos (v. V)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
+// // Book 118: Dos mas dos son cinco
+// {"Dos mas dos son cinco", "Joan Josep Climent Colomer", "Matematicas", 'F', 1, true},
+// // Book 119: El algebra es la base de la programacion
+// {"El algebra es la base de la programacion", "Joan Josep Climent Colomer", "Humor absurdo", ' ', 0, false},
+// // Book 120: Autobiografia de una miseria humana
+// {"Autobiografia de una miseria humana", "Joan Josep Climent Colomer", "Esperpento", ' ', 0, false},
+// // Book 121: El arte mundial antes y despues de mi
+// {"El arte mundial antes y despues de mi", "Nacho Taulet Perman", "Arte", ' ', 0, false},
+// // Book 122: La parte Creativa
+// {"La parte Creativa", "Nacho Taulet Perman", "Arte", 'G', 2, true},
+// // Book 123: Llamame cuando se muera tu abuelo
+// {"Llamame cuando se muera tu abuelo", "Jose Bart Carrion", "Teatro", ' ', 0, false},
+// // Book 124: Soy un incomprendido
+// {"Soy un incomprendido", "Jose Bart Carrion", "Autobiografia", ' ', 0, false},
+// // Book 125: El arte de limpiar botijos por dentro
+// {"El arte de limpiar botijos por dentro", "Varios autores", "Manualidades", ' ', 0, false},
+// };
} // namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 29676cdef92..b3d2ff36546 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -329,7 +329,6 @@ void PelrockEngine::checkMouse() {
if (_alfredState.animState == ALFRED_WALKING && !_alfredState.isWalkingCancelable) {
// Ignore clicks while Alfred is walking
_events->_leftMouseClicked = false;
- debug("Ignoring mouse click while Alfred is walking");
return;
}
@@ -1308,6 +1307,11 @@ void PelrockEngine::gameLoop() {
void PelrockEngine::computerLoop() {
Computer computer(_events);
computer.run();
+ if(_state->selectedBookIndex != -1 && _state->bookLetter != '\0') {
+ Common::StringArray lines;
+ lines.push_back(Common::String::format(computer._memorizedMsg, _state->bookLetter));
+ _dialog->sayAlfred(lines);
+ }
}
void PelrockEngine::extraScreenLoop() {
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 08af8c0331c..26378f0079b 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -24,6 +24,7 @@
#include "pelrock/pelrock.h"
#include "pelrock/room.h"
#include "pelrock/util.h"
+#include "resources.h"
namespace Pelrock {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 22aec4820cb..4191fe5b2f7 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -49,6 +49,7 @@ public:
void clearSpecialAnim();
void loadInventoryItems();
void loadHardcodedText();
+ void loadComputerText();
void getExtraScreen(int screenIndex, byte *screenBuf, byte *palette);
Common::Array<Common::StringArray> getCredits();
Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size, bool decode = false);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 329190948f9..1fca82e42bf 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -481,7 +481,10 @@ struct GameStateData {
Common::Array<byte> inventoryItems;
int16 selectedInventoryItem = -1;
+
int libraryShelf = -1;
+ int selectedBookIndex = -1;
+ unsigned char bookLetter = '\0';
Common::HashMap<byte, Common::Array<Sticker>> stickersPerRoom;
Common::HashMap<byte, Common::Array<ExitChange>> roomExitChanges;
Common::HashMap<byte, Common::Array<WalkBoxChange>> roomWalkBoxChanges;
@@ -548,6 +551,28 @@ struct GameStateData {
void setRootDisabledState(byte room, byte root, bool disabled) {
conversationRootsState[room * 4 + root] = disabled ? 1 : 0;
}
+
+ int findFirstBookIndex() {
+ for (uint i = 0; i < inventoryItems.size(); i++) {
+ int x = inventoryItems[i];
+ if ((x >= 11) && (x <= 58))
+ return x;
+ }
+ return -1;
+ }
+
+
+ int booksInInventory() {
+ int l = inventoryItems.size();
+ int count = 0;
+ for (int i = 0; i < l; i++) {
+ int x = inventoryItems[i];
+ if ((x >= 11) && (x <= 58))
+ count++;
+ }
+ return count;
+ }
+
};
struct SaveGameData {
Commit: dd28828c1abe0e17eaf48975e5d2d850f53e9a64
https://github.com/scummvm/scummvm/commit/dd28828c1abe0e17eaf48975e5d2d850f53e9a64
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:52+02:00
Commit Message:
PELROCK: implement reading of books
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index ab4c33c2d88..44d75bd57f0 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -123,6 +123,7 @@ const CombinationEntry combinationTable[] = {
{1, 53, &PelrockEngine::giveIdToGuard},
{5, 53, &PelrockEngine::giveMoneyToGuard},
{7, 353, &PelrockEngine::useAmuletWithStatue},
+ {8, 102, &PelrockEngine::giveFormulaToLibrarian},
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -177,7 +178,7 @@ void PelrockEngine::buyFromStore(HotSpot *hotspot, int stickerId) {
if (hotspot->extra == 69) {
_room->disableSprite(15, 3); // Disable monkey brain sprite
}
- _state->addInventoryItem(hotspot->extra);
+ addInventoryItem(hotspot->extra);
_currentHotspot = nullptr;
walkLoop(224, 283, ALFRED_LEFT);
_dialog->say(_res->_ingameTexts[CUESTA1000]);
@@ -619,6 +620,12 @@ void PelrockEngine::pickBooksFromShelf3(HotSpot *hotspot) {
pickUpBook(3);
}
+void PelrockEngine::giveFormulaToLibrarian(int inventoryObject, HotSpot *hotspot) {
+ _dialog->say(_res->_ingameTexts[REGALO_LIBRO_RECETAS]);
+ _state->removeInventoryItem(8);
+ addInventoryItem(59);
+}
+
void PelrockEngine::pickUpBook(int i) {
if (!_state->hasInventoryItem(10)) {
_dialog->say(_res->_ingameTexts[VENGA_ACA]);
@@ -635,11 +642,11 @@ void PelrockEngine::pickUpBook(int i) {
int booksInInventory = _state->booksInInventory();
if (booksInInventory == 3) {
int firstBook = _state->findFirstBookIndex();
- if(firstBook != -1)
+ if (firstBook != -1)
_state->removeInventoryItem(firstBook);
_dialog->say(_res->_ingameTexts[TENDRE_DEJAR_LIBRO]);
}
- _state->addInventoryItem(_state->selectedBookIndex);
+ addInventoryItem(_state->selectedBookIndex);
_state->selectedBookIndex = -1;
}
}
@@ -672,7 +679,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
debug("Using item %d on Alfred", inventoryObject);
switch (inventoryObject) {
- case 63: // Recipe book
+ case 63: // Recipe
_res->loadAlfredSpecialAnim(1);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
waitForSpecialAnimation();
@@ -681,8 +688,48 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
debug("After extra screen");
_dialog->say(_res->_ingameTexts[QUEASCO]);
break;
+ case 59: // Recipe book
+ if (!_state->hasInventoryItem(64)) {
+ _res->loadAlfredSpecialAnim(0);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _dialog->say(_res->_ingameTexts[HOJAENTREPAGINAS]);
+ addInventoryItem(64);
+ } else {
+ _res->loadAlfredSpecialAnim(0);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _dialog->say(_res->_ingameTexts[NOENTIENDONADA]);
+ }
+ break;
+ case 17: // Egyptian book
+ _res->loadAlfredSpecialAnim(0);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _dialog->say(_res->_ingameTexts[YASEEGIPCIO]);
+ _state->setFlag(FLAG_ALFRED_SABE_EGIPCIO, true);
+ break;
+ case 24:
+ _res->loadAlfredSpecialAnim(0);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _dialog->say(_res->_ingameTexts[COSASAPRENDIDO]);
+ _state->setFlag(FLAG_ALFRED_INTELIGENTE, true);
+ break;
+ case 64:
+ _res->loadAlfredSpecialAnim(0);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ loadExtraScreenAndPresent(5);
+ if(_state->getFlag(FLAG_ALFRED_SABE_EGIPCIO)) {
+ _dialog->say(_res->_ingameTexts[FORMULAVIAJETIEMPO]);
+ }
+ else {
+ _dialog->say(_res->_ingameTexts[QUELASTIMA_NOSEEGIPCIO]);
+ }
+ break;
case 0: // yellow book
- _res->loadAlfredSpecialAnim(2);
+ _res->loadAlfredSpecialAnim(0);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
waitForSpecialAnimation();
_dialog->say(_res->_ingameTexts[CUENTOPARECIDO]);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 052b418c668..1b9d3bd8f67 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -296,6 +296,7 @@ public:
void pickBooksFromShelf1(HotSpot *hotspot);
void pickBooksFromShelf2(HotSpot *hotspot);
void pickBooksFromShelf3(HotSpot *hotspot);
+ void giveFormulaToLibrarian(int inventoryObject, HotSpot *hotspot);
void pickUpBook(int i);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 4191fe5b2f7..1dbda4171f4 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -49,7 +49,7 @@ public:
void clearSpecialAnim();
void loadInventoryItems();
void loadHardcodedText();
- void loadComputerText();
+ Common::StringArray loadComputerText();
void getExtraScreen(int screenIndex, byte *screenBuf, byte *palette);
Common::Array<Common::StringArray> getCredits();
Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size, bool decode = false);
Commit: a6ed3a2764017c08bace10b3da9a7f7d29a99d6b
https://github.com/scummvm/scummvm/commit/a6ed3a2764017c08bace10b3da9a7f7d29a99d6b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:52+02:00
Commit Message:
PELROCK: Implements room 14
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 44d75bd57f0..515be30c5f1 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -189,31 +189,61 @@ void PelrockEngine::buyFromStore(HotSpot *hotspot, int stickerId) {
}
void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex) {
- if (actionTrigger == 328) {
+ switch (actionTrigger) {
+ case 328:
debug("Disabling root %d in room %d", rootIndex, room);
_state->setRootDisabledState(room, rootIndex, true);
- } else if (actionTrigger == 329) {
+ break;
+ case 329:
debug("Would now enable X easter egg");
- } else if (actionTrigger == 258) {
+ break;
+ case 258:
_state->setFlag(FLAG_GUARDIA_PIDECOSAS, true);
_state->setRootDisabledState(4, 1, true);
- } else if (actionTrigger == 259) {
+ break;
+ case 259:
_dialog->say(_res->_ingameTexts[NO_EMPECEMOS]);
- } else if (actionTrigger == 260) {
+ break;
+ case 260:
_dialog->say(_res->_ingameTexts[CUERPO_DANONE], 1);
_dialog->say(_res->_ingameTexts[CABEZA_HUECA]);
- } else if (actionTrigger == 261) {
+ break;
+ case 261:
_dialog->say(_res->_ingameTexts[ESO_LO_SERAS_TU], 1);
- } else if (actionTrigger == 262) {
+ break;
+ case 262:
_dialog->say(_res->_ingameTexts[DEMASIADO_NO_PUEDO_PENSAR], 1);
- } else if (actionTrigger == 263) {
+ break;
+ case 263:
_dialog->say(_res->_ingameTexts[UN_POCO_RESPETO]);
- } else if (actionTrigger == 264) {
+ break;
+ case 264:
// disables the two first roots, the second one will be enabled later!
_state->setRootDisabledState(room, rootIndex, true);
_state->setRootDisabledState(room, rootIndex + 1, true);
- } else {
+ break;
+ case 272:
+ _state->setRootDisabledState(room, rootIndex, true);
+ break;
+ case 273:
+ WalkBox w1;
+ w1.x = 436;
+ w1.y = 356;
+ w1.w = 4;
+ w1.h = 14;
+ w1.flags = 0;
+ WalkBox w2;
+ w2.x = 440;
+ w2.y = 368;
+ w2.w = 148;
+ w2.h = 2;
+ w2.flags = 0;
+
+ _room->addWalkbox(w1);
+ _room->addWalkbox(w2);
+ default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
+ break;
}
}
@@ -535,6 +565,7 @@ void PelrockEngine::giveIdToGuard(int inventoryObject, HotSpot *hotspot) {
}
if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
_state->setRootDisabledState(4, 2, true);
+ _room->enableSprite(4, 2, 100, true);
return;
}
}
@@ -551,6 +582,8 @@ void PelrockEngine::giveMoneyToGuard(int inventoryObject, HotSpot *hotspot) {
}
if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
_state->setRootDisabledState(4, 2, true);
+ _room->enableSprite(2, 100, true);
+ _room->enableSprite(3, 100, true);
return;
}
}
@@ -715,6 +748,8 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
waitForSpecialAnimation();
_dialog->say(_res->_ingameTexts[COSASAPRENDIDO]);
_state->setFlag(FLAG_ALFRED_INTELIGENTE, true);
+ _state->setRootDisabledState(14, 0, true);
+ _state->setRootDisabledState(14, 1, true);
break;
case 64:
_res->loadAlfredSpecialAnim(0);
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index 3b5a7c327b5..a7a01679c8c 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -42,7 +42,7 @@ bool PelrockConsole::cmdLoadRoom(int argc, const char **argv) {
int roomNumber = atoi(argv[1]);
g_engine->setScreen(roomNumber, ALFRED_DOWN);
- debugPrintf("Loaded room %d", roomNumber);
+ debugPrintf("Loaded room %d\n", roomNumber);
return true;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b3d2ff36546..a6ac2a3ce5c 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -435,7 +435,7 @@ void PelrockEngine::updatePaletteAnimations() {
}
void PelrockEngine::paintDebugLayer() {
- bool showWalkboxes = false;
+ bool showWalkboxes = true;
if (showWalkboxes) {
for (uint i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index e6641fb8712..71f1361224c 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -198,6 +198,7 @@ void RoomManager::setActionMask(HotSpot *hotspot, byte actionMask) {
}
void RoomManager::addWalkbox(WalkBox walkbox) {
+ _currentRoomWalkboxes.push_back(walkbox);
g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 00d231976f7..0c796789a74 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -51,6 +51,12 @@ static const int unpickableHotspotExtras[] = {
362,
};
+enum PersistType {
+ PERSIST_TEMP,
+ PERSIST_PERM,
+ PERSIST_BOTH
+};
+
class RoomManager {
public:
RoomManager();
Commit: bdad1b18ac5a5ecefb3df490147d7b4dd34bf3bf
https://github.com/scummvm/scummvm/commit/bdad1b18ac5a5ecefb3df490147d7b4dd34bf3bf
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:52+02:00
Commit Message:
PELROCK: Room changes refactor
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/saveload.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 515be30c5f1..b317a6aa710 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -133,8 +133,8 @@ void PelrockEngine::openDoor(HotSpot *hotspot, int exitIndex, int sticker, bool
_dialog->say(_res->_ingameTexts[text]);
return;
}
- _room->enableExit(exitIndex, !stayClosed);
- _room->addSticker(sticker, !stayClosed);
+ _room->enableExit(exitIndex, stayClosed ? PERSIST_TEMP : PERSIST_BOTH);
+ _room->addSticker(sticker, stayClosed ? PERSIST_TEMP : PERSIST_BOTH);
_sound->playSound(_room->_roomSfx[0]);
}
@@ -144,7 +144,7 @@ void PelrockEngine::closeDoor(HotSpot *hotspot, int exitIndex, int sticker, bool
_dialog->say(_res->_ingameTexts[text]);
return;
}
- _room->disableExit(exitIndex, !stayOpen);
+ _room->disableExit(exitIndex, stayOpen ? PERSIST_TEMP : PERSIST_BOTH);
_room->removeSticker(sticker);
_sound->playSound(_room->_roomSfx[1]);
}
@@ -297,6 +297,10 @@ void PelrockEngine::openIceCreamShopDoor(HotSpot *hotspot) {
}
void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
+ if(!_room->hasSticker(91)) {
+ _dialog->say(_res->_ingameTexts[YA_CERRADO_M]);
+ return;
+ }
_room->removeSticker(91);
_room->enableHotspot(hotspot);
}
@@ -441,8 +445,8 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[YOMEVOY]);
_state->setFlag(FLAG_TIENDA_ABIERTA, true);
- _room->onlyPersistSticker(_room->_currentRoomNumber, 9);
- _room->onlyPersistSticker(_room->_currentRoomNumber, 10);
+ _room->addStickerToRoom(_room->_currentRoomNumber, 9, PERSIST_PERM);
+ _room->addStickerToRoom(_room->_currentRoomNumber, 10, PERSIST_PERM);
_room->disableHotspot(_room->findHotspotByExtra(295)); // Disable storefront hotspot
_room->disableHotspot(_room->findHotspotByExtra(294)); // Disable window hotspot
walkTo(639, _alfredState.y);
@@ -565,7 +569,7 @@ void PelrockEngine::giveIdToGuard(int inventoryObject, HotSpot *hotspot) {
}
if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
_state->setRootDisabledState(4, 2, true);
- _room->enableSprite(4, 2, 100, true);
+ _room->enableSprite(4, 2, 100);
return;
}
}
@@ -582,8 +586,8 @@ void PelrockEngine::giveMoneyToGuard(int inventoryObject, HotSpot *hotspot) {
}
if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
_state->setRootDisabledState(4, 2, true);
- _room->enableSprite(2, 100, true);
- _room->enableSprite(3, 100, true);
+ _room->enableSprite(2, 100);
+ _room->enableSprite(3, 100);
return;
}
}
@@ -659,6 +663,10 @@ void PelrockEngine::giveFormulaToLibrarian(int inventoryObject, HotSpot *hotspot
addInventoryItem(59);
}
+void PelrockEngine::openNewspaperDoor(HotSpot *hotspot) {
+ openDoor(hotspot, 0, 90, FEMININE, true);
+}
+
void PelrockEngine::pickUpBook(int i) {
if (!_state->hasInventoryItem(10)) {
_dialog->say(_res->_ingameTexts[VENGA_ACA]);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a6ac2a3ce5c..994839b0fec 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -152,10 +152,10 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- // setScreen(0, ALFRED_DOWN);
+ setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(5, ALFRED_DOWN);
- setScreen(9, ALFRED_DOWN);
+ // setScreen(9, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 1b9d3bd8f67..345cc3407e6 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -297,6 +297,7 @@ public:
void pickBooksFromShelf2(HotSpot *hotspot);
void pickBooksFromShelf3(HotSpot *hotspot);
void giveFormulaToLibrarian(int inventoryObject, HotSpot *hotspot);
+ void openNewspaperDoor(HotSpot *hotspot);
void pickUpBook(int i);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 71f1361224c..86d5e81bdab 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -88,48 +88,59 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
}
}
-void RoomManager::addSticker(int stickerId, bool persist) {
- Sticker sticker = g_engine->_res->getSticker(stickerId);
- _roomStickers.push_back(sticker);
- addStickerToRoom(_currentRoomNumber, stickerId);
+void RoomManager::addSticker(int stickerId, int persist) {
+ addStickerToRoom(_currentRoomNumber, stickerId, persist);
}
-void RoomManager::addStickerToRoom(byte room, int stickerId) {
+void RoomManager::addStickerToRoom(byte room, int stickerId, int persist) {
Sticker sticker = g_engine->_res->getSticker(stickerId);
- g_engine->_state->stickersPerRoom[room].push_back(sticker);
+ if (room == _currentRoomNumber && persist & PERSIST_TEMP) {
+ _roomStickers.push_back(sticker);
+ }
+ if (persist & PERSIST_PERM) {
+ g_engine->_state->stickersPerRoom[room].push_back(sticker);
+ }
}
-void RoomManager::onlyPersistSticker(byte room, int stickerId) {
- Sticker sticker = g_engine->_res->getSticker(stickerId);
- g_engine->_state->stickersPerRoom[room].push_back(sticker);
+void RoomManager::removeSticker(int stickerId) {
+ removeStickerFromRoom(_currentRoomNumber, stickerId);
}
-void RoomManager::removeSticker(int stickerIndex) {
+void RoomManager::removeStickerFromRoom(byte room, int stickerId) {
// First check and remove from room stickers
for (uint i = 0; i < _roomStickers.size(); i++) {
- if (_roomStickers[i].stickerIndex == stickerIndex) {
+ if (_roomStickers[i].stickerIndex == stickerId) {
_roomStickers.remove_at(i);
return;
}
}
// Then check and remove from persisted stickers
- for (uint i = 0; i < g_engine->_state->stickersPerRoom[_currentRoomNumber].size(); i++) {
- if (g_engine->_state->stickersPerRoom[_currentRoomNumber][i].stickerIndex == stickerIndex) {
- g_engine->_state->stickersPerRoom[_currentRoomNumber].remove_at(i);
+ for (uint i = 0; i < g_engine->_state->stickersPerRoom[room].size(); i++) {
+ if (g_engine->_state->stickersPerRoom[room][i].stickerIndex == stickerId) {
+ g_engine->_state->stickersPerRoom[room].remove_at(i);
return;
}
}
}
bool RoomManager::hasSticker(int index) {
+ return hasSticker(_currentRoomNumber, index);
+}
+
+bool RoomManager::hasSticker(byte room, int index) {
for (uint i = 0; i < _roomStickers.size(); i++) {
if (_roomStickers[i].stickerIndex == index) {
return true;
}
}
- for (uint i = 0; i < g_engine->_state->stickersPerRoom[_currentRoomNumber].size(); i++) {
- if (g_engine->_state->stickersPerRoom[_currentRoomNumber][i].stickerIndex == index) {
+
+ if (room != _currentRoomNumber) {
+ return false;
+ }
+
+ for (uint i = 0; i < g_engine->_state->stickersPerRoom[room].size(); i++) {
+ if (g_engine->_state->stickersPerRoom[room][i].stickerIndex == index) {
return true;
}
}
@@ -137,69 +148,144 @@ bool RoomManager::hasSticker(int index) {
return false;
}
-void RoomManager::changeExit(int index, bool enabled, bool persist) {
- _currentRoomExits[index].isEnabled = enabled;
- if (persist)
- g_engine->_state->roomExitChanges[_currentRoomNumber].push_back({_currentRoomNumber, _currentRoomExits[index].index, _currentRoomExits[index]});
+void RoomManager::changeExit(byte index, bool enabled, int persist) {
+ changeExit(_currentRoomNumber, index, enabled, persist);
}
-void RoomManager::disableExit(int index, bool persist) {
+void RoomManager::changeExit(byte room, byte index, bool enabled, int persist) {
+ if (room == _currentRoomNumber & persist & PERSIST_TEMP) {
+ _currentRoomExits[index].isEnabled = enabled;
+ }
+ if (persist & PERSIST_PERM)
+ g_engine->_state->roomExitChanges[room].push_back({room, index, enabled});
+}
+
+void RoomManager::disableExit(byte index, int persist) {
changeExit(index, false, persist);
}
-void RoomManager::enableExit(int index, bool persist) {
+void RoomManager::disableExit(byte room, byte index, int persist) {
+ changeExit(room, index, false, persist);
+}
+
+void RoomManager::enableExit(byte index, int persist) {
changeExit(index, true, persist);
}
-void RoomManager::changeWalkBox(WalkBox walkbox) {
- g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
+void RoomManager::enableExit(byte room, byte index, int persist) {
+ changeExit(room, index, true, persist);
+}
+
+void RoomManager::changeWalkBox(WalkBox walkbox, int persist) {
+ changeWalkbox(_currentRoomNumber, walkbox, persist);
+}
+
+void RoomManager::changeWalkbox(byte room, WalkBox walkbox, int persist) {
+ if (room == _currentRoomNumber & persist & PERSIST_TEMP) {
+ _currentRoomWalkboxes[walkbox.index] = walkbox;
+ }
+ if (persist & PERSIST_PERM) {
+ g_engine->_state->roomWalkBoxChanges[room].push_back({room, walkbox.index, walkbox});
+ }
}
-void RoomManager::changeHotSpot(HotSpot hotspot) {
- g_engine->_state->roomHotSpotChanges[_currentRoomNumber].push_back({_currentRoomNumber, hotspot.innerIndex, hotspot});
+void RoomManager::changeHotSpot(HotSpot hotspot, int persist) {
+ changeHotspot(_currentRoomNumber, hotspot, persist);
}
-void RoomManager::disableSprite(byte roomNumber, int spriteIndex, bool persist) {
- if (roomNumber == _currentRoomNumber) {
+void RoomManager::changeHotspot(byte room, HotSpot hotspot, int persist) {
+ if (room == _currentRoomNumber & persist & PERSIST_TEMP) {
+ for (uint i = 0; i < _currentRoomHotspots.size(); i++) {
+ if (!_currentRoomHotspots[i].isSprite && _currentRoomHotspots[i].innerIndex == hotspot.innerIndex) {
+ _currentRoomHotspots[i] = hotspot;
+ break;
+ }
+ }
+ }
+ if (persist & PERSIST_PERM) {
+ g_engine->_state->roomHotSpotChanges[room].push_back({_currentRoomNumber, hotspot.innerIndex, hotspot});
+ }
+}
+
+void RoomManager::disableSprite(byte spriteIndex, int persist) {
+ disableSprite(_currentRoomNumber, spriteIndex, persist);
+}
+
+void RoomManager::disableSprite(byte roomNumber, byte spriteIndex, int persist) {
+ if (roomNumber == _currentRoomNumber & persist & PERSIST_TEMP) {
_currentRoomAnims[spriteIndex].zOrder = 255;
+ _currentRoomAnims[spriteIndex].isHotspotDisabled = true;
+ }
+ if (persist & PERSIST_PERM) {
+ g_engine->_state->spriteChanges[roomNumber].push_back({roomNumber, spriteIndex, 255});
}
- g_engine->_state->disabledSprites[roomNumber].push_back(spriteIndex);
}
-void RoomManager::enableSprite(int spriteIndex, int zOrder, bool persist) {
- _currentRoomAnims[spriteIndex].zOrder = zOrder;
+void RoomManager::enableSprite(byte spriteIndex, byte zOrder, int persist) {
+ enableSprite(_currentRoomNumber, spriteIndex, zOrder, persist);
}
-void RoomManager::enableHotspot(HotSpot *hotspot, bool persist) {
- hotspot->isEnabled = true;
- if (persist) {
- changeHotSpot(*hotspot);
+void RoomManager::enableSprite(byte roomNumber, byte spriteIndex, byte zOrder, int persist) {
+ if (roomNumber == _currentRoomNumber & persist & PERSIST_TEMP) {
+ _currentRoomAnims[spriteIndex].zOrder = zOrder;
}
+ if (persist & PERSIST_PERM) {
+ g_engine->_state->spriteChanges[roomNumber].push_back({roomNumber, spriteIndex, zOrder});
+ }
+}
+
+void RoomManager::enableHotspot(HotSpot *hotspot, int persist) {
+ enableHotspot(_currentRoomNumber, hotspot, persist);
}
-void RoomManager::disableHotspot(HotSpot *hotspot, bool persist) {
- hotspot->isEnabled = false;
- if (persist) {
- changeHotSpot(*hotspot);
+void RoomManager::enableHotspot(byte room, HotSpot *hotspot, int persist) {
+ if (persist & PERSIST_TEMP && room == _currentRoomNumber) {
+ hotspot->isEnabled = true;
+ }
+ if (persist & PERSIST_PERM) {
+ changeHotspot(room, *hotspot);
}
}
-void RoomManager::moveHotspot(HotSpot *hotspot, int16 newX, int16 newY, bool persist) {
- hotspot->x = newX;
- hotspot->y = newY;
- if (persist) {
- changeHotSpot(*hotspot);
+void RoomManager::disableHotspot(HotSpot *hotspot, int persist) {
+ disableHotspot(_currentRoomNumber, hotspot, persist);
+}
+
+void RoomManager::disableHotspot(byte room, HotSpot *hotspot, int persist) {
+ if (persist & PERSIST_TEMP && room == _currentRoomNumber) {
+ hotspot->isEnabled = false;
+ }
+ if (persist & PERSIST_PERM) {
+ changeHotspot(room, *hotspot);
}
}
-void RoomManager::setActionMask(HotSpot *hotspot, byte actionMask) {
- hotspot->actionFlags = actionMask;
- changeHotSpot(*hotspot);
+void RoomManager::moveHotspot(HotSpot *hotspot, int16 newX, int16 newY, int persist) {
+ if (persist & PERSIST_TEMP) {
+ hotspot->x = newX;
+ hotspot->y = newY;
+ }
+ if (persist & PERSIST_PERM) {
+ changeHotspot(_currentRoomNumber, *hotspot, persist);
+ }
}
-void RoomManager::addWalkbox(WalkBox walkbox) {
- _currentRoomWalkboxes.push_back(walkbox);
- g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
+void RoomManager::setActionMask(HotSpot *hotspot, byte actionMask, int persist) {
+ if (persist & PERSIST_TEMP) {
+ hotspot->actionFlags = actionMask;
+ }
+ if (persist & PERSIST_PERM) {
+ changeHotspot(_currentRoomNumber, *hotspot, persist);
+ }
+}
+
+void RoomManager::addWalkbox(WalkBox walkbox, int persist) {
+ if (persist & PERSIST_TEMP) {
+ _currentRoomWalkboxes.push_back(walkbox);
+ }
+ if (persist & PERSIST_PERM) {
+ g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
+ }
}
Sprite *RoomManager::findSpriteByIndex(byte index) {
@@ -310,20 +396,6 @@ Common::Array<Exit> RoomManager::loadExits(byte *data, size_t size) {
int exitDataOffset = 0x1BF;
for (int i = 0; i < exitCount; i++) {
int exitOffset = exitDataOffset + i * 14;
- bool isChanged = false;
- if (g_engine->_state->roomExitChanges.contains(_currentRoomNumber)) {
- // if the exit has been changed, load the changed version
- for (int j = 0; j < g_engine->_state->roomExitChanges[_currentRoomNumber].size(); j++) {
- if (g_engine->_state->roomExitChanges[_currentRoomNumber][j].exitIndex == i) {
- exits.push_back(g_engine->_state->roomExitChanges[_currentRoomNumber][j].exit);
- isChanged = true;
- break;
- }
- }
- }
-
- if (isChanged)
- continue;
Exit exit;
exit.index = i;
@@ -355,6 +427,15 @@ Common::Array<Exit> RoomManager::loadExits(byte *data, size_t size) {
break;
}
+ if (g_engine->_state->roomExitChanges.contains(_currentRoomNumber)) {
+ // if the exit has been changed, load the changed version
+ for (int j = 0; j < g_engine->_state->roomExitChanges[_currentRoomNumber].size(); j++) {
+ if (g_engine->_state->roomExitChanges[_currentRoomNumber][j].exitIndex == i) {
+ exit.isEnabled = g_engine->_state->roomExitChanges[_currentRoomNumber][j].enabled;
+ break;
+ }
+ }
+ }
exits.push_back(exit);
// debug("Exit %d: targetRoom=%d isEnabled=%d x=%d y=%d w=%d h=%d targetX=%d targetY=%d dir=%d",
// i, exit.targetRoom, exit.isEnabled, exit.x, exit.y, exit.w, exit.h,
@@ -572,7 +653,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
uint32_t metadata_start = spriteCountPos + (44 * 2 + 5);
uint32_t picOffset = 0;
- Common::Array<int> disabledSprites = g_engine->_state->disabledSprites[_currentRoomNumber];
+ Common::Array<SpriteChange> spriteChanges = g_engine->_state->spriteChanges[_currentRoomNumber];
for (int i = 0; i < spriteCount; i++) {
uint32_t animOffset = metadata_start + (i * 44);
@@ -589,10 +670,12 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
sprite.spriteType = data[animOffset + 33];
sprite.actionFlags = data[animOffset + 34];
sprite.isHotspotDisabled = data[animOffset + 38];
- for (int j = 0; j < disabledSprites.size(); j++) {
- if (disabledSprites[j] == sprite.index) {
- sprite.zOrder = 255;
- sprite.isHotspotDisabled = 1;
+ for (int j = 0; j < spriteChanges.size(); j++) {
+ if (spriteChanges[j].spriteIndex == sprite.index) {
+ sprite.zOrder = spriteChanges[j].zIndex;
+ if(sprite.zOrder == 255) {
+ sprite.isHotspotDisabled = 1;
+ }
break;
}
}
@@ -727,7 +810,7 @@ uint32 RoomManager::loadDescriptions(byte *pair12data, size_t pair12size, Common
pos++;
}
// Hardcoded fix in the original!
- if(_currentRoomNumber == 3 && description.text.size() == 1 && description.text[0] == 0x2D) {
+ if (_currentRoomNumber == 3 && description.text.size() == 1 && description.text[0] == 0x2D) {
outDescriptions.push_back(description);
}
outDescriptions.push_back(description);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 0c796789a74..96499e7ae1e 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -51,11 +51,10 @@ static const int unpickableHotspotExtras[] = {
362,
};
-enum PersistType {
- PERSIST_TEMP,
- PERSIST_PERM,
- PERSIST_BOTH
-};
+
+#define PERSIST_TEMP 1
+#define PERSIST_PERM 2
+#define PERSIST_BOTH 3
class RoomManager {
public:
@@ -68,41 +67,54 @@ public:
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
/** Methods to modify room data at runtime **/
- void addSticker(int stickerId, bool persist = true);
- void addStickerToRoom(byte room, int stickerId);
- void onlyPersistSticker(byte room, int stickerId);
- void removeSticker(int index);
- void removeSticker(byte room, int index);
+ void addSticker(int stickerId, int persist = PERSIST_BOTH);
+ void addStickerToRoom(byte room, int stickerId, int persist = PERSIST_BOTH);
+
+ void removeSticker(int stickerId);
+ void removeStickerFromRoom(byte room, int stickerId);
+
bool hasSticker(int index);
bool hasSticker(byte room, int index);
- void changeExit(int index, bool enabled, bool persist = true);
- void changeExit(byte room, int index, bool enabled, bool persist = true);
- void disableExit(int index, bool persist = true);
- void disableExit(byte room, int index, bool persist = true);
- void enableExit(int index, bool persist = true);
- void enableExit(byte room, int index, bool persist = true);
- void changeWalkBox(WalkBox walkbox);
- void changeWalkbox(byte room, WalkBox walkbox);
- void changeHotSpot(HotSpot hotspot);
- void changeHotspot(byte room, HotSpot hotspot);
- void disableSprite(byte roomNumber, int spriteIndex, bool persist = true);
- void enableSprite(int spriteIndex, int zOrder, bool persist = true);
- void enableSprite(byte roomNumber, int spriteIndex, int zOrder, bool persist = true);
+
+ void changeExit(byte index, bool enabled, int persist = PERSIST_BOTH);
+ void changeExit(byte room, byte index, bool enabled, int persist = PERSIST_BOTH);
+
+ void disableExit(byte index, int persist = PERSIST_BOTH);
+ void disableExit(byte room, byte index, int persist = PERSIST_BOTH);
+ void enableExit(byte index, int persist = PERSIST_BOTH);
+ void enableExit(byte room, byte index, int persist = PERSIST_BOTH);
+
+ void changeWalkBox(WalkBox walkbox, int persist = PERSIST_BOTH);
+ void changeWalkbox(byte room, WalkBox walkbox, int persist = PERSIST_BOTH);
+
+ void changeHotSpot(HotSpot hotspot, int persist = PERSIST_BOTH);
+ void changeHotspot(byte room, HotSpot hotspot, int persist = PERSIST_BOTH);
+
+ void disableSprite(byte spriteIndex, int persist = PERSIST_BOTH);
+ void disableSprite(byte roomNumber, byte spriteIndex, int persist = PERSIST_BOTH);
+ void enableSprite(byte spriteIndex, byte zOrder, int persist = PERSIST_BOTH);
+ void enableSprite(byte roomNumber, byte spriteIndex, byte zOrder, int persist = PERSIST_BOTH);
/**
* Utility function to enable or disable a hotspot, with an option to persist the change.
*/
- void enableHotspot(HotSpot *hotspot, bool persist = true);
- void enableHotspot(byte room, HotSpot *hotspot, bool persist = true);
- void disableHotspot(HotSpot *hotspot, bool persist = true);
- void disableHotspot(byte room, HotSpot *hotspot, bool persist = true);
- void moveHotspot(HotSpot *hotspot, int16 newX, int16 newY, bool persist = true);
- void setActionMask(HotSpot *hotspot, byte actionMask);
- void moveHotspot(byte room, HotSpot *hotspot, int16 newX, int16 newY, bool persist = true);
- void addWalkbox(WalkBox walkbox);
- void addWalkbox(byte room, WalkBox walkbox);
+ void enableHotspot(HotSpot *hotspot, int persist = PERSIST_BOTH);
+ void enableHotspot(byte room, HotSpot *hotspot, int persist = PERSIST_BOTH);
+
+ void disableHotspot(HotSpot *hotspot, int persist = PERSIST_BOTH);
+ void disableHotspot(byte room, HotSpot *hotspot, int persist = PERSIST_BOTH);
+
+ void moveHotspot(HotSpot *hotspot, int16 newX, int16 newY, int persist = PERSIST_BOTH);
+ void moveHotspot(byte room, HotSpot *hotspot, int16 newX, int16 newY, int persist = PERSIST_BOTH);
+ void setActionMask(HotSpot *hotspot, byte actionMask, int persist = PERSIST_BOTH);
+
+ void addWalkbox(WalkBox walkbox, int persist = PERSIST_BOTH);
+ void addWalkbox(byte room, WalkBox walkbox, int persist = PERSIST_BOTH);
+
void applyDisabledChoices(byte roomNumber, byte *conversationData, size_t conversationDataSize);
void applyDisabledChoice(ResetEntry entry, byte *conversationData, size_t conversationDataSize);
void addDisabledChoice(ChoiceOption choice);
+
+
bool isPickableByExtra(uint16 extra) {
int size = sizeof(unpickableHotspotExtras) / sizeof(unpickableHotspotExtras[0]);
for (int i = 0; i < size; i++) {
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index 51066a03da5..b665f9c244f 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -50,7 +50,8 @@ void syncExit(Common::Serializer &s, Exit &exit) {
void syncExitChange(Common::Serializer &s, ExitChange &change) {
s.syncAsByte(change.roomNumber);
s.syncAsByte(change.exitIndex);
- syncExit(s, change.exit);
+ s.syncAsByte((byte &)change.enabled);
+ // syncExit(s, change.exit);
}
void syncWalkBox(Common::Serializer &s, WalkBox &walkbox) {
@@ -82,6 +83,12 @@ void syncHotSpot(Common::Serializer &s, HotSpot &hotspot) {
s.syncAsByte(hotspot.zOrder);
}
+void syncSpriteChange(Common::Serializer &s, SpriteChange &change) {
+ s.syncAsByte(change.roomNumber);
+ s.syncAsByte(change.spriteIndex);
+ s.syncAsByte(change.zIndex);
+}
+
void syncHotSpotChange(Common::Serializer &s, HotSpotChange &change) {
s.syncAsByte(change.roomNumber);
s.syncAsByte(change.hotspotIndex);
@@ -265,34 +272,34 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
}
}
- uint16 disabledSpritesSize = (uint16)gameState->disabledSprites.size();
+ uint16 disabledSpritesSize = (uint16)gameState->spriteChanges.size();
s.syncAsUint16LE(disabledSpritesSize);
if (s.isSaving()) {
- for (const auto &spritePair : gameState->disabledSprites) {
+ for (const auto &spritePair : gameState->spriteChanges) {
byte roomNumber = spritePair._key;
s.syncAsByte(roomNumber);
- const Common::Array<int> &sprites = spritePair._value;
+ const Common::Array<SpriteChange> &sprites = spritePair._value;
uint16 numSprites = (uint16)sprites.size();
s.syncAsUint16LE(numSprites);
for (uint16 i = 0; i < numSprites; ++i) {
- int spriteIndex = sprites[i];
- s.syncAsByte(spriteIndex);
+ SpriteChange spriteChange = sprites[i];
+ syncSpriteChange(s, spriteChange);
}
}
} else {
- gameState->disabledSprites.clear();
+ gameState->spriteChanges.clear();
for (uint16 idx = 0; idx < disabledSpritesSize; ++idx) {
byte roomNumber;
s.syncAsByte(roomNumber);
uint16 numSprites;
s.syncAsUint16LE(numSprites);
- Common::Array<int> sprites;
+ Common::Array<SpriteChange> sprites;
for (uint16 i = 0; i < numSprites; ++i) {
- int spriteIndex;
- s.syncAsByte(spriteIndex);
- sprites.push_back(spriteIndex);
+ SpriteChange spriteChange;
+ syncSpriteChange(s, spriteChange);
+ sprites.push_back(spriteChange);
}
- gameState->disabledSprites[roomNumber] = sprites;
+ gameState->spriteChanges[roomNumber] = sprites;
}
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 1fca82e42bf..5e752d964de 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -327,6 +327,15 @@ enum GameState {
COMPUTER = 104
};
+struct SpriteChange
+{
+ byte roomNumber;
+ byte spriteIndex;
+ byte zIndex;
+
+};
+
+
struct HotSpotChange {
byte roomNumber;
byte hotspotIndex;
@@ -336,7 +345,7 @@ struct HotSpotChange {
struct ExitChange {
byte roomNumber;
byte exitIndex;
- Exit exit;
+ bool enabled;
};
struct WalkBoxChange {
@@ -481,7 +490,6 @@ struct GameStateData {
Common::Array<byte> inventoryItems;
int16 selectedInventoryItem = -1;
-
int libraryShelf = -1;
int selectedBookIndex = -1;
unsigned char bookLetter = '\0';
@@ -490,7 +498,7 @@ struct GameStateData {
Common::HashMap<byte, Common::Array<WalkBoxChange>> roomWalkBoxChanges;
Common::HashMap<byte, Common::Array<HotSpotChange>> roomHotSpotChanges;
Common::HashMap<byte, Common::Array<ResetEntry>> disabledBranches;
- Common::HashMap<byte, Common::Array<int>> disabledSprites;
+ Common::HashMap<byte, Common::Array<SpriteChange>> spriteChanges;
GameStateData() {
memset(conversationRootsState, 0, 4 * 56);
Commit: f22d5018c2dc89379869e0c19647d27ce8886145
https://github.com/scummvm/scummvm/commit/f22d5018c2dc89379869e0c19647d27ce8886145
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:53+02:00
Commit Message:
PELROCK: Enable animations when museum is open
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index b317a6aa710..c992cb14096 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -101,6 +101,10 @@ const ActionEntry actionTable[] = {
{361, PICKUP, &PelrockEngine::pickBooksFromShelf2},
{362, PICKUP, &PelrockEngine::pickBooksFromShelf3},
+ // Room 16
+ {388, OPEN, &PelrockEngine::openNewspaperDoor},
+ {388, CLOSE, &PelrockEngine::closeNewspaperDoor},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -222,6 +226,9 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setRootDisabledState(room, rootIndex, true);
_state->setRootDisabledState(room, rootIndex + 1, true);
break;
+ case 267:
+ _state->setRootDisabledState(7, 1, true);
+ break;
case 272:
_state->setRootDisabledState(room, rootIndex, true);
break;
@@ -297,7 +304,7 @@ void PelrockEngine::openIceCreamShopDoor(HotSpot *hotspot) {
}
void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
- if(!_room->hasSticker(91)) {
+ if (!_room->hasSticker(91)) {
_dialog->say(_res->_ingameTexts[YA_CERRADO_M]);
return;
}
@@ -565,15 +572,23 @@ void PelrockEngine::giveIdToGuard(int inventoryObject, HotSpot *hotspot) {
if (!_state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
_state->setFlag(FLAG_GUARDIA_DNI_ENTREGADO, true);
_dialog->say(_res->_ingameTexts[DEACUERDO]);
- return;
}
if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
- _state->setRootDisabledState(4, 2, true);
- _room->enableSprite(4, 2, 100);
+ unlockMuseum();
return;
}
}
+void PelrockEngine::unlockMuseum() {
+ _state->setRootDisabledState(4, 2, true);
+ _room->enableSprite(2, 100, PERSIST_PERM);
+ _room->enableSprite(3, 100, PERSIST_PERM);
+ _room->addStickerToRoom(4, 87, PERSIST_PERM);
+ _room->addStickerToRoom(4, 88, PERSIST_PERM);
+ _room->addStickerToRoom(4, 89, PERSIST_PERM);
+ _room->addStickerToRoom(4, 90, PERSIST_PERM);
+}
+
void PelrockEngine::giveMoneyToGuard(int inventoryObject, HotSpot *hotspot) {
if (!_state->getFlag(FLAG_GUARDIA_PIDECOSAS)) {
_dialog->say(_res->_ingameTexts[PRETENDEUSTED_SOBORNARME]);
@@ -582,12 +597,9 @@ void PelrockEngine::giveMoneyToGuard(int inventoryObject, HotSpot *hotspot) {
_state->setFlag(FLAG_SOBORNO_PORTERO, true);
_dialog->say(_res->_ingameTexts[MUYBIEN]);
_state->removeInventoryItem(5); // Remove 1000 pesetas bill
- return;
}
if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
- _state->setRootDisabledState(4, 2, true);
- _room->enableSprite(2, 100);
- _room->enableSprite(3, 100);
+ unlockMuseum();
return;
}
}
@@ -618,7 +630,6 @@ void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
_currentHotspot = statueHotspot;
walkAndAction(statueHotspot, TALK);
- _state->setRootDisabledState(7, 1, true);
// TODO: Undo palette anim!
}
@@ -664,15 +675,38 @@ void PelrockEngine::giveFormulaToLibrarian(int inventoryObject, HotSpot *hotspot
}
void PelrockEngine::openNewspaperDoor(HotSpot *hotspot) {
- openDoor(hotspot, 0, 90, FEMININE, true);
+ openDoor(hotspot, 2, 50, MASCULINE, false);
+}
+
+void PelrockEngine::closeNewspaperDoor(HotSpot *hotspot) {
+ closeDoor(hotspot, 2, 50, MASCULINE, false);
}
void PelrockEngine::pickUpBook(int i) {
if (!_state->hasInventoryItem(10)) {
_dialog->say(_res->_ingameTexts[VENGA_ACA]);
_state->setRootDisabledState(9, 0, true);
+
+ if (_state->hasInventoryItem(3)) {
+ _state->setRootDisabledState(9, 1, true);
+ addInventoryItem(10);
+ }
+
_alfredState.isWalkingCancelable = false;
walkAndAction(_room->findHotspotByExtra(102), TALK);
+ // After dialog ends, reenable first dialog root if no photo in inventory
+ // Wait for dialog to end to reenable first dialog root
+ while (!shouldQuit() && _queuedAction.isQueued) {
+ _events->pollEvent();
+ renderScene(OVERLAY_NONE);
+ _screen->update();
+ }
+ if (!_state->hasInventoryItem(3)) {
+
+ _state->setRootDisabledState(9, 0, false);
+ } else {
+ _state->setRootDisabledState(9, 2, true);
+ }
} else {
if (_state->libraryShelf == -1) {
_dialog->say(_res->_ingameTexts[TODOS]);
@@ -764,10 +798,9 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_alfredState.animState = ALFRED_SPECIAL_ANIM;
waitForSpecialAnimation();
loadExtraScreenAndPresent(5);
- if(_state->getFlag(FLAG_ALFRED_SABE_EGIPCIO)) {
+ if (_state->getFlag(FLAG_ALFRED_SABE_EGIPCIO)) {
_dialog->say(_res->_ingameTexts[FORMULAVIAJETIEMPO]);
- }
- else {
+ } else {
_dialog->say(_res->_ingameTexts[QUELASTIMA_NOSEEGIPCIO]);
}
break;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 994839b0fec..f2cafbb23e1 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -152,9 +152,9 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(0, ALFRED_DOWN);
+ // setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
- // setScreen(5, ALFRED_DOWN);
+ setScreen(7, ALFRED_DOWN);
// setScreen(9, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 345cc3407e6..0ec596a1d25 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -285,6 +285,7 @@ public:
void useCordWithPlug(int inventoryObject, HotSpot *hotspot);
void pickCables(HotSpot *hotspot);
void giveIdToGuard(int inventoryObject, HotSpot *hotspot);
+ void unlockMuseum();
void giveMoneyToGuard(int inventoryObject, HotSpot *hotspot);
void openMuseumDoor(HotSpot *hotspot);
void useAmuletWithStatue(int inventoryObject, HotSpot *hotspot);
@@ -298,6 +299,7 @@ public:
void pickBooksFromShelf3(HotSpot *hotspot);
void giveFormulaToLibrarian(int inventoryObject, HotSpot *hotspot);
void openNewspaperDoor(HotSpot *hotspot);
+ void closeNewspaperDoor(HotSpot *hotspot);
void pickUpBook(int i);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 86d5e81bdab..e00d9780776 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -153,7 +153,7 @@ void RoomManager::changeExit(byte index, bool enabled, int persist) {
}
void RoomManager::changeExit(byte room, byte index, bool enabled, int persist) {
- if (room == _currentRoomNumber & persist & PERSIST_TEMP) {
+ if (room == _currentRoomNumber && persist & PERSIST_TEMP) {
_currentRoomExits[index].isEnabled = enabled;
}
if (persist & PERSIST_PERM)
@@ -181,7 +181,7 @@ void RoomManager::changeWalkBox(WalkBox walkbox, int persist) {
}
void RoomManager::changeWalkbox(byte room, WalkBox walkbox, int persist) {
- if (room == _currentRoomNumber & persist & PERSIST_TEMP) {
+ if (room == _currentRoomNumber && persist & PERSIST_TEMP) {
_currentRoomWalkboxes[walkbox.index] = walkbox;
}
if (persist & PERSIST_PERM) {
@@ -194,7 +194,7 @@ void RoomManager::changeHotSpot(HotSpot hotspot, int persist) {
}
void RoomManager::changeHotspot(byte room, HotSpot hotspot, int persist) {
- if (room == _currentRoomNumber & persist & PERSIST_TEMP) {
+ if (room == _currentRoomNumber && persist & PERSIST_TEMP) {
for (uint i = 0; i < _currentRoomHotspots.size(); i++) {
if (!_currentRoomHotspots[i].isSprite && _currentRoomHotspots[i].innerIndex == hotspot.innerIndex) {
_currentRoomHotspots[i] = hotspot;
@@ -212,7 +212,7 @@ void RoomManager::disableSprite(byte spriteIndex, int persist) {
}
void RoomManager::disableSprite(byte roomNumber, byte spriteIndex, int persist) {
- if (roomNumber == _currentRoomNumber & persist & PERSIST_TEMP) {
+ if (roomNumber == _currentRoomNumber && persist & PERSIST_TEMP) {
_currentRoomAnims[spriteIndex].zOrder = 255;
_currentRoomAnims[spriteIndex].isHotspotDisabled = true;
}
@@ -226,7 +226,7 @@ void RoomManager::enableSprite(byte spriteIndex, byte zOrder, int persist) {
}
void RoomManager::enableSprite(byte roomNumber, byte spriteIndex, byte zOrder, int persist) {
- if (roomNumber == _currentRoomNumber & persist & PERSIST_TEMP) {
+ if (roomNumber == _currentRoomNumber && persist & PERSIST_TEMP) {
_currentRoomAnims[spriteIndex].zOrder = zOrder;
}
if (persist & PERSIST_PERM) {
Commit: 2e9a0fb46e043e6890483b4404fab104fa776426
https://github.com/scummvm/scummvm/commit/2e9a0fb46e043e6890483b4404fab104fa776426
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:53+02:00
Commit Message:
PELROCK: Room 17
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index c992cb14096..05d829c0c4e 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -105,6 +105,10 @@ const ActionEntry actionTable[] = {
{388, OPEN, &PelrockEngine::openNewspaperDoor},
{388, CLOSE, &PelrockEngine::closeNewspaperDoor},
+ // Room 17
+ {393, OPEN, &PelrockEngine::openNewspaperBossDor},
+ {393, CLOSE, &PelrockEngine::closeNewspaperBossDoor},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -682,6 +686,14 @@ void PelrockEngine::closeNewspaperDoor(HotSpot *hotspot) {
closeDoor(hotspot, 2, 50, MASCULINE, false);
}
+void PelrockEngine::openNewspaperBossDor(HotSpot *hotspot) {
+ openDoor(hotspot, 1, 52, MASCULINE, true);
+}
+
+void PelrockEngine::closeNewspaperBossDoor(HotSpot *hotspot) {
+ closeDoor(hotspot, 1, 52, MASCULINE, true);
+}
+
void PelrockEngine::pickUpBook(int i) {
if (!_state->hasInventoryItem(10)) {
_dialog->say(_res->_ingameTexts[VENGA_ACA]);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 0ec596a1d25..236d21befe0 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -300,6 +300,8 @@ public:
void giveFormulaToLibrarian(int inventoryObject, HotSpot *hotspot);
void openNewspaperDoor(HotSpot *hotspot);
void closeNewspaperDoor(HotSpot *hotspot);
+ void openNewspaperBossDor(HotSpot *hotspot);
+ void closeNewspaperBossDoor(HotSpot *hotspot);
void pickUpBook(int i);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index e00d9780776..f61b3d20e67 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -704,6 +704,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
uint32_t needed = anim.w * anim.h * anim.nframes;
for (int i = 0; i < anim.nframes; i++) {
anim.animData[i] = new byte[anim.w * anim.h];
+ // debug("Extracting frame %d for anim %d-%d, w=%d h=%d, pixelDataSize=%d, current offset %d", i, j, anim.nframes, anim.w, anim.h, pixelDataSize, picOffset);
extractSingleFrame(pixelData + picOffset, anim.animData[i], i, anim.w, anim.h);
}
sprite.animData[j] = anim;
Commit: 97258764ff0c4ac1cc557d4ea5196f62581a9571
https://github.com/scummvm/scummvm/commit/97258764ff0c4ac1cc557d4ea5196f62581a9571
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:53+02:00
Commit Message:
PELROCK: Implements passer-by animations
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f2cafbb23e1..868cacbef3a 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -200,16 +200,20 @@ Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
// Sort sprites by zOrder in-place using insertion sort (efficient for nearly-sorted data)
void sortAnimsByZOrder(Common::Array<Sprite> &anims) {
- for (size_t i = 1; i < anims.size(); ++i) {
+ for (size_t i = 0; i < anims.size(); ++i) {
Sprite key = anims[i];
int z = key.zOrder;
size_t j = i;
- while (j > 0 && anims[j - 1].zOrder > z) {
+ while (j > 0 && anims[j - 1].zOrder < z) {
anims[j] = anims[j - 1];
--j;
}
anims[j] = key;
}
+ debug("Sorted anims by zOrder");
+ for (size_t i = 0; i < anims.size(); i++) {
+ debug("Anim %d, extra = %d: zOrder=%d", i, anims[i].extra, anims[i].zOrder);
+ }
}
void PelrockEngine::playSoundIfNeeded() {
@@ -251,11 +255,13 @@ bool PelrockEngine::renderScene(int overlayMode) {
return false;
}
-const int kPasserbyTriggerFrameInterval = 0x3FF;
+// const int kPasserbyTriggerFrameInterval = 0x3FF;
+const int kPasserbyTriggerFrameInterval = 15;
void PelrockEngine::frameTriggers() {
- if ((_chrono->getFrameCount() & kPasserbyTriggerFrameInterval) == kPasserbyTriggerFrameInterval) {
- debug("Would trigger passer-by");
+ uint32 frameCount = _chrono->getFrameCount();
+ // Passerby animations
+ if ((frameCount & kPasserbyTriggerFrameInterval) == kPasserbyTriggerFrameInterval) {
switch (_room->_currentRoomNumber) {
case 9: {
Sprite *mouse = _room->findSpriteByIndex(2);
@@ -269,11 +275,8 @@ void PelrockEngine::frameTriggers() {
mouse->animData[3].movementFlags = 0x3E0;
break;
}
- default:
- break;
}
}
-
if (_room->_currentRoomNumber == 9) {
// Mouse animation on library
Sprite *mouse = _room->findSpriteByIndex(2);
@@ -286,6 +289,54 @@ void PelrockEngine::frameTriggers() {
}
}
}
+ passerByAnim(frameCount);
+}
+
+void PelrockEngine::passerByAnim(uint32 frameCount) {
+ if (_room->_passerByAnims == nullptr) {
+ debug("No passerby anims for this room");
+ return;
+ }
+ if (_room->_passerByAnims->latch == false) {
+ int animIndex = _room->_passerByAnims->numAnims == 1 ? 0 : getRandomNumber(_room->_passerByAnims->numAnims - 1);
+ PasserByAnim anim = _room->_passerByAnims->passerByAnims[animIndex];
+ if ((frameCount & anim.frameTrigger) == anim.frameTrigger) {
+ Sprite *sprite = _room->findSpriteByIndex(anim.spriteIndex);
+ if (sprite && sprite->zOrder == -1) {
+ debug("Starting passerby anim for sprite %d at index %d", anim.spriteIndex, animIndex);
+ sprite->zOrder = anim.targetZIndex;
+ _room->_passerByAnims->latch = true;
+ _room->_passerByAnims->currentAnimIndex = animIndex;
+ }
+ }
+ } else {
+ PasserByAnim anim = _room->_passerByAnims->passerByAnims[_room->_passerByAnims->currentAnimIndex];
+ byte direction = anim.dir;
+ int spriteIndex = anim.spriteIndex;
+ int startX = anim.startX;
+ int startY = anim.startY;
+
+ Sprite *sprite = _room->findSpriteByIndex(spriteIndex);
+ if (direction == RIGHT) {
+ if (sprite->x >= anim.resetX) {
+ sprite->x = startX;
+ sprite->y = startY;
+ sprite->zOrder = -1;
+ sprite->curAnimIndex = 0;
+ sprite->animData[0].curFrame = 0;
+ _room->_passerByAnims->latch = false;
+ }
+ } else if (direction == LEFT) {
+ if (sprite->x <= anim.resetX) {
+ sprite->x = startX;
+ sprite->y = startY;
+ sprite->zOrder = -1;
+ sprite->curAnimIndex = 0;
+ sprite->animData[0].curFrame = 0;
+ _room->_passerByAnims->latch = false;
+ }
+ }
+ }
}
void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
@@ -1307,7 +1358,7 @@ void PelrockEngine::gameLoop() {
void PelrockEngine::computerLoop() {
Computer computer(_events);
computer.run();
- if(_state->selectedBookIndex != -1 && _state->bookLetter != '\0') {
+ if (_state->selectedBookIndex != -1 && _state->bookLetter != '\0') {
Common::StringArray lines;
lines.push_back(Common::String::format(computer._memorizedMsg, _state->bookLetter));
_dialog->sayAlfred(lines);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 236d21befe0..1ec970af8d2 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -230,6 +230,8 @@ public:
bool renderScene(int overlayMode = OVERLAY_NONE);
void frameTriggers();
+ void passerByAnim(uint32 frameCount);
+
void changeCursor(Cursor cursor);
// Actions
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index f61b3d20e67..8ecf72ff31d 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -589,10 +589,205 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
_currentPaletteAnim = nullptr;
}
+ if (_passerByAnims != nullptr) {
+ delete _passerByAnims;
+ }
+ _passerByAnims = loadPasserByAnims(roomNumber);
+
delete[] pair10;
delete[] pair12;
}
+int streetWalkerIndices[] = {
+ -1, // room 0,
+ 5, // room 1,
+ 3, // room 2,
+ 6, // room 3,
+ -1, // room 4,
+ -1, // room 5,
+ -1, // room 6,
+ -1, // room 7,
+ 7, // room 8,
+ -1, // room 9,
+ -1, // room 10,
+ -1, // room 11,
+ -1, // room 12,
+ -1, // room 13,
+ 2, // room 14,
+ -1, // room 15,
+ 2
+
+};
+RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
+ RoomPasserBys *anims = nullptr;
+ switch (roomNumber) {
+ // case 9: {
+ // Sprite *mouse = findSpriteByIndex(2);
+ // mouse->zOrder = 1;
+ // mouse->animData[0].loopCount = 3;
+ // mouse->animData[1].loopCount = 1;
+ // mouse->animData[1].movementFlags = 0x3FF;
+ // mouse->animData[2].loopCount = 1;
+ // mouse->animData[2].movementFlags = 0x801F;
+ // mouse->animData[3].loopCount = 3;
+ // mouse->animData[3].movementFlags = 0x3E0;
+ // break;
+ // }
+
+ case 1:
+ case 2:
+ case 3:
+ case 8:
+ case 14:
+ case 16: {
+ anims = new RoomPasserBys(roomNumber, 1);
+ PasserByAnim anim;
+ anim.spriteIndex = streetWalkerIndices[roomNumber];
+ Sprite *camel = findSpriteByIndex(anim.spriteIndex);
+ anim.startX = camel->x;
+ anim.startY = camel->y;
+ anim.dir = RIGHT;
+ anim.frameTrigger = 0x1FFF;
+ anim.targetZIndex = 1;
+ anim.resetX = 639 + camel->w;
+
+ anims->passerByAnims[0] = anim;
+ break;
+ }
+ case 21: {
+ anims = new RoomPasserBys(roomNumber, 1);
+ PasserByAnim anim;
+ anim.spriteIndex = 3;
+ Sprite *camel = findSpriteByIndex(3);
+ anim.startX = camel->x;
+ anim.startY = camel->y;
+ anim.dir = LEFT;
+ anim.resetX = 0 - camel->w;
+ anim.targetZIndex = 1;
+
+ anims->passerByAnims[0] = anim;
+ break;
+ }
+ case 29: {
+ Sprite *carLeft = findSpriteByIndex(2);
+ Sprite *carRight = findSpriteByIndex(3);
+
+ anims = new RoomPasserBys(roomNumber, 2);
+ PasserByAnim animA;
+ animA.spriteIndex = 2;
+ animA.startX = carLeft->x;
+ animA.startY = carLeft->y;
+ animA.dir = LEFT;
+ animA.resetX = carRight->x + carRight->w - carLeft->w;
+ animA.targetZIndex = 100;
+
+ anims->passerByAnims[0] = animA;
+ PasserByAnim animB;
+ animB.spriteIndex = 3;
+ animB.startX = carRight->x;
+ animB.startY = carRight->y;
+ animB.dir = RIGHT;
+ animB.targetZIndex = 100;
+ animB.resetX = 639 + carRight->w;
+ anims->passerByAnims[1] = animB;
+ break;
+ }
+ case 31: {
+
+ anims = new RoomPasserBys(roomNumber, 1);
+ Sprite *walker = findSpriteByIndex(2);
+ Sprite *dark = findSpriteByIndex(5);
+ PasserByAnim anim;
+ anim.spriteIndex = 2;
+ anim.startX = walker->x;
+ anim.startY = walker->y;
+ anim.dir = RIGHT;
+ anim.resetX = dark->x;
+ anim.targetZIndex = dark->zOrder + 1;
+ anims->passerByAnims[0] = anim;
+ break;
+ }
+ case 46: {
+ Sprite *catRight = findSpriteByIndex(2);
+ Sprite *catLeft = findSpriteByIndex(3);
+ Sprite *blank = findSpriteByIndex(0);
+ anims = new RoomPasserBys(roomNumber, 2);
+ PasserByAnim animA;
+ animA.spriteIndex = 2;
+ animA.startX = catRight->x;
+ animA.startY = catRight->y;
+ animA.dir = RIGHT;
+ animA.resetX = catLeft->x;
+ animA.targetZIndex = blank->zOrder + 1;
+
+ anims->passerByAnims[0] = animA;
+ PasserByAnim animB;
+ animB.spriteIndex = 3;
+ animB.startX = catLeft->x;
+ animB.startY = catLeft->y;
+ animB.dir = LEFT;
+ animB.resetX = blank->x;
+ animB.targetZIndex = blank->zOrder + 1;
+ anims->passerByAnims[1] = animB;
+ break;
+ }
+ case 47: {
+ Sprite *mouseRight = findSpriteByIndex(3);
+ Sprite *mouseLeft = findSpriteByIndex(4);
+ Sprite *papers = findSpriteByIndex(1);
+
+ anims = new RoomPasserBys(roomNumber, 2);
+ PasserByAnim animA;
+ animA.spriteIndex = 3;
+ animA.startX = mouseRight->x;
+ animA.startY = mouseRight->y;
+ animA.dir = RIGHT;
+ animA.resetX = mouseLeft->x;
+ animA.targetZIndex = papers->zOrder + 1;
+ anims->passerByAnims[0] = animA;
+
+ PasserByAnim animB;
+ animB.spriteIndex = 4;
+ animB.startX = mouseLeft->x;
+ animB.startY = mouseLeft->y;
+ animB.dir = LEFT;
+ animB.resetX = mouseRight->x;
+ animB.targetZIndex = papers->zOrder + 1;
+ anims->passerByAnims[1] = animB;
+ break;
+ }
+ case 50: {
+ Sprite *mummyLeft = findSpriteByIndex(2);
+ Sprite *mummyRight = findSpriteByIndex(3);
+
+ anims = new RoomPasserBys(roomNumber, 2);
+ PasserByAnim animA;
+ animA.spriteIndex = 2;
+ animA.startX = mummyLeft->x;
+ animA.startY = mummyLeft->y;
+ animA.dir = LEFT;
+ animA.resetX = 0 - mummyLeft->w;
+ animA.targetZIndex = 1;
+
+ anims->passerByAnims[0] = animA;
+ PasserByAnim animB;
+ animB.spriteIndex = 3;
+ animB.startX = mummyRight->x;
+ animB.startY = mummyRight->y;
+ animB.dir = RIGHT;
+ animB.targetZIndex = 1;
+ animB.resetX = 639 + mummyRight->w;
+ anims->passerByAnims[1] = animB;
+ break;
+ }
+ default:
+ break;
+ }
+ if (anims != nullptr)
+ debug("Loaded passerby anims for room %d, count = %d", roomNumber, anims->numAnims);
+ return anims;
+}
+
Common::Array<HotSpot> RoomManager::unifyHotspots(Common::Array<Pelrock::Sprite> &anims, Common::Array<Pelrock::HotSpot> &staticHotspots) {
Common::Array<HotSpot> unifiedHotspots;
for (int i = 0; i < anims.size(); i++) {
@@ -673,7 +868,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
for (int j = 0; j < spriteChanges.size(); j++) {
if (spriteChanges[j].spriteIndex == sprite.index) {
sprite.zOrder = spriteChanges[j].zIndex;
- if(sprite.zOrder == 255) {
+ if (sprite.zOrder == 255) {
sprite.isHotspotDisabled = 1;
}
break;
@@ -945,7 +1140,7 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
readUntilBuda(&talkFile, talkHeader.spritePointer, data, dataSize);
size_t decompressedSize = rleDecompress(data, dataSize, 0, dataSize, &decompressed);
free(data);
- // debug("Decompressed talking anim A size: %zu, decompressed size: %zu", dataSize, decompressedSize);
+ debug("Decompressed talking anim A size: %zu, decompressed size: %zu", dataSize, decompressedSize);
for (int i = 0; i < talkHeader.numFramesAnimA; i++) {
talkHeader.animA[i] = new byte[talkHeader.wAnimA * talkHeader.hAnimA];
extractSingleFrame(decompressed, talkHeader.animA[i], i, talkHeader.wAnimA, talkHeader.hAnimA);
@@ -955,7 +1150,14 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
talkHeader.animB = new byte *[talkHeader.numFramesAnimB];
for (int i = 0; i < talkHeader.numFramesAnimB; i++) {
talkHeader.animB[i] = new byte[talkHeader.wAnimB * talkHeader.hAnimB];
- extractSingleFrame(decompressed + animASize, talkHeader.animB[i], i, talkHeader.wAnimB, talkHeader.hAnimB);
+ uint32 offset = animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB);
+ debug("Extracting talking anim B frame %d at offset %d, size = %d", i, animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB), talkHeader.wAnimB * talkHeader.hAnimB);
+ if (offset + talkHeader.wAnimB * talkHeader.hAnimB >= decompressedSize) {
+ debug("Error: offset %d is beyond decompressed size %zu", offset, decompressedSize);
+ talkHeader.numFramesAnimB = 0;
+ } else {
+ extractSingleFrame(decompressed + animASize, talkHeader.animB[i], i, talkHeader.wAnimB, talkHeader.hAnimB);
+ }
}
}
free(decompressed);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 96499e7ae1e..0ae126f14eb 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -61,6 +61,7 @@ public:
RoomManager();
~RoomManager();
void loadRoomMetadata(Common::File *roomFile, int roomNumber);
+ RoomPasserBys *loadPasserByAnims(int roomNumber);
Common::Array<HotSpot> unifyHotspots(Common::Array<Pelrock::Sprite> &anims, Common::Array<Pelrock::HotSpot> &staticHotspots);
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
@@ -150,6 +151,7 @@ public:
byte _musicTrack = 0;
Common::Array<byte> _roomSfx;
PaletteAnim *_currentPaletteAnim = nullptr;
+ RoomPasserBys *_passerByAnims = nullptr;
byte *_conversationData = nullptr;
size_t _conversationDataSize = 0;
Common::Array<Sticker> _roomStickers;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 5e752d964de..a7b861aec4c 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -405,6 +405,30 @@ struct PaletteAnim {
byte tickCount = 0;
};
+#define RIGHT 0
+#define LEFT 1
+
+struct PasserByAnim
+{
+ uint32 frameTrigger = 0x3FF;
+ int16 startX;
+ int16 startY;
+ int16 resetX;
+ bool dir;
+ byte spriteIndex;
+ byte targetZIndex;
+};
+
+struct RoomPasserBys {
+ byte roomNumber;
+ PasserByAnim passerByAnims[2];
+ byte currentAnimIndex = 0;
+ byte numAnims = 0;
+ bool latch = false;
+ RoomPasserBys(byte roomNum, byte numAnims) : roomNumber(roomNum), numAnims(numAnims) {}
+};
+
+
/**
* Structure to hold a parsed choice option
*/
Commit: d369e67fd78693d0580f158d5a60c911fa6ca4ae
https://github.com/scummvm/scummvm/commit/d369e67fd78693d0580f158d5a60c911fa6ca4ae
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:54+02:00
Commit Message:
PELROCK: Model mouse animation in room9 as passer-by
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 868cacbef3a..275d622f846 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -210,10 +210,10 @@ void sortAnimsByZOrder(Common::Array<Sprite> &anims) {
}
anims[j] = key;
}
- debug("Sorted anims by zOrder");
- for (size_t i = 0; i < anims.size(); i++) {
- debug("Anim %d, extra = %d: zOrder=%d", i, anims[i].extra, anims[i].zOrder);
- }
+ // debug("Sorted anims by zOrder");
+ // for (size_t i = 0; i < anims.size(); i++) {
+ // debug("Anim %d, extra = %d: zOrder=%d", i, anims[i].extra, anims[i].zOrder);
+ // }
}
void PelrockEngine::playSoundIfNeeded() {
@@ -260,35 +260,6 @@ bool PelrockEngine::renderScene(int overlayMode) {
const int kPasserbyTriggerFrameInterval = 15;
void PelrockEngine::frameTriggers() {
uint32 frameCount = _chrono->getFrameCount();
- // Passerby animations
- if ((frameCount & kPasserbyTriggerFrameInterval) == kPasserbyTriggerFrameInterval) {
- switch (_room->_currentRoomNumber) {
- case 9: {
- Sprite *mouse = _room->findSpriteByIndex(2);
- mouse->zOrder = 1;
- mouse->animData[0].loopCount = 3;
- mouse->animData[1].loopCount = 1;
- mouse->animData[1].movementFlags = 0x3FF;
- mouse->animData[2].loopCount = 1;
- mouse->animData[2].movementFlags = 0x801F;
- mouse->animData[3].loopCount = 3;
- mouse->animData[3].movementFlags = 0x3E0;
- break;
- }
- }
- }
- if (_room->_currentRoomNumber == 9) {
- // Mouse animation on library
- Sprite *mouse = _room->findSpriteByIndex(2);
- if (mouse) {
- if (mouse->y > 355) {
- mouse->x = 82;
- mouse->y = 315;
- mouse->zOrder = 255;
- mouse->curAnimIndex = 0;
- }
- }
- }
passerByAnim(frameCount);
}
@@ -305,6 +276,9 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
if (sprite && sprite->zOrder == -1) {
debug("Starting passerby anim for sprite %d at index %d", anim.spriteIndex, animIndex);
sprite->zOrder = anim.targetZIndex;
+ sprite->curAnimIndex = 0;
+ sprite->animData[0].curFrame = 0;
+ sprite->animData[0].curLoop = 0;
_room->_passerByAnims->latch = true;
_room->_passerByAnims->currentAnimIndex = animIndex;
}
@@ -312,13 +286,15 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
} else {
PasserByAnim anim = _room->_passerByAnims->passerByAnims[_room->_passerByAnims->currentAnimIndex];
byte direction = anim.dir;
+
int spriteIndex = anim.spriteIndex;
int startX = anim.startX;
int startY = anim.startY;
-
+ debug("Checking passerby anim %d for sprite %d, direction %d", _room->_passerByAnims->currentAnimIndex, spriteIndex, direction);
Sprite *sprite = _room->findSpriteByIndex(spriteIndex);
- if (direction == RIGHT) {
- if (sprite->x >= anim.resetX) {
+ if (direction == PASSERBY_RIGHT) {
+ debug("Checking passerby anim for sprite %d moving RIGHT, curpos is %d", spriteIndex, sprite->x);
+ if (sprite->x >= anim.resetCoord) {
sprite->x = startX;
sprite->y = startY;
sprite->zOrder = -1;
@@ -326,8 +302,20 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
sprite->animData[0].curFrame = 0;
_room->_passerByAnims->latch = false;
}
- } else if (direction == LEFT) {
- if (sprite->x <= anim.resetX) {
+ } else if (direction == PASSERBY_LEFT) {
+ debug("Checking passerby anim for sprite %d moving LEFT, curpos is %d", spriteIndex, sprite->x);
+
+ if (sprite->x <= anim.resetCoord) {
+ sprite->x = startX;
+ sprite->y = startY;
+ sprite->zOrder = -1;
+ sprite->curAnimIndex = 0;
+ sprite->animData[0].curFrame = 0;
+ _room->_passerByAnims->latch = false;
+ }
+ } else if (direction == PASSERBY_DOWN) {
+ debug("Checking passerby anim for sprite %d moving DOWN, curpos is %d, reset %d", spriteIndex, sprite->y, anim.resetCoord);
+ if (sprite->y >= anim.resetCoord) {
sprite->x = startX;
sprite->y = startY;
sprite->zOrder = -1;
@@ -1013,6 +1001,10 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
return;
}
+ if(_room->_currentRoomNumber == 9 && sprite->index == 2) {
+ debug("Drawing sprite 2 in room 9, anim %d, frame %d/%d, loop %d/%d", sprite->curAnimIndex, animData.curFrame, animData.nframes, animData.curLoop, animData.loopCount);
+ }
+
applyMovement(&(sprite->x), &(sprite->y), &(sprite->zOrder), animData.movementFlags);
int x = sprite->x;
int y = sprite->y;
@@ -1352,6 +1344,7 @@ void PelrockEngine::gameLoop() {
_events->pollEvent();
checkMouse();
renderScene();
+ // _events->waitForKey();
_screen->update();
}
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 8ecf72ff31d..473bd24fb27 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -621,18 +621,29 @@ int streetWalkerIndices[] = {
RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
RoomPasserBys *anims = nullptr;
switch (roomNumber) {
- // case 9: {
- // Sprite *mouse = findSpriteByIndex(2);
- // mouse->zOrder = 1;
- // mouse->animData[0].loopCount = 3;
- // mouse->animData[1].loopCount = 1;
- // mouse->animData[1].movementFlags = 0x3FF;
- // mouse->animData[2].loopCount = 1;
- // mouse->animData[2].movementFlags = 0x801F;
- // mouse->animData[3].loopCount = 3;
- // mouse->animData[3].movementFlags = 0x3E0;
- // break;
- // }
+ case 9: {
+ Sprite *mouse = findSpriteByIndex(2);
+ Sprite *blank = findSpriteByIndex(4);
+ mouse->animData[0].loopCount = 3;
+ mouse->animData[1].loopCount = 1;
+ mouse->animData[1].movementFlags = 0x3FF;
+ mouse->animData[2].loopCount = 1;
+ mouse->animData[2].movementFlags = 0x801F;
+ mouse->animData[3].loopCount = 4;
+ mouse->animData[3].movementFlags = 0x3C0;
+
+ anims = new RoomPasserBys(roomNumber, 1);
+ PasserByAnim anim;
+ anim.spriteIndex = 2;
+ anim.startX = mouse->x;
+ anim.startY = mouse->y;
+ anim.dir = PASSERBY_DOWN;
+ anim.targetZIndex = blank->zOrder + 1;
+ anim.resetCoord = blank->y;
+ anims->passerByAnims[0] = anim;
+ debug("Loaded passerby animation for room %d, direction = %d", roomNumber, anim.dir);
+ break;
+ }
case 1:
case 2:
@@ -646,10 +657,10 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
Sprite *camel = findSpriteByIndex(anim.spriteIndex);
anim.startX = camel->x;
anim.startY = camel->y;
- anim.dir = RIGHT;
+ anim.dir = PASSERBY_RIGHT;
anim.frameTrigger = 0x1FFF;
anim.targetZIndex = 1;
- anim.resetX = 639 + camel->w;
+ anim.resetCoord = 639 + camel->w;
anims->passerByAnims[0] = anim;
break;
@@ -661,8 +672,8 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
Sprite *camel = findSpriteByIndex(3);
anim.startX = camel->x;
anim.startY = camel->y;
- anim.dir = LEFT;
- anim.resetX = 0 - camel->w;
+ anim.dir = PASSERBY_LEFT;
+ anim.resetCoord = 0 - camel->w;
anim.targetZIndex = 1;
anims->passerByAnims[0] = anim;
@@ -677,8 +688,8 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animA.spriteIndex = 2;
animA.startX = carLeft->x;
animA.startY = carLeft->y;
- animA.dir = LEFT;
- animA.resetX = carRight->x + carRight->w - carLeft->w;
+ animA.dir = PASSERBY_LEFT;
+ animA.resetCoord = carRight->x + carRight->w - carLeft->w;
animA.targetZIndex = 100;
anims->passerByAnims[0] = animA;
@@ -686,9 +697,9 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animB.spriteIndex = 3;
animB.startX = carRight->x;
animB.startY = carRight->y;
- animB.dir = RIGHT;
+ animB.dir = PASSERBY_RIGHT;
animB.targetZIndex = 100;
- animB.resetX = 639 + carRight->w;
+ animB.resetCoord = 639 + carRight->w;
anims->passerByAnims[1] = animB;
break;
}
@@ -701,8 +712,8 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
anim.spriteIndex = 2;
anim.startX = walker->x;
anim.startY = walker->y;
- anim.dir = RIGHT;
- anim.resetX = dark->x;
+ anim.dir = PASSERBY_RIGHT;
+ anim.resetCoord = dark->x;
anim.targetZIndex = dark->zOrder + 1;
anims->passerByAnims[0] = anim;
break;
@@ -716,8 +727,8 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animA.spriteIndex = 2;
animA.startX = catRight->x;
animA.startY = catRight->y;
- animA.dir = RIGHT;
- animA.resetX = catLeft->x;
+ animA.dir = PASSERBY_RIGHT;
+ animA.resetCoord = catLeft->x;
animA.targetZIndex = blank->zOrder + 1;
anims->passerByAnims[0] = animA;
@@ -725,8 +736,8 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animB.spriteIndex = 3;
animB.startX = catLeft->x;
animB.startY = catLeft->y;
- animB.dir = LEFT;
- animB.resetX = blank->x;
+ animB.dir = PASSERBY_LEFT;
+ animB.resetCoord = blank->x;
animB.targetZIndex = blank->zOrder + 1;
anims->passerByAnims[1] = animB;
break;
@@ -741,8 +752,8 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animA.spriteIndex = 3;
animA.startX = mouseRight->x;
animA.startY = mouseRight->y;
- animA.dir = RIGHT;
- animA.resetX = mouseLeft->x;
+ animA.dir = PASSERBY_RIGHT;
+ animA.resetCoord = mouseLeft->x;
animA.targetZIndex = papers->zOrder + 1;
anims->passerByAnims[0] = animA;
@@ -750,8 +761,8 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animB.spriteIndex = 4;
animB.startX = mouseLeft->x;
animB.startY = mouseLeft->y;
- animB.dir = LEFT;
- animB.resetX = mouseRight->x;
+ animB.dir = PASSERBY_LEFT;
+ animB.resetCoord = mouseRight->x;
animB.targetZIndex = papers->zOrder + 1;
anims->passerByAnims[1] = animB;
break;
@@ -765,8 +776,8 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animA.spriteIndex = 2;
animA.startX = mummyLeft->x;
animA.startY = mummyLeft->y;
- animA.dir = LEFT;
- animA.resetX = 0 - mummyLeft->w;
+ animA.dir = PASSERBY_LEFT;
+ animA.resetCoord = 0 - mummyLeft->w;
animA.targetZIndex = 1;
anims->passerByAnims[0] = animA;
@@ -774,9 +785,9 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animB.spriteIndex = 3;
animB.startX = mummyRight->x;
animB.startY = mummyRight->y;
- animB.dir = RIGHT;
+ animB.dir = PASSERBY_RIGHT;
animB.targetZIndex = 1;
- animB.resetX = 639 + mummyRight->w;
+ animB.resetCoord = 639 + mummyRight->w;
anims->passerByAnims[1] = animB;
break;
}
@@ -868,9 +879,6 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
for (int j = 0; j < spriteChanges.size(); j++) {
if (spriteChanges[j].spriteIndex == sprite.index) {
sprite.zOrder = spriteChanges[j].zIndex;
- if (sprite.zOrder == 255) {
- sprite.isHotspotDisabled = 1;
- }
break;
}
}
@@ -981,7 +989,6 @@ uint32 RoomManager::loadDescriptions(byte *pair12data, size_t pair12size, Common
uint32_t lastDescPos = 0;
outDescriptions.clear();
while (pos < (pair12size)) {
- int desc_pos = 0;
if (pair12data[pos] == 0xFF) {
Description description;
@@ -1199,7 +1206,7 @@ byte *RoomManager::loadShadowMap(int roomNumber) {
readUntilBuda(&shadowMapFile, shadowOffset, compressed, compressedSize);
byte *shadows = nullptr;
- size_t output = rleDecompress(compressed, compressedSize, 0, 640 * 400, &shadows);
+ rleDecompress(compressed, compressedSize, 0, 640 * 400, &shadows);
free(compressed);
shadowMapFile.close();
return shadows;
@@ -1259,7 +1266,6 @@ byte RoomManager::loadMusicTrackForRoom(Common::File *roomFile, int roomOffset)
uint32_t pair9offset = roomOffset + (9 * 8);
roomFile->seek(pair9offset, SEEK_SET);
uint32_t pair9_data_offset = roomFile->readUint32LE();
- uint32_t pair9_size = roomFile->readUint32LE();
roomFile->seek(pair9_data_offset, SEEK_SET);
byte musicTrack = roomFile->readByte();
@@ -1271,7 +1277,6 @@ Common::Array<byte> RoomManager::loadRoomSfx(Common::File *roomFile, int roomOff
uint32_t pair9offset = roomOffset + (9 * 8);
roomFile->seek(pair9offset, SEEK_SET);
uint32_t pair9_data_offset = roomFile->readUint32LE();
- uint32_t pair9_size = roomFile->readUint32LE();
roomFile->seek(pair9_data_offset, SEEK_SET);
roomFile->skip(1); // skip music track byte
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index a7b861aec4c..f6022cfbca5 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -405,16 +405,16 @@ struct PaletteAnim {
byte tickCount = 0;
};
-#define RIGHT 0
-#define LEFT 1
-
+#define PASSERBY_RIGHT 0
+#define PASSERBY_LEFT 1
+#define PASSERBY_DOWN 2
struct PasserByAnim
{
uint32 frameTrigger = 0x3FF;
int16 startX;
int16 startY;
- int16 resetX;
- bool dir;
+ int16 resetCoord;
+ byte dir;
byte spriteIndex;
byte targetZIndex;
};
Commit: 8d94e680e89bde8363ba669a40c0cb5ef17879f0
https://github.com/scummvm/scummvm/commit/8d94e680e89bde8363ba669a40c0cb5ef17879f0
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:54+02:00
Commit Message:
PELROCK: Implements palette animation on statue
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 05d829c0c4e..308758d9a8a 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -413,9 +413,9 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
// TODO: Play Alfred's throwing animation
// This would require adding a new special animation entry
- // _res->loadAlfredSpecialAnim(BRICK_THROW_ANIM);
- // _alfredState.animState = ALFRED_SPECIAL_ANIM;
- // waitForSpecialAnimation();
+ _res->loadAlfredSpecialAnim(4);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
// TODO: Animate sprite 8 (brick projectile) moving to window
Sprite *brickSprite = _room->findSpriteByIndex(7);
@@ -629,13 +629,15 @@ void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
_state->setRootDisabledState(7, 0, true);
_state->setRootDisabledState(7, 1, false);
_state->setRootDisabledState(7, 2, true);
- // TODO: Palette anim
+ _alfredState.direction = ALFRED_RIGHT;
+
HotSpot *statueHotspot = _room->findHotspotByExtra(91);
_currentHotspot = statueHotspot;
-
+ walkTo(statueHotspot->x + statueHotspot->w / 2, statueHotspot->y + statueHotspot->h);
+ animateStatuePaletteFade(false);
walkAndAction(statueHotspot, TALK);
-
- // TODO: Undo palette anim!
+ waitForActionEnd();
+ animateStatuePaletteFade(true);
}
}
@@ -708,11 +710,7 @@ void PelrockEngine::pickUpBook(int i) {
walkAndAction(_room->findHotspotByExtra(102), TALK);
// After dialog ends, reenable first dialog root if no photo in inventory
// Wait for dialog to end to reenable first dialog root
- while (!shouldQuit() && _queuedAction.isQueued) {
- _events->pollEvent();
- renderScene(OVERLAY_NONE);
- _screen->update();
- }
+ waitForActionEnd();
if (!_state->hasInventoryItem(3)) {
_state->setRootDisabledState(9, 0, false);
@@ -827,4 +825,107 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
}
}
+void PelrockEngine::animateStatuePaletteFade(bool reverse) {
+ // Structure at JUEGO.EXE offset 0x4C700
+ struct StatuePaletteData {
+ uint16 x; // 368
+ uint16 y; // 148
+ uint16 type; // 2
+ uint16 padding; // 0
+ byte indices[16]; // Palette indices to modify
+ byte source[16][3]; // Source RGB values (6-bit VGA)
+ byte target[16][3]; // Target RGB values (6-bit VGA)
+ };
+
+ Common::File exeFile;
+ if (!exeFile.open("JUEGO.EXE")) {
+ warning("Could not open JUEGO.EXE for statue palette animation");
+ return;
+ }
+
+ // Read the palette data structure from JUEGO.EXE
+ exeFile.seek(0x4C700, SEEK_SET);
+
+ StatuePaletteData paletteData;
+ paletteData.x = exeFile.readUint16LE();
+ paletteData.y = exeFile.readUint16LE();
+ paletteData.type = exeFile.readUint16LE();
+ paletteData.padding = exeFile.readUint16LE();
+
+ exeFile.read(paletteData.indices, 16);
+
+ for (int i = 0; i < 16; i++) {
+ paletteData.source[i][0] = exeFile.readByte();
+ paletteData.source[i][1] = exeFile.readByte();
+ paletteData.source[i][2] = exeFile.readByte();
+ }
+
+ for (int i = 0; i < 16; i++) {
+ paletteData.target[i][0] = exeFile.readByte();
+ paletteData.target[i][1] = exeFile.readByte();
+ paletteData.target[i][2] = exeFile.readByte();
+ }
+
+ exeFile.close();
+
+ // Animation parameters
+ const int kNumFrames = 7; // 7 step updates total
+ const int kDelayMs = 200; // ~12 ticks at 60Hz (~200ms)
+
+ // Get current palette
+ byte currentPalette[768];
+ memcpy(currentPalette, _room->_roomPalette, 768);
+
+ // Perform the fade animation
+ int frame = 0;
+ while (!shouldQuit() && frame <= kNumFrames) {
+ _events->pollEvent();
+ _chrono->updateChrono();
+
+ if (_chrono->_gameTick) {
+ for (int i = 0; i < 16; i++) {
+ byte paletteIndex = paletteData.indices[i];
+
+ // Determine source and target based on direction
+ byte *srcColor = reverse ? paletteData.target[i] : paletteData.source[i];
+ byte *dstColor = reverse ? paletteData.source[i] : paletteData.target[i];
+
+ // Linear interpolation (6-bit VGA values)
+ byte r6 = srcColor[0] + ((dstColor[0] - srcColor[0]) * frame) / kNumFrames;
+ byte g6 = srcColor[1] + ((dstColor[1] - srcColor[1]) * frame) / kNumFrames;
+ byte b6 = srcColor[2] + ((dstColor[2] - srcColor[2]) * frame) / kNumFrames;
+
+ // Convert 6-bit VGA (0-63) to 8-bit (0-255) by shifting left 2 bits
+ currentPalette[paletteIndex * 3 + 0] = r6 << 2;
+ currentPalette[paletteIndex * 3 + 1] = g6 << 2;
+ currentPalette[paletteIndex * 3 + 2] = b6 << 2;
+ }
+
+ // Apply the palette
+ g_system->getPaletteManager()->setPalette(currentPalette, 0, 256);
+ // // Update the room's internal palette
+ // memcpy(_room->_roomPalette, currentPalette, 768);
+
+ // Redraw the scene with the new palette
+ copyBackgroundToBuffer();
+ placeStickersFirstPass();
+
+ chooseAlfredStateAndDraw();
+ placeStickersSecondPass();
+ presentFrame();
+
+ frame++;
+ }
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+}
+
+void PelrockEngine::waitForActionEnd() {
+ while (!shouldQuit() && _queuedAction.isQueued) {
+ _events->pollEvent();
+ renderScene(OVERLAY_NONE);
+ _screen->update();
+ }
+}
} // End of namespace Pelrock
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 1d80751bdc3..46ee8a57e47 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -481,11 +481,17 @@ struct AlfredSpecialAnimOffset {
int h = 0;
int numBudas;
int loops;
+ int numAlfred;
uint32 offset;
int stride = 0;
+ uint32 size;
- AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, uint32 off, int loops)
- : numFrames(nF), w(width), h(height), numBudas(nBudas), offset(off), loops(loops) {
+ AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, int numAlfred, uint32 off, int loops)
+ : numFrames(nF), w(width), h(height), numBudas(nBudas), numAlfred(numAlfred), offset(off), loops(loops) {
+ AlfredSpecialAnimOffset(nF, width, height, nBudas, numAlfred, off, loops, w * h * nF);
+ }
+ AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, int numAlfred, uint32 off, int loops, uint32 sz)
+ : numFrames(nF), w(width), h(height), numBudas(nBudas), numAlfred(numAlfred), offset(off), loops(loops), size(sz) {
stride = w * h;
}
AlfredSpecialAnimOffset() {
@@ -493,10 +499,11 @@ struct AlfredSpecialAnimOffset {
};
static const AlfredSpecialAnimOffset alfredSpecialAnims[] = {
- {10, 51, 102, 1, 559685, 1}, // READ BOOK
- {10, 51, 102, 1, 578943, 1}, // READ RECIPE
- {3, 45, 87, 0, 37000, 1}, // ELECTRIC SHOCK 1
- {2, 82, 58, 0, 53106, 20}, // ELECTRIC SHOCK 3
+ {10, 51, 102, 1, 7, 559685, 1}, // READ BOOK
+ {10, 51, 102, 1, 7, 578943, 1}, // READ RECIPE
+ {3, 45, 87, 0, 7, 37000, 1}, // ELECTRIC SHOCK 1
+ {2, 82, 58, 0, 7, 53106, 20}, // ELECTRIC SHOCK 3
+ {3, 71, 110, 1, 2, 20724, 1, 62480}, // Throw
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 275d622f846..c63444e1450 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -265,7 +265,6 @@ void PelrockEngine::frameTriggers() {
void PelrockEngine::passerByAnim(uint32 frameCount) {
if (_room->_passerByAnims == nullptr) {
- debug("No passerby anims for this room");
return;
}
if (_room->_passerByAnims->latch == false) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 1ec970af8d2..a8bc2d407ec 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -307,6 +307,9 @@ public:
void pickUpBook(int i);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
+
+ void animateStatuePaletteFade(bool reverse = false);
+ void waitForActionEnd();
};
extern PelrockEngine *g_engine;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 26378f0079b..1311c14fa32 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -218,39 +218,42 @@ void ResourceManager::loadAlfredAnims() {
}
void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
- AlfredSpecialAnimOffset offset = alfredSpecialAnims[numAnim];
- Common::File alfred7;
- if (!alfred7.open(Common::Path("ALFRED.7"))) {
- error("Could not open ALFRED.7");
+ AlfredSpecialAnimOffset anim = alfredSpecialAnims[numAnim];
+
+ Common::String filename = Common::String::format("ALFRED.%d", anim.numAlfred);
+ Common::File alfredFile;
+ if (!alfredFile.open(Common::Path(filename))) {
+ error("Could not open %s", filename.c_str());
return;
}
- alfred7.seek(offset.offset, SEEK_SET);
+ alfredFile.seek(anim.offset, SEEK_SET);
if (_currentSpecialAnim)
delete _currentSpecialAnim;
- _currentSpecialAnim = new AlfredSpecialAnim(offset.numFrames, offset.w, offset.h, offset.numBudas, offset.offset, offset.loops);
- _currentSpecialAnim->animData = new byte[offset.numFrames * offset.w * offset.h];
- if (offset.numBudas > 0) {
- mergeRleBlocks(&alfred7, offset.offset, offset.numBudas, _currentSpecialAnim->animData);
+ _currentSpecialAnim = new AlfredSpecialAnim(anim.numFrames, anim.w, anim.h, anim.numBudas, anim.offset, anim.loops, anim.size);
+ _currentSpecialAnim->animData = new byte[anim.size];
+ if (anim.numBudas > 0) {
+ debug("Loading special anim with budas: numBudas=%d, totalSize %d", anim.numBudas, anim.size);
+ mergeRleBlocks(&alfredFile, anim.offset, anim.numBudas, _currentSpecialAnim->animData);
} else {
- alfred7.read(_currentSpecialAnim->animData, offset.numFrames * offset.w * offset.h);
+ alfredFile.read(_currentSpecialAnim->animData, anim.numFrames * anim.w * anim.h);
}
if (reverse) {
// reverse frames for testing
- byte *reversedData = new byte[offset.numFrames * offset.w * offset.h];
- for (int i = 0; i < offset.numFrames; i++) {
+ byte *reversedData = new byte[anim.numFrames * anim.w * anim.h];
+ for (int i = 0; i < anim.numFrames; i++) {
extractSingleFrame(_currentSpecialAnim->animData,
- &reversedData[i * offset.w * offset.h],
- offset.numFrames - 1 - i,
- offset.w,
- offset.h);
+ &reversedData[i * anim.w * anim.h],
+ anim.numFrames - 1 - i,
+ anim.w,
+ anim.h);
}
delete[] _currentSpecialAnim->animData;
_currentSpecialAnim->animData = reversedData;
}
_isSpecialAnimFinished = false;
- alfred7.close();
+ alfredFile.close();
}
void ResourceManager::clearSpecialAnim() {
@@ -421,6 +424,7 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
readUntilBuda(stream, stream->pos(), thisBlock, blockSize);
uint8_t *block_data = nullptr;
size_t decompressedSize = rleDecompress(thisBlock, blockSize, 0, 640 * 400, &block_data, true);
+ debug("Decompressed block %d: %zu bytes", i, decompressedSize);
memcpy(outputBuffer + combined_size, block_data, decompressedSize);
combined_size += decompressedSize;
free(block_data);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index f6022cfbca5..f76a904613f 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -133,8 +133,9 @@ struct AlfredSpecialAnim {
uint32 stride = 0;
int curFrame = 0;
int curLoop = 0;
- AlfredSpecialAnim(int nF, int width, int height, int nBudas, uint32 off, int loopCount)
- : numFrames(nF), w(width), h(height), loopCount(loopCount) {
+ uint32 size = 0;
+ AlfredSpecialAnim(int nF, int width, int height, int nBudas, uint32 off, int loopCount, uint32 sz)
+ : numFrames(nF), w(width), h(height), loopCount(loopCount), size(sz) {
stride = w * h;
}
~AlfredSpecialAnim() {
Commit: fb9ae7561f69dfcf99367b22608580000a97e371
https://github.com/scummvm/scummvm/commit/fb9ae7561f69dfcf99367b22608580000a97e371
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:54+02:00
Commit Message:
PELROCK: Adds side effect to reading recipe
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 308758d9a8a..3f62d20b22e 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -770,6 +770,11 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
waitForSpecialAnimation();
loadExtraScreenAndPresent(3);
+ _state->setRootDisabledState(17, 0, true);
+ _state->setRootDisabledState(18, 0, true);
+ _state->setRootDisabledState(18, 1, true);
+ _state->setRootDisabledState(18, 2, true);
+ _state->setRootDisabledState(18, 3, true);
debug("After extra screen");
_dialog->say(_res->_ingameTexts[QUEASCO]);
break;
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 46ee8a57e47..b2e21f426d9 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -488,7 +488,7 @@ struct AlfredSpecialAnimOffset {
AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, int numAlfred, uint32 off, int loops)
: numFrames(nF), w(width), h(height), numBudas(nBudas), numAlfred(numAlfred), offset(off), loops(loops) {
- AlfredSpecialAnimOffset(nF, width, height, nBudas, numAlfred, off, loops, w * h * nF);
+ AlfredSpecialAnimOffset(nF, width, height, nBudas, numAlfred, off, loops, width * height * nF);
}
AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, int numAlfred, uint32 off, int loops, uint32 sz)
: numFrames(nF), w(width), h(height), numBudas(nBudas), numAlfred(numAlfred), offset(off), loops(loops), size(sz) {
@@ -498,13 +498,5 @@ struct AlfredSpecialAnimOffset {
}
};
-static const AlfredSpecialAnimOffset alfredSpecialAnims[] = {
- {10, 51, 102, 1, 7, 559685, 1}, // READ BOOK
- {10, 51, 102, 1, 7, 578943, 1}, // READ RECIPE
- {3, 45, 87, 0, 7, 37000, 1}, // ELECTRIC SHOCK 1
- {2, 82, 58, 0, 7, 53106, 20}, // ELECTRIC SHOCK 3
- {3, 71, 110, 1, 2, 20724, 1, 62480}, // Throw
-};
-
} // End of namespace Pelrock
#endif
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 1311c14fa32..8d130872258 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -33,8 +33,17 @@ ResourceManager::ResourceManager(/* args */) {
for (int i = 0; i < 4; i++) {
alfredIdle[i] = nullptr;
}
+
}
+const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
+ {10, 51, 102, 1, 7, 559685, 1, }, // READ BOOK
+ {10, 51, 102, 1, 7, 578943, 1}, // READ RECIPE
+ {3, 45, 87, 0, 7, 37000, 1}, // ELECTRIC SHOCK 1
+ {2, 82, 58, 0, 7, 53106, 20}, // ELECTRIC SHOCK 3
+ {3, 71, 110, 1, 2, 20724, 1, 62480}, // Throw
+};
+
ResourceManager::~ResourceManager() {
for (int i = 0; i < 5; i++) {
delete[] _cursorMasks[i];
@@ -231,9 +240,10 @@ void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
if (_currentSpecialAnim)
delete _currentSpecialAnim;
_currentSpecialAnim = new AlfredSpecialAnim(anim.numFrames, anim.w, anim.h, anim.numBudas, anim.offset, anim.loops, anim.size);
- _currentSpecialAnim->animData = new byte[anim.size];
+ uint32 size = anim.size == 0 ? anim.numFrames * anim.w * anim.h : anim.size;
+ _currentSpecialAnim->animData = new byte[size];
if (anim.numBudas > 0) {
- debug("Loading special anim with budas: numBudas=%d, totalSize %d", anim.numBudas, anim.size);
+ debug("Loading special anim with budas: numBudas=%d, totalSize %d", anim.numBudas, size);
mergeRleBlocks(&alfredFile, anim.offset, anim.numBudas, _currentSpecialAnim->animData);
} else {
alfredFile.read(_currentSpecialAnim->animData, anim.numFrames * anim.w * anim.h);
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 1dbda4171f4..a8d99221f92 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -75,6 +75,8 @@ public:
// Special anims
AlfredSpecialAnim *_currentSpecialAnim = nullptr;
bool _isSpecialAnimFinished = false;
+ static const AlfredSpecialAnimOffset alfredSpecialAnims[];
+
};
} // End of namespace Pelrock
Commit: a0f37b533d96e0940abac68f41c835a8a02a08bc
https://github.com/scummvm/scummvm/commit/a0f37b533d96e0940abac68f41c835a8a02a08bc
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:55+02:00
Commit Message:
PELROCK: Fixes animations in room 40
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 3f62d20b22e..9478d1f12b3 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -109,6 +109,10 @@ const ActionEntry actionTable[] = {
{393, OPEN, &PelrockEngine::openNewspaperBossDor},
{393, CLOSE, &PelrockEngine::closeNewspaperBossDoor},
+ // Room 19
+ {400, OPEN, &PelrockEngine::openTravelAgencyDoor},
+ {400, CLOSE, &PelrockEngine::closeTravelAgencyDoor},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -131,7 +135,7 @@ const CombinationEntry combinationTable[] = {
{1, 53, &PelrockEngine::giveIdToGuard},
{5, 53, &PelrockEngine::giveMoneyToGuard},
{7, 353, &PelrockEngine::useAmuletWithStatue},
- {8, 102, &PelrockEngine::giveFormulaToLibrarian},
+ {8, 102, &PelrockEngine::giveSecretCodeToLibrarian},
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -252,6 +256,16 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_room->addWalkbox(w1);
_room->addWalkbox(w2);
+ case 274:
+ case 275:
+ case 276:
+ _state->setRootDisabledState(room, rootIndex, true);
+ break;
+ case 277:
+ _state->setRootDisabledState(room, rootIndex, true);
+ _state->setFlag(FLAG_JEFE_INGRESA_PASTA, true);
+
+ break;
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
@@ -674,7 +688,7 @@ void PelrockEngine::pickBooksFromShelf3(HotSpot *hotspot) {
pickUpBook(3);
}
-void PelrockEngine::giveFormulaToLibrarian(int inventoryObject, HotSpot *hotspot) {
+void PelrockEngine::giveSecretCodeToLibrarian(int inventoryObject, HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[REGALO_LIBRO_RECETAS]);
_state->removeInventoryItem(8);
addInventoryItem(59);
@@ -696,6 +710,22 @@ void PelrockEngine::closeNewspaperBossDoor(HotSpot *hotspot) {
closeDoor(hotspot, 1, 52, MASCULINE, true);
}
+void PelrockEngine::openTravelAgencyDoor(HotSpot *hotspot) {
+ // In order to unlock the second part of the game, we need to ensure
+ // we have all we need to solve the game once there
+ if(
+ _state->hasInventoryItem(17) &&
+ _state->hasInventoryItem(59)
+ ) {
+ openDoor(hotspot, 0, 55, FEMININE, false);
+ }
+ // The game originally did nothing here
+}
+
+void PelrockEngine::closeTravelAgencyDoor(HotSpot *hotspot) {
+ closeDoor(hotspot, 0, 55, FEMININE, false);
+}
+
void PelrockEngine::pickUpBook(int i) {
if (!_state->hasInventoryItem(10)) {
_dialog->say(_res->_ingameTexts[VENGA_ACA]);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index a8bc2d407ec..45851f7c2e8 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -299,11 +299,13 @@ public:
void pickBooksFromShelf1(HotSpot *hotspot);
void pickBooksFromShelf2(HotSpot *hotspot);
void pickBooksFromShelf3(HotSpot *hotspot);
- void giveFormulaToLibrarian(int inventoryObject, HotSpot *hotspot);
+ void giveSecretCodeToLibrarian(int inventoryObject, HotSpot *hotspot);
void openNewspaperDoor(HotSpot *hotspot);
void closeNewspaperDoor(HotSpot *hotspot);
void openNewspaperBossDor(HotSpot *hotspot);
void closeNewspaperBossDoor(HotSpot *hotspot);
+ void openTravelAgencyDoor(HotSpot *hotspot);
+ void closeTravelAgencyDoor(HotSpot *hotspot);
void pickUpBook(int i);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 473bd24fb27..3504f3cac47 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -846,8 +846,18 @@ void RoomManager::loadAnimationPixelData(Common::File *roomFile, int roomOffset,
roomFile->seek(offset, SEEK_SET);
roomFile->read(pixelData, size);
if (offset > 0 && size > 0) {
- outSize = rleDecompress(pixelData, size, 0, size, &buffer, true);
+ if(_currentRoomNumber != 40) {
+ outSize = rleDecompress(pixelData, size, 0, size, &buffer, true);
+ }
+ else {
+ // room 40 has uncompressed animation data for some reason
+ buffer = new byte[size];
+ Common::copy(pixelData, pixelData + size, buffer);
+ outSize = size;
+ }
}
+
+
}
Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size) {
Commit: 6480e47ea4199bbb868561e965ddbdfa46c953cf
https://github.com/scummvm/scummvm/commit/6480e47ea4199bbb868561e965ddbdfa46c953cf
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:55+02:00
Commit Message:
PELROCK: Implements water reflection effect
Changed paths:
engines/pelrock/graphics.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 59a540cf077..15801ddd60f 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -38,7 +38,7 @@ Common::Point GraphicsManager::showOverlay(int height, byte *buf) {
for (int x = 0; x < 640; x++) {
for (int y = overlayY; y < 400; y++) {
int index = y * 640 + x;
- buf[index] = g_engine->_room->paletteRemaps[0][buf[index]];
+ buf[index] = g_engine->_room->_paletteRemaps[0][buf[index]];
}
}
return Common::Point(overlayX, overlayY);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index c63444e1450..e2127b6cf78 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -154,7 +154,7 @@ void PelrockEngine::init() {
loadAnims();
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
- setScreen(7, ALFRED_DOWN);
+ setScreen(25, ALFRED_DOWN);
// setScreen(9, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
@@ -326,6 +326,28 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
}
}
+void PelrockEngine::reflectionEffect(byte *buf, int x, int y, int width, int height) {
+ // Water reflection - draws mirrored sprite on water pixels
+ // Only sprite pixels 0-15 are reflected (checked via pixel & 0xF0 == 0)
+ for (int row = 0; row < height; row++) {
+ int reflectY = y + row;
+
+ if (reflectY >= 400)
+ break; // Screen boundary
+
+ for (int col = 0; col < width; col++) {
+ byte pixel = buf[(height - 1 - row) * width + col]; // Read from bottom up for mirror
+ // Only reflect pixels 0-15 (high nibble must be 0)
+ if (pixel != 255 && (pixel & 0xF0) == 0) {
+ byte bgPixel = _compositeBuffer[reflectY * 640 + x + col];
+ if (bgPixel >= 223 && bgPixel < 228) { // Is water (0xDF-0xE3)
+ _compositeBuffer[reflectY * 640 + x + col] = _room->_paletteRemaps[4][pixel];
+ }
+ }
+ }
+ }
+}
+
void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
debug("Executing action %d on hotspot %d", action, hotspot->extra);
if (action == ITEM) {
@@ -839,36 +861,12 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
break;
}
}
- // // This if is needed to draw Alfred when idle, when the switch case results in a state change
- // if (_alfredState.animState == ALFRED_IDLE) {
- // drawAlfred(_res->alfredIdle[_alfredState.direction]);
- // }
}
-/**
- * Scales and shades alfred sprite and draws it to the composite buffer
- */
-void PelrockEngine::drawAlfred(byte *buf) {
-
- ScaleCalculation scale = calculateScaling(_alfredState.y, _room->_scaleParams);
-
- // Update Alfred's scale state for use by other functions
- _alfredState.scaledX = scale.scaleX;
- _alfredState.scaledY = scale.scaleY;
-
- // Use the pre-calculated scaled dimensions from calculateScaling
- int finalHeight = scale.scaledHeight;
- int finalWidth = scale.scaledWidth;
-
- if (finalHeight <= 0) {
- finalHeight = 1;
- }
- if (finalWidth <= 0) {
- finalWidth = 1;
- }
+byte *PelrockEngine::scale(int scaleY, int finalWidth, int finalHeight, byte *buf) {
// The scaling table is indexed by how many scanlines to skip (scaleY), not by final height
- int scaleIndex = scale.scaleY;
+ int scaleIndex = scaleY;
if (scaleIndex >= (int)_heightScalingTable.size()) {
scaleIndex = _heightScalingTable.size() - 1;
}
@@ -877,8 +875,6 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
int linesToSkip = kAlfredFrameHeight - finalHeight;
- int shadowPos = _alfredState.y; // - finalHeight;
- bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + _alfredState.x] != 0xFF;
byte *finalBuf = new byte[finalWidth * finalHeight];
@@ -948,16 +944,52 @@ void PelrockEngine::drawAlfred(byte *buf) {
} else {
Common::copy(buf, buf + (kAlfredFrameWidth * kAlfredFrameHeight), finalBuf);
}
+ return finalBuf;
+}
+
+/**
+ * Scales and shades alfred sprite and draws it to the composite buffer
+ */
+void PelrockEngine::drawAlfred(byte *buf) {
+
+ ScaleCalculation scaleCalc = calculateScaling(_alfredState.y, _room->_scaleParams);
+
+ // Update Alfred's scale state for use by other functions
+ _alfredState.scaledX = scaleCalc.scaleX;
+ _alfredState.scaledY = scaleCalc.scaleY;
+
+ // Use the pre-calculated scaled dimensions from calculateScaling
+ int finalHeight = scaleCalc.scaledHeight;
+ int finalWidth = scaleCalc.scaledWidth;
+
+ if (finalHeight <= 0) {
+ finalHeight = 1;
+ }
+ if (finalWidth <= 0) {
+ finalWidth = 1;
+ }
+ byte *finalBuf = scale(scaleCalc.scaleY, finalWidth, finalHeight, buf);
+
+ int shadowPos = _alfredState.y; // - finalHeight;
+ bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + _alfredState.x] != 0xFF;
if (shadeCharacter) {
for (int i = 0; i < finalWidth * finalHeight; i++) {
if (finalBuf[i] != 255) {
- finalBuf[i] = _room->paletteRemaps[1][finalBuf[i]];
+ finalBuf[i] = _room->_paletteRemaps[1][finalBuf[i]];
}
}
}
drawSpriteToBuffer(_compositeBuffer, 640, finalBuf, _alfredState.x, _alfredState.y - finalHeight, finalWidth, finalHeight, 255);
+
+ // Water reflection (rooms 25 and 45 only)
+ if (_room->_currentRoomNumber == 25 || _room->_currentRoomNumber == 45) {
+ // Offset from Alfred's feet to start of reflection
+ int yOffset = (_room->_currentRoomNumber == 45) ? 25 : 13;
+ reflectionEffect(finalBuf, _alfredState.x, _alfredState.y + yOffset, finalWidth, finalHeight);
+ }
+
delete[] finalBuf;
}
@@ -1000,7 +1032,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
return;
}
- if(_room->_currentRoomNumber == 9 && sprite->index == 2) {
+ if (_room->_currentRoomNumber == 9 && sprite->index == 2) {
debug("Drawing sprite 2 in room 9, anim %d, frame %d/%d, loop %d/%d", sprite->curAnimIndex, animData.curFrame, animData.nframes, animData.curLoop, animData.loopCount);
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 45851f7c2e8..776569da328 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -102,6 +102,7 @@ private:
void lookAt(HotSpot *hotspot);
void chooseAlfredStateAndDraw();
+ byte *scale(int scaleY, int finalWidth, int finalHeight, byte *buf);
void drawAlfred(byte *buf);
void drawNextFrame(Sprite *animSet);
void animateTalkingNPC(Sprite *animSet);
@@ -231,7 +232,7 @@ public:
void frameTriggers();
void passerByAnim(uint32 frameCount);
-
+ void reflectionEffect(byte *buf, int x, int y, int width, int height);
void changeCursor(Cursor cursor);
// Actions
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 3504f3cac47..7e73944bc46 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -30,6 +30,7 @@ namespace Pelrock {
RoomManager::RoomManager() {
_pixelsShadows = new byte[640 * 400];
_roomNames = loadRoomNames();
+ loadWaterPaletteRemap();
}
RoomManager::~RoomManager() {
@@ -40,6 +41,17 @@ RoomManager::~RoomManager() {
delete[] _resetData;
}
+void RoomManager::loadWaterPaletteRemap() {
+ //Extra remap for water effect
+ Common::File exe;
+ if(!exe.open("JUEGO.EXE")) {
+ error("Couldnt find file JUEGO.EXE");
+ }
+ exe.seek(0x4C77C, SEEK_SET);
+ exe.read(_paletteRemaps[4], 256);
+ exe.close();
+}
+
void RoomManager::getPalette(Common::File *roomFile, int roomOffset, byte *palette) {
// get palette
int paletteOffset = roomOffset + (11 * 8);
@@ -1232,11 +1244,12 @@ void RoomManager::loadRemaps(int roomNumber) {
uint32 remapOffset = 0x200 + (roomNumber * 1024);
remapFile.seek(remapOffset, SEEK_SET);
- remapFile.read(paletteRemaps[0], 256);
- remapFile.read(paletteRemaps[1], 256);
- remapFile.read(paletteRemaps[2], 256);
- remapFile.read(paletteRemaps[3], 256);
+ remapFile.read(_paletteRemaps[0], 256);
+ remapFile.read(_paletteRemaps[1], 256);
+ remapFile.read(_paletteRemaps[2], 256);
+ remapFile.read(_paletteRemaps[3], 256);
remapFile.close();
+
}
Common::StringArray RoomManager::loadRoomNames() {
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 0ae126f14eb..16fc12d2b86 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -66,6 +66,7 @@ public:
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
void getBackground(Common::File *roomFile, int roomOffset, byte *background);
+ void loadWaterPaletteRemap();
/** Methods to modify room data at runtime **/
void addSticker(int stickerId, int persist = PERSIST_BOTH);
@@ -147,7 +148,7 @@ public:
ScalingParams _scaleParams;
byte *_pixelsShadows = nullptr;
byte _roomPalette[768];
- byte paletteRemaps[4][256];
+ byte _paletteRemaps[5][256];
byte _musicTrack = 0;
Common::Array<byte> _roomSfx;
PaletteAnim *_currentPaletteAnim = nullptr;
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index e4c5aa39f10..29089cf6677 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -26,6 +26,7 @@
#include "pelrock/pelrock.h"
#include "pelrock/types.h"
#include "pelrock/util.h"
+#include "util.h"
namespace Pelrock {
@@ -338,4 +339,18 @@ Common::StringArray arrayOf(Common::String str) {
return Common::StringArray(1, str);
}
+
+void invertSprite(byte *spriteBuf, int w, int h) {
+ // invert horizontal lines so character is upside down
+ for (int y = 0; y < h / 2; y++) {
+ for (int x = 0; x < w; x++) {
+ int topIndex = y * w + x;
+ int bottomIndex = (h - 1 - y) * w + x;
+ byte temp = spriteBuf[topIndex];
+ spriteBuf[topIndex] = spriteBuf[bottomIndex];
+ spriteBuf[bottomIndex] = temp;
+ }
+ }
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 9af486dbe51..3b416b754b1 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -47,6 +47,7 @@ void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
byte decodeChar(byte b);
void changeGameSpeed(Common::Event e);
Common::StringArray arrayOf(Common::String str);
+void invertSprite(byte *data, int w, int h);
static const int special_chars[] = {
168, // inverted ?
Commit: ea33ffd9674e161648c2bc9e26205eae05c8724c
https://github.com/scummvm/scummvm/commit/ea33ffd9674e161648c2bc9e26205eae05c8724c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:55+02:00
Commit Message:
PELROCK: Restrict reflection effect to y position
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index e2127b6cf78..5d4d74d70b8 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -327,6 +327,30 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
}
void PelrockEngine::reflectionEffect(byte *buf, int x, int y, int width, int height) {
+
+
+ // ScaleCalculation scaleCalc = calculateScaling(y + 50, _room->_scaleParams);
+
+ // // Update Alfred's scale state for use by other functions
+ // _alfredState.scaledX = scaleCalc.scaleX;
+ // _alfredState.scaledY = scaleCalc.scaleY;
+
+ // // Use the pre-calculated scaled dimensions from calculateScaling
+ // int finalHeight = scaleCalc.scaledHeight;
+ // int finalWidth = scaleCalc.scaledWidth;
+
+ // if (finalHeight <= 0) {
+ // finalHeight = 1;
+ // }
+ // if (finalWidth <= 0) {
+ // finalWidth = 1;
+ // }
+
+ // byte *finalBuf = scale(scaleCalc.scaleY, finalWidth, finalHeight, buf);
+ // height = finalHeight;
+ // width = finalWidth;
+
+
// Water reflection - draws mirrored sprite on water pixels
// Only sprite pixels 0-15 are reflected (checked via pixel & 0xF0 == 0)
for (int row = 0; row < height; row++) {
@@ -336,6 +360,7 @@ void PelrockEngine::reflectionEffect(byte *buf, int x, int y, int width, int hei
break; // Screen boundary
for (int col = 0; col < width; col++) {
+ // byte pixel = finalBuf[(height - 1 - row) * width + col]; // Read from bottom up for mirror
byte pixel = buf[(height - 1 - row) * width + col]; // Read from bottom up for mirror
// Only reflect pixels 0-15 (high nibble must be 0)
if (pixel != 255 && (pixel & 0xF0) == 0) {
@@ -984,7 +1009,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
drawSpriteToBuffer(_compositeBuffer, 640, finalBuf, _alfredState.x, _alfredState.y - finalHeight, finalWidth, finalHeight, 255);
// Water reflection (rooms 25 and 45 only)
- if (_room->_currentRoomNumber == 25 || _room->_currentRoomNumber == 45) {
+ if ((_room->_currentRoomNumber == 25 || _room->_currentRoomNumber == 45) && _alfredState.y >= 299) {
// Offset from Alfred's feet to start of reflection
int yOffset = (_room->_currentRoomNumber == 45) ? 25 : 13;
reflectionEffect(finalBuf, _alfredState.x, _alfredState.y + yOffset, finalWidth, finalHeight);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 776569da328..972769c9a55 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -102,7 +102,6 @@ private:
void lookAt(HotSpot *hotspot);
void chooseAlfredStateAndDraw();
- byte *scale(int scaleY, int finalWidth, int finalHeight, byte *buf);
void drawAlfred(byte *buf);
void drawNextFrame(Sprite *animSet);
void animateTalkingNPC(Sprite *animSet);
@@ -121,6 +120,7 @@ private:
void calculateScalingMasks();
ScaleCalculation calculateScaling(int yPos, ScalingParams scalingParams);
+ byte *scale(int scaleY, int finalWidth, int finalHeight, byte *buf);
Common::Array<Common::Array<int>> _widthScalingTable;
Common::Array<Common::Array<int>> _heightScalingTable;
Commit: 2a510cdcec4578942d5ee0d7d0b403cded0343d2
https://github.com/scummvm/scummvm/commit/2a510cdcec4578942d5ee0d7d0b403cded0343d2
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:56+02:00
Commit Message:
PELROCK: Disable branches in travel agency
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 9478d1f12b3..f5fd30a5f3f 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -178,6 +178,8 @@ void PelrockEngine::addInventoryItem(int item) {
g_system->delayMillis(10);
}
_state->addInventoryItem(item);
+
+ checkObjectsForPart2();
}
void PelrockEngine::buyFromStore(HotSpot *hotspot, int stickerId) {
@@ -264,7 +266,9 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 277:
_state->setRootDisabledState(room, rootIndex, true);
_state->setFlag(FLAG_JEFE_INGRESA_PASTA, true);
-
+ break;
+ case 278:
+ _state->setRootDisabledState(room, rootIndex, true);
break;
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
@@ -711,19 +715,15 @@ void PelrockEngine::closeNewspaperBossDoor(HotSpot *hotspot) {
}
void PelrockEngine::openTravelAgencyDoor(HotSpot *hotspot) {
- // In order to unlock the second part of the game, we need to ensure
- // we have all we need to solve the game once there
- if(
- _state->hasInventoryItem(17) &&
- _state->hasInventoryItem(59)
- ) {
- openDoor(hotspot, 0, 55, FEMININE, false);
+
+ if(_state->getFlag(FLAG_AGENCIA_ABIERTA)) {
+ openDoor(hotspot, 1, 57, FEMININE, false);
}
// The game originally did nothing here
}
void PelrockEngine::closeTravelAgencyDoor(HotSpot *hotspot) {
- closeDoor(hotspot, 0, 55, FEMININE, false);
+ closeDoor(hotspot, 1, 57, FEMININE, false);
}
void PelrockEngine::pickUpBook(int i) {
@@ -765,6 +765,7 @@ void PelrockEngine::pickUpBook(int i) {
_state->selectedBookIndex = -1;
}
}
+
}
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
@@ -915,9 +916,10 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
int frame = 0;
while (!shouldQuit() && frame <= kNumFrames) {
_events->pollEvent();
- _chrono->updateChrono();
- if (_chrono->_gameTick) {
+ bool didRender = renderScene(OVERLAY_NONE);
+ if(didRender) {
+
for (int i = 0; i < 16; i++) {
byte paletteIndex = paletteData.indices[i];
@@ -938,23 +940,30 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
// Apply the palette
g_system->getPaletteManager()->setPalette(currentPalette, 0, 256);
- // // Update the room's internal palette
- // memcpy(_room->_roomPalette, currentPalette, 768);
-
- // Redraw the scene with the new palette
- copyBackgroundToBuffer();
- placeStickersFirstPass();
-
- chooseAlfredStateAndDraw();
- placeStickersSecondPass();
- presentFrame();
-
frame++;
}
_screen->update();
g_system->delayMillis(10);
}
}
+/**
+ * In order to unlock the second part of the game, we need to ensure
+ * we have all we need to solve the game once there
+ */
+void PelrockEngine::checkObjectsForPart2() {
+ if (_state->hasInventoryItem(17) &&
+ _state->hasInventoryItem(59) &&
+ _state->hasInventoryItem(24)
+ ) {
+ _room->addStickerToRoom(19, 54, PERSIST_BOTH);
+ _room->addStickerToRoom(19, 55, PERSIST_BOTH);
+ _room->addStickerToRoom(19, 56, PERSIST_BOTH);
+ _room->addStickerToRoom(19, 58, PERSIST_BOTH);
+ _state->setFlag(FLAG_AGENCIA_ABIERTA, true);
+ // _state->setFlag(FLAG_PUEDE_VIAJAR_EN_EL_TIEMPO, true);
+ // _state->setRootDisabledState(19, 0, true);
+ }
+}
void PelrockEngine::waitForActionEnd() {
while (!shouldQuit() && _queuedAction.isQueued) {
@@ -963,4 +972,7 @@ void PelrockEngine::waitForActionEnd() {
_screen->update();
}
}
+
+// void checkOBjec
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index a7a01679c8c..0dff4c54566 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -54,7 +54,8 @@ bool PelrockConsole::cmdGiveItems(int argc, const char **argv) {
for (int i = 1; i < argc; i++) {
int itemId = atoi(argv[i]);
bool markAsSelected = g_engine->_state->inventoryItems.empty();
- g_engine->_state->addInventoryItem(itemId);
+ g_engine->addInventoryItem(itemId);
+ // g_engine->_state->addInventoryItem(itemId);
if (markAsSelected)
g_engine->_state->selectedInventoryItem = itemId;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 972769c9a55..2b5d1b1ff96 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -312,6 +312,7 @@ public:
void closeMcDoor(HotSpot *hotspot);
void animateStatuePaletteFade(bool reverse = false);
+ void checkObjectsForPart2();
void waitForActionEnd();
};
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index f76a904613f..b9b3ac14b97 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -504,8 +504,9 @@ struct ResetEntry {
#define FLAG_INGREDIENTES_CONSEGUIDOS 48
#define FLAG_GUARDIA_PIDECOSAS 49
#define FLAG_GUARDIA_DNI_ENTREGADO 50
+#define FLAG_AGENCIA_ABIERTA 51
-const int kNumGameFlags = 51;
+const int kNumGameFlags = 52;
struct GameStateData {
byte flags[kNumGameFlags];
Commit: 7002cdd213a03fe7687ca2db9892f0f0e58b7de3
https://github.com/scummvm/scummvm/commit/7002cdd213a03fe7687ca2db9892f0f0e58b7de3
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:56+02:00
Commit Message:
PELROCK: Map animation
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.cpp
engines/pelrock/console.h
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/sound.cpp
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index f5fd30a5f3f..80838b59cb2 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -270,6 +270,9 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 278:
_state->setRootDisabledState(room, rootIndex, true);
break;
+ case 279:
+ travelToEgypt();
+ break;
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
@@ -339,6 +342,8 @@ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
if (_state->getFlag(FLAG_JEFE_INGRESA_PASTA)) {
_state->setFlag(FLAG_JEFE_INGRESA_PASTA, false);
addInventoryItem(75);
+ _state->setRootDisabledState(20, 0, true);
+ _state->setRootDisabledState(20, 1, true);
} else {
int billCount = 0;
for (uint i = 0; i < _state->inventoryItems.size(); i++) {
@@ -788,6 +793,15 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
// loadExtraScreenAndPresent(9);
_state->stateGame = COMPUTER;
break;
+ case 145:
+ _dialog->say(_res->_ingameTexts[NOVIO2METROS]);
+ break;
+ case 281:
+ _dialog->say(_res->_ingameTexts[GRANIDEA]);
+ break;
+ case 282:
+ _dialog->say(_res->_ingameTexts[SELORECOMIENDO]);
+ break;
}
}
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index 0dff4c54566..11a1f24031d 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -29,11 +29,38 @@ namespace Pelrock {
PelrockConsole::PelrockConsole(PelrockEngine *engine) : GUI::Debugger(), _engine(engine) {
registerCmd("room", WRAP_METHOD(PelrockConsole, cmdLoadRoom));
registerCmd("give", WRAP_METHOD(PelrockConsole, cmdGiveItems));
+ registerCmd("disableRoot", WRAP_METHOD(PelrockConsole, disableRoot));
+ registerCmd("setFlag", WRAP_METHOD(PelrockConsole, setFlag));
}
PelrockConsole::~PelrockConsole() {
}
+
+bool PelrockConsole::setFlag(int argc, const char **argv) {
+ if (argc < 3) {
+ debugPrintf("Usage: setFlag <flagIndex> <value>");
+ return true;
+ }
+ int flagIndex = atoi(argv[1]);
+ int value = atoi(argv[2]);
+ _engine->_state->setFlag(flagIndex, value);
+ debugPrintf("Set flag %d to %d\n", flagIndex, value);
+ return true;
+}
+
+bool PelrockConsole::disableRoot(int argc, const char **argv) {
+ if (argc < 3) {
+ debugPrintf("Usage: disableRoot <roomNumber> <rootIndex>");
+ return true;
+ }
+ int roomNumber = atoi(argv[1]);
+ int rootIndex = atoi(argv[2]);
+ _engine->_state->setRootDisabledState(roomNumber, rootIndex, true);
+ debugPrintf("Disabled root %d in room %d\n", rootIndex, roomNumber);
+ return true;
+}
+
bool PelrockConsole::cmdLoadRoom(int argc, const char **argv) {
if (argc < 2) {
debugPrintf("Usage: room <roomNumber>");
diff --git a/engines/pelrock/console.h b/engines/pelrock/console.h
index 41b007da25c..f8728363680 100644
--- a/engines/pelrock/console.h
+++ b/engines/pelrock/console.h
@@ -34,6 +34,8 @@ private:
bool cmdLoadRoom(int argc, const char **argv);
bool cmdGiveItems(int argc, const char **argv);
bool cmdTest(int argc, const char **argv);
+ bool disableRoot(int argc, const char **argv);
+ bool setFlag(int argc, const char **argv);
public:
PelrockConsole(PelrockEngine *engine);
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index b2e21f426d9..a187a70ebf4 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -461,7 +461,7 @@ const ExtraImages extraScreens[] = {
{0x9237B, // tablet
0xB0EE7,
8},
- {0xB11ED, // map
+ {0x000B11F1, // map
0xDE011,
8},
{0xFFC47, // girl book
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 5d4d74d70b8..80b61729915 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -231,6 +231,48 @@ void PelrockEngine::playSoundIfNeeded() {
}
}
+void PelrockEngine::travelToEgypt() {
+ _sound->playMusicTrack(26, false);
+ byte *palette = new byte[768];
+ if (_extraScreen == nullptr) {
+ _extraScreen = new byte[640 * 400];
+ }
+ _res->getExtraScreen(6, _extraScreen, palette);
+ CursorMan.showMouse(false);
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+
+ memcpy(_screen->getPixels(), _extraScreen, 640 * 400);
+ int frameCount = 0;
+ while (!shouldQuit() && frameCount < 96) {
+ _events->pollEvent();
+ g_system->delayMillis(10);
+ _chrono->updateChrono();
+ if(_chrono->_gameTick && _chrono->getFrameCount() % 2 == 0) {
+ int colorIndex = 160 + frameCount;
+ int index = colorIndex * 3;
+ palette[index] = 255; // Red
+ palette[index + 1] = 0; // Green
+ palette[index + 2] = 0; // Blue
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+ frameCount++;
+ }
+ drawPaletteSquares((byte *)_screen->getPixels(), palette);
+
+ _screen->markAllDirty();
+ _screen->update();
+ }
+
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+ free(_extraScreen);
+ _extraScreen = nullptr;
+ CursorMan.showMouse(true);
+ delete[] _extraScreen;
+ delete[] palette;
+ _screen->markAllDirty();
+ _screen->update();
+
+}
+
bool PelrockEngine::renderScene(int overlayMode) {
_chrono->updateChrono();
@@ -1399,6 +1441,9 @@ void PelrockEngine::gameLoop() {
_events->pollEvent();
checkMouse();
+ if(_events->_lastKeyEvent == Common::KeyCode::KEYCODE_m) {
+ travelToEgypt();
+ }
renderScene();
// _events->waitForKey();
_screen->update();
@@ -1678,6 +1723,7 @@ void PelrockEngine::setScreen(int roomNumber, AlfredDirection dir) {
}
void PelrockEngine::loadExtraScreenAndPresent(int screenIndex) {
+
byte *palette = new byte[768];
if (_extraScreen == nullptr) {
_extraScreen = new byte[640 * 400];
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 2b5d1b1ff96..1a6232cc55a 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -109,6 +109,7 @@ private:
void playSoundIfNeeded();
+
void gameLoop();
void computerLoop();
void extraScreenLoop();
@@ -235,6 +236,8 @@ public:
void reflectionEffect(byte *buf, int x, int y, int width, int height);
void changeCursor(Cursor cursor);
+ void travelToEgypt();
+
// Actions
void doExtraActions(int roomNumber);
void addInventoryItem(int item);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 8d130872258..bc17308f07e 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -434,9 +434,14 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
readUntilBuda(stream, stream->pos(), thisBlock, blockSize);
uint8_t *block_data = nullptr;
size_t decompressedSize = rleDecompress(thisBlock, blockSize, 0, 640 * 400, &block_data, true);
- debug("Decompressed block %d: %zu bytes", i, decompressedSize);
+ debug("Decompressed block %d: %zu bytes, total %zu", i, decompressedSize, combined_size + decompressedSize);
+ if (combined_size + decompressedSize > 640 * 400) {
+ debug("Warning: decompressed data exceeds output buffer size, truncating");
+ decompressedSize = 640 * 400 - combined_size;
+ }
memcpy(outputBuffer + combined_size, block_data, decompressedSize);
combined_size += decompressedSize;
+
free(block_data);
free(thisBlock);
}
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 98f57125cc9..b94f925b14f 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -213,7 +213,7 @@ void SoundManager::playMusicTrack(int trackNumber, bool loop) {
}
_currentMusicTrack = trackNumber;
g_system->getAudioCDManager()->stop();
- // g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 0, 0, 0);
+ g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 1, 0, 0);
}
void SoundManager::loadSoundIndex() {
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 29089cf6677..6eb82d4f66c 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -165,7 +165,9 @@ size_t rleDecompress(
} else {
// In fixed mode, we've hit the limit - something is wrong
// but grow minimally to avoid crash
- bufferCapacity += 256;
+ // bufferCapacity += 256;
+ break;
+
}
uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
if (!newBuf) {
@@ -353,4 +355,35 @@ void invertSprite(byte *spriteBuf, int w, int h) {
}
}
+void drawPaletteSquares(byte *screenBuffer, byte *palette) {
+ // Draw 3x3 squares for all 256 palette colors
+ // Arrange them in a 16x16 grid (256 colors)
+ const int squareSize = 6;
+ const int colorsPerRow = 16;
+ const int startX = 10; // Left margin
+ const int startY = 10; // Top margin
+ const int spacing = 1; // Space between squares
+
+ for (int colorIndex = 0; colorIndex < 256; colorIndex++) {
+ int row = colorIndex / colorsPerRow;
+ int col = colorIndex % colorsPerRow;
+
+ int x = startX + col * (squareSize + spacing);
+ int y = startY + row * (squareSize + spacing);
+
+ // Draw the 3x3 square with the current color
+ for (int py = 0; py < squareSize; py++) {
+ for (int px = 0; px < squareSize; px++) {
+ int destX = x + px;
+ int destY = y + py;
+
+ // Bounds check
+ if (destX >= 0 && destX < 640 && destY >= 0 && destY < 400) {
+ screenBuffer[destY * 640 + destX] = colorIndex;
+ }
+ }
+ }
+ }
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 3b416b754b1..3425c7ef455 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -48,6 +48,7 @@ byte decodeChar(byte b);
void changeGameSpeed(Common::Event e);
Common::StringArray arrayOf(Common::String str);
void invertSprite(byte *data, int w, int h);
+void drawPaletteSquares(byte *screenBuffer, byte *palette);
static const int special_chars[] = {
168, // inverted ?
Commit: 73d9d97fb97626d6b88110e3e0533b71bf090676
https://github.com/scummvm/scummvm/commit/73d9d97fb97626d6b88110e3e0533b71bf090676
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:56+02:00
Commit Message:
PELROCK: Fix walking algorithm so it doesnt exit the room when interacting with doors
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 80b61729915..cd84c318264 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -839,21 +839,23 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
break;
}
_alfredState.setState(ALFRED_INTERACTING);
+ // Don't check exits when there's a queued action - action executes first
+ break;
+ }
+
+ // Only check exits after walking is complete AND no queued action
+ Exit *exit = isExitUnder(_alfredState.x, _alfredState.y);
+ if (exit != nullptr) {
+ debug("Using exit to room %d", exit->targetRoom);
+ _alfredState.x = exit->targetX;
+ _alfredState.y = exit->targetY;
+ setScreen(exit->targetRoom, exit->dir);
}
}
} else {
_currentContext.movementBuffer[_currentStep] = step;
}
- Exit *exit = isExitUnder(_alfredState.x, _alfredState.y);
-
- if (exit != nullptr /*&& exit->isEnabled*/) {
- debug("Using exit to room %d", exit->targetRoom);
- _alfredState.x = exit->targetX;
- _alfredState.y = exit->targetY;
- setScreen(exit->targetRoom, exit->dir);
- }
-
if (_alfredState.curFrame >= walkingAnimLengths[_alfredState.direction]) {
_alfredState.curFrame = 0;
}
@@ -1336,8 +1338,9 @@ int PelrockEngine::isHotspotUnder(int x, int y) {
Exit *PelrockEngine::isExitUnder(int x, int y) {
for (uint i = 0; i < _room->_currentRoomExits.size(); i++) {
Exit exit = _room->_currentRoomExits[i];
- if (x >= exit.x && x <= (exit.x + exit.w) &&
- y >= exit.y && y <= (exit.y + exit.h) && exit.isEnabled) {
+ // Original game uses: x <= exit.x + exit.w - 1 and y <= exit.y + exit.h - 1
+ if (x >= exit.x && x <= (exit.x + exit.w - 1) &&
+ y >= exit.y && y <= (exit.y + exit.h - 1) && exit.isEnabled) {
return &(_room->_currentRoomExits[i]);
}
}
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index b94f925b14f..55f0edf0a55 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -38,7 +38,7 @@
namespace Pelrock {
SoundManager::SoundManager(Audio::Mixer *mixer)
- : _mixer(mixer), _currentVolume(255), _musicFile(nullptr) {
+ : _mixer(mixer), _currentVolume(128), _musicFile(nullptr) {
// TODO: Initialize sound manager
g_system->getAudioCDManager()->open();
}
@@ -213,7 +213,7 @@ void SoundManager::playMusicTrack(int trackNumber, bool loop) {
}
_currentMusicTrack = trackNumber;
g_system->getAudioCDManager()->stop();
- g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 1, 0, 0);
+ // g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 0, 0, 0);
}
void SoundManager::loadSoundIndex() {
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 5f0f90c895e..604773622ab 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -158,8 +158,8 @@ class SoundManager {
public:
SoundManager(Audio::Mixer *mixer);
~SoundManager();
- void playSound(byte index, int volume = 255, int channel = -1);
- void playSound(byte *soundData, uint32 size, int volume = 255);
+ void playSound(byte index, int volume = 128, int channel = -1);
+ void playSound(byte *soundData, uint32 size, int volume = 128);
void stopAllSounds();
void stopSound(int channel);
void stopMusic();
Commit: 14dfa22ef4d9945faf9ad21a2e2b21dbbbe1d81b
https://github.com/scummvm/scummvm/commit/14dfa22ef4d9945faf9ad21a2e2b21dbbbe1d81b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:56+02:00
Commit Message:
PELROCK: implements fade to black
Changed paths:
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 15801ddd60f..a9e9e2b1390 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -20,7 +20,10 @@
*/
#include "common/scummsys.h"
+#include "engines/util.h"
+#include "graphics/paletteman.h"
+#include "graphics.h"
#include "pelrock/graphics.h"
#include "pelrock/pelrock.h"
@@ -69,6 +72,39 @@ void GraphicsManager::putBackgroundSlice(byte *buf, int x, int y, int w, int h,
}
}
+void GraphicsManager::fadeToBlack() {
+ byte palette[768];
+ g_system->getPaletteManager()->grabPalette(palette, 0, 256);
+ while (!g_engine->shouldQuit()) {
+ g_engine->_events->pollEvent();
+ g_engine->_chrono->updateChrono();
+ if (g_engine->_chrono->_gameTick) {
+
+ for (int i = 0; i < 768; i++) {
+ if (palette[i] > 0) {
+ palette[i] = MAX(palette[i] / 2, 0);
+ }
+ }
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+
+ bool allBlack = true;
+ for (int i = 0; i < 768; i++) {
+ if (palette[i] != 0) {
+ allBlack = false;
+ }
+ }
+
+ if (allBlack) {
+ break;
+ }
+
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+ }
+ g_system->delayMillis(10);
+ }
+}
+
void GraphicsManager::clearScreen() {
memset(g_engine->_screen->getPixels(), 0, g_engine->_screen->pitch * g_engine->_screen->h);
}
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index caa28e18f4c..a55e7749d73 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -34,6 +34,7 @@ public:
Common::Point showOverlay(int height, byte *buf);
byte *grabBackgroundSlice(byte *buf, int x, int y, int w, int h);
void putBackgroundSlice(byte *buf, int x, int y, int w, int h, byte *slice);
+ void fadeToBlack();
void clearScreen();
};
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index a2bea00e420..9c3c1a9a1fb 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -136,6 +136,7 @@ void MenuManager::checkMouseClick(int x, int y) {
void MenuManager::menuLoop() {
+ g_system->getPaletteManager()->setPalette(_mainMenuPalette, 0, 256);
g_engine->changeCursor(DEFAULT);
while (!g_engine->shouldQuit() && !_events->_rightMouseClicked) {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index cd84c318264..babbf9fec74 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -117,6 +117,7 @@ Common::Error PelrockEngine::run() {
init();
while (!shouldQuit()) {
if (_state->stateGame == SETTINGS) {
+ _graphics->clearScreen();
_menu->menuLoop();
_state->stateGame = GAME;
} else if (_state->stateGame == GAME) {
@@ -232,6 +233,7 @@ void PelrockEngine::playSoundIfNeeded() {
}
void PelrockEngine::travelToEgypt() {
+ _graphics->fadeToBlack();
_sound->playMusicTrack(26, false);
byte *palette = new byte[768];
if (_extraScreen == nullptr) {
@@ -247,12 +249,12 @@ void PelrockEngine::travelToEgypt() {
_events->pollEvent();
g_system->delayMillis(10);
_chrono->updateChrono();
- if(_chrono->_gameTick && _chrono->getFrameCount() % 2 == 0) {
+ if (_chrono->_gameTick && _chrono->getFrameCount() % 2 == 0) {
int colorIndex = 160 + frameCount;
int index = colorIndex * 3;
- palette[index] = 255; // Red
- palette[index + 1] = 0; // Green
- palette[index + 2] = 0; // Blue
+ palette[index] = 255; // Red
+ palette[index + 1] = 0; // Green
+ palette[index + 2] = 0; // Blue
g_system->getPaletteManager()->setPalette(palette, 0, 256);
frameCount++;
}
@@ -261,6 +263,7 @@ void PelrockEngine::travelToEgypt() {
_screen->markAllDirty();
_screen->update();
}
+ _graphics->clearScreen();
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
free(_extraScreen);
@@ -270,7 +273,6 @@ void PelrockEngine::travelToEgypt() {
delete[] palette;
_screen->markAllDirty();
_screen->update();
-
}
bool PelrockEngine::renderScene(int overlayMode) {
@@ -370,7 +372,6 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
void PelrockEngine::reflectionEffect(byte *buf, int x, int y, int width, int height) {
-
// ScaleCalculation scaleCalc = calculateScaling(y + 50, _room->_scaleParams);
// // Update Alfred's scale state for use by other functions
@@ -392,7 +393,6 @@ void PelrockEngine::reflectionEffect(byte *buf, int x, int y, int width, int hei
// height = finalHeight;
// width = finalWidth;
-
// Water reflection - draws mirrored sprite on water pixels
// Only sprite pixels 0-15 are reflected (checked via pixel & 0xF0 == 0)
for (int row = 0; row < height; row++) {
@@ -495,7 +495,6 @@ void PelrockEngine::checkMouse() {
checkLongMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_longClicked = false;
} else if (_events->_rightMouseClicked) {
- g_system->getPaletteManager()->setPalette(_menu->_mainMenuPalette, 0, 256);
_events->_rightMouseClicked = false;
_state->stateGame = SETTINGS;
}
@@ -944,7 +943,6 @@ byte *PelrockEngine::scale(int scaleY, int finalWidth, int finalHeight, byte *bu
}
int linesToSkip = kAlfredFrameHeight - finalHeight;
-
byte *finalBuf = new byte[finalWidth * finalHeight];
if (linesToSkip > 0) {
@@ -1444,7 +1442,7 @@ void PelrockEngine::gameLoop() {
_events->pollEvent();
checkMouse();
- if(_events->_lastKeyEvent == Common::KeyCode::KEYCODE_m) {
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_m) {
travelToEgypt();
}
renderScene();
@@ -1733,6 +1731,7 @@ void PelrockEngine::loadExtraScreenAndPresent(int screenIndex) {
}
_res->getExtraScreen(screenIndex, _extraScreen, palette);
CursorMan.showMouse(false);
+ _graphics->clearScreen();
g_system->getPaletteManager()->setPalette(palette, 0, 256);
extraScreenLoop();
CursorMan.showMouse(true);
Commit: d65032835f678f68f01013b94759050e92ef4407
https://github.com/scummvm/scummvm/commit/d65032835f678f68f01013b94759050e92ef4407
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:57+02:00
Commit Message:
PELROCK: Room 21 (map)
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/util.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index babbf9fec74..cb1024f4e7a 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -286,11 +286,17 @@ bool PelrockEngine::renderScene(int overlayMode) {
copyBackgroundToBuffer();
placeStickersFirstPass();
+
updateAnimations();
+ placeStickersSecondPass();
+
renderOverlay(overlayMode);
+ mouseHoverForMap();
+
presentFrame();
+
updatePaletteAnimations();
_screen->markAllDirty();
@@ -299,6 +305,13 @@ bool PelrockEngine::renderScene(int overlayMode) {
return false;
}
+void PelrockEngine::mouseHoverForMap() {
+ if (_room->_currentRoomNumber == 21 && !_hoveredMapLocation.empty()) {
+ Common::Rect r = _largeFont->getBoundingBox(_hoveredMapLocation.c_str());
+ drawText(_compositeBuffer, _largeFont, _hoveredMapLocation.c_str(), _events->_mouseX - r.width() / 2, _events->_mouseY - r.height(), 640, ALFRED_COLOR);
+ }
+}
+
// const int kPasserbyTriggerFrameInterval = 0x3FF;
const int kPasserbyTriggerFrameInterval = 15;
@@ -453,6 +466,7 @@ void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
void PelrockEngine::checkMouse() {
checkMouseHover();
+
if (_alfredState.animState == ALFRED_WALKING && !_alfredState.isWalkingCancelable) {
// Ignore clicks while Alfred is walking
_events->_leftMouseClicked = false;
@@ -486,12 +500,11 @@ void PelrockEngine::checkMouse() {
_currentHotspot = nullptr;
}
} else if (_events->_leftMouseClicked) {
-
// Regular click (not during popup mode)
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_leftMouseClicked = false;
_actionPopupState.isActive = false;
- } else if (_events->_longClicked) {
+ } else if (_events->_longClicked && !_room->_currentRoomNumber == 21) {
checkLongMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_longClicked = false;
} else if (_events->_rightMouseClicked) {
@@ -624,6 +637,7 @@ void PelrockEngine::placeStickersFirstPass() {
void PelrockEngine::placeStickersSecondPass() {
// Some stickers need to be placed AFTER sprites, hardcoded in the original
if (_room->_currentRoomNumber == 3) {
+ debug("Placing second-pass stickers for room 3");
for (uint i = 0; i < _state->stickersPerRoom[3].size(); i++) {
if (_state->stickersPerRoom[3][i].stickerIndex == 14) {
placeSticker(_state->stickersPerRoom[3][i]);
@@ -1634,10 +1648,24 @@ void PelrockEngine::changeCursor(Cursor cursor) {
void PelrockEngine::checkMouseHover() {
bool hotspotDetected = false;
-
int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
+
+ bool alfredDetected = false;
+ if (isAlfredUnder(_events->_mouseX, _events->_mouseY)) {
+ alfredDetected = true;
+ _hoveredMapLocation = "Alfred";
+ }
+
if (hotspotIndex != -1) {
hotspotDetected = true;
+ _hoveredMapLocation = _room->_currentRoomDescriptions[hotspotIndex].text;
+ }
+ else if (!alfredDetected) {
+ _hoveredMapLocation = "";
+ }
+
+ if(_room->_currentRoomNumber == 21) {
+ return;
}
if (isActionUnder(_events->_mouseX, _events->_mouseY) != NO_ACTION) {
@@ -1647,10 +1675,7 @@ void PelrockEngine::checkMouseHover() {
// Calculate walk target first (before checking anything else)
Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, hotspotDetected, hotspotDetected ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
- bool alfredDetected = false;
- if (isAlfredUnder(_events->_mouseX, _events->_mouseY)) {
- alfredDetected = true;
- }
+
// Check if walk target hits any exit
bool exitDetected = false;
Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 1a6232cc55a..359a1013034 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -147,6 +147,8 @@ private:
bool gameInitialized = false;
bool screenReady = false;
+ Common::String _hoveredMapLocation = "";
+
// int prevDirX = 0;
// int prevDirY = 0;
// Common::String objectToShow = "";
@@ -230,6 +232,7 @@ public:
void loadExtraScreenAndPresent(int screenIndex);
void waitForSpecialAnimation();
bool renderScene(int overlayMode = OVERLAY_NONE);
+void mouseHoverForMap();
void frameTriggers();
void passerByAnim(uint32 frameCount);
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 6eb82d4f66c..31bab7e10e0 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -68,7 +68,7 @@ void drawText(byte *screenBuffer, Graphics::Font *font, Common::String text, int
int bboxH = rect.height();
surface.create(bboxW, bboxH, Graphics::PixelFormat::createFormatCLUT8());
-
+ surface.fillRect(Common::Rect(0, 0, bboxW, bboxH), 255);
if (x + bboxW > 640) {
x = 640 - bboxW - 2;
}
@@ -89,7 +89,7 @@ void drawText(byte *screenBuffer, Graphics::Font *font, Common::String text, int
for (int px = 0; px < bboxW; px++) {
int destIdx = (y + py) * 640 + (x + px);
int pixelColor = *((byte *)surface.getBasePtr(px, py));
- if (pixelColor != 0)
+ if(pixelColor != 255)
screenBuffer[destIdx] = pixelColor;
}
}
Commit: 562e22178055dd03c30722103e0f59fc959ca8d4
https://github.com/scummvm/scummvm/commit/562e22178055dd03c30722103e0f59fc959ca8d4
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:57+02:00
Commit Message:
PELROCK: show entire inventory when picking object
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 80838b59cb2..eeff6471a5f 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -165,7 +165,7 @@ void PelrockEngine::addInventoryItem(int item) {
if (_state->inventoryItems.empty()) {
_state->selectedInventoryItem = item;
}
- _flashingIcon = item;
+ _newItem = item;
int frameCounter = 0;
while (frameCounter < kIconFlashDuration) {
_events->pollEvent();
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index 11a1f24031d..7ffbb0c6154 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -81,8 +81,7 @@ bool PelrockConsole::cmdGiveItems(int argc, const char **argv) {
for (int i = 1; i < argc; i++) {
int itemId = atoi(argv[i]);
bool markAsSelected = g_engine->_state->inventoryItems.empty();
- g_engine->addInventoryItem(itemId);
- // g_engine->_state->addInventoryItem(itemId);
+ g_engine->_state->addInventoryItem(itemId);
if (markAsSelected)
g_engine->_state->selectedInventoryItem = itemId;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index cb1024f4e7a..952dd2c6544 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -155,7 +155,7 @@ void PelrockEngine::init() {
loadAnims();
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
- setScreen(25, ALFRED_DOWN);
+ setScreen(23, ALFRED_DOWN);
// setScreen(9, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
@@ -199,6 +199,8 @@ Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
return verbs;
}
+Common::Point getPositionInBallonForIndex(int i);
+
// Sort sprites by zOrder in-place using insertion sort (efficient for nearly-sorted data)
void sortAnimsByZOrder(Common::Array<Sprite> &anims) {
for (size_t i = 0; i < anims.size(); ++i) {
@@ -478,7 +480,6 @@ void PelrockEngine::checkMouse() {
_alfredState.curFrame = 0;
_alfredState.setState(ALFRED_IDLE);
}
-
// Handle mouse release after long press (popup selection mode)
if (_events->_popupSelectionMode && !_events->_leftMouseButton) {
_events->_leftMouseButton = false;
@@ -504,7 +505,7 @@ void PelrockEngine::checkMouse() {
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_leftMouseClicked = false;
_actionPopupState.isActive = false;
- } else if (_events->_longClicked && !_room->_currentRoomNumber == 21) {
+ } else if (_events->_longClicked && _room->_currentRoomNumber != 21) {
checkLongMouseClick(_events->_mouseClickX, _events->_mouseClickY);
_events->_longClicked = false;
} else if (_events->_rightMouseClicked) {
@@ -1193,24 +1194,6 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
void PelrockEngine::calculateScalingMasks() {
- // for scale_factor in range(CHAR_WIDTH):
- // step = CHAR_WIDTH / (scale_factor + 1.0)
- // row = []
- // index = 0.0
- // source_pixel = 0
-
- // while index < CHAR_WIDTH:
- // row.append(source_pixel)
- // index += step
- // source_pixel += 1
- // if source_pixel >= CHAR_WIDTH:
- // source_pixel = CHAR_WIDTH - 1
-
- // # Pad to exactly CHAR_WIDTH entries
- // while len(row) < CHAR_WIDTH:
- // row.append(row[-1] if row else 0)
- // width_table.append(row[:CHAR_WIDTH])
-
for (int scaleFactor = 0; scaleFactor < kAlfredFrameWidth; scaleFactor++) {
float step = kAlfredFrameWidth / (scaleFactor + 1.0f);
Common::Array<int> row;
@@ -1234,22 +1217,6 @@ void PelrockEngine::calculateScalingMasks() {
_widthScalingTable.push_back(row);
}
- // height_table = []
- // for scale_factor in range(CHAR_HEIGHT):
- // step = CHAR_HEIGHT / (scale_factor + 1.0)
- // row = [0] * CHAR_HEIGHT # Initialize all to 0
-
- // # Mark positions where we should keep/duplicate the scanline
- // position = step
- // counter = 1
- // while position < CHAR_HEIGHT:
- // idx = round(position)
- // if idx < CHAR_HEIGHT:
- // row[idx] = counter
- // counter += 1
- // position += step
-
- // height_table.append(row)
for (int scaleFactor = 0; scaleFactor < kAlfredFrameHeight; scaleFactor++) {
float step = kAlfredFrameHeight / (scaleFactor + 1.0f);
Common::Array<int> row;
@@ -1380,6 +1347,10 @@ bool PelrockEngine::isSpriteUnder(Sprite *sprite, int x, int y) {
return false;
}
+Common::Point getPositionInBallonForIndex(int i, int x, int y) {
+ return Common::Point(x + 20 + (i * (kVerbIconWidth + 2)), y + 20);
+}
+
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
drawSpriteToBuffer(_compositeBuffer, 640, _res->_popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
@@ -1390,11 +1361,11 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
if (icon == actions[i] && shouldBlink) {
continue;
}
- drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], posx + 20 + (i * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
+ Common::Point p = getPositionInBallonForIndex(i, posx, posy);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], p.x, p.y, kVerbIconWidth, kVerbIconHeight, 1);
}
- bool itemUnder = isItemUnder(_events->_mouseX, _events->_mouseY);
if (_state->selectedInventoryItem >= 0 && !_state->inventoryItems.empty()) {
- if (itemUnder && shouldBlink) {
+ if (icon == ITEM && shouldBlink) {
return;
}
drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->selectedInventoryItem).iconData, posx + 20 + (actions.size() * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
@@ -1442,13 +1413,26 @@ void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
drawSpriteToBuffer(_compositeBuffer, 640, frame, x, y, w, h, 255);
}
+Common::Point getPositionInOverlayForIndex(uint index) {
+ return Common::Point(5 + index * (60 + 2), 400 - 60 - 5);
+}
+
+
void PelrockEngine::pickupIconFlash() {
_graphics->showOverlay(65, _compositeBuffer);
- if (_flashingIcon == -1)
+ if (_newItem == -1)
return;
- InventoryObject item = _res->getIconForObject(_flashingIcon);
+ uint invSize = _state->inventoryItems.size();
+ for( int i = 0; i < invSize; i++) {
+ Common::Point p = getPositionInOverlayForIndex(i);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->inventoryItems[i]).iconData, p.x, p.y, 60, 60, 1);
+ }
+
+ InventoryObject item = _res->getIconForObject(_newItem);
if (_chrono->getFrameCount() % kIconBlinkPeriod == 0) {
- drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 5, 400 - 60 - 5, 60, 60, 1);
+ Common::Point p = getPositionInOverlayForIndex(invSize);
+ debug("Drawing pickup icon for item %d at inventory index %d, position %d,%d", _newItem, invSize, p.x, p.y);
+ drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, p.x, p.y, 60, 60, 1);
}
}
@@ -1570,9 +1554,8 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
int loopEnd = _state->selectedInventoryItem != -1 ? actions.size() + 1 : actions.size();
for (int i = 0; i < loopEnd; i++) {
- int actionX = _actionPopupState.x + 20 + (i * (kVerbIconWidth + 2));
- int actionY = _actionPopupState.y + 20;
- Common::Rect actionRect = Common::Rect(actionX, actionY, actionX + kVerbIconWidth, actionY + kVerbIconHeight);
+ Common::Point p = getPositionInBallonForIndex(i, _actionPopupState.x, _actionPopupState.y);
+ Common::Rect actionRect = Common::Rect(p.x, p.y, p.x + kVerbIconWidth, p.y + kVerbIconHeight);
if (i == actions.size()) {
// Check inventory item
@@ -1586,17 +1569,6 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
return NO_ACTION;
}
-bool PelrockEngine::isItemUnder(int x, int y) {
- Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
- Common::Rect itemRect = Common::Rect(_actionPopupState.x + 20 + (actions.size() * (kVerbIconWidth + 2)), _actionPopupState.y + 20,
- _actionPopupState.x + 20 + (actions.size() * (kVerbIconWidth + 2)) + kVerbIconWidth,
- _actionPopupState.y + 20 + kVerbIconHeight);
- if (itemRect.contains(x, y)) {
- return true;
- }
- return false;
-}
-
bool PelrockEngine::isAlfredUnder(int x, int y) {
int alfredX = _alfredState.x;
int alfredY = _alfredState.y;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 359a1013034..061668f4eba 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -76,7 +76,6 @@ private:
Common::Array<VerbIcon> availableActions(HotSpot *hotspot);
VerbIcon isActionUnder(int x, int y);
- bool isItemUnder(int x, int y);
bool isAlfredUnder(int x, int y);
int isHotspotUnder(int x, int y);
Exit *isExitUnder(int x, int y);
@@ -136,7 +135,7 @@ private:
ActionPopupState _actionPopupState;
HotSpot *_currentHotspot = nullptr;
- int _flashingIcon = -1;
+ int _newItem = -1;
Common::Point _curWalkTarget;
QueuedAction _queuedAction;
@@ -232,7 +231,7 @@ public:
void loadExtraScreenAndPresent(int screenIndex);
void waitForSpecialAnimation();
bool renderScene(int overlayMode = OVERLAY_NONE);
-void mouseHoverForMap();
+ void mouseHoverForMap();
void frameTriggers();
void passerByAnim(uint32 frameCount);
Commit: 4d4ff456f058204f620f69026651aa7ecd7258a2
https://github.com/scummvm/scummvm/commit/4d4ff456f058204f620f69026651aa7ecd7258a2
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:57+02:00
Commit Message:
PERLOCK: adjust mouse hover over Alfred
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 952dd2c6544..7245d7a133a 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1036,14 +1036,15 @@ void PelrockEngine::drawAlfred(byte *buf) {
ScaleCalculation scaleCalc = calculateScaling(_alfredState.y, _room->_scaleParams);
- // Update Alfred's scale state for use by other functions
- _alfredState.scaledX = scaleCalc.scaleX;
- _alfredState.scaledY = scaleCalc.scaleY;
-
// Use the pre-calculated scaled dimensions from calculateScaling
int finalHeight = scaleCalc.scaledHeight;
int finalWidth = scaleCalc.scaledWidth;
+
+ // Update Alfred's scale state for use by other functions
+ _alfredState.w = finalWidth;
+ _alfredState.h = finalHeight;
+
if (finalHeight <= 0) {
finalHeight = 1;
}
@@ -1051,28 +1052,28 @@ void PelrockEngine::drawAlfred(byte *buf) {
finalWidth = 1;
}
- byte *finalBuf = scale(scaleCalc.scaleY, finalWidth, finalHeight, buf);
+ byte *scaledBuf = scale(scaleCalc.scaleY, finalWidth, finalHeight, buf);
+ delete[] _alfredSprite;
+ _alfredSprite = scaledBuf;
int shadowPos = _alfredState.y; // - finalHeight;
bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + _alfredState.x] != 0xFF;
if (shadeCharacter) {
for (int i = 0; i < finalWidth * finalHeight; i++) {
- if (finalBuf[i] != 255) {
- finalBuf[i] = _room->_paletteRemaps[1][finalBuf[i]];
+ if (_alfredSprite[i] != 255) {
+ _alfredSprite[i] = _room->_paletteRemaps[1][_alfredSprite[i]];
}
}
}
- drawSpriteToBuffer(_compositeBuffer, 640, finalBuf, _alfredState.x, _alfredState.y - finalHeight, finalWidth, finalHeight, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, _alfredSprite, _alfredState.x, _alfredState.y - finalHeight, finalWidth, finalHeight, 255);
// Water reflection (rooms 25 and 45 only)
if ((_room->_currentRoomNumber == 25 || _room->_currentRoomNumber == 45) && _alfredState.y >= 299) {
// Offset from Alfred's feet to start of reflection
int yOffset = (_room->_currentRoomNumber == 45) ? 25 : 13;
- reflectionEffect(finalBuf, _alfredState.x, _alfredState.y + yOffset, finalWidth, finalHeight);
+ reflectionEffect(_alfredSprite, _alfredState.x, _alfredState.y + yOffset, finalWidth, finalHeight);
}
-
- delete[] finalBuf;
}
void applyMovement(int16_t *x, int16_t *y, int8_t *z, uint16_t flags) {
@@ -1512,13 +1513,13 @@ AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
calculatedDirection = ALFRED_LEFT; // Face LEFT
}
// Check if Alfred's right edge is before sprite's left edge
- else if ((_alfredState.x + kAlfredFrameWidth - _alfredState.scaledX) < hotspot->x) {
+ else if ((_alfredState.x + _alfredState.w) < hotspot->x) {
calculatedDirection = ALFRED_RIGHT; // Face RIGHT
}
// Alfred is horizontally overlapping with sprite
else {
// Check if Alfred's top is above sprite's bottom OR Alfred is within sprite's Y range
- if (((_alfredState.y + kAlfredFrameHeight - _alfredState.scaledY) < hotspot->y) ||
+ if (((_alfredState.y + _alfredState.h) < hotspot->y) ||
(_alfredState.y <= hotspot->y + hotspot->h &&
hotspot->zOrder <= ((399 - _alfredState.y) / 2) + 10)) {
calculatedDirection = ALFRED_DOWN; // Face DOWN
@@ -1532,11 +1533,11 @@ AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
calculatedDirection = ALFRED_LEFT; // Face LEFT
}
// Check if Alfred's right edge is before hotspot's left edge
- else if ((_alfredState.x + kAlfredFrameWidth - _alfredState.scaledX) < hotspot->x) {
+ else if ((_alfredState.x + _alfredState.w) < hotspot->x) {
calculatedDirection = ALFRED_RIGHT; // Face RIGHT
}
// Check vertical positioning
- else if (((_alfredState.y + kAlfredFrameHeight - _alfredState.scaledY) < hotspot->y) ||
+ else if (((_alfredState.y + _alfredState.h) < hotspot->y) ||
(_alfredState.y <= hotspot->y + hotspot->h &&
(hotspot->actionFlags & 0x80) == 0x80)) {
calculatedDirection = ALFRED_DOWN; // Face DOWN
@@ -1570,16 +1571,15 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
}
bool PelrockEngine::isAlfredUnder(int x, int y) {
- int alfredX = _alfredState.x;
- int alfredY = _alfredState.y;
- // Use scaled dimensions (width - scaleX, height - scaleY)
- int alfredW = kAlfredFrameWidth - _alfredState.scaledX;
- int alfredH = kAlfredFrameHeight - _alfredState.scaledY;
-
- if (alfredY - alfredH > y || alfredY < y || alfredX > x || alfredX + alfredW < x) {
- return false;
+ int localX = x - _alfredState.x;
+ int localY = y - _alfredState.y + _alfredState.h; // Adjust for scaling (since Alfred's position is based on his feet, but sprite may be scaled from the top)
+ if (localX >= 0 && localX < _alfredState.w && localY >= 0 && localY < _alfredState.h) {
+ byte pixel = _alfredSprite[localY * _alfredState.w + localX];
+ if (pixel != 255) {
+ return true;
+ }
}
- return true;
+ return false;
}
void PelrockEngine::checkMouseClick(int x, int y) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 061668f4eba..b470c431f24 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -147,6 +147,7 @@ private:
bool screenReady = false;
Common::String _hoveredMapLocation = "";
+ byte *_alfredSprite = nullptr;
// int prevDirX = 0;
// int prevDirY = 0;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index b9b3ac14b97..e6bff318382 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -163,8 +163,8 @@ struct AlfredState {
uint16 movementSpeedY = 5; // pixels per frame
uint16 x = 319;
uint16 y = 302;
- uint16 scaledX = 0;
- uint16 scaledY = 0;
+ byte w = kAlfredFrameWidth;
+ byte h = kAlfredFrameHeight;
int idleFrameCounter = 0;
bool isWalkingCancelable = true;
Commit: 398957a124dd40b09b1f00c542602bb9990d44c5
https://github.com/scummvm/scummvm/commit/398957a124dd40b09b1f00c542602bb9990d44c5
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:58+02:00
Commit Message:
PELROCK: Improve action selection
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index eeff6471a5f..ccc0569c119 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -793,7 +793,7 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
// loadExtraScreenAndPresent(9);
_state->stateGame = COMPUTER;
break;
- case 145:
+ case 280:
_dialog->say(_res->_ingameTexts[NOVIO2METROS]);
break;
case 281:
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 7245d7a133a..50a72e96a7a 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -488,14 +488,16 @@ void PelrockEngine::checkMouse() {
_actionPopupState.isActive = false;
// Mouse was released while popup is active
VerbIcon actionClicked = isActionUnder(_events->_releaseX, _events->_releaseY);
- debug("Popup action clicked: %d, is alfredunder %d", actionClicked, _actionPopupState.isAlfredUnder);
- if (_actionPopupState.isAlfredUnder) {
- debug("Using item on Alfred");
- useOnAlfred(_state->selectedInventoryItem);
- } else if (actionClicked != NO_ACTION && _currentHotspot != nullptr) {
+ if(actionClicked != NO_ACTION) {
+ debug("Popup action clicked: %d, is alfredunder %d", actionClicked, _actionPopupState.isAlfredUnder);
+ }
+ if (actionClicked != NO_ACTION && _currentHotspot != nullptr) {
// Action was selected - queue it
walkAndAction(_currentHotspot, actionClicked);
- } else {
+ } else if (_actionPopupState.isAlfredUnder && actionClicked != NO_ACTION) {
+ debug("Using item on Alfred");
+ useOnAlfred(_state->selectedInventoryItem);
+ } else {
// Released outside popup - just close it
_queuedAction = QueuedAction{NO_ACTION, -1, false};
_currentHotspot = nullptr;
@@ -1630,6 +1632,7 @@ void PelrockEngine::checkMouseHover() {
if (hotspotIndex != -1) {
hotspotDetected = true;
+ debug("Hotspot detected: %s", _room->_currentRoomDescriptions[hotspotIndex].text.c_str());
_hoveredMapLocation = _room->_currentRoomDescriptions[hotspotIndex].text;
}
else if (!alfredDetected) {
Commit: 433b1eb364dc40ebfe52900b14bbe6c0d4384591
https://github.com/scummvm/scummvm/commit/433b1eb364dc40ebfe52900b14bbe6c0d4384591
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:58+02:00
Commit Message:
PELROCK: Dialog refactor into functions
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index ccc0569c119..d4e5d51e72d 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -273,6 +273,52 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 279:
travelToEgypt();
break;
+ // moros
+ case 330:
+ break;
+ case 331:
+ break;
+ case 332:
+ break;
+ case 333:
+ break;
+ case 334:
+ break;
+ case 335:
+ break;
+ case 336:
+ break;
+ case 337:
+ break;
+ case 338:
+ break;
+ case 339:
+ break;
+ case 340:
+ break;
+ case 341:
+ break;
+ case 342:
+ break;
+ case 343:
+ break;
+ case 344:
+ break;
+ case 345:
+ break;
+ case 346:
+ break;
+ case 347:
+ break;
+ case 348:
+ break;
+ case 349:
+ break;
+ case 350:
+ break;
+ case 351:
+ break;
+ // end moros
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 7dc5629975f..828c500170b 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -20,6 +20,7 @@
*/
#include "pelrock/dialog.h"
+#include "dialog.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
@@ -246,7 +247,6 @@ void DialogManager::displayDialogue(Common::String text, byte speakerId) {
* Returns the index of the selected choice in the choices array
*/
int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer) {
- // Clear any existing click state
_events->_leftMouseClicked = false;
int overlayHeight = choices.size() * kChoiceHeight + 2;
@@ -255,13 +255,11 @@ int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *co
while (!g_engine->shouldQuit()) {
_events->pollEvent();
- // Render the scene with choices overlay
g_engine->renderScene(OVERLAY_CHOICES);
if (_events->_leftMouseClicked) {
_events->_leftMouseClicked = false;
- // Check if click is in the choices area
if (_events->_mouseClickY >= overlayY) {
int selectedIndex = (_events->_mouseClickY - overlayY - 2) / kChoiceHeight;
if (selectedIndex >= 0 && selectedIndex < (int)choices.size()) {
@@ -460,145 +458,48 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
return;
}
setCurSprite(animSet ? animSet->index : -1);
- // _curSprite = animSet;
debug("Starting conversation with %d bytes of data, for npc %d, hotspot %d", dataSize, npcIndex, animSet ? animSet->index : -1);
- uint32 position = 0;
- int currentChoiceLevel = -1; // Track the current choice level
- uint32 lastChoiceMenuPosition = 0; // Track where we last showed a choice menu
- ChoiceOption lastSelectedChoice; // Track the last choice we selected
- bool skipToChoices = false; // After F0, skip directly to choice parsing
-
- // Find the speaker tree for this NPC; they are marked by 0xFE 0xXX where XX is NPC index + 1
- bool speakerTreeOffsetFound = false;
- int currentConversationTree = npcIndex + 1;
- while (position < dataSize && !speakerTreeOffsetFound) {
- if (conversationData[position] == CTRL_ALT_SPEAKER_ROOT && conversationData[position + 1] == currentConversationTree) {
- speakerTreeOffsetFound = true;
- position += 2; // Move past the speaker tree marker and npc index
- } else {
- position++;
- }
- }
- // Right after the speaker conversation tree, we are in branch 0
- int currentRoot = 0;
- while (g_engine->_state->getRootDisabledState(g_engine->_room->_currentRoomNumber, currentRoot)) {
- // This root is disabled, skip to next
- while (position < dataSize) {
- if (conversationData[position] == CTRL_END_BRANCH) {
- position++; // Move past end branch marker
- currentRoot++;
- break;
- }
- position++;
- }
- }
-
- // Skip any junk at start until we find a speaker marker or choice marker
- while (position < dataSize &&
- conversationData[position] != CTRL_SPEAKER_ID &&
- conversationData[position] != CTRL_DIALOGUE_MARKER &&
- conversationData[position] != CTRL_DIALOGUE_MARKER_ONEOFF) {
- position++;
- }
-
- // OUTER LOOP: Continue until conversation ends
- while (position < dataSize && !g_engine->shouldQuit()) {
- // Skip control bytes that should be ignored (but handle F0 specially)
- while (position < dataSize &&
- (conversationData[position] == CTRL_ALT_END_MARKER_1 ||
- conversationData[position] == CTRL_ALT_END_MARKER_2)) {
- position++;
- }
+ // Initialize conversation state
+ ConversationState state = initializeConversation(conversationData, dataSize, npcIndex);
+ bool skipToChoices = false;
- // Handle F0 "Go Back" - return to the last choice menu position
- // Disable the choice that led us here before rewinding
- if (position < dataSize && conversationData[position] == CTRL_GO_BACK) {
- debug("F0 Go Back at position %u, rewinding to lastChoiceMenuPosition %u", position, lastChoiceMenuPosition);
+ // Main conversation loop
+ while (state.position < dataSize && !g_engine->shouldQuit()) {
+ state.position = skipControlBytes(conversationData, dataSize, state.position);
- if (lastChoiceMenuPosition > 0) {
- // Disable the choice that led to this F0
- if (lastSelectedChoice.dataOffset > 0) {
- debug("F0: Disabling choice that led here at offset %u", lastSelectedChoice.dataOffset);
- g_engine->_room->addDisabledChoice(lastSelectedChoice);
- }
- position = lastChoiceMenuPosition;
- skipToChoices = true; // Skip directly to choice parsing
- // Jump directly to choice parsing section
- // Don't continue - let it fall through
+ if (state.position < dataSize && conversationData[state.position] == CTRL_GO_BACK) {
+ if (handleGoBack(conversationData, state.position, state)) {
+ skipToChoices = true;
} else {
- debug("F0: No previous choice menu, ending conversation");
- break;
+ break; // End conversation if no previous menu
}
}
- if (position >= dataSize) {
+ if (state.position >= dataSize) {
debug("Reached end of data while skipping control bytes");
break;
}
- // 1. Read and display current dialogue (unless skipping to choices)
- uint32 endPos = position; // Declare outside the if block
if (!skipToChoices) {
- Common::String text;
- byte speakerId;
- endPos = readTextBlock(conversationData, dataSize, position, text, speakerId);
- Common::Array<Common::Array<Common::String>> wrappedText = wordWrap(text);
- // debug("Word wrapping %s produces %d pages", text.c_str(), wrappedText.size());
- // Skip spurious single character artifacts
- if (!text.empty() && text.size() > 1) {
- displayDialogue(wrappedText, speakerId);
- }
-
- // Move to end of text
- position = endPos;
+ state.position = readAndDisplayDialogue(conversationData, dataSize, state.position);
}
- // 2. Check for end of conversation (skip if going directly to choices)
if (!skipToChoices) {
- if (position >= dataSize) {
- debug("Reached end of data after reading dialogue");
- break;
- }
-
- byte controlByte = conversationData[position];
-
- if (controlByte == CTRL_END_CONVERSATION) {
- debug("End of conversation marker found");
- break;
- }
-
- if (controlByte == CTRL_ACTION_TRIGGER) {
- uint16 actionCode = conversationData[position + 1] | (conversationData[position + 2] << 8);
- debug("Action trigger %d encountered!", actionCode);
- g_engine->dialogActionTrigger(
- actionCode,
- g_engine->_room->_currentRoomNumber,
- currentRoot);
- break;
- }
-
- // Move past control byte
- if (controlByte == CTRL_END_TEXT) {
- position++;
- if (position >= dataSize) {
- debug("Reached end of data after moving past control byte");
- break;
+ ConversationEndResult endResult = checkConversationEnd(conversationData, dataSize, state.position);
+ if (endResult.shouldEnd) {
+ if (endResult.hasAction) {
+ g_engine->dialogActionTrigger(endResult.actionCode, g_engine->_room->_currentRoomNumber, state.currentRoot);
}
+ break;
}
+ state.position = endResult.nextPosition;
}
-
- // 3. Before parsing choices, check if we're at a choice marker
- // Skip control bytes to peek at next meaningful byte
- uint32 peekPos = position;
+ // Check for choice markers
+ uint32 peekPos = state.position;
if (!skipToChoices) {
- while (peekPos < dataSize &&
- (conversationData[peekPos] == CTRL_ALT_END_MARKER_1 ||
- conversationData[peekPos] == CTRL_ALT_END_MARKER_2 ||
- conversationData[peekPos] == CTRL_TEXT_TERMINATOR)) {
- peekPos++;
- }
+ peekPos = peekNextMeaningfulByte(conversationData, dataSize, state.position);
// If not at a choice marker, there's more dialogue to read
if (peekPos < dataSize &&
@@ -610,75 +511,47 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
}
- // 4. Parse choices - save position for F0 "go back"
- skipToChoices = false; // Reset flag
- lastChoiceMenuPosition = position;
+ // Parse choices
+ skipToChoices = false;
+ state.lastChoiceMenuPosition = state.position;
+
Common::Array<ChoiceOption> *choices = new Common::Array<ChoiceOption>();
- parseChoices(conversationData, dataSize, position, choices);
+ parseChoices(conversationData, dataSize, state.position, choices);
- // Store original choice count before potentially adding goodbye
uint originalChoiceCount = choices->size();
-
- // Only consider adding goodbye if there are MULTIPLE choices
- // If there's only 1 choice, it's auto-dialogue and should not have goodbye
- if (originalChoiceCount > 1) {
- // Check if ANY choice has a conversation terminator (F4 or F8)
- // If so, there's already a way to exit - don't add goodbye option
- bool anyChoiceTerminatesConversation = false;
- for (uint i = 0; i < choices->size(); i++) {
- if ((*choices)[i].hasConversationEndMarker) {
- anyChoiceTerminatesConversation = true;
- break;
- }
- }
- if (!anyChoiceTerminatesConversation) {
- // No choice ends the conversation, so add the goodbye option
- ChoiceOption termChoice;
- termChoice.choiceIndex = currentChoiceLevel;
- termChoice.isTerminator = true;
- termChoice.isDisabled = false;
- termChoice.shouldDisableOnSelect = false;
- termChoice.text = g_engine->_res->_conversationTerminator;
- choices->push_back(termChoice);
- }
- }
+ addGoodbyeOptionIfNeeded(choices, state.currentChoiceLevel, originalChoiceCount);
debug("Parsed %u choices", choices->size());
for (uint i = 0; i < choices->size(); i++) {
debug(" Choice %u (index %d): \"%s\" (Disabled: %s)", i, (*choices)[i].choiceIndex, (*choices)[i].text.c_str(),
(*choices)[i].isDisabled ? "Yes" : "No");
}
+
if (choices->empty()) {
- // No choices, continue reading dialogue
- position = peekPos;
+ state.position = peekPos;
continue;
}
- // Check if we have a currentChoiceLevel and if these choices are at the expected level
- if (currentChoiceLevel >= 0) {
- // After F0, we expect choices at the SAME level (currentChoiceLevel)
- // Otherwise, we expect choices at the NEXT level (currentChoiceLevel + 1)
+ // Validate choice level
+ if (state.currentChoiceLevel >= 0) {
bool foundExpectedLevel = false;
for (uint i = 0; i < choices->size(); i++) {
- if ((*choices)[i].choiceIndex == currentChoiceLevel ||
- (*choices)[i].choiceIndex == currentChoiceLevel + 1) {
+ if ((*choices)[i].choiceIndex == state.currentChoiceLevel ||
+ (*choices)[i].choiceIndex == state.currentChoiceLevel + 1) {
foundExpectedLevel = true;
- // Update currentChoiceLevel to match what we found
- currentChoiceLevel = (*choices)[i].choiceIndex;
+ state.currentChoiceLevel = (*choices)[i].choiceIndex;
break;
}
}
if (!foundExpectedLevel) {
- debug("No choices found at level %d or %d, ending conversation", currentChoiceLevel, currentChoiceLevel + 1);
+ debug("No choices found at level %d or %d, ending conversation", state.currentChoiceLevel, state.currentChoiceLevel + 1);
break;
}
}
- // 5. Display choices and get selection
+ // Process user selection
int selectedIndex = 0;
-
- // Check if this is auto-dialogue (only one choice)
if (choices->size() == 1) {
// Auto-dialogue: display it automatically
debug("Auto-selecting single choice: \"%s\"", (*choices)[0].text.c_str());
@@ -695,56 +568,241 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
_currentChoices = nullptr;
}
_currentChoices = choices;
- // Use displayChoices to show and select
selectedIndex = selectChoice(choiceTexts, g_engine->_compositeBuffer);
}
- // 6. Move position to after the selected choice
- if (selectedIndex >= 0 && selectedIndex < (int)choices->size()) {
+ state.position = processChoiceSelection(conversationData, dataSize, choices, selectedIndex, state);
+ }
- // Save this choice in case we hit F0 and need to disable it
- lastSelectedChoice = (*choices)[selectedIndex];
- if (lastSelectedChoice.isTerminator) {
- displayDialogue(lastSelectedChoice.text, ALFRED_COLOR);
+ debug("Conversation ended");
+}
+
+uint32 DialogManager::findRoot(int ¤tRoot, uint32 currentPosition, uint32 dataSize, const byte *conversationData) {
+ while (g_engine->_state->getRootDisabledState(g_engine->_room->_currentRoomNumber, currentRoot)) {
+ // This root is disabled, skip to next
+ while (currentPosition < dataSize) {
+ if (conversationData[currentPosition] == CTRL_END_BRANCH) {
+ currentPosition++; // Move past end branch marker
+ currentRoot++;
break;
}
- position = (*choices)[selectedIndex].dataOffset;
- currentChoiceLevel = (*choices)[selectedIndex].choiceIndex;
-
- // Read and display the selected choice as dialogue
- Common::String choiceText;
- byte choiceSpeakerId;
- endPos = readTextBlock(conversationData, dataSize, position, choiceText, choiceSpeakerId);
-
- if (!choiceText.empty() && choiceText.size() > 1) {
- displayDialogue(choiceText, ALFRED_COLOR);
- // Only disable FB choice if all sub-branches are exhausted
- if ((*choices)[selectedIndex].shouldDisableOnSelect) {
- bool shouldDisable = checkAllSubBranchesExhausted(conversationData, dataSize, endPos, currentChoiceLevel);
- if (shouldDisable) {
- debug("Disabling one-time choice at index %d after selection", selectedIndex);
- g_engine->_room->addDisabledChoice((*choices)[selectedIndex]);
- }
- }
- }
+ currentPosition++;
+ }
+ }
+ return currentPosition;
+}
+
+uint32 DialogManager::findSpeaker(byte npcIndex, uint32 dataSize, const byte *conversationData) {
+ // Find the speaker tree for this NPC; they are marked by 0xFE 0xXX where XX is NPC index + 1
+ bool speakerTreeOffsetFound = false;
+ int currentConversationTree = npcIndex + 1;
+ uint32 position = 0;
+ while (position < dataSize && !speakerTreeOffsetFound) {
+ if (conversationData[position] == CTRL_ALT_SPEAKER_ROOT && conversationData[position + 1] == currentConversationTree) {
+ speakerTreeOffsetFound = true;
+ position += 2; // Move past the speaker tree marker and npc index
+ } else {
+ position++;
+ }
+ }
+ return position;
+}
- position = endPos;
+// Skip control bytes that should be ignored
+uint32 DialogManager::skipControlBytes(const byte *data, uint32 dataSize, uint32 position) {
+ while (position < dataSize &&
+ (data[position] == CTRL_ALT_END_MARKER_1 ||
+ data[position] == CTRL_ALT_END_MARKER_2)) {
+ position++;
+ }
+ return position;
+}
- // Skip past end marker
- if (position < dataSize) {
- byte endByte = conversationData[position];
- if (endByte == CTRL_END_TEXT || endByte == CTRL_END_BRANCH ||
- endByte == CTRL_ACTION_TRIGGER) {
- position++;
- }
- }
+// Peek at next meaningful byte after skipping control bytes
+uint32 DialogManager::peekNextMeaningfulByte(const byte *data, uint32 dataSize, uint32 position) {
+ uint32 peekPos = position;
+ while (peekPos < dataSize &&
+ (data[peekPos] == CTRL_ALT_END_MARKER_1 ||
+ data[peekPos] == CTRL_ALT_END_MARKER_2 ||
+ data[peekPos] == CTRL_TEXT_TERMINATOR)) {
+ peekPos++;
+ }
+ return peekPos;
+}
+
+// Initialize conversation by finding speaker and root
+ConversationState DialogManager::initializeConversation(const byte *data, uint32 dataSize, byte npcIndex) {
+ ConversationState state;
+ state.position = findSpeaker(npcIndex, dataSize, data);
+ state.currentRoot = 0;
+ state.position = findRoot(state.currentRoot, state.position, dataSize, data);
+ state.currentChoiceLevel = -1;
+ state.lastChoiceMenuPosition = 0;
+ state.lastSelectedChoice = ChoiceOption();
+
+ // Skip any junk at start until we find a speaker marker
+ while (state.position < dataSize && data[state.position] != CTRL_SPEAKER_ID) {
+ state.position++;
+ }
+
+ return state;
+}
+
+// Handle F0 "Go Back" control byte
+bool DialogManager::handleGoBack(const byte *data, uint32 position, ConversationState &state) {
+ if (data[position] != CTRL_GO_BACK) {
+ return false;
+ }
+
+ debug("F0 Go Back at position %u, rewinding to lastChoiceMenuPosition %u", position, state.lastChoiceMenuPosition);
+
+ if (state.lastChoiceMenuPosition > 0) {
+ // Disable the choice that led to this F0
+ if (state.lastSelectedChoice.dataOffset > 0) {
+ debug("F0: Disabling choice that led here at offset %u", state.lastSelectedChoice.dataOffset);
+ g_engine->_room->addDisabledChoice(state.lastSelectedChoice);
}
+ state.position = state.lastChoiceMenuPosition;
+ return true; // Skip to choices
+ } else {
+ debug("F0: No previous choice menu, ending conversation");
+ return false; // End conversation
}
+}
- debug("Conversation ended");
- // Note: The caller should set inConversation = false after this returns
+uint32 DialogManager::readAndDisplayDialogue(const byte *data, uint32 dataSize, uint32 position) {
+ Common::String text;
+ byte speakerId;
+ uint32 endPos = readTextBlock(data, dataSize, position, text, speakerId);
+ Common::Array<Common::Array<Common::String>> wrappedText = wordWrap(text);
+
+ // Skip spurious single character artifacts
+ if (!text.empty() && text.size() > 1) {
+ displayDialogue(wrappedText, speakerId);
+ }
+
+ return endPos;
+}
+
+ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint32 dataSize, uint32 position) {
+ ConversationEndResult result;
+ result.shouldEnd = false;
+ result.nextPosition = position;
+ result.hasAction = false;
+ result.actionCode = 0;
+
+ if (position >= dataSize) {
+ debug("Reached end of data after reading dialogue");
+ result.shouldEnd = true;
+ return result;
+ }
+
+ byte controlByte = data[position];
+
+ if (controlByte == CTRL_END_CONVERSATION) {
+ debug("End of conversation marker found");
+ result.shouldEnd = true;
+ return result;
+ }
+
+ if (controlByte == CTRL_ACTION_TRIGGER) {
+ result.actionCode = data[position + 1] | (data[position + 2] << 8);
+ debug("Action trigger %d encountered!", result.actionCode);
+ result.shouldEnd = true;
+ result.hasAction = true;
+ return result;
+ }
+
+ // Move past control byte
+ if (controlByte == CTRL_END_TEXT) {
+ result.nextPosition = position + 1;
+ }
+
+ return result;
}
+void DialogManager::addGoodbyeOptionIfNeeded(Common::Array<ChoiceOption> *choices, int currentChoiceLevel, uint originalChoiceCount) {
+ // Only consider adding goodbye if there are MULTIPLE choices
+ // If there's only 1 choice, it's auto-dialogue and should not have goodbye
+ if (originalChoiceCount <= 1) {
+ return;
+ }
+
+ // Check if ANY choice has a conversation terminator (F4 or F8)
+ // If so, there's already a way to exit - don't add goodbye option
+ bool anyChoiceTerminatesConversation = false;
+ for (uint i = 0; i < choices->size(); i++) {
+ if ((*choices)[i].hasConversationEndMarker) {
+ anyChoiceTerminatesConversation = true;
+ break;
+ }
+ }
+
+ if (!anyChoiceTerminatesConversation) {
+ ChoiceOption termChoice;
+ termChoice.choiceIndex = currentChoiceLevel;
+ termChoice.isTerminator = true;
+ termChoice.isDisabled = false;
+ termChoice.shouldDisableOnSelect = false;
+ termChoice.text = g_engine->_res->_conversationTerminator;
+ choices->push_back(termChoice);
+ }
+}
+
+// Handle choice selection and response
+uint32 DialogManager::processChoiceSelection(
+ const byte *data,
+ uint32 dataSize,
+ Common::Array<ChoiceOption> *choices,
+ int selectedIndex,
+ ConversationState &state) {
+
+ if (selectedIndex < 0 || selectedIndex >= (int)choices->size()) {
+ return state.position;
+ }
+
+ // Save this choice in case we hit F0 and need to disable it
+ state.lastSelectedChoice = (*choices)[selectedIndex];
+
+ if (state.lastSelectedChoice.isTerminator) {
+ displayDialogue(state.lastSelectedChoice.text, ALFRED_COLOR);
+ return dataSize; // End conversation
+ }
+
+ uint32 position = (*choices)[selectedIndex].dataOffset;
+ state.currentChoiceLevel = (*choices)[selectedIndex].choiceIndex;
+
+ // Read and display the selected choice as dialogue
+ Common::String choiceText;
+ byte choiceSpeakerId;
+ uint32 endPos = readTextBlock(data, dataSize, position, choiceText, choiceSpeakerId);
+
+ if (!choiceText.empty() && choiceText.size() > 1) {
+ displayDialogue(choiceText, ALFRED_COLOR);
+
+ // Only disable FB choice if all sub-branches are exhausted
+ if ((*choices)[selectedIndex].shouldDisableOnSelect) {
+ bool shouldDisable = checkAllSubBranchesExhausted(data, dataSize, endPos, state.currentChoiceLevel);
+ if (shouldDisable) {
+ debug("Disabling one-time choice at index %d after selection", selectedIndex);
+ g_engine->_room->addDisabledChoice((*choices)[selectedIndex]);
+ }
+ }
+ }
+
+ position = endPos;
+
+ // Skip past end marker
+ if (position < dataSize) {
+ byte endByte = data[position];
+ if (endByte == CTRL_END_TEXT || endByte == CTRL_END_BRANCH ||
+ endByte == CTRL_ACTION_TRIGGER) {
+ position++;
+ }
+ }
+
+ return position;
+}
void DialogManager::sayAlfred(Common::StringArray texts) {
g_engine->_alfredState.setState(ALFRED_TALKING);
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 03c578ca35e..3c42ed7dff9 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -50,6 +50,22 @@ namespace Pelrock {
#define CTRL_ALT_END_MARKER_2 0xEB /* Alt end marker 2 */
#define CTRL_ALT_SPEAKER_ROOT 0xFE /* Separates conversations from different speakers */
+// Helper structures for conversation state management
+struct ConversationState {
+ uint32 position;
+ int currentChoiceLevel;
+ uint32 lastChoiceMenuPosition;
+ ChoiceOption lastSelectedChoice;
+ int currentRoot;
+};
+
+struct ConversationEndResult {
+ bool shouldEnd;
+ uint32 nextPosition;
+ uint16 actionCode;
+ bool hasAction;
+};
+
class DialogManager {
private:
Graphics::Screen *_screen = nullptr;
@@ -67,6 +83,16 @@ private:
void checkMouse();
bool checkAllSubBranchesExhausted(const byte *data, uint32 dataSize, uint32 startPos, int currentChoiceLevel);
+ // Refactored helper functions for startConversation
+ uint32 skipControlBytes(const byte *data, uint32 dataSize, uint32 position);
+ uint32 peekNextMeaningfulByte(const byte *data, uint32 dataSize, uint32 position);
+ ConversationState initializeConversation(const byte *data, uint32 dataSize, byte npcIndex);
+ bool handleGoBack(const byte *data, uint32 position, ConversationState &state);
+ uint32 readAndDisplayDialogue(const byte *data, uint32 dataSize, uint32 position);
+ ConversationEndResult checkConversationEnd(const byte *data, uint32 dataSize, uint32 position);
+ void addGoodbyeOptionIfNeeded(Common::Array<ChoiceOption> *choices, int currentChoiceLevel, uint originalChoiceCount);
+ uint32 processChoiceSelection(const byte *data, uint32 dataSize, Common::Array<ChoiceOption> *choices, int selectedIndex, ConversationState &state);
+
public:
DialogManager(Graphics::Screen *screen, PelrockEventManager *events, GraphicsManager *graphics);
~DialogManager();
@@ -74,6 +100,8 @@ public:
void displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer);
int selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer);
void startConversation(const byte *conversationData, uint32 dataSize, byte npcIndex, Sprite *alfredAnimSet = nullptr);
+ uint32 findRoot(int ¤tRoot, uint32 position, uint32 dataSize, const byte *conversationData);
+ uint32 findSpeaker(byte npcIndex, uint32 dataSize, const byte *conversationData);
void sayAlfred(Description description);
void sayAlfred(Common::StringArray texts);
void say(Common::StringArray texts, byte spriteIndex = 0);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 50a72e96a7a..26bf9867463 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -155,7 +155,7 @@ void PelrockEngine::init() {
loadAnims();
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
- setScreen(23, ALFRED_DOWN);
+ setScreen(22, ALFRED_DOWN);
// setScreen(9, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
@@ -1632,7 +1632,6 @@ void PelrockEngine::checkMouseHover() {
if (hotspotIndex != -1) {
hotspotDetected = true;
- debug("Hotspot detected: %s", _room->_currentRoomDescriptions[hotspotIndex].text.c_str());
_hoveredMapLocation = _room->_currentRoomDescriptions[hotspotIndex].text;
}
else if (!alfredDetected) {
Commit: c27335f3623e316f4621d9152ba4da9cade5e836
https://github.com/scummvm/scummvm/commit/c27335f3623e316f4621d9152ba4da9cade5e836
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:58+02:00
Commit Message:
PELROCK: Implements cascade disable of choice trees in conversations
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/room.cpp
engines/pelrock/sound.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 828c500170b..d99c2fec6dd 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+#include "common/stack.h"
#include "pelrock/dialog.h"
#include "dialog.h"
@@ -80,7 +81,7 @@ uint32 DialogManager::readTextBlock(
int lineIndex = data[++pos];
pos++; // blank
- debug("Reading text block starting at pos %u, line index %d, speaker ID %d", startPos, lineIndex, outSpeakerId);
+ // debug("Reading text block starting at pos %u, line index %d, speaker ID %d", startPos, lineIndex, outSpeakerId);
// Read text until control byte
while (pos < dataSize) {
byte b = data[pos];
@@ -223,7 +224,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (_events->_leftMouseClicked) {
_events->_leftMouseClicked = false;
- debug("Dialogue click to advance, current page: %d, totalPages: %d", curPage, (int)dialogueLines.size());
+ // debug("Dialogue click to advance, current page: %d, totalPages: %d", curPage, (int)dialogueLines.size());
if (curPage < (int)dialogueLines.size() - 1) {
curPage++;
} else {
@@ -239,6 +240,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
}
void DialogManager::displayDialogue(Common::String text, byte speakerId) {
+ debug("Displaying dialogue: \"%s\" (Speaker ID: %d)", text.c_str(), speakerId);
displayDialogue(wordWrap(text), speakerId);
}
@@ -464,13 +466,13 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// Initialize conversation state
ConversationState state = initializeConversation(conversationData, dataSize, npcIndex);
bool skipToChoices = false;
-
+ Common::Stack<uint32> positionStack; // Stack to handle nested branches for "go back" functionality
// Main conversation loop
while (state.position < dataSize && !g_engine->shouldQuit()) {
state.position = skipControlBytes(conversationData, dataSize, state.position);
if (state.position < dataSize && conversationData[state.position] == CTRL_GO_BACK) {
- if (handleGoBack(conversationData, state.position, state)) {
+ if (handleGoBack(conversationData, positionStack, state.position, state)) {
skipToChoices = true;
} else {
break; // End conversation if no previous menu
@@ -513,7 +515,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// Parse choices
skipToChoices = false;
- state.lastChoiceMenuPosition = state.position;
+ uint32 positionAtChoices = state.position;
Common::Array<ChoiceOption> *choices = new Common::Array<ChoiceOption>();
parseChoices(conversationData, dataSize, state.position, choices);
@@ -526,12 +528,23 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
debug(" Choice %u (index %d): \"%s\" (Disabled: %s)", i, (*choices)[i].choiceIndex, (*choices)[i].text.c_str(),
(*choices)[i].isDisabled ? "Yes" : "No");
}
+ debug("-----------------------");
if (choices->empty()) {
- state.position = peekPos;
+ state.position = positionStack.empty() ? 0 : positionStack.pop();
+ if(state.position == 0) {
+ debug("No choices and no previous position to go back to, ending conversation");
+ break;
+ }
+ checkAllSubBranchesExhausted(conversationData, dataSize, state.position, state.currentChoiceLevel-1);
+ debug("No choices found, popping back to previous choice menu, position %u", state.position);
+ skipToChoices = true;
+ // state.position = peekPos;
continue;
}
+ positionStack.push(positionAtChoices); // Push position of this choice menu onto stack for potential "go back"
+
// Validate choice level
if (state.currentChoiceLevel >= 0) {
bool foundExpectedLevel = false;
@@ -637,7 +650,6 @@ ConversationState DialogManager::initializeConversation(const byte *data, uint32
state.currentRoot = 0;
state.position = findRoot(state.currentRoot, state.position, dataSize, data);
state.currentChoiceLevel = -1;
- state.lastChoiceMenuPosition = 0;
state.lastSelectedChoice = ChoiceOption();
// Skip any junk at start until we find a speaker marker
@@ -649,25 +661,30 @@ ConversationState DialogManager::initializeConversation(const byte *data, uint32
}
// Handle F0 "Go Back" control byte
-bool DialogManager::handleGoBack(const byte *data, uint32 position, ConversationState &state) {
+// When F0 is hit, all choices at the current level have been exhausted.
+// The cascading disable in disableChoiceIfNeeded should have already disabled
+// the choices that led here. We just need to go back to the parent level.
+bool DialogManager::handleGoBack(const byte *data, Common::Stack<uint32> &positionStack, uint32 position, ConversationState &state) {
if (data[position] != CTRL_GO_BACK) {
return false;
}
- debug("F0 Go Back at position %u, rewinding to lastChoiceMenuPosition %u", position, state.lastChoiceMenuPosition);
+ debug("F0 Go Back hit at position %u, current level %d", position, state.currentChoiceLevel);
- if (state.lastChoiceMenuPosition > 0) {
- // Disable the choice that led to this F0
- if (state.lastSelectedChoice.dataOffset > 0) {
- debug("F0: Disabling choice that led here at offset %u", state.lastSelectedChoice.dataOffset);
- g_engine->_room->addDisabledChoice(state.lastSelectedChoice);
- }
- state.position = state.lastChoiceMenuPosition;
- return true; // Skip to choices
- } else {
- debug("F0: No previous choice menu, ending conversation");
- return false; // End conversation
+ // Pop position stack - we're going back to parent level
+ uint32 parentPos = positionStack.empty() ? 0 : positionStack.pop();
+
+ if (parentPos == 0) {
+ debug("F0: No parent position on stack, ending conversation");
+ return false;
}
+
+ // Go up one level
+ state.currentChoiceLevel--;
+ state.position = parentPos;
+ debug("F0: Moved back to level %d, position %u", state.currentChoiceLevel, parentPos);
+
+ return true;
}
uint32 DialogManager::readAndDisplayDialogue(const byte *data, uint32 dataSize, uint32 position) {
@@ -779,15 +796,8 @@ uint32 DialogManager::processChoiceSelection(
if (!choiceText.empty() && choiceText.size() > 1) {
displayDialogue(choiceText, ALFRED_COLOR);
-
- // Only disable FB choice if all sub-branches are exhausted
- if ((*choices)[selectedIndex].shouldDisableOnSelect) {
- bool shouldDisable = checkAllSubBranchesExhausted(data, dataSize, endPos, state.currentChoiceLevel);
- if (shouldDisable) {
- debug("Disabling one-time choice at index %d after selection", selectedIndex);
- g_engine->_room->addDisabledChoice((*choices)[selectedIndex]);
- }
- }
+ debug("Will check if choice should be disabled after displaying dialogue");
+ disableChoiceIfNeeded(choices, selectedIndex, data, dataSize, endPos, state);
}
position = endPos;
@@ -803,6 +813,94 @@ uint32 DialogManager::processChoiceSelection(
return position;
}
+void DialogManager::disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> *choices, int selectedIndex, const byte *data, uint32 dataSize, uint32 endPos, Pelrock::ConversationState &state) {
+ // Cascading parent disable:
+ // 1. Check if current choice's sub-branches are exhausted
+ // 2. If so AND it's 0xFB, disable the current choice
+ // 3. Go up to parent level, check if parent's sub-branches are exhausted
+ // 4. Continue until we find a level with active sub-branches or reach level 1
+
+ // Start with the currently selected choice
+ int currentLevel = state.currentChoiceLevel;
+ uint32 currentChoicePos = (*choices)[selectedIndex].dataOffset;
+ bool isCurrentFB = (*choices)[selectedIndex].shouldDisableOnSelect;
+
+ while (currentLevel >= 1) {
+ // Check if all sub-branches at this level are exhausted
+ bool allExhausted = checkAllSubBranchesExhausted(data, dataSize, currentChoicePos + 4, currentLevel);
+
+ if (!allExhausted) {
+ debug("Cascading disable stopped at level %d - active sub-branches found", currentLevel);
+ break;
+ }
+
+ // Check if this choice is F1 (repeatable) - don't disable
+ if (!isCurrentFB) {
+ debug("Choice at level %d is repeatable (F1), stopping cascade", currentLevel);
+ break;
+ }
+
+ // Disable this one-time choice
+ debug("Cascading disable: level %d, offset %u", currentLevel, currentChoicePos);
+ ChoiceOption choiceToDisable;
+ choiceToDisable.room = g_engine->_room->_currentRoomNumber;
+ choiceToDisable.dataOffset = currentChoicePos;
+ choiceToDisable.choiceIndex = currentLevel;
+ choiceToDisable.shouldDisableOnSelect = true;
+ g_engine->_room->addDisabledChoice(choiceToDisable);
+
+ // Stop if we've reached level 1
+ if (currentLevel <= 1) {
+ debug("Reached level 1, stopping cascading disable");
+ break;
+ }
+
+ // Go up one level - scan backwards to find the parent FB/F1 marker at (currentLevel - 1)
+ currentLevel--;
+ uint32 scanPos = currentChoicePos;
+ bool foundParent = false;
+
+ while (scanPos > 0) {
+ scanPos--;
+ byte b = data[scanPos];
+
+ // Found 0xFB marker
+ if (b == CTRL_DIALOGUE_MARKER_ONEOFF && scanPos + 1 < dataSize) {
+ byte idx = data[scanPos + 1];
+ if (idx == (byte)currentLevel) {
+ currentChoicePos = scanPos;
+ isCurrentFB = true;
+ foundParent = true;
+ debug("Found parent FB at level %d, pos %u", currentLevel, currentChoicePos);
+ break;
+ }
+ }
+ // Found 0xF1 marker (repeatable)
+ else if (b == CTRL_DIALOGUE_MARKER && scanPos + 1 < dataSize) {
+ byte idx = data[scanPos + 1];
+ if (idx == (byte)currentLevel) {
+ // Found 0xF1 parent - will stop cascade on next iteration
+ currentChoicePos = scanPos;
+ isCurrentFB = false;
+ foundParent = true;
+ debug("Found parent 0xF1 at level %d, pos %u - will stop cascade", currentLevel, currentChoicePos);
+ break;
+ }
+ }
+
+ // Hit boundary markers - stop searching
+ if (b == CTRL_ALT_SPEAKER_ROOT || b == CTRL_END_BRANCH || b == CTRL_ALT_END_MARKER_1) {
+ debug("Hit boundary at pos %u while looking for parent level %d", scanPos, currentLevel);
+ break;
+ }
+ }
+
+ if (!foundParent) {
+ debug("Could not find parent at level %d, stopping cascade", currentLevel);
+ break;
+ }
+ }
+}
void DialogManager::sayAlfred(Common::StringArray texts) {
g_engine->_alfredState.setState(ALFRED_TALKING);
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 3c42ed7dff9..44361644696 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -22,6 +22,7 @@
#define PELROCK_DIALOG_H
#include "common/scummsys.h"
+#include "common/stack.h"
#include "graphics/screen.h"
#include "pelrock/events.h"
@@ -54,7 +55,6 @@ namespace Pelrock {
struct ConversationState {
uint32 position;
int currentChoiceLevel;
- uint32 lastChoiceMenuPosition;
ChoiceOption lastSelectedChoice;
int currentRoot;
};
@@ -87,11 +87,12 @@ private:
uint32 skipControlBytes(const byte *data, uint32 dataSize, uint32 position);
uint32 peekNextMeaningfulByte(const byte *data, uint32 dataSize, uint32 position);
ConversationState initializeConversation(const byte *data, uint32 dataSize, byte npcIndex);
- bool handleGoBack(const byte *data, uint32 position, ConversationState &state);
+ bool handleGoBack(const byte *data, Common::Stack<uint32> &positionStack, uint32 position, ConversationState &state);
uint32 readAndDisplayDialogue(const byte *data, uint32 dataSize, uint32 position);
ConversationEndResult checkConversationEnd(const byte *data, uint32 dataSize, uint32 position);
void addGoodbyeOptionIfNeeded(Common::Array<ChoiceOption> *choices, int currentChoiceLevel, uint originalChoiceCount);
uint32 processChoiceSelection(const byte *data, uint32 dataSize, Common::Array<ChoiceOption> *choices, int selectedIndex, ConversationState &state);
+ void disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> * choices, int selectedIndex, const byte * data, uint32 dataSize, uint32 endPos, Pelrock::ConversationState & state);
public:
DialogManager(Graphics::Screen *screen, PelrockEventManager *events, GraphicsManager *graphics);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 7e73944bc46..2433cf5e920 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -1082,6 +1082,8 @@ void RoomManager::addDisabledChoice(ChoiceOption choice) {
uint32 disableOffset = choice.dataOffset + 2;
debug("Adding disabled branch for room %d at offset %d (FA written at %d)",
choice.room, choice.dataOffset, disableOffset);
+
+ debug("Disabled branch is: \"%s\"", choice.text.c_str());
ResetEntry resetEntry = ResetEntry();
resetEntry.room = choice.room;
resetEntry.offset = disableOffset;
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 55f0edf0a55..be2d885d732 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -93,7 +93,7 @@ void SoundManager::playSound(SonidoFile sound, int volume, int channel) {
// Create raw audio stream (8-bit unsigned mono is common for old games)
stream = Audio::makeRawStream(pcmData, pcmSize, sampleRate, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
} else {
- debug("Unknown sound format at offset %d, with size %d", sound.offset, sound.size);
+ debug("Unknown sound format on sound with name %s at offset %d, with size %d", sound.filename.c_str(), sound.offset, sound.size);
delete[] data;
return;
}
Commit: 90c330d3454939828606fbbc19dd03d6b8a3027d
https://github.com/scummvm/scummvm/commit/90c330d3454939828606fbbc19dd03d6b8a3027d
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:59+02:00
Commit Message:
PELROCK: Room 22 actions
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/sound.cpp
engines/pelrock/types.h
engines/pelrock/util.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index d4e5d51e72d..83609979d8b 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -273,50 +273,85 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 279:
travelToEgypt();
break;
- // moros
+ // moros
+ case 317:
+ addInventoryItem(95);
+ break;
case 330:
+ // Two oranges
+ addInventoryItem(103);
break;
case 331:
+ _dialog->say(_res->_ingameTexts[HECHOELPRIMO]);
break;
case 332:
+ //psychologist card
+ if(!_state->hasInventoryItem(104)) {
+ addInventoryItem(104);
+ }
break;
case 333:
+ _dialog->say(_res->_ingameTexts[MEHANTOMADO_EL_PELO]);
break;
case 334:
+ addInventoryItem(86);
+ _state->setRootDisabledState(room, rootIndex, true);
+
break;
case 335:
+ //many oranges
+ addInventoryItem(104);
break;
case 336:
+ _dialog->say(_res->_ingameTexts[PESADO_UNRATO]);
break;
case 337:
- break;
case 338:
- break;
case 339:
- break;
case 340:
- break;
case 341:
- break;
case 342:
- break;
case 343:
- break;
case 344:
- break;
case 345:
- break;
case 346:
+ _state->setRootDisabledState(room, rootIndex, true);
break;
- case 347:
- break;
- case 348:
- break;
+ case 348: {
+ //game originally crashes here intentionally!
+ g_system->quit();
+ }
case 349:
+ _state->setFlag(FLAG_CONSIGNAS_VENDEDOR, _state->getFlag(FLAG_CONSIGNAS_VENDEDOR) + 1);
+ if (_state->getFlag(FLAG_CONSIGNAS_VENDEDOR) == 2) {
+ _state->setRootDisabledState(room, rootIndex, true);
+ }
break;
case 350:
+ _state->setFlag(FLAG_CONSIGNAS_VENDEDOR, _state->getFlag(FLAG_CONSIGNAS_VENDEDOR) + 1);
+ if (_state->getFlag(FLAG_CONSIGNAS_VENDEDOR) == 2) {
+ _state->setRootDisabledState(room, rootIndex, true);
+ }
break;
case 351:
+ _dialog->say(_res->_ingameTexts[TRAIDOR], 0);
+ _dialog->say(_res->_ingameTexts[TUTIA], 1);
+ _dialog->say(_res->_ingameTexts[LATUYA], 0);
+ _dialog->say(_res->_ingameTexts[GORDO], 1);
+ _dialog->say(_res->_ingameTexts[FIDEO], 0);
+ _dialog->say(_res->_ingameTexts[LIMPIACULO], 1);
+ _dialog->say(_res->_ingameTexts[CONTUTURBANTE], 0);
+ _dialog->say(_res->_ingameTexts[OSO], 1);
+ _dialog->say(_res->_ingameTexts[COMADREJA], 0);
+ _dialog->say(_res->_ingameTexts[CABEZON], 1);
+ _dialog->say(_res->_ingameTexts[TUABUELO], 0);
+ _dialog->say(_res->_ingameTexts[TUMUJER], 1);
+ _dialog->say(_res->_ingameTexts[PERDEDOR], 0);
+ _dialog->say(_res->_ingameTexts[SOYMEJORQUETU], 1);
+ _dialog->say(_res->_ingameTexts[TRAMPOSO], 0);
+ _dialog->say(_res->_ingameTexts[MALPERDEDOR], 1);
+ _dialog->say(_res->_ingameTexts[PARAUNAVEZ], 0);
+ _dialog->say(_res->_ingameTexts[MEJORMELARGO], 1);
break;
// end moros
default:
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index a187a70ebf4..9ff2fa9fd2e 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -473,6 +473,9 @@ const ExtraImages extraScreens[] = {
{0x152A88, // portrait
0x15BFC8,
8},
+ {2727564, // CD
+ 2833276,
+ 8}
};
struct AlfredSpecialAnimOffset {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 26bf9867463..3de1df77290 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -488,7 +488,7 @@ void PelrockEngine::checkMouse() {
_actionPopupState.isActive = false;
// Mouse was released while popup is active
VerbIcon actionClicked = isActionUnder(_events->_releaseX, _events->_releaseY);
- if(actionClicked != NO_ACTION) {
+ if (actionClicked != NO_ACTION) {
debug("Popup action clicked: %d, is alfredunder %d", actionClicked, _actionPopupState.isAlfredUnder);
}
if (actionClicked != NO_ACTION && _currentHotspot != nullptr) {
@@ -497,7 +497,7 @@ void PelrockEngine::checkMouse() {
} else if (_actionPopupState.isAlfredUnder && actionClicked != NO_ACTION) {
debug("Using item on Alfred");
useOnAlfred(_state->selectedInventoryItem);
- } else {
+ } else {
// Released outside popup - just close it
_queuedAction = QueuedAction{NO_ACTION, -1, false};
_currentHotspot = nullptr;
@@ -1042,7 +1042,6 @@ void PelrockEngine::drawAlfred(byte *buf) {
int finalHeight = scaleCalc.scaledHeight;
int finalWidth = scaleCalc.scaledWidth;
-
// Update Alfred's scale state for use by other functions
_alfredState.w = finalWidth;
_alfredState.h = finalHeight;
@@ -1420,13 +1419,12 @@ Common::Point getPositionInOverlayForIndex(uint index) {
return Common::Point(5 + index * (60 + 2), 400 - 60 - 5);
}
-
void PelrockEngine::pickupIconFlash() {
_graphics->showOverlay(65, _compositeBuffer);
if (_newItem == -1)
return;
uint invSize = _state->inventoryItems.size();
- for( int i = 0; i < invSize; i++) {
+ for (int i = 0; i < invSize; i++) {
Common::Point p = getPositionInOverlayForIndex(i);
drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->inventoryItems[i]).iconData, p.x, p.y, 60, 60, 1);
}
@@ -1446,6 +1444,9 @@ void PelrockEngine::gameLoop() {
if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_m) {
travelToEgypt();
}
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_n) {
+ loadExtraScreenAndPresent(10);
+ }
renderScene();
// _events->waitForKey();
_screen->update();
@@ -1574,8 +1575,8 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
bool PelrockEngine::isAlfredUnder(int x, int y) {
int localX = x - _alfredState.x;
- int localY = y - _alfredState.y + _alfredState.h; // Adjust for scaling (since Alfred's position is based on his feet, but sprite may be scaled from the top)
- if (localX >= 0 && localX < _alfredState.w && localY >= 0 && localY < _alfredState.h) {
+ int localY = y - _alfredState.y + _alfredState.h; // Adjust for scaling (since Alfred's position is based on his feet, but sprite may be scaled from the top)
+ if (_alfredSprite != nullptr && localX >= 0 && localX < _alfredState.w && localY >= 0 && localY < _alfredState.h) {
byte pixel = _alfredSprite[localY * _alfredState.w + localX];
if (pixel != 255) {
return true;
@@ -1633,12 +1634,11 @@ void PelrockEngine::checkMouseHover() {
if (hotspotIndex != -1) {
hotspotDetected = true;
_hoveredMapLocation = _room->_currentRoomDescriptions[hotspotIndex].text;
- }
- else if (!alfredDetected) {
+ } else if (!alfredDetected) {
_hoveredMapLocation = "";
}
- if(_room->_currentRoomNumber == 21) {
+ if (_room->_currentRoomNumber == 21) {
return;
}
@@ -1649,7 +1649,6 @@ void PelrockEngine::checkMouseHover() {
// Calculate walk target first (before checking anything else)
Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, hotspotDetected, hotspotDetected ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
-
// Check if walk target hits any exit
bool exitDetected = false;
Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index be2d885d732..4738fe93744 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -108,7 +108,7 @@ void SoundManager::playSound(SonidoFile sound, int volume, int channel) {
_mixer->stopHandle(_sfxHandles[channel]);
}
}
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
+ // _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
}
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index e6bff318382..87dd315c631 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -505,8 +505,9 @@ struct ResetEntry {
#define FLAG_GUARDIA_PIDECOSAS 49
#define FLAG_GUARDIA_DNI_ENTREGADO 50
#define FLAG_AGENCIA_ABIERTA 51
+#define FLAG_CONSIGNAS_VENDEDOR 52
-const int kNumGameFlags = 52;
+const int kNumGameFlags = 53;
struct GameStateData {
byte flags[kNumGameFlags];
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 31bab7e10e0..709614e875d 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -89,7 +89,7 @@ void drawText(byte *screenBuffer, Graphics::Font *font, Common::String text, int
for (int px = 0; px < bboxW; px++) {
int destIdx = (y + py) * 640 + (x + px);
int pixelColor = *((byte *)surface.getBasePtr(px, py));
- if(pixelColor != 255)
+ if(pixelColor != 255 && destIdx >= 0 && destIdx < 256000)
screenBuffer[destIdx] = pixelColor;
}
}
Commit: 876544feb332612c064bf3675aaa9ce1972c9f05
https://github.com/scummvm/scummvm/commit/876544feb332612c064bf3675aaa9ce1972c9f05
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:59+02:00
Commit Message:
PELROCK: Fixes shading bug
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 83609979d8b..c8e998d48b2 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -354,6 +354,18 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_dialog->say(_res->_ingameTexts[MEJORMELARGO], 1);
break;
// end moros
+ //puta 2
+ case 352:
+ break;
+ case 353:
+ break;
+ case 354:
+ break;
+ case 355:
+ break;
+ case 356:
+ break;
+ //end puta
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 3de1df77290..f971194c1d8 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1057,12 +1057,29 @@ void PelrockEngine::drawAlfred(byte *buf) {
delete[] _alfredSprite;
_alfredSprite = scaledBuf;
- int shadowPos = _alfredState.y; // - finalHeight;
- bool shadeCharacter = _room->_pixelsShadows[shadowPos * 640 + _alfredState.x] != 0xFF;
- if (shadeCharacter) {
+ // Shadow detection: scan across Alfred's width at feet line.
+ // Original game scans shadow buffer
+ // at (topY + 0x66) * 640 + X + col for col = 0..width, where topY + 0x66 = feetY.
+ // The shadow map value (0-3) indexes into the palette remap tables.
+ byte shadowLevel = 0xFF; // 0xFF = no shadow
+ int feetY = _alfredState.y;
+ if (feetY >= 0 && feetY < 400 && _room->_pixelsShadows != nullptr) {
+ for (int col = 0; col < finalWidth; col++) {
+ int checkX = _alfredState.x + col;
+ if (checkX >= 0 && checkX < 640) {
+ byte shadowVal = _room->_pixelsShadows[feetY * 640 + checkX];
+ if (shadowVal != 0xFF) {
+ shadowLevel = shadowVal;
+ break; // Original breaks on first shadow pixel found
+ }
+ }
+ }
+ }
+
+ if (shadowLevel != 0xFF && shadowLevel < 4) {
for (int i = 0; i < finalWidth * finalHeight; i++) {
if (_alfredSprite[i] != 255) {
- _alfredSprite[i] = _room->_paletteRemaps[1][_alfredSprite[i]];
+ _alfredSprite[i] = _room->_paletteRemaps[3 - shadowLevel][_alfredSprite[i]];
}
}
}
Commit: 104e61136de7f226fd3e5259a16e6eda789c83c3
https://github.com/scummvm/scummvm/commit/104e61136de7f226fd3e5259a16e6eda789c83c3
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T12:59:59+02:00
Commit Message:
PELROCK: Palette effect on room 28
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index c8e998d48b2..7bf4000ad0b 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -113,6 +113,9 @@ const ActionEntry actionTable[] = {
{400, OPEN, &PelrockEngine::openTravelAgencyDoor},
{400, CLOSE, &PelrockEngine::closeTravelAgencyDoor},
+ // Room 28
+ {472, PICKUP, &PelrockEngine::pickUpRoom28Object},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -318,8 +321,9 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setRootDisabledState(room, rootIndex, true);
break;
case 348: {
- //game originally crashes here intentionally!
- g_system->quit();
+ // Anti-piracy punishment: corrupt screen + noise + crash
+ antiPiracyEffect();
+ break;
}
case 349:
_state->setFlag(FLAG_CONSIGNAS_VENDEDOR, _state->getFlag(FLAG_CONSIGNAS_VENDEDOR) + 1);
@@ -1080,6 +1084,130 @@ void PelrockEngine::waitForActionEnd() {
}
}
-// void checkOBjec
+/**
+ * Handler for picking up object with extra_id 472 in Room 28.
+ * Loads a special palette from ALFRED.7 at offset 0x1610CE and
+ * fades to it using the step-wise palette transition.
+ *
+ * Original handler at Ghidra address 0x1FED8.
+ */
+void PelrockEngine::pickUpRoom28Object(HotSpot *hotspot) {
+ // Load the special palette from ALFRED.7 at offset 0x1610CE
+ static const uint32 kRoom28PaletteOffset = 0x1610CE;
+
+ Common::File alfred7;
+ if (!alfred7.open(Common::Path("ALFRED.7"))) {
+ warning("Could not open ALFRED.7 for room 28 palette");
+ return;
+ }
+
+ byte targetPalette[768];
+ alfred7.seek(kRoom28PaletteOffset, SEEK_SET);
+ alfred7.read(targetPalette, 768);
+ alfred7.close();
+
+ // Convert 6-bit VGA palette (0-63) to 8-bit (0-255)
+ for (int i = 0; i < 768; i++) {
+ targetPalette[i] = targetPalette[i] << 2;
+ }
+
+ // Fade from current palette to the new palette
+ _graphics->fadePaletteToTarget(targetPalette, 25);
+ debug("Finished palette fade for room 28 object pickup");
+ // Pick up the item
+ // addInventoryItem(hotspot->extra);
+ _room->disableHotspot(hotspot);
+}
+
+/**
+ * Original behavior:
+ * 1. Stop all sound
+ * 2. Loop: corrupt the background buffer pointer with random values,
+ * copy garbage to screen, write sequential memory bytes to PC speaker
+ * port 0x61 to produce noise
+ * 3. On keypress: divide by zero -> crash to DOS
+ *
+ * ScummVM behavior:
+ * 1. Stop all sound
+ * 2. Loop: fill screen with random pixels, play white noise
+ * 3. On keypress: return to launcher
+ */
+void PelrockEngine::antiPiracyEffect() {
+ _sound->stopAllSounds();
+ _sound->stopMusic();
+
+ // Generate a buffer of white noise for the PC speaker simulation
+ const int kNoiseLength = 16000; // 1 second at 8kHz
+ byte *noiseData = new byte[kNoiseLength + 44]; // WAV header + data
+
+ // Write a minimal WAV header
+ memcpy(noiseData, "RIFF", 4);
+ WRITE_LE_UINT32(noiseData + 4, kNoiseLength + 36);
+ memcpy(noiseData + 8, "WAVE", 4);
+ memcpy(noiseData + 12, "fmt ", 4);
+ WRITE_LE_UINT32(noiseData + 16, 16); // chunk size
+ WRITE_LE_UINT16(noiseData + 20, 1); // PCM format
+ WRITE_LE_UINT16(noiseData + 22, 1); // mono
+ WRITE_LE_UINT32(noiseData + 24, 8000); // sample rate
+ WRITE_LE_UINT32(noiseData + 28, 8000); // byte rate
+ WRITE_LE_UINT16(noiseData + 32, 1); // block align
+ WRITE_LE_UINT16(noiseData + 34, 8); // bits per sample
+ memcpy(noiseData + 36, "data", 4);
+ WRITE_LE_UINT32(noiseData + 40, kNoiseLength);
+
+ // Fill with random noise (simulating garbage bytes written to port 0x61)
+ byte curNoise = (byte)getRandomNumber(255);
+ for (int i = 0; i < kNoiseLength; i++) {
+ noiseData[44 + i] = curNoise;
+ bool changeNoise = getRandomNumber(10) < 2; // 20% chance to change noise value
+ if (changeNoise) {
+ curNoise = (byte)getRandomNumber(255);
+ }
+ }
+
+ // Play the noise
+ _sound->playSound(noiseData, kNoiseLength + 44, 200);
+
+ byte *screenPixels = (byte *)_screen->getPixels();
+ int screenSize = _screen->pitch * _screen->h;
+
+ // Clear any pending key event before starting the loop
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+
+ while (!shouldQuit()) {
+ _events->pollEvent();
+
+ if (_events->_lastKeyEvent != Common::KEYCODE_INVALID) {
+ break;
+ }
+
+ //generate random pixels on the screen (simulating corrupted video memory)
+ for (int i = 0; i < screenSize; i++) {
+ screenPixels[i] = (byte)getRandomNumber(255);
+ }
+
+ // Regenerate noise periodically
+ for (int i = 0; i < kNoiseLength; i++) {
+ noiseData[44 + i] = curNoise;
+ bool changeNoise = getRandomNumber(10) < 2; // 20% chance to change noise value
+ if (changeNoise) {
+ curNoise = (byte)getRandomNumber(255);
+ }
+ }
+ if (!_sound->isPlaying()) {
+ _sound->playSound(noiseData, kNoiseLength + 44, 200);
+ }
+
+ _screen->markAllDirty();
+ _screen->update();
+ g_system->delayMillis(50);
+ }
+
+ _sound->stopAllSounds();
+ delete[] noiseData;
+
+ // Return to launcher
+ Engine::quitGame();
+}
} // End of namespace Pelrock
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index a9e9e2b1390..edff6cb44e3 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -105,6 +105,44 @@ void GraphicsManager::fadeToBlack() {
}
}
+/**
+ * Fades between two palettes by incrementally changing the current palette towards the target palette.
+ */
+void GraphicsManager::fadePaletteToTarget(byte *targetPalette, int stepSize) {
+ byte currentPalette[768];
+ memcpy(currentPalette, g_engine->_room->_roomPalette, 768);
+
+ while (!g_engine->shouldQuit()) {
+ g_engine->_events->pollEvent();
+
+ bool didRender = g_engine->renderScene(OVERLAY_NONE);
+ if (didRender) {
+ bool changed = false;
+
+ for (int i = 0; i < 768; i++) {
+ if (currentPalette[i] < targetPalette[i]) {
+ currentPalette[i] = MIN((int)currentPalette[i] + stepSize, (int)targetPalette[i]);
+ changed = true;
+ } else if (currentPalette[i] > targetPalette[i]) {
+ currentPalette[i] = MAX((int)currentPalette[i] - stepSize, (int)targetPalette[i]);
+ changed = true;
+ }
+ }
+
+ if (!changed)
+ break;
+
+ g_system->getPaletteManager()->setPalette(currentPalette, 0, 256);
+ }
+
+ g_engine->_screen->update();
+ g_system->delayMillis(10);
+ }
+
+ memcpy(g_engine->_room->_roomPalette, targetPalette, 768);
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+}
+
void GraphicsManager::clearScreen() {
memset(g_engine->_screen->getPixels(), 0, g_engine->_screen->pitch * g_engine->_screen->h);
}
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index a55e7749d73..8965a6b8464 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -35,6 +35,7 @@ public:
byte *grabBackgroundSlice(byte *buf, int x, int y, int w, int h);
void putBackgroundSlice(byte *buf, int x, int y, int w, int h, byte *slice);
void fadeToBlack();
+ void fadePaletteToTarget(byte *targetPalette, int stepSize);
void clearScreen();
};
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f971194c1d8..8238221944d 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1460,9 +1460,15 @@ void PelrockEngine::gameLoop() {
checkMouse();
if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_m) {
travelToEgypt();
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_n) {
loadExtraScreenAndPresent(10);
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_p) {
+ antiPiracyEffect();
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
renderScene();
// _events->waitForKey();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index b470c431f24..bb681c79bd9 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -318,6 +318,8 @@ public:
void closeMcDoor(HotSpot *hotspot);
void animateStatuePaletteFade(bool reverse = false);
+ void pickUpRoom28Object(HotSpot *hotspot);
+ void antiPiracyEffect();
void checkObjectsForPart2();
void waitForActionEnd();
};
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 16fc12d2b86..1cf969b758f 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -49,6 +49,7 @@ static const int unpickableHotspotExtras[] = {
360, // library shelves
361,
362,
+ 472, // matches
};
Commit: 99d7edabea19ba21dfc289b6a141f0cd133cc914
https://github.com/scummvm/scummvm/commit/99d7edabea19ba21dfc289b6a141f0cd133cc914
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:00+02:00
Commit Message:
PELROCK: Room 23
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 7bf4000ad0b..a2ca82dc2da 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -114,7 +114,7 @@ const ActionEntry actionTable[] = {
{400, CLOSE, &PelrockEngine::closeTravelAgencyDoor},
// Room 28
- {472, PICKUP, &PelrockEngine::pickUpRoom28Object},
+ {472, PICKUP, &PelrockEngine::pickUpMatches},
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
@@ -358,16 +358,26 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_dialog->say(_res->_ingameTexts[MEJORMELARGO], 1);
break;
// end moros
- //puta 2
- case 352:
- break;
case 353:
+ _state->setRootDisabledState(room, rootIndex, true);
+ _state->setRootDisabledState(room, rootIndex + 1, true);
break;
case 354:
+ if(_state->hasInventoryItem(105)) {
+ addInventoryItem(105);
+ }
break;
+ case 352:
case 355:
+ _graphics->fadeToBlack();
+ _alfredState.x = 342;
+ _alfredState.y = 277;
+ setScreen(31, ALFRED_DOWN);
break;
case 356:
+ _state->setRootDisabledState(room, 0, true);
+ _state->setRootDisabledState(room, 1, true);
+ _state->setRootDisabledState(room, 2, true);
break;
//end puta
default:
@@ -1091,7 +1101,7 @@ void PelrockEngine::waitForActionEnd() {
*
* Original handler at Ghidra address 0x1FED8.
*/
-void PelrockEngine::pickUpRoom28Object(HotSpot *hotspot) {
+void PelrockEngine::pickUpMatches(HotSpot *hotspot) {
// Load the special palette from ALFRED.7 at offset 0x1610CE
static const uint32 kRoom28PaletteOffset = 0x1610CE;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 8238221944d..85304337777 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1079,7 +1079,8 @@ void PelrockEngine::drawAlfred(byte *buf) {
if (shadowLevel != 0xFF && shadowLevel < 4) {
for (int i = 0; i < finalWidth * finalHeight; i++) {
if (_alfredSprite[i] != 255) {
- _alfredSprite[i] = _room->_paletteRemaps[3 - shadowLevel][_alfredSprite[i]];
+ // _alfredSprite[i] = _room->_paletteRemaps[3 - shadowLevel][_alfredSprite[i]];
+ _alfredSprite[i] = _room->_paletteRemaps[0][_alfredSprite[i]];
}
}
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index bb681c79bd9..482266a09d9 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -318,7 +318,7 @@ public:
void closeMcDoor(HotSpot *hotspot);
void animateStatuePaletteFade(bool reverse = false);
- void pickUpRoom28Object(HotSpot *hotspot);
+ void pickUpMatches(HotSpot *hotspot);
void antiPiracyEffect();
void checkObjectsForPart2();
void waitForActionEnd();
Commit: 1c366f311fc5d82c80e853d322e0e2702717c9c9
https://github.com/scummvm/scummvm/commit/1c366f311fc5d82c80e853d322e0e2702717c9c9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:00+02:00
Commit Message:
PELROCK: Implements crocodile animation
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/sound.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index a2ca82dc2da..5bbb5010e5a 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -135,10 +135,13 @@ const CombinationEntry combinationTable[] = {
{4, 294, &PelrockEngine::useBrickWithWindow},
{4, 295, &PelrockEngine::useBrickWithShopWindow},
{6, 315, &PelrockEngine::useCordWithPlug},
- {1, 53, &PelrockEngine::giveIdToGuard},
- {5, 53, &PelrockEngine::giveMoneyToGuard},
+ {1, 309, &PelrockEngine::giveIdToGuard},
+ {5, 309, &PelrockEngine::giveMoneyToGuard},
{7, 353, &PelrockEngine::useAmuletWithStatue},
- {8, 102, &PelrockEngine::giveSecretCodeToLibrarian},
+ {8, 353, &PelrockEngine::useSecretCodeWithStatue},
+ {8, 358, &PelrockEngine::giveSecretCodeToLibrarian},
+ {4, 358, &PelrockEngine::useBrickWithLibrarian}, // Any hotspot in the lamppost will work
+ {76, 469, &PelrockEngine::usePumpkinWithRiver},
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -212,7 +215,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setRootDisabledState(room, rootIndex, true);
break;
case 329:
- debug("Would now enable X easter egg");
+ _state->setFlag(FLAG_PUTA_250_VECES, true);
break;
case 258:
_state->setFlag(FLAG_GUARDIA_PIDECOSAS, true);
@@ -280,6 +283,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 317:
addInventoryItem(95);
break;
+
case 330:
// Two oranges
addInventoryItem(103);
@@ -369,7 +373,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
case 352:
case 355:
- _graphics->fadeToBlack();
+ _graphics->fadeToBlack(10);
_alfredState.x = 342;
_alfredState.y = 277;
setScreen(31, ALFRED_DOWN);
@@ -550,20 +554,20 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
// TODO: Animate sprite 8 (brick projectile) moving to window
Sprite *brickSprite = _room->findSpriteByIndex(7);
HotSpot *windowHotspot = _room->findHotspotByExtra(294);
- brickSprite->x = _alfredState.x - brickSprite->w / 2;
- brickSprite->y = _alfredState.y - kAlfredFrameHeight;
- brickSprite->zOrder = 20; // Make it visible
+ brickSprite->x = 420;
+ brickSprite->y = 241;
+ brickSprite->zOrder = 10; // Make it visible
int target = windowHotspot->y + windowHotspot->h / 2;
while (!shouldQuit()) {
_events->pollEvent();
renderScene(OVERLAY_NONE);
- if (_chrono->_gameTick) {
- _room->findSpriteByIndex(7)->y -= 40;
- if (_room->findSpriteByIndex(7)->y < target) {
+ // if (_chrono->_gameTick) {
+ _room->findSpriteByIndex(7)->y -= 10;
+ if (_room->findSpriteByIndex(7)->y <= 70) {
_room->findSpriteByIndex(7)->zOrder = -1;
break;
}
- }
+ // }
_screen->update();
g_system->delayMillis(10);
}
@@ -590,7 +594,7 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
_room->addStickerToRoom(_room->_currentRoomNumber, 10, PERSIST_PERM);
_room->disableHotspot(_room->findHotspotByExtra(295)); // Disable storefront hotspot
_room->disableHotspot(_room->findHotspotByExtra(294)); // Disable window hotspot
- walkTo(639, _alfredState.y);
+ walkTo(630, _alfredState.y);
}
void PelrockEngine::moveCable(HotSpot *hotspot) {
@@ -771,6 +775,10 @@ void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
}
}
+void PelrockEngine::useSecretCodeWithStatue(int inventoryObject, HotSpot *hotspot) {
+ _dialog->say(_res->_ingameTexts[NOESAMIAQUIENDEBES], 1);
+}
+
void PelrockEngine::pickUpLetter(HotSpot *hotspot) {
addInventoryItem(9);
_room->setActionMask(hotspot, ACTION_MASK_NONE); // Disable hotspot
@@ -810,6 +818,10 @@ void PelrockEngine::giveSecretCodeToLibrarian(int inventoryObject, HotSpot *hots
addInventoryItem(59);
}
+void PelrockEngine::useBrickWithLibrarian(int inventoryObject, HotSpot *hotspot) {
+ _dialog->say(_res->_ingameTexts[YSI_METIRA_MAQUINA]);
+}
+
void PelrockEngine::openNewspaperDoor(HotSpot *hotspot) {
openDoor(hotspot, 2, 50, MASCULINE, false);
}
@@ -838,6 +850,32 @@ void PelrockEngine::closeTravelAgencyDoor(HotSpot *hotspot) {
closeDoor(hotspot, 1, 57, FEMININE, false);
}
+void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
+ _sound->playMusicTrack(27);
+ _dialog->say(_res->_ingameTexts[PRIMERINGREDIENTE]);
+ _dialog->say(_res->_ingameTexts[CUIDADOIMPRUDENTE]);
+ _res->loadAlfredSpecialAnim(5);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ _alfredState.x -= 10;
+ _alfredState.y += 20;
+ waitForSpecialAnimation();
+ _sound->playSound(_room->_roomSfx[0], 100, 0); // Belch
+ bool isPlaying = true;
+ while (!shouldQuit() && isPlaying) {
+ _events->pollEvent();
+ isPlaying = _sound->isPlaying(0);
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+ _graphics->fadeToBlack(10);
+ //update conversaton state
+ _alfredState.x = 300;
+ _alfredState.y = 238;
+ setScreen(28, ALFRED_DOWN);
+ _dialog->say(_res->_ingameTexts[QUEOSCUROESTAESTO]);
+
+}
+
void PelrockEngine::pickUpBook(int i) {
if (!_state->hasInventoryItem(10)) {
_dialog->say(_res->_ingameTexts[VENGA_ACA]);
@@ -916,6 +954,12 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
debug("Using item %d on Alfred", inventoryObject);
switch (inventoryObject) {
+ case 9: // carta
+ _dialog->say(_res->_ingameTexts[CORRESPONDENCIA_AJENA]);
+ break;
+ case 34: // Como hacerse rico...
+ _dialog->say(_res->_ingameTexts[PERIODICOSENSACIONALISTA], 1);
+ break;
case 63: // Recipe
_res->loadAlfredSpecialAnim(1);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index edff6cb44e3..bda96e13442 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -72,7 +72,7 @@ void GraphicsManager::putBackgroundSlice(byte *buf, int x, int y, int w, int h,
}
}
-void GraphicsManager::fadeToBlack() {
+void GraphicsManager::fadeToBlack(int stepSize) {
byte palette[768];
g_system->getPaletteManager()->grabPalette(palette, 0, 256);
while (!g_engine->shouldQuit()) {
@@ -82,7 +82,7 @@ void GraphicsManager::fadeToBlack() {
for (int i = 0; i < 768; i++) {
if (palette[i] > 0) {
- palette[i] = MAX(palette[i] / 2, 0);
+ palette[i] = MAX(palette[i] - stepSize, 0);
}
}
g_system->getPaletteManager()->setPalette(palette, 0, 256);
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index 8965a6b8464..be2230e10a9 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -34,7 +34,7 @@ public:
Common::Point showOverlay(int height, byte *buf);
byte *grabBackgroundSlice(byte *buf, int x, int y, int w, int h);
void putBackgroundSlice(byte *buf, int x, int y, int w, int h, byte *slice);
- void fadeToBlack();
+ void fadeToBlack(int stepSize);
void fadePaletteToTarget(byte *targetPalette, int stepSize);
void clearScreen();
};
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 85304337777..28cb289d895 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -155,8 +155,8 @@ void PelrockEngine::init() {
loadAnims();
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
- setScreen(22, ALFRED_DOWN);
- // setScreen(9, ALFRED_DOWN);
+ // setScreen(22, ALFRED_DOWN);
+ setScreen(9, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -235,7 +235,7 @@ void PelrockEngine::playSoundIfNeeded() {
}
void PelrockEngine::travelToEgypt() {
- _graphics->fadeToBlack();
+ _graphics->fadeToBlack(10);
_sound->playMusicTrack(26, false);
byte *palette = new byte[768];
if (_extraScreen == nullptr) {
@@ -304,6 +304,23 @@ bool PelrockEngine::renderScene(int overlayMode) {
_screen->markAllDirty();
return true;
}
+
+ switch (_room->_currentRoomNumber) {
+ case 2: {
+ if (_events->_lastKeyEvent == Common::KEYCODE_x) {
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ debug("Pressed X in room 2, numPressedX is now %d, flag is %d", _numPressedX + 1, _state->getFlag(FLAG_PUTA_250_VECES));
+ if (_state->getFlag(FLAG_PUTA_250_VECES) == true) {
+ _numPressedX++;
+ if (_numPressedX == 250) {
+ _dialog->say(_res->_ingameTexts[YLOSCONDONES]);
+ }
+ }
+ }
+ break;
+ }
+ }
+
return false;
}
@@ -640,7 +657,6 @@ void PelrockEngine::placeStickersFirstPass() {
void PelrockEngine::placeStickersSecondPass() {
// Some stickers need to be placed AFTER sprites, hardcoded in the original
if (_room->_currentRoomNumber == 3) {
- debug("Placing second-pass stickers for room 3");
for (uint i = 0; i < _state->stickersPerRoom[3].size(); i++) {
if (_state->stickersPerRoom[3][i].stickerIndex == 14) {
placeSticker(_state->stickersPerRoom[3][i]);
@@ -1576,15 +1592,15 @@ AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
}
VerbIcon PelrockEngine::isActionUnder(int x, int y) {
- if (_currentHotspot == nullptr) {
+ /*if (_currentHotspot == nullptr) {
return NO_ACTION;
- }
+ }*/
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
int loopEnd = _state->selectedInventoryItem != -1 ? actions.size() + 1 : actions.size();
for (int i = 0; i < loopEnd; i++) {
Common::Point p = getPositionInBallonForIndex(i, _actionPopupState.x, _actionPopupState.y);
Common::Rect actionRect = Common::Rect(p.x, p.y, p.x + kVerbIconWidth, p.y + kVerbIconHeight);
-
+ debug("Checking action %d at rect (%d,%d) to (%d,%d) against mouse position %d,%d", i, actionRect.left, actionRect.top, actionRect.right, actionRect.bottom, x, y);
if (i == actions.size()) {
// Check inventory item
if (actionRect.contains(x, y)) {
@@ -1594,6 +1610,7 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
return actions[i];
}
}
+ debug("No action under mouse at position %d,%d", x, y);
return NO_ACTION;
}
@@ -1668,6 +1685,7 @@ void PelrockEngine::checkMouseHover() {
if (isActionUnder(_events->_mouseX, _events->_mouseY) != NO_ACTION) {
hotspotDetected = false;
+ debug("Mouse is over action icon, not hotspot, so showing action cursor");
}
// Calculate walk target first (before checking anything else)
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 482266a09d9..90560b89ba0 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -149,6 +149,8 @@ private:
Common::String _hoveredMapLocation = "";
byte *_alfredSprite = nullptr;
+ int _numPressedX = 0;
+
// int prevDirX = 0;
// int prevDirY = 0;
// Common::String objectToShow = "";
@@ -298,6 +300,7 @@ public:
void giveMoneyToGuard(int inventoryObject, HotSpot *hotspot);
void openMuseumDoor(HotSpot *hotspot);
void useAmuletWithStatue(int inventoryObject, HotSpot *hotspot);
+ void useSecretCodeWithStatue(int inventoryObject, HotSpot *hotspot);
void pickUpLetter(HotSpot *hotspot);
void openLibraryOutdoorsDoor(HotSpot *hotspot);
void closeLibraryOutdoorsDoor(HotSpot *hotspot);
@@ -307,12 +310,14 @@ public:
void pickBooksFromShelf2(HotSpot *hotspot);
void pickBooksFromShelf3(HotSpot *hotspot);
void giveSecretCodeToLibrarian(int inventoryObject, HotSpot *hotspot);
+ void useBrickWithLibrarian(int inventoryObject, HotSpot *hotspot);
void openNewspaperDoor(HotSpot *hotspot);
void closeNewspaperDoor(HotSpot *hotspot);
void openNewspaperBossDor(HotSpot *hotspot);
void closeNewspaperBossDoor(HotSpot *hotspot);
void openTravelAgencyDoor(HotSpot *hotspot);
void closeTravelAgencyDoor(HotSpot *hotspot);
+ void usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot);
void pickUpBook(int i);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index bc17308f07e..f7fa6e94803 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -42,6 +42,7 @@ const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
{3, 45, 87, 0, 7, 37000, 1}, // ELECTRIC SHOCK 1
{2, 82, 58, 0, 7, 53106, 20}, // ELECTRIC SHOCK 3
{3, 71, 110, 1, 2, 20724, 1, 62480}, // Throw
+ {14, 171, 107, 1, 7, 1556540, 1} , //crocodile
};
ResourceManager::~ResourceManager() {
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 2433cf5e920..495c43fce1e 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -894,8 +894,8 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
sprite.stride = READ_LE_INT16(data + animOffset + 6);
sprite.numAnims = data[animOffset + 8];
sprite.zOrder = data[animOffset + 23];
- sprite.extra = data[animOffset + 32];
- sprite.spriteType = data[animOffset + 33];
+ sprite.extra = READ_LE_INT16(data + animOffset + 32);
+ debug("Sprite %d: x=%d y=%d w=%d h=%d stride=%d numAnims=%d zOrder=%d extra=%d", i, sprite.x, sprite.y, sprite.w, sprite.h, sprite.stride, sprite.numAnims, sprite.zOrder, sprite.extra);
sprite.actionFlags = data[animOffset + 34];
sprite.isHotspotDisabled = data[animOffset + 38];
for (int j = 0; j < spriteChanges.size(); j++) {
@@ -908,7 +908,6 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
break;
}
sprite.animData = new Anim[sprite.numAnims];
- // debug("Sprite %d has %d sub-anims, type %d, actionFlags %d, isDisabled? %d", i, sprite.numAnims, sprite.spriteType, sprite.actionFlags, sprite.isHotspotDisabled);
int subAnimOffset = animOffset + 10;
for (int j = 0; j < sprite.numAnims; j++) {
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 4738fe93744..3b4e32d4331 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -108,7 +108,7 @@ void SoundManager::playSound(SonidoFile sound, int volume, int channel) {
_mixer->stopHandle(_sfxHandles[channel]);
}
}
- // _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
}
}
@@ -213,7 +213,7 @@ void SoundManager::playMusicTrack(int trackNumber, bool loop) {
}
_currentMusicTrack = trackNumber;
g_system->getAudioCDManager()->stop();
- // g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 0, 0, 0);
+ g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 0, 0, 0);
}
void SoundManager::loadSoundIndex() {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 87dd315c631..2028f549702 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -231,13 +231,13 @@ struct Sprite {
uint16 stride; // 6-7
int numAnims; // 8
int curAnimIndex = 0;
- int8 zOrder;
- byte spriteType; // 33
+ int8 zOrder; //32-33
+
byte actionFlags; // 34
bool isHotspotDisabled; // 38
bool isTalking = false;
Anim *animData;
- byte extra;
+ int16 extra;
};
struct HotSpot {
@@ -506,8 +506,9 @@ struct ResetEntry {
#define FLAG_GUARDIA_DNI_ENTREGADO 50
#define FLAG_AGENCIA_ABIERTA 51
#define FLAG_CONSIGNAS_VENDEDOR 52
+#define FLAG_PUTA_250_VECES 53
-const int kNumGameFlags = 53;
+const int kNumGameFlags = 54;
struct GameStateData {
byte flags[kNumGameFlags];
Commit: 186db8d250dcd87da683c07a129ebb264c0709b1
https://github.com/scummvm/scummvm/commit/186db8d250dcd87da683c07a129ebb264c0709b1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:00+02:00
Commit Message:
PELROCK: Sfx in menu
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 5bbb5010e5a..c5832e1c4d6 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -113,9 +113,13 @@ const ActionEntry actionTable[] = {
{400, OPEN, &PelrockEngine::openTravelAgencyDoor},
{400, CLOSE, &PelrockEngine::closeTravelAgencyDoor},
+ // Room 25
+ {609, PICKUP, &PelrockEngine::pickupSunflower},
+
// Room 28
{472, PICKUP, &PelrockEngine::pickUpMatches},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -131,7 +135,7 @@ const ActionEntry actionTable[] = {
const CombinationEntry combinationTable[] = {
{2, 281, &PelrockEngine::useCardWithATM},
- {62, 117, &PelrockEngine::useSpicySauceWithBurger},
+ {62, 373, &PelrockEngine::useSpicySauceWithBurger},
{4, 294, &PelrockEngine::useBrickWithWindow},
{4, 295, &PelrockEngine::useBrickWithShopWindow},
{6, 315, &PelrockEngine::useCordWithPlug},
@@ -373,10 +377,8 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
case 352:
case 355:
- _graphics->fadeToBlack(10);
- _alfredState.x = 342;
- _alfredState.y = 277;
- setScreen(31, ALFRED_DOWN);
+ //a la carcel
+ toJail();
break;
case 356:
_state->setRootDisabledState(room, 0, true);
@@ -384,12 +386,61 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setRootDisabledState(room, 2, true);
break;
//end puta
+ // sabio
+ case 366:
+ _state->setRootDisabledState(room, rootIndex, true);
+ break;
+ case 363:
+ toJail();
+ break;
+ case 367: //accept riddle
+ _state->setRootDisabledState(room, 26, true);
+ walkAndAction(_room->findHotspotByExtra(467), TALK);
+ break;
+// hasta aqui
+
+ case 357: // mal
+ _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) - 1);
+ _state->setRootDisabledState(room, rootIndex, true);
+ break;
+ case 358: // muy mal
+ _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) - 2);
+ _state->setRootDisabledState(room, rootIndex, true);
+ break;
+ case 359: // bien
+ _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) + 1);
+ if(_state->getFlag(FLAG_RESPUESTAS_ACERTADAS) == 15) {
+ addInventoryItem(106); // pin
+ _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, 0);
+
+ }
+ _state->setRootDisabledState(room, rootIndex, true);
+ break;
+ case 360:
+
+ case 361:
+ _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, 0);
+ //back to conversation 27
+ case 362:
+//?
+ case 365:
+ //correct
+ case 364:
+ //wrong
+
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
}
}
+void PelrockEngine::toJail() {
+ _graphics->fadeToBlack(10);
+ _alfredState.x = 342;
+ _alfredState.y = 277;
+ setScreen(31, ALFRED_DOWN);
+}
+
void PelrockEngine::noOpAction(HotSpot *hotspot) {
}
@@ -521,6 +572,7 @@ void PelrockEngine::openKitchenDoorFromInside(HotSpot *hotspot) {
void PelrockEngine::useSpicySauceWithBurger(int inventoryObject, HotSpot *hotspot) {
_state->setFlag(FLAG_PUESTA_SALSA_PICANTE, true);
+ _sound->playSound(_room->_roomSfx[2]);
_dialog->say(_res->_ingameTexts[VAESTAR_POCOFUERTE]);
}
@@ -873,9 +925,23 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
_alfredState.y = 238;
setScreen(28, ALFRED_DOWN);
_dialog->say(_res->_ingameTexts[QUEOSCUROESTAESTO]);
+}
+void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
+ if(_state->getFlag(FLAG_PARADOJA_RESUELTA) == false) {
+ _dialog->say(_res->_ingameTexts[OIGA]);
+ for(int i = 0; i < 26; i++) {
+ _state->setRootDisabledState(25, i, true);
+ }
+
+ walkAndAction(_room->findHotspotByExtra(467), TALK);
+ }
+ else {
+
+ }
}
+
void PelrockEngine::pickUpBook(int i) {
if (!_state->hasInventoryItem(10)) {
_dialog->say(_res->_ingameTexts[VENGA_ACA]);
@@ -1138,6 +1204,7 @@ void PelrockEngine::waitForActionEnd() {
}
}
+
/**
* Handler for picking up object with extra_id 472 in Room 28.
* Loads a special palette from ALFRED.7 at offset 0x1610CE and
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 9c3c1a9a1fb..69449dcc1f4 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -31,7 +31,7 @@
namespace Pelrock {
-Pelrock::MenuManager::MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res) : _screen(screen), _events(events), _res(res) {
+Pelrock::MenuManager::MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res, SoundManager *sound) : _screen(screen), _events(events), _res(res), _sound(sound) {
}
void MenuManager::drawColoredText(Graphics::ManagedSurface *screen, const Common::String &text, int x, int y, int w, Graphics::Font *font) {
@@ -97,11 +97,7 @@ void MenuManager::checkMouseClick(int x, int y) {
for (int i = 0; i < 4; i++) {
if (x >= 140 + (82 * i) && x <= 140 + (82 * i) + 64 &&
y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
- _selectedInvIndex = g_engine->_state->inventoryItems[_curInventoryPage * 4 + i];
- _menuText = _inventoryDescriptions[_selectedInvIndex];
- g_engine->_state->selectedInventoryItem = _selectedInvIndex;
- selectedItem = true;
- debug("Selected inventory item %d", _selectedInvIndex);
+ selectedItem = selectInventoryItem(i);
return;
}
}
@@ -134,6 +130,18 @@ void MenuManager::checkMouseClick(int x, int y) {
}
}
+bool MenuManager::selectInventoryItem(int i) {
+ if (_curInventoryPage * 4 + i >= g_engine->_state->inventoryItems.size())
+ return false;
+
+ _selectedInvIndex = g_engine->_state->inventoryItems[_curInventoryPage * 4 + i];
+ _menuText = _inventoryDescriptions[_selectedInvIndex];
+ _sound->playSound(inventorySounds[_selectedInvIndex], 100, 0);
+ g_engine->_state->selectedInventoryItem = _selectedInvIndex;
+ debug("Selected inventory item %d", _selectedInvIndex);
+ return true;
+}
+
void MenuManager::menuLoop() {
g_system->getPaletteManager()->setPalette(_mainMenuPalette, 0, 256);
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 32b0b14505d..781b721715d 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -26,6 +26,7 @@
#include "pelrock/events.h"
#include "pelrock/resources.h"
+#include "pelrock/sound.h"
namespace Pelrock {
@@ -46,9 +47,126 @@ enum MenuButton {
NO_BUTTON
};
+static const char *inventorySounds[113] = {
+
+ "HOJASZZZ.SMP", // 0 - Default leaf rustle
+ "11ZZZZZZ.SMP", // 1 -
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "GLASS1ZZ.SMP", // 4 - Glass clink (brick)
+ "11ZZZZZZ.SMP",
+ "ELEC3ZZZ.SMP", // 6 - Electric zap
+ "REMATERL.SMP", // 7 - Rematerialize
+ "81ZZZZZZ.SMP", // 8 - (numbered SFX)
+ "HOJASZZZ.SMP",
+ "SSSHTZZZ.SMP", // 10 - Shushing
+ "HOJASZZZ.SMP", // 11 - Default leaf rustle
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP", // 20
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP", // 30
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP", // 40
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP", // 50
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "BOTEZZZZ.SMP", // 60
+ "BOTEZZZZ.SMP", // 61
+ "BOTEZZZZ.SMP", // 62 - Bottle sound
+ "BELCHZZZ.SMP", // 63 - Belch
+ "BEAMZZZZ.SMP", // 64 - Beam/ray
+ "ELVIS1ZZ.SMP", // 65 - Elvis impression
+ "CAT_1ZZZ.SMP", // 66 - Cat sound
+ "BOOOOOIZ.SMP", // 67 - Boing
+ "DISCOSZZ.SMP", // 68 - Disco music
+ "MONORLZZ.SMP", // 69 - Monorail
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "CARACOLA.SMP", // 73 - Seashell
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "WATER_2Z.SMP", // 76 - Water splash
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "EEEEKZZZ.SMP", // 79 - Shriek
+ "REMATERL.SMP", // 80 - Rematerialize
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "ELVIS1ZZ.SMP", // 83 - Elvis impression
+ "RIMSHOTZ.SMP", // 84 - Rimshot
+ "HOJASZZZ.SMP",
+ "WATER_2Z.SMP", // 86 - Water splash
+ "MOTOSZZZ.SMP", // 87 - Motorcycle
+ "HOJASZZZ.SMP",
+ "TWANGZZZ.SMP", // 89 - Twang
+ "HOJASZZZ.SMP",
+ "QUAKE2ZZ.SMP", // 91 - Earthquake
+ "HOJASZZZ.SMP",
+ "SORBOZZZ.SMP", // 93 - Slurp
+ "BOTEZZZZ.SMP", // 94 - Bottle sound
+ "ELVIS1ZZ.SMP", // 95 - Elvis impression
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "LLAVESZZ.SMP", // 100 - Keys jingling
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "EVLLAUGH.SMP", // 104 - Evil laugh
+ "HOJASZZZ.SMP",
+ "BURROLZZ.SMP", // 106 - Donkey bray
+ "HOJASZZZ.SMP",
+ "TWANGZZZ.SMP", // 108
+ "HOJASZZZ.SMP",
+ "TWANGZZZ.SMP", // 110
+ "ELVIS1ZZ.SMP", // 111 - Elvis impression
+ "SEX3ZZZZ.SMP" // 112 - Suggestive sound
+};
+
class MenuManager {
public:
- MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res);
+ MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res, SoundManager *sound);
~MenuManager();
void menuLoop();
void drawScreen();
@@ -58,6 +176,7 @@ public:
private:
void checkMouseClick(int x, int y);
+ bool selectInventoryItem(int i);
void loadMenuTexts();
void cleanUp();
void drawButtons();
@@ -67,6 +186,7 @@ private:
Graphics::Screen *_screen = nullptr;
PelrockEventManager *_events = nullptr;
ResourceManager *_res = nullptr;
+ SoundManager *_sound = nullptr;
byte *_mainMenu = nullptr;
byte *_compositeBuffer = nullptr;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 28cb289d895..3cb01f23df7 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -95,7 +95,7 @@ Common::Error PelrockEngine::run() {
_res = new ResourceManager();
_sound = new SoundManager(_mixer);
_dialog = new DialogManager(_screen, _events, _graphics);
- _menu = new MenuManager(_screen, _events, _res);
+ _menu = new MenuManager(_screen, _events, _res, _sound);
_smallFont = new SmallFont();
_smallFont->load("ALFRED.4");
_largeFont = new LargeFont();
@@ -156,7 +156,7 @@ void PelrockEngine::init() {
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
- setScreen(9, ALFRED_DOWN);
+ setScreen(25, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -1600,7 +1600,6 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
for (int i = 0; i < loopEnd; i++) {
Common::Point p = getPositionInBallonForIndex(i, _actionPopupState.x, _actionPopupState.y);
Common::Rect actionRect = Common::Rect(p.x, p.y, p.x + kVerbIconWidth, p.y + kVerbIconHeight);
- debug("Checking action %d at rect (%d,%d) to (%d,%d) against mouse position %d,%d", i, actionRect.left, actionRect.top, actionRect.right, actionRect.bottom, x, y);
if (i == actions.size()) {
// Check inventory item
if (actionRect.contains(x, y)) {
@@ -1610,7 +1609,7 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
return actions[i];
}
}
- debug("No action under mouse at position %d,%d", x, y);
+
return NO_ACTION;
}
@@ -1685,7 +1684,6 @@ void PelrockEngine::checkMouseHover() {
if (isActionUnder(_events->_mouseX, _events->_mouseY) != NO_ACTION) {
hotspotDetected = false;
- debug("Mouse is over action icon, not hotspot, so showing action cursor");
}
// Calculate walk target first (before checking anything else)
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 90560b89ba0..284f5e1c275 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -250,6 +250,8 @@ public:
void performActionTrigger(uint16 actionTrigger);
void dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex);
+ void toJail();
+
void executeAction(VerbIcon action, HotSpot *hotspot);
void openRoomDrawer(HotSpot *hotspot);
void closeRoomDrawer(HotSpot *hotspot);
@@ -318,6 +320,7 @@ public:
void openTravelAgencyDoor(HotSpot *hotspot);
void closeTravelAgencyDoor(HotSpot *hotspot);
void usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot);
+ void pickupSunflower(HotSpot *hotspot);
void pickUpBook(int i);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 3b4e32d4331..5f519e9e4d8 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -34,6 +34,7 @@
#include "pelrock/pelrock.h"
#include "pelrock/sound.h"
+#include "sound.h"
namespace Pelrock {
@@ -58,6 +59,15 @@ void SoundManager::playSound(byte index, int volume, int channel) {
}
}
+void SoundManager::playSound(const char *filename, int volume, int channel) {
+ auto it = _soundMap.find(filename);
+ if (it != _soundMap.end()) {
+ playSound(it->_value, volume);
+ } else {
+ debug("Sound file %s not found in sound map", filename);
+ }
+}
+
void SoundManager::playSound(SonidoFile sound, int volume, int channel) {
Common::File sonidosFile;
if (!sonidosFile.open(Common::Path("SONIDOS.DAT"))) {
@@ -99,12 +109,11 @@ void SoundManager::playSound(SonidoFile sound, int volume, int channel) {
}
if (stream) {
- if(channel == -1) {
+ if (channel == -1) {
// Find a free channel
- channel = findFreeChannel();
- }
- else {
- if(_mixer->isSoundHandleActive(_sfxHandles[channel])) {
+ channel = findFreeChannel();
+ } else {
+ if (_mixer->isSoundHandleActive(_sfxHandles[channel])) {
_mixer->stopHandle(_sfxHandles[channel]);
}
}
@@ -157,7 +166,7 @@ int SoundManager::getSampleRate(byte *data, SoundFormat format) {
}
int SoundManager::findFreeChannel() {
- //Reserve first 3 channels for one-off sounds
+ // Reserve first 3 channels for one-off sounds
for (int i = 3; i < kMaxChannels; i++) {
if (!_mixer->isSoundHandleActive(_sfxHandles[i])) {
return i;
@@ -245,7 +254,7 @@ void SoundManager::loadSoundIndex() {
sonidosFile.close();
}
-static const uint kAmbientCounterMask = 0x1F; // Trigger when (counter & mask) == mask
+static const uint kAmbientCounterMask = 0x1F; // Trigger when (counter & mask) == mask
int SoundManager::tickAmbientSound(uint32 frameCount) {
// Counter gate: only trigger every 32 frames when (counter & 0x1F) == 0x1F
@@ -261,7 +270,7 @@ int SoundManager::tickAmbientSound(uint32 frameCount) {
// Pick random ambient slot 0-3 (corresponds to room sound indices 4-7)
int ambientSlotOffset = g_engine->getRandomNumber(3);
- return ambientSlotOffset; // Caller adds 4 to get room sound index
+ return ambientSlotOffset; // Caller adds 4 to get room sound index
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 604773622ab..de38a2fb4c1 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -150,15 +150,15 @@ struct SoundData {
uint32 size;
};
-
const int kMaxChannels = 15;
-const int kAmbientSoundSlotBase = 4; // Room sound indices 4-7 are ambient sounds
+const int kAmbientSoundSlotBase = 4; // Room sound indices 4-7 are ambient sounds
class SoundManager {
public:
SoundManager(Audio::Mixer *mixer);
~SoundManager();
void playSound(byte index, int volume = 128, int channel = -1);
+ void playSound(const char *filename, int volume, int channel);
void playSound(byte *soundData, uint32 size, int volume = 128);
void stopAllSounds();
void stopSound(int channel);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 2028f549702..8093d1f5d18 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -465,6 +465,7 @@ struct ResetEntry {
#define FLAG_ALFRED_INTELIGENTE 9
#define FLAG_ALFRED_SABE_EGIPCIO 10
#define FLAG_VENDEDOR_DEJA_DE_JODER 11
+
#define FLAG_VIAJE_A_EGIPTO 12
#define FLAG_PARADOJA_RESUELTA 13
#define FLAG_CROCODILLO_ENCENDIDO 14
@@ -502,13 +503,15 @@ struct ResetEntry {
#define FLAG_TIENDA_ABIERTA 46
#define FLAG_NUMERO_DE_COPAS 47
#define FLAG_INGREDIENTES_CONSEGUIDOS 48
+
#define FLAG_GUARDIA_PIDECOSAS 49
#define FLAG_GUARDIA_DNI_ENTREGADO 50
#define FLAG_AGENCIA_ABIERTA 51
#define FLAG_CONSIGNAS_VENDEDOR 52
#define FLAG_PUTA_250_VECES 53
+#define FLAG_RESPUESTAS_ACERTADAS 54
-const int kNumGameFlags = 54;
+const int kNumGameFlags = 55;
struct GameStateData {
byte flags[kNumGameFlags];
Commit: ae81d1088f00b7b7d723e5fcd1d8e0059885dca9
https://github.com/scummvm/scummvm/commit/ae81d1088f00b7b7d723e5fcd1d8e0059885dca9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:00+02:00
Commit Message:
PELROCK: Fixes conversation root model to be setRoot
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.cpp
engines/pelrock/console.h
engines/pelrock/dialog.cpp
engines/pelrock/saveload.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index c5832e1c4d6..be04fbf1080 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -215,15 +215,15 @@ void PelrockEngine::buyFromStore(HotSpot *hotspot, int stickerId) {
void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex) {
switch (actionTrigger) {
case 328:
- debug("Disabling root %d in room %d", rootIndex, room);
- _state->setRootDisabledState(room, rootIndex, true);
+ debug("Setting current root to %d in room %d", rootIndex + 1, room);
+ _state->setCurrentRoot(room, rootIndex + 1);
break;
case 329:
_state->setFlag(FLAG_PUTA_250_VECES, true);
break;
case 258:
_state->setFlag(FLAG_GUARDIA_PIDECOSAS, true);
- _state->setRootDisabledState(4, 1, true);
+ _state->setCurrentRoot(4, 2);
break;
case 259:
_dialog->say(_res->_ingameTexts[NO_EMPECEMOS]);
@@ -242,15 +242,14 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_dialog->say(_res->_ingameTexts[UN_POCO_RESPETO]);
break;
case 264:
- // disables the two first roots, the second one will be enabled later!
- _state->setRootDisabledState(room, rootIndex, true);
- _state->setRootDisabledState(room, rootIndex + 1, true);
+ // skip to root after the next one
+ _state->setCurrentRoot(room, rootIndex + 2);
break;
case 267:
- _state->setRootDisabledState(7, 1, true);
+ _state->setCurrentRoot(7, 2);
break;
case 272:
- _state->setRootDisabledState(room, rootIndex, true);
+ _state->setCurrentRoot(room, rootIndex + 1);
break;
case 273:
WalkBox w1;
@@ -271,14 +270,14 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 274:
case 275:
case 276:
- _state->setRootDisabledState(room, rootIndex, true);
+ _state->setCurrentRoot(room, rootIndex + 1);
break;
case 277:
- _state->setRootDisabledState(room, rootIndex, true);
+ _state->setCurrentRoot(room, rootIndex + 1);
_state->setFlag(FLAG_JEFE_INGRESA_PASTA, true);
break;
case 278:
- _state->setRootDisabledState(room, rootIndex, true);
+ _state->setCurrentRoot(room, rootIndex + 1);
break;
case 279:
travelToEgypt();
@@ -306,7 +305,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
case 334:
addInventoryItem(86);
- _state->setRootDisabledState(room, rootIndex, true);
+ _state->setCurrentRoot(room, rootIndex + 1);
break;
case 335:
@@ -326,7 +325,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 344:
case 345:
case 346:
- _state->setRootDisabledState(room, rootIndex, true);
+ _state->setCurrentRoot(room, rootIndex + 1);
break;
case 348: {
// Anti-piracy punishment: corrupt screen + noise + crash
@@ -336,13 +335,13 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 349:
_state->setFlag(FLAG_CONSIGNAS_VENDEDOR, _state->getFlag(FLAG_CONSIGNAS_VENDEDOR) + 1);
if (_state->getFlag(FLAG_CONSIGNAS_VENDEDOR) == 2) {
- _state->setRootDisabledState(room, rootIndex, true);
+ _state->setCurrentRoot(room, rootIndex + 1);
}
break;
case 350:
_state->setFlag(FLAG_CONSIGNAS_VENDEDOR, _state->getFlag(FLAG_CONSIGNAS_VENDEDOR) + 1);
if (_state->getFlag(FLAG_CONSIGNAS_VENDEDOR) == 2) {
- _state->setRootDisabledState(room, rootIndex, true);
+ _state->setCurrentRoot(room, rootIndex + 1);
}
break;
case 351:
@@ -367,8 +366,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
// end moros
case 353:
- _state->setRootDisabledState(room, rootIndex, true);
- _state->setRootDisabledState(room, rootIndex + 1, true);
+ _state->setCurrentRoot(room, rootIndex + 2);
break;
case 354:
if(_state->hasInventoryItem(105)) {
@@ -381,52 +379,62 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
toJail();
break;
case 356:
- _state->setRootDisabledState(room, 0, true);
- _state->setRootDisabledState(room, 1, true);
- _state->setRootDisabledState(room, 2, true);
+ _state->setCurrentRoot(room, 3);
break;
//end puta
// sabio
case 366:
- _state->setRootDisabledState(room, rootIndex, true);
+ _state->setCurrentRoot(room, rootIndex + 1);
break;
case 363:
toJail();
break;
case 367: //accept riddle
- _state->setRootDisabledState(room, 26, true);
+ _state->setCurrentRoot(room, 27);
walkAndAction(_room->findHotspotByExtra(467), TALK);
break;
// hasta aqui
- case 357: // mal
- _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) - 1);
- _state->setRootDisabledState(room, rootIndex, true);
+ case 357: // wrong answer: counter-- (min 0)
+ if (_state->getFlag(FLAG_RESPUESTAS_ACERTADAS) > 0) {
+ _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) - 1);
+ }
+ _state->setCurrentRoot(room, rootIndex + 1);
break;
- case 358: // muy mal
- _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) - 2);
- _state->setRootDisabledState(room, rootIndex, true);
+ case 358: // very wrong answer: counter-=2 (min 0)
+ if (_state->getFlag(FLAG_RESPUESTAS_ACERTADAS) > 1) {
+ _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) - 2);
+ }
+ _state->setCurrentRoot(room, rootIndex + 1);
break;
- case 359: // bien
+ case 359: // correct answer: counter++, award pin at 15
_state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) + 1);
- if(_state->getFlag(FLAG_RESPUESTAS_ACERTADAS) == 15) {
+ if (_state->getFlag(FLAG_RESPUESTAS_ACERTADAS) == 15) {
addInventoryItem(106); // pin
_state->setFlag(FLAG_RESPUESTAS_ACERTADAS, 0);
-
}
- _state->setRootDisabledState(room, rootIndex, true);
+ _state->setCurrentRoot(room, rootIndex + 1);
break;
- case 360:
-
- case 361:
+ case 360: // neutral reset: counter = 0
_state->setFlag(FLAG_RESPUESTAS_ACERTADAS, 0);
- //back to conversation 27
- case 362:
-//?
- case 365:
- //correct
- case 364:
- //wrong
+ _state->setCurrentRoot(room, rootIndex + 1);
+ break;
+ case 361: // "no sé" (I don't know): no counter change, just advance
+ _state->setCurrentRoot(room, rootIndex + 1);
+ break;
+ case 362: // special trigger: enables HIJODELAGRANPUTA cheat code
+ // Sets cheat_code_checking_enabled flag in original (0x495F3)
+ // TODO: Implement cheat code sequence checker in game loop
+ _state->setFlag(FLAG_CHEAT_CODE_ENABLED, 1);
+ _state->setCurrentRoot(room, rootIndex + 1);
+ break;
+ case 364: // riddle wrong answer: advance to next riddle
+ _state->setCurrentRoot(room, rootIndex + 1);
+ break;
+ case 365: // riddle correct: set riddle-solved flag
+ _state->setFlag(FLAG_RIDDLE_SOLVED, 1);
+ _state->setCurrentRoot(room, rootIndex + 1);
+ break;
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
@@ -499,13 +507,12 @@ void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
_room->enableHotspot(hotspot);
}
-void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
+ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
debug("Withdrawing money from ATM using card (inv obj %d)", inventoryObject);
if (_state->getFlag(FLAG_JEFE_INGRESA_PASTA)) {
_state->setFlag(FLAG_JEFE_INGRESA_PASTA, false);
addInventoryItem(75);
- _state->setRootDisabledState(20, 0, true);
- _state->setRootDisabledState(20, 1, true);
+ _state->setCurrentRoot(20, 2);
} else {
int billCount = 0;
for (uint i = 0; i < _state->inventoryItems.size(); i++) {
@@ -750,7 +757,7 @@ void PelrockEngine::pickCables(HotSpot *hotspot) {
_room->addSticker(21);
_dialog->say(_res->_ingameTexts[RELOJ_HA_CAMBIADO]);
- _state->setRootDisabledState(4, 0, true);
+ _state->setCurrentRoot(4, 1);
}
void PelrockEngine::giveIdToGuard(int inventoryObject, HotSpot *hotspot) {
@@ -770,7 +777,7 @@ void PelrockEngine::giveIdToGuard(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::unlockMuseum() {
- _state->setRootDisabledState(4, 2, true);
+ _state->setCurrentRoot(4, 3);
_room->enableSprite(2, 100, PERSIST_PERM);
_room->enableSprite(3, 100, PERSIST_PERM);
_room->addStickerToRoom(4, 87, PERSIST_PERM);
@@ -812,9 +819,7 @@ void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
if (!_room->hasSticker(24)) {
_room->addSticker(24);
_state->removeInventoryItem(7);
- _state->setRootDisabledState(7, 0, true);
- _state->setRootDisabledState(7, 1, false);
- _state->setRootDisabledState(7, 2, true);
+ _state->setCurrentRoot(7, 1);
_alfredState.direction = ALFRED_RIGHT;
HotSpot *statueHotspot = _room->findHotspotByExtra(91);
@@ -930,9 +935,7 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
if(_state->getFlag(FLAG_PARADOJA_RESUELTA) == false) {
_dialog->say(_res->_ingameTexts[OIGA]);
- for(int i = 0; i < 26; i++) {
- _state->setRootDisabledState(25, i, true);
- }
+ _state->setCurrentRoot(25, 26);
walkAndAction(_room->findHotspotByExtra(467), TALK);
}
@@ -945,10 +948,10 @@ void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
void PelrockEngine::pickUpBook(int i) {
if (!_state->hasInventoryItem(10)) {
_dialog->say(_res->_ingameTexts[VENGA_ACA]);
- _state->setRootDisabledState(9, 0, true);
+ _state->setCurrentRoot(9, 1);
if (_state->hasInventoryItem(3)) {
- _state->setRootDisabledState(9, 1, true);
+ _state->setCurrentRoot(9, 2);
addInventoryItem(10);
}
@@ -959,9 +962,9 @@ void PelrockEngine::pickUpBook(int i) {
waitForActionEnd();
if (!_state->hasInventoryItem(3)) {
- _state->setRootDisabledState(9, 0, false);
+ _state->setCurrentRoot(9, 0);
} else {
- _state->setRootDisabledState(9, 2, true);
+ _state->setCurrentRoot(9, 3);
}
} else {
if (_state->libraryShelf == -1) {
@@ -1032,11 +1035,8 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
waitForSpecialAnimation();
loadExtraScreenAndPresent(3);
- _state->setRootDisabledState(17, 0, true);
- _state->setRootDisabledState(18, 0, true);
- _state->setRootDisabledState(18, 1, true);
- _state->setRootDisabledState(18, 2, true);
- _state->setRootDisabledState(18, 3, true);
+ _state->setCurrentRoot(17, 1);
+ _state->setCurrentRoot(18, 4);
debug("After extra screen");
_dialog->say(_res->_ingameTexts[QUEASCO]);
break;
@@ -1067,8 +1067,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
waitForSpecialAnimation();
_dialog->say(_res->_ingameTexts[COSASAPRENDIDO]);
_state->setFlag(FLAG_ALFRED_INTELIGENTE, true);
- _state->setRootDisabledState(14, 0, true);
- _state->setRootDisabledState(14, 1, true);
+ _state->setCurrentRoot(14, 2);
break;
case 64:
_res->loadAlfredSpecialAnim(0);
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index 7ffbb0c6154..d7cdabcb528 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -29,7 +29,7 @@ namespace Pelrock {
PelrockConsole::PelrockConsole(PelrockEngine *engine) : GUI::Debugger(), _engine(engine) {
registerCmd("room", WRAP_METHOD(PelrockConsole, cmdLoadRoom));
registerCmd("give", WRAP_METHOD(PelrockConsole, cmdGiveItems));
- registerCmd("disableRoot", WRAP_METHOD(PelrockConsole, disableRoot));
+ registerCmd("setRoot", WRAP_METHOD(PelrockConsole, setRoot));
registerCmd("setFlag", WRAP_METHOD(PelrockConsole, setFlag));
}
@@ -49,15 +49,15 @@ bool PelrockConsole::setFlag(int argc, const char **argv) {
return true;
}
-bool PelrockConsole::disableRoot(int argc, const char **argv) {
+bool PelrockConsole::setRoot(int argc, const char **argv) {
if (argc < 3) {
- debugPrintf("Usage: disableRoot <roomNumber> <rootIndex>");
+ debugPrintf("Usage: setRoot <roomNumber> <rootIndex>");
return true;
}
int roomNumber = atoi(argv[1]);
int rootIndex = atoi(argv[2]);
- _engine->_state->setRootDisabledState(roomNumber, rootIndex, true);
- debugPrintf("Disabled root %d in room %d\n", rootIndex, roomNumber);
+ _engine->_state->setCurrentRoot(roomNumber, rootIndex);
+ debugPrintf("Set current root to %d in room %d\n", rootIndex, roomNumber);
return true;
}
diff --git a/engines/pelrock/console.h b/engines/pelrock/console.h
index f8728363680..aafaa3afc39 100644
--- a/engines/pelrock/console.h
+++ b/engines/pelrock/console.h
@@ -34,7 +34,7 @@ private:
bool cmdLoadRoom(int argc, const char **argv);
bool cmdGiveItems(int argc, const char **argv);
bool cmdTest(int argc, const char **argv);
- bool disableRoot(int argc, const char **argv);
+ bool setRoot(int argc, const char **argv);
bool setFlag(int argc, const char **argv);
public:
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index d99c2fec6dd..f606390665b 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -446,14 +446,6 @@ void DialogManager::setCurSprite(int index) {
_curSprite = nullptr;
}
-bool isRootDisabled(byte room, int root) {
-
- if (g_engine->_state->getRootDisabledState(room, root)) {
- return true;
- }
- return false;
-}
-
void DialogManager::startConversation(const byte *conversationData, uint32 dataSize, byte npcIndex, Sprite *animSet) {
if (!conversationData || dataSize == 0) {
debug("startConversation: No conversation data");
@@ -591,17 +583,22 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
uint32 DialogManager::findRoot(int ¤tRoot, uint32 currentPosition, uint32 dataSize, const byte *conversationData) {
- while (g_engine->_state->getRootDisabledState(g_engine->_room->_currentRoomNumber, currentRoot)) {
- // This root is disabled, skip to next
- while (currentPosition < dataSize) {
+ // Check if a specific root has been set for this room
+ int targetRoot = g_engine->_state->getCurrentRoot(g_engine->_room->_currentRoomNumber);
+
+ if (targetRoot >= 0) {
+ // Skip to the specified root
+ while (currentRoot < targetRoot && currentPosition < dataSize) {
if (conversationData[currentPosition] == CTRL_END_BRANCH) {
currentPosition++; // Move past end branch marker
currentRoot++;
- break;
+ } else {
+ currentPosition++;
}
- currentPosition++;
}
}
+ // If targetRoot is -1 or not set, use the first root (default behavior)
+
return currentPosition;
}
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index b665f9c244f..d6dcf7dbc72 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -335,8 +335,8 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
}
}
- // Conversation roots state
- s.syncBytes(gameState->conversationRootsState, 4 * 56);
+ // Conversation current root indices
+ s.syncBytes(gameState->conversationCurrentRoot, 56);
return !s.err();
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 8093d1f5d18..959929f17b3 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -510,8 +510,10 @@ struct ResetEntry {
#define FLAG_CONSIGNAS_VENDEDOR 52
#define FLAG_PUTA_250_VECES 53
#define FLAG_RESPUESTAS_ACERTADAS 54
+#define FLAG_CHEAT_CODE_ENABLED 55 // 0x495F3 - enables HIJODELAGRANPUTA cheat code input
+#define FLAG_RIDDLE_SOLVED 56 // 0x495D0 - set when Egyptian riddle answered correctly
-const int kNumGameFlags = 55;
+const int kNumGameFlags = 57;
struct GameStateData {
byte flags[kNumGameFlags];
@@ -532,15 +534,15 @@ struct GameStateData {
Common::HashMap<byte, Common::Array<SpriteChange>> spriteChanges;
GameStateData() {
- memset(conversationRootsState, 0, 4 * 56);
+ memset(conversationCurrentRoot, 0xFF, 56); // 0xFF = not set
for (int i = 0; i < kNumGameFlags; i++)
flags[i] = 0;
flags[FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ] = true;
}
~GameStateData() {
- delete[] conversationRootsState;
- conversationRootsState = nullptr;
+ delete[] conversationCurrentRoot;
+ conversationCurrentRoot = nullptr;
}
void addDisabledBranch(ResetEntry entry) {
@@ -581,14 +583,23 @@ struct GameStateData {
return false;
}
- byte *conversationRootsState = new byte[4 * 56];
+ // Store current root index for each room (0xFF = not set, use findRoot logic)
+ byte *conversationCurrentRoot = new byte[56];
- bool getRootDisabledState(byte room, byte root) const {
- return (conversationRootsState[room * 4 + root] != 0);
+ int getCurrentRoot(byte room) const {
+ if (room >= 56)
+ return -1;
+ return (conversationCurrentRoot[room] == 0xFF) ? -1 : conversationCurrentRoot[room];
}
- void setRootDisabledState(byte room, byte root, bool disabled) {
- conversationRootsState[room * 4 + root] = disabled ? 1 : 0;
+ void setCurrentRoot(byte room, int root) {
+ if (room >= 56)
+ return;
+ if (root < 0 || root > 254) {
+ conversationCurrentRoot[room] = 0xFF; // Reset to auto-select
+ } else {
+ conversationCurrentRoot[room] = (byte)root;
+ }
}
int findFirstBookIndex() {
Commit: 77340b2ddeb0fe5bb5fac3733c529dfad6a6f2f1
https://github.com/scummvm/scummvm/commit/77340b2ddeb0fe5bb5fac3733c529dfad6a6f2f1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:01+02:00
Commit Message:
PELROCK: Room 25
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index be04fbf1080..1dcd1dc749f 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -119,7 +119,6 @@ const ActionEntry actionTable[] = {
// Room 28
{472, PICKUP, &PelrockEngine::pickUpMatches},
-
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -295,8 +294,8 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_dialog->say(_res->_ingameTexts[HECHOELPRIMO]);
break;
case 332:
- //psychologist card
- if(!_state->hasInventoryItem(104)) {
+ // psychologist card
+ if (!_state->hasInventoryItem(104)) {
addInventoryItem(104);
}
break;
@@ -309,7 +308,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
case 335:
- //many oranges
+ // many oranges
addInventoryItem(104);
break;
case 336:
@@ -369,56 +368,65 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(room, rootIndex + 2);
break;
case 354:
- if(_state->hasInventoryItem(105)) {
+ if (_state->hasInventoryItem(105)) {
addInventoryItem(105);
}
break;
case 352:
case 355:
- //a la carcel
+ // a la carcel
toJail();
break;
case 356:
_state->setCurrentRoot(room, 3);
break;
- //end puta
- // sabio
+ // end puta
+ // sabio
case 366:
_state->setCurrentRoot(room, rootIndex + 1);
break;
case 363:
toJail();
break;
- case 367: //accept riddle
+ case 367: // accept riddle
_state->setCurrentRoot(room, 27);
walkAndAction(_room->findHotspotByExtra(467), TALK);
break;
-// hasta aqui
+ // hasta aqui
case 357: // wrong answer: counter-- (min 0)
+ {
if (_state->getFlag(FLAG_RESPUESTAS_ACERTADAS) > 0) {
_state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) - 1);
}
- _state->setCurrentRoot(room, rootIndex + 1);
+ advanceQuotesConversation(rootIndex, room);
break;
+ }
case 358: // very wrong answer: counter-=2 (min 0)
+ {
if (_state->getFlag(FLAG_RESPUESTAS_ACERTADAS) > 1) {
_state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) - 2);
}
- _state->setCurrentRoot(room, rootIndex + 1);
+ advanceQuotesConversation(rootIndex, room);
break;
+ }
case 359: // correct answer: counter++, award pin at 15
+ {
_state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) + 1);
if (_state->getFlag(FLAG_RESPUESTAS_ACERTADAS) == 15) {
addInventoryItem(106); // pin
_state->setFlag(FLAG_RESPUESTAS_ACERTADAS, 0);
}
- _state->setCurrentRoot(room, rootIndex + 1);
+ advanceQuotesConversation(rootIndex, room);
break;
+ }
case 360: // neutral reset: counter = 0
+ {
_state->setFlag(FLAG_RESPUESTAS_ACERTADAS, 0);
_state->setCurrentRoot(room, rootIndex + 1);
+ advanceQuotesConversation(rootIndex, room);
break;
+ }
case 361: // "no sé" (I don't know): no counter change, just advance
_state->setCurrentRoot(room, rootIndex + 1);
break;
@@ -426,14 +434,20 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
// Sets cheat_code_checking_enabled flag in original (0x495F3)
// TODO: Implement cheat code sequence checker in game loop
_state->setFlag(FLAG_CHEAT_CODE_ENABLED, 1);
- _state->setCurrentRoot(room, rootIndex + 1);
+ advanceQuotesConversation(rootIndex, room);
break;
case 364: // riddle wrong answer: advance to next riddle
- _state->setCurrentRoot(room, rootIndex + 1);
+ {
+ int targetIndex = rootIndex + 1;
+ if (rootIndex == 43) {
+ targetIndex = 27; // skip riddle explanation
+ }
+ _state->setCurrentRoot(room, targetIndex);
break;
+ }
case 365: // riddle correct: set riddle-solved flag
- _state->setFlag(FLAG_RIDDLE_SOLVED, 1);
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setFlag(FLAG_PARADOJA_RESUELTA, 1);
+ _state->setCurrentRoot(room, 1);
break;
default:
@@ -442,6 +456,14 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
}
}
+void PelrockEngine::advanceQuotesConversation(byte rootIndex, byte room) {
+ int targetRoot = rootIndex + 1;
+ if (targetRoot == 26) {
+ targetRoot = 2;
+ }
+ _state->setCurrentRoot(room, targetRoot);
+}
+
void PelrockEngine::toJail() {
_graphics->fadeToBlack(10);
_alfredState.x = 342;
@@ -507,7 +529,7 @@ void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
_room->enableHotspot(hotspot);
}
- void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
+void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
debug("Withdrawing money from ATM using card (inv obj %d)", inventoryObject);
if (_state->getFlag(FLAG_JEFE_INGRESA_PASTA)) {
_state->setFlag(FLAG_JEFE_INGRESA_PASTA, false);
@@ -621,11 +643,11 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
_events->pollEvent();
renderScene(OVERLAY_NONE);
// if (_chrono->_gameTick) {
- _room->findSpriteByIndex(7)->y -= 10;
- if (_room->findSpriteByIndex(7)->y <= 70) {
- _room->findSpriteByIndex(7)->zOrder = -1;
- break;
- }
+ _room->findSpriteByIndex(7)->y -= 10;
+ if (_room->findSpriteByIndex(7)->y <= 70) {
+ _room->findSpriteByIndex(7)->zOrder = -1;
+ break;
+ }
// }
_screen->update();
g_system->delayMillis(10);
@@ -897,7 +919,7 @@ void PelrockEngine::closeNewspaperBossDoor(HotSpot *hotspot) {
void PelrockEngine::openTravelAgencyDoor(HotSpot *hotspot) {
- if(_state->getFlag(FLAG_AGENCIA_ABIERTA)) {
+ if (_state->getFlag(FLAG_AGENCIA_ABIERTA)) {
openDoor(hotspot, 1, 57, FEMININE, false);
}
// The game originally did nothing here
@@ -925,7 +947,7 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
g_system->delayMillis(10);
}
_graphics->fadeToBlack(10);
- //update conversaton state
+ // update conversaton state
_alfredState.x = 300;
_alfredState.y = 238;
setScreen(28, ALFRED_DOWN);
@@ -933,18 +955,19 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
- if(_state->getFlag(FLAG_PARADOJA_RESUELTA) == false) {
+ if (_state->getFlag(FLAG_PARADOJA_RESUELTA) == false) {
_dialog->say(_res->_ingameTexts[OIGA]);
_state->setCurrentRoot(25, 26);
-
+ _state->setFlag(FLAG_RIDDLE_PRESENTED, true);
walkAndAction(_room->findHotspotByExtra(467), TALK);
- }
- else {
-
+ } else {
+ addInventoryItem(85);
+ _room->disableHotspot(hotspot);
+ _state->setCurrentRoot(25, 1);
+ _room->addSticker(73);
}
}
-
void PelrockEngine::pickUpBook(int i) {
if (!_state->hasInventoryItem(10)) {
_dialog->say(_res->_ingameTexts[VENGA_ACA]);
@@ -984,7 +1007,6 @@ void PelrockEngine::pickUpBook(int i) {
_state->selectedBookIndex = -1;
}
}
-
}
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
@@ -1062,12 +1084,17 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_state->setFlag(FLAG_ALFRED_SABE_EGIPCIO, true);
break;
case 24:
- _res->loadAlfredSpecialAnim(0);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
- _dialog->say(_res->_ingameTexts[COSASAPRENDIDO]);
- _state->setFlag(FLAG_ALFRED_INTELIGENTE, true);
- _state->setCurrentRoot(14, 2);
+ if (_state->getFlag(FLAG_RIDDLE_PRESENTED) == true) {
+ _dialog->say(_res->_ingameTexts[CAPITULOPARADOJAS]);
+ _state->setCurrentRoot(25, 44);
+ } else {
+ _res->loadAlfredSpecialAnim(0);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _dialog->say(_res->_ingameTexts[COSASAPRENDIDO]);
+ _state->setFlag(FLAG_ALFRED_INTELIGENTE, true);
+ _state->setCurrentRoot(14, 2);
+ }
break;
case 64:
_res->loadAlfredSpecialAnim(0);
@@ -1148,7 +1175,7 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
_events->pollEvent();
bool didRender = renderScene(OVERLAY_NONE);
- if(didRender) {
+ if (didRender) {
for (int i = 0; i < 16; i++) {
byte paletteIndex = paletteData.indices[i];
@@ -1183,8 +1210,7 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
void PelrockEngine::checkObjectsForPart2() {
if (_state->hasInventoryItem(17) &&
_state->hasInventoryItem(59) &&
- _state->hasInventoryItem(24)
- ) {
+ _state->hasInventoryItem(24)) {
_room->addStickerToRoom(19, 54, PERSIST_BOTH);
_room->addStickerToRoom(19, 55, PERSIST_BOTH);
_room->addStickerToRoom(19, 56, PERSIST_BOTH);
@@ -1203,7 +1229,6 @@ void PelrockEngine::waitForActionEnd() {
}
}
-
/**
* Handler for picking up object with extra_id 472 in Room 28.
* Loads a special palette from ALFRED.7 at offset 0x1610CE and
@@ -1257,7 +1282,7 @@ void PelrockEngine::antiPiracyEffect() {
_sound->stopMusic();
// Generate a buffer of white noise for the PC speaker simulation
- const int kNoiseLength = 16000; // 1 second at 8kHz
+ const int kNoiseLength = 16000; // 1 second at 8kHz
byte *noiseData = new byte[kNoiseLength + 44]; // WAV header + data
// Write a minimal WAV header
@@ -1265,13 +1290,13 @@ void PelrockEngine::antiPiracyEffect() {
WRITE_LE_UINT32(noiseData + 4, kNoiseLength + 36);
memcpy(noiseData + 8, "WAVE", 4);
memcpy(noiseData + 12, "fmt ", 4);
- WRITE_LE_UINT32(noiseData + 16, 16); // chunk size
- WRITE_LE_UINT16(noiseData + 20, 1); // PCM format
- WRITE_LE_UINT16(noiseData + 22, 1); // mono
- WRITE_LE_UINT32(noiseData + 24, 8000); // sample rate
- WRITE_LE_UINT32(noiseData + 28, 8000); // byte rate
- WRITE_LE_UINT16(noiseData + 32, 1); // block align
- WRITE_LE_UINT16(noiseData + 34, 8); // bits per sample
+ WRITE_LE_UINT32(noiseData + 16, 16); // chunk size
+ WRITE_LE_UINT16(noiseData + 20, 1); // PCM format
+ WRITE_LE_UINT16(noiseData + 22, 1); // mono
+ WRITE_LE_UINT32(noiseData + 24, 8000); // sample rate
+ WRITE_LE_UINT32(noiseData + 28, 8000); // byte rate
+ WRITE_LE_UINT16(noiseData + 32, 1); // block align
+ WRITE_LE_UINT16(noiseData + 34, 8); // bits per sample
memcpy(noiseData + 36, "data", 4);
WRITE_LE_UINT32(noiseData + 40, kNoiseLength);
@@ -1301,7 +1326,7 @@ void PelrockEngine::antiPiracyEffect() {
break;
}
- //generate random pixels on the screen (simulating corrupted video memory)
+ // generate random pixels on the screen (simulating corrupted video memory)
for (int i = 0; i < screenSize; i++) {
screenPixels[i] = (byte)getRandomNumber(255);
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index f606390665b..ecefc64faff 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -585,7 +585,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
uint32 DialogManager::findRoot(int ¤tRoot, uint32 currentPosition, uint32 dataSize, const byte *conversationData) {
// Check if a specific root has been set for this room
int targetRoot = g_engine->_state->getCurrentRoot(g_engine->_room->_currentRoomNumber);
-
+
if (targetRoot >= 0) {
// Skip to the specified root
while (currentRoot < targetRoot && currentPosition < dataSize) {
@@ -598,7 +598,7 @@ uint32 DialogManager::findRoot(int ¤tRoot, uint32 currentPosition, uint32
}
}
// If targetRoot is -1 or not set, use the first root (default behavior)
-
+
return currentPosition;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 284f5e1c275..d7edb3fd9bd 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -250,6 +250,8 @@ public:
void performActionTrigger(uint16 actionTrigger);
void dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex);
+ void advanceQuotesConversation(byte rootIndex, byte room);
+
void toJail();
void executeAction(VerbIcon action, HotSpot *hotspot);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 1cf969b758f..a8107699e84 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -50,6 +50,7 @@ static const int unpickableHotspotExtras[] = {
361,
362,
472, // matches
+ 609 // sunflower
};
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 959929f17b3..e0f96b70891 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -465,9 +465,11 @@ struct ResetEntry {
#define FLAG_ALFRED_INTELIGENTE 9
#define FLAG_ALFRED_SABE_EGIPCIO 10
#define FLAG_VENDEDOR_DEJA_DE_JODER 11
+#define FLAG_PARADOJA_RESUELTA 13
+
+
#define FLAG_VIAJE_A_EGIPTO 12
-#define FLAG_PARADOJA_RESUELTA 13
#define FLAG_CROCODILLO_ENCENDIDO 14
#define FLAG_MIRA_SIMBOLO_FUERA_MUSEO 15
#define FLAG_PUERTA_SECRETA_ABIERTA 16
@@ -511,7 +513,7 @@ struct ResetEntry {
#define FLAG_PUTA_250_VECES 53
#define FLAG_RESPUESTAS_ACERTADAS 54
#define FLAG_CHEAT_CODE_ENABLED 55 // 0x495F3 - enables HIJODELAGRANPUTA cheat code input
-#define FLAG_RIDDLE_SOLVED 56 // 0x495D0 - set when Egyptian riddle answered correctly
+#define FLAG_RIDDLE_PRESENTED 56
const int kNumGameFlags = 57;
Commit: 8067a173d116ef02d62d8ab151dd9fa496dd3161
https://github.com/scummvm/scummvm/commit/8067a173d116ef02d62d8ab151dd9fa496dd3161
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:01+02:00
Commit Message:
PELROCK: Implements picking up objects in room 28
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 1dcd1dc749f..09bfcc1013d 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -118,6 +118,10 @@ const ActionEntry actionTable[] = {
// Room 28
{472, PICKUP, &PelrockEngine::pickUpMatches},
+ {87, PICKUP, &PelrockEngine::pickUpChainsaw},
+ {88, PICKUP, &PelrockEngine::pickUpSpellbook},
+ {89, PICKUP, &PelrockEngine::pickUpBoot},
+ {112, PICKUP, &PelrockEngine::pickupCondoms},
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
@@ -966,6 +970,14 @@ void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
_state->setCurrentRoot(25, 1);
_room->addSticker(73);
}
+ checkIngredients();
+}
+
+void PelrockEngine::checkIngredients() {
+ byte ingredientes = _state->getFlag(FLAG_INGREDIENTES_CONSEGUIDOS);
+ int textLine = PRIMERINGREDIENTE + ingredientes;
+ _dialog->say(_res->_ingameTexts[textLine]);
+ _state->setFlag(FLAG_INGREDIENTES_CONSEGUIDOS, ingredientes + 1);
}
void PelrockEngine::pickUpBook(int i) {
@@ -1009,6 +1021,25 @@ void PelrockEngine::pickUpBook(int i) {
}
}
+void PelrockEngine::pickUpChainsaw(HotSpot *hotspot) {
+
+ _room->addSticker(99);
+}
+
+void PelrockEngine::pickUpSpellbook(HotSpot *hotspot) {
+ _room->addSticker(97);
+}
+
+void PelrockEngine::pickUpBoot(HotSpot *hotspot) {
+
+ _room->addSticker(98);
+}
+
+void PelrockEngine::pickupCondoms(HotSpot *hotspot) {
+
+ _room->addSticker(100);
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
@@ -1216,8 +1247,6 @@ void PelrockEngine::checkObjectsForPart2() {
_room->addStickerToRoom(19, 56, PERSIST_BOTH);
_room->addStickerToRoom(19, 58, PERSIST_BOTH);
_state->setFlag(FLAG_AGENCIA_ABIERTA, true);
- // _state->setFlag(FLAG_PUEDE_VIAJAR_EN_EL_TIEMPO, true);
- // _state->setRootDisabledState(19, 0, true);
}
}
@@ -1233,8 +1262,6 @@ void PelrockEngine::waitForActionEnd() {
* Handler for picking up object with extra_id 472 in Room 28.
* Loads a special palette from ALFRED.7 at offset 0x1610CE and
* fades to it using the step-wise palette transition.
- *
- * Original handler at Ghidra address 0x1FED8.
*/
void PelrockEngine::pickUpMatches(HotSpot *hotspot) {
// Load the special palette from ALFRED.7 at offset 0x1610CE
@@ -1260,8 +1287,12 @@ void PelrockEngine::pickUpMatches(HotSpot *hotspot) {
_graphics->fadePaletteToTarget(targetPalette, 25);
debug("Finished palette fade for room 28 object pickup");
// Pick up the item
- // addInventoryItem(hotspot->extra);
_room->disableHotspot(hotspot);
+ _state->setFlag(FLAG_CROCODILLO_ENCENDIDO, true);
+ _room->moveHotspot(_room->findHotspotByExtra(87), 415, 171);
+ _room->moveHotspot(_room->findHotspotByExtra(88), 305, 217);
+ _room->moveHotspot(_room->findHotspotByExtra(89), 201, 239);
+ _room->moveHotspot(_room->findHotspotByExtra(112), 261, 259);
}
/**
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 3cb01f23df7..3f26f1d81cc 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -670,13 +670,13 @@ void PelrockEngine::placeSticker(Sticker sticker) {
for (int y = 0; y < sticker.h; y++) {
for (int x = 0; x < sticker.w; x++) {
byte pixel = sticker.stickerData[y * sticker.w + x];
- if (pixel != 0) {
+ // if (pixel != 0) {
int bgX = sticker.x + x;
int bgY = sticker.y + y;
if (bgX >= 0 && bgX < 640 && bgY >= 0 && bgY < 400) {
_compositeBuffer[bgY * 640 + bgX] = pixel;
}
- }
+ // }
}
}
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index d7edb3fd9bd..820c9354bd0 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -323,7 +323,12 @@ public:
void closeTravelAgencyDoor(HotSpot *hotspot);
void usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot);
void pickupSunflower(HotSpot *hotspot);
+ void checkIngredients();
void pickUpBook(int i);
+ void pickUpChainsaw(HotSpot *hotspot);
+ void pickUpSpellbook(HotSpot *hotspot);
+ void pickUpBoot(HotSpot *hotspot);
+ void pickupCondoms(HotSpot *hotspot);
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
Commit: 1f929725d2ac323f75acaf629a450a21d67088ca
https://github.com/scummvm/scummvm/commit/1f929725d2ac323f75acaf629a450a21d67088ca
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:01+02:00
Commit Message:
PELROCK: Spell book
Changed paths:
A engines/pelrock/extrascreens.cpp
A engines/pelrock/extrascreens.h
engines/pelrock/actions.cpp
engines/pelrock/computer.cpp
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/module.mk
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 09bfcc1013d..ac8ea7ff1aa 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -26,6 +26,7 @@
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
+#include "pelrock/extrascreens.h"
namespace Pelrock {
@@ -1138,6 +1139,41 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_dialog->say(_res->_ingameTexts[QUELASTIMA_NOSEEGIPCIO]);
}
break;
+ case 88: {
+
+ SpellBook spellBook = SpellBook(_events, _res);
+ _res->loadAlfredSpecialAnim(0);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+
+ Spell *spell = spellBook.run();
+ if (spell) {
+ _alfredState.direction = ALFRED_LEFT;
+ _dialog->say(_res->_ingameTexts[DIOSHALCON + spell->page], 1);
+ if(spell->page == 12 && _room->_currentRoomNumber == 28) {
+ _graphics->clearScreen();
+ int waitFrames = 0;
+ //blank screen for half a second
+ while (!shouldQuit() && waitFrames < 20)
+ {
+ _events->pollEvent();
+ _chrono->updateChrono();
+ if(_chrono->_gameTick) {
+ waitFrames++;
+ }
+ _screen->markAllDirty();
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+
+ _alfredState.x = 145;
+ _alfredState.y = 312;
+ setScreen(25, ALFRED_RIGHT);
+ _dialog->say(_res->_ingameTexts[MENUDAAVENTURA]);
+ }
+ }
+ break;
+ }
case 0: // yellow book
_res->loadAlfredSpecialAnim(0);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index 4b675b82dec..04b9d7c9005 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -23,7 +23,6 @@
#include "common/system.h"
#include "graphics/paletteman.h"
-#include "computer.h"
#include "pelrock/computer.h"
#include "pelrock/library_books.h"
#include "pelrock/pelrock.h"
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
new file mode 100644
index 00000000000..e47a39e2223
--- /dev/null
+++ b/engines/pelrock/extrascreens.cpp
@@ -0,0 +1,175 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "common/events.h"
+#include "graphics/paletteman.h"
+
+#include "extrascreens.h"
+#include "pelrock/extrascreens.h"
+#include "pelrock/graphics.h"
+#include "pelrock/util.h"
+
+namespace Pelrock {
+
+SpellBook::SpellBook(PelrockEventManager *eventMan, ResourceManager *res)
+ : _backgroundScreen(nullptr),
+ _palette(nullptr),
+ _events(eventMan),
+ _res(res),
+ _spell(nullptr) {
+ init();
+}
+
+SpellBook::~SpellBook() {
+ cleanup();
+}
+
+Spell *SpellBook::run() {
+ loadBackground();
+ g_engine->changeCursor(DEFAULT);
+ while (!g_engine->shouldQuit() && !_selectedSpell) {
+ _events->pollEvent();
+ drawScreen();
+ if (_events->_leftMouseClicked) {
+ _events->_leftMouseClicked = false;
+ checkMouse(_events->_mouseClickX, _events->_mouseClickY);
+ }
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+ g_system->delayMillis(10);
+ }
+ memset(g_engine->_screen->getPixels(), 0, 640 * 400);
+ // Restore room palette
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+ return _selectedSpell;
+}
+
+void SpellBook::init() {
+ _compositeScreen = new byte[640 * 400];
+
+ // selectPage(0);
+}
+
+void SpellBook::selectPage(int page) {
+ _spell = new Spell();
+ _spell->page = page;
+ Common::File alfred7;
+ if (!alfred7.open("ALFRED.7")) {
+ return;
+ }
+
+ Common::File juegoFile;
+ if (!juegoFile.open("JUEGO.EXE")) {
+ return;
+ }
+
+ alfred7.seek(1268719, SEEK_SET);
+ int w = 119;
+ int h = 99;
+ int nFrames = 13;
+ byte *compressedData = nullptr;
+ byte *spriteData = nullptr;
+ size_t outSize = 0;
+ readUntilBuda(&alfred7, 1268723, compressedData, outSize);
+ rleDecompress(compressedData, outSize, 0, w * h * nFrames, &spriteData, false);
+ _spell->image = new byte[w * h];
+ extractSingleFrame(spriteData, _spell->image, page, w, h);
+
+ juegoFile.seek(0x0004661C, SEEK_SET);
+ byte *textData = new byte[2861];
+ juegoFile.read(textData, 2861);
+
+ for (int i = 0; i < 2861; ++i) {
+ if (textData[i] == 0x0D)
+ textData[i] = 23;
+ }
+
+ Common::Array<Common::StringArray> spells = _res->processTextData(textData, 2861, true);
+
+ _spell->text = spells[page];
+ delete[] compressedData;
+ delete[] spriteData;
+ alfred7.close();
+ juegoFile.close();
+}
+
+void SpellBook::drawScreen() {
+ memcpy(_compositeScreen, _backgroundScreen, 640 * 400);
+
+ int textY = 83;
+ int textX = 317;
+
+ if (_spell != nullptr) {
+ drawSpriteToBuffer(_compositeScreen, 640, _spell->image, 168, 143, 119, 99, 207);
+ g_engine->_graphics->drawColoredTexts(_compositeScreen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
+ }
+
+ drawPaletteSquares(_compositeScreen, _palette);
+ memcpy(g_engine->_screen->getPixels(), _compositeScreen, 640 * 400);
+ if (_spell != nullptr) {
+ g_engine->_graphics->drawColoredTexts(g_engine->_screen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
+ }
+}
+
+void SpellBook::loadBackground() {
+ _backgroundScreen = new byte[640 * 400];
+ _palette = new byte[768];
+ _res->getExtraScreen(8, _backgroundScreen, _palette);
+ g_system->getPaletteManager()->setPalette(_palette, 0, 256);
+}
+
+void SpellBook::cleanup() {
+ if (_backgroundScreen) {
+ delete[] _backgroundScreen;
+ _backgroundScreen = nullptr;
+ }
+ if (_palette) {
+ delete[] _palette;
+ _palette = nullptr;
+ }
+ if (_spell) {
+ delete _spell;
+ _spell = nullptr;
+ }
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+}
+
+void SpellBook::checkMouse(int x, int y) {
+ // Check bookmarks
+ for (int i = 0; i < 13; i++) {
+ Common::Rect r = Common::Rect(_bookmarks[i].x, _bookmarks[i].y, _bookmarks[i].x + _bookmarks[i].w, _bookmarks[i].y + _bookmarks[i].h);
+ if (r.contains(x, y)) {
+ selectPage(_bookmarks[i].page);
+ return;
+ }
+ }
+
+ // Check text area
+ if (_spell == nullptr) {
+ return;
+ }
+ Common::Rect textArea = Common::Rect(321, 81, 321 + 140, 81 + (_spell->text.size() * 10));
+ if (textArea.contains(x, y)) {
+ _selectedSpell = _spell;
+ }
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/extrascreens.h b/engines/pelrock/extrascreens.h
new file mode 100644
index 00000000000..c1fe52a1be5
--- /dev/null
+++ b/engines/pelrock/extrascreens.h
@@ -0,0 +1,92 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PELROCK_EXTRASCREENS_H
+#define PELROCK_EXTRASCREENS_H
+
+#include "pelrock/pelrock.h"
+
+namespace Pelrock {
+
+class PelrockEngine;
+
+struct Spell {
+ Common::StringArray text;
+ int page;
+ byte *image;
+};
+
+struct Bookmark {
+ int16 x;
+ int16 y;
+ byte w;
+ byte h;
+ int page;
+};
+
+static const Bookmark _bookmarks[13] = {
+ {244, 8, 23, 40, 0},
+ {396, 17, 44, 20, 1},
+ {480, 68, 40, 42, 4},
+ {480, 129, 30, 25, 5},
+ {480, 224, 28, 32, 8},
+ {416, 344, 23, 17, 12},
+ {368, 346, 28, 34, 11},
+ {198, 340, 26, 28, 10},
+ {164, 336, 33, 17, 9},
+ {95, 277, 33, 24, 7},
+ {105, 227, 27, 33, 6},
+ {103, 118, 30, 26, 3},
+ {101, 78, 36, 33, 2}
+};
+
+class SpellBook {
+
+public:
+ SpellBook(PelrockEventManager *eventMan, ResourceManager *res);
+ ~SpellBook();
+
+ /**
+ * returns the spell the user selected
+ */
+ Spell *run();
+
+private:
+ PelrockEventManager *_events;
+ ResourceManager *_res;
+ byte *_backgroundScreen;
+ byte *_compositeScreen;
+ byte *_palette;
+
+ Spell *_spell = nullptr;
+
+ Spell *_selectedSpell = nullptr;
+ void init();
+ void selectPage(int page);
+ void drawScreen();
+ void loadBackground();
+ void cleanup();
+ void checkMouse(int x, int y);
+};
+
+} // End of namespace Pelrock
+
+#endif // PELROCK_EXTRASCREENS_H
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index bda96e13442..5d88c147a5a 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -147,4 +147,91 @@ void GraphicsManager::clearScreen() {
memset(g_engine->_screen->getPixels(), 0, g_engine->_screen->pitch * g_engine->_screen->h);
}
+void GraphicsManager::drawColoredText(Graphics::ManagedSurface *screen, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font) {
+ int currentX = x;
+
+ Common::String segment;
+ for (uint i = 0; i < text.size(); i++) {
+ if (text[i] == '@' && i + 1 < text.size()) {
+ // Draw accumulated segment
+ if (!segment.empty()) {
+ font->drawString(screen, segment, currentX, y, w, defaultColor);
+ currentX += font->getStringWidth(segment);
+ segment.clear();
+ }
+ defaultColor = text[i + 1];
+ i++; // skip color code
+ } else {
+ segment += text[i];
+ }
+ }
+
+ // Draw remaining segment
+ if (!segment.empty()) {
+ font->drawString(screen, segment, currentX, y, w, defaultColor);
+ }
+}
+
+void GraphicsManager::drawColoredText(byte *buf, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font) {
+
+ Graphics::Surface tempSurface;
+ Common::Rect r = font->getBoundingBox(text); // Ensure font metrics are loaded before creating surface
+
+ tempSurface.create(r.width(), r.height(), Graphics::PixelFormat::createFormatCLUT8());
+
+ int currentX = x;
+
+ Common::String segment;
+ for (uint i = 0; i < text.size(); i++) {
+ if (text[i] == '@' && i + 1 < text.size()) {
+ // Draw accumulated segment
+ if (!segment.empty()) {
+ font->drawString(&tempSurface, segment, currentX, y, w, defaultColor);
+ currentX += font->getStringWidth(segment);
+ segment.clear();
+ }
+ defaultColor = text[i + 1];
+ i++; // skip color code
+ } else {
+ segment += text[i];
+ }
+ }
+
+ // Draw remaining segment
+ if (!segment.empty()) {
+ font->drawString(&tempSurface, segment, currentX, y, w, defaultColor);
+ }
+
+ for(int j = 0; j < tempSurface.h; j++) {
+ for(int i = 0; i < tempSurface.w; i++) {
+ int idx = j * tempSurface.w + i;
+ if (y + j < 400 && x + i < 640) {
+ byte pixel = *((byte *)tempSurface.getBasePtr(i, j));
+ if (pixel != 0) { // Assuming 0 is transparent
+ debug("Drawing pixel at (%d, %d) with color %d", x + i, y + j, pixel);
+ buf[(y + j) * 640 + (x + i)] = pixel;
+ }
+ }
+ }
+ }
+}
+
+void GraphicsManager::drawColoredTexts(Graphics::ManagedSurface *surface, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font) {
+ int currentX = x;
+ byte currentColor = 255;
+
+ for(int i =0; i < text.size(); i++) {
+ drawColoredText(surface, text[i], currentX, y + i * (font->getFontHeight() + yPadding), w, currentColor, font);
+ }
+}
+
+void GraphicsManager::drawColoredTexts(byte *buf, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font) {
+ int currentX = x;
+ byte currentColor = 255;
+
+ for(int i =0; i < text.size(); i++) {
+ drawColoredText(buf, text[i], currentX, y + i * (font->getFontHeight() + yPadding), w, currentColor, font);
+ }
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index be2230e10a9..fd2de370bd2 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -21,7 +21,11 @@
#ifndef PELROCK_GRAPHICS_H
#define PELROCK_GRAPHICS_H
+#include "common/array.h"
+#include "common/str-array.h"
#include "common/scummsys.h"
+
+#include "graphics/font.h"
#include "graphics/screen.h"
namespace Pelrock {
@@ -37,6 +41,10 @@ public:
void fadeToBlack(int stepSize);
void fadePaletteToTarget(byte *targetPalette, int stepSize);
void clearScreen();
+ void drawColoredText(Graphics::ManagedSurface *screen, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font);
+ void drawColoredText(byte *buf, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font);
+ void drawColoredTexts(Graphics::ManagedSurface *surface, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font);
+ void drawColoredTexts(byte *buf, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 69449dcc1f4..b67c763260e 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -34,32 +34,6 @@ namespace Pelrock {
Pelrock::MenuManager::MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res, SoundManager *sound) : _screen(screen), _events(events), _res(res), _sound(sound) {
}
-void MenuManager::drawColoredText(Graphics::ManagedSurface *screen, const Common::String &text, int x, int y, int w, Graphics::Font *font) {
- int currentX = x;
- uint32 currentColor = 255;
-
- Common::String segment;
- for (uint i = 0; i < text.size(); i++) {
- if (text[i] == '@' && i + 1 < text.size()) {
- // Draw accumulated segment
- if (!segment.empty()) {
- font->drawString(screen, segment, currentX, y, w, currentColor);
- currentX += font->getStringWidth(segment);
- segment.clear();
- }
- currentColor = text[i + 1];
- i++; // skip color code
- } else {
- segment += text[i];
- }
- }
-
- // Draw remaining segment
- if (!segment.empty()) {
- font->drawString(screen, segment, currentX, y, w, currentColor);
- }
-}
-
MenuButton MenuManager::isButtonClicked(int x, int y) {
if (_questionMarkRect.contains(x, y)) {
return QUESTION_MARK_BUTTON;
@@ -175,8 +149,9 @@ void MenuManager::drawScreen() {
drawInventoryIcons();
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+ byte defaultColor = 255;
for (int i = 0; _menuText.size() > i; i++) {
- drawColoredText(_screen, _menuText[i], 230, 200 + (i * 10), 200, g_engine->_smallFont);
+ g_engine->_graphics->drawColoredText(_screen, _menuText[i], 230, 200 + (i * 10), 200, defaultColor, g_engine->_smallFont);
}
drawText(g_engine->_smallFont, Common::String::format("%d,%d", _events->_mouseX, _events->_mouseY), 0, 0, 640, 13);
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 781b721715d..0c097817f77 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -180,7 +180,6 @@ private:
void loadMenuTexts();
void cleanUp();
void drawButtons();
- void drawColoredText(Graphics::ManagedSurface *surface, const Common::String &text, int x, int y, int w, Graphics::Font *font);
void readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect);
MenuButton isButtonClicked(int x, int y);
Graphics::Screen *_screen = nullptr;
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index 5a295a952b0..dbbf56ce979 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -20,7 +20,8 @@ MODULE_OBJS = \
dialog.o \
menu.o \
graphics.o \
- saveload.o
+ saveload.o \
+ extrascreens.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 9ff2fa9fd2e..0af6d1883c0 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -467,9 +467,13 @@ const ExtraImages extraScreens[] = {
{0xFFC47, // girl book
0x1180C9,
8},
- {0x1183C5, // book
+ /*{0x1183C5, // book
0x1358F3,
- 8},
+ 8},*/
+{ 1147849,
+ 1267955,
+ 8
+},
{0x152A88, // portrait
0x15BFC8,
8},
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 3f26f1d81cc..55711136eaa 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -39,6 +39,7 @@
#include "pelrock/computer.h"
#include "pelrock/console.h"
#include "pelrock/detection.h"
+#include "pelrock/extrascreens.h"
#include "pelrock/fonts/small_font.h"
#include "pelrock/offsets.h"
#include "pelrock/pathfinding.h"
@@ -156,7 +157,7 @@ void PelrockEngine::init() {
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
- setScreen(25, ALFRED_DOWN);
+ setScreen(28, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -1487,6 +1488,14 @@ void PelrockEngine::gameLoop() {
antiPiracyEffect();
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_s) {
+ SpellBook spellBook(_events, _res);
+ Spell *selectedSpell = spellBook.run();
+ if(selectedSpell != nullptr) {
+ _dialog->sayAlfred(selectedSpell->text);
+ }
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
renderScene();
// _events->waitForKey();
_screen->update();
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index f7fa6e94803..6fdec3ae0cf 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -24,7 +24,6 @@
#include "pelrock/pelrock.h"
#include "pelrock/room.h"
#include "pelrock/util.h"
-#include "resources.h"
namespace Pelrock {
@@ -358,10 +357,11 @@ Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data,
pos++;
continue;
}
- if (data[pos] == 0x00) {
+ if (data[pos] == 0x00 || data[pos] == 0x78) {
pos++;
continue;
}
+
if (data[pos] == CTRL_SPEAKER_ID) {
byte color = data[pos + 1];
desc.append(1, '@');
@@ -435,7 +435,7 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
readUntilBuda(stream, stream->pos(), thisBlock, blockSize);
uint8_t *block_data = nullptr;
size_t decompressedSize = rleDecompress(thisBlock, blockSize, 0, 640 * 400, &block_data, true);
- debug("Decompressed block %d: %zu bytes, total %zu", i, decompressedSize, combined_size + decompressedSize);
+ // debug("Decompressed block %d: %zu bytes, total %zu", i, decompressedSize, combined_size + decompressedSize);
if (combined_size + decompressedSize > 640 * 400) {
debug("Warning: decompressed data exceeds output buffer size, truncating");
decompressedSize = 640 * 400 - combined_size;
Commit: 496946f4b27bbe27675015201494bd36e880bd3c
https://github.com/scummvm/scummvm/commit/496946f4b27bbe27675015201494bd36e880bd3c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:02+02:00
Commit Message:
PELROCK: Implements Egyptian museum
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index ac8ea7ff1aa..aa4779cca8c 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -124,6 +124,19 @@ const ActionEntry actionTable[] = {
{89, PICKUP, &PelrockEngine::pickUpBoot},
{112, PICKUP, &PelrockEngine::pickupCondoms},
+ // Room 29
+ {434, OPEN, &PelrockEngine::openEgyptMuseumDoor},
+ {434, CLOSE, &PelrockEngine::closeEgyptMuseumDoor},
+
+ // Room 30
+ {435, PUSH, &PelrockEngine::pushSymbol1},
+ {436, PUSH, &PelrockEngine::pushSymbol2},
+ {437, PUSH, &PelrockEngine::pushSymbol3},
+ {438, PUSH, &PelrockEngine::pushSymbol4},
+
+ // Room 38
+ {81, PICKUP, &PelrockEngine::pickUpHairStrand},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -1041,6 +1054,70 @@ void PelrockEngine::pickupCondoms(HotSpot *hotspot) {
_room->addSticker(100);
}
+void PelrockEngine::openEgyptMuseumDoor(HotSpot *hotspot) {
+ openDoor(hotspot, 0, 59, MASCULINE, false);
+}
+
+void PelrockEngine::closeEgyptMuseumDoor(HotSpot *hotspot) {
+ closeDoor(hotspot, 0, 59, MASCULINE, false);
+}
+
+void PelrockEngine::pushSymbol1(HotSpot *hotspot) {
+ if(_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
+ debug("Current symbols pulled: %d", symbolsPulled);
+ _state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x1);
+ debug("New symbols pulled: %d", _state->getFlag(FLAG_SYMBOLS_PUSHED));
+ checkAllSymbols();
+ }
+}
+
+void PelrockEngine::pushSymbol2(HotSpot *hotspot) {
+ if(_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
+ debug("Current symbols pulled: %d", symbolsPulled);
+ _state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x2);
+ debug("New symbols pulled: %d", _state->getFlag(FLAG_SYMBOLS_PUSHED));
+ checkAllSymbols();
+ }
+}
+
+void PelrockEngine::pushSymbol3(HotSpot *hotspot) {
+ if(_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
+ debug("Current symbols pulled: %d", symbolsPulled);
+ _state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x4);
+ debug("New symbols pulled: %d", _state->getFlag(FLAG_SYMBOLS_PUSHED));
+ checkAllSymbols();
+ }
+}
+
+void PelrockEngine::pushSymbol4(HotSpot *hotspot) {
+ if(_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
+ debug("Current symbols pulled: %d", symbolsPulled);
+ _state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x8);
+ debug("New symbols pulled: %d", _state->getFlag(FLAG_SYMBOLS_PUSHED));
+ checkAllSymbols();
+ }
+}
+
+void PelrockEngine::pickUpHairStrand(HotSpot *hotspot) {
+ checkIngredients();
+}
+
+void PelrockEngine::checkAllSymbols() {
+ byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
+ debug("Checking symbols, current value: %d", symbolsPulled);
+ if(symbolsPulled == 0x0F) {
+ //Activates animation
+ _room->enableSprite(4, 100, PERSIST_TEMP);
+ _room->enableExit(0, PERSIST_BOTH);
+ _room->addSticker(61);
+ _room->addSticker(63);
+ }
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
@@ -1070,6 +1147,9 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
case 282:
_dialog->say(_res->_ingameTexts[SELORECOMIENDO]);
break;
+ case 327:
+ _state->setFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO, true);
+ break;
}
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 55711136eaa..87b09417263 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -157,7 +157,7 @@ void PelrockEngine::init() {
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
- setScreen(28, ALFRED_DOWN);
+ setScreen(30, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -1180,6 +1180,10 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
animData.curFrame = 0;
animData.curLoop++;
} else {
+ if(sprite->disableAfterSequence) {
+ sprite->zOrder = -1;
+ return;
+ }
animData.curFrame = 0;
animData.curLoop = 0;
if (sprite->curAnimIndex < sprite->numAnims - 1) {
@@ -1356,7 +1360,7 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
Exit exit = _room->_currentRoomExits[i];
// Original game uses: x <= exit.x + exit.w - 1 and y <= exit.y + exit.h - 1
if (x >= exit.x && x <= (exit.x + exit.w - 1) &&
- y >= exit.y && y <= (exit.y + exit.h - 1) && exit.isEnabled) {
+ y >= exit.y && y <= (exit.y + exit.h - 1) /*&& exit.isEnabled*/) {
return &(_room->_currentRoomExits[i]);
}
}
@@ -1813,7 +1817,18 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_dialog->say(_res->_ingameTexts[QUIENYO]);
_dialog->say(_res->_ingameTexts[PINTA_BUENAPERSONA]);
}
-
+ case 38: {
+ int x = _alfredState.x;
+ int y = _alfredState.y;
+ _alfredState.x -= 57;
+ _alfredState.y += 2;
+ _res->loadAlfredSpecialAnim(6);
+ _alfredState.setState(ALFRED_SPECIAL_ANIM);
+ waitForSpecialAnimation();
+ _alfredState.x = x;
+ _alfredState.y = y;
+ break;
+ }
default:
break;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 820c9354bd0..2302c045bdc 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -329,6 +329,14 @@ public:
void pickUpSpellbook(HotSpot *hotspot);
void pickUpBoot(HotSpot *hotspot);
void pickupCondoms(HotSpot *hotspot);
+ void openEgyptMuseumDoor(HotSpot *hotspot);
+ void closeEgyptMuseumDoor(HotSpot *hotspot);
+ void pushSymbol1(HotSpot *hotspot);
+ void pushSymbol2(HotSpot *hotspot);
+ void pushSymbol3(HotSpot *hotspot);
+ void pushSymbol4(HotSpot *hotspot);
+ void pickUpHairStrand(HotSpot *hotspot);
+ void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 6fdec3ae0cf..b46915b8def 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -36,12 +36,13 @@ ResourceManager::ResourceManager(/* args */) {
}
const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
- {10, 51, 102, 1, 7, 559685, 1, }, // READ BOOK
+ {10, 51, 102, 1, 7, 559685, 1,}, // READ BOOK
{10, 51, 102, 1, 7, 578943, 1}, // READ RECIPE
{3, 45, 87, 0, 7, 37000, 1}, // ELECTRIC SHOCK 1
{2, 82, 58, 0, 7, 53106, 20}, // ELECTRIC SHOCK 3
{3, 71, 110, 1, 2, 20724, 1, 62480}, // Throw
{14, 171, 107, 1, 7, 1556540, 1} , //crocodile
+ {12, 113, 103, 1, 7, 1583702, 1} // exit through manhole
};
ResourceManager::~ResourceManager() {
@@ -244,7 +245,11 @@ void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
_currentSpecialAnim->animData = new byte[size];
if (anim.numBudas > 0) {
debug("Loading special anim with budas: numBudas=%d, totalSize %d", anim.numBudas, size);
- mergeRleBlocks(&alfredFile, anim.offset, anim.numBudas, _currentSpecialAnim->animData);
+ byte *thisBlock = nullptr;
+ size_t blockSize = 0;
+ readUntilBuda(&alfredFile, anim.offset, thisBlock, blockSize);
+ rleDecompress(thisBlock, blockSize, 0, size, &_currentSpecialAnim->animData, false);
+ delete[] thisBlock;
} else {
alfredFile.read(_currentSpecialAnim->animData, anim.numFrames * anim.w * anim.h);
}
@@ -435,7 +440,7 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
readUntilBuda(stream, stream->pos(), thisBlock, blockSize);
uint8_t *block_data = nullptr;
size_t decompressedSize = rleDecompress(thisBlock, blockSize, 0, 640 * 400, &block_data, true);
- // debug("Decompressed block %d: %zu bytes, total %zu", i, decompressedSize, combined_size + decompressedSize);
+ debug("Decompressed block %d: %zu bytes, total %zu", i, decompressedSize, combined_size + decompressedSize);
if (combined_size + decompressedSize > 640 * 400) {
debug("Warning: decompressed data exceeds output buffer size, truncating");
decompressedSize = 640 * 400 - combined_size;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 495c43fce1e..52f556912a4 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -898,6 +898,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
debug("Sprite %d: x=%d y=%d w=%d h=%d stride=%d numAnims=%d zOrder=%d extra=%d", i, sprite.x, sprite.y, sprite.w, sprite.h, sprite.stride, sprite.numAnims, sprite.zOrder, sprite.extra);
sprite.actionFlags = data[animOffset + 34];
sprite.isHotspotDisabled = data[animOffset + 38];
+ sprite.disableAfterSequence = data[animOffset + 39];
for (int j = 0; j < spriteChanges.size(); j++) {
if (spriteChanges[j].spriteIndex == sprite.index) {
sprite.zOrder = spriteChanges[j].zIndex;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index e0f96b70891..1bcd8a17d54 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -235,6 +235,7 @@ struct Sprite {
byte actionFlags; // 34
bool isHotspotDisabled; // 38
+ bool disableAfterSequence = false; // 39
bool isTalking = false;
Anim *animData;
int16 extra;
@@ -466,12 +467,12 @@ struct ResetEntry {
#define FLAG_ALFRED_SABE_EGIPCIO 10
#define FLAG_VENDEDOR_DEJA_DE_JODER 11
#define FLAG_PARADOJA_RESUELTA 13
+#define FLAG_MIRA_SIMBOLO_FUERA_MUSEO 15
+#define FLAG_CROCODILLO_ENCENDIDO 14
#define FLAG_VIAJE_A_EGIPTO 12
-#define FLAG_CROCODILLO_ENCENDIDO 14
-#define FLAG_MIRA_SIMBOLO_FUERA_MUSEO 15
#define FLAG_PUERTA_SECRETA_ABIERTA 16
#define FLAG_ROBA_PELO_PRINCESA 17
#define FLAG_A_LA_CARCEL 18
@@ -514,8 +515,9 @@ struct ResetEntry {
#define FLAG_RESPUESTAS_ACERTADAS 54
#define FLAG_CHEAT_CODE_ENABLED 55 // 0x495F3 - enables HIJODELAGRANPUTA cheat code input
#define FLAG_RIDDLE_PRESENTED 56
+#define FLAG_SYMBOLS_PUSHED 57
-const int kNumGameFlags = 57;
+const int kNumGameFlags = 58;
struct GameStateData {
byte flags[kNumGameFlags];
Commit: 87d5093bfd6002dcba4c741cbf905fb88b87fda3
https://github.com/scummvm/scummvm/commit/87d5093bfd6002dcba4c741cbf905fb88b87fda3
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:02+02:00
Commit Message:
PELROCK: Play sound when opening secret door
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index aa4779cca8c..58b5585c4e1 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1111,6 +1111,7 @@ void PelrockEngine::checkAllSymbols() {
debug("Checking symbols, current value: %d", symbolsPulled);
if(symbolsPulled == 0x0F) {
//Activates animation
+ _sound->playSound(_room->_roomSfx[0]);
_room->enableSprite(4, 100, PERSIST_TEMP);
_room->enableExit(0, PERSIST_BOTH);
_room->addSticker(61);
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 0af6d1883c0..1ed37e6f326 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -401,30 +401,30 @@ const uint16_t description_offsets[NUM_DESCRIPTIONS] = {
0x1D7A, // Object 77: Un poco de escayola vieja
0x1DA3, // Object 78: Un cacho de ladrillo
0x1DCC, // Object 79: Un boligrafo
- 0x1DE5, // Object 80: Un radiocasete
- 0x1E00, // Object 81: Es una pistola. (Real como la vida misma)
- 0x1E49, // Object 82: Una pieza de fruta
- 0x1E6B, // Object 83: Un frasco de pastillas para dormir
- 0x1EA0, // Object 84: Una pulsera
- 0x1EB9, // Object 85: Una estatua pequeña
- 0x1EE0, // Object 86: Una jodida (disculpen las molestias) cinta de video
- 0x1F4F, // Object 87: Una jodida (disculpen las molestias) cadena hifi
- 0x1FBE, // Object 88: Una magdalena
- 0x1FD8, // Object 89: Un poco de cecina
- 0x1FFC, // Object 90: Un televisor portatil con forma de Mickey Mouse
- 0x2053, // Object 91: Un destornillador
- 0x2071, // Object 92: Alicates de electricista
- 0x2097, // Object 93: Un cable
- 0x20AE, // Object 94: Una linterna
- 0x20C6, // Object 95: Unas pilas gigantes
- 0x20E7, // Object 96: La bolsa de basura negra
- 0x2116, // Object 97: Foto de un tal Gerardo (desconocido)
- 0x2158, // Object 98: Una cinta de casete
- 0x2179, // Object 99: Un walkman
- 0x218F, // Object 100: Un papel con un telefono
- 0x21BE, // Object 101: Una llave grande de metacrilato
- 0x21F1, // Object 102: Una pequeña llave
- 0x220E, // Object 103: Autenticas naranjas de Nules
+ 0x1DE5, // Object 80: Un radiocasete < --- aqui
+ 0x1E00, // Object 81: El pelo de una princesa egipcia
+ 0x1E49, // Object 82: Un mogollon de pasta
+ 0x1E6B, // Object 83: Una replica de Elvis
+ 0x1EA0, // Object 84: Aunque no sean piramides se puede decir que son monumentos
+ 0x1EB9, // Object 85: Un girasol
+ 0x1EE0, // Object 86: Una calabaza llena de agua
+ 0x1F4F, // Object 87: Una motosierra
+ 0x1FBE, // Object 88: Un libro de recetas magicas
+ 0x1FD8, // Object 89: Una bota usada
+ 0x1FFC, // Object 90: Una autentica piedra egipcia
+ 0x2053, // Object 91: Una piedra egipcia
+ 0x2071, // Object 92: Un poco de barro
+ 0x2097, // Object 93: Licor de arena
+ 0x20AE, // Object 94: Crema para el sol
+ 0x20C6, // Object 95: Banda sonora de alfred pelrock
+ 0x20E7, // Object 96: Un album de pantallas
+ 0x2116, // Object 97: Plano de la piramide
+ 0x2158, // Object 98: Plano detallado
+ 0x2179, // Object 99: Es una peluca
+ 0x218F, // Object 100: Una pequeña llave
+ 0x21BE, // Object 101: Un trozo de papel con unos numeritos
+ 0x21F1, // Object 102: Autenticas naranjas de Nules
+ 0x220E, // Object 103: Un mogollon de naranjas de Nules
0x2236, // Object 104: No se haga el loco: Llameme !!!
0x2285, // Object 105: Folletos explicativos sobre el SIDA
0x22BE, // Object 106: Un pin que acredita mi sabiduria
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 87b09417263..d72895aae7b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1360,7 +1360,7 @@ Exit *PelrockEngine::isExitUnder(int x, int y) {
Exit exit = _room->_currentRoomExits[i];
// Original game uses: x <= exit.x + exit.w - 1 and y <= exit.y + exit.h - 1
if (x >= exit.x && x <= (exit.x + exit.w - 1) &&
- y >= exit.y && y <= (exit.y + exit.h - 1) /*&& exit.isEnabled*/) {
+ y >= exit.y && y <= (exit.y + exit.h - 1) && exit.isEnabled) {
return &(_room->_currentRoomExits[i]);
}
}
Commit: 556703dc941ed85bb196923369747a8e6e4f84ac
https://github.com/scummvm/scummvm/commit/556703dc941ed85bb196923369747a8e6e4f84ac
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:02+02:00
Commit Message:
PELROCK: Implements Rooms 31 and 32
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/menu.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/saveload.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 58b5585c4e1..1979779bc92 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -137,6 +137,10 @@ const ActionEntry actionTable[] = {
// Room 38
{81, PICKUP, &PelrockEngine::pickUpHairStrand},
+ // Room 31
+ {462, OPEN, &PelrockEngine::openJailFloorTile},
+ // Room 32
+ {473, OPEN, &PelrockEngine::openTunnelDrawer},
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -467,7 +471,13 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setFlag(FLAG_PARADOJA_RESUELTA, 1);
_state->setCurrentRoot(room, 1);
break;
-
+ case 292:
+ _state->setCurrentRoot(room, rootIndex + 1);
+ break;
+ case 293:
+ _room->disableHotspot(_room->findHotspotByExtra(451)); // Disable talk hotspot for the riddle
+ _state->setCurrentRoot(room, rootIndex + 1);
+ break;
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
@@ -956,7 +966,7 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
_alfredState.x -= 10;
_alfredState.y += 20;
waitForSpecialAnimation();
- _sound->playSound(_room->_roomSfx[0], 100, 0); // Belch
+ _sound->playSound(_room->_roomSfx[0], 0); // Belch
bool isPlaying = true;
while (!shouldQuit() && isPlaying) {
_events->pollEvent();
@@ -1102,10 +1112,6 @@ void PelrockEngine::pushSymbol4(HotSpot *hotspot) {
}
}
-void PelrockEngine::pickUpHairStrand(HotSpot *hotspot) {
- checkIngredients();
-}
-
void PelrockEngine::checkAllSymbols() {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
debug("Checking symbols, current value: %d", symbolsPulled);
@@ -1119,6 +1125,24 @@ void PelrockEngine::checkAllSymbols() {
}
}
+void PelrockEngine::pickUpHairStrand(HotSpot *hotspot) {
+ checkIngredients();
+}
+
+void PelrockEngine::openJailFloorTile(HotSpot *hotspot) {
+ if (_room->hasSticker(77)) {
+ _dialog->say(_res->_ingameTexts[YA_ABIERTO_M]);
+ return;
+ }
+ _room->enableExit(0, PERSIST_BOTH);
+ _room->addSticker(77, PERSIST_BOTH);
+}
+
+void PelrockEngine::openTunnelDrawer(HotSpot *hotspot) {
+ _room->addSticker(78, PERSIST_BOTH);
+ _room->disableHotspot(hotspot);
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
@@ -1151,6 +1175,10 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
case 327:
_state->setFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO, true);
break;
+ case 294:
+ HotSpot *floorTile = _room->findHotspotByExtra(462);
+ floorTile->actionFlags = ACTION_MASK_OPEN;
+ _room->changeHotSpot(*floorTile);
}
}
@@ -1459,7 +1487,7 @@ void PelrockEngine::antiPiracyEffect() {
}
// Play the noise
- _sound->playSound(noiseData, kNoiseLength + 44, 200);
+ _sound->playSound(noiseData, kNoiseLength + 44);
byte *screenPixels = (byte *)_screen->getPixels();
int screenSize = _screen->pitch * _screen->h;
@@ -1488,7 +1516,7 @@ void PelrockEngine::antiPiracyEffect() {
}
}
if (!_sound->isPlaying()) {
- _sound->playSound(noiseData, kNoiseLength + 44, 200);
+ _sound->playSound(noiseData, kNoiseLength + 44);
}
_screen->markAllDirty();
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index ecefc64faff..82055ccf378 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -215,9 +215,9 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos), 255);
drawPos(_screen, xPos, yPos, speakerId);
- drawRect(_screen, xPos, yPos,
- s.getRect().width(),
- s.getRect().height(), speakerId);
+ // drawRect(_screen, xPos, yPos,
+ // s.getRect().width(),
+ // s.getRect().height(), speakerId);
// Present to screen
_screen->markAllDirty();
_screen->update();
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index b67c763260e..2110525df6e 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -110,7 +110,7 @@ bool MenuManager::selectInventoryItem(int i) {
_selectedInvIndex = g_engine->_state->inventoryItems[_curInventoryPage * 4 + i];
_menuText = _inventoryDescriptions[_selectedInvIndex];
- _sound->playSound(inventorySounds[_selectedInvIndex], 100, 0);
+ _sound->playSound(inventorySounds[_selectedInvIndex], 0);
g_engine->_state->selectedInventoryItem = _selectedInvIndex;
debug("Selected inventory item %d", _selectedInvIndex);
return true;
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 1ed37e6f326..f77ae9531c4 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -338,9 +338,10 @@ const uint16_t description_offsets[NUM_DESCRIPTIONS] = {
0x039E, // Object 14: Titulo: El sistema inmunologico de los cefalopodos (v.I)
0x0412, // Object 15: Titulo: Dos y dos son 5
0x0493, // Object 16: Titulo: La parte creativa
- 0x057B, // Object 17: Titulo: 10 maneras de preparar fideos chinos
- 0x065C, // Object 18: Titulo: Los Peces Gato del Rio Tajo
- 0x06D8, // Object 19: Titulo: Gato por liebre
+ 0x057B, // Object 17: Titulo: Aprenda egipcio en 10 dias
+ 0x065C, // Object 18: Titulo: Gato por liebre
+ 0x06D8, // Object 19: Titulo: Enrique de Ofterdingeng
+
0x0753, // Object 20: Titulo: Hiper-cocina para solteros
0x07CE, // Object 21: Titulo: El camaleon humano
0x084E, // Object 22: Titulo: Psiquiatria Avanzada (vol. 8)
@@ -379,29 +380,30 @@ const uint16_t description_offsets[NUM_DESCRIPTIONS] = {
0x185D, // Object 55: Titulo: Los Heraldos Negros
0x18D1, // Object 56: Titulo: La Piedra Rosetta
0x194A, // Object 57: Titulo: Fabulas de Ciencia Ficcion
- 0x19C3, // Object 58: Titulo: Elogio de la pereza
- 0x1A35, // Object 59: Un pequeño altavoz
- 0x1A52, // Object 60: Un altavoz mediano
- 0x1A70, // Object 61: Un altavoz grande
- 0x1A8C, // Object 62: Un extintor
- 0x1AA3, // Object 63: Parece un extintor, pero es un termo de cafe. De los de antes, de los grandes
- 0x1B2D, // Object 64: Un termo con cafe
- 0x1B53, // Object 65: Una cafetera expres para una taza
- 0x1B8D, // Object 66: La tarjeta de acceso de Erika
- 0x1BBE, // Object 67: Billetes de avion para salir por patas hacia Valencia
- 0x1C26, // Object 68: Una bolsa de patatas fritas
- 0x1C52, // Object 69: Llave de la habitacion de Lucy
- 0x1C82, // Object 70: Llave de la habitacion de Erika
- 0x1CB3, // Object 71: Un ordenador de sobremesa
- 0x1CE1, // Object 72: Un cuadro
- 0x1CF9, // Object 73: Una moto mega-retuneada
- 0x1D24, // Object 74: Una lamparita
- 0x1D3F, // Object 75: Un libro gordo
- 0x1D5C, // Object 76: Un libro finito
- 0x1D7A, // Object 77: Un poco de escayola vieja
- 0x1DA3, // Object 78: Un cacho de ladrillo
- 0x1DCC, // Object 79: Un boligrafo
- 0x1DE5, // Object 80: Un radiocasete < --- aqui
+ 0x19C3, // Object 58: Titulo: La musica amansa a las fieras
+
+ 0x1A35, // Object 59: Un libro de recetas magicas
+ 0x1A52, // Object 60: Un bote de tomate
+ 0x1A70, // Object 61: Un bote de mostaza
+ 0x1A8C, // Object 62: Salsa ultra-picante
+ 0x1AA3, // Object 63: Receta de las hamburguesas de McDowells
+ 0x1B2D, // Object 64: Un papiro con una inscripcion jeroglifica
+ 0x1B53, // Object 65: Una guitarra española
+ 0x1B8D, // Object 66: Un pez disecado
+ 0x1BBE, // Object 67: Un osito de peluche
+ 0x1C26, // Object 68: Unos discos antiguos
+ 0x1C52, // Object 69: Un cerebro de mono
+ 0x1C82, // Object 70: Novelas del salvaje oeste
+ 0x1CB3, // Object 71: Una paleta
+ 0x1CE1, // Object 72: Caramelos de todos los sabores
+ 0x1CF9, // Object 73: Una caracola
+ 0x1D24, // Object 74: Un sombrero
+ 0x1D3F, // Object 75: 150000 pesetas
+ 0x1D5C, // Object 76: Una calabaza para meter agua dentro
+ 0x1D7A, // Object 77: Henna roja para el pelo
+ 0x1DA3, // Object 78: Piramides de recuerdo
+ 0x1DCC, // Object 79: Un chupa-chup de higo chumbo
+ 0x1DE5, // Object 80: Un amuleto egipcio
0x1E00, // Object 81: El pelo de una princesa egipcia
0x1E49, // Object 82: Un mogollon de pasta
0x1E6B, // Object 83: Una replica de Elvis
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 2302c045bdc..3338db34518 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -336,6 +336,8 @@ public:
void pushSymbol3(HotSpot *hotspot);
void pushSymbol4(HotSpot *hotspot);
void pickUpHairStrand(HotSpot *hotspot);
+ void openJailFloorTile(HotSpot *hotspot);
+ void openTunnelDrawer(HotSpot *hotspot);
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 52f556912a4..0f6fb18e071 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -472,7 +472,7 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
// if the hotspot has been changed, load the changed version
for (int j = 0; j < g_engine->_state->roomHotSpotChanges[_currentRoomNumber].size(); j++) {
if (g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspotIndex == spot.innerIndex) {
- debug("Hotspot %d has been changed, loading changed version, Hotspot x=%d, y = %d, extra = %d", spot.innerIndex, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.x, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.y, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.extra);
+ debug("Hotspot %d has been changed, loading changed version, Hotspot x=%d, y = %d, extra = %d, isEnabled=%d", spot.innerIndex, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.x, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.y, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.extra, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.isEnabled);
hotspots.push_back(g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot);
isChanged = true;
break;
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index d6dcf7dbc72..06e00ae088f 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -77,7 +77,7 @@ void syncHotSpot(Common::Serializer &s, HotSpot &hotspot) {
s.syncAsSint16LE(hotspot.w);
s.syncAsSint16LE(hotspot.h);
s.syncAsByte(hotspot.actionFlags);
- s.syncAsByte(hotspot.extra);
+ s.syncAsSint16LE(hotspot.extra);
s.syncAsByte((byte &)hotspot.isEnabled);
s.syncAsByte((byte &)hotspot.isSprite);
s.syncAsByte(hotspot.zOrder);
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 5f519e9e4d8..6eee91a28e4 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -49,26 +49,26 @@ SoundManager::~SoundManager() {
stopMusic();
}
-void SoundManager::playSound(byte index, int volume, int channel) {
+void SoundManager::playSound(byte index, int channel) {
// debug("Playing sound index %d (%s)", index, SOUND_FILENAMES[index]);
auto it = _soundMap.find(SOUND_FILENAMES[index]);
if (it != _soundMap.end()) {
- playSound(it->_value, volume);
+ playSound(it->_value);
} else {
debug("Sound file %s not found in sound map", SOUND_FILENAMES[index]);
}
}
-void SoundManager::playSound(const char *filename, int volume, int channel) {
+void SoundManager::playSound(const char *filename, int channel) {
auto it = _soundMap.find(filename);
if (it != _soundMap.end()) {
- playSound(it->_value, volume);
+ playSound(it->_value);
} else {
debug("Sound file %s not found in sound map", filename);
}
}
-void SoundManager::playSound(SonidoFile sound, int volume, int channel) {
+void SoundManager::playSound(SonidoFile sound, int channel) {
Common::File sonidosFile;
if (!sonidosFile.open(Common::Path("SONIDOS.DAT"))) {
debug("Failed to open SONIDOS.DAT");
@@ -117,15 +117,15 @@ void SoundManager::playSound(SonidoFile sound, int volume, int channel) {
_mixer->stopHandle(_sfxHandles[channel]);
}
}
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, 255U, 0, DisposeAfterUse::YES);
}
}
-void SoundManager::playSound(byte *soundData, uint32 size, int volume) {
+void SoundManager::playSound(byte *soundData, uint32 size) {
Audio::AudioStream *stream = Audio::makeRawStream(soundData, size, 11025, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
if (stream) {
int channel = findFreeChannel();
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, volume, 0, DisposeAfterUse::YES);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, 255U, 0, DisposeAfterUse::YES);
}
}
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index de38a2fb4c1..bd3f27ed6db 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -157,9 +157,9 @@ class SoundManager {
public:
SoundManager(Audio::Mixer *mixer);
~SoundManager();
- void playSound(byte index, int volume = 128, int channel = -1);
- void playSound(const char *filename, int volume, int channel);
- void playSound(byte *soundData, uint32 size, int volume = 128);
+ void playSound(byte index, int channel = -1);
+ void playSound(const char *filename, int channel);
+ void playSound(byte *soundData, uint32 size);
void stopAllSounds();
void stopSound(int channel);
void stopMusic();
@@ -182,7 +182,7 @@ public:
int tickAmbientSound(uint32 frameCount);
private:
- void playSound(SonidoFile sound, int volume = 255, int channel = -1);
+ void playSound(SonidoFile sound, int channel = -1);
SoundFormat detectFormat(byte *data, uint32 size);
int getSampleRate(byte *data, SoundFormat format);
int findFreeChannel();
@@ -196,6 +196,7 @@ private:
Audio::SoundHandle _musicHandle;
Audio::SoundHandle _sfxHandles[kMaxChannels];
Common::HashMap<Common::String, SonidoFile> _soundMap;
+
};
} // End of namespace Pelrock
Commit: 426763e30a769c89965ea8b527cfbf9943023da5
https://github.com/scummvm/scummvm/commit/426763e30a769c89965ea8b527cfbf9943023da5
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:02+02:00
Commit Message:
PELROCK: Implements Room 33
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.cpp
engines/pelrock/console.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 1979779bc92..67c40827c01 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -141,6 +141,11 @@ const ActionEntry actionTable[] = {
{462, OPEN, &PelrockEngine::openJailFloorTile},
// Room 32
{473, OPEN, &PelrockEngine::openTunnelDrawer},
+ // Room 33
+ {651, OPEN, &PelrockEngine::openSafe},
+ {465, OPEN, &PelrockEngine::openTunnelDoor},
+ {465, CLOSE, &PelrockEngine::closeTunnelDoor},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -167,6 +172,7 @@ const CombinationEntry combinationTable[] = {
{8, 358, &PelrockEngine::giveSecretCodeToLibrarian},
{4, 358, &PelrockEngine::useBrickWithLibrarian}, // Any hotspot in the lamppost will work
{76, 469, &PelrockEngine::usePumpkinWithRiver},
+ {100, 650, &PelrockEngine::useKeyWithPortrait},
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -497,6 +503,7 @@ void PelrockEngine::toJail() {
_alfredState.x = 342;
_alfredState.y = 277;
setScreen(31, ALFRED_DOWN);
+ _room->moveHotspot(_room->findHotspotByExtra(101), 444, 166);
}
void PelrockEngine::noOpAction(HotSpot *hotspot) {
@@ -1143,6 +1150,29 @@ void PelrockEngine::openTunnelDrawer(HotSpot *hotspot) {
_room->disableHotspot(hotspot);
}
+void PelrockEngine::useKeyWithPortrait(int inventoryObject, HotSpot *hotspot) {
+ _room->disableHotspot(hotspot);
+ _room->addSticker(101);
+}
+
+void PelrockEngine::openSafe(HotSpot *hotspot) {
+ if(_state->getFlag(FLAG_CLAVE_CAJA_FUERTE) == true) {
+ _room->addSticker(102);
+ _dialog->say(_res->_ingameTexts[GRANCANTIDAD_DINERO]);
+ addInventoryItem(82);
+ } else {
+ _dialog->say(_res->_ingameTexts[SISUPIERA_COMBINACION]);
+ }
+}
+
+void PelrockEngine::openTunnelDoor(HotSpot *hotspot) {
+ openDoor(hotspot, 0, 66, MASCULINE, true);
+}
+
+void PelrockEngine::closeTunnelDoor(HotSpot *hotspot) {
+ closeDoor(hotspot, 0, 66, MASCULINE, true);
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
@@ -1289,6 +1319,13 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
waitForSpecialAnimation();
_dialog->say(_res->_ingameTexts[CUENTOPARECIDO]);
break;
+ case 101: // combination
+ _res->loadAlfredSpecialAnim(1);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _dialog->say(_res->_ingameTexts[PARECE_COMBINACION_CAJAFUERTE]);
+ _state->setFlag(FLAG_CLAVE_CAJA_FUERTE, true);
+ break;
default:
break;
}
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index d7cdabcb528..404512862a5 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -29,15 +29,16 @@ namespace Pelrock {
PelrockConsole::PelrockConsole(PelrockEngine *engine) : GUI::Debugger(), _engine(engine) {
registerCmd("room", WRAP_METHOD(PelrockConsole, cmdLoadRoom));
registerCmd("give", WRAP_METHOD(PelrockConsole, cmdGiveItems));
- registerCmd("setRoot", WRAP_METHOD(PelrockConsole, setRoot));
- registerCmd("setFlag", WRAP_METHOD(PelrockConsole, setFlag));
+ registerCmd("setRoot", WRAP_METHOD(PelrockConsole, cmdSetRoot));
+ registerCmd("setFlag", WRAP_METHOD(PelrockConsole, cmdSetFlag));
+ registerCmd("toJail", WRAP_METHOD(PelrockConsole, cmdToJail));
}
PelrockConsole::~PelrockConsole() {
}
-bool PelrockConsole::setFlag(int argc, const char **argv) {
+bool PelrockConsole::cmdSetFlag(int argc, const char **argv) {
if (argc < 3) {
debugPrintf("Usage: setFlag <flagIndex> <value>");
return true;
@@ -49,7 +50,7 @@ bool PelrockConsole::setFlag(int argc, const char **argv) {
return true;
}
-bool PelrockConsole::setRoot(int argc, const char **argv) {
+bool PelrockConsole::cmdSetRoot(int argc, const char **argv) {
if (argc < 3) {
debugPrintf("Usage: setRoot <roomNumber> <rootIndex>");
return true;
@@ -90,4 +91,9 @@ bool PelrockConsole::cmdGiveItems(int argc, const char **argv) {
return true;
}
+bool PelrockConsole::cmdToJail(int argc, const char **argv) {
+ g_engine->toJail();
+ return true;
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/console.h b/engines/pelrock/console.h
index aafaa3afc39..ff86ea92f52 100644
--- a/engines/pelrock/console.h
+++ b/engines/pelrock/console.h
@@ -33,9 +33,10 @@ private:
PelrockEngine *_engine;
bool cmdLoadRoom(int argc, const char **argv);
bool cmdGiveItems(int argc, const char **argv);
+ bool cmdToJail(int argc, const char **argv);
bool cmdTest(int argc, const char **argv);
- bool setRoot(int argc, const char **argv);
- bool setFlag(int argc, const char **argv);
+ bool cmdSetRoot(int argc, const char **argv);
+ bool cmdSetFlag(int argc, const char **argv);
public:
PelrockConsole(PelrockEngine *engine);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index d72895aae7b..f9afd57cf65 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -880,6 +880,11 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
Exit *exit = isExitUnder(_alfredState.x, _alfredState.y);
if (exit != nullptr) {
debug("Using exit to room %d", exit->targetRoom);
+ if(exit->targetRoom == 31 && _room->_currentRoomNumber == 32) {
+ _res->loadAlfredSpecialAnim(8);
+ _alfredState.setState(ALFRED_SPECIAL_ANIM);
+ waitForSpecialAnimation();
+ }
_alfredState.x = exit->targetX;
_alfredState.y = exit->targetY;
setScreen(exit->targetRoom, exit->dir);
@@ -1723,7 +1728,6 @@ void PelrockEngine::checkMouseHover() {
}
void PelrockEngine::setScreen(int roomNumber, AlfredDirection dir) {
-
Common::File roomFile;
if (!roomFile.open(Common::Path("ALFRED.1"))) {
error("Could not open ALFRED.1");
@@ -1829,6 +1833,20 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_alfredState.y = y;
break;
}
+ case 32: {
+ if(_room->_prevRoomNumber == 31) {
+ int x = _alfredState.x;
+ int y = _alfredState.y;
+ // _alfredState.x += 57;
+ // _alfredState.y -= 2;
+ _res->loadAlfredSpecialAnim(7);
+ _alfredState.setState(ALFRED_SPECIAL_ANIM);
+ waitForSpecialAnimation();
+ _alfredState.x = x;
+ _alfredState.y = y;
+
+ }
+ }
default:
break;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 3338db34518..cd14e5a0239 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -338,6 +338,10 @@ public:
void pickUpHairStrand(HotSpot *hotspot);
void openJailFloorTile(HotSpot *hotspot);
void openTunnelDrawer(HotSpot *hotspot);
+ void useKeyWithPortrait(int inventoryObject, HotSpot *hotspot);
+ void openSafe(HotSpot *hotspot);
+ void openTunnelDoor(HotSpot *hotspot);
+ void closeTunnelDoor(HotSpot *hotspot);
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index b46915b8def..44057dadb16 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -36,13 +36,15 @@ ResourceManager::ResourceManager(/* args */) {
}
const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
- {10, 51, 102, 1, 7, 559685, 1,}, // READ BOOK
- {10, 51, 102, 1, 7, 578943, 1}, // READ RECIPE
- {3, 45, 87, 0, 7, 37000, 1}, // ELECTRIC SHOCK 1
- {2, 82, 58, 0, 7, 53106, 20}, // ELECTRIC SHOCK 3
- {3, 71, 110, 1, 2, 20724, 1, 62480}, // Throw
- {14, 171, 107, 1, 7, 1556540, 1} , //crocodile
- {12, 113, 103, 1, 7, 1583702, 1} // exit through manhole
+ {10, 51, 102, 1, 7, 559685, 1,}, // 0 - READ BOOK
+ {10, 51, 102, 1, 7, 578943, 1}, // 1 - READ RECIPE
+ {3, 45, 87, 0, 7, 37000, 1}, // 2 - ELECTRIC SHOCK 1
+ {2, 82, 58, 0, 7, 53106, 20}, // 3 - ELECTRIC SHOCK 3
+ {3, 71, 110, 1, 2, 20724, 1, 62480}, // 4 - Throw
+ {14, 171, 107, 1, 7, 1556540, 1} , // 5 - crocodile
+ {12, 113, 103, 1, 7, 1583702, 1}, // 6 - exit through manhole
+ {11, 33, 72, 1, 7, 1761234, 1}, // 7 - alfred climbs down
+ {9, 33, 72, 1, 7, 1766378, 1} // 8 - alfred climbs up
};
ResourceManager::~ResourceManager() {
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 0f6fb18e071..adb389bc798 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -527,6 +527,7 @@ void RoomManager::resetConversationStates(byte roomNumber, byte *conversationDat
void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
_roomStickers.clear();
+ _prevRoomNumber = _currentRoomNumber;
_currentRoomNumber = roomNumber;
int roomOffset = roomNumber * kRoomStructSize;
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index a8107699e84..03b666c9320 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -140,6 +140,7 @@ public:
}
byte _currentRoomNumber = 0;
+ int _prevRoomNumber = -1;
Common::Array<HotSpot> _currentRoomHotspots;
Common::Array<Sprite> _currentRoomAnims;
Common::Array<Exit> _currentRoomExits;
Commit: 92cb18e7b708d5b27854c37850607cf9a929e0ac
https://github.com/scummvm/scummvm/commit/92cb18e7b708d5b27854c37850607cf9a929e0ac
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:03+02:00
Commit Message:
PELROCK: Fixes animation always playing when entering room 38
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 2110525df6e..f8f08ce9a14 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -99,6 +99,9 @@ void MenuManager::checkMouseClick(int x, int y) {
case LOAD_GAME_BUTTON:
g_engine->loadGameDialog();
break;
+ case EXIT_MENU_BUTTON:
+ g_engine->quitGame();
+ break;
default:
break;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f9afd57cf65..f7faae56339 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1822,16 +1822,18 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_dialog->say(_res->_ingameTexts[PINTA_BUENAPERSONA]);
}
case 38: {
- int x = _alfredState.x;
- int y = _alfredState.y;
- _alfredState.x -= 57;
- _alfredState.y += 2;
- _res->loadAlfredSpecialAnim(6);
- _alfredState.setState(ALFRED_SPECIAL_ANIM);
- waitForSpecialAnimation();
- _alfredState.x = x;
- _alfredState.y = y;
- break;
+ if(_room->_prevRoomNumber == 30) {
+ int x = _alfredState.x;
+ int y = _alfredState.y;
+ _alfredState.x -= 57;
+ _alfredState.y += 2;
+ _res->loadAlfredSpecialAnim(6);
+ _alfredState.setState(ALFRED_SPECIAL_ANIM);
+ waitForSpecialAnimation();
+ _alfredState.x = x;
+ _alfredState.y = y;
+ break;
+ }
}
case 32: {
if(_room->_prevRoomNumber == 31) {
Commit: 9519dd6c93b59d33190f68a2e55eed76f2dc3261
https://github.com/scummvm/scummvm/commit/9519dd6c93b59d33190f68a2e55eed76f2dc3261
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:03+02:00
Commit Message:
PELROCK: Tunnel exit animation
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f7faae56339..1fb97ecda7d 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1800,6 +1800,7 @@ void PelrockEngine::waitForSpecialAnimation() {
while (!g_engine->shouldQuit() && !_res->_isSpecialAnimFinished) {
_events->pollEvent();
renderScene(OVERLAY_NONE);
+ _events->waitForKey();
_screen->update();
g_system->delayMillis(10);
}
@@ -1839,8 +1840,6 @@ void PelrockEngine::doExtraActions(int roomNumber) {
if(_room->_prevRoomNumber == 31) {
int x = _alfredState.x;
int y = _alfredState.y;
- // _alfredState.x += 57;
- // _alfredState.y -= 2;
_res->loadAlfredSpecialAnim(7);
_alfredState.setState(ALFRED_SPECIAL_ANIM);
waitForSpecialAnimation();
@@ -1849,6 +1848,19 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
}
+ case 27: {
+ if(_room->_prevRoomNumber == 33) {
+ int x = _alfredState.x;
+ int y = _alfredState.y;
+ _alfredState.x = 12;
+ _alfredState.y += 10;
+ _res->loadAlfredSpecialAnim(9);
+ _alfredState.setState(ALFRED_SPECIAL_ANIM);
+ waitForSpecialAnimation();
+ _alfredState.x = x;
+ _alfredState.y = y;
+ }
+ }
default:
break;
}
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 44057dadb16..a68eb19ac5f 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -44,7 +44,9 @@ const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
{14, 171, 107, 1, 7, 1556540, 1} , // 5 - crocodile
{12, 113, 103, 1, 7, 1583702, 1}, // 6 - exit through manhole
{11, 33, 72, 1, 7, 1761234, 1}, // 7 - alfred climbs down
- {9, 33, 72, 1, 7, 1766378, 1} // 8 - alfred climbs up
+ {9, 33, 72, 1, 7, 1766378, 1}, // 8 - alfred climbs up
+ {16, 158, 115, 0, 7, 1770196, 1}, // 9 - alfred exits tunnel
+ {7, 208, 102, 0, 7, 1600956, 1} // 10 - alfred with workers
};
ResourceManager::~ResourceManager() {
Commit: d89bbc6eb957bacbe9370191b302a189468899b5
https://github.com/scummvm/scummvm/commit/d89bbc6eb957bacbe9370191b302a189468899b5
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:03+02:00
Commit Message:
PELROCK: Fixes conversations in room 27
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1fb97ecda7d..b5c068cbdc1 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -157,7 +157,7 @@ void PelrockEngine::init() {
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
- setScreen(30, ALFRED_DOWN);
+ setScreen(27, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -802,7 +802,7 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
}
changeCursor(DEFAULT);
debug("Talking to hotspot %d (%d) with extra %d", hotspot->index, hotspot->isSprite ? hotspot->index : hotspot->index - _room->_currentRoomAnims.size(), hotspot->extra);
- _dialog->startConversation(_room->_conversationData, _room->_conversationDataSize, hotspot->index, animSet);
+ _dialog->startConversation(_room->_conversationData, _room->_conversationDataSize, animSet->talkingAnimIndex, animSet);
}
void PelrockEngine::lookAt(HotSpot *hotspot) {
@@ -1426,7 +1426,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
// Change with the right index
- int index = animSet->index;
+ int index = animSet->talkingAnimIndex;
TalkingAnims *animHeader = &_room->_talkingAnimHeader;
int x = animSet->x + (index ? animHeader->offsetXAnimB : animHeader->offsetXAnimA);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index adb389bc798..c1744b15e5e 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -883,7 +883,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
uint32_t picOffset = 0;
Common::Array<SpriteChange> spriteChanges = g_engine->_state->spriteChanges[_currentRoomNumber];
-
+ int talkingAnims = 0;
for (int i = 0; i < spriteCount; i++) {
uint32_t animOffset = metadata_start + (i * 44);
Sprite sprite;
@@ -898,6 +898,9 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
sprite.extra = READ_LE_INT16(data + animOffset + 32);
debug("Sprite %d: x=%d y=%d w=%d h=%d stride=%d numAnims=%d zOrder=%d extra=%d", i, sprite.x, sprite.y, sprite.w, sprite.h, sprite.stride, sprite.numAnims, sprite.zOrder, sprite.extra);
sprite.actionFlags = data[animOffset + 34];
+ if(sprite.actionFlags & ACTION_MASK_TALK) {
+ sprite.talkingAnimIndex = talkingAnims++;
+ }
sprite.isHotspotDisabled = data[animOffset + 38];
sprite.disableAfterSequence = data[animOffset + 39];
for (int j = 0; j < spriteChanges.size(); j++) {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 1bcd8a17d54..b0602bd8a77 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -237,6 +237,7 @@ struct Sprite {
bool isHotspotDisabled; // 38
bool disableAfterSequence = false; // 39
bool isTalking = false;
+ byte talkingAnimIndex = 0;
Anim *animData;
int16 extra;
};
@@ -469,6 +470,7 @@ struct ResetEntry {
#define FLAG_PARADOJA_RESUELTA 13
#define FLAG_MIRA_SIMBOLO_FUERA_MUSEO 15
#define FLAG_CROCODILLO_ENCENDIDO 14
+#define FLAG_CLAVE_CAJA_FUERTE 19
@@ -476,7 +478,6 @@ struct ResetEntry {
#define FLAG_PUERTA_SECRETA_ABIERTA 16
#define FLAG_ROBA_PELO_PRINCESA 17
#define FLAG_A_LA_CARCEL 18
-#define FLAG_CLAVE_CAJA_FUERTE 19
#define FLAG_SE_HA_PUESTO_EL_MUNECO 20
#define FLAG_VIGILANTE_BEBE_AGUA 21
#define FLAG_VIGILANTE_MEANDO 22
Commit: d8f0c53e7f52d968775cb5ddacf4c79739d46fb9
https://github.com/scummvm/scummvm/commit/d8f0c53e7f52d968775cb5ddacf4c79739d46fb9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:04+02:00
Commit Message:
PELROCK: Activate room 27's new conversations when opening Safe
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
engines/pelrock/saveload.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 67c40827c01..53195a35ee1 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -484,6 +484,22 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_room->disableHotspot(_room->findHotspotByExtra(451)); // Disable talk hotspot for the riddle
_state->setCurrentRoot(room, rootIndex + 1);
break;
+ //merchants
+ case 370:
+ break;
+ case 371:
+ break;
+ case 286:
+ break;
+ case 287:
+ break;
+ case 288:
+ break;
+ case 289:
+ break;
+ case 290:
+ break;
+ // end merchants
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
@@ -1160,6 +1176,8 @@ void PelrockEngine::openSafe(HotSpot *hotspot) {
_room->addSticker(102);
_dialog->say(_res->_ingameTexts[GRANCANTIDAD_DINERO]);
addInventoryItem(82);
+ _state->setCurrentRoot(27, 1, 0);
+ _state->setCurrentRoot(27, 1, 1);
} else {
_dialog->say(_res->_ingameTexts[SISUPIERA_COMBINACION]);
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 82055ccf378..21332852b11 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -582,9 +582,9 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
debug("Conversation ended");
}
-uint32 DialogManager::findRoot(int ¤tRoot, uint32 currentPosition, uint32 dataSize, const byte *conversationData) {
+uint32 DialogManager::findRoot(int npc, int ¤tRoot, uint32 currentPosition, uint32 dataSize, const byte *conversationData) {
// Check if a specific root has been set for this room
- int targetRoot = g_engine->_state->getCurrentRoot(g_engine->_room->_currentRoomNumber);
+ int targetRoot = g_engine->_state->getCurrentRoot(g_engine->_room->_currentRoomNumber, npc);
if (targetRoot >= 0) {
// Skip to the specified root
@@ -645,7 +645,7 @@ ConversationState DialogManager::initializeConversation(const byte *data, uint32
ConversationState state;
state.position = findSpeaker(npcIndex, dataSize, data);
state.currentRoot = 0;
- state.position = findRoot(state.currentRoot, state.position, dataSize, data);
+ state.position = findRoot(npcIndex, state.currentRoot, state.position, dataSize, data);
state.currentChoiceLevel = -1;
state.lastSelectedChoice = ChoiceOption();
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 44361644696..67c124576e6 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -101,7 +101,7 @@ public:
void displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer);
int selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer);
void startConversation(const byte *conversationData, uint32 dataSize, byte npcIndex, Sprite *alfredAnimSet = nullptr);
- uint32 findRoot(int ¤tRoot, uint32 position, uint32 dataSize, const byte *conversationData);
+ uint32 findRoot(int npc, int ¤tRoot, uint32 position, uint32 dataSize, const byte *conversationData);
uint32 findSpeaker(byte npcIndex, uint32 dataSize, const byte *conversationData);
void sayAlfred(Description description);
void sayAlfred(Common::StringArray texts);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b5c068cbdc1..14edf33a3bf 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1800,7 +1800,7 @@ void PelrockEngine::waitForSpecialAnimation() {
while (!g_engine->shouldQuit() && !_res->_isSpecialAnimFinished) {
_events->pollEvent();
renderScene(OVERLAY_NONE);
- _events->waitForKey();
+ // _events->waitForKey();
_screen->update();
g_system->delayMillis(10);
}
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index 06e00ae088f..c110acaf2b7 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -336,7 +336,7 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
}
// Conversation current root indices
- s.syncBytes(gameState->conversationCurrentRoot, 56);
+ s.syncBytes(gameState->conversationCurrentRoot, 112);
return !s.err();
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index b0602bd8a77..283b1b14fa3 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -589,21 +589,21 @@ struct GameStateData {
}
// Store current root index for each room (0xFF = not set, use findRoot logic)
- byte *conversationCurrentRoot = new byte[56];
+ byte *conversationCurrentRoot = new byte[112];
- int getCurrentRoot(byte room) const {
+ int getCurrentRoot(byte room, int npc = 0) const {
if (room >= 56)
return -1;
- return (conversationCurrentRoot[room] == 0xFF) ? -1 : conversationCurrentRoot[room];
+ return (conversationCurrentRoot[room * 2 + npc] == 0xFF) ? -1 : conversationCurrentRoot[room * 2 + npc];
}
- void setCurrentRoot(byte room, int root) {
+ void setCurrentRoot(byte room, int root, int npc = 0) {
if (room >= 56)
return;
if (root < 0 || root > 254) {
- conversationCurrentRoot[room] = 0xFF; // Reset to auto-select
+ conversationCurrentRoot[room * 2 + npc] = 0xFF; // Reset to auto-select
} else {
- conversationCurrentRoot[room] = (byte)root;
+ conversationCurrentRoot[room * 2 + npc] = (byte)root;
}
}
Commit: a3d3a1778e2bdf7fc47556800bc31bc75cc831f1
https://github.com/scummvm/scummvm/commit/a3d3a1778e2bdf7fc47556800bc31bc75cc831f1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:04+02:00
Commit Message:
PELROCK: Fix conversation advancement on previously done tirggers
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 53195a35ee1..edbdfa091de 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -23,10 +23,10 @@
#include "pelrock.h"
#include "pelrock/actions.h"
+#include "pelrock/extrascreens.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
-#include "pelrock/extrascreens.h"
namespace Pelrock {
@@ -243,14 +243,14 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
switch (actionTrigger) {
case 328:
debug("Setting current root to %d in room %d", rootIndex + 1, room);
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 329:
_state->setFlag(FLAG_PUTA_250_VECES, true);
break;
case 258:
_state->setFlag(FLAG_GUARDIA_PIDECOSAS, true);
- _state->setCurrentRoot(4, 2);
+ _state->setCurrentRoot(4, 2, 0);
break;
case 259:
_dialog->say(_res->_ingameTexts[NO_EMPECEMOS]);
@@ -270,13 +270,13 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
case 264:
// skip to root after the next one
- _state->setCurrentRoot(room, rootIndex + 2);
+ _state->setCurrentRoot(room, rootIndex + 2, 0);
break;
case 267:
- _state->setCurrentRoot(7, 2);
+ _state->setCurrentRoot(7, 2, 0);
break;
case 272:
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 273:
WalkBox w1;
@@ -297,14 +297,14 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 274:
case 275:
case 276:
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 277:
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
_state->setFlag(FLAG_JEFE_INGRESA_PASTA, true);
break;
case 278:
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 279:
travelToEgypt();
@@ -332,8 +332,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
case 334:
addInventoryItem(86);
- _state->setCurrentRoot(room, rootIndex + 1);
-
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 335:
// many oranges
@@ -352,7 +351,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 344:
case 345:
case 346:
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 348: {
// Anti-piracy punishment: corrupt screen + noise + crash
@@ -362,13 +361,13 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 349:
_state->setFlag(FLAG_CONSIGNAS_VENDEDOR, _state->getFlag(FLAG_CONSIGNAS_VENDEDOR) + 1);
if (_state->getFlag(FLAG_CONSIGNAS_VENDEDOR) == 2) {
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 1);
}
break;
case 350:
_state->setFlag(FLAG_CONSIGNAS_VENDEDOR, _state->getFlag(FLAG_CONSIGNAS_VENDEDOR) + 1);
if (_state->getFlag(FLAG_CONSIGNAS_VENDEDOR) == 2) {
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 1);
}
break;
case 351:
@@ -393,7 +392,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
// end moros
case 353:
- _state->setCurrentRoot(room, rootIndex + 2);
+ _state->setCurrentRoot(room, rootIndex + 2, 0);
break;
case 354:
if (_state->hasInventoryItem(105)) {
@@ -406,18 +405,18 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
toJail();
break;
case 356:
- _state->setCurrentRoot(room, 3);
+ _state->setCurrentRoot(room, 3, 0);
break;
// end puta
// sabio
case 366:
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 363:
toJail();
break;
case 367: // accept riddle
- _state->setCurrentRoot(room, 27);
+ _state->setCurrentRoot(room, 27, 0);
walkAndAction(_room->findHotspotByExtra(467), TALK);
break;
// hasta aqui
@@ -451,12 +450,12 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 360: // neutral reset: counter = 0
{
_state->setFlag(FLAG_RESPUESTAS_ACERTADAS, 0);
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
advanceQuotesConversation(rootIndex, room);
break;
}
case 361: // "no sé" (I don't know): no counter change, just advance
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 362: // special trigger: enables HIJODELAGRANPUTA cheat code
// Sets cheat_code_checking_enabled flag in original (0x495F3)
@@ -470,34 +469,51 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
if (rootIndex == 43) {
targetIndex = 27; // skip riddle explanation
}
- _state->setCurrentRoot(room, targetIndex);
+ _state->setCurrentRoot(room, targetIndex, 0);
break;
}
case 365: // riddle correct: set riddle-solved flag
_state->setFlag(FLAG_PARADOJA_RESUELTA, 1);
- _state->setCurrentRoot(room, 1);
+ _state->setCurrentRoot(room, 1, 0);
break;
case 292:
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 293:
_room->disableHotspot(_room->findHotspotByExtra(451)); // Disable talk hotspot for the riddle
- _state->setCurrentRoot(room, rootIndex + 1);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
- //merchants
+ // merchants
case 370:
+ addInventoryItem(111);
break;
case 371:
+ addInventoryItem(111);
+ addInventoryItem(110);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 286:
+ addInventoryItem(83);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 287:
+ addInventoryItem(77);
+ addInventoryItem(107);
+ givenItems();
break;
case 288:
+ addInventoryItem(78);
+ givenItems();
break;
case 289:
+ addInventoryItem(79);
+ addInventoryItem(108);
+ givenItems();
break;
case 290:
+ addInventoryItem(80);
+ addInventoryItem(109);
+ givenItems();
break;
// end merchants
default:
@@ -506,12 +522,19 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
}
}
+void PelrockEngine::givenItems() {
+ _state->setFlag(FLAG_MERCHANT_GIVENITEMS, _state->getFlag(FLAG_MERCHANT_GIVENITEMS) + 1);
+ if(_state->getFlag(FLAG_MERCHANT_GIVENITEMS) == 4) {
+ _state->setCurrentRoot(27, 2, 1);
+ }
+}
+
void PelrockEngine::advanceQuotesConversation(byte rootIndex, byte room) {
int targetRoot = rootIndex + 1;
if (targetRoot == 26) {
targetRoot = 2;
}
- _state->setCurrentRoot(room, targetRoot);
+ _state->setCurrentRoot(room, targetRoot, 0);
}
void PelrockEngine::toJail() {
@@ -585,7 +608,7 @@ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
if (_state->getFlag(FLAG_JEFE_INGRESA_PASTA)) {
_state->setFlag(FLAG_JEFE_INGRESA_PASTA, false);
addInventoryItem(75);
- _state->setCurrentRoot(20, 2);
+ _state->setCurrentRoot(20, 2, 0);
} else {
int billCount = 0;
for (uint i = 0; i < _state->inventoryItems.size(); i++) {
@@ -830,7 +853,7 @@ void PelrockEngine::pickCables(HotSpot *hotspot) {
_room->addSticker(21);
_dialog->say(_res->_ingameTexts[RELOJ_HA_CAMBIADO]);
- _state->setCurrentRoot(4, 1);
+ _state->setCurrentRoot(4, 1, 0);
}
void PelrockEngine::giveIdToGuard(int inventoryObject, HotSpot *hotspot) {
@@ -850,7 +873,7 @@ void PelrockEngine::giveIdToGuard(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::unlockMuseum() {
- _state->setCurrentRoot(4, 3);
+ _state->setCurrentRoot(4, 3, 0);
_room->enableSprite(2, 100, PERSIST_PERM);
_room->enableSprite(3, 100, PERSIST_PERM);
_room->addStickerToRoom(4, 87, PERSIST_PERM);
@@ -892,7 +915,7 @@ void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
if (!_room->hasSticker(24)) {
_room->addSticker(24);
_state->removeInventoryItem(7);
- _state->setCurrentRoot(7, 1);
+ _state->setCurrentRoot(7, 1, 0);
_alfredState.direction = ALFRED_RIGHT;
HotSpot *statueHotspot = _room->findHotspotByExtra(91);
@@ -1008,13 +1031,13 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
if (_state->getFlag(FLAG_PARADOJA_RESUELTA) == false) {
_dialog->say(_res->_ingameTexts[OIGA]);
- _state->setCurrentRoot(25, 26);
+ _state->setCurrentRoot(25, 26, 0);
_state->setFlag(FLAG_RIDDLE_PRESENTED, true);
walkAndAction(_room->findHotspotByExtra(467), TALK);
} else {
addInventoryItem(85);
_room->disableHotspot(hotspot);
- _state->setCurrentRoot(25, 1);
+ _state->setCurrentRoot(25, 1, 0);
_room->addSticker(73);
}
checkIngredients();
@@ -1030,10 +1053,10 @@ void PelrockEngine::checkIngredients() {
void PelrockEngine::pickUpBook(int i) {
if (!_state->hasInventoryItem(10)) {
_dialog->say(_res->_ingameTexts[VENGA_ACA]);
- _state->setCurrentRoot(9, 1);
+ _state->setCurrentRoot(9, 1, 0);
if (_state->hasInventoryItem(3)) {
- _state->setCurrentRoot(9, 2);
+ _state->setCurrentRoot(9, 2, 0);
addInventoryItem(10);
}
@@ -1044,9 +1067,9 @@ void PelrockEngine::pickUpBook(int i) {
waitForActionEnd();
if (!_state->hasInventoryItem(3)) {
- _state->setCurrentRoot(9, 0);
+ _state->setCurrentRoot(9, 0, 0);
} else {
- _state->setCurrentRoot(9, 3);
+ _state->setCurrentRoot(9, 3, 0);
}
} else {
if (_state->libraryShelf == -1) {
@@ -1096,7 +1119,7 @@ void PelrockEngine::closeEgyptMuseumDoor(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol1(HotSpot *hotspot) {
- if(_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
debug("Current symbols pulled: %d", symbolsPulled);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x1);
@@ -1106,7 +1129,7 @@ void PelrockEngine::pushSymbol1(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol2(HotSpot *hotspot) {
- if(_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
debug("Current symbols pulled: %d", symbolsPulled);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x2);
@@ -1116,7 +1139,7 @@ void PelrockEngine::pushSymbol2(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol3(HotSpot *hotspot) {
- if(_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
debug("Current symbols pulled: %d", symbolsPulled);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x4);
@@ -1126,7 +1149,7 @@ void PelrockEngine::pushSymbol3(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol4(HotSpot *hotspot) {
- if(_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
debug("Current symbols pulled: %d", symbolsPulled);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x8);
@@ -1138,8 +1161,8 @@ void PelrockEngine::pushSymbol4(HotSpot *hotspot) {
void PelrockEngine::checkAllSymbols() {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
debug("Checking symbols, current value: %d", symbolsPulled);
- if(symbolsPulled == 0x0F) {
- //Activates animation
+ if (symbolsPulled == 0x0F) {
+ // Activates animation
_sound->playSound(_room->_roomSfx[0]);
_room->enableSprite(4, 100, PERSIST_TEMP);
_room->enableExit(0, PERSIST_BOTH);
@@ -1172,7 +1195,7 @@ void PelrockEngine::useKeyWithPortrait(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::openSafe(HotSpot *hotspot) {
- if(_state->getFlag(FLAG_CLAVE_CAJA_FUERTE) == true) {
+ if (_state->getFlag(FLAG_CLAVE_CAJA_FUERTE) == true) {
_room->addSticker(102);
_dialog->say(_res->_ingameTexts[GRANCANTIDAD_DINERO]);
addInventoryItem(82);
@@ -1246,8 +1269,8 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
waitForSpecialAnimation();
loadExtraScreenAndPresent(3);
- _state->setCurrentRoot(17, 1);
- _state->setCurrentRoot(18, 4);
+ _state->setCurrentRoot(17, 1, 0);
+ _state->setCurrentRoot(18, 4, 0);
debug("After extra screen");
_dialog->say(_res->_ingameTexts[QUEASCO]);
break;
@@ -1275,14 +1298,14 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
case 24:
if (_state->getFlag(FLAG_RIDDLE_PRESENTED) == true) {
_dialog->say(_res->_ingameTexts[CAPITULOPARADOJAS]);
- _state->setCurrentRoot(25, 44);
+ _state->setCurrentRoot(25, 44, 0);
} else {
_res->loadAlfredSpecialAnim(0);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
waitForSpecialAnimation();
_dialog->say(_res->_ingameTexts[COSASAPRENDIDO]);
_state->setFlag(FLAG_ALFRED_INTELIGENTE, true);
- _state->setCurrentRoot(14, 2);
+ _state->setCurrentRoot(14, 2, 0);
}
break;
case 64:
@@ -1307,15 +1330,14 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
if (spell) {
_alfredState.direction = ALFRED_LEFT;
_dialog->say(_res->_ingameTexts[DIOSHALCON + spell->page], 1);
- if(spell->page == 12 && _room->_currentRoomNumber == 28) {
+ if (spell->page == 12 && _room->_currentRoomNumber == 28) {
_graphics->clearScreen();
int waitFrames = 0;
- //blank screen for half a second
- while (!shouldQuit() && waitFrames < 20)
- {
+ // blank screen for half a second
+ while (!shouldQuit() && waitFrames < 20) {
_events->pollEvent();
_chrono->updateChrono();
- if(_chrono->_gameTick) {
+ if (_chrono->_gameTick) {
waitFrames++;
}
_screen->markAllDirty();
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index 404512862a5..929d83a7205 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -52,13 +52,14 @@ bool PelrockConsole::cmdSetFlag(int argc, const char **argv) {
bool PelrockConsole::cmdSetRoot(int argc, const char **argv) {
if (argc < 3) {
- debugPrintf("Usage: setRoot <roomNumber> <rootIndex>");
+ debugPrintf("Usage: setRoot <roomNumber> <rootIndex> <npcIndex (optional, default=0)>");
return true;
}
int roomNumber = atoi(argv[1]);
int rootIndex = atoi(argv[2]);
- _engine->_state->setCurrentRoot(roomNumber, rootIndex);
- debugPrintf("Set current root to %d in room %d\n", rootIndex, roomNumber);
+ int npcIndex = (argc >= 4) ? atoi(argv[3]) : 0;
+ _engine->_state->setCurrentRoot(roomNumber, rootIndex, npcIndex);
+ debugPrintf("Set current root to %d in room %d for npc %d\n", rootIndex, roomNumber, npcIndex);
return true;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index cd14e5a0239..4f3f3469c19 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -250,8 +250,8 @@ public:
void performActionTrigger(uint16 actionTrigger);
void dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex);
+ void givenItems();
void advanceQuotesConversation(byte rootIndex, byte room);
-
void toJail();
void executeAction(VerbIcon action, HotSpot *hotspot);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 283b1b14fa3..11598cca564 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -471,6 +471,8 @@ struct ResetEntry {
#define FLAG_MIRA_SIMBOLO_FUERA_MUSEO 15
#define FLAG_CROCODILLO_ENCENDIDO 14
#define FLAG_CLAVE_CAJA_FUERTE 19
+#define FLAG_INGREDIENTES_CONSEGUIDOS 48
+#define FLAG_MERCHANT_GIVENITEMS 58
@@ -506,7 +508,6 @@ struct ResetEntry {
#define FLAG_HA_USADO_AGUA 45
#define FLAG_TIENDA_ABIERTA 46
#define FLAG_NUMERO_DE_COPAS 47
-#define FLAG_INGREDIENTES_CONSEGUIDOS 48
#define FLAG_GUARDIA_PIDECOSAS 49
#define FLAG_GUARDIA_DNI_ENTREGADO 50
@@ -518,7 +519,7 @@ struct ResetEntry {
#define FLAG_RIDDLE_PRESENTED 56
#define FLAG_SYMBOLS_PUSHED 57
-const int kNumGameFlags = 58;
+const int kNumGameFlags = 59;
struct GameStateData {
byte flags[kNumGameFlags];
@@ -591,13 +592,13 @@ struct GameStateData {
// Store current root index for each room (0xFF = not set, use findRoot logic)
byte *conversationCurrentRoot = new byte[112];
- int getCurrentRoot(byte room, int npc = 0) const {
+ int getCurrentRoot(byte room, int npc) const {
if (room >= 56)
return -1;
return (conversationCurrentRoot[room * 2 + npc] == 0xFF) ? -1 : conversationCurrentRoot[room * 2 + npc];
}
- void setCurrentRoot(byte room, int root, int npc = 0) {
+ void setCurrentRoot(byte room, int root, int npc) {
if (room >= 56)
return;
if (root < 0 || root > 254) {
Commit: d7e147ed85391d9cff34161d2949d50e6878290c
https://github.com/scummvm/scummvm/commit/d7e147ed85391d9cff34161d2949d50e6878290c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:04+02:00
Commit Message:
PELROCK: Trigger police after going to jail
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index edbdfa091de..e684d581cda 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -516,6 +516,17 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
givenItems();
break;
// end merchants
+ case 369:
+ case 383:
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
+ break;
+ case 295:
+ addInventoryItem(84);
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
+ break;
+ case 285:
+ toJail();
+ break;
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
@@ -542,6 +553,7 @@ void PelrockEngine::toJail() {
_alfredState.x = 342;
_alfredState.y = 277;
setScreen(31, ALFRED_DOWN);
+ _state->setFlag(FLAG_A_LA_CARCEL, true);
_room->moveHotspot(_room->findHotspotByExtra(101), 444, 166);
}
@@ -1032,15 +1044,15 @@ void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
if (_state->getFlag(FLAG_PARADOJA_RESUELTA) == false) {
_dialog->say(_res->_ingameTexts[OIGA]);
_state->setCurrentRoot(25, 26, 0);
- _state->setFlag(FLAG_RIDDLE_PRESENTED, true);
walkAndAction(_room->findHotspotByExtra(467), TALK);
+ _state->setFlag(FLAG_RIDDLE_PRESENTED, true);
} else {
addInventoryItem(85);
_room->disableHotspot(hotspot);
_state->setCurrentRoot(25, 1, 0);
_room->addSticker(73);
+ checkIngredients();
}
- checkIngredients();
}
void PelrockEngine::checkIngredients() {
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 21332852b11..5636c573c58 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -453,7 +453,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
setCurSprite(animSet ? animSet->index : -1);
- debug("Starting conversation with %d bytes of data, for npc %d, hotspot %d", dataSize, npcIndex, animSet ? animSet->index : -1);
+ debug("Starting conversation with %d bytes of data, for npc %d, hotspot %d, currentRoot is = %d", dataSize, npcIndex, animSet ? animSet->index : -1, g_engine->_state->getCurrentRoot(g_engine->_room->_currentRoomNumber, npcIndex));
// Initialize conversation state
ConversationState state = initializeConversation(conversationData, dataSize, npcIndex);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 14edf33a3bf..16a360c8502 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1860,6 +1860,21 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_alfredState.x = x;
_alfredState.y = y;
}
+ break;
+ }
+ case 26: {
+ if(_state->getFlag(FLAG_A_LA_CARCEL) == true) {
+ if(!_state->getFlag(FLAG_SE_HA_PUESTO_EL_MUNECO)) {
+ _state->setCurrentRoot(26, 2, 1);
+ } else {
+ _dialog->say(_res->_ingameTexts[OIGAUSTED], 1);
+ _dialog->say(_res->_ingameTexts[ESAMI]);
+ _dialog->say(_res->_ingameTexts[VENGAAHORAMISMO], 1);
+ _state->setCurrentRoot(26, 1, 1);
+ walkAndAction(_room->findHotspotByExtra(421), TALK);
+ }
+ }
+ break;
}
default:
break;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 11598cca564..967c70e01bb 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -540,7 +540,7 @@ struct GameStateData {
Common::HashMap<byte, Common::Array<SpriteChange>> spriteChanges;
GameStateData() {
- memset(conversationCurrentRoot, 0xFF, 56); // 0xFF = not set
+ memset(conversationCurrentRoot, 0, 112); // Initialize all to 0xFF (not set)
for (int i = 0; i < kNumGameFlags; i++)
flags[i] = 0;
flags[FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ] = true;
Commit: f2af94bf4c74c3691bb15dbc5c6238743cd9a580
https://github.com/scummvm/scummvm/commit/f2af94bf4c74c3691bb15dbc5c6238743cd9a580
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:05+02:00
Commit Message:
PELROCK: Doll animation in prison cell
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index e684d581cda..6182144ef85 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -173,6 +173,7 @@ const CombinationEntry combinationTable[] = {
{4, 358, &PelrockEngine::useBrickWithLibrarian}, // Any hotspot in the lamppost will work
{76, 469, &PelrockEngine::usePumpkinWithRiver},
{100, 650, &PelrockEngine::useKeyWithPortrait},
+ {83, 461, &PelrockEngine::useDollWithBed},
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -1226,6 +1227,27 @@ void PelrockEngine::closeTunnelDoor(HotSpot *hotspot) {
closeDoor(hotspot, 0, 66, MASCULINE, true);
}
+void PelrockEngine::useDollWithBed(int inventoryObject, HotSpot *hotspot) {
+ int x = _alfredState.x;
+ int y = _alfredState.y;
+ _alfredState.x -= 36;
+ _alfredState.y += 7;
+ _res->loadAlfredSpecialAnim(11);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _alfredState.x -= 4;
+ _alfredState.y += 12;
+ _res->loadAlfredSpecialAnim(12);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _alfredState.direction = ALFRED_DOWN;
+ _state->setFlag(FLAG_SE_HA_PUESTO_EL_MUNECO, true);
+ _state->removeInventoryItem(83);
+ _room->addSticker(126);
+ _alfredState.x = x;
+ _alfredState.y = y;
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 16a360c8502..47bdbe997e3 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -157,7 +157,7 @@ void PelrockEngine::init() {
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
- setScreen(27, ALFRED_DOWN);
+ setScreen(31, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 4f3f3469c19..178591e1cc6 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -342,6 +342,7 @@ public:
void openSafe(HotSpot *hotspot);
void openTunnelDoor(HotSpot *hotspot);
void closeTunnelDoor(HotSpot *hotspot);
+ void useDollWithBed(int inventoryObject, HotSpot *hotspot);
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index a68eb19ac5f..520b104e927 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -46,7 +46,9 @@ const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
{11, 33, 72, 1, 7, 1761234, 1}, // 7 - alfred climbs down
{9, 33, 72, 1, 7, 1766378, 1}, // 8 - alfred climbs up
{16, 158, 115, 0, 7, 1770196, 1}, // 9 - alfred exits tunnel
- {7, 208, 102, 0, 7, 1600956, 1} // 10 - alfred with workers
+ {7, 208, 102, 0, 7, 1600956, 1}, // 10 - alfred with workers
+ {23, 116, 124, 1, 7, 2060916, 1}, // 11 - Munheco 1
+ {18, 177, 124, 1, 7, 2115632, 1}, // 12 - Munheco 2
};
ResourceManager::~ResourceManager() {
Commit: 2d39406a8578a9e0dac67cf852137a04b090b08f
https://github.com/scummvm/scummvm/commit/2d39406a8578a9e0dac67cf852137a04b090b08f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:05+02:00
Commit Message:
PELROCK: Disables interaction during cutscenes
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 6182144ef85..97841372fda 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -762,6 +762,7 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
_room->addStickerToRoom(_room->_currentRoomNumber, 10, PERSIST_PERM);
_room->disableHotspot(_room->findHotspotByExtra(295)); // Disable storefront hotspot
_room->disableHotspot(_room->findHotspotByExtra(294)); // Disable window hotspot
+ _disableAction = true; // Prevent player from doing anything until they move Alfred
walkTo(630, _alfredState.y);
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 47bdbe997e3..3a656bf319d 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -487,6 +487,10 @@ void PelrockEngine::checkMouse() {
checkMouseHover();
+ if(_disableAction) {
+ return;
+ }
+
if (_alfredState.animState == ALFRED_WALKING && !_alfredState.isWalkingCancelable) {
// Ignore clicks while Alfred is walking
_events->_leftMouseClicked = false;
@@ -860,7 +864,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
debug("Finished walking to target");
_alfredState.setState(ALFRED_IDLE);
_alfredState.isWalkingCancelable = true;
-
+ _disableAction = false;
if (_currentHotspot != nullptr)
_alfredState.direction = calculateAlfredsDirection(_currentHotspot);
drawAlfred(_res->alfredIdle[_alfredState.direction]);
@@ -1561,6 +1565,7 @@ void PelrockEngine::walkTo(int x, int y) {
}
void PelrockEngine::walkAndAction(HotSpot *hotspot, VerbIcon action) {
+ _disableAction = true;
walkTo(hotspot->x + hotspot->w / 2, hotspot->y + hotspot->h);
_queuedAction = QueuedAction{action, hotspot->index, true};
}
@@ -1864,7 +1869,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
case 26: {
if(_state->getFlag(FLAG_A_LA_CARCEL) == true) {
- if(!_state->getFlag(FLAG_SE_HA_PUESTO_EL_MUNECO)) {
+ if(_state->getFlag(FLAG_SE_HA_PUESTO_EL_MUNECO) == true) {
_state->setCurrentRoot(26, 2, 1);
} else {
_dialog->say(_res->_ingameTexts[OIGAUSTED], 1);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 178591e1cc6..bf34a6b8ea7 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -178,7 +178,7 @@ public:
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
DoubleSmallFont *_doubleSmallFont = nullptr;
-
+ bool _disableAction = false;
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
Commit: d385e8a5071ff3b16323e06a3e81131e62df241e
https://github.com/scummvm/scummvm/commit/d385e8a5071ff3b16323e06a3e81131e62df241e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:05+02:00
Commit Message:
PELROCK: Implements using glue + patches to build inflated doll
Changed paths:
engines/pelrock/actions.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 97841372fda..278bbf23b8a 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1401,6 +1401,17 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_dialog->say(_res->_ingameTexts[PARECE_COMBINACION_CAJAFUERTE]);
_state->setFlag(FLAG_CLAVE_CAJA_FUERTE, true);
break;
+ case 108:
+ case 109: {
+ if(_state->hasInventoryItem(110) == true) {
+ _state->removeInventoryItem(110);
+ _state->removeInventoryItem(109);
+ _state->removeInventoryItem(108);
+ addInventoryItem(83);
+ _dialog->say(_res->_ingameTexts[MUNECO_ARREGLADO]);
+ }
+ break;
+ }
default:
break;
}
Commit: cdb379e9ad63669b66072421a215a4b195ff34ee
https://github.com/scummvm/scummvm/commit/cdb379e9ad63669b66072421a215a4b195ff34ee
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:06+02:00
Commit Message:
PELROCK: Fixes resetting palette in room 28
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/resources.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 278bbf23b8a..a2b564540dc 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1532,30 +1532,16 @@ void PelrockEngine::waitForActionEnd() {
* fades to it using the step-wise palette transition.
*/
void PelrockEngine::pickUpMatches(HotSpot *hotspot) {
- // Load the special palette from ALFRED.7 at offset 0x1610CE
- static const uint32 kRoom28PaletteOffset = 0x1610CE;
-
- Common::File alfred7;
- if (!alfred7.open(Common::Path("ALFRED.7"))) {
- warning("Could not open ALFRED.7 for room 28 palette");
- return;
- }
byte targetPalette[768];
- alfred7.seek(kRoom28PaletteOffset, SEEK_SET);
- alfred7.read(targetPalette, 768);
- alfred7.close();
-
- // Convert 6-bit VGA palette (0-63) to 8-bit (0-255)
- for (int i = 0; i < 768; i++) {
- targetPalette[i] = targetPalette[i] << 2;
- }
+ _res->getPaletteForRoom28(targetPalette);
// Fade from current palette to the new palette
_graphics->fadePaletteToTarget(targetPalette, 25);
debug("Finished palette fade for room 28 object pickup");
// Pick up the item
_room->disableHotspot(hotspot);
+ Common::copy(targetPalette, targetPalette + 768, _room->_roomPalette);
_state->setFlag(FLAG_CROCODILLO_ENCENDIDO, true);
_room->moveHotspot(_room->findHotspotByExtra(87), 415, 171);
_room->moveHotspot(_room->findHotspotByExtra(88), 305, 217);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 3a656bf319d..b92baaf6b24 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1867,6 +1867,15 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
break;
}
+ case 28: {
+ if(_state->getFlag(FLAG_CROCODILLO_ENCENDIDO) == true) {
+ byte palette[768];
+ _res->getPaletteForRoom28(palette);
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+ Common::copy(palette, palette + 768, _room->_roomPalette);
+ break;
+ }
+ }
case 26: {
if(_state->getFlag(FLAG_A_LA_CARCEL) == true) {
if(_state->getFlag(FLAG_SE_HA_PUESTO_EL_MUNECO) == true) {
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 520b104e927..1a150749150 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -24,6 +24,7 @@
#include "pelrock/pelrock.h"
#include "pelrock/room.h"
#include "pelrock/util.h"
+#include "resources.h"
namespace Pelrock {
@@ -320,6 +321,26 @@ void ResourceManager::loadHardcodedText() {
exe.close();
}
+void ResourceManager::getPaletteForRoom28(byte *palette) {
+ // Load the special palette from ALFRED.7 at offset 0x1610CE
+ static const uint32 kRoom28PaletteOffset = 0x1610CE;
+
+ Common::File alfred7;
+ if (!alfred7.open(Common::Path("ALFRED.7"))) {
+ warning("Could not open ALFRED.7 for room 28 palette");
+ return;
+ }
+
+ alfred7.seek(kRoom28PaletteOffset, SEEK_SET);
+ alfred7.read(palette, 768);
+
+ // Convert 6-bit VGA palette (0-63) to 8-bit (0-255)
+ for (int i = 0; i < 768; i++) {
+ palette[i] = palette[i] << 2;
+ }
+
+ alfred7.close();
+}
void ResourceManager::getExtraScreen(int screenIndex, byte *screenBuf, byte *palette) {
Common::File alfred7;
if (!alfred7.open("ALFRED.7")) {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index a8d99221f92..bcada5183d0 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -49,6 +49,7 @@ public:
void clearSpecialAnim();
void loadInventoryItems();
void loadHardcodedText();
+ void getPaletteForRoom28(byte *palette);
Common::StringArray loadComputerText();
void getExtraScreen(int screenIndex, byte *screenBuf, byte *palette);
Common::Array<Common::StringArray> getCredits();
Commit: 7d7038667e9e0b9da60a2de70f0054ba51f49afc
https://github.com/scummvm/scummvm/commit/7d7038667e9e0b9da60a2de70f0054ba51f49afc
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:06+02:00
Commit Message:
PELROCK: Fixes statue never giving object 8 (note)
Changed paths:
engines/pelrock/actions.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index a2b564540dc..cf878af747e 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -62,7 +62,7 @@ const ActionEntry actionTable[] = {
// Room 3
{290, OPEN, &PelrockEngine::openShopDoor},
{290, CLOSE, &PelrockEngine::closeShopDoor},
- {32, OPEN, &PelrockEngine::openLamppost},
+ {288, OPEN, &PelrockEngine::openLamppost},
{308, PICKUP, &PelrockEngine::moveCable}, // Lamppost cable
// Room 15
@@ -932,13 +932,14 @@ void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
_state->setCurrentRoot(7, 1, 0);
_alfredState.direction = ALFRED_RIGHT;
- HotSpot *statueHotspot = _room->findHotspotByExtra(91);
+ HotSpot *statueHotspot = _room->findHotspotByExtra(347);
_currentHotspot = statueHotspot;
walkTo(statueHotspot->x + statueHotspot->w / 2, statueHotspot->y + statueHotspot->h);
animateStatuePaletteFade(false);
walkAndAction(statueHotspot, TALK);
waitForActionEnd();
animateStatuePaletteFade(true);
+ addInventoryItem(8);
}
}
Commit: 44a183687775dc0d759ae7bd2761ae3346333d12
https://github.com/scummvm/scummvm/commit/44a183687775dc0d759ae7bd2761ae3346333d12
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:06+02:00
Commit Message:
PELROCK: "Running" sprites in rooms 34, 36
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index cf878af747e..fac151a1a7c 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -165,7 +165,7 @@ const CombinationEntry combinationTable[] = {
{4, 294, &PelrockEngine::useBrickWithWindow},
{4, 295, &PelrockEngine::useBrickWithShopWindow},
{6, 315, &PelrockEngine::useCordWithPlug},
- {1, 309, &PelrockEngine::giveIdToGuard},
+ {1, 309, &PelrockEngine::showIdToGuard},
{5, 309, &PelrockEngine::giveMoneyToGuard},
{7, 353, &PelrockEngine::useAmuletWithStatue},
{8, 353, &PelrockEngine::useSecretCodeWithStatue},
@@ -174,6 +174,8 @@ const CombinationEntry combinationTable[] = {
{76, 469, &PelrockEngine::usePumpkinWithRiver},
{100, 650, &PelrockEngine::useKeyWithPortrait},
{83, 461, &PelrockEngine::useDollWithBed},
+ {84, 503, &PelrockEngine::giveMagazineToGuard},
+ {86, 500, &PelrockEngine::giveWaterToGuard},
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -528,6 +530,29 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 285:
toJail();
break;
+ case 374:
+ case 372:
+ case 373:
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
+ break;
+ case 297: {
+ // sprite moves to right
+ _room->enableExit(0);
+ Sprite *sprite = _room->findSpriteByIndex(0);
+ sprite->animData[0].movementFlags = 0x1C; // Move right
+ //Basic loop to wait until the sprite has reached the door
+ while (!shouldQuit()) {
+ _events->pollEvent();
+ renderScene();
+ if (sprite->x >= 206) {
+ break;
+ }
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+ _room->disableSprite(0);
+ } break;
+
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
@@ -536,7 +561,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
void PelrockEngine::givenItems() {
_state->setFlag(FLAG_MERCHANT_GIVENITEMS, _state->getFlag(FLAG_MERCHANT_GIVENITEMS) + 1);
- if(_state->getFlag(FLAG_MERCHANT_GIVENITEMS) == 4) {
+ if (_state->getFlag(FLAG_MERCHANT_GIVENITEMS) == 4) {
_state->setCurrentRoot(27, 2, 1);
}
}
@@ -762,7 +787,7 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
_room->addStickerToRoom(_room->_currentRoomNumber, 10, PERSIST_PERM);
_room->disableHotspot(_room->findHotspotByExtra(295)); // Disable storefront hotspot
_room->disableHotspot(_room->findHotspotByExtra(294)); // Disable window hotspot
- _disableAction = true; // Prevent player from doing anything until they move Alfred
+ _disableAction = true; // Prevent player from doing anything until they move Alfred
walkTo(630, _alfredState.y);
}
@@ -834,10 +859,10 @@ void PelrockEngine::useCordWithPlug(int inventoryObject, HotSpot *hotspot) {
if (!_room->hasSticker(18)) {
_dialog->say(_res->_ingameTexts[PRIMERO_ABRIRLO]);
} else {
- debug("Flag is %d", _state->getFlag(FLAG_CABLES_PUESTOS));
if (_state->getFlag(FLAG_CABLES_PUESTOS)) {
_room->addSticker(19);
_room->moveHotspot(_room->findHotspotByIndex(6), 391, 381);
+ _state->removeInventoryItem(6);
}
}
}
@@ -870,7 +895,7 @@ void PelrockEngine::pickCables(HotSpot *hotspot) {
_state->setCurrentRoot(4, 1, 0);
}
-void PelrockEngine::giveIdToGuard(int inventoryObject, HotSpot *hotspot) {
+void PelrockEngine::showIdToGuard(int inventoryObject, HotSpot *hotspot) {
if (!_state->getFlag(FLAG_GUARDIA_PIDECOSAS)) {
_dialog->say(_res->_ingameTexts[CUANDOMELOPIDA]);
return;
@@ -1019,8 +1044,10 @@ void PelrockEngine::closeTravelAgencyDoor(HotSpot *hotspot) {
}
void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
+ _state->removeInventoryItem(76);
+ addInventoryItem(86);
_sound->playMusicTrack(27);
- _dialog->say(_res->_ingameTexts[PRIMERINGREDIENTE]);
+ checkIngredients();
_dialog->say(_res->_ingameTexts[CUIDADOIMPRUDENTE]);
_res->loadAlfredSpecialAnim(5);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
@@ -1250,6 +1277,54 @@ void PelrockEngine::useDollWithBed(int inventoryObject, HotSpot *hotspot) {
_alfredState.y = y;
}
+void PelrockEngine::giveMagazineToGuard(int inventoryObject, HotSpot *hotspot) {
+ _state->removeInventoryItem(84);
+ _state->setCurrentRoot(34, 4, 0);
+ walkAndAction(hotspot, TALK);
+ waitForActionEnd();
+}
+
+void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
+ _state->setFlag(FLAG_VIGILANTE_BEBE_AGUA, _state->getFlag(FLAG_VIGILANTE_BEBE_AGUA) + 1);
+
+ _dialog->say(_res->_ingameTexts[ALACONUSTED]);
+ _state->removeInventoryItem(86);
+ addInventoryItem(76);
+ if (_state->getFlag(FLAG_VIGILANTE_BEBE_AGUA) == 1) {
+ _dialog->say(_res->_ingameTexts[MEMEO]);
+
+ // guard running
+ Sprite *sprite = _room->findSpriteByIndex(0);
+ sprite->animData[0].nframes = 5;
+ sprite->animData[0].movementFlags = 0x1C; // Move right
+ byte state = 0;
+ //Basic loop to wait until the sprite has reached the door
+ while (!shouldQuit()) {
+ _events->pollEvent();
+ renderScene();
+ if (sprite->x >= 339 && state == 0) {
+ state = 1;
+ sprite->animData[0].movementFlags = 0x240;
+ }
+ if(sprite->y <= 188 && state == 1) {
+ state = 2;
+ sprite->animData[0].movementFlags = 0x14; // Move
+ }
+ if(sprite->x <= 327 && state == 2) {
+ sprite->zOrder = -1; // Hide sprite
+ break;
+ }
+ debug("Guard position: (%d, %d), state: %d", sprite->x, sprite->y, state);
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+ _room->disableSprite(36, 0, PERSIST_BOTH);
+ _room->enableExit(0, PERSIST_BOTH);
+ } else {
+ _state->setCurrentRoot(36, _state->getCurrentRoot(36, 0) + 1, 0);
+ }
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
@@ -1404,7 +1479,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
case 108:
case 109: {
- if(_state->hasInventoryItem(110) == true) {
+ if (_state->hasInventoryItem(110) == true) {
_state->removeInventoryItem(110);
_state->removeInventoryItem(109);
_state->removeInventoryItem(108);
@@ -1413,6 +1488,13 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
}
break;
}
+ case 84: {
+ _res->loadAlfredSpecialAnim(1);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ loadExtraScreenAndPresent(7);
+ break;
+ }
default:
break;
}
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index f77ae9531c4..0c35e16c060 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -469,20 +469,15 @@ const ExtraImages extraScreens[] = {
{0xFFC47, // girl book
0x1180C9,
8},
- /*{0x1183C5, // book
- 0x1358F3,
- 8},*/
-{ 1147849,
- 1267955,
- 8
-},
+ {1147849,
+ 1267955,
+ 8},
{0x152A88, // portrait
0x15BFC8,
8},
- {2727564, // CD
+ {2727564, // CD
2833276,
- 8}
-};
+ 8}};
struct AlfredSpecialAnimOffset {
int numFrames = 0;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b92baaf6b24..274cba31d19 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -157,7 +157,7 @@ void PelrockEngine::init() {
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
- setScreen(31, ALFRED_DOWN);
+ setScreen(36, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -584,7 +584,7 @@ void PelrockEngine::updateAnimations() {
void PelrockEngine::presentFrame() {
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- paintDebugLayer();
+ // paintDebugLayer();
_screen->markAllDirty();
}
@@ -1160,10 +1160,6 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
return;
}
- if (_room->_currentRoomNumber == 9 && sprite->index == 2) {
- debug("Drawing sprite 2 in room 9, anim %d, frame %d/%d, loop %d/%d", sprite->curAnimIndex, animData.curFrame, animData.nframes, animData.curLoop, animData.loopCount);
- }
-
applyMovement(&(sprite->x), &(sprite->y), &(sprite->zOrder), animData.movementFlags);
int x = sprite->x;
int y = sprite->y;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index bf34a6b8ea7..6960f7d0e26 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -299,7 +299,7 @@ public:
void openPlug(HotSpot *hotspot);
void useCordWithPlug(int inventoryObject, HotSpot *hotspot);
void pickCables(HotSpot *hotspot);
- void giveIdToGuard(int inventoryObject, HotSpot *hotspot);
+ void showIdToGuard(int inventoryObject, HotSpot *hotspot);
void unlockMuseum();
void giveMoneyToGuard(int inventoryObject, HotSpot *hotspot);
void openMuseumDoor(HotSpot *hotspot);
@@ -343,6 +343,8 @@ public:
void openTunnelDoor(HotSpot *hotspot);
void closeTunnelDoor(HotSpot *hotspot);
void useDollWithBed(int inventoryObject, HotSpot *hotspot);
+ void giveMagazineToGuard(int inventoryObject, HotSpot *hotspot);
+ void giveWaterToGuard(int inventoryObject, HotSpot *hotspot);
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index c1744b15e5e..c9c5c9e2b3f 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -224,8 +224,10 @@ void RoomManager::disableSprite(byte spriteIndex, int persist) {
}
void RoomManager::disableSprite(byte roomNumber, byte spriteIndex, int persist) {
+ debug("Disabling sprite %d in room %d with persist %d", spriteIndex, roomNumber, persist);
if (roomNumber == _currentRoomNumber && persist & PERSIST_TEMP) {
- _currentRoomAnims[spriteIndex].zOrder = 255;
+ debug("Disabling sprite LOCALLY %d in room %d with persist %d", spriteIndex, roomNumber, persist);
+ _currentRoomAnims[spriteIndex].zOrder = -1;
_currentRoomAnims[spriteIndex].isHotspotDisabled = true;
}
if (persist & PERSIST_PERM) {
@@ -940,6 +942,12 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
// debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
// debug(" Movement flags: 0x%04X", anim.movementFlags);
picOffset += needed;
+
+ if(_currentRoomNumber == 36 && i == 0) {
+ // Room 36 sets its anim to 1 to appear idle and only enables anim later on
+ anim.nframes = 1;
+ }
+
} else {
continue;
// debug("Anim %d-%d: invalid dimensions, skipping", i, j);
Commit: 19605d40a5c186d9965f10960636a449e947efc5
https://github.com/scummvm/scummvm/commit/19605d40a5c186d9965f10960636a449e947efc5
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:06+02:00
Commit Message:
PELROCK: Implements room 37
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index fac151a1a7c..7f1ee1854a3 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -146,6 +146,9 @@ const ActionEntry actionTable[] = {
{465, OPEN, &PelrockEngine::openTunnelDoor},
{465, CLOSE, &PelrockEngine::closeTunnelDoor},
+ //Room 37
+ {90, PICKUP, &PelrockEngine::pickUpStone},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -540,7 +543,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_room->enableExit(0);
Sprite *sprite = _room->findSpriteByIndex(0);
sprite->animData[0].movementFlags = 0x1C; // Move right
- //Basic loop to wait until the sprite has reached the door
+ // Basic loop to wait until the sprite has reached the door
while (!shouldQuit()) {
_events->pollEvent();
renderScene();
@@ -1298,7 +1301,7 @@ void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
sprite->animData[0].nframes = 5;
sprite->animData[0].movementFlags = 0x1C; // Move right
byte state = 0;
- //Basic loop to wait until the sprite has reached the door
+ // Basic loop to wait until the sprite has reached the door
while (!shouldQuit()) {
_events->pollEvent();
renderScene();
@@ -1306,11 +1309,11 @@ void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
state = 1;
sprite->animData[0].movementFlags = 0x240;
}
- if(sprite->y <= 188 && state == 1) {
+ if (sprite->y <= 188 && state == 1) {
state = 2;
sprite->animData[0].movementFlags = 0x14; // Move
}
- if(sprite->x <= 327 && state == 2) {
+ if (sprite->x <= 327 && state == 2) {
sprite->zOrder = -1; // Hide sprite
break;
}
@@ -1325,6 +1328,10 @@ void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
}
}
+void PelrockEngine::pickUpStone(HotSpot *hotspot) {
+ checkIngredients();
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
@@ -1357,11 +1364,19 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
case 327:
_state->setFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO, true);
break;
- case 294:
+ case 294: {
HotSpot *floorTile = _room->findHotspotByExtra(462);
floorTile->actionFlags = ACTION_MASK_OPEN;
_room->changeHotSpot(*floorTile);
}
+
+ case 307: {
+ HotSpot *stone = _room->findHotspotByExtra(90);
+ stone->actionFlags = ACTION_MASK_PICKUP;
+ _room->changeHotSpot(*stone);
+ break;
+ }
+ }
}
void PelrockEngine::useOnAlfred(int inventoryObject) {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 274cba31d19..4e0e8b60948 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -584,7 +584,7 @@ void PelrockEngine::updateAnimations() {
void PelrockEngine::presentFrame() {
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- // paintDebugLayer();
+ paintDebugLayer();
_screen->markAllDirty();
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 6960f7d0e26..e856b1843c3 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -345,6 +345,7 @@ public:
void useDollWithBed(int inventoryObject, HotSpot *hotspot);
void giveMagazineToGuard(int inventoryObject, HotSpot *hotspot);
void giveWaterToGuard(int inventoryObject, HotSpot *hotspot);
+ void pickUpStone(HotSpot *hotspot);
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index c9c5c9e2b3f..214be21a605 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -212,6 +212,7 @@ void RoomManager::changeHotspot(byte room, HotSpot hotspot, int persist) {
_currentRoomHotspots[i] = hotspot;
break;
}
+ debug("Hotspot %d in room %d does not match changed hotspot inner index %d", _currentRoomHotspots[i].innerIndex, room, hotspot.innerIndex);
}
}
if (persist & PERSIST_PERM) {
Commit: 1e225caa411cd76d51494ac3c87acb73de7ace1c
https://github.com/scummvm/scummvm/commit/1e225caa411cd76d51494ac3c87acb73de7ace1c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:07+02:00
Commit Message:
PELROCK: Implemented time travel animation
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 7f1ee1854a3..02d3f9f0229 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -146,7 +146,7 @@ const ActionEntry actionTable[] = {
{465, OPEN, &PelrockEngine::openTunnelDoor},
{465, CLOSE, &PelrockEngine::closeTunnelDoor},
- //Room 37
+ // Room 37
{90, PICKUP, &PelrockEngine::pickUpStone},
// Generic handlers
@@ -179,6 +179,12 @@ const CombinationEntry combinationTable[] = {
{83, 461, &PelrockEngine::useDollWithBed},
{84, 503, &PelrockEngine::giveMagazineToGuard},
{86, 500, &PelrockEngine::giveWaterToGuard},
+
+ // Room 35 (cauldron)
+ {90, 506, &PelrockEngine::magicFormula},
+ {85, 506, &PelrockEngine::magicFormula},
+ {86, 506, &PelrockEngine::magicFormula},
+ {81, 506, &PelrockEngine::magicFormula},
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -1332,6 +1338,44 @@ void PelrockEngine::pickUpStone(HotSpot *hotspot) {
checkIngredients();
}
+void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
+ _state->removeInventoryItem(inventoryObject);
+ _state->setFlag(FLAG_FORMULA_MAGICA, _state->getFlag(FLAG_FORMULA_MAGICA) + 1);
+ if (_state->getFlag(FLAG_FORMULA_MAGICA) == 4) {
+
+ size_t frameSize = 98 * 138;
+ size_t bufSize = frameSize * 11;
+ byte *smokeFrames = new byte[bufSize];
+ _res->loadOtherSpecialAnim(1526432, true, smokeFrames, bufSize);
+ Graphics::Surface smokeSurface;
+ smokeSurface.create(98, 138, Graphics::PixelFormat::createFormatCLUT8());
+ int curFrame = 0;
+ while (!shouldQuit()) {
+ _events->pollEvent();
+
+ bool didRender = renderScene(OVERLAY_NONE);
+
+ memset(smokeSurface.getPixels(), 0, frameSize);
+ extractSingleFrame(smokeFrames, (byte *)smokeSurface.getPixels(), curFrame, 98, 138);
+ _screen->transBlitFrom(smokeSurface, Common::Point(_alfredState.x, _alfredState.y - _alfredState.h), 255);
+ if (curFrame == 5) {
+ _alfredState.setState(ALFRED_SKIP_DRAWING);
+ }
+ if (didRender && _chrono->getFrameCount() % 2 == 0) {
+ curFrame++;
+
+ if (curFrame >= 11) {
+ break;
+ }
+ }
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+ _alfredState.setState(ALFRED_IDLE);
+ setScreen(39, ALFRED_UP);
+ }
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 4e0e8b60948..79ba055d22b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -157,7 +157,7 @@ void PelrockEngine::init() {
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
- setScreen(36, ALFRED_DOWN);
+ setScreen(35, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -824,6 +824,9 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
}
switch (_alfredState.animState) {
+ case ALFRED_SKIP_DRAWING: {
+ break;
+ }
case ALFRED_IDLE: {
drawAlfred(_res->alfredIdle[_alfredState.direction]);
break;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index e856b1843c3..9f9716bc69f 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -346,6 +346,7 @@ public:
void giveMagazineToGuard(int inventoryObject, HotSpot *hotspot);
void giveWaterToGuard(int inventoryObject, HotSpot *hotspot);
void pickUpStone(HotSpot *hotspot);
+ void magicFormula(int inventoryObject, HotSpot *hotspot);
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 1a150749150..2be2c3aec2f 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -50,6 +50,7 @@ const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
{7, 208, 102, 0, 7, 1600956, 1}, // 10 - alfred with workers
{23, 116, 124, 1, 7, 2060916, 1}, // 11 - Munheco 1
{18, 177, 124, 1, 7, 2115632, 1}, // 12 - Munheco 2
+ {11, 98, 138, 1, 7, 1526432, 1}, // 13 - Munheco 3
};
ResourceManager::~ResourceManager() {
@@ -234,6 +235,24 @@ void ResourceManager::loadAlfredAnims() {
free(alfredCombLeftRaw);
}
+void ResourceManager::loadOtherSpecialAnim(uint32 offset, bool rleCompressed, byte *&buffer, size_t bufferSize) {
+ Common::File alfred7;
+ if (!alfred7.open(Common::Path("ALFRED.7"))) {
+ error("Could not open ALFRED.7");
+ return;
+ }
+
+ if (rleCompressed) {
+ byte *compressed = nullptr;
+ size_t compressedSize = 0;
+ readUntilBuda(&alfred7, offset, compressed, compressedSize);
+ rleDecompress(compressed, compressedSize, 0, bufferSize, &buffer, false);
+ }
+
+ alfred7.close();
+
+}
+
void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
AlfredSpecialAnimOffset anim = alfredSpecialAnims[numAnim];
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index bcada5183d0..cd1b3bc1520 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -45,6 +45,7 @@ public:
void loadCursors();
void loadInteractionIcons();
void loadAlfredAnims();
+ void loadOtherSpecialAnim(uint32 offset, bool rleCompressed, byte *&buffer, size_t bufferSize);
void loadAlfredSpecialAnim(int numAnim, bool reverse = false);
void clearSpecialAnim();
void loadInventoryItems();
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 967c70e01bb..6fad2fb3e63 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -114,7 +114,8 @@ enum AlfredAnimState {
ALFRED_TALKING,
ALFRED_INTERACTING,
ALFRED_COMB,
- ALFRED_SPECIAL_ANIM
+ ALFRED_SPECIAL_ANIM,
+ ALFRED_SKIP_DRAWING
};
enum AlfredDirection {
Commit: 63056fbb62e00dfaa0f180ba6bba10bad01d42da
https://github.com/scummvm/scummvm/commit/63056fbb62e00dfaa0f180ba6bba10bad01d42da
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:07+02:00
Commit Message:
PELROCK: Swimming pool cutscene (partial implementation)
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 02d3f9f0229..720d5bb6f61 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -149,6 +149,8 @@ const ActionEntry actionTable[] = {
// Room 37
{90, PICKUP, &PelrockEngine::pickUpStone},
+ // Room 39
+ {700, PICKUP, &PelrockEngine::swimmingPoolCutscene},
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -1313,11 +1315,11 @@ void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
renderScene();
if (sprite->x >= 339 && state == 0) {
state = 1;
- sprite->animData[0].movementFlags = 0x240;
+ sprite->animData[0].movementFlags = 0x240; // Move up
}
if (sprite->y <= 188 && state == 1) {
state = 2;
- sprite->animData[0].movementFlags = 0x14; // Move
+ sprite->animData[0].movementFlags = 0x14; // Move left
}
if (sprite->x <= 327 && state == 2) {
sprite->zOrder = -1; // Hide sprite
@@ -1338,6 +1340,101 @@ void PelrockEngine::pickUpStone(HotSpot *hotspot) {
checkIngredients();
}
+/**
+ * Naked girls swim underwater, guard enters the scene.
+ * "diving" animation is stored in Alfred.7 as a single RLE chunk with multiple continuous sprite sizes.
+ */
+void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
+ byte *buffer = nullptr;
+ size_t bufSize = 0;
+
+ struct SwimmerInfo {
+ int w;
+ int h;
+ int nFrames;
+ int curFrame;
+ int totalSize;
+ Sprite *sprite;
+ int x;
+ int y;
+ byte *data;
+ };
+
+ Sprite *sprite1 = _room->findSpriteByIndex(3);
+ Sprite *sprite2 = _room->findSpriteByIndex(4);
+ Sprite *sprite3 = _room->findSpriteByIndex(5);
+ Sprite *sprite4 = _room->findSpriteByIndex(6);
+ SwimmerInfo swimmers[4];
+ swimmers[0] = {93, 88, 9, 0, 93 * 88 * 9, sprite1, sprite1->x, sprite1->y - 30, nullptr};
+ swimmers[1] = {68, 31, 7, 0, 68 * 31 * 7, sprite2, sprite2->x, sprite2->y, nullptr};
+ swimmers[2] = {79, 95, 9, 0, 79 * 95 * 9, sprite3, sprite3->x, sprite3->y, nullptr};
+ swimmers[3] = {54, 42, 8, 0, 54 * 42 * 8, sprite4, sprite4->x, sprite4->y, nullptr};
+
+ _res->loadOtherSpecialAnim(1446862, true, buffer, bufSize);
+
+ int acc = swimmers[0].totalSize;
+ swimmers[0].data = new byte[swimmers[0].totalSize];
+ Common::copy(buffer, buffer + swimmers[0].totalSize, swimmers[0].data);
+
+ swimmers[1].data = new byte[swimmers[1].totalSize];
+ Common::copy(buffer + acc, buffer + acc + swimmers[1].totalSize, swimmers[1].data);
+ acc += swimmers[1].totalSize;
+
+ swimmers[2].data = new byte[swimmers[2].totalSize];
+ Common::copy(buffer + acc, buffer + acc + swimmers[2].totalSize, swimmers[2].data);
+ acc += swimmers[2].totalSize;
+
+ swimmers[3].data = new byte[swimmers[3].totalSize];
+ Common::copy(buffer + acc, buffer + acc + swimmers[3].totalSize, swimmers[3].data);
+ acc += swimmers[3].totalSize;
+
+ Graphics::Surface surfaces[4];
+ for (int i = 0; i < 4; i++) {
+ surfaces[i].create(swimmers[i].w, swimmers[i].h, Graphics::PixelFormat::createFormatCLUT8());
+ }
+ sprite1->zOrder = -1;
+ sprite2->zOrder = -1;
+ sprite3->zOrder = -1;
+ sprite4->zOrder = -1;
+
+ while (!shouldQuit()) {
+ _events->pollEvent();
+ bool didRender = renderScene(OVERLAY_NONE);
+ for (int i = 0; i < 4; i++) {
+ if (swimmers[i].curFrame >= swimmers[i].nFrames) {
+ continue;
+ }
+ debug("Swimmer %d position: (%d, %d)", i + 1, swimmers[i].sprite->x, swimmers[i].sprite->y);
+ memset(surfaces[i].getPixels(), 0, swimmers[i].w * swimmers[i].h);
+ extractSingleFrame(swimmers[i].data, (byte *)surfaces[i].getPixels(), swimmers[i].curFrame, swimmers[i].w, swimmers[i].h);
+ debug("Moving swimmer %d to (%d, %d)", i + 1, swimmers[i].x, swimmers[i].y);
+ _screen->transBlitFrom(surfaces[i], Common::Point(swimmers[i].x, swimmers[i].y), 255);
+ }
+
+ if (didRender && _chrono->getFrameCount() % 2 == 0) {
+ if (swimmers[0].curFrame < swimmers[0].nFrames)
+ swimmers[0].curFrame++;
+ if (swimmers[1].curFrame < swimmers[1].nFrames)
+ swimmers[1].curFrame++;
+ if (swimmers[2].curFrame < swimmers[2].nFrames)
+ swimmers[2].curFrame++;
+ if (swimmers[3].curFrame < swimmers[3].nFrames)
+ swimmers[3].curFrame++;
+ _events->waitForKey();
+ if (swimmers[0].curFrame >= swimmers[0].nFrames &&
+ swimmers[1].curFrame >= swimmers[1].nFrames &&
+ swimmers[2].curFrame >= swimmers[2].nFrames &&
+ swimmers[3].curFrame >= swimmers[3].nFrames) {
+ break;
+ }
+ }
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+ Sprite *guard = _room->findSpriteByIndex(0);
+ guard->animData[0].movementFlags = 0x14;
+}
+
void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
_state->removeInventoryItem(inventoryObject);
_state->setFlag(FLAG_FORMULA_MAGICA, _state->getFlag(FLAG_FORMULA_MAGICA) + 1);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 79ba055d22b..9f702636187 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -157,7 +157,7 @@ void PelrockEngine::init() {
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
- setScreen(35, ALFRED_DOWN);
+ setScreen(39, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 9f9716bc69f..711e6bbafe9 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -346,6 +346,7 @@ public:
void giveMagazineToGuard(int inventoryObject, HotSpot *hotspot);
void giveWaterToGuard(int inventoryObject, HotSpot *hotspot);
void pickUpStone(HotSpot *hotspot);
+ void swimmingPoolCutscene(HotSpot *hotspot);
void magicFormula(int inventoryObject, HotSpot *hotspot);
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 2be2c3aec2f..0e99b0359fa 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -235,7 +235,7 @@ void ResourceManager::loadAlfredAnims() {
free(alfredCombLeftRaw);
}
-void ResourceManager::loadOtherSpecialAnim(uint32 offset, bool rleCompressed, byte *&buffer, size_t bufferSize) {
+void ResourceManager::loadOtherSpecialAnim(uint32 offset, bool rleCompressed, byte *&buffer, size_t &bufferSize) {
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
error("Could not open ALFRED.7");
@@ -246,11 +246,9 @@ void ResourceManager::loadOtherSpecialAnim(uint32 offset, bool rleCompressed, by
byte *compressed = nullptr;
size_t compressedSize = 0;
readUntilBuda(&alfred7, offset, compressed, compressedSize);
- rleDecompress(compressed, compressedSize, 0, bufferSize, &buffer, false);
+ bufferSize = rleDecompress(compressed, compressedSize, 0, 0, &buffer, true);
}
-
alfred7.close();
-
}
void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index cd1b3bc1520..e016fff7c93 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -45,7 +45,7 @@ public:
void loadCursors();
void loadInteractionIcons();
void loadAlfredAnims();
- void loadOtherSpecialAnim(uint32 offset, bool rleCompressed, byte *&buffer, size_t bufferSize);
+ void loadOtherSpecialAnim(uint32 offset, bool rleCompressed, byte *&buffer, size_t &bufferSize);
void loadAlfredSpecialAnim(int numAnim, bool reverse = false);
void clearSpecialAnim();
void loadInventoryItems();
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 03b666c9320..7197ece76d7 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -44,13 +44,6 @@ static const int unpickableHotspotExtras[] = {
74,
6,
7,
- 316, // wires
- 357, // mailbox should pick a different hotspot,
- 360, // library shelves
- 361,
- 362,
- 472, // matches
- 609 // sunflower
};
@@ -120,6 +113,8 @@ public:
bool isPickableByExtra(uint16 extra) {
+ if(extra > 112)
+ return false;
int size = sizeof(unpickableHotspotExtras) / sizeof(unpickableHotspotExtras[0]);
for (int i = 0; i < size; i++) {
if (extra == unpickableHotspotExtras[i])
Commit: bcf440271ce377794a16f21d365c92fa12a86b41
https://github.com/scummvm/scummvm/commit/bcf440271ce377794a16f21d365c92fa12a86b41
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:07+02:00
Commit Message:
PELROCK: Implement police showing up after raiding tomb
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 720d5bb6f61..1beb1db5be0 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -415,6 +415,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
case 352:
case 355:
+ case 291:
// a la carcel
toJail();
break;
@@ -1226,6 +1227,7 @@ void PelrockEngine::checkAllSymbols() {
void PelrockEngine::pickUpHairStrand(HotSpot *hotspot) {
checkIngredients();
+ _state->setFlag(FLAG_ROBA_PELO_PRINCESA,true);
}
void PelrockEngine::openJailFloorTile(HotSpot *hotspot) {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 9f702636187..d9e6ba05cb6 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1835,6 +1835,8 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_res->loadAlfredSpecialAnim(6);
_alfredState.setState(ALFRED_SPECIAL_ANIM);
waitForSpecialAnimation();
+
+ _room->addStickerToRoom(38, 123, PERSIST_TEMP);
_alfredState.x = x;
_alfredState.y = y;
break;
@@ -1889,6 +1891,15 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
break;
}
+ case 30: {
+ if(_state->getFlag(FLAG_ROBA_PELO_PRINCESA) == true) {
+ _state->setFlag(FLAG_ROBA_PELO_PRINCESA, false);
+ _room->enableSprite(0, 200, PERSIST_TEMP);
+ _dialog->say(_res->_ingameTexts[OIGAUSTED]);
+ walkAndAction(_room->findHotspotByExtra(0), TALK);
+ }
+ break;
+ }
default:
break;
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 6fad2fb3e63..67002cb1ee1 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -474,20 +474,21 @@ struct ResetEntry {
#define FLAG_CLAVE_CAJA_FUERTE 19
#define FLAG_INGREDIENTES_CONSEGUIDOS 48
#define FLAG_MERCHANT_GIVENITEMS 58
+#define FLAG_ROBA_PELO_PRINCESA 17
+#define FLAG_A_LA_CARCEL 18
+#define FLAG_SE_HA_PUESTO_EL_MUNECO 20
+#define FLAG_VIGILANTE_BEBE_AGUA 21
+#define FLAG_FORMULA_MAGICA 26
#define FLAG_VIAJE_A_EGIPTO 12
+
#define FLAG_PUERTA_SECRETA_ABIERTA 16
-#define FLAG_ROBA_PELO_PRINCESA 17
-#define FLAG_A_LA_CARCEL 18
-#define FLAG_SE_HA_PUESTO_EL_MUNECO 20
-#define FLAG_VIGILANTE_BEBE_AGUA 21
#define FLAG_VIGILANTE_MEANDO 22
#define FLAG_PIRAMIDE_JODIDA 23
#define FLAG_PIRAMIDE_JODIDA2 24
#define FLAG_VIGILANTE_PAJEANDOSE 25
-#define FLAG_FORMULA_MAGICA 26
#define FLAG_VIAJA_AL_PASADO 27
#define FLAG_APARECE_EUNUCO 28
#define FLAG_AL_FARAON 29
Commit: e71aa5b8d1beba4dea4f897e3f717156015c9895
https://github.com/scummvm/scummvm/commit/e71aa5b8d1beba4dea4f897e3f717156015c9895
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:08+02:00
Commit Message:
PELROCK: Full animations in swimming pool cutscene
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 1beb1db5be0..9b3a604f19d 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1227,7 +1227,7 @@ void PelrockEngine::checkAllSymbols() {
void PelrockEngine::pickUpHairStrand(HotSpot *hotspot) {
checkIngredients();
- _state->setFlag(FLAG_ROBA_PELO_PRINCESA,true);
+ _state->setFlag(FLAG_ROBA_PELO_PRINCESA, true);
}
void PelrockEngine::openJailFloorTile(HotSpot *hotspot) {
@@ -1351,82 +1351,58 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
size_t bufSize = 0;
struct SwimmerInfo {
+ int spriteIndex;
+ int16 x;
+ int16 y;
int w;
int h;
int nFrames;
- int curFrame;
int totalSize;
- Sprite *sprite;
- int x;
- int y;
- byte *data;
+ uint16 movementFlags;
};
- Sprite *sprite1 = _room->findSpriteByIndex(3);
- Sprite *sprite2 = _room->findSpriteByIndex(4);
- Sprite *sprite3 = _room->findSpriteByIndex(5);
- Sprite *sprite4 = _room->findSpriteByIndex(6);
- SwimmerInfo swimmers[4];
- swimmers[0] = {93, 88, 9, 0, 93 * 88 * 9, sprite1, sprite1->x, sprite1->y - 30, nullptr};
- swimmers[1] = {68, 31, 7, 0, 68 * 31 * 7, sprite2, sprite2->x, sprite2->y, nullptr};
- swimmers[2] = {79, 95, 9, 0, 79 * 95 * 9, sprite3, sprite3->x, sprite3->y, nullptr};
- swimmers[3] = {54, 42, 8, 0, 54 * 42 * 8, sprite4, sprite4->x, sprite4->y, nullptr};
+ SwimmerInfo swimmers[4] = {
+ {3, 3, -17, 93, 88, 9, 93 * 88 * 9, 0x02FF}, // Move right and up
+ {4, 1, 0, 68, 31, 7, 68 * 31 * 7, 0},
+ {5, -14, -18, 79, 95, 9, 79 * 95 * 9, 0},
+ {6, -1, -8, 54, 42, 8, 54 * 42 * 8, 0}};
_res->loadOtherSpecialAnim(1446862, true, buffer, bufSize);
- int acc = swimmers[0].totalSize;
- swimmers[0].data = new byte[swimmers[0].totalSize];
- Common::copy(buffer, buffer + swimmers[0].totalSize, swimmers[0].data);
-
- swimmers[1].data = new byte[swimmers[1].totalSize];
- Common::copy(buffer + acc, buffer + acc + swimmers[1].totalSize, swimmers[1].data);
- acc += swimmers[1].totalSize;
-
- swimmers[2].data = new byte[swimmers[2].totalSize];
- Common::copy(buffer + acc, buffer + acc + swimmers[2].totalSize, swimmers[2].data);
- acc += swimmers[2].totalSize;
-
- swimmers[3].data = new byte[swimmers[3].totalSize];
- Common::copy(buffer + acc, buffer + acc + swimmers[3].totalSize, swimmers[3].data);
- acc += swimmers[3].totalSize;
-
- Graphics::Surface surfaces[4];
+ int acc = 0;
for (int i = 0; i < 4; i++) {
- surfaces[i].create(swimmers[i].w, swimmers[i].h, Graphics::PixelFormat::createFormatCLUT8());
+ Sprite *sprite = _room->findSpriteByIndex(swimmers[i].spriteIndex);
+ sprite->x = sprite->x + swimmers[i].x;
+ sprite->y = sprite->y + swimmers[i].y;
+ sprite->w = swimmers[i].w;
+ sprite->h = swimmers[i].h;
+ sprite->animData[0].nframes = swimmers[i].nFrames;
+ sprite->animData[0].movementFlags = swimmers[i].movementFlags;
+ sprite->animData[0].curFrame = 0;
+ sprite->animData[0].loopCount = 0;
+ sprite->animData[0].curLoop = 0;
+ sprite->animData[0].speed = 0;
+ sprite->animData[0].elpapsedFrames = 0;
+ sprite->disableAfterSequence = true;
+
+ sprite->animData[0].animData = new byte *[sprite->animData[0].nframes];
+ byte *spriteFrames[sprite->animData[0].nframes];
+ for (int i = 0; i < sprite->animData[0].nframes; i++) {
+ sprite->animData[0].animData[i] = new byte[sprite->w * sprite->h];
+ extractSingleFrame(buffer + acc, sprite->animData[0].animData[i], i, sprite->w, sprite->h);
+ }
+ acc += sprite->w * sprite->h * sprite->animData[0].nframes;
}
- sprite1->zOrder = -1;
- sprite2->zOrder = -1;
- sprite3->zOrder = -1;
- sprite4->zOrder = -1;
+ _sound->stopMusic();
+ _sound->playMusicTrack(28);
+ Sprite *s1 = _room->findSpriteByIndex(3);
while (!shouldQuit()) {
_events->pollEvent();
bool didRender = renderScene(OVERLAY_NONE);
- for (int i = 0; i < 4; i++) {
- if (swimmers[i].curFrame >= swimmers[i].nFrames) {
- continue;
- }
- debug("Swimmer %d position: (%d, %d)", i + 1, swimmers[i].sprite->x, swimmers[i].sprite->y);
- memset(surfaces[i].getPixels(), 0, swimmers[i].w * swimmers[i].h);
- extractSingleFrame(swimmers[i].data, (byte *)surfaces[i].getPixels(), swimmers[i].curFrame, swimmers[i].w, swimmers[i].h);
- debug("Moving swimmer %d to (%d, %d)", i + 1, swimmers[i].x, swimmers[i].y);
- _screen->transBlitFrom(surfaces[i], Common::Point(swimmers[i].x, swimmers[i].y), 255);
- }
- if (didRender && _chrono->getFrameCount() % 2 == 0) {
- if (swimmers[0].curFrame < swimmers[0].nFrames)
- swimmers[0].curFrame++;
- if (swimmers[1].curFrame < swimmers[1].nFrames)
- swimmers[1].curFrame++;
- if (swimmers[2].curFrame < swimmers[2].nFrames)
- swimmers[2].curFrame++;
- if (swimmers[3].curFrame < swimmers[3].nFrames)
- swimmers[3].curFrame++;
- _events->waitForKey();
- if (swimmers[0].curFrame >= swimmers[0].nFrames &&
- swimmers[1].curFrame >= swimmers[1].nFrames &&
- swimmers[2].curFrame >= swimmers[2].nFrames &&
- swimmers[3].curFrame >= swimmers[3].nFrames) {
+ if (didRender) {
+ if (_room->findSpriteByIndex(swimmers[0].spriteIndex)->zOrder == -1) {
break;
}
}
@@ -1435,6 +1411,21 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
}
Sprite *guard = _room->findSpriteByIndex(0);
guard->animData[0].movementFlags = 0x14;
+ while (!shouldQuit()) {
+ _events->pollEvent();
+ renderScene();
+ if (guard->x <= _alfredState.x + 70) {
+ break;
+ }
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+
+ guard->animData[0].movementFlags = 0;
+ guard->animData[0].curFrame = 0;
+ guard->animData[0].nframes = 1;
+ _alfredState.direction = ALFRED_RIGHT;
+ talkTo(_room->findHotspotByExtra(guard->extra));
}
void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index d9e6ba05cb6..c3b0d362887 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -613,7 +613,7 @@ void PelrockEngine::paintDebugLayer() {
if (showSprites) {
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
Sprite sprite = _room->_currentRoomAnims[i];
- drawRect(_screen, sprite.x, sprite.y, sprite.animData->w, sprite.animData->h, 14);
+ drawRect(_screen, sprite.x, sprite.y, sprite.w, sprite.h, 14);
_smallFont->drawString(_screen, Common::String::format("S %d", sprite.index), sprite.x + 2, sprite.y, 640, 14);
}
}
@@ -1166,8 +1166,8 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
applyMovement(&(sprite->x), &(sprite->y), &(sprite->zOrder), animData.movementFlags);
int x = sprite->x;
int y = sprite->y;
- int w = animData.w;
- int h = animData.h;
+ int w = sprite->w;
+ int h = sprite->h;
if (sprite->isTalking) {
animateTalkingNPC(sprite);
return;
@@ -1385,10 +1385,10 @@ bool PelrockEngine::isSpriteUnder(Sprite *sprite, int x, int y) {
Anim &animData = sprite->animData[sprite->curAnimIndex];
int curFrame = animData.curFrame;
- int localX = x - animData.x;
- int localY = y - animData.y;
- if (localX >= 0 && localX < animData.w && localY >= 0 && localY < animData.h) {
- byte pixel = animData.animData[curFrame][localY * animData.w + localX];
+ int localX = x - sprite->x;
+ int localY = y - sprite->y;
+ if (localX >= 0 && localX < sprite->w && localY >= 0 && localY < sprite->h) {
+ byte pixel = animData.animData[curFrame][localY * sprite->w + localX];
if (pixel != 255) {
return true;
}
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 214be21a605..72822cd3a02 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -920,10 +920,6 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
for (int j = 0; j < sprite.numAnims; j++) {
Anim anim;
- anim.x = sprite.x;
- anim.y = sprite.y;
- anim.w = sprite.w;
- anim.h = sprite.h;
anim.curFrame = 0;
anim.nframes = data[subAnimOffset + j];
@@ -931,18 +927,18 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
anim.speed = data[subAnimOffset + 8 + j];
anim.movementFlags = data[subAnimOffset + 14 + (j * 2)] | (data[subAnimOffset + 14 + (j * 2) + 1] << 8);
+ uint32_t totalBytesPerFrame = sprite.w * sprite.h * anim.nframes;
anim.animData = new byte *[anim.nframes];
- if (anim.w > 0 && anim.h > 0 && anim.nframes > 0) {
- uint32_t needed = anim.w * anim.h * anim.nframes;
+ if (sprite.w > 0 && sprite.h > 0 && anim.nframes > 0) {
for (int i = 0; i < anim.nframes; i++) {
- anim.animData[i] = new byte[anim.w * anim.h];
- // debug("Extracting frame %d for anim %d-%d, w=%d h=%d, pixelDataSize=%d, current offset %d", i, j, anim.nframes, anim.w, anim.h, pixelDataSize, picOffset);
- extractSingleFrame(pixelData + picOffset, anim.animData[i], i, anim.w, anim.h);
+ anim.animData[i] = new byte[sprite.w * sprite.h];
+ // debug("Extracting frame %d for anim %d-%d, w=%d h=%d, pixelDataSize=%d, current offset %d", i, j, anim.nframes, sprite.w, sprite.h, pixelDataSize, picOffset);
+ extractSingleFrame(pixelData + picOffset, anim.animData[i], i, sprite.w, sprite.h);
}
sprite.animData[j] = anim;
// debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
// debug(" Movement flags: 0x%04X", anim.movementFlags);
- picOffset += needed;
+ picOffset += totalBytesPerFrame;
if(_currentRoomNumber == 36 && i == 0) {
// Room 36 sets its anim to 1 to appear idle and only enables anim later on
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 67002cb1ee1..b098259c4b9 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -194,10 +194,6 @@ typedef struct {
} PathContext;
struct Anim {
- int16 x;
- int16 y;
- int w;
- int h;
int nframes;
int curFrame = 0;
int curLoop = 0;
Commit: bd9ee4a407996a57adeca07cfc043c07a20aeb11
https://github.com/scummvm/scummvm/commit/bd9ee4a407996a57adeca07cfc043c07a20aeb11
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:08+02:00
Commit Message:
PELROCK: Implements rest of swimming cutscene
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 9b3a604f19d..b88ab0dc749 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1396,7 +1396,6 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
_sound->stopMusic();
_sound->playMusicTrack(28);
- Sprite *s1 = _room->findSpriteByIndex(3);
while (!shouldQuit()) {
_events->pollEvent();
bool didRender = renderScene(OVERLAY_NONE);
@@ -1426,6 +1425,22 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
guard->animData[0].nframes = 1;
_alfredState.direction = ALFRED_RIGHT;
talkTo(_room->findHotspotByExtra(guard->extra));
+ if(shouldQuit()) {
+ return;
+ }
+ _graphics->fadeToBlack(10);
+ _alfredState.x = 271;
+ _alfredState.y = 385;
+ setScreen(40, ALFRED_UP);
+ walkAndAction(_room->findHotspotByExtra(640), TALK);
+ waitForActionEnd();
+ if(shouldQuit()) {
+ return;
+ }
+ _graphics->fadeToBlack(10);
+ _alfredState.x = 271;
+ _alfredState.y = 385;
+ setScreen(41, ALFRED_UP);
}
void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 5636c573c58..fcd6b8503c0 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -736,6 +736,12 @@ ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint
}
void DialogManager::addGoodbyeOptionIfNeeded(Common::Array<ChoiceOption> *choices, int currentChoiceLevel, uint originalChoiceCount) {
+ // Room entry handlers can globally disable the goodbye option for certain rooms
+ // (e.g. rooms 39/40 pharaoh, room 48).
+ if (_goodbyeDisabled) {
+ return;
+ }
+
// Only consider adding goodbye if there are MULTIPLE choices
// If there's only 1 choice, it's auto-dialogue and should not have goodbye
if (originalChoiceCount <= 1) {
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 67c124576e6..532515fbcbd 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -113,6 +113,9 @@ public:
Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
Common::Array<Common::Array<Common::String>> wordWrap(Common::StringArray texts);
Common::Array<ChoiceOption> *_currentChoices = nullptr;
+
+ // When true, the goodbye option is suppressed for all conversations in the current room.
+ bool _goodbyeDisabled = false;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index c3b0d362887..cd9f635284d 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1811,6 +1811,9 @@ void PelrockEngine::waitForSpecialAnimation() {
}
void PelrockEngine::doExtraActions(int roomNumber) {
+ // Reset goodbye-disabled flag each room load. Specific rooms set it below.
+ _dialog->_goodbyeDisabled = false;
+
switch (roomNumber) {
case 4:
if (_state->getFlag(FLAG_PUESTA_SALSA_PICANTE) && !_state->getFlag(FLAG_JEFE_ENCARCELADO)) {
@@ -1879,6 +1882,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
case 26: {
if(_state->getFlag(FLAG_A_LA_CARCEL) == true) {
+ _dialog->_goodbyeDisabled = true;
if(_state->getFlag(FLAG_SE_HA_PUESTO_EL_MUNECO) == true) {
_state->setCurrentRoot(26, 2, 1);
} else {
@@ -1893,6 +1897,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
case 30: {
if(_state->getFlag(FLAG_ROBA_PELO_PRINCESA) == true) {
+ _dialog->_goodbyeDisabled = true;
_state->setFlag(FLAG_ROBA_PELO_PRINCESA, false);
_room->enableSprite(0, 200, PERSIST_TEMP);
_dialog->say(_res->_ingameTexts[OIGAUSTED]);
@@ -1900,6 +1905,15 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
break;
}
+ case 39:
+ case 40:
+ // Rooms 39/40 are the pharaoh's guard and throne room â all conversation
+ // paths lead to capture, no voluntary exit allowed.
+ _dialog->_goodbyeDisabled = true;
+ break;
+ case 48:
+ _dialog->_goodbyeDisabled = true;
+ break;
default:
break;
}
Commit: afa4597b81bab90c9dbee66d229e496292f53359
https://github.com/scummvm/scummvm/commit/afa4597b81bab90c9dbee66d229e496292f53359
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:08+02:00
Commit Message:
PELROCK: Fixes bug in walkAndAction where alfred wouldnt end up looking in the right direction
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index b88ab0dc749..9db05d019b6 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1424,7 +1424,8 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
guard->animData[0].curFrame = 0;
guard->animData[0].nframes = 1;
_alfredState.direction = ALFRED_RIGHT;
- talkTo(_room->findHotspotByExtra(guard->extra));
+ walkAndAction(_room->findHotspotByExtra(guard->extra), TALK);
+ waitForActionEnd();
if(shouldQuit()) {
return;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index cd9f635284d..38d35f7b930 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -487,7 +487,7 @@ void PelrockEngine::checkMouse() {
checkMouseHover();
- if(_disableAction) {
+ if (_disableAction) {
return;
}
@@ -676,11 +676,11 @@ void PelrockEngine::placeSticker(Sticker sticker) {
for (int x = 0; x < sticker.w; x++) {
byte pixel = sticker.stickerData[y * sticker.w + x];
// if (pixel != 0) {
- int bgX = sticker.x + x;
- int bgY = sticker.y + y;
- if (bgX >= 0 && bgX < 640 && bgY >= 0 && bgY < 400) {
- _compositeBuffer[bgY * 640 + bgX] = pixel;
- }
+ int bgX = sticker.x + x;
+ int bgY = sticker.y + y;
+ if (bgX >= 0 && bgX < 640 && bgY >= 0 && bgY < 400) {
+ _compositeBuffer[bgY * 640 + bgX] = pixel;
+ }
// }
}
}
@@ -868,14 +868,21 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.setState(ALFRED_IDLE);
_alfredState.isWalkingCancelable = true;
_disableAction = false;
- if (_currentHotspot != nullptr)
+ if (_queuedAction.isQueued) {
+ // When a queued action exists, face toward its target hotspot
+ // (not _currentHotspot which is the mouse-hovered one)
+ HotSpot *targetHotspot = &_room->_currentRoomHotspots[_queuedAction.hotspotIndex];
+ _alfredState.direction = calculateAlfredsDirection(targetHotspot);
+ } else if (_currentHotspot != nullptr) {
_alfredState.direction = calculateAlfredsDirection(_currentHotspot);
+ }
drawAlfred(_res->alfredIdle[_alfredState.direction]);
if (_queuedAction.isQueued) {
// look and talk execute immediately, others need interaction animation first
if (_queuedAction.verb == TALK || _queuedAction.verb == LOOK) {
_queuedAction.isQueued = false;
- doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
+ HotSpot *actionHotspot = &_room->_currentRoomHotspots[_queuedAction.hotspotIndex];
+ doAction(_queuedAction.verb, actionHotspot);
break;
}
_alfredState.setState(ALFRED_INTERACTING);
@@ -887,7 +894,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
Exit *exit = isExitUnder(_alfredState.x, _alfredState.y);
if (exit != nullptr) {
debug("Using exit to room %d", exit->targetRoom);
- if(exit->targetRoom == 31 && _room->_currentRoomNumber == 32) {
+ if (exit->targetRoom == 31 && _room->_currentRoomNumber == 32) {
_res->loadAlfredSpecialAnim(8);
_alfredState.setState(ALFRED_SPECIAL_ANIM);
waitForSpecialAnimation();
@@ -1188,7 +1195,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
animData.curFrame = 0;
animData.curLoop++;
} else {
- if(sprite->disableAfterSequence) {
+ if (sprite->disableAfterSequence) {
sprite->zOrder = -1;
return;
}
@@ -1503,7 +1510,7 @@ void PelrockEngine::gameLoop() {
if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_s) {
SpellBook spellBook(_events, _res);
Spell *selectedSpell = spellBook.run();
- if(selectedSpell != nullptr) {
+ if (selectedSpell != nullptr) {
_dialog->sayAlfred(selectedSpell->text);
}
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
@@ -1830,7 +1837,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_dialog->say(_res->_ingameTexts[PINTA_BUENAPERSONA]);
}
case 38: {
- if(_room->_prevRoomNumber == 30) {
+ if (_room->_prevRoomNumber == 30) {
int x = _alfredState.x;
int y = _alfredState.y;
_alfredState.x -= 57;
@@ -1846,7 +1853,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
}
case 32: {
- if(_room->_prevRoomNumber == 31) {
+ if (_room->_prevRoomNumber == 31) {
int x = _alfredState.x;
int y = _alfredState.y;
_res->loadAlfredSpecialAnim(7);
@@ -1854,11 +1861,10 @@ void PelrockEngine::doExtraActions(int roomNumber) {
waitForSpecialAnimation();
_alfredState.x = x;
_alfredState.y = y;
-
}
}
case 27: {
- if(_room->_prevRoomNumber == 33) {
+ if (_room->_prevRoomNumber == 33) {
int x = _alfredState.x;
int y = _alfredState.y;
_alfredState.x = 12;
@@ -1872,7 +1878,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
break;
}
case 28: {
- if(_state->getFlag(FLAG_CROCODILLO_ENCENDIDO) == true) {
+ if (_state->getFlag(FLAG_CROCODILLO_ENCENDIDO) == true) {
byte palette[768];
_res->getPaletteForRoom28(palette);
g_system->getPaletteManager()->setPalette(palette, 0, 256);
@@ -1881,9 +1887,9 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
}
case 26: {
- if(_state->getFlag(FLAG_A_LA_CARCEL) == true) {
+ if (_state->getFlag(FLAG_A_LA_CARCEL) == true) {
_dialog->_goodbyeDisabled = true;
- if(_state->getFlag(FLAG_SE_HA_PUESTO_EL_MUNECO) == true) {
+ if (_state->getFlag(FLAG_SE_HA_PUESTO_EL_MUNECO) == true) {
_state->setCurrentRoot(26, 2, 1);
} else {
_dialog->say(_res->_ingameTexts[OIGAUSTED], 1);
@@ -1896,7 +1902,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
break;
}
case 30: {
- if(_state->getFlag(FLAG_ROBA_PELO_PRINCESA) == true) {
+ if (_state->getFlag(FLAG_ROBA_PELO_PRINCESA) == true) {
_dialog->_goodbyeDisabled = true;
_state->setFlag(FLAG_ROBA_PELO_PRINCESA, false);
_room->enableSprite(0, 200, PERSIST_TEMP);
Commit: 892a4db75372ff8b264f4547535a9135e9ebfa66
https://github.com/scummvm/scummvm/commit/892a4db75372ff8b264f4547535a9135e9ebfa66
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:09+02:00
Commit Message:
PELROCK: Stone pass skeleton
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 9db05d019b6..205408bfb29 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -181,6 +181,8 @@ const CombinationEntry combinationTable[] = {
{83, 461, &PelrockEngine::useDollWithBed},
{84, 503, &PelrockEngine::giveMagazineToGuard},
{86, 500, &PelrockEngine::giveWaterToGuard},
+ {91, 601, &PelrockEngine::giveStoneToSlaves},
+ {92, 601, &PelrockEngine::giveStoneToSlaves}, // Item 92 = mud/clay, same handler
// Room 35 (cauldron)
{90, 506, &PelrockEngine::magicFormula},
@@ -433,6 +435,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 367: // accept riddle
_state->setCurrentRoot(room, 27, 0);
walkAndAction(_room->findHotspotByExtra(467), TALK);
+ waitForActionEnd();
break;
// hasta aqui
@@ -564,7 +567,17 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
}
_room->disableSprite(0);
} break;
-
+ case 313:
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
+ break;
+ case 308: {
+ int targetBranch = rootIndex + 1;
+ if (targetBranch > 17) {
+ targetBranch = 3;
+ }
+ _state->setCurrentRoot(room, targetBranch, 0);
+ break;
+ }
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
@@ -1116,9 +1129,6 @@ void PelrockEngine::pickUpBook(int i) {
_alfredState.isWalkingCancelable = false;
walkAndAction(_room->findHotspotByExtra(102), TALK);
- // After dialog ends, reenable first dialog root if no photo in inventory
- // Wait for dialog to end to reenable first dialog root
- waitForActionEnd();
if (!_state->hasInventoryItem(3)) {
_state->setCurrentRoot(9, 0, 0);
@@ -1294,7 +1304,6 @@ void PelrockEngine::giveMagazineToGuard(int inventoryObject, HotSpot *hotspot) {
_state->removeInventoryItem(84);
_state->setCurrentRoot(34, 4, 0);
walkAndAction(hotspot, TALK);
- waitForActionEnd();
}
void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
@@ -1342,6 +1351,76 @@ void PelrockEngine::pickUpStone(HotSpot *hotspot) {
checkIngredients();
}
+void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
+ // Remove whichever stone item was used (91 = Egyptian stone, 92 = mud/clay)
+ _state->removeInventoryItem(inventoryObject);
+
+ // Play 7-frame 208Ã102 stone-passing animation
+ size_t frameSize = 208 * 102;
+ size_t bufSize = frameSize * 7;
+ byte *animData = new byte[bufSize];
+ _res->loadOtherSpecialAnim(1600956, false, animData, bufSize);
+
+ Graphics::Surface animSurface;
+ animSurface.create(208, 102, Graphics::PixelFormat::createFormatCLUT8());
+ int curFrame = 0;
+ while (!shouldQuit()) {
+ _events->pollEvent();
+
+ bool didRender = renderScene(OVERLAY_NONE);
+
+ memset(animSurface.getPixels(), 0, frameSize);
+ extractSingleFrame(animData, (byte *)animSurface.getPixels(), curFrame, 208, 102);
+ _screen->transBlitFrom(animSurface, Common::Point(0, 298), 255);
+ if (didRender && _chrono->getFrameCount() % 2 == 0) {
+ curFrame++;
+
+ if (curFrame >= 7) {
+ break;
+ }
+ }
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+ animSurface.free();
+ delete[] animData;
+
+ //play some sound
+
+ _dialog->say(_res->_ingameTexts[HAYQUECELEBRARLO]);
+
+ // TODO: wait for slave sprite frame 6 animation (sprite index derived from
+ // play drinking animation
+ // room_sprite_data_ptr + sprite_id * 0x2C, then poll +0x20 == 6)
+
+ // Increment stone delivery counter (tracks 0â1â2â3)
+ byte counter = _state->getFlag(FLAG_DA_PIEDRA);
+ debug("Current stone delivery count: %d", counter);
+ if (counter < 3) {
+ _state->setFlag(FLAG_DA_PIEDRA, ++counter);
+ }
+
+ // At 2nd stone delivery: slave starts singing (conversation root 2)
+ // Root 2 text: "¡Deesde Santuurce a Bilbaooo...!"
+ if (counter == 2) {
+ _state->setCurrentRoot(41, 2, 0);
+ }
+
+ // At 3rd stone delivery: pyramid is complete
+ if (counter == 3) {
+ _room->disableSprite(0);
+ // Render permanent pyramid sticker (ALFRED.6 offset 0x0696AD = sticker index 116)
+ _room->addSticker(116, PERSIST_PERM);
+
+ // TODO: add 5 walkboxes for completed pyramid layout (write_data_to_alfred1 Ã4)
+ // Original game writes walkbox countâ5 and walkbox data to ALFRED.1 room 41.
+ // Walkbox coordinates TBD from binary analysis.
+
+ // Mark pyramid quest complete
+ _state->setFlag(FLAG_PIEDRAS_COGIDAS, true);
+ }
+}
+
/**
* Naked girls swim underwater, guard enters the scene.
* "diving" animation is stored in Alfred.7 as a single RLE chunk with multiple continuous sprite sizes.
@@ -1425,7 +1504,6 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
guard->animData[0].nframes = 1;
_alfredState.direction = ALFRED_RIGHT;
walkAndAction(_room->findHotspotByExtra(guard->extra), TALK);
- waitForActionEnd();
if(shouldQuit()) {
return;
}
@@ -1434,7 +1512,6 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
_alfredState.y = 385;
setScreen(40, ALFRED_UP);
walkAndAction(_room->findHotspotByExtra(640), TALK);
- waitForActionEnd();
if(shouldQuit()) {
return;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 38d35f7b930..fb8a69fa81b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1574,6 +1574,7 @@ void PelrockEngine::walkAndAction(HotSpot *hotspot, VerbIcon action) {
_disableAction = true;
walkTo(hotspot->x + hotspot->w / 2, hotspot->y + hotspot->h);
_queuedAction = QueuedAction{action, hotspot->index, true};
+ waitForActionEnd();
}
AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 711e6bbafe9..6ee7d0cbe31 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -346,6 +346,7 @@ public:
void giveMagazineToGuard(int inventoryObject, HotSpot *hotspot);
void giveWaterToGuard(int inventoryObject, HotSpot *hotspot);
void pickUpStone(HotSpot *hotspot);
+ void giveStoneToSlaves(int inventoryObject, HotSpot *hotspot);
void swimmingPoolCutscene(HotSpot *hotspot);
void magicFormula(int inventoryObject, HotSpot *hotspot);
void checkAllSymbols();
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 0e99b0359fa..ab39d0b955f 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -248,6 +248,10 @@ void ResourceManager::loadOtherSpecialAnim(uint32 offset, bool rleCompressed, by
readUntilBuda(&alfred7, offset, compressed, compressedSize);
bufferSize = rleDecompress(compressed, compressedSize, 0, 0, &buffer, true);
}
+ else {
+ alfred7.seek(offset, SEEK_SET);
+ alfred7.read(buffer, bufferSize);
+ }
alfred7.close();
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index b098259c4b9..6f0e99fe3ae 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -475,6 +475,7 @@ struct ResetEntry {
#define FLAG_SE_HA_PUESTO_EL_MUNECO 20
#define FLAG_VIGILANTE_BEBE_AGUA 21
#define FLAG_FORMULA_MAGICA 26
+#define FLAG_DA_PIEDRA 31
@@ -489,7 +490,6 @@ struct ResetEntry {
#define FLAG_APARECE_EUNUCO 28
#define FLAG_AL_FARAON 29
#define FLAG_A_CURRAR 30
-#define FLAG_DA_PIEDRA 31
#define FLAG_PIEDRAS_COGIDAS 32
#define FLAG_GUARDIAS_BORRACHOS 33
#define FLAG_PIEDRA_FAKE_MOJADA 34
Commit: 82bcbdcdacea9d7b6da0923369d611825a390046
https://github.com/scummvm/scummvm/commit/82bcbdcdacea9d7b6da0923369d611825a390046
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:09+02:00
Commit Message:
PELROCK: Implements cutscenes in room 41
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/sound.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 205408bfb29..d44e2e3870a 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -37,6 +37,8 @@ const ActionEntry actionTable[] = {
// Room 0
{261, OPEN, &PelrockEngine::openRoomDrawer},
{261, CLOSE, &PelrockEngine::closeRoomDrawer},
+ {263, OPEN, &PelrockEngine::openClosedDrawer},
+
{268, OPEN, &PelrockEngine::openRoomDoor},
{268, CLOSE, &PelrockEngine::closeRoomDoor},
{3, PICKUP, &PelrockEngine::pickUpPhoto},
@@ -666,6 +668,10 @@ void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
_room->enableHotspot(hotspot);
}
+void PelrockEngine::openClosedDrawer(HotSpot *hotspot) {
+ _dialog->say(_res->_ingameTexts[ESTAN_CERRADOS]);
+}
+
void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
debug("Withdrawing money from ATM using card (inv obj %d)", inventoryObject);
if (_state->getFlag(FLAG_JEFE_INGRESA_PASTA)) {
@@ -1080,13 +1086,7 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
_alfredState.y += 20;
waitForSpecialAnimation();
_sound->playSound(_room->_roomSfx[0], 0); // Belch
- bool isPlaying = true;
- while (!shouldQuit() && isPlaying) {
- _events->pollEvent();
- isPlaying = _sound->isPlaying(0);
- _screen->update();
- g_system->delayMillis(10);
- }
+ waitForSoundEnd();
_graphics->fadeToBlack(10);
// update conversaton state
_alfredState.x = 300;
@@ -1095,6 +1095,15 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[QUEOSCUROESTAESTO]);
}
+void PelrockEngine::waitForSoundEnd() {
+ while (!shouldQuit() && _sound->isPlaying(0)) {
+ _events->pollEvent();
+ renderScene(OVERLAY_NONE);
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+}
+
void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
if (_state->getFlag(FLAG_PARADOJA_RESUELTA) == false) {
_dialog->say(_res->_ingameTexts[OIGA]);
@@ -1351,47 +1360,68 @@ void PelrockEngine::pickUpStone(HotSpot *hotspot) {
checkIngredients();
}
-void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
- // Remove whichever stone item was used (91 = Egyptian stone, 92 = mud/clay)
- _state->removeInventoryItem(inventoryObject);
-
- // Play 7-frame 208Ã102 stone-passing animation
- size_t frameSize = 208 * 102;
- size_t bufSize = frameSize * 7;
+void PelrockEngine::playSpecialAnim(uint32 offset, bool compressed, int x, int y, int width, int height, int numFrames) {
+ size_t frameSize = width * height;
+ debug("Frame size: %d bytes", frameSize);
+ size_t bufSize = frameSize * numFrames;
byte *animData = new byte[bufSize];
- _res->loadOtherSpecialAnim(1600956, false, animData, bufSize);
+ _res->loadOtherSpecialAnim(offset, compressed, animData, bufSize);
Graphics::Surface animSurface;
- animSurface.create(208, 102, Graphics::PixelFormat::createFormatCLUT8());
+ animSurface.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
int curFrame = 0;
+ bool firstFrame = true;
while (!shouldQuit()) {
_events->pollEvent();
bool didRender = renderScene(OVERLAY_NONE);
-
- memset(animSurface.getPixels(), 0, frameSize);
- extractSingleFrame(animData, (byte *)animSurface.getPixels(), curFrame, 208, 102);
- _screen->transBlitFrom(animSurface, Common::Point(0, 298), 255);
- if (didRender && _chrono->getFrameCount() % 2 == 0) {
- curFrame++;
-
- if (curFrame >= 7) {
- break;
+ if(didRender) {
+ memset(animSurface.getPixels(), 0, frameSize);
+ extractSingleFrame(animData, (byte *)animSurface.getPixels(), curFrame, width, height);
+ _screen->transBlitFrom(animSurface, Common::Point(x, y), 255);
+ if (_chrono->getFrameCount() % 2 == 0) {
+ curFrame++;
+ if (curFrame >= numFrames) {
+ _screen->markAllDirty();
+ _screen->update();
+ break;
+ }
}
}
+ _screen->markAllDirty();
_screen->update();
+ // _events->waitForKey();
g_system->delayMillis(10);
}
animSurface.free();
delete[] animData;
- //play some sound
+}
+
+void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
+ // Remove whichever stone item was used (91 = Egyptian stone, 92 = mud/clay)
+ _state->removeInventoryItem(inventoryObject);
+
+ Sprite *masters = _room->findSpriteByExtra(600);
+ byte zIndex = masters->zOrder;
+ // Capture coordinates now, before any playSpecialAnim loop runs renderScene and
+ // sortAnimsByZOrder reorders _currentRoomAnims (which would make the pointer stale).
+ int16 mastersX = masters->x;
+ int16 mastersY = masters->y;
+
+ // Slaves take stone then chant
+ playSpecialAnim(1600956, false, 0, 298, 208, 102, 7);
+ _sound->playSound(_room->_roomSfx[0], 0);
+ // waitForSoundEnd();
_dialog->say(_res->_ingameTexts[HAYQUECELEBRARLO]);
- // TODO: wait for slave sprite frame 6 animation (sprite index derived from
- // play drinking animation
- // room_sprite_data_ptr + sprite_id * 0x2C, then poll +0x20 == 6)
+
+ //drinking animation and sound
+ _sound->playSound(_room->_roomSfx[1], 0);
+
+ _room->disableSprite(0);
+ playSpecialAnim(1473360, true, mastersX - 5, mastersY - 1, 152, 83, 7);
// Increment stone delivery counter (tracks 0â1â2â3)
byte counter = _state->getFlag(FLAG_DA_PIEDRA);
@@ -1400,25 +1430,26 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
_state->setFlag(FLAG_DA_PIEDRA, ++counter);
}
- // At 2nd stone delivery: slave starts singing (conversation root 2)
- // Root 2 text: "¡Deesde Santuurce a Bilbaooo...!"
+ // At 2nd stone delivery: masters starts singing (conversation root 2)
if (counter == 2) {
_state->setCurrentRoot(41, 2, 0);
}
- // At 3rd stone delivery: pyramid is complete
+ // At 3rd stone delivery: masters get wasted
if (counter == 3) {
- _room->disableSprite(0);
- // Render permanent pyramid sticker (ALFRED.6 offset 0x0696AD = sticker index 116)
- _room->addSticker(116, PERSIST_PERM);
+ playSpecialAnim(1512060, true, mastersX - 28, mastersY - 6, 172, 96, 3);
- // TODO: add 5 walkboxes for completed pyramid layout (write_data_to_alfred1 Ã4)
- // Original game writes walkbox countâ5 and walkbox data to ALFRED.1 room 41.
- // Walkbox coordinates TBD from binary analysis.
+ _room->addSticker(116);
- // Mark pyramid quest complete
+ WalkBox w1 = {3, 187, 374, 5, 17};
+ WalkBox w2 = {4, 141, 374, 46, 4};
+ _room->addWalkbox(w1);
+ _room->addWalkbox(w2);
_state->setFlag(FLAG_PIEDRAS_COGIDAS, true);
}
+ else {
+ _room->enableSprite(0, zIndex);
+ }
}
/**
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index fb8a69fa81b..633d3d5878a 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -157,7 +157,7 @@ void PelrockEngine::init() {
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
- setScreen(39, ALFRED_DOWN);
+ setScreen(41, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -302,7 +302,14 @@ bool PelrockEngine::renderScene(int overlayMode) {
updatePaletteAnimations();
- _screen->markAllDirty();
+ // Execute deferred actions AFTER renderScene, so any scene changes
+ // (addSticker, disableSprite, etc.) are in place before the next frame's
+ // placeStickersFirstPass + presentFrame.
+ if (_queuedAction.readyToExecute) {
+ _queuedAction.readyToExecute = false;
+ doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
+ }
+
return true;
}
@@ -521,7 +528,7 @@ void PelrockEngine::checkMouse() {
useOnAlfred(_state->selectedInventoryItem);
} else {
// Released outside popup - just close it
- _queuedAction = QueuedAction{NO_ACTION, -1, false};
+ _queuedAction = QueuedAction{NO_ACTION, -1, false, false};
_currentHotspot = nullptr;
}
} else if (_events->_leftMouseClicked) {
@@ -559,6 +566,7 @@ void PelrockEngine::updateAnimations() {
// First pass: sprites behind Alfred (sprite zOrder > alfredZOrder)
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].zOrder > alfredZOrder || _room->_currentRoomAnims[i].zOrder < 0) {
+ // debug("Drawing anim %d with zOrder %d in first pass (behind Alfred)", i, _room->_currentRoomAnims[i].zOrder);
drawNextFrame(&_room->_currentRoomAnims[i]);
}
}
@@ -569,6 +577,7 @@ void PelrockEngine::updateAnimations() {
// Second pass: sprites in front of Alfred (sprite zOrder <= alfredZOrder)
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].zOrder <= alfredZOrder && _room->_currentRoomAnims[i].zOrder >= 0) {
+ // debug("Drawing anim %d with zOrder %d in second pass (in front of Alfred)", i, _room->_currentRoomAnims[i].zOrder);
drawNextFrame(&_room->_currentRoomAnims[i]);
}
}
@@ -602,10 +611,10 @@ void PelrockEngine::paintDebugLayer() {
bool showWalkboxes = true;
if (showWalkboxes) {
+ debug("Drawing walkboxes, count: %d", _room->_currentRoomWalkboxes.size());
for (uint i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
WalkBox box = _room->_currentRoomWalkboxes[i];
- drawRect(_screen, box.x, box.y, box.w, box.h, 150 + i);
- // _smallFont->drawString(_screen, Common::String::format("%d", i), box.x + 2, box.y + 2, 640, 14);
+ drawRect(_screen, box.x, box.y, box.w, box.h, 13);
}
}
@@ -613,6 +622,10 @@ void PelrockEngine::paintDebugLayer() {
if (showSprites) {
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
Sprite sprite = _room->_currentRoomAnims[i];
+ if(sprite.zOrder < 0) {
+ // Skip sprites with negative zOrder (not rendered)
+ continue;
+ }
drawRect(_screen, sprite.x, sprite.y, sprite.w, sprite.h, 14);
_smallFont->drawString(_screen, Common::String::format("S %d", sprite.index), sprite.x + 2, sprite.y, 640, 14);
}
@@ -880,9 +893,10 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (_queuedAction.isQueued) {
// look and talk execute immediately, others need interaction animation first
if (_queuedAction.verb == TALK || _queuedAction.verb == LOOK) {
+ // Defer to after renderScene so any scene changes (stickers,
+ // sprites) take effect before the next presentFrame.
_queuedAction.isQueued = false;
- HotSpot *actionHotspot = &_room->_currentRoomHotspots[_queuedAction.hotspotIndex];
- doAction(_queuedAction.verb, actionHotspot);
+ _queuedAction.readyToExecute = true;
break;
}
_alfredState.setState(ALFRED_INTERACTING);
@@ -941,9 +955,11 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.curFrame++;
if (_alfredState.curFrame >= interactingAnimLength) {
if (_queuedAction.isQueued) {
+ // Defer to after renderScene so any scene changes (stickers,
+ // sprites) take effect before the next presentFrame.
_queuedAction.isQueued = false;
+ _queuedAction.readyToExecute = true;
_alfredState.setState(ALFRED_IDLE);
- doAction(_queuedAction.verb, &_room->_currentRoomHotspots[_queuedAction.hotspotIndex]);
break;
}
}
@@ -1495,28 +1511,30 @@ void PelrockEngine::gameLoop() {
_events->pollEvent();
checkMouse();
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_m) {
- travelToEgypt();
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_n) {
- loadExtraScreenAndPresent(10);
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_p) {
- antiPiracyEffect();
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_s) {
- SpellBook spellBook(_events, _res);
- Spell *selectedSpell = spellBook.run();
- if (selectedSpell != nullptr) {
- _dialog->sayAlfred(selectedSpell->text);
- }
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
+
+ // if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_m) {
+ // travelToEgypt();
+ // _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ // }
+ // if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_n) {
+ // loadExtraScreenAndPresent(10);
+ // _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ // }
+ // if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_p) {
+ // antiPiracyEffect();
+ // _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ // }
+ // if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_s) {
+ // SpellBook spellBook(_events, _res);
+ // Spell *selectedSpell = spellBook.run();
+ // if (selectedSpell != nullptr) {
+ // _dialog->sayAlfred(selectedSpell->text);
+ // }
+ // _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ // }
+
renderScene();
- // _events->waitForKey();
+
_screen->update();
}
@@ -1573,7 +1591,7 @@ void PelrockEngine::walkTo(int x, int y) {
void PelrockEngine::walkAndAction(HotSpot *hotspot, VerbIcon action) {
_disableAction = true;
walkTo(hotspot->x + hotspot->w / 2, hotspot->y + hotspot->h);
- _queuedAction = QueuedAction{action, hotspot->index, true};
+ _queuedAction = QueuedAction{action, hotspot->index, true, false};
waitForActionEnd();
}
@@ -1658,7 +1676,7 @@ bool PelrockEngine::isAlfredUnder(int x, int y) {
void PelrockEngine::checkMouseClick(int x, int y) {
// This handles regular clicks (not popup selection)
- _queuedAction = QueuedAction{NO_ACTION, -1, false};
+ _queuedAction = QueuedAction{NO_ACTION, -1, false, false};
_actionPopupState.isActive = false;
_currentHotspot = nullptr;
_alfredState.idleFrameCounter = 0;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 6ee7d0cbe31..508dca0945d 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -138,7 +138,7 @@ private:
int _newItem = -1;
Common::Point _curWalkTarget;
- QueuedAction _queuedAction;
+ QueuedAction _queuedAction = {NO_ACTION, -1, false, false};
bool showShadows = false;
@@ -257,6 +257,7 @@ public:
void executeAction(VerbIcon action, HotSpot *hotspot);
void openRoomDrawer(HotSpot *hotspot);
void closeRoomDrawer(HotSpot *hotspot);
+ void openClosedDrawer(HotSpot *hotspot);
void openRoomDoor(HotSpot *hotspot);
void closeRoomDoor(HotSpot *hotspot);
void pickUpAndDisable(HotSpot *hotspot);
@@ -322,6 +323,7 @@ public:
void openTravelAgencyDoor(HotSpot *hotspot);
void closeTravelAgencyDoor(HotSpot *hotspot);
void usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot);
+ void waitForSoundEnd();
void pickupSunflower(HotSpot *hotspot);
void checkIngredients();
void pickUpBook(int i);
@@ -346,6 +348,7 @@ public:
void giveMagazineToGuard(int inventoryObject, HotSpot *hotspot);
void giveWaterToGuard(int inventoryObject, HotSpot *hotspot);
void pickUpStone(HotSpot *hotspot);
+ void playSpecialAnim(uint32 offset, bool compressed, int x, int y, int width, int height, int numFrames);
void giveStoneToSlaves(int inventoryObject, HotSpot *hotspot);
void swimmingPoolCutscene(HotSpot *hotspot);
void magicFormula(int inventoryObject, HotSpot *hotspot);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 72822cd3a02..4f00a6d10d9 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -228,8 +228,14 @@ void RoomManager::disableSprite(byte roomNumber, byte spriteIndex, int persist)
debug("Disabling sprite %d in room %d with persist %d", spriteIndex, roomNumber, persist);
if (roomNumber == _currentRoomNumber && persist & PERSIST_TEMP) {
debug("Disabling sprite LOCALLY %d in room %d with persist %d", spriteIndex, roomNumber, persist);
- _currentRoomAnims[spriteIndex].zOrder = -1;
- _currentRoomAnims[spriteIndex].isHotspotDisabled = true;
+ // Search by sprite.index, not by array position: sortAnimsByZOrder reorders the
+ // array every frame so a raw array index is unreliable.
+ for (uint i = 0; i < _currentRoomAnims.size(); i++) {
+ if (_currentRoomAnims[i].index == spriteIndex) {
+ _currentRoomAnims[i].zOrder = -1;
+ break;
+ }
+ }
}
if (persist & PERSIST_PERM) {
g_engine->_state->spriteChanges[roomNumber].push_back({roomNumber, spriteIndex, 255});
@@ -242,7 +248,13 @@ void RoomManager::enableSprite(byte spriteIndex, byte zOrder, int persist) {
void RoomManager::enableSprite(byte roomNumber, byte spriteIndex, byte zOrder, int persist) {
if (roomNumber == _currentRoomNumber && persist & PERSIST_TEMP) {
- _currentRoomAnims[spriteIndex].zOrder = zOrder;
+ // Search by sprite.index field, not by array position (array is re-sorted every frame).
+ for (uint i = 0; i < _currentRoomAnims.size(); i++) {
+ if (_currentRoomAnims[i].index == spriteIndex) {
+ _currentRoomAnims[i].zOrder = zOrder;
+ break;
+ }
+ }
}
if (persist & PERSIST_PERM) {
g_engine->_state->spriteChanges[roomNumber].push_back({roomNumber, spriteIndex, zOrder});
@@ -312,6 +324,15 @@ Sprite *RoomManager::findSpriteByIndex(byte index) {
return nullptr;
}
+Sprite *RoomManager::findSpriteByExtra(int16 extra) {
+ for (uint i = 0; i < _currentRoomAnims.size(); i++) {
+ if (_currentRoomAnims[i].extra == extra) {
+ return &_currentRoomAnims[i];
+ }
+ }
+ return nullptr;
+}
+
HotSpot *RoomManager::findHotspotByIndex(byte index) {
for (uint i = 0; i < _currentRoomHotspots.size(); i++) {
if (!_currentRoomHotspots[i].isSprite && _currentRoomHotspots[i].innerIndex == index) {
@@ -923,6 +944,9 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
anim.curFrame = 0;
anim.nframes = data[subAnimOffset + j];
+ if (_currentRoomNumber == 41 && i == 1) {
+ anim.nframes = 3;
+ }
anim.loopCount = data[subAnimOffset + 4 + j];
anim.speed = data[subAnimOffset + 8 + j];
anim.movementFlags = data[subAnimOffset + 14 + (j * 2)] | (data[subAnimOffset + 14 + (j * 2) + 1] << 8);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 7197ece76d7..f807b91a233 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -123,6 +123,7 @@ public:
return true;
}
Sprite *findSpriteByIndex(byte index);
+ Sprite *findSpriteByExtra(int16 extra);
HotSpot *findHotspotByIndex(byte index);
HotSpot *findHotspotByExtra(uint16 extra);
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 6eee91a28e4..cee1f3675ca 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -53,7 +53,7 @@ void SoundManager::playSound(byte index, int channel) {
// debug("Playing sound index %d (%s)", index, SOUND_FILENAMES[index]);
auto it = _soundMap.find(SOUND_FILENAMES[index]);
if (it != _soundMap.end()) {
- playSound(it->_value);
+ playSound(it->_value, channel);
} else {
debug("Sound file %s not found in sound map", SOUND_FILENAMES[index]);
}
@@ -62,7 +62,7 @@ void SoundManager::playSound(byte index, int channel) {
void SoundManager::playSound(const char *filename, int channel) {
auto it = _soundMap.find(filename);
if (it != _soundMap.end()) {
- playSound(it->_value);
+ playSound(it->_value, channel);
} else {
debug("Sound file %s not found in sound map", filename);
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 6f0e99fe3ae..0a790393cf0 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -303,7 +303,8 @@ struct WalkBox {
struct QueuedAction {
VerbIcon verb;
int hotspotIndex;
- bool isQueued;
+ bool isQueued; // Alfred is walking/interacting toward the target
+ bool readyToExecute; // Animation done - execute after the current renderScene
};
struct ScalingParams {
@@ -332,7 +333,6 @@ struct SpriteChange
byte roomNumber;
byte spriteIndex;
byte zIndex;
-
};
Commit: 831355caa204e883c3c82723b494f63d6295a89b
https://github.com/scummvm/scummvm/commit/831355caa204e883c3c82723b494f63d6295a89b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:09+02:00
Commit Message:
PELROCK: Implements rooms 43, 44, 45
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/pathfinding.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index d44e2e3870a..a1d10a52ba8 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -153,6 +153,16 @@ const ActionEntry actionTable[] = {
// Room 39
{700, PICKUP, &PelrockEngine::swimmingPoolCutscene},
+
+ // Room 41
+ {605, PICKUP, &PelrockEngine::pickUpStones},
+ {606, PICKUP, &PelrockEngine::pickUpStones},
+ {607, PICKUP, &PelrockEngine::pickUpStones},
+ {608, PICKUP, &PelrockEngine::pickUpMud},
+
+ // Room 44
+ {613, OPEN, &PelrockEngine::openPyramidDoor},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -191,6 +201,10 @@ const CombinationEntry combinationTable[] = {
{85, 506, &PelrockEngine::magicFormula},
{86, 506, &PelrockEngine::magicFormula},
{81, 506, &PelrockEngine::magicFormula},
+
+ {76, 617, &PelrockEngine::usePumpkinWithPond},
+
+ {86, 614, &PelrockEngine::useWaterOnFakeStone},
// End marker
{WILDCARD, WILDCARD, nullptr}};
@@ -327,10 +341,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 279:
travelToEgypt();
break;
- // moros
- case 317:
- addInventoryItem(95);
- break;
+ // moros
case 330:
// Two oranges
@@ -580,6 +591,49 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(room, targetBranch, 0);
break;
}
+ /* pyramid merchant*/
+ case 314:
+ addInventoryItem(93);
+ break;
+ case 316:
+ addInventoryItem(94);
+ break;
+ case 317:
+ // CD
+ addInventoryItem(95);
+ break;
+ case 318:
+ // bg book
+ addInventoryItem(96);
+ break;
+ case 319:
+ // add pyramid map
+ addInventoryItem(97);
+ _state->setCurrentRoot(room, 2, 0);
+ break;
+ case 320:
+ _state->setCurrentRoot(room, 2, 0);
+ break;
+ case 324:
+ // ?
+ break;
+ // girls in pond
+ case 321:
+ _state->setCurrentRoot(45, 1, 0);
+ _sound->playSound("TWANGZZZ.SMP", 0);
+ break;
+ case 376: {
+ _res->loadAlfredSpecialAnim(14);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ loadExtraScreenAndPresent(12);
+ _state->setCurrentRoot(45, 2, 0);
+ } break;
+ case 377:
+ _state->setCurrentRoot(45, 3, 0);
+ break;
+ case 30840:
+ break;
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
@@ -1375,7 +1429,7 @@ void PelrockEngine::playSpecialAnim(uint32 offset, bool compressed, int x, int y
_events->pollEvent();
bool didRender = renderScene(OVERLAY_NONE);
- if(didRender) {
+ if (didRender) {
memset(animSurface.getPixels(), 0, frameSize);
extractSingleFrame(animData, (byte *)animSurface.getPixels(), curFrame, width, height);
_screen->transBlitFrom(animSurface, Common::Point(x, y), 255);
@@ -1395,7 +1449,6 @@ void PelrockEngine::playSpecialAnim(uint32 offset, bool compressed, int x, int y
}
animSurface.free();
delete[] animData;
-
}
void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
@@ -1412,12 +1465,11 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
// Slaves take stone then chant
playSpecialAnim(1600956, false, 0, 298, 208, 102, 7);
_sound->playSound(_room->_roomSfx[0], 0);
- // waitForSoundEnd();
+ waitForSoundEnd();
_dialog->say(_res->_ingameTexts[HAYQUECELEBRARLO]);
-
- //drinking animation and sound
+ // drinking animation and sound
_sound->playSound(_room->_roomSfx[1], 0);
_room->disableSprite(0);
@@ -1429,7 +1481,7 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
if (counter < 3) {
_state->setFlag(FLAG_DA_PIEDRA, ++counter);
}
-
+ debug("New stone delivery count: %d", _state->getFlag(FLAG_DA_PIEDRA));
// At 2nd stone delivery: masters starts singing (conversation root 2)
if (counter == 2) {
_state->setCurrentRoot(41, 2, 0);
@@ -1445,9 +1497,9 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
WalkBox w2 = {4, 141, 374, 46, 4};
_room->addWalkbox(w1);
_room->addWalkbox(w2);
- _state->setFlag(FLAG_PIEDRAS_COGIDAS, true);
- }
- else {
+ _state->setFlag(FLAG_GUARDIAS_BORRACHOS, true);
+ } else {
+ debug("Re-enabling master sprite with zIndex %d", zIndex);
_room->enableSprite(0, zIndex);
}
}
@@ -1535,7 +1587,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
guard->animData[0].nframes = 1;
_alfredState.direction = ALFRED_RIGHT;
walkAndAction(_room->findHotspotByExtra(guard->extra), TALK);
- if(shouldQuit()) {
+ if (shouldQuit()) {
return;
}
_graphics->fadeToBlack(10);
@@ -1543,7 +1595,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
_alfredState.y = 385;
setScreen(40, ALFRED_UP);
walkAndAction(_room->findHotspotByExtra(640), TALK);
- if(shouldQuit()) {
+ if (shouldQuit()) {
return;
}
_graphics->fadeToBlack(10);
@@ -1552,6 +1604,67 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
setScreen(41, ALFRED_UP);
}
+void PelrockEngine::pickUpStones(HotSpot *hotspot) {
+ if (_state->hasInventoryItem(91)) {
+ _dialog->say(_res->_ingameTexts[PESADEMASIADO]);
+ return;
+ }
+ if (_state->getFlag(FLAG_PIEDRAS_COGIDAS) >= 2) {
+ _dialog->say(_res->_ingameTexts[NINGUNATAMANHOAPROPIADO]);
+ return;
+ } else {
+ addInventoryItem(91);
+ _state->setFlag(FLAG_PIEDRAS_COGIDAS, _state->getFlag(FLAG_PIEDRAS_COGIDAS) + 1);
+ debug("Piedras cogidas: %d", _state->getFlag(FLAG_PIEDRAS_COGIDAS));
+ }
+}
+
+void PelrockEngine::pickUpMud(HotSpot *hotspot) {
+ if (_state->getFlag(FLAG_PIEDRAS_COGIDAS) != 2) {
+ _dialog->say(_res->_ingameTexts[PARAQUECOGERBARRO]);
+ return;
+ } else {
+ addInventoryItem(92);
+ _state->setFlag(FLAG_PIEDRAS_COGIDAS, _state->getFlag(FLAG_PIEDRAS_COGIDAS) + 1);
+ _dialog->say(_res->_ingameTexts[BUENOCOGEREUNPOCO]);
+ }
+}
+
+void PelrockEngine::openPyramidDoor(HotSpot *hotspot) {
+ _dialog->say(_res->_ingameTexts[ABSOLUTAMENTECERRADO]);
+}
+
+void PelrockEngine::usePumpkinWithPond(int inventoryObject, HotSpot *hotspot) {
+ _state->removeInventoryItem(76);
+ addInventoryItem(86);
+}
+
+void PelrockEngine::useWaterOnFakeStone(int inventoryObject, HotSpot *hotspot) {
+
+ int count = _state->getFlag(FLAG_PIEDRA_FAKE_MOJADA);
+ if(count != 3) {
+ _state->removeInventoryItem(86);
+ addInventoryItem(76);
+ switch (count)
+ {
+ case 0:
+ _room->addSticker(120);
+ break;
+ case 1:
+ _room->addSticker(121);
+ break;
+ case 2:
+ _room->addSticker(122);
+ _room->enableExit(1);
+ break;
+ default:
+ break;
+ }
+ count++;
+ _state->setFlag(FLAG_PIEDRA_FAKE_MOJADA, count);
+ }
+}
+
void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
_state->removeInventoryItem(inventoryObject);
_state->setFlag(FLAG_FORMULA_MAGICA, _state->getFlag(FLAG_FORMULA_MAGICA) + 1);
@@ -1768,6 +1881,15 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
loadExtraScreenAndPresent(7);
break;
}
+ case 97: {
+ _res->loadAlfredSpecialAnim(1);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ loadExtraScreenAndPresent(11);
+ _dialog->say(_res->_ingameTexts[MEHANTOMADO_EL_PELO]);
+ _state->setCurrentRoot(43, 1, 0);
+ break;
+ }
default:
break;
}
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 0c35e16c060..60b7a9a83cf 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -210,7 +210,7 @@ enum TextIndices {
CAPITULOPARADOJAS,
HAYQUECELEBRARLO,
PESADEMASIADO,
- NINGUNATEMAAPROPIADO,
+ NINGUNATAMANHOAPROPIADO,
PARAQUECOGERBARRO,
BUENOCOGEREUNPOCO,
ABSOLUTAMENTECERRADO,
@@ -445,39 +445,49 @@ struct ExtraImages {
};
const ExtraImages extraScreens[] = {
- {0x00, // Portrait above bed
+ {0x00, // 0 - Portrait above bed
0x7984,
8},
- {0x1A9EE, // Computer screen
+ {0x1A9EE, // 1 - Computer screen
0x305A2,
8},
- {0x647C3, // Alfred circle
+ {0x647C3, // 2 - Alfred circle
0x7B6B1,
4},
- {0x6FBCD, // Recipe
+ {0x6FBCD, // 3 - Recipe
0x7B6B1,
8},
- {0x7BA11, // Newspaper
+ {0x7BA11, // 4 - Newspaper
0x88745,
8},
- {0x9237B, // tablet
+ {0x9237B, // 5 - tablet
0xB0EE7,
8},
- {0x000B11F1, // map
+ {0x000B11F1, // 6 - map
0xDE011,
8},
- {0xFFC47, // girl book
+ {0xFFC47, // 7 - girl book
0x1180C9,
8},
- {1147849,
+ {1147849, // 8 - unknown
1267955,
8},
- {0x152A88, // portrait
+ {0x152A88, // 9 - portrait
0x15BFC8,
8},
- {2727564, // CD
+ {2727564, // 10 - CD
2833276,
- 8}};
+ 8},
+ {
+ 2834044, // 11 - pyramid map
+ 2971800,
+ 8},
+ {
+ 2306538, // 12 - CENSORED
+ 2321064,
+ 8
+ },
+};
struct AlfredSpecialAnimOffset {
int numFrames = 0;
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
index d141bb3af21..e7a89c34818 100644
--- a/engines/pelrock/pathfinding.cpp
+++ b/engines/pelrock/pathfinding.cpp
@@ -103,7 +103,7 @@ bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<
context->pathLength = buildWalkboxPath(walkboxes, startBox, destBox, context->pathBuffer);
debug("Walkbox path to point");
for (int i = 0; i < context->pathLength; i++) {
- debug("Walkbox %d: %d", i, context->pathBuffer[i]);
+ // debug("Walkbox %d: %d", i, context->pathBuffer[i]);
}
if (context->pathLength == 0) {
debug("Error: No path found\n");
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 633d3d5878a..a2424d910fa 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -157,7 +157,8 @@ void PelrockEngine::init() {
// setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
- setScreen(41, ALFRED_DOWN);
+ // setScreen(41, ALFRED_DOWN);
+ setScreen(43, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -611,7 +612,6 @@ void PelrockEngine::paintDebugLayer() {
bool showWalkboxes = true;
if (showWalkboxes) {
- debug("Drawing walkboxes, count: %d", _room->_currentRoomWalkboxes.size());
for (uint i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
WalkBox box = _room->_currentRoomWalkboxes[i];
drawRect(_screen, box.x, box.y, box.w, box.h, 13);
@@ -1198,6 +1198,10 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
int frameSize = sprite->stride;
int curFrame = animData.curFrame;
+ if(curFrame >= animData.nframes) {
+ debug("Warning: curFrame %d exceeds nframes %d for sprite %d anim %d", curFrame, animData.nframes, sprite->index, sprite->curAnimIndex);
+ curFrame = 0;
+ }
drawSpriteToBuffer(_compositeBuffer, 640, animData.animData[curFrame], x, y, w, h, 255);
// Original in the game: increment FIRST, then check (not check-then-increment)
@@ -1721,7 +1725,8 @@ void PelrockEngine::checkMouseHover() {
if (hotspotIndex != -1) {
hotspotDetected = true;
- _hoveredMapLocation = _room->_currentRoomDescriptions[hotspotIndex].text;
+ if(hotspotIndex < _room->_currentRoomDescriptions.size())
+ _hoveredMapLocation = _room->_currentRoomDescriptions[hotspotIndex].text;
} else if (!alfredDetected) {
_hoveredMapLocation = "";
}
@@ -1939,6 +1944,16 @@ void PelrockEngine::doExtraActions(int roomNumber) {
case 48:
_dialog->_goodbyeDisabled = true;
break;
+ case 10:{
+ // _events->waitForKey();
+ // while(!shouldQuit()) {
+ // playSpecialAnim(212915, true, 287, 152, 62, 58, 10);
+ // playSpecialAnim(236645, true, 287, 152, 62, 58, 10);
+ // // setScreen(11, ALFRED_DOWN);
+ // playSpecialAnim(261449, true, 0, 223, 64, 97, 8);
+ // }
+ break;
+ }
default:
break;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 508dca0945d..5acb31eb49f 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -351,6 +351,11 @@ public:
void playSpecialAnim(uint32 offset, bool compressed, int x, int y, int width, int height, int numFrames);
void giveStoneToSlaves(int inventoryObject, HotSpot *hotspot);
void swimmingPoolCutscene(HotSpot *hotspot);
+ void pickUpStones(HotSpot *hotspot);
+ void pickUpMud(HotSpot *hotspot);
+ void openPyramidDoor(HotSpot *hotspot);
+ void usePumpkinWithPond(int inventoryObject, HotSpot *hotspot);
+ void useWaterOnFakeStone(int inventoryObject, HotSpot *hotspot);
void magicFormula(int inventoryObject, HotSpot *hotspot);
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index ab39d0b955f..935651fa54a 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -51,6 +51,7 @@ const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
{23, 116, 124, 1, 7, 2060916, 1}, // 11 - Munheco 1
{18, 177, 124, 1, 7, 2115632, 1}, // 12 - Munheco 2
{11, 98, 138, 1, 7, 1526432, 1}, // 13 - Munheco 3
+ {4, 51, 102, 1, 7, 2972568, 1}, // 14 - descamisa
};
ResourceManager::~ResourceManager() {
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 4f00a6d10d9..7330e8237f8 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -247,6 +247,14 @@ void RoomManager::enableSprite(byte spriteIndex, byte zOrder, int persist) {
}
void RoomManager::enableSprite(byte roomNumber, byte spriteIndex, byte zOrder, int persist) {
+ for(int i =0; i < g_engine->_state->spriteChanges[roomNumber].size(); i++) {
+ if (g_engine->_state->spriteChanges[roomNumber][i].spriteIndex == spriteIndex) {
+ debug("Removing pending sprite change for sprite %d in room %d", spriteIndex, roomNumber);
+ g_engine->_state->spriteChanges[roomNumber].remove_at(i);
+ break;
+ }
+ }
+
if (roomNumber == _currentRoomNumber && persist & PERSIST_TEMP) {
// Search by sprite.index field, not by array position (array is re-sorted every frame).
for (uint i = 0; i < _currentRoomAnims.size(); i++) {
@@ -257,6 +265,7 @@ void RoomManager::enableSprite(byte roomNumber, byte spriteIndex, byte zOrder, i
}
}
if (persist & PERSIST_PERM) {
+ debug("Enabling sprite %d in room %d with zOrder %d and persist %d", spriteIndex, roomNumber, zOrder, persist);
g_engine->_state->spriteChanges[roomNumber].push_back({roomNumber, spriteIndex, zOrder});
}
}
@@ -929,6 +938,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
sprite.disableAfterSequence = data[animOffset + 39];
for (int j = 0; j < spriteChanges.size(); j++) {
if (spriteChanges[j].spriteIndex == sprite.index) {
+ debug("Sprite %d has been changed, loading changed version with zOrder %d", sprite.index, spriteChanges[j].zIndex);
sprite.zOrder = spriteChanges[j].zIndex;
break;
}
@@ -955,6 +965,10 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
anim.animData = new byte *[anim.nframes];
if (sprite.w > 0 && sprite.h > 0 && anim.nframes > 0) {
for (int i = 0; i < anim.nframes; i++) {
+ if(picOffset >= pixelDataSize) {
+ debug("Pixel data offset out of bounds for sprite %d anim %d, offset %d, size %d", i, j, picOffset, pixelDataSize);
+ break;
+ }
anim.animData[i] = new byte[sprite.w * sprite.h];
// debug("Extracting frame %d for anim %d-%d, w=%d h=%d, pixelDataSize=%d, current offset %d", i, j, anim.nframes, sprite.w, sprite.h, pixelDataSize, picOffset);
extractSingleFrame(pixelData + picOffset, anim.animData[i], i, sprite.w, sprite.h);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index f807b91a233..f318c66ae9c 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -44,6 +44,8 @@ static const int unpickableHotspotExtras[] = {
74,
6,
7,
+ 91, //mud and stone should only be picked under certain conditions!
+ 92
};
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 0a790393cf0..b18138a74d4 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -476,6 +476,7 @@ struct ResetEntry {
#define FLAG_VIGILANTE_BEBE_AGUA 21
#define FLAG_FORMULA_MAGICA 26
#define FLAG_DA_PIEDRA 31
+#define FLAG_GUARDIAS_BORRACHOS 33
@@ -491,7 +492,6 @@ struct ResetEntry {
#define FLAG_AL_FARAON 29
#define FLAG_A_CURRAR 30
#define FLAG_PIEDRAS_COGIDAS 32
-#define FLAG_GUARDIAS_BORRACHOS 33
#define FLAG_PIEDRA_FAKE_MOJADA 34
#define FLAG_PUERTA_BUENA 35
#define FLAG_TRAMPILLA_ABIERTA 36
Commit: 4043d1ffc27b56e4aea7fa81eed4d3255575f982
https://github.com/scummvm/scummvm/commit/4043d1ffc27b56e4aea7fa81eed4d3255575f982
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:10+02:00
Commit Message:
PELROCK: Crawl animation for room 55, fixes palette remappings
Changed paths:
engines/pelrock/graphics.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 5d88c147a5a..c1552d88d7e 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -41,7 +41,7 @@ Common::Point GraphicsManager::showOverlay(int height, byte *buf) {
for (int x = 0; x < 640; x++) {
for (int y = overlayY; y < 400; y++) {
int index = y * 640 + x;
- buf[index] = g_engine->_room->_paletteRemaps[0][buf[index]];
+ buf[index] = g_engine->_room->_paletteRemaps[2][buf[index]];
}
}
return Common::Point(overlayX, overlayY);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a2424d910fa..1ce9bf7a4cb 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -158,7 +158,8 @@ void PelrockEngine::init() {
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
// setScreen(41, ALFRED_DOWN);
- setScreen(43, ALFRED_DOWN);
+ // setScreen(43, ALFRED_DOWN);
+ setScreen(55, ALFRED_RIGHT);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -622,7 +623,7 @@ void PelrockEngine::paintDebugLayer() {
if (showSprites) {
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
Sprite sprite = _room->_currentRoomAnims[i];
- if(sprite.zOrder < 0) {
+ if (sprite.zOrder < 0) {
// Skip sprites with negative zOrder (not rendered)
continue;
}
@@ -841,7 +842,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
break;
}
case ALFRED_IDLE: {
- drawAlfred(_res->alfredIdle[_alfredState.direction]);
+ drawIdleFrame();
break;
}
case ALFRED_WALKING: {
@@ -873,7 +874,8 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (step.distanceY > 0)
step.distanceY -= MIN(_alfredState.movementSpeedY, step.distanceY);
- if (step.distanceX <= 0 && step.distanceY <= 0) {
+ if (step.distanceX <= 0 && step.
+ distanceY <= 0) {
_currentStep++;
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
@@ -889,7 +891,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
} else if (_currentHotspot != nullptr) {
_alfredState.direction = calculateAlfredsDirection(_currentHotspot);
}
- drawAlfred(_res->alfredIdle[_alfredState.direction]);
+ drawIdleFrame();
if (_queuedAction.isQueued) {
// look and talk execute immediately, others need interaction animation first
if (_queuedAction.verb == TALK || _queuedAction.verb == LOOK) {
@@ -921,13 +923,24 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
} else {
_currentContext.movementBuffer[_currentStep] = step;
}
+ if (_room->_currentRoomNumber == 55) {
+ if (_alfredState.curFrame >= 9) {
+ _alfredState.curFrame = 0;
+ }
+ if (_alfredState.animState == ALFRED_WALKING) { // in case it changed to idle above
+ debug("Drawing crawl frame %d for direction %d", _alfredState.curFrame, _alfredState.direction);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCrawlFrames[_alfredState.direction][_alfredState.curFrame], _alfredState.x, _alfredState.y - 55, 130, 55, 255);
+ _alfredState.curFrame++;
+ }
+ } else {
+ if (_alfredState.curFrame >= walkingAnimLengths[_alfredState.direction]) {
+ _alfredState.curFrame = 0;
+ }
+ if (_alfredState.animState == ALFRED_WALKING) { // in case it changed to idle above
- if (_alfredState.curFrame >= walkingAnimLengths[_alfredState.direction]) {
- _alfredState.curFrame = 0;
- }
- if (_alfredState.animState == ALFRED_WALKING) { // in case it changed to idle above
- drawAlfred(_res->alfredWalkFrames[_alfredState.direction][_alfredState.curFrame]);
- _alfredState.curFrame++;
+ drawAlfred(_res->alfredWalkFrames[_alfredState.direction][_alfredState.curFrame]);
+ _alfredState.curFrame++;
+ }
}
break;
}
@@ -1000,6 +1013,14 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
}
}
+void PelrockEngine::drawIdleFrame() {
+ if (_room->_currentRoomNumber == 55) {
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCrawlFrames[_alfredState.direction][0], _alfredState.x, _alfredState.y - 55, 130, 55, 255);
+ } else {
+ drawAlfred(_res->alfredIdle[_alfredState.direction]);
+ }
+}
+
byte *PelrockEngine::scale(int scaleY, int finalWidth, int finalHeight, byte *buf) {
// The scaling table is indexed by how many scanlines to skip (scaleY), not by final height
@@ -1113,26 +1134,28 @@ void PelrockEngine::drawAlfred(byte *buf) {
// Original game scans shadow buffer
// at (topY + 0x66) * 640 + X + col for col = 0..width, where topY + 0x66 = feetY.
// The shadow map value (0-3) indexes into the palette remap tables.
- byte shadowLevel = 0xFF; // 0xFF = no shadow
- int feetY = _alfredState.y;
- if (feetY >= 0 && feetY < 400 && _room->_pixelsShadows != nullptr) {
- for (int col = 0; col < finalWidth; col++) {
- int checkX = _alfredState.x + col;
- if (checkX >= 0 && checkX < 640) {
- byte shadowVal = _room->_pixelsShadows[feetY * 640 + checkX];
- if (shadowVal != 0xFF) {
- shadowLevel = shadowVal;
- break; // Original breaks on first shadow pixel found
+ if (_room->_pixelsShadows != nullptr) {
+ byte shadowLevel = 0xFF; // 0xFF = no shadow
+ int feetY = _alfredState.y;
+ if (feetY >= 0 && feetY < 400 && _room->_pixelsShadows != nullptr) {
+ for (int col = 0; col < finalWidth; col++) {
+ int checkX = _alfredState.x + col;
+ if (checkX >= 0 && checkX < 640) {
+ byte shadowVal = _room->_pixelsShadows[feetY * 640 + checkX];
+ if (shadowVal != 0xFF) {
+ shadowLevel = shadowVal;
+ break; // Original breaks on first shadow pixel found
+ }
}
}
}
- }
- if (shadowLevel != 0xFF && shadowLevel < 4) {
- for (int i = 0; i < finalWidth * finalHeight; i++) {
- if (_alfredSprite[i] != 255) {
- // _alfredSprite[i] = _room->_paletteRemaps[3 - shadowLevel][_alfredSprite[i]];
- _alfredSprite[i] = _room->_paletteRemaps[0][_alfredSprite[i]];
+ if (shadowLevel != 0xFF && shadowLevel < 4) {
+ for (int i = 0; i < finalWidth * finalHeight; i++) {
+ if (_alfredSprite[i] != 255) {
+ _alfredSprite[i] = _room->_paletteRemaps[shadowLevel][_alfredSprite[i]];
+ // _alfredSprite[i] = _room->_paletteRemaps[0][_alfredSprite[i]];
+ }
}
}
}
@@ -1198,7 +1221,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
int frameSize = sprite->stride;
int curFrame = animData.curFrame;
- if(curFrame >= animData.nframes) {
+ if (curFrame >= animData.nframes) {
debug("Warning: curFrame %d exceeds nframes %d for sprite %d anim %d", curFrame, animData.nframes, sprite->index, sprite->curAnimIndex);
curFrame = 0;
}
@@ -1725,7 +1748,7 @@ void PelrockEngine::checkMouseHover() {
if (hotspotIndex != -1) {
hotspotDetected = true;
- if(hotspotIndex < _room->_currentRoomDescriptions.size())
+ if (hotspotIndex < _room->_currentRoomDescriptions.size())
_hoveredMapLocation = _room->_currentRoomDescriptions[hotspotIndex].text;
} else if (!alfredDetected) {
_hoveredMapLocation = "";
@@ -1944,7 +1967,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
case 48:
_dialog->_goodbyeDisabled = true;
break;
- case 10:{
+ case 10: {
// _events->waitForKey();
// while(!shouldQuit()) {
// playSpecialAnim(212915, true, 287, 152, 62, 58, 10);
@@ -1953,7 +1976,11 @@ void PelrockEngine::doExtraActions(int roomNumber) {
// playSpecialAnim(261449, true, 0, 223, 64, 97, 8);
// }
break;
- }
+ }
+ case 55: {
+
+ break;
+ }
default:
break;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 5acb31eb49f..0377c974501 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -101,6 +101,7 @@ private:
void lookAt(HotSpot *hotspot);
void chooseAlfredStateAndDraw();
+void drawIdleFrame();
void drawAlfred(byte *buf);
void drawNextFrame(Sprite *animSet);
void animateTalkingNPC(Sprite *animSet);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 935651fa54a..12c87fcbd7b 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -147,10 +147,12 @@ void ResourceManager::loadAlfredAnims() {
int index = 0;
int index3 = 0;
- uint32_t capacity = 3060 * 102;
- unsigned char *pic = new unsigned char[capacity];
- rleDecompress(bufferFile, alfred3Size, 0, capacity, &pic);
+ uint32_t capacity = 3060 * 102 + 2340 * 55;
+ unsigned char *completePic = new unsigned char[capacity];
+ rleDecompress(bufferFile, alfred3Size, 0, capacity, &completePic);
+ byte *stdFramesPic = new byte[3060 * 102];
+ Common::copy(completePic, completePic + 3060 * 102, stdFramesPic);
int frameSize = kAlfredFrameHeight * kAlfredFrameWidth;
for (int i = 0; i < 4; i++) {
alfredIdle[i] = new byte[frameSize];
@@ -170,12 +172,12 @@ void ResourceManager::loadAlfredAnims() {
int standingFrame = prevWalkingFrames;
- extractSingleFrame(pic, alfredIdle[i], standingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ extractSingleFrame(stdFramesPic, alfredIdle[i], standingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
for (int j = 0; j < walkingAnimLengths[i]; j++) {
alfredWalkFrames[i][j] = new byte[frameSize];
int walkingFrame = prevWalkingFrames + 1 + j;
- extractSingleFrame(pic, alfredWalkFrames[i][j], walkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ extractSingleFrame(stdFramesPic, alfredWalkFrames[i][j], walkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
}
alfredTalkFrames[i] = new byte *[talkingAnimLengths[i]];
@@ -184,7 +186,7 @@ void ResourceManager::loadAlfredAnims() {
for (int j = 0; j < talkingAnimLengths[i]; j++) {
alfredTalkFrames[i][j] = new byte[frameSize];
int talkingFrame = talkingStartFrame + j;
- extractSingleFrame(pic, alfredTalkFrames[i][j], talkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ extractSingleFrame(stdFramesPic, alfredTalkFrames[i][j], talkingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
}
alfredInteractFrames[i] = new byte *[interactingAnimLength];
@@ -192,7 +194,19 @@ void ResourceManager::loadAlfredAnims() {
for (int j = 0; j < interactingAnimLength; j++) {
alfredInteractFrames[i][j] = new byte[frameSize];
int interactingFrame = interactingStartFrame + j;
- extractSingleFrame(pic, alfredInteractFrames[i][j], interactingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ extractSingleFrame(stdFramesPic, alfredInteractFrames[i][j], interactingFrame, kAlfredFrameWidth, kAlfredFrameHeight);
+ }
+ }
+
+ byte *crawlFramesPic = new byte[2340 * 55];
+ Common::copy(completePic + 3060 * 102, completePic + 3060 * 102 + 2340 * 55, crawlFramesPic);
+ int crawlFrameSize = 2340 * 55;
+ for (int i = 0; i < 4; i++) {
+ alfredCrawlFrames[i] = new byte *[9];
+ for (int j = 0; j < 9; j++) {
+ int walkingFrame = (i % 2) * 9 + j;
+ alfredCrawlFrames[i][j] = new byte[crawlFrameSize];
+ extractSingleFrame(crawlFramesPic, alfredCrawlFrames[i][j], walkingFrame, 130, 55);
}
}
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index e016fff7c93..d4c6ea0e2f4 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -62,7 +62,7 @@ public:
byte *alfredIdle[4]; // 4 directions
byte **alfredWalkFrames[4]; // 4 arrays of arrays
-
+ byte **alfredCrawlFrames[4];
byte **alfredTalkFrames[4]; // 4 arrays of arrays
byte **alfredCombFrames[2];
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 7330e8237f8..69851aa4c47 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -1277,7 +1277,12 @@ byte *RoomManager::loadShadowMap(int roomNumber) {
readUntilBuda(&shadowMapFile, shadowOffset, compressed, compressedSize);
byte *shadows = nullptr;
- rleDecompress(compressed, compressedSize, 0, 640 * 400, &shadows);
+ size_t decompressedSize = rleDecompress(compressed, compressedSize, 0, 640 * 400, &shadows);
+ if(decompressedSize == 0) {
+ debug("Failed to decompress shadow map for room %d", roomNumber);
+ shadows = nullptr;
+ }
+ debug("Decompressed shadow map for room %d, compressed size: %zu, decompressed size: %zu", roomNumber, compressedSize, decompressedSize);
free(compressed);
shadowMapFile.close();
return shadows;
@@ -1290,7 +1295,7 @@ void RoomManager::loadRemaps(int roomNumber) {
error("Couldnt find file ALFRED.9");
}
- uint32 remapOffset = 0x200 + (roomNumber * 1024);
+ uint32 remapOffset =/* 0x200 + */(roomNumber * 1024);
remapFile.seek(remapOffset, SEEK_SET);
remapFile.read(_paletteRemaps[0], 256);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index b18138a74d4..804070845a3 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -21,6 +21,7 @@
#ifndef PELROCK_TYPES_H
#define PELROCK_TYPES_H
+#include "common/debug.h"
#include "common/scummsys.h"
#include "common/system.h"
#include "common/types.h"
@@ -170,6 +171,7 @@ struct AlfredState {
bool isWalkingCancelable = true;
void setState(AlfredAnimState nextState) {
+ debug("Transitioning Alfred from state %d to state %d", animState, nextState);
animState = nextState;
curFrame = 0;
}
Commit: e71946da22ce65b86c79ecedacb44153e8380da0
https://github.com/scummvm/scummvm/commit/e71946da22ce65b86c79ecedacb44153e8380da0
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:10+02:00
Commit Message:
PELROCK: Room 47
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index a1d10a52ba8..5447535c14c 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -163,6 +163,13 @@ const ActionEntry actionTable[] = {
// Room 44
{613, OPEN, &PelrockEngine::openPyramidDoor},
+ // Room 46
+ {621, OPEN, &PelrockEngine::openArchitectDoor},
+ {621, CLOSE, &PelrockEngine::closeArchitectDoor},
+
+ // Room 47
+ {628, PICKUP, &PelrockEngine::pickupPyramidMap},
+
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
{WILDCARD, TALK, &PelrockEngine::noOpAction}, // Generic talk action
@@ -614,9 +621,22 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 320:
_state->setCurrentRoot(room, 2, 0);
break;
- case 324:
- // ?
+ case 324: {
+ HotSpot hotspot = HotSpot();
+ hotspot.extra = 628;
+ hotspot.x = 221;
+ hotspot.y = 202;
+ hotspot.w = 50;
+ hotspot.h = 56;
+ hotspot.isEnabled = true;
+ hotspot.isSprite = false;
+ hotspot.actionFlags = 8;
+ hotspot.index = 9;
+ hotspot.innerIndex = 5;
+ _room->changeHotspot(47, hotspot);
+ _state->setCurrentRoot(room, 2, 0);
break;
+ }
// girls in pond
case 321:
_state->setCurrentRoot(45, 1, 0);
@@ -633,6 +653,12 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(45, 3, 0);
break;
case 30840:
+ //toJail()? not present in the game
+ break;
+
+ case 323:
+ _state->setCurrentRoot(47, 1, 0);
+ _state->setCurrentRoot(43, 3, 0);
break;
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
@@ -1703,6 +1729,18 @@ void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
}
}
+void PelrockEngine::openArchitectDoor(HotSpot *hotspot) {
+ openDoor(hotspot, 2, 124, FEMININE, true);
+}
+
+void PelrockEngine::closeArchitectDoor(HotSpot *hotspot) {
+ closeDoor(hotspot, 2, 124, FEMININE, true);
+}
+
+void PelrockEngine::pickupPyramidMap(HotSpot *hotspot) {
+ addInventoryItem(98);
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
@@ -1747,6 +1785,11 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
_room->changeHotSpot(*stone);
break;
}
+
+ case 322: {
+ _dialog->say(_res->_ingameTexts[NOSETEOCURRAACERCARTE]);
+ break;
+ }
}
}
@@ -1890,6 +1933,12 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_state->setCurrentRoot(43, 1, 0);
break;
}
+ case 98: {
+ _res->loadAlfredSpecialAnim(1);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _dialog->say(_res->_ingameTexts[PUERTAAUTENTICA_IZQUIERDA]);
+ }
default:
break;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1ce9bf7a4cb..424cef4f320 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -159,7 +159,7 @@ void PelrockEngine::init() {
// setScreen(22, ALFRED_DOWN);
// setScreen(41, ALFRED_DOWN);
// setScreen(43, ALFRED_DOWN);
- setScreen(55, ALFRED_RIGHT);
+ setScreen(46, ALFRED_RIGHT);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -375,10 +375,10 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
int spriteIndex = anim.spriteIndex;
int startX = anim.startX;
int startY = anim.startY;
- debug("Checking passerby anim %d for sprite %d, direction %d", _room->_passerByAnims->currentAnimIndex, spriteIndex, direction);
+ // debug("Checking passerby anim %d for sprite %d, direction %d", _room->_passerByAnims->currentAnimIndex, spriteIndex, direction);
Sprite *sprite = _room->findSpriteByIndex(spriteIndex);
if (direction == PASSERBY_RIGHT) {
- debug("Checking passerby anim for sprite %d moving RIGHT, curpos is %d", spriteIndex, sprite->x);
+ // debug("Checking passerby anim for sprite %d moving RIGHT, curpos is %d", spriteIndex, sprite->x);
if (sprite->x >= anim.resetCoord) {
sprite->x = startX;
sprite->y = startY;
@@ -388,7 +388,7 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
_room->_passerByAnims->latch = false;
}
} else if (direction == PASSERBY_LEFT) {
- debug("Checking passerby anim for sprite %d moving LEFT, curpos is %d", spriteIndex, sprite->x);
+ // debug("Checking passerby anim for sprite %d moving LEFT, curpos is %d", spriteIndex, sprite->x);
if (sprite->x <= anim.resetCoord) {
sprite->x = startX;
@@ -399,7 +399,7 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
_room->_passerByAnims->latch = false;
}
} else if (direction == PASSERBY_DOWN) {
- debug("Checking passerby anim for sprite %d moving DOWN, curpos is %d, reset %d", spriteIndex, sprite->y, anim.resetCoord);
+ // debug("Checking passerby anim for sprite %d moving DOWN, curpos is %d, reset %d", spriteIndex, sprite->y, anim.resetCoord);
if (sprite->y >= anim.resetCoord) {
sprite->x = startX;
sprite->y = startY;
@@ -914,6 +914,16 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_res->loadAlfredSpecialAnim(8);
_alfredState.setState(ALFRED_SPECIAL_ANIM);
waitForSpecialAnimation();
+ } else if (exit->targetRoom == 55 && _room->_currentRoomNumber == 44) {
+ uint16 x = _alfredState.x;
+ uint16 y = _alfredState.y;
+ _alfredState.x -= 20;
+ _alfredState.y += 5;
+ _res->loadAlfredSpecialAnim(15);
+ _alfredState.setState(ALFRED_SPECIAL_ANIM);
+ waitForSpecialAnimation();
+ _alfredState.x = x;
+ _alfredState.y = y;
}
_alfredState.x = exit->targetX;
_alfredState.y = exit->targetY;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 0377c974501..e0b390f7492 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -101,7 +101,7 @@ private:
void lookAt(HotSpot *hotspot);
void chooseAlfredStateAndDraw();
-void drawIdleFrame();
+ void drawIdleFrame();
void drawAlfred(byte *buf);
void drawNextFrame(Sprite *animSet);
void animateTalkingNPC(Sprite *animSet);
@@ -358,6 +358,9 @@ public:
void usePumpkinWithPond(int inventoryObject, HotSpot *hotspot);
void useWaterOnFakeStone(int inventoryObject, HotSpot *hotspot);
void magicFormula(int inventoryObject, HotSpot *hotspot);
+ void openArchitectDoor(HotSpot *hotspot);
+ void closeArchitectDoor(HotSpot *hotspot);
+ void pickupPyramidMap(HotSpot *hotspot);
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 12c87fcbd7b..37fe0a14776 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -33,7 +33,6 @@ ResourceManager::ResourceManager(/* args */) {
for (int i = 0; i < 4; i++) {
alfredIdle[i] = nullptr;
}
-
}
const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
@@ -52,6 +51,7 @@ const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
{18, 177, 124, 1, 7, 2115632, 1}, // 12 - Munheco 2
{11, 98, 138, 1, 7, 1526432, 1}, // 13 - Munheco 3
{4, 51, 102, 1, 7, 2972568, 1}, // 14 - descamisa
+ {13, 95, 99, 1, 7, 1749464, 1}, // 15 - alfred enters secret passage
};
ResourceManager::~ResourceManager() {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 804070845a3..207b4808139 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -171,7 +171,6 @@ struct AlfredState {
bool isWalkingCancelable = true;
void setState(AlfredAnimState nextState) {
- debug("Transitioning Alfred from state %d to state %d", animState, nextState);
animState = nextState;
curFrame = 0;
}
Commit: c5a47052d4ee4590638cbb8c3a87b5b94326e75e
https://github.com/scummvm/scummvm/commit/c5a47052d4ee4590638cbb8c3a87b5b94326e75e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:10+02:00
Commit Message:
PELROCK: Wrong door cutscene in Room 48
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 5447535c14c..128048a0a31 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -653,7 +653,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(45, 3, 0);
break;
case 30840:
- //toJail()? not present in the game
+ // toJail()? not present in the game
break;
case 323:
@@ -1668,11 +1668,10 @@ void PelrockEngine::usePumpkinWithPond(int inventoryObject, HotSpot *hotspot) {
void PelrockEngine::useWaterOnFakeStone(int inventoryObject, HotSpot *hotspot) {
int count = _state->getFlag(FLAG_PIEDRA_FAKE_MOJADA);
- if(count != 3) {
+ if (count != 3) {
_state->removeInventoryItem(86);
addInventoryItem(76);
- switch (count)
- {
+ switch (count) {
case 0:
_room->addSticker(120);
break;
@@ -1696,36 +1695,54 @@ void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
_state->setFlag(FLAG_FORMULA_MAGICA, _state->getFlag(FLAG_FORMULA_MAGICA) + 1);
if (_state->getFlag(FLAG_FORMULA_MAGICA) == 4) {
- size_t frameSize = 98 * 138;
- size_t bufSize = frameSize * 11;
- byte *smokeFrames = new byte[bufSize];
- _res->loadOtherSpecialAnim(1526432, true, smokeFrames, bufSize);
- Graphics::Surface smokeSurface;
- smokeSurface.create(98, 138, Graphics::PixelFormat::createFormatCLUT8());
- int curFrame = 0;
- while (!shouldQuit()) {
- _events->pollEvent();
+ smokeAnimation(-1);
+ _alfredState.setState(ALFRED_IDLE);
+ setScreen(39, ALFRED_UP);
+ }
+}
+
+void PelrockEngine::smokeAnimation(int spriteIndex, bool hide) {
+ size_t frameSize = 98 * 138;
+ size_t bufSize = frameSize * 11;
+ byte *smokeFrames = new byte[bufSize];
+ _res->loadOtherSpecialAnim(1526432, true, smokeFrames, bufSize);
+ Graphics::Surface smokeSurface;
+ smokeSurface.create(98, 138, Graphics::PixelFormat::createFormatCLUT8());
+ int curFrame = 0;
+ int x = _alfredState.x;
+ int y = _alfredState.y - _alfredState.h;
+ if (spriteIndex >= 0) {
+ x = _room->findSpriteByIndex(spriteIndex)->x;
+ y = _room->findSpriteByIndex(spriteIndex)->y;
+ }
+ while (!shouldQuit()) {
+ _events->pollEvent();
- bool didRender = renderScene(OVERLAY_NONE);
+ bool didRender = renderScene(OVERLAY_NONE);
- memset(smokeSurface.getPixels(), 0, frameSize);
- extractSingleFrame(smokeFrames, (byte *)smokeSurface.getPixels(), curFrame, 98, 138);
- _screen->transBlitFrom(smokeSurface, Common::Point(_alfredState.x, _alfredState.y - _alfredState.h), 255);
- if (curFrame == 5) {
+ memset(smokeSurface.getPixels(), 0, frameSize);
+ extractSingleFrame(smokeFrames, (byte *)smokeSurface.getPixels(), curFrame, 98, 138);
+ _screen->transBlitFrom(smokeSurface, Common::Point(x, y), 255);
+ if (curFrame == 5) {
+ if (spriteIndex == -1) {
_alfredState.setState(ALFRED_SKIP_DRAWING);
+ } else {
+ if (hide) {
+ _room->disableSprite(spriteIndex);
+ } else {
+ _room->enableSprite(spriteIndex, 200);
+ }
}
- if (didRender && _chrono->getFrameCount() % 2 == 0) {
- curFrame++;
+ }
+ if (didRender && _chrono->getFrameCount()) {
+ curFrame++;
- if (curFrame >= 11) {
- break;
- }
+ if (curFrame >= 11) {
+ break;
}
- _screen->update();
- g_system->delayMillis(10);
}
- _alfredState.setState(ALFRED_IDLE);
- setScreen(39, ALFRED_UP);
+ _screen->update();
+ g_system->delayMillis(10);
}
}
@@ -1934,16 +1951,36 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
}
case 98: {
- _res->loadAlfredSpecialAnim(1);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
- _dialog->say(_res->_ingameTexts[PUERTAAUTENTICA_IZQUIERDA]);
+ chooseCorrectDoor();
}
default:
break;
}
}
+void PelrockEngine::chooseCorrectDoor() {
+ _res->loadAlfredSpecialAnim(1);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ byte puertaBuena = _state->getFlag(FLAG_PUERTA_BUENA);
+ if (puertaBuena == 0) { // if not set yet, choose randomly
+ int choice = getRandomNumber(1);
+ _state->setFlag(FLAG_PUERTA_BUENA, choice + 1);
+ debug("Randomly chosen good door: %d", _state->getFlag(FLAG_PUERTA_BUENA));
+ }
+ puertaBuena = _state->getFlag(FLAG_PUERTA_BUENA);
+ Common::String doorText = _res->_izquierda;
+ if (puertaBuena == 1) {
+ doorText = _res->_izquierda;
+ } else if (puertaBuena == 2) {
+ doorText = _res->_derecha;
+ }
+ Common::StringArray fullTextArray = _res->_ingameTexts[PUERTAAUTENTICA_IZQUIERDA];
+ fullTextArray[0] = fullTextArray[0].substr(0, 45);
+ fullTextArray[0].append(doorText);
+ _dialog->say(fullTextArray);
+}
+
void PelrockEngine::animateStatuePaletteFade(bool reverse) {
// Structure at JUEGO.EXE offset 0x4C700
struct StatuePaletteData {
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 60b7a9a83cf..41f5c192547 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -51,7 +51,7 @@ static const uint32 kMenuTextOffset = 0x49203;
static const uint32 kMenuTextSize = 230;
static const uint32 kAlfredResponsesOffset = 0x441DC;
static const uint32 kConversationTerminatorOffset = 0x0492EE;
-static const uint32 kAlfredResponsesSize = 12163;
+static const uint32 kAlfredResponsesSize = 12143;
static const uint32 kCreditsOffset = 0x49F60;
static const uint32 kCreditsSize = 2540;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 424cef4f320..4da96005162 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -788,6 +788,9 @@ void PelrockEngine::animateRotatePalette(PaletteAnim *anim) {
}
void PelrockEngine::doAction(VerbIcon action, HotSpot *hotspot) {
+ if (action == NO_ACTION) {
+ return;
+ }
switch (action) {
case LOOK:
lookAt(hotspot);
@@ -874,8 +877,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
if (step.distanceY > 0)
step.distanceY -= MIN(_alfredState.movementSpeedY, step.distanceY);
- if (step.distanceX <= 0 && step.
- distanceY <= 0) {
+ if (step.distanceX <= 0 && step.distanceY <= 0) {
_currentStep++;
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
@@ -910,21 +912,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
Exit *exit = isExitUnder(_alfredState.x, _alfredState.y);
if (exit != nullptr) {
debug("Using exit to room %d", exit->targetRoom);
- if (exit->targetRoom == 31 && _room->_currentRoomNumber == 32) {
- _res->loadAlfredSpecialAnim(8);
- _alfredState.setState(ALFRED_SPECIAL_ANIM);
- waitForSpecialAnimation();
- } else if (exit->targetRoom == 55 && _room->_currentRoomNumber == 44) {
- uint16 x = _alfredState.x;
- uint16 y = _alfredState.y;
- _alfredState.x -= 20;
- _alfredState.y += 5;
- _res->loadAlfredSpecialAnim(15);
- _alfredState.setState(ALFRED_SPECIAL_ANIM);
- waitForSpecialAnimation();
- _alfredState.x = x;
- _alfredState.y = y;
- }
+ exitTriggers(exit);
_alfredState.x = exit->targetX;
_alfredState.y = exit->targetY;
setScreen(exit->targetRoom, exit->dir);
@@ -1023,6 +1011,37 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
}
}
+void PelrockEngine::exitTriggers(Pelrock::Exit *exit) {
+ if (exit->targetRoom == 31 && _room->_currentRoomNumber == 32) {
+ _res->loadAlfredSpecialAnim(8);
+ _alfredState.setState(ALFRED_SPECIAL_ANIM);
+ waitForSpecialAnimation();
+ } else if (exit->targetRoom == 55 && _room->_currentRoomNumber == 44) {
+ uint16 x = _alfredState.x;
+ uint16 y = _alfredState.y;
+ _alfredState.x -= 20;
+ _alfredState.y += 5;
+ _res->loadAlfredSpecialAnim(15);
+ _alfredState.setState(ALFRED_SPECIAL_ANIM);
+ waitForSpecialAnimation();
+ _alfredState.x = x;
+ _alfredState.y = y;
+ } else if (exit->targetRoom == 48 && _room->_currentRoomNumber == 46) {
+ smokeAnimation(-1);
+ uint16 x = _alfredState.x;
+ uint16 y = _alfredState.y;
+ if (x < 282) {
+ if (_state->getFlag(FLAG_PUERTA_BUENA) == 1) {
+ _state->setFlag(FLAG_CORRECT_DOOR_CHOSEN, true);
+ }
+ } else {
+ if (_state->getFlag(FLAG_PUERTA_BUENA) == 2) {
+ _state->setFlag(FLAG_CORRECT_DOOR_CHOSEN, true);
+ }
+ }
+ }
+}
+
void PelrockEngine::drawIdleFrame() {
if (_room->_currentRoomNumber == 55) {
drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCrawlFrames[_alfredState.direction][0], _alfredState.x, _alfredState.y - 55, 130, 55, 255);
@@ -1974,9 +1993,6 @@ void PelrockEngine::doExtraActions(int roomNumber) {
// paths lead to capture, no voluntary exit allowed.
_dialog->_goodbyeDisabled = true;
break;
- case 48:
- _dialog->_goodbyeDisabled = true;
- break;
case 10: {
// _events->waitForKey();
// while(!shouldQuit()) {
@@ -1987,8 +2003,29 @@ void PelrockEngine::doExtraActions(int roomNumber) {
// }
break;
}
- case 55: {
+ case 48: {
+ _dialog->_goodbyeDisabled = true;
+ if (_state->getFlag(FLAG_CORRECT_DOOR_CHOSEN) == true) {
+ } else {
+ _dialog->say(_res->_ingameTexts[OHMISALVADOR]);
+ _dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
+ // _state->setCurrentRoot(48, 0, 1);
+ Sprite *thinMummy = _room->findSpriteByIndex(0);
+ Sprite *thickMummy = _room->findSpriteByIndex(1);
+ HotSpot *fatMummy = nullptr;
+ for (uint i = 0; i < _room->_currentRoomHotspots.size(); i++) {
+ if (_room->_currentRoomHotspots[i].isSprite && _room->_currentRoomHotspots[i].index == 1) {
+ fatMummy = &_room->_currentRoomHotspots[i];
+ }
+ }
+ walkAndAction(fatMummy, NO_ACTION);
+ smokeAnimation(0);
+ smokeAnimation(1, false);
+
+ walkAndAction(fatMummy, TALK);
+ debug("Restart game now!");
+ }
break;
}
default:
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index e0b390f7492..9bad4333d67 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -101,6 +101,7 @@ private:
void lookAt(HotSpot *hotspot);
void chooseAlfredStateAndDraw();
+ void exitTriggers(Pelrock::Exit *exit);
void drawIdleFrame();
void drawAlfred(byte *buf);
void drawNextFrame(Sprite *animSet);
@@ -109,7 +110,6 @@ private:
void playSoundIfNeeded();
-
void gameLoop();
void computerLoop();
void extraScreenLoop();
@@ -282,6 +282,7 @@ public:
void noOpAction(HotSpot *hotspot);
void noOpItem(int item, HotSpot *hotspot);
void useOnAlfred(int inventoryObject);
+ void chooseCorrectDoor();
void useCardWithATM(int inventoryObject, HotSpot *hotspot);
void useBrickWithWindow(int inventoryObject, HotSpot *hotspot);
void moveCable(HotSpot *hotspot);
@@ -358,6 +359,7 @@ public:
void usePumpkinWithPond(int inventoryObject, HotSpot *hotspot);
void useWaterOnFakeStone(int inventoryObject, HotSpot *hotspot);
void magicFormula(int inventoryObject, HotSpot *hotspot);
+ void smokeAnimation(int spriteIndex, bool hide = true);
void openArchitectDoor(HotSpot *hotspot);
void closeArchitectDoor(HotSpot *hotspot);
void pickupPyramidMap(HotSpot *hotspot);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 37fe0a14776..9913571a9c0 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -36,22 +36,30 @@ ResourceManager::ResourceManager(/* args */) {
}
const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
- {10, 51, 102, 1, 7, 559685, 1,}, // 0 - READ BOOK
- {10, 51, 102, 1, 7, 578943, 1}, // 1 - READ RECIPE
- {3, 45, 87, 0, 7, 37000, 1}, // 2 - ELECTRIC SHOCK 1
- {2, 82, 58, 0, 7, 53106, 20}, // 3 - ELECTRIC SHOCK 3
+ {
+ 10,
+ 51,
+ 102,
+ 1,
+ 7,
+ 559685,
+ 1,
+ }, // 0 - READ BOOK
+ {10, 51, 102, 1, 7, 578943, 1}, // 1 - READ RECIPE
+ {3, 45, 87, 0, 7, 37000, 1}, // 2 - ELECTRIC SHOCK 1
+ {2, 82, 58, 0, 7, 53106, 20}, // 3 - ELECTRIC SHOCK 3
{3, 71, 110, 1, 2, 20724, 1, 62480}, // 4 - Throw
- {14, 171, 107, 1, 7, 1556540, 1} , // 5 - crocodile
- {12, 113, 103, 1, 7, 1583702, 1}, // 6 - exit through manhole
- {11, 33, 72, 1, 7, 1761234, 1}, // 7 - alfred climbs down
- {9, 33, 72, 1, 7, 1766378, 1}, // 8 - alfred climbs up
- {16, 158, 115, 0, 7, 1770196, 1}, // 9 - alfred exits tunnel
- {7, 208, 102, 0, 7, 1600956, 1}, // 10 - alfred with workers
- {23, 116, 124, 1, 7, 2060916, 1}, // 11 - Munheco 1
- {18, 177, 124, 1, 7, 2115632, 1}, // 12 - Munheco 2
- {11, 98, 138, 1, 7, 1526432, 1}, // 13 - Munheco 3
- {4, 51, 102, 1, 7, 2972568, 1}, // 14 - descamisa
- {13, 95, 99, 1, 7, 1749464, 1}, // 15 - alfred enters secret passage
+ {14, 171, 107, 1, 7, 1556540, 1}, // 5 - crocodile
+ {12, 113, 103, 1, 7, 1583702, 1}, // 6 - exit through manhole
+ {11, 33, 72, 1, 7, 1761234, 1}, // 7 - alfred climbs down
+ {9, 33, 72, 1, 7, 1766378, 1}, // 8 - alfred climbs up
+ {16, 158, 115, 0, 7, 1770196, 1}, // 9 - alfred exits tunnel
+ {7, 208, 102, 0, 7, 1600956, 1}, // 10 - alfred with workers
+ {23, 116, 124, 1, 7, 2060916, 1}, // 11 - Munheco 1
+ {18, 177, 124, 1, 7, 2115632, 1}, // 12 - Munheco 2
+ {11, 98, 138, 1, 7, 1526432, 1}, // 13 - Munheco 3
+ {4, 51, 102, 1, 7, 2972568, 1}, // 14 - descamisa
+ {13, 95, 99, 1, 7, 1749464, 1}, // 15 - alfred enters secret passage
};
ResourceManager::~ResourceManager() {
@@ -262,8 +270,7 @@ void ResourceManager::loadOtherSpecialAnim(uint32 offset, bool rleCompressed, by
size_t compressedSize = 0;
readUntilBuda(&alfred7, offset, compressed, compressedSize);
bufferSize = rleDecompress(compressed, compressedSize, 0, 0, &buffer, true);
- }
- else {
+ } else {
alfred7.seek(offset, SEEK_SET);
alfred7.read(buffer, bufferSize);
}
@@ -349,6 +356,9 @@ void ResourceManager::loadHardcodedText() {
exe.seek(kAlfredResponsesOffset, SEEK_SET);
exe.read(descBuffer, kAlfredResponsesSize);
_ingameTexts = processTextData(descBuffer, kAlfredResponsesSize);
+ // exe.seek(-1, SEEK_CUR);
+ _izquierda = exe.readString();
+ _derecha = exe.readString(0xFD);
byte *terminatorBuffer = new byte[39];
exe.seek(kConversationTerminatorOffset, SEEK_SET);
exe.read(terminatorBuffer, 39);
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index d4c6ea0e2f4..679a484f028 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -72,13 +72,14 @@ public:
byte *_verbIcons[9];
byte *_popUpBalloon = nullptr;
Common::Array<Common::StringArray> _ingameTexts;
+ Common::String _izquierda;
+ Common::String _derecha;
Common::String _conversationTerminator;
// Special anims
AlfredSpecialAnim *_currentSpecialAnim = nullptr;
bool _isSpecialAnimFinished = false;
static const AlfredSpecialAnimOffset alfredSpecialAnims[];
-
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 207b4808139..cd6a2163fcb 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -477,12 +477,15 @@ struct ResetEntry {
#define FLAG_VIGILANTE_BEBE_AGUA 21
#define FLAG_FORMULA_MAGICA 26
#define FLAG_DA_PIEDRA 31
+#define FLAG_PIEDRAS_COGIDAS 32
#define FLAG_GUARDIAS_BORRACHOS 33
+#define FLAG_PUERTA_BUENA 35
+#define FLAG_PIEDRA_FAKE_MOJADA 34
+#define FLAG_TIENDA_ABIERTA 46
#define FLAG_VIAJE_A_EGIPTO 12
-
#define FLAG_PUERTA_SECRETA_ABIERTA 16
#define FLAG_VIGILANTE_MEANDO 22
#define FLAG_PIRAMIDE_JODIDA 23
@@ -492,9 +495,7 @@ struct ResetEntry {
#define FLAG_APARECE_EUNUCO 28
#define FLAG_AL_FARAON 29
#define FLAG_A_CURRAR 30
-#define FLAG_PIEDRAS_COGIDAS 32
-#define FLAG_PIEDRA_FAKE_MOJADA 34
-#define FLAG_PUERTA_BUENA 35
+
#define FLAG_TRAMPILLA_ABIERTA 36
#define FLAG_HABITACION_PRINCESA 37
#define FLAG_A_POR_LA_PRINCESA 38
@@ -505,7 +506,6 @@ struct ResetEntry {
#define FLAG_FROM_INTRO 43
#define FLAG_HE_TIRADO_PIEDRA 44
#define FLAG_HA_USADO_AGUA 45
-#define FLAG_TIENDA_ABIERTA 46
#define FLAG_NUMERO_DE_COPAS 47
#define FLAG_GUARDIA_PIDECOSAS 49
@@ -514,11 +514,12 @@ struct ResetEntry {
#define FLAG_CONSIGNAS_VENDEDOR 52
#define FLAG_PUTA_250_VECES 53
#define FLAG_RESPUESTAS_ACERTADAS 54
-#define FLAG_CHEAT_CODE_ENABLED 55 // 0x495F3 - enables HIJODELAGRANPUTA cheat code input
+#define FLAG_CHEAT_CODE_ENABLED 55
#define FLAG_RIDDLE_PRESENTED 56
#define FLAG_SYMBOLS_PUSHED 57
+#define FLAG_CORRECT_DOOR_CHOSEN 58
-const int kNumGameFlags = 59;
+const int kNumGameFlags = 60;
struct GameStateData {
byte flags[kNumGameFlags];
Commit: 91be0ceead856eef71d3ac87c018623fcd1521ff
https://github.com/scummvm/scummvm/commit/91be0ceead856eef71d3ac87c018623fcd1521ff
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:10+02:00
Commit Message:
PELROCK: Correct choice of door in room 48 (hatch)
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 128048a0a31..29905642b6c 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1952,9 +1952,13 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
}
case 98: {
chooseCorrectDoor();
+ break;
}
- default:
+ default: {
+ byte response = (byte)getRandomNumber(12);
+ _dialog->say(_res->_ingameTexts[154 + response]);
break;
+ }
}
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 4da96005162..4f6ccef1353 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1820,6 +1820,7 @@ void PelrockEngine::setScreen(int roomNumber, AlfredDirection dir) {
error("Could not open ALFRED.1");
return;
}
+ changeCursor(DEFAULT);
_sound->stopAllSounds();
_currentHotspot = nullptr;
_alfredState.direction = dir;
@@ -2006,7 +2007,28 @@ void PelrockEngine::doExtraActions(int roomNumber) {
case 48: {
_dialog->_goodbyeDisabled = true;
if (_state->getFlag(FLAG_CORRECT_DOOR_CHOSEN) == true) {
+ if(_state->getFlag(FLAG_TRAMPILLA_ABIERTA) == true) {
+ }
+ else {
+ _dialog->say(_res->_ingameTexts[OHMISALVADOR]);
+ _dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
+ walkAndAction(_room->findHotspotByExtra(634), TALK);
+ _room->addSticker(134);
+ //wait a few frames
+ int framesToWait = 0;
+ while(!shouldQuit() && framesToWait < 10) {
+ _events->pollEvent();
+
+ bool didRender = renderScene(OVERLAY_NONE);
+ if(didRender) framesToWait++;
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+ _alfredState.x = 294;
+ _alfredState.y = 387;
+ setScreen(49, ALFRED_UP);
+ }
} else {
_dialog->say(_res->_ingameTexts[OHMISALVADOR]);
_dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
Commit: f26411b2890b978167dc9a1dd4384be936eccbe2
https://github.com/scummvm/scummvm/commit/f26411b2890b978167dc9a1dd4384be936eccbe2
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:11+02:00
Commit Message:
PELROCK: Room 49
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 29905642b6c..bbf2365b81a 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -660,6 +660,18 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(47, 1, 0);
_state->setCurrentRoot(43, 3, 0);
break;
+ case 325:
+ _state->setFlag(FLAG_ESQUELETO_RECONOCE, _state->getFlag(FLAG_ESQUELETO_RECONOCE) + 1);
+ if(_state->getFlag(FLAG_ESQUELETO_RECONOCE) == 2) {
+ _state->setCurrentRoot(49, 1, 0);
+ }
+ break;
+ case 326:
+ _state->setCurrentRoot(49, 2, 0);
+ break;
+ case 378:
+ _state->setCurrentRoot(49, 3, 0);
+ break;
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index cd6a2163fcb..9bd5ec34147 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -518,8 +518,9 @@ struct ResetEntry {
#define FLAG_RIDDLE_PRESENTED 56
#define FLAG_SYMBOLS_PUSHED 57
#define FLAG_CORRECT_DOOR_CHOSEN 58
+#define FLAG_ESQUELETO_RECONOCE 59
-const int kNumGameFlags = 60;
+const int kNumGameFlags = 61;
struct GameStateData {
byte flags[kNumGameFlags];
Commit: 20202772b6b7f42b5ca48b1bdcc99121a2928d6e
https://github.com/scummvm/scummvm/commit/20202772b6b7f42b5ca48b1bdcc99121a2928d6e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:11+02:00
Commit Message:
PELROCK: Trigger newspaper scene also in room 0
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 4f6ccef1353..250b75c4ad7 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1900,6 +1900,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
switch (roomNumber) {
case 4:
+ case 0:
if (_state->getFlag(FLAG_PUESTA_SALSA_PICANTE) && !_state->getFlag(FLAG_JEFE_ENCARCELADO)) {
_state->setFlag(FLAG_JEFE_ENCARCELADO, true);
_room->disableSprite(13, 0, true);
Commit: 39cca76119a08b5ab58d8a8f9a9c4122a03784ef
https://github.com/scummvm/scummvm/commit/39cca76119a08b5ab58d8a8f9a9c4122a03784ef
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:11+02:00
Commit Message:
PELROCK: Implements timing and spells in rooms 51-54
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 250b75c4ad7..d45fe547d7f 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -341,12 +341,12 @@ void PelrockEngine::mouseHoverForMap() {
}
}
-// const int kPasserbyTriggerFrameInterval = 0x3FF;
+const int kPasserbyTriggerFrameInterval = 0x3FF;
-const int kPasserbyTriggerFrameInterval = 15;
void PelrockEngine::frameTriggers() {
uint32 frameCount = _chrono->getFrameCount();
passerByAnim(frameCount);
+ handleFlightRoomFrame();
}
void PelrockEngine::passerByAnim(uint32 frameCount) {
@@ -2051,9 +2051,100 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
break;
}
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ initGodsSequences(_room->_currentRoomNumber);
+ break;
default:
break;
}
}
+struct FlightRoomCfg {
+ int spriteIdx;
+ int appearFrames;
+ int spellFrames;
+};
+
+static const FlightRoomCfg kFlightRooms[] = {
+ {1, 31, 17}, // room 51
+ {0, 30, 13}, // room 52
+ {1, 30, 13}, // room 53
+ {1, 38, 11}, // room 54
+};
+
+void PelrockEngine::initGodsSequences(int roomNumber) {
+ int idx = roomNumber - 51;
+ _flightFrameCounter = 0;
+ _flightSorcererSpriteIdx = kFlightRooms[idx].spriteIdx;
+ _flightSorcererAppeared = false;
+ _flightSpellCast = false;
+ _flightSpellFrameCounter = 0;
+ _flightInBlockingAnim = false;
+
+ _room->disableSprite(_flightSorcererSpriteIdx);
+}
+
+void PelrockEngine::handleFlightRoomFrame() {
+ int room = _room->_currentRoomNumber;
+ if (room < 51 || room > 54)
+ return;
+
+ // Guard against reentrance from blocking animation loops calling renderScene
+ if (_flightInBlockingAnim)
+ return;
+
+ int idx = room - 51;
+
+ _flightFrameCounter++;
+
+ // Phase 1: NPC appearance at tick 64
+ if (!_flightSorcererAppeared && _flightFrameCounter >= 64) {
+ _flightSorcererAppeared = true;
+ _flightInBlockingAnim = true;
+ _room->findSpriteByIndex(_flightSorcererSpriteIdx)->animData[0].nframes = 1;
+ smokeAnimation(_flightSorcererSpriteIdx, false);
+ _flightInBlockingAnim = false;
+ return;
+ }
+
+ // Phase 2: spell trigger at tick 104 (64 + 40)
+ if (_flightSorcererAppeared && !_flightSpellCast && _flightFrameCounter >= 104) {
+ _flightSpellCast = true;
+ _flightSpellFrameCounter = 0;
+ }
+
+ // Phase 3: wait 40 ticks after spell trigger, then cast
+ if (_flightSpellCast) {
+ _flightSpellFrameCounter++;
+ if (_flightSpellFrameCounter >= 40) {
+ _flightInBlockingAnim = true;
+
+ int spellFrames = kFlightRooms[idx].spellFrames;
+ int framesDone = 0;
+ _room->findSpriteByIndex(_flightSorcererSpriteIdx)->animData[0].nframes = kFlightRooms[idx].spellFrames;
+ _room->findSpriteByIndex(_flightSorcererSpriteIdx)->animData[0].speed = 1;
+
+ while (!shouldQuit() && framesDone < spellFrames) {
+ _events->pollEvent();
+ if (renderScene(OVERLAY_NONE))
+ framesDone++;
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+ _room->findSpriteByIndex(_flightSorcererSpriteIdx)->animData[0].nframes = 1;
+ smokeAnimation(-1, true);
+
+ _flightInBlockingAnim = false;
+
+ _alfredState.x = 294;
+ _alfredState.y = 387;
+ _alfredState.direction = ALFRED_UP;
+ setScreen(49, ALFRED_UP);
+ }
+ }
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 9bad4333d67..e27b40515a4 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -174,6 +174,14 @@ public:
byte *_compositeBuffer = nullptr; // Working composition buffer
bool _mouseDisabled = false;
+
+ int _flightFrameCounter = 0;
+ int _flightSorcererSpriteIdx = -1;
+ bool _flightSorcererAppeared = false;
+ bool _flightSpellCast = false;
+ int _flightSpellFrameCounter = 0;
+ bool _flightInBlockingAnim = false;
+
GameStateData *_state = new GameStateData();
SmallFont *_smallFont = nullptr;
@@ -237,6 +245,7 @@ public:
bool renderScene(int overlayMode = OVERLAY_NONE);
void mouseHoverForMap();
void frameTriggers();
+ void handleFlightRoomFrame();
void passerByAnim(uint32 frameCount);
void reflectionEffect(byte *buf, int x, int y, int width, int height);
@@ -246,6 +255,7 @@ public:
// Actions
void doExtraActions(int roomNumber);
+ void initGodsSequences(int roomNumber);
void addInventoryItem(int item);
void buyFromStore(HotSpot *hotspot, int stickerId);
void performActionTrigger(uint16 actionTrigger);
Commit: 943271a5e7d7d1ca537a688f96ecb55e58c486f1
https://github.com/scummvm/scummvm/commit/943271a5e7d7d1ca537a688f96ecb55e58c486f1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:12+02:00
Commit Message:
PELROCK: Stop frame counter during dialog
Changed paths:
engines/pelrock/chrono.cpp
engines/pelrock/chrono.h
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/extrascreens.cpp
engines/pelrock/extrascreens.h
engines/pelrock/menu.cpp
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index db0f7d8c10a..a020350332b 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -39,7 +39,9 @@ void ChronoManager::updateChrono() {
if ((currentTime - _lastTick) >= kTickMs / _speedMultiplier) {
_gameTick = true;
- _frameCount++;
+ if(!_pauseCounter) {
+ _frameCount++;
+ }
_lastTick = currentTime;
} else {
_gameTick = false;
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index f7f67229545..673108c433b 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -52,6 +52,7 @@ public:
bool _gameTick = false;
bool countTextDown = false;
+ bool _pauseCounter = false;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index fcd6b8503c0..e744f8a4a20 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -186,6 +186,8 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
// Clear any existing click state
_events->_leftMouseClicked = false;
+ _dialogActive = true;
+ g_engine->_chrono->_pauseCounter = true;
int curPage = 0;
// Render loop - display text and wait for click
@@ -236,6 +238,8 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (_curSprite != nullptr) {
_curSprite->isTalking = false;
}
+ _dialogActive = false;
+ g_engine->_chrono->_pauseCounter = false;
g_engine->_alfredState.setState(ALFRED_IDLE);
}
@@ -250,6 +254,8 @@ void DialogManager::displayDialogue(Common::String text, byte speakerId) {
*/
int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer) {
_events->_leftMouseClicked = false;
+ _dialogActive = true;
+ g_engine->_chrono->_pauseCounter = true;
int overlayHeight = choices.size() * kChoiceHeight + 2;
int overlayY = 400 - overlayHeight;
@@ -265,6 +271,8 @@ int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *co
if (_events->_mouseClickY >= overlayY) {
int selectedIndex = (_events->_mouseClickY - overlayY - 2) / kChoiceHeight;
if (selectedIndex >= 0 && selectedIndex < (int)choices.size()) {
+ _dialogActive = false;
+ g_engine->_chrono->_pauseCounter = false;
return selectedIndex;
}
}
@@ -273,6 +281,8 @@ int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *co
g_system->delayMillis(10);
}
+ _dialogActive = false;
+ g_engine->_chrono->_pauseCounter = false;
return 0;
}
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 532515fbcbd..0ebc5f0362b 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -116,6 +116,9 @@ public:
// When true, the goodbye option is suppressed for all conversations in the current room.
bool _goodbyeDisabled = false;
+
+ // True while a blocking dialog or conversation is on screen.
+ bool _dialogActive = false;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
index e47a39e2223..aa983833ae9 100644
--- a/engines/pelrock/extrascreens.cpp
+++ b/engines/pelrock/extrascreens.cpp
@@ -44,12 +44,13 @@ SpellBook::~SpellBook() {
Spell *SpellBook::run() {
loadBackground();
g_engine->changeCursor(DEFAULT);
- while (!g_engine->shouldQuit() && !_selectedSpell) {
+ bool exit = false;
+ while (!g_engine->shouldQuit() && !exit) {
_events->pollEvent();
drawScreen();
if (_events->_leftMouseClicked) {
_events->_leftMouseClicked = false;
- checkMouse(_events->_mouseClickX, _events->_mouseClickY);
+ exit = checkMouse(_events->_mouseClickX, _events->_mouseClickY);
}
g_engine->_screen->markAllDirty();
g_engine->_screen->update();
@@ -152,24 +153,27 @@ void SpellBook::cleanup() {
g_engine->_screen->update();
}
-void SpellBook::checkMouse(int x, int y) {
+bool SpellBook::checkMouse(int x, int y) {
// Check bookmarks
for (int i = 0; i < 13; i++) {
Common::Rect r = Common::Rect(_bookmarks[i].x, _bookmarks[i].y, _bookmarks[i].x + _bookmarks[i].w, _bookmarks[i].y + _bookmarks[i].h);
if (r.contains(x, y)) {
selectPage(_bookmarks[i].page);
- return;
+ return false;
}
}
// Check text area
if (_spell == nullptr) {
- return;
+ return true;
}
+
Common::Rect textArea = Common::Rect(321, 81, 321 + 140, 81 + (_spell->text.size() * 10));
if (textArea.contains(x, y)) {
_selectedSpell = _spell;
+ return true;
}
+ return false;
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/extrascreens.h b/engines/pelrock/extrascreens.h
index c1fe52a1be5..6be65f30087 100644
--- a/engines/pelrock/extrascreens.h
+++ b/engines/pelrock/extrascreens.h
@@ -84,7 +84,7 @@ private:
void drawScreen();
void loadBackground();
void cleanup();
- void checkMouse(int x, int y);
+ bool checkMouse(int x, int y);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index f8f08ce9a14..acdf8d1ded0 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -145,7 +145,6 @@ void MenuManager::menuLoop() {
void MenuManager::drawScreen() {
memcpy(_compositeBuffer, _mainMenu, 640 * 400);
- // memset(_compositeBuffer, 0, 640 * 400);
if (showButtons)
drawButtons();
Commit: 8c0062a9542ddb2d04b79ead466a0ec48f24214b
https://github.com/scummvm/scummvm/commit/8c0062a9542ddb2d04b79ead466a0ec48f24214b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:12+02:00
Commit Message:
PELROCK: Play sound when using amulet and during electric shock
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index bbf2365b81a..eddc72efe57 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -779,7 +779,10 @@ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
}
if (billCount < 13) {
addInventoryItem(5); // 1000 pesetas bill
- _dialog->say(_res->_ingameTexts[TEAPETECE_BUENRATO]);
+ bool sayLine = getRandomNumber(15) == 1; // 1 in 15 chance to say the line about not having more money
+ if(sayLine) {
+ _dialog->say(_res->_ingameTexts[TEAPETECE_BUENRATO]);
+ }
} else {
_dialog->say(_res->_ingameTexts[NOTENGOMASDINERO]);
}
@@ -1003,6 +1006,8 @@ void PelrockEngine::pickCables(HotSpot *hotspot) {
// electric shock
int prevX = _alfredState.x;
_alfredState.x -= 20;
+ // original incorrectly played door closing sound here
+ _sound->playSound("ELEC3ZZZ.SMP", 0);
_res->loadAlfredSpecialAnim(3);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
waitForSpecialAnimation();
@@ -1083,6 +1088,7 @@ void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
HotSpot *statueHotspot = _room->findHotspotByExtra(347);
_currentHotspot = statueHotspot;
walkTo(statueHotspot->x + statueHotspot->w / 2, statueHotspot->y + statueHotspot->h);
+ _sound->playSound(_room->_roomSfx[0]); // Magic sound
animateStatuePaletteFade(false);
walkAndAction(statueHotspot, TALK);
waitForActionEnd();
@@ -1998,7 +2004,6 @@ void PelrockEngine::chooseCorrectDoor() {
}
void PelrockEngine::animateStatuePaletteFade(bool reverse) {
- // Structure at JUEGO.EXE offset 0x4C700
struct StatuePaletteData {
uint16 x; // 368
uint16 y; // 148
@@ -2041,8 +2046,7 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
exeFile.close();
// Animation parameters
- const int kNumFrames = 7; // 7 step updates total
- const int kDelayMs = 200; // ~12 ticks at 60Hz (~200ms)
+ const int numFrames = 7; // 7 step updates total
// Get current palette
byte currentPalette[768];
@@ -2050,7 +2054,7 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
// Perform the fade animation
int frame = 0;
- while (!shouldQuit() && frame <= kNumFrames) {
+ while (!shouldQuit() && frame <= numFrames) {
_events->pollEvent();
bool didRender = renderScene(OVERLAY_NONE);
@@ -2064,9 +2068,9 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
byte *dstColor = reverse ? paletteData.source[i] : paletteData.target[i];
// Linear interpolation (6-bit VGA values)
- byte r6 = srcColor[0] + ((dstColor[0] - srcColor[0]) * frame) / kNumFrames;
- byte g6 = srcColor[1] + ((dstColor[1] - srcColor[1]) * frame) / kNumFrames;
- byte b6 = srcColor[2] + ((dstColor[2] - srcColor[2]) * frame) / kNumFrames;
+ byte r6 = srcColor[0] + ((dstColor[0] - srcColor[0]) * frame) / numFrames;
+ byte g6 = srcColor[1] + ((dstColor[1] - srcColor[1]) * frame) / numFrames;
+ byte b6 = srcColor[2] + ((dstColor[2] - srcColor[2]) * frame) / numFrames;
// Convert 6-bit VGA (0-63) to 8-bit (0-255) by shifting left 2 bits
currentPalette[paletteIndex * 3 + 0] = r6 << 2;
@@ -2082,6 +2086,7 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
g_system->delayMillis(10);
}
}
+
/**
* In order to unlock the second part of the game, we need to ensure
* we have all we need to solve the game once there
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 41f5c192547..819def28a65 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -499,13 +499,14 @@ struct AlfredSpecialAnimOffset {
uint32 offset;
int stride = 0;
uint32 size;
+ int speed = 2;
- AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, int numAlfred, uint32 off, int loops)
- : numFrames(nF), w(width), h(height), numBudas(nBudas), numAlfred(numAlfred), offset(off), loops(loops) {
- AlfredSpecialAnimOffset(nF, width, height, nBudas, numAlfred, off, loops, width * height * nF);
+ AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, int numAlfred, uint32 off, int loops, int speed = 2)
+ : numFrames(nF), w(width), h(height), numBudas(nBudas), numAlfred(numAlfred), offset(off), loops(loops), speed(speed) {
+ AlfredSpecialAnimOffset(nF, width, height, nBudas, numAlfred, off, loops, speed, width * height * nF);
}
- AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, int numAlfred, uint32 off, int loops, uint32 sz)
- : numFrames(nF), w(width), h(height), numBudas(nBudas), numAlfred(numAlfred), offset(off), loops(loops), size(sz) {
+ AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, int numAlfred, uint32 off, int loops, int speed, uint32 sz)
+ : numFrames(nF), w(width), h(height), numBudas(nBudas), numAlfred(numAlfred), offset(off), loops(loops), size(sz), speed(speed) {
stride = w * h;
}
AlfredSpecialAnimOffset() {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index d45fe547d7f..9955dba47d1 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -990,7 +990,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
// Scale special anim frame to Alfred size before drawing
drawSpriteToBuffer(_compositeBuffer, 640, frame, _alfredState.x, _alfredState.y - _res->_currentSpecialAnim->h, _res->_currentSpecialAnim->w, _res->_currentSpecialAnim->h, 255);
}
- if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0) {
+ if (_chrono->getFrameCount() % _res->_currentSpecialAnim->speed == 0) {
_res->_currentSpecialAnim->curFrame++;
if (_res->_currentSpecialAnim->curFrame >= _res->_currentSpecialAnim->numFrames) {
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 9913571a9c0..d5723293b27 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -36,18 +36,10 @@ ResourceManager::ResourceManager(/* args */) {
}
const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
- {
- 10,
- 51,
- 102,
- 1,
- 7,
- 559685,
- 1,
- }, // 0 - READ BOOK
+ {10, 51, 102, 1, 7, 559685, 1}, // 0 - READ BOOK
{10, 51, 102, 1, 7, 578943, 1}, // 1 - READ RECIPE
{3, 45, 87, 0, 7, 37000, 1}, // 2 - ELECTRIC SHOCK 1
- {2, 82, 58, 0, 7, 53106, 20}, // 3 - ELECTRIC SHOCK 3
+ {2, 82, 58, 0, 7, 53106, 20, 1}, // 3 - ELECTRIC SHOCK 3
{3, 71, 110, 1, 2, 20724, 1, 62480}, // 4 - Throw
{14, 171, 107, 1, 7, 1556540, 1}, // 5 - crocodile
{12, 113, 103, 1, 7, 1583702, 1}, // 6 - exit through manhole
@@ -290,7 +282,7 @@ void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
alfredFile.seek(anim.offset, SEEK_SET);
if (_currentSpecialAnim)
delete _currentSpecialAnim;
- _currentSpecialAnim = new AlfredSpecialAnim(anim.numFrames, anim.w, anim.h, anim.numBudas, anim.offset, anim.loops, anim.size);
+ _currentSpecialAnim = new AlfredSpecialAnim(anim.numFrames, anim.w, anim.h, anim.numBudas, anim.offset, anim.loops, anim.size, anim.speed);
uint32 size = anim.size == 0 ? anim.numFrames * anim.w * anim.h : anim.size;
_currentSpecialAnim->animData = new byte[size];
if (anim.numBudas > 0) {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 9bd5ec34147..f5f1feebf6f 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -136,10 +136,12 @@ struct AlfredSpecialAnim {
int curFrame = 0;
int curLoop = 0;
uint32 size = 0;
- AlfredSpecialAnim(int nF, int width, int height, int nBudas, uint32 off, int loopCount, uint32 sz)
- : numFrames(nF), w(width), h(height), loopCount(loopCount), size(sz) {
+ int speed = 2;
+ AlfredSpecialAnim(int nF, int width, int height, int nBudas, uint32 off, int loopCount, uint32 sz, int spd = 2)
+ : numFrames(nF), w(width), h(height), loopCount(loopCount), size(sz), speed(spd) {
stride = w * h;
}
+
~AlfredSpecialAnim() {
if (animData) {
delete[] animData;
Commit: ced34be28fb813ee52dd7172e0ba3421cd063f6f
https://github.com/scummvm/scummvm/commit/ced34be28fb813ee52dd7172e0ba3421cd063f6f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:12+02:00
Commit Message:
PELROCK: Gods/Sorcerer scenes in rooms 51, 52, 53, 54
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/chrono.h
engines/pelrock/dialog.cpp
engines/pelrock/extrascreens.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index eddc72efe57..0b9e9e0bbf1 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -662,7 +662,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
case 325:
_state->setFlag(FLAG_ESQUELETO_RECONOCE, _state->getFlag(FLAG_ESQUELETO_RECONOCE) + 1);
- if(_state->getFlag(FLAG_ESQUELETO_RECONOCE) == 2) {
+ if (_state->getFlag(FLAG_ESQUELETO_RECONOCE) == 2) {
_state->setCurrentRoot(49, 1, 0);
}
break;
@@ -778,9 +778,9 @@ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
}
}
if (billCount < 13) {
- addInventoryItem(5); // 1000 pesetas bill
+ addInventoryItem(5); // 1000 pesetas bill
bool sayLine = getRandomNumber(15) == 1; // 1 in 15 chance to say the line about not having more money
- if(sayLine) {
+ if (sayLine) {
_dialog->say(_res->_ingameTexts[TEAPETECE_BUENRATO]);
}
} else {
@@ -1895,7 +1895,6 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
}
break;
case 88: {
-
SpellBook spellBook = SpellBook(_events, _res);
_res->loadAlfredSpecialAnim(0);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
@@ -1905,25 +1904,48 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
if (spell) {
_alfredState.direction = ALFRED_LEFT;
_dialog->say(_res->_ingameTexts[DIOSHALCON + spell->page], 1);
- if (spell->page == 12 && _room->_currentRoomNumber == 28) {
- _graphics->clearScreen();
- int waitFrames = 0;
- // blank screen for half a second
- while (!shouldQuit() && waitFrames < 20) {
- _events->pollEvent();
- _chrono->updateChrono();
- if (_chrono->_gameTick) {
- waitFrames++;
+ switch (_room->_currentRoomNumber) {
+ case 28: {
+ if (spell->page == 12) {
+ _graphics->clearScreen();
+ int waitFrames = 0;
+ // blank screen for half a second
+ while (!shouldQuit() && waitFrames < 20) {
+ _events->pollEvent();
+ _chrono->updateChrono();
+ if (_chrono->_gameTick) {
+ waitFrames++;
+ }
+ _screen->markAllDirty();
+ _screen->update();
+ g_system->delayMillis(10);
}
- _screen->markAllDirty();
- _screen->update();
- g_system->delayMillis(10);
- }
- _alfredState.x = 145;
- _alfredState.y = 312;
- setScreen(25, ALFRED_RIGHT);
- _dialog->say(_res->_ingameTexts[MENUDAAVENTURA]);
+ _alfredState.x = 145;
+ _alfredState.y = 312;
+ setScreen(25, ALFRED_RIGHT);
+ _dialog->say(_res->_ingameTexts[MENUDAAVENTURA]);
+ }
+ break;
+ }
+ case 51:
+ case 52:
+ case 53:
+ case 54: {
+ debug("Flight spell cast in room %d, spell page: %d", _room->_currentRoomNumber, spell->page);
+ int flightIndex = _room->_currentRoomNumber - 51;
+ debug("Correct page for this spell is = %d", kFlightRooms[flightIndex].spellPage);
+ if(_flightSorcererAppeared && !_flightInBlockingAnim && spell->page == kFlightRooms[flightIndex].spellPage) {
+ _state->setFlag(FLAG_COMO_ESTAN_LOS_DIOSES, _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) | (1 << flightIndex));
+ debug("Flight spell successful, starting animation and updating state");
+ debug("Updated FLAG_COMO_ESTAN_LOS_DIOSES: %d", _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES));
+ smokeAnimation(kFlightRooms[flightIndex].spriteIdx, true);
+ _room->addStickerToRoom(_room->_currentRoomNumber, 127 + flightIndex);
+ }
+ break;
+ }
+ default:
+ break;
}
}
break;
@@ -1976,7 +1998,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
byte response = (byte)getRandomNumber(12);
_dialog->say(_res->_ingameTexts[154 + response]);
break;
- }
+ }
}
}
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 673108c433b..0e8b5f3b8b9 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -39,6 +39,7 @@ private:
uint32 _lastTick = 0;
byte _speedMultiplier = 1;
uint32 _frameCount = 0;
+ bool _pauseCounter = false;
public:
ChronoManager();
@@ -46,13 +47,14 @@ public:
void updateChrono();
void changeSpeed();
void delay(uint32 ms);
+ inline void pauseCounter() { _pauseCounter = true; }
+ inline void resumeCounter() { _pauseCounter = false; }
uint32 getFrameCount() const {
return _frameCount;
}
bool _gameTick = false;
bool countTextDown = false;
- bool _pauseCounter = false;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index e744f8a4a20..96ef5091fa9 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -187,7 +187,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
// Clear any existing click state
_events->_leftMouseClicked = false;
_dialogActive = true;
- g_engine->_chrono->_pauseCounter = true;
+ g_engine->_chrono->pauseCounter();
int curPage = 0;
// Render loop - display text and wait for click
@@ -239,7 +239,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_curSprite->isTalking = false;
}
_dialogActive = false;
- g_engine->_chrono->_pauseCounter = false;
+ g_engine->_chrono->resumeCounter();
g_engine->_alfredState.setState(ALFRED_IDLE);
}
@@ -255,7 +255,7 @@ void DialogManager::displayDialogue(Common::String text, byte speakerId) {
int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer) {
_events->_leftMouseClicked = false;
_dialogActive = true;
- g_engine->_chrono->_pauseCounter = true;
+ g_engine->_chrono->pauseCounter();
int overlayHeight = choices.size() * kChoiceHeight + 2;
int overlayY = 400 - overlayHeight;
@@ -272,7 +272,7 @@ int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *co
int selectedIndex = (_events->_mouseClickY - overlayY - 2) / kChoiceHeight;
if (selectedIndex >= 0 && selectedIndex < (int)choices.size()) {
_dialogActive = false;
- g_engine->_chrono->_pauseCounter = false;
+ g_engine->_chrono->resumeCounter();
return selectedIndex;
}
}
@@ -282,7 +282,7 @@ int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *co
}
_dialogActive = false;
- g_engine->_chrono->_pauseCounter = false;
+ g_engine->_chrono->resumeCounter();
return 0;
}
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
index aa983833ae9..ca708c9aa72 100644
--- a/engines/pelrock/extrascreens.cpp
+++ b/engines/pelrock/extrascreens.cpp
@@ -69,6 +69,7 @@ void SpellBook::init() {
}
void SpellBook::selectPage(int page) {
+ debug("Selected spell page: %d", page);
_spell = new Spell();
_spell->page = page;
Common::File alfred7;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 9955dba47d1..27e0deb3ad2 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -977,7 +977,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
break;
}
case ALFRED_SPECIAL_ANIM: {
-
byte *frame = new byte[_res->_currentSpecialAnim->stride * _res->_currentSpecialAnim->numFrames];
extractSingleFrame(_res->_currentSpecialAnim->animData,
frame,
@@ -2008,21 +2007,21 @@ void PelrockEngine::doExtraActions(int roomNumber) {
case 48: {
_dialog->_goodbyeDisabled = true;
if (_state->getFlag(FLAG_CORRECT_DOOR_CHOSEN) == true) {
- if(_state->getFlag(FLAG_TRAMPILLA_ABIERTA) == true) {
+ if (_state->getFlag(FLAG_TRAMPILLA_ABIERTA) == true) {
- }
- else {
+ } else {
_dialog->say(_res->_ingameTexts[OHMISALVADOR]);
_dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
walkAndAction(_room->findHotspotByExtra(634), TALK);
_room->addSticker(134);
- //wait a few frames
+ // wait a few frames
int framesToWait = 0;
- while(!shouldQuit() && framesToWait < 10) {
+ while (!shouldQuit() && framesToWait < 10) {
_events->pollEvent();
bool didRender = renderScene(OVERLAY_NONE);
- if(didRender) framesToWait++;
+ if (didRender)
+ framesToWait++;
_screen->update();
g_system->delayMillis(10);
}
@@ -2062,19 +2061,6 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
}
-struct FlightRoomCfg {
- int spriteIdx;
- int appearFrames;
- int spellFrames;
-};
-
-static const FlightRoomCfg kFlightRooms[] = {
- {1, 31, 17}, // room 51
- {0, 30, 13}, // room 52
- {1, 30, 13}, // room 53
- {1, 38, 11}, // room 54
-};
-
void PelrockEngine::initGodsSequences(int roomNumber) {
int idx = roomNumber - 51;
_flightFrameCounter = 0;
@@ -2091,17 +2077,25 @@ void PelrockEngine::handleFlightRoomFrame() {
int room = _room->_currentRoomNumber;
if (room < 51 || room > 54)
return;
+ int idx = room - 51;
+
+ if (_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) & (1 << idx)) {
+ // Gods are already defeated in this room, no need to run sequence
+ return;
+ }
// Guard against reentrance from blocking animation loops calling renderScene
if (_flightInBlockingAnim)
return;
- int idx = room - 51;
-
+ if (_alfredState.animState != ALFRED_IDLE) {
+ return;
+ }
_flightFrameCounter++;
// Phase 1: NPC appearance at tick 64
if (!_flightSorcererAppeared && _flightFrameCounter >= 64) {
+ _sound->playSound(_room->_roomSfx[0]);
_flightSorcererAppeared = true;
_flightInBlockingAnim = true;
_room->findSpriteByIndex(_flightSorcererSpriteIdx)->animData[0].nframes = 1;
@@ -2112,21 +2106,28 @@ void PelrockEngine::handleFlightRoomFrame() {
// Phase 2: spell trigger at tick 104 (64 + 40)
if (_flightSorcererAppeared && !_flightSpellCast && _flightFrameCounter >= 104) {
+ debug("spell cast triggered for room %d at frame %d", room, _flightFrameCounter);
_flightSpellCast = true;
_flightSpellFrameCounter = 0;
}
// Phase 3: wait 40 ticks after spell trigger, then cast
if (_flightSpellCast) {
+ if (_alfredState.animState != ALFRED_IDLE) {
+ debug("blocking animation active at frame %d, delaying spell cast", _flightFrameCounter);
+ return;
+ }
+ debug("in spell cast phase for room %d at frame %d", room, _flightFrameCounter);
_flightSpellFrameCounter++;
- if (_flightSpellFrameCounter >= 40) {
+ if (_flightSpellFrameCounter >= 40 && !(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) & (1 << idx))) {
+ debug("spell cast animation starting for room %d at frame %d, flag is %d", room, _flightFrameCounter, _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES));
_flightInBlockingAnim = true;
int spellFrames = kFlightRooms[idx].spellFrames;
int framesDone = 0;
_room->findSpriteByIndex(_flightSorcererSpriteIdx)->animData[0].nframes = kFlightRooms[idx].spellFrames;
_room->findSpriteByIndex(_flightSorcererSpriteIdx)->animData[0].speed = 1;
-
+ _sound->playSound(_room->_roomSfx[1]);
while (!shouldQuit() && framesDone < spellFrames) {
_events->pollEvent();
if (renderScene(OVERLAY_NONE))
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 69851aa4c47..10203030f87 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -225,9 +225,7 @@ void RoomManager::disableSprite(byte spriteIndex, int persist) {
}
void RoomManager::disableSprite(byte roomNumber, byte spriteIndex, int persist) {
- debug("Disabling sprite %d in room %d with persist %d", spriteIndex, roomNumber, persist);
if (roomNumber == _currentRoomNumber && persist & PERSIST_TEMP) {
- debug("Disabling sprite LOCALLY %d in room %d with persist %d", spriteIndex, roomNumber, persist);
// Search by sprite.index, not by array position: sortAnimsByZOrder reorders the
// array every frame so a raw array index is unreliable.
for (uint i = 0; i < _currentRoomAnims.size(); i++) {
@@ -249,7 +247,6 @@ void RoomManager::enableSprite(byte spriteIndex, byte zOrder, int persist) {
void RoomManager::enableSprite(byte roomNumber, byte spriteIndex, byte zOrder, int persist) {
for(int i =0; i < g_engine->_state->spriteChanges[roomNumber].size(); i++) {
if (g_engine->_state->spriteChanges[roomNumber][i].spriteIndex == spriteIndex) {
- debug("Removing pending sprite change for sprite %d in room %d", spriteIndex, roomNumber);
g_engine->_state->spriteChanges[roomNumber].remove_at(i);
break;
}
@@ -265,7 +262,6 @@ void RoomManager::enableSprite(byte roomNumber, byte spriteIndex, byte zOrder, i
}
}
if (persist & PERSIST_PERM) {
- debug("Enabling sprite %d in room %d with zOrder %d and persist %d", spriteIndex, roomNumber, zOrder, persist);
g_engine->_state->spriteChanges[roomNumber].push_back({roomNumber, spriteIndex, zOrder});
}
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index f5f1feebf6f..60e0caa505d 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -642,6 +642,22 @@ struct SaveGameData {
GameStateData *gameState = nullptr;
};
+
+struct FlightRoomCfg {
+ int roomNumber;
+ int spriteIdx;
+ int appearFrames;
+ int spellFrames;
+ int spellPage;
+};
+
+static const FlightRoomCfg kFlightRooms[] = {
+ {51, 1, 31, 17, 8}, // room 51
+ {52, 0, 30, 13, 4}, // room 52
+ {53, 1, 30, 13, 0}, // room 53
+ {54, 1, 38, 11, 2}, // room 54
+};
+
} // End of namespace Pelrock
#endif
Commit: f26de9e5e1c9fcc80f86a324fe9dce6c902a7925
https://github.com/scummvm/scummvm/commit/f26de9e5e1c9fcc80f86a324fe9dce6c902a7925
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:12+02:00
Commit Message:
PELROCK: Implements missing useless item combinations
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 0b9e9e0bbf1..b910376a5d8 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -208,6 +208,7 @@ const CombinationEntry combinationTable[] = {
{85, 506, &PelrockEngine::magicFormula},
{86, 506, &PelrockEngine::magicFormula},
{81, 506, &PelrockEngine::magicFormula},
+ {99, 506, &PelrockEngine::useWigWithPot},
{76, 617, &PelrockEngine::usePumpkinWithPond},
@@ -1263,7 +1264,6 @@ void PelrockEngine::pickUpBook(int i) {
}
void PelrockEngine::pickUpChainsaw(HotSpot *hotspot) {
-
_room->addSticker(99);
}
@@ -1708,6 +1708,11 @@ void PelrockEngine::useWaterOnFakeStone(int inventoryObject, HotSpot *hotspot) {
}
}
+void PelrockEngine::useWigWithPot(int inventoryObject, HotSpot *hotspot) {
+ _dialog->say(_res->_ingameTexts[NOERAAUTENTICO]);
+ _state->removeInventoryItem(99);
+}
+
void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
_state->removeInventoryItem(inventoryObject);
_state->setFlag(FLAG_FORMULA_MAGICA, _state->getFlag(FLAG_FORMULA_MAGICA) + 1);
@@ -1965,12 +1970,27 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
case 108:
case 109: {
+
if (_state->hasInventoryItem(110) == true) {
- _state->removeInventoryItem(110);
- _state->removeInventoryItem(109);
- _state->removeInventoryItem(108);
- addInventoryItem(83);
- _dialog->say(_res->_ingameTexts[MUNECO_ARREGLADO]);
+ if(_state->hasInventoryItem(109) == true && _state->hasInventoryItem(108) == true) {
+ _state->removeInventoryItem(110);
+ _state->removeInventoryItem(109);
+ _state->removeInventoryItem(108);
+ addInventoryItem(83);
+ _dialog->say(_res->_ingameTexts[MUNECO_ARREGLADO]);
+ return;
+ }
+ else if(_state->hasInventoryItem(109) == true) {
+ _dialog->say(_res->_ingameTexts[NOTENGOPARCHES]);
+
+ }
+ else if(_state->hasInventoryItem(108) == true) {
+ _dialog->say(_res->_ingameTexts[NOTENGOPEGAMENTO]);
+ }
+ }
+ else {
+ byte response = (byte)getRandomNumber(12);
+ _dialog->say(_res->_ingameTexts[154 + response]);
}
break;
}
@@ -1994,6 +2014,10 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
chooseCorrectDoor();
break;
}
+ case 87: {
+ _dialog->say(_res->_ingameTexts[NECESITOGASOLINA]);
+ break;
+ }
default: {
byte response = (byte)getRandomNumber(12);
_dialog->say(_res->_ingameTexts[154 + response]);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 27e0deb3ad2..b17f56082c3 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -2088,7 +2088,7 @@ void PelrockEngine::handleFlightRoomFrame() {
if (_flightInBlockingAnim)
return;
- if (_alfredState.animState != ALFRED_IDLE) {
+ if (_alfredState.animState != ALFRED_IDLE || _actionPopupState.isActive) {
return;
}
_flightFrameCounter++;
@@ -2113,10 +2113,6 @@ void PelrockEngine::handleFlightRoomFrame() {
// Phase 3: wait 40 ticks after spell trigger, then cast
if (_flightSpellCast) {
- if (_alfredState.animState != ALFRED_IDLE) {
- debug("blocking animation active at frame %d, delaying spell cast", _flightFrameCounter);
- return;
- }
debug("in spell cast phase for room %d at frame %d", room, _flightFrameCounter);
_flightSpellFrameCounter++;
if (_flightSpellFrameCounter >= 40 && !(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) & (1 << idx))) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index e27b40515a4..183d773b2bd 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -368,6 +368,7 @@ public:
void openPyramidDoor(HotSpot *hotspot);
void usePumpkinWithPond(int inventoryObject, HotSpot *hotspot);
void useWaterOnFakeStone(int inventoryObject, HotSpot *hotspot);
+ void useWigWithPot(int inventoryObject, HotSpot *hotspot);
void magicFormula(int inventoryObject, HotSpot *hotspot);
void smokeAnimation(int spriteIndex, bool hide = true);
void openArchitectDoor(HotSpot *hotspot);
Commit: 63179eff5eeb843c01d6e88aa6c3f905237fcacd
https://github.com/scummvm/scummvm/commit/63179eff5eeb843c01d6e88aa6c3f905237fcacd
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:13+02:00
Commit Message:
PELROCK: Loads CD Player screen
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/extrascreens.cpp
engines/pelrock/extrascreens.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index b910376a5d8..dffaa63087b 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -2018,6 +2018,11 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_dialog->say(_res->_ingameTexts[NECESITOGASOLINA]);
break;
}
+ case 95: {
+ CDPlayer player = CDPlayer(_events, _res, _sound);
+ player.run();
+ break;
+ }
default: {
byte response = (byte)getRandomNumber(12);
_dialog->say(_res->_ingameTexts[154 + response]);
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
index ca708c9aa72..055604dd404 100644
--- a/engines/pelrock/extrascreens.cpp
+++ b/engines/pelrock/extrascreens.cpp
@@ -123,7 +123,6 @@ void SpellBook::drawScreen() {
g_engine->_graphics->drawColoredTexts(_compositeScreen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
}
- drawPaletteSquares(_compositeScreen, _palette);
memcpy(g_engine->_screen->getPixels(), _compositeScreen, 640 * 400);
if (_spell != nullptr) {
g_engine->_graphics->drawColoredTexts(g_engine->_screen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
@@ -177,4 +176,92 @@ bool SpellBook::checkMouse(int x, int y) {
return false;
}
+
+CDPlayer::CDPlayer(PelrockEventManager *eventMan, ResourceManager *res, SoundManager *sound) : _events(eventMan), _res(res), _sound(sound) {
+ init();
+}
+
+CDPlayer::~CDPlayer() {
+ cleanup();
+}
+
+void CDPlayer::run() {
+ loadBackground();
+ loadControls();
+ g_engine->changeCursor(DEFAULT);
+
+ while(!g_engine->shouldQuit()) {
+ _events->pollEvent();
+ drawScreen();
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+ g_system->delayMillis(10);
+ }
+ memset(g_engine->_screen->getPixels(), 0, 640 * 400);
+ // Restore room palette
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+}
+
+void CDPlayer::init() {
+ _compositeScreen = new byte[640 * 400];
+}
+
+void CDPlayer::drawScreen() {
+ memcpy(_compositeScreen, _backgroundScreen, 640 * 400);
+ drawSpriteToBuffer(_compositeScreen, 640, _controls, 0, 0, 213, 72, 207);
+ memcpy(g_engine->_screen->getPixels(), _compositeScreen, 640 * 400);
+}
+
+void CDPlayer::loadBackground() {
+ _backgroundScreen = new byte[640 * 400];
+ _palette = new byte[768];
+ _res->getExtraScreen(10, _backgroundScreen, _palette);
+ g_system->getPaletteManager()->setPalette(_palette, 0, 256);
+}
+
+void CDPlayer::cleanup() {
+ if (_backgroundScreen) {
+ delete[] _backgroundScreen;
+ _backgroundScreen = nullptr;
+ }
+
+ if (_palette) {
+ delete[] _palette;
+ _palette = nullptr;
+ }
+
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+}
+
+void CDPlayer::checkMouse(int x, int y) {
+
+}
+
+void CDPlayer::loadControls() {
+ _controls = new byte[213*72];
+ Common::File alfred7;
+ if (!alfred7.open("ALFRED.7")) {
+ return;
+ }
+ alfred7.seek(2214760, SEEK_SET);
+ byte *compressedData = nullptr;
+ size_t outSize = 0;
+ readUntilBuda(&alfred7, 2214760, compressedData, outSize);
+ byte *rawData = nullptr;
+
+ size_t decompressedSize = rleDecompress(compressedData, outSize, 0, 0, &rawData, true);
+
+ debug("Decompressed CD player controls: %d bytes", decompressedSize);
+ Common::copy(rawData, rawData + 213 * 72, _controls);
+ // for(int i = 0; i < 5; i++) {
+ // for (int j = 0; j < 2; j++) {
+ // buttons[i][j] = _controls + (i * 2 + j) * 213 * 72;
+ // }
+ // }
+ alfred7.close();
+ delete[] compressedData;
+ delete[] rawData;
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/extrascreens.h b/engines/pelrock/extrascreens.h
index 6be65f30087..da1624e4a1e 100644
--- a/engines/pelrock/extrascreens.h
+++ b/engines/pelrock/extrascreens.h
@@ -87,6 +87,56 @@ private:
bool checkMouse(int x, int y);
};
+
+class CDPlayer {
+
+public:
+ CDPlayer(PelrockEventManager *eventMan, ResourceManager *res, SoundManager *sound);
+ ~CDPlayer();
+
+ void run();
+
+private:
+ void init();
+ void drawScreen();
+ void loadBackground();
+ void loadControls();
+ void checkMouse(int x, int y);
+ void cleanup();
+ ResourceManager *_res;
+ SoundManager *_sound;
+ PelrockEventManager *_events;
+ byte *_backgroundScreen;
+ byte *_compositeScreen;
+ byte *_palette;
+ byte *_controls;
+ byte *buttons[5][2];
+};
+
+
+class BackgroundBook {
+
+public:
+ BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res);
+ ~BackgroundBook();
+
+ void run();
+
+private:
+ void init();
+ void drawScreen();
+ void loadBackground();
+ void loadControls();
+ void checkMouse(int x, int y);
+ void cleanup();
+ PelrockEventManager *_events;
+ ResourceManager *_res;
+ byte *_backgroundScreen;
+ byte *_compositeScreen;
+ byte *_palette;
+ byte *_controls;
+};
+
} // End of namespace Pelrock
#endif // PELROCK_EXTRASCREENS_H
Commit: 14945d2f9c14166908b84bda6071a1b93a7f1572
https://github.com/scummvm/scummvm/commit/14945d2f9c14166908b84bda6071a1b93a7f1572
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:13+02:00
Commit Message:
PELROCK: CD Player (except pause)
Changed paths:
engines/pelrock/extrascreens.cpp
engines/pelrock/extrascreens.h
engines/pelrock/pelrock.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
index 055604dd404..2fe16abdc6c 100644
--- a/engines/pelrock/extrascreens.cpp
+++ b/engines/pelrock/extrascreens.cpp
@@ -176,7 +176,6 @@ bool SpellBook::checkMouse(int x, int y) {
return false;
}
-
CDPlayer::CDPlayer(PelrockEventManager *eventMan, ResourceManager *res, SoundManager *sound) : _events(eventMan), _res(res), _sound(sound) {
init();
}
@@ -186,12 +185,18 @@ CDPlayer::~CDPlayer() {
}
void CDPlayer::run() {
- loadBackground();
- loadControls();
+
g_engine->changeCursor(DEFAULT);
- while(!g_engine->shouldQuit()) {
+ while (!g_engine->shouldQuit()) {
_events->pollEvent();
+ checkMouse(_events->_mouseX, _events->_mouseY);
+
+ if (_events->_rightMouseClicked) {
+ _events->_rightMouseClicked = false;
+ break;
+ }
+
drawScreen();
g_engine->_screen->markAllDirty();
g_engine->_screen->update();
@@ -204,12 +209,45 @@ void CDPlayer::run() {
void CDPlayer::init() {
_compositeScreen = new byte[640 * 400];
+ loadBackground();
+ loadControls();
+ loadTrackNames();
+}
+
+void CDPlayer::loadTrackNames() {
+ Common::File juegoFile;
+ if (!juegoFile.open("JUEGO.EXE")) {
+ return;
+ }
+ juegoFile.seek(0x049893, SEEK_SET);
+
+ for (int i = 0; i < 31; i++) {
+ trackNames[i] = juegoFile.readString(0, 30);
+ debug("Loaded track name: %s", trackNames[i].c_str());
+ }
+
+ juegoFile.close();
}
void CDPlayer::drawScreen() {
memcpy(_compositeScreen, _backgroundScreen, 640 * 400);
- drawSpriteToBuffer(_compositeScreen, 640, _controls, 0, 0, 213, 72, 207);
+ drawSpriteToBuffer(_compositeScreen, 640, _controls, 1, 1, 213, 72, 207);
+
+ drawButtons();
+
memcpy(g_engine->_screen->getPixels(), _compositeScreen, 640 * 400);
+ g_engine->_smallFont->drawString(g_engine->_screen, trackNames[_selectedTrack - 2], 26, 17, 640, 255, Graphics::kTextAlignLeft);
+}
+
+void CDPlayer::drawButtons() {
+
+ for (int i = 0; i < 5; i++) {
+ if (_selectedButton == i) {
+ drawSpriteToBuffer(_compositeScreen, 640, buttons[i][1], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ } else {
+ drawSpriteToBuffer(_compositeScreen, 640, buttons[i][0], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ }
+ }
}
void CDPlayer::loadBackground() {
@@ -230,16 +268,64 @@ void CDPlayer::cleanup() {
_palette = nullptr;
}
+ for (int i = 0; i < 5; i++) {
+ delete[] buttons[i][0];
+ delete[] buttons[i][1];
+ }
+
g_engine->_screen->markAllDirty();
g_engine->_screen->update();
}
void CDPlayer::checkMouse(int x, int y) {
+ if (_events->_leftMouseClicked) {
+ switch (_selectedButton) {
+ case STOP_BUTTON:
+ _sound->stopMusic();
+ break;
+ case PAUSE_BUTTON:
+ _sound->pauseMusic();
+ break;
+ case PLAY_BUTTON:
+ _sound->stopMusic();
+ _sound->playMusicTrack(_selectedTrack, true);
+ break;
+ case PREVIOUS_BUTTON:
+ if (_selectedTrack > 2) {
+ _selectedTrack--;
+ }
+ break;
+ case NEXT_BUTTON:
+ if (_selectedTrack < 32) {
+ _selectedTrack++;
+ }
+ break;
+ default:
+ break;
+ }
+ _selectedButton = NO_BUTTON;
+ _events->_leftMouseClicked = false;
+ }
+ if (_events->_leftMouseButton != 0 && _selectedButton == NO_BUTTON) {
+ _selectedButton = isButtonClicked(_events->_mouseX, _events->_mouseY);
+ if(_selectedButton != NO_BUTTON) {
+ _sound->playSound("11ZZZZZZ.SMP", 0);
+ }
+ }
+}
+
+CDPlayer::CDControls CDPlayer::isButtonClicked(int x, int y) {
+ for (int i = 0; i < 5; i++) {
+ if (_buttonRects[i].contains(x, y)) {
+ return static_cast<CDControls>(i);
+ }
+ }
+ return NO_BUTTON;
}
void CDPlayer::loadControls() {
- _controls = new byte[213*72];
+ _controls = new byte[213 * 72];
Common::File alfred7;
if (!alfred7.open("ALFRED.7")) {
return;
@@ -253,12 +339,17 @@ void CDPlayer::loadControls() {
size_t decompressedSize = rleDecompress(compressedData, outSize, 0, 0, &rawData, true);
debug("Decompressed CD player controls: %d bytes", decompressedSize);
- Common::copy(rawData, rawData + 213 * 72, _controls);
- // for(int i = 0; i < 5; i++) {
- // for (int j = 0; j < 2; j++) {
- // buttons[i][j] = _controls + (i * 2 + j) * 213 * 72;
- // }
- // }
+ uint32 pos = 213 * 72;
+ Common::copy(rawData, rawData + pos, _controls);
+ for (int i = 0; i < 5; i++) {
+ for (int j = 0; j < 2; j++) {
+ int w = _buttonRects[i].width();
+ int h = _buttonRects[i].height();
+ buttons[i][j] = new byte[w * h];
+ Common::copy(rawData + pos, rawData + pos + w * h, buttons[i][j]);
+ pos += w * h;
+ }
+ }
alfred7.close();
delete[] compressedData;
delete[] rawData;
diff --git a/engines/pelrock/extrascreens.h b/engines/pelrock/extrascreens.h
index da1624e4a1e..285bbb51e72 100644
--- a/engines/pelrock/extrascreens.h
+++ b/engines/pelrock/extrascreens.h
@@ -90,6 +90,15 @@ private:
class CDPlayer {
+enum CDControls {
+ STOP_BUTTON,
+ PAUSE_BUTTON,
+ PLAY_BUTTON,
+ PREVIOUS_BUTTON,
+ NEXT_BUTTON,
+ NO_BUTTON
+};
+
public:
CDPlayer(PelrockEventManager *eventMan, ResourceManager *res, SoundManager *sound);
~CDPlayer();
@@ -98,11 +107,14 @@ public:
private:
void init();
+ void loadTrackNames();
void drawScreen();
+ void drawButtons();
void loadBackground();
void loadControls();
void checkMouse(int x, int y);
void cleanup();
+ CDControls isButtonClicked(int x, int y);
ResourceManager *_res;
SoundManager *_sound;
PelrockEventManager *_events;
@@ -111,6 +123,17 @@ private:
byte *_palette;
byte *_controls;
byte *buttons[5][2];
+ Common::String trackNames[31];
+ Common::Rect _buttonRects[5] = {
+ Common::Rect(Common::Point(17, 46), 37, 26), // Stop
+ Common::Rect(Common::Point(57, 48), 33, 23), // Pause
+ Common::Rect(Common::Point(92, 44), 34, 28), // Play
+ Common::Rect(Common::Point(128, 45), 38, 24), // Previous
+ Common::Rect(Common::Point(168, 44), 41, 28) // Next
+ };
+ int _selectedTrack = 2;
+ CDControls _selectedButton = NO_BUTTON;
+
};
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b17f56082c3..fb75db39f6b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -159,7 +159,8 @@ void PelrockEngine::init() {
// setScreen(22, ALFRED_DOWN);
// setScreen(41, ALFRED_DOWN);
// setScreen(43, ALFRED_DOWN);
- setScreen(46, ALFRED_RIGHT);
+ // setScreen(46, ALFRED_RIGHT);
+ setScreen(0, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -1567,26 +1568,31 @@ void PelrockEngine::gameLoop() {
_events->pollEvent();
checkMouse();
- // if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_m) {
- // travelToEgypt();
- // _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- // }
- // if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_n) {
- // loadExtraScreenAndPresent(10);
- // _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- // }
- // if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_p) {
- // antiPiracyEffect();
- // _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- // }
- // if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_s) {
- // SpellBook spellBook(_events, _res);
- // Spell *selectedSpell = spellBook.run();
- // if (selectedSpell != nullptr) {
- // _dialog->sayAlfred(selectedSpell->text);
- // }
- // _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- // }
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_m) {
+ travelToEgypt();
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_n) {
+ loadExtraScreenAndPresent(10);
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_p) {
+ antiPiracyEffect();
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_s) {
+ SpellBook spellBook(_events, _res);
+ Spell *selectedSpell = spellBook.run();
+ if (selectedSpell != nullptr) {
+ _dialog->sayAlfred(selectedSpell->text);
+ }
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_c) {
+ CDPlayer cdPlayer(_events, _res, _sound);
+ cdPlayer.run();
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
renderScene();
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index cee1f3675ca..4eef53ddf46 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -208,9 +208,20 @@ bool SoundManager::isPlaying(int channel) const {
}
void SoundManager::stopMusic() {
+ _isPaused = false;
g_system->getAudioCDManager()->stop();
}
+void SoundManager::pauseMusic() {
+ uint32 elapsed = g_system->getMillis() - _cdPlayStartTime;
+ uint32 elapsedFrames = elapsed * 75 / 1000;
+ _cdTrackStart += elapsedFrames; // advance the start offset
+ if (_cdTrackDuration > 0)
+ _cdTrackDuration -= elapsedFrames; // shrink remaining duration
+ g_system->getAudioCDManager()->stop();
+ _isPaused = true;
+}
+
bool SoundManager::isMusicPlaying() {
return g_system->getAudioCDManager()->isPlaying();
}
@@ -221,8 +232,11 @@ void SoundManager::playMusicTrack(int trackNumber, bool loop) {
return;
}
_currentMusicTrack = trackNumber;
+ _cdTrackStart = 0;
+ _cdTrackDuration = 0;
+ _cdPlayStartTime = g_system->getMillis();
g_system->getAudioCDManager()->stop();
- g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 0, 0, 0);
+ g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 0, _cdTrackStart, _cdTrackDuration);
}
void SoundManager::loadSoundIndex() {
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index bd3f27ed6db..631732ab58a 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -162,17 +162,16 @@ public:
void playSound(byte *soundData, uint32 size);
void stopAllSounds();
void stopSound(int channel);
- void stopMusic();
- bool isMusicPlaying();
void setVolume(int volume);
bool isPlaying() const;
bool isPlaying(int channel) const;
- void playMusicTrack(int trackNumber, bool loop = true);
- bool isMusicPlaying() const {
- return _isMusicPlaying;
- }
void loadSoundIndex();
+ bool isMusicPlaying();
+ void playMusicTrack(int trackNumber, bool loop = true);
+ void stopMusic();
+ void pauseMusic();
+
/**
* Check if ambient sound should play this frame.
* @param frameCount Current game frame counter
@@ -197,6 +196,11 @@ private:
Audio::SoundHandle _sfxHandles[kMaxChannels];
Common::HashMap<Common::String, SonidoFile> _soundMap;
+
+ uint32 _cdTrackStart = 0;
+ uint32 _cdTrackDuration;
+ uint32 _cdPlayStartTime; // time at the moment of calling play()
+ bool _isPaused = false;
};
} // End of namespace Pelrock
Commit: 3f7f9b75f0028887261cd9f4d795a519b1725556
https://github.com/scummvm/scummvm/commit/3f7f9b75f0028887261cd9f4d795a519b1725556
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:13+02:00
Commit Message:
PELROCK: Implements background book
Changed paths:
engines/pelrock/extrascreens.cpp
engines/pelrock/extrascreens.h
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/sound.cpp
engines/pelrock/sound.h
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
index 2fe16abdc6c..446a8e986d8 100644
--- a/engines/pelrock/extrascreens.cpp
+++ b/engines/pelrock/extrascreens.cpp
@@ -205,6 +205,8 @@ void CDPlayer::run() {
memset(g_engine->_screen->getPixels(), 0, 640 * 400);
// Restore room palette
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+ _sound->stopMusic();
+ _sound->playMusicTrack(g_engine->_room->_musicTrack, true);
}
void CDPlayer::init() {
@@ -287,8 +289,13 @@ void CDPlayer::checkMouse(int x, int y) {
_sound->pauseMusic();
break;
case PLAY_BUTTON:
- _sound->stopMusic();
- _sound->playMusicTrack(_selectedTrack, true);
+ if(_sound->_isPaused && _sound->_currentMusicTrack == _selectedTrack) {
+ _sound->playMusicTrack(_selectedTrack, true);
+ }
+ else {
+ _sound->stopMusic();
+ _sound->playMusicTrack(_selectedTrack, true);
+ }
break;
case PREVIOUS_BUTTON:
if (_selectedTrack > 2) {
@@ -355,4 +362,185 @@ void CDPlayer::loadControls() {
delete[] rawData;
}
+BackgroundBook::BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res) : _events(eventMan), _res(res) {
+ init();
+}
+
+BackgroundBook::~BackgroundBook() {
+ cleanup();
+}
+
+void BackgroundBook::run() {
+ g_engine->changeCursor(DEFAULT);
+ while (!g_engine->shouldQuit()) {
+ _events->pollEvent();
+ checkMouse(_events->_mouseX, _events->_mouseY);
+
+ if (_events->_rightMouseClicked) {
+ _events->_rightMouseClicked = false;
+ break;
+ }
+
+ drawScreen();
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+ g_system->delayMillis(10);
+ }
+ memset(g_engine->_screen->getPixels(), 0, 640 * 400);
+ // Restore room palette
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+}
+
+void BackgroundBook::init() {
+ _compositeScreen = new byte[640 * 400];
+ loadBackground();
+ loadButtons();
+ loadRoomNames();
+}
+
+void BackgroundBook::checkMouse(int x, int y) {
+ if (_events->_leftMouseClicked) {
+ switch (_selectedButton) {
+ case PREVIOUS_BUTTON:
+ if (_selectedPage > 0) {
+ _selectedPage--;
+ }
+ break;
+ case NEXT_BUTTON:
+ if ((_selectedPage + 1) * kItemsPerPage < _roomNames.size()) {
+ _selectedPage++;
+ }
+ break;
+ default:
+ break;
+ }
+ _selectedButton = NO_BUTTON;
+
+ int firstItem = _selectedPage * kItemsPerPage;
+ if (y >= 72 && y < 72 + (kItemsPerPage * g_engine->_smallFont->getFontHeight()) && x >= 37 && x <= 37 + 200) {
+ int itemIndex = (y - 72) / g_engine->_smallFont->getFontHeight();
+ if (firstItem + itemIndex < _roomNames.size()) {
+ Common::String roomName = _roomNames[firstItem + itemIndex];
+ debug("Selected room: %s", roomName.c_str());
+ }
+ }
+
+ _events->_leftMouseClicked = false;
+ }
+
+ if (_events->_leftMouseButton != 0 && _selectedButton == NO_BUTTON) {
+ _selectedButton = isButtonClicked(_events->_mouseX, _events->_mouseY);
+ }
+}
+
+BackgroundBook::Buttons BackgroundBook::isButtonClicked(int x, int y) {
+ for (int i = 0; i < 2; i++) {
+ if (_buttonRects[i].contains(x, y)) {
+ return static_cast<Buttons>(i);
+ }
+ }
+ return NO_BUTTON;
+}
+
+void BackgroundBook::loadRoomNames() {
+ Common::StringArray roomNames;
+ Common::File juegoExe;
+ if (!juegoExe.open(Common::Path("JUEGO.EXE"))) {
+ error("Couldnt find file JUEGO.EXE");
+ }
+
+ size_t namesSize = 1335;
+ juegoExe.seek(0x49315, SEEK_SET);
+ byte *namesData = new byte[namesSize];
+ juegoExe.read(namesData, namesSize);
+ uint32 pos = 0;
+ Common::String currentName = "";
+ while (pos < namesSize) {
+ if (namesData[pos] == 0xFD &&
+ namesData[pos + 1] == 0x00 &&
+ namesData[pos + 2] == 0x08 &&
+ namesData[pos + 3] == 0x02) {
+ if (currentName.size() > 0) {
+ roomNames.push_back(currentName);
+ }
+ currentName = "";
+ pos += 4;
+ continue;
+ }
+ currentName += (char)namesData[pos];
+ pos++;
+ }
+ delete[] namesData;
+ juegoExe.close();
+ _roomNames = roomNames;
+}
+
+
+void BackgroundBook::drawScreen() {
+ memcpy(_compositeScreen, _backgroundScreen, 640 * 400);
+ drawButtons();
+ memcpy(g_engine->_screen->getPixels(), _compositeScreen, 640 * 400);
+
+
+ int firstItem = _selectedPage * kItemsPerPage;
+ for(int i = 0; i < kItemsPerPage; i++) {
+ if(firstItem + i >= _roomNames.size()) {
+ break;
+ }
+ // g_engine->_graphics->drawColoredTexts(_compositeScreen, _roomNames[i], 37, 72 + (i * g_engine->_smallFont->getFontHeight()), 640, 0, Graphics::kTextAlignLeft);
+ // g_engine->_graphics->drawColoredTexts(_compositeScreen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
+ g_engine->_smallFont->drawString(g_engine->_screen, _roomNames[firstItem + i], 37, 72 + (i * g_engine->_smallFont->getFontHeight()), 640, 2, Graphics::kTextAlignLeft);
+ }
+}
+
+void BackgroundBook::drawButtons() {
+ for (int i = 0; i < 2; i++) {
+ if (_selectedButton == i) {
+ drawSpriteToBuffer(_compositeScreen, 640, _buttons[i][0], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ } else {
+ drawSpriteToBuffer(_compositeScreen, 640, _buttons[i][1], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ }
+ }
+}
+
+void BackgroundBook::loadBackground() {
+ _backgroundScreen = new byte[640 * 400];
+ _palette = new byte[768];
+ _res->getExtraScreen(13, _backgroundScreen, _palette);
+ g_system->getPaletteManager()->setPalette(_palette, 0, 256);
+}
+
+void BackgroundBook::loadButtons() {
+ Common::File alfred7;
+ if (!alfred7.open("ALFRED.7")) {
+ return;
+ }
+ alfred7.seek(3188448, SEEK_SET);
+ for(int i = 0; i < 2; i++) {
+ for(int j = 0; j < 2; j++) {
+ int w = _buttonRects[i].width();
+ int h = _buttonRects[i].height();
+ _buttons[i][j] = new byte[w * h];
+ alfred7.read(_buttons[i][j], w * h);
+ }
+ }
+
+ alfred7.close();
+}
+
+void BackgroundBook::cleanup() {
+ if (_compositeScreen) {
+ delete[] _compositeScreen;
+ _compositeScreen = nullptr;
+ }
+ if (_backgroundScreen) {
+ delete[] _backgroundScreen;
+ _backgroundScreen = nullptr;
+ }
+ if (_palette) {
+ delete[] _palette;
+ _palette = nullptr;
+ }
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/extrascreens.h b/engines/pelrock/extrascreens.h
index 285bbb51e72..951843b1910 100644
--- a/engines/pelrock/extrascreens.h
+++ b/engines/pelrock/extrascreens.h
@@ -122,8 +122,8 @@ private:
byte *_compositeScreen;
byte *_palette;
byte *_controls;
- byte *buttons[5][2];
Common::String trackNames[31];
+ byte *buttons[5][2];
Common::Rect _buttonRects[5] = {
Common::Rect(Common::Point(17, 46), 37, 26), // Stop
Common::Rect(Common::Point(57, 48), 33, 23), // Pause
@@ -138,6 +138,12 @@ private:
class BackgroundBook {
+enum Buttons {
+ PREVIOUS_BUTTON,
+ NEXT_BUTTON,
+ NO_BUTTON
+};
+ int kItemsPerPage = 22;
public:
BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res);
@@ -147,17 +153,29 @@ public:
private:
void init();
+ void loadRoomNames();
void drawScreen();
+ void drawButtons();
+ void loadButtons();
void loadBackground();
- void loadControls();
void checkMouse(int x, int y);
+ BackgroundBook::Buttons isButtonClicked(int x, int y);
void cleanup();
+
PelrockEventManager *_events;
ResourceManager *_res;
byte *_backgroundScreen;
byte *_compositeScreen;
byte *_palette;
- byte *_controls;
+ byte *_buttons[2][2];
+ Buttons _selectedButton = NO_BUTTON;
+ int _selectedPage = 0;
+
+ Common::Rect _buttonRects[2] = {
+ Common::Rect(Common::Point(238, 104), 28, 44), // Stop
+ Common::Rect(Common::Point(238, 178), 28, 44), // Pause
+ };
+ Common::StringArray _roomNames;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 819def28a65..e54a9462521 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -487,6 +487,12 @@ const ExtraImages extraScreens[] = {
2321064,
8
},
+ {
+ 0x00226358,
+ 0x00236AA8,
+ 8
+ },
+
};
struct AlfredSpecialAnimOffset {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index fb75db39f6b..d5f25f76f14 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1593,6 +1593,11 @@ void PelrockEngine::gameLoop() {
cdPlayer.run();
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_b) {
+ BackgroundBook backgroundBook(_events, _res);
+ backgroundBook.run();
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
renderScene();
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 10203030f87..fcfa9c51877 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -29,7 +29,6 @@ namespace Pelrock {
RoomManager::RoomManager() {
_pixelsShadows = new byte[640 * 400];
- _roomNames = loadRoomNames();
loadWaterPaletteRemap();
}
@@ -1302,39 +1301,6 @@ void RoomManager::loadRemaps(int roomNumber) {
}
-Common::StringArray RoomManager::loadRoomNames() {
- Common::StringArray roomNames;
- Common::File juegoExe;
- if (!juegoExe.open(Common::Path("JUEGO.EXE"))) {
- error("Couldnt find file JUEGO.EXE");
- }
-
- size_t namesSize = 1335;
- juegoExe.seek(0x49315, SEEK_SET);
- byte *namesData = new byte[namesSize];
- juegoExe.read(namesData, namesSize);
- uint32 pos = 0;
- Common::String currentName = "";
- while (pos < namesSize) {
- if (namesData[pos] == 0xFD &&
- namesData[pos + 1] == 0x00 &&
- namesData[pos + 2] == 0x08 &&
- namesData[pos + 3] == 0x02) {
- if (currentName.size() > 0) {
- roomNames.push_back(currentName);
- }
- currentName = "";
- pos += 4;
- continue;
- }
- currentName += (char)namesData[pos];
- pos++;
- }
- delete[] namesData;
- juegoExe.close();
- return roomNames;
-}
-
byte RoomManager::loadMusicTrackForRoom(Common::File *roomFile, int roomOffset) {
uint32_t pair9offset = roomOffset + (9 * 8);
roomFile->seek(pair9offset, SEEK_SET);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index f318c66ae9c..205d7f5b012 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -130,12 +130,6 @@ public:
HotSpot *findHotspotByExtra(uint16 extra);
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
- Common::String getRoomName(int roomNumber) {
- if (roomNumber >= 0 && (uint)roomNumber < _roomNames.size()) {
- return _roomNames[roomNumber];
- }
- return "Unknown Room";
- }
byte _currentRoomNumber = 0;
int _prevRoomNumber = -1;
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 4eef53ddf46..fbb24786726 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -227,14 +227,17 @@ bool SoundManager::isMusicPlaying() {
}
void SoundManager::playMusicTrack(int trackNumber, bool loop) {
- if (_currentMusicTrack == trackNumber && isMusicPlaying()) {
+ if (!_isPaused && _currentMusicTrack == trackNumber && isMusicPlaying()) {
// Already playing this track
return;
}
_currentMusicTrack = trackNumber;
- _cdTrackStart = 0;
- _cdTrackDuration = 0;
- _cdPlayStartTime = g_system->getMillis();
+
+ if(!_isPaused) {
+ _cdTrackStart = 0;
+ _cdTrackDuration = 0;
+ _cdPlayStartTime = g_system->getMillis();
+ }
g_system->getAudioCDManager()->stop();
g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 0, _cdTrackStart, _cdTrackDuration);
}
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 631732ab58a..09a5941ac0d 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -179,6 +179,8 @@ public:
* Add kAmbientSoundSlotBase (4) to get room sound index
*/
int tickAmbientSound(uint32 frameCount);
+ bool _isPaused = false;
+ byte _currentMusicTrack = 0;
private:
void playSound(SonidoFile sound, int channel = -1);
@@ -191,7 +193,6 @@ private:
bool _isMusicPlaying = false;
int _currentVolume;
Common::File *_musicFile;
- byte _currentMusicTrack = 0;
Audio::SoundHandle _musicHandle;
Audio::SoundHandle _sfxHandles[kMaxChannels];
Common::HashMap<Common::String, SonidoFile> _soundMap;
@@ -200,7 +201,7 @@ private:
uint32 _cdTrackStart = 0;
uint32 _cdTrackDuration;
uint32 _cdPlayStartTime; // time at the moment of calling play()
- bool _isPaused = false;
+
};
} // End of namespace Pelrock
Commit: 6f69e96103cd9fad8fa3f7d7cf19940f83777922
https://github.com/scummvm/scummvm/commit/6f69e96103cd9fad8fa3f7d7cf19940f83777922
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:14+02:00
Commit Message:
PELROCK: Improves styling in Library Computer
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/computer.cpp
engines/pelrock/computer.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index dffaa63087b..994845be397 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -707,7 +707,11 @@ void PelrockEngine::noOpAction(HotSpot *hotspot) {
}
void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
- // 154 to 169
+ if(item >= 11 && item <= 47 && hotspot->extra == 358) {
+ _state->removeInventoryItem(item);
+ _dialog->say(_res->_ingameTexts[DEACUERDO_2]);
+ return;
+ }
debug("No-op item %d with hotspot %d", item, hotspot->extra);
_alfredState.direction = ALFRED_DOWN;
byte response = (byte)getRandomNumber(12);
@@ -2024,6 +2028,14 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
}
default: {
+ if(inventoryObject >= 11 && inventoryObject <= 47) {
+ _res->loadAlfredSpecialAnim(0);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+ _dialog->say(_res->_ingameTexts[LIBRO_ABURRIDO]);
+ return;
+ }
+
byte response = (byte)getRandomNumber(12);
_dialog->say(_res->_ingameTexts[154 + response]);
break;
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index 04b9d7c9005..03930f125fa 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -39,24 +39,6 @@ Computer::Computer(PelrockEventManager *eventMan)
_memorizedBookIndex(-1),
_events(eventMan) {
- // Initialize UI strings (Spanish - original game language)
- _menuTitle = "MENU PRINCIPAL";
- _menuOption1 = "1 CONSULTAR POR TITULO";
- _menuOption2 = "2 CONSULTAR POR AUTOR";
- _menuOption3 = "3 CANCELAR";
- _promptLetter = "Teclea una letra (A-Z):";
- _labelTitle = "Titulo : ";
- _labelAuthor = "Autor : ";
- _labelGenre = "Genero : ";
- _labelSituacion = "Situacion : ";
- _statusPhysical = "Estante %c, fila %d";
- _statusCatalogOnly = "Solo en catalogo";
- _optMemorizar = "(M)emorizar";
- _optSeguir = "(S)eguir";
- _optCancelar = "(C)ancelar";
- _noResults = "No se encontraron libros";
- _memorizedMsg = "Bueno... Tendre que buscar en la estanteria de la %c";
-
init();
}
@@ -87,20 +69,22 @@ void Computer::init() {
_libraryBooks.push_back(book);
}
- for(int i = 0; i < _libraryBooks.size(); i++) {
+ for (int i = 0; i < _libraryBooks.size(); i++) {
const LibraryBook &book = _libraryBooks[i];
debug("Loaded book: title='%s', author='%s', genre='%s', unknown=%d, shelf=%d, available=%d",
book.title.c_str(), book.author.c_str(), book.genre.c_str(),
book.inventoryIndex, book.shelf, book.available);
}
+ _computerText = g_engine->_res->loadComputerText();
+
_searchResults.clear();
_currentResult = 0;
_searchLetter = 0;
_memorizedBookIndex = -1;
+ _lineHeight = g_engine->_smallFont->getFontHeight();
}
-
Computer::~Computer() {
cleanup();
}
@@ -131,6 +115,7 @@ void Computer::cleanup() {
int Computer::run() {
loadBackground();
_state = STATE_MAIN_MENU;
+ g_engine->changeCursor(DEFAULT);
while (!g_engine->shouldQuit() && _state != STATE_EXIT) {
_events->pollEvent();
@@ -166,77 +151,83 @@ void Computer::drawScreen() {
// Clear to background
memcpy(g_engine->_screen->getPixels(), _backgroundScreen, 640 * 400);
- int textY = 100;
- int textX = 180;
+ int textY = 97;
+ int textX = 225;
+
+ byte defaultColor = 0; // Light gray
switch (_state) {
- case STATE_MAIN_MENU:
- g_engine->_smallFont->drawString(g_engine->_screen, _menuTitle, textX, textY, 280, 15, Graphics::kTextAlignCenter);
- g_engine->_smallFont->drawString(g_engine->_screen, _menuOption1, textX, textY + 40, 280, 14);
- g_engine->_smallFont->drawString(g_engine->_screen, _menuOption2, textX, textY + 60, 280, 14);
- g_engine->_smallFont->drawString(g_engine->_screen, _menuOption3, textX, textY + 80, 280, 14);
+ case STATE_MAIN_MENU: {
+ int textY = 97;
+ int textX = 225;
+ for (int i = 0; _computerText[0].size() > i; i++) {
+ Common::String line = _computerText[0][i];
+ g_engine->_graphics->drawColoredText(g_engine->_screen, line, textX, textY + i * _lineHeight, 200, defaultColor, g_engine->_smallFont);
+ }
break;
+ }
case STATE_SEARCH_BY_TITLE:
case STATE_SEARCH_BY_AUTHOR:
- g_engine->_smallFont->drawString(g_engine->_screen,
- _searchType == 0 ? "CONSULTAR POR TITULO" : "CONSULTAR POR AUTOR",
- textX, textY, 280, 15, Graphics::kTextAlignCenter);
- g_engine->_smallFont->drawString(g_engine->_screen, _promptLetter, textX, textY + 40, 280, 14);
+ for (int i = 0; _computerText[1].size() > i; i++) {
+ Common::String line = _computerText[1][i];
+ g_engine->_graphics->drawColoredText(g_engine->_screen, line, 172, 258 + i * _lineHeight, 200, defaultColor, g_engine->_smallFont);
+ }
break;
case STATE_SHOW_RESULTS: {
- Common::String header = Common::String::format(
- "Consulta de %s, letra %c",
- _searchType == 0 ? "TITULO" : "AUTOR",
- _searchLetter);
- g_engine->_smallFont->drawString(g_engine->_screen, header, textX, textY, 280, 15, Graphics::kTextAlignCenter);
-
- if (_searchResults.empty()) {
- g_engine->_smallFont->drawString(g_engine->_screen, _noResults, textX, textY + 50, 280, 14);
- } else {
- // Display current book
- int bookIdx = _searchResults[_currentResult];
- const LibraryBook &book = _libraryBooks[bookIdx];
-
- // Title (may be long, truncate if needed)
- Common::String titleLine = Common::String::format("%s%s", _labelTitle, book.title.c_str());
- g_engine->_smallFont->drawString(g_engine->_screen, titleLine, textX - 50, textY + 40, 340, 14);
- // Author
- Common::String authorLine = Common::String::format("%s%s", _labelAuthor, book.author.c_str());
- g_engine->_smallFont->drawString(g_engine->_screen, authorLine, textX - 50, textY + 60, 340, 14);
-
- // Genre
- Common::String genreLine = Common::String::format("%s%s", _labelGenre, book.genre.c_str());
- g_engine->_smallFont->drawString(g_engine->_screen, genreLine, textX - 50, textY + 80, 340, 14);
-
- // Situacion (location/availability)
- Common::String situacionLine;
- if (book.available) {
- situacionLine = Common::String::format("%s Estanteria %d",
- _labelSituacion, book.shelf);
- } else {
- situacionLine = Common::String::format("%s%s",
- _labelSituacion, _statusCatalogOnly);
- }
- g_engine->_smallFont->drawString(g_engine->_screen, situacionLine, textX - 50, textY + 100, 340,
- book.available ? 10 : 8); // Green if physical, gray if catalog-only
-
- // Show result counter
- Common::String counter = Common::String::format("Libro %d de %d",
- _currentResult + 1, (int)_searchResults.size());
- g_engine->_smallFont->drawString(g_engine->_screen, counter, textX, textY + 130, 280, 14, Graphics::kTextAlignCenter);
-
- // Show navigation options
- Common::String navOptions;
- if (book.available) {
- navOptions = Common::String::format("%s %s %s", _optMemorizar, _optSeguir, _optCancelar);
- } else {
- navOptions = Common::String::format("%s %s", _optSeguir, _optCancelar);
- }
- g_engine->_smallFont->drawString(g_engine->_screen, navOptions, textX, textY + 160, 280, 8, Graphics::kTextAlignCenter);
+ const char *section = _searchType == 0 ? "TITULO " : "AUTOR ";
+ Common::String title = _computerText[2][0];
+ int replacementIndex = title.findFirstOf("XXXXXXX");
+
+ title.replace(replacementIndex, 7, section);
+ int replacementIndex2 = title.findFirstOf("X");
+ title.replace(replacementIndex2, 1, Common::String(1, _searchLetter));
+ g_engine->_graphics->drawColoredText(g_engine->_screen, title, 210, 97, 200, defaultColor, g_engine->_smallFont);
+
+ int textX = 161;
+ int textY = 131;
+ int increment = 28;
+
+ // Display current book
+ int bookIdx = _searchResults[_currentResult];
+ const LibraryBook &book = _libraryBooks[bookIdx];
+
+ // Title (may be long, truncate if needed)
+ Common::String titleLine = _computerText[3][0];
+ int titlePlaceholderIndex = titleLine.findFirstOf("XXXX");
+
+ titleLine.replace(titlePlaceholderIndex, titleLine.size() - titlePlaceholderIndex, book.title);
+ g_engine->_graphics->drawColoredText(g_engine->_screen, titleLine, textX, textY, 340, defaultColor, g_engine->_smallFont);
+
+ // Author
+ Common::String authorLine = _computerText[4][0];
+ int authorPlaceholderIndex = authorLine.findFirstOf("XXXX");
+ authorLine.replace(authorPlaceholderIndex, authorLine.size() - authorPlaceholderIndex, book.author);
+ g_engine->_graphics->drawColoredText(g_engine->_screen, authorLine, textX, textY + increment, 340, defaultColor, g_engine->_smallFont);
+
+ // Genre
+ Common::String genreLine = _computerText[5][0];
+ int genrePlaceholderIndex = genreLine.findFirstOf("XXXX");
+ genreLine.replace(genrePlaceholderIndex, genreLine.size() - genrePlaceholderIndex, book.genre);
+ g_engine->_graphics->drawColoredText(g_engine->_screen, genreLine, textX, textY + increment * 2, 340, defaultColor, g_engine->_smallFont);
+
+ // Situacion (location/availability)
+ Common::String situacionLine = _computerText[6][0];
+ int situacionPlaceholderIndex = situacionLine.findFirstOf("XXXX");
+ situacionLine.replace(situacionPlaceholderIndex, situacionLine.size() - situacionPlaceholderIndex, book.available ? "Disponible" : "Prestado");
+ g_engine->_graphics->drawColoredText(g_engine->_screen, situacionLine, textX, textY + increment * 3, 340, defaultColor, g_engine->_smallFont);
+
+ // Show navigation options
+ Common::String navOptions;
+ Common::String actions = _computerText[7][0];
+ if (!book.available) {
+ actions.setChar(180, 1);
+ actions.setChar(180, 4);
}
+ g_engine->_graphics->drawColoredText(g_engine->_screen, actions, 174, 258, 325, defaultColor, g_engine->_smallFont);
+
} break;
case STATE_EXIT:
@@ -263,8 +254,13 @@ void Computer::handleSearchInput() {
_events->_lastKeyEvent <= Common::KEYCODE_z) {
_searchLetter = 'A' + (_events->_lastKeyEvent - Common::KEYCODE_a);
performSearch();
- _currentResult = 0;
- _state = STATE_SHOW_RESULTS;
+ if (!_searchResults.empty()) {
+ _currentResult = 0;
+ _state = STATE_SHOW_RESULTS;
+ } else {
+ // No results, return to main menu
+ _state = STATE_MAIN_MENU;
+ }
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
} else if (_events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
_state = STATE_MAIN_MENU;
diff --git a/engines/pelrock/computer.h b/engines/pelrock/computer.h
index 7f0117c9f4c..ea1ba3c0a88 100644
--- a/engines/pelrock/computer.h
+++ b/engines/pelrock/computer.h
@@ -65,22 +65,9 @@ private:
Common::Array<LibraryBook> _libraryBooks;
int _currentResult;
int _memorizedBookIndex; // Index of book that was memorized (-1 if none)
+ int _lineHeight;
- const char *_menuTitle;
- const char *_menuOption1; // "CONSULTAR POR TITULO"
- const char *_menuOption2; // "CONSULTAR POR AUTOR"
- const char *_menuOption3; // "CANCELAR"
- const char *_promptLetter; // "Teclea una letra (A-Z):"
- const char *_labelTitle; // "Titulo : "
- const char *_labelAuthor; // "Autor : "
- const char *_labelGenre; // "Genero : "
- const char *_labelSituacion; // "Situacion : "
- const char *_statusPhysical; // "Estante %c, fila %d"
- const char *_statusCatalogOnly; // "Solo en catalogo"
- const char *_optMemorizar; // "(M)emorizar"
- const char *_optSeguir; // "(S)eguir"
- const char *_optCancelar; // "(C)ancelar"
- const char *_noResults; // "No se encontraron libros"
+ Common::Array<Common::StringArray> _computerText;
void loadBackground();
void cleanup();
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index d5f25f76f14..a6b9914545e 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1598,6 +1598,12 @@ void PelrockEngine::gameLoop() {
backgroundBook.run();
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_w) {
+ Computer computer(_events);
+
+ computer.run();
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
renderScene();
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index d5723293b27..3ea8726e44e 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -379,6 +379,24 @@ void ResourceManager::getPaletteForRoom28(byte *palette) {
alfred7.close();
}
+
+Common::Array<Common::StringArray> ResourceManager::loadComputerText() {
+
+ Common::File exe;
+ if (!exe.open("JUEGO.EXE")) {
+ error("Couldnt find file JUEGO.EXE");
+ }
+ int bufSize = 416;
+ byte *computerTextBuf = new byte[bufSize];
+ exe.seek(0x0004901A, SEEK_SET);
+ exe.read(computerTextBuf, bufSize);
+ Common::Array<Common::StringArray> computerTexts = processTextData(computerTextBuf, bufSize);
+
+ delete[] computerTextBuf;
+
+ exe.close();
+ return computerTexts;
+}
void ResourceManager::getExtraScreen(int screenIndex, byte *screenBuf, byte *palette) {
Common::File alfred7;
if (!alfred7.open("ALFRED.7")) {
@@ -416,6 +434,7 @@ Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data,
Common::StringArray lines;
Common::Array<Common::StringArray> texts;
while (pos < size) {
+ debug("Processing byte %02X at pos %d", data[pos], pos);
if (data[pos] == CTRL_END_TEXT) {
if (!desc.empty()) {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 679a484f028..400631e683d 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -51,7 +51,7 @@ public:
void loadInventoryItems();
void loadHardcodedText();
void getPaletteForRoom28(byte *palette);
- Common::StringArray loadComputerText();
+ Common::Array<Common::StringArray> loadComputerText();
void getExtraScreen(int screenIndex, byte *screenBuf, byte *palette);
Common::Array<Common::StringArray> getCredits();
Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size, bool decode = false);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 205d7f5b012..5257e5fadb0 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -172,7 +172,6 @@ private:
byte loadMusicTrackForRoom(Common::File *roomFile, int roomOffset);
Common::Array<byte> loadRoomSfx(Common::File *roomFile, int roomOffset);
- Common::StringArray _roomNames;
byte *_resetData = nullptr;
};
Commit: ccc3065030de380733dd0d11b1063816075a8cfe
https://github.com/scummvm/scummvm/commit/ccc3065030de380733dd0d11b1063816075a8cfe
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:14+02:00
Commit Message:
PELROCK: Implements ending cutscene on room 52
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.cpp
engines/pelrock/console.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 994845be397..a84b7b5fe51 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -707,7 +707,7 @@ void PelrockEngine::noOpAction(HotSpot *hotspot) {
}
void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
- if(item >= 11 && item <= 47 && hotspot->extra == 358) {
+ if (item >= 11 && item <= 47 && hotspot->extra == 358) {
_state->removeInventoryItem(item);
_dialog->say(_res->_ingameTexts[DEACUERDO_2]);
return;
@@ -1834,7 +1834,86 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
_dialog->say(_res->_ingameTexts[NOSETEOCURRAACERCARTE]);
break;
}
+ case 375: {
+ endingScene();
+ break;
+ }
+ }
+}
+
+void PelrockEngine::endingScene() {
+ int phase = 0;
+
+ int lines[5][4] = {
+ {57, 176, 301, 322},
+ {138, 159, 283, 292},
+ {213, 156, 325, 277},
+ {460, 163, 370, 292},
+ {530, 167, 353, 320}};
+
+ int stickers[5] = {113, 114, 110, 111, 112};
+
+ while (phase < 5) {
+ debug("Starting ending scene phase %d", phase);
+ for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ debug("Current room anim %d: zOrder %d, disableAfterSequence %d", _room->_currentRoomAnims[i].index, _room->_currentRoomAnims[i].zOrder, _room->_currentRoomAnims[i].disableAfterSequence);
+ }
+ Sprite *thisSprite = _room->findSpriteByIndex(phase + 1);
+ thisSprite->animData[0].curFrame = 0;
+ thisSprite->zOrder = 200;
+
+ while (!shouldQuit() && _room->findSpriteByIndex(phase + 1)->zOrder != -1) {
+ _events->pollEvent();
+ renderScene(OVERLAY_NONE);
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+
+ _sound->playSound(_room->_roomSfx[3], 0);
+
+ copyBackgroundToBuffer();
+ placeStickersFirstPass();
+ updateAnimations();
+ presentFrame();
+
+ for (int i = 0; i < 19; i++) {
+ if (shouldQuit()) {
+ return;
+ }
+ int x1 = lines[phase][0];
+ int y1 = lines[phase][1];
+ int x2 = lines[phase][2] + i;
+ int y2 = lines[phase][3];
+ _screen->drawLine(x1, y1, x2, y2, 255);
+ }
+ _screen->markAllDirty();
+ _screen->update();
+ g_system->delayMillis(10);
+
+ if (shouldQuit()) {
+ return;
+ }
+
+ _room->addSticker(stickers[phase]);
+ copyBackgroundToBuffer();
+ placeStickersFirstPass();
+ updateAnimations();
+ presentFrame();
+
+ phase++;
}
+
+ _room->addSticker(115);
+ _screen->markAllDirty();
+ _screen->update();
+
+ _dialog->say(_res->_ingameTexts[MAREDEDEU]);
+
+ smokeAnimation(-1, true);
+ _state->setCurrentRoot(48, 1, 0);
+ _alfredState.x = 138;
+ _alfredState.y = 255;
+ setScreen(48, ALFRED_DOWN);
}
void PelrockEngine::useOnAlfred(int inventoryObject) {
@@ -1944,7 +2023,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
debug("Flight spell cast in room %d, spell page: %d", _room->_currentRoomNumber, spell->page);
int flightIndex = _room->_currentRoomNumber - 51;
debug("Correct page for this spell is = %d", kFlightRooms[flightIndex].spellPage);
- if(_flightSorcererAppeared && !_flightInBlockingAnim && spell->page == kFlightRooms[flightIndex].spellPage) {
+ if (_flightSorcererAppeared && !_flightInBlockingAnim && spell->page == kFlightRooms[flightIndex].spellPage) {
_state->setFlag(FLAG_COMO_ESTAN_LOS_DIOSES, _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) | (1 << flightIndex));
debug("Flight spell successful, starting animation and updating state");
debug("Updated FLAG_COMO_ESTAN_LOS_DIOSES: %d", _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES));
@@ -1976,23 +2055,20 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
case 109: {
if (_state->hasInventoryItem(110) == true) {
- if(_state->hasInventoryItem(109) == true && _state->hasInventoryItem(108) == true) {
- _state->removeInventoryItem(110);
- _state->removeInventoryItem(109);
- _state->removeInventoryItem(108);
- addInventoryItem(83);
- _dialog->say(_res->_ingameTexts[MUNECO_ARREGLADO]);
- return;
- }
- else if(_state->hasInventoryItem(109) == true) {
+ if (_state->hasInventoryItem(109) == true && _state->hasInventoryItem(108) == true) {
+ _state->removeInventoryItem(110);
+ _state->removeInventoryItem(109);
+ _state->removeInventoryItem(108);
+ addInventoryItem(83);
+ _dialog->say(_res->_ingameTexts[MUNECO_ARREGLADO]);
+ return;
+ } else if (_state->hasInventoryItem(109) == true) {
_dialog->say(_res->_ingameTexts[NOTENGOPARCHES]);
- }
- else if(_state->hasInventoryItem(108) == true) {
+ } else if (_state->hasInventoryItem(108) == true) {
_dialog->say(_res->_ingameTexts[NOTENGOPEGAMENTO]);
}
- }
- else {
+ } else {
byte response = (byte)getRandomNumber(12);
_dialog->say(_res->_ingameTexts[154 + response]);
}
@@ -2028,7 +2104,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
}
default: {
- if(inventoryObject >= 11 && inventoryObject <= 47) {
+ if (inventoryObject >= 11 && inventoryObject <= 47) {
_res->loadAlfredSpecialAnim(0);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
waitForSpecialAnimation();
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index 929d83a7205..b796869b9f0 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -32,11 +32,28 @@ PelrockConsole::PelrockConsole(PelrockEngine *engine) : GUI::Debugger(), _engine
registerCmd("setRoot", WRAP_METHOD(PelrockConsole, cmdSetRoot));
registerCmd("setFlag", WRAP_METHOD(PelrockConsole, cmdSetFlag));
registerCmd("toJail", WRAP_METHOD(PelrockConsole, cmdToJail));
+ registerCmd("removeSticker", WRAP_METHOD(PelrockConsole, cmdRemoveSticker));
}
PelrockConsole::~PelrockConsole() {
}
+bool PelrockConsole::cmdRemoveSticker(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Usage: removeSticker <stickerId>");
+ return true;
+ }
+ int stickerId = atoi(argv[1]);
+ for(int i = 0; i < g_engine->_state->stickersPerRoom[g_engine->_room->_currentRoomNumber].size(); i++) {
+ if (g_engine->_state->stickersPerRoom[g_engine->_room->_currentRoomNumber][i].stickerIndex == stickerId) {
+ g_engine->_state->stickersPerRoom[g_engine->_room->_currentRoomNumber].remove_at(i);
+ debugPrintf("Removed sticker %d from room %d\n", stickerId, g_engine->_room->_currentRoomNumber);
+ return true;
+ }
+ }
+ debugPrintf("Removed sticker %d from room %d\n", stickerId, g_engine->_room->_currentRoomNumber);
+ return true;
+}
bool PelrockConsole::cmdSetFlag(int argc, const char **argv) {
if (argc < 3) {
diff --git a/engines/pelrock/console.h b/engines/pelrock/console.h
index ff86ea92f52..a426c5d4cb6 100644
--- a/engines/pelrock/console.h
+++ b/engines/pelrock/console.h
@@ -41,6 +41,7 @@ private:
public:
PelrockConsole(PelrockEngine *engine);
~PelrockConsole() override;
+ bool cmdRemoveSticker(int argc, const char **argv);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a6b9914545e..aae60b36907 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -160,7 +160,8 @@ void PelrockEngine::init() {
// setScreen(41, ALFRED_DOWN);
// setScreen(43, ALFRED_DOWN);
// setScreen(46, ALFRED_RIGHT);
- setScreen(0, ALFRED_DOWN);
+ // setScreen(0, ALFRED_DOWN);
+ setScreen(52, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -347,7 +348,7 @@ const int kPasserbyTriggerFrameInterval = 0x3FF;
void PelrockEngine::frameTriggers() {
uint32 frameCount = _chrono->getFrameCount();
passerByAnim(frameCount);
- handleFlightRoomFrame();
+ // make();
}
void PelrockEngine::passerByAnim(uint32 frameCount) {
@@ -1605,6 +1606,11 @@ void PelrockEngine::gameLoop() {
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_e && _room->_currentRoomNumber == 52) {
+ endingScene();
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
+
renderScene();
_screen->update();
@@ -2023,6 +2029,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
case 48: {
_dialog->_goodbyeDisabled = true;
+
if (_state->getFlag(FLAG_CORRECT_DOOR_CHOSEN) == true) {
if (_state->getFlag(FLAG_TRAMPILLA_ABIERTA) == true) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 183d773b2bd..5a74bbf2d48 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -377,6 +377,7 @@ public:
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
+ void endingScene();
void animateStatuePaletteFade(bool reverse = false);
void pickUpMatches(HotSpot *hotspot);
Commit: 27d21a0a070424ed2ab28b3ba6fd37dac2f14481
https://github.com/scummvm/scummvm/commit/27d21a0a070424ed2ab28b3ba6fd37dac2f14481
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:14+02:00
Commit Message:
PELROCK: Implements scene with girl in the outro
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index a84b7b5fe51..2f98a338a01 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1835,13 +1835,13 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
break;
}
case 375: {
- endingScene();
+ teletransportToPrincess();
break;
}
}
}
-void PelrockEngine::endingScene() {
+void PelrockEngine::teletransportToPrincess() {
int phase = 0;
int lines[5][4] = {
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index e54a9462521..e5d37e1a862 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -488,10 +488,15 @@ const ExtraImages extraScreens[] = {
8
},
{
- 0x00226358,
- 0x00236AA8,
- 8
+ 0x00226358, // 13 - Background book
+ 0x00236AA8,
+ 8
},
+ {
+ 3058226, // 14 - Ending
+ 3185280,
+ 8
+ }
};
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index aae60b36907..87d0f2df065 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -154,14 +154,14 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- // setScreen(0, ALFRED_DOWN);
+ setScreen(0, ALFRED_DOWN);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
// setScreen(41, ALFRED_DOWN);
// setScreen(43, ALFRED_DOWN);
// setScreen(46, ALFRED_RIGHT);
// setScreen(0, ALFRED_DOWN);
- setScreen(52, ALFRED_DOWN);
+ // setScreen(52, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
// alfredState.x = 576;
@@ -243,14 +243,14 @@ void PelrockEngine::travelToEgypt() {
_graphics->fadeToBlack(10);
_sound->playMusicTrack(26, false);
byte *palette = new byte[768];
- if (_extraScreen == nullptr) {
- _extraScreen = new byte[640 * 400];
+ if (_bgScreen == nullptr) {
+ _bgScreen = new byte[640 * 400];
}
- _res->getExtraScreen(6, _extraScreen, palette);
+ _res->getExtraScreen(6, _bgScreen, palette);
CursorMan.showMouse(false);
g_system->getPaletteManager()->setPalette(palette, 0, 256);
- memcpy(_screen->getPixels(), _extraScreen, 640 * 400);
+ memcpy(_screen->getPixels(), _bgScreen, 640 * 400);
int frameCount = 0;
while (!shouldQuit() && frameCount < 96) {
_events->pollEvent();
@@ -273,10 +273,10 @@ void PelrockEngine::travelToEgypt() {
_graphics->clearScreen();
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
- free(_extraScreen);
- _extraScreen = nullptr;
+ free(_bgScreen);
+ _bgScreen = nullptr;
CursorMan.showMouse(true);
- delete[] _extraScreen;
+ delete[] _bgScreen;
delete[] palette;
_screen->markAllDirty();
_screen->update();
@@ -348,7 +348,7 @@ const int kPasserbyTriggerFrameInterval = 0x3FF;
void PelrockEngine::frameTriggers() {
uint32 frameCount = _chrono->getFrameCount();
passerByAnim(frameCount);
- // make();
+ handleFlightRoomFrame();
}
void PelrockEngine::passerByAnim(uint32 frameCount) {
@@ -1607,6 +1607,11 @@ void PelrockEngine::gameLoop() {
}
if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_e && _room->_currentRoomNumber == 52) {
+ teletransportToPrincess();
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
+
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_f) {
endingScene();
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
@@ -1627,7 +1632,7 @@ void PelrockEngine::computerLoop() {
}
void PelrockEngine::extraScreenLoop() {
- memcpy(_screen->getPixels(), _extraScreen, 640 * 400);
+ memcpy(_screen->getPixels(), _bgScreen, 640 * 400);
while (!shouldQuit()) {
_events->pollEvent();
@@ -1641,8 +1646,8 @@ void PelrockEngine::extraScreenLoop() {
}
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
- free(_extraScreen);
- _extraScreen = nullptr;
+ free(_bgScreen);
+ _bgScreen = nullptr;
}
void PelrockEngine::walkLoop(int16 x, int16 y, AlfredDirection direction) {
@@ -1891,16 +1896,16 @@ void PelrockEngine::setScreen(int roomNumber, AlfredDirection dir) {
void PelrockEngine::loadExtraScreenAndPresent(int screenIndex) {
byte *palette = new byte[768];
- if (_extraScreen == nullptr) {
- _extraScreen = new byte[640 * 400];
+ if (_bgScreen == nullptr) {
+ _bgScreen = new byte[640 * 400];
}
- _res->getExtraScreen(screenIndex, _extraScreen, palette);
+ _res->getExtraScreen(screenIndex, _bgScreen, palette);
CursorMan.showMouse(false);
_graphics->clearScreen();
g_system->getPaletteManager()->setPalette(palette, 0, 256);
extraScreenLoop();
CursorMan.showMouse(true);
- delete[] _extraScreen;
+ delete[] _bgScreen;
delete[] palette;
_screen->markAllDirty();
_screen->update();
@@ -2033,9 +2038,17 @@ void PelrockEngine::doExtraActions(int roomNumber) {
if (_state->getFlag(FLAG_CORRECT_DOOR_CHOSEN) == true) {
if (_state->getFlag(FLAG_TRAMPILLA_ABIERTA) == true) {
+ _dialog->say(_res->_ingameTexts[OHMISALVADOR]);
+ _dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
+ _state->setCurrentRoot(48, 1, 0);
+ walkAndAction(_room->findHotspotByExtra(634), TALK);
+
+ endingScene();
+
} else {
_dialog->say(_res->_ingameTexts[OHMISALVADOR]);
_dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
+ _state->setFlag(FLAG_TRAMPILLA_ABIERTA, true);
walkAndAction(_room->findHotspotByExtra(634), TALK);
_room->addSticker(134);
// wait a few frames
@@ -2051,6 +2064,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
_alfredState.x = 294;
_alfredState.y = 387;
+ _room->addSticker(136);
setScreen(49, ALFRED_UP);
}
} else {
@@ -2085,6 +2099,138 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
}
+void PelrockEngine::endingScene() {
+ byte *palette = new byte[768];
+ if (_bgScreen == nullptr) {
+ _bgScreen = new byte[640 * 400];
+ }
+ _res->getExtraScreen(14, _bgScreen, palette);
+ CursorMan.showMouse(false);
+ _graphics->clearScreen();
+ g_system->getPaletteManager()->setPalette(palette, 0, 256);
+ Common::File alfred7;
+ if (!alfred7.open(Common::Path("ALFRED.7"))) {
+ error("Could not open ALFRED.7");
+ return;
+ }
+ byte *decompressedBuf = nullptr;
+ size_t decompressedSize = 0;
+ rleDecompressSingleBuda(&alfred7, 3222250, decompressedBuf, decompressedSize);
+ alfred7.close();
+
+ int animValues[4][8] = {
+ {426, 211, 114, 189, 2, 2, 0, 0}, // Legs anim values (2 frames)
+ {287, 68, 42, 26, 3, 1, 1, 15}, // Eyes anim values (3 frames)
+ {172, 173, 93, 71, 3, 1, 3, 17}, // Alfred hand anim values (3 frames)
+ {241, 334, 55, 66, 2, 2, 0, 0} // Hand anim values (2 frames)
+ };
+
+ uint32 pos = 0;
+ Common::Array<Sprite *> sprites;
+ for (int i = 0; i < 4; i++) {
+ Sprite *sprite = new Sprite();
+ sprite->x = animValues[i][0];
+ sprite->y = animValues[i][1];
+ sprite->w = animValues[i][2];
+ sprite->h = animValues[i][3];
+ sprite->stride = animValues[i][2] * animValues[i][3];
+ bool idleAnim = animValues[i][7] > 0;
+ if (idleAnim) {
+ sprite->numAnims = 2;
+ } else {
+ sprite->numAnims = 1;
+ }
+
+ sprite->animData = new Anim[sprite->numAnims];
+ Anim mainAnim;
+ mainAnim.nframes = animValues[i][4];
+ mainAnim.loopCount = animValues[i][6];
+ mainAnim.speed = animValues[i][5];
+
+ byte *legsAnimData = new byte[sprite->stride * mainAnim.nframes];
+ Common::copy(decompressedBuf + pos, decompressedBuf + pos + sprite->stride * mainAnim.nframes, legsAnimData);
+ mainAnim.animData = new byte *[mainAnim.nframes];
+ for (int j = 0; j < mainAnim.nframes; j++) {
+ mainAnim.animData[j] = new byte[sprite->stride];
+ extractSingleFrame(legsAnimData, mainAnim.animData[j], j, sprite->w, sprite->h);
+ }
+
+ if (idleAnim) {
+ Anim idleAnim;
+ idleAnim.nframes = 1;
+ idleAnim.loopCount = 1;
+ idleAnim.speed = animValues[i][7];
+ idleAnim.animData = new byte *[1];
+ idleAnim.animData[0] = new byte[sprite->stride];
+ extractSingleFrame(legsAnimData, idleAnim.animData[0], 0, sprite->w, sprite->h);
+ sprite->animData[0] = idleAnim;
+ sprite->animData[1] = mainAnim;
+ } else {
+ sprite->animData[0] = mainAnim;
+ }
+
+ pos += sprite->stride * mainAnim.nframes;
+ delete[] legsAnimData;
+ sprites.push_back(sprite);
+ }
+
+ Common::Rect bbox1 = _largeFont->getBoundingBox("ALFRED PELROCK");
+ Common::Rect bbox2 = _largeFont->getBoundingBox("En busca de un sueño");
+ int y1 = 400 / 2 - bbox1.height() / 2;
+ int y2 = 400 / 2 + bbox1.height() / 2;
+ int ticks = 0;
+ _sound->playMusicTrack(3);
+ while (!shouldQuit()) {
+ _events->pollEvent();
+
+ _chrono->updateChrono();
+
+ if (_chrono->_gameTick) {
+
+ memcpy(_compositeBuffer, _bgScreen, 640 * 400);
+
+ for (Sprite *sprite : sprites) {
+ drawNextFrame(sprite);
+ }
+
+ memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+ if (ticks > 30 && ticks < 180) {
+ drawText(_largeFont, "ALFRED PELROCK", 0, y1, 640, 255);
+ drawText(_largeFont, "En busca de un sue\x80o", 0, y2, 640, 255);
+ }
+
+ if (ticks > 200) {
+ break;
+ }
+ ticks++;
+ }
+
+ g_system->delayMillis(10);
+ _screen->markAllDirty();
+ _screen->update();
+ }
+
+ memset(_screen->getPixels(), 0, 640 * 400);
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+ free(_bgScreen);
+ _bgScreen = nullptr;
+
+ CursorMan.showMouse(true);
+ delete[] _bgScreen;
+ _bgScreen = nullptr;
+ delete[] palette;
+ _screen->markAllDirty();
+ _screen->update();
+ if (shouldQuit())
+ return;
+ credits();
+}
+
+void PelrockEngine::credits() {
+
+ debug("Starting credits sequence");
+}
+
void PelrockEngine::initGodsSequences(int roomNumber) {
int idx = roomNumber - 51;
_flightFrameCounter = 0;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 5a74bbf2d48..3adb91b7b8d 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -131,7 +131,7 @@ private:
PathContext _currentContext;
byte *_currentBackground = nullptr; // Clean background - NEVER modified
- byte *_extraScreen = nullptr;
+ byte *_bgScreen = nullptr;
ActionPopupState _actionPopupState;
@@ -255,6 +255,8 @@ public:
// Actions
void doExtraActions(int roomNumber);
+ void endingScene();
+ void credits();
void initGodsSequences(int roomNumber);
void addInventoryItem(int item);
void buyFromStore(HotSpot *hotspot, int stickerId);
@@ -377,7 +379,7 @@ public:
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
- void endingScene();
+ void teletransportToPrincess();
void animateStatuePaletteFade(bool reverse = false);
void pickUpMatches(HotSpot *hotspot);
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 709614e875d..4efb535eb50 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -240,6 +240,14 @@ void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *
outSize = pos;
}
+void rleDecompressSingleBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&outBuffer, size_t &outSize){
+ byte *buffer = nullptr;
+ size_t size = 0;
+ readUntilBuda(stream, startPos, buffer, size);
+ outSize = rleDecompress(buffer, size, 0, 0, &outBuffer, true);
+ free(buffer);
+}
+
// Helper function for transparent blitting
void drawSpriteToBuffer(byte *buffer, int bufferWidth, byte *sprite, int x, int y, int width, int height, int transparentColor) {
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 3425c7ef455..98305b9319c 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -34,6 +34,7 @@ namespace Pelrock {
const int EXPECTED_SIZE = 640 * 400;
size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data, bool untilBuda = true);
void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize);
+void rleDecompressSingleBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize);
void drawSpriteToBuffer(byte *buffer, int bufferWidth, byte *sprite, int x, int y, int width, int height, int transparentColor);
void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY);
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight);
Commit: 7fe55502095fe4786079fb35fb6cf986a8d6f807
https://github.com/scummvm/scummvm/commit/7fe55502095fe4786079fb35fb6cf986a8d6f807
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:15+02:00
Commit Message:
PELROCK: Enables final hotspot after fight sequence
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.h
engines/pelrock/dialog.cpp
engines/pelrock/extrascreens.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 2f98a338a01..3b743ef4e48 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1855,9 +1855,6 @@ void PelrockEngine::teletransportToPrincess() {
while (phase < 5) {
debug("Starting ending scene phase %d", phase);
- for (int i = 0; i < _room->_currentRoomAnims.size(); i++) {
- debug("Current room anim %d: zOrder %d, disableAfterSequence %d", _room->_currentRoomAnims[i].index, _room->_currentRoomAnims[i].zOrder, _room->_currentRoomAnims[i].disableAfterSequence);
- }
Sprite *thisSprite = _room->findSpriteByIndex(phase + 1);
thisSprite->animData[0].curFrame = 0;
thisSprite->zOrder = 200;
@@ -2029,7 +2026,21 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
debug("Updated FLAG_COMO_ESTAN_LOS_DIOSES: %d", _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES));
smokeAnimation(kFlightRooms[flightIndex].spriteIdx, true);
_room->addStickerToRoom(_room->_currentRoomNumber, 127 + flightIndex);
+ // if(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) == 0b1111) {
+ HotSpot hotspot = HotSpot();
+ hotspot.actionFlags = 0;
+ hotspot.extra = 999;
+ hotspot.x = 320;
+ hotspot.y = 288;
+ hotspot.w = 35;
+ hotspot.h = 21;
+ hotspot.innerIndex = 0;
+ hotspot.index = 8;
+ _room->changeHotspot(52, hotspot);
+ // }
}
+
+
break;
}
default:
diff --git a/engines/pelrock/console.h b/engines/pelrock/console.h
index a426c5d4cb6..e20cd09951e 100644
--- a/engines/pelrock/console.h
+++ b/engines/pelrock/console.h
@@ -37,11 +37,11 @@ private:
bool cmdTest(int argc, const char **argv);
bool cmdSetRoot(int argc, const char **argv);
bool cmdSetFlag(int argc, const char **argv);
+ bool cmdRemoveSticker(int argc, const char **argv);
public:
PelrockConsole(PelrockEngine *engine);
~PelrockConsole() override;
- bool cmdRemoveSticker(int argc, const char **argv);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 96ef5091fa9..400cb513941 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -187,7 +187,6 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
// Clear any existing click state
_events->_leftMouseClicked = false;
_dialogActive = true;
- g_engine->_chrono->pauseCounter();
int curPage = 0;
// Render loop - display text and wait for click
@@ -239,7 +238,6 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_curSprite->isTalking = false;
}
_dialogActive = false;
- g_engine->_chrono->resumeCounter();
g_engine->_alfredState.setState(ALFRED_IDLE);
}
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
index 446a8e986d8..1dd9673b356 100644
--- a/engines/pelrock/extrascreens.cpp
+++ b/engines/pelrock/extrascreens.cpp
@@ -345,7 +345,7 @@ void CDPlayer::loadControls() {
size_t decompressedSize = rleDecompress(compressedData, outSize, 0, 0, &rawData, true);
- debug("Decompressed CD player controls: %d bytes", decompressedSize);
+ // debug("Decompressed CD player controls: %d bytes", decompressedSize);
uint32 pos = 213 * 72;
Common::copy(rawData, rawData + pos, _controls);
for (int i = 0; i < 5; i++) {
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 3ea8726e44e..4eb473bae70 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -434,7 +434,6 @@ Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data,
Common::StringArray lines;
Common::Array<Common::StringArray> texts;
while (pos < size) {
- debug("Processing byte %02X at pos %d", data[pos], pos);
if (data[pos] == CTRL_END_TEXT) {
if (!desc.empty()) {
@@ -524,7 +523,7 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
readUntilBuda(stream, stream->pos(), thisBlock, blockSize);
uint8_t *block_data = nullptr;
size_t decompressedSize = rleDecompress(thisBlock, blockSize, 0, 640 * 400, &block_data, true);
- debug("Decompressed block %d: %zu bytes, total %zu", i, decompressedSize, combined_size + decompressedSize);
+ // debug("Decompressed block %d: %zu bytes, total %zu", i, decompressedSize, combined_size + decompressedSize);
if (combined_size + decompressedSize > 640 * 400) {
debug("Warning: decompressed data exceeds output buffer size, truncating");
decompressedSize = 640 * 400 - combined_size;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index fcfa9c51877..c50af161fb3 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -854,6 +854,7 @@ Common::Array<HotSpot> RoomManager::unifyHotspots(Common::Array<Pelrock::Sprite>
thisHotspot.isEnabled = !anims[i].isHotspotDisabled;
thisHotspot.isSprite = true;
thisHotspot.zOrder = anims[i].zOrder;
+ thisHotspot.innerIndex = anims[i].index;
unifiedHotspots.push_back(thisHotspot);
}
@@ -1213,7 +1214,7 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
readUntilBuda(&talkFile, talkHeader.spritePointer, data, dataSize);
size_t decompressedSize = rleDecompress(data, dataSize, 0, dataSize, &decompressed);
free(data);
- debug("Decompressed talking anim A size: %zu, decompressed size: %zu", dataSize, decompressedSize);
+ // debug("Decompressed talking anim A size: %zu, decompressed size: %zu", dataSize, decompressedSize);
for (int i = 0; i < talkHeader.numFramesAnimA; i++) {
talkHeader.animA[i] = new byte[talkHeader.wAnimA * talkHeader.hAnimA];
extractSingleFrame(decompressed, talkHeader.animA[i], i, talkHeader.wAnimA, talkHeader.hAnimA);
@@ -1224,7 +1225,7 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
for (int i = 0; i < talkHeader.numFramesAnimB; i++) {
talkHeader.animB[i] = new byte[talkHeader.wAnimB * talkHeader.hAnimB];
uint32 offset = animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB);
- debug("Extracting talking anim B frame %d at offset %d, size = %d", i, animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB), talkHeader.wAnimB * talkHeader.hAnimB);
+ // debug("Extracting talking anim B frame %d at offset %d, size = %d", i, animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB), talkHeader.wAnimB * talkHeader.hAnimB);
if (offset + talkHeader.wAnimB * talkHeader.hAnimB >= decompressedSize) {
debug("Error: offset %d is beyond decompressed size %zu", offset, decompressedSize);
talkHeader.numFramesAnimB = 0;
@@ -1277,7 +1278,7 @@ byte *RoomManager::loadShadowMap(int roomNumber) {
debug("Failed to decompress shadow map for room %d", roomNumber);
shadows = nullptr;
}
- debug("Decompressed shadow map for room %d, compressed size: %zu, decompressed size: %zu", roomNumber, compressedSize, decompressedSize);
+ // debug("Decompressed shadow map for room %d, compressed size: %zu, decompressed size: %zu", roomNumber, compressedSize, decompressedSize);
free(compressed);
shadowMapFile.close();
return shadows;
Commit: 78a126017cc63921b85be40e352c72b90be4ea6d
https://github.com/scummvm/scummvm/commit/78a126017cc63921b85be40e352c72b90be4ea6d
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:15+02:00
Commit Message:
PELROCK: Loads inventory paging arrows
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 87d0f2df065..2effd749c00 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -167,6 +167,22 @@ void PelrockEngine::init() {
// alfredState.x = 576;
// alfredState.y = 374;
}
+
+ loadInventoryArrows();
+}
+
+void PelrockEngine::loadInventoryArrows() {
+ Common::File alfred7;
+ if(!alfred7.open("ALFRED.7")) {
+ error("Failed to open ALFRED.7 to load inventory arrows");
+ return;
+ }
+ alfred7.seek(3186048, SEEK_SET); // Offset for inventory arrows in ALFRED.7
+ _inventoryOverlayState.arrows[0] = new byte[20 * 60];
+ _inventoryOverlayState.arrows[1] = new byte[20 * 60];
+ alfred7.read(_inventoryOverlayState.arrows[0], 20 * 60);
+ alfred7.read(_inventoryOverlayState.arrows[1], 20 * 60);
+ alfred7.close();
}
void PelrockEngine::loadAnims() {
@@ -1485,7 +1501,9 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
VerbIcon icon = isActionUnder(_events->_mouseX, _events->_mouseY);
+
bool shouldBlink = _chrono->getFrameCount() % kIconBlinkPeriod == 0;
+
for (uint i = 0; i < actions.size(); i++) {
if (icon == actions[i] && shouldBlink) {
continue;
@@ -1493,17 +1511,29 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
Common::Point p = getPositionInBallonForIndex(i, posx, posy);
drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], p.x, p.y, kVerbIconWidth, kVerbIconHeight, 1);
}
+
+ if(icon == ITEM) {
+ if(!_inventoryOverlayState.isActive) {
+ _inventoryOverlayState.isActive = true;
+ // _inventoryOverlayState.page =
+ }
+ showInventoryOverlay();
+ }
+
if (_state->selectedInventoryItem >= 0 && !_state->inventoryItems.empty()) {
if (icon == ITEM && shouldBlink) {
return;
}
drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->selectedInventoryItem).iconData, posx + 20 + (actions.size() * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
+
if (_actionPopupState.curFrame < 3) {
_actionPopupState.curFrame++;
} else {
_actionPopupState.curFrame = 0;
}
+
+
}
void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
@@ -1543,11 +1573,11 @@ void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
}
Common::Point getPositionInOverlayForIndex(uint index) {
- return Common::Point(5 + index * (60 + 2), 400 - 60 - 5);
+ return Common::Point(20 + index * (60), 340);
}
void PelrockEngine::pickupIconFlash() {
- _graphics->showOverlay(65, _compositeBuffer);
+ _graphics->showOverlay(60, _compositeBuffer);
if (_newItem == -1)
return;
uint invSize = _state->inventoryItems.size();
@@ -1564,6 +1594,19 @@ void PelrockEngine::pickupIconFlash() {
}
}
+void PelrockEngine::showInventoryOverlay() {
+ _graphics->showOverlay(60, _compositeBuffer);
+ uint invSize = _state->inventoryItems.size();
+ int firstItem = _inventoryOverlayState.page * kInventoryPageSize;
+
+ for (int i = firstItem; i < invSize && i < firstItem + kInventoryPageSize; i++) {
+ Common::Point p = getPositionInOverlayForIndex(i - firstItem);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->inventoryItems[i]).iconData, p.x, p.y, 60, 60, 1);
+ }
+ drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
+ drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[1], 620, 340, 20, 60, 255);
+}
+
void PelrockEngine::gameLoop() {
_events->pollEvent();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 3adb91b7b8d..a1e03ef0045 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -65,6 +65,7 @@ private:
MenuManager *_menu = nullptr;
void init();
+ void loadInventoryArrows();
void loadAnims();
/*
@@ -110,6 +111,8 @@ private:
void playSoundIfNeeded();
+ void showInventoryOverlay();
+
void gameLoop();
void computerLoop();
void extraScreenLoop();
@@ -134,6 +137,8 @@ private:
byte *_bgScreen = nullptr;
ActionPopupState _actionPopupState;
+ InventoryOverlayState _inventoryOverlayState;
+
HotSpot *_currentHotspot = nullptr;
int _newItem = -1;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 60e0caa505d..cbe3cdf7f2f 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -83,9 +83,10 @@ const int kChoiceHeight = 16; // Height of each choice line in pixels
const int kTalkAnimationSpeed = 2; // Frames per update
const int kAlfredAnimationSpeed = 2; // Frames per update
-
const int kAlfredIdleAnimationFrameCount = 300;
+const int kInventoryPageSize = 10;
+
// Direction flags (bit-packed)
#define MOVE_RIGHT 0x01 // Move right (positive X)
#define MOVE_LEFT 0x02 // Move left (negative X)
@@ -159,6 +160,12 @@ struct ActionPopupState {
bool isAlfredUnder = false;
};
+struct InventoryOverlayState {
+ bool isActive = false;
+ int page = 0;
+ byte *arrows[2] = { nullptr, nullptr };
+};
+
struct AlfredState {
AlfredAnimState animState = ALFRED_IDLE;
AlfredDirection direction = ALFRED_DOWN;
@@ -411,6 +418,7 @@ struct PaletteAnim {
#define PASSERBY_RIGHT 0
#define PASSERBY_LEFT 1
#define PASSERBY_DOWN 2
+
struct PasserByAnim
{
uint32 frameTrigger = 0x3FF;
@@ -484,7 +492,7 @@ struct ResetEntry {
#define FLAG_PUERTA_BUENA 35
#define FLAG_PIEDRA_FAKE_MOJADA 34
#define FLAG_TIENDA_ABIERTA 46
-
+#define FLAG_COMO_ESTAN_LOS_DIOSES 41
#define FLAG_VIAJE_A_EGIPTO 12
@@ -503,7 +511,6 @@ struct ResetEntry {
#define FLAG_A_POR_LA_PRINCESA 38
#define FLAG_VUELTA_A_EMPEZAR 39
#define FLAG_A_LOS_PASILLOS 40
-#define FLAG_COMO_ESTAN_LOS_DIOSES 41
#define FLAG_END_OF_GAME 42
#define FLAG_FROM_INTRO 43
#define FLAG_HE_TIRADO_PIEDRA 44
@@ -642,7 +649,6 @@ struct SaveGameData {
GameStateData *gameState = nullptr;
};
-
struct FlightRoomCfg {
int roomNumber;
int spriteIdx;
Commit: e197092b5ef6296291658c8a8079a01312e4a576
https://github.com/scummvm/scummvm/commit/e197092b5ef6296291658c8a8079a01312e4a576
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:15+02:00
Commit Message:
PELROCK: Implements inventory overlay when using items
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
engines/pelrock/util.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 2effd749c00..c272b57eae4 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -154,7 +154,7 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(0, ALFRED_DOWN);
+ setScreen(0, ALFRED_LEFT);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
// setScreen(41, ALFRED_DOWN);
@@ -164,7 +164,7 @@ void PelrockEngine::init() {
// setScreen(52, ALFRED_DOWN);
// setScreen(15, ALFRED_DOWN);
// setScreen(2, ALFRED_LEFT);
- // alfredState.x = 576;
+ // _alfredState.x = 576;
// alfredState.y = 374;
}
@@ -1492,11 +1492,18 @@ bool PelrockEngine::isSpriteUnder(Sprite *sprite, int x, int y) {
return false;
}
-Common::Point getPositionInBallonForIndex(int i, int x, int y) {
- return Common::Point(x + 20 + (i * (kVerbIconWidth + 2)), y + 20);
+Common::Point getPositionInBalloonForIndex(int i, int x, int y) {
+ return Common::Point(4 + x + (i * kVerbIconWidth), y + 18);
+}
+
+Common::Rect getActionArea(int x, int y) {
+ Common::Point p1 = getPositionInBalloonForIndex(0, x, y);
+ Common::Point p2 = getPositionInBalloonForIndex(4, x, y);
+ return Common::Rect(p1.x, p1.y, p2.x + kVerbIconWidth, p2.y + kVerbIconHeight);
}
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
+
drawSpriteToBuffer(_compositeBuffer, 640, _res->_popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
@@ -1508,23 +1515,29 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
if (icon == actions[i] && shouldBlink) {
continue;
}
- Common::Point p = getPositionInBallonForIndex(i, posx, posy);
+ Common::Point p = getPositionInBalloonForIndex(i, posx, posy);
drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], p.x, p.y, kVerbIconWidth, kVerbIconHeight, 1);
}
- if(icon == ITEM) {
- if(!_inventoryOverlayState.isActive) {
- _inventoryOverlayState.isActive = true;
- // _inventoryOverlayState.page =
- }
+ Common::Rect actionArea = getActionArea(posx, posy);
+ // moving mouse over action area outside of the item closes the inventoryoverlay
+ if (actionArea.contains(_events->_mouseX, _events->_mouseY)) {
+ _inventoryOverlayState.isActive = icon == ITEM;
+ }
+
+ if(_inventoryOverlayState.isActive) {
showInventoryOverlay();
+ if(_inventoryOverlayState.posInInventorySelectionArea(_events->_mouseX, _events->_mouseY)) {
+ checkMouseOverInventoryOverlay(_events->_mouseX, _events->_mouseY);
+ }
}
+
if (_state->selectedInventoryItem >= 0 && !_state->inventoryItems.empty()) {
- if (icon == ITEM && shouldBlink) {
- return;
+ if (icon != ITEM || !shouldBlink) {
+ Common::Point p = getPositionInBalloonForIndex(actions.size(), posx, posy);
+ drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->selectedInventoryItem).iconData, p.x, p.y, kVerbIconWidth, kVerbIconHeight, 1);
}
- drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->selectedInventoryItem).iconData, posx + 20 + (actions.size() * (kVerbIconWidth + 2)), posy + 20, kVerbIconWidth, kVerbIconHeight, 1);
}
if (_actionPopupState.curFrame < 3) {
@@ -1532,8 +1545,6 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
} else {
_actionPopupState.curFrame = 0;
}
-
-
}
void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
@@ -1601,12 +1612,44 @@ void PelrockEngine::showInventoryOverlay() {
for (int i = firstItem; i < invSize && i < firstItem + kInventoryPageSize; i++) {
Common::Point p = getPositionInOverlayForIndex(i - firstItem);
+ if( i == _inventoryOverlayState.flashingIconIndex && _chrono->getFrameCount() % kIconBlinkPeriod == 0) {
+ continue;
+ }
drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->inventoryItems[i]).iconData, p.x, p.y, 60, 60, 1);
}
+
drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[1], 620, 340, 20, 60, 255);
}
+void PelrockEngine::checkMouseOverInventoryOverlay(int x, int y) {
+
+ if(x < 20) {
+ // if(_inventoryOverlayState.page > 0) {
+ // _inventoryOverlayState.page--;
+ // }
+ debug("left arrow of inventory overlay");
+ } else if(x >= 620) {
+ // uint maxPage = (_state->inventoryItems.size() - 1) / kInventoryPageSize;
+ // if(_inventoryOverlayState.page < maxPage) {
+ // _inventoryOverlayState.page++;
+ // }
+ debug("right arrow of inventory overlay");
+ } else {
+ // mouse hover over inventory item, laid out horizontally, y coordinate is not relevant for determining which item is selected
+ int index = (x - 20) / 60 + (_inventoryOverlayState.page * kInventoryPageSize);
+ if(index < _state->inventoryItems.size()) {
+ debug("hovering over inventory item %d at index %d", _state->inventoryItems[index], index);
+ // _state->selectedInventoryItem = index;
+ _inventoryOverlayState.flashingIconIndex = index;
+ } else {
+ debug("hovering over empty slot in inventory overlay, no item at index %d", index);
+ // _state->selectedInventoryItem = -1;
+ _inventoryOverlayState.flashingIconIndex = -1;
+ }
+ }
+}
+
void PelrockEngine::gameLoop() {
_events->pollEvent();
@@ -1772,7 +1815,7 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
int loopEnd = _state->selectedInventoryItem != -1 ? actions.size() + 1 : actions.size();
for (int i = 0; i < loopEnd; i++) {
- Common::Point p = getPositionInBallonForIndex(i, _actionPopupState.x, _actionPopupState.y);
+ Common::Point p = getPositionInBalloonForIndex(i, _actionPopupState.x, _actionPopupState.y);
Common::Rect actionRect = Common::Rect(p.x, p.y, p.x + kVerbIconWidth, p.y + kVerbIconHeight);
if (i == actions.size()) {
// Check inventory item
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index a1e03ef0045..f47ba3be604 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -113,6 +113,8 @@ private:
void showInventoryOverlay();
+ void checkMouseOverInventoryOverlay(int x, int y);
+
void gameLoop();
void computerLoop();
void extraScreenLoop();
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index cbe3cdf7f2f..db650c74b2b 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -21,6 +21,7 @@
#ifndef PELROCK_TYPES_H
#define PELROCK_TYPES_H
+#include "common/rect.h"
#include "common/debug.h"
#include "common/scummsys.h"
#include "common/system.h"
@@ -163,7 +164,14 @@ struct ActionPopupState {
struct InventoryOverlayState {
bool isActive = false;
int page = 0;
+ int flashingIconIndex = -1;
+ Common::Rect inventorySelectionArea = Common::Rect(0, 340, 640, 400);
+ Common::Rect ballonInventoryPath = Common::Rect(0, 0, kBalloonWidth, kBalloonHeight);
byte *arrows[2] = { nullptr, nullptr };
+
+ bool posInInventorySelectionArea(int x, int y) {
+ return inventorySelectionArea.contains(x, y);
+ }
};
struct AlfredState {
@@ -172,7 +180,7 @@ struct AlfredState {
int curFrame = 0;
uint16 movementSpeedX = 6; // pixels per frame
uint16 movementSpeedY = 5; // pixels per frame
- uint16 x = 319;
+ uint16 x = 330;
uint16 y = 302;
byte w = kAlfredFrameWidth;
byte h = kAlfredFrameHeight;
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 4efb535eb50..c27d22fbe34 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -48,7 +48,7 @@ void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color
void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color) {
Graphics::Surface surface;
surface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
- drawRect(&surface, 0, 0, w, h, color);
+ drawRect(&surface, 0, 0, w - 1, h, color);
for (int py = 0; py < h; py++) {
for (int px = 0; px < w; px++) {
Commit: 8ccb1b06a25e18c402b25282cc055503b95e0634
https://github.com/scummvm/scummvm/commit/8ccb1b06a25e18c402b25282cc055503b95e0634
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:16+02:00
Commit Message:
PELROCK: Implements inventory overlay scroll and click
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index c272b57eae4..8a2842824a4 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -546,11 +546,17 @@ void PelrockEngine::checkMouse() {
} else if (_actionPopupState.isAlfredUnder && actionClicked != NO_ACTION) {
debug("Using item on Alfred");
useOnAlfred(_state->selectedInventoryItem);
+ } else if (_inventoryOverlayState.isActive && _inventoryOverlayState.posInInventorySelectionArea(_events->_releaseX, _events->_releaseY)) {
+ int item = checkMouseClickInventoryOverlay(_events->_releaseX, _events->_releaseY);
+ _state->selectedInventoryItem = item;
+ walkAndAction(_currentHotspot, ITEM);
} else {
// Released outside popup - just close it
_queuedAction = QueuedAction{NO_ACTION, -1, false, false};
_currentHotspot = nullptr;
}
+
+
} else if (_events->_leftMouseClicked) {
// Regular click (not during popup mode)
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
@@ -1523,6 +1529,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
// moving mouse over action area outside of the item closes the inventoryoverlay
if (actionArea.contains(_events->_mouseX, _events->_mouseY)) {
_inventoryOverlayState.isActive = icon == ITEM;
+ _inventoryOverlayState.flashingIconIndex = -1;
}
if(_inventoryOverlayState.isActive) {
@@ -1608,7 +1615,7 @@ void PelrockEngine::pickupIconFlash() {
void PelrockEngine::showInventoryOverlay() {
_graphics->showOverlay(60, _compositeBuffer);
uint invSize = _state->inventoryItems.size();
- int firstItem = _inventoryOverlayState.page * kInventoryPageSize;
+ int firstItem = _inventoryOverlayState.invStartingPos * kInventoryPageSize;
for (int i = firstItem; i < invSize && i < firstItem + kInventoryPageSize; i++) {
Common::Point p = getPositionInOverlayForIndex(i - firstItem);
@@ -1618,26 +1625,28 @@ void PelrockEngine::showInventoryOverlay() {
drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->inventoryItems[i]).iconData, p.x, p.y, 60, 60, 1);
}
- drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
- drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[1], 620, 340, 20, 60, 255);
+ //draw arrows if there are more items to show in either direction
+ if(_inventoryOverlayState.invStartingPos > 0) {
+ drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
+ }
+ if((firstItem + kInventoryPageSize) < invSize) {
+ drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[1], 620, 340, 20, 60, 255);
+ }
+ // drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
}
void PelrockEngine::checkMouseOverInventoryOverlay(int x, int y) {
-
if(x < 20) {
- // if(_inventoryOverlayState.page > 0) {
- // _inventoryOverlayState.page--;
- // }
- debug("left arrow of inventory overlay");
+ if(_inventoryOverlayState.invStartingPos > 0 && _chrono->getFrameCount() % 2 == 0) {
+ _inventoryOverlayState.invStartingPos--;
+ }
} else if(x >= 620) {
- // uint maxPage = (_state->inventoryItems.size() - 1) / kInventoryPageSize;
- // if(_inventoryOverlayState.page < maxPage) {
- // _inventoryOverlayState.page++;
- // }
- debug("right arrow of inventory overlay");
+ if(_inventoryOverlayState.invStartingPos < (_state->inventoryItems.size() / kInventoryPageSize) && _chrono->getFrameCount() % 2 == 0) {
+ _inventoryOverlayState.invStartingPos++;
+ }
} else {
// mouse hover over inventory item, laid out horizontally, y coordinate is not relevant for determining which item is selected
- int index = (x - 20) / 60 + (_inventoryOverlayState.page * kInventoryPageSize);
+ int index = (x - 20) / 60 + (_inventoryOverlayState.invStartingPos * kInventoryPageSize);
if(index < _state->inventoryItems.size()) {
debug("hovering over inventory item %d at index %d", _state->inventoryItems[index], index);
// _state->selectedInventoryItem = index;
@@ -1650,6 +1659,18 @@ void PelrockEngine::checkMouseOverInventoryOverlay(int x, int y) {
}
}
+int PelrockEngine::checkMouseClickInventoryOverlay(int x, int y) {
+ if(x < 20) {
+ return -1;
+ } else if(x >= 620) {
+ return -1;
+ } else {
+ // mouse hover over inventory item, laid out horizontally, y coordinate is not relevant for determining which item is selected
+ int index = (x - 20) / 60 + (_inventoryOverlayState.invStartingPos * kInventoryPageSize);
+ return _state->inventoryItems[index];
+ }
+}
+
void PelrockEngine::gameLoop() {
_events->pollEvent();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index f47ba3be604..a32bc60b0d3 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -114,6 +114,7 @@ private:
void showInventoryOverlay();
void checkMouseOverInventoryOverlay(int x, int y);
+ int checkMouseClickInventoryOverlay(int x, int y);
void gameLoop();
void computerLoop();
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index db650c74b2b..41dfea8d976 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -163,7 +163,7 @@ struct ActionPopupState {
struct InventoryOverlayState {
bool isActive = false;
- int page = 0;
+ int invStartingPos = 0;
int flashingIconIndex = -1;
Common::Rect inventorySelectionArea = Common::Rect(0, 340, 640, 400);
Common::Rect ballonInventoryPath = Common::Rect(0, 0, kBalloonWidth, kBalloonHeight);
Commit: 1f188c55f886920db6a120125f2790e190a4a722
https://github.com/scummvm/scummvm/commit/1f188c55f886920db6a120125f2790e190a4a722
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:16+02:00
Commit Message:
PELROCK: Scroll dialog choices
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 400cb513941..7be58fa128d 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -20,8 +20,8 @@
*/
#include "common/stack.h"
-#include "pelrock/dialog.h"
#include "dialog.h"
+#include "pelrock/dialog.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
@@ -117,14 +117,44 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *c
Common::Point overlayPos = _graphics->showOverlay(overlayHeight, compositeBuffer);
for (uint i = 0; i < choices->size(); i++) {
ChoiceOption choice = (*choices)[i];
- int choicePadding = 32;
int width = g_engine->_doubleSmallFont->getStringWidth(choice.text);
- Common::Rect bbox(0, overlayPos.y + i * kChoiceHeight, width + choicePadding * 2, overlayPos.y + i * kChoiceHeight + kChoiceHeight);
- int color = 14;
+ int yPos = overlayPos.y + 2 + i * kChoiceHeight;
+ Common::Rect bbox(kChoicePadding, yPos, kChoicePadding + 600, yPos + kChoiceHeight);
+ Common::Rect leftArrowBox(0, yPos, kChoicePadding, yPos + kChoiceHeight);
+ Common::Rect rightArrowBox(640 - kChoicePadding, yPos, 640, yPos + kChoiceHeight);
+ int choiceColor = 14;
+ int lArrowColor = 14;
+ int rArrowColor = 14;
+
if (bbox.contains(_events->_mouseX, _events->_mouseY)) {
- color = 15;
+ choiceColor = 15;
+ } else if (leftArrowBox.contains(_events->_mouseX, _events->_mouseY)) {
+ if (choice.charOffset > 0) {
+ choice.charOffset--;
+ choices->remove_at(i);
+ choices->insert_at(i, choice);
+ }
+ lArrowColor = 15;
+ } else if (rightArrowBox.contains(_events->_mouseX, _events->_mouseY)) {
+ if (i == 0) {
+ debug("First choice charOffset %d, text length %d", choice.charOffset, choice.text.size());
+ }
+ if (choice.charOffset + 76 < choice.text.size()) {
+ choice.charOffset = choice.charOffset + 1;
+ choices->remove_at(i);
+ choices->insert_at(i, choice);
+ debug("Right arrow clicked, new charOffset %d, text length %d", choice.charOffset, choice.text.size());
+ }
+ rArrowColor = 15;
+ }
+
+ if (choice.charOffset > 0) {
+ drawText(compositeBuffer, g_engine->_doubleSmallFont, _leftArrow, 0, yPos, g_engine->_doubleSmallFont->getCharWidth(17), lArrowColor);
+ }
+ drawText(compositeBuffer, g_engine->_doubleSmallFont, choice.text.substr(choice.charOffset, 76), kChoicePadding, yPos, 620, choiceColor);
+ if (choice.charOffset + 76 < choice.text.size()) {
+ drawText(compositeBuffer, g_engine->_doubleSmallFont, _rightArrow, 640 - kArrowWidth, yPos, g_engine->_doubleSmallFont->getCharWidth(16), rArrowColor);
}
- drawText(compositeBuffer, g_engine->_doubleSmallFont, choice.text, choicePadding, overlayPos.y + 2 + i * kChoiceHeight, 620, color);
}
}
@@ -216,10 +246,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos), 255);
drawPos(_screen, xPos, yPos, speakerId);
- // drawRect(_screen, xPos, yPos,
- // s.getRect().width(),
- // s.getRect().height(), speakerId);
- // Present to screen
+
_screen->markAllDirty();
_screen->update();
@@ -368,8 +395,10 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
}
textPos++;
}
- if (!opt.isDisabled)
+ if (!opt.isDisabled) {
+ opt.text = " " + opt.text; // Adds three spaces for padding to allow for scrolling past the indentation
outChoices->push_back(opt);
+ }
} else if (choiceIndex < firstChoiceIndex) {
// Hit a choice at a LOWER level - stop scanning
// This means we've gone past all choices at our level
@@ -532,11 +561,11 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
if (choices->empty()) {
state.position = positionStack.empty() ? 0 : positionStack.pop();
- if(state.position == 0) {
+ if (state.position == 0) {
debug("No choices and no previous position to go back to, ending conversation");
break;
}
- checkAllSubBranchesExhausted(conversationData, dataSize, state.position, state.currentChoiceLevel-1);
+ checkAllSubBranchesExhausted(conversationData, dataSize, state.position, state.currentChoiceLevel - 1);
debug("No choices found, popping back to previous choice menu, position %u", state.position);
skipToChoices = true;
// state.position = peekPos;
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 0ebc5f0362b..85362b44dd5 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -67,6 +67,9 @@ struct ConversationEndResult {
};
class DialogManager {
+ const static int kMaxChoiceChars = 50; // Max characters to show for a choice option (for truncation)
+ const static int kArrowWidth = 8; // Width of arrow character for scroll
+ const static int kChoicePadding = 16; // padding for the choice text surface
private:
Graphics::Screen *_screen = nullptr;
PelrockEventManager *_events = nullptr;
@@ -87,12 +90,12 @@ private:
uint32 skipControlBytes(const byte *data, uint32 dataSize, uint32 position);
uint32 peekNextMeaningfulByte(const byte *data, uint32 dataSize, uint32 position);
ConversationState initializeConversation(const byte *data, uint32 dataSize, byte npcIndex);
- bool handleGoBack(const byte *data, Common::Stack<uint32> &positionStack, uint32 position, ConversationState &state);
+ bool handleGoBack(const byte *data, Common::Stack<uint32> &positionStack, uint32 position, ConversationState &state);
uint32 readAndDisplayDialogue(const byte *data, uint32 dataSize, uint32 position);
ConversationEndResult checkConversationEnd(const byte *data, uint32 dataSize, uint32 position);
void addGoodbyeOptionIfNeeded(Common::Array<ChoiceOption> *choices, int currentChoiceLevel, uint originalChoiceCount);
uint32 processChoiceSelection(const byte *data, uint32 dataSize, Common::Array<ChoiceOption> *choices, int selectedIndex, ConversationState &state);
- void disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> * choices, int selectedIndex, const byte * data, uint32 dataSize, uint32 endPos, Pelrock::ConversationState & state);
+ void disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> *choices, int selectedIndex, const byte *data, uint32 dataSize, uint32 endPos, Pelrock::ConversationState &state);
public:
DialogManager(Graphics::Screen *screen, PelrockEventManager *events, GraphicsManager *graphics);
@@ -119,6 +122,9 @@ public:
// True while a blocking dialog or conversation is on screen.
bool _dialogActive = false;
+
+ Common::String _leftArrow = Common::String(17);
+ Common::String _rightArrow = Common::String(16);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 8a2842824a4..9b590d96be2 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -154,9 +154,9 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(0, ALFRED_LEFT);
+ // setScreen(0, ALFRED_LEFT);
// setScreen(3, ALFRED_RIGHT);
- // setScreen(22, ALFRED_DOWN);
+ setScreen(22, ALFRED_DOWN);
// setScreen(41, ALFRED_DOWN);
// setScreen(43, ALFRED_DOWN);
// setScreen(46, ALFRED_RIGHT);
@@ -173,7 +173,7 @@ void PelrockEngine::init() {
void PelrockEngine::loadInventoryArrows() {
Common::File alfred7;
- if(!alfred7.open("ALFRED.7")) {
+ if (!alfred7.open("ALFRED.7")) {
error("Failed to open ALFRED.7 to load inventory arrows");
return;
}
@@ -556,7 +556,6 @@ void PelrockEngine::checkMouse() {
_currentHotspot = nullptr;
}
-
} else if (_events->_leftMouseClicked) {
// Regular click (not during popup mode)
checkMouseClick(_events->_mouseClickX, _events->_mouseClickY);
@@ -1532,14 +1531,13 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
_inventoryOverlayState.flashingIconIndex = -1;
}
- if(_inventoryOverlayState.isActive) {
+ if (_inventoryOverlayState.isActive) {
showInventoryOverlay();
- if(_inventoryOverlayState.posInInventorySelectionArea(_events->_mouseX, _events->_mouseY)) {
+ if (_inventoryOverlayState.posInInventorySelectionArea(_events->_mouseX, _events->_mouseY)) {
checkMouseOverInventoryOverlay(_events->_mouseX, _events->_mouseY);
}
}
-
if (_state->selectedInventoryItem >= 0 && !_state->inventoryItems.empty()) {
if (icon != ITEM || !shouldBlink) {
Common::Point p = getPositionInBalloonForIndex(actions.size(), posx, posy);
@@ -1619,35 +1617,35 @@ void PelrockEngine::showInventoryOverlay() {
for (int i = firstItem; i < invSize && i < firstItem + kInventoryPageSize; i++) {
Common::Point p = getPositionInOverlayForIndex(i - firstItem);
- if( i == _inventoryOverlayState.flashingIconIndex && _chrono->getFrameCount() % kIconBlinkPeriod == 0) {
+ if (i == _inventoryOverlayState.flashingIconIndex && _chrono->getFrameCount() % kIconBlinkPeriod == 0) {
continue;
}
drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->inventoryItems[i]).iconData, p.x, p.y, 60, 60, 1);
}
- //draw arrows if there are more items to show in either direction
- if(_inventoryOverlayState.invStartingPos > 0) {
- drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
+ // draw arrows if there are more items to show in either direction
+ if (_inventoryOverlayState.invStartingPos > 0) {
+ drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
}
- if((firstItem + kInventoryPageSize) < invSize) {
+ if ((firstItem + kInventoryPageSize) < invSize) {
drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[1], 620, 340, 20, 60, 255);
}
// drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
}
void PelrockEngine::checkMouseOverInventoryOverlay(int x, int y) {
- if(x < 20) {
- if(_inventoryOverlayState.invStartingPos > 0 && _chrono->getFrameCount() % 2 == 0) {
+ if (x < 20) {
+ if (_inventoryOverlayState.invStartingPos > 0 && _chrono->getFrameCount() % 2 == 0) {
_inventoryOverlayState.invStartingPos--;
}
- } else if(x >= 620) {
- if(_inventoryOverlayState.invStartingPos < (_state->inventoryItems.size() / kInventoryPageSize) && _chrono->getFrameCount() % 2 == 0) {
+ } else if (x >= 620) {
+ if (_inventoryOverlayState.invStartingPos < (_state->inventoryItems.size() / kInventoryPageSize) && _chrono->getFrameCount() % 2 == 0) {
_inventoryOverlayState.invStartingPos++;
}
} else {
// mouse hover over inventory item, laid out horizontally, y coordinate is not relevant for determining which item is selected
int index = (x - 20) / 60 + (_inventoryOverlayState.invStartingPos * kInventoryPageSize);
- if(index < _state->inventoryItems.size()) {
+ if (index < _state->inventoryItems.size()) {
debug("hovering over inventory item %d at index %d", _state->inventoryItems[index], index);
// _state->selectedInventoryItem = index;
_inventoryOverlayState.flashingIconIndex = index;
@@ -1660,9 +1658,9 @@ void PelrockEngine::checkMouseOverInventoryOverlay(int x, int y) {
}
int PelrockEngine::checkMouseClickInventoryOverlay(int x, int y) {
- if(x < 20) {
+ if (x < 20) {
return -1;
- } else if(x >= 620) {
+ } else if (x >= 620) {
return -1;
} else {
// mouse hover over inventory item, laid out horizontally, y coordinate is not relevant for determining which item is selected
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 41dfea8d976..22f7d967f88 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -21,8 +21,8 @@
#ifndef PELROCK_TYPES_H
#define PELROCK_TYPES_H
-#include "common/rect.h"
#include "common/debug.h"
+#include "common/rect.h"
#include "common/scummsys.h"
#include "common/system.h"
#include "common/types.h"
@@ -81,7 +81,7 @@ const int kAlfredFrameHeight = 102;
const int kChoiceHeight = 16; // Height of each choice line in pixels
-const int kTalkAnimationSpeed = 2; // Frames per update
+const int kTalkAnimationSpeed = 2; // Frames per update
const int kAlfredAnimationSpeed = 2; // Frames per update
const int kAlfredIdleAnimationFrameCount = 300;
@@ -167,7 +167,7 @@ struct InventoryOverlayState {
int flashingIconIndex = -1;
Common::Rect inventorySelectionArea = Common::Rect(0, 340, 640, 400);
Common::Rect ballonInventoryPath = Common::Rect(0, 0, kBalloonWidth, kBalloonHeight);
- byte *arrows[2] = { nullptr, nullptr };
+ byte *arrows[2] = {nullptr, nullptr};
bool posInInventorySelectionArea(int x, int y) {
return inventorySelectionArea.contains(x, y);
@@ -246,10 +246,10 @@ struct Sprite {
uint16 stride; // 6-7
int numAnims; // 8
int curAnimIndex = 0;
- int8 zOrder; //32-33
+ int8 zOrder; // 32-33
- byte actionFlags; // 34
- bool isHotspotDisabled; // 38
+ byte actionFlags; // 34
+ bool isHotspotDisabled; // 38
bool disableAfterSequence = false; // 39
bool isTalking = false;
byte talkingAnimIndex = 0;
@@ -321,8 +321,8 @@ struct WalkBox {
struct QueuedAction {
VerbIcon verb;
int hotspotIndex;
- bool isQueued; // Alfred is walking/interacting toward the target
- bool readyToExecute; // Animation done - execute after the current renderScene
+ bool isQueued; // Alfred is walking/interacting toward the target
+ bool readyToExecute; // Animation done - execute after the current renderScene
};
struct ScalingParams {
@@ -346,14 +346,12 @@ enum GameState {
COMPUTER = 104
};
-struct SpriteChange
-{
+struct SpriteChange {
byte roomNumber;
byte spriteIndex;
byte zIndex;
};
-
struct HotSpotChange {
byte roomNumber;
byte hotspotIndex;
@@ -427,8 +425,7 @@ struct PaletteAnim {
#define PASSERBY_LEFT 1
#define PASSERBY_DOWN 2
-struct PasserByAnim
-{
+struct PasserByAnim {
uint32 frameTrigger = 0x3FF;
int16 startX;
int16 startY;
@@ -447,7 +444,6 @@ struct RoomPasserBys {
RoomPasserBys(byte roomNum, byte numAnims) : roomNumber(roomNum), numAnims(numAnims) {}
};
-
/**
* Structure to hold a parsed choice option
*/
@@ -460,6 +456,7 @@ struct ChoiceOption {
bool shouldDisableOnSelect = false;
bool hasConversationEndMarker = false;
bool isTerminator = false;
+ int charOffset = 0;
ChoiceOption() : choiceIndex(-1), dataOffset(0) {}
};
@@ -502,7 +499,6 @@ struct ResetEntry {
#define FLAG_TIENDA_ABIERTA 46
#define FLAG_COMO_ESTAN_LOS_DIOSES 41
-
#define FLAG_VIAJE_A_EGIPTO 12
#define FLAG_PUERTA_SECRETA_ABIERTA 16
#define FLAG_VIGILANTE_MEANDO 22
@@ -635,7 +631,6 @@ struct GameStateData {
return -1;
}
-
int booksInInventory() {
int l = inventoryItems.size();
int count = 0;
@@ -646,7 +641,6 @@ struct GameStateData {
}
return count;
}
-
};
struct SaveGameData {
Commit: d574cf97d001699a53fb9ee8abb1eeea9d757d33
https://github.com/scummvm/scummvm/commit/d574cf97d001699a53fb9ee8abb1eeea9d757d33
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:16+02:00
Commit Message:
PELROCK: add correct sizing to dialogue surface
Changed paths:
engines/pelrock/dialog.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 7be58fa128d..25c6108a79c 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -161,7 +161,7 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *c
Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId) {
int maxWidth = 0;
- int height = dialogueLines.size() * 24;
+ int height = dialogueLines.size() * 25; // Add some padding
for (int i = 0; i < dialogueLines.size(); i++) {
maxWidth = MAX(maxWidth, g_engine->_largeFont->getStringWidth(dialogueLines[i]));
}
Commit: 3d1eb5b3882799002411d36d6b72e39aee24b36c
https://github.com/scummvm/scummvm/commit/3d1eb5b3882799002411d36d6b72e39aee24b36c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:16+02:00
Commit Message:
PELROCK: Implements missing actions
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 3b743ef4e48..877827a4efe 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -46,6 +46,7 @@ const ActionEntry actionTable[] = {
// Room 1
{4, PICKUP, &PelrockEngine::pickUpBrick}, // Brick
{277, OPEN, &PelrockEngine::openIceCreamShopDoor},
+ {273, PICKUP, &PelrockEngine::pickupGarbageCan},
// Room 2
{282, OPEN, &PelrockEngine::openMcDoor},
{282, CLOSE, &PelrockEngine::closeMcDoor},
@@ -85,6 +86,8 @@ const ActionEntry actionTable[] = {
{315, OPEN, &PelrockEngine::openPlug},
{316, PICKUP, &PelrockEngine::pickCables},
{312, OPEN, &PelrockEngine::openMuseumDoor},
+ {310, PICKUP, &PelrockEngine::pickupFruit},
+ {311, PICKUP, &PelrockEngine::pickupFruit},
// // Room 5
// {},
@@ -756,6 +759,10 @@ void PelrockEngine::openIceCreamShopDoor(HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[HELADERIA_CERRADA]);
}
+void PelrockEngine::pickupGarbageCan(HotSpot *hotspot) {
+ _dialog->say(_res->_ingameTexts[POBRE_PERO_NO_HE_LLEGADO_A_ESO]);
+}
+
void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
if (!_room->hasSticker(91)) {
_dialog->say(_res->_ingameTexts[YA_CERRADO_M]);
@@ -1082,6 +1089,10 @@ void PelrockEngine::openMuseumDoor(HotSpot *hotspot) {
}
}
+void PelrockEngine::pickupFruit(HotSpot *hotspot) {
+ _dialog->say(_res->_ingameTexts[NO_THEY_MAKEYOU_FAT]);
+}
+
void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
if (!_room->hasSticker(24)) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index a32bc60b0d3..435969c995f 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -299,6 +299,7 @@ public:
void pickYellowBook(HotSpot *hotspot);
void pickUpBrick(HotSpot *hotspot);
void openIceCreamShopDoor(HotSpot *hotspot);
+ void pickupGarbageCan(HotSpot *hotspot);
void noOpAction(HotSpot *hotspot);
void noOpItem(int item, HotSpot *hotspot);
void useOnAlfred(int inventoryObject);
@@ -326,6 +327,7 @@ public:
void unlockMuseum();
void giveMoneyToGuard(int inventoryObject, HotSpot *hotspot);
void openMuseumDoor(HotSpot *hotspot);
+ void pickupFruit(HotSpot *hotspot);
void useAmuletWithStatue(int inventoryObject, HotSpot *hotspot);
void useSecretCodeWithStatue(int inventoryObject, HotSpot *hotspot);
void pickUpLetter(HotSpot *hotspot);
Commit: 121b734d3442c243d8b1bce9abb2398389ce004b
https://github.com/scummvm/scummvm/commit/121b734d3442c243d8b1bce9abb2398389ce004b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:17+02:00
Commit Message:
PELROCK: Credits in main menu
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index acdf8d1ded0..0840da818c4 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -84,6 +84,8 @@ void MenuManager::checkMouseClick(int x, int y) {
switch (button) {
case QUESTION_MARK_BUTTON:
debug("Show credits");
+ _events->_leftMouseClicked = false;
+ showCredits();
break;
case INVENTORY_PREV_BUTTON:
if (_curInventoryPage > 0)
@@ -107,6 +109,46 @@ void MenuManager::checkMouseClick(int x, int y) {
}
}
+void MenuManager::showCredits() {
+ memset(_compositeBuffer, 0, 640 * 400);
+ Common::File alfred7;
+ if (!alfred7.open(Common::Path("ALFRED.7"))) {
+ error("Could not open ALFRED.7");
+ return;
+ }
+
+ alfred7.seek(kCreditsBackgroundOffset, SEEK_SET);
+ alfred7.read(_compositeBuffer, 640 * 400);
+ byte *creditsBuf = nullptr;
+ size_t creditsSize = 0;
+ int numCredits = 29;
+ int creditWidth = 240;
+ int creditHeight = 22;
+ readUntilBuda(&alfred7, kCreditsBackgroundOffset + 256000, creditsBuf, creditsSize);
+ byte *decompressedCredits = nullptr;
+ rleDecompress(creditsBuf, creditsSize, 0, 0, &decompressedCredits, true);
+ // draw credits in two columns taking the entire height of the screen and stating in y = 0
+ for(int i = 0; i < 34; i++) {
+ byte *singleCredit = new byte[creditWidth * creditHeight];
+ int x = (i < 34 / 2) ? 39 : 359;
+ int y = 3 + (i % (34 / 2)) * (400 / (34 / 2));
+ extractSingleFrame(decompressedCredits, singleCredit, kCreditsOrder[i], creditWidth, creditHeight);
+ drawSpriteToBuffer(_compositeBuffer, 640, singleCredit, x, y, creditWidth, creditHeight, 255);
+ delete[] singleCredit;
+ }
+
+ memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+ delete[] decompressedCredits;
+ delete[] creditsBuf;
+
+ while(!g_engine->shouldQuit() && !_events->_leftMouseClicked && !_events->_rightMouseClicked) {
+ _events->pollEvent();
+ _screen->markAllDirty();
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+}
+
bool MenuManager::selectInventoryItem(int i) {
if (_curInventoryPage * 4 + i >= g_engine->_state->inventoryItems.size())
return false;
@@ -123,6 +165,7 @@ void MenuManager::menuLoop() {
g_system->getPaletteManager()->setPalette(_mainMenuPalette, 0, 256);
g_engine->changeCursor(DEFAULT);
+
while (!g_engine->shouldQuit() && !_events->_rightMouseClicked) {
_events->pollEvent();
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 0c097817f77..30d6d5cc1db 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -33,6 +33,7 @@ namespace Pelrock {
const int kQuestionMarkOffset = 3214046;
const int kInvLeftArrowOffset = 3215906;
const int kTransparentColor = 15;
+const uint32 kCreditsBackgroundOffset = 3271454;
enum MenuButton {
QUESTION_MARK_BUTTON,
@@ -47,6 +48,43 @@ enum MenuButton {
NO_BUTTON
};
+static const int kCreditsOrder[34] = {
+ 5, // PROGRAMACION
+ 8, // Juan Jose Gil
+ 20, // Jose Vicente Pons
+ 24, // LuisFer Fernandez
+ 22, // Fernando Perez
+ 7, // GRAFICOS
+ 12, // Queral,
+ 14, // Ana maria polo
+ 18, // Juan Arocas
+ 16, // Gost
+ 26, // Astorga
+ 28, // Santi Sanz
+ 2, // Fernando Aparicio
+ 11,// INTRODUCCION
+ 12, // Queral,
+ 26, // Astorga
+ 28, // Santi Sanz
+ 9, // MUSICA
+ 6, // Rufino Acosta
+ 13, // GUION
+ 8, // Juan Jose Gil
+ 19, // DIALOGOS
+ 4, // Vicent raul arnau,
+ 8, // Juan Jose Gil,
+ 21, // PROBADORES
+ 0, //David Burgos
+ 10, // Alberto Leon
+ 1, // Carles Pons
+ 3, // Roman Pons
+ 25, // Andres Ruiz,
+ 27, // Juan Jose Ruiz
+ 23, // Marilo
+ 15, // PRODUCCION
+ 17 // DDM
+};
+
static const char *inventorySounds[113] = {
"HOJASZZZ.SMP", // 0 - Default leaf rustle
@@ -176,6 +214,7 @@ public:
private:
void checkMouseClick(int x, int y);
+ void showCredits();
bool selectInventoryItem(int i);
void loadMenuTexts();
void cleanUp();
Commit: 87769a6d090a22faad5163b29db46e0a55241087
https://github.com/scummvm/scummvm/commit/87769a6d090a22faad5163b29db46e0a55241087
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:17+02:00
Commit Message:
PELROCK: Refactor alfred special anim code into its own function
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 877827a4efe..5425de59fde 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -647,9 +647,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_sound->playSound("TWANGZZZ.SMP", 0);
break;
case 376: {
- _res->loadAlfredSpecialAnim(14);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(14);
loadExtraScreenAndPresent(12);
_state->setCurrentRoot(45, 2, 0);
} break;
@@ -876,13 +874,8 @@ void PelrockEngine::openLamppost(HotSpot *hotspot) {
void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
- // TODO: Play Alfred's throwing animation
- // This would require adding a new special animation entry
- _res->loadAlfredSpecialAnim(4);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(4);
- // TODO: Animate sprite 8 (brick projectile) moving to window
Sprite *brickSprite = _room->findSpriteByIndex(7);
HotSpot *windowHotspot = _room->findHotspotByExtra(294);
brickSprite->x = 420;
@@ -892,17 +885,14 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
while (!shouldQuit()) {
_events->pollEvent();
renderScene(OVERLAY_NONE);
- // if (_chrono->_gameTick) {
_room->findSpriteByIndex(7)->y -= 10;
if (_room->findSpriteByIndex(7)->y <= 70) {
_room->findSpriteByIndex(7)->zOrder = -1;
break;
}
- // }
_screen->update();
g_system->delayMillis(10);
}
- // This would involve loading and animating the room sprite
// Add the broken window sticker
_room->addSticker(11);
@@ -1011,24 +1001,17 @@ void PelrockEngine::pickCables(HotSpot *hotspot) {
return;
}
// Duck to pick cables
- _res->loadAlfredSpecialAnim(2);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
-
+ playAlfredSpecialAnim(2);
// electric shock
int prevX = _alfredState.x;
_alfredState.x -= 20;
// original incorrectly played door closing sound here
_sound->playSound("ELEC3ZZZ.SMP", 0);
- _res->loadAlfredSpecialAnim(3);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(3);
_alfredState.x = prevX;
// Stand up (reverse of duck)
- _res->loadAlfredSpecialAnim(2, true);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(2, true);
_room->addSticker(21);
_dialog->say(_res->_ingameTexts[RELOJ_HA_CAMBIADO]);
@@ -1194,11 +1177,9 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
_sound->playMusicTrack(27);
checkIngredients();
_dialog->say(_res->_ingameTexts[CUIDADOIMPRUDENTE]);
- _res->loadAlfredSpecialAnim(5);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
_alfredState.x -= 10;
_alfredState.y += 20;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(5);
_sound->playSound(_room->_roomSfx[0], 0); // Belch
waitForSoundEnd();
_graphics->fadeToBlack(10);
@@ -1209,6 +1190,12 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[QUEOSCUROESTAESTO]);
}
+void PelrockEngine::playAlfredSpecialAnim(int anim, bool reverse) {
+ _res->loadAlfredSpecialAnim(anim, reverse);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ waitForSpecialAnimation();
+}
+
void PelrockEngine::waitForSoundEnd() {
while (!shouldQuit() && _sound->isPlaying(0)) {
_events->pollEvent();
@@ -1406,14 +1393,10 @@ void PelrockEngine::useDollWithBed(int inventoryObject, HotSpot *hotspot) {
int y = _alfredState.y;
_alfredState.x -= 36;
_alfredState.y += 7;
- _res->loadAlfredSpecialAnim(11);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(11);
_alfredState.x -= 4;
_alfredState.y += 12;
- _res->loadAlfredSpecialAnim(12);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(12);
_alfredState.direction = ALFRED_DOWN;
_state->setFlag(FLAG_SE_HA_PUESTO_EL_MUNECO, true);
_state->removeInventoryItem(83);
@@ -1935,9 +1918,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_dialog->say(_res->_ingameTexts[PERIODICOSENSACIONALISTA], 1);
break;
case 63: // Recipe
- _res->loadAlfredSpecialAnim(1);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(1);
loadExtraScreenAndPresent(3);
_state->setCurrentRoot(17, 1, 0);
@@ -1947,22 +1928,16 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
case 59: // Recipe book
if (!_state->hasInventoryItem(64)) {
- _res->loadAlfredSpecialAnim(0);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(0);
_dialog->say(_res->_ingameTexts[HOJAENTREPAGINAS]);
addInventoryItem(64);
} else {
- _res->loadAlfredSpecialAnim(0);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(0);
_dialog->say(_res->_ingameTexts[NOENTIENDONADA]);
}
break;
case 17: // Egyptian book
- _res->loadAlfredSpecialAnim(0);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(0);
_dialog->say(_res->_ingameTexts[YASEEGIPCIO]);
_state->setFlag(FLAG_ALFRED_SABE_EGIPCIO, true);
break;
@@ -1971,18 +1946,14 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_dialog->say(_res->_ingameTexts[CAPITULOPARADOJAS]);
_state->setCurrentRoot(25, 44, 0);
} else {
- _res->loadAlfredSpecialAnim(0);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(0);
_dialog->say(_res->_ingameTexts[COSASAPRENDIDO]);
_state->setFlag(FLAG_ALFRED_INTELIGENTE, true);
_state->setCurrentRoot(14, 2, 0);
}
break;
case 64:
- _res->loadAlfredSpecialAnim(0);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(0);
loadExtraScreenAndPresent(5);
if (_state->getFlag(FLAG_ALFRED_SABE_EGIPCIO)) {
_dialog->say(_res->_ingameTexts[FORMULAVIAJETIEMPO]);
@@ -1992,9 +1963,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
case 88: {
SpellBook spellBook = SpellBook(_events, _res);
- _res->loadAlfredSpecialAnim(0);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(0);
Spell *spell = spellBook.run();
if (spell) {
@@ -2061,15 +2030,11 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
}
case 0: // yellow book
- _res->loadAlfredSpecialAnim(0);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(0);
_dialog->say(_res->_ingameTexts[CUENTOPARECIDO]);
break;
case 101: // combination
- _res->loadAlfredSpecialAnim(1);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(1);
_dialog->say(_res->_ingameTexts[PARECE_COMBINACION_CAJAFUERTE]);
_state->setFlag(FLAG_CLAVE_CAJA_FUERTE, true);
break;
@@ -2097,16 +2062,12 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
}
case 84: {
- _res->loadAlfredSpecialAnim(1);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(1);
loadExtraScreenAndPresent(7);
break;
}
case 97: {
- _res->loadAlfredSpecialAnim(1);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(1);
loadExtraScreenAndPresent(11);
_dialog->say(_res->_ingameTexts[MEHANTOMADO_EL_PELO]);
_state->setCurrentRoot(43, 1, 0);
@@ -2127,9 +2088,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
}
default: {
if (inventoryObject >= 11 && inventoryObject <= 47) {
- _res->loadAlfredSpecialAnim(0);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(0);
_dialog->say(_res->_ingameTexts[LIBRO_ABURRIDO]);
return;
}
@@ -2142,9 +2101,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
}
void PelrockEngine::chooseCorrectDoor() {
- _res->loadAlfredSpecialAnim(1);
- _alfredState.animState = ALFRED_SPECIAL_ANIM;
- waitForSpecialAnimation();
+ playAlfredSpecialAnim(1);
byte puertaBuena = _state->getFlag(FLAG_PUERTA_BUENA);
if (puertaBuena == 0) { // if not set yet, choose randomly
int choice = getRandomNumber(1);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 435969c995f..8aa35244cb3 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -347,6 +347,7 @@ public:
void openTravelAgencyDoor(HotSpot *hotspot);
void closeTravelAgencyDoor(HotSpot *hotspot);
void usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot);
+ void playAlfredSpecialAnim(int anim, bool reverse = false);
void waitForSoundEnd();
void pickupSunflower(HotSpot *hotspot);
void checkIngredients();
Commit: c491840579737ddf7d6c2cbf3bf7f4b359c43039
https://github.com/scummvm/scummvm/commit/c491840579737ddf7d6c2cbf3bf7f4b359c43039
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:17+02:00
Commit Message:
PELROCK: Fixes positioning action balloon and inventory scroll
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 25c6108a79c..a5e88c4be26 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -191,8 +191,10 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_curSprite->isTalking = false;
}
// Offset X position for Alfred to avoid overlapping with his sprite
- xBasePos = g_engine->_alfredState.x; //+ kAlfredFrameWidth / 2 - maxWidth / 2;
- yBasePos = g_engine->_alfredState.y - kAlfredFrameHeight; // Above sprite, adjust for line
+ xBasePos = g_engine->_alfredState.x;
+ // Original game: uses the scaled character height (varies with perspective),
+ // not the fixed kAlfredFrameHeight. _alfredState.h is updated by drawAlfred().
+ yBasePos = g_engine->_alfredState.y - g_engine->_alfredState.h; // Above scaled sprite top
} else {
g_engine->_alfredState.setState(ALFRED_IDLE);
if (_curSprite != nullptr) {
@@ -240,9 +242,9 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
Graphics::Surface s = getDialogueSurface(textLines, speakerId);
- // Clamp to screen bounds
- xPos = CLIP(xPos, 0, 640 - maxWidth);
- yPos = CLIP(yPos, 0, 400 - s.getRect().height());
+ // Clamp to screen bounds (original game: min Y = 1, max X = 639 - width)
+ xPos = CLIP(xPos, 0, 639 - maxWidth);
+ yPos = CLIP(yPos, 1, 400 - (int)s.getRect().height());
_screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos), 255);
drawPos(_screen, xPos, yPos, speakerId);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 9b590d96be2..123445a28bc 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -154,9 +154,9 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- // setScreen(0, ALFRED_LEFT);
+ setScreen(0, ALFRED_LEFT);
// setScreen(3, ALFRED_RIGHT);
- setScreen(22, ALFRED_DOWN);
+ // setScreen(22, ALFRED_DOWN);
// setScreen(41, ALFRED_DOWN);
// setScreen(43, ALFRED_DOWN);
// setScreen(46, ALFRED_RIGHT);
@@ -1319,17 +1319,13 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
bool alfredUnder = isAlfredUnder(x, y);
if ((hotspotIndex != -1 || alfredUnder) && !_actionPopupState.isActive) {
- _actionPopupState.x = _alfredState.x + kAlfredFrameWidth / 2 - kBalloonWidth / 2;
- if (_actionPopupState.x < 0)
- _actionPopupState.x = 0;
- if (_actionPopupState.x + kBalloonWidth > 640) {
- _actionPopupState.x = 640 - kBalloonWidth;
- }
+ // Original game positions balloon at alfred_x - 70, clamped to [1, 390]
+ _actionPopupState.x = CLIP((int)_alfredState.x - 70, 1, 390);
- _actionPopupState.y = _alfredState.y - kAlfredFrameHeight - kBalloonHeight;
- if (_actionPopupState.y < 0) {
- _actionPopupState.y = 0;
- }
+ // Original game: Y = max(10, alfred_y - character_sprite_height - 102)
+ // The 102 offset is a fixed gap above Alfred's head, NOT the balloon height.
+ // This means the balloon bottom overlaps Alfred's head by ~10 pixels.
+ _actionPopupState.y = MAX(10, (int)_alfredState.y - (int)kAlfredFrameHeight - 102);
_actionPopupState.isActive = true;
_actionPopupState.curFrame = 0;
debug("Setting alfred under popup: %d", alfredUnder);
@@ -1613,9 +1609,11 @@ void PelrockEngine::pickupIconFlash() {
void PelrockEngine::showInventoryOverlay() {
_graphics->showOverlay(60, _compositeBuffer);
uint invSize = _state->inventoryItems.size();
- int firstItem = _inventoryOverlayState.invStartingPos * kInventoryPageSize;
+ // invStartingPos is an ITEM index (not a page number).
+ // The original game scrolls 1 item at a time, not 1 page at a time.
+ int firstItem = _inventoryOverlayState.invStartingPos;
- for (int i = firstItem; i < invSize && i < firstItem + kInventoryPageSize; i++) {
+ for (int i = firstItem; i < (int)invSize && i < firstItem + kInventoryPageSize; i++) {
Common::Point p = getPositionInOverlayForIndex(i - firstItem);
if (i == _inventoryOverlayState.flashingIconIndex && _chrono->getFrameCount() % kIconBlinkPeriod == 0) {
continue;
@@ -1627,31 +1625,30 @@ void PelrockEngine::showInventoryOverlay() {
if (_inventoryOverlayState.invStartingPos > 0) {
drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
}
- if ((firstItem + kInventoryPageSize) < invSize) {
+ if (firstItem + kInventoryPageSize < (int)invSize) {
drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[1], 620, 340, 20, 60, 255);
}
- // drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
}
void PelrockEngine::checkMouseOverInventoryOverlay(int x, int y) {
+ // Original game: invStartingPos is an item index, scrolls 1 item per frame
+ // with no frame throttling (scrolls every game tick = ~55ms).
if (x < 20) {
- if (_inventoryOverlayState.invStartingPos > 0 && _chrono->getFrameCount() % 2 == 0) {
+ if (_inventoryOverlayState.invStartingPos > 0) {
_inventoryOverlayState.invStartingPos--;
}
} else if (x >= 620) {
- if (_inventoryOverlayState.invStartingPos < (_state->inventoryItems.size() / kInventoryPageSize) && _chrono->getFrameCount() % 2 == 0) {
+ if (_inventoryOverlayState.invStartingPos + kInventoryPageSize < (int)_state->inventoryItems.size()) {
_inventoryOverlayState.invStartingPos++;
}
} else {
- // mouse hover over inventory item, laid out horizontally, y coordinate is not relevant for determining which item is selected
- int index = (x - 20) / 60 + (_inventoryOverlayState.invStartingPos * kInventoryPageSize);
- if (index < _state->inventoryItems.size()) {
+ // mouse hover over inventory item, laid out horizontally, y coordinate is not relevant
+ int index = (x - 20) / 60 + _inventoryOverlayState.invStartingPos;
+ if (index < (int)_state->inventoryItems.size()) {
debug("hovering over inventory item %d at index %d", _state->inventoryItems[index], index);
- // _state->selectedInventoryItem = index;
_inventoryOverlayState.flashingIconIndex = index;
} else {
debug("hovering over empty slot in inventory overlay, no item at index %d", index);
- // _state->selectedInventoryItem = -1;
_inventoryOverlayState.flashingIconIndex = -1;
}
}
@@ -1663,9 +1660,12 @@ int PelrockEngine::checkMouseClickInventoryOverlay(int x, int y) {
} else if (x >= 620) {
return -1;
} else {
- // mouse hover over inventory item, laid out horizontally, y coordinate is not relevant for determining which item is selected
- int index = (x - 20) / 60 + (_inventoryOverlayState.invStartingPos * kInventoryPageSize);
- return _state->inventoryItems[index];
+ // mouse hover over inventory item, laid out horizontally, y coordinate is not relevant
+ int index = (x - 20) / 60 + _inventoryOverlayState.invStartingPos;
+ if (index < (int)_state->inventoryItems.size()) {
+ return _state->inventoryItems[index];
+ }
+ return -1;
}
}
Commit: d0997de2960496ea32665d3a099ad29f9f2c10f9
https://github.com/scummvm/scummvm/commit/d0997de2960496ea32665d3a099ad29f9f2c10f9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:18+02:00
Commit Message:
PELROCK: Pickup bush in room 2, door in room 47
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 5425de59fde..4289dbf3441 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -50,6 +50,8 @@ const ActionEntry actionTable[] = {
// Room 2
{282, OPEN, &PelrockEngine::openMcDoor},
{282, CLOSE, &PelrockEngine::closeMcDoor},
+ {283, PICKUP, &PelrockEngine::pickupBush},
+ {284, PICKUP, &PelrockEngine::pickupBush},
// Room 12
{60, PICKUP, &PelrockEngine::grabKetchup},
@@ -84,8 +86,9 @@ const ActionEntry actionTable[] = {
// Room 4
{315, OPEN, &PelrockEngine::openPlug},
- {316, PICKUP, &PelrockEngine::pickCables},
{312, OPEN, &PelrockEngine::openMuseumDoor},
+ {316, PICKUP, &PelrockEngine::pickCables},
+ {312, CLOSE, &PelrockEngine::closeMuseumDoor},
{310, PICKUP, &PelrockEngine::pickupFruit},
{311, PICKUP, &PelrockEngine::pickupFruit},
@@ -172,6 +175,8 @@ const ActionEntry actionTable[] = {
// Room 47
{628, PICKUP, &PelrockEngine::pickupPyramidMap},
+ {800, OPEN, &PelrockEngine::openArchitectDoorFromInside},
+ {800, CLOSE, &PelrockEngine::closeArchitectDoorFromInside},
// Generic handlers
{WILDCARD, PICKUP, &PelrockEngine::noOpAction}, // Generic pickup action
@@ -808,6 +813,10 @@ void PelrockEngine::closeMcDoor(HotSpot *hotspot) {
closeDoor(hotspot, 2, 7, FEMININE, false);
}
+void PelrockEngine::pickupBush(HotSpot *hotspot) {
+ _dialog->say(_res->_ingameTexts[MEHEVUELTOAPINCHAR]);
+}
+
void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
addInventoryItem(hotspot->extra);
_room->disableHotspot(hotspot);
@@ -1072,6 +1081,10 @@ void PelrockEngine::openMuseumDoor(HotSpot *hotspot) {
}
}
+void PelrockEngine::closeMuseumDoor(HotSpot *hotspot) {
+ closeDoor(hotspot, 1, 22, FEMININE, false);
+}
+
void PelrockEngine::pickupFruit(HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[NO_THEY_MAKEYOU_FAT]);
}
@@ -1779,6 +1792,26 @@ void PelrockEngine::pickupPyramidMap(HotSpot *hotspot) {
addInventoryItem(98);
}
+void PelrockEngine::openArchitectDoorFromInside(HotSpot *hotspot) {
+ if (!_room->hasSticker(104)) {
+ _dialog->say(_res->_ingameTexts[YA_ABIERTA_F]);
+ return;
+ }
+ _room->enableExit(0, PERSIST_TEMP);
+ _room->removeSticker(104);
+ _sound->playSound(_room->_roomSfx[0]);
+}
+
+void PelrockEngine::closeArchitectDoorFromInside(HotSpot *hotspot) {
+ if (_room->hasSticker(104)) {
+ _dialog->say(_res->_ingameTexts[YA_CERRADA_F]);
+ return;
+ }
+ _room->disableExit(0, PERSIST_TEMP);
+ _room->addSticker(104, PERSIST_TEMP);
+ _sound->playSound(_room->_roomSfx[1]);
+}
+
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
@@ -1835,6 +1868,26 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
}
}
+// Bresenham line draw using a 256-byte palette remap table (semi-transparent effect).
+// Each pixel on the line is replaced by remapTable[existing_color] instead of a flat color.
+static void drawRemappedLine(byte *buf, int x0, int y0, int x1, int y1, const byte *remapTable) {
+ int dx = ABS(x1 - x0);
+ int dy = ABS(y1 - y0);
+ int sx = (x0 < x1) ? 1 : -1;
+ int sy = (y0 < y1) ? 1 : -1;
+ int err = dx - dy;
+ while (true) {
+ if (x0 >= 0 && x0 < 640 && y0 >= 0 && y0 < 400) {
+ int idx = y0 * 640 + x0;
+ buf[idx] = remapTable[buf[idx]];
+ }
+ if (x0 == x1 && y0 == y1) break;
+ int e2 = 2 * err;
+ if (e2 > -dy) { err -= dy; x0 += sx; }
+ if (e2 < dx) { err += dx; y0 += sy; }
+ }
+}
+
void PelrockEngine::teletransportToPrincess() {
int phase = 0;
@@ -1862,48 +1915,68 @@ void PelrockEngine::teletransportToPrincess() {
_sound->playSound(_room->_roomSfx[3], 0);
+ // Draw 19 semi-transparent remapped lines (behind sprites, matching original)
+ // Original uses shadow_palette_remap_tables[1] â _paletteRemaps[1] from ALFRED.9
copyBackgroundToBuffer();
placeStickersFirstPass();
updateAnimations();
presentFrame();
-
+ _screen->update();
+ g_system->delayMillis(10);
for (int i = 0; i < 19; i++) {
- if (shouldQuit()) {
+ if (shouldQuit())
return;
- }
int x1 = lines[phase][0];
int y1 = lines[phase][1];
int x2 = lines[phase][2] + i;
int y2 = lines[phase][3];
- _screen->drawLine(x1, y1, x2, y2, 255);
+ drawRemappedLine(_compositeBuffer, x1, y1, x2, y2, _room->_paletteRemaps[1]);
}
- _screen->markAllDirty();
+ updateAnimations();
+ presentFrame();
_screen->update();
g_system->delayMillis(10);
-
- if (shouldQuit()) {
+ _events->pollEvent();
+ if (shouldQuit())
return;
- }
+ // Restore clean frame with sticker (lines gone)
_room->addSticker(stickers[phase]);
copyBackgroundToBuffer();
placeStickersFirstPass();
updateAnimations();
presentFrame();
+ _screen->update();
phase++;
}
+ // small delay before last sticker
+ int delay = 10;
+ while (!shouldQuit() && delay > 0) {
+ _events->pollEvent();
+ bool didRender = renderScene(OVERLAY_NONE);
+ _screen->update();
+ g_system->delayMillis(10);
+ if (didRender) {
+ delay--;
+ }
+ }
_room->addSticker(115);
- _screen->markAllDirty();
+ copyBackgroundToBuffer();
+ placeStickersFirstPass();
+ updateAnimations();
+ presentFrame();
_screen->update();
_dialog->say(_res->_ingameTexts[MAREDEDEU]);
+ // endgameTransportAnimation();
smokeAnimation(-1, true);
+ _state->setFlag(FLAG_END_OF_GAME, 1);
_state->setCurrentRoot(48, 1, 0);
- _alfredState.x = 138;
- _alfredState.y = 255;
+ _alfredState.x = 138;
+ _alfredState.y = 255;
setScreen(48, ALFRED_DOWN);
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 123445a28bc..f6f4285c056 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1716,7 +1716,7 @@ void PelrockEngine::gameLoop() {
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_f) {
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_q) {
endingScene();
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 8aa35244cb3..1397186c177 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -327,6 +327,7 @@ public:
void unlockMuseum();
void giveMoneyToGuard(int inventoryObject, HotSpot *hotspot);
void openMuseumDoor(HotSpot *hotspot);
+ void closeMuseumDoor(HotSpot *hotspot);
void pickupFruit(HotSpot *hotspot);
void useAmuletWithStatue(int inventoryObject, HotSpot *hotspot);
void useSecretCodeWithStatue(int inventoryObject, HotSpot *hotspot);
@@ -384,12 +385,16 @@ public:
void useWigWithPot(int inventoryObject, HotSpot *hotspot);
void magicFormula(int inventoryObject, HotSpot *hotspot);
void smokeAnimation(int spriteIndex, bool hide = true);
+ // void endgameTransportAnimation();
void openArchitectDoor(HotSpot *hotspot);
void closeArchitectDoor(HotSpot *hotspot);
void pickupPyramidMap(HotSpot *hotspot);
+ void openArchitectDoorFromInside(HotSpot *hotspot);
+ void closeArchitectDoorFromInside(HotSpot *hotspot);
void checkAllSymbols();
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
+ void pickupBush(HotSpot *hotspot);
void teletransportToPrincess();
void animateStatuePaletteFade(bool reverse = false);
Commit: 2510f3061bd080b1e101fe8ca86d6b0c13be0bf9
https://github.com/scummvm/scummvm/commit/2510f3061bd080b1e101fe8ca86d6b0c13be0bf9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:18+02:00
Commit Message:
PELROCK: Implements action and continue trigger in conversations
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 4289dbf3441..cb4fdb93758 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -679,12 +679,36 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 378:
_state->setCurrentRoot(49, 3, 0);
break;
+ case 380:
+ turnLightsOff();
+ break;
default:
debug("Got actionTrigger %d in dialogActionTrigger, but no handler defined", actionTrigger);
break;
}
}
+/**
+ * Turns the screen all dark by changing all palette colors except those of the dialog text for both
+ * Alfred and the princess.
+ */
+void PelrockEngine::turnLightsOff() {
+ memset(_currentBackground, 0, 640 * 400);
+ memset(_compositeBuffer, 0, 640 * 400);
+ memset(_screen->getPixels(), 0, 640 * 400);
+ byte darkPalette[768] = {};
+ darkPalette[238 * 3 + 0] = 60 << 2; // R = 240
+ darkPalette[238 * 3 + 1] = 57 << 2; // G = 228
+ darkPalette[238 * 3 + 2] = 57 << 2; // B = 228
+ darkPalette[13 * 3 + 0] = 63 << 2; // R = 252
+ darkPalette[13 * 3 + 1] = 21 << 2; // G = 84
+ darkPalette[13 * 3 + 2] = 63 << 2; // B = 252
+ g_system->getPaletteManager()->setPalette(darkPalette, 0, 256);
+ memcpy(_room->_roomPalette, darkPalette, 768);
+ _screen->markAllDirty();
+ _screen->update();
+}
+
void PelrockEngine::givenItems() {
_state->setFlag(FLAG_MERCHANT_GIVENITEMS, _state->getFlag(FLAG_MERCHANT_GIVENITEMS) + 1);
if (_state->getFlag(FLAG_MERCHANT_GIVENITEMS) == 4) {
@@ -1881,10 +1905,17 @@ static void drawRemappedLine(byte *buf, int x0, int y0, int x1, int y1, const by
int idx = y0 * 640 + x0;
buf[idx] = remapTable[buf[idx]];
}
- if (x0 == x1 && y0 == y1) break;
+ if (x0 == x1 && y0 == y1)
+ break;
int e2 = 2 * err;
- if (e2 > -dy) { err -= dy; x0 += sx; }
- if (e2 < dx) { err += dx; y0 += sy; }
+ if (e2 > -dy) {
+ err -= dy;
+ x0 += sx;
+ }
+ if (e2 < dx) {
+ err += dx;
+ y0 += sy;
+ }
}
}
@@ -1932,6 +1963,7 @@ void PelrockEngine::teletransportToPrincess() {
int y2 = lines[phase][3];
drawRemappedLine(_compositeBuffer, x1, y1, x2, y2, _room->_paletteRemaps[1]);
}
+
updateAnimations();
presentFrame();
_screen->update();
@@ -1973,7 +2005,7 @@ void PelrockEngine::teletransportToPrincess() {
// endgameTransportAnimation();
smokeAnimation(-1, true);
- _state->setFlag(FLAG_END_OF_GAME, 1);
+ _state->setFlag(FLAG_END_OF_GAME, true);
_state->setCurrentRoot(48, 1, 0);
_alfredState.x = 138;
_alfredState.y = 255;
@@ -2080,20 +2112,19 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
smokeAnimation(kFlightRooms[flightIndex].spriteIdx, true);
_room->addStickerToRoom(_room->_currentRoomNumber, 127 + flightIndex);
// if(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) == 0b1111) {
- HotSpot hotspot = HotSpot();
- hotspot.actionFlags = 0;
- hotspot.extra = 999;
- hotspot.x = 320;
- hotspot.y = 288;
- hotspot.w = 35;
- hotspot.h = 21;
- hotspot.innerIndex = 0;
- hotspot.index = 8;
- _room->changeHotspot(52, hotspot);
+ HotSpot hotspot = HotSpot();
+ hotspot.actionFlags = 0;
+ hotspot.extra = 999;
+ hotspot.x = 320;
+ hotspot.y = 288;
+ hotspot.w = 35;
+ hotspot.h = 21;
+ hotspot.innerIndex = 0;
+ hotspot.index = 8;
+ _room->changeHotspot(52, hotspot);
// }
}
-
break;
}
default:
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index a5e88c4be26..6513ab87e09 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -87,9 +87,9 @@ uint32 DialogManager::readTextBlock(
byte b = data[pos];
// End markers - stop reading text
- if (b == CTRL_END_TEXT || b == CTRL_END_CONVERSATION || b == CTRL_ACTION_TRIGGER ||
+ if (b == CTRL_END_TEXT || b == CTRL_END_CONVERSATION || b == CTRL_ACTION_AND_END ||
b == CTRL_END_BRANCH || b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_ONEOFF ||
- b == CTRL_TEXT_TERMINATOR || b == CTRL_ALT_END_MARKER_1 || b == CTRL_ALT_END_MARKER_2 ||
+ b == CTRL_TEXT_TERMINATOR || b == CTRL_ALT_END_MARKER_1 || b == CTRL_ACTION_AND_CONTINUE ||
b == CTRL_GO_BACK || b == CTRL_SPEAKER_ID) {
break;
}
@@ -378,7 +378,7 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
break;
}
// Found a conversation terminator - this choice ends the conversation
- if (sb == CTRL_END_CONVERSATION || sb == CTRL_ACTION_TRIGGER) {
+ if (sb == CTRL_END_CONVERSATION || sb == CTRL_ACTION_AND_END) {
opt.hasConversationEndMarker = true;
break;
}
@@ -521,10 +521,11 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
if (!skipToChoices) {
ConversationEndResult endResult = checkConversationEnd(conversationData, dataSize, state.position);
+ // Dispatch action for both 0xF8 (action+end) and 0xEB (action+continue)
+ if (endResult.hasAction) {
+ g_engine->dialogActionTrigger(endResult.actionCode, g_engine->_room->_currentRoomNumber, state.currentRoot);
+ }
if (endResult.shouldEnd) {
- if (endResult.hasAction) {
- g_engine->dialogActionTrigger(endResult.actionCode, g_engine->_room->_currentRoomNumber, state.currentRoot);
- }
break;
}
state.position = endResult.nextPosition;
@@ -658,10 +659,11 @@ uint32 DialogManager::findSpeaker(byte npcIndex, uint32 dataSize, const byte *co
}
// Skip control bytes that should be ignored
+// NOTE: 0xEB (CTRL_ALT_END_MARKER_2) must NOT be skipped here â it is an action-and-continue
+// trigger that must be processed by checkConversationEnd, not silently discarded.
uint32 DialogManager::skipControlBytes(const byte *data, uint32 dataSize, uint32 position) {
while (position < dataSize &&
- (data[position] == CTRL_ALT_END_MARKER_1 ||
- data[position] == CTRL_ALT_END_MARKER_2)) {
+ data[position] == CTRL_ALT_END_MARKER_1) {
position++;
}
return position;
@@ -672,7 +674,6 @@ uint32 DialogManager::peekNextMeaningfulByte(const byte *data, uint32 dataSize,
uint32 peekPos = position;
while (peekPos < dataSize &&
(data[peekPos] == CTRL_ALT_END_MARKER_1 ||
- data[peekPos] == CTRL_ALT_END_MARKER_2 ||
data[peekPos] == CTRL_TEXT_TERMINATOR)) {
peekPos++;
}
@@ -758,7 +759,7 @@ ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint
return result;
}
- if (controlByte == CTRL_ACTION_TRIGGER) {
+ if (controlByte == CTRL_ACTION_AND_END) {
result.actionCode = data[position + 1] | (data[position + 2] << 8);
debug("Action trigger %d encountered!", result.actionCode);
result.shouldEnd = true;
@@ -766,6 +767,18 @@ ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint
return result;
}
+ if (controlByte == CTRL_ACTION_AND_CONTINUE) {
+ // 0xEB: action-and-continue â dispatch the action but do NOT exit the conversation.
+ if (position + 2 < dataSize) {
+ result.actionCode = data[position + 1] | (data[position + 2] << 8);
+ debug("Action-and-continue trigger %d encountered (0xEB)", result.actionCode);
+ result.hasAction = true;
+ }
+ result.shouldEnd = false;
+ result.nextPosition = position + 3;
+ return result;
+ }
+
// Move past control byte
if (controlByte == CTRL_END_TEXT) {
result.nextPosition = position + 1;
@@ -848,7 +861,7 @@ uint32 DialogManager::processChoiceSelection(
if (position < dataSize) {
byte endByte = data[position];
if (endByte == CTRL_END_TEXT || endByte == CTRL_END_BRANCH ||
- endByte == CTRL_ACTION_TRIGGER) {
+ endByte == CTRL_ACTION_AND_END) {
position++;
}
}
@@ -1022,7 +1035,7 @@ bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speake
}
bool isEndMarker(unsigned char char_byte) {
- return char_byte == CTRL_END_TEXT || char_byte == CTRL_END_CONVERSATION || char_byte == CTRL_ACTION_TRIGGER || char_byte == CTRL_GO_BACK;
+ return char_byte == CTRL_END_TEXT || char_byte == CTRL_END_CONVERSATION || char_byte == CTRL_ACTION_AND_END || char_byte == CTRL_GO_BACK;
}
int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
@@ -1041,7 +1054,7 @@ int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
isEnd = true;
}
if (pos < text.size() && !isEnd) {
- if (text[pos] == CTRL_ACTION_TRIGGER) { // 0xF8 (-8) special case
+ if (text[pos] == CTRL_ACTION_AND_END) { // 0xF8 (-8) special case
wordLength += 3;
} else {
// Count all consecutive spaces
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 85362b44dd5..73ae82a13ec 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -41,14 +41,14 @@ namespace Pelrock {
#define CTRL_DIALOGUE_MARKER 0xF1 /* Choice marker that sticks */
#define CTRL_DISABLED_CHOICE 0xFA /* Disabled choice marker */
#define CTRL_PAGE_BREAK_CONV 0xF9 /* Page break in conversation */
-#define CTRL_ACTION_TRIGGER 0xF8 /* Action trigger */
+#define CTRL_ACTION_AND_END 0xF8 /* Action trigger */
#define CTRL_END_BRANCH 0xF7 /* End of branch */
#define CTRL_LINE_CONTINUE 0xF6 /* Line continue/newline */
#define CTRL_ALT_END_MARKER_1 0xF5 /* Alt end marker - do nothing */
#define CTRL_END_CONVERSATION 0xF4 /* End conversation and disable option */
#define CTRL_DIALOGUE_MARKER_ONEOFF 0xFB /* Alt choice marker that disappears */
#define CTRL_GO_BACK 0xF0 /* Go back in conversation */
-#define CTRL_ALT_END_MARKER_2 0xEB /* Alt end marker 2 */
+#define CTRL_ACTION_AND_CONTINUE 0xEB /* Action-and-continue: dispatch action, conversation keeps going (unlike 0xF8 which exits) */
#define CTRL_ALT_SPEAKER_ROOT 0xFE /* Separates conversations from different speakers */
// Helper structures for conversation state management
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 1397186c177..e15f62cf509 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -271,6 +271,8 @@ public:
void performActionTrigger(uint16 actionTrigger);
void dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex);
+ void turnLightsOff();
+
void givenItems();
void advanceQuotesConversation(byte rootIndex, byte room);
void toJail();
Commit: 3b03b4ba43e417b4a0b8f48a4155b900282c5ada
https://github.com/scummvm/scummvm/commit/3b03b4ba43e417b4a0b8f48a4155b900282c5ada
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:18+02:00
Commit Message:
PELROCK: Implements credits in the ending
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/saveload.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index cb4fdb93758..b107fb3c7c2 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -728,7 +728,7 @@ void PelrockEngine::toJail() {
_graphics->fadeToBlack(10);
_alfredState.x = 342;
_alfredState.y = 277;
- setScreen(31, ALFRED_DOWN);
+ setScreenAndPrepare(31, ALFRED_DOWN);
_state->setFlag(FLAG_A_LA_CARCEL, true);
_room->moveHotspot(_room->findHotspotByExtra(101), 444, 166);
}
@@ -1223,7 +1223,7 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
// update conversaton state
_alfredState.x = 300;
_alfredState.y = 238;
- setScreen(28, ALFRED_DOWN);
+ setScreenAndPrepare(28, ALFRED_DOWN);
_dialog->say(_res->_ingameTexts[QUEOSCUROESTAESTO]);
}
@@ -1672,7 +1672,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
_graphics->fadeToBlack(10);
_alfredState.x = 271;
_alfredState.y = 385;
- setScreen(40, ALFRED_UP);
+ setScreenAndPrepare(40, ALFRED_UP);
walkAndAction(_room->findHotspotByExtra(640), TALK);
if (shouldQuit()) {
return;
@@ -1680,7 +1680,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
_graphics->fadeToBlack(10);
_alfredState.x = 271;
_alfredState.y = 385;
- setScreen(41, ALFRED_UP);
+ setScreenAndPrepare(41, ALFRED_UP);
}
void PelrockEngine::pickUpStones(HotSpot *hotspot) {
@@ -1755,7 +1755,7 @@ void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
smokeAnimation(-1);
_alfredState.setState(ALFRED_IDLE);
- setScreen(39, ALFRED_UP);
+ setScreenAndPrepare(39, ALFRED_UP);
}
}
@@ -2009,7 +2009,7 @@ void PelrockEngine::teletransportToPrincess() {
_state->setCurrentRoot(48, 1, 0);
_alfredState.x = 138;
_alfredState.y = 255;
- setScreen(48, ALFRED_DOWN);
+ setScreenAndPrepare(48, ALFRED_DOWN);
}
void PelrockEngine::useOnAlfred(int inventoryObject) {
@@ -2093,7 +2093,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_alfredState.x = 145;
_alfredState.y = 312;
- setScreen(25, ALFRED_RIGHT);
+ setScreenAndPrepare(25, ALFRED_RIGHT);
_dialog->say(_res->_ingameTexts[MENUDAAVENTURA]);
}
break;
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index b796869b9f0..a4676a5e913 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -87,7 +87,7 @@ bool PelrockConsole::cmdLoadRoom(int argc, const char **argv) {
}
int roomNumber = atoi(argv[1]);
- g_engine->setScreen(roomNumber, ALFRED_DOWN);
+ g_engine->setScreenAndPrepare(roomNumber, ALFRED_DOWN);
debugPrintf("Loaded room %d\n", roomNumber);
return true;
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 6513ab87e09..f5e691e6dbb 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -167,7 +167,7 @@ Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String
}
Graphics::Surface s;
- s.create(maxWidth, height, Graphics::PixelFormat::createFormatCLUT8());
+ s.create(maxWidth + 1, height + 1, Graphics::PixelFormat::createFormatCLUT8());
s.fillRect(s.getRect(), 255); // Clear surface
for (int i = 0; i < dialogueLines.size(); i++) {
@@ -215,7 +215,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (dialogueLines.empty()) {
return;
}
-
+ _dismissDialog = false;
// Clear any existing click state
_events->_leftMouseClicked = false;
_dialogActive = true;
@@ -258,9 +258,13 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (curPage < (int)dialogueLines.size() - 1) {
curPage++;
} else {
- break; // Exit dialogue on last page click
+ _dismissDialog = true;
}
}
+ if(_dismissDialog) {
+ _dismissDialog = false;
+ break; // Exit dialogue if dismissed programmatically
+ }
g_system->delayMillis(10);
}
if (_curSprite != nullptr) {
@@ -761,7 +765,7 @@ ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint
if (controlByte == CTRL_ACTION_AND_END) {
result.actionCode = data[position + 1] | (data[position + 2] << 8);
- debug("Action trigger %d encountered!", result.actionCode);
+ debug("Action-and-end trigger %d encountered!", result.actionCode);
result.shouldEnd = true;
result.hasAction = true;
return result;
@@ -771,7 +775,7 @@ ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint
// 0xEB: action-and-continue â dispatch the action but do NOT exit the conversation.
if (position + 2 < dataSize) {
result.actionCode = data[position + 1] | (data[position + 2] << 8);
- debug("Action-and-continue trigger %d encountered (0xEB)", result.actionCode);
+ debug("Action-and-continue trigger %d encountered", result.actionCode);
result.hasAction = true;
}
result.shouldEnd = false;
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 73ae82a13ec..e3ce72c7e9f 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -122,6 +122,7 @@ public:
// True while a blocking dialog or conversation is on screen.
bool _dialogActive = false;
+ bool _dismissDialog = false; // When true, the current dialog will be dismissed on the next iteration of the conversation loop (used for programmatically closing dialogs, e.g. when exiting a room)
Common::String _leftArrow = Common::String(17);
Common::String _rightArrow = Common::String(16);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f6f4285c056..261104fd926 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -154,7 +154,7 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreen(0, ALFRED_LEFT);
+ setScreenAndPrepare(0, ALFRED_LEFT);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
// setScreen(41, ALFRED_DOWN);
@@ -241,6 +241,8 @@ void sortAnimsByZOrder(Common::Array<Sprite> &anims) {
}
void PelrockEngine::playSoundIfNeeded() {
+ if (_disableAmbientSounds)
+ return;
// Get ambient slot offset (0-3) or -1 if no sound this frame
int ambientSlotOffset = _sound->tickAmbientSound(_chrono->getFrameCount());
if (ambientSlotOffset >= 0) {
@@ -938,7 +940,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
exitTriggers(exit);
_alfredState.x = exit->targetX;
_alfredState.y = exit->targetY;
- setScreen(exit->targetRoom, exit->dir);
+ setScreenAndPrepare(exit->targetRoom, exit->dir);
}
}
} else {
@@ -1946,7 +1948,7 @@ void PelrockEngine::checkMouseHover() {
}
}
-void PelrockEngine::setScreen(int roomNumber, AlfredDirection dir) {
+void PelrockEngine::setScreen(int roomNumber) {
Common::File roomFile;
if (!roomFile.open(Common::Path("ALFRED.1"))) {
error("Could not open ALFRED.1");
@@ -1955,8 +1957,6 @@ void PelrockEngine::setScreen(int roomNumber, AlfredDirection dir) {
changeCursor(DEFAULT);
_sound->stopAllSounds();
_currentHotspot = nullptr;
- _alfredState.direction = dir;
- _alfredState.setState(ALFRED_IDLE);
_currentStep = 0;
int roomOffset = roomNumber * kRoomStructSize;
_alfredState.curFrame = 0;
@@ -1964,18 +1964,30 @@ void PelrockEngine::setScreen(int roomNumber, AlfredDirection dir) {
byte *palette = new byte[256 * 3];
_room->getPalette(&roomFile, roomOffset, palette);
- byte *background = new byte[640 * 400];
- _room->getBackground(&roomFile, roomOffset, background);
+ if (_currentBackground != nullptr) {
+ delete[] _currentBackground;
+ }
+ _currentBackground = new byte[640 * 400];
+ _room->getBackground(&roomFile, roomOffset, _currentBackground);
_screen->clear();
- _screen->markAllDirty();
- _screen->update();
- Common::copy(background, background + 640 * 400, _currentBackground);
copyBackgroundToBuffer();
g_system->getPaletteManager()->setPalette(palette, 0, 256);
_room->loadRoomMetadata(&roomFile, roomNumber);
+
+ _screen->markAllDirty();
+ _screen->update();
+
+ roomFile.close();
+ delete[] palette;
+}
+
+void PelrockEngine::setScreenAndPrepare(int roomNumber, AlfredDirection dir) {
+ setScreen(roomNumber);
+ _alfredState.direction = dir;
+ _alfredState.setState(ALFRED_IDLE);
_room->loadRoomTalkingAnimations(roomNumber);
if (_room->_musicTrack > 0)
_sound->playMusicTrack(_room->_musicTrack);
@@ -1989,13 +2001,7 @@ void PelrockEngine::setScreen(int roomNumber, AlfredDirection dir) {
_alfredState.y = w.y;
}
- _screen->markAllDirty();
- _screen->update();
-
doExtraActions(roomNumber);
- roomFile.close();
- delete[] background;
- delete[] palette;
}
void PelrockEngine::loadExtraScreenAndPresent(int screenIndex) {
@@ -2140,38 +2146,37 @@ void PelrockEngine::doExtraActions(int roomNumber) {
case 48: {
_dialog->_goodbyeDisabled = true;
- if (_state->getFlag(FLAG_CORRECT_DOOR_CHOSEN) == true) {
- if (_state->getFlag(FLAG_TRAMPILLA_ABIERTA) == true) {
+ if (_state->getFlag(FLAG_END_OF_GAME) == true) {
- _dialog->say(_res->_ingameTexts[OHMISALVADOR]);
- _dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
- _state->setCurrentRoot(48, 1, 0);
- walkAndAction(_room->findHotspotByExtra(634), TALK);
+ _dialog->say(_res->_ingameTexts[OHMISALVADOR]);
+ _dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
+ _state->setCurrentRoot(48, 1, 0);
+ walkAndAction(_room->findHotspotByExtra(634), TALK);
- endingScene();
+ endingScene();
- } else {
- _dialog->say(_res->_ingameTexts[OHMISALVADOR]);
- _dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
- _state->setFlag(FLAG_TRAMPILLA_ABIERTA, true);
- walkAndAction(_room->findHotspotByExtra(634), TALK);
- _room->addSticker(134);
- // wait a few frames
- int framesToWait = 0;
- while (!shouldQuit() && framesToWait < 10) {
- _events->pollEvent();
-
- bool didRender = renderScene(OVERLAY_NONE);
- if (didRender)
- framesToWait++;
- _screen->update();
- g_system->delayMillis(10);
- }
- _alfredState.x = 294;
- _alfredState.y = 387;
- _room->addSticker(136);
- setScreen(49, ALFRED_UP);
+ } else if (_state->getFlag(FLAG_CORRECT_DOOR_CHOSEN) == true) {
+ _dialog->say(_res->_ingameTexts[OHMISALVADOR]);
+ _dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
+ _state->setFlag(FLAG_TRAMPILLA_ABIERTA, true);
+ walkAndAction(_room->findHotspotByExtra(634), TALK);
+ _room->addSticker(134);
+ // wait a few frames
+ int framesToWait = 0;
+ while (!shouldQuit() && framesToWait < 10) {
+ _events->pollEvent();
+
+ bool didRender = renderScene(OVERLAY_NONE);
+ if (didRender)
+ framesToWait++;
+ _screen->update();
+ g_system->delayMillis(10);
}
+ _alfredState.x = 294;
+ _alfredState.y = 387;
+ _room->addSticker(136);
+ setScreenAndPrepare(49, ALFRED_UP);
+
} else {
_dialog->say(_res->_ingameTexts[OHMISALVADOR]);
_dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
@@ -2285,13 +2290,14 @@ void PelrockEngine::endingScene() {
int y2 = 400 / 2 + bbox1.height() / 2;
int ticks = 0;
_sound->playMusicTrack(3);
+ // Loop runs indefinitely â original game waits for any keypress before advancing to credits.
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
while (!shouldQuit()) {
_events->pollEvent();
_chrono->updateChrono();
if (_chrono->_gameTick) {
-
memcpy(_compositeBuffer, _bgScreen, 640 * 400);
for (Sprite *sprite : sprites) {
@@ -2299,17 +2305,20 @@ void PelrockEngine::endingScene() {
}
memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
- if (ticks > 30 && ticks < 180) {
+ // Title text visible frames 21â149 (original: frame > 0x14 && frame < 0x96)
+ if (ticks > 20 && ticks < 150) {
drawText(_largeFont, "ALFRED PELROCK", 0, y1, 640, 255);
drawText(_largeFont, "En busca de un sue\x80o", 0, y2, 640, 255);
}
-
- if (ticks > 200) {
- break;
- }
ticks++;
}
+ // Any keypress advances to credits (original: infinite loop until input)
+ if (_events->_lastKeyEvent != Common::KEYCODE_INVALID) {
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ break;
+ }
+
g_system->delayMillis(10);
_screen->markAllDirty();
_screen->update();
@@ -2317,12 +2326,10 @@ void PelrockEngine::endingScene() {
memset(_screen->getPixels(), 0, 640 * 400);
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
- free(_bgScreen);
+ delete[] _bgScreen;
_bgScreen = nullptr;
CursorMan.showMouse(true);
- delete[] _bgScreen;
- _bgScreen = nullptr;
delete[] palette;
_screen->markAllDirty();
_screen->update();
@@ -2332,8 +2339,102 @@ void PelrockEngine::endingScene() {
}
void PelrockEngine::credits() {
+ // 25-page room slideshow: each page loads a game room and overlays credit texts.
+ static const int kNumCreditPages = 25;
+ static const int kCreditRooms[kNumCreditPages] = {
+ 22, 27, 36, 23, 24, 37, 25, 26, 49, 43, 35, 52, 29,
+ 39, 40, 41, 45, 47, 21, 50, 46, 42, 34, 30, 14};
+ static const int kFramesPerPage = 35;
+
+ Common::Array<Common::StringArray> creditTexts = _res->getCredits();
+
+ Common::File roomFile;
+ if (!roomFile.open(Common::Path("ALFRED.1"))) {
+ error("Could not open ALFRED.1 for credits");
+ return;
+ }
+
+ byte *bg = new byte[640 * 400];
+ byte *palette = new byte[768];
+ CursorMan.showMouse(false);
+
+ // Outer restart loop â keypress during display restarts from page 0
+ bool restart = false;
+ _alfredState.setState(ALFRED_SKIP_DRAWING);
+ _disableAmbientSounds = true;
+ do {
+ restart = false;
+ for (int page = 0; page < kNumCreditPages && !shouldQuit(); page++) {
+ debug("Credits: loading page %d (room %d)", page, kCreditRooms[page]);
+ setScreen(kCreditRooms[page]);
+
+ Common::StringArray lines;
+
+ if (page < (int)creditTexts.size()) {
+ for (const Common::String &block : creditTexts[page]) {
+ Common::String cur;
+ for (uint ci = 0; ci < block.size(); ci++) {
+ byte b = (byte)block[ci];
+ if (b == 0xB1) {
+ if (!cur.empty()) {
+ lines.push_back(cur);
+ cur.clear();
+ }
+ } else if (b >= 0x20) {
+ cur += (char)b;
+ }
+ }
+ if (!cur.empty())
+ lines.push_back(cur);
+ }
+ }
- debug("Starting credits sequence");
+ // Compute vertical centering (LargeFont: CHAR_HEIGHT = 24px per line)
+ int lineH = _largeFont->getFontHeight();
+ int totalH = (int)lines.size() * lineH;
+ int startY = (400 - totalH) / 2;
+
+ byte speakerId;
+ _dialog->processColorAndTrim(lines, speakerId);
+ Graphics::Surface s = _dialog->getDialogueSurface(lines, speakerId);
+
+ int frames = 0;
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ while (!shouldQuit() && frames < kFramesPerPage) {
+ debug("Credits page %d, frame %d/%d", page, frames, kFramesPerPage);
+ _events->pollEvent();
+ bool didRender = renderScene(OVERLAY_NONE);
+
+ if (didRender) {
+ _screen->transBlitFrom(s, s.getRect(), Common::Point(0, startY), 255);
+
+ if (_chrono->getFrameCount() % 2 == 0) // Original game increments frame counter every other frame
+ frames++;
+ }
+ _screen->markAllDirty();
+ _screen->update();
+ g_system->delayMillis(10);
+
+ // Keypress â restart slideshow from page 0 (original behaviour)
+ if (_events->_lastKeyEvent != Common::KEYCODE_INVALID) {
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ restart = true;
+ break;
+ }
+ }
+
+ _screen->markAllDirty();
+ _screen->update();
+ if (restart)
+ break;
+ }
+ } while (restart && !shouldQuit());
+
+ _disableAmbientSounds = false;
+ delete[] bg;
+ delete[] palette;
+ roomFile.close();
+ CursorMan.showMouse(true);
}
void PelrockEngine::initGodsSequences(int roomNumber) {
@@ -2414,7 +2515,7 @@ void PelrockEngine::handleFlightRoomFrame() {
_alfredState.x = 294;
_alfredState.y = 387;
_alfredState.direction = ALFRED_UP;
- setScreen(49, ALFRED_UP);
+ setScreenAndPrepare(49, ALFRED_UP);
}
}
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index e15f62cf509..6b57cbbc8c9 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -189,6 +189,7 @@ public:
bool _flightSpellCast = false;
int _flightSpellFrameCounter = 0;
bool _flightInBlockingAnim = false;
+ bool _disableAmbientSounds = false;
GameStateData *_state = new GameStateData();
@@ -247,7 +248,8 @@ public:
return syncGame(s);
}
- void setScreen(int s, AlfredDirection dir);
+ void setScreen(int s);
+ void setScreenAndPrepare(int s, AlfredDirection dir);
void loadExtraScreenAndPresent(int screenIndex);
void waitForSpecialAnimation();
bool renderScene(int overlayMode = OVERLAY_NONE);
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index c110acaf2b7..07ee9409bba 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -373,7 +373,7 @@ void PelrockEngine::loadGame(SaveGameData &saveGame) {
_alfredState.direction = (AlfredDirection)saveGame.alfredDir;
_state = saveGame.gameState;
- setScreen(saveGame.currentRoom, _alfredState.direction);
+ setScreenAndPrepare(saveGame.currentRoom, _alfredState.direction);
_state->stateGame = GAME;
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 22f7d967f88..7b5483f032d 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -484,8 +484,6 @@ struct ResetEntry {
#define FLAG_MIRA_SIMBOLO_FUERA_MUSEO 15
#define FLAG_CROCODILLO_ENCENDIDO 14
#define FLAG_CLAVE_CAJA_FUERTE 19
-#define FLAG_INGREDIENTES_CONSEGUIDOS 48
-#define FLAG_MERCHANT_GIVENITEMS 58
#define FLAG_ROBA_PELO_PRINCESA 17
#define FLAG_A_LA_CARCEL 18
#define FLAG_SE_HA_PUESTO_EL_MUNECO 20
@@ -494,10 +492,25 @@ struct ResetEntry {
#define FLAG_DA_PIEDRA 31
#define FLAG_PIEDRAS_COGIDAS 32
#define FLAG_GUARDIAS_BORRACHOS 33
-#define FLAG_PUERTA_BUENA 35
#define FLAG_PIEDRA_FAKE_MOJADA 34
-#define FLAG_TIENDA_ABIERTA 46
+#define FLAG_PUERTA_BUENA 35
+#define FLAG_TRAMPILLA_ABIERTA 36
#define FLAG_COMO_ESTAN_LOS_DIOSES 41
+#define FLAG_TIENDA_ABIERTA 46
+#define FLAG_END_OF_GAME 42
+#define FLAG_INGREDIENTES_CONSEGUIDOS 48
+#define FLAG_GUARDIA_PIDECOSAS 49
+#define FLAG_GUARDIA_DNI_ENTREGADO 50
+#define FLAG_AGENCIA_ABIERTA 51
+#define FLAG_CONSIGNAS_VENDEDOR 52
+#define FLAG_PUTA_250_VECES 53
+#define FLAG_RESPUESTAS_ACERTADAS 54
+#define FLAG_CHEAT_CODE_ENABLED 55
+#define FLAG_RIDDLE_PRESENTED 56
+#define FLAG_SYMBOLS_PUSHED 57
+#define FLAG_MERCHANT_GIVENITEMS 58
+#define FLAG_CORRECT_DOOR_CHOSEN 59
+#define FLAG_ESQUELETO_RECONOCE 60
#define FLAG_VIAJE_A_EGIPTO 12
#define FLAG_PUERTA_SECRETA_ABIERTA 16
@@ -510,29 +523,15 @@ struct ResetEntry {
#define FLAG_AL_FARAON 29
#define FLAG_A_CURRAR 30
-#define FLAG_TRAMPILLA_ABIERTA 36
#define FLAG_HABITACION_PRINCESA 37
#define FLAG_A_POR_LA_PRINCESA 38
#define FLAG_VUELTA_A_EMPEZAR 39
#define FLAG_A_LOS_PASILLOS 40
-#define FLAG_END_OF_GAME 42
#define FLAG_FROM_INTRO 43
#define FLAG_HE_TIRADO_PIEDRA 44
#define FLAG_HA_USADO_AGUA 45
#define FLAG_NUMERO_DE_COPAS 47
-#define FLAG_GUARDIA_PIDECOSAS 49
-#define FLAG_GUARDIA_DNI_ENTREGADO 50
-#define FLAG_AGENCIA_ABIERTA 51
-#define FLAG_CONSIGNAS_VENDEDOR 52
-#define FLAG_PUTA_250_VECES 53
-#define FLAG_RESPUESTAS_ACERTADAS 54
-#define FLAG_CHEAT_CODE_ENABLED 55
-#define FLAG_RIDDLE_PRESENTED 56
-#define FLAG_SYMBOLS_PUSHED 57
-#define FLAG_CORRECT_DOOR_CHOSEN 58
-#define FLAG_ESQUELETO_RECONOCE 59
-
const int kNumGameFlags = 61;
struct GameStateData {
Commit: 923774a099fe97495d7361924aaa3114da9b5ec1
https://github.com/scummvm/scummvm/commit/923774a099fe97495d7361924aaa3114da9b5ec1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:18+02:00
Commit Message:
PELROCK: Implements pyramid shaking scene
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index b107fb3c7c2..3e343aec52a 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1490,7 +1490,18 @@ void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::pickUpStone(HotSpot *hotspot) {
+ _room->addSticker(117);
+ _state->setFlag(FLAG_PIRAMIDE_JODIDA, true);
+ _sound->playSound("QUAKE2ZZ.SMP", 0, 0);
+ _shakeEffectState.enable();
checkIngredients();
+ _dialog->say(_res->_ingameTexts[AYAYAY]);
+ _alfredState.direction = ALFRED_DOWN;
+ _dialog->say(_res->_ingameTexts[NADIELOHAVISTO]);
+
+ _alfredState.direction = ALFRED_LEFT;
+ _disableAction = true;
+ walkTo(592, 306);
}
void PelrockEngine::playSpecialAnim(uint32 offset, bool compressed, int x, int y, int width, int height, int numFrames) {
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index f5e691e6dbb..cfcfdf4a868 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -240,12 +240,20 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int xPos = xBasePos - maxWidth / 2;
int yPos = yBasePos - height;
+
Graphics::Surface s = getDialogueSurface(textLines, speakerId);
// Clamp to screen bounds (original game: min Y = 1, max X = 639 - width)
xPos = CLIP(xPos, 0, 639 - maxWidth);
yPos = CLIP(yPos, 1, 400 - (int)s.getRect().height());
+ if(g_engine->_shakeEffectState.enabled) {
+ debug("Applying shake effect to dialogue, shakeX: %d", g_engine->_shakeEffectState.shakeX);
+ xPos -= g_engine->_shakeEffectState.shakeX;
+ } else {
+ debug("No shake effect applied to dialogue");
+ }
+
_screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos), 255);
drawPos(_screen, xPos, yPos, speakerId);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 261104fd926..77031c2deb7 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -367,6 +367,21 @@ void PelrockEngine::frameTriggers() {
uint32 frameCount = _chrono->getFrameCount();
passerByAnim(frameCount);
handleFlightRoomFrame();
+ shakeEffect();
+}
+
+void PelrockEngine::shakeEffect() {
+ if(!_shakeEffectState.enabled) {
+ return;
+ }
+ if(_room->_currentRoomNumber == 36) {
+ _shakeEffectState.disable();
+ return;
+ }
+
+ _shakeEffectState.shakeX = (_chrono->getFrameCount() % 4 < 2) ? 2 : -2;
+ g_system->setShakePos(_shakeEffectState.shakeX, _shakeEffectState.shakeY);
+ _alfredState.x += (_shakeEffectState.shakeX/2); // Adjust Alfred's position to counteract shake for better readability
}
void PelrockEngine::passerByAnim(uint32 frameCount) {
@@ -2397,7 +2412,6 @@ void PelrockEngine::credits() {
byte speakerId;
_dialog->processColorAndTrim(lines, speakerId);
Graphics::Surface s = _dialog->getDialogueSurface(lines, speakerId);
-
int frames = 0;
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
while (!shouldQuit() && frames < kFramesPerPage) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 6b57cbbc8c9..11bf406a39d 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -179,6 +179,7 @@ public:
ChronoManager *_chrono = nullptr;
PelrockEventManager *_events = nullptr;
AlfredState _alfredState;
+ ShakeEffectState _shakeEffectState;
byte *_compositeBuffer = nullptr; // Working composition buffer
bool _mouseDisabled = false;
@@ -255,6 +256,7 @@ public:
bool renderScene(int overlayMode = OVERLAY_NONE);
void mouseHoverForMap();
void frameTriggers();
+ void shakeEffect();
void handleFlightRoomFrame();
void passerByAnim(uint32 frameCount);
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index fbb24786726..f543601fe3b 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -59,16 +59,16 @@ void SoundManager::playSound(byte index, int channel) {
}
}
-void SoundManager::playSound(const char *filename, int channel) {
+void SoundManager::playSound(const char *filename, int channel, int loopCount) {
auto it = _soundMap.find(filename);
if (it != _soundMap.end()) {
- playSound(it->_value, channel);
+ playSound(it->_value, channel, loopCount);
} else {
debug("Sound file %s not found in sound map", filename);
}
}
-void SoundManager::playSound(SonidoFile sound, int channel) {
+void SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
Common::File sonidosFile;
if (!sonidosFile.open(Common::Path("SONIDOS.DAT"))) {
debug("Failed to open SONIDOS.DAT");
@@ -82,7 +82,7 @@ void SoundManager::playSound(SonidoFile sound, int channel) {
SoundFormat format = detectFormat(data, sound.size);
uint32_t sampleRate = getSampleRate(data, format);
- Audio::AudioStream *stream = nullptr;
+ Audio::SeekableAudioStream *stream = nullptr;
if (format == SOUND_FORMAT_RIFF) {
// For WAV/RIFF files, use the wave decoder
@@ -117,7 +117,9 @@ void SoundManager::playSound(SonidoFile sound, int channel) {
_mixer->stopHandle(_sfxHandles[channel]);
}
}
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, 255U, 0, DisposeAfterUse::YES);
+ Audio::AudioStream *finalStream = loopCount == -1 ? stream : Audio::makeLoopingAudioStream(stream, 0);
+
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], finalStream, loopCount, 255U, 0, DisposeAfterUse::YES);
}
}
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 09a5941ac0d..ec4d1f4dd81 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -29,12 +29,12 @@
namespace Pelrock {
-typedef struct {
+struct SonidoFile {
Common::String filename;
uint32_t offset;
uint32_t size;
unsigned char *data;
-} SonidoFile;
+};
static const char *SOUND_FILENAMES[] = {
"NO_SOUND.SMP", // 0 - Silence/disabled
@@ -158,7 +158,7 @@ public:
SoundManager(Audio::Mixer *mixer);
~SoundManager();
void playSound(byte index, int channel = -1);
- void playSound(const char *filename, int channel);
+ void playSound(const char *filename, int channel, int loopCount = 1);
void playSound(byte *soundData, uint32 size);
void stopAllSounds();
void stopSound(int channel);
@@ -183,7 +183,7 @@ public:
byte _currentMusicTrack = 0;
private:
- void playSound(SonidoFile sound, int channel = -1);
+ void playSound(SonidoFile sound, int channel = -1, int loopCount = 1);
SoundFormat detectFormat(byte *data, uint32 size);
int getSampleRate(byte *data, SoundFormat format);
int findFreeChannel();
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 7b5483f032d..1d4079d5cd3 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -193,23 +193,42 @@ struct AlfredState {
}
};
-typedef struct {
+struct ShakeEffectState
+{
+ bool enabled = false;
+ int shakeX = 0;
+ int shakeY = 0;
+
+ void enable() {
+ enabled = true;
+ }
+
+ void disable() {
+ enabled = false;
+ shakeX = 0;
+ shakeY = 0;
+ g_system->setShakePos(0, 0);
+ }
+};
+
+
+struct MovementStep {
uint8_t flags; /* Direction flags (see MOVE_* constants) */
uint16_t distanceX; // Horizontal distance to move
uint16_t distanceY; // Vertical distance to move
-} MovementStep;
+};
/**
* Pathfinding context
*/
-typedef struct {
+struct PathContext {
uint8_t *pathBuffer; // Sequence of walkbox indices
MovementStep *movementBuffer; // Array of movement steps
uint8_t *compressed_path; // Final compressed path
uint16_t pathLength;
uint16_t movementCount;
uint16_t compressed_length;
-} PathContext;
+};
struct Anim {
int nframes;
@@ -488,6 +507,7 @@ struct ResetEntry {
#define FLAG_A_LA_CARCEL 18
#define FLAG_SE_HA_PUESTO_EL_MUNECO 20
#define FLAG_VIGILANTE_BEBE_AGUA 21
+#define FLAG_PIRAMIDE_JODIDA 23
#define FLAG_FORMULA_MAGICA 26
#define FLAG_DA_PIEDRA 31
#define FLAG_PIEDRAS_COGIDAS 32
@@ -515,7 +535,6 @@ struct ResetEntry {
#define FLAG_VIAJE_A_EGIPTO 12
#define FLAG_PUERTA_SECRETA_ABIERTA 16
#define FLAG_VIGILANTE_MEANDO 22
-#define FLAG_PIRAMIDE_JODIDA 23
#define FLAG_PIRAMIDE_JODIDA2 24
#define FLAG_VIGILANTE_PAJEANDOSE 25
#define FLAG_VIAJA_AL_PASADO 27
Commit: 919f61d3f8c0dd60cbd4738b5a4c4ada3f879dbe
https://github.com/scummvm/scummvm/commit/919f61d3f8c0dd60cbd4738b5a4c4ada3f879dbe
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:19+02:00
Commit Message:
PELROCK: Pyramid collapsing animation on room 36
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/sound.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 3e343aec52a..8812bf50dad 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1454,34 +1454,10 @@ void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[ALACONUSTED]);
_state->removeInventoryItem(86);
addInventoryItem(76);
- if (_state->getFlag(FLAG_VIGILANTE_BEBE_AGUA) == 1) {
+ if (_state->getFlag(FLAG_VIGILANTE_BEBE_AGUA) == 3) {
_dialog->say(_res->_ingameTexts[MEMEO]);
-
- // guard running
- Sprite *sprite = _room->findSpriteByIndex(0);
- sprite->animData[0].nframes = 5;
- sprite->animData[0].movementFlags = 0x1C; // Move right
- byte state = 0;
- // Basic loop to wait until the sprite has reached the door
- while (!shouldQuit()) {
- _events->pollEvent();
- renderScene();
- if (sprite->x >= 339 && state == 0) {
- state = 1;
- sprite->animData[0].movementFlags = 0x240; // Move up
- }
- if (sprite->y <= 188 && state == 1) {
- state = 2;
- sprite->animData[0].movementFlags = 0x14; // Move left
- }
- if (sprite->x <= 327 && state == 2) {
- sprite->zOrder = -1; // Hide sprite
- break;
- }
- debug("Guard position: (%d, %d), state: %d", sprite->x, sprite->y, state);
- _screen->update();
- g_system->delayMillis(10);
- }
+ _state->setFlag(FLAG_VIGILANTE_MEANDO, true);
+ guardMovement();
_room->disableSprite(36, 0, PERSIST_BOTH);
_room->enableExit(0, PERSIST_BOTH);
} else {
@@ -1489,10 +1465,39 @@ void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
}
}
+void PelrockEngine::guardMovement() {
+
+ // guard running
+ Sprite *sprite = _room->findSpriteByIndex(0);
+ sprite->animData[0].nframes = 5;
+ sprite->animData[0].movementFlags = 0x1C; // Move right
+ byte state = 0;
+ // Basic loop to wait until the sprite has reached the door
+ while (!shouldQuit()) {
+ _events->pollEvent();
+ renderScene();
+ if (sprite->x >= 339 && state == 0) {
+ state = 1;
+ sprite->animData[0].movementFlags = 0x240; // Move up
+ }
+ if (sprite->y <= 188 && state == 1) {
+ state = 2;
+ sprite->animData[0].movementFlags = 0x14; // Move left
+ }
+ if (sprite->x <= 327 && state == 2) {
+ sprite->zOrder = -1; // Hide sprite
+ break;
+ }
+ debug("Guard position: (%d, %d), state: %d", sprite->x, sprite->y, state);
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+}
+
void PelrockEngine::pickUpStone(HotSpot *hotspot) {
_room->addSticker(117);
_state->setFlag(FLAG_PIRAMIDE_JODIDA, true);
- _sound->playSound("QUAKE2ZZ.SMP", 0, 0);
+ _sound->playSound("QUAKE2ZZ.SMP", 0, -1);
_shakeEffectState.enable();
checkIngredients();
_dialog->say(_res->_ingameTexts[AYAYAY]);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 77031c2deb7..2f804f30f6c 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -154,7 +154,9 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- setScreenAndPrepare(0, ALFRED_LEFT);
+ // setScreenAndPrepare(0, ALFRED_LEFT);
+ setScreenAndPrepare(36, ALFRED_LEFT);
+
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
// setScreen(41, ALFRED_DOWN);
@@ -374,10 +376,6 @@ void PelrockEngine::shakeEffect() {
if(!_shakeEffectState.enabled) {
return;
}
- if(_room->_currentRoomNumber == 36) {
- _shakeEffectState.disable();
- return;
- }
_shakeEffectState.shakeX = (_chrono->getFrameCount() % 4 < 2) ? 2 : -2;
g_system->setShakePos(_shakeEffectState.shakeX, _shakeEffectState.shakeY);
@@ -1737,6 +1735,12 @@ void PelrockEngine::gameLoop() {
endingScene();
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_u) {
+ if(_room->_currentRoomNumber == 36) {
+ pyramidCollapse();
+ }
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ }
renderScene();
@@ -2142,6 +2146,20 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
break;
}
+ case 36: {
+ if(_shakeEffectState.enabled) {
+ _shakeEffectState.disable();
+ }
+ if(_state->getFlag(FLAG_PIRAMIDE_JODIDA) == true &&
+ // _state->getFlag(FLAG_VIGILANTE_MEANDO) == true &&
+ _state->getFlag(FLAG_PIRAMIDE_JODIDA2) == false) {
+ _state->setFlag(FLAG_VIGILANTE_MEANDO, false);
+ _state->setFlag(FLAG_PIRAMIDE_JODIDA2, true);
+ debug("Pyramid is now active!");
+ pyramidCollapse();
+ }
+ break;
+ }
case 39:
case 40:
// Rooms 39/40 are the pharaoh's guard and throne room â all conversation
@@ -2224,6 +2242,128 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
}
+void PelrockEngine::pyramidCollapse() {
+ // === Pyramid Collapse Sequence (Room 36 per-frame handler at 0x1098F) ===
+ // Binary: sprite index 2 = collapse animation, sprite index 0 = NPC guard.
+ // Original sprite table indices are offset by 2 from ScummVM indices due
+ // to the 2 header sprite slots in the room data.
+
+ // Hide NPC initially â binary sets sprite_2 field 0x21 = 0xFF (zOrder = -1)
+ Sprite *npc = _room->findSpriteByIndex(0);
+ if (npc)
+ npc->zOrder = -1;
+
+ // Start collapse animation â binary sets sprite_4 field 0x21 = 0xFE (zOrder = 254)
+ Sprite *collapseSprite = _room->findSpriteByIndex(2);
+ if (collapseSprite)
+ collapseSprite->zOrder = 254;
+
+ // Play collapse sound
+ _sound->playSound("QUAKE1ZZ.SMP", 0);
+
+ // ----- PHASE 1: Wait for collapse animation frame 5 -----
+ // Binary: loop sleep(0x69) + tick + render, check sprite_4 field 0x20 == 5
+ while (!shouldQuit()) {
+ _events->pollEvent();
+ renderScene(OVERLAY_NONE);
+ _screen->update();
+ g_system->delayMillis(10);
+ collapseSprite = _room->findSpriteByIndex(2);
+ if (!collapseSprite || collapseSprite->animData[collapseSprite->curAnimIndex].curFrame >= 5) {
+ collapseSprite->zOrder = -1; // Hide collapse animation sprite after frame 5
+ break;
+ }
+ }
+ debug("Collapse animation reached frame 5, applying background changes");
+
+ // ----- PHASE 2: Background tile copies (hide pyramid top) -----
+ // Copy 1: 99Ã45 from secondary buffer to front buffer (fills collapsed area)
+ {
+ static const int srcX = 240, srcY = 145;
+ // static const int dstX = 510, dstY = 33;
+ static const int copyW = 99, copyH = 45;
+ for (int row = 0; row < copyH; row++) {
+ memcpy(
+ _currentBackground + (srcY + row) * 640 + srcX,
+ _compositeBuffer + (srcY + row) * 640 + srcX,
+ copyW);
+ }
+ }
+ _room->findSpriteByIndex(2)->zOrder = -1;
+
+ _dialog->say(_res->_ingameTexts[YANOSEHACEONCOMOANTES]);
+ npc = _room->findSpriteByIndex(0);
+ if (npc)
+ npc->zOrder = 254;
+
+ npc = _room->findSpriteByIndex(0);
+ npc->animData[0].nframes = 5;
+ if (npc) {
+ npc->animData[npc->curAnimIndex].movementFlags = 0x1C;
+ npc->y -= 25; // One-time nudge upward to emerge from behind pyramid
+ }
+ while (!shouldQuit()) {
+ _events->pollEvent();
+ renderScene(OVERLAY_NONE);
+ _screen->update();
+ g_system->delayMillis(10);
+ npc = _room->findSpriteByIndex(0);
+ if (!npc || npc->x >= 339) break;
+ }
+
+ npc = _room->findSpriteByIndex(0);
+ if (npc)
+ npc->animData[npc->curAnimIndex].movementFlags = 0x340;
+ while (!shouldQuit()) {
+ _events->pollEvent();
+ renderScene(OVERLAY_NONE);
+ _screen->update();
+ g_system->delayMillis(10);
+ npc = _room->findSpriteByIndex(0);
+ if (!npc || npc->y >= 206) break;
+ }
+
+ npc = _room->findSpriteByIndex(0);
+ if (npc)
+ npc->animData[npc->curAnimIndex].movementFlags = 0x14;
+ while (!shouldQuit()) {
+ _events->pollEvent();
+ renderScene(OVERLAY_NONE);
+ _screen->update();
+ g_system->delayMillis(10);
+ npc = _room->findSpriteByIndex(0);
+ if (!npc || npc->x <= 307) break;
+ }
+
+ // Stop NPC movement
+ npc = _room->findSpriteByIndex(0);
+ npc->animData[0].nframes = 1;
+ if (npc)
+ npc->animData[npc->curAnimIndex].movementFlags = 0;
+
+ _dialog->say(_res->_ingameTexts[POR5MINUTOS], 0);
+
+ _room->disableExit(36, 0);
+
+ _room->addStickerToRoom(21, 79);
+ _room->disableExit(21, 2, PERSIST_BOTH);
+ HotSpot *pyramidHotspot = new HotSpot();
+ pyramidHotspot->x = 510;
+ pyramidHotspot->y = 33;
+ pyramidHotspot->w = 99;
+ pyramidHotspot->h = 45;
+ pyramidHotspot->extra = 411;
+ pyramidHotspot->isEnabled = false;
+ pyramidHotspot->innerIndex = 2;
+ pyramidHotspot->index = 7;
+ _room->disableHotspot(21, pyramidHotspot, PERSIST_BOTH);
+
+ _dialog->say(_res->_ingameTexts[TALUEGOLUCAS]);
+
+ // Walk Alfred to right edge exit -> room 21
+ walkLoop(603, 212, ALFRED_RIGHT);
+}
+
void PelrockEngine::endingScene() {
byte *palette = new byte[768];
if (_bgScreen == nullptr) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 11bf406a39d..872160fa48a 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -267,6 +267,7 @@ public:
// Actions
void doExtraActions(int roomNumber);
+void pyramidCollapse();
void endingScene();
void credits();
void initGodsSequences(int roomNumber);
@@ -379,6 +380,7 @@ public:
void useDollWithBed(int inventoryObject, HotSpot *hotspot);
void giveMagazineToGuard(int inventoryObject, HotSpot *hotspot);
void giveWaterToGuard(int inventoryObject, HotSpot *hotspot);
+ void guardMovement();
void pickUpStone(HotSpot *hotspot);
void playSpecialAnim(uint32 offset, bool compressed, int x, int y, int width, int height, int numFrames);
void giveStoneToSlaves(int inventoryObject, HotSpot *hotspot);
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index f543601fe3b..5015e32566c 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -117,7 +117,8 @@ void SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
_mixer->stopHandle(_sfxHandles[channel]);
}
}
- Audio::AudioStream *finalStream = loopCount == -1 ? stream : Audio::makeLoopingAudioStream(stream, 0);
+ debug("Playing sound with loop count %d on channel %d", loopCount, channel);
+ Audio::AudioStream *finalStream = loopCount != -1 ? stream : Audio::makeLoopingAudioStream(stream, 0);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], finalStream, loopCount, 255U, 0, DisposeAfterUse::YES);
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 1d4079d5cd3..0bfe3ead7c2 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -507,7 +507,9 @@ struct ResetEntry {
#define FLAG_A_LA_CARCEL 18
#define FLAG_SE_HA_PUESTO_EL_MUNECO 20
#define FLAG_VIGILANTE_BEBE_AGUA 21
+#define FLAG_VIGILANTE_MEANDO 22
#define FLAG_PIRAMIDE_JODIDA 23
+#define FLAG_PIRAMIDE_JODIDA2 24
#define FLAG_FORMULA_MAGICA 26
#define FLAG_DA_PIEDRA 31
#define FLAG_PIEDRAS_COGIDAS 32
@@ -534,8 +536,6 @@ struct ResetEntry {
#define FLAG_VIAJE_A_EGIPTO 12
#define FLAG_PUERTA_SECRETA_ABIERTA 16
-#define FLAG_VIGILANTE_MEANDO 22
-#define FLAG_PIRAMIDE_JODIDA2 24
#define FLAG_VIGILANTE_PAJEANDOSE 25
#define FLAG_VIAJA_AL_PASADO 27
#define FLAG_APARECE_EUNUCO 28
Commit: e53ffc7a6d7275c9db8e4befa3bd971e51841ac9
https://github.com/scummvm/scummvm/commit/e53ffc7a6d7275c9db8e4befa3bd971e51841ac9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:19+02:00
Commit Message:
PELROCK: Adjusts text in credits slideshow
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index cfcfdf4a868..21fcbacf1e0 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -158,7 +158,7 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *c
}
}
-Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId) {
+Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId, Graphics::TextAlign alignment) {
int maxWidth = 0;
int height = dialogueLines.size() * 25; // Add some padding
@@ -174,7 +174,8 @@ Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String
int xPos = 0;
int yPos = i * 25; // Above sprite, adjust for line
- g_engine->_largeFont->drawString(&s, dialogueLines[i], xPos, yPos, maxWidth, speakerId, Graphics::kTextAlignCenter);
+ debug("Drawing dialogue line %d: \"%s\" at position (%d, %d) with speaker ID %d", i, dialogueLines[i].c_str(), xPos, yPos, speakerId);
+ g_engine->_largeFont->drawString(&s, dialogueLines[i], xPos, yPos, maxWidth, speakerId, alignment);
}
return s;
@@ -1028,21 +1029,25 @@ bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speake
speakerId = lines[0][1];
if (speakerMarker == '@') {
-
for (int i = 0; i < lines.size(); i++) {
// Remove first two marker bytes
- if (lines[i].size() > 2) {
- lines[i] = lines[i].substr(2);
-
- if (lines[i][0] == 0x78 && lines[i][1] == 0x78) { // Remove additional control chars
+ if (i == 0) {
+ if (lines[i].size() > 2) {
lines[i] = lines[i].substr(2);
+
+ if (lines[i][0] == 0x78 && lines[i][1] == 0x78) { // Remove additional control chars
+ lines[i] = lines[i].substr(2);
+ }
+ } else {
+ lines[i] = "";
}
- } else {
- lines[i] = "";
}
}
return true;
}
+ else {
+ debug("No speaker marker found, defaulting to Alfred");
+ }
return false;
}
@@ -1080,7 +1085,7 @@ int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
}
Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::String text) {
-
+ debug("Word-wrapping text: \"%s\"", text.c_str());
Common::Array<Common::Array<Common::String>> pages;
Common::Array<Common::String> currentPage;
Common::Array<Common::String> currentLine;
@@ -1090,9 +1095,9 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
while (position < text.size()) {
bool isEnd = false;
int wordLength = calculateWordLength(text, position, isEnd);
- // # Extract the word (including trailing spaces)
+ // Extract the word (including trailing spaces)
Common::String word = text.substr(position, wordLength);
- // # Key decision: if word_length > chars_remaining, wrap to next line
+ // if word_length > chars_remaining, wrap to next line
if (wordLength > charsRemaining) {
// Word is longer than the entire line - need to split
currentPage.push_back(joinStrings(currentLine, ""));
@@ -1137,32 +1142,63 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
break;
}
}
- if (currentLine.empty() == false) {
+
+ if (!currentLine.empty()) {
Common::String lineText = joinStrings(currentLine, "");
while (lineText.lastChar() == CHAR_SPACE) {
lineText = lineText.substr(0, lineText.size() - 1);
}
currentPage.push_back(lineText);
}
- if (currentPage.empty() == false) {
+
+ if (!currentPage.empty()) {
pages.push_back(currentPage);
}
- for (int i = 0; i < pages.size(); i++) {
- for (int j = 0; j < pages[i].size(); j++) {
- }
+
+ //print all the pages and lines for debugging
+ for (uint i = 0; i < pages.size(); i++) {
+ debug("Page %d:", i);
+ for (uint j = 0; j < pages[i].size(); j++) {
+ debug(" Line %d: \"%s\"", j, pages[i][j].c_str());
+ }
}
return pages;
}
-Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::StringArray texts) {
- Common::Array<Common::Array<Common::String>> allWrappedLines;
- for (int i = 0; i < texts.size(); i++) {
- Common::Array<Common::Array<Common::String>> wrapped = wordWrap(texts[i]);
- for (int j = 0; j < wrapped.size(); j++) {
- allWrappedLines.push_back(wrapped[j]);
+Common::Array<Common::StringArray> DialogManager::wordWrap(Common::StringArray texts) {
+ // Sometimes we already get a pre-processed list of strings the character has to speak
+ // but we still need to add line breaks if they exceed the max chars.
+ // That means if we receive 3 lines but one is longer than the max we need to make 4 lines.
+ // if we already have 5 pages, but one of them exceeds the max, we need to construct a new page.
+ // for this is not enough to just push the result of wordWrap(String) becasue we still need to calculate new pages.
+
+ Common::Array<Common::StringArray> pages;
+ Common::Array<Common::String> currentPage;
+ int currentLineNum = 0;
+ for (uint i = 0; i < texts.size(); i++) {
+ Common::String thisLine = texts[i];
+ Common::Array<Common::Array<Common::String>> wrapped = wordWrap(thisLine);
+ debug("Wrapped line %s, %d into %d pages", thisLine.c_str(), thisLine.size(), wrapped.size());
+ for (uint j = 0; j < wrapped.size(); j++) {
+ for (int i = 0; i < wrapped[j].size(); i++)
+ {
+ if(currentLineNum < MAX_LINES) {
+ currentPage.push_back(wrapped[j][i]);
+ currentLineNum++;
+ } else {
+ pages.push_back(currentPage);
+ currentPage.clear();
+ currentPage.push_back(wrapped[j][i]);
+ currentLineNum = 1;
+ }
+ }
}
}
- return allWrappedLines;
-}
+ if (!currentPage.empty()) {
+ pages.push_back(currentPage);
+ }
+
+ return pages;
+}
} // namespace Pelrock
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index e3ce72c7e9f..dbffbeb2d58 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -111,7 +111,7 @@ public:
void say(Common::StringArray texts, byte spriteIndex = 0);
void say(Common::StringArray texts, int16 x, int16 y);
bool processColorAndTrim(Common::StringArray &lines, byte &speakerId);
- Graphics::Surface getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId);
+ Graphics::Surface getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId, Graphics::TextAlign alignment = Graphics::kTextAlignCenter);
Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
Common::Array<Common::Array<Common::String>> wordWrap(Common::StringArray texts);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 2f804f30f6c..469ca86bab0 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -155,7 +155,7 @@ void PelrockEngine::init() {
gameInitialized = true;
loadAnims();
// setScreenAndPrepare(0, ALFRED_LEFT);
- setScreenAndPrepare(36, ALFRED_LEFT);
+ setScreenAndPrepare(36, ALFRED_LEFT);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
@@ -373,13 +373,13 @@ void PelrockEngine::frameTriggers() {
}
void PelrockEngine::shakeEffect() {
- if(!_shakeEffectState.enabled) {
+ if (!_shakeEffectState.enabled) {
return;
}
_shakeEffectState.shakeX = (_chrono->getFrameCount() % 4 < 2) ? 2 : -2;
g_system->setShakePos(_shakeEffectState.shakeX, _shakeEffectState.shakeY);
- _alfredState.x += (_shakeEffectState.shakeX/2); // Adjust Alfred's position to counteract shake for better readability
+ _alfredState.x += (_shakeEffectState.shakeX / 2); // Adjust Alfred's position to counteract shake for better readability
}
void PelrockEngine::passerByAnim(uint32 frameCount) {
@@ -1736,12 +1736,16 @@ void PelrockEngine::gameLoop() {
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_u) {
- if(_room->_currentRoomNumber == 36) {
+ if (_room->_currentRoomNumber == 36) {
pyramidCollapse();
}
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_k) {
+ credits();
+ }
+
renderScene();
_screen->update();
@@ -2147,12 +2151,12 @@ void PelrockEngine::doExtraActions(int roomNumber) {
break;
}
case 36: {
- if(_shakeEffectState.enabled) {
+ if (_shakeEffectState.enabled) {
_shakeEffectState.disable();
}
- if(_state->getFlag(FLAG_PIRAMIDE_JODIDA) == true &&
- // _state->getFlag(FLAG_VIGILANTE_MEANDO) == true &&
- _state->getFlag(FLAG_PIRAMIDE_JODIDA2) == false) {
+ if (_state->getFlag(FLAG_PIRAMIDE_JODIDA) == true &&
+ // _state->getFlag(FLAG_VIGILANTE_MEANDO) == true &&
+ _state->getFlag(FLAG_PIRAMIDE_JODIDA2) == false) {
_state->setFlag(FLAG_VIGILANTE_MEANDO, false);
_state->setFlag(FLAG_PIRAMIDE_JODIDA2, true);
debug("Pyramid is now active!");
@@ -2308,7 +2312,8 @@ void PelrockEngine::pyramidCollapse() {
_screen->update();
g_system->delayMillis(10);
npc = _room->findSpriteByIndex(0);
- if (!npc || npc->x >= 339) break;
+ if (!npc || npc->x >= 339)
+ break;
}
npc = _room->findSpriteByIndex(0);
@@ -2320,7 +2325,8 @@ void PelrockEngine::pyramidCollapse() {
_screen->update();
g_system->delayMillis(10);
npc = _room->findSpriteByIndex(0);
- if (!npc || npc->y >= 206) break;
+ if (!npc || npc->y >= 206)
+ break;
}
npc = _room->findSpriteByIndex(0);
@@ -2332,7 +2338,8 @@ void PelrockEngine::pyramidCollapse() {
_screen->update();
g_system->delayMillis(10);
npc = _room->findSpriteByIndex(0);
- if (!npc || npc->x <= 307) break;
+ if (!npc || npc->x <= 307)
+ break;
}
// Stop NPC movement
@@ -2494,101 +2501,87 @@ void PelrockEngine::endingScene() {
}
void PelrockEngine::credits() {
+ _sound->playMusicTrack(3);
// 25-page room slideshow: each page loads a game room and overlays credit texts.
static const int kNumCreditPages = 25;
static const int kCreditRooms[kNumCreditPages] = {
22, 27, 36, 23, 24, 37, 25, 26, 49, 43, 35, 52, 29,
39, 40, 41, 45, 47, 21, 50, 46, 42, 34, 30, 14};
- static const int kFramesPerPage = 35;
+ static const int kFramesPerPage = 45;
Common::Array<Common::StringArray> creditTexts = _res->getCredits();
- Common::File roomFile;
- if (!roomFile.open(Common::Path("ALFRED.1"))) {
- error("Could not open ALFRED.1 for credits");
- return;
- }
-
- byte *bg = new byte[640 * 400];
- byte *palette = new byte[768];
CursorMan.showMouse(false);
// Outer restart loop â keypress during display restarts from page 0
bool restart = false;
_alfredState.setState(ALFRED_SKIP_DRAWING);
_disableAmbientSounds = true;
+ _disableAction = true;
+ bool keyPressed = false;
do {
- restart = false;
for (int page = 0; page < kNumCreditPages && !shouldQuit(); page++) {
- debug("Credits: loading page %d (room %d)", page, kCreditRooms[page]);
+ // loads screen
setScreen(kCreditRooms[page]);
- Common::StringArray lines;
-
- if (page < (int)creditTexts.size()) {
- for (const Common::String &block : creditTexts[page]) {
- Common::String cur;
- for (uint ci = 0; ci < block.size(); ci++) {
- byte b = (byte)block[ci];
- if (b == 0xB1) {
- if (!cur.empty()) {
- lines.push_back(cur);
- cur.clear();
- }
- } else if (b >= 0x20) {
- cur += (char)b;
- }
- }
- if (!cur.empty())
- lines.push_back(cur);
- }
+ byte speakerId;
+ _dialog->processColorAndTrim(creditTexts[page], speakerId);
+
+ // Text is already encoded for new lines but should also be wrapped to respect the max chars per line!
+ creditTexts[page] = _dialog->wordWrap(creditTexts[page])[0];
+ // all lines start with a space but the first one contains the trailing space of the speakerId
+ creditTexts[page][0] = creditTexts[page][0].substr(1, creditTexts[page][0].size() - 1);
+
+ int height = creditTexts[page].size() * 25; // Add some padding
+
+ Graphics::Surface s;
+ s.create(640, height + 1, Graphics::PixelFormat::createFormatCLUT8());
+ s.fillRect(s.getRect(), 255); // Clear surface
+
+ int maxWidth = 0;
+ /**
+ * Last line is less indented for some reason, so skip that for calculation
+ */
+ for (int i = 0; i < creditTexts[page].size(); i++) {
+ maxWidth = MAX(maxWidth, g_engine->_largeFont->getStringWidth(creditTexts[page][i]));
}
- // Compute vertical centering (LargeFont: CHAR_HEIGHT = 24px per line)
- int lineH = _largeFont->getFontHeight();
- int totalH = (int)lines.size() * lineH;
- int startY = (400 - totalH) / 2;
+ int startX = 320 - (maxWidth / 2);
+ int startY = (400 - s.getRect().height()) / 2 - 10;
+
+ for (int i = 0; i < creditTexts[page].size(); i++) {
+ // subtract that extra negative identation
+ int xPos = i == creditTexts[page].size() - 1 ? startX - 10 : startX;
+ int yPos = i * 25; // Above sprite, adjust for line
+ g_engine->_largeFont->drawString(&s, creditTexts[page][i], xPos, yPos, 640, speakerId, Graphics::kTextAlignLeft);
+ }
- byte speakerId;
- _dialog->processColorAndTrim(lines, speakerId);
- Graphics::Surface s = _dialog->getDialogueSurface(lines, speakerId);
int frames = 0;
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
while (!shouldQuit() && frames < kFramesPerPage) {
- debug("Credits page %d, frame %d/%d", page, frames, kFramesPerPage);
_events->pollEvent();
bool didRender = renderScene(OVERLAY_NONE);
if (didRender) {
_screen->transBlitFrom(s, s.getRect(), Common::Point(0, startY), 255);
-
- if (_chrono->getFrameCount() % 2 == 0) // Original game increments frame counter every other frame
- frames++;
+ frames++;
}
_screen->markAllDirty();
_screen->update();
g_system->delayMillis(10);
-
- // Keypress â restart slideshow from page 0 (original behaviour)
if (_events->_lastKeyEvent != Common::KEYCODE_INVALID) {
- _events->_lastKeyEvent = Common::KEYCODE_INVALID;
- restart = true;
+ // Any key press exits credits
+ keyPressed = true;
break;
}
}
-
- _screen->markAllDirty();
- _screen->update();
- if (restart)
+ if (keyPressed) {
break;
+ }
}
- } while (restart && !shouldQuit());
+ } while (restart && !shouldQuit() && !keyPressed);
- _disableAmbientSounds = false;
- delete[] bg;
- delete[] palette;
- roomFile.close();
- CursorMan.showMouse(true);
+ g_engine->quitGame();
}
void PelrockEngine::initGodsSequences(int roomNumber) {
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 872160fa48a..e52474519b6 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -61,7 +61,6 @@ private:
Common::RandomSource _randomSource;
VideoManager *_videoManager = nullptr;
SoundManager *_sound = nullptr;
- DialogManager *_dialog = nullptr;
MenuManager *_menu = nullptr;
void init();
@@ -178,6 +177,7 @@ public:
RoomManager *_room = nullptr;
ChronoManager *_chrono = nullptr;
PelrockEventManager *_events = nullptr;
+ DialogManager *_dialog = nullptr;
AlfredState _alfredState;
ShakeEffectState _shakeEffectState;
byte *_compositeBuffer = nullptr; // Working composition buffer
@@ -267,7 +267,7 @@ public:
// Actions
void doExtraActions(int roomNumber);
-void pyramidCollapse();
+ void pyramidCollapse();
void endingScene();
void credits();
void initGodsSequences(int roomNumber);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 4eb473bae70..93452c8777a 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -435,13 +435,10 @@ Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data,
Common::Array<Common::StringArray> texts;
while (pos < size) {
if (data[pos] == CTRL_END_TEXT) {
- if (!desc.empty()) {
-
lines.push_back(desc);
texts.push_back(lines);
lines.clear();
desc = Common::String();
- }
pos++;
continue;
}
@@ -458,8 +455,11 @@ Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data,
continue;
}
- if (data[pos] == 0xC8) {
- lines.push_back(desc);
+
+ if (data[pos] == 0xC8 || data[pos] == 0xB1) {
+ if(!desc.empty() || data[pos] == 0xC8) {
+ lines.push_back(desc);
+ }
desc = Common::String();
pos++;
continue;
Commit: 24970d5b9030ac48fd09412364878b7c1b0a8228
https://github.com/scummvm/scummvm/commit/24970d5b9030ac48fd09412364878b7c1b0a8228
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:19+02:00
Commit Message:
PELROCK: Post intro cutscene
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 8812bf50dad..6c84682c650 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -357,7 +357,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 279:
travelToEgypt();
break;
- // moros
+ // merchants
case 330:
// Two oranges
@@ -435,7 +435,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_dialog->say(_res->_ingameTexts[PARAUNAVEZ], 0);
_dialog->say(_res->_ingameTexts[MEJORMELARGO], 1);
break;
- // end moros
+ // end merchants
case 353:
_state->setCurrentRoot(room, rootIndex + 2, 0);
break;
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 21fcbacf1e0..711cc71d2dd 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -174,7 +174,7 @@ Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String
int xPos = 0;
int yPos = i * 25; // Above sprite, adjust for line
- debug("Drawing dialogue line %d: \"%s\" at position (%d, %d) with speaker ID %d", i, dialogueLines[i].c_str(), xPos, yPos, speakerId);
+ // debug("Drawing dialogue line %d: \"%s\" at position (%d, %d) with speaker ID %d", i, dialogueLines[i].c_str(), xPos, yPos, speakerId);
g_engine->_largeFont->drawString(&s, dialogueLines[i], xPos, yPos, maxWidth, speakerId, alignment);
}
@@ -185,7 +185,10 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int16 xBasePos = 0;
int16 yBasePos = 0;
if (speakerId == ALFRED_COLOR) {
- if (g_engine->_alfredState.animState != ALFRED_TALKING) {
+ if (g_engine->_state->getFlag(FLAG_FROM_INTRO) == true) {
+ debug("Setting special anim");
+ g_engine->_alfredState.setState(ALFRED_SPECIAL_ANIM);
+ } else {
g_engine->_alfredState.setState(ALFRED_TALKING);
}
if (_curSprite != nullptr) {
@@ -221,7 +224,8 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_events->_leftMouseClicked = false;
_dialogActive = true;
int curPage = 0;
-
+ bool fromIntro = g_engine->_state->getFlag(FLAG_FROM_INTRO) == true;
+ debug("Displaying dialog, from intro = %d", fromIntro);
// Render loop - display text and wait for click
while (!g_engine->shouldQuit()) {
_events->pollEvent();
@@ -241,18 +245,15 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int xPos = xBasePos - maxWidth / 2;
int yPos = yBasePos - height;
-
Graphics::Surface s = getDialogueSurface(textLines, speakerId);
// Clamp to screen bounds (original game: min Y = 1, max X = 639 - width)
xPos = CLIP(xPos, 0, 639 - maxWidth);
yPos = CLIP(yPos, 1, 400 - (int)s.getRect().height());
- if(g_engine->_shakeEffectState.enabled) {
+ if (g_engine->_shakeEffectState.enabled) {
debug("Applying shake effect to dialogue, shakeX: %d", g_engine->_shakeEffectState.shakeX);
xPos -= g_engine->_shakeEffectState.shakeX;
- } else {
- debug("No shake effect applied to dialogue");
}
_screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos), 255);
@@ -263,17 +264,25 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (_events->_leftMouseClicked) {
_events->_leftMouseClicked = false;
- // debug("Dialogue click to advance, current page: %d, totalPages: %d", curPage, (int)dialogueLines.size());
- if (curPage < (int)dialogueLines.size() - 1) {
- curPage++;
- } else {
- _dismissDialog = true;
+ if (!_disableClickToAdvance) {
+ // debug("Dialogue click to advance, current page: %d, totalPages: %d", curPage, (int)dialogueLines.size());
+ if (curPage < (int)dialogueLines.size() - 1) {
+ curPage++;
+ } else {
+ _dismissDialog = true;
+ }
}
}
- if(_dismissDialog) {
+ if (_dismissDialog) {
_dismissDialog = false;
break; // Exit dialogue if dismissed programmatically
}
+
+ if(fromIntro && g_engine->_res->_isSpecialAnimFinished) {
+ debug("Dismissing due to speciawl anim ending!");
+ break;
+ }
+
g_system->delayMillis(10);
}
if (_curSprite != nullptr) {
@@ -970,7 +979,12 @@ void DialogManager::disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> *
}
}
void DialogManager::sayAlfred(Common::StringArray texts) {
- g_engine->_alfredState.setState(ALFRED_TALKING);
+ if (g_engine->_state->getFlag(FLAG_FROM_INTRO) == true) {
+ debug("Setting special anim");
+ g_engine->_alfredState.setState(ALFRED_SPECIAL_ANIM);
+ } else {
+ g_engine->_alfredState.setState(ALFRED_TALKING);
+ }
_curSprite = nullptr;
Common::Array<Common::StringArray> textLines = wordWrap(texts);
@@ -1044,8 +1058,7 @@ bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speake
}
}
return true;
- }
- else {
+ } else {
debug("No speaker marker found, defaulting to Alfred");
}
return false;
@@ -1155,12 +1168,12 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
pages.push_back(currentPage);
}
- //print all the pages and lines for debugging
+ // print all the pages and lines for debugging
for (uint i = 0; i < pages.size(); i++) {
debug("Page %d:", i);
for (uint j = 0; j < pages[i].size(); j++) {
debug(" Line %d: \"%s\"", j, pages[i][j].c_str());
- }
+ }
}
return pages;
}
@@ -1180,9 +1193,8 @@ Common::Array<Common::StringArray> DialogManager::wordWrap(Common::StringArray t
Common::Array<Common::Array<Common::String>> wrapped = wordWrap(thisLine);
debug("Wrapped line %s, %d into %d pages", thisLine.c_str(), thisLine.size(), wrapped.size());
for (uint j = 0; j < wrapped.size(); j++) {
- for (int i = 0; i < wrapped[j].size(); i++)
- {
- if(currentLineNum < MAX_LINES) {
+ for (int i = 0; i < wrapped[j].size(); i++) {
+ if (currentLineNum < MAX_LINES) {
currentPage.push_back(wrapped[j][i]);
currentLineNum++;
} else {
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index dbffbeb2d58..1e0c61e68bb 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -123,6 +123,7 @@ public:
// True while a blocking dialog or conversation is on screen.
bool _dialogActive = false;
bool _dismissDialog = false; // When true, the current dialog will be dismissed on the next iteration of the conversation loop (used for programmatically closing dialogs, e.g. when exiting a room)
+ bool _disableClickToAdvance = false;
Common::String _leftArrow = Common::String(17);
Common::String _rightArrow = Common::String(16);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 469ca86bab0..ec595061cd0 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -122,9 +122,11 @@ Common::Error PelrockEngine::run() {
_menu->menuLoop();
_state->stateGame = GAME;
} else if (_state->stateGame == GAME) {
+ maybePlayPostIntro();
gameLoop();
} else if (_state->stateGame == INTRO) {
_videoManager->playIntro();
+ _state->setFlag(FLAG_FROM_INTRO, true);
_state->stateGame = GAME;
} else if (_state->stateGame == COMPUTER) {
computerLoop();
@@ -154,8 +156,8 @@ void PelrockEngine::init() {
if (gameInitialized == false) {
gameInitialized = true;
loadAnims();
- // setScreenAndPrepare(0, ALFRED_LEFT);
- setScreenAndPrepare(36, ALFRED_LEFT);
+ setScreenAndPrepare(0, ALFRED_DOWN);
+ // setScreenAndPrepare(36, ALFRED_LEFT);
// setScreen(3, ALFRED_RIGHT);
// setScreen(22, ALFRED_DOWN);
@@ -372,6 +374,29 @@ void PelrockEngine::frameTriggers() {
shakeEffect();
}
+void PelrockEngine::maybePlayPostIntro() {
+ if (_state->getFlag(FLAG_FROM_INTRO)) {
+ setScreenAndPrepare(0, ALFRED_LEFT);
+ _alfredState.x = 396;
+ _alfredState.y = 267;
+
+ _res->loadAlfredSpecialAnim(16, false);
+ _alfredState.animState = ALFRED_SPECIAL_ANIM;
+ _dialog->_disableClickToAdvance = true;
+ _dialog->say(_res->_ingameTexts[VAYASUENHO]);
+ _dialog->_disableClickToAdvance = false;
+ waitForSpecialAnimation();
+ _graphics->fadeToBlack(20);
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+ _state->setFlag(FLAG_FROM_INTRO, false);
+ _alfredState.direction = ALFRED_DOWN;
+ _alfredState.x = kAlfredInitialPosX;
+ _alfredState.y = kAlfredInitialPosY;
+ // setScreenAndPrepare(0, ALFRED_DOWN);
+ _dialog->say(_res->_ingameTexts[MENSAJEOTRAEPOCA]);
+ }
+}
+
void PelrockEngine::shakeEffect() {
if (!_shakeEffectState.enabled) {
return;
@@ -1751,6 +1776,7 @@ void PelrockEngine::gameLoop() {
_screen->update();
}
+
void PelrockEngine::computerLoop() {
Computer computer(_events);
computer.run();
@@ -2231,7 +2257,12 @@ void PelrockEngine::doExtraActions(int roomNumber) {
smokeAnimation(1, false);
walkAndAction(fatMummy, TALK);
- debug("Restart game now!");
+ _state->clear();
+ _alfredState.x = kAlfredInitialPosX;
+ _alfredState.y = kAlfredInitialPosY;
+ _graphics->fadeToBlack(20);
+ _state->setFlag(FLAG_FROM_INTRO, true);
+ setScreenAndPrepare(0, ALFRED_LEFT);
}
break;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index e52474519b6..187c28df98a 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -116,6 +116,7 @@ private:
int checkMouseClickInventoryOverlay(int x, int y);
void gameLoop();
+ void firstScene();
void computerLoop();
void extraScreenLoop();
void walkLoop(int16 x, int16 y, AlfredDirection direction);
@@ -256,6 +257,7 @@ public:
bool renderScene(int overlayMode = OVERLAY_NONE);
void mouseHoverForMap();
void frameTriggers();
+ void maybePlayPostIntro();
void shakeEffect();
void handleFlightRoomFrame();
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 93452c8777a..c9fd605f7d4 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -52,6 +52,7 @@ const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
{11, 98, 138, 1, 7, 1526432, 1}, // 13 - Munheco 3
{4, 51, 102, 1, 7, 2972568, 1}, // 14 - descamisa
{13, 95, 99, 1, 7, 1749464, 1}, // 15 - alfred enters secret passage
+ {14, 71, 66, 1, 7, 3038454, 1, 2}, // 16- Alfred in bed
};
ResourceManager::~ResourceManager() {
@@ -212,6 +213,7 @@ void ResourceManager::loadAlfredAnims() {
free(bufferFile);
+
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
error("Could not open ALFRED.7");
@@ -219,6 +221,7 @@ void ResourceManager::loadAlfredAnims() {
}
int spriteMapSize = frameSize * 11;
+ /* Combing */
byte *alfredCombRightRaw;
size_t alfredCombRightSize;
@@ -245,9 +248,10 @@ void ResourceManager::loadAlfredAnims() {
extractSingleFrame(alfredCombLeft, alfredCombFrames[1][i], i, kAlfredFrameWidth, kAlfredFrameHeight);
}
- alfred7.close();
free(alfredCombRightRaw);
free(alfredCombLeftRaw);
+
+ alfred7.close();
}
void ResourceManager::loadOtherSpecialAnim(uint32 offset, bool rleCompressed, byte *&buffer, size_t &bufferSize) {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 0bfe3ead7c2..bbd2b765a83 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -88,6 +88,9 @@ const int kAlfredIdleAnimationFrameCount = 300;
const int kInventoryPageSize = 10;
+const int kAlfredInitialPosX = 235;
+const int kAlfredInitialPosY = 279;
+
// Direction flags (bit-packed)
#define MOVE_RIGHT 0x01 // Move right (positive X)
#define MOVE_LEFT 0x02 // Move left (negative X)
@@ -118,7 +121,8 @@ enum AlfredAnimState {
ALFRED_INTERACTING,
ALFRED_COMB,
ALFRED_SPECIAL_ANIM,
- ALFRED_SKIP_DRAWING
+ ALFRED_SKIP_DRAWING,
+ ALFRED_IN_BED
};
enum AlfredDirection {
@@ -180,8 +184,8 @@ struct AlfredState {
int curFrame = 0;
uint16 movementSpeedX = 6; // pixels per frame
uint16 movementSpeedY = 5; // pixels per frame
- uint16 x = 330;
- uint16 y = 302;
+ uint16 x = kAlfredInitialPosX;
+ uint16 y = kAlfredInitialPosY;
byte w = kAlfredFrameWidth;
byte h = kAlfredFrameHeight;
int idleFrameCounter = 0;
@@ -572,10 +576,7 @@ struct GameStateData {
Common::HashMap<byte, Common::Array<SpriteChange>> spriteChanges;
GameStateData() {
- memset(conversationCurrentRoot, 0, 112); // Initialize all to 0xFF (not set)
- for (int i = 0; i < kNumGameFlags; i++)
- flags[i] = 0;
- flags[FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ] = true;
+ clear();
}
~GameStateData() {
@@ -583,6 +584,25 @@ struct GameStateData {
conversationCurrentRoot = nullptr;
}
+ void clear() {
+ memset(conversationCurrentRoot, 0, 112); // Initialize all to 0xFF (not set)
+ for (int i = 0; i < kNumGameFlags; i++)
+ flags[i] = 0;
+ flags[FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ] = true;
+ disabledBranches.clear();
+ inventoryItems.clear();
+ stickersPerRoom.clear();
+ roomExitChanges.clear();
+ roomWalkBoxChanges.clear();
+ roomHotSpotChanges.clear();
+ spriteChanges.clear();
+ disabledBranches.clear();
+ libraryShelf = -1;
+ selectedBookIndex = -1;
+ bookLetter = '\0';
+ stateGame = GAME;
+ }
+
void addDisabledBranch(ResetEntry entry) {
disabledBranches[entry.room].push_back(entry);
}
Commit: fc84b9a8945c4c3da451ef2fc56f9afd27ee7ac3
https://github.com/scummvm/scummvm/commit/fc84b9a8945c4c3da451ef2fc56f9afd27ee7ac3
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:20+02:00
Commit Message:
PELROCK: Fix warnings
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/computer.cpp
engines/pelrock/dialog.cpp
engines/pelrock/extrascreens.cpp
engines/pelrock/extrascreens.h
engines/pelrock/graphics.cpp
engines/pelrock/library_books.h
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/types.h
engines/pelrock/util.cpp
engines/pelrock/video/video.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 6c84682c650..f1047ddd261 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -332,13 +332,11 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
w1.y = 356;
w1.w = 4;
w1.h = 14;
- w1.flags = 0;
WalkBox w2;
w2.x = 440;
w2.y = 368;
w2.w = 148;
w2.h = 2;
- w2.flags = 0;
_room->addWalkbox(w1);
_room->addWalkbox(w2);
@@ -914,7 +912,6 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
brickSprite->x = 420;
brickSprite->y = 241;
brickSprite->zOrder = 10; // Make it visible
- int target = windowHotspot->y + windowHotspot->h / 2;
while (!shouldQuit()) {
_events->pollEvent();
renderScene(OVERLAY_NONE);
@@ -1511,7 +1508,6 @@ void PelrockEngine::pickUpStone(HotSpot *hotspot) {
void PelrockEngine::playSpecialAnim(uint32 offset, bool compressed, int x, int y, int width, int height, int numFrames) {
size_t frameSize = width * height;
- debug("Frame size: %d bytes", frameSize);
size_t bufSize = frameSize * numFrames;
byte *animData = new byte[bufSize];
_res->loadOtherSpecialAnim(offset, compressed, animData, bufSize);
@@ -1519,7 +1515,6 @@ void PelrockEngine::playSpecialAnim(uint32 offset, bool compressed, int x, int y
Graphics::Surface animSurface;
animSurface.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
int curFrame = 0;
- bool firstFrame = true;
while (!shouldQuit()) {
_events->pollEvent();
@@ -1588,8 +1583,8 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
_room->addSticker(116);
- WalkBox w1 = {3, 187, 374, 5, 17};
- WalkBox w2 = {4, 141, 374, 46, 4};
+ WalkBox w1 = {3, 187, 374, 5, 17, 0};
+ WalkBox w2 = {4, 141, 374, 46, 4, 0};
_room->addWalkbox(w1);
_room->addWalkbox(w2);
_state->setFlag(FLAG_GUARDIAS_BORRACHOS, true);
@@ -1643,10 +1638,9 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
sprite->disableAfterSequence = true;
sprite->animData[0].animData = new byte *[sprite->animData[0].nframes];
- byte *spriteFrames[sprite->animData[0].nframes];
- for (int i = 0; i < sprite->animData[0].nframes; i++) {
- sprite->animData[0].animData[i] = new byte[sprite->w * sprite->h];
- extractSingleFrame(buffer + acc, sprite->animData[0].animData[i], i, sprite->w, sprite->h);
+ for (int j = 0; j < sprite->animData[0].nframes; j++) {
+ sprite->animData[0].animData[j] = new byte[sprite->w * sprite->h];
+ extractSingleFrame(buffer + acc, sprite->animData[0].animData[j], j, sprite->w, sprite->h);
}
acc += sprite->w * sprite->h * sprite->animData[0].nframes;
}
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index 03930f125fa..5a1ee64e2cc 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -50,8 +50,6 @@ void Computer::init() {
}
alfred7File.seek(kBookDataOffset, SEEK_SET);
- int index = 0;
- int index2 = 0;
while (alfred7File.pos() < kBookDataEnd) {
LibraryBook book;
@@ -151,9 +149,6 @@ void Computer::drawScreen() {
// Clear to background
memcpy(g_engine->_screen->getPixels(), _backgroundScreen, 640 * 400);
- int textY = 97;
- int textX = 225;
-
byte defaultColor = 0; // Light gray
switch (_state) {
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 711cc71d2dd..6038cf219d4 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -80,6 +80,7 @@ uint32 DialogManager::readTextBlock(
}
int lineIndex = data[++pos];
+ debug("Line index %d", lineIndex);
pos++; // blank
// debug("Reading text block starting at pos %u, line index %d, speaker ID %d", startPos, lineIndex, outSpeakerId);
// Read text until control byte
@@ -117,7 +118,6 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *c
Common::Point overlayPos = _graphics->showOverlay(overlayHeight, compositeBuffer);
for (uint i = 0; i < choices->size(); i++) {
ChoiceOption choice = (*choices)[i];
- int width = g_engine->_doubleSmallFont->getStringWidth(choice.text);
int yPos = overlayPos.y + 2 + i * kChoiceHeight;
Common::Rect bbox(kChoicePadding, yPos, kChoicePadding + 600, yPos + kChoiceHeight);
Common::Rect leftArrowBox(0, yPos, kChoicePadding, yPos + kChoiceHeight);
@@ -1193,14 +1193,14 @@ Common::Array<Common::StringArray> DialogManager::wordWrap(Common::StringArray t
Common::Array<Common::Array<Common::String>> wrapped = wordWrap(thisLine);
debug("Wrapped line %s, %d into %d pages", thisLine.c_str(), thisLine.size(), wrapped.size());
for (uint j = 0; j < wrapped.size(); j++) {
- for (int i = 0; i < wrapped[j].size(); i++) {
+ for (int k = 0; k < wrapped[j].size(); k++) {
if (currentLineNum < MAX_LINES) {
- currentPage.push_back(wrapped[j][i]);
+ currentPage.push_back(wrapped[j][k]);
currentLineNum++;
} else {
pages.push_back(currentPage);
currentPage.clear();
- currentPage.push_back(wrapped[j][i]);
+ currentPage.push_back(wrapped[j][k]);
currentLineNum = 1;
}
}
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
index 1dd9673b356..b1901494a0d 100644
--- a/engines/pelrock/extrascreens.cpp
+++ b/engines/pelrock/extrascreens.cpp
@@ -225,7 +225,6 @@ void CDPlayer::loadTrackNames() {
for (int i = 0; i < 31; i++) {
trackNames[i] = juegoFile.readString(0, 30);
- debug("Loaded track name: %s", trackNames[i].c_str());
}
juegoFile.close();
@@ -310,13 +309,13 @@ void CDPlayer::checkMouse(int x, int y) {
default:
break;
}
- _selectedButton = NO_BUTTON;
+ _selectedButton = NO_CDBUTTON;
_events->_leftMouseClicked = false;
}
- if (_events->_leftMouseButton != 0 && _selectedButton == NO_BUTTON) {
+ if (_events->_leftMouseButton != 0 && _selectedButton == NO_CDBUTTON) {
_selectedButton = isButtonClicked(_events->_mouseX, _events->_mouseY);
- if(_selectedButton != NO_BUTTON) {
+ if(_selectedButton != NO_CDBUTTON) {
_sound->playSound("11ZZZZZZ.SMP", 0);
}
}
@@ -328,7 +327,7 @@ CDPlayer::CDControls CDPlayer::isButtonClicked(int x, int y) {
return static_cast<CDControls>(i);
}
}
- return NO_BUTTON;
+ return NO_CDBUTTON;
}
void CDPlayer::loadControls() {
@@ -343,7 +342,7 @@ void CDPlayer::loadControls() {
readUntilBuda(&alfred7, 2214760, compressedData, outSize);
byte *rawData = nullptr;
- size_t decompressedSize = rleDecompress(compressedData, outSize, 0, 0, &rawData, true);
+ rleDecompress(compressedData, outSize, 0, 0, &rawData, true);
// debug("Decompressed CD player controls: %d bytes", decompressedSize);
uint32 pos = 213 * 72;
@@ -414,7 +413,7 @@ void BackgroundBook::checkMouse(int x, int y) {
default:
break;
}
- _selectedButton = NO_BUTTON;
+ _selectedButton = NO_BG_BUTTON;
int firstItem = _selectedPage * kItemsPerPage;
if (y >= 72 && y < 72 + (kItemsPerPage * g_engine->_smallFont->getFontHeight()) && x >= 37 && x <= 37 + 200) {
@@ -428,7 +427,7 @@ void BackgroundBook::checkMouse(int x, int y) {
_events->_leftMouseClicked = false;
}
- if (_events->_leftMouseButton != 0 && _selectedButton == NO_BUTTON) {
+ if (_events->_leftMouseButton != 0 && _selectedButton == NO_BG_BUTTON) {
_selectedButton = isButtonClicked(_events->_mouseX, _events->_mouseY);
}
}
@@ -439,7 +438,7 @@ BackgroundBook::Buttons BackgroundBook::isButtonClicked(int x, int y) {
return static_cast<Buttons>(i);
}
}
- return NO_BUTTON;
+ return NO_BG_BUTTON;
}
void BackgroundBook::loadRoomNames() {
diff --git a/engines/pelrock/extrascreens.h b/engines/pelrock/extrascreens.h
index 951843b1910..8f0c209d42e 100644
--- a/engines/pelrock/extrascreens.h
+++ b/engines/pelrock/extrascreens.h
@@ -96,7 +96,7 @@ enum CDControls {
PLAY_BUTTON,
PREVIOUS_BUTTON,
NEXT_BUTTON,
- NO_BUTTON
+ NO_CDBUTTON
};
public:
@@ -132,7 +132,7 @@ private:
Common::Rect(Common::Point(168, 44), 41, 28) // Next
};
int _selectedTrack = 2;
- CDControls _selectedButton = NO_BUTTON;
+ CDControls _selectedButton = NO_CDBUTTON;
};
@@ -141,7 +141,7 @@ class BackgroundBook {
enum Buttons {
PREVIOUS_BUTTON,
NEXT_BUTTON,
- NO_BUTTON
+ NO_BG_BUTTON
};
int kItemsPerPage = 22;
@@ -168,7 +168,7 @@ private:
byte *_compositeScreen;
byte *_palette;
byte *_buttons[2][2];
- Buttons _selectedButton = NO_BUTTON;
+ Buttons _selectedButton = NO_BG_BUTTON;
int _selectedPage = 0;
Common::Rect _buttonRects[2] = {
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index c1552d88d7e..74fcf293483 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -204,7 +204,6 @@ void GraphicsManager::drawColoredText(byte *buf, const Common::String &text, int
for(int j = 0; j < tempSurface.h; j++) {
for(int i = 0; i < tempSurface.w; i++) {
- int idx = j * tempSurface.w + i;
if (y + j < 400 && x + i < 640) {
byte pixel = *((byte *)tempSurface.getBasePtr(i, j));
if (pixel != 0) { // Assuming 0 is transparent
diff --git a/engines/pelrock/library_books.h b/engines/pelrock/library_books.h
index 15a6491b98e..7f38362b7d6 100644
--- a/engines/pelrock/library_books.h
+++ b/engines/pelrock/library_books.h
@@ -45,7 +45,7 @@ struct LibraryBook {
bool available; // true = can be found on shelf, false = catalog only
};
-const LibraryBook noBook = {"", "", "", 0, 0, false};
+static const LibraryBook noBook = {"", "", "", 0, 0, false};
// static const int kLibraryBookCount = 125;
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 0840da818c4..6bfb31678ec 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -121,7 +121,6 @@ void MenuManager::showCredits() {
alfred7.read(_compositeBuffer, 640 * 400);
byte *creditsBuf = nullptr;
size_t creditsSize = 0;
- int numCredits = 29;
int creditWidth = 240;
int creditHeight = 22;
readUntilBuda(&alfred7, kCreditsBackgroundOffset + 256000, creditsBuf, creditsSize);
@@ -270,12 +269,6 @@ void MenuManager::loadMenu() {
alfred7.seek(2563266, SEEK_SET);
alfred7.read(_mainMenu + curPos, 92160);
} else {
- Common::File alfred7;
- if (!alfred7.open(Common::Path("ALFRED.7"))) {
- error("Could not open ALFRED.7");
- return;
- }
-
_mainMenu = new byte[640 * 400];
alfred7.seek(kAlternateSettingsPaletteOffset, SEEK_SET);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index ec595061cd0..ef165ba0472 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -365,8 +365,6 @@ void PelrockEngine::mouseHoverForMap() {
}
}
-const int kPasserbyTriggerFrameInterval = 0x3FF;
-
void PelrockEngine::frameTriggers() {
uint32 frameCount = _chrono->getFrameCount();
passerByAnim(frameCount);
@@ -375,7 +373,7 @@ void PelrockEngine::frameTriggers() {
}
void PelrockEngine::maybePlayPostIntro() {
- if (_state->getFlag(FLAG_FROM_INTRO)) {
+ if (_state->getFlag(FLAG_FROM_INTRO) == true) {
setScreenAndPrepare(0, ALFRED_LEFT);
_alfredState.x = 396;
_alfredState.y = 267;
@@ -1091,7 +1089,6 @@ void PelrockEngine::exitTriggers(Pelrock::Exit *exit) {
} else if (exit->targetRoom == 48 && _room->_currentRoomNumber == 46) {
smokeAnimation(-1);
uint16 x = _alfredState.x;
- uint16 y = _alfredState.y;
if (x < 282) {
if (_state->getFlag(FLAG_PUERTA_BUENA) == 1) {
_state->setFlag(FLAG_CORRECT_DOOR_CHOSEN, true);
@@ -1310,7 +1307,6 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
return;
}
- int frameSize = sprite->stride;
int curFrame = animData.curFrame;
if (curFrame >= animData.nframes) {
debug("Warning: curFrame %d exceeds nframes %d for sprite %d anim %d", curFrame, animData.nframes, sprite->index, sprite->curAnimIndex);
@@ -2244,8 +2240,6 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_dialog->say(_res->_ingameTexts[OHMISALVADOR]);
_dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
// _state->setCurrentRoot(48, 0, 1);
- Sprite *thinMummy = _room->findSpriteByIndex(0);
- Sprite *thickMummy = _room->findSpriteByIndex(1);
HotSpot *fatMummy = nullptr;
for (uint i = 0; i < _room->_currentRoomHotspots.size(); i++) {
if (_room->_currentRoomHotspots[i].isSprite && _room->_currentRoomHotspots[i].index == 1) {
@@ -2437,8 +2431,8 @@ void PelrockEngine::endingScene() {
sprite->w = animValues[i][2];
sprite->h = animValues[i][3];
sprite->stride = animValues[i][2] * animValues[i][3];
- bool idleAnim = animValues[i][7] > 0;
- if (idleAnim) {
+ bool isIdleAnim = animValues[i][7] > 0;
+ if (isIdleAnim) {
sprite->numAnims = 2;
} else {
sprite->numAnims = 1;
@@ -2458,7 +2452,7 @@ void PelrockEngine::endingScene() {
extractSingleFrame(legsAnimData, mainAnim.animData[j], j, sprite->w, sprite->h);
}
- if (idleAnim) {
+ if (isIdleAnim) {
Anim idleAnim;
idleAnim.nframes = 1;
idleAnim.loopCount = 1;
@@ -2478,7 +2472,6 @@ void PelrockEngine::endingScene() {
}
Common::Rect bbox1 = _largeFont->getBoundingBox("ALFRED PELROCK");
- Common::Rect bbox2 = _largeFont->getBoundingBox("En busca de un sueño");
int y1 = 400 / 2 - bbox1.height() / 2;
int y2 = 400 / 2 + bbox1.height() / 2;
int ticks = 0;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index c9fd605f7d4..546bd1c88af 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -127,7 +127,6 @@ void ResourceManager::loadInteractionIcons() {
int iconSize = kVerbIconHeight * kVerbIconWidth;
for (int i = 0; i < kNumVerbIcons; i++) {
- uint32_t iconOffset = i * iconSize;
_verbIcons[i] = new byte[iconSize];
alfred4File.read(_verbIcons[i], iconSize);
}
@@ -146,8 +145,6 @@ void ResourceManager::loadAlfredAnims() {
alfred3.read(bufferFile, alfred3Size);
alfred3.close();
- int index = 0;
- int index3 = 0;
uint32_t capacity = 3060 * 102 + 2340 * 55;
unsigned char *completePic = new unsigned char[capacity];
rleDecompress(bufferFile, alfred3Size, 0, capacity, &completePic);
@@ -241,7 +238,7 @@ void ResourceManager::loadAlfredAnims() {
size_t alfredCombLeftSize;
readUntilBuda(&alfred7, ALFRED7_ALFRED_COMB_L, alfredCombLeftRaw, alfredCombLeftSize);
byte *alfredCombLeft = nullptr;
- size_t outSize = rleDecompress(alfredCombLeftRaw, alfredCombLeftSize, 0, spriteMapSize, &alfredCombLeft);
+ rleDecompress(alfredCombLeftRaw, alfredCombLeftSize, 0, spriteMapSize, &alfredCombLeft);
for (int i = 0; i < 11; i++) {
alfredCombFrames[1][i] = new byte[frameSize];
@@ -333,7 +330,6 @@ void ResourceManager::loadInventoryItems() {
alfred4File.seek(42366, SEEK_SET);
alfred4File.read(iconData, iconsSize);
- int iconSize = 60 * 60; // each icon has 30 bytes of header
for (int i = 0; i < 69; i++) {
_inventoryIcons[i].index = i;
extractSingleFrame(iconData, _inventoryIcons[i].iconData, i, 60, 60);
@@ -523,7 +519,6 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
for (int i = 0; i < numBlocks; i++) {
byte *thisBlock = nullptr;
size_t blockSize = 0;
- uint32 pos = stream->pos();
readUntilBuda(stream, stream->pos(), thisBlock, blockSize);
uint8_t *block_data = nullptr;
size_t decompressedSize = rleDecompress(thisBlock, blockSize, 0, 640 * 400, &block_data, true);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index c50af161fb3..2923879abaf 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -960,14 +960,14 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
uint32_t totalBytesPerFrame = sprite.w * sprite.h * anim.nframes;
anim.animData = new byte *[anim.nframes];
if (sprite.w > 0 && sprite.h > 0 && anim.nframes > 0) {
- for (int i = 0; i < anim.nframes; i++) {
+ for (int k = 0; k < anim.nframes; k++) {
if(picOffset >= pixelDataSize) {
- debug("Pixel data offset out of bounds for sprite %d anim %d, offset %d, size %d", i, j, picOffset, pixelDataSize);
+ debug("Pixel data offset out of bounds for sprite %d anim %d, offset %u, size %lu", i, j, picOffset, pixelDataSize);
break;
}
- anim.animData[i] = new byte[sprite.w * sprite.h];
+ anim.animData[k] = new byte[sprite.w * sprite.h];
// debug("Extracting frame %d for anim %d-%d, w=%d h=%d, pixelDataSize=%d, current offset %d", i, j, anim.nframes, sprite.w, sprite.h, pixelDataSize, picOffset);
- extractSingleFrame(pixelData + picOffset, anim.animData[i], i, sprite.w, sprite.h);
+ extractSingleFrame(pixelData + picOffset, anim.animData[k], k, sprite.w, sprite.h);
}
sprite.animData[j] = anim;
// debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
@@ -1224,10 +1224,10 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
talkHeader.animB = new byte *[talkHeader.numFramesAnimB];
for (int i = 0; i < talkHeader.numFramesAnimB; i++) {
talkHeader.animB[i] = new byte[talkHeader.wAnimB * talkHeader.hAnimB];
- uint32 offset = animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB);
+ uint32 animBFrameOffset = animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB);
// debug("Extracting talking anim B frame %d at offset %d, size = %d", i, animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB), talkHeader.wAnimB * talkHeader.hAnimB);
- if (offset + talkHeader.wAnimB * talkHeader.hAnimB >= decompressedSize) {
- debug("Error: offset %d is beyond decompressed size %zu", offset, decompressedSize);
+ if (animBFrameOffset + talkHeader.wAnimB * talkHeader.hAnimB >= decompressedSize) {
+ debug("Error: offset %d is beyond decompressed size %zu", animBFrameOffset, decompressedSize);
talkHeader.numFramesAnimB = 0;
} else {
extractSingleFrame(decompressed + animASize, talkHeader.animB[i], i, talkHeader.wAnimB, talkHeader.hAnimB);
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 5015e32566c..30e18ccf30b 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -39,7 +39,7 @@
namespace Pelrock {
SoundManager::SoundManager(Audio::Mixer *mixer)
- : _mixer(mixer), _currentVolume(128), _musicFile(nullptr) {
+ : _mixer(mixer), _currentVolume(128) {
// TODO: Initialize sound manager
g_system->getAudioCDManager()->open();
}
@@ -117,7 +117,6 @@ void SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
_mixer->stopHandle(_sfxHandles[channel]);
}
}
- debug("Playing sound with loop count %d on channel %d", loopCount, channel);
Audio::AudioStream *finalStream = loopCount != -1 ? stream : Audio::makeLoopingAudioStream(stream, 0);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], finalStream, loopCount, 255U, 0, DisposeAfterUse::YES);
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index ec4d1f4dd81..e5b971dd7e3 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -190,9 +190,7 @@ private:
private:
Audio::Mixer *_mixer;
- bool _isMusicPlaying = false;
int _currentVolume;
- Common::File *_musicFile;
Audio::SoundHandle _musicHandle;
Audio::SoundHandle _sfxHandles[kMaxChannels];
Common::HashMap<Common::String, SonidoFile> _soundMap;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index bbd2b765a83..77a63a52151 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -121,8 +121,7 @@ enum AlfredAnimState {
ALFRED_INTERACTING,
ALFRED_COMB,
ALFRED_SPECIAL_ANIM,
- ALFRED_SKIP_DRAWING,
- ALFRED_IN_BED
+ ALFRED_SKIP_DRAWING
};
enum AlfredDirection {
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index c27d22fbe34..58a53b1c6c3 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -213,7 +213,6 @@ size_t rleDecompress(
}
void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize) {
- const char marker[] = "BUDA";
const int markerLen = 4;
size_t bufferSize = 4096;
size_t pos = 0;
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index a4f726a8478..0b682059e51 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -63,7 +63,6 @@ void VideoManager::playIntro() {
_textSurface.fillRect(Common::Rect(0, 0, 640, 400), 255);
for (int sequence = 0; sequence < 1; sequence++) {
uint16 frameCounter = 0;
- int chunksInBuffer = 0;
bool videoExitFlag = false;
while (!videoExitFlag && !g_engine->shouldQuit() && _events->_lastKeyEvent != Common::KEYCODE_ESCAPE) {
Commit: 849b58d6a520c39cceb530083845c2141183f655
https://github.com/scummvm/scummvm/commit/849b58d6a520c39cceb530083845c2141183f655
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:20+02:00
Commit Message:
PELROCK: Fixes fall-through with salesman
Changed paths:
engines/pelrock/actions.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index f1047ddd261..6c88af3c6c7 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -340,6 +340,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_room->addWalkbox(w1);
_room->addWalkbox(w2);
+ break;
case 274:
case 275:
case 276:
Commit: 0a34967556d7d8009f88ae350c2d2d8602b07399
https://github.com/scummvm/scummvm/commit/0a34967556d7d8009f88ae350c2d2d8602b07399
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:20+02:00
Commit Message:
PELROCK: Fall through room 15
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index ef165ba0472..b8a3c4f6589 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -2096,6 +2096,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_dialog->say(_res->_ingameTexts[GAMBERROS]);
_dialog->say(_res->_ingameTexts[QUIENYO]);
_dialog->say(_res->_ingameTexts[PINTA_BUENAPERSONA]);
+ break;
}
case 38: {
if (_room->_prevRoomNumber == 30) {
Commit: 692e16d654bee51e1dde57dc8954377e56bd4d51
https://github.com/scummvm/scummvm/commit/692e16d654bee51e1dde57dc8954377e56bd4d51
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:21+02:00
Commit Message:
PELROCK: Implements dog pee animation in room 19 and pigeons scene in 24
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index b8a3c4f6589..f7387341132 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -370,6 +370,35 @@ void PelrockEngine::frameTriggers() {
passerByAnim(frameCount);
handleFlightRoomFrame();
shakeEffect();
+ maybeHaveDogPee();
+}
+
+void PelrockEngine::maybeHaveDogPee() {
+
+ if (_room->_currentRoomNumber != 19) {
+ return;
+ }
+ Sprite * dog = _room->findSpriteByIndex(2);
+
+ if(_alfredState.x < 146 && !_isDogPeeing) {
+ _isDogPeeing = true;
+ dog->animData[0].nframes = 24;
+ while(!shouldQuit() && dog->animData[0].curFrame < 23) {
+ _events->pollEvent();
+ renderScene(OVERLAY_NONE);
+
+ _screen->update();
+ g_system->delayMillis(10);
+ }
+ dog->animData[0].nframes = 9;
+ dog->animData[0].curFrame = 0;
+
+ _dialog->say(_res->_ingameTexts[QUEASCO_CASIMEMEA]);
+ _currentHotspot = nullptr; // Clear so arrival direction isn't overridden by dog hotspot
+ walkTo(152, _alfredState.y);
+ _isDogPeeing = false;
+ }
+
}
void PelrockEngine::maybePlayPostIntro() {
@@ -1325,7 +1354,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
animData.curFrame = 0;
animData.curLoop++;
} else {
- if (sprite->disableAfterSequence) {
+ if (sprite->disableAfterSequence && sprite->curAnimIndex == sprite->numAnims - 1) {
sprite->zOrder = -1;
return;
}
@@ -1925,18 +1954,6 @@ void PelrockEngine::checkMouseClick(int x, int y) {
_curWalkTarget = walkTarget;
walkTo(walkTarget.x, walkTarget.y);
-
- // { // For quick room navigation
- // Exit *exit = isExitUnder(walkTarget.x, walkTarget.y);
-
- // if (exit != nullptr) {
- // alfredState.x = exit->targetX;
- // alfredState.y = exit->targetY;
-
- // setScreen(exit->targetRoom, exit->dir);
- // } else {
- // }
- // }
}
void PelrockEngine::changeCursor(Cursor cursor) {
@@ -2098,6 +2115,38 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_dialog->say(_res->_ingameTexts[PINTA_BUENAPERSONA]);
break;
}
+ case 19: {
+ Sprite *dog = _room->findSpriteByIndex(2);
+ dog->animData[0].nframes = 9;
+ break;
+ }
+ case 24: {
+ _room->findSpriteByIndex(1)->numAnims = 1;
+
+ if(_state->hasInventoryItem(88) && _state->getFlag(FLAG_PIGEON_DEAD) == false) {
+ _dialog->say(_res->_ingameTexts[PROBARLIBRO]);
+ playAlfredSpecialAnim(0);
+ Sprite *pigeons = _room->findSpriteByIndex(1);
+ pigeons->numAnims = 4;
+ pigeons->curAnimIndex = 0;
+ pigeons->disableAfterSequence = true;
+ pigeons->animData[0].curFrame = 0;
+ while(!g_engine->shouldQuit() && pigeons->zOrder != -1) {
+ _events->pollEvent();
+ renderScene();
+ _screen->update();
+ // debug("Pigeons animation, current anim index %d, current frame %d", pigeons->curAnimIndex, pigeons->animData[pigeons->curAnimIndex].curFrame);
+ // if(pigeons->curAnimIndex == 3 && pigeons->animData[3].curFrame == 3) {
+ // debug("Pigeons animation finished, hiding pigeons and enabling next part of the scene");
+ // pigeons->zOrder = -1;
+ // }
+ g_system->delayMillis(10);
+ }
+ _dialog->say(_res->_ingameTexts[PRACTICAR_MAS]);
+ _state->setFlag(FLAG_PIGEON_DEAD, true);
+ }
+ break;
+ }
case 38: {
if (_room->_prevRoomNumber == 30) {
int x = _alfredState.x;
@@ -2548,6 +2597,10 @@ void PelrockEngine::credits() {
for (int page = 0; page < kNumCreditPages && !shouldQuit(); page++) {
// loads screen
setScreen(kCreditRooms[page]);
+ if(kCreditRooms[page] == 24) {
+ Sprite *pigeons = _room->findSpriteByIndex(1);
+ pigeons->disableAfterSequence = true;
+ }
byte speakerId;
_dialog->processColorAndTrim(creditTexts[page], speakerId);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 187c28df98a..fe2da82f092 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -192,6 +192,7 @@ public:
int _flightSpellFrameCounter = 0;
bool _flightInBlockingAnim = false;
bool _disableAmbientSounds = false;
+ bool _isDogPeeing = false;
GameStateData *_state = new GameStateData();
@@ -257,6 +258,7 @@ public:
bool renderScene(int overlayMode = OVERLAY_NONE);
void mouseHoverForMap();
void frameTriggers();
+ void maybeHaveDogPee();
void maybePlayPostIntro();
void shakeEffect();
void handleFlightRoomFrame();
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 2923879abaf..44ab35729ba 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -666,12 +666,13 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
Sprite *mouse = findSpriteByIndex(2);
Sprite *blank = findSpriteByIndex(4);
mouse->animData[0].loopCount = 3;
+ mouse->animData[0].movementFlags = 0x1F;
mouse->animData[1].loopCount = 1;
mouse->animData[1].movementFlags = 0x3FF;
mouse->animData[2].loopCount = 1;
- mouse->animData[2].movementFlags = 0x801F;
+ mouse->animData[2].movementFlags = 0x1F;
mouse->animData[3].loopCount = 4;
- mouse->animData[3].movementFlags = 0x3C0;
+ mouse->animData[3].movementFlags = 0x3E0;
anims = new RoomPasserBys(roomNumber, 1);
PasserByAnim anim;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 77a63a52151..5e3e624df09 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -448,7 +448,8 @@ struct PaletteAnim {
#define PASSERBY_DOWN 2
struct PasserByAnim {
- uint32 frameTrigger = 0x3FF;
+ // uint32 frameTrigger = 0x3FF;
+ uint32 frameTrigger = 0x96;
int16 startX;
int16 startY;
int16 resetCoord;
@@ -553,8 +554,9 @@ struct ResetEntry {
#define FLAG_HE_TIRADO_PIEDRA 44
#define FLAG_HA_USADO_AGUA 45
#define FLAG_NUMERO_DE_COPAS 47
+#define FLAG_PIGEON_DEAD 61
-const int kNumGameFlags = 61;
+const int kNumGameFlags = 62;
struct GameStateData {
byte flags[kNumGameFlags];
Commit: 2f0ac4216560f5f2c2d3ea2fd07d77850bf59170
https://github.com/scummvm/scummvm/commit/2f0ac4216560f5f2c2d3ea2fd07d77850bf59170
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:21+02:00
Commit Message:
PELROCK: Implements sound effects and music in intro video
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.h
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 6c88af3c6c7..17c6e16ad2a 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -2414,7 +2414,7 @@ void PelrockEngine::antiPiracyEffect() {
}
// Play the noise
- _sound->playSound(noiseData, kNoiseLength + 44);
+ _sound->playSound(noiseData, kNoiseLength + 44, 0);
byte *screenPixels = (byte *)_screen->getPixels();
int screenSize = _screen->pitch * _screen->h;
@@ -2443,7 +2443,7 @@ void PelrockEngine::antiPiracyEffect() {
}
}
if (!_sound->isPlaying()) {
- _sound->playSound(noiseData, kNoiseLength + 44);
+ _sound->playSound(noiseData, kNoiseLength + 44, 0);
}
_screen->markAllDirty();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index fe2da82f092..d6dc1584a65 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -151,7 +151,7 @@ private:
bool showShadows = false;
- bool shouldPlayIntro = false;
+ bool shouldPlayIntro = true;
bool gameInitialized = false;
bool screenReady = false;
@@ -160,13 +160,6 @@ private:
int _numPressedX = 0;
- // int prevDirX = 0;
- // int prevDirY = 0;
- // Common::String objectToShow = "";
- // int prevWhichScreen = 0;
- // int whichScreen = 0;
- // byte *pixelsShadows; // =new int[640*400];
-
protected:
// Engine APIs
Common::Error run() override;
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 30e18ccf30b..5321351ac57 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -123,10 +123,12 @@ void SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
}
}
-void SoundManager::playSound(byte *soundData, uint32 size) {
+void SoundManager::playSound(byte *soundData, uint32 size, int channel) {
Audio::AudioStream *stream = Audio::makeRawStream(soundData, size, 11025, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
if (stream) {
- int channel = findFreeChannel();
+ if (_mixer->isSoundHandleActive(_sfxHandles[channel])) {
+ _mixer->stopHandle(_sfxHandles[channel]);
+ }
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, 255U, 0, DisposeAfterUse::YES);
}
}
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index e5b971dd7e3..6e33487d34b 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -159,7 +159,7 @@ public:
~SoundManager();
void playSound(byte index, int channel = -1);
void playSound(const char *filename, int channel, int loopCount = 1);
- void playSound(byte *soundData, uint32 size);
+ void playSound(byte *soundData, uint32 size, int channel);
void stopAllSounds();
void stopSound(int channel);
void setVolume(int volume);
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 0b682059e51..2dce77e9e56 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -92,22 +92,36 @@ void VideoManager::playIntro() {
if (_voiceEffect.contains(frameCounter)) {
// Wait for any playing voice to finish before starting new one
- while (_sound->isPlaying()) {
+ while (_sound->isPlaying(0)) {
_events->pollEvent();
g_system->delayMillis(10);
if (g_engine->shouldQuit() || _events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
break;
}
}
- Voice voice = _voiceEffect[frameCounter];
+ AudioEffect voice = _voiceEffect[frameCounter];
debug("Playing voice effect: '%s'", voice.filename.c_str());
VoiceData voiceData = _sounds[voice.filename];
_introSndFile.seek(voiceData.offset, SEEK_SET);
byte *voiceBuffer = new byte[voiceData.length];
_introSndFile.read(voiceBuffer, voiceData.length);
- _sound->playSound(voiceBuffer, voiceData.length);
+ _sound->playSound(voiceBuffer, voiceData.length, 0);
}
+ if(_sfxEffect.contains(frameCounter)) {
+ AudioEffect sfx = _sfxEffect[frameCounter];
+ debug("Playing SFX effect: '%s'", sfx.filename.c_str());
+ VoiceData sfxData = _sounds[sfx.filename];
+ _introSndFile.seek(sfxData.offset, SEEK_SET);
+ byte *sfxBuffer = new byte[sfxData.length];
+ _introSndFile.read(sfxBuffer, sfxData.length);
+ _sound->playSound(sfxBuffer, sfxData.length, 1);
+ }
+
+ if(_musicEffect.contains(frameCounter)) {
+ MusicEffect music = _musicEffect[frameCounter];
+ _sound->playMusicTrack(music.trackNumber, true);
+ }
if (subtitle != nullptr) {
Common::StringArray lines = _dialog->wordWrap(subtitle->text)[0];
@@ -272,21 +286,57 @@ void VideoManager::initMetadata() {
Subtitle subtitle = readSubtitle(metadataFile);
_subtitles.push_back(subtitle);
} else if (nextChar == 'x') {
- Voice voice = readVoice(metadataFile);
+ AudioEffect voice = readAudioEffect(metadataFile);
// Read filename (up to 12 bytes, null-terminated)
_voiceEffect[voice.startFrame] = voice;
+ } else if (nextChar == 'f') {
+ AudioEffect sfx = readAudioEffect(metadataFile);
+ _sfxEffect[sfx.startFrame] = sfx;
+ }
+ else if (nextChar == 'c') {
+ MusicEffect music = readMusicEffect(metadataFile);
+ _musicEffect[music.startFrame] = music;
}
}
}
debug("Loaded %d subtitles", _subtitles.size());
- debug("Loaded %d audio effects", _voiceEffect.size());
+ debug("Loaded %d speech files", _voiceEffect.size());
metadataFile.close();
}
-Voice VideoManager::readVoice(Common::File &metadataFile) {
- Voice voice;
+MusicEffect VideoManager::readMusicEffect(Common::File &metadataFile) {
+ MusicEffect music;
+ Common::String buffer;
+
+ // Skip spaces after "/c"
+ while (!metadataFile.eos() && metadataFile.readByte() == ' ')
+ ;
+ metadataFile.seek(-1, SEEK_CUR); // Step back one byte
+
+ bool frameCountRead = false;
+ while (!metadataFile.eos()) {
+ char c = metadataFile.readByte();
+ if (c == ' ') {
+ if (!buffer.empty() && !frameCountRead) {
+ music.startFrame = atoi(buffer.c_str());
+ buffer.clear();
+ frameCountRead = true;
+ }
+ } else if (c == 0x0D || c == 0x0A) {
+ break;
+ } else {
+ buffer += c;
+ }
+ }
+ music.trackNumber = atoi(buffer.c_str());
+ debug("Loaded music effect: frame %d, track %d", music.startFrame, music.trackNumber);
+ return music;
+}
+
+AudioEffect VideoManager::readAudioEffect(Common::File &metadataFile) {
+ AudioEffect voice;
Common::String buffer;
// Skip spaces after "/x"
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index 064a0c7b7ae..aa4fbf5412b 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -42,6 +42,7 @@ struct Effect {
};
struct AudioEffect : Effect {
+ Common::String filename;
};
struct Subtitle : Effect {
@@ -52,16 +53,8 @@ struct Subtitle : Effect {
Common::String text;
};
-struct Voice : AudioEffect {
- Common::String filename;
-};
-
-struct Sfx : AudioEffect {
- uint32 soundId;
-};
-
-struct ExtraSound : AudioEffect {
- Common::String filename;
+struct MusicEffect : Effect {
+ uint32 trackNumber;
};
struct VoiceData {
@@ -112,7 +105,8 @@ private:
void initMetadata();
void readSubtitle(Common::File &metadataFile, Pelrock::Subtitle &subtitle);
Subtitle readSubtitle(Common::File &metadataFile);
- Voice readVoice(Common::File &metadataFile);
+ MusicEffect readMusicEffect(Common::File &metadataFile);
+ AudioEffect readAudioEffect(Common::File &metadataFile);
char decodeChar(byte c);
Subtitle *getSubtitleForFrame(uint16 frameNumber);
int _currentSubtitleIndex = 0;
@@ -120,7 +114,9 @@ private:
Graphics::ManagedSurface _textSurface = Graphics::ManagedSurface();
Common::Array<ChunkHeader> _chunkBuffer;
Common::Array<Subtitle> _subtitles;
- Common::HashMap<uint16, Voice> _voiceEffect;
+ Common::HashMap<uint16, AudioEffect> _voiceEffect;
+ Common::HashMap<uint16, AudioEffect> _sfxEffect;
+ Common::HashMap<uint16, MusicEffect> _musicEffect;
Common::HashMap<Common::String, VoiceData> _sounds;
Common::File _introSndFile;
};
Commit: 0e07504d16c5d8701b05753a6e86705c7522c2ac
https://github.com/scummvm/scummvm/commit/0e07504d16c5d8701b05753a6e86705c7522c2ac
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:21+02:00
Commit Message:
PELROCK: Fixes animation in room 3 and computer text
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/computer.cpp
engines/pelrock/computer.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/resources.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 17c6e16ad2a..49c2e3f1315 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -925,6 +925,7 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
g_system->delayMillis(10);
}
+ debug("Brick hit the window");
// Add the broken window sticker
_room->addSticker(11);
_sound->playSound(_room->_roomSfx[2]); // Play glass breaking sound
@@ -1273,7 +1274,7 @@ void PelrockEngine::pickUpBook(int i) {
}
_alfredState.isWalkingCancelable = false;
- walkAndAction(_room->findHotspotByExtra(102), TALK);
+ walkAndAction(_room->findHotspotByExtra(358), TALK);
if (!_state->hasInventoryItem(3)) {
_state->setCurrentRoot(9, 0, 0);
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index 5a1ee64e2cc..fc251c14d6a 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -67,19 +67,13 @@ void Computer::init() {
_libraryBooks.push_back(book);
}
- for (int i = 0; i < _libraryBooks.size(); i++) {
- const LibraryBook &book = _libraryBooks[i];
- debug("Loaded book: title='%s', author='%s', genre='%s', unknown=%d, shelf=%d, available=%d",
- book.title.c_str(), book.author.c_str(), book.genre.c_str(),
- book.inventoryIndex, book.shelf, book.available);
- }
-
_computerText = g_engine->_res->loadComputerText();
_searchResults.clear();
_currentResult = 0;
_searchLetter = 0;
_memorizedBookIndex = -1;
+ _memorizedMsg = _computerText[10][0].substr(16, _computerText[10][0].size() - 16); // "Bueno... Tendre que buscar en la estanteria de la %c"
_lineHeight = g_engine->_smallFont->getFontHeight();
}
@@ -211,7 +205,7 @@ void Computer::drawScreen() {
// Situacion (location/availability)
Common::String situacionLine = _computerText[6][0];
int situacionPlaceholderIndex = situacionLine.findFirstOf("XXXX");
- situacionLine.replace(situacionPlaceholderIndex, situacionLine.size() - situacionPlaceholderIndex, book.available ? "Disponible" : "Prestado");
+ situacionLine.replace(situacionPlaceholderIndex, situacionLine.size() - situacionPlaceholderIndex, book.available ? _computerText[8][0] : _computerText[9][0]);
g_engine->_graphics->drawColoredText(g_engine->_screen, situacionLine, textX, textY + increment * 3, 340, defaultColor, g_engine->_smallFont);
// Show navigation options
diff --git a/engines/pelrock/computer.h b/engines/pelrock/computer.h
index ea1ba3c0a88..e666d7de5bc 100644
--- a/engines/pelrock/computer.h
+++ b/engines/pelrock/computer.h
@@ -42,7 +42,7 @@ public:
* @return Book index if a book was memorized, -1 otherwise
*/
int run();
- const char *_memorizedMsg; // "Bueno... Tendre que buscar en la estanteria de la %c"
+ Common::String _memorizedMsg; // "Bueno... Tendre que buscar en la estanteria de la %c"
private:
enum ComputerState {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f7387341132..1a95787527a 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1079,6 +1079,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
// Scale special anim frame to Alfred size before drawing
drawSpriteToBuffer(_compositeBuffer, 640, frame, _alfredState.x, _alfredState.y - _res->_currentSpecialAnim->h, _res->_currentSpecialAnim->w, _res->_currentSpecialAnim->h, 255);
}
+ debug("Playing special anim frame %d/%d, speed %d", _res->_currentSpecialAnim->curFrame, _res->_currentSpecialAnim->numFrames, _res->_currentSpecialAnim->speed);
if (_chrono->getFrameCount() % _res->_currentSpecialAnim->speed == 0) {
_res->_currentSpecialAnim->curFrame++;
@@ -1807,7 +1808,7 @@ void PelrockEngine::computerLoop() {
computer.run();
if (_state->selectedBookIndex != -1 && _state->bookLetter != '\0') {
Common::StringArray lines;
- lines.push_back(Common::String::format(computer._memorizedMsg, _state->bookLetter));
+ lines.push_back(computer._memorizedMsg + _state->bookLetter);
_dialog->sayAlfred(lines);
}
}
@@ -2087,8 +2088,8 @@ void PelrockEngine::loadExtraScreenAndPresent(int screenIndex) {
void PelrockEngine::waitForSpecialAnimation() {
while (!g_engine->shouldQuit() && !_res->_isSpecialAnimFinished) {
_events->pollEvent();
+ debug("Waiting for special animation to finish, current frame %d", _res->_currentSpecialAnim->curFrame);
renderScene(OVERLAY_NONE);
- // _events->waitForKey();
_screen->update();
g_system->delayMillis(10);
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index d6dc1584a65..44020602b92 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -151,7 +151,7 @@ private:
bool showShadows = false;
- bool shouldPlayIntro = true;
+ bool shouldPlayIntro = false;
bool gameInitialized = false;
bool screenReady = false;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 546bd1c88af..da9f1007cf0 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -40,7 +40,7 @@ const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
{10, 51, 102, 1, 7, 578943, 1}, // 1 - READ RECIPE
{3, 45, 87, 0, 7, 37000, 1}, // 2 - ELECTRIC SHOCK 1
{2, 82, 58, 0, 7, 53106, 20, 1}, // 3 - ELECTRIC SHOCK 3
- {3, 71, 110, 1, 2, 20724, 1, 62480}, // 4 - Throw
+ {3, 71, 110, 1, 2, 20724, 1, 1, 62480}, // 4 - Throw
{14, 171, 107, 1, 7, 1556540, 1}, // 5 - crocodile
{12, 113, 103, 1, 7, 1583702, 1}, // 6 - exit through manhole
{11, 33, 72, 1, 7, 1761234, 1}, // 7 - alfred climbs down
@@ -386,12 +386,19 @@ Common::Array<Common::StringArray> ResourceManager::loadComputerText() {
if (!exe.open("JUEGO.EXE")) {
error("Couldnt find file JUEGO.EXE");
}
- int bufSize = 416;
+ int bufSize = 490;
byte *computerTextBuf = new byte[bufSize];
exe.seek(0x0004901A, SEEK_SET);
exe.read(computerTextBuf, bufSize);
Common::Array<Common::StringArray> computerTexts = processTextData(computerTextBuf, bufSize);
+ for(int i = 0; i < computerTexts.size(); i++) {
+ debug("Computer text %d:", i);
+ Common::StringArray &lines = computerTexts[i];
+ for (int j = 0; j < lines.size(); j++) {
+ debug(" Line %d: '%s'", j, lines[j].c_str());
+ }
+ }
delete[] computerTextBuf;
exe.close();
Commit: 60acdb4c8d0f71fdce9ba3236bbf192e2df16208
https://github.com/scummvm/scummvm/commit/60acdb4c8d0f71fdce9ba3236bbf192e2df16208
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:21+02:00
Commit Message:
PELROCK: Fixes menu descriptions
Changed paths:
engines/pelrock/computer.cpp
engines/pelrock/computer.h
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/offsets.h
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index fc251c14d6a..18e1f250ec5 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -73,6 +73,8 @@ void Computer::init() {
_currentResult = 0;
_searchLetter = 0;
_memorizedBookIndex = -1;
+ _titleMsg = _computerText[10][0].substr(0, 7);
+ _authorMsg = _computerText[10][0].substr(7, 6);
_memorizedMsg = _computerText[10][0].substr(16, _computerText[10][0].size() - 16); // "Bueno... Tendre que buscar en la estanteria de la %c"
_lineHeight = g_engine->_smallFont->getFontHeight();
}
@@ -166,7 +168,7 @@ void Computer::drawScreen() {
case STATE_SHOW_RESULTS: {
- const char *section = _searchType == 0 ? "TITULO " : "AUTOR ";
+ const char *section = _searchType == 0 ? _titleMsg.c_str() : _authorMsg.c_str();
Common::String title = _computerText[2][0];
int replacementIndex = title.findFirstOf("XXXXXXX");
diff --git a/engines/pelrock/computer.h b/engines/pelrock/computer.h
index e666d7de5bc..848fec53cc9 100644
--- a/engines/pelrock/computer.h
+++ b/engines/pelrock/computer.h
@@ -42,6 +42,8 @@ public:
* @return Book index if a book was memorized, -1 otherwise
*/
int run();
+ Common::String _titleMsg;
+ Common::String _authorMsg;
Common::String _memorizedMsg; // "Bueno... Tendre que buscar en la estanteria de la %c"
private:
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 6bfb31678ec..4680e454e7e 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -69,8 +69,10 @@ void MenuManager::checkMouseClick(int x, int y) {
bool selectedItem = false;
for (int i = 0; i < 4; i++) {
- if (x >= 140 + (82 * i) && x <= 140 + (82 * i) + 64 &&
- y >= 115 - (8 * i) && y <= 115 - (8 * i) + 64) {
+
+ Common::Rect itemRect = Common::Rect(_inventorySlots[i], 60, 60);
+
+ if (itemRect.contains(x, y)) {
selectedItem = selectInventoryItem(i);
return;
}
@@ -127,7 +129,7 @@ void MenuManager::showCredits() {
byte *decompressedCredits = nullptr;
rleDecompress(creditsBuf, creditsSize, 0, 0, &decompressedCredits, true);
// draw credits in two columns taking the entire height of the screen and stating in y = 0
- for(int i = 0; i < 34; i++) {
+ for (int i = 0; i < 34; i++) {
byte *singleCredit = new byte[creditWidth * creditHeight];
int x = (i < 34 / 2) ? 39 : 359;
int y = 3 + (i % (34 / 2)) * (400 / (34 / 2));
@@ -140,7 +142,7 @@ void MenuManager::showCredits() {
delete[] decompressedCredits;
delete[] creditsBuf;
- while(!g_engine->shouldQuit() && !_events->_leftMouseClicked && !_events->_rightMouseClicked) {
+ while (!g_engine->shouldQuit() && !_events->_leftMouseClicked && !_events->_rightMouseClicked) {
_events->pollEvent();
_screen->markAllDirty();
_screen->update();
@@ -208,10 +210,11 @@ void MenuManager::drawInventoryIcons() {
if (g_engine->_state->inventoryItems.size() <= itemIndex)
continue;
InventoryObject item = g_engine->_res->getIconForObject(g_engine->_state->inventoryItems[itemIndex]);
- drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, 140 + (82 * i), 115 - (8 * i), 60, 60, 1);
+ Common::Point slot = _inventorySlots[i];
+ drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, slot.x, slot.y, 60, 60, 1);
if (debugIcons) {
- drawRect(_compositeBuffer, 140 + (82 * i), 115 - (8 * i), 60, 60, 13);
- drawText(_compositeBuffer, g_engine->_smallFont, Common::String::format("ID %d", g_engine->_state->inventoryItems[itemIndex]), 140 + (82 * i) + 2, 115 - (8 * i) + 2, 640, 13);
+ drawRect(_compositeBuffer, slot.x, slot.y, 60, 60, 13);
+ drawText(_compositeBuffer, g_engine->_smallFont, Common::String::format("ID %d", g_engine->_state->inventoryItems[itemIndex]), slot.x + 2, slot.y + 2, 640, 13);
}
}
}
@@ -294,6 +297,10 @@ void MenuManager::loadMenu() {
_menuText = _menuTexts[0];
alfred7.close();
+
+ for (int i = 0; i < 4; i++) {
+ _inventorySlots.push_back(Common::Point(140 + (82 * i), 115 - (8 * i)));
+ }
}
void MenuManager::readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect) {
@@ -317,6 +324,9 @@ void MenuManager::loadMenuTexts() {
exe.seek(kInventoryDescriptionsOffset, SEEK_SET);
exe.read(descBuffer, kInventoryDescriptionsSize);
_inventoryDescriptions = _res->processTextData(descBuffer, kInventoryDescriptionsSize, true);
+ for(size_t i = 0; i < _inventoryDescriptions.size(); i++) {
+ debug("Inventory description %d: %s", i, _inventoryDescriptions[i][0].c_str());
+ }
delete[] descBuffer;
Common::String desc = "";
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 30d6d5cc1db..658c9c9243d 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -261,6 +261,7 @@ private:
int _curInventoryPage = 0;
Common::StringArray _menuText;
Common::Array<Common::StringArray> _inventoryDescriptions;
+ Common::Array<Common::Point> _inventorySlots;
bool showButtons = true;
};
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index e5d37e1a862..05f5a82f24f 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -45,7 +45,7 @@ static const uint32_t kSettingsPaletteOffset = 0x2884c2; // 640 * 480
#define DESCRIPTION_BASE_OFFSET 0x4715D
#define NUM_DESCRIPTIONS 113
-static const uint32 kInventoryDescriptionsOffset = 0x4715D;
+static const uint32 kInventoryDescriptionsOffset = 0x4715E;
static const uint32 kInventoryDescriptionsSize = 7868;
static const uint32 kMenuTextOffset = 0x49203;
static const uint32 kMenuTextSize = 230;
Commit: c2cbca370cedb17b63c0bbdb3eb3fa87abb795b5
https://github.com/scummvm/scummvm/commit/c2cbca370cedb17b63c0bbdb3eb3fa87abb795b5
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:22+02:00
Commit Message:
PELROCK: Fixes walkboxes in room 14
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 49c2e3f1315..a704fafb94b 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -326,21 +326,14 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 272:
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
- case 273:
- WalkBox w1;
- w1.x = 436;
- w1.y = 356;
- w1.w = 4;
- w1.h = 14;
- WalkBox w2;
- w2.x = 440;
- w2.y = 368;
- w2.w = 148;
- w2.h = 2;
+ case 273: {
+ WalkBox w1 = { 3, 436, 356, 4, 14, 0 };
+ WalkBox w2 = { 4, 440, 368,148, 2, 0 };
_room->addWalkbox(w1);
_room->addWalkbox(w2);
break;
+ }
case 274:
case 275:
case 276:
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 44ab35729ba..a62a615fa98 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -315,6 +315,7 @@ void RoomManager::addWalkbox(WalkBox walkbox, int persist) {
_currentRoomWalkboxes.push_back(walkbox);
}
if (persist & PERSIST_PERM) {
+ debug("Adding walkbox change for room %d, index %d, x=%d y=%d w=%d h=%d", _currentRoomNumber, walkbox.index, walkbox.x, walkbox.y, walkbox.w, walkbox.h);
g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
}
}
@@ -1007,16 +1008,18 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
int16 w = READ_LE_INT16(data + boxOffset + 4);
int16 h = READ_LE_INT16(data + boxOffset + 6);
byte flags = data[boxOffset + 8];
- // debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
+ debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
WalkBox box;
box.index = i;
bool isChanged = false;
if (g_engine->_state->roomWalkBoxChanges.contains(_currentRoomNumber)) {
+ debug("Checking for changes to walkbox %d in room %d", i, _currentRoomNumber);
// if the walkbox has been changed, load the changed version
for (int j = 0; j < g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
if (g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == i) {
walkboxes.push_back(g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
isChanged = true;
+ debug("Walkbox %d has been changed, loading changed version, x1=%d y1=%d w=%d h=%d", i, g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox.x, g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox.y, g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox.w, g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox.h);
break;
}
}
@@ -1042,11 +1045,12 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
}
}
if (!found) {
+ debug("Adding new walkbox for room %d at index %d", _currentRoomNumber, g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex);
walkboxes.push_back(g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
}
}
}
-
+ debug("Total walkboxes for room %d: %d", _currentRoomNumber, walkboxes.size());
return walkboxes;
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 5e3e624df09..6efc93e3401 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -448,8 +448,7 @@ struct PaletteAnim {
#define PASSERBY_DOWN 2
struct PasserByAnim {
- // uint32 frameTrigger = 0x3FF;
- uint32 frameTrigger = 0x96;
+ uint32 frameTrigger = 0x3FF;
int16 startX;
int16 startY;
int16 resetCoord;
Commit: 197f9e676d9f2f2c8ff8fa46d7969a20c9fe2d85
https://github.com/scummvm/scummvm/commit/197f9e676d9f2f2c8ff8fa46d7969a20c9fe2d85
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:22+02:00
Commit Message:
PELROCK: Fixes music in travel scene
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/console.cpp
engines/pelrock/console.h
engines/pelrock/pelrock.cpp
engines/pelrock/sound.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index a704fafb94b..5cff78e7307 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -346,14 +346,16 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 278:
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
- case 279:
+ case 279:{
+ _state->removeInventoryItem(75);
travelToEgypt();
+
break;
// merchants
-
+ }
case 330:
// Two oranges
- addInventoryItem(103);
+ addInventoryItem(102);
break;
case 331:
_dialog->say(_res->_ingameTexts[HECHOELPRIMO]);
@@ -373,7 +375,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
case 335:
// many oranges
- addInventoryItem(104);
+ addInventoryItem(103);
break;
case 336:
_dialog->say(_res->_ingameTexts[PESADO_UNRATO]);
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index a4676a5e913..0a5f6f25f3e 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -31,6 +31,7 @@ PelrockConsole::PelrockConsole(PelrockEngine *engine) : GUI::Debugger(), _engine
registerCmd("give", WRAP_METHOD(PelrockConsole, cmdGiveItems));
registerCmd("setRoot", WRAP_METHOD(PelrockConsole, cmdSetRoot));
registerCmd("setFlag", WRAP_METHOD(PelrockConsole, cmdSetFlag));
+ registerCmd("getFlag", WRAP_METHOD(PelrockConsole, cmdGetFlag));
registerCmd("toJail", WRAP_METHOD(PelrockConsole, cmdToJail));
registerCmd("removeSticker", WRAP_METHOD(PelrockConsole, cmdRemoveSticker));
}
@@ -67,6 +68,17 @@ bool PelrockConsole::cmdSetFlag(int argc, const char **argv) {
return true;
}
+bool PelrockConsole::cmdGetFlag(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Usage: getFlag <flagIndex>");
+ return true;
+ }
+ int flagIndex = atoi(argv[1]);
+ int value = _engine->_state->getFlag(flagIndex);
+ debugPrintf("Flag %d is %d\n", flagIndex, value);
+ return true;
+}
+
bool PelrockConsole::cmdSetRoot(int argc, const char **argv) {
if (argc < 3) {
debugPrintf("Usage: setRoot <roomNumber> <rootIndex> <npcIndex (optional, default=0)>");
diff --git a/engines/pelrock/console.h b/engines/pelrock/console.h
index e20cd09951e..53f5dfca4ce 100644
--- a/engines/pelrock/console.h
+++ b/engines/pelrock/console.h
@@ -37,6 +37,7 @@ private:
bool cmdTest(int argc, const char **argv);
bool cmdSetRoot(int argc, const char **argv);
bool cmdSetFlag(int argc, const char **argv);
+ bool cmdGetFlag(int argc, const char **argv);
bool cmdRemoveSticker(int argc, const char **argv);
public:
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1a95787527a..d8ecb49cf1b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -263,7 +263,8 @@ void PelrockEngine::playSoundIfNeeded() {
void PelrockEngine::travelToEgypt() {
_graphics->fadeToBlack(10);
- _sound->playMusicTrack(26, false);
+
+ _sound->playMusicTrack(26, 1);
byte *palette = new byte[768];
if (_bgScreen == nullptr) {
_bgScreen = new byte[640 * 400];
@@ -287,7 +288,6 @@ void PelrockEngine::travelToEgypt() {
g_system->getPaletteManager()->setPalette(palette, 0, 256);
frameCount++;
}
- drawPaletteSquares((byte *)_screen->getPixels(), palette);
_screen->markAllDirty();
_screen->update();
@@ -302,6 +302,7 @@ void PelrockEngine::travelToEgypt() {
delete[] palette;
_screen->markAllDirty();
_screen->update();
+ setScreenAndPrepare(21, ALFRED_DOWN);
}
bool PelrockEngine::renderScene(int overlayMode) {
@@ -2104,7 +2105,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
case 0:
if (_state->getFlag(FLAG_PUESTA_SALSA_PICANTE) && !_state->getFlag(FLAG_JEFE_ENCARCELADO)) {
_state->setFlag(FLAG_JEFE_ENCARCELADO, true);
- _room->disableSprite(13, 0, true);
+ _room->disableSprite(13, 0, PERSIST_BOTH);
loadExtraScreenAndPresent(4);
}
break;
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 5321351ac57..96b621e9769 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -119,7 +119,7 @@ void SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
}
Audio::AudioStream *finalStream = loopCount != -1 ? stream : Audio::makeLoopingAudioStream(stream, 0);
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], finalStream, loopCount, 255U, 0, DisposeAfterUse::YES);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], finalStream, loopCount, _currentVolume, 0, DisposeAfterUse::YES);
}
}
@@ -129,7 +129,7 @@ void SoundManager::playSound(byte *soundData, uint32 size, int channel) {
if (_mixer->isSoundHandleActive(_sfxHandles[channel])) {
_mixer->stopHandle(_sfxHandles[channel]);
}
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, 255U, 0, DisposeAfterUse::YES);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, _currentVolume, 0, DisposeAfterUse::YES);
}
}
@@ -233,9 +233,11 @@ bool SoundManager::isMusicPlaying() {
void SoundManager::playMusicTrack(int trackNumber, bool loop) {
if (!_isPaused && _currentMusicTrack == trackNumber && isMusicPlaying()) {
// Already playing this track
+ debug("Track %d is already playing", trackNumber);
return;
}
_currentMusicTrack = trackNumber;
+ debug("Playing music track %d, loop=%d", trackNumber, loop);
if(!_isPaused) {
_cdTrackStart = 0;
Commit: acae2fa73395b594e1880da80713cc801e7afbed
https://github.com/scummvm/scummvm/commit/acae2fa73395b594e1880da80713cc801e7afbed
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:22+02:00
Commit Message:
PELROCK: Fixes using pumpkin with river
Changed paths:
engines/pelrock/actions.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 5cff78e7307..9a66fb40c65 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -370,7 +370,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_dialog->say(_res->_ingameTexts[MEHANTOMADO_EL_PELO]);
break;
case 334:
- addInventoryItem(86);
+ addInventoryItem(76);
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 335:
@@ -1203,8 +1203,8 @@ void PelrockEngine::closeTravelAgencyDoor(HotSpot *hotspot) {
}
void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
- _state->removeInventoryItem(76);
- addInventoryItem(86);
+ _state->removeInventoryItem(86);
+ addInventoryItem(76);
_sound->playMusicTrack(27);
checkIngredients();
_dialog->say(_res->_ingameTexts[CUIDADOIMPRUDENTE]);
@@ -1213,10 +1213,13 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
playAlfredSpecialAnim(5);
_sound->playSound(_room->_roomSfx[0], 0); // Belch
waitForSoundEnd();
+ _alfredState.animState = ALFRED_SKIP_DRAWING;
_graphics->fadeToBlack(10);
// update conversaton state
_alfredState.x = 300;
_alfredState.y = 238;
+ waitForSoundEnd();
+ _alfredState.animState = ALFRED_IDLE;
setScreenAndPrepare(28, ALFRED_DOWN);
_dialog->say(_res->_ingameTexts[QUEOSCUROESTAESTO]);
}
@@ -1879,6 +1882,7 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
HotSpot *floorTile = _room->findHotspotByExtra(462);
floorTile->actionFlags = ACTION_MASK_OPEN;
_room->changeHotSpot(*floorTile);
+ break;
}
case 307: {
Commit: 3ec216e9e91f63899cbd0144ce372353b55e9b7d
https://github.com/scummvm/scummvm/commit/3ec216e9e91f63899cbd0144ce372353b55e9b7d
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:23+02:00
Commit Message:
PELROCK: Migrate to using ManagedSurfaces
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/computer.cpp
engines/pelrock/computer.h
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/extrascreens.cpp
engines/pelrock/extrascreens.h
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 9a66fb40c65..6110d1562c1 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -687,9 +687,9 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
* Alfred and the princess.
*/
void PelrockEngine::turnLightsOff() {
- memset(_currentBackground, 0, 640 * 400);
- memset(_compositeBuffer, 0, 640 * 400);
- memset(_screen->getPixels(), 0, 640 * 400);
+ _currentBackground.clear(0);
+ _compositeBuffer.clear(0);
+ _screen->clear(0);
byte darkPalette[768] = {};
darkPalette[238 * 3 + 0] = 60 << 2; // R = 240
darkPalette[238 * 3 + 1] = 57 << 2; // G = 228
@@ -1972,7 +1972,7 @@ void PelrockEngine::teletransportToPrincess() {
int y1 = lines[phase][1];
int x2 = lines[phase][2] + i;
int y2 = lines[phase][3];
- drawRemappedLine(_compositeBuffer, x1, y1, x2, y2, _room->_paletteRemaps[1]);
+ drawRemappedLine((byte *)_compositeBuffer.getPixels(), x1, y1, x2, y2, _room->_paletteRemaps[1]);
}
updateAnimations();
@@ -2078,7 +2078,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
}
break;
case 88: {
- SpellBook spellBook = SpellBook(_events, _res);
+ SpellBook spellBook(_events, _res);
playAlfredSpecialAnim(0);
Spell *spell = spellBook.run();
@@ -2197,7 +2197,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
}
case 95: {
- CDPlayer player = CDPlayer(_events, _res, _sound);
+ CDPlayer player(_events, _res, _sound);
player.run();
break;
}
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index 18e1f250ec5..fe8b574f810 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -30,8 +30,7 @@
namespace Pelrock {
Computer::Computer(PelrockEventManager *eventMan)
- : _backgroundScreen(nullptr),
- _palette(nullptr),
+ : _palette(nullptr),
_state(STATE_MAIN_MENU),
_searchLetter(0),
_searchType(0),
@@ -85,17 +84,14 @@ Computer::~Computer() {
void Computer::loadBackground() {
_palette = new byte[768];
- _backgroundScreen = new byte[640 * 400];
+ _backgroundScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
- g_engine->_res->getExtraScreen(1, _backgroundScreen, _palette);
+ g_engine->_res->getExtraScreen(1, (byte *)_backgroundScreen.getPixels(), _palette);
g_system->getPaletteManager()->setPalette(_palette, 0, 256);
}
void Computer::cleanup() {
- if (_backgroundScreen) {
- delete[] _backgroundScreen;
- _backgroundScreen = nullptr;
- }
+ _backgroundScreen.free();
if (_palette) {
// Restore room palette
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
@@ -143,7 +139,7 @@ int Computer::run() {
void Computer::drawScreen() {
// Clear to background
- memcpy(g_engine->_screen->getPixels(), _backgroundScreen, 640 * 400);
+ g_engine->_screen->blitFrom(_backgroundScreen);
byte defaultColor = 0; // Light gray
diff --git a/engines/pelrock/computer.h b/engines/pelrock/computer.h
index 848fec53cc9..c34e918f873 100644
--- a/engines/pelrock/computer.h
+++ b/engines/pelrock/computer.h
@@ -24,6 +24,7 @@
#include "common/array.h"
#include "common/str.h"
+#include "graphics/managed_surface.h"
#include "pelrock/events.h"
#include "pelrock/library_books.h"
@@ -56,7 +57,7 @@ private:
};
PelrockEventManager *_events;
- byte *_backgroundScreen;
+ Graphics::ManagedSurface _backgroundScreen;
byte *_palette;
// State variables
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 6038cf219d4..1319172f159 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -112,7 +112,7 @@ uint32 DialogManager::readTextBlock(
return pos;
}
-void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer) {
+void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, Graphics::ManagedSurface &compositeBuffer) {
int overlayHeight = choices->size() * kChoiceHeight + 2;
Common::Point overlayPos = _graphics->showOverlay(overlayHeight, compositeBuffer);
@@ -301,7 +301,7 @@ void DialogManager::displayDialogue(Common::String text, byte speakerId) {
* Select a choice from displayed options
* Returns the index of the selected choice in the choices array
*/
-int DialogManager::selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer) {
+int DialogManager::selectChoice(Common::Array<Common::String> &choices, Graphics::ManagedSurface &compositeBuffer) {
_events->_leftMouseClicked = false;
_dialogActive = true;
g_engine->_chrono->pauseCounter();
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 1e0c61e68bb..51e98d0f1dd 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -23,6 +23,7 @@
#include "common/scummsys.h"
#include "common/stack.h"
+#include "graphics/managed_surface.h"
#include "graphics/screen.h"
#include "pelrock/events.h"
@@ -101,8 +102,8 @@ public:
DialogManager(Graphics::Screen *screen, PelrockEventManager *events, GraphicsManager *graphics);
~DialogManager();
- void displayChoices(Common::Array<ChoiceOption> *choices, byte *compositeBuffer);
- int selectChoice(Common::Array<Common::String> &choices, byte *compositeBuffer);
+ void displayChoices(Common::Array<ChoiceOption> *choices, Graphics::ManagedSurface &compositeBuffer);
+ int selectChoice(Common::Array<Common::String> &choices, Graphics::ManagedSurface &compositeBuffer);
void startConversation(const byte *conversationData, uint32 dataSize, byte npcIndex, Sprite *alfredAnimSet = nullptr);
uint32 findRoot(int npc, int ¤tRoot, uint32 position, uint32 dataSize, const byte *conversationData);
uint32 findSpeaker(byte npcIndex, uint32 dataSize, const byte *conversationData);
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
index b1901494a0d..0c9ad6fa5bd 100644
--- a/engines/pelrock/extrascreens.cpp
+++ b/engines/pelrock/extrascreens.cpp
@@ -29,8 +29,7 @@
namespace Pelrock {
SpellBook::SpellBook(PelrockEventManager *eventMan, ResourceManager *res)
- : _backgroundScreen(nullptr),
- _palette(nullptr),
+ : _palette(nullptr),
_events(eventMan),
_res(res),
_spell(nullptr) {
@@ -56,14 +55,14 @@ Spell *SpellBook::run() {
g_engine->_screen->update();
g_system->delayMillis(10);
}
- memset(g_engine->_screen->getPixels(), 0, 640 * 400);
+ g_engine->_screen->clear(0);
// Restore room palette
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
return _selectedSpell;
}
void SpellBook::init() {
- _compositeScreen = new byte[640 * 400];
+ _compositeScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
// selectPage(0);
}
@@ -113,34 +112,32 @@ void SpellBook::selectPage(int page) {
}
void SpellBook::drawScreen() {
- memcpy(_compositeScreen, _backgroundScreen, 640 * 400);
+ _compositeScreen.blitFrom(_backgroundScreen);
int textY = 83;
int textX = 317;
if (_spell != nullptr) {
- drawSpriteToBuffer(_compositeScreen, 640, _spell->image, 168, 143, 119, 99, 207);
+ drawSpriteToBuffer(_compositeScreen, _spell->image, 168, 143, 119, 99, 207);
g_engine->_graphics->drawColoredTexts(_compositeScreen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
}
- memcpy(g_engine->_screen->getPixels(), _compositeScreen, 640 * 400);
+ g_engine->_screen->blitFrom(_compositeScreen);
if (_spell != nullptr) {
g_engine->_graphics->drawColoredTexts(g_engine->_screen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
}
}
void SpellBook::loadBackground() {
- _backgroundScreen = new byte[640 * 400];
+ _backgroundScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
_palette = new byte[768];
- _res->getExtraScreen(8, _backgroundScreen, _palette);
+ _res->getExtraScreen(8, (byte *)_backgroundScreen.getPixels(), _palette);
g_system->getPaletteManager()->setPalette(_palette, 0, 256);
}
void SpellBook::cleanup() {
- if (_backgroundScreen) {
- delete[] _backgroundScreen;
- _backgroundScreen = nullptr;
- }
+ _backgroundScreen.free();
+ _compositeScreen.free();
if (_palette) {
delete[] _palette;
_palette = nullptr;
@@ -202,7 +199,7 @@ void CDPlayer::run() {
g_engine->_screen->update();
g_system->delayMillis(10);
}
- memset(g_engine->_screen->getPixels(), 0, 640 * 400);
+ g_engine->_screen->clear(0);
// Restore room palette
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
_sound->stopMusic();
@@ -210,7 +207,7 @@ void CDPlayer::run() {
}
void CDPlayer::init() {
- _compositeScreen = new byte[640 * 400];
+ _compositeScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
loadBackground();
loadControls();
loadTrackNames();
@@ -231,12 +228,12 @@ void CDPlayer::loadTrackNames() {
}
void CDPlayer::drawScreen() {
- memcpy(_compositeScreen, _backgroundScreen, 640 * 400);
- drawSpriteToBuffer(_compositeScreen, 640, _controls, 1, 1, 213, 72, 207);
+ _compositeScreen.blitFrom(_backgroundScreen);
+ drawSpriteToBuffer(_compositeScreen, _controls, 1, 1, 213, 72, 207);
drawButtons();
- memcpy(g_engine->_screen->getPixels(), _compositeScreen, 640 * 400);
+ g_engine->_screen->blitFrom(_compositeScreen);
g_engine->_smallFont->drawString(g_engine->_screen, trackNames[_selectedTrack - 2], 26, 17, 640, 255, Graphics::kTextAlignLeft);
}
@@ -244,25 +241,23 @@ void CDPlayer::drawButtons() {
for (int i = 0; i < 5; i++) {
if (_selectedButton == i) {
- drawSpriteToBuffer(_compositeScreen, 640, buttons[i][1], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ drawSpriteToBuffer(_compositeScreen, buttons[i][1], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
} else {
- drawSpriteToBuffer(_compositeScreen, 640, buttons[i][0], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ drawSpriteToBuffer(_compositeScreen, buttons[i][0], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
}
}
}
void CDPlayer::loadBackground() {
- _backgroundScreen = new byte[640 * 400];
+ _backgroundScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
_palette = new byte[768];
- _res->getExtraScreen(10, _backgroundScreen, _palette);
+ _res->getExtraScreen(10, (byte *)_backgroundScreen.getPixels(), _palette);
g_system->getPaletteManager()->setPalette(_palette, 0, 256);
}
void CDPlayer::cleanup() {
- if (_backgroundScreen) {
- delete[] _backgroundScreen;
- _backgroundScreen = nullptr;
- }
+ _backgroundScreen.free();
+ _compositeScreen.free();
if (_palette) {
delete[] _palette;
@@ -385,13 +380,13 @@ void BackgroundBook::run() {
g_engine->_screen->update();
g_system->delayMillis(10);
}
- memset(g_engine->_screen->getPixels(), 0, 640 * 400);
+ g_engine->_screen->clear(0);
// Restore room palette
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
}
void BackgroundBook::init() {
- _compositeScreen = new byte[640 * 400];
+ _compositeScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
loadBackground();
loadButtons();
loadRoomNames();
@@ -476,9 +471,9 @@ void BackgroundBook::loadRoomNames() {
void BackgroundBook::drawScreen() {
- memcpy(_compositeScreen, _backgroundScreen, 640 * 400);
+ _compositeScreen.blitFrom(_backgroundScreen);
drawButtons();
- memcpy(g_engine->_screen->getPixels(), _compositeScreen, 640 * 400);
+ g_engine->_screen->blitFrom(_compositeScreen);
int firstItem = _selectedPage * kItemsPerPage;
@@ -495,17 +490,17 @@ void BackgroundBook::drawScreen() {
void BackgroundBook::drawButtons() {
for (int i = 0; i < 2; i++) {
if (_selectedButton == i) {
- drawSpriteToBuffer(_compositeScreen, 640, _buttons[i][0], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ drawSpriteToBuffer(_compositeScreen, _buttons[i][0], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
} else {
- drawSpriteToBuffer(_compositeScreen, 640, _buttons[i][1], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ drawSpriteToBuffer(_compositeScreen, _buttons[i][1], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
}
}
}
void BackgroundBook::loadBackground() {
- _backgroundScreen = new byte[640 * 400];
+ _backgroundScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
_palette = new byte[768];
- _res->getExtraScreen(13, _backgroundScreen, _palette);
+ _res->getExtraScreen(13, (byte *)_backgroundScreen.getPixels(), _palette);
g_system->getPaletteManager()->setPalette(_palette, 0, 256);
}
@@ -528,14 +523,8 @@ void BackgroundBook::loadButtons() {
}
void BackgroundBook::cleanup() {
- if (_compositeScreen) {
- delete[] _compositeScreen;
- _compositeScreen = nullptr;
- }
- if (_backgroundScreen) {
- delete[] _backgroundScreen;
- _backgroundScreen = nullptr;
- }
+ _compositeScreen.free();
+ _backgroundScreen.free();
if (_palette) {
delete[] _palette;
_palette = nullptr;
diff --git a/engines/pelrock/extrascreens.h b/engines/pelrock/extrascreens.h
index 8f0c209d42e..f0226b1d965 100644
--- a/engines/pelrock/extrascreens.h
+++ b/engines/pelrock/extrascreens.h
@@ -22,6 +22,8 @@
#ifndef PELROCK_EXTRASCREENS_H
#define PELROCK_EXTRASCREENS_H
+#include "graphics/managed_surface.h"
+
#include "pelrock/pelrock.h"
namespace Pelrock {
@@ -72,8 +74,8 @@ public:
private:
PelrockEventManager *_events;
ResourceManager *_res;
- byte *_backgroundScreen;
- byte *_compositeScreen;
+ Graphics::ManagedSurface _backgroundScreen;
+ Graphics::ManagedSurface _compositeScreen;
byte *_palette;
Spell *_spell = nullptr;
@@ -118,8 +120,8 @@ private:
ResourceManager *_res;
SoundManager *_sound;
PelrockEventManager *_events;
- byte *_backgroundScreen;
- byte *_compositeScreen;
+ Graphics::ManagedSurface _backgroundScreen;
+ Graphics::ManagedSurface _compositeScreen;
byte *_palette;
byte *_controls;
Common::String trackNames[31];
@@ -164,8 +166,8 @@ private:
PelrockEventManager *_events;
ResourceManager *_res;
- byte *_backgroundScreen;
- byte *_compositeScreen;
+ Graphics::ManagedSurface _backgroundScreen;
+ Graphics::ManagedSurface _compositeScreen;
byte *_palette;
byte *_buttons[2][2];
Buttons _selectedButton = NO_BG_BUTTON;
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 74fcf293483..d0c1c79b1eb 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -35,38 +35,37 @@ GraphicsManager::GraphicsManager() {
GraphicsManager::~GraphicsManager() {
}
-Common::Point GraphicsManager::showOverlay(int height, byte *buf) {
+Common::Point GraphicsManager::showOverlay(int height, Graphics::ManagedSurface &buf) {
int overlayY = 400 - height;
int overlayX = 0;
for (int x = 0; x < 640; x++) {
for (int y = overlayY; y < 400; y++) {
- int index = y * 640 + x;
- buf[index] = g_engine->_room->_paletteRemaps[2][buf[index]];
+ byte pixel = (byte)buf.getPixel(x, y);
+ buf.setPixel(x, y, g_engine->_room->_paletteRemaps[2][pixel]);
}
}
return Common::Point(overlayX, overlayY);
}
-byte *GraphicsManager::grabBackgroundSlice(byte *buf, int x, int y, int w, int h) {
+byte *GraphicsManager::grabBackgroundSlice(Graphics::ManagedSurface &buf, int x, int y, int w, int h) {
byte *bg = new byte[w * h];
for (int j = 0; j < w; j++) {
for (int i = 0; i < h; i++) {
int idx = i * w + j;
if (y + i < 400 && x + j < 640) {
- *(bg + idx) = buf[(y + i) * 640 + (x + j)];
+ *(bg + idx) = (byte)buf.getPixel(x + j, y + i);
}
}
}
return bg;
}
-void GraphicsManager::putBackgroundSlice(byte *buf, int x, int y, int w, int h, byte *slice) {
+void GraphicsManager::putBackgroundSlice(Graphics::ManagedSurface &buf, int x, int y, int w, int h, byte *slice) {
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
int index = (j * w + i);
if (x + i < 640 && y + j < 400) {
- buf[(y + j) * 640 + (x + i)] = slice[index];
- // *(byte *)_screen->getBasePtr(x + i, y + j) = slice[index];
+ buf.setPixel(x + i, y + j, slice[index]);
}
}
}
@@ -144,7 +143,7 @@ void GraphicsManager::fadePaletteToTarget(byte *targetPalette, int stepSize) {
}
void GraphicsManager::clearScreen() {
- memset(g_engine->_screen->getPixels(), 0, g_engine->_screen->pitch * g_engine->_screen->h);
+ g_engine->_screen->clear(0);
}
void GraphicsManager::drawColoredText(Graphics::ManagedSurface *screen, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font) {
@@ -172,7 +171,7 @@ void GraphicsManager::drawColoredText(Graphics::ManagedSurface *screen, const Co
}
}
-void GraphicsManager::drawColoredText(byte *buf, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font) {
+void GraphicsManager::drawColoredText(Graphics::ManagedSurface &buf, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font) {
Graphics::Surface tempSurface;
Common::Rect r = font->getBoundingBox(text); // Ensure font metrics are loaded before creating surface
@@ -202,17 +201,9 @@ void GraphicsManager::drawColoredText(byte *buf, const Common::String &text, int
font->drawString(&tempSurface, segment, currentX, y, w, defaultColor);
}
- for(int j = 0; j < tempSurface.h; j++) {
- for(int i = 0; i < tempSurface.w; i++) {
- if (y + j < 400 && x + i < 640) {
- byte pixel = *((byte *)tempSurface.getBasePtr(i, j));
- if (pixel != 0) { // Assuming 0 is transparent
- debug("Drawing pixel at (%d, %d) with color %d", x + i, y + j, pixel);
- buf[(y + j) * 640 + (x + i)] = pixel;
- }
- }
- }
- }
+ // Use transBlitFrom to blit non-zero pixels
+ buf.transBlitFrom(tempSurface, Common::Point(x, y), 0);
+ tempSurface.free();
}
void GraphicsManager::drawColoredTexts(Graphics::ManagedSurface *surface, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font) {
@@ -224,7 +215,7 @@ void GraphicsManager::drawColoredTexts(Graphics::ManagedSurface *surface, const
}
}
-void GraphicsManager::drawColoredTexts(byte *buf, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font) {
+void GraphicsManager::drawColoredTexts(Graphics::ManagedSurface &buf, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font) {
int currentX = x;
byte currentColor = 255;
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index fd2de370bd2..6d31b038367 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -26,6 +26,7 @@
#include "common/scummsys.h"
#include "graphics/font.h"
+#include "graphics/managed_surface.h"
#include "graphics/screen.h"
namespace Pelrock {
@@ -35,16 +36,16 @@ public:
GraphicsManager();
~GraphicsManager();
- Common::Point showOverlay(int height, byte *buf);
- byte *grabBackgroundSlice(byte *buf, int x, int y, int w, int h);
- void putBackgroundSlice(byte *buf, int x, int y, int w, int h, byte *slice);
+ Common::Point showOverlay(int height, Graphics::ManagedSurface &buf);
+ byte *grabBackgroundSlice(Graphics::ManagedSurface &buf, int x, int y, int w, int h);
+ void putBackgroundSlice(Graphics::ManagedSurface &buf, int x, int y, int w, int h, byte *slice);
void fadeToBlack(int stepSize);
void fadePaletteToTarget(byte *targetPalette, int stepSize);
void clearScreen();
void drawColoredText(Graphics::ManagedSurface *screen, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font);
- void drawColoredText(byte *buf, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font);
+ void drawColoredText(Graphics::ManagedSurface &buf, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font);
void drawColoredTexts(Graphics::ManagedSurface *surface, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font);
- void drawColoredTexts(byte *buf, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font);
+ void drawColoredTexts(Graphics::ManagedSurface &buf, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font);
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 4680e454e7e..9ddad5ec3ca 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -112,7 +112,7 @@ void MenuManager::checkMouseClick(int x, int y) {
}
void MenuManager::showCredits() {
- memset(_compositeBuffer, 0, 640 * 400);
+ _compositeBuffer.clear(0);
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
error("Could not open ALFRED.7");
@@ -120,7 +120,7 @@ void MenuManager::showCredits() {
}
alfred7.seek(kCreditsBackgroundOffset, SEEK_SET);
- alfred7.read(_compositeBuffer, 640 * 400);
+ alfred7.read(_compositeBuffer.getPixels(), 640 * 400);
byte *creditsBuf = nullptr;
size_t creditsSize = 0;
int creditWidth = 240;
@@ -134,11 +134,11 @@ void MenuManager::showCredits() {
int x = (i < 34 / 2) ? 39 : 359;
int y = 3 + (i % (34 / 2)) * (400 / (34 / 2));
extractSingleFrame(decompressedCredits, singleCredit, kCreditsOrder[i], creditWidth, creditHeight);
- drawSpriteToBuffer(_compositeBuffer, 640, singleCredit, x, y, creditWidth, creditHeight, 255);
+ drawSpriteToBuffer(_compositeBuffer, singleCredit, x, y, creditWidth, creditHeight, 255);
delete[] singleCredit;
}
- memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+ _screen->blitFrom(_compositeBuffer);
delete[] decompressedCredits;
delete[] creditsBuf;
@@ -188,13 +188,13 @@ void MenuManager::menuLoop() {
}
void MenuManager::drawScreen() {
- memcpy(_compositeBuffer, _mainMenu, 640 * 400);
+ _compositeBuffer.blitFrom(_mainMenu);
if (showButtons)
drawButtons();
drawInventoryIcons();
- memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+ _screen->blitFrom(_compositeBuffer);
byte defaultColor = 255;
for (int i = 0; _menuText.size() > i; i++) {
g_engine->_graphics->drawColoredText(_screen, _menuText[i], 230, 200 + (i * 10), 200, defaultColor, g_engine->_smallFont);
@@ -211,9 +211,9 @@ void MenuManager::drawInventoryIcons() {
continue;
InventoryObject item = g_engine->_res->getIconForObject(g_engine->_state->inventoryItems[itemIndex]);
Common::Point slot = _inventorySlots[i];
- drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, slot.x, slot.y, 60, 60, 1);
+ drawSpriteToBuffer(_compositeBuffer, item.iconData, slot.x, slot.y, 60, 60, 1);
if (debugIcons) {
- drawRect(_compositeBuffer, slot.x, slot.y, 60, 60, 13);
+ drawRect(&_compositeBuffer, slot.x, slot.y, 60, 60, 13);
drawText(_compositeBuffer, g_engine->_smallFont, Common::String::format("ID %d", g_engine->_state->inventoryItems[itemIndex]), slot.x + 2, slot.y + 2, 640, 13);
}
}
@@ -228,8 +228,8 @@ void MenuManager::loadMenu() {
return;
}
- _compositeBuffer = new byte[640 * 400];
- _mainMenu = new byte[640 * 400];
+ _compositeBuffer.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+ _mainMenu.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
loadMenuTexts();
if (!alternateMenu) {
alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
@@ -242,7 +242,7 @@ void MenuManager::loadMenu() {
uint32 curPos = 0;
alfred7.seek(2405266, SEEK_SET);
- alfred7.read(_mainMenu, 65536);
+ alfred7.read(_mainMenu.getPixels(), 65536);
curPos += 65536;
@@ -251,28 +251,28 @@ void MenuManager::loadMenu() {
byte *decompressedPart1 = nullptr;
size_t decompressedSize = rleDecompress(compressedPart1, 29418, 0, 0, &decompressedPart1, true);
- memcpy(_mainMenu + curPos, decompressedPart1, decompressedSize);
+ memcpy((byte *)_mainMenu.getPixels() + curPos, decompressedPart1, decompressedSize);
curPos += decompressedSize;
delete[] compressedPart1;
delete[] decompressedPart1;
alfred7.seek(2500220, SEEK_SET);
- alfred7.read(_mainMenu + curPos, 32768);
+ alfred7.read((byte *)_mainMenu.getPixels() + curPos, 32768);
curPos += 32768;
byte *compressedPart2 = new byte[30288];
alfred7.read(compressedPart2, 30288);
byte *decompressedPart2 = nullptr;
decompressedSize = rleDecompress(compressedPart2, 30288, 0, 0, &decompressedPart2, true);
- memcpy(_mainMenu + curPos, decompressedPart2, decompressedSize);
+ memcpy((byte *)_mainMenu.getPixels() + curPos, decompressedPart2, decompressedSize);
curPos += decompressedSize;
debug("Settings menu size loaded: %d, with last block %d", curPos, curPos + 92160);
delete[] compressedPart2;
delete[] decompressedPart2;
alfred7.seek(2563266, SEEK_SET);
- alfred7.read(_mainMenu + curPos, 92160);
+ alfred7.read((byte *)_mainMenu.getPixels() + curPos, 92160);
} else {
- _mainMenu = new byte[640 * 400];
+ _mainMenu.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
alfred7.seek(kAlternateSettingsPaletteOffset, SEEK_SET);
alfred7.read(_mainMenuPalette, 768);
@@ -282,7 +282,7 @@ void MenuManager::loadMenu() {
_mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
}
- g_engine->_res->mergeRleBlocks(&alfred7, kAlternateSettingsMenuOffset, 8, _mainMenu);
+ g_engine->_res->mergeRleBlocks(&alfred7, kAlternateSettingsMenuOffset, 8, (byte *)_mainMenu.getPixels());
}
readButton(alfred7, 3193376, _saveButtons, _saveGameRect);
@@ -350,39 +350,39 @@ void MenuManager::drawButtons() {
button = isButtonClicked(_events->_mouseX, _events->_mouseY);
}
byte *buf = button == QUESTION_MARK_BUTTON ? _questionMark[1] : _questionMark[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _questionMarkRect.left, _questionMarkRect.top, _questionMarkRect.width(), _questionMarkRect.height(), kTransparentColor);
+ drawSpriteToBuffer(_compositeBuffer, buf, _questionMarkRect.left, _questionMarkRect.top, _questionMarkRect.width(), _questionMarkRect.height(), kTransparentColor);
buf = button == INVENTORY_PREV_BUTTON ? _inventoryLeftArrow[1] : _inventoryLeftArrow[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _invLeft.left, _invLeft.top, _invLeft.width(), _invLeft.height(), kTransparentColor);
+ drawSpriteToBuffer(_compositeBuffer, buf, _invLeft.left, _invLeft.top, _invLeft.width(), _invLeft.height(), kTransparentColor);
buf = button == INVENTORY_NEXT_BUTTON ? _inventoryRightArrow[1] : _inventoryRightArrow[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _invRight.left, _invRight.top, _invRight.width(), _invRight.height(), kTransparentColor);
+ drawSpriteToBuffer(_compositeBuffer, buf, _invRight.left, _invRight.top, _invRight.width(), _invRight.height(), kTransparentColor);
buf = button == SAVE_GAME_BUTTON ? _saveButtons[1] : _saveButtons[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _saveGameRect.left, _saveGameRect.top, _saveGameRect.width(), _saveGameRect.height(), kTransparentColor);
+ drawSpriteToBuffer(_compositeBuffer, buf, _saveGameRect.left, _saveGameRect.top, _saveGameRect.width(), _saveGameRect.height(), kTransparentColor);
buf = button == LOAD_GAME_BUTTON ? _loadButtons[1] : _loadButtons[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _loadGameRect.left, _loadGameRect.top, _loadGameRect.width(), _loadGameRect.height(), kTransparentColor);
+ drawSpriteToBuffer(_compositeBuffer, buf, _loadGameRect.left, _loadGameRect.top, _loadGameRect.width(), _loadGameRect.height(), kTransparentColor);
buf = button == LOAD_GAME_BUTTON ? _loadButtons[1] : _loadButtons[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _loadGameRect.left, _loadGameRect.top, _loadGameRect.width(), _loadGameRect.height(), kTransparentColor);
+ drawSpriteToBuffer(_compositeBuffer, buf, _loadGameRect.left, _loadGameRect.top, _loadGameRect.width(), _loadGameRect.height(), kTransparentColor);
buf = button == SOUNDS_BUTTON ? _soundsButtons[1] : _soundsButtons[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _soundsRect.left, _soundsRect.top, _soundsRect.width(), _soundsRect.height(), kTransparentColor);
+ drawSpriteToBuffer(_compositeBuffer, buf, _soundsRect.left, _soundsRect.top, _soundsRect.width(), _soundsRect.height(), kTransparentColor);
buf = button == EXIT_MENU_BUTTON ? _exitToDosButtons[1] : _exitToDosButtons[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _exitToDosRect.left, _exitToDosRect.top, _exitToDosRect.width(), _exitToDosRect.height(), kTransparentColor);
+ drawSpriteToBuffer(_compositeBuffer, buf, _exitToDosRect.left, _exitToDosRect.top, _exitToDosRect.width(), _exitToDosRect.height(), kTransparentColor);
buf = button == SAVEGAME_PREV_BUTTON ? _savesUpArrows[1] : _savesUpArrows[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _savesUp.left, _savesUp.top, _savesUp.width(), _savesUp.height(), kTransparentColor);
+ drawSpriteToBuffer(_compositeBuffer, buf, _savesUp.left, _savesUp.top, _savesUp.width(), _savesUp.height(), kTransparentColor);
buf = button == SAVEGAME_NEXT_BUTTON ? _savesDownArrows[1] : _savesDownArrows[0];
- drawSpriteToBuffer(_compositeBuffer, 640, buf, _savesDown.left, _savesDown.top, _savesDown.width(), _savesDown.height(), kTransparentColor);
+ drawSpriteToBuffer(_compositeBuffer, buf, _savesDown.left, _savesDown.top, _savesDown.width(), _savesDown.height(), kTransparentColor);
}
Pelrock::MenuManager::~MenuManager() {
- delete[] _mainMenu;
- delete[] _compositeBuffer;
+ _mainMenu.free();
+ _compositeBuffer.free();
delete[] _questionMark[0];
delete[] _questionMark[1];
delete[] _inventoryLeftArrow[0];
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 658c9c9243d..36bfe819821 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -22,6 +22,7 @@
#define PELROCK_MENU_H
#include "graphics/font.h"
+#include "graphics/managed_surface.h"
#include "graphics/screen.h"
#include "pelrock/events.h"
@@ -225,8 +226,8 @@ private:
PelrockEventManager *_events = nullptr;
ResourceManager *_res = nullptr;
SoundManager *_sound = nullptr;
- byte *_mainMenu = nullptr;
- byte *_compositeBuffer = nullptr;
+ Graphics::ManagedSurface _mainMenu;
+ Graphics::ManagedSurface _compositeBuffer;
Common::Rect _saveGameRect = Common::Rect(Common::Point(132, 186), 81, 34);
byte *_saveButtons[2] = {nullptr};
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index d8ecb49cf1b..f23cc843ea6 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -58,10 +58,6 @@ PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) :
}
PelrockEngine::~PelrockEngine() {
- if (_compositeBuffer)
- delete[] _compositeBuffer;
- if (_currentBackground)
- delete[] _currentBackground;
delete _largeFont;
delete _smallFont;
delete _doubleSmallFont;
@@ -147,8 +143,8 @@ void PelrockEngine::init() {
_menu->loadMenu();
calculateScalingMasks();
- _compositeBuffer = new byte[640 * 400];
- _currentBackground = new byte[640 * 400];
+ _compositeBuffer.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+ _currentBackground.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
changeCursor(DEFAULT);
CursorMan.showMouse(true);
@@ -266,14 +262,14 @@ void PelrockEngine::travelToEgypt() {
_sound->playMusicTrack(26, 1);
byte *palette = new byte[768];
- if (_bgScreen == nullptr) {
- _bgScreen = new byte[640 * 400];
+ if (!_bgScreen.getPixels()) {
+ _bgScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
}
- _res->getExtraScreen(6, _bgScreen, palette);
+ _res->getExtraScreen(6, (byte *)_bgScreen.getPixels(), palette);
CursorMan.showMouse(false);
g_system->getPaletteManager()->setPalette(palette, 0, 256);
- memcpy(_screen->getPixels(), _bgScreen, 640 * 400);
+ _screen->blitFrom(_bgScreen);
int frameCount = 0;
while (!shouldQuit() && frameCount < 96) {
_events->pollEvent();
@@ -295,10 +291,8 @@ void PelrockEngine::travelToEgypt() {
_graphics->clearScreen();
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
- free(_bgScreen);
- _bgScreen = nullptr;
+ _bgScreen.free();
CursorMan.showMouse(true);
- delete[] _bgScreen;
delete[] palette;
_screen->markAllDirty();
_screen->update();
@@ -534,9 +528,12 @@ void PelrockEngine::reflectionEffect(byte *buf, int x, int y, int width, int hei
byte pixel = buf[(height - 1 - row) * width + col]; // Read from bottom up for mirror
// Only reflect pixels 0-15 (high nibble must be 0)
if (pixel != 255 && (pixel & 0xF0) == 0) {
- byte bgPixel = _compositeBuffer[reflectY * 640 + x + col];
- if (bgPixel >= 223 && bgPixel < 228) { // Is water (0xDF-0xE3)
- _compositeBuffer[reflectY * 640 + x + col] = _room->_paletteRemaps[4][pixel];
+ int px = x + col;
+ if (px >= 0 && px < 640) {
+ byte bgPixel = (byte)_compositeBuffer.getPixel(px, reflectY);
+ if (bgPixel >= 223 && bgPixel < 228) { // Is water (0xDF-0xE3)
+ _compositeBuffer.setPixel(px, reflectY, _room->_paletteRemaps[4][pixel]);
+ }
}
}
}
@@ -640,7 +637,7 @@ void PelrockEngine::checkMouse() {
void PelrockEngine::copyBackgroundToBuffer() {
// copy background to buffer
- memcpy(_compositeBuffer, _currentBackground, 640 * 400);
+ _compositeBuffer.blitFrom(_currentBackground);
}
// Calculate Alfred's z-order based on Y position
@@ -685,7 +682,7 @@ void PelrockEngine::updateAnimations() {
}
void PelrockEngine::presentFrame() {
- memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+ _screen->blitFrom(_compositeBuffer);
paintDebugLayer();
_screen->markAllDirty();
}
@@ -749,7 +746,7 @@ void PelrockEngine::paintDebugLayer() {
drawPos(_screen, _curWalkTarget.x, _curWalkTarget.y, 100);
if (showShadows) {
- memcpy(_screen->getPixels(), _room->_pixelsShadows, 640 * 400);
+ _screen->copyRectToSurface(_room->_pixelsShadows, 640, 0, 0, 640, 400);
}
_smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
_smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", _alfredState.x, _alfredState.y, _alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
@@ -777,18 +774,18 @@ void PelrockEngine::placeStickersSecondPass() {
}
void PelrockEngine::placeSticker(Sticker sticker) {
- for (int y = 0; y < sticker.h; y++) {
- for (int x = 0; x < sticker.w; x++) {
- byte pixel = sticker.stickerData[y * sticker.w + x];
- // if (pixel != 0) {
- int bgX = sticker.x + x;
- int bgY = sticker.y + y;
- if (bgX >= 0 && bgX < 640 && bgY >= 0 && bgY < 400) {
- _compositeBuffer[bgY * 640 + bgX] = pixel;
- }
- // }
- }
- }
+ // Wrap sticker data as a surface and blit (no transparency - all pixels copied)
+ Graphics::Surface stickerSurf;
+ stickerSurf.init(sticker.w, sticker.h, sticker.w, sticker.stickerData, Graphics::PixelFormat::createFormatCLUT8());
+ // Clip to screen bounds
+ Common::Rect destRect(sticker.x, sticker.y, sticker.x + sticker.w, sticker.y + sticker.h);
+ Common::Rect screenRect(0, 0, 640, 400);
+ destRect.clip(screenRect);
+ if (destRect.isEmpty())
+ return;
+ Common::Rect srcRect(destRect.left - sticker.x, destRect.top - sticker.y,
+ destRect.right - sticker.x, destRect.bottom - sticker.y);
+ _compositeBuffer.blitFrom(stickerSurf, srcRect, Common::Point(destRect.left, destRect.top));
}
void PelrockEngine::renderOverlay(int overlayMode) {
@@ -1018,7 +1015,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
}
if (_alfredState.animState == ALFRED_WALKING) { // in case it changed to idle above
debug("Drawing crawl frame %d for direction %d", _alfredState.curFrame, _alfredState.direction);
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCrawlFrames[_alfredState.direction][_alfredState.curFrame], _alfredState.x, _alfredState.y - 55, 130, 55, 255);
+ drawSpriteToBuffer(_compositeBuffer, _res->alfredCrawlFrames[_alfredState.direction][_alfredState.curFrame], _alfredState.x, _alfredState.y - 55, 130, 55, 255);
_alfredState.curFrame++;
}
} else {
@@ -1078,7 +1075,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
drawAlfred(frame);
} else {
// Scale special anim frame to Alfred size before drawing
- drawSpriteToBuffer(_compositeBuffer, 640, frame, _alfredState.x, _alfredState.y - _res->_currentSpecialAnim->h, _res->_currentSpecialAnim->w, _res->_currentSpecialAnim->h, 255);
+ drawSpriteToBuffer(_compositeBuffer, frame, _alfredState.x, _alfredState.y - _res->_currentSpecialAnim->h, _res->_currentSpecialAnim->w, _res->_currentSpecialAnim->h, 255);
}
debug("Playing special anim frame %d/%d, speed %d", _res->_currentSpecialAnim->curFrame, _res->_currentSpecialAnim->numFrames, _res->_currentSpecialAnim->speed);
if (_chrono->getFrameCount() % _res->_currentSpecialAnim->speed == 0) {
@@ -1134,7 +1131,7 @@ void PelrockEngine::exitTriggers(Pelrock::Exit *exit) {
void PelrockEngine::drawIdleFrame() {
if (_room->_currentRoomNumber == 55) {
- drawSpriteToBuffer(_compositeBuffer, 640, _res->alfredCrawlFrames[_alfredState.direction][0], _alfredState.x, _alfredState.y - 55, 130, 55, 255);
+ drawSpriteToBuffer(_compositeBuffer, _res->alfredCrawlFrames[_alfredState.direction][0], _alfredState.x, _alfredState.y - 55, 130, 55, 255);
} else {
drawAlfred(_res->alfredIdle[_alfredState.direction]);
}
@@ -1279,7 +1276,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
}
- drawSpriteToBuffer(_compositeBuffer, 640, _alfredSprite, _alfredState.x, _alfredState.y - finalHeight, finalWidth, finalHeight, 255);
+ drawSpriteToBuffer(_compositeBuffer, _alfredSprite, _alfredState.x, _alfredState.y - finalHeight, finalWidth, finalHeight, 255);
// Water reflection (rooms 25 and 45 only)
if ((_room->_currentRoomNumber == 25 || _room->_currentRoomNumber == 45) && _alfredState.y >= 299) {
@@ -1343,7 +1340,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
debug("Warning: curFrame %d exceeds nframes %d for sprite %d anim %d", curFrame, animData.nframes, sprite->index, sprite->curAnimIndex);
curFrame = 0;
}
- drawSpriteToBuffer(_compositeBuffer, 640, animData.animData[curFrame], x, y, w, h, 255);
+ drawSpriteToBuffer(_compositeBuffer, animData.animData[curFrame], x, y, w, h, 255);
// Original in the game: increment FIRST, then check (not check-then-increment)
animData.elpapsedFrames++;
@@ -1572,7 +1569,7 @@ Common::Rect getActionArea(int x, int y) {
void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
- drawSpriteToBuffer(_compositeBuffer, 640, _res->_popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
+ drawSpriteToBuffer(_compositeBuffer, _res->_popUpBalloon + (curFrame * kBalloonHeight * kBalloonWidth), posx, posy, kBalloonWidth, kBalloonHeight, 255);
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
VerbIcon icon = isActionUnder(_events->_mouseX, _events->_mouseY);
@@ -1584,7 +1581,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
continue;
}
Common::Point p = getPositionInBalloonForIndex(i, posx, posy);
- drawSpriteToBuffer(_compositeBuffer, 640, _res->_verbIcons[actions[i]], p.x, p.y, kVerbIconWidth, kVerbIconHeight, 1);
+ drawSpriteToBuffer(_compositeBuffer, _res->_verbIcons[actions[i]], p.x, p.y, kVerbIconWidth, kVerbIconHeight, 1);
}
Common::Rect actionArea = getActionArea(posx, posy);
@@ -1604,7 +1601,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
if (_state->selectedInventoryItem >= 0 && !_state->inventoryItems.empty()) {
if (icon != ITEM || !shouldBlink) {
Common::Point p = getPositionInBalloonForIndex(actions.size(), posx, posy);
- drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->selectedInventoryItem).iconData, p.x, p.y, kVerbIconWidth, kVerbIconHeight, 1);
+ drawSpriteToBuffer(_compositeBuffer, _res->getIconForObject(_state->selectedInventoryItem).iconData, p.x, p.y, kVerbIconWidth, kVerbIconHeight, 1);
}
}
@@ -1648,7 +1645,7 @@ void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
}
byte *frame = index ? animHeader->animB[curFrame] : animHeader->animA[curFrame];
- drawSpriteToBuffer(_compositeBuffer, 640, frame, x, y, w, h, 255);
+ drawSpriteToBuffer(_compositeBuffer, frame, x, y, w, h, 255);
}
Common::Point getPositionInOverlayForIndex(uint index) {
@@ -1662,14 +1659,14 @@ void PelrockEngine::pickupIconFlash() {
uint invSize = _state->inventoryItems.size();
for (int i = 0; i < invSize; i++) {
Common::Point p = getPositionInOverlayForIndex(i);
- drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->inventoryItems[i]).iconData, p.x, p.y, 60, 60, 1);
+ drawSpriteToBuffer(_compositeBuffer, _res->getIconForObject(_state->inventoryItems[i]).iconData, p.x, p.y, 60, 60, 1);
}
InventoryObject item = _res->getIconForObject(_newItem);
if (_chrono->getFrameCount() % kIconBlinkPeriod == 0) {
Common::Point p = getPositionInOverlayForIndex(invSize);
debug("Drawing pickup icon for item %d at inventory index %d, position %d,%d", _newItem, invSize, p.x, p.y);
- drawSpriteToBuffer(_compositeBuffer, 640, item.iconData, p.x, p.y, 60, 60, 1);
+ drawSpriteToBuffer(_compositeBuffer, item.iconData, p.x, p.y, 60, 60, 1);
}
}
@@ -1685,15 +1682,15 @@ void PelrockEngine::showInventoryOverlay() {
if (i == _inventoryOverlayState.flashingIconIndex && _chrono->getFrameCount() % kIconBlinkPeriod == 0) {
continue;
}
- drawSpriteToBuffer(_compositeBuffer, 640, _res->getIconForObject(_state->inventoryItems[i]).iconData, p.x, p.y, 60, 60, 1);
+ drawSpriteToBuffer(_compositeBuffer, _res->getIconForObject(_state->inventoryItems[i]).iconData, p.x, p.y, 60, 60, 1);
}
// draw arrows if there are more items to show in either direction
if (_inventoryOverlayState.invStartingPos > 0) {
- drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
+ drawSpriteToBuffer(_compositeBuffer, _inventoryOverlayState.arrows[0], 0, 340, 20, 60, 255);
}
if (firstItem + kInventoryPageSize < (int)invSize) {
- drawSpriteToBuffer(_compositeBuffer, 640, _inventoryOverlayState.arrows[1], 620, 340, 20, 60, 255);
+ drawSpriteToBuffer(_compositeBuffer, _inventoryOverlayState.arrows[1], 620, 340, 20, 60, 255);
}
}
@@ -1815,7 +1812,7 @@ void PelrockEngine::computerLoop() {
}
void PelrockEngine::extraScreenLoop() {
- memcpy(_screen->getPixels(), _bgScreen, 640 * 400);
+ _screen->blitFrom(_bgScreen);
while (!shouldQuit()) {
_events->pollEvent();
@@ -1829,8 +1826,7 @@ void PelrockEngine::extraScreenLoop() {
}
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
- free(_bgScreen);
- _bgScreen = nullptr;
+ _bgScreen.free();
}
void PelrockEngine::walkLoop(int16 x, int16 y, AlfredDirection direction) {
@@ -2028,11 +2024,8 @@ void PelrockEngine::setScreen(int roomNumber) {
byte *palette = new byte[256 * 3];
_room->getPalette(&roomFile, roomOffset, palette);
- if (_currentBackground != nullptr) {
- delete[] _currentBackground;
- }
- _currentBackground = new byte[640 * 400];
- _room->getBackground(&roomFile, roomOffset, _currentBackground);
+ _currentBackground.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+ _room->getBackground(&roomFile, roomOffset, (byte *)_currentBackground.getPixels());
_screen->clear();
@@ -2071,16 +2064,15 @@ void PelrockEngine::setScreenAndPrepare(int roomNumber, AlfredDirection dir) {
void PelrockEngine::loadExtraScreenAndPresent(int screenIndex) {
byte *palette = new byte[768];
- if (_bgScreen == nullptr) {
- _bgScreen = new byte[640 * 400];
+ if (!_bgScreen.getPixels()) {
+ _bgScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
}
- _res->getExtraScreen(screenIndex, _bgScreen, palette);
+ _res->getExtraScreen(screenIndex, (byte *)_bgScreen.getPixels(), palette);
CursorMan.showMouse(false);
_graphics->clearScreen();
g_system->getPaletteManager()->setPalette(palette, 0, 256);
extraScreenLoop();
CursorMan.showMouse(true);
- delete[] _bgScreen;
delete[] palette;
_screen->markAllDirty();
_screen->update();
@@ -2363,12 +2355,8 @@ void PelrockEngine::pyramidCollapse() {
static const int srcX = 240, srcY = 145;
// static const int dstX = 510, dstY = 33;
static const int copyW = 99, copyH = 45;
- for (int row = 0; row < copyH; row++) {
- memcpy(
- _currentBackground + (srcY + row) * 640 + srcX,
- _compositeBuffer + (srcY + row) * 640 + srcX,
- copyW);
- }
+ Common::Rect copyRect(srcX, srcY, srcX + copyW, srcY + copyH);
+ _currentBackground.blitFrom(_compositeBuffer, copyRect, Common::Point(srcX, srcY));
}
_room->findSpriteByIndex(2)->zOrder = -1;
@@ -2450,10 +2438,10 @@ void PelrockEngine::pyramidCollapse() {
void PelrockEngine::endingScene() {
byte *palette = new byte[768];
- if (_bgScreen == nullptr) {
- _bgScreen = new byte[640 * 400];
+ if (!_bgScreen.getPixels()) {
+ _bgScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
}
- _res->getExtraScreen(14, _bgScreen, palette);
+ _res->getExtraScreen(14, (byte *)_bgScreen.getPixels(), palette);
CursorMan.showMouse(false);
_graphics->clearScreen();
g_system->getPaletteManager()->setPalette(palette, 0, 256);
@@ -2536,13 +2524,13 @@ void PelrockEngine::endingScene() {
_chrono->updateChrono();
if (_chrono->_gameTick) {
- memcpy(_compositeBuffer, _bgScreen, 640 * 400);
+ _compositeBuffer.blitFrom(_bgScreen);
for (Sprite *sprite : sprites) {
drawNextFrame(sprite);
}
- memcpy(_screen->getPixels(), _compositeBuffer, 640 * 400);
+ _screen->blitFrom(_compositeBuffer);
// Title text visible frames 21â149 (original: frame > 0x14 && frame < 0x96)
if (ticks > 20 && ticks < 150) {
drawText(_largeFont, "ALFRED PELROCK", 0, y1, 640, 255);
@@ -2562,10 +2550,9 @@ void PelrockEngine::endingScene() {
_screen->update();
}
- memset(_screen->getPixels(), 0, 640 * 400);
+ _screen->clear(0);
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
- delete[] _bgScreen;
- _bgScreen = nullptr;
+ _bgScreen.free();
CursorMan.showMouse(true);
delete[] palette;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 44020602b92..6df37af5dc1 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -33,6 +33,7 @@
#include "common/util.h"
#include "engines/engine.h"
#include "engines/savestate.h"
+#include "graphics/managed_surface.h"
#include "graphics/screen.h"
#include "image/png.h"
@@ -136,8 +137,8 @@ private:
int _currentStep = 0;
PathContext _currentContext;
- byte *_currentBackground = nullptr; // Clean background - NEVER modified
- byte *_bgScreen = nullptr;
+ Graphics::ManagedSurface _currentBackground; // Clean background - NEVER modified
+ Graphics::ManagedSurface _bgScreen;
ActionPopupState _actionPopupState;
InventoryOverlayState _inventoryOverlayState;
@@ -174,7 +175,7 @@ public:
DialogManager *_dialog = nullptr;
AlfredState _alfredState;
ShakeEffectState _shakeEffectState;
- byte *_compositeBuffer = nullptr; // Working composition buffer
+ Graphics::ManagedSurface _compositeBuffer; // Working composition buffer
bool _mouseDisabled = false;
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 58a53b1c6c3..8032112eb8c 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -114,6 +114,32 @@ void drawText(Graphics::Font *font, Common::String text, int x, int y, int w, by
font->drawString(g_engine->_screen, text.c_str(), x, y, w, color, Graphics::kTextAlignCenter);
}
+void drawText(Graphics::ManagedSurface &dest, Graphics::Font *font, Common::String text, int x, int y, int w, byte color, Graphics::TextAlign align) {
+ Common::Rect rect = font->getBoundingBox(text.c_str());
+ int bboxW = rect.width();
+ int bboxH = rect.height();
+
+ Graphics::Surface surface;
+ surface.create(bboxW, bboxH, Graphics::PixelFormat::createFormatCLUT8());
+ surface.fillRect(Common::Rect(0, 0, bboxW, bboxH), 255);
+ if (x + bboxW > 640) {
+ x = 640 - bboxW - 2;
+ }
+ if (y + bboxH > 400) {
+ y = 400 - bboxH - 2;
+ }
+ if (x < 0) {
+ x = 0;
+ }
+ if (y < 0) {
+ y = 0;
+ }
+
+ font->drawString(&surface, text.c_str(), 0, 0, bboxW, color, align);
+ dest.transBlitFrom(surface, Common::Point(x, y), 255);
+ surface.free();
+}
+
size_t rleDecompress(
const uint8_t *input,
size_t inputSize,
@@ -268,6 +294,13 @@ void drawSpriteToBuffer(byte *buffer, int bufferWidth, byte *sprite, int x, int
}
}
+// ManagedSurface overload: wraps sprite data in a Surface and uses transBlitFrom
+void drawSpriteToBuffer(Graphics::ManagedSurface &dest, byte *sprite, int x, int y, int width, int height, int transparentColor) {
+ Graphics::Surface spriteSurf;
+ spriteSurf.init(width, height, width, sprite, Graphics::PixelFormat::createFormatCLUT8());
+ dest.transBlitFrom(spriteSurf, Common::Point(x, y), transparentColor);
+}
+
void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY) {
for (int y = 0; y < surface->h; y++) {
for (int x = 0; x < surface->w; x++) {
@@ -393,4 +426,22 @@ void drawPaletteSquares(byte *screenBuffer, byte *palette) {
}
}
+void drawPaletteSquares(Graphics::ManagedSurface &dest, byte *palette) {
+ const int squareSize = 6;
+ const int colorsPerRow = 16;
+ const int startX = 10;
+ const int startY = 10;
+ const int spacing = 1;
+
+ for (int colorIndex = 0; colorIndex < 256; colorIndex++) {
+ int row = colorIndex / colorsPerRow;
+ int col = colorIndex % colorsPerRow;
+
+ int x = startX + col * (squareSize + spacing);
+ int y = startY + row * (squareSize + spacing);
+
+ dest.fillRect(Common::Rect(x, y, x + squareSize, y + squareSize), colorIndex);
+ }
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 98305b9319c..1aedf5a2b4f 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -36,12 +36,14 @@ size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uin
void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize);
void rleDecompressSingleBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize);
void drawSpriteToBuffer(byte *buffer, int bufferWidth, byte *sprite, int x, int y, int width, int height, int transparentColor);
+void drawSpriteToBuffer(Graphics::ManagedSurface &dest, byte *sprite, int x, int y, int width, int height, int transparentColor);
void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY);
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight);
void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color);
void drawText(byte *screenBuffer, Graphics::Font *font, Common::String text, int x, int y, int w, byte color, Graphics::TextAlign align = Graphics::kTextAlignLeft);
+void drawText(Graphics::ManagedSurface &dest, Graphics::Font *font, Common::String text, int x, int y, int w, byte color, Graphics::TextAlign align = Graphics::kTextAlignLeft);
void drawText(Graphics::Font *font, Common::String text, int x, int y, int w, byte color);
Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
@@ -50,6 +52,7 @@ void changeGameSpeed(Common::Event e);
Common::StringArray arrayOf(Common::String str);
void invertSprite(byte *data, int w, int h);
void drawPaletteSquares(byte *screenBuffer, byte *palette);
+void drawPaletteSquares(Graphics::ManagedSurface &dest, byte *palette);
static const int special_chars[] = {
168, // inverted ?
Commit: 133fe537c9e95f51088136ba0beda3ee22cf1cdf
https://github.com/scummvm/scummvm/commit/133fe537c9e95f51088136ba0beda3ee22cf1cdf
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:23+02:00
Commit Message:
PELROCK: Fixes original bug in statue
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 6110d1562c1..5bd86dea95c 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -320,9 +320,12 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
// skip to root after the next one
_state->setCurrentRoot(room, rootIndex + 2, 0);
break;
- case 267:
+ case 267: {
_state->setCurrentRoot(7, 2, 0);
+ addInventoryItem(8);
+ animateStatuePaletteFade(true);
break;
+ }
case 272:
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
@@ -1122,8 +1125,6 @@ void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
animateStatuePaletteFade(false);
walkAndAction(statueHotspot, TALK);
waitForActionEnd();
- animateStatuePaletteFade(true);
- addInventoryItem(8);
}
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f23cc843ea6..bec290f5559 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -2101,6 +2101,10 @@ void PelrockEngine::doExtraActions(int roomNumber) {
loadExtraScreenAndPresent(4);
}
break;
+ case 7: { // not in the original but it was clearly a bug
+ _dialog->_goodbyeDisabled = true;
+ break;
+ }
case 15:
if (_state->getFlag(FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ)) {
_state->setFlag(FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ, false);
Commit: d94c6dc3790f5a7a738a81f919a3e10ceb4bc2ce
https://github.com/scummvm/scummvm/commit/d94c6dc3790f5a7a738a81f919a3e10ceb4bc2ce
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:23+02:00
Commit Message:
PELROCK: Fixes intro timing
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/video/video.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 5bd86dea95c..ca9761466d4 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -592,6 +592,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
g_system->delayMillis(10);
}
_room->disableSprite(0);
+ _state->setCurrentRoot(room, 2, 0);
} break;
case 313:
_state->setCurrentRoot(room, rootIndex + 1, 0);
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 2dce77e9e56..9c7243def1b 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -61,88 +61,106 @@ void VideoManager::playIntro() {
_videoSurface.fillRect(Common::Rect(0, 0, 640, 400), 0);
_textSurface.fillRect(Common::Rect(0, 0, 640, 400), 255);
- for (int sequence = 0; sequence < 1; sequence++) {
- uint16 frameCounter = 0;
- bool videoExitFlag = false;
- while (!videoExitFlag && !g_engine->shouldQuit() && _events->_lastKeyEvent != Common::KEYCODE_ESCAPE) {
- _chrono->updateChrono();
- _events->pollEvent();
+ uint16 frameCounter = 0;
+ bool videoExitFlag = false;
+
+ while (!videoExitFlag && !g_engine->shouldQuit() && _events->_lastKeyEvent != Common::KEYCODE_ESCAPE) {
+ _events->pollEvent();
+
+ ChunkHeader chunk;
+ readChunk(videoFile, chunk);
+ debug("Read chunk type %d at frame %d", chunk.chunkType, frameCounter);
+
+ switch (chunk.chunkType) {
+ case 1:
+ case 2: {
+ // Visual frame: wait for chrono timing before presenting
+ // Fix Bug 2/3: only visual frames (types 1/2) participate in chrono gating
Subtitle *subtitle = getSubtitleForFrame(frameCounter);
int frameSkip = subtitle != nullptr ? 4 : 2;
- if (_chrono->_gameTick && _chrono->getFrameCount() % frameSkip == 0) {
- ChunkHeader chunk;
- readChunk(videoFile, chunk);
- debug("Read chunk type %d at frame %d", chunk.chunkType, frameCounter);
- switch (chunk.chunkType) {
- case 1:
- case 2:
- processFrame(chunk, frameCounter++);
- break;
- case 3:
- videoExitFlag = true;
- break;
- case 4:
- loadPalette(chunk);
- break;
- default:
- debug("Unknown chunk type %d encountered", chunk.chunkType);
+ while (!g_engine->shouldQuit() && _events->_lastKeyEvent != Common::KEYCODE_ESCAPE) {
+ _chrono->updateChrono();
+ _events->pollEvent();
+ if (_chrono->_gameTick && _chrono->getFrameCount() % frameSkip == 0)
break;
- }
-
- if (_voiceEffect.contains(frameCounter)) {
- // Wait for any playing voice to finish before starting new one
- while (_sound->isPlaying(0)) {
- _events->pollEvent();
- g_system->delayMillis(10);
- if (g_engine->shouldQuit() || _events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
- break;
- }
- }
- AudioEffect voice = _voiceEffect[frameCounter];
- debug("Playing voice effect: '%s'", voice.filename.c_str());
- VoiceData voiceData = _sounds[voice.filename];
- _introSndFile.seek(voiceData.offset, SEEK_SET);
- byte *voiceBuffer = new byte[voiceData.length];
- _introSndFile.read(voiceBuffer, voiceData.length);
- _sound->playSound(voiceBuffer, voiceData.length, 0);
- }
+ g_system->delayMillis(10);
+ }
- if(_sfxEffect.contains(frameCounter)) {
- AudioEffect sfx = _sfxEffect[frameCounter];
- debug("Playing SFX effect: '%s'", sfx.filename.c_str());
- VoiceData sfxData = _sounds[sfx.filename];
- _introSndFile.seek(sfxData.offset, SEEK_SET);
- byte *sfxBuffer = new byte[sfxData.length];
- _introSndFile.read(sfxBuffer, sfxData.length);
- _sound->playSound(sfxBuffer, sfxData.length, 1);
+ // Fix Bug 1: capture current frame BEFORE increment so audio fires at the correct frame
+ int currentFrame = frameCounter++;
+ processFrame(chunk, currentFrame);
+
+ // Fix Bug 1: all audio checks use currentFrame (not the already-incremented frameCounter)
+ if (_voiceEffect.contains(currentFrame)) {
+ // Wait for any playing voice to finish before starting new one
+ while (_sound->isPlaying(0)) {
+ _events->pollEvent();
+ g_system->delayMillis(10);
+ if (g_engine->shouldQuit() || _events->_lastKeyEvent == Common::KEYCODE_ESCAPE)
+ break;
}
+ AudioEffect voice = _voiceEffect[currentFrame];
+ debug("Playing voice effect: '%s'", voice.filename.c_str());
+ VoiceData voiceData = _sounds[voice.filename];
+ _introSndFile.seek(voiceData.offset, SEEK_SET);
+ byte *voiceBuffer = new byte[voiceData.length];
+ _introSndFile.read(voiceBuffer, voiceData.length);
+ _sound->playSound(voiceBuffer, voiceData.length, 0);
+ }
- if(_musicEffect.contains(frameCounter)) {
- MusicEffect music = _musicEffect[frameCounter];
- _sound->playMusicTrack(music.trackNumber, true);
- }
+ if (_sfxEffect.contains(currentFrame)) {
+ AudioEffect sfx = _sfxEffect[currentFrame];
+ debug("Playing SFX effect: '%s'", sfx.filename.c_str());
+ VoiceData sfxData = _sounds[sfx.filename];
+ _introSndFile.seek(sfxData.offset, SEEK_SET);
+ byte *sfxBuffer = new byte[sfxData.length];
+ _introSndFile.read(sfxBuffer, sfxData.length);
+ _sound->playSound(sfxBuffer, sfxData.length, 1);
+ }
- if (subtitle != nullptr) {
- Common::StringArray lines = _dialog->wordWrap(subtitle->text)[0];
+ if (_musicEffect.contains(currentFrame)) {
+ MusicEffect music = _musicEffect[currentFrame];
+ _sound->playMusicTrack(music.trackNumber, true);
+ }
- byte color;
- _dialog->processColorAndTrim(lines, color);
- Graphics::Surface s = _dialog->getDialogueSurface(lines, color);
- _textSurface.transBlitFrom(s, Common::Point(subtitle->x, subtitle->y), 255);
+ // Fix Bug 4: subtitles are suppressed in the blackout range (frames 571-669)
+ bool inBlackoutRange = (currentFrame >= 571 && currentFrame <= 669);
+ if (subtitle != nullptr && !inBlackoutRange) {
+ Common::StringArray lines = _dialog->wordWrap(subtitle->text)[0];
- drawPos(&_textSurface, subtitle->x, subtitle->y, color);
- drawRect(&_textSurface, subtitle->x, subtitle->y,
- s.getRect().width(),
- s.getRect().height(), color);
- }
+ byte color;
+ _dialog->processColorAndTrim(lines, color);
+ Graphics::Surface s = _dialog->getDialogueSurface(lines, color);
+ _textSurface.transBlitFrom(s, Common::Point(subtitle->x, subtitle->y), 255);
- presentFrame();
+ drawPos(&_textSurface, subtitle->x, subtitle->y, color);
+ drawRect(&_textSurface, subtitle->x, subtitle->y,
+ s.getRect().width(),
+ s.getRect().height(), color);
}
- g_system->delayMillis(10);
+
+ presentFrame();
+ break;
+ }
+ case 3:
+ videoExitFlag = true;
+ break;
+ case 4:
+ loadPalette(chunk);
+ break;
+ case 6:
+ // Fix Bug 3: type 6 is a timing pad. Original costs ~20ms per chunk.
+ // Do NOT gate on chrono â process immediately with a short delay.
+ g_system->delayMillis(20);
+ break;
+ default:
+ debug("Unknown chunk type %d encountered", chunk.chunkType);
+ break;
}
- debug("Total frames played: %d", frameCounter);
}
+
+ debug("Total frames played: %d", frameCounter);
videoFile.close();
}
Commit: a4c9db112d0750cd57552e80b576939caf467a63
https://github.com/scummvm/scummvm/commit/a4c9db112d0750cd57552e80b576939caf467a63
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:24+02:00
Commit Message:
PELROCK: Fixes inventory overlay glitches (autoscrolls on last icon)
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/extrascreens.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index ca9761466d4..2f3aac6a705 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -252,6 +252,7 @@ void PelrockEngine::addInventoryItem(int item) {
}
_newItem = item;
int frameCounter = 0;
+ _state->addInventoryItem(item);
while (frameCounter < kIconFlashDuration) {
_events->pollEvent();
@@ -262,7 +263,6 @@ void PelrockEngine::addInventoryItem(int item) {
}
g_system->delayMillis(10);
}
- _state->addInventoryItem(item);
checkObjectsForPart2();
}
@@ -1205,25 +1205,27 @@ void PelrockEngine::closeTravelAgencyDoor(HotSpot *hotspot) {
}
void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
- _state->removeInventoryItem(86);
- addInventoryItem(76);
- _sound->playMusicTrack(27);
- checkIngredients();
- _dialog->say(_res->_ingameTexts[CUIDADOIMPRUDENTE]);
- _alfredState.x -= 10;
- _alfredState.y += 20;
- playAlfredSpecialAnim(5);
- _sound->playSound(_room->_roomSfx[0], 0); // Belch
- waitForSoundEnd();
- _alfredState.animState = ALFRED_SKIP_DRAWING;
- _graphics->fadeToBlack(10);
- // update conversaton state
- _alfredState.x = 300;
- _alfredState.y = 238;
- waitForSoundEnd();
- _alfredState.animState = ALFRED_IDLE;
- setScreenAndPrepare(28, ALFRED_DOWN);
- _dialog->say(_res->_ingameTexts[QUEOSCUROESTAESTO]);
+ _state->removeInventoryItem(76);
+ addInventoryItem(86);
+ if(_state->getFlag(FLAG_CROCODILLO_ENCENDIDO) == false) {
+ _sound->playMusicTrack(27);
+ checkIngredients();
+ _dialog->say(_res->_ingameTexts[CUIDADOIMPRUDENTE]);
+ _alfredState.x -= 10;
+ _alfredState.y += 20;
+ playAlfredSpecialAnim(5);
+ _sound->playSound(_room->_roomSfx[0], 0); // Belch
+ waitForSoundEnd();
+ _alfredState.animState = ALFRED_SKIP_DRAWING;
+ _graphics->fadeToBlack(10);
+ // update conversaton state
+ _alfredState.x = 300;
+ _alfredState.y = 238;
+ waitForSoundEnd();
+ _alfredState.animState = ALFRED_IDLE;
+ setScreenAndPrepare(28, ALFRED_DOWN);
+ _dialog->say(_res->_ingameTexts[QUEOSCUROESTAESTO]);
+ }
}
void PelrockEngine::playAlfredSpecialAnim(int anim, bool reverse) {
@@ -1761,6 +1763,9 @@ void PelrockEngine::useWigWithPot(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
+ if(inventoryObject == 86) {
+ addInventoryItem(76);
+ }
_state->removeInventoryItem(inventoryObject);
_state->setFlag(FLAG_FORMULA_MAGICA, _state->getFlag(FLAG_FORMULA_MAGICA) + 1);
if (_state->getFlag(FLAG_FORMULA_MAGICA) == 4) {
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 1319172f159..9b94bcea530 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -838,7 +838,7 @@ void DialogManager::addGoodbyeOptionIfNeeded(Common::Array<ChoiceOption> *choice
termChoice.isTerminator = true;
termChoice.isDisabled = false;
termChoice.shouldDisableOnSelect = false;
- termChoice.text = g_engine->_res->_conversationTerminator;
+ termChoice.text = " " + g_engine->_res->_conversationTerminator;
choices->push_back(termChoice);
}
}
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
index 0c9ad6fa5bd..bb6457a29c2 100644
--- a/engines/pelrock/extrascreens.cpp
+++ b/engines/pelrock/extrascreens.cpp
@@ -63,8 +63,6 @@ Spell *SpellBook::run() {
void SpellBook::init() {
_compositeScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
-
- // selectPage(0);
}
void SpellBook::selectPage(int page) {
@@ -93,7 +91,7 @@ void SpellBook::selectPage(int page) {
_spell->image = new byte[w * h];
extractSingleFrame(spriteData, _spell->image, page, w, h);
- juegoFile.seek(0x0004661C, SEEK_SET);
+ juegoFile.seek(0x0004661D, SEEK_SET);
byte *textData = new byte[2861];
juegoFile.read(textData, 2861);
@@ -103,7 +101,6 @@ void SpellBook::selectPage(int page) {
}
Common::Array<Common::StringArray> spells = _res->processTextData(textData, 2861, true);
-
_spell->text = spells[page];
delete[] compressedData;
delete[] spriteData;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index bec290f5559..6924697df5f 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1391,6 +1391,7 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
// This means the balloon bottom overlaps Alfred's head by ~10 pixels.
_actionPopupState.y = MAX(10, (int)_alfredState.y - (int)kAlfredFrameHeight - 102);
_actionPopupState.isActive = true;
+ _inventoryOverlayState.invStartingPos = -1;
_actionPopupState.curFrame = 0;
debug("Setting alfred under popup: %d", alfredUnder);
_actionPopupState.isAlfredUnder = alfredUnder;
@@ -1592,8 +1593,14 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
if (_inventoryOverlayState.isActive) {
+ // find selectedInventoryItem index in inventoryItems, set invStartingPos to that index if found, otherwise 0
+ int scrollPos = getScrollPositionForItem(_state->selectedInventoryItem);
+ if(_inventoryOverlayState.invStartingPos == -1) {
+ _inventoryOverlayState.invStartingPos = scrollPos != -1 ? scrollPos : 0;
+ }
showInventoryOverlay();
if (_inventoryOverlayState.posInInventorySelectionArea(_events->_mouseX, _events->_mouseY)) {
+ _inventoryOverlayState.flashingIconIndex = -1;
checkMouseOverInventoryOverlay(_events->_mouseX, _events->_mouseY);
}
}
@@ -1612,6 +1619,23 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
}
}
+int PelrockEngine::getScrollPositionForItem(int item) {
+ int selectedIndex = -1;
+ for (size_t i = 0; i < _state->inventoryItems.size(); i++) {
+ if (_state->inventoryItems[i] == item) {
+ selectedIndex = i;
+ break;
+ }
+ }
+ if (selectedIndex != -1) {
+ // put the selected item at the end in the overlay
+ if (_state->inventoryItems.size() > kInventoryPageSize) {
+ selectedIndex = CLIP(selectedIndex, 0, (int)_state->inventoryItems.size() - kInventoryPageSize);
+ }
+ }
+ return selectedIndex;
+}
+
void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
// Change with the right index
@@ -1653,21 +1677,10 @@ Common::Point getPositionInOverlayForIndex(uint index) {
}
void PelrockEngine::pickupIconFlash() {
- _graphics->showOverlay(60, _compositeBuffer);
- if (_newItem == -1)
- return;
uint invSize = _state->inventoryItems.size();
- for (int i = 0; i < invSize; i++) {
- Common::Point p = getPositionInOverlayForIndex(i);
- drawSpriteToBuffer(_compositeBuffer, _res->getIconForObject(_state->inventoryItems[i]).iconData, p.x, p.y, 60, 60, 1);
- }
-
- InventoryObject item = _res->getIconForObject(_newItem);
- if (_chrono->getFrameCount() % kIconBlinkPeriod == 0) {
- Common::Point p = getPositionInOverlayForIndex(invSize);
- debug("Drawing pickup icon for item %d at inventory index %d, position %d,%d", _newItem, invSize, p.x, p.y);
- drawSpriteToBuffer(_compositeBuffer, item.iconData, p.x, p.y, 60, 60, 1);
- }
+ _inventoryOverlayState.invStartingPos = getScrollPositionForItem(_state->inventoryItems[invSize - 1]);
+ _inventoryOverlayState.flashingIconIndex = invSize - 1;
+ showInventoryOverlay();
}
void PelrockEngine::showInventoryOverlay() {
@@ -1675,6 +1688,12 @@ void PelrockEngine::showInventoryOverlay() {
uint invSize = _state->inventoryItems.size();
// invStartingPos is an ITEM index (not a page number).
// The original game scrolls 1 item at a time, not 1 page at a time.
+ if(_inventoryOverlayState.invStartingPos == -1) {
+ _inventoryOverlayState.invStartingPos = getScrollPositionForItem(_state->selectedInventoryItem);
+ if(_inventoryOverlayState.invStartingPos == -1) {
+ _inventoryOverlayState.invStartingPos = 0;
+ }
+ }
int firstItem = _inventoryOverlayState.invStartingPos;
for (int i = firstItem; i < (int)invSize && i < firstItem + kInventoryPageSize; i++) {
@@ -1701,10 +1720,12 @@ void PelrockEngine::checkMouseOverInventoryOverlay(int x, int y) {
if (_inventoryOverlayState.invStartingPos > 0) {
_inventoryOverlayState.invStartingPos--;
}
+ debug("Mouse at x=%d triggers scroll left, new invStartingPos=%d", x, _inventoryOverlayState.invStartingPos);
} else if (x >= 620) {
if (_inventoryOverlayState.invStartingPos + kInventoryPageSize < (int)_state->inventoryItems.size()) {
_inventoryOverlayState.invStartingPos++;
}
+ debug("Mouse at x=%d triggers scroll right, new invStartingPos=%d", x, _inventoryOverlayState.invStartingPos);
} else {
// mouse hover over inventory item, laid out horizontally, y coordinate is not relevant
int index = (x - 20) / 60 + _inventoryOverlayState.invStartingPos;
@@ -1959,6 +1980,10 @@ void PelrockEngine::changeCursor(Cursor cursor) {
}
void PelrockEngine::checkMouseHover() {
+ if(_actionPopupState.isActive) {
+ debug("Mouse hover ignored because action popup is active");
+ return;
+ }
bool hotspotDetected = false;
int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 6df37af5dc1..46ef3f43767 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -84,6 +84,8 @@ private:
void showActionBalloon(int posx, int posy, int curFrame);
+ int getScrollPositionForItem(int item);
+
void checkMouse();
void copyBackgroundToBuffer();
void updateAnimations();
Commit: cef88966e5bda54b4a96737b4a8150c3146fc9b7
https://github.com/scummvm/scummvm/commit/cef88966e5bda54b4a96737b4a8150c3146fc9b7
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:24+02:00
Commit Message:
PELROCK: Fixes stone delivery sequence in rooms 41 & 42
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 2f3aac6a705..e6b91df562b 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -600,7 +600,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 308: {
int targetBranch = rootIndex + 1;
if (targetBranch > 17) {
- targetBranch = 3;
+ targetBranch = 2;
}
_state->setCurrentRoot(room, targetBranch, 0);
break;
@@ -1234,8 +1234,8 @@ void PelrockEngine::playAlfredSpecialAnim(int anim, bool reverse) {
waitForSpecialAnimation();
}
-void PelrockEngine::waitForSoundEnd() {
- while (!shouldQuit() && _sound->isPlaying(0)) {
+void PelrockEngine::waitForSoundEnd(int channel) {
+ while (!shouldQuit() && _sound->isPlaying(channel)) {
_events->pollEvent();
renderScene(OVERLAY_NONE);
_screen->update();
@@ -1563,17 +1563,19 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[HAYQUECELEBRARLO]);
+ byte counter = _state->getFlag(FLAG_DA_PIEDRA);
// drinking animation and sound
- _sound->playSound(_room->_roomSfx[1], 0);
+ _sound->playSound(_room->_roomSfx[1], 2);
+
+ _room->findSpriteByIndex(0)->zOrder = -1;
- _room->disableSprite(0);
- playSpecialAnim(1473360, true, mastersX - 5, mastersY - 1, 152, 83, 7);
+ playSpecialAnim(1473360, true, mastersX - 6, mastersY - 1, 152, 83, 7);
// Increment stone delivery counter (tracks 0â1â2â3)
- byte counter = _state->getFlag(FLAG_DA_PIEDRA);
debug("Current stone delivery count: %d", counter);
if (counter < 3) {
_state->setFlag(FLAG_DA_PIEDRA, ++counter);
+ _room->findSpriteByIndex(0)->zOrder = zIndex;
}
debug("New stone delivery count: %d", _state->getFlag(FLAG_DA_PIEDRA));
// At 2nd stone delivery: masters starts singing (conversation root 2)
@@ -1583,18 +1585,14 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
// At 3rd stone delivery: masters get wasted
if (counter == 3) {
+ _room->disableSprite(0, PERSIST_BOTH);
playSpecialAnim(1512060, true, mastersX - 28, mastersY - 6, 172, 96, 3);
-
_room->addSticker(116);
-
WalkBox w1 = {3, 187, 374, 5, 17, 0};
WalkBox w2 = {4, 141, 374, 46, 4, 0};
_room->addWalkbox(w1);
_room->addWalkbox(w2);
_state->setFlag(FLAG_GUARDIAS_BORRACHOS, true);
- } else {
- debug("Re-enabling master sprite with zIndex %d", zIndex);
- _room->enableSprite(0, zIndex);
}
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 9b94bcea530..5cc7535edcf 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -1098,7 +1098,6 @@ int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
}
Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::String text) {
- debug("Word-wrapping text: \"%s\"", text.c_str());
Common::Array<Common::Array<Common::String>> pages;
Common::Array<Common::String> currentPage;
Common::Array<Common::String> currentLine;
@@ -1169,12 +1168,12 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
}
// print all the pages and lines for debugging
- for (uint i = 0; i < pages.size(); i++) {
- debug("Page %d:", i);
- for (uint j = 0; j < pages[i].size(); j++) {
- debug(" Line %d: \"%s\"", j, pages[i][j].c_str());
- }
- }
+ // for (uint i = 0; i < pages.size(); i++) {
+ // debug("Page %d:", i);
+ // for (uint j = 0; j < pages[i].size(); j++) {
+ // debug(" Line %d: \"%s\"", j, pages[i][j].c_str());
+ // }
+ // }
return pages;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 6924697df5f..dd00c2f2f09 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1740,6 +1740,7 @@ void PelrockEngine::checkMouseOverInventoryOverlay(int x, int y) {
}
int PelrockEngine::checkMouseClickInventoryOverlay(int x, int y) {
+
if (x < 20) {
return -1;
} else if (x >= 620) {
@@ -1872,6 +1873,10 @@ void PelrockEngine::walkTo(int x, int y) {
}
void PelrockEngine::walkAndAction(HotSpot *hotspot, VerbIcon action) {
+ if(_currentHotspot == nullptr) {
+ debug("Error: walkAndAction called with null hotspot");
+ return;
+ }
_disableAction = true;
walkTo(hotspot->x + hotspot->w / 2, hotspot->y + hotspot->h);
_queuedAction = QueuedAction{action, hotspot->index, true, false};
@@ -1981,7 +1986,6 @@ void PelrockEngine::changeCursor(Cursor cursor) {
void PelrockEngine::checkMouseHover() {
if(_actionPopupState.isActive) {
- debug("Mouse hover ignored because action popup is active");
return;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 46ef3f43767..4ea450ae383 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -356,7 +356,7 @@ public:
void closeTravelAgencyDoor(HotSpot *hotspot);
void usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot);
void playAlfredSpecialAnim(int anim, bool reverse = false);
- void waitForSoundEnd();
+ void waitForSoundEnd(int channel = 0);
void pickupSunflower(HotSpot *hotspot);
void checkIngredients();
void pickUpBook(int i);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index a62a615fa98..ff099f4faf3 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -246,6 +246,7 @@ void RoomManager::enableSprite(byte spriteIndex, byte zOrder, int persist) {
void RoomManager::enableSprite(byte roomNumber, byte spriteIndex, byte zOrder, int persist) {
for(int i =0; i < g_engine->_state->spriteChanges[roomNumber].size(); i++) {
if (g_engine->_state->spriteChanges[roomNumber][i].spriteIndex == spriteIndex) {
+ debug("Removing sprite change for room %d, sprite index %d, zOrder %d", roomNumber, spriteIndex, g_engine->_state->spriteChanges[roomNumber][i].zIndex);
g_engine->_state->spriteChanges[roomNumber].remove_at(i);
break;
}
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 96b621e9769..42340cdb5fe 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -49,11 +49,11 @@ SoundManager::~SoundManager() {
stopMusic();
}
-void SoundManager::playSound(byte index, int channel) {
+void SoundManager::playSound(byte index, int channel, int loopCount) {
// debug("Playing sound index %d (%s)", index, SOUND_FILENAMES[index]);
auto it = _soundMap.find(SOUND_FILENAMES[index]);
if (it != _soundMap.end()) {
- playSound(it->_value, channel);
+ playSound(it->_value, channel, loopCount);
} else {
debug("Sound file %s not found in sound map", SOUND_FILENAMES[index]);
}
@@ -115,11 +115,15 @@ void SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
} else {
if (_mixer->isSoundHandleActive(_sfxHandles[channel])) {
_mixer->stopHandle(_sfxHandles[channel]);
+ debug("Stopped active sound on channel %d to play new sound %s", channel, sound.filename.c_str());
+ }
+ else {
+ debug("Warning: channel %d is already free when trying to play sound %s", channel, sound.filename.c_str());
}
}
Audio::AudioStream *finalStream = loopCount != -1 ? stream : Audio::makeLoopingAudioStream(stream, 0);
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], finalStream, loopCount, _currentVolume, 0, DisposeAfterUse::YES);
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], finalStream, -1, _currentVolume, 0, DisposeAfterUse::YES);
}
}
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 6e33487d34b..3480b333974 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -157,7 +157,7 @@ class SoundManager {
public:
SoundManager(Audio::Mixer *mixer);
~SoundManager();
- void playSound(byte index, int channel = -1);
+ void playSound(byte index, int channel = -1, int loopCount = 1);
void playSound(const char *filename, int channel, int loopCount = 1);
void playSound(byte *soundData, uint32 size, int channel);
void stopAllSounds();
Commit: b0fe4b04a9ee3351e02f130e262261b9f9e029ce
https://github.com/scummvm/scummvm/commit/b0fe4b04a9ee3351e02f130e262261b9f9e029ce
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:24+02:00
Commit Message:
PELROCK: Fixes credits not restarting
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index e6b91df562b..19c85ee504a 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1761,10 +1761,10 @@ void PelrockEngine::useWigWithPot(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
+ _state->removeInventoryItem(inventoryObject);
if(inventoryObject == 86) {
addInventoryItem(76);
}
- _state->removeInventoryItem(inventoryObject);
_state->setFlag(FLAG_FORMULA_MAGICA, _state->getFlag(FLAG_FORMULA_MAGICA) + 1);
if (_state->getFlag(FLAG_FORMULA_MAGICA) == 4) {
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index dd00c2f2f09..28ec71e66ec 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1873,8 +1873,7 @@ void PelrockEngine::walkTo(int x, int y) {
}
void PelrockEngine::walkAndAction(HotSpot *hotspot, VerbIcon action) {
- if(_currentHotspot == nullptr) {
- debug("Error: walkAndAction called with null hotspot");
+ if(hotspot == nullptr) {
return;
}
_disableAction = true;
@@ -2610,7 +2609,6 @@ void PelrockEngine::credits() {
CursorMan.showMouse(false);
// Outer restart loop â keypress during display restarts from page 0
- bool restart = false;
_alfredState.setState(ALFRED_SKIP_DRAWING);
_disableAmbientSounds = true;
_disableAction = true;
@@ -2679,7 +2677,7 @@ void PelrockEngine::credits() {
break;
}
}
- } while (restart && !shouldQuit() && !keyPressed);
+ } while (!shouldQuit() && !keyPressed);
g_engine->quitGame();
}
Commit: 1f06f642782cebf9ec5aee5bc3699191d7e6d374
https://github.com/scummvm/scummvm/commit/1f06f642782cebf9ec5aee5bc3699191d7e6d374
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:24+02:00
Commit Message:
PELROCK: Fixes credits changing color upon repeat
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 28ec71e66ec..aea025c45b4 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -2605,10 +2605,22 @@ void PelrockEngine::credits() {
static const int kFramesPerPage = 45;
Common::Array<Common::StringArray> creditTexts = _res->getCredits();
+ Common::Array<int> creditsSpeakerId;
+ // Preprocess credit texts: extract speaker IDs and apply word wrapping
+ for(int i = 0; i < creditTexts.size(); i++) {
+ byte speakerId;
+ _dialog->processColorAndTrim(creditTexts[i], speakerId);
+ creditsSpeakerId.push_back(speakerId);
+ // Text is already encoded for new lines but should also be wrapped to respect the max chars per line!
+ creditTexts[i] = _dialog->wordWrap(creditTexts[i])[0];
+ // all lines start with a space but the first one contains the trailing space of the speakerId
+ creditTexts[i][0] = creditTexts[i][0].substr(1, creditTexts[i][0].size() - 1);
+ }
CursorMan.showMouse(false);
// Outer restart loop â keypress during display restarts from page 0
+
_alfredState.setState(ALFRED_SKIP_DRAWING);
_disableAmbientSounds = true;
_disableAction = true;
@@ -2622,14 +2634,6 @@ void PelrockEngine::credits() {
pigeons->disableAfterSequence = true;
}
- byte speakerId;
- _dialog->processColorAndTrim(creditTexts[page], speakerId);
-
- // Text is already encoded for new lines but should also be wrapped to respect the max chars per line!
- creditTexts[page] = _dialog->wordWrap(creditTexts[page])[0];
- // all lines start with a space but the first one contains the trailing space of the speakerId
- creditTexts[page][0] = creditTexts[page][0].substr(1, creditTexts[page][0].size() - 1);
-
int height = creditTexts[page].size() * 25; // Add some padding
Graphics::Surface s;
@@ -2651,7 +2655,7 @@ void PelrockEngine::credits() {
// subtract that extra negative identation
int xPos = i == creditTexts[page].size() - 1 ? startX - 10 : startX;
int yPos = i * 25; // Above sprite, adjust for line
- g_engine->_largeFont->drawString(&s, creditTexts[page][i], xPos, yPos, 640, speakerId, Graphics::kTextAlignLeft);
+ g_engine->_largeFont->drawString(&s, creditTexts[page][i], xPos, yPos, 640, creditsSpeakerId[page], Graphics::kTextAlignLeft);
}
int frames = 0;
Commit: aa3c4639b8b7d88bc7365b27155d2ca281f21af1
https://github.com/scummvm/scummvm/commit/aa3c4639b8b7d88bc7365b27155d2ca281f21af1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:25+02:00
Commit Message:
PELROCK: Fixes removal of letter x in ingame texts
Changed paths:
engines/pelrock/resources.cpp
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index da9f1007cf0..504ca209d28 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -449,7 +449,7 @@ Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data,
pos++;
continue;
}
- if (data[pos] == 0x00 || data[pos] == 0x78) {
+ if (data[pos] == 0x00) {
pos++;
continue;
}
Commit: e482a187e1718b403ec9540b79c2c32038cb9f17
https://github.com/scummvm/scummvm/commit/e482a187e1718b403ec9540b79c2c32038cb9f17
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:25+02:00
Commit Message:
PELROCK: Fixes for end cutscene
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 19c85ee504a..37a8f82d90f 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1902,7 +1902,7 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
break;
}
case 375: {
- teletransportToPrincess();
+ teleportToPrincess();
break;
}
}
@@ -1935,7 +1935,7 @@ static void drawRemappedLine(byte *buf, int x0, int y0, int x1, int y1, const by
}
}
-void PelrockEngine::teletransportToPrincess() {
+void PelrockEngine::teleportToPrincess() {
int phase = 0;
int lines[5][4] = {
@@ -1948,7 +1948,6 @@ void PelrockEngine::teletransportToPrincess() {
int stickers[5] = {113, 114, 110, 111, 112};
while (phase < 5) {
- debug("Starting ending scene phase %d", phase);
Sprite *thisSprite = _room->findSpriteByIndex(phase + 1);
thisSprite->animData[0].curFrame = 0;
thisSprite->zOrder = 200;
@@ -1957,19 +1956,17 @@ void PelrockEngine::teletransportToPrincess() {
_events->pollEvent();
renderScene(OVERLAY_NONE);
_screen->update();
- g_system->delayMillis(10);
}
_sound->playSound(_room->_roomSfx[3], 0);
- // Draw 19 semi-transparent remapped lines (behind sprites, matching original)
- // Original uses shadow_palette_remap_tables[1] â _paletteRemaps[1] from ALFRED.9
+ // Draw 19 semi-transparent remapped lines
copyBackgroundToBuffer();
placeStickersFirstPass();
updateAnimations();
presentFrame();
_screen->update();
- g_system->delayMillis(10);
+
for (int i = 0; i < 19; i++) {
if (shouldQuit())
return;
@@ -1983,7 +1980,7 @@ void PelrockEngine::teletransportToPrincess() {
updateAnimations();
presentFrame();
_screen->update();
- g_system->delayMillis(10);
+
_events->pollEvent();
if (shouldQuit())
return;
@@ -1995,7 +1992,6 @@ void PelrockEngine::teletransportToPrincess() {
updateAnimations();
presentFrame();
_screen->update();
-
phase++;
}
// small delay before last sticker
@@ -2019,7 +2015,6 @@ void PelrockEngine::teletransportToPrincess() {
_dialog->say(_res->_ingameTexts[MAREDEDEU]);
- // endgameTransportAnimation();
smokeAnimation(-1, true);
_state->setFlag(FLAG_END_OF_GAME, true);
_state->setCurrentRoot(48, 1, 0);
@@ -2089,9 +2084,9 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
Spell *spell = spellBook.run();
if (spell) {
_alfredState.direction = ALFRED_LEFT;
- _dialog->say(_res->_ingameTexts[DIOSHALCON + spell->page], 1);
switch (_room->_currentRoomNumber) {
case 28: {
+ _dialog->say(_res->_ingameTexts[DIOSHALCON + spell->page], 1);
if (spell->page == 12) {
_graphics->clearScreen();
int waitFrames = 0;
@@ -2118,6 +2113,8 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
case 52:
case 53:
case 54: {
+ _sound->playSound(_room->_roomSfx[8], 0);
+ _dialog->say(_res->_ingameTexts[DIOSHALCON + spell->page], 1);
debug("Flight spell cast in room %d, spell page: %d", _room->_currentRoomNumber, spell->page);
int flightIndex = _room->_currentRoomNumber - 51;
debug("Correct page for this spell is = %d", kFlightRooms[flightIndex].spellPage);
@@ -2125,22 +2122,25 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_state->setFlag(FLAG_COMO_ESTAN_LOS_DIOSES, _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) | (1 << flightIndex));
debug("Flight spell successful, starting animation and updating state");
debug("Updated FLAG_COMO_ESTAN_LOS_DIOSES: %d", _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES));
+ _sound->playSound(_room->_roomSfx[1], 0);
smokeAnimation(kFlightRooms[flightIndex].spriteIdx, true);
_room->addStickerToRoom(_room->_currentRoomNumber, 127 + flightIndex);
- // if(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) == 0b1111) {
- HotSpot hotspot = HotSpot();
- hotspot.actionFlags = 0;
- hotspot.extra = 999;
- hotspot.x = 320;
- hotspot.y = 288;
- hotspot.w = 35;
- hotspot.h = 21;
- hotspot.innerIndex = 0;
- hotspot.index = 8;
- _room->changeHotspot(52, hotspot);
- // }
+ if(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) == 0b1111) {
+ HotSpot hotspot = HotSpot();
+ hotspot.actionFlags = 0;
+ hotspot.extra = 999;
+ hotspot.x = 320;
+ hotspot.y = 288;
+ hotspot.w = 35;
+ hotspot.h = 21;
+ hotspot.innerIndex = 0;
+ hotspot.index = 8;
+ _room->changeHotspot(52, hotspot);
+ }
+ }
+ else {
+ _sound->playSound(_room->_roomSfx[2], 0);
}
-
break;
}
default:
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index aea025c45b4..d69c571275d 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1798,7 +1798,7 @@ void PelrockEngine::gameLoop() {
}
if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_e && _room->_currentRoomNumber == 52) {
- teletransportToPrincess();
+ teleportToPrincess();
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 4ea450ae383..96286d5b569 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -403,7 +403,7 @@ public:
void openMcDoor(HotSpot *hotspot);
void closeMcDoor(HotSpot *hotspot);
void pickupBush(HotSpot *hotspot);
- void teletransportToPrincess();
+ void teleportToPrincess();
void animateStatuePaletteFade(bool reverse = false);
void pickUpMatches(HotSpot *hotspot);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index ff099f4faf3..2c52568a54b 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -1330,7 +1330,7 @@ Common::Array<byte> RoomManager::loadRoomSfx(Common::File *roomFile, int roomOff
for (int i = 0; i < kNumSfxPerRoom; i++) {
byte sfx = roomFile->readByte();
roomSfx[i] = sfx;
- // debug("SFX %d for room at offset %d is %d (%s)", i, roomOffset, sfx, SOUND_FILENAMES[sfx]);
+ debug("SFX %d for room at offset %d is %d (%s)", i, roomOffset, sfx, SOUND_FILENAMES[sfx]);
}
return roomSfx;
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 5257e5fadb0..a2c98b4dc72 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -29,7 +29,7 @@
namespace Pelrock {
-static const int kNumSfxPerRoom = 8;
+static const int kNumSfxPerRoom = 9;
static const int unpickableHotspotExtras[] = {
308, // lamppost cable
65, // objects in shop
Commit: 23093df6e0416c898754f20acac30ae8ddf3954f
https://github.com/scummvm/scummvm/commit/23093df6e0416c898754f20acac30ae8ddf3954f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:25+02:00
Commit Message:
PELROCK: General code cleanup
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/events.h
engines/pelrock/graphics.cpp
engines/pelrock/offsets.h
engines/pelrock/pathfinding.cpp
engines/pelrock/pathfinding.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/types.h
engines/pelrock/util.cpp
engines/pelrock/util.h
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 37a8f82d90f..0defabc6729 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1135,7 +1135,7 @@ void PelrockEngine::useSecretCodeWithStatue(int inventoryObject, HotSpot *hotspo
void PelrockEngine::pickUpLetter(HotSpot *hotspot) {
addInventoryItem(9);
- _room->setActionMask(hotspot, ACTION_MASK_NONE); // Disable hotspot
+ _room->setActionMask(hotspot, kActionMaskNone); // Disable hotspot
}
void PelrockEngine::openLibraryOutdoorsDoor(HotSpot *hotspot) {
@@ -1885,14 +1885,14 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
break;
case 294: {
HotSpot *floorTile = _room->findHotspotByExtra(462);
- floorTile->actionFlags = ACTION_MASK_OPEN;
+ floorTile->actionFlags = kActionMaskOpen;
_room->changeHotSpot(*floorTile);
break;
}
case 307: {
HotSpot *stone = _room->findHotspotByExtra(90);
- stone->actionFlags = ACTION_MASK_PICKUP;
+ stone->actionFlags = kActionMaskPickup;
_room->changeHotSpot(*stone);
break;
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 5cc7535edcf..9b0bd49770d 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -47,7 +47,7 @@ uint32 DialogManager::readTextBlock(
byte &outSpeakerId) {
uint32 pos = startPos;
- outSpeakerId = ALFRED_COLOR; // Default to Alfred's color
+ outSpeakerId = kAlfredColor; // Default to Alfred's color
outText = "";
// Skip control bytes at start
@@ -75,7 +75,7 @@ uint32 DialogManager::readTextBlock(
pos++;
}
// Choice text is always spoken by ALFRED
- outSpeakerId = ALFRED_COLOR;
+ outSpeakerId = kAlfredColor;
pos += 2;
}
@@ -162,7 +162,7 @@ Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String
int maxWidth = 0;
int height = dialogueLines.size() * 25; // Add some padding
- for (int i = 0; i < dialogueLines.size(); i++) {
+ for (uint i = 0; i < dialogueLines.size(); i++) {
maxWidth = MAX(maxWidth, g_engine->_largeFont->getStringWidth(dialogueLines[i]));
}
@@ -170,7 +170,7 @@ Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String
s.create(maxWidth + 1, height + 1, Graphics::PixelFormat::createFormatCLUT8());
s.fillRect(s.getRect(), 255); // Clear surface
- for (int i = 0; i < dialogueLines.size(); i++) {
+ for (uint i = 0; i < dialogueLines.size(); i++) {
int xPos = 0;
int yPos = i * 25; // Above sprite, adjust for line
@@ -184,7 +184,7 @@ Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String
void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>> dialogueLines, byte speakerId) {
int16 xBasePos = 0;
int16 yBasePos = 0;
- if (speakerId == ALFRED_COLOR) {
+ if (speakerId == kAlfredColor) {
if (g_engine->_state->getFlag(FLAG_FROM_INTRO) == true) {
debug("Setting special anim");
g_engine->_alfredState.setState(ALFRED_SPECIAL_ANIM);
@@ -238,7 +238,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int maxWidth = 0;
int height = textLines.size() * 24;
- for (int i = 0; i < textLines.size(); i++) {
+ for (uint i = 0; i < textLines.size(); i++) {
maxWidth = MAX(maxWidth, g_engine->_largeFont->getStringWidth(textLines[i]));
}
@@ -859,7 +859,7 @@ uint32 DialogManager::processChoiceSelection(
state.lastSelectedChoice = (*choices)[selectedIndex];
if (state.lastSelectedChoice.isTerminator) {
- displayDialogue(state.lastSelectedChoice.text, ALFRED_COLOR);
+ displayDialogue(state.lastSelectedChoice.text, kAlfredColor);
return dataSize; // End conversation
}
@@ -872,7 +872,7 @@ uint32 DialogManager::processChoiceSelection(
uint32 endPos = readTextBlock(data, dataSize, position, choiceText, choiceSpeakerId);
if (!choiceText.empty() && choiceText.size() > 1) {
- displayDialogue(choiceText, ALFRED_COLOR);
+ displayDialogue(choiceText, kAlfredColor);
debug("Will check if choice should be disabled after displaying dialogue");
disableChoiceIfNeeded(choices, selectedIndex, data, dataSize, endPos, state);
}
@@ -988,7 +988,7 @@ void DialogManager::sayAlfred(Common::StringArray texts) {
_curSprite = nullptr;
Common::Array<Common::StringArray> textLines = wordWrap(texts);
- displayDialogue(textLines, ALFRED_COLOR);
+ displayDialogue(textLines, kAlfredColor);
}
void DialogManager::sayAlfred(Description description) {
@@ -1009,7 +1009,7 @@ void DialogManager::say(Common::StringArray texts, byte spriteIndex) {
bool wasProcessed = processColorAndTrim(texts, speakerId);
if (wasProcessed) {
- if (speakerId == ALFRED_COLOR) {
+ if (speakerId == kAlfredColor) {
sayAlfred(texts);
return;
} else {
@@ -1043,7 +1043,7 @@ bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speake
speakerId = lines[0][1];
if (speakerMarker == '@') {
- for (int i = 0; i < lines.size(); i++) {
+ for (uint i = 0; i < lines.size(); i++) {
// Remove first two marker bytes
if (i == 0) {
if (lines[i].size() > 2) {
@@ -1064,7 +1064,7 @@ bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speake
return false;
}
-bool isEndMarker(unsigned char char_byte) {
+bool isEndMarker(byte char_byte) {
return char_byte == CTRL_END_TEXT || char_byte == CTRL_END_CONVERSATION || char_byte == CTRL_ACTION_AND_END || char_byte == CTRL_GO_BACK;
}
@@ -1084,7 +1084,7 @@ int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
isEnd = true;
}
if (pos < text.size() && !isEnd) {
- if (text[pos] == CTRL_ACTION_AND_END) { // 0xF8 (-8) special case
+ if ((byte)text[pos] == CTRL_ACTION_AND_END) { // 0xF8 (-8) special case
wordLength += 3;
} else {
// Count all consecutive spaces
@@ -1101,7 +1101,7 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
Common::Array<Common::Array<Common::String>> pages;
Common::Array<Common::String> currentPage;
Common::Array<Common::String> currentLine;
- int charsRemaining = MAX_CHARS_PER_LINE;
+ int charsRemaining = kMaxCharsPerLine;
int position = 0;
int currentLineNum = 0;
while (position < text.size()) {
@@ -1114,10 +1114,10 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
// Word is longer than the entire line - need to split
currentPage.push_back(joinStrings(currentLine, ""));
currentLine.clear();
- charsRemaining = MAX_CHARS_PER_LINE;
+ charsRemaining = kMaxCharsPerLine;
currentLineNum++;
- if (currentLineNum >= MAX_LINES) {
+ if (currentLineNum >= kMaxLines) {
pages.push_back(currentPage);
currentPage.clear();
currentLineNum = 0;
@@ -1137,10 +1137,10 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
currentPage.push_back(lineText);
// current_line = [' ' * trailing_spaces]
Common::String current_line(trailingSpaces, ' ');
- charsRemaining = MAX_CHARS_PER_LINE - trailingSpaces;
+ charsRemaining = kMaxCharsPerLine - trailingSpaces;
currentLineNum += 1;
- if (currentLineNum >= MAX_LINES) {
+ if (currentLineNum >= kMaxLines) {
pages.push_back(currentPage);
currentPage.clear();
currentLineNum = 0;
@@ -1193,7 +1193,7 @@ Common::Array<Common::StringArray> DialogManager::wordWrap(Common::StringArray t
debug("Wrapped line %s, %d into %d pages", thisLine.c_str(), thisLine.size(), wrapped.size());
for (uint j = 0; j < wrapped.size(); j++) {
for (int k = 0; k < wrapped[j].size(); k++) {
- if (currentLineNum < MAX_LINES) {
+ if (currentLineNum < kMaxLines) {
currentPage.push_back(wrapped[j][k]);
currentLineNum++;
} else {
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 51e98d0f1dd..568d596b61f 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -37,20 +37,36 @@ namespace Pelrock {
// Control character codes (negative values in signed char)
#define CHAR_SPACE 0x20 /* ' ' */
#define CTRL_SPEAKER_ID 0x08 /* Next byte is speaker ID (color) */
-#define CTRL_END_TEXT 0xFD /* End of text segment */
-#define CTRL_TEXT_TERMINATOR 0xFC /* Text terminator */
-#define CTRL_DIALOGUE_MARKER 0xF1 /* Choice marker that sticks */
-#define CTRL_DISABLED_CHOICE 0xFA /* Disabled choice marker */
-#define CTRL_PAGE_BREAK_CONV 0xF9 /* Page break in conversation */
-#define CTRL_ACTION_AND_END 0xF8 /* Action trigger */
-#define CTRL_END_BRANCH 0xF7 /* End of branch */
-#define CTRL_LINE_CONTINUE 0xF6 /* Line continue/newline */
-#define CTRL_ALT_END_MARKER_1 0xF5 /* Alt end marker - do nothing */
-#define CTRL_END_CONVERSATION 0xF4 /* End conversation and disable option */
-#define CTRL_DIALOGUE_MARKER_ONEOFF 0xFB /* Alt choice marker that disappears */
-#define CTRL_GO_BACK 0xF0 /* Go back in conversation */
-#define CTRL_ACTION_AND_CONTINUE 0xEB /* Action-and-continue: dispatch action, conversation keeps going (unlike 0xF8 which exits) */
-#define CTRL_ALT_SPEAKER_ROOT 0xFE /* Separates conversations from different speakers */
+const byte kCtrlEndText = 0xFD; /* End of text segment */
+const byte kCtrlTextTerminator = 0xFC; /* Text terminator */
+const byte kCtrlDialogueMarker = 0xF1; /* Choice marker that sticks */
+const byte kCtrlDisabledChoice = 0xFA; /* Disabled choice marker */
+const byte kCtrlPageBreakConv = 0xF9; /* Page break in conversation */
+const byte kCtrlActionAndEnd = 0xF8; /* Action trigger */
+const byte kCtrlEndBranch = 0xF7; /* End of branch */
+const byte kCtrlLineContinue = 0xF6; /* Line continue/newline */
+const byte kCtrlAltEndMarker1 = 0xF5; /* Alt end marker - do nothing */
+const byte kCtrlEndConversation = 0xF4; /* End conversation and disable option */
+const byte kCtrlDialogueMarkerOneoff = 0xFB; /* Alt choice marker that disappears */
+const byte kCtrlGoBack = 0xF0; /* Go back in conversation */
+const byte kCtrlActionAndContinue = 0xEB; /* Action-and-continue: dispatch action, conversation keeps going (unlike 0xF8 which exits) */
+const byte kCtrlAltSpeakerRoot = 0xFE; /* Separates conversations from different speakers */
+
+// Keep old names as aliases for compatibility
+#define CTRL_END_TEXT kCtrlEndText
+#define CTRL_TEXT_TERMINATOR kCtrlTextTerminator
+#define CTRL_DIALOGUE_MARKER kCtrlDialogueMarker
+#define CTRL_DISABLED_CHOICE kCtrlDisabledChoice
+#define CTRL_PAGE_BREAK_CONV kCtrlPageBreakConv
+#define CTRL_ACTION_AND_END kCtrlActionAndEnd
+#define CTRL_END_BRANCH kCtrlEndBranch
+#define CTRL_LINE_CONTINUE kCtrlLineContinue
+#define CTRL_ALT_END_MARKER_1 kCtrlAltEndMarker1
+#define CTRL_END_CONVERSATION kCtrlEndConversation
+#define CTRL_DIALOGUE_MARKER_ONEOFF kCtrlDialogueMarkerOneoff
+#define CTRL_GO_BACK kCtrlGoBack
+#define CTRL_ACTION_AND_CONTINUE kCtrlActionAndContinue
+#define CTRL_ALT_SPEAKER_ROOT kCtrlAltSpeakerRoot
// Helper structures for conversation state management
struct ConversationState {
diff --git a/engines/pelrock/events.h b/engines/pelrock/events.h
index fe25ba04382..6b2c54a700c 100644
--- a/engines/pelrock/events.h
+++ b/engines/pelrock/events.h
@@ -41,8 +41,8 @@ public:
bool _longClicked = false;
bool _rightMouseClicked = false;
bool _popupSelectionMode = false;
- bool _leftMouseButton = 0;
- bool _rightMouseButton = 0;
+ bool _leftMouseButton = false;
+ bool _rightMouseButton = false;
Common::KeyCode _lastKeyEvent = Common::KEYCODE_INVALID;
PelrockEventManager();
void pollEvent();
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index d0c1c79b1eb..062de9031bb 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -210,7 +210,7 @@ void GraphicsManager::drawColoredTexts(Graphics::ManagedSurface *surface, const
int currentX = x;
byte currentColor = 255;
- for(int i =0; i < text.size(); i++) {
+ for (uint i = 0; i < text.size(); i++) {
drawColoredText(surface, text[i], currentX, y + i * (font->getFontHeight() + yPadding), w, currentColor, font);
}
}
@@ -219,7 +219,7 @@ void GraphicsManager::drawColoredTexts(Graphics::ManagedSurface &buf, const Comm
int currentX = x;
byte currentColor = 255;
- for(int i =0; i < text.size(); i++) {
+ for (uint i = 0; i < text.size(); i++) {
drawColoredText(buf, text[i], currentX, y + i * (font->getFontHeight() + yPadding), w, currentColor, font);
}
}
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 05f5a82f24f..1a2da8ac59f 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -25,25 +25,25 @@
namespace Pelrock {
-static const uint32_t cursor_offsets[5] = {
+static const uint32 cursor_offsets[5] = {
0x0FDDFD,
0x0FDCDD,
0x0FDF1D,
0x0FE33D,
0x367EF0};
-static const uint32_t kBalloonFramesOffset = 2176936;
-static const uint32_t kBalloonFramesSize = 24950;
+static const uint32 kBalloonFramesOffset = 2176936;
+static const uint32 kBalloonFramesSize = 24950;
-static const uint32_t ALFRED7_ALFRED_COMB_R = 67768;
-static const uint32_t ALFRED7_ALFRED_COMB_L = 88408;
+static const uint32 ALFRED7_ALFRED_COMB_R = 67768;
+static const uint32 ALFRED7_ALFRED_COMB_L = 88408;
-static const uint32_t kAlternateSettingsMenuOffset = 910097;
-static const uint32_t kAlternateSettingsPaletteOffset = 1038141; // 640 * 480
-static const uint32_t kSettingsPaletteOffset = 0x2884c2; // 640 * 480
+static const uint32 kAlternateSettingsMenuOffset = 910097;
+static const uint32 kAlternateSettingsPaletteOffset = 1038141; // 640 * 480
+static const uint32 kSettingsPaletteOffset = 0x2884c2; // 640 * 480
-#define DESCRIPTION_BASE_OFFSET 0x4715D
-#define NUM_DESCRIPTIONS 113
+const uint32 kDescriptionBaseOffset = 0x4715D;
+const uint16 kNumDescriptions = 113;
static const uint32 kInventoryDescriptionsOffset = 0x4715E;
static const uint32 kInventoryDescriptionsSize = 7868;
@@ -55,7 +55,7 @@ static const uint32 kAlfredResponsesSize = 12143;
static const uint32 kCreditsOffset = 0x49F60;
static const uint32 kCreditsSize = 2540;
-const uint32_t pegatina_offsets[137] = {
+static const uint32 pegatina_offsets[137] = {
0x000000, 0x00005B, 0x0000B6, 0x000298, 0x00047A, 0x0023C8, 0x004316, 0x004376,
0x005119, 0x005EBC, 0x0083ED, 0x008529, 0x0092C4, 0x00A3AA, 0x00B490, 0x00B6A6,
0x00C05A, 0x00CA0E, 0x00D3D0, 0x00D46E, 0x00F036, 0x00FB8F, 0x00FC55, 0x0119D7,
@@ -75,7 +75,7 @@ const uint32_t pegatina_offsets[137] = {
0x07ECED, 0x07F52F, 0x07FD71, 0x080591, 0x080B24, 0x080B84, 0x080F39, 0x0812F5,
0x0816B1};
-const byte pegatina_rooms[140] = {
+static const byte pegatina_rooms[140] = {
0, 0, 0, 0, 0, 0, 0, // Sprites 0-6: Room 0
2, 2, // Sprites 7-8: Room 2
3, 3, 3, 3, 3, 3, 3, 3, // Sprites 9-16: Room 3
@@ -319,8 +319,8 @@ enum TextIndices {
LASPUERTAS_DELCIELO,
};
-// Description offsets relative to DESCRIPTION_BASE_OFFSET
-const uint16_t description_offsets[NUM_DESCRIPTIONS] = {
+// Description offsets relative to kDescriptionBaseOffset
+static const uint16 description_offsets[kNumDescriptions] = {
0x0000, // Object 0: Historia de la Princesa Zenna y su amante insatisfecho
0x0058, // Object 1: Nombre: Alfred Pelrock
0x00C4, // Object 2: La tipica tarjeta por la que te sacan commisiones
@@ -444,7 +444,7 @@ struct ExtraImages {
byte numChunks;
};
-const ExtraImages extraScreens[] = {
+static const ExtraImages extraScreens[] = {
{0x00, // 0 - Portrait above bed
0x7984,
8},
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
index e7a89c34818..b1dfdeb790c 100644
--- a/engines/pelrock/pathfinding.cpp
+++ b/engines/pelrock/pathfinding.cpp
@@ -27,24 +27,24 @@
namespace Pelrock {
-Common::String printMovementFlags(uint8_t flags) {
+Common::String printMovementFlags(byte flags) {
Common::String result;
- if (flags & MOVE_HORIZ) {
+ if (flags & kMoveHoriz) {
result += "HORIZ ";
}
- if (flags & MOVE_VERT) {
+ if (flags & kMoveVert) {
result += "VERT ";
}
- if (flags & MOVE_DOWN) {
+ if (flags & kMoveDown) {
result += "DOWN ";
}
- if (flags & MOVE_LEFT) {
+ if (flags & kMoveLeft) {
result += "LEFT ";
}
- if (flags & MOVE_UP) {
+ if (flags & kMoveUp) {
result += "UP ";
}
- if (flags & MOVE_RIGHT) {
+ if (flags & kMoveRight) {
result += "RIGHT ";
}
return result;
@@ -52,11 +52,11 @@ Common::String printMovementFlags(uint8_t flags) {
bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<WalkBox> &walkboxes, PathContext *context, HotSpot *hotspot) {
- if (context->pathBuffer == NULL) {
- context->pathBuffer = (uint8_t *)malloc(MAX_PATH_LENGTH);
+ if (context->pathBuffer == nullptr) {
+ context->pathBuffer = (byte *)malloc(kMaxPathLength);
}
- if (context->movementBuffer == NULL) {
- context->movementBuffer = (MovementStep *)malloc(MAX_MOVEMENT_STEPS * sizeof(MovementStep));
+ if (context->movementBuffer == nullptr) {
+ context->movementBuffer = (MovementStep *)malloc(kMaxMovementSteps * sizeof(MovementStep));
}
int startX = sourceX;
@@ -66,8 +66,8 @@ bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<
targetY = target.y;
// debug("Startx= %d, starty= %d, destx= %d, desty= %d", startX, startY, targetX, targetY);
- uint8_t startBox = findWalkboxForPoint(walkboxes, startX, startY);
- uint8_t destBox = findWalkboxForPoint(walkboxes, targetX, targetY);
+ byte startBox = findWalkboxForPoint(walkboxes, startX, startY);
+ byte destBox = findWalkboxForPoint(walkboxes, targetX, targetY);
// debug("Pathfinding from (%d, %d) in box %d to (%d, %d) in box %d\n", startX, startY, startBox, targetX, targetY, destBox);
// Check if both points are in valid walkboxes
@@ -82,18 +82,18 @@ bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<
direct_step.flags = 0;
if (startX < targetX) {
direct_step.distanceX = targetX - startX;
- direct_step.flags |= MOVE_RIGHT;
+ direct_step.flags |= kMoveRight;
} else {
direct_step.distanceX = startX - targetX;
- direct_step.flags |= MOVE_LEFT;
+ direct_step.flags |= kMoveLeft;
}
if (startY < targetY) {
direct_step.distanceY = targetY - startY;
- direct_step.flags |= MOVE_DOWN;
+ direct_step.flags |= kMoveDown;
} else {
direct_step.distanceY = startY - targetY;
- direct_step.flags |= MOVE_UP;
+ direct_step.flags |= kMoveUp;
}
context->movementBuffer[0] = direct_step;
@@ -193,8 +193,8 @@ Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes,
return target;
}
-uint8_t findWalkboxForPoint(Common::Array<WalkBox> &walkboxes, uint16_t x, uint16_t y) {
- for (uint8_t i = 0; i < walkboxes.size(); i++) {
+byte findWalkboxForPoint(Common::Array<WalkBox> &walkboxes, uint16 x, uint16 y) {
+ for (byte i = 0; i < walkboxes.size(); i++) {
if (isPointInWalkbox(&walkboxes[i], x, y)) {
return i;
}
@@ -202,7 +202,7 @@ uint8_t findWalkboxForPoint(Common::Array<WalkBox> &walkboxes, uint16_t x, uint1
return 0xFF; // Not found
}
-bool isPointInWalkbox(WalkBox *box, uint16_t x, uint16_t y) {
+bool isPointInWalkbox(WalkBox *box, uint16 x, uint16 y) {
return (x >= box->x &&
x <= box->x + box->w &&
y >= box->y &&
@@ -213,10 +213,10 @@ bool isPointInWalkbox(WalkBox *box, uint16_t x, uint16_t y) {
* Check if two walkboxes overlap or touch (are adjacent)
*/
bool areWalkboxesAdjacent(WalkBox *box1, WalkBox *box2) {
- uint16_t box1_x_max = box1->x + box1->w;
- uint16_t box1_y_max = box1->y + box1->h;
- uint16_t box2_x_max = box2->x + box2->w;
- uint16_t box2_y_max = box2->y + box2->h;
+ uint16 box1_x_max = box1->x + box1->w;
+ uint16 box1_y_max = box1->y + box1->h;
+ uint16 box2_x_max = box2->x + box2->w;
+ uint16 box2_y_max = box2->y + box2->h;
// Check if X ranges overlap
bool xOverlap = (box1->x <= box2_x_max) && (box2->x <= box1_x_max);
@@ -227,14 +227,14 @@ bool areWalkboxesAdjacent(WalkBox *box1, WalkBox *box2) {
return xOverlap && yOverlap;
}
-uint8_t getAdjacentWalkbox(Common::Array<WalkBox> &walkboxes, uint8_t currentBoxIndex) {
+byte getAdjacentWalkbox(Common::Array<WalkBox> &walkboxes, byte currentBoxIndex) {
WalkBox *currentBox = &walkboxes[currentBoxIndex];
// Mark current walkbox as visited
currentBox->flags = 0x01;
// Search for adjacent unvisited walkbox
- for (uint8_t i = 0; i < walkboxes.size(); i++) {
+ for (byte i = 0; i < walkboxes.size(); i++) {
// Skip current walkbox
if (i == currentBoxIndex) {
continue;
@@ -260,10 +260,10 @@ void clearVisitedFlags(Common::Array<WalkBox> &walkboxes) {
}
}
-uint16_t buildWalkboxPath(Common::Array<WalkBox> &walkboxes, uint8_t startBox, uint8_t destBox, uint8_t *pathBuffer) {
+uint16 buildWalkboxPath(Common::Array<WalkBox> &walkboxes, byte startBox, byte destBox, byte *pathBuffer) {
- uint16_t pathIndex = 0;
- uint8_t currentBox = startBox;
+ uint16 pathIndex = 0;
+ byte currentBox = startBox;
// Initialize path with start walkbox
pathBuffer[pathIndex++] = startBox;
@@ -272,8 +272,8 @@ uint16_t buildWalkboxPath(Common::Array<WalkBox> &walkboxes, uint8_t startBox, u
clearVisitedFlags(walkboxes);
// Breadth-first search through walkboxes
- while (currentBox != destBox && pathIndex < MAX_PATH_LENGTH - 1) {
- uint8_t nextBox = getAdjacentWalkbox(walkboxes, currentBox);
+ while (currentBox != destBox && pathIndex < kMaxPathLength - 1) {
+ byte nextBox = getAdjacentWalkbox(walkboxes, currentBox);
if (nextBox == 0xFF) {
// Dead end - backtrack
@@ -296,7 +296,7 @@ uint16_t buildWalkboxPath(Common::Array<WalkBox> &walkboxes, uint8_t startBox, u
}
// Terminate path
- pathBuffer[pathIndex] = PATH_END;
+ pathBuffer[pathIndex] = kPathEnd;
debug("Built walkbox path of length %d", pathIndex);
return pathIndex;
}
@@ -304,7 +304,7 @@ uint16_t buildWalkboxPath(Common::Array<WalkBox> &walkboxes, uint8_t startBox, u
/**
* Calculate movement needed to reach a target within a walkbox
*/
-void calculateMovementToTarget(uint16_t currentX, uint16_t currentY, uint16_t targetX, uint16_t targetY, WalkBox *box, MovementStep *step) {
+void calculateMovementToTarget(uint16 currentX, uint16 currentY, uint16 targetX, uint16 targetY, WalkBox *box, MovementStep *step) {
step->flags = 0;
step->distanceX = 0;
step->distanceY = 0;
@@ -313,22 +313,22 @@ void calculateMovementToTarget(uint16_t currentX, uint16_t currentY, uint16_t ta
if (currentX < box->x) {
// Need to move right to enter walkbox
step->distanceX = box->x - currentX;
- step->flags |= MOVE_RIGHT;
+ step->flags |= kMoveRight;
} else if (currentX > box->x + box->w) {
// Need to move left to enter walkbox
step->distanceX = currentX - (box->x + box->w);
- step->flags |= MOVE_LEFT;
+ step->flags |= kMoveLeft;
}
// Calculate vertical movement
if (currentY < box->y) {
// Need to move down to enter walkbox
step->distanceY = box->y - currentY;
- step->flags |= MOVE_DOWN;
+ step->flags |= kMoveDown;
} else if (currentY > box->y + box->h) {
// Need to move up to enter walkbox
step->distanceY = currentY - (box->y + box->h);
- step->flags |= MOVE_UP;
+ step->flags |= kMoveUp;
}
}
@@ -336,19 +336,19 @@ void calculateMovementToTarget(uint16_t currentX, uint16_t currentY, uint16_t ta
* Generate movement steps from walkbox path
* Returns: number of movement steps generated
*/
-uint16_t generateMovementSteps(Common::Array<WalkBox> &walkboxes,
- uint8_t *pathBuffer,
- uint16_t pathLength,
- uint16_t startX, uint16_t startY,
- uint16_t destX, uint16_t destY,
+uint16 generateMovementSteps(Common::Array<WalkBox> &walkboxes,
+ byte *pathBuffer,
+ uint16 pathLength,
+ uint16 startX, uint16 startY,
+ uint16 destX, uint16 destY,
MovementStep *movementBuffer) {
- uint16_t currentX = startX;
- uint16_t currentY = startY;
- uint16_t movementIndex = 0;
+ uint16 currentX = startX;
+ uint16 currentY = startY;
+ uint16 movementIndex = 0;
// Generate movements for each walkbox in path
- for (uint16_t i = 0; i < pathLength && pathBuffer[i] != PATH_END; i++) {
- uint8_t boxIndex = pathBuffer[i];
+ for (uint16 i = 0; i < pathLength && pathBuffer[i] != kPathEnd; i++) {
+ byte boxIndex = pathBuffer[i];
WalkBox *box = &walkboxes[boxIndex];
MovementStep step;
@@ -358,15 +358,15 @@ uint16_t generateMovementSteps(Common::Array<WalkBox> &walkboxes,
movementBuffer[movementIndex++] = step;
// Update current position
- if (step.flags & MOVE_RIGHT) {
+ if (step.flags & kMoveRight) {
currentX = box->x;
- } else if (step.flags & MOVE_LEFT) {
+ } else if (step.flags & kMoveLeft) {
currentX = box->x + box->w;
}
- if (step.flags & MOVE_DOWN) {
+ if (step.flags & kMoveDown) {
currentY = box->y;
- } else if (step.flags & MOVE_UP) {
+ } else if (step.flags & kMoveUp) {
currentY = box->y + box->h;
}
}
@@ -378,20 +378,20 @@ uint16_t generateMovementSteps(Common::Array<WalkBox> &walkboxes,
if (currentX < destX) {
final_step.distanceX = destX - currentX;
- final_step.flags |= MOVE_RIGHT;
+ final_step.flags |= kMoveRight;
} else if (currentX > destX) {
final_step.distanceX = currentX - destX;
- final_step.flags |= MOVE_LEFT;
+ final_step.flags |= kMoveLeft;
} else {
final_step.distanceX = 0;
}
if (currentY < destY) {
final_step.distanceY = destY - currentY;
- final_step.flags |= MOVE_DOWN;
+ final_step.flags |= kMoveDown;
} else if (currentY > destY) {
final_step.distanceY = currentY - destY;
- final_step.flags |= MOVE_UP;
+ final_step.flags |= kMoveUp;
} else {
final_step.distanceY = 0;
}
diff --git a/engines/pelrock/pathfinding.h b/engines/pelrock/pathfinding.h
index 6b7a3a628ef..f6f3d2c1063 100644
--- a/engines/pelrock/pathfinding.h
+++ b/engines/pelrock/pathfinding.h
@@ -39,11 +39,11 @@ bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<
* @return Calculated walk target point.
*/
Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes, int sourceX, int sourceY, bool mouseHoverState, HotSpot *hotspot);
-uint8_t findWalkboxForPoint(Common::Array<WalkBox> &walkboxes, uint16_t x, uint16_t y);
-uint8_t getAdjacentWalkbox(Common::Array<WalkBox> &walkboxes, uint8_t current_box_index);
-uint16_t buildWalkboxPath(Common::Array<WalkBox> &walkboxes, uint8_t start_box, uint8_t dest_box, uint8_t *path_buffer);
-uint16_t generateMovementSteps(Common::Array<WalkBox> &walkboxes, uint8_t *path_buffer, uint16_t path_length, uint16_t start_x, uint16_t start_y, uint16_t dest_x, uint16_t dest_y, MovementStep *movement_buffer);
-bool isPointInWalkbox(WalkBox *box, uint16_t x, uint16_t y);
+byte findWalkboxForPoint(Common::Array<WalkBox> &walkboxes, uint16 x, uint16 y);
+byte getAdjacentWalkbox(Common::Array<WalkBox> &walkboxes, byte current_box_index);
+uint16 buildWalkboxPath(Common::Array<WalkBox> &walkboxes, byte start_box, byte dest_box, byte *path_buffer);
+uint16 generateMovementSteps(Common::Array<WalkBox> &walkboxes, byte *path_buffer, uint16 path_length, uint16 start_x, uint16 start_y, uint16 dest_x, uint16 dest_y, MovementStep *movement_buffer);
+bool isPointInWalkbox(WalkBox *box, uint16 x, uint16 y);
void clearVisitedFlags(Common::Array<WalkBox> &walkboxes);
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index d69c571275d..e1a594d3234 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -71,6 +71,14 @@ PelrockEngine::~PelrockEngine() {
delete _dialog;
delete _menu;
delete _graphics;
+ delete _state;
+ delete[] _alfredSprite;
+ delete[] _inventoryOverlayState.arrows[0];
+ delete[] _inventoryOverlayState.arrows[1];
+ // Free path-finding buffers (allocated via malloc in findPath)
+ free(_currentContext.pathBuffer);
+ free(_currentContext.movementBuffer);
+ free(_currentContext.compressed_path);
}
uint32 PelrockEngine::getFeatures() const {
@@ -196,25 +204,25 @@ Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
Common::Array<VerbIcon> verbs;
verbs.push_back(LOOK);
- if (hotspot->actionFlags & ACTION_MASK_OPEN) {
+ if (hotspot->actionFlags & kActionMaskOpen) {
verbs.push_back(OPEN);
}
- if (hotspot->actionFlags & ACTION_MASK_CLOSE) {
+ if (hotspot->actionFlags & kActionMaskClose) {
verbs.push_back(CLOSE);
}
- if (hotspot->actionFlags & ACTION_MASK_UNKNOWN) {
+ if (hotspot->actionFlags & kActionMaskUnknown) {
verbs.push_back(UNKNOWN);
}
- if (hotspot->actionFlags & ACTION_MASK_PICKUP) {
+ if (hotspot->actionFlags & kActionMaskPickup) {
verbs.push_back(PICKUP);
}
- if (hotspot->actionFlags & ACTION_MASK_TALK) {
+ if (hotspot->actionFlags & kActionMaskTalk) {
verbs.push_back(TALK);
}
- if (hotspot->actionFlags & ACTION_MASK_PUSH) {
+ if (hotspot->actionFlags & kActionMaskPush) {
verbs.push_back(PUSH);
}
- if (hotspot->actionFlags & ACTION_MASK_PULL) {
+ if (hotspot->actionFlags & kActionMaskPull) {
verbs.push_back(PULL);
}
return verbs;
@@ -356,7 +364,7 @@ bool PelrockEngine::renderScene(int overlayMode) {
void PelrockEngine::mouseHoverForMap() {
if (_room->_currentRoomNumber == 21 && !_hoveredMapLocation.empty()) {
Common::Rect r = _largeFont->getBoundingBox(_hoveredMapLocation.c_str());
- drawText(_compositeBuffer, _largeFont, _hoveredMapLocation.c_str(), _events->_mouseX - r.width() / 2, _events->_mouseY - r.height(), 640, ALFRED_COLOR);
+ drawText(_compositeBuffer, _largeFont, _hoveredMapLocation.c_str(), _events->_mouseX - r.width() / 2, _events->_mouseY - r.height(), 640, kAlfredColor);
}
}
@@ -457,7 +465,7 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
int startY = anim.startY;
// debug("Checking passerby anim %d for sprite %d, direction %d", _room->_passerByAnims->currentAnimIndex, spriteIndex, direction);
Sprite *sprite = _room->findSpriteByIndex(spriteIndex);
- if (direction == PASSERBY_RIGHT) {
+ if (direction == kPasserbyRight) {
// debug("Checking passerby anim for sprite %d moving RIGHT, curpos is %d", spriteIndex, sprite->x);
if (sprite->x >= anim.resetCoord) {
sprite->x = startX;
@@ -467,7 +475,7 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
sprite->animData[0].curFrame = 0;
_room->_passerByAnims->latch = false;
}
- } else if (direction == PASSERBY_LEFT) {
+ } else if (direction == kPasserbyLeft) {
// debug("Checking passerby anim for sprite %d moving LEFT, curpos is %d", spriteIndex, sprite->x);
if (sprite->x <= anim.resetCoord) {
@@ -478,7 +486,7 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
sprite->animData[0].curFrame = 0;
_room->_passerByAnims->latch = false;
}
- } else if (direction == PASSERBY_DOWN) {
+ } else if (direction == kPasserbyDown) {
// debug("Checking passerby anim for sprite %d moving DOWN, curpos is %d, reset %d", spriteIndex, sprite->y, anim.resetCoord);
if (sprite->y >= anim.resetCoord) {
sprite->x = startX;
@@ -939,21 +947,21 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
case ALFRED_WALKING: {
MovementStep step = _currentContext.movementBuffer[_currentStep];
if (step.distanceX > 0) {
- if (step.flags & MOVE_RIGHT) {
+ if (step.flags & kMoveRight) {
_alfredState.direction = ALFRED_RIGHT;
_alfredState.x += MIN(_alfredState.movementSpeedX, step.distanceX);
}
- if (step.flags & MOVE_LEFT) {
+ if (step.flags & kMoveLeft) {
_alfredState.direction = ALFRED_LEFT;
_alfredState.x -= MIN(_alfredState.movementSpeedX, step.distanceX);
}
}
if (step.distanceY > 0) {
- if (step.flags & MOVE_DOWN) {
+ if (step.flags & kMoveDown) {
_alfredState.direction = ALFRED_DOWN;
_alfredState.y += MIN(_alfredState.movementSpeedY, step.distanceY);
}
- if (step.flags & MOVE_UP) {
+ if (step.flags & kMoveUp) {
_alfredState.direction = ALFRED_UP;
_alfredState.y -= MIN(_alfredState.movementSpeedY, step.distanceY);
}
@@ -1286,7 +1294,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
}
-void applyMovement(int16_t *x, int16_t *y, int8_t *z, uint16_t flags) {
+void applyMovement(int16 *x, int16 *y, int8 *z, uint16 flags) {
// X-axis movement
if (flags & 0x10) { // Bit 4: X movement enabled
int amount = flags & 0x07; // Bits 0-2: pixels per frame
@@ -2644,14 +2652,14 @@ void PelrockEngine::credits() {
/**
* Last line is less indented for some reason, so skip that for calculation
*/
- for (int i = 0; i < creditTexts[page].size(); i++) {
+ for (uint i = 0; i < creditTexts[page].size(); i++) {
maxWidth = MAX(maxWidth, g_engine->_largeFont->getStringWidth(creditTexts[page][i]));
}
int startX = 320 - (maxWidth / 2);
int startY = (400 - s.getRect().height()) / 2 - 10;
- for (int i = 0; i < creditTexts[page].size(); i++) {
+ for (uint i = 0; i < creditTexts[page].size(); i++) {
// subtract that extra negative identation
int xPos = i == creditTexts[page].size() - 1 ? startX - 10 : startX;
int yPos = i * 25; // Above sprite, adjust for line
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 504ca209d28..894a1ffec2f 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -81,8 +81,20 @@ ResourceManager::~ResourceManager() {
delete[] alfredIdle[i];
}
+ for (int i = 0; i < 11; i++) {
+ delete[] alfredCombFrames[0][i];
+ delete[] alfredCombFrames[1][i];
+ }
delete[] alfredCombFrames[0];
delete[] alfredCombFrames[1];
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 9; j++) {
+ delete[] alfredCrawlFrames[i][j];
+ }
+ delete[] alfredCrawlFrames[i];
+ }
+
delete[] _inventoryIcons;
}
@@ -92,7 +104,7 @@ void ResourceManager::loadCursors() {
error("Couldnt find file ALFRED.7");
}
for (int i = 0; i < 5; i++) {
- uint32_t cursorOffset = cursor_offsets[i];
+ uint32 cursorOffset = cursor_offsets[i];
alfred7File.seek(cursorOffset);
_cursorMasks[i] = new byte[kCursorSize];
alfred7File.read(_cursorMasks[i], kCursorSize);
@@ -108,10 +120,10 @@ void ResourceManager::loadInteractionIcons() {
alfred7File.seek(kBalloonFramesOffset, SEEK_SET);
- uint32_t totalBalloonSize = kBalloonWidth * kBalloonHeight * kBalloonFrames;
+ uint32 totalBalloonSize = kBalloonWidth * kBalloonHeight * kBalloonFrames;
_popUpBalloon = new byte[totalBalloonSize];
- uint32_t compressedSize = kBalloonFramesSize;
+ uint32 compressedSize = kBalloonFramesSize;
byte *raw = new byte[compressedSize];
alfred7File.read(raw, compressedSize);
@@ -140,13 +152,13 @@ void ResourceManager::loadAlfredAnims() {
return;
}
int alfred3Size = alfred3.size();
- unsigned char *bufferFile = (unsigned char *)malloc(alfred3Size);
+ byte *bufferFile = (byte *)malloc(alfred3Size);
alfred3.seek(0, SEEK_SET);
alfred3.read(bufferFile, alfred3Size);
alfred3.close();
- uint32_t capacity = 3060 * 102 + 2340 * 55;
- unsigned char *completePic = new unsigned char[capacity];
+ uint32 capacity = 3060 * 102 + 2340 * 55;
+ byte *completePic = new byte[capacity];
rleDecompress(bufferFile, alfred3Size, 0, capacity, &completePic);
byte *stdFramesPic = new byte[3060 * 102];
@@ -208,6 +220,9 @@ void ResourceManager::loadAlfredAnims() {
}
}
+ delete[] crawlFramesPic;
+ delete[] stdFramesPic;
+ delete[] completePic;
free(bufferFile);
@@ -245,6 +260,8 @@ void ResourceManager::loadAlfredAnims() {
extractSingleFrame(alfredCombLeft, alfredCombFrames[1][i], i, kAlfredFrameWidth, kAlfredFrameHeight);
}
+ free(alfredCombRight);
+ free(alfredCombLeft);
free(alfredCombRightRaw);
free(alfredCombLeftRaw);
@@ -355,6 +372,7 @@ void ResourceManager::loadHardcodedText() {
exe.seek(kConversationTerminatorOffset, SEEK_SET);
exe.read(terminatorBuffer, 39);
_conversationTerminator = Common::String((const char *)terminatorBuffer, 39);
+ delete[] terminatorBuffer;
delete[] descBuffer;
exe.close();
}
@@ -527,7 +545,7 @@ void ResourceManager::mergeRleBlocks(Common::SeekableReadStream *stream, uint32
byte *thisBlock = nullptr;
size_t blockSize = 0;
readUntilBuda(stream, stream->pos(), thisBlock, blockSize);
- uint8_t *block_data = nullptr;
+ byte *block_data = nullptr;
size_t decompressedSize = rleDecompress(thisBlock, blockSize, 0, 640 * 400, &block_data, true);
// debug("Decompressed block %d: %zu bytes, total %zu", i, decompressedSize, combined_size + decompressedSize);
if (combined_size + decompressedSize > 640 * 400) {
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 2c52568a54b..7a613ee0042 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -74,18 +74,18 @@ void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *ba
// get screen
size_t combined_size = 0;
for (int pair_idx = 0; pair_idx < 8; pair_idx++) {
- uint32_t pair_offset = roomOffset + (pair_idx * 8);
+ uint32 pair_offset = roomOffset + (pair_idx * 8);
if (pair_offset + 8 > roomFile->size())
continue;
roomFile->seek(pair_offset, SEEK_SET);
- uint32_t offset = roomFile->readUint32LE();
- uint32_t size = roomFile->readUint32LE();
+ uint32 offset = roomFile->readUint32LE();
+ uint32 size = roomFile->readUint32LE();
if (offset > 0 && size > 0 && offset < roomFile->size()) {
byte *data = new byte[size];
roomFile->seek(offset, SEEK_SET);
roomFile->read(data, size);
- uint8_t *block_data = NULL;
+ byte *block_data = nullptr;
size_t block_size = rleDecompress(data, size, 0, 640 * 400, &block_data);
if (block_size + combined_size > 640 * 400) {
debug(" Warning: decompressed background size exceeds buffer size!");
@@ -365,7 +365,7 @@ PaletteAnim *RoomManager::getPaletteAnimForRoom(int roomNumber) {
debug("Could not open JUEGO.EXE for palette animation!");
return nullptr;
}
- uint32_t offset = 0;
+ uint32 offset = 0;
switch (roomNumber) {
case 0:
offset = 0x0004B88C;
@@ -471,7 +471,7 @@ Common::Array<Exit> RoomManager::loadExits(byte *data, size_t size) {
if (g_engine->_state->roomExitChanges.contains(_currentRoomNumber)) {
// if the exit has been changed, load the changed version
- for (int j = 0; j < g_engine->_state->roomExitChanges[_currentRoomNumber].size(); j++) {
+ for (uint j = 0; j < g_engine->_state->roomExitChanges[_currentRoomNumber].size(); j++) {
if (g_engine->_state->roomExitChanges[_currentRoomNumber][j].exitIndex == i) {
exit.isEnabled = g_engine->_state->roomExitChanges[_currentRoomNumber][j].enabled;
break;
@@ -500,7 +500,7 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
bool isChanged = false;
if (g_engine->_state->roomHotSpotChanges.contains(_currentRoomNumber)) {
// if the hotspot has been changed, load the changed version
- for (int j = 0; j < g_engine->_state->roomHotSpotChanges[_currentRoomNumber].size(); j++) {
+ for (uint j = 0; j < g_engine->_state->roomHotSpotChanges[_currentRoomNumber].size(); j++) {
if (g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspotIndex == spot.innerIndex) {
debug("Hotspot %d has been changed, loading changed version, Hotspot x=%d, y = %d, extra = %d, isEnabled=%d", spot.innerIndex, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.x, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.y, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.extra, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.isEnabled);
hotspots.push_back(g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot);
@@ -573,10 +573,10 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
_roomSfx = loadRoomSfx(roomFile, roomOffset);
// Pair 10
- uint32_t pair10offset = roomOffset + (10 * 8);
+ uint32 pair10offset = roomOffset + (10 * 8);
roomFile->seek(pair10offset, SEEK_SET);
- uint32_t pair10dataOffset = roomFile->readUint32LE();
- uint32_t pair10size = roomFile->readUint32LE();
+ uint32 pair10dataOffset = roomFile->readUint32LE();
+ uint32 pair10size = roomFile->readUint32LE();
byte *pair10 = new byte[pair10size];
roomFile->seek(pair10dataOffset, SEEK_SET);
@@ -597,10 +597,10 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
// Pair 11 is the palette, already loaded
// Pair 12 - Room Texts
- uint32_t pair12offset = roomOffset + (12 * 8);
+ uint32 pair12offset = roomOffset + (12 * 8);
roomFile->seek(pair12offset, SEEK_SET);
- uint32_t pair12dataOffset = roomFile->readUint32LE();
- uint32_t pair12size = roomFile->readUint32LE();
+ uint32 pair12dataOffset = roomFile->readUint32LE();
+ uint32 pair12size = roomFile->readUint32LE();
byte *pair12 = new byte[pair12size];
roomFile->seek(pair12dataOffset, SEEK_SET);
@@ -617,7 +617,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
loadRemaps(roomNumber);
- for (int i = 0; i < _currentRoomHotspots.size(); i++) {
+ for (uint i = 0; i < _currentRoomHotspots.size(); i++) {
HotSpot hotspot = _currentRoomHotspots[i];
drawRect(g_engine->_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 200 + i);
}
@@ -681,7 +681,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
anim.spriteIndex = 2;
anim.startX = mouse->x;
anim.startY = mouse->y;
- anim.dir = PASSERBY_DOWN;
+ anim.dir = kPasserbyDown;
anim.targetZIndex = blank->zOrder + 1;
anim.resetCoord = blank->y;
anims->passerByAnims[0] = anim;
@@ -701,7 +701,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
Sprite *camel = findSpriteByIndex(anim.spriteIndex);
anim.startX = camel->x;
anim.startY = camel->y;
- anim.dir = PASSERBY_RIGHT;
+ anim.dir = kPasserbyRight;
anim.frameTrigger = 0x1FFF;
anim.targetZIndex = 1;
anim.resetCoord = 639 + camel->w;
@@ -716,7 +716,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
Sprite *camel = findSpriteByIndex(3);
anim.startX = camel->x;
anim.startY = camel->y;
- anim.dir = PASSERBY_LEFT;
+ anim.dir = kPasserbyLeft;
anim.resetCoord = 0 - camel->w;
anim.targetZIndex = 1;
@@ -732,7 +732,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animA.spriteIndex = 2;
animA.startX = carLeft->x;
animA.startY = carLeft->y;
- animA.dir = PASSERBY_LEFT;
+ animA.dir = kPasserbyLeft;
animA.resetCoord = carRight->x + carRight->w - carLeft->w;
animA.targetZIndex = 100;
@@ -741,7 +741,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animB.spriteIndex = 3;
animB.startX = carRight->x;
animB.startY = carRight->y;
- animB.dir = PASSERBY_RIGHT;
+ animB.dir = kPasserbyRight;
animB.targetZIndex = 100;
animB.resetCoord = 639 + carRight->w;
anims->passerByAnims[1] = animB;
@@ -756,7 +756,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
anim.spriteIndex = 2;
anim.startX = walker->x;
anim.startY = walker->y;
- anim.dir = PASSERBY_RIGHT;
+ anim.dir = kPasserbyRight;
anim.resetCoord = dark->x;
anim.targetZIndex = dark->zOrder + 1;
anims->passerByAnims[0] = anim;
@@ -771,7 +771,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animA.spriteIndex = 2;
animA.startX = catRight->x;
animA.startY = catRight->y;
- animA.dir = PASSERBY_RIGHT;
+ animA.dir = kPasserbyRight;
animA.resetCoord = catLeft->x;
animA.targetZIndex = blank->zOrder + 1;
@@ -780,7 +780,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animB.spriteIndex = 3;
animB.startX = catLeft->x;
animB.startY = catLeft->y;
- animB.dir = PASSERBY_LEFT;
+ animB.dir = kPasserbyLeft;
animB.resetCoord = blank->x;
animB.targetZIndex = blank->zOrder + 1;
anims->passerByAnims[1] = animB;
@@ -796,7 +796,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animA.spriteIndex = 3;
animA.startX = mouseRight->x;
animA.startY = mouseRight->y;
- animA.dir = PASSERBY_RIGHT;
+ animA.dir = kPasserbyRight;
animA.resetCoord = mouseLeft->x;
animA.targetZIndex = papers->zOrder + 1;
anims->passerByAnims[0] = animA;
@@ -805,7 +805,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animB.spriteIndex = 4;
animB.startX = mouseLeft->x;
animB.startY = mouseLeft->y;
- animB.dir = PASSERBY_LEFT;
+ animB.dir = kPasserbyLeft;
animB.resetCoord = mouseRight->x;
animB.targetZIndex = papers->zOrder + 1;
anims->passerByAnims[1] = animB;
@@ -820,7 +820,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animA.spriteIndex = 2;
animA.startX = mummyLeft->x;
animA.startY = mummyLeft->y;
- animA.dir = PASSERBY_LEFT;
+ animA.dir = kPasserbyLeft;
animA.resetCoord = 0 - mummyLeft->w;
animA.targetZIndex = 1;
@@ -829,7 +829,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
animB.spriteIndex = 3;
animB.startX = mummyRight->x;
animB.startY = mummyRight->y;
- animB.dir = PASSERBY_RIGHT;
+ animB.dir = kPasserbyRight;
animB.targetZIndex = 1;
animB.resetCoord = 639 + mummyRight->w;
anims->passerByAnims[1] = animB;
@@ -845,7 +845,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
Common::Array<HotSpot> RoomManager::unifyHotspots(Common::Array<Pelrock::Sprite> &anims, Common::Array<Pelrock::HotSpot> &staticHotspots) {
Common::Array<HotSpot> unifiedHotspots;
- for (int i = 0; i < anims.size(); i++) {
+ for (uint i = 0; i < anims.size(); i++) {
HotSpot thisHotspot;
thisHotspot.index = i;
thisHotspot.x = anims[i].x;
@@ -862,7 +862,7 @@ Common::Array<HotSpot> RoomManager::unifyHotspots(Common::Array<Pelrock::Sprite>
}
// debug("total descriptions = %d, anims = %d, hotspots = %d", descriptions.size(), anims.size(), staticHotspots.size());
- for (int i = 0; i < staticHotspots.size(); i++) {
+ for (uint i = 0; i < staticHotspots.size(); i++) {
HotSpot hotspot = staticHotspots[i];
hotspot.index = anims.size() + i;
unifiedHotspots.push_back(hotspot);
@@ -882,10 +882,10 @@ void RoomManager::init() {
}
void RoomManager::loadAnimationPixelData(Common::File *roomFile, int roomOffset, byte *&buffer, size_t &outSize) {
- uint32_t pair_offset = roomOffset + (8 * 8);
+ uint32 pair_offset = roomOffset + (8 * 8);
roomFile->seek(pair_offset, SEEK_SET);
- uint32_t offset = roomFile->readUint32LE();
- uint32_t size = roomFile->readUint32LE();
+ uint32 offset = roomFile->readUint32LE();
+ uint32 size = roomFile->readUint32LE();
byte *pixelData = new byte[size];
roomFile->seek(offset, SEEK_SET);
@@ -908,16 +908,16 @@ void RoomManager::loadAnimationPixelData(Common::File *roomFile, int roomOffset,
Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size) {
Common::Array<Sprite> anims = Common::Array<Sprite>();
- uint32_t spriteCountPos = 5;
+ uint32 spriteCountPos = 5;
byte spriteCount = data[spriteCountPos] - 2;
debug("Sprite count: %d", spriteCount);
- uint32_t metadata_start = spriteCountPos + (44 * 2 + 5);
- uint32_t picOffset = 0;
+ uint32 metadata_start = spriteCountPos + (44 * 2 + 5);
+ uint32 picOffset = 0;
Common::Array<SpriteChange> spriteChanges = g_engine->_state->spriteChanges[_currentRoomNumber];
int talkingAnims = 0;
for (int i = 0; i < spriteCount; i++) {
- uint32_t animOffset = metadata_start + (i * 44);
+ uint32 animOffset = metadata_start + (i * 44);
Sprite sprite;
sprite.index = i;
sprite.x = READ_LE_INT16(data + animOffset + 0);
@@ -930,12 +930,12 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
sprite.extra = READ_LE_INT16(data + animOffset + 32);
debug("Sprite %d: x=%d y=%d w=%d h=%d stride=%d numAnims=%d zOrder=%d extra=%d", i, sprite.x, sprite.y, sprite.w, sprite.h, sprite.stride, sprite.numAnims, sprite.zOrder, sprite.extra);
sprite.actionFlags = data[animOffset + 34];
- if(sprite.actionFlags & ACTION_MASK_TALK) {
+ if(sprite.actionFlags & kActionMaskTalk) {
sprite.talkingAnimIndex = talkingAnims++;
}
sprite.isHotspotDisabled = data[animOffset + 38];
sprite.disableAfterSequence = data[animOffset + 39];
- for (int j = 0; j < spriteChanges.size(); j++) {
+ for (uint j = 0; j < spriteChanges.size(); j++) {
if (spriteChanges[j].spriteIndex == sprite.index) {
debug("Sprite %d has been changed, loading changed version with zOrder %d", sprite.index, spriteChanges[j].zIndex);
sprite.zOrder = spriteChanges[j].zIndex;
@@ -960,7 +960,7 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
anim.speed = data[subAnimOffset + 8 + j];
anim.movementFlags = data[subAnimOffset + 14 + (j * 2)] | (data[subAnimOffset + 14 + (j * 2) + 1] << 8);
- uint32_t totalBytesPerFrame = sprite.w * sprite.h * anim.nframes;
+ uint32 totalBytesPerFrame = sprite.w * sprite.h * anim.nframes;
anim.animData = new byte *[anim.nframes];
if (sprite.w > 0 && sprite.h > 0 && anim.nframes > 0) {
for (int k = 0; k < anim.nframes; k++) {
@@ -1000,10 +1000,10 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
byte walkboxCount = data[walkboxCountOffset];
// debug("Walkbox count: %d", walkbox_count);
- uint32_t walkboxOffset = 0x218;
+ uint32 walkboxOffset = 0x218;
Common::Array<WalkBox> walkboxes;
for (int i = 0; i < walkboxCount; i++) {
- uint32_t boxOffset = walkboxOffset + i * 9;
+ uint32 boxOffset = walkboxOffset + i * 9;
int16 x1 = READ_LE_INT16(data + boxOffset);
int16 y1 = READ_LE_INT16(data + boxOffset + 2);
int16 w = READ_LE_INT16(data + boxOffset + 4);
@@ -1016,7 +1016,7 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
if (g_engine->_state->roomWalkBoxChanges.contains(_currentRoomNumber)) {
debug("Checking for changes to walkbox %d in room %d", i, _currentRoomNumber);
// if the walkbox has been changed, load the changed version
- for (int j = 0; j < g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
+ for (uint j = 0; j < g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
if (g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == i) {
walkboxes.push_back(g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
isChanged = true;
@@ -1037,9 +1037,9 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
if (g_engine->_state->roomWalkBoxChanges.contains(_currentRoomNumber)) {
// Add any new walkboxes that were added
- for (int j = 0; j < g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
+ for (uint j = 0; j < g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
bool found = false;
- for (int i = 0; i < walkboxes.size(); i++) {
+ for (uint i = 0; i < walkboxes.size(); i++) {
if (g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == walkboxes[i].index) {
found = true;
break;
@@ -1056,8 +1056,8 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
}
uint32 RoomManager::loadDescriptions(byte *pair12data, size_t pair12size, Common::Array<Description> &outDescriptions) {
- uint32_t pos = 0;
- uint32_t lastDescPos = 0;
+ uint32 pos = 0;
+ uint32 lastDescPos = 0;
outDescriptions.clear();
while (pos < (pair12size)) {
if (pair12data[pos] == 0xFF) {
@@ -1115,7 +1115,7 @@ void RoomManager::applyDisabledChoices(byte roomNumber, byte *conversationData,
return;
}
debug("Disabling %d conversation branches for room %d", disabledBranches.size(), roomNumber);
- for (int i = 0; i < disabledBranches.size(); i++) {
+ for (uint i = 0; i < disabledBranches.size(); i++) {
ResetEntry resetEntry = disabledBranches[i];
applyDisabledChoice(resetEntry, conversationData, conversationDataSize);
}
@@ -1248,7 +1248,7 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
ScalingParams RoomManager::loadScalingParams(byte *data, size_t size) {
- uint32_t scalingParamsOffset = 0x214;
+ uint32 scalingParamsOffset = 0x214;
ScalingParams scalingParams;
scalingParams.yThreshold = READ_LE_INT16(data + scalingParamsOffset);
@@ -1309,9 +1309,9 @@ void RoomManager::loadRemaps(int roomNumber) {
}
byte RoomManager::loadMusicTrackForRoom(Common::File *roomFile, int roomOffset) {
- uint32_t pair9offset = roomOffset + (9 * 8);
+ uint32 pair9offset = roomOffset + (9 * 8);
roomFile->seek(pair9offset, SEEK_SET);
- uint32_t pair9_data_offset = roomFile->readUint32LE();
+ uint32 pair9_data_offset = roomFile->readUint32LE();
roomFile->seek(pair9_data_offset, SEEK_SET);
byte musicTrack = roomFile->readByte();
@@ -1320,9 +1320,9 @@ byte RoomManager::loadMusicTrackForRoom(Common::File *roomFile, int roomOffset)
}
Common::Array<byte> RoomManager::loadRoomSfx(Common::File *roomFile, int roomOffset) {
- uint32_t pair9offset = roomOffset + (9 * 8);
+ uint32 pair9offset = roomOffset + (9 * 8);
roomFile->seek(pair9offset, SEEK_SET);
- uint32_t pair9_data_offset = roomFile->readUint32LE();
+ uint32 pair9_data_offset = roomFile->readUint32LE();
roomFile->seek(pair9_data_offset, SEEK_SET);
roomFile->skip(1); // skip music track byte
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 42340cdb5fe..1969cf6a78a 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -38,6 +38,105 @@
namespace Pelrock {
+const char *SOUND_FILENAMES[] = {
+ "NO_SOUND.SMP", // 0 - Silence/disabled
+ "BUHO_ZZZ.SMP", // 1 - Owl
+ "BIRD_1_1.SMP", // 2 - Bird variant 1
+ "BIRD_1_2.SMP", // 3 - Bird variant 2
+ "BIRD_1_3.SMP", // 4 - Bird variant 3
+ "DESPERZZ.SMP", // 5 - Yawn/stretch
+ "HORN_5ZZ.SMP", // 6 - Car horn 5
+ "HORN_6ZZ.SMP", // 7 - Car horn 6
+ "HORN_8ZZ.SMP", // 8 - Car horn 8
+ "SUZIPASS.SMP", // 9 - Suzi passing
+ "CAT_1ZZZ.SMP", // 10 - Cat
+ "DOG_01ZZ.SMP", // 11 - Dog bark 1
+ "DOG_02ZZ.SMP", // 12 - Dog bark 2
+ "DOG_04ZZ.SMP", // 13 - Dog bark 4
+ "DOG_05ZZ.SMP", // 14 - Dog bark 5
+ "DOG_06ZZ.SMP", // 15 - Dog bark 6
+ "DOG_07ZZ.SMP", // 16 - Dog bark 7
+ "DOG_09ZZ.SMP", // 17 - Dog bark 9
+ "ALARMZZZ.SMP", // 18 - Alarm
+ "AMBULAN1.SMP", // 19 - Ambulance
+ "FOUNTAIN.SMP", // 20 - Fountain
+ "GRILLOSZ.SMP", // 21 - Crickets
+ "HOJASZZZ.SMP", // 22 - Leaves rustling
+ "FLASHZZZ.SMP", // 23 - Flash/camera
+ "CUCHI1ZZ.SMP", // 24 - Knife 1
+ "KNRRRRRZ.SMP", // 25 - Snoring
+ "PHONE_02.SMP", // 26 - Phone ring 2
+ "PHONE_03.SMP", // 27 - Phone ring 3
+ "SSSHTZZZ.SMP", // 28 - Shush/quiet
+ "BURGUER1.SMP", // 29 - Burger sizzle
+ "FLIES_2Z.SMP", // 30 - Flies buzzing
+ "PARRILLA.SMP", // 31 - Grill
+ "WATER_2Z.SMP", // 32 - Water
+ "XIQUETZZ.SMP", // 33 - Whistle
+ "RONQUIZZ.SMP", // 34 - Snoring
+ "MOCO1ZZZ.SMP", // 35 - Snot/mucus 1
+ "MOCO2ZZZ.SMP", // 36 - Snot/mucus 2
+ "SPRINGZZ.SMP", // 37 - Spring bounce
+ "MARUJASZ.SMP", // 38 - Gossip/chatter
+ "ELECTROZ.SMP", // 39 - Electric shock
+ "GLASS1ZZ.SMP", // 40 - Glass clink
+ "OPDOORZZ.SMP", // 41 - Door open
+ "CLDOORZZ.SMP", // 42 - Door close
+ "FXH2ZZZZ.SMP", // 43 - Effect 2
+ "BOTEZZZZ.SMP", // 44 - Bottle
+ "ELEC3ZZZ.SMP", // 45 - Electric 3
+ "AJARLZZZ.SMP", // 46 - Ajar/creak
+ "BELCHZZZ.SMP", // 47 - Belch/burp
+ "64ZZZZZZ.SMP", // 48 - Sound effect 64
+ "BIRDOWL2.SMP", // 49 - Bird/owl 2
+ "BUBBLE2Z.SMP", // 50 - Bubbles
+ "BURGUER1.SMP", // 51 - Burger (duplicate)
+ "CACKLEZZ.SMP", // 52 - Cackle/laugh
+ "CERAMIC1.SMP", // 53 - Ceramic break
+ "CLANG5ZZ.SMP", // 54 - Metal clang
+ "CUCHI2ZZ.SMP", // 55 - Knife 2
+ "CUCHI3ZZ.SMP", // 56 - Knife 3
+ "ELEC3ZZZ.SMP", // 57 - Electric 3 (duplicate)
+ "HOJASZZZ.SMP", // 58 - Leaves (duplicate)
+ "LIMA1ZZZ.SMP", // 59 - File/rasp
+ "MOROSZZZ.SMP", // 60 - Moors/crowd
+ "MOROZZZZ.SMP", // 61 - Moor/crowd
+ "MUD1ZZZZ.SMP", // 62 - Mud squelch
+ "PICOZZZZ.SMP", // 63 - Pickaxe
+ "PICO1XZZ.SMP", // 64 - Pickaxe 1
+ "PICO2XZZ.SMP", // 65 - Pickaxe 2
+ "PICO3XZZ.SMP", // 66 - Pickaxe 3
+ "RIMSHOTZ.SMP", // 67 - Rimshot drum
+ "RONCOZZZ.SMP", // 68 - Snoring
+ "SORBOZZZ.SMP", // 69 - Slurp/sip
+ "VIENTO1Z.SMP", // 70 - Wind
+ "2ZZZZZZZ.SMP", // 71 - Sound 2
+ "20ZZZZZZ.SMP", // 72 - Sound 20
+ "21ZZZZZZ.SMP", // 73 - Sound 21
+ "23ZZZZZZ.SMP", // 74 - Sound 23
+ "107ZZZZZ.SMP", // 75 - Sound 107
+ "39ZZZZZZ.SMP", // 76 - Sound 39
+ "81ZZZZZZ.SMP", // 77 - Sound 81
+ "88ZZZZZZ.SMP", // 78 - Sound 88
+ "92ZZZZZZ.SMP", // 79 - Sound 92
+ "SAW_2ZZZ.SMP", // 80 - Saw
+ "QUAKE2ZZ.SMP", // 81 - Earthquake
+ "ROCKSZZZ.SMP", // 82 - Rocks falling
+ "IN_FIREZ.SMP", // 83 - Fire
+ "BEAMZZZZ.SMP", // 84 - Beam/ray
+ "GLISSDWN.SMP", // 85 - Glissando down
+ "REMATERL.SMP", // 86 - Rematerialize
+ "FXH1ZZZZ.SMP", // 87 - Effect 1
+ "FXH3ZZZZ.SMP", // 88 - Effect 3
+ "FXH4ZZZZ.SMP", // 89 - Effect 4
+ "MATCHZZZ.SMP", // 90 - Match strike
+ "SURF_01Z.SMP", // 91 - Surf wave 1
+ "SURF_02Z.SMP", // 92 - Surf wave 2
+ "SURF_04Z.SMP", // 93 - Surf wave 4
+ "TWANGZZZ.SMP", // 94 - Twang
+ "LANDCRAS.SMP", // 95 - Crash landing
+};
+
SoundManager::SoundManager(Audio::Mixer *mixer)
: _mixer(mixer), _currentVolume(128) {
// TODO: Initialize sound manager
@@ -81,7 +180,7 @@ void SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
sonidosFile.close();
SoundFormat format = detectFormat(data, sound.size);
- uint32_t sampleRate = getSampleRate(data, format);
+ uint32 sampleRate = getSampleRate(data, format);
Audio::SeekableAudioStream *stream = nullptr;
if (format == SOUND_FORMAT_RIFF) {
@@ -270,7 +369,7 @@ void SoundManager::loadSoundIndex() {
debug("SONIDOS.DAT contains %u files", fileCount);
sonidosFile.skip(3); // Padding bytes
- for (uint32_t i = 0; i < fileCount; i++) {
+ for (uint32 i = 0; i < fileCount; i++) {
SonidoFile sonido;
sonido.filename = sonidosFile.readString('\0', 12);
sonidosFile.skip(1);
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 3480b333974..86195d7af38 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -31,109 +31,12 @@ namespace Pelrock {
struct SonidoFile {
Common::String filename;
- uint32_t offset;
- uint32_t size;
- unsigned char *data;
+ uint32 offset;
+ uint32 size;
+ byte *data;
};
-static const char *SOUND_FILENAMES[] = {
- "NO_SOUND.SMP", // 0 - Silence/disabled
- "BUHO_ZZZ.SMP", // 1 - Owl
- "BIRD_1_1.SMP", // 2 - Bird variant 1
- "BIRD_1_2.SMP", // 3 - Bird variant 2
- "BIRD_1_3.SMP", // 4 - Bird variant 3
- "DESPERZZ.SMP", // 5 - Yawn/stretch
- "HORN_5ZZ.SMP", // 6 - Car horn 5
- "HORN_6ZZ.SMP", // 7 - Car horn 6
- "HORN_8ZZ.SMP", // 8 - Car horn 8
- "SUZIPASS.SMP", // 9 - Suzi passing
- "CAT_1ZZZ.SMP", // 10 - Cat
- "DOG_01ZZ.SMP", // 11 - Dog bark 1
- "DOG_02ZZ.SMP", // 12 - Dog bark 2
- "DOG_04ZZ.SMP", // 13 - Dog bark 4
- "DOG_05ZZ.SMP", // 14 - Dog bark 5
- "DOG_06ZZ.SMP", // 15 - Dog bark 6
- "DOG_07ZZ.SMP", // 16 - Dog bark 7
- "DOG_09ZZ.SMP", // 17 - Dog bark 9
- "ALARMZZZ.SMP", // 18 - Alarm
- "AMBULAN1.SMP", // 19 - Ambulance
- "FOUNTAIN.SMP", // 20 - Fountain
- "GRILLOSZ.SMP", // 21 - Crickets
- "HOJASZZZ.SMP", // 22 - Leaves rustling
- "FLASHZZZ.SMP", // 23 - Flash/camera
- "CUCHI1ZZ.SMP", // 24 - Knife 1
- "KNRRRRRZ.SMP", // 25 - Snoring
- "PHONE_02.SMP", // 26 - Phone ring 2
- "PHONE_03.SMP", // 27 - Phone ring 3
- "SSSHTZZZ.SMP", // 28 - Shush/quiet
- "BURGUER1.SMP", // 29 - Burger sizzle
- "FLIES_2Z.SMP", // 30 - Flies buzzing
- "PARRILLA.SMP", // 31 - Grill
- "WATER_2Z.SMP", // 32 - Water
- "XIQUETZZ.SMP", // 33 - Whistle
- "RONQUIZZ.SMP", // 34 - Snoring
- "MOCO1ZZZ.SMP", // 35 - Snot/mucus 1
- "MOCO2ZZZ.SMP", // 36 - Snot/mucus 2
- "SPRINGZZ.SMP", // 37 - Spring bounce
- "MARUJASZ.SMP", // 38 - Gossip/chatter
- "ELECTROZ.SMP", // 39 - Electric shock
- "GLASS1ZZ.SMP", // 40 - Glass clink
- "OPDOORZZ.SMP", // 41 - Door open
- "CLDOORZZ.SMP", // 42 - Door close
- "FXH2ZZZZ.SMP", // 43 - Effect 2
- "BOTEZZZZ.SMP", // 44 - Bottle
- "ELEC3ZZZ.SMP", // 45 - Electric 3
- "AJARLZZZ.SMP", // 46 - Ajar/creak
- "BELCHZZZ.SMP", // 47 - Belch/burp
- "64ZZZZZZ.SMP", // 48 - Sound effect 64
- "BIRDOWL2.SMP", // 49 - Bird/owl 2
- "BUBBLE2Z.SMP", // 50 - Bubbles
- "BURGUER1.SMP", // 51 - Burger (duplicate)
- "CACKLEZZ.SMP", // 52 - Cackle/laugh
- "CERAMIC1.SMP", // 53 - Ceramic break
- "CLANG5ZZ.SMP", // 54 - Metal clang
- "CUCHI2ZZ.SMP", // 55 - Knife 2
- "CUCHI3ZZ.SMP", // 56 - Knife 3
- "ELEC3ZZZ.SMP", // 57 - Electric 3 (duplicate)
- "HOJASZZZ.SMP", // 58 - Leaves (duplicate)
- "LIMA1ZZZ.SMP", // 59 - File/rasp
- "MOROSZZZ.SMP", // 60 - Moors/crowd
- "MOROZZZZ.SMP", // 61 - Moor/crowd
- "MUD1ZZZZ.SMP", // 62 - Mud squelch
- "PICOZZZZ.SMP", // 63 - Pickaxe
- "PICO1XZZ.SMP", // 64 - Pickaxe 1
- "PICO2XZZ.SMP", // 65 - Pickaxe 2
- "PICO3XZZ.SMP", // 66 - Pickaxe 3
- "RIMSHOTZ.SMP", // 67 - Rimshot drum
- "RONCOZZZ.SMP", // 68 - Snoring
- "SORBOZZZ.SMP", // 69 - Slurp/sip
- "VIENTO1Z.SMP", // 70 - Wind
- "2ZZZZZZZ.SMP", // 71 - Sound 2
- "20ZZZZZZ.SMP", // 72 - Sound 20
- "21ZZZZZZ.SMP", // 73 - Sound 21
- "23ZZZZZZ.SMP", // 74 - Sound 23
- "107ZZZZZ.SMP", // 75 - Sound 107
- "39ZZZZZZ.SMP", // 76 - Sound 39
- "81ZZZZZZ.SMP", // 77 - Sound 81
- "88ZZZZZZ.SMP", // 78 - Sound 88
- "92ZZZZZZ.SMP", // 79 - Sound 92
- "SAW_2ZZZ.SMP", // 80 - Saw
- "QUAKE2ZZ.SMP", // 81 - Earthquake
- "ROCKSZZZ.SMP", // 82 - Rocks falling
- "IN_FIREZ.SMP", // 83 - Fire
- "BEAMZZZZ.SMP", // 84 - Beam/ray
- "GLISSDWN.SMP", // 85 - Glissando down
- "REMATERL.SMP", // 86 - Rematerialize
- "FXH1ZZZZ.SMP", // 87 - Effect 1
- "FXH3ZZZZ.SMP", // 88 - Effect 3
- "FXH4ZZZZ.SMP", // 89 - Effect 4
- "MATCHZZZ.SMP", // 90 - Match strike
- "SURF_01Z.SMP", // 91 - Surf wave 1
- "SURF_02Z.SMP", // 92 - Surf wave 2
- "SURF_04Z.SMP", // 93 - Surf wave 4
- "TWANGZZZ.SMP", // 94 - Twang
- "LANDCRAS.SMP", // 95 - Crash landing
-};
+extern const char *SOUND_FILENAMES[];
enum SoundFormat {
SOUND_FORMAT_RAWPCM,
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 6efc93e3401..fb597db08c8 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -37,14 +37,14 @@ enum Cursor {
COMBINATION
};
-#define ACTION_MASK_NONE 0
-#define ACTION_MASK_OPEN 1
-#define ACTION_MASK_CLOSE 2
-#define ACTION_MASK_UNKNOWN 4
-#define ACTION_MASK_PICKUP 8
-#define ACTION_MASK_TALK 16
-#define ACTION_MASK_PUSH 32
-#define ACTION_MASK_PULL 128
+const byte kActionMaskNone = 0;
+const byte kActionMaskOpen = 1;
+const byte kActionMaskClose = 2;
+const byte kActionMaskUnknown = 4;
+const byte kActionMaskPickup = 8;
+const byte kActionMaskTalk = 16;
+const byte kActionMaskPush = 32;
+const byte kActionMaskPull = 128;
enum VerbIcon {
PICKUP,
@@ -60,7 +60,7 @@ enum VerbIcon {
NO_ACTION
};
-static const uint32 kLongClickDuration = 500; // 500ms for long click
+const uint32 kLongClickDuration = 500; // 500ms for long click
const int kCursorWidth = 16;
const int kCursorHeight = 18;
const int kCursorSize = 288; // 16 * 18
@@ -92,25 +92,32 @@ const int kAlfredInitialPosX = 235;
const int kAlfredInitialPosY = 279;
// Direction flags (bit-packed)
-#define MOVE_RIGHT 0x01 // Move right (positive X)
-#define MOVE_LEFT 0x02 // Move left (negative X)
-#define MOVE_HORIZ 0x03 // Horizontal movement mask
-#define MOVE_DOWN 0x04 // Move down (positive Y)
-#define MOVE_UP 0x08 // Move up (negative Y)
-#define MOVE_VERT 0x0C // Vertical movement mask
-#define MAX_PATH_LENGTH 100
-#define MAX_MOVEMENT_STEPS 100 // 500 bytes / 5 bytes per step
-#define PATH_END 0xFF // End of path marker
-
-#define MAX_CHARS_PER_LINE 0x2F // 47 characters
-#define MAX_LINES 5 // Maximum number of lines per page (0-indexed check against 4)
-
-#define ALFRED_COLOR 0x0D
-
-#define OVERLAY_NONE 0
-#define OVERLAY_CHOICES 1
-#define OVERLAY_PICKUP_ICON 2
-#define OVERLAY_ACTION 3
+const byte kMoveRight = 0x01; // Move right (positive X)
+const byte kMoveLeft = 0x02; // Move left (negative X)
+const byte kMoveHoriz = 0x03; // Horizontal movement mask
+const byte kMoveDown = 0x04; // Move down (positive Y)
+const byte kMoveUp = 0x08; // Move up (negative Y)
+const byte kMoveVert = 0x0C; // Vertical movement mask
+const int kMaxPathLength = 100;
+const int kMaxMovementSteps = 100; // 500 bytes / 5 bytes per step
+const byte kPathEnd = 0xFF; // End of path marker
+
+const int kMaxCharsPerLine = 0x2F; // 47 characters
+const int kMaxLines = 5; // Maximum number of lines per page
+
+const byte kAlfredColor = 0x0D;
+
+enum OverlayMode {
+ OVERLAY_NONE = 0,
+ OVERLAY_CHOICES = 1,
+ OVERLAY_PICKUP_ICON = 2,
+ OVERLAY_ACTION = 3
+};
+
+// Passerby direction constants
+const byte kPasserbyRight = 0;
+const byte kPasserbyLeft = 1;
+const byte kPasserbyDown = 2;
const byte kIconBlinkPeriod = 4;
@@ -216,21 +223,21 @@ struct ShakeEffectState
struct MovementStep {
- uint8_t flags; /* Direction flags (see MOVE_* constants) */
- uint16_t distanceX; // Horizontal distance to move
- uint16_t distanceY; // Vertical distance to move
+ byte flags; /* Direction flags (see kMove* constants) */
+ uint16 distanceX; // Horizontal distance to move
+ uint16 distanceY; // Vertical distance to move
};
/**
* Pathfinding context
*/
struct PathContext {
- uint8_t *pathBuffer; // Sequence of walkbox indices
+ byte *pathBuffer; // Sequence of walkbox indices
MovementStep *movementBuffer; // Array of movement steps
- uint8_t *compressed_path; // Final compressed path
- uint16_t pathLength;
- uint16_t movementCount;
- uint16_t compressed_length;
+ byte *compressed_path; // Final compressed path
+ uint16 pathLength;
+ uint16 movementCount;
+ uint16 compressed_length;
};
struct Anim {
@@ -443,10 +450,6 @@ struct PaletteAnim {
byte tickCount = 0;
};
-#define PASSERBY_RIGHT 0
-#define PASSERBY_LEFT 1
-#define PASSERBY_DOWN 2
-
struct PasserByAnim {
uint32 frameTrigger = 0x3FF;
int16 startX;
@@ -567,7 +570,7 @@ struct GameStateData {
int libraryShelf = -1;
int selectedBookIndex = -1;
- unsigned char bookLetter = '\0';
+ char bookLetter = '\0';
Common::HashMap<byte, Common::Array<Sticker>> stickersPerRoom;
Common::HashMap<byte, Common::Array<ExitChange>> roomExitChanges;
Common::HashMap<byte, Common::Array<WalkBoxChange>> roomWalkBoxChanges;
@@ -585,7 +588,7 @@ struct GameStateData {
}
void clear() {
- memset(conversationCurrentRoot, 0, 112); // Initialize all to 0xFF (not set)
+ memset(conversationCurrentRoot, 0xFF, 112); // Initialize all to 0xFF (not set)
for (int i = 0; i < kNumGameFlags; i++)
flags[i] = 0;
flags[FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ] = true;
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 8032112eb8c..9e522918a23 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -141,15 +141,15 @@ void drawText(Graphics::ManagedSurface &dest, Graphics::Font *font, Common::Stri
}
size_t rleDecompress(
- const uint8_t *input,
+ const byte *input,
size_t inputSize,
- uint32_t offset,
- uint32_t expectedSize,
- uint8_t **out_data,
+ uint32 offset,
+ uint32 expectedSize,
+ byte **out_data,
bool untilBuda) {
// Check for uncompressed markers
if (inputSize == 0x8000 || inputSize == 0x6800) {
- *out_data = (uint8_t *)malloc(inputSize);
+ *out_data = (byte *)malloc(inputSize);
if (!*out_data)
return 0;
memcpy(*out_data, input + offset, inputSize);
@@ -159,27 +159,27 @@ size_t rleDecompress(
// RLE compressed
size_t bufferCapacity;
size_t result_size = 0;
- uint32_t pos = offset;
- uint8_t last_value = 0;
+ uint32 pos = offset;
+ byte last_value = 0;
if (untilBuda || expectedSize == 0) {
// Dynamic allocation mode - grow buffer as needed
bufferCapacity = 4096;
- *out_data = (uint8_t *)malloc(bufferCapacity);
+ *out_data = (byte *)malloc(bufferCapacity);
if (!*out_data)
return 0;
} else {
// Fixed size mode
bufferCapacity = expectedSize;
- *out_data = (uint8_t *)malloc(bufferCapacity);
+ *out_data = (byte *)malloc(bufferCapacity);
if (!*out_data)
return 0;
}
while (pos + 2 <= inputSize) {
// Read the RLE pair
- uint8_t count = input[pos];
- uint8_t value = input[pos + 1];
+ byte count = input[pos];
+ byte value = input[pos + 1];
last_value = value;
// Write pixels for this pair
@@ -195,7 +195,7 @@ size_t rleDecompress(
break;
}
- uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
+ byte *newBuf = (byte *)realloc(*out_data, bufferCapacity);
if (!newBuf) {
free(*out_data);
*out_data = nullptr;
@@ -217,7 +217,7 @@ size_t rleDecompress(
// Grow buffer if needed
if (result_size >= bufferCapacity) {
bufferCapacity++;
- uint8_t *newBuf = (uint8_t *)realloc(*out_data, bufferCapacity);
+ byte *newBuf = (byte *)realloc(*out_data, bufferCapacity);
if (!newBuf) {
free(*out_data);
*out_data = nullptr;
@@ -238,7 +238,7 @@ size_t rleDecompress(
return result_size;
}
-void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize) {
+void readUntilBuda(Common::SeekableReadStream *stream, uint32 startPos, byte *&buffer, size_t &outSize) {
const int markerLen = 4;
size_t bufferSize = 4096;
size_t pos = 0;
@@ -265,7 +265,7 @@ void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *
outSize = pos;
}
-void rleDecompressSingleBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&outBuffer, size_t &outSize){
+void rleDecompressSingleBuda(Common::SeekableReadStream *stream, uint32 startPos, byte *&outBuffer, size_t &outSize){
byte *buffer = nullptr;
size_t size = 0;
readUntilBuda(stream, startPos, buffer, size);
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 1aedf5a2b4f..fe61d1d2d42 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -32,9 +32,9 @@
namespace Pelrock {
const int EXPECTED_SIZE = 640 * 400;
-size_t rleDecompress(const uint8_t *data, size_t data_size, uint32_t offset, uint32_t size, uint8_t **out_data, bool untilBuda = true);
-void readUntilBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize);
-void rleDecompressSingleBuda(Common::SeekableReadStream *stream, uint32_t startPos, byte *&buffer, size_t &outSize);
+size_t rleDecompress(const byte *data, size_t data_size, uint32 offset, uint32 size, byte **out_data, bool untilBuda = true);
+void readUntilBuda(Common::SeekableReadStream *stream, uint32 startPos, byte *&buffer, size_t &outSize);
+void rleDecompressSingleBuda(Common::SeekableReadStream *stream, uint32 startPos, byte *&buffer, size_t &outSize);
void drawSpriteToBuffer(byte *buffer, int bufferWidth, byte *sprite, int x, int y, int width, int height, int transparentColor);
void drawSpriteToBuffer(Graphics::ManagedSurface &dest, byte *sprite, int x, int y, int width, int height, int transparentColor);
void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY);
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 9c7243def1b..cb36bc35ecc 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -281,8 +281,8 @@ void VideoManager::initMetadata() {
char signature[5] = {0};
_introSndFile.read(signature, 4);
if (strcmp(signature, "PACK") == 0) {
- uint32_t numFiles = _introSndFile.readUint32LE();
- for (uint32_t i = 0; i < numFiles; ++i) {
+ uint32 numFiles = _introSndFile.readUint32LE();
+ for (uint32 i = 0; i < numFiles; ++i) {
VoiceData sound;
Common::String filename = _introSndFile.readString();
// _introSndFile.skip(1);
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index aa4fbf5412b..392734eb5fc 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -30,9 +30,9 @@
namespace Pelrock {
struct ChunkHeader {
- uint32_t blockCount; // +0x00: Number of 0x5000-byte blocks
- uint32_t dataOffset; // +0x04: Varies by chunk type
- uint8_t chunkType; // +0x08: 1=RLE, 2=BlockCopy, 3=End, 4=Palette, 6=Special
+ uint32 blockCount; // +0x00: Number of 0x5000-byte blocks
+ uint32 dataOffset; // +0x04: Varies by chunk type
+ byte chunkType; // +0x08: 1=RLE, 2=BlockCopy, 3=End, 4=Palette, 6=Special
// +0x0D: Frame data begins
byte *data;
};
Commit: b7057581cbdec775c76bd9ce56aed6898b90a0ad
https://github.com/scummvm/scummvm/commit/b7057581cbdec775c76bd9ce56aed6898b90a0ad
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:26+02:00
Commit Message:
PELROCK: Disable looping for incidental music
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/sound.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 0defabc6729..1ccd01c386b 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1855,7 +1855,7 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
case 257: // look portrait
- _sound->playMusicTrack(25);
+ _sound->playMusicTrack(25, false);
loadExtraScreenAndPresent(9);
_dialog->say(_res->_ingameTexts[QUEBUENA_ESTA]);
_screen->markAllDirty();
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index e1a594d3234..569d314581b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -268,7 +268,7 @@ void PelrockEngine::playSoundIfNeeded() {
void PelrockEngine::travelToEgypt() {
_graphics->fadeToBlack(10);
- _sound->playMusicTrack(26, 1);
+ _sound->playMusicTrack(26, false);
byte *palette = new byte[768];
if (!_bgScreen.getPixels()) {
_bgScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 1969cf6a78a..2d5f1be7aa0 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -348,7 +348,7 @@ void SoundManager::playMusicTrack(int trackNumber, bool loop) {
_cdPlayStartTime = g_system->getMillis();
}
g_system->getAudioCDManager()->stop();
- g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 0, _cdTrackStart, _cdTrackDuration);
+ g_system->getAudioCDManager()->play(trackNumber, loop ? -1 : 1, _cdTrackStart, _cdTrackDuration);
}
void SoundManager::loadSoundIndex() {
Commit: f1b6d3a7edf75a13bead2b1acf74d1f9c13db912
https://github.com/scummvm/scummvm/commit/f1b6d3a7edf75a13bead2b1acf74d1f9c13db912
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:26+02:00
Commit Message:
PELROCK: Fixes stale item staying in action popup after use
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/types.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 9ddad5ec3ca..6682cf1ecac 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -166,7 +166,7 @@ void MenuManager::menuLoop() {
g_system->getPaletteManager()->setPalette(_mainMenuPalette, 0, 256);
g_engine->changeCursor(DEFAULT);
-
+ _menuText = _menuTexts[0];
while (!g_engine->shouldQuit() && !_events->_rightMouseClicked) {
_events->pollEvent();
@@ -221,7 +221,6 @@ void MenuManager::drawInventoryIcons() {
void MenuManager::loadMenu() {
- bool alternateMenu = false;
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
error("Could not open ALFRED.7");
@@ -231,60 +230,46 @@ void MenuManager::loadMenu() {
_compositeBuffer.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
_mainMenu.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
loadMenuTexts();
- if (!alternateMenu) {
- alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
- alfred7.read(_mainMenuPalette, 768);
- for (int i = 0; i < 256; i++) {
- _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
- _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
- _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
- }
-
- uint32 curPos = 0;
- alfred7.seek(2405266, SEEK_SET);
- alfred7.read(_mainMenu.getPixels(), 65536);
-
- curPos += 65536;
-
- byte *compressedPart1 = new byte[29418];
- alfred7.read(compressedPart1, 29418);
- byte *decompressedPart1 = nullptr;
- size_t decompressedSize = rleDecompress(compressedPart1, 29418, 0, 0, &decompressedPart1, true);
-
- memcpy((byte *)_mainMenu.getPixels() + curPos, decompressedPart1, decompressedSize);
- curPos += decompressedSize;
-
- delete[] compressedPart1;
- delete[] decompressedPart1;
- alfred7.seek(2500220, SEEK_SET);
- alfred7.read((byte *)_mainMenu.getPixels() + curPos, 32768);
- curPos += 32768;
- byte *compressedPart2 = new byte[30288];
- alfred7.read(compressedPart2, 30288);
- byte *decompressedPart2 = nullptr;
- decompressedSize = rleDecompress(compressedPart2, 30288, 0, 0, &decompressedPart2, true);
-
- memcpy((byte *)_mainMenu.getPixels() + curPos, decompressedPart2, decompressedSize);
- curPos += decompressedSize;
- debug("Settings menu size loaded: %d, with last block %d", curPos, curPos + 92160);
- delete[] compressedPart2;
- delete[] decompressedPart2;
- alfred7.seek(2563266, SEEK_SET);
- alfred7.read((byte *)_mainMenu.getPixels() + curPos, 92160);
- } else {
- _mainMenu.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
-
- alfred7.seek(kAlternateSettingsPaletteOffset, SEEK_SET);
- alfred7.read(_mainMenuPalette, 768);
- for (int i = 0; i < 256; i++) {
- _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
- _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
- _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
- }
-
- g_engine->_res->mergeRleBlocks(&alfred7, kAlternateSettingsMenuOffset, 8, (byte *)_mainMenu.getPixels());
+ alfred7.seek(kSettingsPaletteOffset, SEEK_SET);
+ alfred7.read(_mainMenuPalette, 768);
+ for (int i = 0; i < 256; i++) {
+ _mainMenuPalette[i * 3] = _mainMenuPalette[i * 3] << 2;
+ _mainMenuPalette[i * 3 + 1] = _mainMenuPalette[i * 3 + 1] << 2;
+ _mainMenuPalette[i * 3 + 2] = _mainMenuPalette[i * 3 + 2] << 2;
}
+ uint32 curPos = 0;
+ alfred7.seek(2405266, SEEK_SET);
+ alfred7.read(_mainMenu.getPixels(), 65536);
+
+ curPos += 65536;
+
+ byte *compressedPart1 = new byte[29418];
+ alfred7.read(compressedPart1, 29418);
+ byte *decompressedPart1 = nullptr;
+ size_t decompressedSize = rleDecompress(compressedPart1, 29418, 0, 0, &decompressedPart1, true);
+
+ memcpy((byte *)_mainMenu.getPixels() + curPos, decompressedPart1, decompressedSize);
+ curPos += decompressedSize;
+
+ delete[] compressedPart1;
+ delete[] decompressedPart1;
+ alfred7.seek(2500220, SEEK_SET);
+ alfred7.read((byte *)_mainMenu.getPixels() + curPos, 32768);
+ curPos += 32768;
+ byte *compressedPart2 = new byte[30288];
+ alfred7.read(compressedPart2, 30288);
+ byte *decompressedPart2 = nullptr;
+ decompressedSize = rleDecompress(compressedPart2, 30288, 0, 0, &decompressedPart2, true);
+
+ memcpy((byte *)_mainMenu.getPixels() + curPos, decompressedPart2, decompressedSize);
+ curPos += decompressedSize;
+ debug("Settings menu size loaded: %d, with last block %d", curPos, curPos + 92160);
+ delete[] compressedPart2;
+ delete[] decompressedPart2;
+ alfred7.seek(2563266, SEEK_SET);
+ alfred7.read((byte *)_mainMenu.getPixels() + curPos, 92160);
+
readButton(alfred7, 3193376, _saveButtons, _saveGameRect);
readButton(alfred7, alfred7.pos(), _loadButtons, _loadGameRect);
readButton(alfred7, alfred7.pos(), _soundsButtons, _soundsRect);
@@ -324,9 +309,6 @@ void MenuManager::loadMenuTexts() {
exe.seek(kInventoryDescriptionsOffset, SEEK_SET);
exe.read(descBuffer, kInventoryDescriptionsSize);
_inventoryDescriptions = _res->processTextData(descBuffer, kInventoryDescriptionsSize, true);
- for(size_t i = 0; i < _inventoryDescriptions.size(); i++) {
- debug("Inventory description %d: %s", i, _inventoryDescriptions[i][0].c_str());
- }
delete[] descBuffer;
Common::String desc = "";
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 569d314581b..9e5a51dec7b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -76,9 +76,12 @@ PelrockEngine::~PelrockEngine() {
delete[] _inventoryOverlayState.arrows[0];
delete[] _inventoryOverlayState.arrows[1];
// Free path-finding buffers (allocated via malloc in findPath)
- free(_currentContext.pathBuffer);
- free(_currentContext.movementBuffer);
- free(_currentContext.compressed_path);
+ if(_currentContext.pathBuffer) {
+ free(_currentContext.pathBuffer);
+ }
+ if(_currentContext.movementBuffer) {
+ free(_currentContext.movementBuffer);
+ }
}
uint32 PelrockEngine::getFeatures() const {
@@ -1874,7 +1877,7 @@ void PelrockEngine::walkLoop(int16 x, int16 y, AlfredDirection direction) {
void PelrockEngine::walkTo(int x, int y) {
_currentStep = 0;
- PathContext context = {nullptr, nullptr, nullptr, 0, 0, 0};
+ PathContext context = {nullptr, nullptr, 0, 0, 0};
findPath(_alfredState.x, _alfredState.y, x, y, _room->_currentRoomWalkboxes, &context, _currentHotspot);
_currentContext = context;
_alfredState.setState(ALFRED_WALKING);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 96286d5b569..4dad41aeb7f 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -137,7 +137,7 @@ private:
// walking
int _currentStep = 0;
- PathContext _currentContext;
+ PathContext _currentContext = {nullptr, nullptr, 0, 0, 0};
Graphics::ManagedSurface _currentBackground; // Clean background - NEVER modified
Graphics::ManagedSurface _bgScreen;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index fb597db08c8..3440d1b0ab9 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -37,14 +37,14 @@ enum Cursor {
COMBINATION
};
-const byte kActionMaskNone = 0;
-const byte kActionMaskOpen = 1;
-const byte kActionMaskClose = 2;
+const byte kActionMaskNone = 0;
+const byte kActionMaskOpen = 1;
+const byte kActionMaskClose = 2;
const byte kActionMaskUnknown = 4;
-const byte kActionMaskPickup = 8;
-const byte kActionMaskTalk = 16;
-const byte kActionMaskPush = 32;
-const byte kActionMaskPull = 128;
+const byte kActionMaskPickup = 8;
+const byte kActionMaskTalk = 16;
+const byte kActionMaskPush = 32;
+const byte kActionMaskPull = 128;
enum VerbIcon {
PICKUP,
@@ -93,31 +93,31 @@ const int kAlfredInitialPosY = 279;
// Direction flags (bit-packed)
const byte kMoveRight = 0x01; // Move right (positive X)
-const byte kMoveLeft = 0x02; // Move left (negative X)
+const byte kMoveLeft = 0x02; // Move left (negative X)
const byte kMoveHoriz = 0x03; // Horizontal movement mask
-const byte kMoveDown = 0x04; // Move down (positive Y)
-const byte kMoveUp = 0x08; // Move up (negative Y)
-const byte kMoveVert = 0x0C; // Vertical movement mask
-const int kMaxPathLength = 100;
-const int kMaxMovementSteps = 100; // 500 bytes / 5 bytes per step
-const byte kPathEnd = 0xFF; // End of path marker
+const byte kMoveDown = 0x04; // Move down (positive Y)
+const byte kMoveUp = 0x08; // Move up (negative Y)
+const byte kMoveVert = 0x0C; // Vertical movement mask
+const int kMaxPathLength = 100;
+const int kMaxMovementSteps = 100; // 500 bytes / 5 bytes per step
+const byte kPathEnd = 0xFF; // End of path marker
-const int kMaxCharsPerLine = 0x2F; // 47 characters
-const int kMaxLines = 5; // Maximum number of lines per page
+const int kMaxCharsPerLine = 0x2F; // 47 characters
+const int kMaxLines = 5; // Maximum number of lines per page
const byte kAlfredColor = 0x0D;
enum OverlayMode {
- OVERLAY_NONE = 0,
- OVERLAY_CHOICES = 1,
+ OVERLAY_NONE = 0,
+ OVERLAY_CHOICES = 1,
OVERLAY_PICKUP_ICON = 2,
- OVERLAY_ACTION = 3
+ OVERLAY_ACTION = 3
};
// Passerby direction constants
const byte kPasserbyRight = 0;
-const byte kPasserbyLeft = 1;
-const byte kPasserbyDown = 2;
+const byte kPasserbyLeft = 1;
+const byte kPasserbyDown = 2;
const byte kIconBlinkPeriod = 4;
@@ -203,8 +203,7 @@ struct AlfredState {
}
};
-struct ShakeEffectState
-{
+struct ShakeEffectState {
bool enabled = false;
int shakeX = 0;
int shakeY = 0;
@@ -221,9 +220,8 @@ struct ShakeEffectState
}
};
-
struct MovementStep {
- byte flags; /* Direction flags (see kMove* constants) */
+ byte flags; /* Direction flags (see kMove* constants) */
uint16 distanceX; // Horizontal distance to move
uint16 distanceY; // Vertical distance to move
};
@@ -232,12 +230,11 @@ struct MovementStep {
* Pathfinding context
*/
struct PathContext {
- byte *pathBuffer; // Sequence of walkbox indices
+ byte *pathBuffer; // Sequence of walkbox indices
MovementStep *movementBuffer; // Array of movement steps
- byte *compressed_path; // Final compressed path
- uint16 pathLength;
- uint16 movementCount;
- uint16 compressed_length;
+ uint16 pathLength;
+ uint16 movementCount;
+ uint16 compressed_length;
};
struct Anim {
@@ -630,7 +627,14 @@ struct GameStateData {
for (uint i = 0; i < inventoryItems.size(); i++) {
if (inventoryItems[i] == id) {
inventoryItems.remove_at(i);
- return;
+ break;
+ }
+ }
+ if (selectedInventoryItem == id) {
+ if (inventoryItems.size() > 0) {
+ selectedInventoryItem = inventoryItems[0];
+ } else {
+ selectedInventoryItem = -1;
}
}
}
Commit: ad219ccbbd08185baf8d2bf022205f32d2019d36
https://github.com/scummvm/scummvm/commit/ad219ccbbd08185baf8d2bf022205f32d2019d36
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:26+02:00
Commit Message:
PELROCK: Fixes book titles not having new lines
Changed paths:
R engines/pelrock/library_books.h
engines/pelrock/computer.cpp
engines/pelrock/computer.h
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index fe8b574f810..5c90775c4ac 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -21,10 +21,10 @@
#include "common/events.h"
#include "common/system.h"
+#include "graphics/cursorman.h"
#include "graphics/paletteman.h"
#include "pelrock/computer.h"
-#include "pelrock/library_books.h"
#include "pelrock/pelrock.h"
namespace Pelrock {
@@ -41,6 +41,22 @@ Computer::Computer(PelrockEventManager *eventMan)
init();
}
+Common::StringArray split(const Common::String &str) {
+ Common::StringArray result;
+ Common::String token;
+
+ for (uint i = 0; i < str.size(); i++) {
+ if ((unsigned char)str[i] == 0xC8) {
+ result.push_back(token);
+ token.clear();
+ } else {
+ token += str[i];
+ }
+ }
+ result.push_back(token); // last token
+ return result;
+}
+
void Computer::init() {
Common::File alfred7File;
if (!alfred7File.open("ALFRED.7")) {
@@ -51,12 +67,13 @@ void Computer::init() {
alfred7File.seek(kBookDataOffset, SEEK_SET);
while (alfred7File.pos() < kBookDataEnd) {
LibraryBook book;
-
- book.title = alfred7File.readString(0, kBookTitleSize);
- book.author = alfred7File.readString(0, kBookAuthorSize);
+ Common::String title = alfred7File.readString(0, kBookTitleSize);
+ title.trim();
+ book.title = split(title);
+ Common::String author = alfred7File.readString(0, kBookAuthorSize);
+ author.trim();
+ book.author = split(author);
book.genre = alfred7File.readString(0, kBookGenreSize);
- book.title.trim();
- book.author.trim();
book.genre.trim();
book.inventoryIndex = alfred7File.readByte() - 55;
book.shelf = alfred7File.readByte();
@@ -100,11 +117,13 @@ void Computer::cleanup() {
}
g_engine->_screen->markAllDirty();
g_engine->_screen->update();
+ CursorMan.showMouse(true);
}
int Computer::run() {
loadBackground();
_state = STATE_MAIN_MENU;
+ CursorMan.showMouse(false);
g_engine->changeCursor(DEFAULT);
while (!g_engine->shouldQuit() && _state != STATE_EXIT) {
@@ -185,14 +204,35 @@ void Computer::drawScreen() {
Common::String titleLine = _computerText[3][0];
int titlePlaceholderIndex = titleLine.findFirstOf("XXXX");
- titleLine.replace(titlePlaceholderIndex, titleLine.size() - titlePlaceholderIndex, book.title);
- g_engine->_graphics->drawColoredText(g_engine->_screen, titleLine, textX, textY, 340, defaultColor, g_engine->_smallFont);
+ int titleIndex = 0;
+ while(titleIndex < book.title.size()) {
+ Common::String thisLine;
+ if(titleIndex == 0) {
+ thisLine = titleLine;
+ thisLine.replace(titlePlaceholderIndex, titleLine.size() - titlePlaceholderIndex, book.title[titleIndex]);
+ } else {
+ thisLine = book.title[titleIndex];
+ }
+ g_engine->_graphics->drawColoredText(g_engine->_screen, thisLine, textX, textY + _lineHeight * titleIndex, 340, defaultColor, g_engine->_smallFont);
+ titleIndex++;
+ }
// Author
Common::String authorLine = _computerText[4][0];
int authorPlaceholderIndex = authorLine.findFirstOf("XXXX");
- authorLine.replace(authorPlaceholderIndex, authorLine.size() - authorPlaceholderIndex, book.author);
- g_engine->_graphics->drawColoredText(g_engine->_screen, authorLine, textX, textY + increment, 340, defaultColor, g_engine->_smallFont);
+ int authorIndex = 0;
+
+ while(authorIndex < book.author.size()) {
+ Common::String thisLine;
+ if(authorIndex == 0) {
+ thisLine = authorLine;
+ thisLine.replace(authorPlaceholderIndex, authorLine.size() - authorPlaceholderIndex, book.author[authorIndex]);
+ } else {
+ thisLine = book.author[authorIndex];
+ }
+ g_engine->_graphics->drawColoredText(g_engine->_screen, thisLine, textX, textY + increment + _lineHeight * authorIndex, 340, defaultColor, g_engine->_smallFont);
+ authorIndex++;
+ }
// Genre
Common::String genreLine = _computerText[5][0];
@@ -258,7 +298,9 @@ void Computer::handleSearchInput() {
void Computer::handleResultsDisplay() {
if (_events->_lastKeyEvent == Common::KEYCODE_s) {
if (!_searchResults.empty()) {
- _currentResult = (_currentResult + 1) % _searchResults.size();
+ _currentResult = (_currentResult + 1);
+ if(_currentResult >= _searchResults.size())
+ _state = STATE_MAIN_MENU;
}
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
} else if (_events->_lastKeyEvent == Common::KEYCODE_m) {
@@ -292,16 +334,16 @@ void Computer::memorizeBook(int bookIndex) {
g_engine->_state->libraryShelf = book.shelf; // 0-based shelf index
g_engine->_state->selectedBookIndex = book.inventoryIndex;
- g_engine->_state->bookLetter = book.title[0];
+ g_engine->_state->bookLetter = book.title[0][0];
- debug("Memorized book '%s' with index %d, shelf %d, letter %c", book.title.c_str(), g_engine->_state->selectedBookIndex, g_engine->_state->libraryShelf, g_engine->_state->bookLetter);
+ debug("Memorized book '%s' with index %d, shelf %d, letter %c", book.title[0].c_str(), g_engine->_state->selectedBookIndex, g_engine->_state->libraryShelf, g_engine->_state->bookLetter);
}
void Computer::performSearch() {
_searchResults.clear();
for (int i = 0; i < _libraryBooks.size(); i++) {
- Common::String searchField = _searchType == 0 ? _libraryBooks[i].title : _libraryBooks[i].author;
+ Common::String searchField = _searchType == 0 ? _libraryBooks[i].title[0] : _libraryBooks[i].author[0];
// Check if first letter matches (case-insensitive)
char firstChar = searchField[0];
diff --git a/engines/pelrock/computer.h b/engines/pelrock/computer.h
index c34e918f873..f4ff43c5bdf 100644
--- a/engines/pelrock/computer.h
+++ b/engines/pelrock/computer.h
@@ -27,11 +27,34 @@
#include "graphics/managed_surface.h"
#include "pelrock/events.h"
-#include "pelrock/library_books.h"
namespace Pelrock {
-class PelrockEngine;
+// Book data location in ALFRED.7
+static const uint32 kBookDataOffset = 0x309E0;
+static const uint32 kBookDataEnd = 0x33F05;
+static const int kBookEntrySize = 108; // 55 + 30 + 20 + 1 + 1 + 1
+
+// Field sizes
+static const int kBookTitleSize = 55;
+static const int kBookAuthorSize = 30;
+static const int kBookGenreSize = 20;
+
+// Status byte values
+static const byte kBookStatusCatalogOnly = 0x01; // No physical copy
+static const byte kBookStatusPhysical = 0x02; // Has physical copy on shelf
+
+struct LibraryBook {
+ Common::StringArray title; //55 bytes for title
+ Common::StringArray author; //30 bytes for author
+ Common::String genre; //20 bytes for genre
+ byte inventoryIndex;
+ byte shelf; // 1-3 for row number, 0 if catalog-only
+ bool available; // true = can be found on shelf, false = catalog only
+};
+
+
+static const LibraryBook noBook = { Common::StringArray(), Common::StringArray(), "", 0, 0, false};
class Computer {
public:
diff --git a/engines/pelrock/library_books.h b/engines/pelrock/library_books.h
deleted file mode 100644
index 7f38362b7d6..00000000000
--- a/engines/pelrock/library_books.h
+++ /dev/null
@@ -1,308 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * Alfred Pelrock Library Book Database
- * Extracted from ALFRED.7 offset 0x309E0 to 0x33F05
- *
- * This file was auto-generated by extract_alfred7_books_full.py
- * DO NOT EDIT MANUALLY
- *
- * Book format in ALFRED.7 (108 bytes per entry):
- * - Title: 55 bytes (space-padded)
- * - Author: 30 bytes (space-padded)
- * - Genre: 20 bytes (space-padded)
- * - Shelf Letter: 1 byte (A-Z or space if catalog-only)
- * - Shelf Row: 1 byte (1-3 or space)
- * - Status: 1 byte (0x01=catalog only, 0x02=physical copy)
- */
-
-#ifndef PELROCK_LIBRARY_BOOKS_H
-#define PELROCK_LIBRARY_BOOKS_H
-
-#include "common/scummsys.h"
-
-namespace Pelrock {
-
-// Book data location in ALFRED.7
-static const uint32 kBookDataOffset = 0x309E0;
-static const uint32 kBookDataEnd = 0x33F05;
-static const int kBookEntrySize = 108; // 55 + 30 + 20 + 1 + 1 + 1
-
-// Field sizes
-static const int kBookTitleSize = 55;
-static const int kBookAuthorSize = 30;
-static const int kBookGenreSize = 20;
-
-// Status byte values
-static const byte kBookStatusCatalogOnly = 0x01; // No physical copy
-static const byte kBookStatusPhysical = 0x02; // Has physical copy on shelf
-
-struct LibraryBook {
- Common::String title; //55 bytes for title
- Common::String author; //30 bytes for author
- Common::String genre; //20 bytes for genre
- byte inventoryIndex;
- byte shelf; // 1-3 for row number, 0 if catalog-only
- bool available; // true = can be found on shelf, false = catalog only
-};
-
-static const LibraryBook noBook = {"", "", "", 0, 0, false};
-
-
-// static const int kLibraryBookCount = 125;
-
-// static const LibraryBook kLibraryBooks[] = {
-// // Book 1: Los hombres: ¡ Como caparlos !
-// {"Los hombres: ¡ Como caparlos !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
-// // Book 2: Mujeres del mundo: ¡ No os depileis las ...
-// {"Mujeres del mundo: ¡ No os depileis las axilas !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
-// // Book 3: Gato por liebre
-// {"Gato por liebre", "Karlos Arguiñano", "Cocina", 'I', 1, true},
-// // Book 4: Hamlet
-// {"Hamlet", "William Shakespeare", "Teatro", ' ', 0, false},
-// // Book 5: Fausto
-// {"Fausto", "Goethe", "Novela", ' ', 0, false},
-// // Book 6: Enrique de Ofterdingen
-// {"Enrique de Ofterdingen", "Novalis", "Novela", 'J', 1, true},
-// // Book 7: Guia de desobediencia civica
-// {"Guia de desobediencia civica", "Azagra", "Ensayo", ' ', 0, false},
-// // Book 8: Literatura en la edad de piedra: cuestio...
-// {"Literatura en la edad de piedra: cuestion de fuerza", "Profesor Cebollo", "Ensayo", ' ', 0, false},
-// // Book 9: Turbo C ++ con Intratex
-// {"Turbo C ++ con Intratex", "Programadores reunidos", "Informatica", ' ', 0, false},
-// // Book 10: Codigo Maquina a pelo
-// {"Codigo Maquina a pelo", "Programadores reunidos", "Informatica", 'K', 1, true},
-// // Book 11: Asesino por vocacion
-// {"Asesino por vocacion", "Chema Ton", "Novela negra", ' ', 0, false},
-// // Book 12: Poemas rebuscados
-// {"Poemas rebuscados", "Ramon Rodriguez", "Poesia", ' ', 0, false},
-// // Book 13: El parto de las tortugas: Un proceso len...
-// {"El parto de las tortugas: Un proceso lento", "Profesor Lorin Colorado", "Biologia", ' ', 0, false},
-// // Book 14: Te parto la cara ¡ Capuyo !
-// {"Te parto la cara ¡ Capuyo !", "Jhonny Rapper", "Critica Social", 'L', 3, true},
-// // Book 15: En los tugurios del Himalaya
-// {"En los tugurios del Himalaya", "Coronel Tapioca", "Aventuras", ' ', 0, false},
-// // Book 16: En las callejuelas del amazonas
-// {"En las callejuelas del amazonas", "Coronel Tapioca", "Aventuras", ' ', 0, false},
-// // Book 17: En las selvas de Londres
-// {"En las selvas de Londres", "Coronel Tapioca", "Aventuras", 'M', 1, true},
-// // Book 18: Sueños binarios
-// {"Sueños binarios", "Doctor Chip", "Ciencia ficcion", ' ', 0, false},
-// // Book 19: Cien cuentos cortisimos
-// {"Cien cuentos cortisimos", "Billi el rapido", "Novela", ' ', 0, false},
-// // Book 20: Teoria de la relatividad
-// {"Teoria de la relatividad", "Alfred Einstein", "Ciencia", ' ', 0, false},
-// // Book 21: El ultimo paso para la cuadratura del ci...
-// {"El ultimo paso para la cuadratura del circulo", "Anonimo", "Filosofia", 'N', 1, true},
-// // Book 22: Correlacion entre el sentido de los colo...
-// {"Correlacion entre el sentido de los colores y sonidos", "Anonimo", "Filosofia", ' ', 0, false},
-// // Book 23: Los cuatro evangelios: Interpretados por...
-// {"Los cuatro evangelios: Interpretados por ordenador", "Doctor Chip", "Teologia", ' ', 0, false},
-// // Book 24: Enciclopedia de bolsillo
-// {"Enciclopedia de bolsillo", "Profesor Lumbreras", "Enciclopedia", 'O', 1, true},
-// // Book 25: Sigueme y revienta
-// {"Sigueme y revienta", "M. Indurain", "Deporte", 'P', 3, true},
-// // Book 26: Me duele too...
-// {"Me duele too...", "Carmen Opausica", "Ensayo", ' ', 0, false},
-// // Book 27: El Perro de Sam Rocker si tiene rabo
-// {"El Perro de Sam Rocker si tiene rabo", "El Perro de Sam Rocker", "Biografia", ' ', 0, false},
-// // Book 28: Donde estara mi carro ?
-// {"Donde estara mi carro ?", "Manolo Escobar", "Aventuras", ' ', 0, false},
-// // Book 29: Oh tu, bella flor del jardin
-// {"Oh tu, bella flor del jardin", "La abeja Maya", "Poesia", 'Q', 2, true},
-// // Book 30: Yogui, ¡ Bajate de esa motoneta !
-// {"Yogui, ¡ Bajate de esa motoneta !", "Bubu", "Filosofia", ' ', 0, false},
-// // Book 31: Odio a muerte a loh mardito rohedore !
-// {"Odio a muerte a loh mardito rohedore !", "Er gato Yin", "Zoologia", ' ', 0, false},
-// // Book 32: Pissi, Dissi, ¡ Sargan de su aguhero !
-// {"Pissi, Dissi, ¡ Sargan de su aguhero !", "Er gato Yin", "Zoologia", ' ', 0, false},
-// // Book 33: Mardito sea ... ¡ Er queso !
-// {"Mardito sea ... ¡ Er queso !", "Er gato Yin", "Zoologia", ' ', 0, false},
-// // Book 34: La mate porque era mia
-// {"La mate porque era mia", "Loquillo", "Novela", ' ', 0, false},
-// // Book 35: Los gallos: Esos desconocidos
-// {"Los gallos: Esos desconocidos", "Paco rico", "Zoologia", ' ', 0, false},
-// // Book 36: Cuentos corrientes
-// {"Cuentos corrientes", "Pepe Lopez", "Novela", 'R', 1, true},
-// // Book 37: Mas madera
-// {"Mas madera", "R. Gepetto", "Bricolage", 'S', 2, true},
-// // Book 38: Cuentos del Lejano Oriente
-// {"Cuentos del Lejano Oriente", "Jhonny Mc. Dowall", "Novela", ' ', 0, false},
-// // Book 39: Saca el guiski cheli
-// {"Saca el guiski cheli", "Manolo lailo", "Cronica Social", ' ', 0, false},
-// // Book 40: Ta totao !
-// {"Ta totao !", "Lao Tse", "Filosofia", ' ', 0, false},
-// // Book 41: Mis conversaciones con el señor Roca
-// {"Mis conversaciones con el señor Roca", "Francisca Gando", "Epistolar", 'T', 2, true},
-// // Book 42: Guia para la supervivencia
-// {"Guia para la supervivencia", "Robinson Crusoe", "Manual", ' ', 0, false},
-// // Book 43: No esperes a ser la segunda: ¡ Engaña a ...
-// {"No esperes a ser la segunda: ¡ Engaña a tu marido !", "Herminia Gutierrez", "Feminismo", ' ', 0, false},
-// // Book 44: Yoga Sutras
-// {"Yoga Sutras", "Patanjali", "Filosofia", 'X', 3, true},
-// // Book 45: El juego de los Abalorios
-// {"El juego de los Abalorios", "Herman Hesse", "Novela", ' ', 0, false},
-// // Book 46: Tienes suerte de ser tan pequeño, ¡ mard...
-// {"Tienes suerte de ser tan pequeño, ¡ mardito roedo !", "Er gato Yin", "Novela", ' ', 0, false},
-// // Book 47: Como hacerse rico en diez minutos
-// {"Como hacerse rico en diez minutos", "El Dioni", "Manual", 'Y', 1, true},
-// // Book 48: Te querre a pesar de tu madre
-// {"Te querre a pesar de tu madre", "Corin Tellado", "Novela rosa", ' ', 0, false},
-// // Book 49: Hasta que el mando a distancia nos separ...
-// {"Hasta que el mando a distancia nos separe", "Corin Tellado", "Novela rosa", ' ', 0, false},
-// // Book 50: Una pasion ostentorea
-// {"Una pasion ostentorea", "Corin Tellado y Jesus Gil", "Novela rosa", 'Z', 3, true},
-// // Book 51: Por mi, como si te la machacas
-// {"Por mi, como si te la machacas", "Seneca", "Filosofia", ' ', 0, false},
-// // Book 52: Conversaciones con mi caballo
-// {"Conversaciones con mi caballo", "Jesus Gil", "Humor", ' ', 0, false},
-// // Book 53: El poder curativo de la mierda comun
-// {"El poder curativo de la mierda comun", "Sri Ramachrinaraska", "Esoterismo", ' ', 1, true},
-// // Book 54: La liberacion mediante la eneriga de los...
-// {"La liberacion mediante la eneriga de los pedos", "Sri Ramachrinaraska", "Esoterismo", ' ', 0, false},
-// // Book 55: Sobre la imperceptibilidad de lo imperce...
-// {"Sobre la imperceptibilidad de lo imperceptible", "Perogrullo", "Ensayo", ' ', 0, false},
-// // Book 56: Piojos; como educarlos sin traumas
-// {"Piojos; como educarlos sin traumas", "Franz Franzfrenz", "Psicologia", ' ', 0, false},
-// // Book 57: I Ching
-// {"I Ching", "Richard Willem", "Filosofia", ' ', 0, false},
-// // Book 58: No se nada, ni me importa
-// {"No se nada, ni me importa", "Socrates", "Filosofia", 'U', 2, true},
-// // Book 59: No he sido yo, ¡ Lo juro !
-// {"No he sido yo, ¡ Lo juro !", "Juan Jose Gil", "Biografia", ' ', 0, false},
-// // Book 60: Relatos cortos
-// {"Relatos cortos", "Tachenko", "Novela de ficcion", 'V', 3, true},
-// // Book 61: El martillo como elemento cognitivo
-// {"El martillo como elemento cognitivo", "Friedrich Nietzsche", "Filosofia", ' ', 0, false},
-// // Book 62: La maravillosa vida del escarabajo pelot...
-// {"La maravillosa vida del escarabajo pelotero (v. I)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
-// // Book 63: La maravillosa vida del escarabajo pelot...
-// {"La maravillosa vida del escarabajo pelotero (v. II)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
-// // Book 64: La maravillosa vida del escarabajo pelot...
-// {"La maravillosa vida del escarabajo pelotero (v. III)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
-// // Book 65: La maravillosa vida del escarabajo pelot...
-// {"La maravillosa vida del escarabajo pelotero (v. IV)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
-// // Book 66: La maravillosa vida del escarabajo pelot...
-// {"La maravillosa vida del escarabajo pelotero (v. V)", "Dr. Federico Ãazo", "Botanica", ' ', 0, false},
-// // Book 67: Tu eliges: Tu madre o yo
-// {"Tu eliges: Tu madre o yo", "Anonimo", "Psicologia aplicada", 'W', 3, true},
-// // Book 68: Mi lucha
-// {"Mi lucha", "Adolf Hitler", "Humor negro", ' ', 0, false},
-// // Book 69: Cuentos de amor y desidia
-// {"Cuentos de amor y desidia", "Jardiel Poncela", "Teatro", ' ', 1, true},
-// // Book 70: Nuevas andanzas de Zaratustra
-// {"Nuevas andanzas de Zaratustra", "Anonimo", "Aventuras", ' ', 2, true},
-// // Book 71: Me se cuadre ¡ Coño !
-// {"Me se cuadre ¡ Coño !", "Sargento Cienfuegos", "Etica militar", ' ', 2, true},
-// // Book 72: Gatos: solos o con Ketchup
-// {"Gatos: solos o con Ketchup", "El perro de Sam Rocker", "Cocina", ' ', 1, true},
-// // Book 73: Querida Adelaida: mi marido NO ha dejado...
-// {"Querida Adelaida: mi marido NO ha dejado de roncar", "Maruja Mones", "Epistolar", ' ', 0, false},
-// // Book 74: Sobre el papel de El Lepe en el nuevo Or...
-// {"Sobre el papel de El Lepe en el nuevo Orden Mundial", "General Sintacha", "Estrategia", ' ', 0, false},
-// // Book 75: Aqui no hay nadie que se acueste sin cen...
-// {"Aqui no hay nadie que se acueste sin cenar (v. I)", "Fidel Castro", "Politica", ' ', 1, true},
-// // Book 76: Aqui no hay nadie que se acueste sin cen...
-// {"Aqui no hay nadie que se acueste sin cenar (v. II)", "Fidel Castro", "Politica", ' ', 0, false},
-// // Book 77: Aqui no hay nadie que se acueste sin cen...
-// {"Aqui no hay nadie que se acueste sin cenar (v. III)", "Fidel Castro", "Politica", ' ', 0, false},
-// // Book 78: Aqui no hay nadie que se acueste sin cen...
-// {"Aqui no hay nadie que se acueste sin cenar (v. IV)", "Fidel Castro", "Politica", ' ', 0, false},
-// // Book 79: Aqui no hay nadie que se acueste sin cen...
-// {"Aqui no hay nadie que se acueste sin cenar (v. V)", "Fidel Castro", "Politica", ' ', 0, false},
-// // Book 80: Domine la metafisica en 5 dias
-// {"Domine la metafisica en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
-// // Book 81: Domine el ensamblador en 5 dias
-// {"Domine el ensamblador en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
-// // Book 82: Dominese a si mismo en 5 dias
-// {"Dominese a si mismo en 5 dias", "Profesor Pinocho", "Manual", ' ', 1, true},
-// // Book 83: Piernas de Ciertopelo
-// {"Piernas de Ciertopelo", "Chichi Mondongo", "Erotica", ' ', 2, true},
-// // Book 84: Otra vuelta de tuerca
-// {"Otra vuelta de tuerca", "Pepe, el fontanero", "Bricolage", ' ', 2, true},
-// // Book 85: La Tierra: ¡ Planeta limpio !
-// {"La Tierra: ¡ Planeta limpio !", "Juan, el basurero", "Ciencia Ficcion", ' ', 2, true},
-// // Book 86: Liberad a Brian !
-// {"Liberad a Brian !", "Roger Rabitt", "Historica", ' ', 2, true},
-// // Book 87: La vida es una mierda
-// {"La vida es una mierda", "Juanjo Dido", "Ensayo", ' ', 2, true},
-// // Book 88: No era eso lo que yo di a entender
-// {"No era eso lo que yo di a entender", "Jesus de Nazaret", "Religion", ' ', 2, true},
-// // Book 89: Castigos a Piratas Informaticos
-// {"Castigos a Piratas Informaticos", "Torquemada", "Inquisicion", ' ', 1, true},
-// // Book 90: Confiesa, bruja asquerosa
-// {"Confiesa, bruja asquerosa", "Troquemada", "Inquisicion", ' ', 1, true},
-// // Book 91: El cocherito lere
-// {"El cocherito lere", "Paco costas", "Automovilismo", ' ', 1, true},
-// // Book 92: La musica amansa a las fieras
-// {"La musica amansa a las fieras", "Wagner", "Musica", ' ', 2, true},
-// // Book 93: Pinocho en el Parlamento
-// {"Pinocho en el Parlamento", "Carmen Tirosa", "Cronica Social", ' ', 0, false},
-// // Book 94: Hagase famoso gracias a la energia de la...
-// {"Hagase famoso gracias a la energia de las petunias", "Carmelo Cuelo", "Esoterismo", ' ', 0, false},
-// // Book 95: Dios mio, ¡ Que cruz !
-// {"Dios mio, ¡ Que cruz !", "Jesus de Nazaret", "Autobiografia", ' ', 0, false},
-// // Book 96: Psicologia de la motivacion inmotivada
-// {"Psicologia de la motivacion inmotivada", "Dr. Chemi", "Psicologia", ' ', 2, true},
-// // Book 97: Magia rosa para iniciados
-// {"Magia rosa para iniciados", "Manolo Lailo", "Esoterismo", ' ', 0, false},
-// // Book 98: Un mundo Feliz
-// {"Un mundo Feliz", "Aldous Huxley", "Novela", ' ', 0, false},
-// // Book 99: Sexo oral y por escrito
-// {"Sexo oral y por escrito", "Franz Masturmann", "Sexologia", ' ', 3, true},
-// // Book 100: El contrato social de aprendizaje
-// {"El contrato social de aprendizaje", "Rousseau", "Ensayo", ' ', 1, true},
-// // Book 101: Vida sexual del escarabajo de la Patagon...
-// {"Vida sexual del escarabajo de la Patagonia", "Dr. Tedio Plomez", "Botanica", ' ', 3, true},
-// // Book 102: Manual del necrofago
-// {"Manual del necrofago", "Jesus Gil", "Manual", ' ', 0, false},
-// // Book 103: Canticos espirituales en formato *.ZIP
-// {"Canticos espirituales en formato *.ZIP", "Doctor Chip", "Poesia", 'B', 1, true},
-// // Book 104: Novela erotica en formato *.MAS
-// {"Novela erotica en formato *.MAS", "Doctor Chip", "Erotica", ' ', 0, false},
-// // Book 105: Plopuestas colelacionales en coyuntulas ...
-// {"Plopuestas colelacionales en coyuntulas bilatelales", "Senadol Chan Chu Yo", "Politica", ' ', 0, false},
-// // Book 106: Ereh un fistro
-// {"Ereh un fistro", "Chiquito de la casa", "Humor", ' ', 0, false},
-// // Book 107: El hacedor de la Lluvia
-// {"El hacedor de la Lluvia", "Herman Hesse", "Cuentos", ' ', 0, false},
-// // Book 108: Pasiones recalcitrantes
-// {"Pasiones recalcitrantes", "Corin Tellado", "Novela rosa", 'C', 2, true},
-// // Book 109: No me mates con tomate
-// {"No me mates con tomate", "Karlos Arguiñano", "Cocina", ' ', 0, false},
-// // Book 110: El valenciano en los albores del siglo X...
-// {"El valenciano en los albores del siglo XXI", "Jaume i Pascual", "Nacionalismo", 'D', 1, true},
-// // Book 111: El valenciano es la lengua del futuro
-// {"El valenciano es la lengua del futuro", "Jaume i Pascual", "Nacionalismo", ' ', 0, false},
-// // Book 112: Valencia: mes que mai
-// {"Valencia: mes que mai", "Jaume i Pascual", "Nacionalismo", ' ', 0, false},
-// // Book 113: Sistema inmunitario de los cefalopodos (...
-// {"Sistema inmunitario de los cefalopodos (v. I)", "Dr. Tedio Plomez", "Biologia", 'E', 3, true},
-// // Book 114: Sistema inmunitario de los cefalopodos (...
-// {"Sistema inmunitario de los cefalopodos (v. II)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
-// // Book 115: Sistema inmunitario de los cefalopodos (...
-// {"Sistema inmunitario de los cefalopodos (v. III)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
-// // Book 116: Sistema inmunitario de los cefalopodos (...
-// {"Sistema inmunitario de los cefalopodos (v. IV)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
-// // Book 117: Sistema inmunitario de los cefalopodos (...
-// {"Sistema inmunitario de los cefalopodos (v. V)", "Dr. Tedio Plomez", "Biologia", ' ', 0, false},
-// // Book 118: Dos mas dos son cinco
-// {"Dos mas dos son cinco", "Joan Josep Climent Colomer", "Matematicas", 'F', 1, true},
-// // Book 119: El algebra es la base de la programacion
-// {"El algebra es la base de la programacion", "Joan Josep Climent Colomer", "Humor absurdo", ' ', 0, false},
-// // Book 120: Autobiografia de una miseria humana
-// {"Autobiografia de una miseria humana", "Joan Josep Climent Colomer", "Esperpento", ' ', 0, false},
-// // Book 121: El arte mundial antes y despues de mi
-// {"El arte mundial antes y despues de mi", "Nacho Taulet Perman", "Arte", ' ', 0, false},
-// // Book 122: La parte Creativa
-// {"La parte Creativa", "Nacho Taulet Perman", "Arte", 'G', 2, true},
-// // Book 123: Llamame cuando se muera tu abuelo
-// {"Llamame cuando se muera tu abuelo", "Jose Bart Carrion", "Teatro", ' ', 0, false},
-// // Book 124: Soy un incomprendido
-// {"Soy un incomprendido", "Jose Bart Carrion", "Autobiografia", ' ', 0, false},
-// // Book 125: El arte de limpiar botijos por dentro
-// {"El arte de limpiar botijos por dentro", "Varios autores", "Manualidades", ' ', 0, false},
-// };
-
-} // namespace Pelrock
-
-#endif // PELROCK_LIBRARY_BOOKS_H
Commit: 8577942222838db20d3243fe4d815e44228e727f
https://github.com/scummvm/scummvm/commit/8577942222838db20d3243fe4d815e44228e727f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:27+02:00
Commit Message:
PELROCK: Implement loading of background book
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/computer.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 1ccd01c386b..b736bab7f60 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -2206,6 +2206,11 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
player.run();
break;
}
+ case 96: {
+ BackgroundBook book(_events, _res);
+ book.run();
+ break;
+ }
default: {
if (inventoryObject >= 11 && inventoryObject <= 47) {
playAlfredSpecialAnim(0);
diff --git a/engines/pelrock/computer.h b/engines/pelrock/computer.h
index f4ff43c5bdf..7e9379ccad8 100644
--- a/engines/pelrock/computer.h
+++ b/engines/pelrock/computer.h
@@ -53,9 +53,6 @@ struct LibraryBook {
bool available; // true = can be found on shelf, false = catalog only
};
-
-static const LibraryBook noBook = { Common::StringArray(), Common::StringArray(), "", 0, 0, false};
-
class Computer {
public:
Computer(PelrockEventManager *eventMan);
Commit: 719de81bfbd27c25712545bd8786aed4d98c121b
https://github.com/scummvm/scummvm/commit/719de81bfbd27c25712545bd8786aed4d98c121b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:27+02:00
Commit Message:
PELROCK: Removes all items when moving to Egypt
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 9e5a51dec7b..8db72e9a20f 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -307,7 +307,19 @@ void PelrockEngine::travelToEgypt() {
delete[] palette;
_screen->markAllDirty();
_screen->update();
+
+ _alfredState.x = 575;
+ _alfredState.y = 210;
setScreenAndPrepare(21, ALFRED_DOWN);
+
+ // Original gives 4 items after room load (items 17, 64, 24, 59)
+ _state->inventoryItems.clear();
+ _state->selectedInventoryItem = -1;
+ // we dont want a flashing animation in this case!
+ _state->addInventoryItem(17);
+ _state->addInventoryItem(64);
+ _state->addInventoryItem(24);
+ _state->addInventoryItem(59);
}
bool PelrockEngine::renderScene(int overlayMode) {
Commit: 8962a72e542ba927e527250b1f058c0f09138f1b
https://github.com/scummvm/scummvm/commit/8962a72e542ba927e527250b1f058c0f09138f1b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:27+02:00
Commit Message:
PELROCK: Fixes zorder
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index b736bab7f60..0478d2c396c 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -917,7 +917,7 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
renderScene(OVERLAY_NONE);
_room->findSpriteByIndex(7)->y -= 10;
if (_room->findSpriteByIndex(7)->y <= 70) {
- _room->findSpriteByIndex(7)->zOrder = -1;
+ _room->findSpriteByIndex(7)->zOrder = 255;
break;
}
_screen->update();
@@ -1486,7 +1486,7 @@ void PelrockEngine::guardMovement() {
sprite->animData[0].movementFlags = 0x14; // Move left
}
if (sprite->x <= 327 && state == 2) {
- sprite->zOrder = -1; // Hide sprite
+ sprite->zOrder = 255; // Hide sprite
break;
}
debug("Guard position: (%d, %d), state: %d", sprite->x, sprite->y, state);
@@ -1567,7 +1567,7 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
// drinking animation and sound
_sound->playSound(_room->_roomSfx[1], 2);
- _room->findSpriteByIndex(0)->zOrder = -1;
+ _room->findSpriteByIndex(0)->zOrder = 255;
playSpecialAnim(1473360, true, mastersX - 6, mastersY - 1, 152, 83, 7);
@@ -1654,7 +1654,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
bool didRender = renderScene(OVERLAY_NONE);
if (didRender) {
- if (_room->findSpriteByIndex(swimmers[0].spriteIndex)->zOrder == -1) {
+ if (_room->findSpriteByIndex(swimmers[0].spriteIndex)->zOrder == 255) {
break;
}
}
@@ -1952,7 +1952,7 @@ void PelrockEngine::teleportToPrincess() {
thisSprite->animData[0].curFrame = 0;
thisSprite->zOrder = 200;
- while (!shouldQuit() && _room->findSpriteByIndex(phase + 1)->zOrder != -1) {
+ while (!shouldQuit() && _room->findSpriteByIndex(phase + 1)->zOrder != 255) {
_events->pollEvent();
renderScene(OVERLAY_NONE);
_screen->update();
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 8db72e9a20f..302b684db99 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -461,7 +461,7 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
PasserByAnim anim = _room->_passerByAnims->passerByAnims[animIndex];
if ((frameCount & anim.frameTrigger) == anim.frameTrigger) {
Sprite *sprite = _room->findSpriteByIndex(anim.spriteIndex);
- if (sprite && sprite->zOrder == -1) {
+ if (sprite && sprite->zOrder == 255) {
debug("Starting passerby anim for sprite %d at index %d", anim.spriteIndex, animIndex);
sprite->zOrder = anim.targetZIndex;
sprite->curAnimIndex = 0;
@@ -485,7 +485,7 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
if (sprite->x >= anim.resetCoord) {
sprite->x = startX;
sprite->y = startY;
- sprite->zOrder = -1;
+ sprite->zOrder = 255;
sprite->curAnimIndex = 0;
sprite->animData[0].curFrame = 0;
_room->_passerByAnims->latch = false;
@@ -496,7 +496,7 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
if (sprite->x <= anim.resetCoord) {
sprite->x = startX;
sprite->y = startY;
- sprite->zOrder = -1;
+ sprite->zOrder = 255;
sprite->curAnimIndex = 0;
sprite->animData[0].curFrame = 0;
_room->_passerByAnims->latch = false;
@@ -506,7 +506,7 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
if (sprite->y >= anim.resetCoord) {
sprite->x = startX;
sprite->y = startY;
- sprite->zOrder = -1;
+ sprite->zOrder = 255;
sprite->curAnimIndex = 0;
sprite->animData[0].curFrame = 0;
_room->_passerByAnims->latch = false;
@@ -678,7 +678,7 @@ void PelrockEngine::updateAnimations() {
// First pass: sprites behind Alfred (sprite zOrder > alfredZOrder)
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (_room->_currentRoomAnims[i].zOrder > alfredZOrder || _room->_currentRoomAnims[i].zOrder < 0) {
+ if (_room->_currentRoomAnims[i].zOrder > alfredZOrder || _room->_currentRoomAnims[i].zOrder == 255) {
// debug("Drawing anim %d with zOrder %d in first pass (behind Alfred)", i, _room->_currentRoomAnims[i].zOrder);
drawNextFrame(&_room->_currentRoomAnims[i]);
}
@@ -689,7 +689,7 @@ void PelrockEngine::updateAnimations() {
// Second pass: sprites in front of Alfred (sprite zOrder <= alfredZOrder)
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
- if (_room->_currentRoomAnims[i].zOrder <= alfredZOrder && _room->_currentRoomAnims[i].zOrder >= 0) {
+ if (_room->_currentRoomAnims[i].zOrder <= alfredZOrder && _room->_currentRoomAnims[i].zOrder != 255) {
// debug("Drawing anim %d with zOrder %d in second pass (in front of Alfred)", i, _room->_currentRoomAnims[i].zOrder);
drawNextFrame(&_room->_currentRoomAnims[i]);
}
@@ -734,8 +734,8 @@ void PelrockEngine::paintDebugLayer() {
if (showSprites) {
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
Sprite sprite = _room->_currentRoomAnims[i];
- if (sprite.zOrder < 0) {
- // Skip sprites with negative zOrder (not rendered)
+ if (sprite.zOrder == 255) {
+ // Skip disabled sprites (zOrder 0xFF)
continue;
}
drawRect(_screen, sprite.x, sprite.y, sprite.w, sprite.h, 14);
@@ -1309,7 +1309,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
}
-void applyMovement(int16 *x, int16 *y, int8 *z, uint16 flags) {
+void applyMovement(int16 *x, int16 *y, byte *z, uint16 flags) {
// X-axis movement
if (flags & 0x10) { // Bit 4: X movement enabled
int amount = flags & 0x07; // Bits 0-2: pixels per frame
@@ -1343,8 +1343,8 @@ void applyMovement(int16 *x, int16 *y, int8 *z, uint16 flags) {
void PelrockEngine::drawNextFrame(Sprite *sprite) {
Anim &animData = sprite->animData[sprite->curAnimIndex];
- if (sprite->zOrder == -1) {
- // skips z0rder -1 sprites
+ if (sprite->zOrder == 255) {
+ // Skip disabled sprites (zOrder 0xFF = disabled in original game)
return;
}
@@ -1377,7 +1377,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
animData.curLoop++;
} else {
if (sprite->disableAfterSequence && sprite->curAnimIndex == sprite->numAnims - 1) {
- sprite->zOrder = -1;
+ sprite->zOrder = 255;
return;
}
animData.curFrame = 0;
@@ -2180,15 +2180,10 @@ void PelrockEngine::doExtraActions(int roomNumber) {
pigeons->curAnimIndex = 0;
pigeons->disableAfterSequence = true;
pigeons->animData[0].curFrame = 0;
- while(!g_engine->shouldQuit() && pigeons->zOrder != -1) {
+ while(!g_engine->shouldQuit() && pigeons->zOrder != 255) {
_events->pollEvent();
renderScene();
_screen->update();
- // debug("Pigeons animation, current anim index %d, current frame %d", pigeons->curAnimIndex, pigeons->animData[pigeons->curAnimIndex].curFrame);
- // if(pigeons->curAnimIndex == 3 && pigeons->animData[3].curFrame == 3) {
- // debug("Pigeons animation finished, hiding pigeons and enabling next part of the scene");
- // pigeons->zOrder = -1;
- // }
g_system->delayMillis(10);
}
_dialog->say(_res->_ingameTexts[PRACTICAR_MAS]);
@@ -2376,10 +2371,10 @@ void PelrockEngine::pyramidCollapse() {
// Original sprite table indices are offset by 2 from ScummVM indices due
// to the 2 header sprite slots in the room data.
- // Hide NPC initially â binary sets sprite_2 field 0x21 = 0xFF (zOrder = -1)
+ // Hide NPC initially â binary sets sprite_2 field 0x21 = 0xFF (zOrder = 255)
Sprite *npc = _room->findSpriteByIndex(0);
if (npc)
- npc->zOrder = -1;
+ npc->zOrder = 255;
// Start collapse animation â binary sets sprite_4 field 0x21 = 0xFE (zOrder = 254)
Sprite *collapseSprite = _room->findSpriteByIndex(2);
@@ -2398,7 +2393,7 @@ void PelrockEngine::pyramidCollapse() {
g_system->delayMillis(10);
collapseSprite = _room->findSpriteByIndex(2);
if (!collapseSprite || collapseSprite->animData[collapseSprite->curAnimIndex].curFrame >= 5) {
- collapseSprite->zOrder = -1; // Hide collapse animation sprite after frame 5
+ collapseSprite->zOrder = 255; // Hide collapse animation sprite after frame 5
break;
}
}
@@ -2413,7 +2408,7 @@ void PelrockEngine::pyramidCollapse() {
Common::Rect copyRect(srcX, srcY, srcX + copyW, srcY + copyH);
_currentBackground.blitFrom(_compositeBuffer, copyRect, Common::Point(srcX, srcY));
}
- _room->findSpriteByIndex(2)->zOrder = -1;
+ _room->findSpriteByIndex(2)->zOrder = 255;
_dialog->say(_res->_ingameTexts[YANOSEHACEONCOMOANTES]);
npc = _room->findSpriteByIndex(0);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 7a613ee0042..8e05a8469da 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -229,7 +229,7 @@ void RoomManager::disableSprite(byte roomNumber, byte spriteIndex, int persist)
// array every frame so a raw array index is unreliable.
for (uint i = 0; i < _currentRoomAnims.size(); i++) {
if (_currentRoomAnims[i].index == spriteIndex) {
- _currentRoomAnims[i].zOrder = -1;
+ _currentRoomAnims[i].zOrder = 255;
break;
}
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 3440d1b0ab9..04248301f3d 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -272,7 +272,7 @@ struct Sprite {
uint16 stride; // 6-7
int numAnims; // 8
int curAnimIndex = 0;
- int8 zOrder; // 32-33
+ byte zOrder; // byte at file offset 23 (in-memory struct offset 0x21). Unsigned 0-254, 255=disabled
byte actionFlags; // 34
bool isHotspotDisabled; // 38
Commit: 0aa41619236f59fa4cbfadce40c5b89fdc5928d7
https://github.com/scummvm/scummvm/commit/0aa41619236f59fa4cbfadce40c5b89fdc5928d7
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:27+02:00
Commit Message:
PELROCK: Adds extra stickers with glowy eyes to statues in final fight
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 0478d2c396c..f4f603c7935 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -2125,7 +2125,9 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_sound->playSound(_room->_roomSfx[1], 0);
smokeAnimation(kFlightRooms[flightIndex].spriteIdx, true);
_room->addStickerToRoom(_room->_currentRoomNumber, 127 + flightIndex);
- if(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) == 0b1111) {
+ _room->addStickerToRoom(52, 106 + flightIndex);
+
+ if(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) == 15) { // all 4 spells successful
HotSpot hotspot = HotSpot();
hotspot.actionFlags = 0;
hotspot.extra = 999;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 302b684db99..6723b3ca330 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -2085,9 +2085,6 @@ void PelrockEngine::setScreen(int roomNumber) {
_room->loadRoomMetadata(&roomFile, roomNumber);
- _screen->markAllDirty();
- _screen->update();
-
roomFile.close();
delete[] palette;
}
@@ -2359,6 +2356,9 @@ void PelrockEngine::doExtraActions(int roomNumber) {
case 53:
case 54:
initGodsSequences(_room->_currentRoomNumber);
+ if(roomNumber == 52) {
+ _room->addStickerToRoom(52, 105);
+ }
break;
default:
break;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 8e05a8469da..0311234fc00 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -106,6 +106,10 @@ void RoomManager::addSticker(int stickerId, int persist) {
void RoomManager::addStickerToRoom(byte room, int stickerId, int persist) {
Sticker sticker = g_engine->_res->getSticker(stickerId);
if (room == _currentRoomNumber && persist & PERSIST_TEMP) {
+ if(hasSticker(sticker.stickerIndex)) {
+ debug("Sticker %d already exists in room %d, skipping add", stickerId, room);
+ return;
+ }
_roomStickers.push_back(sticker);
}
if (persist & PERSIST_PERM) {
Commit: d9d8e6cac0a98542c97be490974e1b4c20ec7e86
https://github.com/scummvm/scummvm/commit/d9d8e6cac0a98542c97be490974e1b4c20ec7e86
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:28+02:00
Commit Message:
PELROCK: Implements background viewer
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/extrascreens.cpp
engines/pelrock/extrascreens.h
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index f4f603c7935..1b5ead2c48e 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -2209,7 +2209,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
}
case 96: {
- BackgroundBook book(_events, _res);
+ BackgroundBook book(_events, _res, _room);
book.run();
break;
}
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
index bb6457a29c2..d7d6e13f22b 100644
--- a/engines/pelrock/extrascreens.cpp
+++ b/engines/pelrock/extrascreens.cpp
@@ -24,6 +24,7 @@
#include "extrascreens.h"
#include "pelrock/extrascreens.h"
#include "pelrock/graphics.h"
+#include "pelrock/room.h"
#include "pelrock/util.h"
namespace Pelrock {
@@ -353,7 +354,7 @@ void CDPlayer::loadControls() {
delete[] rawData;
}
-BackgroundBook::BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res) : _events(eventMan), _res(res) {
+BackgroundBook::BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res, RoomManager *room) : _events(eventMan), _res(res), _room(room) {
init();
}
@@ -410,9 +411,11 @@ void BackgroundBook::checkMouse(int x, int y) {
int firstItem = _selectedPage * kItemsPerPage;
if (y >= 72 && y < 72 + (kItemsPerPage * g_engine->_smallFont->getFontHeight()) && x >= 37 && x <= 37 + 200) {
int itemIndex = (y - 72) / g_engine->_smallFont->getFontHeight();
- if (firstItem + itemIndex < _roomNames.size()) {
- Common::String roomName = _roomNames[firstItem + itemIndex];
- debug("Selected room: %s", roomName.c_str());
+ int roomIndex = firstItem + itemIndex;
+ if (roomIndex < (int)_roomNames.size()) {
+ _events->_leftMouseClicked = false;
+ int finalRoomIndex = roomIndex < 10 ? roomIndex: roomIndex + 2;
+ showRoom(finalRoomIndex);
}
}
@@ -440,17 +443,14 @@ void BackgroundBook::loadRoomNames() {
error("Couldnt find file JUEGO.EXE");
}
- size_t namesSize = 1335;
- juegoExe.seek(0x49315, SEEK_SET);
+ size_t namesSize = 1297;
+ juegoExe.seek(299797, SEEK_SET);
byte *namesData = new byte[namesSize];
juegoExe.read(namesData, namesSize);
uint32 pos = 0;
Common::String currentName = "";
while (pos < namesSize) {
- if (namesData[pos] == 0xFD &&
- namesData[pos + 1] == 0x00 &&
- namesData[pos + 2] == 0x08 &&
- namesData[pos + 3] == 0x02) {
+ if (namesData[pos] == 0xFD) {
if (currentName.size() > 0) {
roomNames.push_back(currentName);
}
@@ -470,16 +470,17 @@ void BackgroundBook::loadRoomNames() {
void BackgroundBook::drawScreen() {
_compositeScreen.blitFrom(_backgroundScreen);
drawButtons();
- g_engine->_screen->blitFrom(_compositeScreen);
+ if(thumbSurface) {
+ _compositeScreen.blitFrom(*thumbSurface, Common::Point(338, 120));
+ }
+ g_engine->_screen->blitFrom(_compositeScreen);
int firstItem = _selectedPage * kItemsPerPage;
for(int i = 0; i < kItemsPerPage; i++) {
if(firstItem + i >= _roomNames.size()) {
break;
}
- // g_engine->_graphics->drawColoredTexts(_compositeScreen, _roomNames[i], 37, 72 + (i * g_engine->_smallFont->getFontHeight()), 640, 0, Graphics::kTextAlignLeft);
- // g_engine->_graphics->drawColoredTexts(_compositeScreen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
g_engine->_smallFont->drawString(g_engine->_screen, _roomNames[firstItem + i], 37, 72 + (i * g_engine->_smallFont->getFontHeight()), 640, 2, Graphics::kTextAlignLeft);
}
}
@@ -519,6 +520,28 @@ void BackgroundBook::loadButtons() {
alfred7.close();
}
+void BackgroundBook::showRoom(int roomIndex) {
+ Common::File roomFile;
+ if (!roomFile.open(Common::Path("ALFRED.1"))) {
+ warning("BackgroundBook: Could not open ALFRED.1");
+ return;
+ }
+
+ int roomOffset = roomIndex * kRoomStructSize;
+ Graphics::ManagedSurface bgSurface(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+
+ byte *roomPalette = new byte[256 * 3];
+ _room->getPalette(&roomFile, roomOffset, roomPalette);
+ _room->getBackground(&roomFile, roomOffset, (byte *)bgSurface.getPixels());
+ roomFile.close();
+
+ thumbSurface = bgSurface.scale(160, 100);
+ // Set room palette and display the background
+ g_system->getPaletteManager()->setPalette(roomPalette, 0, 256);
+
+ bgSurface.free();
+}
+
void BackgroundBook::cleanup() {
_compositeScreen.free();
_backgroundScreen.free();
@@ -526,6 +549,15 @@ void BackgroundBook::cleanup() {
delete[] _palette;
_palette = nullptr;
}
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ delete[] _buttons[i][j];
+ }
+ }
+ if (thumbSurface) {
+ thumbSurface->free();
+ thumbSurface = nullptr;
+ }
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/extrascreens.h b/engines/pelrock/extrascreens.h
index f0226b1d965..e0c68dd9fc6 100644
--- a/engines/pelrock/extrascreens.h
+++ b/engines/pelrock/extrascreens.h
@@ -148,7 +148,7 @@ enum Buttons {
int kItemsPerPage = 22;
public:
- BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res);
+ BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res, RoomManager *room);
~BackgroundBook();
void run();
@@ -162,12 +162,15 @@ private:
void loadBackground();
void checkMouse(int x, int y);
BackgroundBook::Buttons isButtonClicked(int x, int y);
+ void showRoom(int roomIndex);
void cleanup();
PelrockEventManager *_events;
ResourceManager *_res;
+ RoomManager *_room;
Graphics::ManagedSurface _backgroundScreen;
Graphics::ManagedSurface _compositeScreen;
+ Graphics::ManagedSurface *thumbSurface = nullptr;
byte *_palette;
byte *_buttons[2][2];
Buttons _selectedButton = NO_BG_BUTTON;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 6723b3ca330..2b0bf43e1ee 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1809,7 +1809,7 @@ void PelrockEngine::gameLoop() {
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_b) {
- BackgroundBook backgroundBook(_events, _res);
+ BackgroundBook backgroundBook(_events, _res, _room);
backgroundBook.run();
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
@@ -2074,7 +2074,7 @@ void PelrockEngine::setScreen(int roomNumber) {
byte *palette = new byte[256 * 3];
_room->getPalette(&roomFile, roomOffset, palette);
-
+ memcpy(_room->_roomPalette, palette, 768);
_currentBackground.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
_room->getBackground(&roomFile, roomOffset, (byte *)_currentBackground.getPixels());
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 0311234fc00..cfd51083793 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -66,7 +66,6 @@ void RoomManager::getPalette(Common::File *roomFile, int roomOffset, byte *palet
palette[i * 3 + 1] = palette[i * 3 + 1] << 2;
palette[i * 3 + 2] = palette[i * 3 + 2] << 2;
}
- memcpy(_roomPalette, palette, 768);
}
void RoomManager::getBackground(Common::File *roomFile, int roomOffset, byte *background) {
Commit: cbf01025e923469ba08e940e30150a92ac5701cc
https://github.com/scummvm/scummvm/commit/cbf01025e923469ba08e940e30150a92ac5701cc
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:28+02:00
Commit Message:
PELROCK: Refactor cdplayer, background book, spellbook
Changed paths:
A engines/pelrock/backgroundbook.cpp
A engines/pelrock/backgroundbook.h
A engines/pelrock/cdplayer.cpp
A engines/pelrock/cdplayer.h
A engines/pelrock/spellbook.cpp
A engines/pelrock/spellbook.h
R engines/pelrock/extrascreens.cpp
R engines/pelrock/extrascreens.h
engines/pelrock/actions.cpp
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/sound.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 1b5ead2c48e..81068b91b1d 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -21,11 +21,13 @@
#include "graphics/paletteman.h"
-#include "pelrock.h"
+
#include "pelrock/actions.h"
-#include "pelrock/extrascreens.h"
+#include "pelrock/backgroundbook.h"
+#include "pelrock/cdplayer.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
+#include "pelrock/spellbook.h"
#include "pelrock/util.h"
namespace Pelrock {
diff --git a/engines/pelrock/backgroundbook.cpp b/engines/pelrock/backgroundbook.cpp
new file mode 100644
index 00000000000..8573849ec81
--- /dev/null
+++ b/engines/pelrock/backgroundbook.cpp
@@ -0,0 +1,235 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/events.h"
+#include "graphics/paletteman.h"
+
+#include "pelrock/backgroundbook.h"
+#include "pelrock/room.h"
+#include "pelrock/util.h"
+
+namespace Pelrock {
+
+BackgroundBook::BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res, RoomManager *room)
+ : _events(eventMan), _res(res), _room(room) {
+ init();
+}
+
+BackgroundBook::~BackgroundBook() {
+ cleanup();
+}
+
+void BackgroundBook::run() {
+ g_engine->changeCursor(DEFAULT);
+ while (!g_engine->shouldQuit()) {
+ _events->pollEvent();
+ checkMouse(_events->_mouseX, _events->_mouseY);
+
+ if (_events->_rightMouseClicked) {
+ _events->_rightMouseClicked = false;
+ break;
+ }
+
+ drawScreen();
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+ g_system->delayMillis(10);
+ }
+ g_engine->_screen->clear(0);
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+}
+
+void BackgroundBook::init() {
+ _compositeScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+ loadBackground();
+ loadButtons();
+ loadRoomNames();
+}
+
+void BackgroundBook::checkMouse(int x, int y) {
+ if (_events->_leftMouseClicked) {
+ switch (_selectedButton) {
+ case PREVIOUS_BUTTON:
+ if (_selectedPage > 0) {
+ _selectedPage--;
+ }
+ break;
+ case NEXT_BUTTON:
+ if ((_selectedPage + 1) * kItemsPerPage < (int)_roomNames.size()) {
+ _selectedPage++;
+ }
+ break;
+ default:
+ break;
+ }
+ _selectedButton = NO_BG_BUTTON;
+
+ int firstItem = _selectedPage * kItemsPerPage;
+ if (y >= 72 && y < 72 + (kItemsPerPage * g_engine->_smallFont->getFontHeight()) && x >= 37 && x <= 37 + 200) {
+ int itemIndex = (y - 72) / g_engine->_smallFont->getFontHeight();
+ int roomIndex = firstItem + itemIndex;
+ if (roomIndex < (int)_roomNames.size()) {
+ _events->_leftMouseClicked = false;
+ int finalRoomIndex = roomIndex < 10 ? roomIndex : roomIndex + 2;
+ showRoom(finalRoomIndex);
+ }
+ }
+
+ _events->_leftMouseClicked = false;
+ }
+
+ if (_events->_leftMouseButton != 0 && _selectedButton == NO_BG_BUTTON) {
+ _selectedButton = isButtonClicked(_events->_mouseX, _events->_mouseY);
+ }
+}
+
+BackgroundBook::Buttons BackgroundBook::isButtonClicked(int x, int y) {
+ for (int i = 0; i < 2; i++) {
+ if (_buttonRects[i].contains(x, y)) {
+ return static_cast<Buttons>(i);
+ }
+ }
+ return NO_BG_BUTTON;
+}
+
+void BackgroundBook::loadRoomNames() {
+ Common::StringArray roomNames;
+ Common::File juegoExe;
+ if (!juegoExe.open(Common::Path("JUEGO.EXE"))) {
+ error("Couldnt find file JUEGO.EXE");
+ }
+
+ size_t namesSize = 1297;
+ juegoExe.seek(299797, SEEK_SET);
+ byte *namesData = new byte[namesSize];
+ juegoExe.read(namesData, namesSize);
+ uint32 pos = 0;
+ Common::String currentName = "";
+ while (pos < namesSize) {
+ if (namesData[pos] == 0xFD) {
+ if (currentName.size() > 0) {
+ roomNames.push_back(currentName);
+ }
+ currentName = "";
+ pos += 4;
+ continue;
+ }
+ currentName += (char)namesData[pos];
+ pos++;
+ }
+ delete[] namesData;
+ juegoExe.close();
+ _roomNames = roomNames;
+}
+
+void BackgroundBook::drawScreen() {
+ _compositeScreen.blitFrom(_backgroundScreen);
+ drawButtons();
+
+ if (thumbSurface) {
+ _compositeScreen.blitFrom(*thumbSurface, Common::Point(338, 120));
+ }
+ g_engine->_screen->blitFrom(_compositeScreen);
+
+ int firstItem = _selectedPage * kItemsPerPage;
+ for (int i = 0; i < kItemsPerPage; i++) {
+ if (firstItem + i >= (int)_roomNames.size()) {
+ break;
+ }
+ g_engine->_smallFont->drawString(g_engine->_screen, _roomNames[firstItem + i], 37, 72 + (i * g_engine->_smallFont->getFontHeight()), 640, 2, Graphics::kTextAlignLeft);
+ }
+}
+
+void BackgroundBook::drawButtons() {
+ for (int i = 0; i < 2; i++) {
+ if (_selectedButton == i) {
+ drawSpriteToBuffer(_compositeScreen, _buttons[i][0], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ } else {
+ drawSpriteToBuffer(_compositeScreen, _buttons[i][1], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ }
+ }
+}
+
+void BackgroundBook::loadBackground() {
+ _backgroundScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+ _palette = new byte[768];
+ _res->getExtraScreen(13, (byte *)_backgroundScreen.getPixels(), _palette);
+ g_system->getPaletteManager()->setPalette(_palette, 0, 256);
+}
+
+void BackgroundBook::loadButtons() {
+ Common::File alfred7;
+ if (!alfred7.open("ALFRED.7")) {
+ return;
+ }
+ alfred7.seek(3188448, SEEK_SET);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ int w = _buttonRects[i].width();
+ int h = _buttonRects[i].height();
+ _buttons[i][j] = new byte[w * h];
+ alfred7.read(_buttons[i][j], w * h);
+ }
+ }
+ alfred7.close();
+}
+
+void BackgroundBook::showRoom(int roomIndex) {
+ Common::File roomFile;
+ if (!roomFile.open(Common::Path("ALFRED.1"))) {
+ warning("BackgroundBook: Could not open ALFRED.1");
+ return;
+ }
+
+ int roomOffset = roomIndex * kRoomStructSize;
+ Graphics::ManagedSurface bgSurface(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+
+ byte *roomPalette = new byte[256 * 3];
+ _room->getPalette(&roomFile, roomOffset, roomPalette);
+ _room->getBackground(&roomFile, roomOffset, (byte *)bgSurface.getPixels());
+ roomFile.close();
+
+ thumbSurface = bgSurface.scale(160, 100);
+ // Set room palette and display the background
+ g_system->getPaletteManager()->setPalette(roomPalette, 0, 256);
+
+ bgSurface.free();
+}
+
+void BackgroundBook::cleanup() {
+ _compositeScreen.free();
+ _backgroundScreen.free();
+ if (_palette) {
+ delete[] _palette;
+ _palette = nullptr;
+ }
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ delete[] _buttons[i][j];
+ }
+ }
+ if (thumbSurface) {
+ thumbSurface->free();
+ thumbSurface = nullptr;
+ }
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/backgroundbook.h b/engines/pelrock/backgroundbook.h
new file mode 100644
index 00000000000..f037f4d32ab
--- /dev/null
+++ b/engines/pelrock/backgroundbook.h
@@ -0,0 +1,82 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PELROCK_BACKGROUNDBOOK_H
+#define PELROCK_BACKGROUNDBOOK_H
+
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/str.h"
+#include "graphics/managed_surface.h"
+
+#include "pelrock/pelrock.h"
+
+namespace Pelrock {
+
+class BackgroundBook {
+
+ enum Buttons {
+ PREVIOUS_BUTTON,
+ NEXT_BUTTON,
+ NO_BG_BUTTON
+ };
+
+ int kItemsPerPage = 22;
+
+public:
+ BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res, RoomManager *room);
+ ~BackgroundBook();
+
+ void run();
+
+private:
+ void init();
+ void loadRoomNames();
+ void drawScreen();
+ void drawButtons();
+ void loadButtons();
+ void loadBackground();
+ void checkMouse(int x, int y);
+ Buttons isButtonClicked(int x, int y);
+ void showRoom(int roomIndex);
+ void cleanup();
+
+ PelrockEventManager *_events;
+ ResourceManager *_res;
+ RoomManager *_room;
+ Graphics::ManagedSurface _backgroundScreen;
+ Graphics::ManagedSurface _compositeScreen;
+ Graphics::ManagedSurface *thumbSurface = nullptr;
+ byte *_palette;
+ byte *_buttons[2][2];
+ Buttons _selectedButton = NO_BG_BUTTON;
+ int _selectedPage = 0;
+
+ Common::Rect _buttonRects[2] = {
+ Common::Rect(Common::Point(238, 104), 28, 44), // Previous
+ Common::Rect(Common::Point(238, 178), 28, 44), // Next
+ };
+ Common::StringArray _roomNames;
+};
+
+} // End of namespace Pelrock
+
+#endif
diff --git a/engines/pelrock/cdplayer.cpp b/engines/pelrock/cdplayer.cpp
new file mode 100644
index 00000000000..7b4b5d983b5
--- /dev/null
+++ b/engines/pelrock/cdplayer.cpp
@@ -0,0 +1,211 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/events.h"
+#include "graphics/paletteman.h"
+
+#include "pelrock/cdplayer.h"
+#include "pelrock/room.h"
+#include "pelrock/util.h"
+
+namespace Pelrock {
+
+CDPlayer::CDPlayer(PelrockEventManager *eventMan, ResourceManager *res, SoundManager *sound)
+ : _events(eventMan), _res(res), _sound(sound) {
+ init();
+}
+
+CDPlayer::~CDPlayer() {
+ cleanup();
+}
+
+void CDPlayer::run() {
+ g_engine->changeCursor(DEFAULT);
+
+ while (!g_engine->shouldQuit()) {
+ _events->pollEvent();
+ checkMouse(_events->_mouseX, _events->_mouseY);
+
+ if (_events->_rightMouseClicked) {
+ _events->_rightMouseClicked = false;
+ break;
+ }
+
+ drawScreen();
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+ g_system->delayMillis(10);
+ }
+ g_engine->_screen->clear(0);
+ // Restore room palette
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+ _sound->stopMusic();
+ _sound->playMusicTrack(g_engine->_room->_musicTrack, true);
+}
+
+void CDPlayer::init() {
+ _compositeScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+ loadBackground();
+ loadControls();
+ loadTrackNames();
+}
+
+void CDPlayer::loadTrackNames() {
+ Common::File juegoFile;
+ if (!juegoFile.open("JUEGO.EXE")) {
+ return;
+ }
+ juegoFile.seek(301203, SEEK_SET);
+
+ for (int i = 0; i < 31; i++) {
+ trackNames[i] = juegoFile.readString(0, 30);
+ }
+
+ juegoFile.close();
+}
+
+void CDPlayer::drawScreen() {
+ _compositeScreen.blitFrom(_backgroundScreen);
+ drawSpriteToBuffer(_compositeScreen, _controls, 1, 1, 213, 72, 207);
+
+ drawButtons();
+
+ g_engine->_screen->blitFrom(_compositeScreen);
+ g_engine->_smallFont->drawString(g_engine->_screen, trackNames[_selectedTrack - 2], 26, 17, 640, 255, Graphics::kTextAlignLeft);
+}
+
+void CDPlayer::drawButtons() {
+ for (int i = 0; i < 5; i++) {
+ if (_selectedButton == i) {
+ drawSpriteToBuffer(_compositeScreen, buttons[i][1], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ } else {
+ drawSpriteToBuffer(_compositeScreen, buttons[i][0], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
+ }
+ }
+}
+
+void CDPlayer::loadBackground() {
+ _backgroundScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+ _palette = new byte[768];
+ _res->getExtraScreen(10, (byte *)_backgroundScreen.getPixels(), _palette);
+ g_system->getPaletteManager()->setPalette(_palette, 0, 256);
+}
+
+void CDPlayer::cleanup() {
+ _backgroundScreen.free();
+ _compositeScreen.free();
+
+ if (_palette) {
+ delete[] _palette;
+ _palette = nullptr;
+ }
+
+ for (int i = 0; i < 5; i++) {
+ delete[] buttons[i][0];
+ delete[] buttons[i][1];
+ }
+
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+}
+
+void CDPlayer::checkMouse(int x, int y) {
+ if (_events->_leftMouseClicked) {
+ switch (_selectedButton) {
+ case STOP_BUTTON:
+ _sound->stopMusic();
+ break;
+ case PAUSE_BUTTON:
+ _sound->pauseMusic();
+ break;
+ case PLAY_BUTTON:
+ if (_sound->isPaused() && _sound->getCurrentMusicTrack() == _selectedTrack) {
+ _sound->playMusicTrack(_selectedTrack, true);
+ } else {
+ _sound->stopMusic();
+ _sound->playMusicTrack(_selectedTrack, true);
+ }
+ break;
+ case PREVIOUS_BUTTON:
+ if (_selectedTrack > 2) {
+ _selectedTrack--;
+ }
+ break;
+ case NEXT_BUTTON:
+ if (_selectedTrack < 32) {
+ _selectedTrack++;
+ }
+ break;
+ default:
+ break;
+ }
+ _selectedButton = NO_CDBUTTON;
+ _events->_leftMouseClicked = false;
+ }
+
+ if (_events->_leftMouseButton != 0 && _selectedButton == NO_CDBUTTON) {
+ _selectedButton = isButtonClicked(_events->_mouseX, _events->_mouseY);
+ if (_selectedButton != NO_CDBUTTON) {
+ _sound->playSound("11ZZZZZZ.SMP", 0);
+ }
+ }
+}
+
+CDPlayer::CDControls CDPlayer::isButtonClicked(int x, int y) {
+ for (int i = 0; i < 5; i++) {
+ if (_buttonRects[i].contains(x, y)) {
+ return static_cast<CDControls>(i);
+ }
+ }
+ return NO_CDBUTTON;
+}
+
+void CDPlayer::loadControls() {
+ _controls = new byte[213 * 72];
+ Common::File alfred7;
+ if (!alfred7.open("ALFRED.7")) {
+ return;
+ }
+ alfred7.seek(2214760, SEEK_SET);
+ byte *compressedData = nullptr;
+ size_t outSize = 0;
+ readUntilBuda(&alfred7, 2214760, compressedData, outSize);
+ byte *rawData = nullptr;
+
+ rleDecompress(compressedData, outSize, 0, 0, &rawData, true);
+
+ uint32 pos = 213 * 72;
+ Common::copy(rawData, rawData + pos, _controls);
+ for (int i = 0; i < 5; i++) {
+ for (int j = 0; j < 2; j++) {
+ int w = _buttonRects[i].width();
+ int h = _buttonRects[i].height();
+ buttons[i][j] = new byte[w * h];
+ Common::copy(rawData + pos, rawData + pos + w * h, buttons[i][j]);
+ pos += w * h;
+ }
+ }
+ alfred7.close();
+ delete[] compressedData;
+ delete[] rawData;
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/cdplayer.h b/engines/pelrock/cdplayer.h
new file mode 100644
index 00000000000..23e781f8689
--- /dev/null
+++ b/engines/pelrock/cdplayer.h
@@ -0,0 +1,82 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef PELROCK_CDPLAYER_H
+#define PELROCK_CDPLAYER_H
+
+#include "common/rect.h"
+#include "common/str.h"
+#include "graphics/managed_surface.h"
+
+#include "pelrock/pelrock.h"
+
+namespace Pelrock {
+
+class CDPlayer {
+
+ enum CDControls {
+ STOP_BUTTON,
+ PAUSE_BUTTON,
+ PLAY_BUTTON,
+ PREVIOUS_BUTTON,
+ NEXT_BUTTON,
+ NO_CDBUTTON
+ };
+
+public:
+ CDPlayer(PelrockEventManager *eventMan, ResourceManager *res, SoundManager *sound);
+ ~CDPlayer();
+
+ void run();
+
+private:
+ void init();
+ void loadTrackNames();
+ void drawScreen();
+ void drawButtons();
+ void loadBackground();
+ void loadControls();
+ void checkMouse(int x, int y);
+ void cleanup();
+ CDControls isButtonClicked(int x, int y);
+
+ ResourceManager *_res;
+ SoundManager *_sound;
+ PelrockEventManager *_events;
+ Graphics::ManagedSurface _backgroundScreen;
+ Graphics::ManagedSurface _compositeScreen;
+ byte *_palette;
+ byte *_controls;
+ Common::String trackNames[31];
+ byte *buttons[5][2];
+ Common::Rect _buttonRects[5] = {
+ Common::Rect(Common::Point(17, 46), 37, 26), // Stop
+ Common::Rect(Common::Point(57, 48), 33, 23), // Pause
+ Common::Rect(Common::Point(92, 44), 34, 28), // Play
+ Common::Rect(Common::Point(128, 45), 38, 24), // Previous
+ Common::Rect(Common::Point(168, 44), 41, 28) // Next
+ };
+ int _selectedTrack = 2;
+ CDControls _selectedButton = NO_CDBUTTON;
+};
+
+} // End of namespace Pelrock
+
+#endif
diff --git a/engines/pelrock/extrascreens.cpp b/engines/pelrock/extrascreens.cpp
deleted file mode 100644
index d7d6e13f22b..00000000000
--- a/engines/pelrock/extrascreens.cpp
+++ /dev/null
@@ -1,563 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-#include "common/events.h"
-#include "graphics/paletteman.h"
-
-#include "extrascreens.h"
-#include "pelrock/extrascreens.h"
-#include "pelrock/graphics.h"
-#include "pelrock/room.h"
-#include "pelrock/util.h"
-
-namespace Pelrock {
-
-SpellBook::SpellBook(PelrockEventManager *eventMan, ResourceManager *res)
- : _palette(nullptr),
- _events(eventMan),
- _res(res),
- _spell(nullptr) {
- init();
-}
-
-SpellBook::~SpellBook() {
- cleanup();
-}
-
-Spell *SpellBook::run() {
- loadBackground();
- g_engine->changeCursor(DEFAULT);
- bool exit = false;
- while (!g_engine->shouldQuit() && !exit) {
- _events->pollEvent();
- drawScreen();
- if (_events->_leftMouseClicked) {
- _events->_leftMouseClicked = false;
- exit = checkMouse(_events->_mouseClickX, _events->_mouseClickY);
- }
- g_engine->_screen->markAllDirty();
- g_engine->_screen->update();
- g_system->delayMillis(10);
- }
- g_engine->_screen->clear(0);
- // Restore room palette
- g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
- return _selectedSpell;
-}
-
-void SpellBook::init() {
- _compositeScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
-}
-
-void SpellBook::selectPage(int page) {
- debug("Selected spell page: %d", page);
- _spell = new Spell();
- _spell->page = page;
- Common::File alfred7;
- if (!alfred7.open("ALFRED.7")) {
- return;
- }
-
- Common::File juegoFile;
- if (!juegoFile.open("JUEGO.EXE")) {
- return;
- }
-
- alfred7.seek(1268719, SEEK_SET);
- int w = 119;
- int h = 99;
- int nFrames = 13;
- byte *compressedData = nullptr;
- byte *spriteData = nullptr;
- size_t outSize = 0;
- readUntilBuda(&alfred7, 1268723, compressedData, outSize);
- rleDecompress(compressedData, outSize, 0, w * h * nFrames, &spriteData, false);
- _spell->image = new byte[w * h];
- extractSingleFrame(spriteData, _spell->image, page, w, h);
-
- juegoFile.seek(0x0004661D, SEEK_SET);
- byte *textData = new byte[2861];
- juegoFile.read(textData, 2861);
-
- for (int i = 0; i < 2861; ++i) {
- if (textData[i] == 0x0D)
- textData[i] = 23;
- }
-
- Common::Array<Common::StringArray> spells = _res->processTextData(textData, 2861, true);
- _spell->text = spells[page];
- delete[] compressedData;
- delete[] spriteData;
- alfred7.close();
- juegoFile.close();
-}
-
-void SpellBook::drawScreen() {
- _compositeScreen.blitFrom(_backgroundScreen);
-
- int textY = 83;
- int textX = 317;
-
- if (_spell != nullptr) {
- drawSpriteToBuffer(_compositeScreen, _spell->image, 168, 143, 119, 99, 207);
- g_engine->_graphics->drawColoredTexts(_compositeScreen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
- }
-
- g_engine->_screen->blitFrom(_compositeScreen);
- if (_spell != nullptr) {
- g_engine->_graphics->drawColoredTexts(g_engine->_screen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
- }
-}
-
-void SpellBook::loadBackground() {
- _backgroundScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
- _palette = new byte[768];
- _res->getExtraScreen(8, (byte *)_backgroundScreen.getPixels(), _palette);
- g_system->getPaletteManager()->setPalette(_palette, 0, 256);
-}
-
-void SpellBook::cleanup() {
- _backgroundScreen.free();
- _compositeScreen.free();
- if (_palette) {
- delete[] _palette;
- _palette = nullptr;
- }
- if (_spell) {
- delete _spell;
- _spell = nullptr;
- }
- g_engine->_screen->markAllDirty();
- g_engine->_screen->update();
-}
-
-bool SpellBook::checkMouse(int x, int y) {
- // Check bookmarks
- for (int i = 0; i < 13; i++) {
- Common::Rect r = Common::Rect(_bookmarks[i].x, _bookmarks[i].y, _bookmarks[i].x + _bookmarks[i].w, _bookmarks[i].y + _bookmarks[i].h);
- if (r.contains(x, y)) {
- selectPage(_bookmarks[i].page);
- return false;
- }
- }
-
- // Check text area
- if (_spell == nullptr) {
- return true;
- }
-
- Common::Rect textArea = Common::Rect(321, 81, 321 + 140, 81 + (_spell->text.size() * 10));
- if (textArea.contains(x, y)) {
- _selectedSpell = _spell;
- return true;
- }
- return false;
-}
-
-CDPlayer::CDPlayer(PelrockEventManager *eventMan, ResourceManager *res, SoundManager *sound) : _events(eventMan), _res(res), _sound(sound) {
- init();
-}
-
-CDPlayer::~CDPlayer() {
- cleanup();
-}
-
-void CDPlayer::run() {
-
- g_engine->changeCursor(DEFAULT);
-
- while (!g_engine->shouldQuit()) {
- _events->pollEvent();
- checkMouse(_events->_mouseX, _events->_mouseY);
-
- if (_events->_rightMouseClicked) {
- _events->_rightMouseClicked = false;
- break;
- }
-
- drawScreen();
- g_engine->_screen->markAllDirty();
- g_engine->_screen->update();
- g_system->delayMillis(10);
- }
- g_engine->_screen->clear(0);
- // Restore room palette
- g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
- _sound->stopMusic();
- _sound->playMusicTrack(g_engine->_room->_musicTrack, true);
-}
-
-void CDPlayer::init() {
- _compositeScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
- loadBackground();
- loadControls();
- loadTrackNames();
-}
-
-void CDPlayer::loadTrackNames() {
- Common::File juegoFile;
- if (!juegoFile.open("JUEGO.EXE")) {
- return;
- }
- juegoFile.seek(0x049893, SEEK_SET);
-
- for (int i = 0; i < 31; i++) {
- trackNames[i] = juegoFile.readString(0, 30);
- }
-
- juegoFile.close();
-}
-
-void CDPlayer::drawScreen() {
- _compositeScreen.blitFrom(_backgroundScreen);
- drawSpriteToBuffer(_compositeScreen, _controls, 1, 1, 213, 72, 207);
-
- drawButtons();
-
- g_engine->_screen->blitFrom(_compositeScreen);
- g_engine->_smallFont->drawString(g_engine->_screen, trackNames[_selectedTrack - 2], 26, 17, 640, 255, Graphics::kTextAlignLeft);
-}
-
-void CDPlayer::drawButtons() {
-
- for (int i = 0; i < 5; i++) {
- if (_selectedButton == i) {
- drawSpriteToBuffer(_compositeScreen, buttons[i][1], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
- } else {
- drawSpriteToBuffer(_compositeScreen, buttons[i][0], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
- }
- }
-}
-
-void CDPlayer::loadBackground() {
- _backgroundScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
- _palette = new byte[768];
- _res->getExtraScreen(10, (byte *)_backgroundScreen.getPixels(), _palette);
- g_system->getPaletteManager()->setPalette(_palette, 0, 256);
-}
-
-void CDPlayer::cleanup() {
- _backgroundScreen.free();
- _compositeScreen.free();
-
- if (_palette) {
- delete[] _palette;
- _palette = nullptr;
- }
-
- for (int i = 0; i < 5; i++) {
- delete[] buttons[i][0];
- delete[] buttons[i][1];
- }
-
- g_engine->_screen->markAllDirty();
- g_engine->_screen->update();
-}
-
-void CDPlayer::checkMouse(int x, int y) {
- if (_events->_leftMouseClicked) {
- switch (_selectedButton) {
- case STOP_BUTTON:
- _sound->stopMusic();
- break;
- case PAUSE_BUTTON:
- _sound->pauseMusic();
- break;
- case PLAY_BUTTON:
- if(_sound->_isPaused && _sound->_currentMusicTrack == _selectedTrack) {
- _sound->playMusicTrack(_selectedTrack, true);
- }
- else {
- _sound->stopMusic();
- _sound->playMusicTrack(_selectedTrack, true);
- }
- break;
- case PREVIOUS_BUTTON:
- if (_selectedTrack > 2) {
- _selectedTrack--;
- }
- break;
- case NEXT_BUTTON:
- if (_selectedTrack < 32) {
- _selectedTrack++;
- }
- break;
- default:
- break;
- }
- _selectedButton = NO_CDBUTTON;
- _events->_leftMouseClicked = false;
- }
-
- if (_events->_leftMouseButton != 0 && _selectedButton == NO_CDBUTTON) {
- _selectedButton = isButtonClicked(_events->_mouseX, _events->_mouseY);
- if(_selectedButton != NO_CDBUTTON) {
- _sound->playSound("11ZZZZZZ.SMP", 0);
- }
- }
-}
-
-CDPlayer::CDControls CDPlayer::isButtonClicked(int x, int y) {
- for (int i = 0; i < 5; i++) {
- if (_buttonRects[i].contains(x, y)) {
- return static_cast<CDControls>(i);
- }
- }
- return NO_CDBUTTON;
-}
-
-void CDPlayer::loadControls() {
- _controls = new byte[213 * 72];
- Common::File alfred7;
- if (!alfred7.open("ALFRED.7")) {
- return;
- }
- alfred7.seek(2214760, SEEK_SET);
- byte *compressedData = nullptr;
- size_t outSize = 0;
- readUntilBuda(&alfred7, 2214760, compressedData, outSize);
- byte *rawData = nullptr;
-
- rleDecompress(compressedData, outSize, 0, 0, &rawData, true);
-
- // debug("Decompressed CD player controls: %d bytes", decompressedSize);
- uint32 pos = 213 * 72;
- Common::copy(rawData, rawData + pos, _controls);
- for (int i = 0; i < 5; i++) {
- for (int j = 0; j < 2; j++) {
- int w = _buttonRects[i].width();
- int h = _buttonRects[i].height();
- buttons[i][j] = new byte[w * h];
- Common::copy(rawData + pos, rawData + pos + w * h, buttons[i][j]);
- pos += w * h;
- }
- }
- alfred7.close();
- delete[] compressedData;
- delete[] rawData;
-}
-
-BackgroundBook::BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res, RoomManager *room) : _events(eventMan), _res(res), _room(room) {
- init();
-}
-
-BackgroundBook::~BackgroundBook() {
- cleanup();
-}
-
-void BackgroundBook::run() {
- g_engine->changeCursor(DEFAULT);
- while (!g_engine->shouldQuit()) {
- _events->pollEvent();
- checkMouse(_events->_mouseX, _events->_mouseY);
-
- if (_events->_rightMouseClicked) {
- _events->_rightMouseClicked = false;
- break;
- }
-
- drawScreen();
- g_engine->_screen->markAllDirty();
- g_engine->_screen->update();
- g_system->delayMillis(10);
- }
- g_engine->_screen->clear(0);
- // Restore room palette
- g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
-}
-
-void BackgroundBook::init() {
- _compositeScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
- loadBackground();
- loadButtons();
- loadRoomNames();
-}
-
-void BackgroundBook::checkMouse(int x, int y) {
- if (_events->_leftMouseClicked) {
- switch (_selectedButton) {
- case PREVIOUS_BUTTON:
- if (_selectedPage > 0) {
- _selectedPage--;
- }
- break;
- case NEXT_BUTTON:
- if ((_selectedPage + 1) * kItemsPerPage < _roomNames.size()) {
- _selectedPage++;
- }
- break;
- default:
- break;
- }
- _selectedButton = NO_BG_BUTTON;
-
- int firstItem = _selectedPage * kItemsPerPage;
- if (y >= 72 && y < 72 + (kItemsPerPage * g_engine->_smallFont->getFontHeight()) && x >= 37 && x <= 37 + 200) {
- int itemIndex = (y - 72) / g_engine->_smallFont->getFontHeight();
- int roomIndex = firstItem + itemIndex;
- if (roomIndex < (int)_roomNames.size()) {
- _events->_leftMouseClicked = false;
- int finalRoomIndex = roomIndex < 10 ? roomIndex: roomIndex + 2;
- showRoom(finalRoomIndex);
- }
- }
-
- _events->_leftMouseClicked = false;
- }
-
- if (_events->_leftMouseButton != 0 && _selectedButton == NO_BG_BUTTON) {
- _selectedButton = isButtonClicked(_events->_mouseX, _events->_mouseY);
- }
-}
-
-BackgroundBook::Buttons BackgroundBook::isButtonClicked(int x, int y) {
- for (int i = 0; i < 2; i++) {
- if (_buttonRects[i].contains(x, y)) {
- return static_cast<Buttons>(i);
- }
- }
- return NO_BG_BUTTON;
-}
-
-void BackgroundBook::loadRoomNames() {
- Common::StringArray roomNames;
- Common::File juegoExe;
- if (!juegoExe.open(Common::Path("JUEGO.EXE"))) {
- error("Couldnt find file JUEGO.EXE");
- }
-
- size_t namesSize = 1297;
- juegoExe.seek(299797, SEEK_SET);
- byte *namesData = new byte[namesSize];
- juegoExe.read(namesData, namesSize);
- uint32 pos = 0;
- Common::String currentName = "";
- while (pos < namesSize) {
- if (namesData[pos] == 0xFD) {
- if (currentName.size() > 0) {
- roomNames.push_back(currentName);
- }
- currentName = "";
- pos += 4;
- continue;
- }
- currentName += (char)namesData[pos];
- pos++;
- }
- delete[] namesData;
- juegoExe.close();
- _roomNames = roomNames;
-}
-
-
-void BackgroundBook::drawScreen() {
- _compositeScreen.blitFrom(_backgroundScreen);
- drawButtons();
-
- if(thumbSurface) {
- _compositeScreen.blitFrom(*thumbSurface, Common::Point(338, 120));
- }
- g_engine->_screen->blitFrom(_compositeScreen);
-
- int firstItem = _selectedPage * kItemsPerPage;
- for(int i = 0; i < kItemsPerPage; i++) {
- if(firstItem + i >= _roomNames.size()) {
- break;
- }
- g_engine->_smallFont->drawString(g_engine->_screen, _roomNames[firstItem + i], 37, 72 + (i * g_engine->_smallFont->getFontHeight()), 640, 2, Graphics::kTextAlignLeft);
- }
-}
-
-void BackgroundBook::drawButtons() {
- for (int i = 0; i < 2; i++) {
- if (_selectedButton == i) {
- drawSpriteToBuffer(_compositeScreen, _buttons[i][0], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
- } else {
- drawSpriteToBuffer(_compositeScreen, _buttons[i][1], _buttonRects[i].left, _buttonRects[i].top, _buttonRects[i].width(), _buttonRects[i].height(), 207);
- }
- }
-}
-
-void BackgroundBook::loadBackground() {
- _backgroundScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
- _palette = new byte[768];
- _res->getExtraScreen(13, (byte *)_backgroundScreen.getPixels(), _palette);
- g_system->getPaletteManager()->setPalette(_palette, 0, 256);
-}
-
-void BackgroundBook::loadButtons() {
- Common::File alfred7;
- if (!alfred7.open("ALFRED.7")) {
- return;
- }
- alfred7.seek(3188448, SEEK_SET);
- for(int i = 0; i < 2; i++) {
- for(int j = 0; j < 2; j++) {
- int w = _buttonRects[i].width();
- int h = _buttonRects[i].height();
- _buttons[i][j] = new byte[w * h];
- alfred7.read(_buttons[i][j], w * h);
- }
- }
-
- alfred7.close();
-}
-
-void BackgroundBook::showRoom(int roomIndex) {
- Common::File roomFile;
- if (!roomFile.open(Common::Path("ALFRED.1"))) {
- warning("BackgroundBook: Could not open ALFRED.1");
- return;
- }
-
- int roomOffset = roomIndex * kRoomStructSize;
- Graphics::ManagedSurface bgSurface(640, 400, Graphics::PixelFormat::createFormatCLUT8());
-
- byte *roomPalette = new byte[256 * 3];
- _room->getPalette(&roomFile, roomOffset, roomPalette);
- _room->getBackground(&roomFile, roomOffset, (byte *)bgSurface.getPixels());
- roomFile.close();
-
- thumbSurface = bgSurface.scale(160, 100);
- // Set room palette and display the background
- g_system->getPaletteManager()->setPalette(roomPalette, 0, 256);
-
- bgSurface.free();
-}
-
-void BackgroundBook::cleanup() {
- _compositeScreen.free();
- _backgroundScreen.free();
- if (_palette) {
- delete[] _palette;
- _palette = nullptr;
- }
- for (int i = 0; i < 2; i++) {
- for (int j = 0; j < 2; j++) {
- delete[] _buttons[i][j];
- }
- }
- if (thumbSurface) {
- thumbSurface->free();
- thumbSurface = nullptr;
- }
-}
-
-} // End of namespace Pelrock
diff --git a/engines/pelrock/extrascreens.h b/engines/pelrock/extrascreens.h
deleted file mode 100644
index e0c68dd9fc6..00000000000
--- a/engines/pelrock/extrascreens.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef PELROCK_EXTRASCREENS_H
-#define PELROCK_EXTRASCREENS_H
-
-#include "graphics/managed_surface.h"
-
-#include "pelrock/pelrock.h"
-
-namespace Pelrock {
-
-class PelrockEngine;
-
-struct Spell {
- Common::StringArray text;
- int page;
- byte *image;
-};
-
-struct Bookmark {
- int16 x;
- int16 y;
- byte w;
- byte h;
- int page;
-};
-
-static const Bookmark _bookmarks[13] = {
- {244, 8, 23, 40, 0},
- {396, 17, 44, 20, 1},
- {480, 68, 40, 42, 4},
- {480, 129, 30, 25, 5},
- {480, 224, 28, 32, 8},
- {416, 344, 23, 17, 12},
- {368, 346, 28, 34, 11},
- {198, 340, 26, 28, 10},
- {164, 336, 33, 17, 9},
- {95, 277, 33, 24, 7},
- {105, 227, 27, 33, 6},
- {103, 118, 30, 26, 3},
- {101, 78, 36, 33, 2}
-};
-
-class SpellBook {
-
-public:
- SpellBook(PelrockEventManager *eventMan, ResourceManager *res);
- ~SpellBook();
-
- /**
- * returns the spell the user selected
- */
- Spell *run();
-
-private:
- PelrockEventManager *_events;
- ResourceManager *_res;
- Graphics::ManagedSurface _backgroundScreen;
- Graphics::ManagedSurface _compositeScreen;
- byte *_palette;
-
- Spell *_spell = nullptr;
-
- Spell *_selectedSpell = nullptr;
- void init();
- void selectPage(int page);
- void drawScreen();
- void loadBackground();
- void cleanup();
- bool checkMouse(int x, int y);
-};
-
-
-class CDPlayer {
-
-enum CDControls {
- STOP_BUTTON,
- PAUSE_BUTTON,
- PLAY_BUTTON,
- PREVIOUS_BUTTON,
- NEXT_BUTTON,
- NO_CDBUTTON
-};
-
-public:
- CDPlayer(PelrockEventManager *eventMan, ResourceManager *res, SoundManager *sound);
- ~CDPlayer();
-
- void run();
-
-private:
- void init();
- void loadTrackNames();
- void drawScreen();
- void drawButtons();
- void loadBackground();
- void loadControls();
- void checkMouse(int x, int y);
- void cleanup();
- CDControls isButtonClicked(int x, int y);
- ResourceManager *_res;
- SoundManager *_sound;
- PelrockEventManager *_events;
- Graphics::ManagedSurface _backgroundScreen;
- Graphics::ManagedSurface _compositeScreen;
- byte *_palette;
- byte *_controls;
- Common::String trackNames[31];
- byte *buttons[5][2];
- Common::Rect _buttonRects[5] = {
- Common::Rect(Common::Point(17, 46), 37, 26), // Stop
- Common::Rect(Common::Point(57, 48), 33, 23), // Pause
- Common::Rect(Common::Point(92, 44), 34, 28), // Play
- Common::Rect(Common::Point(128, 45), 38, 24), // Previous
- Common::Rect(Common::Point(168, 44), 41, 28) // Next
- };
- int _selectedTrack = 2;
- CDControls _selectedButton = NO_CDBUTTON;
-
-};
-
-
-class BackgroundBook {
-enum Buttons {
- PREVIOUS_BUTTON,
- NEXT_BUTTON,
- NO_BG_BUTTON
-};
- int kItemsPerPage = 22;
-
-public:
- BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res, RoomManager *room);
- ~BackgroundBook();
-
- void run();
-
-private:
- void init();
- void loadRoomNames();
- void drawScreen();
- void drawButtons();
- void loadButtons();
- void loadBackground();
- void checkMouse(int x, int y);
- BackgroundBook::Buttons isButtonClicked(int x, int y);
- void showRoom(int roomIndex);
- void cleanup();
-
- PelrockEventManager *_events;
- ResourceManager *_res;
- RoomManager *_room;
- Graphics::ManagedSurface _backgroundScreen;
- Graphics::ManagedSurface _compositeScreen;
- Graphics::ManagedSurface *thumbSurface = nullptr;
- byte *_palette;
- byte *_buttons[2][2];
- Buttons _selectedButton = NO_BG_BUTTON;
- int _selectedPage = 0;
-
- Common::Rect _buttonRects[2] = {
- Common::Rect(Common::Point(238, 104), 28, 44), // Stop
- Common::Rect(Common::Point(238, 178), 28, 44), // Pause
- };
- Common::StringArray _roomNames;
-};
-
-} // End of namespace Pelrock
-
-#endif // PELROCK_EXTRASCREENS_H
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index dbbf56ce979..8f1fa08902b 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -21,7 +21,9 @@ MODULE_OBJS = \
menu.o \
graphics.o \
saveload.o \
- extrascreens.o
+ spellbook.o \
+ cdplayer.o \
+ backgroundbook.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 2b0bf43e1ee..ff0343e5744 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -34,12 +34,10 @@
#include "backends/audiocd/audiocd.h"
-#include "pelrock.h"
#include "pelrock/actions.h"
#include "pelrock/computer.h"
#include "pelrock/console.h"
#include "pelrock/detection.h"
-#include "pelrock/extrascreens.h"
#include "pelrock/fonts/small_font.h"
#include "pelrock/offsets.h"
#include "pelrock/pathfinding.h"
@@ -1795,24 +1793,7 @@ void PelrockEngine::gameLoop() {
antiPiracyEffect();
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_s) {
- SpellBook spellBook(_events, _res);
- Spell *selectedSpell = spellBook.run();
- if (selectedSpell != nullptr) {
- _dialog->sayAlfred(selectedSpell->text);
- }
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_c) {
- CDPlayer cdPlayer(_events, _res, _sound);
- cdPlayer.run();
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_b) {
- BackgroundBook backgroundBook(_events, _res, _room);
- backgroundBook.run();
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
+
if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_w) {
Computer computer(_events);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 4dad41aeb7f..03b48167aec 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -163,6 +163,18 @@ private:
int _numPressedX = 0;
+ bool _mouseDisabled = false;
+
+ int _flightFrameCounter = 0;
+ int _flightSorcererSpriteIdx = -1;
+ bool _flightSorcererAppeared = false;
+ bool _flightSpellCast = false;
+ int _flightSpellFrameCounter = 0;
+ bool _flightInBlockingAnim = false;
+ bool _disableAmbientSounds = false;
+ bool _isDogPeeing = false;
+ bool _disableAction = false;
+
protected:
// Engine APIs
Common::Error run() override;
@@ -179,23 +191,11 @@ public:
ShakeEffectState _shakeEffectState;
Graphics::ManagedSurface _compositeBuffer; // Working composition buffer
- bool _mouseDisabled = false;
-
- int _flightFrameCounter = 0;
- int _flightSorcererSpriteIdx = -1;
- bool _flightSorcererAppeared = false;
- bool _flightSpellCast = false;
- int _flightSpellFrameCounter = 0;
- bool _flightInBlockingAnim = false;
- bool _disableAmbientSounds = false;
- bool _isDogPeeing = false;
-
GameStateData *_state = new GameStateData();
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
DoubleSmallFont *_doubleSmallFont = nullptr;
- bool _disableAction = false;
public:
PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc);
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 86195d7af38..baaa8701cad 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -82,8 +82,9 @@ public:
* Add kAmbientSoundSlotBase (4) to get room sound index
*/
int tickAmbientSound(uint32 frameCount);
- bool _isPaused = false;
- byte _currentMusicTrack = 0;
+
+ bool isPaused() const { return _isPaused; }
+ byte getCurrentMusicTrack() const { return _currentMusicTrack; }
private:
void playSound(SonidoFile sound, int channel = -1, int loopCount = 1);
@@ -97,6 +98,8 @@ private:
Audio::SoundHandle _musicHandle;
Audio::SoundHandle _sfxHandles[kMaxChannels];
Common::HashMap<Common::String, SonidoFile> _soundMap;
+ bool _isPaused = false;
+ byte _currentMusicTrack = 0;
uint32 _cdTrackStart = 0;
diff --git a/engines/pelrock/spellbook.cpp b/engines/pelrock/spellbook.cpp
new file mode 100644
index 00000000000..ec8e1d00852
--- /dev/null
+++ b/engines/pelrock/spellbook.cpp
@@ -0,0 +1,174 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/events.h"
+#include "graphics/paletteman.h"
+
+#include "pelrock/graphics.h"
+#include "pelrock/room.h"
+#include "pelrock/spellbook.h"
+#include "pelrock/util.h"
+
+namespace Pelrock {
+
+SpellBook::SpellBook(PelrockEventManager *eventMan, ResourceManager *res)
+ : _palette(nullptr),
+ _events(eventMan),
+ _res(res),
+ _spell(nullptr) {
+ init();
+}
+
+SpellBook::~SpellBook() {
+ cleanup();
+}
+
+Spell *SpellBook::run() {
+ loadBackground();
+ g_engine->changeCursor(DEFAULT);
+ bool exit = false;
+ while (!g_engine->shouldQuit() && !exit) {
+ _events->pollEvent();
+ drawScreen();
+ if (_events->_leftMouseClicked) {
+ _events->_leftMouseClicked = false;
+ exit = checkMouse(_events->_mouseClickX, _events->_mouseClickY);
+ }
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+ g_system->delayMillis(10);
+ }
+ g_engine->_screen->clear(0);
+ // Restore room palette
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+ return _selectedSpell;
+}
+
+void SpellBook::init() {
+ _compositeScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+}
+
+void SpellBook::selectPage(int page) {
+ debug("Selected spell page: %d", page);
+ _spell = new Spell();
+ _spell->page = page;
+ Common::File alfred7;
+ if (!alfred7.open("ALFRED.7")) {
+ return;
+ }
+
+ Common::File juegoFile;
+ if (!juegoFile.open("JUEGO.EXE")) {
+ return;
+ }
+
+ alfred7.seek(1268719, SEEK_SET);
+ int w = 119;
+ int h = 99;
+ int nFrames = 13;
+ byte *compressedData = nullptr;
+ byte *spriteData = nullptr;
+ size_t outSize = 0;
+ readUntilBuda(&alfred7, 1268723, compressedData, outSize);
+ rleDecompress(compressedData, outSize, 0, w * h * nFrames, &spriteData, false);
+ _spell->image = new byte[w * h];
+ extractSingleFrame(spriteData, _spell->image, page, w, h);
+
+ juegoFile.seek(0x0004661D, SEEK_SET);
+ byte *textData = new byte[2861];
+ juegoFile.read(textData, 2861);
+
+ for (int i = 0; i < 2861; ++i) {
+ if (textData[i] == 0x0D)
+ textData[i] = 23;
+ }
+
+ Common::Array<Common::StringArray> spells = _res->processTextData(textData, 2861, true);
+ _spell->text = spells[page];
+ delete[] compressedData;
+ delete[] spriteData;
+ alfred7.close();
+ juegoFile.close();
+}
+
+void SpellBook::drawScreen() {
+ _compositeScreen.blitFrom(_backgroundScreen);
+
+ int textY = 83;
+ int textX = 317;
+
+ if (_spell != nullptr) {
+ drawSpriteToBuffer(_compositeScreen, _spell->image, 168, 143, 119, 99, 207);
+ g_engine->_graphics->drawColoredTexts(_compositeScreen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
+ }
+
+ g_engine->_screen->blitFrom(_compositeScreen);
+ if (_spell != nullptr) {
+ g_engine->_graphics->drawColoredTexts(g_engine->_screen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
+ }
+}
+
+void SpellBook::loadBackground() {
+ _backgroundScreen.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
+ _palette = new byte[768];
+ _res->getExtraScreen(8, (byte *)_backgroundScreen.getPixels(), _palette);
+ g_system->getPaletteManager()->setPalette(_palette, 0, 256);
+}
+
+void SpellBook::cleanup() {
+ _backgroundScreen.free();
+ _compositeScreen.free();
+ if (_palette) {
+ delete[] _palette;
+ _palette = nullptr;
+ }
+ if (_spell) {
+ delete _spell;
+ _spell = nullptr;
+ }
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+}
+
+bool SpellBook::checkMouse(int x, int y) {
+ // Check bookmarks
+ for (int i = 0; i < 13; i++) {
+ Common::Rect r = Common::Rect(_bookmarks[i].x, _bookmarks[i].y, _bookmarks[i].x + _bookmarks[i].w, _bookmarks[i].y + _bookmarks[i].h);
+ if (r.contains(x, y)) {
+ selectPage(_bookmarks[i].page);
+ return false;
+ }
+ }
+
+ // Check text area
+ if (_spell == nullptr) {
+ return true;
+ }
+
+ Common::Rect textArea = Common::Rect(321, 81, 321 + 140, 81 + (_spell->text.size() * 10));
+ if (textArea.contains(x, y)) {
+ _selectedSpell = _spell;
+ return true;
+ }
+ return false;
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/spellbook.h b/engines/pelrock/spellbook.h
new file mode 100644
index 00000000000..6a587d194d4
--- /dev/null
+++ b/engines/pelrock/spellbook.h
@@ -0,0 +1,92 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PELROCK_SPELLBOOK_H
+#define PELROCK_SPELLBOOK_H
+
+#include "graphics/managed_surface.h"
+
+#include "pelrock/pelrock.h"
+
+namespace Pelrock {
+
+struct Spell {
+ Common::StringArray text;
+ int page;
+ byte *image;
+};
+
+struct Bookmark {
+ int16 x;
+ int16 y;
+ byte w;
+ byte h;
+ int page;
+};
+
+static const Bookmark _bookmarks[13] = {
+ {244, 8, 23, 40, 0},
+ {396, 17, 44, 20, 1},
+ {480, 68, 40, 42, 4},
+ {480, 129, 30, 25, 5},
+ {480, 224, 28, 32, 8},
+ {416, 344, 23, 17, 12},
+ {368, 346, 28, 34, 11},
+ {198, 340, 26, 28, 10},
+ {164, 336, 33, 17, 9},
+ {95, 277, 33, 24, 7},
+ {105, 227, 27, 33, 6},
+ {103, 118, 30, 26, 3},
+ {101, 78, 36, 33, 2}
+};
+
+class SpellBook {
+
+public:
+ SpellBook(PelrockEventManager *eventMan, ResourceManager *res);
+ ~SpellBook();
+
+ /**
+ * Returns the spell the user selected
+ */
+ Spell *run();
+
+private:
+ PelrockEventManager *_events;
+ ResourceManager *_res;
+ Graphics::ManagedSurface _backgroundScreen;
+ Graphics::ManagedSurface _compositeScreen;
+ byte *_palette;
+
+ Spell *_spell = nullptr;
+ Spell *_selectedSpell = nullptr;
+
+ void init();
+ void selectPage(int page);
+ void drawScreen();
+ void loadBackground();
+ void cleanup();
+ bool checkMouse(int x, int y);
+};
+
+} // End of namespace Pelrock
+
+#endif
Commit: 8767c0a4bc4020dba8fad49b60c286a7cff4519c
https://github.com/scummvm/scummvm/commit/8767c0a4bc4020dba8fad49b60c286a7cff4519c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:28+02:00
Commit Message:
PELROCK: Turn all offsets and sizes into constants
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/backgroundbook.cpp
engines/pelrock/cdplayer.cpp
engines/pelrock/fonts/large_font.cpp
engines/pelrock/fonts/small_font.cpp
engines/pelrock/menu.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/spellbook.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 81068b91b1d..f88b9cdbe1c 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -32,6 +32,8 @@
namespace Pelrock {
+static const uint32 kStatuePaletteDataOffset = 0x4C700; // JUEGO.EXE â statue palette animation data
+
#define MASCULINE true
#define FEMININE false
@@ -2268,7 +2270,7 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
}
// Read the palette data structure from JUEGO.EXE
- exeFile.seek(0x4C700, SEEK_SET);
+ exeFile.seek(kStatuePaletteDataOffset, SEEK_SET);
StatuePaletteData paletteData;
paletteData.x = exeFile.readUint16LE();
diff --git a/engines/pelrock/backgroundbook.cpp b/engines/pelrock/backgroundbook.cpp
index 8573849ec81..106ae4d079a 100644
--- a/engines/pelrock/backgroundbook.cpp
+++ b/engines/pelrock/backgroundbook.cpp
@@ -28,6 +28,10 @@
namespace Pelrock {
+static const uint32 kBgBookButtonsOffset = 3188448; // ALFRED.7 â UI buttons
+static const uint32 kRoomNamesOffset = 299797; // JUEGO.EXE â room name strings
+static const uint32 kRoomNamesSize = 1297;
+
BackgroundBook::BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res, RoomManager *room)
: _events(eventMan), _res(res), _room(room) {
init();
@@ -117,8 +121,8 @@ void BackgroundBook::loadRoomNames() {
error("Couldnt find file JUEGO.EXE");
}
- size_t namesSize = 1297;
- juegoExe.seek(299797, SEEK_SET);
+ size_t namesSize = kRoomNamesSize;
+ juegoExe.seek(kRoomNamesOffset, SEEK_SET);
byte *namesData = new byte[namesSize];
juegoExe.read(namesData, namesSize);
uint32 pos = 0;
@@ -180,7 +184,7 @@ void BackgroundBook::loadButtons() {
if (!alfred7.open("ALFRED.7")) {
return;
}
- alfred7.seek(3188448, SEEK_SET);
+ alfred7.seek(kBgBookButtonsOffset, SEEK_SET);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
int w = _buttonRects[i].width();
diff --git a/engines/pelrock/cdplayer.cpp b/engines/pelrock/cdplayer.cpp
index 7b4b5d983b5..a67575a2cbb 100644
--- a/engines/pelrock/cdplayer.cpp
+++ b/engines/pelrock/cdplayer.cpp
@@ -28,6 +28,9 @@
namespace Pelrock {
+static const uint32 kCDPlayerTrackNamesOffset = 301203; // JUEGO.EXE â track name strings
+static const uint32 kCDPlayerControlsOffset = 2214760; // ALFRED.7 â controls sprite
+
CDPlayer::CDPlayer(PelrockEventManager *eventMan, ResourceManager *res, SoundManager *sound)
: _events(eventMan), _res(res), _sound(sound) {
init();
@@ -73,7 +76,7 @@ void CDPlayer::loadTrackNames() {
if (!juegoFile.open("JUEGO.EXE")) {
return;
}
- juegoFile.seek(301203, SEEK_SET);
+ juegoFile.seek(kCDPlayerTrackNamesOffset, SEEK_SET);
for (int i = 0; i < 31; i++) {
trackNames[i] = juegoFile.readString(0, 30);
@@ -184,10 +187,10 @@ void CDPlayer::loadControls() {
if (!alfred7.open("ALFRED.7")) {
return;
}
- alfred7.seek(2214760, SEEK_SET);
+ alfred7.seek(kCDPlayerControlsOffset, SEEK_SET);
byte *compressedData = nullptr;
size_t outSize = 0;
- readUntilBuda(&alfred7, 2214760, compressedData, outSize);
+ readUntilBuda(&alfred7, kCDPlayerControlsOffset, compressedData, outSize);
byte *rawData = nullptr;
rleDecompress(compressedData, outSize, 0, 0, &rawData, true);
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index f6aa4f12e7f..22d56c5c761 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -23,6 +23,8 @@
namespace Pelrock {
+static const uint32 kLargeFontOffset = 0x7DC8; // ALFRED.7 â large font bitmap data
+
LargeFont::LargeFont() : _fontData(nullptr) {
}
@@ -36,7 +38,7 @@ bool LargeFont::load(const Common::String &filename) {
return false;
}
- file.seek(0x7DC8, SEEK_SET);
+ file.seek(kLargeFontOffset, SEEK_SET);
const int numChars = 100;
const int charWidth = 12;
const int charHeight = 24;
diff --git a/engines/pelrock/fonts/small_font.cpp b/engines/pelrock/fonts/small_font.cpp
index 9dff0d694e2..93d06bb31d9 100644
--- a/engines/pelrock/fonts/small_font.cpp
+++ b/engines/pelrock/fonts/small_font.cpp
@@ -23,6 +23,8 @@
namespace Pelrock {
+static const uint32 kSmallFontOffset = 0x8F32; // ALFRED.4 â small font bitmap data
+
SmallFont::SmallFont() : _fontData(nullptr) {
}
@@ -36,7 +38,7 @@ bool SmallFont::load(const Common::String &filename) {
return false;
}
- file.seek(0x8F32, SEEK_SET);
+ file.seek(kSmallFontOffset, SEEK_SET);
const int dataSize = kNumChars * 8; // 256 characters, 8x8 pixels
debug("SmallFont::load: Loading font data of size %d from %s", dataSize, filename.c_str());
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 6682cf1ecac..01e478b3d3b 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -31,6 +31,30 @@
namespace Pelrock {
+// ALFRED.7 â alternate settings palette
+static const uint32 kSettingsPaletteOffset = 0x2884C2;
+
+// JUEGO.EXE â inventory object descriptions
+static const uint32 kInventoryDescriptionsOffset = 0x4715E;
+static const uint32 kInventoryDescriptionsSize = 7868;
+
+// JUEGO.EXE â in-menu text strings
+static const uint32 kMenuTextOffset = 0x49203;
+static const uint32 kMenuTextSize = 230;
+
+// ALFRED.7 â main menu background
+static const uint32 kMainMenuPart1Offset = 2405266;
+static const uint32 kMainMenuPart1RawSize = 65536; // first uncompressed chunk
+static const uint32 kMainMenuPart1CompressedSize = 29418; // following compressed tail
+static const uint32 kMainMenuPart2Offset = 2500220;
+static const uint32 kMainMenuPart2RawSize = 32768;
+static const uint32 kMainMenuPart2CompressedSize = 30288;
+static const uint32 kMainMenuPart3Offset = 2563266;
+static const uint32 kMainMenuPart3Size = 92160;
+
+// ALFRED.7 â menu buttons (save/load/sound/exit, one contiguous block)
+static const uint32 kMenuButtonsOffset = 3193376;
+
Pelrock::MenuManager::MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res, SoundManager *sound) : _screen(screen), _events(events), _res(res), _sound(sound) {
}
@@ -239,38 +263,38 @@ void MenuManager::loadMenu() {
}
uint32 curPos = 0;
- alfred7.seek(2405266, SEEK_SET);
- alfred7.read(_mainMenu.getPixels(), 65536);
+ alfred7.seek(kMainMenuPart1Offset, SEEK_SET);
+ alfred7.read(_mainMenu.getPixels(), kMainMenuPart1RawSize);
- curPos += 65536;
+ curPos += kMainMenuPart1RawSize;
- byte *compressedPart1 = new byte[29418];
- alfred7.read(compressedPart1, 29418);
+ byte *compressedPart1 = new byte[kMainMenuPart1CompressedSize];
+ alfred7.read(compressedPart1, kMainMenuPart1CompressedSize);
byte *decompressedPart1 = nullptr;
- size_t decompressedSize = rleDecompress(compressedPart1, 29418, 0, 0, &decompressedPart1, true);
+ size_t decompressedSize = rleDecompress(compressedPart1, kMainMenuPart1CompressedSize, 0, 0, &decompressedPart1, true);
memcpy((byte *)_mainMenu.getPixels() + curPos, decompressedPart1, decompressedSize);
curPos += decompressedSize;
delete[] compressedPart1;
delete[] decompressedPart1;
- alfred7.seek(2500220, SEEK_SET);
- alfred7.read((byte *)_mainMenu.getPixels() + curPos, 32768);
- curPos += 32768;
- byte *compressedPart2 = new byte[30288];
- alfred7.read(compressedPart2, 30288);
+ alfred7.seek(kMainMenuPart2Offset, SEEK_SET);
+ alfred7.read((byte *)_mainMenu.getPixels() + curPos, kMainMenuPart2RawSize);
+ curPos += kMainMenuPart2RawSize;
+ byte *compressedPart2 = new byte[kMainMenuPart2CompressedSize];
+ alfred7.read(compressedPart2, kMainMenuPart2CompressedSize);
byte *decompressedPart2 = nullptr;
- decompressedSize = rleDecompress(compressedPart2, 30288, 0, 0, &decompressedPart2, true);
+ decompressedSize = rleDecompress(compressedPart2, kMainMenuPart2CompressedSize, 0, 0, &decompressedPart2, true);
memcpy((byte *)_mainMenu.getPixels() + curPos, decompressedPart2, decompressedSize);
curPos += decompressedSize;
- debug("Settings menu size loaded: %d, with last block %d", curPos, curPos + 92160);
+ debug("Settings menu size loaded: %d, with last block %d", curPos, curPos + (int)kMainMenuPart3Size);
delete[] compressedPart2;
delete[] decompressedPart2;
- alfred7.seek(2563266, SEEK_SET);
- alfred7.read((byte *)_mainMenu.getPixels() + curPos, 92160);
+ alfred7.seek(kMainMenuPart3Offset, SEEK_SET);
+ alfred7.read((byte *)_mainMenu.getPixels() + curPos, kMainMenuPart3Size);
- readButton(alfred7, 3193376, _saveButtons, _saveGameRect);
+ readButton(alfred7, kMenuButtonsOffset, _saveButtons, _saveGameRect);
readButton(alfred7, alfred7.pos(), _loadButtons, _loadGameRect);
readButton(alfred7, alfred7.pos(), _soundsButtons, _soundsRect);
readButton(alfred7, alfred7.pos(), _exitToDosButtons, _exitToDosRect);
@@ -278,7 +302,7 @@ void MenuManager::loadMenu() {
readButton(alfred7, alfred7.pos(), _inventoryRightArrow, _invRight);
readButton(alfred7, alfred7.pos(), _savesUpArrows, _savesUp);
readButton(alfred7, alfred7.pos(), _savesDownArrows, _savesDown);
- readButton(alfred7, 3214046, _questionMark, _questionMarkRect);
+ readButton(alfred7, kQuestionMarkOffset, _questionMark, _questionMarkRect);
_menuText = _menuTexts[0];
alfred7.close();
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 1a2da8ac59f..e03d6c60501 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -25,37 +25,7 @@
namespace Pelrock {
-static const uint32 cursor_offsets[5] = {
- 0x0FDDFD,
- 0x0FDCDD,
- 0x0FDF1D,
- 0x0FE33D,
- 0x367EF0};
-
-static const uint32 kBalloonFramesOffset = 2176936;
-static const uint32 kBalloonFramesSize = 24950;
-
-static const uint32 ALFRED7_ALFRED_COMB_R = 67768;
-static const uint32 ALFRED7_ALFRED_COMB_L = 88408;
-
-static const uint32 kAlternateSettingsMenuOffset = 910097;
-static const uint32 kAlternateSettingsPaletteOffset = 1038141; // 640 * 480
-static const uint32 kSettingsPaletteOffset = 0x2884c2; // 640 * 480
-
-const uint32 kDescriptionBaseOffset = 0x4715D;
-const uint16 kNumDescriptions = 113;
-
-static const uint32 kInventoryDescriptionsOffset = 0x4715E;
-static const uint32 kInventoryDescriptionsSize = 7868;
-static const uint32 kMenuTextOffset = 0x49203;
-static const uint32 kMenuTextSize = 230;
-static const uint32 kAlfredResponsesOffset = 0x441DC;
-static const uint32 kConversationTerminatorOffset = 0x0492EE;
-static const uint32 kAlfredResponsesSize = 12143;
-static const uint32 kCreditsOffset = 0x49F60;
-static const uint32 kCreditsSize = 2540;
-
-static const uint32 pegatina_offsets[137] = {
+static const uint32 stickerOffsets[137] = {
0x000000, 0x00005B, 0x0000B6, 0x000298, 0x00047A, 0x0023C8, 0x004316, 0x004376,
0x005119, 0x005EBC, 0x0083ED, 0x008529, 0x0092C4, 0x00A3AA, 0x00B490, 0x00B6A6,
0x00C05A, 0x00CA0E, 0x00D3D0, 0x00D46E, 0x00F036, 0x00FB8F, 0x00FC55, 0x0119D7,
@@ -75,51 +45,6 @@ static const uint32 pegatina_offsets[137] = {
0x07ECED, 0x07F52F, 0x07FD71, 0x080591, 0x080B24, 0x080B84, 0x080F39, 0x0812F5,
0x0816B1};
-static const byte pegatina_rooms[140] = {
- 0, 0, 0, 0, 0, 0, 0, // Sprites 0-6: Room 0
- 2, 2, // Sprites 7-8: Room 2
- 3, 3, 3, 3, 3, 3, 3, 3, // Sprites 9-16: Room 3
- 4, 4, 4, 4, 4, // Sprites 17-21: Room 4
- 5, 5, // Sprites 22-23: Room 5
- 7, // Sprite 24: Room 7
- 8, 8, // Sprites 25-26: Room 8
- 9, 9, 9, 9, 9, // Sprites 27-31: Room 9
- 12, 12, // Sprites 32-33: Room 12
- 13, 13, 13, // Sprites 34-36: Room 13
- 12, // Sprite 37: Room 12
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, // Sprites 38-49: Room 15
- 16, 16, // Sprites 50-51: Room 16
- 17, 17, // Sprites 52-53: Room 17
- 19, 19, 19, 19, 19, // Sprites 54-58: Room 19
-
- 0, 0, 0, 0, 0, 0, 0, // Sprites 59-65: Room 0
- 33, 33, // Sprites 66-67: Room 33
- 29, 29, // Sprites 68-69: Room 29
- 0, 0, 0, // Sprites 70-72: Room 0
-
- 34, 35, 31, 25, // Sprites 73-76: Various rooms
- 31, // Sprite 77: Room 31
- 32, // Sprite 78: Room 32
- 21, 25, // Sprites 79-80: Rooms 21, 25
- 0, // Sprite 81: Room 0
- 0, 0, 0, 0, 0, // Sprites 82-86: Room 0
- 4, 4, 4, 4, // Sprites 87-90: Room 4
- 0, 0, 0, 0, // Sprites 91-94: Room 0
- 0, 0, 0, 0, 0, 0, // Sprites 95-100: Room 0
- 33, 33, // Sprites 101-102: Room 33
- 47, 47, // Sprites 103-104: Room 47
- 52, 52, 52, 52, 52, // Sprites 105-109: Room 52
- 52, 52, 52, 52, 52, 52, // Sprites 110-115: Room 52
- 41, // Sprite 116: Room 41
- 0, // Sprite 117: Room 0
- 30, // Sprite 118: Room 30
- 44, 44, 44, 44, // Sprites 119-122: Room 44
- 31, // Sprite 123: Room 31
- 46, 46, // Sprites 124-125: Room 46
- 31, // Sprite 126: Room 31
- 51, 52, 53, 54 // Sprites 127-130: Various rooms
-};
-
enum TextIndices {
ESTAN_CERRADOS,
HOY_NO_DISPONIBLES,
@@ -319,8 +244,9 @@ enum TextIndices {
LASPUERTAS_DELCIELO,
};
-// Description offsets relative to kDescriptionBaseOffset
-static const uint16 description_offsets[kNumDescriptions] = {
+// Description offsets relative to base offset 0x4715D.
+// NOTE: unused dead code â kept for reference only.
+static const uint16 description_offsets[113] = {
0x0000, // Object 0: Historia de la Princesa Zenna y su amante insatisfecho
0x0058, // Object 1: Nombre: Alfred Pelrock
0x00C4, // Object 2: La tipica tarjeta por la que te sacan commisiones
@@ -500,28 +426,19 @@ static const ExtraImages extraScreens[] = {
};
+// AlfredSpecialAnimOffset: POD struct (no constructors) to avoid global-constructor overhead.
+// Fields are ordered to match natural aggregate-initializer order.
+// size == 0 means "compute as numFrames * w * h" at load time.
struct AlfredSpecialAnimOffset {
- int numFrames = 0;
- int w = 0;
- int h = 0;
+ int numFrames;
+ int w;
+ int h;
int numBudas;
- int loops;
int numAlfred;
uint32 offset;
- int stride = 0;
- uint32 size;
- int speed = 2;
-
- AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, int numAlfred, uint32 off, int loops, int speed = 2)
- : numFrames(nF), w(width), h(height), numBudas(nBudas), numAlfred(numAlfred), offset(off), loops(loops), speed(speed) {
- AlfredSpecialAnimOffset(nF, width, height, nBudas, numAlfred, off, loops, speed, width * height * nF);
- }
- AlfredSpecialAnimOffset(int nF, int width, int height, int nBudas, int numAlfred, uint32 off, int loops, int speed, uint32 sz)
- : numFrames(nF), w(width), h(height), numBudas(nBudas), numAlfred(numAlfred), offset(off), loops(loops), size(sz), speed(speed) {
- stride = w * h;
- }
- AlfredSpecialAnimOffset() {
- }
+ int loops;
+ int speed;
+ uint32 size; // 0 = compute from numFrames * w * h
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index ff0343e5744..93aa740080e 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -46,6 +46,8 @@
namespace Pelrock {
+static const uint32 kInventoryArrowsOffset = 3186048; // ALFRED.7 â inventory scroll arrows
+
PelrockEngine *g_engine;
PelrockEngine::PelrockEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst),
@@ -186,7 +188,7 @@ void PelrockEngine::loadInventoryArrows() {
error("Failed to open ALFRED.7 to load inventory arrows");
return;
}
- alfred7.seek(3186048, SEEK_SET); // Offset for inventory arrows in ALFRED.7
+ alfred7.seek(kInventoryArrowsOffset, SEEK_SET); // Inventory arrows in ALFRED.7
_inventoryOverlayState.arrows[0] = new byte[20 * 60];
_inventoryOverlayState.arrows[1] = new byte[20 * 60];
alfred7.read(_inventoryOverlayState.arrows[0], 20 * 60);
@@ -704,7 +706,7 @@ void PelrockEngine::updateAnimations() {
void PelrockEngine::presentFrame() {
_screen->blitFrom(_compositeBuffer);
- paintDebugLayer();
+ // paintDebugLayer();
_screen->markAllDirty();
}
@@ -2110,7 +2112,6 @@ void PelrockEngine::loadExtraScreenAndPresent(int screenIndex) {
void PelrockEngine::waitForSpecialAnimation() {
while (!g_engine->shouldQuit() && !_res->_isSpecialAnimFinished) {
_events->pollEvent();
- debug("Waiting for special animation to finish, current frame %d", _res->_currentSpecialAnim->curFrame);
renderScene(OVERLAY_NONE);
_screen->update();
g_system->delayMillis(10);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 894a1ffec2f..ec51bd361fb 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -28,6 +28,54 @@
namespace Pelrock {
+// ALFRED.7 â cursor sprites
+static const uint32 cursor_offsets[5] = {0x0FDDFD, 0x0FDCDD, 0x0FDF1D, 0x0FE33D, 0x367EF0};
+
+// ALFRED.3 / ALFRED.7 â Alfred combing animations
+static const uint32 ALFRED7_ALFRED_COMB_R = 67768;
+static const uint32 ALFRED7_ALFRED_COMB_L = 88408;
+
+// ALFRED.4 â inventory icon pixel data
+static const uint32 kInventoryIconsOffset = 42366;
+static const uint32 kInventoryIconsTailSize = 423656; // bytes trailing the icon block
+
+// ALFRED.7 â action-popup balloon frames
+static const uint32 kBalloonFramesOffset = 2176936;
+static const uint32 kBalloonFramesSize = 24950; // compressed size
+
+// JUEGO.EXE â Alfred in-game text responses
+static const uint32 kAlfredResponsesOffset = 0x441DC;
+static const uint32 kAlfredResponsesSize = 12143;
+static const uint32 kConversationTerminatorOffset = 0x0492EE;
+
+// JUEGO.EXE â credits
+static const uint32 kCreditsOffset = 0x49F60;
+static const uint32 kCreditsSize = 2540;
+
+// JUEGO.EXE â computer-screen text
+static const uint32 kComputerTextOffset = 0x0004901A;
+static const uint32 kComputerTextSize = 490;
+
+// Alfred special animation data (file index given per entry in alfredSpecialAnims[])
+static const uint32 kAlfredAnimReadBookOffset = 559685; // 0 - READ BOOK
+static const uint32 kAlfredAnimReadRecipeOffset = 578943; // 1 - READ RECIPE
+static const uint32 kAlfredAnimElectricShock1Offset = 37000; // 2 - ELECTRIC SHOCK 1
+static const uint32 kAlfredAnimElectricShock3Offset = 53106; // 3 - ELECTRIC SHOCK 3
+static const uint32 kAlfredAnimThrowOffset = 20724; // 4 - Throw
+static const uint32 kAlfredAnimThrowSize = 62480; // 4 - Throw explicit size
+static const uint32 kAlfredAnimCrocodileOffset = 1556540; // 5 - Crocodile
+static const uint32 kAlfredAnimManholeOffset = 1583702; // 6 - Exit manhole
+static const uint32 kAlfredAnimClimbDownOffset = 1761234; // 7 - Climbs down
+static const uint32 kAlfredAnimClimbUpOffset = 1766378; // 8 - Climbs up
+static const uint32 kAlfredAnimExitTunnelOffset = 1770196; // 9 - Exits tunnel
+static const uint32 kAlfredAnimWorkersOffset = 1600956; // 10 - With workers
+static const uint32 kAlfredAnimMunheco1Offset = 2060916; // 11 - Munheco 1
+static const uint32 kAlfredAnimMunheco2Offset = 2115632; // 12 - Munheco 2
+static const uint32 kAlfredAnimMunheco3Offset = 1526432; // 13 - Munheco 3
+static const uint32 kAlfredAnimDescamisaOffset = 2972568; // 14 - Descamisa
+static const uint32 kAlfredAnimSecretPassageOffset = 1749464; // 15 - Secret passage
+static const uint32 kAlfredAnimInBedOffset = 3038454; // 16 - Alfred in bed
+
ResourceManager::ResourceManager(/* args */) {
_inventoryIcons = new InventoryObject[69];
for (int i = 0; i < 4; i++) {
@@ -36,23 +84,23 @@ ResourceManager::ResourceManager(/* args */) {
}
const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
- {10, 51, 102, 1, 7, 559685, 1}, // 0 - READ BOOK
- {10, 51, 102, 1, 7, 578943, 1}, // 1 - READ RECIPE
- {3, 45, 87, 0, 7, 37000, 1}, // 2 - ELECTRIC SHOCK 1
- {2, 82, 58, 0, 7, 53106, 20, 1}, // 3 - ELECTRIC SHOCK 3
- {3, 71, 110, 1, 2, 20724, 1, 1, 62480}, // 4 - Throw
- {14, 171, 107, 1, 7, 1556540, 1}, // 5 - crocodile
- {12, 113, 103, 1, 7, 1583702, 1}, // 6 - exit through manhole
- {11, 33, 72, 1, 7, 1761234, 1}, // 7 - alfred climbs down
- {9, 33, 72, 1, 7, 1766378, 1}, // 8 - alfred climbs up
- {16, 158, 115, 0, 7, 1770196, 1}, // 9 - alfred exits tunnel
- {7, 208, 102, 0, 7, 1600956, 1}, // 10 - alfred with workers
- {23, 116, 124, 1, 7, 2060916, 1}, // 11 - Munheco 1
- {18, 177, 124, 1, 7, 2115632, 1}, // 12 - Munheco 2
- {11, 98, 138, 1, 7, 1526432, 1}, // 13 - Munheco 3
- {4, 51, 102, 1, 7, 2972568, 1}, // 14 - descamisa
- {13, 95, 99, 1, 7, 1749464, 1}, // 15 - alfred enters secret passage
- {14, 71, 66, 1, 7, 3038454, 1, 2}, // 16- Alfred in bed
+ {10, 51, 102, 1, 7, kAlfredAnimReadBookOffset, 1, 2, 0}, // 0 - READ BOOK
+ {10, 51, 102, 1, 7, kAlfredAnimReadRecipeOffset, 1, 2, 0}, // 1 - READ RECIPE
+ { 3, 45, 87, 0, 7, kAlfredAnimElectricShock1Offset, 1, 2, 0}, // 2 - ELECTRIC SHOCK 1
+ { 2, 82, 58, 0, 7, kAlfredAnimElectricShock3Offset, 20, 1, 0}, // 3 - ELECTRIC SHOCK 3
+ { 3, 71, 110, 1, 2, kAlfredAnimThrowOffset, 1, 1, kAlfredAnimThrowSize}, // 4 - Throw
+ {14, 171, 107, 1, 7, kAlfredAnimCrocodileOffset, 1, 2, 0}, // 5 - crocodile
+ {12, 113, 103, 1, 7, kAlfredAnimManholeOffset, 1, 2, 0}, // 6 - exit through manhole
+ {11, 33, 72, 1, 7, kAlfredAnimClimbDownOffset, 1, 2, 0}, // 7 - alfred climbs down
+ { 9, 33, 72, 1, 7, kAlfredAnimClimbUpOffset, 1, 2, 0}, // 8 - alfred climbs up
+ {16, 158, 115, 0, 7, kAlfredAnimExitTunnelOffset, 1, 2, 0}, // 9 - alfred exits tunnel
+ { 7, 208, 102, 0, 7, kAlfredAnimWorkersOffset, 1, 2, 0}, // 10 - alfred with workers
+ {23, 116, 124, 1, 7, kAlfredAnimMunheco1Offset, 1, 2, 0}, // 11 - Munheco 1
+ {18, 177, 124, 1, 7, kAlfredAnimMunheco2Offset, 1, 2, 0}, // 12 - Munheco 2
+ {11, 98, 138, 1, 7, kAlfredAnimMunheco3Offset, 1, 2, 0}, // 13 - Munheco 3
+ { 4, 51, 102, 1, 7, kAlfredAnimDescamisaOffset, 1, 2, 0}, // 14 - descamisa
+ {13, 95, 99, 1, 7, kAlfredAnimSecretPassageOffset, 1, 2, 0}, // 15 - alfred enters secret passage
+ {14, 71, 66, 1, 7, kAlfredAnimInBedOffset, 1, 2, 0}, // 16 - Alfred in bed
};
ResourceManager::~ResourceManager() {
@@ -342,9 +390,9 @@ void ResourceManager::loadInventoryItems() {
if (!alfred4File.open("ALFRED.4")) {
error("Couldnt find file ALFRED.4");
}
- uint32 iconsSize = alfred4File.size() - 423656;
+ uint32 iconsSize = alfred4File.size() - kInventoryIconsTailSize;
byte *iconData = new byte[iconsSize];
- alfred4File.seek(42366, SEEK_SET);
+ alfred4File.seek(kInventoryIconsOffset, SEEK_SET);
alfred4File.read(iconData, iconsSize);
for (int i = 0; i < 69; i++) {
@@ -404,9 +452,9 @@ Common::Array<Common::StringArray> ResourceManager::loadComputerText() {
if (!exe.open("JUEGO.EXE")) {
error("Couldnt find file JUEGO.EXE");
}
- int bufSize = 490;
+ int bufSize = kComputerTextSize;
byte *computerTextBuf = new byte[bufSize];
- exe.seek(0x0004901A, SEEK_SET);
+ exe.seek(kComputerTextOffset, SEEK_SET);
exe.read(computerTextBuf, bufSize);
Common::Array<Common::StringArray> computerTexts = processTextData(computerTextBuf, bufSize);
@@ -508,14 +556,13 @@ Pelrock::Sticker ResourceManager::getSticker(int stickerIndex) {
error("Couldnt find file ALFRED.6");
}
- uint32 stickerOffset = pegatina_offsets[stickerIndex];
+ uint32 stickerOffset = stickerOffsets[stickerIndex];
alfred6File.seek(stickerOffset, SEEK_SET);
Sticker sticker;
sticker.x = alfred6File.readUint16LE();
sticker.y = alfred6File.readUint16LE();
sticker.w = alfred6File.readByte();
sticker.h = alfred6File.readByte();
- sticker.roomNumber = pegatina_rooms[stickerIndex];
sticker.stickerIndex = stickerIndex;
sticker.stickerData = new byte[sticker.w * sticker.h];
alfred6File.read(sticker.stickerData, sticker.w * sticker.h);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index cfd51083793..e08ad61d9f8 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -27,6 +27,8 @@
namespace Pelrock {
+static const uint32 kPaletteRemapOffset = 0x4C77C; // JUEGO.EXE â water-effect palette remap table
+
RoomManager::RoomManager() {
_pixelsShadows = new byte[640 * 400];
loadWaterPaletteRemap();
@@ -46,7 +48,7 @@ void RoomManager::loadWaterPaletteRemap() {
if(!exe.open("JUEGO.EXE")) {
error("Couldnt find file JUEGO.EXE");
}
- exe.seek(0x4C77C, SEEK_SET);
+ exe.seek(kPaletteRemapOffset, SEEK_SET);
exe.read(_paletteRemaps[4], 256);
exe.close();
}
diff --git a/engines/pelrock/spellbook.cpp b/engines/pelrock/spellbook.cpp
index ec8e1d00852..ac802b8cc93 100644
--- a/engines/pelrock/spellbook.cpp
+++ b/engines/pelrock/spellbook.cpp
@@ -29,6 +29,11 @@
namespace Pelrock {
+static const uint32 kSpellbookImgOffset = 1268719; // ALFRED.7 â spellbook sprite sheet start
+static const uint32 kSpellbookImgDataOffset = 1268723; // ALFRED.7 â compressed sprite data
+static const uint32 kSpellbookTextOffset = 288285; // JUEGO.EXE â spellbook page text
+static const uint32 kSpellbookTextSize = 2861;
+
SpellBook::SpellBook(PelrockEventManager *eventMan, ResourceManager *res)
: _palette(nullptr),
_events(eventMan),
@@ -80,28 +85,28 @@ void SpellBook::selectPage(int page) {
return;
}
- alfred7.seek(1268719, SEEK_SET);
+ alfred7.seek(kSpellbookImgOffset, SEEK_SET);
int w = 119;
int h = 99;
int nFrames = 13;
byte *compressedData = nullptr;
byte *spriteData = nullptr;
size_t outSize = 0;
- readUntilBuda(&alfred7, 1268723, compressedData, outSize);
+ readUntilBuda(&alfred7, kSpellbookImgDataOffset, compressedData, outSize);
rleDecompress(compressedData, outSize, 0, w * h * nFrames, &spriteData, false);
_spell->image = new byte[w * h];
extractSingleFrame(spriteData, _spell->image, page, w, h);
- juegoFile.seek(0x0004661D, SEEK_SET);
- byte *textData = new byte[2861];
- juegoFile.read(textData, 2861);
+ juegoFile.seek(kSpellbookTextOffset, SEEK_SET);
+ byte *textData = new byte[kSpellbookTextSize];
+ juegoFile.read(textData, kSpellbookTextSize);
- for (int i = 0; i < 2861; ++i) {
+ for (int i = 0; i < (int)kSpellbookTextSize; ++i) {
if (textData[i] == 0x0D)
textData[i] = 23;
}
- Common::Array<Common::StringArray> spells = _res->processTextData(textData, 2861, true);
+ Common::Array<Common::StringArray> spells = _res->processTextData(textData, kSpellbookTextSize, true);
_spell->text = spells[page];
delete[] compressedData;
delete[] spriteData;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 04248301f3d..e227d1a4ae9 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -420,7 +420,6 @@ struct PaletteAnimFade {
};
struct Sticker {
- int roomNumber;
int stickerIndex;
uint16 x;
uint16 y;
Commit: 0171a5e989e009c76a58b8070260543432c831ba
https://github.com/scummvm/scummvm/commit/0171a5e989e009c76a58b8070260543432c831ba
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:29+02:00
Commit Message:
PELROCK: Prevent sticker flicker on room change
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 93aa740080e..9764a649f3c 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1027,6 +1027,11 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.x = exit->targetX;
_alfredState.y = exit->targetY;
setScreenAndPrepare(exit->targetRoom, exit->dir);
+ // setScreen() resets the composite buffer to the bare background;
+ // place first-pass stickers now so they are present in the very
+ // first presentFrame() for the new room (avoids a one-frame flash
+ // without stickers).
+ placeStickersFirstPass();
}
}
} else {
Commit: 58677e4489e1329214aad1d51794932ebbda9045
https://github.com/scummvm/scummvm/commit/58677e4489e1329214aad1d51794932ebbda9045
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:29+02:00
Commit Message:
PELROCK: Closes main menu after loading/saving
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/saveload.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 01e478b3d3b..33209820fdf 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -89,7 +89,7 @@ MenuButton MenuManager::isButtonClicked(int x, int y) {
return NO_BUTTON; // Default fallback
}
-void MenuManager::checkMouseClick(int x, int y) {
+bool MenuManager::checkMouseClick(int x, int y) {
bool selectedItem = false;
for (int i = 0; i < 4; i++) {
@@ -98,7 +98,7 @@ void MenuManager::checkMouseClick(int x, int y) {
if (itemRect.contains(x, y)) {
selectedItem = selectInventoryItem(i);
- return;
+ return false;
}
}
if (!selectedItem) {
@@ -122,10 +122,10 @@ void MenuManager::checkMouseClick(int x, int y) {
_curInventoryPage++;
break;
case SAVE_GAME_BUTTON:
- g_engine->saveGameDialog();
+ return g_engine->saveGameDialog();
break;
case LOAD_GAME_BUTTON:
- g_engine->loadGameDialog();
+ return g_engine->loadGameDialog();
break;
case EXIT_MENU_BUTTON:
g_engine->quitGame();
@@ -133,6 +133,7 @@ void MenuManager::checkMouseClick(int x, int y) {
default:
break;
}
+ return false;
}
void MenuManager::showCredits() {
@@ -191,15 +192,19 @@ void MenuManager::menuLoop() {
g_system->getPaletteManager()->setPalette(_mainMenuPalette, 0, 256);
g_engine->changeCursor(DEFAULT);
_menuText = _menuTexts[0];
- while (!g_engine->shouldQuit() && !_events->_rightMouseClicked) {
+ while (!g_engine->shouldQuit()) {
_events->pollEvent();
if (_events->_leftMouseClicked) {
- checkMouseClick(_events->_mouseX, _events->_mouseY);
+ if(checkMouseClick(_events->_mouseX, _events->_mouseY)) {
+ break;
+ }
_events->_leftMouseClicked = false;
}
-
+ if(_events->_rightMouseClicked) {
+ break;
+ }
drawScreen();
_screen->markAllDirty();
_screen->update();
@@ -207,6 +212,7 @@ void MenuManager::menuLoop() {
}
g_engine->_graphics->clearScreen();
_events->_rightMouseClicked = false;
+ _events->_leftMouseClicked = false;
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
cleanUp();
}
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 36bfe819821..76e9eea7ece 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -214,7 +214,7 @@ public:
byte _mainMenuPalette[768] = {0};
private:
- void checkMouseClick(int x, int y);
+ bool checkMouseClick(int x, int y);
void showCredits();
bool selectInventoryItem(int i);
void loadMenuTexts();
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index 07ee9409bba..ac62e159528 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -384,6 +384,7 @@ SaveGameData *PelrockEngine::createSaveGameData() const {
saveGame->alfredY = _alfredState.y;
saveGame->alfredDir = _alfredState.direction;
saveGame->gameState = g_engine->_state;
+ _state->stateGame = GAME;
return saveGame;
}
Commit: 3fb39ab5c7e2caf6b9b09d90836413539f5d8b84
https://github.com/scummvm/scummvm/commit/3fb39ab5c7e2caf6b9b09d90836413539f5d8b84
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:29+02:00
Commit Message:
PELROCK: Implement TTL for dialogue lines
Changed paths:
engines/pelrock/dialog.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 9b0bd49770d..dbadaf4d149 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -128,17 +128,14 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, Graphic
if (bbox.contains(_events->_mouseX, _events->_mouseY)) {
choiceColor = 15;
- } else if (leftArrowBox.contains(_events->_mouseX, _events->_mouseY)) {
+ } else if (leftArrowBox.contains(_events->_mouseX, _events->_mouseY)) { // scroll left
if (choice.charOffset > 0) {
choice.charOffset--;
choices->remove_at(i);
choices->insert_at(i, choice);
}
lArrowColor = 15;
- } else if (rightArrowBox.contains(_events->_mouseX, _events->_mouseY)) {
- if (i == 0) {
- debug("First choice charOffset %d, text length %d", choice.charOffset, choice.text.size());
- }
+ } else if (rightArrowBox.contains(_events->_mouseX, _events->_mouseY)) { // scroll right
if (choice.charOffset + 76 < choice.text.size()) {
choice.charOffset = choice.charOffset + 1;
choices->remove_at(i);
@@ -158,6 +155,11 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, Graphic
}
}
+/**
+ * In order to display multi-line text whilst still centered we create a surface with
+ * the maxWidth + height then print the text onto that surface with the appropriate alignment,
+ * then blit that surface to the screen.
+ */
Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId, Graphics::TextAlign alignment) {
int maxWidth = 0;
@@ -196,7 +198,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
}
// Offset X position for Alfred to avoid overlapping with his sprite
xBasePos = g_engine->_alfredState.x;
- // Original game: uses the scaled character height (varies with perspective),
+ // Original game: uses the scaled character height
// not the fixed kAlfredFrameHeight. _alfredState.h is updated by drawAlfred().
yBasePos = g_engine->_alfredState.y - g_engine->_alfredState.h; // Above scaled sprite top
} else {
@@ -210,10 +212,22 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
displayDialogue(dialogueLines, speakerId, xBasePos, yBasePos); // Default position
}
+uint32 calcPageTtlMs(Common::Array<Common::String> dialogueLine) {
+ uint32 charCount = 0;
+ for (uint i = 0; i < dialogueLine.size(); i++) {
+ charCount += dialogueLine[i].size();
+ }
+ return charCount * kTickMs;
+}
+
/**
- * Display dialogue text and wait for click to advance
- * @param text The text to display
- * @param speakerId The speaker ID which is used as color
+ * Display dialogue text and wait for click or TTL to advance.
+ *
+ * TTL -> Each page auto-advances after (char_count * kTickMs) milliseconds.
+ * Where char_count = total visible characters on the page.
+ *
+ * Skip -> All dialogs are click-skippable unless _disableClickToAdvance flag is enabled; those
+ * dialogs still auto-advance via TTL.
*/
void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>> dialogueLines, byte speakerId, int xBasePos, int yBasePos) {
if (dialogueLines.empty()) {
@@ -226,7 +240,11 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int curPage = 0;
bool fromIntro = g_engine->_state->getFlag(FLAG_FROM_INTRO) == true;
debug("Displaying dialog, from intro = %d", fromIntro);
- // Render loop - display text and wait for click
+
+ uint32 pageTtlMs = calcPageTtlMs(dialogueLines[curPage]);
+ uint32 pageStartMs = g_system->getMillis();
+
+ // Render loop - display text and wait for click or TTL
while (!g_engine->shouldQuit()) {
_events->pollEvent();
@@ -262,17 +280,24 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_screen->markAllDirty();
_screen->update();
- if (_events->_leftMouseClicked) {
+ // Check if TTL expired for this page (always applies, even for _disableClickToAdvance)
+ bool ttlExpired = !fromIntro && (pageTtlMs > 0) && (g_system->getMillis() - pageStartMs >= pageTtlMs);
+
+ // Click-to-advance (disabled for special intro sequences)
+ bool clickAdvance = _events->_leftMouseClicked && !_disableClickToAdvance;
+ if (_events->_leftMouseClicked)
_events->_leftMouseClicked = false;
- if (!_disableClickToAdvance) {
- // debug("Dialogue click to advance, current page: %d, totalPages: %d", curPage, (int)dialogueLines.size());
+
+ if (clickAdvance || ttlExpired) {
if (curPage < (int)dialogueLines.size() - 1) {
curPage++;
+ pageStartMs = g_system->getMillis();
+ pageTtlMs = calcPageTtlMs(dialogueLines[curPage]);
} else {
_dismissDialog = true;
}
}
- }
+
if (_dismissDialog) {
_dismissDialog = false;
break; // Exit dialogue if dismissed programmatically
Commit: 0e5168ea3a401a870a340999384d641e139113d7
https://github.com/scummvm/scummvm/commit/0e5168ea3a401a870a340999384d641e139113d7
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:30+02:00
Commit Message:
PELROCK: Move pertinent code into graphics
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index f88b9cdbe1c..2882dd763d7 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1965,10 +1965,10 @@ void PelrockEngine::teleportToPrincess() {
_sound->playSound(_room->_roomSfx[3], 0);
// Draw 19 semi-transparent remapped lines
- copyBackgroundToBuffer();
- placeStickersFirstPass();
+ _graphics->copyBackgroundToBuffer();
+ _graphics->placeStickersFirstPass();
updateAnimations();
- presentFrame();
+ _graphics->presentFrame();
_screen->update();
for (int i = 0; i < 19; i++) {
@@ -1982,7 +1982,7 @@ void PelrockEngine::teleportToPrincess() {
}
updateAnimations();
- presentFrame();
+ _graphics->presentFrame();
_screen->update();
_events->pollEvent();
@@ -1991,10 +1991,10 @@ void PelrockEngine::teleportToPrincess() {
// Restore clean frame with sticker (lines gone)
_room->addSticker(stickers[phase]);
- copyBackgroundToBuffer();
- placeStickersFirstPass();
+ _graphics->copyBackgroundToBuffer();
+ _graphics->placeStickersFirstPass();
updateAnimations();
- presentFrame();
+ _graphics->presentFrame();
_screen->update();
phase++;
}
@@ -2011,10 +2011,10 @@ void PelrockEngine::teleportToPrincess() {
}
_room->addSticker(115);
- copyBackgroundToBuffer();
- placeStickersFirstPass();
+ _graphics->copyBackgroundToBuffer();
+ _graphics->placeStickersFirstPass();
updateAnimations();
- presentFrame();
+ _graphics->presentFrame();
_screen->update();
_dialog->say(_res->_ingameTexts[MAREDEDEU]);
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index dbadaf4d149..8c7aa0911f5 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -140,7 +140,6 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, Graphic
choice.charOffset = choice.charOffset + 1;
choices->remove_at(i);
choices->insert_at(i, choice);
- debug("Right arrow clicked, new charOffset %d, text length %d", choice.charOffset, choice.text.size());
}
rArrowColor = 15;
}
@@ -289,21 +288,21 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_events->_leftMouseClicked = false;
if (clickAdvance || ttlExpired) {
- if (curPage < (int)dialogueLines.size() - 1) {
- curPage++;
+ if (curPage < (int)dialogueLines.size() - 1) {
+ curPage++;
pageStartMs = g_system->getMillis();
pageTtlMs = calcPageTtlMs(dialogueLines[curPage]);
- } else {
- _dismissDialog = true;
- }
+ } else {
+ _dismissDialog = true;
}
+ }
if (_dismissDialog) {
_dismissDialog = false;
break; // Exit dialogue if dismissed programmatically
}
- if(fromIntro && g_engine->_res->_isSpecialAnimFinished) {
+ if (fromIntro && g_engine->_res->_isSpecialAnimFinished) {
debug("Dismissing due to speciawl anim ending!");
break;
}
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 062de9031bb..279fe2f2622 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -21,11 +21,13 @@
#include "common/scummsys.h"
#include "engines/util.h"
+#include "graphics/cursorman.h"
#include "graphics/paletteman.h"
#include "graphics.h"
#include "pelrock/graphics.h"
#include "pelrock/pelrock.h"
+#include "pelrock/util.h"
namespace Pelrock {
@@ -224,4 +226,329 @@ void GraphicsManager::drawColoredTexts(Graphics::ManagedSurface &buf, const Comm
}
}
+void GraphicsManager::copyBackgroundToBuffer() {
+ g_engine->_compositeBuffer.blitFrom(g_engine->_currentBackground);
+}
+
+void GraphicsManager::presentFrame() {
+ g_engine->_screen->blitFrom(g_engine->_compositeBuffer);
+ // paintDebugLayer();
+ g_engine->_screen->markAllDirty();
+}
+
+void GraphicsManager::updatePaletteAnimations() {
+ if (g_engine->_room->_currentPaletteAnim != nullptr) {
+ if (g_engine->_room->_currentPaletteAnim->paletteMode == 1) {
+ animateFadePalette(g_engine->_room->_currentPaletteAnim);
+ } else {
+ animateRotatePalette(g_engine->_room->_currentPaletteAnim);
+ }
+ }
+}
+
+void GraphicsManager::animateFadePalette(PaletteAnim *anim) {
+ // FADE palette animation - cycles a single palette entry between min/max RGB values
+ // Data layout (after loading from EXE):
+ // data[0] = current R
+ // data[1] = current G
+ // data[2] = current B
+ // data[3] = min R
+ // data[4] = min G
+ // data[5] = min B
+ // data[6] = max R
+ // data[7] = max G
+ // data[8] = max B
+ // data[9] = flags byte:
+ // bits 0-1: R increment
+ // bits 2-3: G increment
+ // bits 4-5: B increment
+ // bit 6: direction (0=decreasing toward min, 1=increasing toward max)
+
+ byte flags = anim->data[9];
+ // Increments are scaled by 4 (<<2) to match the shifted RGB values
+ byte rInc = (flags & 0x03) << 2;
+ byte gInc = ((flags >> 2) & 0x03) << 2;
+ byte bInc = ((flags >> 4) & 0x03) << 2;
+ bool increasing = (flags & 0x40) != 0;
+
+ if (increasing) {
+ // Increasing toward max values
+ anim->data[0] += rInc;
+ anim->data[1] += gInc;
+ anim->data[2] += bInc;
+ // Check if R reached max, then reverse direction
+ if (anim->data[0] >= anim->data[6]) {
+ anim->data[9] &= ~0x40; // Clear direction bit
+ }
+ } else {
+ // Decreasing toward min values
+ anim->data[0] -= rInc;
+ anim->data[1] -= gInc;
+ anim->data[2] -= bInc;
+ // Check if R reached min, then reverse direction
+ if (anim->data[0] <= anim->data[3]) {
+ anim->data[9] |= 0x40; // Set direction bit
+ }
+ }
+
+ g_engine->_room->_roomPalette[anim->startIndex * 3] = anim->data[0];
+ g_engine->_room->_roomPalette[anim->startIndex * 3 + 1] = anim->data[1];
+ g_engine->_room->_roomPalette[anim->startIndex * 3 + 2] = anim->data[2];
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+}
+
+void GraphicsManager::animateRotatePalette(PaletteAnim *anim) {
+ if (anim->curFrame >= anim->data[1]) {
+ anim->curFrame = 0;
+ int colors = anim->paletteMode;
+ byte *paletteValues = new byte[colors * 3];
+ for (int i = 0; i < colors; i++) {
+ paletteValues[i * 3] = g_engine->_room->_roomPalette[(anim->startIndex + i) * 3];
+ paletteValues[i * 3 + 1] = g_engine->_room->_roomPalette[(anim->startIndex + i) * 3 + 1];
+ paletteValues[i * 3 + 2] = g_engine->_room->_roomPalette[(anim->startIndex + i) * 3 + 2];
+ }
+ for (int i = 0; i < colors; i++) {
+ int srcIndex = (i + 1) % colors;
+ g_engine->_room->_roomPalette[(anim->startIndex + i) * 3] = paletteValues[srcIndex * 3];
+ g_engine->_room->_roomPalette[(anim->startIndex + i) * 3 + 1] = paletteValues[srcIndex * 3 + 1];
+ g_engine->_room->_roomPalette[(anim->startIndex + i) * 3 + 2] = paletteValues[srcIndex * 3 + 2];
+ }
+ delete[] paletteValues;
+
+ g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+
+ } else {
+ anim->curFrame++;
+ }
+}
+
+void GraphicsManager::placeStickersFirstPass() {
+ // also place temporary stickers
+ for (uint i = 0; i < g_engine->_room->_roomStickers.size(); i++) {
+ Sticker sticker = g_engine->_room->_roomStickers[i];
+ placeSticker(sticker);
+ }
+}
+
+void GraphicsManager::placeStickersSecondPass() {
+ // Some stickers need to be placed AFTER sprites, hardcoded in the original
+ if (g_engine->_room->_currentRoomNumber == 3) {
+ for (uint i = 0; i < g_engine->_state->stickersPerRoom[3].size(); i++) {
+ if (g_engine->_state->stickersPerRoom[3][i].stickerIndex == 14) {
+ placeSticker(g_engine->_state->stickersPerRoom[3][i]);
+ break;
+ }
+ }
+ }
+}
+
+void GraphicsManager::placeSticker(Sticker sticker) {
+ // Wrap sticker data as a surface and blit (no transparency - all pixels copied)
+ Graphics::Surface stickerSurf;
+ stickerSurf.init(sticker.w, sticker.h, sticker.w, sticker.stickerData, Graphics::PixelFormat::createFormatCLUT8());
+ // Clip to screen bounds
+ Common::Rect destRect(sticker.x, sticker.y, sticker.x + sticker.w, sticker.y + sticker.h);
+ Common::Rect screenRect(0, 0, 640, 400);
+ destRect.clip(screenRect);
+ if (destRect.isEmpty())
+ return;
+ Common::Rect srcRect(destRect.left - sticker.x, destRect.top - sticker.y,
+ destRect.right - sticker.x, destRect.bottom - sticker.y);
+ g_engine->_compositeBuffer.blitFrom(stickerSurf, srcRect, Common::Point(destRect.left, destRect.top));
+}
+
+void GraphicsManager::reflectionEffect(byte *buf, int x, int y, int width, int height) {
+ // Water reflection - draws mirrored sprite on water pixels
+ // Only sprite pixels 0-15 are reflected (checked via pixel & 0xF0 == 0)
+ for (int row = 0; row < height; row++) {
+ int reflectY = y + row;
+
+ if (reflectY >= 400)
+ break; // Screen boundary
+
+ for (int col = 0; col < width; col++) {
+ byte pixel = buf[(height - 1 - row) * width + col]; // Read from bottom up for mirror
+ // Only reflect pixels 0-15 (high nibble must be 0)
+ if (pixel != 255 && (pixel & 0xF0) == 0) {
+ int px = x + col;
+ if (px >= 0 && px < 640) {
+ byte bgPixel = (byte)g_engine->_compositeBuffer.getPixel(px, reflectY);
+ if (bgPixel >= 223 && bgPixel < 228) { // Is water (0xDF-0xE3)
+ g_engine->_compositeBuffer.setPixel(px, reflectY, g_engine->_room->_paletteRemaps[4][pixel]);
+ }
+ }
+ }
+ }
+ }
+}
+
+void GraphicsManager::calculateScalingMasks() {
+ for (int scaleFactor = 0; scaleFactor < kAlfredFrameWidth; scaleFactor++) {
+ float step = kAlfredFrameWidth / (scaleFactor + 1.0f);
+ Common::Array<int> row;
+ float index = 0.0f;
+ int sourcePixel = 0;
+
+ while (index < kAlfredFrameWidth) {
+ row.push_back(sourcePixel);
+ index += step;
+ sourcePixel += 1;
+ if (sourcePixel >= kAlfredFrameWidth) {
+ sourcePixel = kAlfredFrameWidth - 1;
+ }
+ }
+
+ // Pad to exactly kAlfredFrameWidth entries
+ while (row.size() < kAlfredFrameWidth) {
+ row.push_back(row.empty() ? 0 : row[row.size() - 1]);
+ }
+
+ _widthScalingTable.push_back(row);
+ }
+
+ for (int scaleFactor = 0; scaleFactor < kAlfredFrameHeight; scaleFactor++) {
+ float step = kAlfredFrameHeight / (scaleFactor + 1.0f);
+ Common::Array<int> row;
+ row.resize(kAlfredFrameHeight, 0);
+ float position = step;
+ int counter = 1;
+ while (position < kAlfredFrameHeight) {
+ int idx = static_cast<int>(round(position));
+ if (idx < kAlfredFrameHeight) {
+ row[idx] = counter;
+ counter++;
+ }
+ position += step;
+ }
+ _heightScalingTable.push_back(row);
+ }
+}
+
+ScaleCalculation GraphicsManager::calculateScaling(int yPos, ScalingParams scalingParams) {
+ int scaleY = 0;
+ int scaleX = 0;
+ if (scalingParams.scaleMode == 0xFF) {
+ // Maximum scaling - character is very small (used for bird's eye view maps)
+ scaleY = 0x5e; // 94
+ scaleX = 0x2f; // 47
+ } else if (scalingParams.scaleMode == 0xFE) {
+ // No scaling - full size character
+ scaleY = 0;
+ scaleX = 0;
+ } else if (scalingParams.scaleMode == 0) {
+ // Dynamic scaling based on Y position
+ if (scalingParams.yThreshold < yPos) {
+ // Below threshold - no scaling
+ scaleY = 0;
+ scaleX = 0;
+ } else {
+ if (scalingParams.scaleDivisor != 0) {
+ scaleY = (scalingParams.yThreshold - yPos) / scalingParams.scaleDivisor;
+ scaleX = scaleY / 2;
+ } else {
+ scaleY = 0;
+ scaleX = 0;
+ }
+ }
+ } else {
+ scaleY = 0;
+ scaleX = 0;
+ }
+
+ // Original game formula: actual dimensions = base - scale amount
+ int finalHeight = kAlfredFrameHeight - scaleY;
+ if (finalHeight < 1)
+ finalHeight = 1;
+
+ int finalWidth = kAlfredFrameWidth - scaleX;
+ if (finalWidth < 1)
+ finalWidth = 1;
+
+ ScaleCalculation scaleCalc;
+ scaleCalc.scaledHeight = finalHeight;
+ scaleCalc.scaledWidth = finalWidth;
+ scaleCalc.scaleY = scaleY;
+ scaleCalc.scaleX = scaleX;
+ return scaleCalc;
+}
+
+byte *GraphicsManager::scale(int scaleY, int finalWidth, int finalHeight, byte *buf) {
+ // The scaling table is indexed by how many scanlines to skip (scaleY), not by final height
+ int scaleIndex = scaleY;
+ if (scaleIndex >= (int)_heightScalingTable.size()) {
+ scaleIndex = _heightScalingTable.size() - 1;
+ }
+ if (scaleIndex < 0) {
+ scaleIndex = 0;
+ }
+ int linesToSkip = kAlfredFrameHeight - finalHeight;
+
+ byte *finalBuf = new byte[finalWidth * finalHeight];
+
+ if (linesToSkip > 0) {
+ int skipInterval = kAlfredFrameHeight / linesToSkip;
+ Common::Array<float> idealSkipPositions;
+ for (int i = 0; i < linesToSkip; i++) {
+ float idealPos = (i + 0.5f) * skipInterval;
+ idealSkipPositions.push_back(idealPos);
+ }
+
+ Common::Array<int> tableSkipPositions;
+ for (int scanline = 0; scanline < kAlfredFrameHeight; scanline++) {
+ if (_heightScalingTable[scaleIndex][scanline] != 0) {
+ tableSkipPositions.push_back(scanline);
+ }
+ }
+
+ Common::Array<int> skipTheseLines;
+ for (size_t i = 0; i < idealSkipPositions.size(); i++) {
+ float idealPos = idealSkipPositions[i];
+ int closest = -1;
+ int minDiff = INT32_MAX;
+ for (size_t j = 0; j < tableSkipPositions.size(); j++) {
+ int candidate = tableSkipPositions[j];
+ int diff = static_cast<int>(abs(candidate - idealPos));
+ if (diff < minDiff) {
+ minDiff = diff;
+ closest = candidate;
+ }
+ }
+ if (closest != -1) {
+ skipTheseLines.push_back(closest);
+ }
+ if (skipTheseLines.size() >= static_cast<size_t>(linesToSkip)) {
+ break;
+ }
+ }
+
+ int outY = 0;
+ for (int srcY = 0; srcY < kAlfredFrameHeight; srcY++) {
+ bool skipLine = false;
+ for (size_t skipIdx = 0; skipIdx < skipTheseLines.size(); ++skipIdx) {
+ if (skipTheseLines[skipIdx] == srcY) {
+ skipLine = true;
+ break;
+ }
+ }
+ if (!skipLine) {
+ for (int outX = 0; outX < finalWidth; outX++) {
+ int srcX = static_cast<int>(outX * kAlfredFrameWidth / finalWidth);
+ if (srcX >= kAlfredFrameWidth) {
+ srcX = kAlfredFrameWidth - 1;
+ }
+ int srcIndex = srcY * kAlfredFrameWidth + srcX;
+ int outIndex = outY * finalWidth + outX;
+ if (outIndex >= finalWidth * finalHeight || srcIndex >= kAlfredFrameWidth * kAlfredFrameHeight) {
+ } else
+ finalBuf[outIndex] = buf[srcIndex];
+ }
+ outY++;
+ }
+ }
+ } else {
+ Common::copy(buf, buf + (kAlfredFrameWidth * kAlfredFrameHeight), finalBuf);
+ }
+ return finalBuf;
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index 6d31b038367..c205d1bbedd 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -29,6 +29,8 @@
#include "graphics/managed_surface.h"
#include "graphics/screen.h"
+#include "pelrock/types.h"
+
namespace Pelrock {
class GraphicsManager {
@@ -36,16 +38,60 @@ public:
GraphicsManager();
~GraphicsManager();
+ // Overlay / palette utilities
Common::Point showOverlay(int height, Graphics::ManagedSurface &buf);
byte *grabBackgroundSlice(Graphics::ManagedSurface &buf, int x, int y, int w, int h);
void putBackgroundSlice(Graphics::ManagedSurface &buf, int x, int y, int w, int h, byte *slice);
void fadeToBlack(int stepSize);
void fadePaletteToTarget(byte *targetPalette, int stepSize);
void clearScreen();
+
+ // Text rendering
void drawColoredText(Graphics::ManagedSurface *screen, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font);
void drawColoredText(Graphics::ManagedSurface &buf, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font);
void drawColoredTexts(Graphics::ManagedSurface *surface, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font);
void drawColoredTexts(Graphics::ManagedSurface &buf, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font);
+
+ // Frame / background management
+ void copyBackgroundToBuffer();
+ void presentFrame();
+
+ // Sticker rendering
+ void placeStickersFirstPass();
+ void placeStickersSecondPass();
+ void placeSticker(Sticker sticker);
+
+ // Palette animations
+ void updatePaletteAnimations();
+ void animateFadePalette(PaletteAnim *anim);
+ void animateRotatePalette(PaletteAnim *anim);
+
+ /** Water reflection: mirrors buf pixels at (x,y) for water-palette pixels. */
+ void reflectionEffect(byte *buf, int x, int y, int width, int height);
+
+
+ // scaling
+ /**
+ * Initializes _widthScalingTable / _heightScalingTable.
+ * Must be called once during engine init, before any drawAlfred().
+ */
+ void calculateScalingMasks();
+
+ /**
+ * Returns the scaled width/height and scale parameters for Alfred at yPos.
+ */
+ ScaleCalculation calculateScaling(int yPos, ScalingParams scalingParams);
+
+ /**
+ * Scales a source frame (kAlfredFrameWidth à kAlfredFrameHeight) to
+ * (finalWidth à finalHeight) using the pre-computed scaling tables.
+ * Caller owns the returned buffer.
+ */
+ byte *scale(int scaleY, int finalWidth, int finalHeight, byte *buf);
+
+ // Scaling look-up tables initialized by calculateScalingMasks().
+ Common::Array<Common::Array<int>> _widthScalingTable;
+ Common::Array<Common::Array<int>> _heightScalingTable;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 9764a649f3c..25b6baf77af 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -153,7 +153,7 @@ void PelrockEngine::init() {
_sound->loadSoundIndex();
_menu->loadMenu();
- calculateScalingMasks();
+ _graphics->calculateScalingMasks();
_compositeBuffer.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
_currentBackground.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
@@ -330,21 +330,21 @@ bool PelrockEngine::renderScene(int overlayMode) {
playSoundIfNeeded();
- copyBackgroundToBuffer();
+ _graphics->copyBackgroundToBuffer();
- placeStickersFirstPass();
+ _graphics->placeStickersFirstPass();
updateAnimations();
- placeStickersSecondPass();
+ _graphics->placeStickersSecondPass();
renderOverlay(overlayMode);
mouseHoverForMap();
- presentFrame();
+ _graphics->presentFrame();
- updatePaletteAnimations();
+ _graphics->updatePaletteAnimations();
// Execute deferred actions AFTER renderScene, so any scene changes
// (addSticker, disableSprite, etc.) are in place before the next frame's
@@ -515,54 +515,6 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
}
}
-void PelrockEngine::reflectionEffect(byte *buf, int x, int y, int width, int height) {
-
- // ScaleCalculation scaleCalc = calculateScaling(y + 50, _room->_scaleParams);
-
- // // Update Alfred's scale state for use by other functions
- // _alfredState.scaledX = scaleCalc.scaleX;
- // _alfredState.scaledY = scaleCalc.scaleY;
-
- // // Use the pre-calculated scaled dimensions from calculateScaling
- // int finalHeight = scaleCalc.scaledHeight;
- // int finalWidth = scaleCalc.scaledWidth;
-
- // if (finalHeight <= 0) {
- // finalHeight = 1;
- // }
- // if (finalWidth <= 0) {
- // finalWidth = 1;
- // }
-
- // byte *finalBuf = scale(scaleCalc.scaleY, finalWidth, finalHeight, buf);
- // height = finalHeight;
- // width = finalWidth;
-
- // Water reflection - draws mirrored sprite on water pixels
- // Only sprite pixels 0-15 are reflected (checked via pixel & 0xF0 == 0)
- for (int row = 0; row < height; row++) {
- int reflectY = y + row;
-
- if (reflectY >= 400)
- break; // Screen boundary
-
- for (int col = 0; col < width; col++) {
- // byte pixel = finalBuf[(height - 1 - row) * width + col]; // Read from bottom up for mirror
- byte pixel = buf[(height - 1 - row) * width + col]; // Read from bottom up for mirror
- // Only reflect pixels 0-15 (high nibble must be 0)
- if (pixel != 255 && (pixel & 0xF0) == 0) {
- int px = x + col;
- if (px >= 0 && px < 640) {
- byte bgPixel = (byte)_compositeBuffer.getPixel(px, reflectY);
- if (bgPixel >= 223 && bgPixel < 228) { // Is water (0xDF-0xE3)
- _compositeBuffer.setPixel(px, reflectY, _room->_paletteRemaps[4][pixel]);
- }
- }
- }
- }
- }
-}
-
void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
debug("Executing action %d on hotspot %d", action, hotspot->extra);
if (action == ITEM) {
@@ -658,11 +610,6 @@ void PelrockEngine::checkMouse() {
}
}
-void PelrockEngine::copyBackgroundToBuffer() {
- // copy background to buffer
- _compositeBuffer.blitFrom(_currentBackground);
-}
-
// Calculate Alfred's z-order based on Y position
// At Y=399 (bottom of screen): z = 10 (foreground)
// At Y=0 (top of screen): z = 209 (background)
@@ -704,113 +651,6 @@ void PelrockEngine::updateAnimations() {
}
}
-void PelrockEngine::presentFrame() {
- _screen->blitFrom(_compositeBuffer);
- // paintDebugLayer();
- _screen->markAllDirty();
-}
-
-void PelrockEngine::updatePaletteAnimations() {
- if (_room->_currentPaletteAnim != nullptr) {
- if (_room->_currentPaletteAnim->paletteMode == 1) {
- animateFadePalette(_room->_currentPaletteAnim);
- } else {
- animateRotatePalette(_room->_currentPaletteAnim);
- }
- }
-}
-
-void PelrockEngine::paintDebugLayer() {
- bool showWalkboxes = true;
-
- if (showWalkboxes) {
- for (uint i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
- WalkBox box = _room->_currentRoomWalkboxes[i];
- drawRect(_screen, box.x, box.y, box.w, box.h, 13);
- }
- }
-
- bool showSprites = true;
- if (showSprites) {
- for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
- Sprite sprite = _room->_currentRoomAnims[i];
- if (sprite.zOrder == 255) {
- // Skip disabled sprites (zOrder 0xFF)
- continue;
- }
- drawRect(_screen, sprite.x, sprite.y, sprite.w, sprite.h, 14);
- _smallFont->drawString(_screen, Common::String::format("S %d", sprite.index), sprite.x + 2, sprite.y, 640, 14);
- }
- }
-
- bool showHotspots = true;
- if (showHotspots) {
- for (uint i = 0; i < _room->_currentRoomHotspots.size(); i++) {
- HotSpot hotspot = _room->_currentRoomHotspots[i];
- if (!hotspot.isEnabled || hotspot.isSprite)
- continue;
- drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 12);
- _smallFont->drawString(_screen, Common::String::format("HS %d - %d", hotspot.index - _room->_currentRoomAnims.size(), hotspot.extra), hotspot.x + 2, hotspot.y + 2, 640, 12);
- // _smallFont->drawString(_screen, Common::String::format("x=%d", hotspot.extra), hotspot.x + 2, hotspot.y + 2 + 14, 640, 14);
- }
- }
-
- bool showExits = true;
- if (showExits) {
- for (uint i = 0; i < _room->_currentRoomExits.size(); i++) {
- Exit exit = _room->_currentRoomExits[i];
- drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 200 + i);
- _smallFont->drawString(_screen, Common::String::format("Exit %d -> Room %d", i, exit.targetRoom), exit.x + 2, exit.y + 2, 640, 14);
- }
- }
-
- drawPos(_screen, _alfredState.x, _alfredState.y, 13);
- drawPos(_screen, _alfredState.x, _alfredState.y - kAlfredFrameHeight, 13);
- drawPos(_screen, _curWalkTarget.x, _curWalkTarget.y, 100);
-
- if (showShadows) {
- _screen->copyRectToSurface(_room->_pixelsShadows, 640, 0, 0, 640, 400);
- }
- _smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
- _smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", _alfredState.x, _alfredState.y, _alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
- _smallFont->drawString(_screen, Common::String::format("Frame number: %d", _chrono->getFrameCount()), 0, 30, 640, 13);
-}
-
-void PelrockEngine::placeStickersFirstPass() {
- // also place temporary stickers
- for (uint i = 0; i < _room->_roomStickers.size(); i++) {
- Sticker sticker = _room->_roomStickers[i];
- placeSticker(sticker);
- }
-}
-
-void PelrockEngine::placeStickersSecondPass() {
- // Some stickers need to be placed AFTER sprites, hardcoded in the original
- if (_room->_currentRoomNumber == 3) {
- for (uint i = 0; i < _state->stickersPerRoom[3].size(); i++) {
- if (_state->stickersPerRoom[3][i].stickerIndex == 14) {
- placeSticker(_state->stickersPerRoom[3][i]);
- break;
- }
- }
- }
-}
-
-void PelrockEngine::placeSticker(Sticker sticker) {
- // Wrap sticker data as a surface and blit (no transparency - all pixels copied)
- Graphics::Surface stickerSurf;
- stickerSurf.init(sticker.w, sticker.h, sticker.w, sticker.stickerData, Graphics::PixelFormat::createFormatCLUT8());
- // Clip to screen bounds
- Common::Rect destRect(sticker.x, sticker.y, sticker.x + sticker.w, sticker.y + sticker.h);
- Common::Rect screenRect(0, 0, 640, 400);
- destRect.clip(screenRect);
- if (destRect.isEmpty())
- return;
- Common::Rect srcRect(destRect.left - sticker.x, destRect.top - sticker.y,
- destRect.right - sticker.x, destRect.bottom - sticker.y);
- _compositeBuffer.blitFrom(stickerSurf, srcRect, Common::Point(destRect.left, destRect.top));
-}
-
void PelrockEngine::renderOverlay(int overlayMode) {
if (overlayMode == OVERLAY_CHOICES) {
_dialog->displayChoices(_dialog->_currentChoices, _compositeBuffer);
@@ -821,83 +661,6 @@ void PelrockEngine::renderOverlay(int overlayMode) {
}
}
-void PelrockEngine::animateFadePalette(PaletteAnim *anim) {
- // FADE palette animation - cycles a single palette entry between min/max RGB values
- // Data layout (after loading from EXE):
- // data[0] = current R
- // data[1] = current G
- // data[2] = current B
- // data[3] = min R
- // data[4] = min G
- // data[5] = min B
- // data[6] = max R
- // data[7] = max G
- // data[8] = max B
- // data[9] = flags byte:
- // bits 0-1: R increment
- // bits 2-3: G increment
- // bits 4-5: B increment
- // bit 6: direction (0=decreasing toward min, 1=increasing toward max)
-
- byte flags = anim->data[9];
- // Increments are scaled by 4 (<<2) to match the shifted RGB values
- byte rInc = (flags & 0x03) << 2;
- byte gInc = ((flags >> 2) & 0x03) << 2;
- byte bInc = ((flags >> 4) & 0x03) << 2;
- bool increasing = (flags & 0x40) != 0;
-
- if (increasing) {
- // Increasing toward max values
- anim->data[0] += rInc;
- anim->data[1] += gInc;
- anim->data[2] += bInc;
- // Check if R reached max, then reverse direction
- if (anim->data[0] >= anim->data[6]) {
- anim->data[9] &= ~0x40; // Clear direction bit
- }
- } else {
- // Decreasing toward min values
- anim->data[0] -= rInc;
- anim->data[1] -= gInc;
- anim->data[2] -= bInc;
- // Check if R reached min, then reverse direction
- if (anim->data[0] <= anim->data[3]) {
- anim->data[9] |= 0x40; // Set direction bit
- }
- }
-
- _room->_roomPalette[anim->startIndex * 3] = anim->data[0];
- _room->_roomPalette[anim->startIndex * 3 + 1] = anim->data[1];
- _room->_roomPalette[anim->startIndex * 3 + 2] = anim->data[2];
- g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
-}
-
-void PelrockEngine::animateRotatePalette(PaletteAnim *anim) {
-
- if (anim->curFrame >= anim->data[1]) {
- anim->curFrame = 0;
- int colors = anim->paletteMode;
- byte *paletteValues = new byte[colors * 3];
- for (int i = 0; i < colors; i++) {
- paletteValues[i * 3] = _room->_roomPalette[(anim->startIndex + i) * 3];
- paletteValues[i * 3 + 1] = _room->_roomPalette[(anim->startIndex + i) * 3 + 1];
- paletteValues[i * 3 + 2] = _room->_roomPalette[(anim->startIndex + i) * 3 + 2];
- }
- for (int i = 0; i < colors; i++) {
- int srcIndex = (i + 1) % colors;
- _room->_roomPalette[(anim->startIndex + i) * 3] = paletteValues[srcIndex * 3];
- _room->_roomPalette[(anim->startIndex + i) * 3 + 1] = paletteValues[srcIndex * 3 + 1];
- _room->_roomPalette[(anim->startIndex + i) * 3 + 2] = paletteValues[srcIndex * 3 + 2];
- }
- delete[] paletteValues;
-
- g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
-
- } else {
- anim->curFrame++;
- }
-}
-
void PelrockEngine::doAction(VerbIcon action, HotSpot *hotspot) {
if (action == NO_ACTION) {
return;
@@ -1031,7 +794,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
// place first-pass stickers now so they are present in the very
// first presentFrame() for the new room (avoids a one-frame flash
// without stickers).
- placeStickersFirstPass();
+ _graphics->placeStickersFirstPass();
}
}
} else {
@@ -1165,95 +928,12 @@ void PelrockEngine::drawIdleFrame() {
}
}
-byte *PelrockEngine::scale(int scaleY, int finalWidth, int finalHeight, byte *buf) {
-
- // The scaling table is indexed by how many scanlines to skip (scaleY), not by final height
- int scaleIndex = scaleY;
- if (scaleIndex >= (int)_heightScalingTable.size()) {
- scaleIndex = _heightScalingTable.size() - 1;
- }
- if (scaleIndex < 0) {
- scaleIndex = 0;
- }
- int linesToSkip = kAlfredFrameHeight - finalHeight;
-
- byte *finalBuf = new byte[finalWidth * finalHeight];
-
- if (linesToSkip > 0) {
- int skipInterval = kAlfredFrameHeight / linesToSkip;
- Common::Array<float> idealSkipPositions;
- for (int i = 0; i < linesToSkip; i++) {
- float idealPos = (i + 0.5f) * skipInterval;
- idealSkipPositions.push_back(idealPos);
- }
-
- Common::Array<int> tableSkipPositions;
- for (int scanline = 0; scanline < kAlfredFrameHeight; scanline++) {
- if (_heightScalingTable[scaleIndex][scanline] != 0) {
- tableSkipPositions.push_back(scanline);
- }
- }
-
- // for (size_t i = 0; i < tableSkipPositions.size(); i++) {
- // }
-
- Common::Array<int> skipTheseLines;
- for (size_t i = 0; i < idealSkipPositions.size(); i++) {
- float idealPos = idealSkipPositions[i];
- int closest = -1;
- int minDiff = INT32_MAX;
- for (size_t j = 0; j < tableSkipPositions.size(); j++) {
- int candidate = tableSkipPositions[j];
- int diff = static_cast<int>(abs(candidate - idealPos));
- if (diff < minDiff) {
- minDiff = diff;
- closest = candidate;
- }
- }
- if (closest != -1) {
- skipTheseLines.push_back(closest);
- }
- if (skipTheseLines.size() >= static_cast<size_t>(linesToSkip)) {
- break;
- }
- }
-
- int outY = 0;
- for (int srcY = 0; srcY < kAlfredFrameHeight; srcY++) {
- bool skipLine = false;
- for (size_t skipIdx = 0; skipIdx < skipTheseLines.size(); ++skipIdx) {
- if (skipTheseLines[skipIdx] == srcY) {
- skipLine = true;
- break;
- }
- }
- if (!skipLine) {
- for (int outX = 0; outX < finalWidth; outX++) {
- int srcX = static_cast<int>(outX * kAlfredFrameWidth / finalWidth);
- if (srcX >= kAlfredFrameWidth) {
- srcX = kAlfredFrameWidth - 1;
- }
- int srcIndex = srcY * kAlfredFrameWidth + srcX;
- int outIndex = outY * finalWidth + outX;
- if (outIndex >= finalWidth * finalHeight || srcIndex >= kAlfredFrameWidth * kAlfredFrameHeight) {
- } else
- finalBuf[outIndex] = buf[srcIndex];
- }
- outY++;
- }
- }
- } else {
- Common::copy(buf, buf + (kAlfredFrameWidth * kAlfredFrameHeight), finalBuf);
- }
- return finalBuf;
-}
-
/**
* Scales and shades alfred sprite and draws it to the composite buffer
*/
void PelrockEngine::drawAlfred(byte *buf) {
- ScaleCalculation scaleCalc = calculateScaling(_alfredState.y, _room->_scaleParams);
+ ScaleCalculation scaleCalc = _graphics->calculateScaling(_alfredState.y, _room->_scaleParams);
// Use the pre-calculated scaled dimensions from calculateScaling
int finalHeight = scaleCalc.scaledHeight;
@@ -1270,7 +950,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
finalWidth = 1;
}
- byte *scaledBuf = scale(scaleCalc.scaleY, finalWidth, finalHeight, buf);
+ byte *scaledBuf = _graphics->scale(scaleCalc.scaleY, finalWidth, finalHeight, buf);
delete[] _alfredSprite;
_alfredSprite = scaledBuf;
@@ -1310,7 +990,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
if ((_room->_currentRoomNumber == 25 || _room->_currentRoomNumber == 45) && _alfredState.y >= 299) {
// Offset from Alfred's feet to start of reflection
int yOffset = (_room->_currentRoomNumber == 45) ? 25 : 13;
- reflectionEffect(_alfredSprite, _alfredState.x, _alfredState.y + yOffset, finalWidth, finalHeight);
+ _graphics->reflectionEffect(_alfredSprite, _alfredState.x, _alfredState.y + yOffset, finalWidth, finalHeight);
}
}
@@ -1405,6 +1085,60 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
}
}
+void PelrockEngine::paintDebugLayer() {
+ bool showWalkboxes = true;
+
+ if (showWalkboxes) {
+ for (uint i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
+ WalkBox box = _room->_currentRoomWalkboxes[i];
+ drawRect(_screen, box.x, box.y, box.w, box.h, 13);
+ }
+ }
+
+ bool showSprites = true;
+ if (showSprites) {
+ for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ Sprite sprite = _room->_currentRoomAnims[i];
+ if (sprite.zOrder == 255) {
+ continue;
+ }
+ drawRect(_screen, sprite.x, sprite.y, sprite.w, sprite.h, 14);
+ _smallFont->drawString(_screen, Common::String::format("S %d", sprite.index), sprite.x + 2, sprite.y, 640, 14);
+ }
+ }
+
+ bool showHotspots = true;
+ if (showHotspots) {
+ for (uint i = 0; i < _room->_currentRoomHotspots.size(); i++) {
+ HotSpot hotspot = _room->_currentRoomHotspots[i];
+ if (!hotspot.isEnabled || hotspot.isSprite)
+ continue;
+ drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 12);
+ _smallFont->drawString(_screen, Common::String::format("HS %d - %d", hotspot.index - _room->_currentRoomAnims.size(), hotspot.extra), hotspot.x + 2, hotspot.y + 2, 640, 12);
+ }
+ }
+
+ bool showExits = true;
+ if (showExits) {
+ for (uint i = 0; i < _room->_currentRoomExits.size(); i++) {
+ Exit exit = _room->_currentRoomExits[i];
+ drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 200 + i);
+ _smallFont->drawString(_screen, Common::String::format("Exit %d -> Room %d", i, exit.targetRoom), exit.x + 2, exit.y + 2, 640, 14);
+ }
+ }
+
+ drawPos(_screen, _alfredState.x, _alfredState.y, 13);
+ drawPos(_screen, _alfredState.x, _alfredState.y - kAlfredFrameHeight, 13);
+ drawPos(_screen, _curWalkTarget.x, _curWalkTarget.y, 100);
+
+ if (showShadows) {
+ _screen->copyRectToSurface(_room->_pixelsShadows, 640, 0, 0, 640, 400);
+ }
+ _smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
+ _smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", _alfredState.x, _alfredState.y, _alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
+ _smallFont->drawString(_screen, Common::String::format("Frame number: %d", _chrono->getFrameCount()), 0, 30, 640, 13);
+}
+
void PelrockEngine::checkLongMouseClick(int x, int y) {
_alfredState.idleFrameCounter = 0;
int hotspotIndex = isHotspotUnder(x, y);
@@ -1431,98 +1165,6 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
}
}
-void PelrockEngine::calculateScalingMasks() {
-
- for (int scaleFactor = 0; scaleFactor < kAlfredFrameWidth; scaleFactor++) {
- float step = kAlfredFrameWidth / (scaleFactor + 1.0f);
- Common::Array<int> row;
- float index = 0.0f;
- int sourcePixel = 0;
-
- while (index < kAlfredFrameWidth) {
- row.push_back(sourcePixel);
- index += step;
- sourcePixel += 1;
- if (sourcePixel >= kAlfredFrameWidth) {
- sourcePixel = kAlfredFrameWidth - 1;
- }
- }
-
- // Pad to exactly CHAR_WIDTH entries
- while (row.size() < kAlfredFrameWidth) {
- row.push_back(row.empty() ? 0 : row[row.size() - 1]);
- }
-
- _widthScalingTable.push_back(row);
- }
-
- for (int scaleFactor = 0; scaleFactor < kAlfredFrameHeight; scaleFactor++) {
- float step = kAlfredFrameHeight / (scaleFactor + 1.0f);
- Common::Array<int> row;
- row.resize(kAlfredFrameHeight, 0);
- float position = step;
- int counter = 1;
- while (position < kAlfredFrameHeight) {
- int idx = static_cast<int>(round(position));
- if (idx < kAlfredFrameHeight) {
- row[idx] = counter;
- counter++;
- }
- position += step;
- }
- _heightScalingTable.push_back(row);
- }
-}
-
-ScaleCalculation PelrockEngine::calculateScaling(int yPos, ScalingParams scalingParams) {
- // scaleY = amount to subtract from height (94 max for 0xFF mode)
- // scaleX = amount to subtract from width (47 max for 0xFF mode, = scaleY/2)
- int scaleY = 0;
- int scaleX = 0;
- if (scalingParams.scaleMode == 0xFF) {
- // Maximum scaling - character is very small (used for bird's eye view maps)
- scaleY = 0x5e; // 94
- scaleX = 0x2f; // 47
- } else if (scalingParams.scaleMode == 0xFE) {
- // No scaling - full size character
- scaleY = 0;
- scaleX = 0;
- } else if (scalingParams.scaleMode == 0) {
- // Dynamic scaling based on Y position
- if (scalingParams.yThreshold < yPos) {
- // Below threshold - no scaling
- scaleY = 0;
- scaleX = 0;
- } else {
- if (scalingParams.scaleDivisor != 0) {
- scaleY = (scalingParams.yThreshold - yPos) / scalingParams.scaleDivisor;
- scaleX = scaleY / 2;
- } else {
- scaleY = 0;
- scaleX = 0;
- }
- }
- } else {
- scaleY = 0;
- scaleX = 0;
- }
-
- // Original game formula: actual dimensions = base - scale amount
- int finalHeight = kAlfredFrameHeight - scaleY;
- if (finalHeight < 1)
- finalHeight = 1;
-
- int finalWidth = kAlfredFrameWidth - scaleX;
- if (finalWidth < 1)
- finalWidth = 1;
-
- ScaleCalculation scaleCalc;
- scaleCalc.scaledHeight = finalHeight;
- scaleCalc.scaledWidth = finalWidth;
- scaleCalc.scaleY = scaleY;
- scaleCalc.scaleX = scaleX;
- return scaleCalc;
-}
int PelrockEngine::isHotspotUnder(int x, int y) {
@@ -2068,7 +1710,7 @@ void PelrockEngine::setScreen(int roomNumber) {
_screen->clear();
- copyBackgroundToBuffer();
+ _graphics->copyBackgroundToBuffer();
g_system->getPaletteManager()->setPalette(palette, 0, 256);
_room->loadRoomMetadata(&roomFile, roomNumber);
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 03b48167aec..922b7653555 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -87,18 +87,9 @@ private:
int getScrollPositionForItem(int item);
void checkMouse();
- void copyBackgroundToBuffer();
void updateAnimations();
- void presentFrame();
- void updatePaletteAnimations();
- void paintDebugLayer();
- void placeStickersFirstPass();
- void placeStickersSecondPass();
- void placeSticker(Sticker sticker);
void renderOverlay(int overlayMode);
- void animateFadePalette(PaletteAnim *anim);
- void animateRotatePalette(PaletteAnim *anim);
void doAction(VerbIcon action, HotSpot *hotspot);
void talkTo(HotSpot *hotspot);
void lookAt(HotSpot *hotspot);
@@ -127,21 +118,12 @@ private:
void checkMouseHover();
void checkMouseClick(int x, int y);
void checkLongMouseClick(int x, int y);
-
- void calculateScalingMasks();
- ScaleCalculation calculateScaling(int yPos, ScalingParams scalingParams);
- byte *scale(int scaleY, int finalWidth, int finalHeight, byte *buf);
-
- Common::Array<Common::Array<int>> _widthScalingTable;
- Common::Array<Common::Array<int>> _heightScalingTable;
+ void paintDebugLayer();
// walking
int _currentStep = 0;
PathContext _currentContext = {nullptr, nullptr, 0, 0, 0};
- Graphics::ManagedSurface _currentBackground; // Clean background - NEVER modified
- Graphics::ManagedSurface _bgScreen;
-
ActionPopupState _actionPopupState;
InventoryOverlayState _inventoryOverlayState;
@@ -153,7 +135,6 @@ private:
QueuedAction _queuedAction = {NO_ACTION, -1, false, false};
bool showShadows = false;
-
bool shouldPlayIntro = false;
bool gameInitialized = false;
bool screenReady = false;
@@ -190,6 +171,8 @@ public:
AlfredState _alfredState;
ShakeEffectState _shakeEffectState;
Graphics::ManagedSurface _compositeBuffer; // Working composition buffer
+ Graphics::ManagedSurface _currentBackground; // Clean background - NEVER modified
+ Graphics::ManagedSurface _bgScreen;
GameStateData *_state = new GameStateData();
@@ -260,7 +243,6 @@ public:
void handleFlightRoomFrame();
void passerByAnim(uint32 frameCount);
- void reflectionEffect(byte *buf, int x, int y, int width, int height);
void changeCursor(Cursor cursor);
void travelToEgypt();
Commit: 57a84acae1e928f4fc0a13d7dbfed8ddc2f2018e
https://github.com/scummvm/scummvm/commit/57a84acae1e928f4fc0a13d7dbfed8ddc2f2018e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:30+02:00
Commit Message:
PELROCK: Fixes mouse hover breaking if positioned where action popup used to be
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 25b6baf77af..c38d2f3b5f0 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1662,10 +1662,6 @@ void PelrockEngine::checkMouseHover() {
return;
}
- if (isActionUnder(_events->_mouseX, _events->_mouseY) != NO_ACTION) {
- hotspotDetected = false;
- }
-
// Calculate walk target first (before checking anything else)
Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, hotspotDetected, hotspotDetected ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
Commit: 4736dc2ad8c4061805d112e14a7e0346b6c10314
https://github.com/scummvm/scummvm/commit/4736dc2ad8c4061805d112e14a7e0346b6c10314
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:30+02:00
Commit Message:
PELROCK: Implements original timing when walking/talking (halving the speed)
Changed paths:
engines/pelrock/detection.h
engines/pelrock/detection_tables.h
engines/pelrock/metaengine.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/detection.h b/engines/pelrock/detection.h
index 263ea2e9ac3..b66e27e9a5c 100644
--- a/engines/pelrock/detection.h
+++ b/engines/pelrock/detection.h
@@ -39,6 +39,7 @@ extern const PlainGameDescriptor pelrockGames[];
extern const ADGameDescription gameDescriptions[];
#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
+#define GAMEOPTION_ALTERNATE_TIMING GUIO_GAMEOPTIONS2
} // End of namespace Pelrock
diff --git a/engines/pelrock/detection_tables.h b/engines/pelrock/detection_tables.h
index f4c05cbab9e..79c0987d677 100644
--- a/engines/pelrock/detection_tables.h
+++ b/engines/pelrock/detection_tables.h
@@ -31,10 +31,10 @@ const ADGameDescription gameDescriptions[] = {
"pelrock",
nullptr,
AD_ENTRY1s("ALFRED.1", "ee0047cfcceece9c4f6a426245b6f449", 12915352),
- Common::EN_ANY,
+ Common::ES_ESP,
Common::kPlatformDOS,
ADGF_UNSTABLE,
- GUIO1(GUIO_NONE)
+ GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_ALTERNATE_TIMING)
},
AD_TABLE_END_MARKER
diff --git a/engines/pelrock/metaengine.cpp b/engines/pelrock/metaengine.cpp
index a6268bedeaf..11bff334e70 100644
--- a/engines/pelrock/metaengine.cpp
+++ b/engines/pelrock/metaengine.cpp
@@ -39,6 +39,17 @@ static const ADExtraGuiOptionsMap optionsList[] = {
0
}
},
+ {
+ GAMEOPTION_ALTERNATE_TIMING,
+ {
+ _s("Alternate timing"),
+ _s("Use ScummVM's alternate animation timing instead of the original game's slower walking and talking speed"),
+ "alternate_timing",
+ false,
+ 0,
+ 0
+ }
+ },
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index c38d2f3b5f0..52587086ba3 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -92,6 +92,10 @@ Common::String PelrockEngine::getGameId() const {
return _gameDescription->gameId;
}
+bool PelrockEngine::isAlternateTiming() const {
+ return ConfMan.getBool("alternate_timing");
+}
+
// Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
Common::Error PelrockEngine::run() {
@@ -326,6 +330,18 @@ bool PelrockEngine::renderScene(int overlayMode) {
_chrono->updateChrono();
if (_chrono->_gameTick) {
+ if (!isAlternateTiming()) {
+ bool inHalfSpeedMode = (_alfredState.animState == ALFRED_WALKING) ||
+ (_dialog->_dialogActive && _alfredState.animState == ALFRED_TALKING);
+ if (inHalfSpeedMode) {
+ _halfSpeedToggle = !_halfSpeedToggle;
+ if (!_halfSpeedToggle)
+ return false; // skip this tick â animate at half speed
+ } else {
+ _halfSpeedToggle = false; // reset when leaving half-speed mode
+ }
+ }
+
frameTriggers();
playSoundIfNeeded();
@@ -1650,6 +1666,7 @@ void PelrockEngine::checkMouseHover() {
_hoveredMapLocation = "Alfred";
}
+
if (hotspotIndex != -1) {
hotspotDetected = true;
if (hotspotIndex < _room->_currentRoomDescriptions.size())
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 922b7653555..97f0baf72a8 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -146,6 +146,9 @@ private:
bool _mouseDisabled = false;
+ // Original timing: toggles each game tick during walking/talking to halve animation speed
+ bool _halfSpeedToggle = false;
+
int _flightFrameCounter = 0;
int _flightSorcererSpriteIdx = -1;
bool _flightSorcererAppeared = false;
@@ -198,6 +201,12 @@ public:
return _randomSource.getRandomNumber(maxNum);
}
+ /**
+ * Returns true if "Alternate timing" option is enabled.
+ * When false, the engine uses the original game's half-speed walking/talking timing.
+ */
+ bool isAlternateTiming() const;
+
bool hasFeature(EngineFeature f) const override {
return (f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime) ||
Commit: f0fdccb1d8606fd092001bb07e0ee873976eea65
https://github.com/scummvm/scummvm/commit/f0fdccb1d8606fd092001bb07e0ee873976eea65
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:30+02:00
Commit Message:
PELROCK: Respect original timing too for NPC talking animations
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 8c7aa0911f5..2b3e172f655 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -206,6 +206,10 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_curSprite->isTalking = true;
xBasePos = _curSprite->x + _curSprite->w / 2;
yBasePos = _curSprite->y; // Above sprite, adjust for line
+
+ // Set NPC talk speed byte for original timing.
+ TalkingAnims *th = &g_engine->_room->_talkingAnimHeader;
+ g_engine->_npcTalkSpeedByte = _curSprite->talkingAnimIndex ? th->speedByteB : th->speedByteA;
}
}
displayDialogue(dialogueLines, speakerId, xBasePos, yBasePos); // Default position
@@ -243,6 +247,9 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
uint32 pageTtlMs = calcPageTtlMs(dialogueLines[curPage]);
uint32 pageStartMs = g_system->getMillis();
+ if(speakerId != kAlfredColor) {
+ _isNPCTalking = true;
+ }
// Render loop - display text and wait for click or TTL
while (!g_engine->shouldQuit()) {
_events->pollEvent();
@@ -313,6 +320,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_curSprite->isTalking = false;
}
_dialogActive = false;
+ _isNPCTalking = false;
g_engine->_alfredState.setState(ALFRED_IDLE);
}
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 568d596b61f..b021f149630 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -141,6 +141,7 @@ public:
bool _dialogActive = false;
bool _dismissDialog = false; // When true, the current dialog will be dismissed on the next iteration of the conversation loop (used for programmatically closing dialogs, e.g. when exiting a room)
bool _disableClickToAdvance = false;
+ bool _isNPCTalking = false;
Common::String _leftArrow = Common::String(17);
Common::String _rightArrow = Common::String(16);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 52587086ba3..a0f4c703346 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -326,20 +326,39 @@ void PelrockEngine::travelToEgypt() {
_state->addInventoryItem(59);
}
+bool PelrockEngine::shouldSkipFrame() {
+ if (isAlternateTiming()) {
+ return false; // never skip frames in alternate timing mode
+ }
+ int skipAmount = 0;
+ if (_alfredState.animState == ALFRED_WALKING) {
+ skipAmount = 1;
+ } else if (_dialog->_dialogActive) {
+ if (_alfredState.animState == ALFRED_TALKING) {
+ skipAmount = 1; // Alfred speaking
+ } else if (_dialog->_isNPCTalking && _npcTalkSpeedByte > 0) {
+ skipAmount = _npcTalkSpeedByte; // NPC speaking
+ }
+ }
+
+ if (skipAmount > 0) {
+ if (_renderSkipCounter < skipAmount) {
+ _renderSkipCounter++;
+ return true; // skip this tick
+ }
+ _renderSkipCounter = 0; // render this tick, reset
+ } else {
+ _renderSkipCounter = 0;
+ }
+ return false;
+}
+
bool PelrockEngine::renderScene(int overlayMode) {
_chrono->updateChrono();
if (_chrono->_gameTick) {
- if (!isAlternateTiming()) {
- bool inHalfSpeedMode = (_alfredState.animState == ALFRED_WALKING) ||
- (_dialog->_dialogActive && _alfredState.animState == ALFRED_TALKING);
- if (inHalfSpeedMode) {
- _halfSpeedToggle = !_halfSpeedToggle;
- if (!_halfSpeedToggle)
- return false; // skip this tick â animate at half speed
- } else {
- _halfSpeedToggle = false; // reset when leaving half-speed mode
- }
+ if (shouldSkipFrame()) {
+ return false;
}
frameTriggers();
@@ -432,7 +451,6 @@ void PelrockEngine::maybeHaveDogPee() {
walkTo(152, _alfredState.y);
_isDogPeeing = false;
}
-
}
void PelrockEngine::maybePlayPostIntro() {
@@ -713,11 +731,20 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
}
changeCursor(DEFAULT);
debug("Talking to hotspot %d (%d) with extra %d", hotspot->index, hotspot->isSprite ? hotspot->index : hotspot->index - _room->_currentRoomAnims.size(), hotspot->extra);
+
+ // Set NPC talk speed byte for original timing
+ TalkingAnims *th = &_room->_talkingAnimHeader;
+ _npcTalkSpeedByte = animSet->talkingAnimIndex ? th->speedByteB : th->speedByteA;
+ debug("NPC talk speed byte: %d (slot %d)", _npcTalkSpeedByte, animSet->talkingAnimIndex);
+
_dialog->startConversation(_room->_conversationData, _room->_conversationDataSize, animSet->talkingAnimIndex, animSet);
+
+ // Conversation ended â clear NPC talk speed byte
+ _npcTalkSpeedByte = 0;
+ _renderSkipCounter = 0;
}
void PelrockEngine::lookAt(HotSpot *hotspot) {
- debug("Looking at hotspot %d (%d) with extra %d", hotspot->index, hotspot->isSprite ? hotspot->index : hotspot->index - _room->_currentRoomAnims.size(), hotspot->extra);
_dialog->sayAlfred(_room->_currentRoomDescriptions[_currentHotspot->index]);
_actionPopupState.isActive = false;
}
@@ -1181,7 +1208,6 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
}
}
-
int PelrockEngine::isHotspotUnder(int x, int y) {
for (size_t i = 0; i < _room->_currentRoomHotspots.size(); i++) {
@@ -1335,7 +1361,10 @@ void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
int h = index ? animHeader->hAnimB : animHeader->hAnimA;
int numFrames = index ? animHeader->numFramesAnimB : animHeader->numFramesAnimA;
- if (_chrono->getFrameCount() % kTalkAnimationSpeed == 0) {
+ // In the original game, the render rate itself is throttled to match kTalkAnimationSpeed.
+ // When in "Alternate timing" mode, we use kTalkAnimationSpeed to avoid slowing down the game loop.
+ int npcTalkSpeed = isAlternateTiming() ? kTalkAnimationSpeed : 1;
+ if (_chrono->getFrameCount() % npcTalkSpeed == 0) {
if (index) {
animHeader->currentFrameAnimB++;
} else {
@@ -1491,7 +1520,6 @@ void PelrockEngine::gameLoop() {
_screen->update();
}
-
void PelrockEngine::computerLoop() {
Computer computer(_events);
computer.run();
@@ -1666,7 +1694,6 @@ void PelrockEngine::checkMouseHover() {
_hoveredMapLocation = "Alfred";
}
-
if (hotspotIndex != -1) {
hotspotDetected = true;
if (hotspotIndex < _room->_currentRoomDescriptions.size())
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 97f0baf72a8..5677e478f05 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -146,8 +146,10 @@ private:
bool _mouseDisabled = false;
- // Original timing: toggles each game tick during walking/talking to halve animation speed
- bool _halfSpeedToggle = false;
+ // Original timing: counter-based render-skip to replicate process_game_state(N) slowdown.
+ // _renderSkipAmount = N means skip N ticks, then render 1 â (1+N) ticks per render.
+ int _renderSkipAmount = 0;
+ int _renderSkipCounter = 0;
int _flightFrameCounter = 0;
int _flightSorcererSpriteIdx = -1;
@@ -173,6 +175,7 @@ public:
DialogManager *_dialog = nullptr;
AlfredState _alfredState;
ShakeEffectState _shakeEffectState;
+ byte _npcTalkSpeedByte = 0;
Graphics::ManagedSurface _compositeBuffer; // Working composition buffer
Graphics::ManagedSurface _currentBackground; // Clean background - NEVER modified
Graphics::ManagedSurface _bgScreen;
@@ -256,6 +259,8 @@ public:
void travelToEgypt();
+ bool shouldSkipFrame();
+
// Actions
void doExtraActions(int roomNumber);
void pyramidCollapse();
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index e08ad61d9f8..fa229e1ef31 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -1199,7 +1199,8 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
talkHeader.hAnimA = talkFile.readByte();
talkFile.read(&talkHeader.unknown3, 2);
talkHeader.numFramesAnimA = talkFile.readByte();
- talkFile.read(&talkHeader.unknown4, 5);
+ talkFile.read(&talkHeader.unknown4, 4);
+ talkHeader.speedByteA = talkFile.readByte();
talkHeader.offsetXAnimB = talkFile.readByte();
talkHeader.offsetYAnimB = talkFile.readByte();
@@ -1207,7 +1208,9 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
talkHeader.hAnimB = talkFile.readByte();
talkFile.read(&talkHeader.unknown5, 2);
talkHeader.numFramesAnimB = talkFile.readByte();
- talkFile.read(&talkHeader.unknown6, 29);
+ talkFile.read(&talkHeader.unknown7, 4);
+ talkHeader.speedByteB = talkFile.readByte();
+ talkFile.read(&talkHeader.unknown6, 24);
// debug("Talking anim header for room %d: spritePointer=%d, wA=%d, hA=%d, framesA=%d, wB=%d, hB=%d, framesB=%d", roomNumber, talkHeader.spritePointer, talkHeader.wAnimA, talkHeader.hAnimA, talkHeader.numFramesAnimA, talkHeader.wAnimB, talkHeader.hAnimB, talkHeader.numFramesAnimB);
if (talkHeader.spritePointer == 0) {
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index e227d1a4ae9..b500b39d5ff 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -310,17 +310,22 @@ struct TalkingAnims {
byte hAnimA;
byte unknown3[2];
byte numFramesAnimA;
- byte unknown4[5];
+ byte unknown4[4]; // slot 0 data pointer (unused in ScummVM)
+ byte speedByteA; // slot 0 offset 0x12: controls NPC talk render rate (original: 2+speedByte ticks per render)
byte offsetXAnimB;
byte offsetYAnimB;
- byte currentFrameAnimA;
byte wAnimB;
byte hAnimB;
- byte unknown5;
+ byte unknown5[2]; // slot 1 stride (unused in ScummVM)
byte numFramesAnimB;
- byte unknown6[29];
+ byte unknown7[4]; // slot 1 data pointer (unused in ScummVM)
+ byte speedByteB; // slot 1 speed byte at file offset 30
+ byte unknown6[24]; // slots 2-3 (unused)
+
+ // Runtime fields (not read from file)
+ byte currentFrameAnimA;
byte currentFrameAnimB;
byte **animA = nullptr;
Commit: 266df65e9a43e86f967a60093a615d0bad8cabb4
https://github.com/scummvm/scummvm/commit/266df65e9a43e86f967a60093a615d0bad8cabb4
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:31+02:00
Commit Message:
PELROCK: Fixes idle animation of talking character in room 39
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 2882dd763d7..28762c91d5e 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1680,6 +1680,8 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
guard->animData[0].movementFlags = 0;
guard->animData[0].curFrame = 0;
guard->animData[0].nframes = 1;
+ // copy idle frame from talking animation
+ guard->animData[0].animData[0] = _room->_talkingAnimHeader.animA[0];
_alfredState.direction = ALFRED_RIGHT;
walkAndAction(_room->findHotspotByExtra(guard->extra), TALK);
if (shouldQuit()) {
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 2b3e172f655..11935299f1a 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -195,10 +195,8 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
if (_curSprite != nullptr) {
_curSprite->isTalking = false;
}
- // Offset X position for Alfred to avoid overlapping with his sprite
+
xBasePos = g_engine->_alfredState.x;
- // Original game: uses the scaled character height
- // not the fixed kAlfredFrameHeight. _alfredState.h is updated by drawAlfred().
yBasePos = g_engine->_alfredState.y - g_engine->_alfredState.h; // Above scaled sprite top
} else {
g_engine->_alfredState.setState(ALFRED_IDLE);
Commit: 1a9467777cfd095a663ceca1434d8b1accb6625e
https://github.com/scummvm/scummvm/commit/1a9467777cfd095a663ceca1434d8b1accb6625e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:31+02:00
Commit Message:
PELROCK: Icons and scaling for volume control
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 33209820fdf..a4ecb23e424 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -36,21 +36,21 @@ static const uint32 kSettingsPaletteOffset = 0x2884C2;
// JUEGO.EXE â inventory object descriptions
static const uint32 kInventoryDescriptionsOffset = 0x4715E;
-static const uint32 kInventoryDescriptionsSize = 7868;
+static const uint32 kInventoryDescriptionsSize = 7868;
// JUEGO.EXE â in-menu text strings
static const uint32 kMenuTextOffset = 0x49203;
-static const uint32 kMenuTextSize = 230;
+static const uint32 kMenuTextSize = 230;
// ALFRED.7 â main menu background
-static const uint32 kMainMenuPart1Offset = 2405266;
-static const uint32 kMainMenuPart1RawSize = 65536; // first uncompressed chunk
+static const uint32 kMainMenuPart1Offset = 2405266;
+static const uint32 kMainMenuPart1RawSize = 65536; // first uncompressed chunk
static const uint32 kMainMenuPart1CompressedSize = 29418; // following compressed tail
-static const uint32 kMainMenuPart2Offset = 2500220;
-static const uint32 kMainMenuPart2RawSize = 32768;
+static const uint32 kMainMenuPart2Offset = 2500220;
+static const uint32 kMainMenuPart2RawSize = 32768;
static const uint32 kMainMenuPart2CompressedSize = 30288;
-static const uint32 kMainMenuPart3Offset = 2563266;
-static const uint32 kMainMenuPart3Size = 92160;
+static const uint32 kMainMenuPart3Offset = 2563266;
+static const uint32 kMainMenuPart3Size = 92160;
// ALFRED.7 â menu buttons (save/load/sound/exit, one contiguous block)
static const uint32 kMenuButtonsOffset = 3193376;
@@ -86,9 +86,35 @@ MenuButton MenuManager::isButtonClicked(int x, int y) {
if (_savesDown.contains(x, y)) {
return SAVEGAME_NEXT_BUTTON;
}
+ if(_showSoundOptions) {
+ if(_masterVolumeLeftRect.contains(x, y)) {
+ return MASTER_LEFT_BUTTON;
+ }
+ if(_masterVolumeRightRect.contains(x, y)) {
+ return MASTER_RIGHT_BUTTON;
+ }
+ if(_sfxVolumeLeftRect.contains(x, y)) {
+ return SFX_LEFT_BUTTON;
+ }
+ if(_sfxVolumeRightRect.contains(x, y)) {
+ return SFX_RIGHT_BUTTON;
+ }
+ if(_musicVolumeLeftRect.contains(x, y)) {
+ return MUSIC_LEFT_BUTTON;
+ }
+ if(_musicVolumeRightRect.contains(x, y)) {
+ return MUSIC_RIGHT_BUTTON;
+ }
+ }
return NO_BUTTON; // Default fallback
}
+Graphics::ManagedSurface scale(Graphics::ManagedSurface, const byte *original, float scale) {
+ Graphics::ManagedSurface newSurface = Graphics::ManagedSurface(66, 64, Graphics::PixelFormat::createFormatCLUT8());
+ memcpy(newSurface.getPixels(), original, 66 * 64);
+ return *newSurface.scale(66 * scale, 64 * scale);
+}
+
bool MenuManager::checkMouseClick(int x, int y) {
bool selectedItem = false;
@@ -107,6 +133,17 @@ bool MenuManager::checkMouseClick(int x, int y) {
}
MenuButton button = isButtonClicked(x, y);
+
+ if( button != MUSIC_LEFT_BUTTON &&
+ button != MUSIC_RIGHT_BUTTON &&
+ button != SFX_LEFT_BUTTON &&
+ button != SFX_RIGHT_BUTTON &&
+ button != MASTER_LEFT_BUTTON &&
+ button != MASTER_RIGHT_BUTTON
+ ) {
+ _showSoundOptions = false;
+ }
+
switch (button) {
case QUESTION_MARK_BUTTON:
debug("Show credits");
@@ -130,6 +167,34 @@ bool MenuManager::checkMouseClick(int x, int y) {
case EXIT_MENU_BUTTON:
g_engine->quitGame();
break;
+ case SOUNDS_BUTTON:
+ _showSoundOptions = true;
+ _menuText = Common::StringArray();
+ break;
+ case MASTER_LEFT_BUTTON:
+ currentMasterVolumeScale = MAX(0.4f, currentMasterVolumeScale - 0.1f);
+ _masterSoundIcon = scale(_masterSoundIcon, _soundControlMasterIcon, currentMasterVolumeScale);
+ break;
+ case MASTER_RIGHT_BUTTON:
+ currentMasterVolumeScale = MIN(1.0f, currentMasterVolumeScale + 0.1f);
+ _masterSoundIcon = scale(_masterSoundIcon, _soundControlMasterIcon, currentMasterVolumeScale);
+ break;
+ case SFX_LEFT_BUTTON:
+ currentSfxVolumeScale = MAX(0.4f, currentSfxVolumeScale - 0.1f);
+ _sfxSoundIcon = scale(_sfxSoundIcon, _soundControlSfxIcon, currentSfxVolumeScale);
+ break;
+ case SFX_RIGHT_BUTTON:
+ currentSfxVolumeScale = MIN(1.0f, currentSfxVolumeScale + 0.1f);
+ _sfxSoundIcon = scale(_sfxSoundIcon, _soundControlSfxIcon, currentSfxVolumeScale);
+ break;
+ case MUSIC_LEFT_BUTTON:
+ currentMusicVolumeScale = MAX(0.4f, currentMusicVolumeScale - 0.1f);
+ _musicSoundIcon = scale(_musicSoundIcon, _soundControlMusicIcon, currentMusicVolumeScale);
+ break;
+ case MUSIC_RIGHT_BUTTON:
+ currentMusicVolumeScale = MIN(1.0f, currentMusicVolumeScale + 0.1f);
+ _musicSoundIcon = scale(_musicSoundIcon, _soundControlMusicIcon, currentMusicVolumeScale);
+ break;
default:
break;
}
@@ -197,15 +262,16 @@ void MenuManager::menuLoop() {
_events->pollEvent();
if (_events->_leftMouseClicked) {
- if(checkMouseClick(_events->_mouseX, _events->_mouseY)) {
+ if (checkMouseClick(_events->_mouseX, _events->_mouseY)) {
break;
}
_events->_leftMouseClicked = false;
}
- if(_events->_rightMouseClicked) {
+ if (_events->_rightMouseClicked) {
break;
}
drawScreen();
+ drawPaletteSquares((byte *)_screen->getPixels(), _mainMenuPalette);
_screen->markAllDirty();
_screen->update();
g_system->delayMillis(10);
@@ -294,7 +360,6 @@ void MenuManager::loadMenu() {
memcpy((byte *)_mainMenu.getPixels() + curPos, decompressedPart2, decompressedSize);
curPos += decompressedSize;
- debug("Settings menu size loaded: %d, with last block %d", curPos, curPos + (int)kMainMenuPart3Size);
delete[] compressedPart2;
delete[] decompressedPart2;
alfred7.seek(kMainMenuPart3Offset, SEEK_SET);
@@ -310,6 +375,42 @@ void MenuManager::loadMenu() {
readButton(alfred7, alfred7.pos(), _savesDownArrows, _savesDown);
readButton(alfred7, kQuestionMarkOffset, _questionMark, _questionMarkRect);
+ byte *soundArrowsData = nullptr;
+ size_t soundArrowsSize = 0;
+ rleDecompressSingleBuda(&alfred7, kSoundControlOffset, soundArrowsData, soundArrowsSize);
+
+ readButton(soundArrowsData, 0, _soundControlArrowLeft, 36, 28);
+ readButton(soundArrowsData, 36 * 28 * 2, _soundControlArrowRight, 31, 28);
+ delete[] soundArrowsData;
+
+ byte *soundIconMasterData = nullptr;
+ size_t soundIconMasterSize = 0;
+ rleDecompressSingleBuda(&alfred7, kSoundMasterOffset, soundIconMasterData, soundIconMasterSize);
+ _soundControlMasterIcon = new byte[66 * 64];
+ extractSingleFrame(soundIconMasterData, _soundControlMasterIcon, 0, 66, 64);
+ delete[] soundIconMasterData;
+
+ byte *soundIconSfxData = nullptr;
+ size_t soundIconSfxSize = 0;
+ rleDecompressSingleBuda(&alfred7, kSoundSfxOffset, soundIconSfxData, soundIconSfxSize);
+ _soundControlSfxIcon = new byte[66 * 64];
+ extractSingleFrame(soundIconSfxData, _soundControlSfxIcon, 0, 66, 64);
+ delete[] soundIconSfxData;
+
+ byte *soundIconMusicData = nullptr;
+ size_t soundIconMusicSize = 0;
+ rleDecompressSingleBuda(&alfred7, kSoundMusicOffset, soundIconMusicData, soundIconMusicSize);
+ _soundControlMusicIcon = new byte[66 * 64];
+ extractSingleFrame(soundIconMusicData, _soundControlMusicIcon, 0, 66, 64);
+ delete[] soundIconMusicData;
+
+ _masterSoundIcon = Graphics::ManagedSurface(66, 64, Graphics::PixelFormat::createFormatCLUT8());
+ _sfxSoundIcon = Graphics::ManagedSurface(66, 64, Graphics::PixelFormat::createFormatCLUT8());
+ _musicSoundIcon = Graphics::ManagedSurface(66, 64, Graphics::PixelFormat::createFormatCLUT8());
+ memcpy(_masterSoundIcon.getPixels(), _soundControlMasterIcon, 66 * 64);
+ memcpy(_sfxSoundIcon.getPixels(), _soundControlSfxIcon, 66 * 64);
+ memcpy(_musicSoundIcon.getPixels(), _soundControlMusicIcon, 66 * 64);
+
_menuText = _menuTexts[0];
alfred7.close();
@@ -318,12 +419,23 @@ void MenuManager::loadMenu() {
}
}
+void MenuManager::readButton(byte *rawData, uint32 offset, byte *outBuffer[2], int w, int h) {
+ byte *buttonData = new byte[w * h * 2];
+ outBuffer[0] = new byte[w * h];
+ outBuffer[1] = new byte[w * h];
+ Common::copy(rawData + offset, rawData + offset + w * h * 2, buttonData);
+ extractSingleFrame(buttonData, outBuffer[0], 0, w, h);
+ extractSingleFrame(buttonData, outBuffer[1], 1, w, h);
+ delete[] buttonData;
+}
+
void MenuManager::readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect) {
alfred7.seek(offset, SEEK_SET);
byte *buttonData = new byte[rect.width() * rect.height() * 2];
- alfred7.read(buttonData, rect.width() * rect.height() * 2);
outBuffer[0] = new byte[rect.width() * rect.height()];
outBuffer[1] = new byte[rect.width() * rect.height()];
+ alfred7.read(buttonData, rect.width() * rect.height() * 2);
+
extractSingleFrame(buttonData, outBuffer[0], 0, rect.width(), rect.height());
extractSingleFrame(buttonData, outBuffer[1], 1, rect.width(), rect.height());
delete[] buttonData;
@@ -354,6 +466,9 @@ void MenuManager::loadMenuTexts() {
}
void MenuManager::cleanUp() {
+ _masterSoundIcon.free();
+ _sfxSoundIcon.free();
+ _musicSoundIcon.free();
}
void MenuManager::drawButtons() {
@@ -390,6 +505,28 @@ void MenuManager::drawButtons() {
buf = button == SAVEGAME_NEXT_BUTTON ? _savesDownArrows[1] : _savesDownArrows[0];
drawSpriteToBuffer(_compositeBuffer, buf, _savesDown.left, _savesDown.top, _savesDown.width(), _savesDown.height(), kTransparentColor);
+
+ if(_showSoundOptions) {
+ // _compositeBuffer.transBlitFrom(_masterSoundIcon, Common::Point(233, 188), kSoundControlsTransparentColor);
+ // _compositeBuffer.transBlitFrom(_musicSoundIcon, Common::Point(299, 188), kSoundControlsTransparentColor);
+ // _compositeBuffer.transBlitFrom(_sfxSoundIcon, Common::Point(365, 188), kSoundControlsTransparentColor);
+ _compositeBuffer.transBlitFrom(_masterSoundIcon, Common::Point(266 - _masterSoundIcon.w /2 , 212 - _masterSoundIcon.h / 2), kSoundControlsTransparentColor);
+ _compositeBuffer.transBlitFrom(_musicSoundIcon, Common::Point(333 - _musicSoundIcon.w / 2, 212 - _musicSoundIcon.h / 2), kSoundControlsTransparentColor);
+ _compositeBuffer.transBlitFrom(_sfxSoundIcon, Common::Point(399 - _sfxSoundIcon.w / 2, 212 - _sfxSoundIcon.h / 2), kSoundControlsTransparentColor);
+
+ buf = button == MASTER_LEFT_BUTTON ? _soundControlArrowLeft[1] : _soundControlArrowLeft[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _masterVolumeLeftRect.left, _masterVolumeLeftRect.top, _masterVolumeLeftRect.width(), _masterVolumeLeftRect.height(), kSoundControlsTransparentColor);
+ buf = button == MASTER_RIGHT_BUTTON ? _soundControlArrowRight[1] : _soundControlArrowRight[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _masterVolumeRightRect.left, _masterVolumeRightRect.top, _masterVolumeRightRect.width(), _masterVolumeRightRect.height(), kSoundControlsTransparentColor);
+ buf = button == SFX_LEFT_BUTTON ? _soundControlArrowLeft[1] : _soundControlArrowLeft[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _sfxVolumeLeftRect.left, _sfxVolumeLeftRect.top, _sfxVolumeLeftRect.width(), _sfxVolumeLeftRect.height(), kSoundControlsTransparentColor);
+ buf = button == SFX_RIGHT_BUTTON ? _soundControlArrowRight[1] : _soundControlArrowRight[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _sfxVolumeRightRect.left, _sfxVolumeRightRect.top, _sfxVolumeRightRect.width(), _sfxVolumeRightRect.height(), kSoundControlsTransparentColor);
+ buf = button == MUSIC_LEFT_BUTTON ? _soundControlArrowLeft[1] : _soundControlArrowLeft[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _musicVolumeLeftRect.left, _musicVolumeLeftRect.top, _musicVolumeLeftRect.width(), _musicVolumeLeftRect.height(), kSoundControlsTransparentColor);
+ buf = button == MUSIC_RIGHT_BUTTON ? _soundControlArrowRight[1] : _soundControlArrowRight[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _musicVolumeRightRect.left, _musicVolumeRightRect.top, _musicVolumeRightRect.width(), _musicVolumeRightRect.height(), kSoundControlsTransparentColor);
+ }
}
Pelrock::MenuManager::~MenuManager() {
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 76e9eea7ece..9574f89d930 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -31,9 +31,15 @@
namespace Pelrock {
-const int kQuestionMarkOffset = 3214046;
-const int kInvLeftArrowOffset = 3215906;
+const uint32 kQuestionMarkOffset = 3214046;
+const uint32 kInvLeftArrowOffset = 3215906;
+const uint32 kSoundControlOffset = 3037008;
+const uint32 kSoundMasterOffset = 2662588;
+const uint32 kSoundMusicOffset = 2664746;
+const uint32 kSoundSfxOffset = 2667140;
const int kTransparentColor = 15;
+// const int kTransparentColor = 195;
+const int kSoundControlsTransparentColor = 195;
const uint32 kCreditsBackgroundOffset = 3271454;
enum MenuButton {
@@ -46,6 +52,12 @@ enum MenuButton {
SAVE_GAME_BUTTON,
LOAD_GAME_BUTTON,
SOUNDS_BUTTON,
+ MASTER_LEFT_BUTTON,
+ MASTER_RIGHT_BUTTON,
+ SFX_LEFT_BUTTON,
+ SFX_RIGHT_BUTTON,
+ MUSIC_LEFT_BUTTON,
+ MUSIC_RIGHT_BUTTON,
NO_BUTTON
};
@@ -220,6 +232,7 @@ private:
void loadMenuTexts();
void cleanUp();
void drawButtons();
+ void readButton(byte *rawData, uint32 offset, byte *outBuffer[2], int w, int h);
void readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect);
MenuButton isButtonClicked(int x, int y);
Graphics::Screen *_screen = nullptr;
@@ -256,6 +269,31 @@ private:
Common::Rect _questionMarkRect = Common::Rect(Common::Point(217, 293), 31, 30);
byte *_questionMark[2] = {nullptr};
+ Common::Rect _masterVolumeLeftRect = Common::Rect(Common::Point(232, 252), 36, 28);
+ Common::Rect _masterVolumeRightRect = Common::Rect(Common::Point(268, 252), 31, 28);
+
+ Common::Rect _sfxVolumeLeftRect = Common::Rect(Common::Point(298, 252), 36, 28);
+ Common::Rect _sfxVolumeRightRect = Common::Rect(Common::Point(334, 252), 31, 28);
+
+ Common::Rect _musicVolumeLeftRect = Common::Rect(Common::Point(364, 252), 36, 28);
+ Common::Rect _musicVolumeRightRect = Common::Rect(Common::Point(400, 252), 31, 28);
+
+
+ byte *_soundControlArrowLeft[2] = {nullptr};
+ byte *_soundControlArrowRight[2] = {nullptr};
+
+ byte *_soundControlMasterIcon = nullptr;
+ byte *_soundControlSfxIcon = nullptr;
+ byte *_soundControlMusicIcon = nullptr;
+
+ Graphics::ManagedSurface _masterSoundIcon;
+ Graphics::ManagedSurface _sfxSoundIcon;
+ Graphics::ManagedSurface _musicSoundIcon;
+
+ float currentMasterVolumeScale = 1.0f;
+ float currentSfxVolumeScale = 1.0f;
+ float currentMusicVolumeScale = 1.0f;
+
Common::Array<Common::StringArray> _menuTexts;
// Temporary
int _selectedInvIndex = 0;
@@ -265,6 +303,7 @@ private:
Common::Array<Common::Point> _inventorySlots;
bool showButtons = true;
+ bool _showSoundOptions = false;
};
} // End of namespace Pelrock
Commit: cb596d4fbeb5c070d50b2208d8220164f3b8ca7e
https://github.com/scummvm/scummvm/commit/cb596d4fbeb5c070d50b2208d8220164f3b8ca7e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:31+02:00
Commit Message:
PELROCK: Volume icons scale up/down with left button rather than click
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index a4ecb23e424..8e5c2ab2a0e 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -86,23 +86,23 @@ MenuButton MenuManager::isButtonClicked(int x, int y) {
if (_savesDown.contains(x, y)) {
return SAVEGAME_NEXT_BUTTON;
}
- if(_showSoundOptions) {
- if(_masterVolumeLeftRect.contains(x, y)) {
+ if (_showSoundOptions) {
+ if (_masterVolumeLeftRect.contains(x, y)) {
return MASTER_LEFT_BUTTON;
}
- if(_masterVolumeRightRect.contains(x, y)) {
+ if (_masterVolumeRightRect.contains(x, y)) {
return MASTER_RIGHT_BUTTON;
}
- if(_sfxVolumeLeftRect.contains(x, y)) {
+ if (_sfxVolumeLeftRect.contains(x, y)) {
return SFX_LEFT_BUTTON;
}
- if(_sfxVolumeRightRect.contains(x, y)) {
+ if (_sfxVolumeRightRect.contains(x, y)) {
return SFX_RIGHT_BUTTON;
}
- if(_musicVolumeLeftRect.contains(x, y)) {
+ if (_musicVolumeLeftRect.contains(x, y)) {
return MUSIC_LEFT_BUTTON;
}
- if(_musicVolumeRightRect.contains(x, y)) {
+ if (_musicVolumeRightRect.contains(x, y)) {
return MUSIC_RIGHT_BUTTON;
}
}
@@ -115,6 +115,39 @@ Graphics::ManagedSurface scale(Graphics::ManagedSurface, const byte *original, f
return *newSurface.scale(66 * scale, 64 * scale);
}
+void MenuManager::checkMouseDown(int x, int y) {
+ if(!_events->_leftMouseButton) {
+ return;
+ }
+ MenuButton b = isButtonClicked(x, y);
+ switch (b) {
+ case MASTER_LEFT_BUTTON:
+ currentMasterVolumeScale = MAX(0.4f, currentMasterVolumeScale - 0.1f);
+ _masterSoundIcon = scale(_masterSoundIcon, _soundControlMasterIcon, currentMasterVolumeScale);
+ break;
+ case MASTER_RIGHT_BUTTON:
+ currentMasterVolumeScale = MIN(1.0f, currentMasterVolumeScale + 0.1f);
+ _masterSoundIcon = scale(_masterSoundIcon, _soundControlMasterIcon, currentMasterVolumeScale);
+ break;
+ case SFX_LEFT_BUTTON:
+ currentSfxVolumeScale = MAX(0.4f, currentSfxVolumeScale - 0.1f);
+ _sfxSoundIcon = scale(_sfxSoundIcon, _soundControlSfxIcon, currentSfxVolumeScale);
+ break;
+ case SFX_RIGHT_BUTTON:
+ currentSfxVolumeScale = MIN(1.0f, currentSfxVolumeScale + 0.1f);
+ _sfxSoundIcon = scale(_sfxSoundIcon, _soundControlSfxIcon, currentSfxVolumeScale);
+ break;
+ case MUSIC_LEFT_BUTTON:
+ currentMusicVolumeScale = MAX(0.4f, currentMusicVolumeScale - 0.1f);
+ _musicSoundIcon = scale(_musicSoundIcon, _soundControlMusicIcon, currentMusicVolumeScale);
+ break;
+ case MUSIC_RIGHT_BUTTON:
+ currentMusicVolumeScale = MIN(1.0f, currentMusicVolumeScale + 0.1f);
+ _musicSoundIcon = scale(_musicSoundIcon, _soundControlMusicIcon, currentMusicVolumeScale);
+ break;
+ }
+}
+
bool MenuManager::checkMouseClick(int x, int y) {
bool selectedItem = false;
@@ -134,13 +167,12 @@ bool MenuManager::checkMouseClick(int x, int y) {
MenuButton button = isButtonClicked(x, y);
- if( button != MUSIC_LEFT_BUTTON &&
+ if (button != MUSIC_LEFT_BUTTON &&
button != MUSIC_RIGHT_BUTTON &&
button != SFX_LEFT_BUTTON &&
button != SFX_RIGHT_BUTTON &&
button != MASTER_LEFT_BUTTON &&
- button != MASTER_RIGHT_BUTTON
- ) {
+ button != MASTER_RIGHT_BUTTON) {
_showSoundOptions = false;
}
@@ -171,29 +203,11 @@ bool MenuManager::checkMouseClick(int x, int y) {
_showSoundOptions = true;
_menuText = Common::StringArray();
break;
- case MASTER_LEFT_BUTTON:
- currentMasterVolumeScale = MAX(0.4f, currentMasterVolumeScale - 0.1f);
- _masterSoundIcon = scale(_masterSoundIcon, _soundControlMasterIcon, currentMasterVolumeScale);
- break;
- case MASTER_RIGHT_BUTTON:
- currentMasterVolumeScale = MIN(1.0f, currentMasterVolumeScale + 0.1f);
- _masterSoundIcon = scale(_masterSoundIcon, _soundControlMasterIcon, currentMasterVolumeScale);
- break;
case SFX_LEFT_BUTTON:
- currentSfxVolumeScale = MAX(0.4f, currentSfxVolumeScale - 0.1f);
- _sfxSoundIcon = scale(_sfxSoundIcon, _soundControlSfxIcon, currentSfxVolumeScale);
+ _sound->playSound("CAT_1ZZZ.SMP", -1);
break;
case SFX_RIGHT_BUTTON:
- currentSfxVolumeScale = MIN(1.0f, currentSfxVolumeScale + 0.1f);
- _sfxSoundIcon = scale(_sfxSoundIcon, _soundControlSfxIcon, currentSfxVolumeScale);
- break;
- case MUSIC_LEFT_BUTTON:
- currentMusicVolumeScale = MAX(0.4f, currentMusicVolumeScale - 0.1f);
- _musicSoundIcon = scale(_musicSoundIcon, _soundControlMusicIcon, currentMusicVolumeScale);
- break;
- case MUSIC_RIGHT_BUTTON:
- currentMusicVolumeScale = MIN(1.0f, currentMusicVolumeScale + 0.1f);
- _musicSoundIcon = scale(_musicSoundIcon, _soundControlMusicIcon, currentMusicVolumeScale);
+ _sound->playSound("CAT_1ZZZ.SMP", -1);
break;
default:
break;
@@ -260,7 +274,7 @@ void MenuManager::menuLoop() {
while (!g_engine->shouldQuit()) {
_events->pollEvent();
-
+ checkMouseDown(_events->_mouseX, _events->_mouseY);
if (_events->_leftMouseClicked) {
if (checkMouseClick(_events->_mouseX, _events->_mouseY)) {
break;
@@ -506,11 +520,11 @@ void MenuManager::drawButtons() {
buf = button == SAVEGAME_NEXT_BUTTON ? _savesDownArrows[1] : _savesDownArrows[0];
drawSpriteToBuffer(_compositeBuffer, buf, _savesDown.left, _savesDown.top, _savesDown.width(), _savesDown.height(), kTransparentColor);
- if(_showSoundOptions) {
+ if (_showSoundOptions) {
// _compositeBuffer.transBlitFrom(_masterSoundIcon, Common::Point(233, 188), kSoundControlsTransparentColor);
// _compositeBuffer.transBlitFrom(_musicSoundIcon, Common::Point(299, 188), kSoundControlsTransparentColor);
// _compositeBuffer.transBlitFrom(_sfxSoundIcon, Common::Point(365, 188), kSoundControlsTransparentColor);
- _compositeBuffer.transBlitFrom(_masterSoundIcon, Common::Point(266 - _masterSoundIcon.w /2 , 212 - _masterSoundIcon.h / 2), kSoundControlsTransparentColor);
+ _compositeBuffer.transBlitFrom(_masterSoundIcon, Common::Point(266 - _masterSoundIcon.w / 2, 212 - _masterSoundIcon.h / 2), kSoundControlsTransparentColor);
_compositeBuffer.transBlitFrom(_musicSoundIcon, Common::Point(333 - _musicSoundIcon.w / 2, 212 - _musicSoundIcon.h / 2), kSoundControlsTransparentColor);
_compositeBuffer.transBlitFrom(_sfxSoundIcon, Common::Point(399 - _sfxSoundIcon.w / 2, 212 - _sfxSoundIcon.h / 2), kSoundControlsTransparentColor);
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 9574f89d930..25e73d2c929 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -226,6 +226,7 @@ public:
byte _mainMenuPalette[768] = {0};
private:
+ void checkMouseDown(int x, int y);
bool checkMouseClick(int x, int y);
void showCredits();
bool selectInventoryItem(int i);
@@ -272,11 +273,11 @@ private:
Common::Rect _masterVolumeLeftRect = Common::Rect(Common::Point(232, 252), 36, 28);
Common::Rect _masterVolumeRightRect = Common::Rect(Common::Point(268, 252), 31, 28);
- Common::Rect _sfxVolumeLeftRect = Common::Rect(Common::Point(298, 252), 36, 28);
- Common::Rect _sfxVolumeRightRect = Common::Rect(Common::Point(334, 252), 31, 28);
+ Common::Rect _musicVolumeLeftRect = Common::Rect(Common::Point(298, 252), 36, 28);
+ Common::Rect _musicVolumeRightRect = Common::Rect(Common::Point(334, 252), 31, 28);
- Common::Rect _musicVolumeLeftRect = Common::Rect(Common::Point(364, 252), 36, 28);
- Common::Rect _musicVolumeRightRect = Common::Rect(Common::Point(400, 252), 31, 28);
+ Common::Rect _sfxVolumeLeftRect = Common::Rect(Common::Point(364, 252), 36, 28);
+ Common::Rect _sfxVolumeRightRect = Common::Rect(Common::Point(400, 252), 31, 28);
byte *_soundControlArrowLeft[2] = {nullptr};
Commit: 4fefe69117006960df155b7384e051447937a1de
https://github.com/scummvm/scummvm/commit/4fefe69117006960df155b7384e051447937a1de
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:32+02:00
Commit Message:
PELROCK: Implements volume controls
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/sound.cpp
engines/pelrock/sound.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 8e5c2ab2a0e..4d54c1ea3d2 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -58,6 +58,30 @@ static const uint32 kMenuButtonsOffset = 3193376;
Pelrock::MenuManager::MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res, SoundManager *sound) : _screen(screen), _events(events), _res(res), _sound(sound) {
}
+static int levelToMixerVolume(int level) {
+ return (level * 255) / 14;
+}
+
+static int mixerVolumeToLevel(int volume) {
+ return (volume * 14 + 127) / 255;
+}
+
+static float levelToScale(int level) {
+ return 0.4f + (level / 14.0f) * 0.6f;
+}
+
+static void rebuildSoundIcon(Graphics::ManagedSurface &target, const byte *source, int level) {
+ float s = levelToScale(level);
+ int newW = MAX(1, (int)(66 * s));
+ int newH = MAX(1, (int)(64 * s));
+ Graphics::ManagedSurface temp;
+ temp.create(66, 64, Graphics::PixelFormat::createFormatCLUT8());
+ memcpy(temp.getPixels(), source, 66 * 64);
+ Graphics::ManagedSurface *scaled = temp.scale(newW, newH, false);
+ target.copyFrom(*scaled);
+ delete scaled;
+}
+
MenuButton MenuManager::isButtonClicked(int x, int y) {
if (_questionMarkRect.contains(x, y)) {
return QUESTION_MARK_BUTTON;
@@ -109,12 +133,6 @@ MenuButton MenuManager::isButtonClicked(int x, int y) {
return NO_BUTTON; // Default fallback
}
-Graphics::ManagedSurface scale(Graphics::ManagedSurface, const byte *original, float scale) {
- Graphics::ManagedSurface newSurface = Graphics::ManagedSurface(66, 64, Graphics::PixelFormat::createFormatCLUT8());
- memcpy(newSurface.getPixels(), original, 66 * 64);
- return *newSurface.scale(66 * scale, 64 * scale);
-}
-
void MenuManager::checkMouseDown(int x, int y) {
if(!_events->_leftMouseButton) {
return;
@@ -122,28 +140,36 @@ void MenuManager::checkMouseDown(int x, int y) {
MenuButton b = isButtonClicked(x, y);
switch (b) {
case MASTER_LEFT_BUTTON:
- currentMasterVolumeScale = MAX(0.4f, currentMasterVolumeScale - 0.1f);
- _masterSoundIcon = scale(_masterSoundIcon, _soundControlMasterIcon, currentMasterVolumeScale);
+ _masterVolumeLevel = MAX(0, _masterVolumeLevel - 1);
+ _sound->setVolumeMaster(levelToMixerVolume(_masterVolumeLevel));
+ rebuildSoundIcon(_masterSoundIcon, _soundControlMasterIcon, _masterVolumeLevel);
break;
case MASTER_RIGHT_BUTTON:
- currentMasterVolumeScale = MIN(1.0f, currentMasterVolumeScale + 0.1f);
- _masterSoundIcon = scale(_masterSoundIcon, _soundControlMasterIcon, currentMasterVolumeScale);
+ _masterVolumeLevel = MIN(14, _masterVolumeLevel + 1);
+ _sound->setVolumeMaster(levelToMixerVolume(_masterVolumeLevel));
+ rebuildSoundIcon(_masterSoundIcon, _soundControlMasterIcon, _masterVolumeLevel);
break;
case SFX_LEFT_BUTTON:
- currentSfxVolumeScale = MAX(0.4f, currentSfxVolumeScale - 0.1f);
- _sfxSoundIcon = scale(_sfxSoundIcon, _soundControlSfxIcon, currentSfxVolumeScale);
+ _sfxVolumeLevel = MAX(0, _sfxVolumeLevel - 1);
+ _sound->setVolumeSfx(levelToMixerVolume(_sfxVolumeLevel));
+ rebuildSoundIcon(_sfxSoundIcon, _soundControlSfxIcon, _sfxVolumeLevel);
break;
case SFX_RIGHT_BUTTON:
- currentSfxVolumeScale = MIN(1.0f, currentSfxVolumeScale + 0.1f);
- _sfxSoundIcon = scale(_sfxSoundIcon, _soundControlSfxIcon, currentSfxVolumeScale);
+ _sfxVolumeLevel = MIN(14, _sfxVolumeLevel + 1);
+ _sound->setVolumeSfx(levelToMixerVolume(_sfxVolumeLevel));
+ rebuildSoundIcon(_sfxSoundIcon, _soundControlSfxIcon, _sfxVolumeLevel);
break;
case MUSIC_LEFT_BUTTON:
- currentMusicVolumeScale = MAX(0.4f, currentMusicVolumeScale - 0.1f);
- _musicSoundIcon = scale(_musicSoundIcon, _soundControlMusicIcon, currentMusicVolumeScale);
+ _musicVolumeLevel = MAX(0, _musicVolumeLevel - 1);
+ _sound->setVolumeMusic(levelToMixerVolume(_musicVolumeLevel));
+ rebuildSoundIcon(_musicSoundIcon, _soundControlMusicIcon, _musicVolumeLevel);
break;
case MUSIC_RIGHT_BUTTON:
- currentMusicVolumeScale = MIN(1.0f, currentMusicVolumeScale + 0.1f);
- _musicSoundIcon = scale(_musicSoundIcon, _soundControlMusicIcon, currentMusicVolumeScale);
+ _musicVolumeLevel = MIN(14, _musicVolumeLevel + 1);
+ _sound->setVolumeMusic(levelToMixerVolume(_musicVolumeLevel));
+ rebuildSoundIcon(_musicSoundIcon, _soundControlMusicIcon, _musicVolumeLevel);
+ break;
+ default:
break;
}
}
@@ -160,10 +186,7 @@ bool MenuManager::checkMouseClick(int x, int y) {
return false;
}
}
- if (!selectedItem) {
- _selectedInvIndex = -1;
- _menuText = _menuTexts[0];
- }
+
MenuButton button = isButtonClicked(x, y);
@@ -174,6 +197,10 @@ bool MenuManager::checkMouseClick(int x, int y) {
button != MASTER_LEFT_BUTTON &&
button != MASTER_RIGHT_BUTTON) {
_showSoundOptions = false;
+ if (!selectedItem) {
+ _selectedInvIndex = -1;
+ _menuText = _menuTexts[0];
+ }
}
switch (button) {
@@ -270,7 +297,25 @@ void MenuManager::menuLoop() {
g_system->getPaletteManager()->setPalette(_mainMenuPalette, 0, 256);
g_engine->changeCursor(DEFAULT);
+ _showSoundOptions = false;
_menuText = _menuTexts[0];
+
+ // Initialize volume levels from current settings
+ _sfxVolumeLevel = mixerVolumeToLevel(_sound->getVolumeSfx());
+ _musicVolumeLevel = mixerVolumeToLevel(_sound->getVolumeMusic());
+ _masterVolumeLevel = mixerVolumeToLevel(_sound->getVolumeMaster());
+
+ debug("Initial master volume level: %d", _masterVolumeLevel);
+ debug("Initial SFX volume level: %d", _sfxVolumeLevel);
+ debug("Initial Music volume level: %d", _musicVolumeLevel);
+ _masterSoundIcon.create(66, 64, Graphics::PixelFormat::createFormatCLUT8());
+ _sfxSoundIcon.create(66, 64, Graphics::PixelFormat::createFormatCLUT8());
+ _musicSoundIcon.create(66, 64, Graphics::PixelFormat::createFormatCLUT8());
+
+ rebuildSoundIcon(_masterSoundIcon, _soundControlMasterIcon, _masterVolumeLevel);
+ rebuildSoundIcon(_sfxSoundIcon, _soundControlSfxIcon, _sfxVolumeLevel);
+ rebuildSoundIcon(_musicSoundIcon, _soundControlMusicIcon, _musicVolumeLevel);
+
while (!g_engine->shouldQuit()) {
_events->pollEvent();
@@ -418,12 +463,6 @@ void MenuManager::loadMenu() {
extractSingleFrame(soundIconMusicData, _soundControlMusicIcon, 0, 66, 64);
delete[] soundIconMusicData;
- _masterSoundIcon = Graphics::ManagedSurface(66, 64, Graphics::PixelFormat::createFormatCLUT8());
- _sfxSoundIcon = Graphics::ManagedSurface(66, 64, Graphics::PixelFormat::createFormatCLUT8());
- _musicSoundIcon = Graphics::ManagedSurface(66, 64, Graphics::PixelFormat::createFormatCLUT8());
- memcpy(_masterSoundIcon.getPixels(), _soundControlMasterIcon, 66 * 64);
- memcpy(_sfxSoundIcon.getPixels(), _soundControlSfxIcon, 66 * 64);
- memcpy(_musicSoundIcon.getPixels(), _soundControlMusicIcon, 66 * 64);
_menuText = _menuTexts[0];
alfred7.close();
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 25e73d2c929..7a543947682 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -291,9 +291,9 @@ private:
Graphics::ManagedSurface _sfxSoundIcon;
Graphics::ManagedSurface _musicSoundIcon;
- float currentMasterVolumeScale = 1.0f;
- float currentSfxVolumeScale = 1.0f;
- float currentMusicVolumeScale = 1.0f;
+ int _masterVolumeLevel = 14;
+ int _sfxVolumeLevel = 14;
+ int _musicVolumeLevel = 14;
Common::Array<Common::StringArray> _menuTexts;
// Temporary
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 2d5f1be7aa0..46aa916acc6 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -24,6 +24,7 @@
#include "audio/decoders/wave.h"
#include "audio/mixer.h"
+#include "common/config-manager.h"
#include "common/debug.h"
#include "common/endian.h"
#include "common/file.h"
@@ -294,8 +295,34 @@ void SoundManager::stopSound(int channel) {
}
}
-void SoundManager::setVolume(int volume) {
- // TODO: Set sound volume
+void SoundManager::setVolumeSfx(int volume) {
+ ConfMan.setInt("sfx_volume", volume);
+ g_engine->syncSoundSettings();
+}
+
+void SoundManager::setVolumeMusic(int volume) {
+ ConfMan.setInt("music_volume", volume);
+ g_engine->syncSoundSettings();
+}
+
+void SoundManager::setVolumeMaster(int volume) {
+ ConfMan.setInt("sfx_volume", volume);
+ ConfMan.setInt("music_volume", volume);
+ ConfMan.setInt("speech_volume", volume);
+ g_engine->syncSoundSettings();
+}
+
+int SoundManager::getVolumeSfx() const {
+ return ConfMan.getInt("sfx_volume");
+}
+
+int SoundManager::getVolumeMusic() const {
+ return ConfMan.getInt("music_volume");
+}
+
+int SoundManager::getVolumeMaster() const {
+ // Master is the minimum of the channel volumes
+ return MIN(ConfMan.getInt("sfx_volume"), ConfMan.getInt("music_volume"));
}
bool SoundManager::isPlaying() const {
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index baaa8701cad..4a0f6053e50 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -65,7 +65,14 @@ public:
void playSound(byte *soundData, uint32 size, int channel);
void stopAllSounds();
void stopSound(int channel);
- void setVolume(int volume);
+
+ void setVolumeSfx(int volume);
+ void setVolumeMusic(int volume);
+ void setVolumeMaster(int volume);
+ int getVolumeSfx() const;
+ int getVolumeMusic() const;
+ int getVolumeMaster() const;
+
bool isPlaying() const;
bool isPlaying(int channel) const;
void loadSoundIndex();
Commit: 9333118fe97e4a372a3d0f5b32d2652a24d630aa
https://github.com/scummvm/scummvm/commit/9333118fe97e4a372a3d0f5b32d2652a24d630aa
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:32+02:00
Commit Message:
PELROCK: Sounds in menu
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/sound.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 4d54c1ea3d2..9291ec3abdd 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -205,28 +205,35 @@ bool MenuManager::checkMouseClick(int x, int y) {
switch (button) {
case QUESTION_MARK_BUTTON:
+ _sound->playSound("56ZZZZZZ.SMP", 0);
debug("Show credits");
_events->_leftMouseClicked = false;
showCredits();
break;
case INVENTORY_PREV_BUTTON:
+ _sound->playSound("56ZZZZZZ.SMP", 0);
if (_curInventoryPage > 0)
_curInventoryPage--;
break;
case INVENTORY_NEXT_BUTTON:
+ _sound->playSound("56ZZZZZZ.SMP", 0);
if ((_curInventoryPage + 1) * 4 < g_engine->_state->inventoryItems.size())
_curInventoryPage++;
break;
case SAVE_GAME_BUTTON:
+ _sound->playSound("11ZZZZZZ.SMP", 0);
return g_engine->saveGameDialog();
break;
case LOAD_GAME_BUTTON:
+ _sound->playSound("11ZZZZZZ.SMP", 0);
return g_engine->loadGameDialog();
break;
case EXIT_MENU_BUTTON:
+ _sound->playSound("11ZZZZZZ.SMP", 0);
g_engine->quitGame();
break;
case SOUNDS_BUTTON:
+ _sound->playSound("11ZZZZZZ.SMP", 0);
_showSoundOptions = true;
_menuText = Common::StringArray();
break;
@@ -560,9 +567,6 @@ void MenuManager::drawButtons() {
drawSpriteToBuffer(_compositeBuffer, buf, _savesDown.left, _savesDown.top, _savesDown.width(), _savesDown.height(), kTransparentColor);
if (_showSoundOptions) {
- // _compositeBuffer.transBlitFrom(_masterSoundIcon, Common::Point(233, 188), kSoundControlsTransparentColor);
- // _compositeBuffer.transBlitFrom(_musicSoundIcon, Common::Point(299, 188), kSoundControlsTransparentColor);
- // _compositeBuffer.transBlitFrom(_sfxSoundIcon, Common::Point(365, 188), kSoundControlsTransparentColor);
_compositeBuffer.transBlitFrom(_masterSoundIcon, Common::Point(266 - _masterSoundIcon.w / 2, 212 - _masterSoundIcon.h / 2), kSoundControlsTransparentColor);
_compositeBuffer.transBlitFrom(_musicSoundIcon, Common::Point(333 - _musicSoundIcon.w / 2, 212 - _musicSoundIcon.h / 2), kSoundControlsTransparentColor);
_compositeBuffer.transBlitFrom(_sfxSoundIcon, Common::Point(399 - _sfxSoundIcon.w / 2, 212 - _sfxSoundIcon.h / 2), kSoundControlsTransparentColor);
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 7a543947682..a0293eceb87 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -37,8 +37,7 @@ const uint32 kSoundControlOffset = 3037008;
const uint32 kSoundMasterOffset = 2662588;
const uint32 kSoundMusicOffset = 2664746;
const uint32 kSoundSfxOffset = 2667140;
-const int kTransparentColor = 15;
-// const int kTransparentColor = 195;
+const int kTransparentColor = 65;
const int kSoundControlsTransparentColor = 195;
const uint32 kCreditsBackgroundOffset = 3271454;
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 46aa916acc6..151045cd902 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -217,9 +217,6 @@ void SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
_mixer->stopHandle(_sfxHandles[channel]);
debug("Stopped active sound on channel %d to play new sound %s", channel, sound.filename.c_str());
}
- else {
- debug("Warning: channel %d is already free when trying to play sound %s", channel, sound.filename.c_str());
- }
}
Audio::AudioStream *finalStream = loopCount != -1 ? stream : Audio::makeLoopingAudioStream(stream, 0);
Commit: 7aff19c6eafb9d8f1de278df332637388e89e6b3
https://github.com/scummvm/scummvm/commit/7aff19c6eafb9d8f1de278df332637388e89e6b3
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:32+02:00
Commit Message:
sve thumbnail
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 9291ec3abdd..7386610bf47 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -22,6 +22,7 @@
#include "common/debug.h"
#include "common/file.h"
#include "graphics/paletteman.h"
+#include "graphics/thumbnail.h"
#include "menu.h"
#include "pelrock/menu.h"
@@ -302,6 +303,10 @@ bool MenuManager::selectInventoryItem(int i) {
void MenuManager::menuLoop() {
+ //Save screenshot in case the user saves
+ saveScreenshot();
+ g_engine->_saveAllowed = false;
+
g_system->getPaletteManager()->setPalette(_mainMenuPalette, 0, 256);
g_engine->changeCursor(DEFAULT);
_showSoundOptions = false;
@@ -346,9 +351,15 @@ void MenuManager::menuLoop() {
_events->_rightMouseClicked = false;
_events->_leftMouseClicked = false;
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
+ g_engine->_saveAllowed = true;
cleanUp();
}
+void MenuManager::saveScreenshot() {
+ g_engine->_saveThumbnail.free();
+ Graphics::createThumbnail(g_engine->_saveThumbnail);
+}
+
void MenuManager::drawScreen() {
_compositeBuffer.blitFrom(_mainMenu);
if (showButtons)
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index a0293eceb87..8b59bba538d 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -219,6 +219,7 @@ public:
MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res, SoundManager *sound);
~MenuManager();
void menuLoop();
+ void saveScreenshot();
void drawScreen();
void drawInventoryIcons();
void loadMenu();
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 5677e478f05..742ca30c446 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -179,9 +179,10 @@ public:
Graphics::ManagedSurface _compositeBuffer; // Working composition buffer
Graphics::ManagedSurface _currentBackground; // Clean background - NEVER modified
Graphics::ManagedSurface _bgScreen;
+ Graphics::Surface _saveThumbnail;
GameStateData *_state = new GameStateData();
-
+ bool _saveAllowed = true;
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
DoubleSmallFont *_doubleSmallFont = nullptr;
@@ -220,7 +221,7 @@ public:
return true;
}
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override {
- return true;
+ return _saveAllowed;
}
/**
Commit: cf6c76d0f58feebc051cc96f46c32b1ec8dd7e0b
https://github.com/scummvm/scummvm/commit/cf6c76d0f58feebc051cc96f46c32b1ec8dd7e0b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:33+02:00
Commit Message:
PELROCK: Saves games with the right thumbnail
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/metaengine.cpp
engines/pelrock/metaengine.h
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 7386610bf47..950104fb8ab 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -305,7 +305,7 @@ void MenuManager::menuLoop() {
//Save screenshot in case the user saves
saveScreenshot();
- g_engine->_saveAllowed = false;
+ g_engine->_autoSaveAllowed = false;
g_system->getPaletteManager()->setPalette(_mainMenuPalette, 0, 256);
g_engine->changeCursor(DEFAULT);
@@ -342,7 +342,6 @@ void MenuManager::menuLoop() {
break;
}
drawScreen();
- drawPaletteSquares((byte *)_screen->getPixels(), _mainMenuPalette);
_screen->markAllDirty();
_screen->update();
g_system->delayMillis(10);
@@ -351,7 +350,7 @@ void MenuManager::menuLoop() {
_events->_rightMouseClicked = false;
_events->_leftMouseClicked = false;
g_system->getPaletteManager()->setPalette(g_engine->_room->_roomPalette, 0, 256);
- g_engine->_saveAllowed = true;
+ g_engine->_autoSaveAllowed = true;
cleanUp();
}
diff --git a/engines/pelrock/metaengine.cpp b/engines/pelrock/metaengine.cpp
index 11bff334e70..f659918398e 100644
--- a/engines/pelrock/metaengine.cpp
+++ b/engines/pelrock/metaengine.cpp
@@ -20,6 +20,7 @@
*/
#include "common/translation.h"
+#include "graphics/thumbnail.h"
#include "pelrock/metaengine.h"
#include "pelrock/detection.h"
@@ -68,6 +69,15 @@ Common::Error PelrockMetaEngine::createInstance(OSystem *syst, Engine **engine,
return Common::kNoError;
}
+void PelrockMetaEngine::getSavegameThumbnail(Graphics::Surface &thumb) {
+ Pelrock::PelrockEngine *engine = static_cast<Pelrock::PelrockEngine *>(g_engine);
+ if (engine && engine->_saveThumbnail.getPixels()) {
+ thumb.copyFrom(engine->_saveThumbnail);
+ } else {
+ Graphics::createThumbnail(thumb);
+ }
+}
+
bool PelrockMetaEngine::hasFeature(MetaEngineFeature f) const {
return checkExtendedSaves(f) ||
(f == kSupportsLoadingDuringStartup);
diff --git a/engines/pelrock/metaengine.h b/engines/pelrock/metaengine.h
index d1649be567f..596f967bf63 100644
--- a/engines/pelrock/metaengine.h
+++ b/engines/pelrock/metaengine.h
@@ -23,6 +23,7 @@
#define PELROCK_METAENGINE_H
#include "engines/advancedDetector.h"
+#include "graphics/surface.h"
class PelrockMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
public:
@@ -38,6 +39,8 @@ public:
bool hasFeature(MetaEngineFeature f) const override;
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override;
+
+ void getSavegameThumbnail(Graphics::Surface &thumb) override;
};
#endif // PELROCK_METAENGINE_H
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 742ca30c446..79044d61c1c 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -182,7 +182,7 @@ public:
Graphics::Surface _saveThumbnail;
GameStateData *_state = new GameStateData();
- bool _saveAllowed = true;
+ bool _autoSaveAllowed = true;
SmallFont *_smallFont = nullptr;
LargeFont *_largeFont = nullptr;
DoubleSmallFont *_doubleSmallFont = nullptr;
@@ -221,7 +221,11 @@ public:
return true;
}
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override {
- return _saveAllowed;
+ return true;
+ }
+
+ bool canSaveAutosaveCurrently() override {
+ return _autoSaveAllowed;
}
/**
Commit: 48b3c9d8d9e6aa93e191d2dea6fc68c3dfe04b15
https://github.com/scummvm/scummvm/commit/48b3c9d8d9e6aa93e191d2dea6fc68c3dfe04b15
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:33+02:00
Commit Message:
PELROCK: First implementation of sliding screensaver
Changed paths:
A engines/pelrock/slidingpuzzle.cpp
A engines/pelrock/slidingpuzzle.h
engines/pelrock/events.cpp
engines/pelrock/events.h
engines/pelrock/module.mk
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
index c90705e7c06..2c3352b1962 100644
--- a/engines/pelrock/events.cpp
+++ b/engines/pelrock/events.cpp
@@ -42,22 +42,14 @@ void PelrockEventManager::pollEvent() {
case Common::EVENT_QUIT:
case Common::EVENT_RETURN_TO_LAUNCHER:
return;
-
- // case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
- // // handle action
- // handleKey(_event);
- // break;
-
- // case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
- // break;
case Common::EVENT_KEYDOWN:
changeGameSpeed(_event);
- // _keyPressed = true;
_lastKeyEvent = _event.kbd.keycode;
+ _isKeydown = true;
break;
- // return;
- // case Common::EVENT_KEYUP:
- // return;
+ case Common::EVENT_KEYUP:
+ _isKeydown = false;
+ return;
case Common::EVENT_LBUTTONDOWN:
if (_leftMouseButton == 0) {
_clickTime = g_system->getMillis();
@@ -68,10 +60,7 @@ void PelrockEventManager::pollEvent() {
break;
case Common::EVENT_LBUTTONUP:
if (_leftMouseButton == 1) {
- // Don't treat as regular click if we're in popup selection mode
- // if (!_popupSelectionMode) {
_leftMouseClicked = true;
- // }
_releaseX = _event.mouse.x;
_releaseY = _event.mouse.y;
_longClicked = false;
diff --git a/engines/pelrock/events.h b/engines/pelrock/events.h
index 6b2c54a700c..84b86b8ec4a 100644
--- a/engines/pelrock/events.h
+++ b/engines/pelrock/events.h
@@ -43,6 +43,7 @@ public:
bool _popupSelectionMode = false;
bool _leftMouseButton = false;
bool _rightMouseButton = false;
+ bool _isKeydown = false;
Common::KeyCode _lastKeyEvent = Common::KEYCODE_INVALID;
PelrockEventManager();
void pollEvent();
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index 8f1fa08902b..32053f15ecd 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -22,6 +22,7 @@ MODULE_OBJS = \
graphics.o \
saveload.o \
spellbook.o \
+ slidingpuzzle.o \
cdplayer.o \
backgroundbook.o
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a0f4c703346..6ac79b31174 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -42,6 +42,7 @@
#include "pelrock/offsets.h"
#include "pelrock/pathfinding.h"
#include "pelrock/pelrock.h"
+#include "pelrock/slidingpuzzle.h"
#include "pelrock/util.h"
namespace Pelrock {
@@ -1512,11 +1513,16 @@ void PelrockEngine::gameLoop() {
}
if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_k) {
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
credits();
}
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_v) {
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ SlidingPuzzle puzzle(_events, _sound);
+ puzzle.run();
+ }
renderScene();
-
_screen->update();
}
diff --git a/engines/pelrock/slidingpuzzle.cpp b/engines/pelrock/slidingpuzzle.cpp
new file mode 100644
index 00000000000..30ef21061f1
--- /dev/null
+++ b/engines/pelrock/slidingpuzzle.cpp
@@ -0,0 +1,272 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/system.h"
+#include "graphics/paletteman.h"
+
+#include "pelrock/slidingpuzzle.h"
+#include "pelrock/pelrock.h"
+#include "pelrock/events.h"
+#include "pelrock/room.h"
+#include "pelrock/sound.h"
+
+namespace Pelrock {
+
+byte SlidingPuzzle::_sizeIndex = 0;
+
+SlidingPuzzle::SlidingPuzzle(PelrockEventManager *eventMan, SoundManager *sound)
+ : _events(eventMan),
+ _sound(sound),
+ _tileSize(0),
+ _gridWidth(0),
+ _gridHeight(0),
+ _totalTiles(0),
+ _emptyPos(-1),
+ _tileMap(nullptr) {
+}
+
+SlidingPuzzle::~SlidingPuzzle() {
+ delete[] _tileMap;
+ _puzzleBuffer.free();
+}
+
+void SlidingPuzzle::run() {
+ // calculate grid
+ _tileSize = kTileSizes[_sizeIndex];
+ _gridWidth = kPuzzleScreenWidth / _tileSize;
+ _gridHeight = kPuzzleScreenHeight / _tileSize;
+ _totalTiles = _gridWidth * _gridHeight;
+
+ initGrid();
+
+ // Copy the current scene into our working buffer.
+ _puzzleBuffer.create(kPuzzleScreenWidth, kPuzzleScreenHeight, Graphics::PixelFormat::createFormatCLUT8());
+ _puzzleBuffer.copyFrom(g_engine->_compositeBuffer);
+
+ drawGridLines();
+ present();
+
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+
+ //Shuffle
+ shuffleLoop();
+
+ // Guarantee the puzzle is solvable, fix it otherwise
+ ensureSolvable();
+
+ // Remove the last tile to create the empty slot (tile_count = total - 1).
+ _emptyPos = _totalTiles - 1;
+ fillEmptyTile(_emptyPos);
+
+ g_engine->changeCursor(DEFAULT);
+ present();
+
+ puzzleLoop();
+
+ // Cycle to the next tile size for the next activation.
+ _sizeIndex = (_sizeIndex + 1) % kNumPuzzleSizes;
+}
+
+// After shuffling, ensure the resulting permutation is reachable from the solved state.
+// For all our grid widths (8, 16, 32, 64 â all even) with the blank forced to the
+// bottom-right corner (row-from-bottom = 0), the solvability condition is:
+// inversions in _tileMap[0 .. N-2] must be even.
+// Each tile swap flips parity, so if we end up with an odd count, one extra swap fixes it.
+void SlidingPuzzle::ensureSolvable() {
+ int inversions = 0;
+ for (int i = 0; i < _totalTiles - 1; i++) {
+ for (int j = i + 1; j < _totalTiles - 1; j++) {
+ if (_tileMap[i] > _tileMap[j])
+ inversions++;
+ }
+ }
+ if (inversions & 1)
+ swapTiles(0, 1);
+}
+
+// Set up the identity permutation: tile i is in slot i.
+void SlidingPuzzle::initGrid() {
+ _tileMap = new uint16[_totalTiles];
+ for (uint16 i = 0; i < _totalTiles; i++)
+ _tileMap[i] = (uint16)i;
+}
+
+/**
+ * Original draws grid lines to make tile separation evident.
+ */
+void SlidingPuzzle::drawGridLines() {
+ for (int col = 0; col < _gridWidth; col++) {
+ int x = col * _tileSize;
+ _puzzleBuffer.drawLine(x, 0, x, kPuzzleScreenHeight - 1, kEmptyTileColor);
+ }
+ for (int row = 0; row < _gridHeight; row++) {
+ int y = row * _tileSize;
+ _puzzleBuffer.drawLine(0, y, kPuzzleScreenWidth - 1, y, kEmptyTileColor);
+ }
+}
+
+void SlidingPuzzle::swapTiles(int a, int b) {
+ SWAP(_tileMap[a], _tileMap[b]);
+
+ // Pixel coordinates: skip the 1px grid line at top/left of each tile.
+ int ax = (a % _gridWidth) * _tileSize + 1;
+ int ay = (a / _gridWidth) * _tileSize + 1;
+ int bx = (b % _gridWidth) * _tileSize + 1;
+ int by = (b / _gridWidth) * _tileSize + 1;
+ int inner = _tileSize - 1;
+
+ for (int row = 0; row < inner; row++) {
+ byte *pA = (byte *)_puzzleBuffer.getBasePtr(ax, ay + row);
+ byte *pB = (byte *)_puzzleBuffer.getBasePtr(bx, by + row);
+ for (int col = 0; col < inner; col++)
+ SWAP(pA[col], pB[col]);
+ }
+}
+
+void SlidingPuzzle::fillEmptyTile(int pos) {
+ int ex = (pos % _gridWidth) * _tileSize + 1;
+ int ey = (pos / _gridWidth) * _tileSize + 1;
+ int inner = _tileSize - 1;
+ _puzzleBuffer.fillRect(Common::Rect(ex, ey, ex + inner, ey + inner), kEmptyTileColor);
+}
+
+void SlidingPuzzle::present() {
+ g_engine->_screen->blitFrom(_puzzleBuffer);
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+}
+
+void SlidingPuzzle::playTileSound() {
+ _sound->playSound("11ZZZZZZ.SMP", -1);
+}
+
+void SlidingPuzzle::shuffleLoop() {
+ const int shuffleRange = _totalTiles - 1; // never touch the blank slot (N-1)
+ while (!g_engine->shouldQuit()) {
+ _events->pollEvent();
+
+ int a, b;
+ do {
+ a = g_engine->getRandomNumber(shuffleRange - 1);
+ b = g_engine->getRandomNumber(shuffleRange - 1);
+ } while (a == b);
+
+ swapTiles(a, b);
+ present();
+ playTileSound();
+
+ if (_events->_lastKeyEvent != Common::KEYCODE_INVALID) {
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ break;
+ }
+ g_system->delayMillis(10);
+ }
+}
+
+void SlidingPuzzle::puzzleLoop() {
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ _events->_isKeydown = false;
+
+ while (!g_engine->shouldQuit()) {
+ _events->pollEvent();
+
+ if (_events->_leftMouseClicked) {
+ _events->_leftMouseClicked = false;
+ if (handleClick(_events->_mouseClickX, _events->_mouseClickY))
+ break;
+ }
+
+ if (_events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
+ break;
+ }
+
+ // While any key is held, show the original (unscrambled) background.
+ if (_events->_isKeydown && _events->_lastKeyEvent != Common::KEYCODE_ESCAPE) {
+ showOriginalImage();
+ }
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+
+ present();
+ g_system->delayMillis(10);
+ }
+}
+
+bool SlidingPuzzle::handleClick(int screenX, int screenY) {
+ int col = screenX / _tileSize;
+ int row = screenY / _tileSize;
+ if (col >= _gridWidth || row >= _gridHeight)
+ return false;
+
+ int clicked = row * _gridWidth + col;
+ if (clicked == _emptyPos)
+ return false;
+
+ // Check adjacency without row wrap-around.
+ int emptyRow = _emptyPos / _gridWidth;
+ int emptyCol = _emptyPos % _gridWidth;
+ bool adjacent = (row == emptyRow && abs(col - emptyCol) == 1) ||
+ (col == emptyCol && abs(row - emptyRow) == 1);
+ if (!adjacent)
+ return false;
+
+ swapTiles(clicked, _emptyPos);
+ _emptyPos = clicked;
+ fillEmptyTile(_emptyPos);
+ playTileSound();
+ present();
+
+ if (isSolved()) {
+ _sound->playSound("CHIQUITO.WAV", 3);
+ while (!g_engine->shouldQuit() && _sound->isPlaying(3)) {
+ _events->pollEvent();
+ g_system->delayMillis(10);
+ }
+ _sound->stopSound(3);
+ return true;
+ }
+
+ return false;
+}
+
+bool SlidingPuzzle::isSolved() const {
+ for (int i = 0; i < _totalTiles - 1; i++) {
+ if (_tileMap[i] != (uint16)i)
+ return false;
+ }
+ return true;
+}
+
+// show the original background while a key is held.
+void SlidingPuzzle::showOriginalImage() {
+ // original game showed only the room background
+ g_engine->_screen->blitFrom(g_engine->_compositeBuffer);
+ g_engine->_screen->markAllDirty();
+ g_engine->_screen->update();
+
+ while (!g_engine->shouldQuit()) {
+ _events->pollEvent();
+ if (_events->_isKeydown == false)
+ break;
+ g_system->delayMillis(10);
+ }
+}
+
+} // End of namespace Pelrock
diff --git a/engines/pelrock/slidingpuzzle.h b/engines/pelrock/slidingpuzzle.h
new file mode 100644
index 00000000000..fb7b4d3c20e
--- /dev/null
+++ b/engines/pelrock/slidingpuzzle.h
@@ -0,0 +1,79 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PELROCK_SLIDING_PUZZLE_H
+#define PELROCK_SLIDING_PUZZLE_H
+
+#include "common/scummsys.h"
+#include "graphics/managed_surface.h"
+
+#include "pelrock/events.h"
+#include "pelrock/sound.h"
+
+namespace Pelrock {
+
+static const int kPuzzleScreenWidth = 640;
+static const int kPuzzleScreenHeight = 400;
+static const int kNumPuzzleSizes = 4;
+static const int kTileSizes[kNumPuzzleSizes] = {80, 40, 20, 10};
+static const byte kEmptyTileColor = 0x0F;
+
+class SlidingPuzzle {
+public:
+ SlidingPuzzle(PelrockEventManager *eventMan, SoundManager *sound);
+ ~SlidingPuzzle();
+
+ void run();
+
+ // Persisted across activations so the size cycles each time.
+ static byte _sizeIndex;
+
+private:
+ PelrockEventManager *_events;
+ SoundManager *_sound;
+
+ void playTileSound();
+
+ int _tileSize;
+ int _gridWidth;
+ int _gridHeight;
+ int _totalTiles; // gridWidth * gridHeight`
+ int _emptyPos; // index of the empty (removed) tile
+ uint16 *_tileMap; // logical position -> original tile index
+
+ Graphics::ManagedSurface _puzzleBuffer;
+
+ void initGrid();
+ void drawGridLines();
+ void swapTiles(int a, int b);
+ void fillEmptyTile(int pos);
+ void shuffleLoop();
+ void ensureSolvable();
+ void puzzleLoop();
+ bool handleClick(int screenX, int screenY);
+ bool isSolved() const;
+ void showOriginalImage();
+ void present();
+};
+
+} // End of namespace Pelrock
+
+#endif // PELROCK_SLIDING_PUZZLE_H
Commit: 9e1917d9f0fbdde38cdca01bc1dc882a46a2c44e
https://github.com/scummvm/scummvm/commit/9e1917d9f0fbdde38cdca01bc1dc882a46a2c44e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:33+02:00
Commit Message:
PELROCK: Enables fake teeth animation in room 3, increases amount of random responses
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/graphics.cpp
engines/pelrock/pelrock.h
engines/pelrock/slidingpuzzle.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 28762c91d5e..37553d3022b 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -21,7 +21,7 @@
#include "graphics/paletteman.h"
-
+#include "pelrock.h"
#include "pelrock/actions.h"
#include "pelrock/backgroundbook.h"
#include "pelrock/cdplayer.h"
@@ -746,8 +746,7 @@ void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
}
debug("No-op item %d with hotspot %d", item, hotspot->extra);
_alfredState.direction = ALFRED_DOWN;
- byte response = (byte)getRandomNumber(12);
- _dialog->say(_res->_ingameTexts[154 + response]);
+ sayRandomIncorrectResponse();
}
void PelrockEngine::openRoomDoor(HotSpot *hotspot) {
@@ -950,6 +949,7 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
_room->addStickerToRoom(_room->_currentRoomNumber, 10, PERSIST_PERM);
_room->disableHotspot(_room->findHotspotByExtra(295)); // Disable storefront hotspot
_room->disableHotspot(_room->findHotspotByExtra(294)); // Disable window hotspot
+ _room->enableSprite(5, 100, PERSIST_PERM); // Enable fake teeth sprite
_disableAction = true; // Prevent player from doing anything until they move Alfred
walkTo(630, _alfredState.y);
}
@@ -2184,8 +2184,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_dialog->say(_res->_ingameTexts[NOTENGOPEGAMENTO]);
}
} else {
- byte response = (byte)getRandomNumber(12);
- _dialog->say(_res->_ingameTexts[154 + response]);
+ sayRandomIncorrectResponse();
}
break;
}
@@ -2226,13 +2225,16 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
return;
}
- byte response = (byte)getRandomNumber(12);
- _dialog->say(_res->_ingameTexts[154 + response]);
+ sayRandomIncorrectResponse();
break;
}
}
}
+void PelrockEngine::sayRandomIncorrectResponse() {
+ byte response = (byte)getRandomNumber(15);
+ _dialog->say(_res->_ingameTexts[154 + response]);
+}
void PelrockEngine::chooseCorrectDoor() {
playAlfredSpecialAnim(1);
byte puertaBuena = _state->getFlag(FLAG_PUERTA_BUENA);
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 279fe2f2622..6b7c7c325cb 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -232,7 +232,7 @@ void GraphicsManager::copyBackgroundToBuffer() {
void GraphicsManager::presentFrame() {
g_engine->_screen->blitFrom(g_engine->_compositeBuffer);
- // paintDebugLayer();
+ g_engine->paintDebugLayer();
g_engine->_screen->markAllDirty();
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 79044d61c1c..f492898c3fe 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -118,7 +118,6 @@ private:
void checkMouseHover();
void checkMouseClick(int x, int y);
void checkLongMouseClick(int x, int y);
- void paintDebugLayer();
// walking
int _currentStep = 0;
@@ -258,6 +257,7 @@ public:
void maybePlayPostIntro();
void shakeEffect();
void handleFlightRoomFrame();
+ void paintDebugLayer();
void passerByAnim(uint32 frameCount);
void changeCursor(Cursor cursor);
@@ -311,6 +311,7 @@ public:
void noOpAction(HotSpot *hotspot);
void noOpItem(int item, HotSpot *hotspot);
void useOnAlfred(int inventoryObject);
+ void sayRandomIncorrectResponse();
void chooseCorrectDoor();
void useCardWithATM(int inventoryObject, HotSpot *hotspot);
void useBrickWithWindow(int inventoryObject, HotSpot *hotspot);
diff --git a/engines/pelrock/slidingpuzzle.cpp b/engines/pelrock/slidingpuzzle.cpp
index 30ef21061f1..31aacc04e9c 100644
--- a/engines/pelrock/slidingpuzzle.cpp
+++ b/engines/pelrock/slidingpuzzle.cpp
@@ -256,7 +256,7 @@ bool SlidingPuzzle::isSolved() const {
// show the original background while a key is held.
void SlidingPuzzle::showOriginalImage() {
- // original game showed only the room background
+ // original game showed only the room background, we show the entire scene
g_engine->_screen->blitFrom(g_engine->_compositeBuffer);
g_engine->_screen->markAllDirty();
g_engine->_screen->update();
Commit: a7ded2599447685b393c278b8cb5b5bf024ad5dd
https://github.com/scummvm/scummvm/commit/a7ded2599447685b393c278b8cb5b5bf024ad5dd
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:33+02:00
Commit Message:
PELROCK: Fixes for interaction with the statue in room 7
Changed paths:
engines/pelrock/actions.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 37553d3022b..6c4e09bb0f3 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -204,7 +204,7 @@ const CombinationEntry combinationTable[] = {
{1, 309, &PelrockEngine::showIdToGuard},
{5, 309, &PelrockEngine::giveMoneyToGuard},
{7, 353, &PelrockEngine::useAmuletWithStatue},
- {8, 353, &PelrockEngine::useSecretCodeWithStatue},
+ {8, 347, &PelrockEngine::useSecretCodeWithStatue},
{8, 358, &PelrockEngine::giveSecretCodeToLibrarian},
{4, 358, &PelrockEngine::useBrickWithLibrarian}, // Any hotspot in the lamppost will work
{76, 469, &PelrockEngine::usePumpkinWithRiver},
@@ -1128,13 +1128,16 @@ void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
walkTo(statueHotspot->x + statueHotspot->w / 2, statueHotspot->y + statueHotspot->h);
_sound->playSound(_room->_roomSfx[0]); // Magic sound
animateStatuePaletteFade(false);
+ _dialog->say(_res->_ingameTexts[ANDA]);
walkAndAction(statueHotspot, TALK);
waitForActionEnd();
}
}
void PelrockEngine::useSecretCodeWithStatue(int inventoryObject, HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[NOESAMIAQUIENDEBES], 1);
+ _dialog->say(_res->_ingameTexts[NOESAMIAQUIENDEBES]);
+ _dialog->say(_res->_ingameTexts[AQUIENENTONCES]);
+ _dialog->say(_res->_ingameTexts[LIBROSSECRETOS]);
}
void PelrockEngine::pickUpLetter(HotSpot *hotspot) {
Commit: c507068bb2e4f85bf05514d31a668e58154a633f
https://github.com/scummvm/scummvm/commit/c507068bb2e4f85bf05514d31a668e58154a633f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:34+02:00
Commit Message:
PELROCK: Refactors main menu and adds confirmation upon exit
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 950104fb8ab..6529c439525 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/config-manager.h"
#include "common/debug.h"
#include "common/file.h"
#include "graphics/paletteman.h"
@@ -83,7 +84,37 @@ static void rebuildSoundIcon(Graphics::ManagedSurface &target, const byte *sourc
delete scaled;
}
-MenuButton MenuManager::isButtonClicked(int x, int y) {
+SoundMenuButton MenuManager::isSoundMenuButtonUnder(int x, int y) {
+ if (_menuState != SOUND) {
+ return NO_SOUND_BUTTON;
+ }
+ if (_masterVolumeLeftRect.contains(x, y)) {
+ return MASTER_LEFT_BUTTON;
+ }
+ if (_masterVolumeRightRect.contains(x, y)) {
+ return MASTER_RIGHT_BUTTON;
+ }
+ if (_sfxVolumeLeftRect.contains(x, y)) {
+ return SFX_LEFT_BUTTON;
+ }
+ if (_sfxVolumeRightRect.contains(x, y)) {
+ return SFX_RIGHT_BUTTON;
+ }
+ if (_musicVolumeLeftRect.contains(x, y)) {
+ return MUSIC_LEFT_BUTTON;
+ }
+ if (_musicVolumeRightRect.contains(x, y)) {
+ return MUSIC_RIGHT_BUTTON;
+ }
+ return NO_SOUND_BUTTON; // Default fallback
+}
+
+MainMenuButton MenuManager::isMainMenuButtonUnder(int x, int y) {
+ if (_menuState != MAIN_MENU) {
+ debug("Not checking for main menu buttons because menu state is not MAIN_MENU");
+ return NO_MAIN_BUTTON;
+ }
+
if (_questionMarkRect.contains(x, y)) {
return QUESTION_MARK_BUTTON;
}
@@ -111,34 +142,14 @@ MenuButton MenuManager::isButtonClicked(int x, int y) {
if (_savesDown.contains(x, y)) {
return SAVEGAME_NEXT_BUTTON;
}
- if (_showSoundOptions) {
- if (_masterVolumeLeftRect.contains(x, y)) {
- return MASTER_LEFT_BUTTON;
- }
- if (_masterVolumeRightRect.contains(x, y)) {
- return MASTER_RIGHT_BUTTON;
- }
- if (_sfxVolumeLeftRect.contains(x, y)) {
- return SFX_LEFT_BUTTON;
- }
- if (_sfxVolumeRightRect.contains(x, y)) {
- return SFX_RIGHT_BUTTON;
- }
- if (_musicVolumeLeftRect.contains(x, y)) {
- return MUSIC_LEFT_BUTTON;
- }
- if (_musicVolumeRightRect.contains(x, y)) {
- return MUSIC_RIGHT_BUTTON;
- }
- }
- return NO_BUTTON; // Default fallback
+ return NO_MAIN_BUTTON; // Default fallback
}
void MenuManager::checkMouseDown(int x, int y) {
- if(!_events->_leftMouseButton) {
+ if (!_events->_leftMouseButton) {
return;
}
- MenuButton b = isButtonClicked(x, y);
+ SoundMenuButton b = isSoundMenuButtonUnder(x, y);
switch (b) {
case MASTER_LEFT_BUTTON:
_masterVolumeLevel = MAX(0, _masterVolumeLevel - 1);
@@ -176,38 +187,55 @@ void MenuManager::checkMouseDown(int x, int y) {
}
bool MenuManager::checkMouseClick(int x, int y) {
+ debug("Checking mouse click at %d, %d, with menu state %d", x, y, _menuState);
- bool selectedItem = false;
- for (int i = 0; i < 4; i++) {
-
- Common::Rect itemRect = Common::Rect(_inventorySlots[i], 60, 60);
-
- if (itemRect.contains(x, y)) {
- selectedItem = selectInventoryItem(i);
- return false;
- }
+ switch (_menuState) {
+ case MAIN_MENU: {
+ return checkMainMenuMouse(x, y);
+ break;
+ }
+ case SOUND: {
+ checkSoundMenuClick(x, y);
+ break;
}
+ case ORIGINAL_SAVE: {
+ break;
+ }
+ case ORIGINAL_LOAD: {
+ break;
+ }
+ case EXIT_GAME: {
+ break;
+ }
+ }
+ return false;
+}
- MenuButton button = isButtonClicked(x, y);
+void MenuManager::checkSoundMenuClick(int x, int y) {
+ SoundMenuButton soundMenuButton = isSoundMenuButtonUnder(x, y);
+
+ if (soundMenuButton != MUSIC_LEFT_BUTTON &&
+ soundMenuButton != MUSIC_RIGHT_BUTTON &&
+ soundMenuButton != SFX_LEFT_BUTTON &&
+ soundMenuButton != SFX_RIGHT_BUTTON &&
+ soundMenuButton != MASTER_LEFT_BUTTON &&
+ soundMenuButton != MASTER_RIGHT_BUTTON) {
+ _menuState = MAIN_MENU;
+ _menuText = _menuTexts[0];
+ }
- if (button != MUSIC_LEFT_BUTTON &&
- button != MUSIC_RIGHT_BUTTON &&
- button != SFX_LEFT_BUTTON &&
- button != SFX_RIGHT_BUTTON &&
- button != MASTER_LEFT_BUTTON &&
- button != MASTER_RIGHT_BUTTON) {
- _showSoundOptions = false;
- if (!selectedItem) {
- _selectedInvIndex = -1;
- _menuText = _menuTexts[0];
- }
+ if (soundMenuButton == SFX_LEFT_BUTTON || soundMenuButton == SFX_RIGHT_BUTTON) {
+ _sound->playSound("CAT_1ZZZ.SMP", -1);
}
+}
- switch (button) {
+bool MenuManager::checkMainMenuMouse(int x, int y) {
+ debug("Checking main menu buttons");
+ MainMenuButton mainMenuButton = isMainMenuButtonUnder(x, y);
+ switch (mainMenuButton) {
case QUESTION_MARK_BUTTON:
_sound->playSound("56ZZZZZZ.SMP", 0);
- debug("Show credits");
_events->_leftMouseClicked = false;
showCredits();
break;
@@ -223,27 +251,32 @@ bool MenuManager::checkMouseClick(int x, int y) {
break;
case SAVE_GAME_BUTTON:
_sound->playSound("11ZZZZZZ.SMP", 0);
- return g_engine->saveGameDialog();
+ if (ConfMan.getBool("original_menus") == true) {
+ _menuState = ORIGINAL_SAVE;
+ _menuText = Common::StringArray();
+ } else {
+ return g_engine->saveGameDialog();
+ }
break;
case LOAD_GAME_BUTTON:
_sound->playSound("11ZZZZZZ.SMP", 0);
- return g_engine->loadGameDialog();
+ if (ConfMan.getBool("original_menus") == true) {
+ _menuState = ORIGINAL_LOAD;
+ _menuText = Common::StringArray();
+ } else {
+ return g_engine->loadGameDialog();
+ }
break;
case EXIT_MENU_BUTTON:
_sound->playSound("11ZZZZZZ.SMP", 0);
- g_engine->quitGame();
+ _menuState = EXIT_GAME;
+ // g_engine->quitGame();
break;
case SOUNDS_BUTTON:
_sound->playSound("11ZZZZZZ.SMP", 0);
- _showSoundOptions = true;
+ _menuState = SOUND;
_menuText = Common::StringArray();
break;
- case SFX_LEFT_BUTTON:
- _sound->playSound("CAT_1ZZZ.SMP", -1);
- break;
- case SFX_RIGHT_BUTTON:
- _sound->playSound("CAT_1ZZZ.SMP", -1);
- break;
default:
break;
}
@@ -303,18 +336,18 @@ bool MenuManager::selectInventoryItem(int i) {
void MenuManager::menuLoop() {
- //Save screenshot in case the user saves
+ // Save screenshot in case the user saves
saveScreenshot();
g_engine->_autoSaveAllowed = false;
g_system->getPaletteManager()->setPalette(_mainMenuPalette, 0, 256);
g_engine->changeCursor(DEFAULT);
- _showSoundOptions = false;
+ _menuState = MAIN_MENU;
_menuText = _menuTexts[0];
// Initialize volume levels from current settings
- _sfxVolumeLevel = mixerVolumeToLevel(_sound->getVolumeSfx());
- _musicVolumeLevel = mixerVolumeToLevel(_sound->getVolumeMusic());
+ _sfxVolumeLevel = mixerVolumeToLevel(_sound->getVolumeSfx());
+ _musicVolumeLevel = mixerVolumeToLevel(_sound->getVolumeMusic());
_masterVolumeLevel = mixerVolumeToLevel(_sound->getVolumeMaster());
debug("Initial master volume level: %d", _masterVolumeLevel);
@@ -333,14 +366,24 @@ void MenuManager::menuLoop() {
_events->pollEvent();
checkMouseDown(_events->_mouseX, _events->_mouseY);
if (_events->_leftMouseClicked) {
+ _events->_leftMouseClicked = false;
if (checkMouseClick(_events->_mouseX, _events->_mouseY)) {
break;
}
- _events->_leftMouseClicked = false;
}
if (_events->_rightMouseClicked) {
break;
}
+ if (_menuState == EXIT_GAME) {
+ if (_events->_lastKeyEvent == Common::KEYCODE_s) {
+ g_engine->quitGame();
+ } else if (_events->_lastKeyEvent == Common::KEYCODE_n) {
+ _menuState = MAIN_MENU;
+ _menuText = _menuTexts[0];
+ }
+ _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ }
+
drawScreen();
_screen->markAllDirty();
_screen->update();
@@ -480,7 +523,6 @@ void MenuManager::loadMenu() {
extractSingleFrame(soundIconMusicData, _soundControlMusicIcon, 0, 66, 64);
delete[] soundIconMusicData;
-
_menuText = _menuTexts[0];
alfred7.close();
@@ -542,11 +584,42 @@ void MenuManager::cleanUp() {
}
void MenuManager::drawButtons() {
- MenuButton button = NO_BUTTON;
+ // always draw main buttons
+ drawMainButtons();
+
+ switch (_menuState) {
+ case MAIN_MENU:
+ break;
+ case ORIGINAL_SAVE:
+ drawSaves();
+ break;
+ case ORIGINAL_LOAD:
+ drawSaves();
+ break;
+ case SOUND:
+ drawSoundControls();
+ break;
+ case EXIT_GAME:
+ drawConfirmation();
+ break;
+ }
+}
+
+void MenuManager::drawConfirmation() {
+ _menuText = _menuTexts[4];
+}
+
+void MenuManager::drawSaves() {
+}
+
+void MenuManager::drawMainButtons() {
+ MainMenuButton button = NO_MAIN_BUTTON;
if (_events->_leftMouseButton != 0) {
- button = isButtonClicked(_events->_mouseX, _events->_mouseY);
+ button = isMainMenuButtonUnder(_events->_mouseX, _events->_mouseY);
}
- byte *buf = button == QUESTION_MARK_BUTTON ? _questionMark[1] : _questionMark[0];
+
+ byte *buf;
+ buf = button == QUESTION_MARK_BUTTON ? _questionMark[1] : _questionMark[0];
drawSpriteToBuffer(_compositeBuffer, buf, _questionMarkRect.left, _questionMarkRect.top, _questionMarkRect.width(), _questionMarkRect.height(), kTransparentColor);
buf = button == INVENTORY_PREV_BUTTON ? _inventoryLeftArrow[1] : _inventoryLeftArrow[0];
@@ -575,25 +648,30 @@ void MenuManager::drawButtons() {
buf = button == SAVEGAME_NEXT_BUTTON ? _savesDownArrows[1] : _savesDownArrows[0];
drawSpriteToBuffer(_compositeBuffer, buf, _savesDown.left, _savesDown.top, _savesDown.width(), _savesDown.height(), kTransparentColor);
+}
- if (_showSoundOptions) {
- _compositeBuffer.transBlitFrom(_masterSoundIcon, Common::Point(266 - _masterSoundIcon.w / 2, 212 - _masterSoundIcon.h / 2), kSoundControlsTransparentColor);
- _compositeBuffer.transBlitFrom(_musicSoundIcon, Common::Point(333 - _musicSoundIcon.w / 2, 212 - _musicSoundIcon.h / 2), kSoundControlsTransparentColor);
- _compositeBuffer.transBlitFrom(_sfxSoundIcon, Common::Point(399 - _sfxSoundIcon.w / 2, 212 - _sfxSoundIcon.h / 2), kSoundControlsTransparentColor);
-
- buf = button == MASTER_LEFT_BUTTON ? _soundControlArrowLeft[1] : _soundControlArrowLeft[0];
- drawSpriteToBuffer(_compositeBuffer, buf, _masterVolumeLeftRect.left, _masterVolumeLeftRect.top, _masterVolumeLeftRect.width(), _masterVolumeLeftRect.height(), kSoundControlsTransparentColor);
- buf = button == MASTER_RIGHT_BUTTON ? _soundControlArrowRight[1] : _soundControlArrowRight[0];
- drawSpriteToBuffer(_compositeBuffer, buf, _masterVolumeRightRect.left, _masterVolumeRightRect.top, _masterVolumeRightRect.width(), _masterVolumeRightRect.height(), kSoundControlsTransparentColor);
- buf = button == SFX_LEFT_BUTTON ? _soundControlArrowLeft[1] : _soundControlArrowLeft[0];
- drawSpriteToBuffer(_compositeBuffer, buf, _sfxVolumeLeftRect.left, _sfxVolumeLeftRect.top, _sfxVolumeLeftRect.width(), _sfxVolumeLeftRect.height(), kSoundControlsTransparentColor);
- buf = button == SFX_RIGHT_BUTTON ? _soundControlArrowRight[1] : _soundControlArrowRight[0];
- drawSpriteToBuffer(_compositeBuffer, buf, _sfxVolumeRightRect.left, _sfxVolumeRightRect.top, _sfxVolumeRightRect.width(), _sfxVolumeRightRect.height(), kSoundControlsTransparentColor);
- buf = button == MUSIC_LEFT_BUTTON ? _soundControlArrowLeft[1] : _soundControlArrowLeft[0];
- drawSpriteToBuffer(_compositeBuffer, buf, _musicVolumeLeftRect.left, _musicVolumeLeftRect.top, _musicVolumeLeftRect.width(), _musicVolumeLeftRect.height(), kSoundControlsTransparentColor);
- buf = button == MUSIC_RIGHT_BUTTON ? _soundControlArrowRight[1] : _soundControlArrowRight[0];
- drawSpriteToBuffer(_compositeBuffer, buf, _musicVolumeRightRect.left, _musicVolumeRightRect.top, _musicVolumeRightRect.width(), _musicVolumeRightRect.height(), kSoundControlsTransparentColor);
+void MenuManager::drawSoundControls() {
+ SoundMenuButton button = NO_SOUND_BUTTON;
+ if (_events->_leftMouseButton != 0) {
+ button = isSoundMenuButtonUnder(_events->_mouseX, _events->_mouseY);
}
+ byte *buf;
+ _compositeBuffer.transBlitFrom(_masterSoundIcon, Common::Point(266 - _masterSoundIcon.w / 2, 212 - _masterSoundIcon.h / 2), kSoundControlsTransparentColor);
+ _compositeBuffer.transBlitFrom(_musicSoundIcon, Common::Point(333 - _musicSoundIcon.w / 2, 212 - _musicSoundIcon.h / 2), kSoundControlsTransparentColor);
+ _compositeBuffer.transBlitFrom(_sfxSoundIcon, Common::Point(399 - _sfxSoundIcon.w / 2, 212 - _sfxSoundIcon.h / 2), kSoundControlsTransparentColor);
+
+ buf = button == MASTER_LEFT_BUTTON ? _soundControlArrowLeft[1] : _soundControlArrowLeft[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _masterVolumeLeftRect.left, _masterVolumeLeftRect.top, _masterVolumeLeftRect.width(), _masterVolumeLeftRect.height(), kSoundControlsTransparentColor);
+ buf = button == MASTER_RIGHT_BUTTON ? _soundControlArrowRight[1] : _soundControlArrowRight[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _masterVolumeRightRect.left, _masterVolumeRightRect.top, _masterVolumeRightRect.width(), _masterVolumeRightRect.height(), kSoundControlsTransparentColor);
+ buf = button == SFX_LEFT_BUTTON ? _soundControlArrowLeft[1] : _soundControlArrowLeft[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _sfxVolumeLeftRect.left, _sfxVolumeLeftRect.top, _sfxVolumeLeftRect.width(), _sfxVolumeLeftRect.height(), kSoundControlsTransparentColor);
+ buf = button == SFX_RIGHT_BUTTON ? _soundControlArrowRight[1] : _soundControlArrowRight[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _sfxVolumeRightRect.left, _sfxVolumeRightRect.top, _sfxVolumeRightRect.width(), _sfxVolumeRightRect.height(), kSoundControlsTransparentColor);
+ buf = button == MUSIC_LEFT_BUTTON ? _soundControlArrowLeft[1] : _soundControlArrowLeft[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _musicVolumeLeftRect.left, _musicVolumeLeftRect.top, _musicVolumeLeftRect.width(), _musicVolumeLeftRect.height(), kSoundControlsTransparentColor);
+ buf = button == MUSIC_RIGHT_BUTTON ? _soundControlArrowRight[1] : _soundControlArrowRight[0];
+ drawSpriteToBuffer(_compositeBuffer, buf, _musicVolumeRightRect.left, _musicVolumeRightRect.top, _musicVolumeRightRect.width(), _musicVolumeRightRect.height(), kSoundControlsTransparentColor);
}
Pelrock::MenuManager::~MenuManager() {
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 8b59bba538d..731451cacb1 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -41,7 +41,7 @@ const int kTransparentColor = 65;
const int kSoundControlsTransparentColor = 195;
const uint32 kCreditsBackgroundOffset = 3271454;
-enum MenuButton {
+enum MainMenuButton {
QUESTION_MARK_BUTTON,
INVENTORY_PREV_BUTTON,
INVENTORY_NEXT_BUTTON,
@@ -51,13 +51,17 @@ enum MenuButton {
SAVE_GAME_BUTTON,
LOAD_GAME_BUTTON,
SOUNDS_BUTTON,
+ NO_MAIN_BUTTON
+};
+
+enum SoundMenuButton {
MASTER_LEFT_BUTTON,
MASTER_RIGHT_BUTTON,
SFX_LEFT_BUTTON,
SFX_RIGHT_BUTTON,
MUSIC_LEFT_BUTTON,
MUSIC_RIGHT_BUTTON,
- NO_BUTTON
+ NO_SOUND_BUTTON
};
static const int kCreditsOrder[34] = {
@@ -215,6 +219,15 @@ static const char *inventorySounds[113] = {
};
class MenuManager {
+
+ enum MenuState {
+ MAIN_MENU,
+ SOUND,
+ ORIGINAL_SAVE,
+ ORIGINAL_LOAD,
+ EXIT_GAME
+ };
+
public:
MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res, SoundManager *sound);
~MenuManager();
@@ -228,14 +241,22 @@ public:
private:
void checkMouseDown(int x, int y);
bool checkMouseClick(int x, int y);
+void checkSoundMenuClick(int x, int y);
+ bool checkMainMenuMouse(int x, int y, bool &retFlag);
+ bool checkMainMenuMouse(int x, int y); // returns bool if its supposed to close the menu
void showCredits();
bool selectInventoryItem(int i);
void loadMenuTexts();
void cleanUp();
void drawButtons();
+ void drawConfirmation();
+ void drawSaves();
+ void drawMainButtons();
+ void drawSoundControls();
void readButton(byte *rawData, uint32 offset, byte *outBuffer[2], int w, int h);
void readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect);
- MenuButton isButtonClicked(int x, int y);
+ SoundMenuButton isSoundMenuButtonUnder(int x, int y);
+ MainMenuButton isMainMenuButtonUnder(int x, int y);
Graphics::Screen *_screen = nullptr;
PelrockEventManager *_events = nullptr;
ResourceManager *_res = nullptr;
@@ -304,7 +325,7 @@ private:
Common::Array<Common::Point> _inventorySlots;
bool showButtons = true;
- bool _showSoundOptions = false;
+ MenuState _menuState = MAIN_MENU;
};
} // End of namespace Pelrock
Commit: 1d6826d392353a9d9475fc6f57c54c37807e3cf1
https://github.com/scummvm/scummvm/commit/1d6826d392353a9d9475fc6f57c54c37807e3cf1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:34+02:00
Commit Message:
PELROCK: Implements original save/load screens
Changed paths:
engines/pelrock/events.cpp
engines/pelrock/events.h
engines/pelrock/graphics.cpp
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
index 2c3352b1962..effa865cc6f 100644
--- a/engines/pelrock/events.cpp
+++ b/engines/pelrock/events.cpp
@@ -45,6 +45,7 @@ void PelrockEventManager::pollEvent() {
case Common::EVENT_KEYDOWN:
changeGameSpeed(_event);
_lastKeyEvent = _event.kbd.keycode;
+ _lastKeyAscii = _event.kbd.ascii;
_isKeydown = true;
break;
case Common::EVENT_KEYUP:
diff --git a/engines/pelrock/events.h b/engines/pelrock/events.h
index 84b86b8ec4a..c6f477824ca 100644
--- a/engines/pelrock/events.h
+++ b/engines/pelrock/events.h
@@ -45,6 +45,7 @@ public:
bool _rightMouseButton = false;
bool _isKeydown = false;
Common::KeyCode _lastKeyEvent = Common::KEYCODE_INVALID;
+ uint16 _lastKeyAscii = 0;
PelrockEventManager();
void pollEvent();
void waitForKey();
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 6b7c7c325cb..fda9b0e597c 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -156,6 +156,7 @@ void GraphicsManager::drawColoredText(Graphics::ManagedSurface *screen, const Co
if (text[i] == '@' && i + 1 < text.size()) {
// Draw accumulated segment
if (!segment.empty()) {
+ debug("Drawing text segment '%s' at %d, %d with color %d", segment.c_str(), currentX, y, defaultColor);
font->drawString(screen, segment, currentX, y, w, defaultColor);
currentX += font->getStringWidth(segment);
segment.clear();
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 6529c439525..a12263932a6 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -22,6 +22,7 @@
#include "common/config-manager.h"
#include "common/debug.h"
#include "common/file.h"
+#include "engines/metaengine.h"
#include "graphics/paletteman.h"
#include "graphics/thumbnail.h"
@@ -57,6 +58,19 @@ static const uint32 kMainMenuPart3Size = 92160;
// ALFRED.7 â menu buttons (save/load/sound/exit, one contiguous block)
static const uint32 kMenuButtonsOffset = 3193376;
+static const uint32 kQuestionMarkOffset = 3214046;
+static const uint32 kInvLeftArrowOffset = 3215906;
+static const uint32 kSoundControlOffset = 3037008;
+static const uint32 kSoundMasterOffset = 2662588;
+static const uint32 kSoundMusicOffset = 2664746;
+static const uint32 kSoundSfxOffset = 2667140;
+static const int kTransparentColor = 65;
+static const int kSoundControlsTransparentColor = 195;
+static const uint32 kCreditsBackgroundOffset = 3271454;
+static const int16 kTextStartX = 227;
+static const int16 kTextStartY = 191;
+static const byte kNumberColor = 52;
+
Pelrock::MenuManager::MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res, SoundManager *sound) : _screen(screen), _events(events), _res(res), _sound(sound) {
}
@@ -111,7 +125,6 @@ SoundMenuButton MenuManager::isSoundMenuButtonUnder(int x, int y) {
MainMenuButton MenuManager::isMainMenuButtonUnder(int x, int y) {
if (_menuState != MAIN_MENU) {
- debug("Not checking for main menu buttons because menu state is not MAIN_MENU");
return NO_MAIN_BUTTON;
}
@@ -199,10 +212,72 @@ bool MenuManager::checkMouseClick(int x, int y) {
break;
}
case ORIGINAL_SAVE: {
-
+ // Pagination arrows
+ if (_savesUp.contains(x, y)) {
+ if (_saveGamePage > 0) {
+ _saveGamePage--;
+ _editingSaveSlot = -1;
+ }
+ break;
+ }
+ if (_savesDown.contains(x, y)) {
+ if ((_saveGamePage + 1) * 8 < 256) {
+ _saveGamePage++;
+ _editingSaveSlot = -1;
+ }
+ break;
+ }
+ // CANCEL
+ if (_cancelarRect.contains(x, y)) {
+ _editingSaveSlot = -1;
+ _menuState = MAIN_MENU;
+ _menuText = _menuTexts[0];
+ break;
+ }
+ // Save slot click: begin (or switch) editing
+ for (int i = 0; i < (int)_saveSlotRects.size(); i++) {
+ if (_saveSlotRects[i].contains(x, y)) {
+ int slot = _saveGamePage * 8 + i;
+ _editingSaveSlot = slot;
+ _editingName = _saveDescriptions[slot];
+ break;
+ }
+ }
break;
}
case ORIGINAL_LOAD: {
+ // Pagination arrows
+ if (_savesUp.contains(x, y)) {
+ if (_saveGamePage > 0)
+ _saveGamePage--;
+ break;
+ }
+ if (_savesDown.contains(x, y)) {
+ if ((_saveGamePage + 1) * 8 < 256)
+ _saveGamePage++;
+ break;
+ }
+ // CANCELAR
+ if (_cancelarRect.contains(x, y)) {
+ _menuState = MAIN_MENU;
+ _menuText = _menuTexts[0];
+ break;
+ }
+ // Save slot click: load if slot has a save
+ for (int i = 0; i < (int)_saveSlotRects.size(); i++) {
+ if (_saveSlotRects[i].contains(x, y)) {
+ int slot = _saveGamePage * 8 + i;
+ if (!_saveDescriptions[slot].empty()) {
+ g_engine->loadGameState(slot);
+ return true;
+ }
+ else {
+ _menuState = MAIN_MENU;
+ _menuText = _menuTexts[6];
+ }
+ break;
+ }
+ }
break;
}
case EXIT_GAME: {
@@ -252,6 +327,9 @@ bool MenuManager::checkMainMenuMouse(int x, int y) {
case SAVE_GAME_BUTTON:
_sound->playSound("11ZZZZZZ.SMP", 0);
if (ConfMan.getBool("original_menus") == true) {
+ _saveGamePage = 0;
+ _editingSaveSlot = -1;
+ refreshSaveDescriptions();
_menuState = ORIGINAL_SAVE;
_menuText = Common::StringArray();
} else {
@@ -261,6 +339,8 @@ bool MenuManager::checkMainMenuMouse(int x, int y) {
case LOAD_GAME_BUTTON:
_sound->playSound("11ZZZZZZ.SMP", 0);
if (ConfMan.getBool("original_menus") == true) {
+ _saveGamePage = 0;
+ refreshSaveDescriptions();
_menuState = ORIGINAL_LOAD;
_menuText = Common::StringArray();
} else {
@@ -334,6 +414,29 @@ bool MenuManager::selectInventoryItem(int i) {
return true;
}
+void MenuManager::handleSaveMenuKey(Common::KeyCode key, uint16 ascii) {
+ if (key == Common::KEYCODE_ESCAPE) {
+ _editingSaveSlot = -1;
+ _menuState = MAIN_MENU;
+ _menuText = _menuTexts[0];
+ return;
+ }
+ if (_editingSaveSlot < 0)
+ return;
+
+ if (key == Common::KEYCODE_RETURN || key == Common::KEYCODE_KP_ENTER) {
+ // Commit save
+ g_engine->saveGameState(_editingSaveSlot, _editingName);
+ _saveDescriptions[_editingSaveSlot] = _editingName;
+ _editingSaveSlot = -1;
+ } else if (key == Common::KEYCODE_BACKSPACE) {
+ if (!_editingName.empty())
+ _editingName.deleteLastChar();
+ } else if (ascii >= 32 && ascii < 256 && ascii != 127) {
+ _editingName += (char)ascii;
+ }
+}
+
void MenuManager::menuLoop() {
// Save screenshot in case the user saves
@@ -372,16 +475,35 @@ void MenuManager::menuLoop() {
}
}
if (_events->_rightMouseClicked) {
- break;
- }
- if (_menuState == EXIT_GAME) {
- if (_events->_lastKeyEvent == Common::KEYCODE_s) {
- g_engine->quitGame();
- } else if (_events->_lastKeyEvent == Common::KEYCODE_n) {
- _menuState = MAIN_MENU;
- _menuText = _menuTexts[0];
+ _events->_rightMouseClicked = false;
+ // In original save/load sub-menus only CANCELAR / ESC can exit
+ if (_menuState != ORIGINAL_SAVE && _menuState != ORIGINAL_LOAD) {
+ break;
}
+ }
+
+ // Keyboard handling
+ if (_events->_lastKeyEvent != Common::KEYCODE_INVALID) {
+ Common::KeyCode key = _events->_lastKeyEvent;
+ uint16 ascii = _events->_lastKeyAscii;
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ _events->_lastKeyAscii = 0;
+
+ if (_menuState == ORIGINAL_SAVE) {
+ handleSaveMenuKey(key, ascii);
+ } else if (_menuState == ORIGINAL_LOAD) {
+ if (key == Common::KEYCODE_ESCAPE) {
+ _menuState = MAIN_MENU;
+ _menuText = _menuTexts[0];
+ }
+ } else if (_menuState == EXIT_GAME) {
+ if (key == Common::KEYCODE_s) {
+ g_engine->quitGame();
+ } else if (key == Common::KEYCODE_n) {
+ _menuState = MAIN_MENU;
+ _menuText = _menuTexts[0];
+ }
+ }
}
drawScreen();
@@ -412,7 +534,7 @@ void MenuManager::drawScreen() {
_screen->blitFrom(_compositeBuffer);
byte defaultColor = 255;
for (int i = 0; _menuText.size() > i; i++) {
- g_engine->_graphics->drawColoredText(_screen, _menuText[i], 230, 200 + (i * 10), 200, defaultColor, g_engine->_smallFont);
+ g_engine->_graphics->drawColoredText(_screen, _menuText[i], kTextStartX, kTextStartY + (i * _textLineH), 200, defaultColor, g_engine->_smallFont);
}
drawText(g_engine->_smallFont, Common::String::format("%d,%d", _events->_mouseX, _events->_mouseY), 0, 0, 640, 13);
@@ -526,6 +648,7 @@ void MenuManager::loadMenu() {
_menuText = _menuTexts[0];
alfred7.close();
+ _textLineH = g_engine->_smallFont->getFontHeight();
for (int i = 0; i < 4; i++) {
_inventorySlots.push_back(Common::Point(140 + (82 * i), 115 - (8 * i)));
}
@@ -569,8 +692,22 @@ void MenuManager::loadMenuTexts() {
byte *textBuffer = new byte[kMenuTextSize];
exe.seek(kMenuTextOffset, SEEK_SET);
exe.read(textBuffer, kMenuTextSize);
- _menuTexts = _res->processTextData(textBuffer, kMenuTextSize, true);
-
+ Common::Array<Common::StringArray> unprocessedMenuTexts;
+ unprocessedMenuTexts = _res->processTextData(textBuffer, kMenuTextSize, true);
+ _menuText = Common::StringArray();
+ for (int i = 0; i < (int)unprocessedMenuTexts.size(); i++) {
+ if (i == 1) {
+ Common::StringArray emptyText;
+ emptyText.push_back(unprocessedMenuTexts[i][0]);
+ Common::StringArray loadText;
+ loadText.push_back(unprocessedMenuTexts[i][1]);
+ _menuTexts.push_back(emptyText);
+ _menuTexts.push_back(loadText);
+ } else {
+ _menuTexts.push_back(unprocessedMenuTexts[i]);
+ }
+ }
+ debug("Menu texts size after processing: %d", (int)_menuTexts.size());
_menuText = _menuTexts[0];
delete[] textBuffer;
@@ -609,7 +746,74 @@ void MenuManager::drawConfirmation() {
_menuText = _menuTexts[4];
}
+void MenuManager::refreshSaveDescriptions() {
+ _saveDescriptions.clear();
+ _saveDescriptions.resize(256);
+
+ SaveStateList saves = g_engine->getMetaEngine()->listSaves(ConfMan.getActiveDomainName().c_str());
+ for (const SaveStateDescriptor &desc : saves) {
+ int slot = desc.getSaveSlot();
+ if (slot >= 0 && slot < 256)
+ _saveDescriptions[slot] = desc.getDescription();
+ }
+}
void MenuManager::drawSaves() {
+
+ // Compute the area for the overlay
+ const int startX = kTextStartX;
+ const int startY = kTextStartY;
+ const int overlayW = 216;
+ const int numSlots = 8;
+
+ // Headline: _menuTexts[1] = save, _menuTexts[2] = load
+ Common::StringArray headline;
+ if (_menuState == ORIGINAL_SAVE)
+ headline = _menuTexts[3];
+ else
+ headline = _menuTexts[2];
+ _menuText = headline;
+
+ _saveSlotRects.clear();
+
+ int y = startY + _textLineH;
+ const Common::Point mousePos(_events->_mouseX, _events->_mouseY);
+ for (int i = 0; i < numSlots; i++) {
+ int slot = _saveGamePage * numSlots + i;
+ Common::String slotText;
+ Common::String slotNumber = Common::String::format("%02d ", slot + 1);
+ int slotNumberWidth = g_engine->_smallFont->getStringWidth(slotNumber);
+
+ Common::Rect slotRect(startX - 2, y - 1, startX + overlayW - 2, y + _textLineH);
+ bool hovered = (_editingSaveSlot != slot) && slotRect.contains(mousePos);
+ byte textColor = hovered ? 18 : 0x0F;
+
+ if (_editingSaveSlot == slot) {
+ // Show editing cursor
+ slotText = Common::String::format("%s_", _editingName.c_str());
+ textColor = 244; // highlight colour for active editing
+ // Light highlight behind the editing row
+ _compositeBuffer.fillRect(Common::Rect(startX - 2, y - 1, startX + overlayW - 2, y + _textLineH), 1);
+ } else {
+ const Common::String &desc = _saveDescriptions[slot];
+ if (desc.empty())
+ slotText = Common::String::format("%s", _menuTexts[1][0].c_str());
+ else {
+ slotText = desc;
+ slotText.toUppercase();
+ }
+ }
+ drawText(_compositeBuffer, g_engine->_smallFont, slotNumber, startX, y, overlayW, kNumberColor);
+ drawText(_compositeBuffer, g_engine->_smallFont, slotText, startX + slotNumberWidth, y, overlayW - slotNumberWidth, textColor);
+
+ _saveSlotRects.push_back(slotRect);
+ y += _textLineH;
+ }
+
+ // CANCEL row
+ _cancelarRect = Common::Rect(startX - 2, y - 1, startX + overlayW - 2, y + _textLineH);
+ byte cancelColor = _cancelarRect.contains(mousePos) ? 18 : 0x0F;
+ Common::String cancelText = _menuTexts[4][0].substr(2, _menuTexts[4][0].size() - 2);
+ drawText(_compositeBuffer, g_engine->_smallFont, cancelText, startX, y, overlayW, cancelColor);
}
void MenuManager::drawMainButtons() {
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 731451cacb1..a5acd16d8b5 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -31,16 +31,6 @@
namespace Pelrock {
-const uint32 kQuestionMarkOffset = 3214046;
-const uint32 kInvLeftArrowOffset = 3215906;
-const uint32 kSoundControlOffset = 3037008;
-const uint32 kSoundMasterOffset = 2662588;
-const uint32 kSoundMusicOffset = 2664746;
-const uint32 kSoundSfxOffset = 2667140;
-const int kTransparentColor = 65;
-const int kSoundControlsTransparentColor = 195;
-const uint32 kCreditsBackgroundOffset = 3271454;
-
enum MainMenuButton {
QUESTION_MARK_BUTTON,
INVENTORY_PREV_BUTTON,
@@ -241,7 +231,7 @@ public:
private:
void checkMouseDown(int x, int y);
bool checkMouseClick(int x, int y);
-void checkSoundMenuClick(int x, int y);
+ void checkSoundMenuClick(int x, int y);
bool checkMainMenuMouse(int x, int y, bool &retFlag);
bool checkMainMenuMouse(int x, int y); // returns bool if its supposed to close the menu
void showCredits();
@@ -255,6 +245,8 @@ void checkSoundMenuClick(int x, int y);
void drawSoundControls();
void readButton(byte *rawData, uint32 offset, byte *outBuffer[2], int w, int h);
void readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect);
+ void refreshSaveDescriptions();
+ void handleSaveMenuKey(Common::KeyCode key, uint16 ascii);
SoundMenuButton isSoundMenuButtonUnder(int x, int y);
MainMenuButton isMainMenuButtonUnder(int x, int y);
Graphics::Screen *_screen = nullptr;
@@ -326,6 +318,15 @@ void checkSoundMenuClick(int x, int y);
bool showButtons = true;
MenuState _menuState = MAIN_MENU;
+ int _textLineH = 0;
+
+ // Save/Load sub-menu state
+ int _saveGamePage = 0;
+ int _editingSaveSlot = -1; // -1 = not editing any slot
+ Common::String _editingName; // name being typed for a save
+ Common::Rect _cancelarRect; // hit-rect for the CANCELAR row
+ Common::Array<Common::Rect> _saveSlotRects; // hit-rects for the 8 visible save rows
+ Common::StringArray _saveDescriptions; // indexed by slot 0-255
};
} // End of namespace Pelrock
Commit: 7f8b1610880145aa92e32f8b57e831ca4f8816d4
https://github.com/scummvm/scummvm/commit/7f8b1610880145aa92e32f8b57e831ca4f8816d4
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:34+02:00
Commit Message:
PELROCK: Missing actions
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 6c4e09bb0f3..b5622e1653e 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -305,6 +305,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(4, 2, 0);
break;
case 259:
+ _dialog->say(_res->_ingameTexts[DEPIEDRANO_DEHIELO], 1);
_dialog->say(_res->_ingameTexts[NO_EMPECEMOS]);
break;
case 260:
@@ -870,10 +871,14 @@ void PelrockEngine::closeKitchenDoor(HotSpot *HotSpot) {
void PelrockEngine::openKitchenDrawer(HotSpot *hotspot) {
if (!_state->getFlag(FLAG_JEFE_ENCARCELADO)) {
_dialog->say(_res->_ingameTexts[QUITA_ESAS_MANOS]);
- } else {
+ } else if (!_state->getFlag(FLAG_RECIPE_TAKEN)) {
+ _state->setFlag(FLAG_RECIPE_TAKEN, true);
_room->addSticker(36);
addInventoryItem(63); // Add recipe
_dialog->say(_res->_ingameTexts[QUESESTO_RECETA]);
+ } else {
+ // Already took the recipe
+ _dialog->say(_res->_ingameTexts[YAESTA_ABIERTO]);
}
}
@@ -1252,10 +1257,15 @@ void PelrockEngine::waitForSoundEnd(int channel) {
void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
if (_state->getFlag(FLAG_PARADOJA_RESUELTA) == false) {
- _dialog->say(_res->_ingameTexts[OIGA]);
- _state->setCurrentRoot(25, 26, 0);
- walkAndAction(_room->findHotspotByExtra(467), TALK);
- _state->setFlag(FLAG_RIDDLE_PRESENTED, true);
+ if (_state->getFlag(FLAG_RIDDLE_PRESENTED)) {
+ // try to take the sunflower before solving the riddle
+ _dialog->say(_res->_ingameTexts[LEESTOYVIGILANDO]);
+ } else {
+ _dialog->say(_res->_ingameTexts[OIGA]);
+ _state->setCurrentRoot(25, 26, 0);
+ walkAndAction(_room->findHotspotByExtra(467), TALK);
+ _state->setFlag(FLAG_RIDDLE_PRESENTED, true);
+ }
} else {
addInventoryItem(85);
_room->disableHotspot(hotspot);
@@ -2087,6 +2097,11 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
}
break;
case 88: {
+ if (_room->_currentRoomNumber != 28 &&
+ (_room->_currentRoomNumber < 51 || _room->_currentRoomNumber > 54)) {
+ _dialog->say(_res->_ingameTexts[AQUI_NO_NECESITO]);
+ break;
+ }
SpellBook spellBook(_events, _res);
playAlfredSpecialAnim(0);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index b500b39d5ff..7bc1d91b7dd 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -558,8 +558,9 @@ struct ResetEntry {
#define FLAG_HA_USADO_AGUA 45
#define FLAG_NUMERO_DE_COPAS 47
#define FLAG_PIGEON_DEAD 61
+#define FLAG_RECIPE_TAKEN 62
-const int kNumGameFlags = 62;
+const int kNumGameFlags = 63;
struct GameStateData {
byte flags[kNumGameFlags];
Commit: 995444994280b95a83e813910dfc90cdce4ef5a3
https://github.com/scummvm/scummvm/commit/995444994280b95a83e813910dfc90cdce4ef5a3
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:35+02:00
Commit Message:
PELROCK: Fixes conversation bug (present in the original) in room 45
Changed paths:
engines/pelrock/dialog.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 11935299f1a..f8d6c5f8647 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -806,6 +806,18 @@ ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint
byte controlByte = data[position];
if (controlByte == CTRL_END_CONVERSATION) {
+ // Bug in the original in room 45, root 1: The conversation data has F4 (END_CONV) after
+ // the opening NPC text instead of FD (END_TEXT), so the 3 choices that follow are
+ // unreachable. Treat F4 as FD specifically for this root to restore them.
+ int room = g_engine->_room->_currentRoomNumber;
+ uint32 peekPos = position + 1;
+ if (room == 45 && currentRoot == 1 &&
+ peekPos < dataSize &&
+ (data[peekPos] == kCtrlDialogueMarker || data[peekPos] == kCtrlDialogueMarkerOneoff)) {
+ debug("Room 45 Root 1: F4 followed by choice marker treated as FD (data bug workaround)");
+ result.nextPosition = position + 1;
+ return result;
+ }
debug("End of conversation marker found");
result.shouldEnd = true;
return result;
Commit: e35f47c289a887d7277065a7678cc2d9d6b149d3
https://github.com/scummvm/scummvm/commit/e35f47c289a887d7277065a7678cc2d9d6b149d3
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:35+02:00
Commit Message:
PELROCK: Fixes exit confirmation
Changed paths:
engines/pelrock/menu.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index a12263932a6..bea1eca54ec 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -350,7 +350,6 @@ bool MenuManager::checkMainMenuMouse(int x, int y) {
case EXIT_MENU_BUTTON:
_sound->playSound("11ZZZZZZ.SMP", 0);
_menuState = EXIT_GAME;
- // g_engine->quitGame();
break;
case SOUNDS_BUTTON:
_sound->playSound("11ZZZZZZ.SMP", 0);
@@ -743,7 +742,7 @@ void MenuManager::drawButtons() {
}
void MenuManager::drawConfirmation() {
- _menuText = _menuTexts[4];
+ _menuText = _menuTexts[5];
}
void MenuManager::refreshSaveDescriptions() {
Commit: 5708dae5d5b69ad2abf574c2b73ad3388ededa4d
https://github.com/scummvm/scummvm/commit/5708dae5d5b69ad2abf574c2b73ad3388ededa4d
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:35+02:00
Commit Message:
PELROCK: Fixes styling of saving name input
Changed paths:
engines/pelrock/menu.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index bea1eca54ec..130f1ef06bd 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -70,6 +70,8 @@ static const uint32 kCreditsBackgroundOffset = 3271454;
static const int16 kTextStartX = 227;
static const int16 kTextStartY = 191;
static const byte kNumberColor = 52;
+static const byte kCursorChar = 0xDB;
+static const byte kWhiteColor = 0x0F;
Pelrock::MenuManager::MenuManager(Graphics::Screen *screen, PelrockEventManager *events, ResourceManager *res, SoundManager *sound) : _screen(screen), _events(events), _res(res), _sound(sound) {
}
@@ -784,14 +786,13 @@ void MenuManager::drawSaves() {
Common::Rect slotRect(startX - 2, y - 1, startX + overlayW - 2, y + _textLineH);
bool hovered = (_editingSaveSlot != slot) && slotRect.contains(mousePos);
- byte textColor = hovered ? 18 : 0x0F;
+ byte textColor = hovered ? 18 : kWhiteColor;
if (_editingSaveSlot == slot) {
// Show editing cursor
- slotText = Common::String::format("%s_", _editingName.c_str());
- textColor = 244; // highlight colour for active editing
- // Light highlight behind the editing row
- _compositeBuffer.fillRect(Common::Rect(startX - 2, y - 1, startX + overlayW - 2, y + _textLineH), 1);
+ _editingName.toUppercase();
+ slotText = _editingName;
+ textColor = 18; // highlight colour for active editing
} else {
const Common::String &desc = _saveDescriptions[slot];
if (desc.empty())
@@ -804,13 +805,19 @@ void MenuManager::drawSaves() {
drawText(_compositeBuffer, g_engine->_smallFont, slotNumber, startX, y, overlayW, kNumberColor);
drawText(_compositeBuffer, g_engine->_smallFont, slotText, startX + slotNumberWidth, y, overlayW - slotNumberWidth, textColor);
+ if(_editingSaveSlot == slot) {
+ // Draw cursor
+ int cursorX = startX + slotNumberWidth + g_engine->_smallFont->getStringWidth(slotText);
+ drawText(_compositeBuffer, g_engine->_smallFont, Common::String(kCursorChar), cursorX, y, overlayW - (cursorX - startX), kWhiteColor);
+ }
+
_saveSlotRects.push_back(slotRect);
y += _textLineH;
}
// CANCEL row
_cancelarRect = Common::Rect(startX - 2, y - 1, startX + overlayW - 2, y + _textLineH);
- byte cancelColor = _cancelarRect.contains(mousePos) ? 18 : 0x0F;
+ byte cancelColor = _cancelarRect.contains(mousePos) ? 18 : kWhiteColor;
Common::String cancelText = _menuTexts[4][0].substr(2, _menuTexts[4][0].size() - 2);
drawText(_compositeBuffer, g_engine->_smallFont, cancelText, startX, y, overlayW, cancelColor);
}
Commit: 2b1bcc34dc9bf0134b3b184d4097f4eaf88529f8
https://github.com/scummvm/scummvm/commit/2b1bcc34dc9bf0134b3b184d4097f4eaf88529f8
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:35+02:00
Commit Message:
PELROCK: Fixes spells in spellbook having extraneous characters
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 6ac79b31174..df3a285d515 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -912,7 +912,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
// Scale special anim frame to Alfred size before drawing
drawSpriteToBuffer(_compositeBuffer, frame, _alfredState.x, _alfredState.y - _res->_currentSpecialAnim->h, _res->_currentSpecialAnim->w, _res->_currentSpecialAnim->h, 255);
}
- debug("Playing special anim frame %d/%d, speed %d", _res->_currentSpecialAnim->curFrame, _res->_currentSpecialAnim->numFrames, _res->_currentSpecialAnim->speed);
if (_chrono->getFrameCount() % _res->_currentSpecialAnim->speed == 0) {
_res->_currentSpecialAnim->curFrame++;
@@ -1511,7 +1510,6 @@ void PelrockEngine::gameLoop() {
}
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
}
-
if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_k) {
_events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
credits();
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index ec51bd361fb..99fdb4cd677 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -36,45 +36,45 @@ static const uint32 ALFRED7_ALFRED_COMB_R = 67768;
static const uint32 ALFRED7_ALFRED_COMB_L = 88408;
// ALFRED.4 â inventory icon pixel data
-static const uint32 kInventoryIconsOffset = 42366;
+static const uint32 kInventoryIconsOffset = 42366;
static const uint32 kInventoryIconsTailSize = 423656; // bytes trailing the icon block
// ALFRED.7 â action-popup balloon frames
static const uint32 kBalloonFramesOffset = 2176936;
-static const uint32 kBalloonFramesSize = 24950; // compressed size
+static const uint32 kBalloonFramesSize = 24950; // compressed size
// JUEGO.EXE â Alfred in-game text responses
-static const uint32 kAlfredResponsesOffset = 0x441DC;
-static const uint32 kAlfredResponsesSize = 12143;
+static const uint32 kAlfredResponsesOffset = 0x441DC;
+static const uint32 kAlfredResponsesSize = 12143;
static const uint32 kConversationTerminatorOffset = 0x0492EE;
// JUEGO.EXE â credits
static const uint32 kCreditsOffset = 0x49F60;
-static const uint32 kCreditsSize = 2540;
+static const uint32 kCreditsSize = 2540;
// JUEGO.EXE â computer-screen text
static const uint32 kComputerTextOffset = 0x0004901A;
-static const uint32 kComputerTextSize = 490;
+static const uint32 kComputerTextSize = 490;
// Alfred special animation data (file index given per entry in alfredSpecialAnims[])
-static const uint32 kAlfredAnimReadBookOffset = 559685; // 0 - READ BOOK
-static const uint32 kAlfredAnimReadRecipeOffset = 578943; // 1 - READ RECIPE
-static const uint32 kAlfredAnimElectricShock1Offset = 37000; // 2 - ELECTRIC SHOCK 1
-static const uint32 kAlfredAnimElectricShock3Offset = 53106; // 3 - ELECTRIC SHOCK 3
-static const uint32 kAlfredAnimThrowOffset = 20724; // 4 - Throw
-static const uint32 kAlfredAnimThrowSize = 62480; // 4 - Throw explicit size
-static const uint32 kAlfredAnimCrocodileOffset = 1556540; // 5 - Crocodile
-static const uint32 kAlfredAnimManholeOffset = 1583702; // 6 - Exit manhole
-static const uint32 kAlfredAnimClimbDownOffset = 1761234; // 7 - Climbs down
-static const uint32 kAlfredAnimClimbUpOffset = 1766378; // 8 - Climbs up
-static const uint32 kAlfredAnimExitTunnelOffset = 1770196; // 9 - Exits tunnel
-static const uint32 kAlfredAnimWorkersOffset = 1600956; // 10 - With workers
-static const uint32 kAlfredAnimMunheco1Offset = 2060916; // 11 - Munheco 1
-static const uint32 kAlfredAnimMunheco2Offset = 2115632; // 12 - Munheco 2
-static const uint32 kAlfredAnimMunheco3Offset = 1526432; // 13 - Munheco 3
-static const uint32 kAlfredAnimDescamisaOffset = 2972568; // 14 - Descamisa
-static const uint32 kAlfredAnimSecretPassageOffset = 1749464; // 15 - Secret passage
-static const uint32 kAlfredAnimInBedOffset = 3038454; // 16 - Alfred in bed
+static const uint32 kAlfredAnimReadBookOffset = 559685; // 0 - READ BOOK
+static const uint32 kAlfredAnimReadRecipeOffset = 578943; // 1 - READ RECIPE
+static const uint32 kAlfredAnimElectricShock1Offset = 37000; // 2 - ELECTRIC SHOCK 1
+static const uint32 kAlfredAnimElectricShock3Offset = 53106; // 3 - ELECTRIC SHOCK 3
+static const uint32 kAlfredAnimThrowOffset = 20724; // 4 - Throw
+static const uint32 kAlfredAnimThrowSize = 62480; // 4 - Throw explicit size
+static const uint32 kAlfredAnimCrocodileOffset = 1556540; // 5 - Crocodile
+static const uint32 kAlfredAnimManholeOffset = 1583702; // 6 - Exit manhole
+static const uint32 kAlfredAnimClimbDownOffset = 1761234; // 7 - Climbs down
+static const uint32 kAlfredAnimClimbUpOffset = 1766378; // 8 - Climbs up
+static const uint32 kAlfredAnimExitTunnelOffset = 1770196; // 9 - Exits tunnel
+static const uint32 kAlfredAnimWorkersOffset = 1600956; // 10 - With workers
+static const uint32 kAlfredAnimMunheco1Offset = 2060916; // 11 - Munheco 1
+static const uint32 kAlfredAnimMunheco2Offset = 2115632; // 12 - Munheco 2
+static const uint32 kAlfredAnimMunheco3Offset = 1526432; // 13 - Munheco 3
+static const uint32 kAlfredAnimDescamisaOffset = 2972568; // 14 - Descamisa
+static const uint32 kAlfredAnimSecretPassageOffset = 1749464; // 15 - Secret passage
+static const uint32 kAlfredAnimInBedOffset = 3038454; // 16 - Alfred in bed
ResourceManager::ResourceManager(/* args */) {
_inventoryIcons = new InventoryObject[69];
@@ -84,23 +84,23 @@ ResourceManager::ResourceManager(/* args */) {
}
const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
- {10, 51, 102, 1, 7, kAlfredAnimReadBookOffset, 1, 2, 0}, // 0 - READ BOOK
- {10, 51, 102, 1, 7, kAlfredAnimReadRecipeOffset, 1, 2, 0}, // 1 - READ RECIPE
- { 3, 45, 87, 0, 7, kAlfredAnimElectricShock1Offset, 1, 2, 0}, // 2 - ELECTRIC SHOCK 1
- { 2, 82, 58, 0, 7, kAlfredAnimElectricShock3Offset, 20, 1, 0}, // 3 - ELECTRIC SHOCK 3
- { 3, 71, 110, 1, 2, kAlfredAnimThrowOffset, 1, 1, kAlfredAnimThrowSize}, // 4 - Throw
- {14, 171, 107, 1, 7, kAlfredAnimCrocodileOffset, 1, 2, 0}, // 5 - crocodile
- {12, 113, 103, 1, 7, kAlfredAnimManholeOffset, 1, 2, 0}, // 6 - exit through manhole
- {11, 33, 72, 1, 7, kAlfredAnimClimbDownOffset, 1, 2, 0}, // 7 - alfred climbs down
- { 9, 33, 72, 1, 7, kAlfredAnimClimbUpOffset, 1, 2, 0}, // 8 - alfred climbs up
- {16, 158, 115, 0, 7, kAlfredAnimExitTunnelOffset, 1, 2, 0}, // 9 - alfred exits tunnel
- { 7, 208, 102, 0, 7, kAlfredAnimWorkersOffset, 1, 2, 0}, // 10 - alfred with workers
- {23, 116, 124, 1, 7, kAlfredAnimMunheco1Offset, 1, 2, 0}, // 11 - Munheco 1
- {18, 177, 124, 1, 7, kAlfredAnimMunheco2Offset, 1, 2, 0}, // 12 - Munheco 2
- {11, 98, 138, 1, 7, kAlfredAnimMunheco3Offset, 1, 2, 0}, // 13 - Munheco 3
- { 4, 51, 102, 1, 7, kAlfredAnimDescamisaOffset, 1, 2, 0}, // 14 - descamisa
- {13, 95, 99, 1, 7, kAlfredAnimSecretPassageOffset, 1, 2, 0}, // 15 - alfred enters secret passage
- {14, 71, 66, 1, 7, kAlfredAnimInBedOffset, 1, 2, 0}, // 16 - Alfred in bed
+ {10, 51, 102, 1, 7, kAlfredAnimReadBookOffset, 1, 2, 0}, // 0 - READ BOOK
+ {10, 51, 102, 1, 7, kAlfredAnimReadRecipeOffset, 1, 2, 0}, // 1 - READ RECIPE
+ {3, 45, 87, 0, 7, kAlfredAnimElectricShock1Offset, 1, 2, 0}, // 2 - ELECTRIC SHOCK 1
+ {2, 82, 58, 0, 7, kAlfredAnimElectricShock3Offset, 20, 1, 0}, // 3 - ELECTRIC SHOCK 3
+ {3, 71, 110, 1, 2, kAlfredAnimThrowOffset, 1, 1, kAlfredAnimThrowSize}, // 4 - Throw
+ {14, 171, 107, 1, 7, kAlfredAnimCrocodileOffset, 1, 2, 0}, // 5 - crocodile
+ {12, 113, 103, 1, 7, kAlfredAnimManholeOffset, 1, 2, 0}, // 6 - exit through manhole
+ {11, 33, 72, 1, 7, kAlfredAnimClimbDownOffset, 1, 2, 0}, // 7 - alfred climbs down
+ {9, 33, 72, 1, 7, kAlfredAnimClimbUpOffset, 1, 2, 0}, // 8 - alfred climbs up
+ {16, 158, 115, 0, 7, kAlfredAnimExitTunnelOffset, 1, 2, 0}, // 9 - alfred exits tunnel
+ {7, 208, 102, 0, 7, kAlfredAnimWorkersOffset, 1, 2, 0}, // 10 - alfred with workers
+ {23, 116, 124, 1, 7, kAlfredAnimMunheco1Offset, 1, 2, 0}, // 11 - Munheco 1
+ {18, 177, 124, 1, 7, kAlfredAnimMunheco2Offset, 1, 2, 0}, // 12 - Munheco 2
+ {11, 98, 138, 1, 7, kAlfredAnimMunheco3Offset, 1, 2, 0}, // 13 - Munheco 3
+ {4, 51, 102, 1, 7, kAlfredAnimDescamisaOffset, 1, 2, 0}, // 14 - descamisa
+ {13, 95, 99, 1, 7, kAlfredAnimSecretPassageOffset, 1, 2, 0}, // 15 - alfred enters secret passage
+ {14, 71, 66, 1, 7, kAlfredAnimInBedOffset, 1, 2, 0}, // 16 - Alfred in bed
};
ResourceManager::~ResourceManager() {
@@ -273,7 +273,6 @@ void ResourceManager::loadAlfredAnims() {
delete[] completePic;
free(bufferFile);
-
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
error("Could not open ALFRED.7");
@@ -458,7 +457,7 @@ Common::Array<Common::StringArray> ResourceManager::loadComputerText() {
exe.read(computerTextBuf, bufSize);
Common::Array<Common::StringArray> computerTexts = processTextData(computerTextBuf, bufSize);
- for(int i = 0; i < computerTexts.size(); i++) {
+ for (int i = 0; i < computerTexts.size(); i++) {
debug("Computer text %d:", i);
Common::StringArray &lines = computerTexts[i];
for (int j = 0; j < lines.size(); j++) {
@@ -508,10 +507,10 @@ Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data,
Common::Array<Common::StringArray> texts;
while (pos < size) {
if (data[pos] == CTRL_END_TEXT) {
- lines.push_back(desc);
- texts.push_back(lines);
- lines.clear();
- desc = Common::String();
+ lines.push_back(desc);
+ texts.push_back(lines);
+ lines.clear();
+ desc = Common::String();
pos++;
continue;
}
@@ -525,12 +524,15 @@ Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data,
desc.append(1, '@');
desc.append(1, color);
pos += 2;
+ if (data[pos + 1] == 0x78 || data[pos + 2] == 0x78) {
+ pos += 2;
+ }
continue;
}
if (data[pos] == 0xC8 || data[pos] == 0xB1) {
- if(!desc.empty() || data[pos] == 0xC8) {
+ if (!desc.empty() || data[pos] == 0xC8) {
lines.push_back(desc);
}
desc = Common::String();
Commit: 9ede09dccf2b8d8eae6d25236317d2f80ddb1bae
https://github.com/scummvm/scummvm/commit/9ede09dccf2b8d8eae6d25236317d2f80ddb1bae
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:36+02:00
Commit Message:
PELROCK: Amend checkConversation signature
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index f8d6c5f8647..d13f0df33fc 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -572,7 +572,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
if (!skipToChoices) {
- ConversationEndResult endResult = checkConversationEnd(conversationData, dataSize, state.position);
+ ConversationEndResult endResult = checkConversationEnd(conversationData, dataSize, state.position, state.currentRoot);
// Dispatch action for both 0xF8 (action+end) and 0xEB (action+continue)
if (endResult.hasAction) {
g_engine->dialogActionTrigger(endResult.actionCode, g_engine->_room->_currentRoomNumber, state.currentRoot);
@@ -790,7 +790,7 @@ uint32 DialogManager::readAndDisplayDialogue(const byte *data, uint32 dataSize,
return endPos;
}
-ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint32 dataSize, uint32 position) {
+ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint32 dataSize, uint32 position, int currentRoot) {
ConversationEndResult result;
result.shouldEnd = false;
result.nextPosition = position;
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index b021f149630..a808b763c70 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -109,7 +109,7 @@ private:
ConversationState initializeConversation(const byte *data, uint32 dataSize, byte npcIndex);
bool handleGoBack(const byte *data, Common::Stack<uint32> &positionStack, uint32 position, ConversationState &state);
uint32 readAndDisplayDialogue(const byte *data, uint32 dataSize, uint32 position);
- ConversationEndResult checkConversationEnd(const byte *data, uint32 dataSize, uint32 position);
+ ConversationEndResult checkConversationEnd(const byte *data, uint32 dataSize, uint32 position, int currentRoot = -1);
void addGoodbyeOptionIfNeeded(Common::Array<ChoiceOption> *choices, int currentChoiceLevel, uint originalChoiceCount);
uint32 processChoiceSelection(const byte *data, uint32 dataSize, Common::Array<ChoiceOption> *choices, int selectedIndex, ConversationState &state);
void disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> *choices, int selectedIndex, const byte *data, uint32 dataSize, uint32 endPos, Pelrock::ConversationState &state);
Commit: 6b269d220332ec5c47497e3be3122e4e8f0d5b43
https://github.com/scummvm/scummvm/commit/6b269d220332ec5c47497e3be3122e4e8f0d5b43
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:36+02:00
Commit Message:
PELROCK: Fixes bug (present in the original) when handing books to librarian or using them on alfred
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/menu.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index b5622e1653e..056edc609d1 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -740,7 +740,8 @@ void PelrockEngine::noOpAction(HotSpot *hotspot) {
}
void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
- if (item >= 11 && item <= 47 && hotspot->extra == 358) {
+ // Original game checked against 47 instead of 58
+ if (item >= 11 && item <= 58 && hotspot->extra == 358) {
_state->removeInventoryItem(item);
_dialog->say(_res->_ingameTexts[DEACUERDO_2]);
return;
@@ -2237,12 +2238,12 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
}
default: {
- if (inventoryObject >= 11 && inventoryObject <= 47) {
+ // Original game incorrectly checked until object 47
+ if (inventoryObject >= 11 && inventoryObject <= 58) {
playAlfredSpecialAnim(0);
_dialog->say(_res->_ingameTexts[LIBRO_ABURRIDO]);
return;
}
-
sayRandomIncorrectResponse();
break;
}
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 130f1ef06bd..42c8dd6ca58 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -308,7 +308,18 @@ void MenuManager::checkSoundMenuClick(int x, int y) {
}
bool MenuManager::checkMainMenuMouse(int x, int y) {
- debug("Checking main menu buttons");
+
+ // Inventory items
+ bool selectedItem = false;
+ for (int i = 0; i < 4; i++) {
+ Common::Rect itemRect = Common::Rect(_inventorySlots[i], 60, 60);
+ if (itemRect.contains(x, y)) {
+ selectedItem = selectInventoryItem(i);
+ return false;
+ }
+ }
+
+ // Buttons
MainMenuButton mainMenuButton = isMainMenuButtonUnder(x, y);
switch (mainMenuButton) {
case QUESTION_MARK_BUTTON:
Commit: b74947e4da36ec038190858f308fb62f9fb6c994
https://github.com/scummvm/scummvm/commit/b74947e4da36ec038190858f308fb62f9fb6c994
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:36+02:00
Commit Message:
PELROCK: Allows loading from ScummVM's main menu
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 42c8dd6ca58..90ae2ff581d 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -202,7 +202,6 @@ void MenuManager::checkMouseDown(int x, int y) {
}
bool MenuManager::checkMouseClick(int x, int y) {
- debug("Checking mouse click at %d, %d, with menu state %d", x, y, _menuState);
switch (_menuState) {
case MAIN_MENU: {
@@ -232,8 +231,7 @@ bool MenuManager::checkMouseClick(int x, int y) {
// CANCEL
if (_cancelarRect.contains(x, y)) {
_editingSaveSlot = -1;
- _menuState = MAIN_MENU;
- _menuText = _menuTexts[0];
+ backToMainMenu();
break;
}
// Save slot click: begin (or switch) editing
@@ -261,8 +259,7 @@ bool MenuManager::checkMouseClick(int x, int y) {
}
// CANCELAR
if (_cancelarRect.contains(x, y)) {
- _menuState = MAIN_MENU;
- _menuText = _menuTexts[0];
+ backToMainMenu();
break;
}
// Save slot click: load if slot has a save
@@ -271,6 +268,7 @@ bool MenuManager::checkMouseClick(int x, int y) {
int slot = _saveGamePage * 8 + i;
if (!_saveDescriptions[slot].empty()) {
g_engine->loadGameState(slot);
+ backToMainMenu();
return true;
}
else {
@@ -298,8 +296,8 @@ void MenuManager::checkSoundMenuClick(int x, int y) {
soundMenuButton != SFX_RIGHT_BUTTON &&
soundMenuButton != MASTER_LEFT_BUTTON &&
soundMenuButton != MASTER_RIGHT_BUTTON) {
- _menuState = MAIN_MENU;
- _menuText = _menuTexts[0];
+ backToMainMenu();
+ return;
}
if (soundMenuButton == SFX_LEFT_BUTTON || soundMenuButton == SFX_RIGHT_BUTTON) {
@@ -429,8 +427,7 @@ bool MenuManager::selectInventoryItem(int i) {
void MenuManager::handleSaveMenuKey(Common::KeyCode key, uint16 ascii) {
if (key == Common::KEYCODE_ESCAPE) {
_editingSaveSlot = -1;
- _menuState = MAIN_MENU;
- _menuText = _menuTexts[0];
+ backToMainMenu();
return;
}
if (_editingSaveSlot < 0)
@@ -441,6 +438,7 @@ void MenuManager::handleSaveMenuKey(Common::KeyCode key, uint16 ascii) {
g_engine->saveGameState(_editingSaveSlot, _editingName);
_saveDescriptions[_editingSaveSlot] = _editingName;
_editingSaveSlot = -1;
+ backToMainMenu();
} else if (key == Common::KEYCODE_BACKSPACE) {
if (!_editingName.empty())
_editingName.deleteLastChar();
@@ -449,6 +447,11 @@ void MenuManager::handleSaveMenuKey(Common::KeyCode key, uint16 ascii) {
}
}
+void MenuManager::backToMainMenu() {
+ _menuState = MAIN_MENU;
+ _menuText = _menuTexts[0];
+}
+
void MenuManager::menuLoop() {
// Save screenshot in case the user saves
@@ -457,8 +460,7 @@ void MenuManager::menuLoop() {
g_system->getPaletteManager()->setPalette(_mainMenuPalette, 0, 256);
g_engine->changeCursor(DEFAULT);
- _menuState = MAIN_MENU;
- _menuText = _menuTexts[0];
+ backToMainMenu();
// Initialize volume levels from current settings
_sfxVolumeLevel = mixerVolumeToLevel(_sound->getVolumeSfx());
@@ -505,15 +507,13 @@ void MenuManager::menuLoop() {
handleSaveMenuKey(key, ascii);
} else if (_menuState == ORIGINAL_LOAD) {
if (key == Common::KEYCODE_ESCAPE) {
- _menuState = MAIN_MENU;
- _menuText = _menuTexts[0];
+ backToMainMenu();
}
} else if (_menuState == EXIT_GAME) {
if (key == Common::KEYCODE_s) {
g_engine->quitGame();
} else if (key == Common::KEYCODE_n) {
- _menuState = MAIN_MENU;
- _menuText = _menuTexts[0];
+ backToMainMenu();
}
}
}
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index a5acd16d8b5..15293a1157c 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -247,6 +247,7 @@ private:
void readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect);
void refreshSaveDescriptions();
void handleSaveMenuKey(Common::KeyCode key, uint16 ascii);
+void backToMainMenu();
SoundMenuButton isSoundMenuButtonUnder(int x, int y);
MainMenuButton isMainMenuButtonUnder(int x, int y);
Graphics::Screen *_screen = nullptr;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index df3a285d515..f16b6fcdeff 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -120,14 +120,15 @@ Common::Error PelrockEngine::run() {
// Set the engine's debugger console
setDebugger(new PelrockConsole(this));
+ _state->stateGame = shouldPlayIntro ? INTRO : GAME;
+
+ init();
+
// If a savegame was selected from the launcher, load it
int saveSlot = ConfMan.getInt("save_slot");
if (saveSlot != -1)
(void)loadGameState(saveSlot);
- _state->stateGame = shouldPlayIntro ? INTRO : GAME;
-
- init();
while (!shouldQuit()) {
if (_state->stateGame == SETTINGS) {
_graphics->clearScreen();
Commit: a5964bf279872fc0c33f92ba516d5e22c86e9ae0
https://github.com/scummvm/scummvm/commit/a5964bf279872fc0c33f92ba516d5e22c86e9ae0
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:37+02:00
Commit Message:
PELROCK: Fixes extraneous characters on intro's subtitles
Changed paths:
engines/pelrock/detection.h
engines/pelrock/detection_tables.h
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/metaengine.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/video/video.cpp
diff --git a/engines/pelrock/detection.h b/engines/pelrock/detection.h
index b66e27e9a5c..921919f14e9 100644
--- a/engines/pelrock/detection.h
+++ b/engines/pelrock/detection.h
@@ -40,6 +40,7 @@ extern const ADGameDescription gameDescriptions[];
#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
#define GAMEOPTION_ALTERNATE_TIMING GUIO_GAMEOPTIONS2
+#define GAMEOPTION_PLAY_INTRO GUIO_GAMEOPTIONS3
} // End of namespace Pelrock
diff --git a/engines/pelrock/detection_tables.h b/engines/pelrock/detection_tables.h
index 79c0987d677..57be38649ae 100644
--- a/engines/pelrock/detection_tables.h
+++ b/engines/pelrock/detection_tables.h
@@ -34,7 +34,7 @@ const ADGameDescription gameDescriptions[] = {
Common::ES_ESP,
Common::kPlatformDOS,
ADGF_UNSTABLE,
- GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_ALTERNATE_TIMING)
+ GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_ALTERNATE_TIMING, GAMEOPTION_PLAY_INTRO)
},
AD_TABLE_END_MARKER
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 90ae2ff581d..af9af7135bc 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -308,11 +308,11 @@ void MenuManager::checkSoundMenuClick(int x, int y) {
bool MenuManager::checkMainMenuMouse(int x, int y) {
// Inventory items
- bool selectedItem = false;
+
for (int i = 0; i < 4; i++) {
Common::Rect itemRect = Common::Rect(_inventorySlots[i], 60, 60);
if (itemRect.contains(x, y)) {
- selectedItem = selectInventoryItem(i);
+ selectInventoryItem(i);
return false;
}
}
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 15293a1157c..2077c0ee84e 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -247,7 +247,7 @@ private:
void readButton(Common::File &alfred7, uint32 offset, byte *outBuffer[2], Common::Rect rect);
void refreshSaveDescriptions();
void handleSaveMenuKey(Common::KeyCode key, uint16 ascii);
-void backToMainMenu();
+ void backToMainMenu();
SoundMenuButton isSoundMenuButtonUnder(int x, int y);
MainMenuButton isMainMenuButtonUnder(int x, int y);
Graphics::Screen *_screen = nullptr;
diff --git a/engines/pelrock/metaengine.cpp b/engines/pelrock/metaengine.cpp
index f659918398e..e44f3ab20cc 100644
--- a/engines/pelrock/metaengine.cpp
+++ b/engines/pelrock/metaengine.cpp
@@ -51,6 +51,17 @@ static const ADExtraGuiOptionsMap optionsList[] = {
0
}
},
+ {
+ GAMEOPTION_PLAY_INTRO,
+ {
+ _s("Play intro"),
+ _s("Play the game's intro sequence. Plays automatically the first time the game is launched."),
+ "play_intro",
+ false,
+ 0,
+ 0
+ }
+ },
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f16b6fcdeff..bd931f1d419 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -117,6 +117,9 @@ Common::Error PelrockEngine::run() {
_doubleSmallFont->load("ALFRED.4");
_videoManager = new VideoManager(_screen, _events, _chrono, _largeFont, _dialog, _sound);
+ bool playIntroFromConfig = ConfMan.getBool("play_intro");
+ bool hasLaunchedBefore = ConfMan.getBool("launched_before");
+ shouldPlayIntro = playIntroFromConfig || !hasLaunchedBefore;
// Set the engine's debugger console
setDebugger(new PelrockConsole(this));
@@ -138,7 +141,11 @@ Common::Error PelrockEngine::run() {
maybePlayPostIntro();
gameLoop();
} else if (_state->stateGame == INTRO) {
+ CursorMan.showMouse(false);
_videoManager->playIntro();
+ CursorMan.showMouse(true);
+ ConfMan.setBool("launched_before", true);
+ ConfMan.flushToDisk();
_state->setFlag(FLAG_FROM_INTRO, true);
_state->stateGame = GAME;
} else if (_state->stateGame == COMPUTER) {
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index fa229e1ef31..03231bab42a 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -690,7 +690,6 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
anim.targetZIndex = blank->zOrder + 1;
anim.resetCoord = blank->y;
anims->passerByAnims[0] = anim;
- debug("Loaded passerby animation for room %d, direction = %d", roomNumber, anim.dir);
break;
}
@@ -843,8 +842,6 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
default:
break;
}
- if (anims != nullptr)
- debug("Loaded passerby anims for room %d, count = %d", roomNumber, anims->numAnims);
return anims;
}
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index cb36bc35ecc..0aace022921 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -70,7 +70,10 @@ void VideoManager::playIntro() {
ChunkHeader chunk;
readChunk(videoFile, chunk);
- debug("Read chunk type %d at frame %d", chunk.chunkType, frameCounter);
+
+ if(_events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
+ break;
+ }
switch (chunk.chunkType) {
case 1:
@@ -133,11 +136,7 @@ void VideoManager::playIntro() {
_dialog->processColorAndTrim(lines, color);
Graphics::Surface s = _dialog->getDialogueSurface(lines, color);
_textSurface.transBlitFrom(s, Common::Point(subtitle->x, subtitle->y), 255);
-
- drawPos(&_textSurface, subtitle->x, subtitle->y, color);
- drawRect(&_textSurface, subtitle->x, subtitle->y,
- s.getRect().width(),
- s.getRect().height(), color);
+ s.free();
}
presentFrame();
@@ -285,15 +284,11 @@ void VideoManager::initMetadata() {
for (uint32 i = 0; i < numFiles; ++i) {
VoiceData sound;
Common::String filename = _introSndFile.readString();
- // _introSndFile.skip(1);
sound.offset = _introSndFile.readUint32LE();
sound.length = _introSndFile.readUint32LE();
_sounds[filename] = sound;
- debug("Loaded sound: '%s' (offset: %u, length: %u)", filename.c_str(), sound.offset, sound.length);
}
}
-
- debug("Loaded %d sound entries", _sounds.size());
}
while (metadataFile.eos() == false) {
@@ -318,9 +313,6 @@ void VideoManager::initMetadata() {
}
}
- debug("Loaded %d subtitles", _subtitles.size());
- debug("Loaded %d speech files", _voiceEffect.size());
-
metadataFile.close();
}
@@ -349,7 +341,6 @@ MusicEffect VideoManager::readMusicEffect(Common::File &metadataFile) {
}
}
music.trackNumber = atoi(buffer.c_str());
- debug("Loaded music effect: frame %d, track %d", music.startFrame, music.trackNumber);
return music;
}
@@ -378,7 +369,6 @@ AudioEffect VideoManager::readAudioEffect(Common::File &metadataFile) {
}
}
voice.filename = buffer;
- debug("Loaded voice: frame %d, file '%s'", voice.startFrame, voice.filename.c_str());
return voice;
}
@@ -389,8 +379,7 @@ Subtitle VideoManager::readSubtitle(Common::File &metadataFile) {
int valueIndex = 0;
// Skip spaces after "/t"
- while (!metadataFile.eos() && metadataFile.readByte() == ' ')
- ;
+ while (!metadataFile.eos() && metadataFile.readByte() == ' ');
metadataFile.seek(-1, SEEK_CUR); // Step back one byte
// Parse 4 space-delimited numbers
@@ -412,7 +401,8 @@ Subtitle VideoManager::readSubtitle(Common::File &metadataFile) {
break;
}
}
- metadataFile.skip(1); // Skip the extra space
+
+ // metadataFile.skip(1); // Skip the extra space
subtitle.startFrame = values[0];
subtitle.endFrame = values[1];
@@ -421,18 +411,34 @@ Subtitle VideoManager::readSubtitle(Common::File &metadataFile) {
// Read text until CRLF (0x0D 0x0A)
subtitle.text.clear();
+
+ // skip leading spaces in subtitle tex
+ byte nextByte;
+ do {
+ nextByte = metadataFile.readByte();
+ } while (nextByte == ' ' && !metadataFile.eos());
+
+ if(nextByte == 0x08) {
+ subtitle.text += '@';
+ } else {
+ subtitle.text += decodeChar(nextByte);
+ }
+
while (!metadataFile.eos()) {
- char c = metadataFile.readByte();
+ char c = metadataFile.readByte();
if (c == 0x0D) {
char next = metadataFile.readByte();
if (next == 0x0A) {
break;
} else {
- subtitle.text += c;
- subtitle.text += next;
+ subtitle.text += decodeChar(c);
+ subtitle.text += decodeChar(next);
}
} else {
+ if(c == 0x00) {
+ // do nothing
+ }
if (c == 0x08)
subtitle.text += '@';
else
Commit: c1c9772c506950784e65318bae87fc158e90b403
https://github.com/scummvm/scummvm/commit/c1c9772c506950784e65318bae87fc158e90b403
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:37+02:00
Commit Message:
PELROCK: Fixes bug (present in the original) where endless loop can happen during conversation
Changed paths:
engines/pelrock/dialog.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index d13f0df33fc..65272c791ae 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -481,6 +481,11 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
bool DialogManager::checkAllSubBranchesExhausted(const byte *data, uint32 dataSize, uint32 startPos, int currentChoiceLevel) {
uint32 pos = startPos;
+ // Fix for room 26 where an endless loop will happen due to buggy command codes that casued the conversation
+ // to go back with a single choice and thus repeating over and over.
+ int room = g_engine->_room->_currentRoomNumber;
+ bool f0IsBoundary = (room == 26 && currentChoiceLevel == 2 && startPos < dataSize && data[startPos] == 0x0C);
+
while (pos < dataSize) {
byte b = data[pos];
@@ -493,6 +498,13 @@ bool DialogManager::checkAllSubBranchesExhausted(const byte *data, uint32 dataSi
break;
}
+ // For that one bug in room 26
+ // treat F0 as a boundary to prevent scanning past unreachable choices
+ if (b == CTRL_GO_BACK && f0IsBoundary) {
+ debug("checkAllSubBranchesExhausted: F0 boundary hit at pos %u (room %d fix)", pos, room);
+ break;
+ }
+
// Found FB (one-time choice marker)
if (b == CTRL_DIALOGUE_MARKER_ONEOFF && pos + 2 < dataSize) {
byte choiceIdx = data[pos + 1];
Commit: 67735982b71ff7ce02ff6c2173f12711cc5cb721
https://github.com/scummvm/scummvm/commit/67735982b71ff7ce02ff6c2173f12711cc5cb721
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:37+02:00
Commit Message:
PELROCK: Fixes not being able to use stuff with Alfred from inventory overlay
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 65272c791ae..7bf07e9faed 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -501,7 +501,6 @@ bool DialogManager::checkAllSubBranchesExhausted(const byte *data, uint32 dataSi
// For that one bug in room 26
// treat F0 as a boundary to prevent scanning past unreachable choices
if (b == CTRL_GO_BACK && f0IsBoundary) {
- debug("checkAllSubBranchesExhausted: F0 boundary hit at pos %u (room %d fix)", pos, room);
break;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index bd931f1d419..e1f32fc90b6 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -632,7 +632,11 @@ void PelrockEngine::checkMouse() {
} else if (_inventoryOverlayState.isActive && _inventoryOverlayState.posInInventorySelectionArea(_events->_releaseX, _events->_releaseY)) {
int item = checkMouseClickInventoryOverlay(_events->_releaseX, _events->_releaseY);
_state->selectedInventoryItem = item;
- walkAndAction(_currentHotspot, ITEM);
+ if(_actionPopupState.isAlfredUnder) {
+ useOnAlfred(item);
+ } else if (_currentHotspot != nullptr) {
+ walkAndAction(_currentHotspot, ITEM);
+ }
} else {
// Released outside popup - just close it
_queuedAction = QueuedAction{NO_ACTION, -1, false, false};
@@ -1341,18 +1345,24 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
int PelrockEngine::getScrollPositionForItem(int item) {
int selectedIndex = -1;
+ // assign selectedIndex to the index of the item
for (size_t i = 0; i < _state->inventoryItems.size(); i++) {
if (_state->inventoryItems[i] == item) {
selectedIndex = i;
break;
}
}
+ // take the selectedIndex as the starting pos for calculatiom, it should ALWAYS be visible at the end of the overlay, if enough items
if (selectedIndex != -1) {
- // put the selected item at the end in the overlay
- if (_state->inventoryItems.size() > kInventoryPageSize) {
- selectedIndex = CLIP(selectedIndex, 0, (int)_state->inventoryItems.size() - kInventoryPageSize);
+ if (selectedIndex < _inventoryOverlayState.invStartingPos) {
+ selectedIndex = selectedIndex; // scroll left to show the selected item
+ } else if (selectedIndex >= _inventoryOverlayState.invStartingPos + kInventoryPageSize) {
+ selectedIndex = selectedIndex - kInventoryPageSize + 1; // scroll right to show the selected item
+ } else {
+ selectedIndex = _inventoryOverlayState.invStartingPos; // no scrolling needed, keep current starting pos
}
}
+
return selectedIndex;
}
@@ -1401,6 +1411,7 @@ Common::Point getPositionInOverlayForIndex(uint index) {
void PelrockEngine::pickupIconFlash() {
uint invSize = _state->inventoryItems.size();
+ // focus on the last positionin the inventory, where the newly picked up item would be, if there is at least 1 item in the inventory
_inventoryOverlayState.invStartingPos = getScrollPositionForItem(_state->inventoryItems[invSize - 1]);
_inventoryOverlayState.flashingIconIndex = invSize - 1;
showInventoryOverlay();
Commit: 780c84181b3b087f2612ca7c1b15cf5118ca639c
https://github.com/scummvm/scummvm/commit/780c84181b3b087f2612ca7c1b15cf5118ca639c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:38+02:00
Commit Message:
PELROCK: Fix sounds in inventory to leave click as default sound
Changed paths:
engines/pelrock/menu.h
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 2077c0ee84e..6cc811609d2 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -102,7 +102,7 @@ static const char *inventorySounds[113] = {
"ELEC3ZZZ.SMP", // 6 - Electric zap
"REMATERL.SMP", // 7 - Rematerialize
"81ZZZZZZ.SMP", // 8 - (numbered SFX)
- "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP", // 9
"SSSHTZZZ.SMP", // 10 - Shushing
"HOJASZZZ.SMP", // 11 - Default leaf rustle
"HOJASZZZ.SMP",
@@ -163,46 +163,46 @@ static const char *inventorySounds[113] = {
"BOOOOOIZ.SMP", // 67 - Boing
"DISCOSZZ.SMP", // 68 - Disco music
"MONORLZZ.SMP", // 69 - Monorail
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP", // 70
+ "11ZZZZZZ.SMP", // 71
+ "11ZZZZZZ.SMP", // 72
"CARACOLA.SMP", // 73 - Seashell
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP", // 74
+ "11ZZZZZZ.SMP", // 75
"WATER_2Z.SMP", // 76 - Water splash
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP", // 77
+ "11ZZZZZZ.SMP", // 78
"EEEEKZZZ.SMP", // 79 - Shriek
"REMATERL.SMP", // 80 - Rematerialize
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP", // 81
+ "11ZZZZZZ.SMP", // 82
"ELVIS1ZZ.SMP", // 83 - Elvis impression
"RIMSHOTZ.SMP", // 84 - Rimshot
- "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP", // 85
"WATER_2Z.SMP", // 86 - Water splash
"MOTOSZZZ.SMP", // 87 - Motorcycle
"HOJASZZZ.SMP",
"TWANGZZZ.SMP", // 89 - Twang
- "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP", // 90
"QUAKE2ZZ.SMP", // 91 - Earthquake
- "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP", // 92
"SORBOZZZ.SMP", // 93 - Slurp
"BOTEZZZZ.SMP", // 94 - Bottle sound
"ELVIS1ZZ.SMP", // 95 - Elvis impression
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP", // 96
+ "HOJASZZZ.SMP", // 97
+ "HOJASZZZ.SMP", // 98
+ "11ZZZZZZ.SMP", // 99
"LLAVESZZ.SMP", // 100 - Keys jingling
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP", // 101
+ "11ZZZZZZ.SMP", // 102
+ "11ZZZZZZ.SMP", // 103
"EVLLAUGH.SMP", // 104 - Evil laugh
- "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP", // 105
"BURROLZZ.SMP", // 106 - Donkey bray
- "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP", // 107
"TWANGZZZ.SMP", // 108
- "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP", // 109
"TWANGZZZ.SMP", // 110
"ELVIS1ZZ.SMP", // 111 - Elvis impression
"SEX3ZZZZ.SMP" // 112 - Suggestive sound
Commit: 13834000a97a417e459786e64f16fc94e472710c
https://github.com/scummvm/scummvm/commit/13834000a97a417e459786e64f16fc94e472710c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:38+02:00
Commit Message:
PELROCK: Scale tile shuffling with tile count in sliding puzzle minigame
Changed paths:
engines/pelrock/graphics.cpp
engines/pelrock/slidingpuzzle.cpp
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index fda9b0e597c..6b7c7c325cb 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -156,7 +156,6 @@ void GraphicsManager::drawColoredText(Graphics::ManagedSurface *screen, const Co
if (text[i] == '@' && i + 1 < text.size()) {
// Draw accumulated segment
if (!segment.empty()) {
- debug("Drawing text segment '%s' at %d, %d with color %d", segment.c_str(), currentX, y, defaultColor);
font->drawString(screen, segment, currentX, y, w, defaultColor);
currentX += font->getStringWidth(segment);
segment.clear();
diff --git a/engines/pelrock/slidingpuzzle.cpp b/engines/pelrock/slidingpuzzle.cpp
index 31aacc04e9c..a54b1f8ebdc 100644
--- a/engines/pelrock/slidingpuzzle.cpp
+++ b/engines/pelrock/slidingpuzzle.cpp
@@ -160,9 +160,16 @@ void SlidingPuzzle::playTileSound() {
void SlidingPuzzle::shuffleLoop() {
const int shuffleRange = _totalTiles - 1; // never touch the blank slot (N-1)
+
+ // scale tile swap with tile count
+ const int kBaseTileCount = (kPuzzleScreenWidth / kTileSizes[0]) *
+ (kPuzzleScreenHeight / kTileSizes[0]);
+ const int swapsPerFrame = MAX(1, _totalTiles / kBaseTileCount);
+
while (!g_engine->shouldQuit()) {
_events->pollEvent();
+ for (int s = 0; s < swapsPerFrame; s++) {
int a, b;
do {
a = g_engine->getRandomNumber(shuffleRange - 1);
Commit: e31fce39dda84478879dba57109a2095263c37b1
https://github.com/scummvm/scummvm/commit/e31fce39dda84478879dba57109a2095263c37b1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:38+02:00
Commit Message:
PELROCK: Improves anti-piracy joke
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/slidingpuzzle.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 056edc609d1..5c763fb009c 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -19,6 +19,9 @@
*
*/
+#include "audio/audiostream.h"
+#include "audio/decoders/raw.h"
+#include "audio/mixer.h"
#include "graphics/paletteman.h"
#include "pelrock.h"
@@ -2407,94 +2410,59 @@ void PelrockEngine::pickUpMatches(HotSpot *hotspot) {
}
/**
- * Original behavior:
- * 1. Stop all sound
- * 2. Loop: corrupt the background buffer pointer with random values,
- * copy garbage to screen, write sequential memory bytes to PC speaker
- * port 0x61 to produce noise
- * 3. On keypress: divide by zero -> crash to DOS
- *
- * ScummVM behavior:
- * 1. Stop all sound
- * 2. Loop: fill screen with random pixels, play white noise
- * 3. On keypress: return to launcher
+ * Simulates white noise and "crashes" the game
*/
void PelrockEngine::antiPiracyEffect() {
_sound->stopAllSounds();
_sound->stopMusic();
- // Generate a buffer of white noise for the PC speaker simulation
- const int kNoiseLength = 16000; // 1 second at 8kHz
- byte *noiseData = new byte[kNoiseLength + 44]; // WAV header + data
-
- // Write a minimal WAV header
- memcpy(noiseData, "RIFF", 4);
- WRITE_LE_UINT32(noiseData + 4, kNoiseLength + 36);
- memcpy(noiseData + 8, "WAVE", 4);
- memcpy(noiseData + 12, "fmt ", 4);
- WRITE_LE_UINT32(noiseData + 16, 16); // chunk size
- WRITE_LE_UINT16(noiseData + 20, 1); // PCM format
- WRITE_LE_UINT16(noiseData + 22, 1); // mono
- WRITE_LE_UINT32(noiseData + 24, 8000); // sample rate
- WRITE_LE_UINT32(noiseData + 28, 8000); // byte rate
- WRITE_LE_UINT16(noiseData + 32, 1); // block align
- WRITE_LE_UINT16(noiseData + 34, 8); // bits per sample
- memcpy(noiseData + 36, "data", 4);
- WRITE_LE_UINT32(noiseData + 40, kNoiseLength);
-
- // Fill with random noise (simulating garbage bytes written to port 0x61)
- byte curNoise = (byte)getRandomNumber(255);
+ // Generate noise
+ const int kNoiseLength = 8000; // ~1 second at 8000 Hz, will loop
+ byte *noiseData = (byte *)malloc(kNoiseLength);
for (int i = 0; i < kNoiseLength; i++) {
- noiseData[44 + i] = curNoise;
- bool changeNoise = getRandomNumber(10) < 2; // 20% chance to change noise value
- if (changeNoise) {
- curNoise = (byte)getRandomNumber(255);
- }
+ noiseData[i] = (byte)((getRandomNumber(255)));
}
- // Play the noise
- _sound->playSound(noiseData, kNoiseLength + 44, 0);
+ // Create a looping raw audio stream with the random noise data
+ Audio::SeekableAudioStream *rawStream = Audio::makeRawStream(noiseData, kNoiseLength, 8000, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
+ Audio::AudioStream *loopStream = Audio::makeLoopingAudioStream(rawStream, 0);
- byte *screenPixels = (byte *)_screen->getPixels();
- int screenSize = _screen->pitch * _screen->h;
+ Audio::SoundHandle noiseHandle;
+ g_system->getMixer()->playStream(Audio::Mixer::kSFXSoundType, &noiseHandle, loopStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::YES);
- // Clear any pending key event before starting the loop
- _events->_lastKeyEvent = Common::KEYCODE_INVALID;
+ // Set a grayscale palette so random pixel values produce snow effect
+ byte grayPalette[256 * 3];
+ for (int i = 0; i < 256; i++) {
+ grayPalette[i * 3 + 0] = (byte)i; // R
+ grayPalette[i * 3 + 1] = (byte)i; // G
+ grayPalette[i * 3 + 2] = (byte)i; // B
+ }
+ g_system->getPaletteManager()->setPalette(grayPalette, 0, 256);
+
+ byte *screenPixels = (byte *)_screen->getPixels();
while (!shouldQuit()) {
_events->pollEvent();
if (_events->_lastKeyEvent != Common::KEYCODE_INVALID) {
- break;
+ g_system->getMixer()->stopHandle(noiseHandle);
+ g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
+ // Original divides by zero to intentionally crash to DOS.
+ // We exit the game instead
+ g_engine->quitGame();
}
- // generate random pixels on the screen (simulating corrupted video memory)
+ // generate white-noise like scene
+ int screenSize = 640 * 400;
for (int i = 0; i < screenSize; i++) {
screenPixels[i] = (byte)getRandomNumber(255);
}
- // Regenerate noise periodically
- for (int i = 0; i < kNoiseLength; i++) {
- noiseData[44 + i] = curNoise;
- bool changeNoise = getRandomNumber(10) < 2; // 20% chance to change noise value
- if (changeNoise) {
- curNoise = (byte)getRandomNumber(255);
- }
- }
- if (!_sound->isPlaying()) {
- _sound->playSound(noiseData, kNoiseLength + 44, 0);
- }
-
_screen->markAllDirty();
_screen->update();
- g_system->delayMillis(50);
+ g_system->delayMillis(10);
}
- _sound->stopAllSounds();
- delete[] noiseData;
-
- // Return to launcher
- Engine::quitGame();
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index e1f32fc90b6..68bf1dd8f01 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1355,7 +1355,7 @@ int PelrockEngine::getScrollPositionForItem(int item) {
// take the selectedIndex as the starting pos for calculatiom, it should ALWAYS be visible at the end of the overlay, if enough items
if (selectedIndex != -1) {
if (selectedIndex < _inventoryOverlayState.invStartingPos) {
- selectedIndex = selectedIndex; // scroll left to show the selected item
+ // do nothing
} else if (selectedIndex >= _inventoryOverlayState.invStartingPos + kInventoryPageSize) {
selectedIndex = selectedIndex - kInventoryPageSize + 1; // scroll right to show the selected item
} else {
@@ -1539,6 +1539,11 @@ void PelrockEngine::gameLoop() {
puzzle.run();
}
+ if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_h) {
+ _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
+ antiPiracyEffect();
+ }
+
renderScene();
_screen->update();
}
diff --git a/engines/pelrock/slidingpuzzle.cpp b/engines/pelrock/slidingpuzzle.cpp
index a54b1f8ebdc..0baf21f30be 100644
--- a/engines/pelrock/slidingpuzzle.cpp
+++ b/engines/pelrock/slidingpuzzle.cpp
@@ -170,13 +170,14 @@ void SlidingPuzzle::shuffleLoop() {
_events->pollEvent();
for (int s = 0; s < swapsPerFrame; s++) {
- int a, b;
- do {
- a = g_engine->getRandomNumber(shuffleRange - 1);
- b = g_engine->getRandomNumber(shuffleRange - 1);
- } while (a == b);
+ int a, b;
+ do {
+ a = g_engine->getRandomNumber(shuffleRange - 1);
+ b = g_engine->getRandomNumber(shuffleRange - 1);
+ } while (a == b);
- swapTiles(a, b);
+ swapTiles(a, b);
+ }
present();
playTileSound();
Commit: b6f5b1bd5ad5e1521406208fa0d7bd45a7851773
https://github.com/scummvm/scummvm/commit/b6f5b1bd5ad5e1521406208fa0d7bd45a7851773
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:38+02:00
Commit Message:
PELROCK: Fixes bug that would make travel agency inaccesible
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/graphics.cpp
engines/pelrock/sound.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 5c763fb009c..f6aab593323 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -2370,11 +2370,13 @@ void PelrockEngine::checkObjectsForPart2() {
if (_state->hasInventoryItem(17) &&
_state->hasInventoryItem(59) &&
_state->hasInventoryItem(24)) {
- _room->addStickerToRoom(19, 54, PERSIST_BOTH);
- _room->addStickerToRoom(19, 55, PERSIST_BOTH);
- _room->addStickerToRoom(19, 56, PERSIST_BOTH);
- _room->addStickerToRoom(19, 58, PERSIST_BOTH);
- _state->setFlag(FLAG_AGENCIA_ABIERTA, true);
+ if(_state->getFlag(FLAG_AGENCIA_ABIERTA) == false) {
+ _room->addStickerToRoom(19, 54, PERSIST_BOTH);
+ _room->addStickerToRoom(19, 55, PERSIST_BOTH);
+ _room->addStickerToRoom(19, 56, PERSIST_BOTH);
+ _room->addStickerToRoom(19, 58, PERSIST_BOTH);
+ _state->setFlag(FLAG_AGENCIA_ABIERTA, true);
+ }
}
}
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 7bf07e9faed..ee8e99f5b27 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -279,7 +279,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
}
_screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos), 255);
- drawPos(_screen, xPos, yPos, speakerId);
+ // drawPos(_screen, xPos, yPos, speakerId);
_screen->markAllDirty();
_screen->update();
@@ -1243,7 +1243,6 @@ Common::Array<Common::StringArray> DialogManager::wordWrap(Common::StringArray t
for (uint i = 0; i < texts.size(); i++) {
Common::String thisLine = texts[i];
Common::Array<Common::Array<Common::String>> wrapped = wordWrap(thisLine);
- debug("Wrapped line %s, %d into %d pages", thisLine.c_str(), thisLine.size(), wrapped.size());
for (uint j = 0; j < wrapped.size(); j++) {
for (int k = 0; k < wrapped[j].size(); k++) {
if (currentLineNum < kMaxLines) {
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 6b7c7c325cb..eb8d2b6585e 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -232,7 +232,7 @@ void GraphicsManager::copyBackgroundToBuffer() {
void GraphicsManager::presentFrame() {
g_engine->_screen->blitFrom(g_engine->_compositeBuffer);
- g_engine->paintDebugLayer();
+ // g_engine->paintDebugLayer();
g_engine->_screen->markAllDirty();
}
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 151045cd902..80c48612f54 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -40,102 +40,103 @@
namespace Pelrock {
const char *SOUND_FILENAMES[] = {
- "NO_SOUND.SMP", // 0 - Silence/disabled
- "BUHO_ZZZ.SMP", // 1 - Owl
- "BIRD_1_1.SMP", // 2 - Bird variant 1
- "BIRD_1_2.SMP", // 3 - Bird variant 2
- "BIRD_1_3.SMP", // 4 - Bird variant 3
- "DESPERZZ.SMP", // 5 - Yawn/stretch
- "HORN_5ZZ.SMP", // 6 - Car horn 5
- "HORN_6ZZ.SMP", // 7 - Car horn 6
- "HORN_8ZZ.SMP", // 8 - Car horn 8
- "SUZIPASS.SMP", // 9 - Suzi passing
- "CAT_1ZZZ.SMP", // 10 - Cat
- "DOG_01ZZ.SMP", // 11 - Dog bark 1
- "DOG_02ZZ.SMP", // 12 - Dog bark 2
- "DOG_04ZZ.SMP", // 13 - Dog bark 4
- "DOG_05ZZ.SMP", // 14 - Dog bark 5
- "DOG_06ZZ.SMP", // 15 - Dog bark 6
- "DOG_07ZZ.SMP", // 16 - Dog bark 7
- "DOG_09ZZ.SMP", // 17 - Dog bark 9
- "ALARMZZZ.SMP", // 18 - Alarm
- "AMBULAN1.SMP", // 19 - Ambulance
- "FOUNTAIN.SMP", // 20 - Fountain
- "GRILLOSZ.SMP", // 21 - Crickets
- "HOJASZZZ.SMP", // 22 - Leaves rustling
- "FLASHZZZ.SMP", // 23 - Flash/camera
- "CUCHI1ZZ.SMP", // 24 - Knife 1
- "KNRRRRRZ.SMP", // 25 - Snoring
- "PHONE_02.SMP", // 26 - Phone ring 2
- "PHONE_03.SMP", // 27 - Phone ring 3
- "SSSHTZZZ.SMP", // 28 - Shush/quiet
- "BURGUER1.SMP", // 29 - Burger sizzle
- "FLIES_2Z.SMP", // 30 - Flies buzzing
- "PARRILLA.SMP", // 31 - Grill
- "WATER_2Z.SMP", // 32 - Water
- "XIQUETZZ.SMP", // 33 - Whistle
- "RONQUIZZ.SMP", // 34 - Snoring
- "MOCO1ZZZ.SMP", // 35 - Snot/mucus 1
- "MOCO2ZZZ.SMP", // 36 - Snot/mucus 2
- "SPRINGZZ.SMP", // 37 - Spring bounce
- "MARUJASZ.SMP", // 38 - Gossip/chatter
- "ELECTROZ.SMP", // 39 - Electric shock
- "GLASS1ZZ.SMP", // 40 - Glass clink
- "OPDOORZZ.SMP", // 41 - Door open
- "CLDOORZZ.SMP", // 42 - Door close
- "FXH2ZZZZ.SMP", // 43 - Effect 2
- "BOTEZZZZ.SMP", // 44 - Bottle
- "ELEC3ZZZ.SMP", // 45 - Electric 3
- "AJARLZZZ.SMP", // 46 - Ajar/creak
- "BELCHZZZ.SMP", // 47 - Belch/burp
- "64ZZZZZZ.SMP", // 48 - Sound effect 64
- "BIRDOWL2.SMP", // 49 - Bird/owl 2
- "BUBBLE2Z.SMP", // 50 - Bubbles
- "BURGUER1.SMP", // 51 - Burger (duplicate)
- "CACKLEZZ.SMP", // 52 - Cackle/laugh
- "CERAMIC1.SMP", // 53 - Ceramic break
- "CLANG5ZZ.SMP", // 54 - Metal clang
- "CUCHI2ZZ.SMP", // 55 - Knife 2
- "CUCHI3ZZ.SMP", // 56 - Knife 3
- "ELEC3ZZZ.SMP", // 57 - Electric 3 (duplicate)
- "HOJASZZZ.SMP", // 58 - Leaves (duplicate)
- "LIMA1ZZZ.SMP", // 59 - File/rasp
- "MOROSZZZ.SMP", // 60 - Moors/crowd
- "MOROZZZZ.SMP", // 61 - Moor/crowd
- "MUD1ZZZZ.SMP", // 62 - Mud squelch
- "PICOZZZZ.SMP", // 63 - Pickaxe
- "PICO1XZZ.SMP", // 64 - Pickaxe 1
- "PICO2XZZ.SMP", // 65 - Pickaxe 2
- "PICO3XZZ.SMP", // 66 - Pickaxe 3
- "RIMSHOTZ.SMP", // 67 - Rimshot drum
- "RONCOZZZ.SMP", // 68 - Snoring
- "SORBOZZZ.SMP", // 69 - Slurp/sip
- "VIENTO1Z.SMP", // 70 - Wind
- "2ZZZZZZZ.SMP", // 71 - Sound 2
- "20ZZZZZZ.SMP", // 72 - Sound 20
- "21ZZZZZZ.SMP", // 73 - Sound 21
- "23ZZZZZZ.SMP", // 74 - Sound 23
- "107ZZZZZ.SMP", // 75 - Sound 107
- "39ZZZZZZ.SMP", // 76 - Sound 39
- "81ZZZZZZ.SMP", // 77 - Sound 81
- "88ZZZZZZ.SMP", // 78 - Sound 88
- "92ZZZZZZ.SMP", // 79 - Sound 92
- "SAW_2ZZZ.SMP", // 80 - Saw
- "QUAKE2ZZ.SMP", // 81 - Earthquake
- "ROCKSZZZ.SMP", // 82 - Rocks falling
- "IN_FIREZ.SMP", // 83 - Fire
- "BEAMZZZZ.SMP", // 84 - Beam/ray
- "GLISSDWN.SMP", // 85 - Glissando down
- "REMATERL.SMP", // 86 - Rematerialize
- "FXH1ZZZZ.SMP", // 87 - Effect 1
- "FXH3ZZZZ.SMP", // 88 - Effect 3
- "FXH4ZZZZ.SMP", // 89 - Effect 4
- "MATCHZZZ.SMP", // 90 - Match strike
- "SURF_01Z.SMP", // 91 - Surf wave 1
- "SURF_02Z.SMP", // 92 - Surf wave 2
- "SURF_04Z.SMP", // 93 - Surf wave 4
- "TWANGZZZ.SMP", // 94 - Twang
- "LANDCRAS.SMP", // 95 - Crash landing
+ "NO_SOUND.SMP",
+ "BUHO_ZZZ.SMP",
+ "BIRD_1_1.SMP",
+ "BIRD_1_2.SMP",
+ "BIRD_1_3.SMP",
+ "DESPERZZ.SMP",
+ "HORN_5ZZ.SMP",
+ "HORN_6ZZ.SMP",
+ "HORN_8ZZ.SMP",
+ "SUZIPASS.SMP",
+ "CAT_1ZZZ.SMP",
+ "DOG_01ZZ.SMP",
+ "DOG_02ZZ.SMP",
+ "DOG_04ZZ.SMP",
+ "DOG_05ZZ.SMP",
+ "DOG_06ZZ.SMP",
+ "DOG_07ZZ.SMP",
+ "DOG_09ZZ.SMP",
+ "ALARMZZZ.SMP",
+ "AMBULAN1.SMP",
+ "FOUNTAIN.SMP",
+ "GRILLOSZ.SMP",
+ "HOJASZZZ.SMP",
+ "FLASHZZZ.SMP",
+ "CUCHI1ZZ.SMP",
+ "KNRRRRRZ.SMP",
+ "PHONE_02.SMP",
+ "PHONE_03.SMP",
+ "SSSHTZZZ.SMP",
+ "BURGUER1.SMP",
+ "FLIES_2Z.SMP",
+ "PARRILLA.SMP",
+ "WATER_2Z.SMP",
+ "XIQUETZZ.SMP",
+ "RONQUIZZ.SMP",
+ "MOCO1ZZZ.SMP",
+ "MOCO2ZZZ.SMP",
+ "SPRINGZZ.SMP",
+ "MARUJASZ.SMP",
+ "ELECTROZ.SMP",
+ "GLASS1ZZ.SMP",
+ "OPDOORZZ.SMP",
+ "CLDOORZZ.SMP",
+ "FXH2ZZZZ.SMP",
+ "BOTEZZZZ.SMP",
+ "ELEC3ZZZ.SMP",
+ "AJARLZZZ.SMP",
+ "BELCHZZZ.SMP",
+ "64ZZZZZZ.SMP",
+ "BIRDOWL2.SMP",
+ "BUBBLE2Z.SMP",
+ "BURGUER1.SMP",
+ "CACKLEZZ.SMP",
+ "CERAMIC1.SMP",
+ "CLANG5ZZ.SMP",
+ "CUCHI2ZZ.SMP",
+ "CUCHI3ZZ.SMP",
+ "ELEC3ZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "LIMA1ZZZ.SMP",
+ "MOROSZZZ.SMP",
+ "MOROZZZZ.SMP",
+ "MUD1ZZZZ.SMP",
+ "PICOZZZZ.SMP",
+ "PICO1XZZ.SMP",
+ "PICO2XZZ.SMP",
+ "PICO3XZZ.SMP",
+ "RIMSHOTZ.SMP",
+ "RONCOZZZ.SMP",
+ "SORBOZZZ.SMP",
+ "VIENTO1Z.SMP",
+ "2ZZZZZZZ.SMP",
+ "20ZZZZZZ.SMP",
+ "21ZZZZZZ.SMP",
+ "23ZZZZZZ.SMP",
+ "107ZZZZZ.SMP",
+ "39ZZZZZZ.SMP",
+ "81ZZZZZZ.SMP",
+ "88ZZZZZZ.SMP",
+ "92ZZZZZZ.SMP",
+ "SAW_2ZZZ.SMP",
+ "QUAKE2ZZ.SMP",
+ "ROCKSZZZ.SMP",
+ "IN_FIREZ.SMP",
+ "BEAMZZZZ.SMP",
+ "GLISSDWN.SMP",
+ "REMATERL.SMP",
+ "FXH1ZZZZ.SMP",
+ "FXH3ZZZZ.SMP",
+ "FXH4ZZZZ.SMP",
+ "MATCHZZZ.SMP",
+ "SURF_01Z.SMP",
+ "SURF_02Z.SMP",
+ "SURF_04Z.SMP",
+ "TWANGZZZ.SMP",
+ "LANDCRAS.SMP",
+ "KKKKKKKK.SMP",
};
SoundManager::SoundManager(Audio::Mixer *mixer)
Commit: d3e3cb2d7dda74b5e513b7b1edfc043fb3763c55
https://github.com/scummvm/scummvm/commit/d3e3cb2d7dda74b5e513b7b1edfc043fb3763c55
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:39+02:00
Commit Message:
PELROCK: Fix extraneous idle Alfred showing up after being eaten by croc
Changed paths:
engines/pelrock/actions.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index f6aab593323..92f981f4094 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1230,9 +1230,9 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
_alfredState.x -= 10;
_alfredState.y += 20;
playAlfredSpecialAnim(5);
+ _alfredState.animState = ALFRED_SKIP_DRAWING;
_sound->playSound(_room->_roomSfx[0], 0); // Belch
waitForSoundEnd();
- _alfredState.animState = ALFRED_SKIP_DRAWING;
_graphics->fadeToBlack(10);
// update conversaton state
_alfredState.x = 300;
Commit: 027a91d16bb14e270b81127a5770c1ce08e99a15
https://github.com/scummvm/scummvm/commit/027a91d16bb14e270b81127a5770c1ce08e99a15
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:39+02:00
Commit Message:
PELROCK: Ensure same ambient sound doesnt overlap with itself
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 68bf1dd8f01..572239ba639 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -275,7 +275,10 @@ void PelrockEngine::playSoundIfNeeded() {
if (roomSoundIndex < _room->_roomSfx.size()) {
byte soundFileIndex = _room->_roomSfx[roomSoundIndex];
if (soundFileIndex != 0) { // 0 = NO_SOUND.SMP (disabled)
- _sound->playSound(soundFileIndex);
+ // Don't play the same sound twice at the same time
+ if (!_sound->isSoundIndexPlaying(soundFileIndex)) {
+ _sound->playSound(soundFileIndex);
+ }
}
}
}
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 80c48612f54..e575d8410fd 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -143,6 +143,7 @@ SoundManager::SoundManager(Audio::Mixer *mixer)
: _mixer(mixer), _currentVolume(128) {
// TODO: Initialize sound manager
g_system->getAudioCDManager()->open();
+ memset(_sfxSoundIndex, 0xFF, sizeof(_sfxSoundIndex));
}
SoundManager::~SoundManager() {
@@ -154,7 +155,9 @@ void SoundManager::playSound(byte index, int channel, int loopCount) {
// debug("Playing sound index %d (%s)", index, SOUND_FILENAMES[index]);
auto it = _soundMap.find(SOUND_FILENAMES[index]);
if (it != _soundMap.end()) {
- playSound(it->_value, channel, loopCount);
+ int usedChannel = playSound(it->_value, channel, loopCount);
+ if (usedChannel >= 0 && usedChannel < kMaxChannels)
+ _sfxSoundIndex[usedChannel] = index;
} else {
debug("Sound file %s not found in sound map", SOUND_FILENAMES[index]);
}
@@ -169,11 +172,11 @@ void SoundManager::playSound(const char *filename, int channel, int loopCount) {
}
}
-void SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
+int SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
Common::File sonidosFile;
if (!sonidosFile.open(Common::Path("SONIDOS.DAT"))) {
debug("Failed to open SONIDOS.DAT");
- return;
+ return -1;
}
sonidosFile.seek(sound.offset, SEEK_SET);
@@ -206,7 +209,7 @@ void SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
} else {
debug("Unknown sound format on sound with name %s at offset %d, with size %d", sound.filename.c_str(), sound.offset, sound.size);
delete[] data;
- return;
+ return -1;
}
if (stream) {
@@ -222,7 +225,9 @@ void SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
Audio::AudioStream *finalStream = loopCount != -1 ? stream : Audio::makeLoopingAudioStream(stream, 0);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], finalStream, -1, _currentVolume, 0, DisposeAfterUse::YES);
+ return channel;
}
+ return -1;
}
void SoundManager::playSound(byte *soundData, uint32 size, int channel) {
@@ -281,6 +286,14 @@ int SoundManager::findFreeChannel() {
return 0;
}
+bool SoundManager::isSoundIndexPlaying(byte index) const {
+ for (int i = 0; i < kMaxChannels; i++) {
+ if (_sfxSoundIndex[i] == index && _mixer->isSoundHandleActive(_sfxHandles[i]))
+ return true;
+ }
+ return false;
+}
+
void SoundManager::stopAllSounds() {
for (int i = 0; i < kMaxChannels; i++) {
_mixer->stopHandle(_sfxHandles[i]);
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 4a0f6053e50..407abf114c3 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -75,6 +75,7 @@ public:
bool isPlaying() const;
bool isPlaying(int channel) const;
+ bool isSoundIndexPlaying(byte index) const;
void loadSoundIndex();
bool isMusicPlaying();
@@ -94,7 +95,7 @@ public:
byte getCurrentMusicTrack() const { return _currentMusicTrack; }
private:
- void playSound(SonidoFile sound, int channel = -1, int loopCount = 1);
+ int playSound(SonidoFile sound, int channel = -1, int loopCount = 1);
SoundFormat detectFormat(byte *data, uint32 size);
int getSampleRate(byte *data, SoundFormat format);
int findFreeChannel();
@@ -104,6 +105,7 @@ private:
int _currentVolume;
Audio::SoundHandle _musicHandle;
Audio::SoundHandle _sfxHandles[kMaxChannels];
+ byte _sfxSoundIndex[kMaxChannels]; // tracks which sound index is on each channel (0xFF = none)
Common::HashMap<Common::String, SonidoFile> _soundMap;
bool _isPaused = false;
byte _currentMusicTrack = 0;
Commit: ecd269a800236465b2fef66085602f301fad88db
https://github.com/scummvm/scummvm/commit/ecd269a800236465b2fef66085602f301fad88db
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:39+02:00
Commit Message:
PELROCK: Clear inventory before time travelling
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 92f981f4094..552a3738aed 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1790,9 +1790,13 @@ void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
}
_state->setFlag(FLAG_FORMULA_MAGICA, _state->getFlag(FLAG_FORMULA_MAGICA) + 1);
if (_state->getFlag(FLAG_FORMULA_MAGICA) == 4) {
-
smokeAnimation(-1);
_alfredState.setState(ALFRED_IDLE);
+ _state->clearInventory();
+ _state->addInventoryItem(88);
+ _state->addInventoryItem(76);
+ _state->addInventoryItem(82);
+
setScreenAndPrepare(39, ALFRED_UP);
}
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 7bc1d91b7dd..df4df025152 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -628,6 +628,11 @@ struct GameStateData {
inventoryItems.push_back(id);
}
+ void clearInventory() {
+ inventoryItems.clear();
+ selectedInventoryItem = -1;
+ }
+
void removeInventoryItem(int id) {
for (uint i = 0; i < inventoryItems.size(); i++) {
if (inventoryItems[i] == id) {
Commit: dd1ab34e358913c58e07b52f5fa6a312b3cbdb66
https://github.com/scummvm/scummvm/commit/dd1ab34e358913c58e07b52f5fa6a312b3cbdb66
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:40+02:00
Commit Message:
PELROCK: Cleanup video, fonts and actions
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/fonts/large_font.cpp
engines/pelrock/fonts/small_font.cpp
engines/pelrock/fonts/small_font_double.cpp
engines/pelrock/fonts/small_font_double.h
engines/pelrock/video/video.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 552a3738aed..102d776ace9 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -99,12 +99,6 @@ const ActionEntry actionTable[] = {
{310, PICKUP, &PelrockEngine::pickupFruit},
{311, PICKUP, &PelrockEngine::pickupFruit},
- // // Room 5
- // {},
-
- // // Room 7
- // {},
-
// Room 8
{355, OPEN, &PelrockEngine::openLibraryOutdoorsDoor},
{355, CLOSE, &PelrockEngine::closeLibraryOutdoorsDoor},
@@ -209,14 +203,14 @@ const CombinationEntry combinationTable[] = {
{7, 353, &PelrockEngine::useAmuletWithStatue},
{8, 347, &PelrockEngine::useSecretCodeWithStatue},
{8, 358, &PelrockEngine::giveSecretCodeToLibrarian},
- {4, 358, &PelrockEngine::useBrickWithLibrarian}, // Any hotspot in the lamppost will work
+ {4, 358, &PelrockEngine::useBrickWithLibrarian},
{76, 469, &PelrockEngine::usePumpkinWithRiver},
{100, 650, &PelrockEngine::useKeyWithPortrait},
{83, 461, &PelrockEngine::useDollWithBed},
{84, 503, &PelrockEngine::giveMagazineToGuard},
{86, 500, &PelrockEngine::giveWaterToGuard},
{91, 601, &PelrockEngine::giveStoneToSlaves},
- {92, 601, &PelrockEngine::giveStoneToSlaves}, // Item 92 = mud/clay, same handler
+ {92, 601, &PelrockEngine::giveStoneToSlaves},
// Room 35 (cauldron)
{90, 506, &PelrockEngine::magicFormula},
@@ -231,6 +225,9 @@ const CombinationEntry combinationTable[] = {
// End marker
{WILDCARD, WILDCARD, nullptr}};
+/**
+ * Convenience methods for open/close doors which usually have the same behavior
+ */
void PelrockEngine::openDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayClosed) {
if (_room->hasSticker(sticker)) {
int text = masculine == MASCULINE ? YA_ABIERTO_M : YA_ABIERTA_F;
@@ -253,6 +250,9 @@ void PelrockEngine::closeDoor(HotSpot *hotspot, int exitIndex, int sticker, bool
_sound->playSound(_room->_roomSfx[1]);
}
+/**
+ * Adds item to inventory but also shows the item overlay
+ */
void PelrockEngine::addInventoryItem(int item) {
if (_state->inventoryItems.empty()) {
_state->selectedInventoryItem = item;
@@ -274,6 +274,9 @@ void PelrockEngine::addInventoryItem(int item) {
checkObjectsForPart2();
}
+/**
+ * Every object from the store removes bill, adds item, cutscene happens.
+ */
void PelrockEngine::buyFromStore(HotSpot *hotspot, int stickerId) {
if (_state->hasInventoryItem(5) == false) {
_dialog->say(_res->_ingameTexts[NOTENGODINERO]);
@@ -294,10 +297,10 @@ void PelrockEngine::buyFromStore(HotSpot *hotspot, int stickerId) {
}
}
+// F8 commands on conversations
void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte rootIndex) {
switch (actionTrigger) {
case 328:
- debug("Setting current root to %d in room %d", rootIndex + 1, room);
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 329:
@@ -338,8 +341,8 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 273: {
- WalkBox w1 = { 3, 436, 356, 4, 14, 0 };
- WalkBox w2 = { 4, 440, 368,148, 2, 0 };
+ WalkBox w1 = {3, 436, 356, 4, 14, 0};
+ WalkBox w2 = {4, 440, 368, 148, 2, 0};
_room->addWalkbox(w1);
_room->addWalkbox(w2);
@@ -357,7 +360,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 278:
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
- case 279:{
+ case 279: {
_state->removeInventoryItem(75);
travelToEgypt();
@@ -404,7 +407,6 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 348: {
- // Anti-piracy punishment: corrupt screen + noise + crash
antiPiracyEffect();
break;
}
@@ -452,14 +454,13 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 352:
case 355:
case 291:
- // a la carcel
toJail();
break;
case 356:
_state->setCurrentRoot(room, 3, 0);
break;
- // end puta
- // sabio
+ // end hooker
+ // hermit
case 366:
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
@@ -471,7 +472,6 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
walkAndAction(_room->findHotspotByExtra(467), TALK);
waitForActionEnd();
break;
- // hasta aqui
case 357: // wrong answer: counter-- (min 0)
{
@@ -509,9 +509,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 361: // "no sé" (I don't know): no counter change, just advance
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
- case 362: // special trigger: enables HIJODELAGRANPUTA cheat code
- // Sets cheat_code_checking_enabled flag in original (0x495F3)
- // TODO: Implement cheat code sequence checker in game loop
+ case 362:
_state->setFlag(FLAG_CHEAT_CODE_ENABLED, 1);
advanceQuotesConversation(rootIndex, room);
break;
@@ -666,7 +664,6 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(45, 3, 0);
break;
case 30840:
- // toJail()? not present in the game
break;
case 323:
@@ -744,12 +741,12 @@ void PelrockEngine::noOpAction(HotSpot *hotspot) {
void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
// Original game checked against 47 instead of 58
+ // These are books in the library being returned to the librarian
if (item >= 11 && item <= 58 && hotspot->extra == 358) {
_state->removeInventoryItem(item);
_dialog->say(_res->_ingameTexts[DEACUERDO_2]);
return;
}
- debug("No-op item %d with hotspot %d", item, hotspot->extra);
_alfredState.direction = ALFRED_DOWN;
sayRandomIncorrectResponse();
}
@@ -823,8 +820,9 @@ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
}
}
if (billCount < 13) {
- addInventoryItem(5); // 1000 pesetas bill
- bool sayLine = getRandomNumber(15) == 1; // 1 in 15 chance to say the line about not having more money
+ addInventoryItem(5);
+ // 1 in every 15 times, the hooker will say "fancy a good time?"
+ bool sayLine = getRandomNumber(15) == 1;
if (sayLine) {
_dialog->say(_res->_ingameTexts[TEAPETECE_BUENRATO]);
}
@@ -839,7 +837,6 @@ void PelrockEngine::openMcDoor(HotSpot *hotspot) {
}
void PelrockEngine::closeMcDoor(HotSpot *hotspot) {
- // FIXME: Impossible to close right now
closeDoor(hotspot, 2, 7, FEMININE, false);
}
@@ -923,7 +920,7 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
HotSpot *windowHotspot = _room->findHotspotByExtra(294);
brickSprite->x = 420;
brickSprite->y = 241;
- brickSprite->zOrder = 10; // Make it visible
+ brickSprite->zOrder = 10;
while (!shouldQuit()) {
_events->pollEvent();
renderScene(OVERLAY_NONE);
@@ -937,7 +934,6 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
}
debug("Brick hit the window");
- // Add the broken window sticker
_room->addSticker(11);
_sound->playSound(_room->_roomSfx[2]); // Play glass breaking sound
@@ -956,10 +952,10 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
_state->setFlag(FLAG_TIENDA_ABIERTA, true);
_room->addStickerToRoom(_room->_currentRoomNumber, 9, PERSIST_PERM);
_room->addStickerToRoom(_room->_currentRoomNumber, 10, PERSIST_PERM);
- _room->disableHotspot(_room->findHotspotByExtra(295)); // Disable storefront hotspot
+ _room->disableHotspot(_room->findHotspotByExtra(295));
_room->disableHotspot(_room->findHotspotByExtra(294)); // Disable window hotspot
- _room->enableSprite(5, 100, PERSIST_PERM); // Enable fake teeth sprite
- _disableAction = true; // Prevent player from doing anything until they move Alfred
+ _room->enableSprite(5, 100, PERSIST_PERM); // Enable fake teeth sprite
+ _disableAction = true; // Prevent player from doing anything until the action is done
walkTo(630, _alfredState.y);
}
@@ -967,7 +963,7 @@ void PelrockEngine::moveCable(HotSpot *hotspot) {
_room->addSticker(15);
_room->addSticker(16);
_room->addSticker(17);
- _room->addStickerToRoom(4, 20); // Room 4, sticker 20
+ _room->addStickerToRoom(4, 20);
_state->setFlag(FLAG_CABLES_PUESTOS, true);
}
@@ -1049,7 +1045,7 @@ void PelrockEngine::pickCables(HotSpot *hotspot) {
// electric shock
int prevX = _alfredState.x;
_alfredState.x -= 20;
- // original incorrectly played door closing sound here
+ // original incorrectly played door closing sound here!
_sound->playSound("ELEC3ZZZ.SMP", 0);
playAlfredSpecialAnim(3);
_alfredState.x = prevX;
@@ -1095,7 +1091,7 @@ void PelrockEngine::giveMoneyToGuard(int inventoryObject, HotSpot *hotspot) {
} else if (!_state->getFlag(FLAG_SOBORNO_PORTERO)) {
_state->setFlag(FLAG_SOBORNO_PORTERO, true);
_dialog->say(_res->_ingameTexts[MUYBIEN]);
- _state->removeInventoryItem(5); // Remove 1000 pesetas bill
+ _state->removeInventoryItem(5);
}
if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
unlockMuseum();
@@ -1213,7 +1209,7 @@ void PelrockEngine::openTravelAgencyDoor(HotSpot *hotspot) {
if (_state->getFlag(FLAG_AGENCIA_ABIERTA)) {
openDoor(hotspot, 1, 57, FEMININE, false);
}
- // The game originally did nothing here
+ // The game originally already did nothing here
}
void PelrockEngine::closeTravelAgencyDoor(HotSpot *hotspot) {
@@ -1223,7 +1219,7 @@ void PelrockEngine::closeTravelAgencyDoor(HotSpot *hotspot) {
void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
_state->removeInventoryItem(76);
addInventoryItem(86);
- if(_state->getFlag(FLAG_CROCODILLO_ENCENDIDO) == false) {
+ if (_state->getFlag(FLAG_CROCODILLO_ENCENDIDO) == false) {
_sound->playMusicTrack(27);
checkIngredients();
_dialog->say(_res->_ingameTexts[CUIDADOIMPRUDENTE]);
@@ -1234,7 +1230,6 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
_sound->playSound(_room->_roomSfx[0], 0); // Belch
waitForSoundEnd();
_graphics->fadeToBlack(10);
- // update conversaton state
_alfredState.x = 300;
_alfredState.y = 238;
waitForSoundEnd();
@@ -1353,9 +1348,7 @@ void PelrockEngine::closeEgyptMuseumDoor(HotSpot *hotspot) {
void PelrockEngine::pushSymbol1(HotSpot *hotspot) {
if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
- debug("Current symbols pulled: %d", symbolsPulled);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x1);
- debug("New symbols pulled: %d", _state->getFlag(FLAG_SYMBOLS_PUSHED));
checkAllSymbols();
}
}
@@ -1363,9 +1356,7 @@ void PelrockEngine::pushSymbol1(HotSpot *hotspot) {
void PelrockEngine::pushSymbol2(HotSpot *hotspot) {
if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
- debug("Current symbols pulled: %d", symbolsPulled);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x2);
- debug("New symbols pulled: %d", _state->getFlag(FLAG_SYMBOLS_PUSHED));
checkAllSymbols();
}
}
@@ -1373,9 +1364,7 @@ void PelrockEngine::pushSymbol2(HotSpot *hotspot) {
void PelrockEngine::pushSymbol3(HotSpot *hotspot) {
if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
- debug("Current symbols pulled: %d", symbolsPulled);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x4);
- debug("New symbols pulled: %d", _state->getFlag(FLAG_SYMBOLS_PUSHED));
checkAllSymbols();
}
}
@@ -1383,16 +1372,13 @@ void PelrockEngine::pushSymbol3(HotSpot *hotspot) {
void PelrockEngine::pushSymbol4(HotSpot *hotspot) {
if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
- debug("Current symbols pulled: %d", symbolsPulled);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x8);
- debug("New symbols pulled: %d", _state->getFlag(FLAG_SYMBOLS_PUSHED));
checkAllSymbols();
}
}
void PelrockEngine::checkAllSymbols() {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
- debug("Checking symbols, current value: %d", symbolsPulled);
if (symbolsPulled == 0x0F) {
// Activates animation
_sound->playSound(_room->_roomSfx[0]);
@@ -1498,6 +1484,7 @@ void PelrockEngine::guardMovement() {
while (!shouldQuit()) {
_events->pollEvent();
renderScene();
+ // has the guard move right, up, left, then disappear behind the pyramid
if (sprite->x >= 339 && state == 0) {
state = 1;
sprite->animData[0].movementFlags = 0x240; // Move up
@@ -1510,7 +1497,6 @@ void PelrockEngine::guardMovement() {
sprite->zOrder = 255; // Hide sprite
break;
}
- debug("Guard position: (%d, %d), state: %d", sprite->x, sprite->y, state);
_screen->update();
g_system->delayMillis(10);
}
@@ -1559,7 +1545,6 @@ void PelrockEngine::playSpecialAnim(uint32 offset, bool compressed, int x, int y
}
_screen->markAllDirty();
_screen->update();
- // _events->waitForKey();
g_system->delayMillis(10);
}
animSurface.free();
@@ -1567,7 +1552,7 @@ void PelrockEngine::playSpecialAnim(uint32 offset, bool compressed, int x, int y
}
void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
- // Remove whichever stone item was used (91 = Egyptian stone, 92 = mud/clay)
+ // Remove whichever stone item was used (91 = stone, 92 = mud/clay)
_state->removeInventoryItem(inventoryObject);
Sprite *masters = _room->findSpriteByExtra(600);
@@ -1729,7 +1714,6 @@ void PelrockEngine::pickUpStones(HotSpot *hotspot) {
} else {
addInventoryItem(91);
_state->setFlag(FLAG_PIEDRAS_COGIDAS, _state->getFlag(FLAG_PIEDRAS_COGIDAS) + 1);
- debug("Piedras cogidas: %d", _state->getFlag(FLAG_PIEDRAS_COGIDAS));
}
}
@@ -1785,7 +1769,7 @@ void PelrockEngine::useWigWithPot(int inventoryObject, HotSpot *hotspot) {
void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
_state->removeInventoryItem(inventoryObject);
- if(inventoryObject == 86) {
+ if (inventoryObject == 86) {
addInventoryItem(76);
}
_state->setFlag(FLAG_FORMULA_MAGICA, _state->getFlag(FLAG_FORMULA_MAGICA) + 1);
@@ -1879,7 +1863,6 @@ void PelrockEngine::closeArchitectDoorFromInside(HotSpot *hotspot) {
}
void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
- debug("Performing action trigger: %d", actionTrigger);
switch (actionTrigger) {
case 257: // look portrait
_sound->playMusicTrack(25, false);
@@ -1895,7 +1878,6 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
_dialog->say(_res->_ingameTexts[TRABAJARIA_MEJOR_SI_NO_ME_MOLESTARA]);
break;
case 270:
- // loadExtraScreenAndPresent(9);
_state->stateGame = COMPUTER;
break;
case 280:
@@ -2054,10 +2036,10 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
debug("Using item %d on Alfred", inventoryObject);
switch (inventoryObject) {
- case 9: // carta
+ case 9: // Letter
_dialog->say(_res->_ingameTexts[CORRESPONDENCIA_AJENA]);
break;
- case 34: // Como hacerse rico...
+ case 34: // How to become rich book
_dialog->say(_res->_ingameTexts[PERIODICOSENSACIONALISTA], 1);
break;
case 63: // Recipe
@@ -2084,7 +2066,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_dialog->say(_res->_ingameTexts[YASEEGIPCIO]);
_state->setFlag(FLAG_ALFRED_SABE_EGIPCIO, true);
break;
- case 24:
+ case 24: // Encyclopedia
if (_state->getFlag(FLAG_RIDDLE_PRESENTED) == true) {
_dialog->say(_res->_ingameTexts[CAPITULOPARADOJAS]);
_state->setCurrentRoot(25, 44, 0);
@@ -2095,7 +2077,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_state->setCurrentRoot(14, 2, 0);
}
break;
- case 64:
+ case 64: // Formula for time travel
playAlfredSpecialAnim(0);
loadExtraScreenAndPresent(5);
if (_state->getFlag(FLAG_ALFRED_SABE_EGIPCIO)) {
@@ -2104,7 +2086,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_dialog->say(_res->_ingameTexts[QUELASTIMA_NOSEEGIPCIO]);
}
break;
- case 88: {
+ case 88: { // spellbook
if (_room->_currentRoomNumber != 28 &&
(_room->_currentRoomNumber < 51 || _room->_currentRoomNumber > 54)) {
_dialog->say(_res->_ingameTexts[AQUI_NO_NECESITO]);
@@ -2147,19 +2129,15 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
case 54: {
_sound->playSound(_room->_roomSfx[8], 0);
_dialog->say(_res->_ingameTexts[DIOSHALCON + spell->page], 1);
- debug("Flight spell cast in room %d, spell page: %d", _room->_currentRoomNumber, spell->page);
int flightIndex = _room->_currentRoomNumber - 51;
- debug("Correct page for this spell is = %d", kFlightRooms[flightIndex].spellPage);
if (_flightSorcererAppeared && !_flightInBlockingAnim && spell->page == kFlightRooms[flightIndex].spellPage) {
_state->setFlag(FLAG_COMO_ESTAN_LOS_DIOSES, _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) | (1 << flightIndex));
- debug("Flight spell successful, starting animation and updating state");
- debug("Updated FLAG_COMO_ESTAN_LOS_DIOSES: %d", _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES));
_sound->playSound(_room->_roomSfx[1], 0);
smokeAnimation(kFlightRooms[flightIndex].spriteIdx, true);
_room->addStickerToRoom(_room->_currentRoomNumber, 127 + flightIndex);
_room->addStickerToRoom(52, 106 + flightIndex);
- if(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) == 15) { // all 4 spells successful
+ if (_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) == 15) { // all 4 spells successful
HotSpot hotspot = HotSpot();
hotspot.actionFlags = 0;
hotspot.extra = 999;
@@ -2171,8 +2149,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
hotspot.index = 8;
_room->changeHotspot(52, hotspot);
}
- }
- else {
+ } else {
_sound->playSound(_room->_roomSfx[2], 0);
}
break;
@@ -2192,7 +2169,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_dialog->say(_res->_ingameTexts[PARECE_COMBINACION_CAJAFUERTE]);
_state->setFlag(FLAG_CLAVE_CAJA_FUERTE, true);
break;
- case 108:
+ case 108: // glue + patches
case 109: {
if (_state->hasInventoryItem(110) == true) {
@@ -2219,14 +2196,14 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
loadExtraScreenAndPresent(7);
break;
}
- case 97: {
+ case 97: { // pyramid map
playAlfredSpecialAnim(1);
loadExtraScreenAndPresent(11);
_dialog->say(_res->_ingameTexts[MEHANTOMADO_EL_PELO]);
_state->setCurrentRoot(43, 1, 0);
break;
}
- case 98: {
+ case 98: { // correct pyramid blueprints
chooseCorrectDoor();
break;
}
@@ -2245,7 +2222,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
}
default: {
- // Original game incorrectly checked until object 47
+ // Original game incorrectly checked until object 47; Reading any book.
if (inventoryObject >= 11 && inventoryObject <= 58) {
playAlfredSpecialAnim(0);
_dialog->say(_res->_ingameTexts[LIBRO_ABURRIDO]);
@@ -2261,13 +2238,13 @@ void PelrockEngine::sayRandomIncorrectResponse() {
byte response = (byte)getRandomNumber(15);
_dialog->say(_res->_ingameTexts[154 + response]);
}
+
void PelrockEngine::chooseCorrectDoor() {
playAlfredSpecialAnim(1);
byte puertaBuena = _state->getFlag(FLAG_PUERTA_BUENA);
if (puertaBuena == 0) { // if not set yet, choose randomly
int choice = getRandomNumber(1);
_state->setFlag(FLAG_PUERTA_BUENA, choice + 1);
- debug("Randomly chosen good door: %d", _state->getFlag(FLAG_PUERTA_BUENA));
}
puertaBuena = _state->getFlag(FLAG_PUERTA_BUENA);
Common::String doorText = _res->_izquierda;
@@ -2282,6 +2259,9 @@ void PelrockEngine::chooseCorrectDoor() {
_dialog->say(fullTextArray);
}
+/**
+ * When using amulet with statue, the statue turns red-ish and then starts to talk.
+ */
void PelrockEngine::animateStatuePaletteFade(bool reverse) {
struct StatuePaletteData {
uint16 x; // 368
@@ -2324,10 +2304,8 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
exeFile.close();
- // Animation parameters
- const int numFrames = 7; // 7 step updates total
+ const int numFrames = 7;
- // Get current palette
byte currentPalette[768];
memcpy(currentPalette, _room->_roomPalette, 768);
@@ -2342,7 +2320,6 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
for (int i = 0; i < 16; i++) {
byte paletteIndex = paletteData.indices[i];
- // Determine source and target based on direction
byte *srcColor = reverse ? paletteData.target[i] : paletteData.source[i];
byte *dstColor = reverse ? paletteData.source[i] : paletteData.target[i];
@@ -2351,13 +2328,11 @@ void PelrockEngine::animateStatuePaletteFade(bool reverse) {
byte g6 = srcColor[1] + ((dstColor[1] - srcColor[1]) * frame) / numFrames;
byte b6 = srcColor[2] + ((dstColor[2] - srcColor[2]) * frame) / numFrames;
- // Convert 6-bit VGA (0-63) to 8-bit (0-255) by shifting left 2 bits
currentPalette[paletteIndex * 3 + 0] = r6 << 2;
currentPalette[paletteIndex * 3 + 1] = g6 << 2;
currentPalette[paletteIndex * 3 + 2] = b6 << 2;
}
- // Apply the palette
g_system->getPaletteManager()->setPalette(currentPalette, 0, 256);
frame++;
}
@@ -2374,7 +2349,7 @@ void PelrockEngine::checkObjectsForPart2() {
if (_state->hasInventoryItem(17) &&
_state->hasInventoryItem(59) &&
_state->hasInventoryItem(24)) {
- if(_state->getFlag(FLAG_AGENCIA_ABIERTA) == false) {
+ if (_state->getFlag(FLAG_AGENCIA_ABIERTA) == false) {
_room->addStickerToRoom(19, 54, PERSIST_BOTH);
_room->addStickerToRoom(19, 55, PERSIST_BOTH);
_room->addStickerToRoom(19, 56, PERSIST_BOTH);
@@ -2393,9 +2368,7 @@ void PelrockEngine::waitForActionEnd() {
}
/**
- * Handler for picking up object with extra_id 472 in Room 28.
- * Loads a special palette from ALFRED.7 at offset 0x1610CE and
- * fades to it using the step-wise palette transition.
+ * Picking up matches in room 28 has the palette change to "lighten it up".
*/
void PelrockEngine::pickUpMatches(HotSpot *hotspot) {
@@ -2468,7 +2441,6 @@ void PelrockEngine::antiPiracyEffect() {
_screen->update();
g_system->delayMillis(10);
}
-
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index 22d56c5c761..8d4609c5770 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -50,7 +50,6 @@ bool LargeFont::load(const Common::String &filename) {
const int dataSize = numChars * paddedHeight * paddedWidth; // 96 characters à 14 à 26 bytes
byte *rawFontData = new byte[numChars * 48]; // original format: 96 Ã 48 bytes
file.read(rawFontData, numChars * 48);
- debug("LargeFont::load: Loading large font data from %s, size %d bytes", filename.c_str(), dataSize);
file.close();
delete[] _fontData;
@@ -72,7 +71,7 @@ bool LargeFont::load(const Common::String &filename) {
mask[i + pad][bit + 8 + pad] = (rowByte2 & (0x80 >> bit)) != 0;
}
}
-
+ // adds a border mask to the original font
bool borderMask[paddedHeight][paddedWidth] = {false};
for (int y = 0; y < paddedHeight; y++) {
diff --git a/engines/pelrock/fonts/small_font.cpp b/engines/pelrock/fonts/small_font.cpp
index 93d06bb31d9..b439b5db2f9 100644
--- a/engines/pelrock/fonts/small_font.cpp
+++ b/engines/pelrock/fonts/small_font.cpp
@@ -41,7 +41,6 @@ bool SmallFont::load(const Common::String &filename) {
file.seek(kSmallFontOffset, SEEK_SET);
const int dataSize = kNumChars * 8; // 256 characters, 8x8 pixels
- debug("SmallFont::load: Loading font data of size %d from %s", dataSize, filename.c_str());
_fontData = new byte[dataSize];
file.read(_fontData, dataSize);
file.close();
diff --git a/engines/pelrock/fonts/small_font_double.cpp b/engines/pelrock/fonts/small_font_double.cpp
index 19fb92645cf..4ebc5a580ed 100644
--- a/engines/pelrock/fonts/small_font_double.cpp
+++ b/engines/pelrock/fonts/small_font_double.cpp
@@ -18,8 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
-#include "common/debug.h"
#include "pelrock/fonts/small_font_double.h"
+#include "common/debug.h"
namespace Pelrock {
@@ -31,7 +31,6 @@ DoubleSmallFont::~DoubleSmallFont() {
void DoubleSmallFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
if (!_fontData || chr > kNumChars - 1) {
- // debug("DoubleSmallFont::drawChar: Invalid char %d", chr);
return;
}
int charOffset = chr * 8;
diff --git a/engines/pelrock/fonts/small_font_double.h b/engines/pelrock/fonts/small_font_double.h
index 5bf265ca0fa..68a603ff28e 100644
--- a/engines/pelrock/fonts/small_font_double.h
+++ b/engines/pelrock/fonts/small_font_double.h
@@ -29,12 +29,15 @@
#include "pelrock/fonts/small_font.h"
namespace Pelrock {
+
+/**
+ * Same as SmallFont but doubling the height of each character
+ */
class DoubleSmallFont : public SmallFont {
public:
DoubleSmallFont();
~DoubleSmallFont();
-
int getFontHeight() const override { return CHAR_HEIGHT; };
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
@@ -44,4 +47,3 @@ private:
} // End of namespace Pelrock
#endif
-
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 0aace022921..cd344ae194b 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -71,15 +71,13 @@ void VideoManager::playIntro() {
ChunkHeader chunk;
readChunk(videoFile, chunk);
- if(_events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
+ if (_events->_lastKeyEvent == Common::KEYCODE_ESCAPE) {
break;
}
switch (chunk.chunkType) {
case 1:
case 2: {
- // Visual frame: wait for chrono timing before presenting
- // Fix Bug 2/3: only visual frames (types 1/2) participate in chrono gating
Subtitle *subtitle = getSubtitleForFrame(frameCounter);
int frameSkip = subtitle != nullptr ? 4 : 2;
while (!g_engine->shouldQuit() && _events->_lastKeyEvent != Common::KEYCODE_ESCAPE) {
@@ -90,11 +88,9 @@ void VideoManager::playIntro() {
g_system->delayMillis(10);
}
- // Fix Bug 1: capture current frame BEFORE increment so audio fires at the correct frame
int currentFrame = frameCounter++;
processFrame(chunk, currentFrame);
- // Fix Bug 1: all audio checks use currentFrame (not the already-incremented frameCounter)
if (_voiceEffect.contains(currentFrame)) {
// Wait for any playing voice to finish before starting new one
while (_sound->isPlaying(0)) {
@@ -127,9 +123,9 @@ void VideoManager::playIntro() {
_sound->playMusicTrack(music.trackNumber, true);
}
- // Fix Bug 4: subtitles are suppressed in the blackout range (frames 571-669)
- bool inBlackoutRange = (currentFrame >= 571 && currentFrame <= 669);
- if (subtitle != nullptr && !inBlackoutRange) {
+ // subtitles are suppressed in the frame range 571-669)
+ bool skipSubs = (currentFrame >= 571 && currentFrame <= 669);
+ if (subtitle != nullptr && !skipSubs) {
Common::StringArray lines = _dialog->wordWrap(subtitle->text)[0];
byte color;
@@ -149,8 +145,7 @@ void VideoManager::playIntro() {
loadPalette(chunk);
break;
case 6:
- // Fix Bug 3: type 6 is a timing pad. Original costs ~20ms per chunk.
- // Do NOT gate on chrono â process immediately with a short delay.
+ // type 6 is merely wait for 20ms
g_system->delayMillis(20);
break;
default:
@@ -159,7 +154,6 @@ void VideoManager::playIntro() {
}
}
- debug("Total frames played: %d", frameCounter);
videoFile.close();
}
@@ -305,8 +299,7 @@ void VideoManager::initMetadata() {
} else if (nextChar == 'f') {
AudioEffect sfx = readAudioEffect(metadataFile);
_sfxEffect[sfx.startFrame] = sfx;
- }
- else if (nextChar == 'c') {
+ } else if (nextChar == 'c') {
MusicEffect music = readMusicEffect(metadataFile);
_musicEffect[music.startFrame] = music;
}
@@ -379,7 +372,8 @@ Subtitle VideoManager::readSubtitle(Common::File &metadataFile) {
int valueIndex = 0;
// Skip spaces after "/t"
- while (!metadataFile.eos() && metadataFile.readByte() == ' ');
+ while (!metadataFile.eos() && metadataFile.readByte() == ' ')
+ ;
metadataFile.seek(-1, SEEK_CUR); // Step back one byte
// Parse 4 space-delimited numbers
@@ -402,14 +396,11 @@ Subtitle VideoManager::readSubtitle(Common::File &metadataFile) {
}
}
- // metadataFile.skip(1); // Skip the extra space
-
subtitle.startFrame = values[0];
subtitle.endFrame = values[1];
subtitle.x = values[2];
subtitle.y = values[3];
- // Read text until CRLF (0x0D 0x0A)
subtitle.text.clear();
// skip leading spaces in subtitle tex
@@ -418,12 +409,13 @@ Subtitle VideoManager::readSubtitle(Common::File &metadataFile) {
nextByte = metadataFile.readByte();
} while (nextByte == ' ' && !metadataFile.eos());
- if(nextByte == 0x08) {
+ if (nextByte == 0x08) {
subtitle.text += '@';
} else {
subtitle.text += decodeChar(nextByte);
}
+ // Read text until CRLF (0x0D 0x0A)
while (!metadataFile.eos()) {
char c = metadataFile.readByte();
@@ -436,7 +428,7 @@ Subtitle VideoManager::readSubtitle(Common::File &metadataFile) {
subtitle.text += decodeChar(next);
}
} else {
- if(c == 0x00) {
+ if (c == 0x00) {
// do nothing
}
if (c == 0x08)
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index 392734eb5fc..07f79a3606a 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -30,10 +30,10 @@
namespace Pelrock {
struct ChunkHeader {
- uint32 blockCount; // +0x00: Number of 0x5000-byte blocks
- uint32 dataOffset; // +0x04: Varies by chunk type
- byte chunkType; // +0x08: 1=RLE, 2=BlockCopy, 3=End, 4=Palette, 6=Special
- // +0x0D: Frame data begins
+ uint32 blockCount; // +0x00: Number of 0x5000-byte blocks
+ uint32 dataOffset; // +0x04: Varies by chunk type
+ byte chunkType; // +0x08: 1=RLE, 2=BlockCopy, 3=End, 4=Palette, 6=Special
+ // +0x0D: Frame data begins
byte *data;
};
@@ -67,7 +67,7 @@ static const uint32 chunkSize = 0x5000;
static const int video_special_chars[] = {
0x83, // inverted ?
0x82, // inverted !
- 165, // capital N tilde
+ 0xA5, // capital N tilde
0x80, // small n tilde
0x7F, // small u tilde
0x7E, // small o tilde
@@ -84,8 +84,7 @@ public:
ChronoManager *chrono,
LargeFont *largeFont,
DialogManager *dialog,
- SoundManager *sound
- );
+ SoundManager *sound);
~VideoManager();
void playIntro();
@@ -98,7 +97,7 @@ private:
SoundManager *_sound;
void loadPalette(ChunkHeader &chunk);
byte *decodeCopyBlock(byte *data, uint32 offset);
- byte *decodeRLE(byte *data, size_t size, uint32 offset);
+ byte *decodeRLE(byte *data, size_t size, uint32 offset);
void readChunk(Common::SeekableReadStream &stream, ChunkHeader &chunk);
void processFrame(ChunkHeader &chunk, const int frameCount);
void presentFrame();
Commit: ffd5b9652eede8db6fdec6f79f2ecf975a07af18
https://github.com/scummvm/scummvm/commit/ffd5b9652eede8db6fdec6f79f2ecf975a07af18
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:40+02:00
Commit Message:
PELROCK: Cleanup of dialog and computer
Changed paths:
engines/pelrock/backgroundbook.cpp
engines/pelrock/chrono.cpp
engines/pelrock/chrono.h
engines/pelrock/computer.cpp
engines/pelrock/computer.h
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/fonts/large_font.cpp
engines/pelrock/fonts/small_font.h
engines/pelrock/resources.cpp
diff --git a/engines/pelrock/backgroundbook.cpp b/engines/pelrock/backgroundbook.cpp
index 106ae4d079a..b9c78d1d897 100644
--- a/engines/pelrock/backgroundbook.cpp
+++ b/engines/pelrock/backgroundbook.cpp
@@ -29,8 +29,8 @@
namespace Pelrock {
static const uint32 kBgBookButtonsOffset = 3188448; // ALFRED.7 â UI buttons
-static const uint32 kRoomNamesOffset = 299797; // JUEGO.EXE â room name strings
-static const uint32 kRoomNamesSize = 1297;
+static const uint32 kRoomNamesOffset = 299797; // JUEGO.EXE â room name strings
+static const uint32 kRoomNamesSize = 1297;
BackgroundBook::BackgroundBook(PelrockEventManager *eventMan, ResourceManager *res, RoomManager *room)
: _events(eventMan), _res(res), _room(room) {
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index a020350332b..89d00a69c83 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -39,7 +39,7 @@ void ChronoManager::updateChrono() {
if ((currentTime - _lastTick) >= kTickMs / _speedMultiplier) {
_gameTick = true;
- if(!_pauseCounter) {
+ if (!_pauseCounter) {
_frameCount++;
}
_lastTick = currentTime;
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 0e8b5f3b8b9..602d721d2b0 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -25,13 +25,7 @@
namespace Pelrock {
-// const int kTickMs = 18;
-// const int kTickMs = 100;
-// const int kTickMs = 15;
-// const int kTickMs = 33;
-// const int kTickMs = 38;
const int kTickMs = 55;
-// const int kTickMs = 60;
const int kHalfTickMultiplier = 2;
class ChronoManager {
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index 5c90775c4ac..95a7bb81404 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -37,7 +37,6 @@ Computer::Computer(PelrockEventManager *eventMan)
_currentResult(0),
_memorizedBookIndex(-1),
_events(eventMan) {
-
init();
}
@@ -78,8 +77,6 @@ void Computer::init() {
book.inventoryIndex = alfred7File.readByte() - 55;
book.shelf = alfred7File.readByte();
book.available = alfred7File.readByte() == 2;
- // book.index = book.available ? index++ : -1;
- // book.index2 = index2++;
_libraryBooks.push_back(book);
}
@@ -205,9 +202,9 @@ void Computer::drawScreen() {
int titlePlaceholderIndex = titleLine.findFirstOf("XXXX");
int titleIndex = 0;
- while(titleIndex < book.title.size()) {
+ while (titleIndex < book.title.size()) {
Common::String thisLine;
- if(titleIndex == 0) {
+ if (titleIndex == 0) {
thisLine = titleLine;
thisLine.replace(titlePlaceholderIndex, titleLine.size() - titlePlaceholderIndex, book.title[titleIndex]);
} else {
@@ -222,9 +219,9 @@ void Computer::drawScreen() {
int authorPlaceholderIndex = authorLine.findFirstOf("XXXX");
int authorIndex = 0;
- while(authorIndex < book.author.size()) {
+ while (authorIndex < book.author.size()) {
Common::String thisLine;
- if(authorIndex == 0) {
+ if (authorIndex == 0) {
thisLine = authorLine;
thisLine.replace(authorPlaceholderIndex, authorLine.size() - authorPlaceholderIndex, book.author[authorIndex]);
} else {
@@ -240,7 +237,7 @@ void Computer::drawScreen() {
genreLine.replace(genrePlaceholderIndex, genreLine.size() - genrePlaceholderIndex, book.genre);
g_engine->_graphics->drawColoredText(g_engine->_screen, genreLine, textX, textY + increment * 2, 340, defaultColor, g_engine->_smallFont);
- // Situacion (location/availability)
+ // "Situacion" (location/availability)
Common::String situacionLine = _computerText[6][0];
int situacionPlaceholderIndex = situacionLine.findFirstOf("XXXX");
situacionLine.replace(situacionPlaceholderIndex, situacionLine.size() - situacionPlaceholderIndex, book.available ? _computerText[8][0] : _computerText[9][0]);
@@ -299,7 +296,7 @@ void Computer::handleResultsDisplay() {
if (_events->_lastKeyEvent == Common::KEYCODE_s) {
if (!_searchResults.empty()) {
_currentResult = (_currentResult + 1);
- if(_currentResult >= _searchResults.size())
+ if (_currentResult >= _searchResults.size())
_state = STATE_MAIN_MENU;
}
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
@@ -336,7 +333,6 @@ void Computer::memorizeBook(int bookIndex) {
g_engine->_state->selectedBookIndex = book.inventoryIndex;
g_engine->_state->bookLetter = book.title[0][0];
- debug("Memorized book '%s' with index %d, shelf %d, letter %c", book.title[0].c_str(), g_engine->_state->selectedBookIndex, g_engine->_state->libraryShelf, g_engine->_state->bookLetter);
}
void Computer::performSearch() {
diff --git a/engines/pelrock/computer.h b/engines/pelrock/computer.h
index 7e9379ccad8..403a620717d 100644
--- a/engines/pelrock/computer.h
+++ b/engines/pelrock/computer.h
@@ -33,39 +33,31 @@ namespace Pelrock {
// Book data location in ALFRED.7
static const uint32 kBookDataOffset = 0x309E0;
static const uint32 kBookDataEnd = 0x33F05;
-static const int kBookEntrySize = 108; // 55 + 30 + 20 + 1 + 1 + 1
// Field sizes
static const int kBookTitleSize = 55;
static const int kBookAuthorSize = 30;
static const int kBookGenreSize = 20;
-// Status byte values
-static const byte kBookStatusCatalogOnly = 0x01; // No physical copy
-static const byte kBookStatusPhysical = 0x02; // Has physical copy on shelf
-
struct LibraryBook {
- Common::StringArray title; //55 bytes for title
- Common::StringArray author; //30 bytes for author
- Common::String genre; //20 bytes for genre
- byte inventoryIndex;
- byte shelf; // 1-3 for row number, 0 if catalog-only
- bool available; // true = can be found on shelf, false = catalog only
+ Common::StringArray title; // 55 bytes for title
+ Common::StringArray author; // 30 bytes for author
+ Common::String genre; // 20 bytes for genre
+ byte inventoryIndex;
+ byte shelf; // 1-3 for row number
+ bool available; // true = can be found on shelf, false = catalog only
};
class Computer {
public:
Computer(PelrockEventManager *eventMan);
-
~Computer();
/**
* @return Book index if a book was memorized, -1 otherwise
*/
int run();
- Common::String _titleMsg;
- Common::String _authorMsg;
- Common::String _memorizedMsg; // "Bueno... Tendre que buscar en la estanteria de la %c"
+ Common::String _memorizedMsg; // "Bueno... Tendre que buscar en la estanteria de la %c"
private:
enum ComputerState {
@@ -76,19 +68,21 @@ private:
STATE_EXIT
};
- PelrockEventManager *_events;
+ PelrockEventManager *_events = nullptr;
Graphics::ManagedSurface _backgroundScreen;
- byte *_palette;
+ byte *_palette = nullptr;
// State variables
ComputerState _state;
- char _searchLetter;
- int _searchType; // 0 = title, 1 = author
+ char _searchLetter = ' ';
+ int _searchType = 0; // 0 = title, 1 = author
Common::Array<int> _searchResults;
Common::Array<LibraryBook> _libraryBooks;
int _currentResult;
- int _memorizedBookIndex; // Index of book that was memorized (-1 if none)
+ int _memorizedBookIndex; // Index of book that was memorized (-1 if none)
int _lineHeight;
+ Common::String _titleMsg;
+ Common::String _authorMsg;
Common::Array<Common::StringArray> _computerText;
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index ee8e99f5b27..dd810023823 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -51,7 +51,7 @@ uint32 DialogManager::readTextBlock(
outText = "";
// Skip control bytes at start
- if (data[pos] == CTRL_TEXT_TERMINATOR) {
+ if (data[pos] == kCtrlTextTerminator) {
pos += 2;
}
@@ -60,14 +60,14 @@ uint32 DialogManager::readTextBlock(
}
// Check for speaker ID marker
- if (data[pos] == CTRL_SPEAKER_ID) {
+ if (data[pos] == kCtrlSpeakerId) {
pos++;
if (pos < dataSize) {
outSpeakerId = data[pos];
}
}
// Check for dialogue marker (choice text)
- else if (data[pos] == CTRL_DIALOGUE_MARKER || data[pos] == CTRL_DIALOGUE_MARKER_ONEOFF) {
+ else if (data[pos] == kCtrlDialogueMarker || data[pos] == kCtrlDialogueMarkerOneoff) {
pos++; // Skip marker
// Skip choice index
@@ -79,23 +79,24 @@ uint32 DialogManager::readTextBlock(
pos += 2;
}
- int lineIndex = data[++pos];
- debug("Line index %d", lineIndex);
+
+ // Line index could be useful for translations
+ /*int lineIndex = data[++pos]; */
+ pos++; // Skip line index
pos++; // blank
- // debug("Reading text block starting at pos %u, line index %d, speaker ID %d", startPos, lineIndex, outSpeakerId);
// Read text until control byte
while (pos < dataSize) {
byte b = data[pos];
// End markers - stop reading text
- if (b == CTRL_END_TEXT || b == CTRL_END_CONVERSATION || b == CTRL_ACTION_AND_END ||
- b == CTRL_END_BRANCH || b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_ONEOFF ||
- b == CTRL_TEXT_TERMINATOR || b == CTRL_ALT_END_MARKER_1 || b == CTRL_ACTION_AND_CONTINUE ||
- b == CTRL_GO_BACK || b == CTRL_SPEAKER_ID) {
+ if (b == kCtrlEndText || b == kCtrlEndConversation || b == kCtrlActionAndEnd ||
+ b == kCtrlEndBranch || b == kCtrlDialogueMarker || b == kCtrlDialogueMarkerOneoff ||
+ b == kCtrlTextTerminator || b == kCtrlAltEndMarker1 || b == kCtrlActionAndContinue ||
+ b == kCtrlGoBack || b == kCtrlSpeakerId) {
break;
}
- if (b == CTRL_LINE_CONTINUE || b == CTRL_PAGE_BREAK_CONV) {
+ if (b == kCtrlLineContinue || b == kCtrlPageBreakConv) {
warning("Found unexpected line/page break control code in readTextBlock at pos %u", pos);
outText += ' ';
pos++;
@@ -103,7 +104,7 @@ uint32 DialogManager::readTextBlock(
}
// Regular text - does not need decoding
- if (b >= CHAR_SPACE && b <= 0x83) {
+ if (b >= kCtrlSpace && b <= 0x83) {
outText += b;
}
pos++;
@@ -115,6 +116,7 @@ uint32 DialogManager::readTextBlock(
void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, Graphics::ManagedSurface &compositeBuffer) {
int overlayHeight = choices->size() * kChoiceHeight + 2;
+ // Grab the overlay position to start drawing the choices, and draw the choices there
Common::Point overlayPos = _graphics->showOverlay(overlayHeight, compositeBuffer);
for (uint i = 0; i < choices->size(); i++) {
ChoiceOption choice = (*choices)[i];
@@ -145,10 +147,13 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, Graphic
}
if (choice.charOffset > 0) {
+ //draw left arrow
drawText(compositeBuffer, g_engine->_doubleSmallFont, _leftArrow, 0, yPos, g_engine->_doubleSmallFont->getCharWidth(17), lArrowColor);
}
drawText(compositeBuffer, g_engine->_doubleSmallFont, choice.text.substr(choice.charOffset, 76), kChoicePadding, yPos, 620, choiceColor);
+
if (choice.charOffset + 76 < choice.text.size()) {
+ //draw right arrow
drawText(compositeBuffer, g_engine->_doubleSmallFont, _rightArrow, 640 - kArrowWidth, yPos, g_engine->_doubleSmallFont->getCharWidth(16), rArrowColor);
}
}
@@ -187,7 +192,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int16 yBasePos = 0;
if (speakerId == kAlfredColor) {
if (g_engine->_state->getFlag(FLAG_FROM_INTRO) == true) {
- debug("Setting special anim");
+ // Different talking animation for the post-intro sequence in which Alfred speaks in bed
g_engine->_alfredState.setState(ALFRED_SPECIAL_ANIM);
} else {
g_engine->_alfredState.setState(ALFRED_TALKING);
@@ -213,6 +218,9 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
displayDialogue(dialogueLines, speakerId, xBasePos, yBasePos); // Default position
}
+/**
+ * Simply wait tick period * char count
+ */
uint32 calcPageTtlMs(Common::Array<Common::String> dialogueLine) {
uint32 charCount = 0;
for (uint i = 0; i < dialogueLine.size(); i++) {
@@ -240,7 +248,6 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_dialogActive = true;
int curPage = 0;
bool fromIntro = g_engine->_state->getFlag(FLAG_FROM_INTRO) == true;
- debug("Displaying dialog, from intro = %d", fromIntro);
uint32 pageTtlMs = calcPageTtlMs(dialogueLines[curPage]);
uint32 pageStartMs = g_system->getMillis();
@@ -308,7 +315,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
}
if (fromIntro && g_engine->_res->_isSpecialAnimFinished) {
- debug("Dismissing due to speciawl anim ending!");
+ // in post-intro, text stops only after the animation is done!
break;
}
@@ -323,7 +330,6 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
}
void DialogManager::displayDialogue(Common::String text, byte speakerId) {
- debug("Displaying dialogue: \"%s\" (Speaker ID: %d)", text.c_str(), speakerId);
displayDialogue(wordWrap(text), speakerId);
}
@@ -379,19 +385,18 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
int firstChoiceIndex = -1;
// Scan for choices with SAME index
- // The key insight: choices at the same level may be scattered throughout the data,
- // separated by deeper-level sub-branches. We must scan past higher-index choices
- // to find all choices at our level, but stop when we hit a LOWER index.
+ // Choices with the same index are not contiguous; for each choice the entire branch is laid out first.
+ // So we must scan past higher-index choices to find all choices at our level, but stop when we hit a LOWER index.
while (pos < dataSize) {
byte b = data[pos];
// Stop at end markers
- if (b == CTRL_ALT_END_MARKER_1 || b == CTRL_END_BRANCH || b == CTRL_ALT_SPEAKER_ROOT) {
+ if (b == kCtrlAltEndMarker1 || b == kCtrlEndBranch || b == kCtrlAltSpeakerRoot) {
break;
}
// Found a dialogue marker
- if (b == CTRL_DIALOGUE_MARKER || b == CTRL_DIALOGUE_MARKER_ONEOFF) {
+ if (b == kCtrlDialogueMarker || b == kCtrlDialogueMarkerOneoff) {
if (pos + 1 < dataSize) {
int choiceIndex = data[pos + 1];
@@ -404,33 +409,33 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
if (choiceIndex == firstChoiceIndex) {
ChoiceOption opt;
opt.room = g_engine->_room->_currentRoomNumber;
- opt.shouldDisableOnSelect = b == CTRL_DIALOGUE_MARKER_ONEOFF;
+ opt.shouldDisableOnSelect = b == kCtrlDialogueMarkerOneoff;
opt.choiceIndex = choiceIndex;
opt.dataOffset = pos;
pos += 2; // Move past marker + index
- if (data[pos] == CTRL_DISABLED_CHOICE) {
+ if (data[pos] == kCtrlDisabledChoice) {
opt.isDisabled = true;
}
// Parse the choice text
uint32 textPos = pos + 4;
while (textPos < dataSize) {
byte tb = data[textPos];
- if (tb == CTRL_END_TEXT || tb == CTRL_DIALOGUE_MARKER ||
- tb == CTRL_DIALOGUE_MARKER_ONEOFF || tb == CTRL_END_BRANCH ||
- tb == CTRL_ALT_END_MARKER_1) {
+ if (tb == kCtrlEndText || tb == kCtrlDialogueMarker ||
+ tb == kCtrlDialogueMarkerOneoff || tb == kCtrlEndBranch ||
+ tb == kCtrlAltEndMarker1) {
// Check if there is a terminator (F4 or F8) at the end of this choice's response
// Scan forward but stop at another choice marker or branch end
uint32 scanPos = textPos;
while (scanPos < dataSize) {
byte sb = data[scanPos];
// Stop scanning at another choice marker or branch boundaries
- if (sb == CTRL_DIALOGUE_MARKER || sb == CTRL_DIALOGUE_MARKER_ONEOFF ||
- sb == CTRL_END_BRANCH || sb == CTRL_ALT_END_MARKER_1 ||
- sb == CTRL_ALT_SPEAKER_ROOT) {
+ if (sb == kCtrlDialogueMarker || sb == kCtrlDialogueMarkerOneoff ||
+ sb == kCtrlEndBranch || sb == kCtrlAltEndMarker1 ||
+ sb == kCtrlAltSpeakerRoot) {
break;
}
// Found a conversation terminator - this choice ends the conversation
- if (sb == CTRL_END_CONVERSATION || sb == CTRL_ACTION_AND_END) {
+ if (sb == kCtrlEndConversation || sb == kCtrlActionAndEnd) {
opt.hasConversationEndMarker = true;
break;
}
@@ -458,8 +463,6 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
// This means we've gone past all choices at our level
break;
}
- // If choiceIndex > firstChoiceIndex, we're in a deeper sub-branch
- // Continue scanning to find more choices at our level
}
}
@@ -470,7 +473,7 @@ uint32 DialogManager::parseChoices(const byte *data, uint32 dataSize, uint32 sta
}
/**
- * Check if all sub-branches of the current choice level are exhausted.
+ * Check if all sub-branches of the current choice level are exhausted to mark the choice for disabling.
*
* Returns true if we should disable the current choice, which happens when:
* - There are no FB sub-branches at higher indices, OR
@@ -493,27 +496,25 @@ bool DialogManager::checkAllSubBranchesExhausted(const byte *data, uint32 dataSi
// NOTE: Do NOT stop at F4 (CTRL_END_CONVERSATION) - F4 markers appear between
// choices as terminators for each choice's response path. We need to scan
// past them to find all choices at the target level.
- if (b == CTRL_ALT_END_MARKER_1 || b == CTRL_END_BRANCH ||
- b == CTRL_ALT_SPEAKER_ROOT) {
+ if (b == kCtrlAltEndMarker1 || b == kCtrlEndBranch ||
+ b == kCtrlAltSpeakerRoot) {
break;
}
// For that one bug in room 26
// treat F0 as a boundary to prevent scanning past unreachable choices
- if (b == CTRL_GO_BACK && f0IsBoundary) {
+ if (b == kCtrlGoBack && f0IsBoundary) {
break;
}
// Found FB (one-time choice marker)
- if (b == CTRL_DIALOGUE_MARKER_ONEOFF && pos + 2 < dataSize) {
+ if (b == kCtrlDialogueMarkerOneoff && pos + 2 < dataSize) {
byte choiceIdx = data[pos + 1];
// Only check sub-branches (higher index = deeper level)
if (choiceIdx > currentChoiceLevel) {
// Check if NOT disabled (no FA at pos+2)
- if (data[pos + 2] != CTRL_DISABLED_CHOICE) {
- debug("checkAllSubBranchesExhausted: Active FB at pos %u, idx %d (current %d) - NOT exhausted",
- pos, choiceIdx, currentChoiceLevel);
+ if (data[pos + 2] != kCtrlDisabledChoice) {
return false; // Don't disable parent
}
} else if (choiceIdx <= currentChoiceLevel) {
@@ -526,7 +527,6 @@ bool DialogManager::checkAllSubBranchesExhausted(const byte *data, uint32 dataSi
pos++;
}
- debug("checkAllSubBranchesExhausted: All sub-branches exhausted at level %d", currentChoiceLevel);
return true;
}
@@ -550,22 +550,21 @@ void DialogManager::setCurSprite(int index) {
void DialogManager::startConversation(const byte *conversationData, uint32 dataSize, byte npcIndex, Sprite *animSet) {
if (!conversationData || dataSize == 0) {
- debug("startConversation: No conversation data");
+ warning("startConversation: No conversation data");
return;
}
setCurSprite(animSet ? animSet->index : -1);
- debug("Starting conversation with %d bytes of data, for npc %d, hotspot %d, currentRoot is = %d", dataSize, npcIndex, animSet ? animSet->index : -1, g_engine->_state->getCurrentRoot(g_engine->_room->_currentRoomNumber, npcIndex));
-
// Initialize conversation state
ConversationState state = initializeConversation(conversationData, dataSize, npcIndex);
bool skipToChoices = false;
Common::Stack<uint32> positionStack; // Stack to handle nested branches for "go back" functionality
+
// Main conversation loop
while (state.position < dataSize && !g_engine->shouldQuit()) {
state.position = skipControlBytes(conversationData, dataSize, state.position);
- if (state.position < dataSize && conversationData[state.position] == CTRL_GO_BACK) {
+ if (state.position < dataSize && conversationData[state.position] == kCtrlGoBack) {
if (handleGoBack(conversationData, positionStack, state.position, state)) {
skipToChoices = true;
} else {
@@ -600,10 +599,10 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// If not at a choice marker, there's more dialogue to read
if (peekPos < dataSize &&
- conversationData[peekPos] != CTRL_DIALOGUE_MARKER &&
- conversationData[peekPos] != CTRL_DIALOGUE_MARKER_ONEOFF &&
- conversationData[peekPos] != CTRL_END_CONVERSATION &&
- conversationData[peekPos] != CTRL_DISABLED_CHOICE) {
+ conversationData[peekPos] != kCtrlDialogueMarker &&
+ conversationData[peekPos] != kCtrlDialogueMarkerOneoff &&
+ conversationData[peekPos] != kCtrlEndConversation &&
+ conversationData[peekPos] != kCtrlDisabledChoice) {
continue;
}
}
@@ -618,23 +617,15 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
uint originalChoiceCount = choices->size();
addGoodbyeOptionIfNeeded(choices, state.currentChoiceLevel, originalChoiceCount);
- debug("Parsed %u choices", choices->size());
- for (uint i = 0; i < choices->size(); i++) {
- debug(" Choice %u (index %d): \"%s\" (Disabled: %s)", i, (*choices)[i].choiceIndex, (*choices)[i].text.c_str(),
- (*choices)[i].isDisabled ? "Yes" : "No");
- }
- debug("-----------------------");
-
if (choices->empty()) {
state.position = positionStack.empty() ? 0 : positionStack.pop();
if (state.position == 0) {
- debug("No choices and no previous position to go back to, ending conversation");
+ // No choices and no previous position to go back to, ending conversation
break;
}
checkAllSubBranchesExhausted(conversationData, dataSize, state.position, state.currentChoiceLevel - 1);
- debug("No choices found, popping back to previous choice menu, position %u", state.position);
+ // No choices found, popping back to previous choice menu, position %u
skipToChoices = true;
- // state.position = peekPos;
continue;
}
@@ -653,7 +644,6 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
if (!foundExpectedLevel) {
- debug("No choices found at level %d or %d, ending conversation", state.currentChoiceLevel, state.currentChoiceLevel + 1);
break;
}
}
@@ -661,8 +651,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
// Process user selection
int selectedIndex = 0;
if (choices->size() == 1) {
- // Auto-dialogue: display it automatically
- debug("Auto-selecting single choice: \"%s\"", (*choices)[0].text.c_str());
+ // Auto-dialogue: display it automatically if ony one choice!
selectedIndex = 0;
} else {
// Real choice: show menu and wait for selection
@@ -685,6 +674,9 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
debug("Conversation ended");
}
+/**
+ * Finds a conversation root for a given NPC
+ */
uint32 DialogManager::findRoot(int npc, int ¤tRoot, uint32 currentPosition, uint32 dataSize, const byte *conversationData) {
// Check if a specific root has been set for this room
int targetRoot = g_engine->_state->getCurrentRoot(g_engine->_room->_currentRoomNumber, npc);
@@ -692,7 +684,7 @@ uint32 DialogManager::findRoot(int npc, int ¤tRoot, uint32 currentPosition
if (targetRoot >= 0) {
// Skip to the specified root
while (currentRoot < targetRoot && currentPosition < dataSize) {
- if (conversationData[currentPosition] == CTRL_END_BRANCH) {
+ if (conversationData[currentPosition] == kCtrlEndBranch) {
currentPosition++; // Move past end branch marker
currentRoot++;
} else {
@@ -701,17 +693,19 @@ uint32 DialogManager::findRoot(int npc, int ¤tRoot, uint32 currentPosition
}
}
// If targetRoot is -1 or not set, use the first root (default behavior)
-
return currentPosition;
}
+/**
+ * Find the tree for the given NPC.
+ */
uint32 DialogManager::findSpeaker(byte npcIndex, uint32 dataSize, const byte *conversationData) {
// Find the speaker tree for this NPC; they are marked by 0xFE 0xXX where XX is NPC index + 1
bool speakerTreeOffsetFound = false;
int currentConversationTree = npcIndex + 1;
uint32 position = 0;
while (position < dataSize && !speakerTreeOffsetFound) {
- if (conversationData[position] == CTRL_ALT_SPEAKER_ROOT && conversationData[position + 1] == currentConversationTree) {
+ if (conversationData[position] == kCtrlAltSpeakerRoot && conversationData[position + 1] == currentConversationTree) {
speakerTreeOffsetFound = true;
position += 2; // Move past the speaker tree marker and npc index
} else {
@@ -722,11 +716,9 @@ uint32 DialogManager::findSpeaker(byte npcIndex, uint32 dataSize, const byte *co
}
// Skip control bytes that should be ignored
-// NOTE: 0xEB (CTRL_ALT_END_MARKER_2) must NOT be skipped here â it is an action-and-continue
-// trigger that must be processed by checkConversationEnd, not silently discarded.
uint32 DialogManager::skipControlBytes(const byte *data, uint32 dataSize, uint32 position) {
while (position < dataSize &&
- data[position] == CTRL_ALT_END_MARKER_1) {
+ data[position] == kCtrlAltEndMarker1) {
position++;
}
return position;
@@ -736,8 +728,8 @@ uint32 DialogManager::skipControlBytes(const byte *data, uint32 dataSize, uint32
uint32 DialogManager::peekNextMeaningfulByte(const byte *data, uint32 dataSize, uint32 position) {
uint32 peekPos = position;
while (peekPos < dataSize &&
- (data[peekPos] == CTRL_ALT_END_MARKER_1 ||
- data[peekPos] == CTRL_TEXT_TERMINATOR)) {
+ (data[peekPos] == kCtrlAltEndMarker1 ||
+ data[peekPos] == kCtrlTextTerminator)) {
peekPos++;
}
return peekPos;
@@ -753,7 +745,7 @@ ConversationState DialogManager::initializeConversation(const byte *data, uint32
state.lastSelectedChoice = ChoiceOption();
// Skip any junk at start until we find a speaker marker
- while (state.position < dataSize && data[state.position] != CTRL_SPEAKER_ID) {
+ while (state.position < dataSize && data[state.position] != kCtrlSpeakerId) {
state.position++;
}
@@ -765,24 +757,21 @@ ConversationState DialogManager::initializeConversation(const byte *data, uint32
// The cascading disable in disableChoiceIfNeeded should have already disabled
// the choices that led here. We just need to go back to the parent level.
bool DialogManager::handleGoBack(const byte *data, Common::Stack<uint32> &positionStack, uint32 position, ConversationState &state) {
- if (data[position] != CTRL_GO_BACK) {
+ if (data[position] != kCtrlGoBack) {
return false;
}
- debug("F0 Go Back hit at position %u, current level %d", position, state.currentChoiceLevel);
-
// Pop position stack - we're going back to parent level
uint32 parentPos = positionStack.empty() ? 0 : positionStack.pop();
if (parentPos == 0) {
- debug("F0: No parent position on stack, ending conversation");
+ // F0: No parent position on stack, ending conversation
return false;
}
// Go up one level
state.currentChoiceLevel--;
state.position = parentPos;
- debug("F0: Moved back to level %d, position %u", state.currentChoiceLevel, parentPos);
return true;
}
@@ -816,7 +805,7 @@ ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint
byte controlByte = data[position];
- if (controlByte == CTRL_END_CONVERSATION) {
+ if (controlByte == kCtrlEndConversation) {
// Bug in the original in room 45, root 1: The conversation data has F4 (END_CONV) after
// the opening NPC text instead of FD (END_TEXT), so the 3 choices that follow are
// unreachable. Treat F4 as FD specifically for this root to restore them.
@@ -825,28 +814,25 @@ ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint
if (room == 45 && currentRoot == 1 &&
peekPos < dataSize &&
(data[peekPos] == kCtrlDialogueMarker || data[peekPos] == kCtrlDialogueMarkerOneoff)) {
- debug("Room 45 Root 1: F4 followed by choice marker treated as FD (data bug workaround)");
result.nextPosition = position + 1;
return result;
}
- debug("End of conversation marker found");
result.shouldEnd = true;
return result;
}
- if (controlByte == CTRL_ACTION_AND_END) {
+ if (controlByte == kCtrlActionAndEnd) {
result.actionCode = data[position + 1] | (data[position + 2] << 8);
- debug("Action-and-end trigger %d encountered!", result.actionCode);
+ // Action-and-end trigger encountered
result.shouldEnd = true;
result.hasAction = true;
return result;
}
- if (controlByte == CTRL_ACTION_AND_CONTINUE) {
- // 0xEB: action-and-continue â dispatch the action but do NOT exit the conversation.
+ if (controlByte == kCtrlActionAndContinue) {
if (position + 2 < dataSize) {
result.actionCode = data[position + 1] | (data[position + 2] << 8);
- debug("Action-and-continue trigger %d encountered", result.actionCode);
+ // Action-and-continue trigger encountered
result.hasAction = true;
}
result.shouldEnd = false;
@@ -855,16 +841,24 @@ ConversationEndResult DialogManager::checkConversationEnd(const byte *data, uint
}
// Move past control byte
- if (controlByte == CTRL_END_TEXT) {
+ if (controlByte == kCtrlEndText) {
result.nextPosition = position + 1;
}
return result;
}
+/**
+ * When there are no choices that lead to ending conversation, a generic option is added, as long as
+ * _goodbyeDisabled is not set for the room.
+ *
+ * So Goodbye is added if:
+ * - Goodbye is not globally disabled for this room, AND
+ * - There are multiple choices (if only 1, it's auto-dialogue and shouldn't have goodbye), AND
+ * - None of the choices already have a conversation terminator (F4 or F8) in their response path
+ */
void DialogManager::addGoodbyeOptionIfNeeded(Common::Array<ChoiceOption> *choices, int currentChoiceLevel, uint originalChoiceCount) {
// Room entry handlers can globally disable the goodbye option for certain rooms
- // (e.g. rooms 39/40 pharaoh, room 48).
if (_goodbyeDisabled) {
return;
}
@@ -926,8 +920,8 @@ uint32 DialogManager::processChoiceSelection(
if (!choiceText.empty() && choiceText.size() > 1) {
displayDialogue(choiceText, kAlfredColor);
- debug("Will check if choice should be disabled after displaying dialogue");
- disableChoiceIfNeeded(choices, selectedIndex, data, dataSize, endPos, state);
+ //Will check if choice should be disabled after displaying dialogue
+ maybeDisableChoice(choices, selectedIndex, data, dataSize, endPos, state);
}
position = endPos;
@@ -935,21 +929,25 @@ uint32 DialogManager::processChoiceSelection(
// Skip past end marker
if (position < dataSize) {
byte endByte = data[position];
- if (endByte == CTRL_END_TEXT || endByte == CTRL_END_BRANCH ||
- endByte == CTRL_ACTION_AND_END) {
+ if (endByte == kCtrlEndText || endByte == kCtrlEndBranch ||
+ endByte == kCtrlActionAndEnd) {
position++;
}
}
return position;
}
-void DialogManager::disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> *choices, int selectedIndex, const byte *data, uint32 dataSize, uint32 endPos, Pelrock::ConversationState &state) {
+
+void DialogManager::maybeDisableChoice(Common::Array<Pelrock::ChoiceOption> *choices, int selectedIndex, const byte *data, uint32 dataSize, uint32 endPos, Pelrock::ConversationState &state) {
// Cascading parent disable:
// 1. Check if current choice's sub-branches are exhausted
// 2. If so AND it's 0xFB, disable the current choice
// 3. Go up to parent level, check if parent's sub-branches are exhausted
// 4. Continue until we find a level with active sub-branches or reach level 1
+ // Basically this means if the current choice getting disabled was also the last sub-branch of the previous level, that choice also
+ // has to be disabled.
+
// Start with the currently selected choice
int currentLevel = state.currentChoiceLevel;
uint32 currentChoicePos = (*choices)[selectedIndex].dataOffset;
@@ -960,18 +958,15 @@ void DialogManager::disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> *
bool allExhausted = checkAllSubBranchesExhausted(data, dataSize, currentChoicePos + 4, currentLevel);
if (!allExhausted) {
- debug("Cascading disable stopped at level %d - active sub-branches found", currentLevel);
break;
}
// Check if this choice is F1 (repeatable) - don't disable
if (!isCurrentFB) {
- debug("Choice at level %d is repeatable (F1), stopping cascade", currentLevel);
break;
}
// Disable this one-time choice
- debug("Cascading disable: level %d, offset %u", currentLevel, currentChoicePos);
ChoiceOption choiceToDisable;
choiceToDisable.room = g_engine->_room->_currentRoomNumber;
choiceToDisable.dataOffset = currentChoicePos;
@@ -981,7 +976,7 @@ void DialogManager::disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> *
// Stop if we've reached level 1
if (currentLevel <= 1) {
- debug("Reached level 1, stopping cascading disable");
+ // Reached level 1, stopping cascading disable
break;
}
@@ -995,7 +990,7 @@ void DialogManager::disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> *
byte b = data[scanPos];
// Found 0xFB marker
- if (b == CTRL_DIALOGUE_MARKER_ONEOFF && scanPos + 1 < dataSize) {
+ if (b == kCtrlDialogueMarkerOneoff && scanPos + 1 < dataSize) {
byte idx = data[scanPos + 1];
if (idx == (byte)currentLevel) {
currentChoicePos = scanPos;
@@ -1006,34 +1001,34 @@ void DialogManager::disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> *
}
}
// Found 0xF1 marker (repeatable)
- else if (b == CTRL_DIALOGUE_MARKER && scanPos + 1 < dataSize) {
+ else if (b == kCtrlDialogueMarker && scanPos + 1 < dataSize) {
byte idx = data[scanPos + 1];
if (idx == (byte)currentLevel) {
// Found 0xF1 parent - will stop cascade on next iteration
currentChoicePos = scanPos;
isCurrentFB = false;
foundParent = true;
- debug("Found parent 0xF1 at level %d, pos %u - will stop cascade", currentLevel, currentChoicePos);
break;
}
}
// Hit boundary markers - stop searching
- if (b == CTRL_ALT_SPEAKER_ROOT || b == CTRL_END_BRANCH || b == CTRL_ALT_END_MARKER_1) {
- debug("Hit boundary at pos %u while looking for parent level %d", scanPos, currentLevel);
+ if (b == kCtrlAltSpeakerRoot || b == kCtrlEndBranch || b == kCtrlAltEndMarker1) {
break;
}
}
if (!foundParent) {
- debug("Could not find parent at level %d, stopping cascade", currentLevel);
break;
}
}
}
+
+/**
+ * Convenience method if we know it's Alfred talking
+ */
void DialogManager::sayAlfred(Common::StringArray texts) {
if (g_engine->_state->getFlag(FLAG_FROM_INTRO) == true) {
- debug("Setting special anim");
g_engine->_alfredState.setState(ALFRED_SPECIAL_ANIM);
} else {
g_engine->_alfredState.setState(ALFRED_TALKING);
@@ -1044,6 +1039,9 @@ void DialogManager::sayAlfred(Common::StringArray texts) {
displayDialogue(textLines, kAlfredColor);
}
+/**
+ * Convenience method for Descriptions
+ */
void DialogManager::sayAlfred(Description description) {
Common::StringArray texts;
@@ -1054,6 +1052,10 @@ void DialogManager::sayAlfred(Description description) {
}
}
+/**
+ * Convenience method when we want to enforce a specific NPC to speak the line.
+ * Used mostly when it's npc index 1
+ */
void DialogManager::say(Common::StringArray texts, byte spriteIndex) {
if (texts.empty()) {
return;
@@ -1075,6 +1077,10 @@ void DialogManager::say(Common::StringArray texts, byte spriteIndex) {
}
}
+/**
+ * Convenience method to say a line normally but enforce x and y.
+ * Regular path will simply use the sprite's x and y
+ */
void DialogManager::say(Common::StringArray texts, int16 x, int16 y) {
if (texts.empty()) {
return;
@@ -1091,6 +1097,9 @@ void DialogManager::say(Common::StringArray texts, int16 x, int16 y) {
}
}
+/**
+ * Read from the formatted string the color code, and trim text and control chars
+ */
bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speakerId) {
int speakerMarker = lines[0][0];
speakerId = lines[0][1];
@@ -1118,7 +1127,7 @@ bool DialogManager::processColorAndTrim(Common::StringArray &lines, byte &speake
}
bool isEndMarker(byte char_byte) {
- return char_byte == CTRL_END_TEXT || char_byte == CTRL_END_CONVERSATION || char_byte == CTRL_ACTION_AND_END || char_byte == CTRL_GO_BACK;
+ return char_byte == kCtrlEndText || char_byte == kCtrlEndConversation || char_byte == kCtrlActionAndEnd || char_byte == kCtrlGoBack;
}
int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
@@ -1126,7 +1135,7 @@ int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
int pos = startPos;
while (pos < text.size()) {
char char_byte = text[pos];
- if (char_byte == CHAR_SPACE || isEndMarker(char_byte)) {
+ if (char_byte == kCtrlSpace || isEndMarker(char_byte)) {
break;
}
wordLength++;
@@ -1137,11 +1146,11 @@ int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
isEnd = true;
}
if (pos < text.size() && !isEnd) {
- if ((byte)text[pos] == CTRL_ACTION_AND_END) { // 0xF8 (-8) special case
+ if ((byte)text[pos] == kCtrlActionAndEnd) { // 0xF8 (-8) special case
wordLength += 3;
} else {
// Count all consecutive spaces
- while (pos < text.size() && text[pos] == CHAR_SPACE) {
+ while (pos < text.size() && text[pos] == kCtrlSpace) {
wordLength++;
pos++;
}
@@ -1150,6 +1159,11 @@ int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
return wordLength;
}
+/**
+ * Wrap a String into pages of multiple Strings.
+ * The game enforces a maximum of 47 characters per line and 5 lines per page.
+ * If a String is longer than that it gets broken down into multiple pages.
+ */
Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::String text) {
Common::Array<Common::Array<Common::String>> pages;
Common::Array<Common::String> currentPage;
@@ -1182,7 +1196,7 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
if (charsRemaining == 0 && isEnd) {
Common::String lineText = joinStrings(currentLine, "");
- while (lineText.lastChar() == CHAR_SPACE) {
+ while (lineText.lastChar() == kCtrlSpace) {
lineText = lineText.substr(0, lineText.size() - 1);
}
int trailingSpaces = currentLine.size() - lineText.size();
@@ -1210,7 +1224,7 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
if (!currentLine.empty()) {
Common::String lineText = joinStrings(currentLine, "");
- while (lineText.lastChar() == CHAR_SPACE) {
+ while (lineText.lastChar() == kCtrlSpace) {
lineText = lineText.substr(0, lineText.size() - 1);
}
currentPage.push_back(lineText);
@@ -1220,13 +1234,6 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
pages.push_back(currentPage);
}
- // print all the pages and lines for debugging
- // for (uint i = 0; i < pages.size(); i++) {
- // debug("Page %d:", i);
- // for (uint j = 0; j < pages[i].size(); j++) {
- // debug(" Line %d: \"%s\"", j, pages[i][j].c_str());
- // }
- // }
return pages;
}
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index a808b763c70..cda61767630 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -34,39 +34,23 @@
namespace Pelrock {
-// Control character codes (negative values in signed char)
-#define CHAR_SPACE 0x20 /* ' ' */
-#define CTRL_SPEAKER_ID 0x08 /* Next byte is speaker ID (color) */
-const byte kCtrlEndText = 0xFD; /* End of text segment */
-const byte kCtrlTextTerminator = 0xFC; /* Text terminator */
-const byte kCtrlDialogueMarker = 0xF1; /* Choice marker that sticks */
-const byte kCtrlDisabledChoice = 0xFA; /* Disabled choice marker */
-const byte kCtrlPageBreakConv = 0xF9; /* Page break in conversation */
-const byte kCtrlActionAndEnd = 0xF8; /* Action trigger */
-const byte kCtrlEndBranch = 0xF7; /* End of branch */
-const byte kCtrlLineContinue = 0xF6; /* Line continue/newline */
-const byte kCtrlAltEndMarker1 = 0xF5; /* Alt end marker - do nothing */
-const byte kCtrlEndConversation = 0xF4; /* End conversation and disable option */
-const byte kCtrlDialogueMarkerOneoff = 0xFB; /* Alt choice marker that disappears */
-const byte kCtrlGoBack = 0xF0; /* Go back in conversation */
-const byte kCtrlActionAndContinue = 0xEB; /* Action-and-continue: dispatch action, conversation keeps going (unlike 0xF8 which exits) */
-const byte kCtrlAltSpeakerRoot = 0xFE; /* Separates conversations from different speakers */
-
-// Keep old names as aliases for compatibility
-#define CTRL_END_TEXT kCtrlEndText
-#define CTRL_TEXT_TERMINATOR kCtrlTextTerminator
-#define CTRL_DIALOGUE_MARKER kCtrlDialogueMarker
-#define CTRL_DISABLED_CHOICE kCtrlDisabledChoice
-#define CTRL_PAGE_BREAK_CONV kCtrlPageBreakConv
-#define CTRL_ACTION_AND_END kCtrlActionAndEnd
-#define CTRL_END_BRANCH kCtrlEndBranch
-#define CTRL_LINE_CONTINUE kCtrlLineContinue
-#define CTRL_ALT_END_MARKER_1 kCtrlAltEndMarker1
-#define CTRL_END_CONVERSATION kCtrlEndConversation
-#define CTRL_DIALOGUE_MARKER_ONEOFF kCtrlDialogueMarkerOneoff
-#define CTRL_GO_BACK kCtrlGoBack
-#define CTRL_ACTION_AND_CONTINUE kCtrlActionAndContinue
-#define CTRL_ALT_SPEAKER_ROOT kCtrlAltSpeakerRoot
+// Control character codes
+const byte kCtrlSpace = 0x20; /* ' ' */
+const byte kCtrlSpeakerId = 0x08; /* Next byte is speaker ID (color) */
+const byte kCtrlEndText = 0xFD; /* End of text segment */
+const byte kCtrlTextTerminator = 0xFC; /* Text terminator */
+const byte kCtrlDialogueMarker = 0xF1; /* Choice marker that sticks */
+const byte kCtrlDialogueMarkerOneoff = 0xFB; /* Choice marker that disappears after use */
+const byte kCtrlDisabledChoice = 0xFA; /* Disabled choice marker, generally only after usage */
+const byte kCtrlPageBreakConv = 0xF9; /* Page break in conversation */
+const byte kCtrlActionAndEnd = 0xF8; /* Action trigger and end conversation */
+const byte kCtrlActionAndContinue = 0xEB; /* Action-and-continue: dispatch action, conversation keeps going (unlike 0xF8 which exits) */
+const byte kCtrlEndBranch = 0xF7; /* End of branch */
+const byte kCtrlLineContinue = 0xF6; /* Line continue/newline */
+const byte kCtrlAltEndMarker1 = 0xF5; /* Alt end marker - do nothing */
+const byte kCtrlEndConversation = 0xF4; /* End conversation and disable option */
+const byte kCtrlGoBack = 0xF0; /* Go back in conversation */
+const byte kCtrlAltSpeakerRoot = 0xFE; /* Separates conversations from different speakers */
// Helper structures for conversation state management
struct ConversationState {
@@ -84,13 +68,13 @@ struct ConversationEndResult {
};
class DialogManager {
- const static int kMaxChoiceChars = 50; // Max characters to show for a choice option (for truncation)
- const static int kArrowWidth = 8; // Width of arrow character for scroll
- const static int kChoicePadding = 16; // padding for the choice text surface
+ const static int kArrowWidth = 8; // Width of arrow character for scroll
+ const static int kChoicePadding = 16; // padding for the choice text surface
private:
Graphics::Screen *_screen = nullptr;
PelrockEventManager *_events = nullptr;
GraphicsManager *_graphics = nullptr;
+ // Current talking sprite, to disable and replace with talking animation
Sprite *_curSprite = nullptr;
// Private helper functions for conversation parsing
@@ -100,10 +84,8 @@ private:
uint32 readTextBlock(const byte *data, uint32 dataSize, uint32 startPos, Common::String &outText, byte &outSpeakerId);
uint32 parseChoices(const byte *data, uint32 dataSize, uint32 startPos, Common::Array<ChoiceOption> *outChoices);
void setCurSprite(int index);
- void checkMouse();
bool checkAllSubBranchesExhausted(const byte *data, uint32 dataSize, uint32 startPos, int currentChoiceLevel);
- // Refactored helper functions for startConversation
uint32 skipControlBytes(const byte *data, uint32 dataSize, uint32 position);
uint32 peekNextMeaningfulByte(const byte *data, uint32 dataSize, uint32 position);
ConversationState initializeConversation(const byte *data, uint32 dataSize, byte npcIndex);
@@ -112,7 +94,7 @@ private:
ConversationEndResult checkConversationEnd(const byte *data, uint32 dataSize, uint32 position, int currentRoot = -1);
void addGoodbyeOptionIfNeeded(Common::Array<ChoiceOption> *choices, int currentChoiceLevel, uint originalChoiceCount);
uint32 processChoiceSelection(const byte *data, uint32 dataSize, Common::Array<ChoiceOption> *choices, int selectedIndex, ConversationState &state);
- void disableChoiceIfNeeded(Common::Array<Pelrock::ChoiceOption> *choices, int selectedIndex, const byte *data, uint32 dataSize, uint32 endPos, Pelrock::ConversationState &state);
+ void maybeDisableChoice(Common::Array<Pelrock::ChoiceOption> *choices, int selectedIndex, const byte *data, uint32 dataSize, uint32 endPos, Pelrock::ConversationState &state);
public:
DialogManager(Graphics::Screen *screen, PelrockEventManager *events, GraphicsManager *graphics);
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index 8d4609c5770..98048e39d80 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -58,7 +58,7 @@ bool LargeFont::load(const Common::String &filename) {
memset(_fontData, 0, dataSize);
for (int c = 0; c < numChars; c++) {
// Temporary bitmap for character + border
- bool mask[paddedHeight][paddedWidth] = {false};
+ bool mask[paddedHeight][paddedWidth] = {{false}};
// Decode character pixels from rawFontData
int charOffset = c * 0x30;
for (int i = 0; i < charHeight; i++) {
@@ -72,7 +72,7 @@ bool LargeFont::load(const Common::String &filename) {
}
}
// adds a border mask to the original font
- bool borderMask[paddedHeight][paddedWidth] = {false};
+ bool borderMask[paddedHeight][paddedWidth] = {{false}};
for (int y = 0; y < paddedHeight; y++) {
for (int x = 0; x < paddedWidth; x++) {
diff --git a/engines/pelrock/fonts/small_font.h b/engines/pelrock/fonts/small_font.h
index cd80c690a1b..3bde2c152b0 100644
--- a/engines/pelrock/fonts/small_font.h
+++ b/engines/pelrock/fonts/small_font.h
@@ -44,8 +44,8 @@ public:
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
byte *_fontData;
-protected:
+protected:
private:
static const int CHAR_WIDTH = 8;
static const int CHAR_HEIGHT = 8;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 99fdb4cd677..3ebe7a50af5 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -506,7 +506,7 @@ Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data,
Common::StringArray lines;
Common::Array<Common::StringArray> texts;
while (pos < size) {
- if (data[pos] == CTRL_END_TEXT) {
+ if (data[pos] == kCtrlEndText) {
lines.push_back(desc);
texts.push_back(lines);
lines.clear();
@@ -519,7 +519,7 @@ Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data,
continue;
}
- if (data[pos] == CTRL_SPEAKER_ID) {
+ if (data[pos] == kCtrlSpeakerId) {
byte color = data[pos + 1];
desc.append(1, '@');
desc.append(1, color);
Commit: 89189c032b318f17772b8871b8721734010d11fd
https://github.com/scummvm/scummvm/commit/89189c032b318f17772b8871b8721734010d11fd
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:40+02:00
Commit Message:
PELROCK: Cleanup of menu and graphics
Changed paths:
engines/pelrock/events.cpp
engines/pelrock/events.h
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
index effa865cc6f..c12669baa86 100644
--- a/engines/pelrock/events.cpp
+++ b/engines/pelrock/events.cpp
@@ -20,10 +20,10 @@
*/
#include "common/events.h"
+#include "events.h"
#include "pelrock/events.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
-#include "events.h"
namespace Pelrock {
diff --git a/engines/pelrock/events.h b/engines/pelrock/events.h
index c6f477824ca..3198089d687 100644
--- a/engines/pelrock/events.h
+++ b/engines/pelrock/events.h
@@ -30,6 +30,7 @@ class PelrockEventManager {
private:
Common::Event _event;
uint32 _clickTime = 0;
+
public:
int16 _mouseX = 0;
int16 _mouseY = 0;
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index eb8d2b6585e..6d8b3e1173f 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -49,30 +49,6 @@ Common::Point GraphicsManager::showOverlay(int height, Graphics::ManagedSurface
return Common::Point(overlayX, overlayY);
}
-byte *GraphicsManager::grabBackgroundSlice(Graphics::ManagedSurface &buf, int x, int y, int w, int h) {
- byte *bg = new byte[w * h];
- for (int j = 0; j < w; j++) {
- for (int i = 0; i < h; i++) {
- int idx = i * w + j;
- if (y + i < 400 && x + j < 640) {
- *(bg + idx) = (byte)buf.getPixel(x + j, y + i);
- }
- }
- }
- return bg;
-}
-
-void GraphicsManager::putBackgroundSlice(Graphics::ManagedSurface &buf, int x, int y, int w, int h, byte *slice) {
- for (int i = 0; i < w; i++) {
- for (int j = 0; j < h; j++) {
- int index = (j * w + i);
- if (x + i < 640 && y + j < 400) {
- buf.setPixel(x + i, y + j, slice[index]);
- }
- }
- }
-}
-
void GraphicsManager::fadeToBlack(int stepSize) {
byte palette[768];
g_system->getPaletteManager()->grabPalette(palette, 0, 256);
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index c205d1bbedd..1616c0aa215 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -22,8 +22,8 @@
#define PELROCK_GRAPHICS_H
#include "common/array.h"
-#include "common/str-array.h"
#include "common/scummsys.h"
+#include "common/str-array.h"
#include "graphics/font.h"
#include "graphics/managed_surface.h"
@@ -40,8 +40,6 @@ public:
// Overlay / palette utilities
Common::Point showOverlay(int height, Graphics::ManagedSurface &buf);
- byte *grabBackgroundSlice(Graphics::ManagedSurface &buf, int x, int y, int w, int h);
- void putBackgroundSlice(Graphics::ManagedSurface &buf, int x, int y, int w, int h, byte *slice);
void fadeToBlack(int stepSize);
void fadePaletteToTarget(byte *targetPalette, int stepSize);
void clearScreen();
@@ -69,12 +67,7 @@ public:
/** Water reflection: mirrors buf pixels at (x,y) for water-palette pixels. */
void reflectionEffect(byte *buf, int x, int y, int width, int height);
-
// scaling
- /**
- * Initializes _widthScalingTable / _heightScalingTable.
- * Must be called once during engine init, before any drawAlfred().
- */
void calculateScalingMasks();
/**
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index af9af7135bc..e6c0bd4764b 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -129,7 +129,6 @@ MainMenuButton MenuManager::isMainMenuButtonUnder(int x, int y) {
if (_menuState != MAIN_MENU) {
return NO_MAIN_BUTTON;
}
-
if (_questionMarkRect.contains(x, y)) {
return QUESTION_MARK_BUTTON;
}
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 6cc811609d2..a694caf5712 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -55,56 +55,56 @@ enum SoundMenuButton {
};
static const int kCreditsOrder[34] = {
- 5, // PROGRAMACION
- 8, // Juan Jose Gil
- 20, // Jose Vicente Pons
- 24, // LuisFer Fernandez
- 22, // Fernando Perez
- 7, // GRAFICOS
+ 5, // PROGRAMACION
+ 8, // Juan Jose Gil
+ 20, // Jose Vicente Pons
+ 24, // LuisFer Fernandez
+ 22, // Fernando Perez
+ 7, // GRAFICOS
12, // Queral,
14, // Ana maria polo
18, // Juan Arocas
16, // Gost
26, // Astorga
28, // Santi Sanz
- 2, // Fernando Aparicio
- 11,// INTRODUCCION
+ 2, // Fernando Aparicio
+ 11, // INTRODUCCION
12, // Queral,
26, // Astorga
28, // Santi Sanz
- 9, // MUSICA
- 6, // Rufino Acosta
+ 9, // MUSICA
+ 6, // Rufino Acosta
13, // GUION
- 8, // Juan Jose Gil
+ 8, // Juan Jose Gil
19, // DIALOGOS
- 4, // Vicent raul arnau,
- 8, // Juan Jose Gil,
+ 4, // Vicent raul arnau,
+ 8, // Juan Jose Gil,
21, // PROBADORES
- 0, //David Burgos
+ 0, // David Burgos
10, // Alberto Leon
- 1, // Carles Pons
- 3, // Roman Pons
+ 1, // Carles Pons
+ 3, // Roman Pons
25, // Andres Ruiz,
27, // Juan Jose Ruiz
23, // Marilo
15, // PRODUCCION
- 17 // DDM
+ 17 // DDM
};
static const char *inventorySounds[113] = {
- "HOJASZZZ.SMP", // 0 - Default leaf rustle
- "11ZZZZZZ.SMP", // 1 -
+ "HOJASZZZ.SMP", // 0
"11ZZZZZZ.SMP",
"11ZZZZZZ.SMP",
- "GLASS1ZZ.SMP", // 4 - Glass clink (brick)
"11ZZZZZZ.SMP",
- "ELEC3ZZZ.SMP", // 6 - Electric zap
- "REMATERL.SMP", // 7 - Rematerialize
- "81ZZZZZZ.SMP", // 8 - (numbered SFX)
- "11ZZZZZZ.SMP", // 9
- "SSSHTZZZ.SMP", // 10 - Shushing
- "HOJASZZZ.SMP", // 11 - Default leaf rustle
+ "GLASS1ZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "ELEC3ZZZ.SMP",
+ "REMATERL.SMP",
+ "81ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "SSSHTZZZ.SMP", // 10
+ "HOJASZZZ.SMP",
"HOJASZZZ.SMP",
"HOJASZZZ.SMP",
"HOJASZZZ.SMP",
@@ -154,58 +154,58 @@ static const char *inventorySounds[113] = {
"HOJASZZZ.SMP",
"HOJASZZZ.SMP",
"BOTEZZZZ.SMP", // 60
- "BOTEZZZZ.SMP", // 61
- "BOTEZZZZ.SMP", // 62 - Bottle sound
- "BELCHZZZ.SMP", // 63 - Belch
- "BEAMZZZZ.SMP", // 64 - Beam/ray
- "ELVIS1ZZ.SMP", // 65 - Elvis impression
- "CAT_1ZZZ.SMP", // 66 - Cat sound
- "BOOOOOIZ.SMP", // 67 - Boing
- "DISCOSZZ.SMP", // 68 - Disco music
- "MONORLZZ.SMP", // 69 - Monorail
+ "BOTEZZZZ.SMP",
+ "BOTEZZZZ.SMP",
+ "BELCHZZZ.SMP",
+ "BEAMZZZZ.SMP",
+ "ELVIS1ZZ.SMP",
+ "CAT_1ZZZ.SMP",
+ "BOOOOOIZ.SMP",
+ "DISCOSZZ.SMP",
+ "MONORLZZ.SMP",
"11ZZZZZZ.SMP", // 70
- "11ZZZZZZ.SMP", // 71
- "11ZZZZZZ.SMP", // 72
- "CARACOLA.SMP", // 73 - Seashell
- "11ZZZZZZ.SMP", // 74
- "11ZZZZZZ.SMP", // 75
- "WATER_2Z.SMP", // 76 - Water splash
- "11ZZZZZZ.SMP", // 77
- "11ZZZZZZ.SMP", // 78
- "EEEEKZZZ.SMP", // 79 - Shriek
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "CARACOLA.SMP",
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "WATER_2Z.SMP",
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "EEEEKZZZ.SMP",
"REMATERL.SMP", // 80 - Rematerialize
- "11ZZZZZZ.SMP", // 81
- "11ZZZZZZ.SMP", // 82
- "ELVIS1ZZ.SMP", // 83 - Elvis impression
- "RIMSHOTZ.SMP", // 84 - Rimshot
- "11ZZZZZZ.SMP", // 85
- "WATER_2Z.SMP", // 86 - Water splash
- "MOTOSZZZ.SMP", // 87 - Motorcycle
- "HOJASZZZ.SMP",
- "TWANGZZZ.SMP", // 89 - Twang
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "ELVIS1ZZ.SMP",
+ "RIMSHOTZ.SMP",
+ "11ZZZZZZ.SMP",
+ "WATER_2Z.SMP",
+ "MOTOSZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "TWANGZZZ.SMP",
"11ZZZZZZ.SMP", // 90
- "QUAKE2ZZ.SMP", // 91 - Earthquake
- "11ZZZZZZ.SMP", // 92
- "SORBOZZZ.SMP", // 93 - Slurp
- "BOTEZZZZ.SMP", // 94 - Bottle sound
- "ELVIS1ZZ.SMP", // 95 - Elvis impression
- "HOJASZZZ.SMP", // 96
- "HOJASZZZ.SMP", // 97
- "HOJASZZZ.SMP", // 98
- "11ZZZZZZ.SMP", // 99
- "LLAVESZZ.SMP", // 100 - Keys jingling
- "HOJASZZZ.SMP", // 101
- "11ZZZZZZ.SMP", // 102
- "11ZZZZZZ.SMP", // 103
- "EVLLAUGH.SMP", // 104 - Evil laugh
- "11ZZZZZZ.SMP", // 105
- "BURROLZZ.SMP", // 106 - Donkey bray
- "11ZZZZZZ.SMP", // 107
- "TWANGZZZ.SMP", // 108
- "11ZZZZZZ.SMP", // 109
+ "QUAKE2ZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "SORBOZZZ.SMP",
+ "BOTEZZZZ.SMP",
+ "ELVIS1ZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "LLAVESZZ.SMP", // 100
+ "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "EVLLAUGH.SMP",
+ "11ZZZZZZ.SMP",
+ "BURROLZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "TWANGZZZ.SMP",
+ "11ZZZZZZ.SMP",
"TWANGZZZ.SMP", // 110
- "ELVIS1ZZ.SMP", // 111 - Elvis impression
- "SEX3ZZZZ.SMP" // 112 - Suggestive sound
+ "ELVIS1ZZ.SMP",
+ "SEX3ZZZZ.SMP"
};
class MenuManager {
@@ -232,7 +232,6 @@ private:
void checkMouseDown(int x, int y);
bool checkMouseClick(int x, int y);
void checkSoundMenuClick(int x, int y);
- bool checkMainMenuMouse(int x, int y, bool &retFlag);
bool checkMainMenuMouse(int x, int y); // returns bool if its supposed to close the menu
void showCredits();
bool selectInventoryItem(int i);
@@ -293,7 +292,6 @@ private:
Common::Rect _sfxVolumeLeftRect = Common::Rect(Common::Point(364, 252), 36, 28);
Common::Rect _sfxVolumeRightRect = Common::Rect(Common::Point(400, 252), 31, 28);
-
byte *_soundControlArrowLeft[2] = {nullptr};
byte *_soundControlArrowRight[2] = {nullptr};
@@ -323,11 +321,11 @@ private:
// Save/Load sub-menu state
int _saveGamePage = 0;
- int _editingSaveSlot = -1; // -1 = not editing any slot
- Common::String _editingName; // name being typed for a save
- Common::Rect _cancelarRect; // hit-rect for the CANCELAR row
+ int _editingSaveSlot = -1; // -1 = not editing any slot
+ Common::String _editingName; // name being typed for a save
+ Common::Rect _cancelarRect; // hit-rect for the CANCELAR row
Common::Array<Common::Rect> _saveSlotRects; // hit-rects for the 8 visible save rows
- Common::StringArray _saveDescriptions; // indexed by slot 0-255
+ Common::StringArray _saveDescriptions; // indexed by slot 0-255
};
} // End of namespace Pelrock
Commit: cf7004677e62071e985cf681de5b1580eca36f52
https://github.com/scummvm/scummvm/commit/cf7004677e62071e985cf681de5b1580eca36f52
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:41+02:00
Commit Message:
PELROCK: Cleanup of pathfinding and room
Changed paths:
engines/pelrock/pathfinding.cpp
engines/pelrock/pathfinding.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
index b1dfdeb790c..e3dd713db12 100644
--- a/engines/pelrock/pathfinding.cpp
+++ b/engines/pelrock/pathfinding.cpp
@@ -27,29 +27,6 @@
namespace Pelrock {
-Common::String printMovementFlags(byte flags) {
- Common::String result;
- if (flags & kMoveHoriz) {
- result += "HORIZ ";
- }
- if (flags & kMoveVert) {
- result += "VERT ";
- }
- if (flags & kMoveDown) {
- result += "DOWN ";
- }
- if (flags & kMoveLeft) {
- result += "LEFT ";
- }
- if (flags & kMoveUp) {
- result += "UP ";
- }
- if (flags & kMoveRight) {
- result += "RIGHT ";
- }
- return result;
-}
-
bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<WalkBox> &walkboxes, PathContext *context, HotSpot *hotspot) {
if (context->pathBuffer == nullptr) {
@@ -61,15 +38,13 @@ bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<
int startX = sourceX;
int startY = sourceY;
- Common::Point target = calculateWalkTarget(walkboxes, targetX, targetY, 2, nullptr);
+ Common::Point target = calculateWalkTarget(walkboxes, targetX, targetY, nullptr);
targetX = target.x;
targetY = target.y;
- // debug("Startx= %d, starty= %d, destx= %d, desty= %d", startX, startY, targetX, targetY);
byte startBox = findWalkboxForPoint(walkboxes, startX, startY);
byte destBox = findWalkboxForPoint(walkboxes, targetX, targetY);
- // debug("Pathfinding from (%d, %d) in box %d to (%d, %d) in box %d\n", startX, startY, startBox, targetX, targetY, destBox);
// Check if both points are in valid walkboxes
if (startBox == 0xFF || destBox == 0xFF) {
debug("Error: Start or destination not in any walkbox\n");
@@ -101,10 +76,6 @@ bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<
} else {
// Build walkbox path
context->pathLength = buildWalkboxPath(walkboxes, startBox, destBox, context->pathBuffer);
- debug("Walkbox path to point");
- for (int i = 0; i < context->pathLength; i++) {
- // debug("Walkbox %d: %d", i, context->pathBuffer[i]);
- }
if (context->pathLength == 0) {
debug("Error: No path found\n");
return false;
@@ -112,21 +83,16 @@ bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<
// Generate movement steps
context->movementCount = generateMovementSteps(walkboxes, context->pathBuffer, context->pathLength, startX, startY, targetX, targetY, context->movementBuffer);
- // for (int i = 0; i < context->movementCount; i++) {
- // debug("Movement step %d: flags=\"%s\", dx=%d, dy=%d", i, printMovementFlags(context->movementBuffer[i].flags).c_str(), context->movementBuffer[i].distanceX, context->movementBuffer[i].distanceY);
- // }
}
return true;
}
-Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes,
- int sourceX, int sourceY,
- bool mouseHoverState,
- HotSpot *hotspot) {
+Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes, int sourceX, int sourceY, HotSpot *hotspot) {
- if(hotspot != nullptr) {
+ if (hotspot != nullptr) {
+ // if there is a hotspot then the source is the center of the hotspot.
sourceX = hotspot->x + hotspot->w / 2;
- sourceY = hotspot->y + hotspot->h;
+ sourceY = hotspot->y + hotspot->h / 2;
}
// Find nearest walkbox
@@ -151,7 +117,6 @@ Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes,
xDistance = sourceX - (walkboxes[i].x + walkboxes[i].w - 1);
xDirection = 0; // LEFT
}
- // else: sourceX is inside, xDistance = 0
// Calculate Y distance with direction
if (sourceY < walkboxes[i].y) {
@@ -162,7 +127,6 @@ Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes,
yDistance = sourceY - (walkboxes[i].y + walkboxes[i].h - 1);
yDirection = 0; // UP
}
- // else: sourceY is inside, yDistance = 0
uint32 totalDistance = xDistance + yDistance;
@@ -175,7 +139,7 @@ Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes,
}
}
- // Step 3: Calculate final target point
+ // Calculate final target point
Common::Point target;
if (bestXDirection == 1) {
@@ -337,11 +301,11 @@ void calculateMovementToTarget(uint16 currentX, uint16 currentY, uint16 targetX,
* Returns: number of movement steps generated
*/
uint16 generateMovementSteps(Common::Array<WalkBox> &walkboxes,
- byte *pathBuffer,
- uint16 pathLength,
- uint16 startX, uint16 startY,
- uint16 destX, uint16 destY,
- MovementStep *movementBuffer) {
+ byte *pathBuffer,
+ uint16 pathLength,
+ uint16 startX, uint16 startY,
+ uint16 destX, uint16 destY,
+ MovementStep *movementBuffer) {
uint16 currentX = startX;
uint16 currentY = startY;
uint16 movementIndex = 0;
diff --git a/engines/pelrock/pathfinding.h b/engines/pelrock/pathfinding.h
index f6f3d2c1063..6775cf3a4a9 100644
--- a/engines/pelrock/pathfinding.h
+++ b/engines/pelrock/pathfinding.h
@@ -30,15 +30,15 @@ namespace Pelrock {
bool findPath(int sourceX, int sourceY, int targetX, int targetY, Common::Array<WalkBox> &walkboxes, PathContext *context, HotSpot *hotspot = nullptr);
/**
- * Calculate the walk target point based on source coordinates and mouse hover state.
+ * Calculate the walk target point. This is used both for actually walking and for the mouse hover exit calculation. E.g. if the resulting walk target
+ * would lead to the character landing in an exit, the Exit cursor is shown.
* @param walkboxes Array of walkboxes in the current room.
- * @param sourceX X coordinate of the source point (e.g., mouse position).
- * @param sourceY Y coordinate of the source point (e.g., mouse position).
- * @param mouseHoverState State indicating what the mouse is hovering over (0 = nothing, 1 = hotspot hover, 2 = hotspot click).
- * @param hotspot Pointer to the hotspot being hovered over (if applicable).
+ * @param sourceX X coordinate of the source point
+ * @param sourceY Y coordinate of the source point
+ * @param hotspot Pointer to the hotspot being hovered over (if any).
* @return Calculated walk target point.
*/
-Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes, int sourceX, int sourceY, bool mouseHoverState, HotSpot *hotspot);
+Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes, int sourceX, int sourceY, HotSpot *hotspot);
byte findWalkboxForPoint(Common::Array<WalkBox> &walkboxes, uint16 x, uint16 y);
byte getAdjacentWalkbox(Common::Array<WalkBox> &walkboxes, byte current_box_index);
uint16 buildWalkboxPath(Common::Array<WalkBox> &walkboxes, byte start_box, byte dest_box, byte *path_buffer);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 572239ba639..e162930be1d 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1701,7 +1701,7 @@ void PelrockEngine::checkMouseClick(int x, int y) {
isHotspotUnder = true;
}
_currentHotspot = isHotspotUnder ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr;
- Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, isHotspotUnder, _currentHotspot);
+ Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, _currentHotspot);
_curWalkTarget = walkTarget;
walkTo(walkTarget.x, walkTarget.y);
@@ -1738,7 +1738,7 @@ void PelrockEngine::checkMouseHover() {
}
// Calculate walk target first (before checking anything else)
- Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, hotspotDetected, hotspotDetected ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
+ Common::Point walkTarget = calculateWalkTarget(_room->_currentRoomWalkboxes, _events->_mouseX, _events->_mouseY, hotspotDetected ? &_room->_currentRoomHotspots[hotspotIndex] : nullptr);
// Check if walk target hits any exit
bool exitDetected = false;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 3ebe7a50af5..825a63a6318 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -69,9 +69,9 @@ static const uint32 kAlfredAnimClimbDownOffset = 1761234; // 7 - Climbs dow
static const uint32 kAlfredAnimClimbUpOffset = 1766378; // 8 - Climbs up
static const uint32 kAlfredAnimExitTunnelOffset = 1770196; // 9 - Exits tunnel
static const uint32 kAlfredAnimWorkersOffset = 1600956; // 10 - With workers
-static const uint32 kAlfredAnimMunheco1Offset = 2060916; // 11 - Munheco 1
-static const uint32 kAlfredAnimMunheco2Offset = 2115632; // 12 - Munheco 2
-static const uint32 kAlfredAnimMunheco3Offset = 1526432; // 13 - Munheco 3
+static const uint32 kAlfredAnimMunheco1Offset = 2060916; // 11 - Doll 1
+static const uint32 kAlfredAnimMunheco2Offset = 2115632; // 12 - Doll 2
+static const uint32 kAlfredAnimMunheco3Offset = 1526432; // 13 - Doll 3
static const uint32 kAlfredAnimDescamisaOffset = 2972568; // 14 - Descamisa
static const uint32 kAlfredAnimSecretPassageOffset = 1749464; // 15 - Secret passage
static const uint32 kAlfredAnimInBedOffset = 3038454; // 16 - Alfred in bed
@@ -95,10 +95,10 @@ const AlfredSpecialAnimOffset ResourceManager::alfredSpecialAnims[] = {
{9, 33, 72, 1, 7, kAlfredAnimClimbUpOffset, 1, 2, 0}, // 8 - alfred climbs up
{16, 158, 115, 0, 7, kAlfredAnimExitTunnelOffset, 1, 2, 0}, // 9 - alfred exits tunnel
{7, 208, 102, 0, 7, kAlfredAnimWorkersOffset, 1, 2, 0}, // 10 - alfred with workers
- {23, 116, 124, 1, 7, kAlfredAnimMunheco1Offset, 1, 2, 0}, // 11 - Munheco 1
- {18, 177, 124, 1, 7, kAlfredAnimMunheco2Offset, 1, 2, 0}, // 12 - Munheco 2
- {11, 98, 138, 1, 7, kAlfredAnimMunheco3Offset, 1, 2, 0}, // 13 - Munheco 3
- {4, 51, 102, 1, 7, kAlfredAnimDescamisaOffset, 1, 2, 0}, // 14 - descamisa
+ {23, 116, 124, 1, 7, kAlfredAnimMunheco1Offset, 1, 2, 0}, // 11 - Doll 1
+ {18, 177, 124, 1, 7, kAlfredAnimMunheco2Offset, 1, 2, 0}, // 12 - Doll 2
+ {11, 98, 138, 1, 7, kAlfredAnimMunheco3Offset, 1, 2, 0}, // 13 - Doll 3
+ {4, 51, 102, 1, 7, kAlfredAnimDescamisaOffset, 1, 2, 0}, // 14 - Taking off shirt
{13, 95, 99, 1, 7, kAlfredAnimSecretPassageOffset, 1, 2, 0}, // 15 - alfred enters secret passage
{14, 71, 66, 1, 7, kAlfredAnimInBedOffset, 1, 2, 0}, // 16 - Alfred in bed
};
@@ -351,7 +351,6 @@ void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
uint32 size = anim.size == 0 ? anim.numFrames * anim.w * anim.h : anim.size;
_currentSpecialAnim->animData = new byte[size];
if (anim.numBudas > 0) {
- debug("Loading special anim with budas: numBudas=%d, totalSize %d", anim.numBudas, size);
byte *thisBlock = nullptr;
size_t blockSize = 0;
readUntilBuda(&alfredFile, anim.offset, thisBlock, blockSize);
@@ -397,7 +396,6 @@ void ResourceManager::loadInventoryItems() {
for (int i = 0; i < 69; i++) {
_inventoryIcons[i].index = i;
extractSingleFrame(iconData, _inventoryIcons[i].iconData, i, 60, 60);
- // _inventoryIcons[i].description = _inventoryDescriptions[i];
}
delete[] iconData;
}
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 400631e683d..6dfb6c06879 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -44,8 +44,17 @@ public:
void loadSettingsMenu();
void loadCursors();
void loadInteractionIcons();
+ /**
+ * Loads standard Alfred animations
+ */
void loadAlfredAnims();
+ /**
+ * Loads some other special anims for NPCs
+ */
void loadOtherSpecialAnim(uint32 offset, bool rleCompressed, byte *&buffer, size_t &bufferSize);
+ /**
+ * Loads one of the pre-defined Special anims for alfred.
+ */
void loadAlfredSpecialAnim(int numAnim, bool reverse = false);
void clearSpecialAnim();
void loadInventoryItems();
@@ -62,11 +71,11 @@ public:
byte *alfredIdle[4]; // 4 directions
byte **alfredWalkFrames[4]; // 4 arrays of arrays
- byte **alfredCrawlFrames[4];
+ byte **alfredCrawlFrames[4];// 4 arrays of arrays
byte **alfredTalkFrames[4]; // 4 arrays of arrays
+ byte **alfredInteractFrames[4];
byte **alfredCombFrames[2];
- byte **alfredInteractFrames[4];
byte *_cursorMasks[5];
byte *_verbIcons[9];
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 03231bab42a..396552cbadb 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -43,9 +43,9 @@ RoomManager::~RoomManager() {
}
void RoomManager::loadWaterPaletteRemap() {
- //Extra remap for water effect
+ // Extra remap for water effect
Common::File exe;
- if(!exe.open("JUEGO.EXE")) {
+ if (!exe.open("JUEGO.EXE")) {
error("Couldnt find file JUEGO.EXE");
}
exe.seek(kPaletteRemapOffset, SEEK_SET);
@@ -107,7 +107,7 @@ void RoomManager::addSticker(int stickerId, int persist) {
void RoomManager::addStickerToRoom(byte room, int stickerId, int persist) {
Sticker sticker = g_engine->_res->getSticker(stickerId);
if (room == _currentRoomNumber && persist & PERSIST_TEMP) {
- if(hasSticker(sticker.stickerIndex)) {
+ if (hasSticker(sticker.stickerIndex)) {
debug("Sticker %d already exists in room %d, skipping add", stickerId, room);
return;
}
@@ -216,7 +216,6 @@ void RoomManager::changeHotspot(byte room, HotSpot hotspot, int persist) {
_currentRoomHotspots[i] = hotspot;
break;
}
- debug("Hotspot %d in room %d does not match changed hotspot inner index %d", _currentRoomHotspots[i].innerIndex, room, hotspot.innerIndex);
}
}
if (persist & PERSIST_PERM) {
@@ -249,9 +248,8 @@ void RoomManager::enableSprite(byte spriteIndex, byte zOrder, int persist) {
}
void RoomManager::enableSprite(byte roomNumber, byte spriteIndex, byte zOrder, int persist) {
- for(int i =0; i < g_engine->_state->spriteChanges[roomNumber].size(); i++) {
+ for (int i = 0; i < g_engine->_state->spriteChanges[roomNumber].size(); i++) {
if (g_engine->_state->spriteChanges[roomNumber][i].spriteIndex == spriteIndex) {
- debug("Removing sprite change for room %d, sprite index %d, zOrder %d", roomNumber, spriteIndex, g_engine->_state->spriteChanges[roomNumber][i].zIndex);
g_engine->_state->spriteChanges[roomNumber].remove_at(i);
break;
}
@@ -321,7 +319,6 @@ void RoomManager::addWalkbox(WalkBox walkbox, int persist) {
_currentRoomWalkboxes.push_back(walkbox);
}
if (persist & PERSIST_PERM) {
- debug("Adding walkbox change for room %d, index %d, x=%d y=%d w=%d h=%d", _currentRoomNumber, walkbox.index, walkbox.x, walkbox.y, walkbox.w, walkbox.h);
g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].push_back({_currentRoomNumber, walkbox.index, walkbox});
}
}
@@ -347,7 +344,6 @@ Sprite *RoomManager::findSpriteByExtra(int16 extra) {
HotSpot *RoomManager::findHotspotByIndex(byte index) {
for (uint i = 0; i < _currentRoomHotspots.size(); i++) {
if (!_currentRoomHotspots[i].isSprite && _currentRoomHotspots[i].innerIndex == index) {
- debug("Found hotspot %d at index %d, extra = %d", index, i, _currentRoomHotspots[i].extra);
return &_currentRoomHotspots[i];
}
}
@@ -422,11 +418,6 @@ PaletteAnim *RoomManager::getPaletteAnimForRoom(int roomNumber) {
anim->paletteMode = exeFile.readByte();
exeFile.read(anim->data, 10);
if (anim->paletteMode == 1) {
- // FADE mode: shift RGB values to convert from 6-bit VGA to 8-bit
- // data[0-2] = current R,G,B
- // data[3-5] = min R,G,B
- // data[6-8] = max R,G,B
- // data[9] = flags (R/G/B increments + direction) - NOT shifted
for (int i = 0; i < 9; i++) {
anim->data[i] = anim->data[i] << 2;
}
@@ -484,9 +475,6 @@ Common::Array<Exit> RoomManager::loadExits(byte *data, size_t size) {
}
}
exits.push_back(exit);
- // debug("Exit %d: targetRoom=%d isEnabled=%d x=%d y=%d w=%d h=%d targetX=%d targetY=%d dir=%d",
- // i, exit.targetRoom, exit.isEnabled, exit.x, exit.y, exit.w, exit.h,
- // exit.targetX, exit.targetY, exit.dir);
}
return exits;
}
@@ -507,7 +495,6 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
// if the hotspot has been changed, load the changed version
for (uint j = 0; j < g_engine->_state->roomHotSpotChanges[_currentRoomNumber].size(); j++) {
if (g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspotIndex == spot.innerIndex) {
- debug("Hotspot %d has been changed, loading changed version, Hotspot x=%d, y = %d, extra = %d, isEnabled=%d", spot.innerIndex, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.x, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.y, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.extra, g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot.isEnabled);
hotspots.push_back(g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot);
isChanged = true;
break;
@@ -523,7 +510,6 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
spot.h = data[hotspotOffset + 6];
spot.isSprite = false;
spot.extra = READ_LE_INT16(data + hotspotOffset + 7);
- debug("Hotspot %d: type=%d x=%d y=%d w=%d h=%d extra=%d, index =%d, isEnabled=%d", spot.innerIndex, spot.actionFlags, spot.x, spot.y, spot.w, spot.h, spot.extra, spot.innerIndex, spot.isEnabled);
hotspots.push_back(spot);
}
@@ -554,7 +540,6 @@ void RoomManager::resetConversationStates(byte roomNumber, byte *conversationDat
continue;
}
Common::copy(entry.data, entry.data + entry.dataSize, conversationData + entry.offset);
- // delete[] entry.data;
}
alfredB.close();
}
@@ -646,6 +631,9 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
delete[] pair12;
}
+/**
+ * A number of rooms have a single passerby sprite that walks across the screen.
+ */
int streetWalkerIndices[] = {
-1, // room 0,
5, // room 1,
@@ -664,8 +652,8 @@ int streetWalkerIndices[] = {
2, // room 14,
-1, // room 15,
2
-
};
+
RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
RoomPasserBys *anims = nullptr;
switch (roomNumber) {
@@ -877,10 +865,6 @@ void RoomManager::init() {
if (!alfred8.open("ALFRED.8")) {
error("Couldnt find file ALFRED.8");
}
- // _resetDataSize = alfred8.size();
- // _resetData = new byte[_resetDataSize];
- // alfred8.read(_resetData, _resetDataSize);
- // alfred8.close();
}
void RoomManager::loadAnimationPixelData(Common::File *roomFile, int roomOffset, byte *&buffer, size_t &outSize) {
@@ -893,18 +877,15 @@ void RoomManager::loadAnimationPixelData(Common::File *roomFile, int roomOffset,
roomFile->seek(offset, SEEK_SET);
roomFile->read(pixelData, size);
if (offset > 0 && size > 0) {
- if(_currentRoomNumber != 40) {
+ if (_currentRoomNumber != 40) {
outSize = rleDecompress(pixelData, size, 0, size, &buffer, true);
- }
- else {
+ } else {
// room 40 has uncompressed animation data for some reason
buffer = new byte[size];
Common::copy(pixelData, pixelData + size, buffer);
outSize = size;
}
}
-
-
}
Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size) {
@@ -930,16 +911,14 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
sprite.numAnims = data[animOffset + 8];
sprite.zOrder = data[animOffset + 23];
sprite.extra = READ_LE_INT16(data + animOffset + 32);
- debug("Sprite %d: x=%d y=%d w=%d h=%d stride=%d numAnims=%d zOrder=%d extra=%d", i, sprite.x, sprite.y, sprite.w, sprite.h, sprite.stride, sprite.numAnims, sprite.zOrder, sprite.extra);
sprite.actionFlags = data[animOffset + 34];
- if(sprite.actionFlags & kActionMaskTalk) {
+ if (sprite.actionFlags & kActionMaskTalk) {
sprite.talkingAnimIndex = talkingAnims++;
}
sprite.isHotspotDisabled = data[animOffset + 38];
sprite.disableAfterSequence = data[animOffset + 39];
for (uint j = 0; j < spriteChanges.size(); j++) {
if (spriteChanges[j].spriteIndex == sprite.index) {
- debug("Sprite %d has been changed, loading changed version with zOrder %d", sprite.index, spriteChanges[j].zIndex);
sprite.zOrder = spriteChanges[j].zIndex;
break;
}
@@ -966,27 +945,23 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
anim.animData = new byte *[anim.nframes];
if (sprite.w > 0 && sprite.h > 0 && anim.nframes > 0) {
for (int k = 0; k < anim.nframes; k++) {
- if(picOffset >= pixelDataSize) {
+ if (picOffset >= pixelDataSize) {
debug("Pixel data offset out of bounds for sprite %d anim %d, offset %u, size %lu", i, j, picOffset, pixelDataSize);
break;
}
anim.animData[k] = new byte[sprite.w * sprite.h];
- // debug("Extracting frame %d for anim %d-%d, w=%d h=%d, pixelDataSize=%d, current offset %d", i, j, anim.nframes, sprite.w, sprite.h, pixelDataSize, picOffset);
extractSingleFrame(pixelData + picOffset, anim.animData[k], k, sprite.w, sprite.h);
}
sprite.animData[j] = anim;
- // debug(" Anim %d-%d: x=%d y=%d w=%d h=%d nframes=%d loopCount=%d speed=%d", i, j, anim.x, anim.y, anim.w, anim.h, anim.nframes, anim.loopCount, anim.speed);
- // debug(" Movement flags: 0x%04X", anim.movementFlags);
picOffset += totalBytesPerFrame;
- if(_currentRoomNumber == 36 && i == 0) {
+ if (_currentRoomNumber == 36 && i == 0) {
// Room 36 sets its anim to 1 to appear idle and only enables anim later on
anim.nframes = 1;
}
} else {
continue;
- // debug("Anim %d-%d: invalid dimensions, skipping", i, j);
}
sprite.animData[j] = anim;
}
@@ -1011,18 +986,15 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
int16 w = READ_LE_INT16(data + boxOffset + 4);
int16 h = READ_LE_INT16(data + boxOffset + 6);
byte flags = data[boxOffset + 8];
- debug("Walkbox %d: x1=%d y1=%d w=%d h=%d", i, x1, y1, w, h);
WalkBox box;
box.index = i;
bool isChanged = false;
if (g_engine->_state->roomWalkBoxChanges.contains(_currentRoomNumber)) {
- debug("Checking for changes to walkbox %d in room %d", i, _currentRoomNumber);
// if the walkbox has been changed, load the changed version
for (uint j = 0; j < g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
if (g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == i) {
walkboxes.push_back(g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
isChanged = true;
- debug("Walkbox %d has been changed, loading changed version, x1=%d y1=%d w=%d h=%d", i, g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox.x, g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox.y, g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox.w, g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox.h);
break;
}
}
@@ -1048,12 +1020,10 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
}
}
if (!found) {
- debug("Adding new walkbox for room %d at index %d", _currentRoomNumber, g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex);
walkboxes.push_back(g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
}
}
}
- debug("Total walkboxes for room %d: %d", _currentRoomNumber, walkboxes.size());
return walkboxes;
}
@@ -1111,12 +1081,14 @@ void RoomManager::loadConversationData(byte *pair12data, size_t pair12size, uint
}
}
+/**
+ * Disables choices according to saved data
+ */
void RoomManager::applyDisabledChoices(byte roomNumber, byte *conversationData, size_t conversationDataSize) {
Common::Array<ResetEntry> disabledBranches = g_engine->_state->disabledBranches[roomNumber];
if (disabledBranches.size() == 0) {
return;
}
- debug("Disabling %d conversation branches for room %d", disabledBranches.size(), roomNumber);
for (uint i = 0; i < disabledBranches.size(); i++) {
ResetEntry resetEntry = disabledBranches[i];
applyDisabledChoice(resetEntry, conversationData, conversationDataSize);
@@ -1134,7 +1106,7 @@ void RoomManager::addDisabledChoice(ChoiceOption choice) {
debug("Adding disabled branch for room %d at offset %d (FA written at %d)",
choice.room, choice.dataOffset, disableOffset);
- debug("Disabled branch is: \"%s\"", choice.text.c_str());
+ debug("Disabled branch is: \"%s\"", choice.text.c_str());
ResetEntry resetEntry = ResetEntry();
resetEntry.room = choice.room;
resetEntry.offset = disableOffset;
@@ -1208,7 +1180,6 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
talkFile.read(&talkHeader.unknown7, 4);
talkHeader.speedByteB = talkFile.readByte();
talkFile.read(&talkHeader.unknown6, 24);
- // debug("Talking anim header for room %d: spritePointer=%d, wA=%d, hA=%d, framesA=%d, wB=%d, hB=%d, framesB=%d", roomNumber, talkHeader.spritePointer, talkHeader.wAnimA, talkHeader.hAnimA, talkHeader.numFramesAnimA, talkHeader.wAnimB, talkHeader.hAnimB, talkHeader.numFramesAnimB);
if (talkHeader.spritePointer == 0) {
debug("No talking animation for room %d", roomNumber);
@@ -1225,7 +1196,6 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
readUntilBuda(&talkFile, talkHeader.spritePointer, data, dataSize);
size_t decompressedSize = rleDecompress(data, dataSize, 0, dataSize, &decompressed);
free(data);
- // debug("Decompressed talking anim A size: %zu, decompressed size: %zu", dataSize, decompressedSize);
for (int i = 0; i < talkHeader.numFramesAnimA; i++) {
talkHeader.animA[i] = new byte[talkHeader.wAnimA * talkHeader.hAnimA];
extractSingleFrame(decompressed, talkHeader.animA[i], i, talkHeader.wAnimA, talkHeader.hAnimA);
@@ -1236,7 +1206,6 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
for (int i = 0; i < talkHeader.numFramesAnimB; i++) {
talkHeader.animB[i] = new byte[talkHeader.wAnimB * talkHeader.hAnimB];
uint32 animBFrameOffset = animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB);
- // debug("Extracting talking anim B frame %d at offset %d, size = %d", i, animASize + (i * talkHeader.wAnimB * talkHeader.hAnimB), talkHeader.wAnimB * talkHeader.hAnimB);
if (animBFrameOffset + talkHeader.wAnimB * talkHeader.hAnimB >= decompressedSize) {
debug("Error: offset %d is beyond decompressed size %zu", animBFrameOffset, decompressedSize);
talkHeader.numFramesAnimB = 0;
@@ -1285,7 +1254,7 @@ byte *RoomManager::loadShadowMap(int roomNumber) {
byte *shadows = nullptr;
size_t decompressedSize = rleDecompress(compressed, compressedSize, 0, 640 * 400, &shadows);
- if(decompressedSize == 0) {
+ if (decompressedSize == 0) {
debug("Failed to decompress shadow map for room %d", roomNumber);
shadows = nullptr;
}
@@ -1302,7 +1271,7 @@ void RoomManager::loadRemaps(int roomNumber) {
error("Couldnt find file ALFRED.9");
}
- uint32 remapOffset =/* 0x200 + */(roomNumber * 1024);
+ uint32 remapOffset = /* 0x200 + */ (roomNumber * 1024);
remapFile.seek(remapOffset, SEEK_SET);
remapFile.read(_paletteRemaps[0], 256);
@@ -1310,7 +1279,6 @@ void RoomManager::loadRemaps(int roomNumber) {
remapFile.read(_paletteRemaps[2], 256);
remapFile.read(_paletteRemaps[3], 256);
remapFile.close();
-
}
byte RoomManager::loadMusicTrackForRoom(Common::File *roomFile, int roomOffset) {
@@ -1335,7 +1303,6 @@ Common::Array<byte> RoomManager::loadRoomSfx(Common::File *roomFile, int roomOff
for (int i = 0; i < kNumSfxPerRoom; i++) {
byte sfx = roomFile->readByte();
roomSfx[i] = sfx;
- debug("SFX %d for room at offset %d is %d (%s)", i, roomOffset, sfx, SOUND_FILENAMES[sfx]);
}
return roomSfx;
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index a2c98b4dc72..65116ae2cd8 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -32,7 +32,7 @@ namespace Pelrock {
static const int kNumSfxPerRoom = 9;
static const int unpickableHotspotExtras[] = {
308, // lamppost cable
- 65, // objects in shop
+ 65, // objects in shop
66,
67,
68,
@@ -44,10 +44,8 @@ static const int unpickableHotspotExtras[] = {
74,
6,
7,
- 91, //mud and stone should only be picked under certain conditions!
- 92
-};
-
+ 91, // mud and stone should only be picked under certain conditions!
+ 92};
#define PERSIST_TEMP 1
#define PERSIST_PERM 2
@@ -58,7 +56,13 @@ public:
RoomManager();
~RoomManager();
void loadRoomMetadata(Common::File *roomFile, int roomNumber);
+ /**
+ * Passer by animations are animations of characters that merely traverse the scene as ambient
+ */
RoomPasserBys *loadPasserByAnims(int roomNumber);
+ /**
+ * Treats sprites and hotspots the same.
+ */
Common::Array<HotSpot> unifyHotspots(Common::Array<Pelrock::Sprite> &anims, Common::Array<Pelrock::HotSpot> &staticHotspots);
void loadRoomTalkingAnimations(int roomNumber);
void getPalette(Common::File *roomFile, int roomOffset, byte *palette);
@@ -113,9 +117,11 @@ public:
void applyDisabledChoice(ResetEntry entry, byte *conversationData, size_t conversationDataSize);
void addDisabledChoice(ChoiceOption choice);
-
+ /**
+ * Will apply the default "take item with given extra" handler if returns true
+ */
bool isPickableByExtra(uint16 extra) {
- if(extra > 112)
+ if (extra > 112)
return false;
int size = sizeof(unpickableHotspotExtras) / sizeof(unpickableHotspotExtras[0]);
for (int i = 0; i < size; i++) {
@@ -124,13 +130,13 @@ public:
}
return true;
}
+
Sprite *findSpriteByIndex(byte index);
Sprite *findSpriteByExtra(int16 extra);
HotSpot *findHotspotByIndex(byte index);
HotSpot *findHotspotByExtra(uint16 extra);
PaletteAnim *getPaletteAnimForRoom(int roomNumber);
-
byte _currentRoomNumber = 0;
int _prevRoomNumber = -1;
Common::Array<HotSpot> _currentRoomHotspots;
Commit: 9afa4e1c632ca559ae5cb99c71c1306fb77e881f
https://github.com/scummvm/scummvm/commit/9afa4e1c632ca559ae5cb99c71c1306fb77e881f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:41+02:00
Commit Message:
PELROCK: Cleanup of sound and spellbook
Changed paths:
engines/pelrock/slidingpuzzle.cpp
engines/pelrock/slidingpuzzle.h
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/spellbook.cpp
engines/pelrock/spellbook.h
diff --git a/engines/pelrock/slidingpuzzle.cpp b/engines/pelrock/slidingpuzzle.cpp
index 0baf21f30be..e2625962127 100644
--- a/engines/pelrock/slidingpuzzle.cpp
+++ b/engines/pelrock/slidingpuzzle.cpp
@@ -22,10 +22,10 @@
#include "common/system.h"
#include "graphics/paletteman.h"
-#include "pelrock/slidingpuzzle.h"
-#include "pelrock/pelrock.h"
#include "pelrock/events.h"
+#include "pelrock/pelrock.h"
#include "pelrock/room.h"
+#include "pelrock/slidingpuzzle.h"
#include "pelrock/sound.h"
namespace Pelrock {
@@ -50,8 +50,8 @@ SlidingPuzzle::~SlidingPuzzle() {
void SlidingPuzzle::run() {
// calculate grid
- _tileSize = kTileSizes[_sizeIndex];
- _gridWidth = kPuzzleScreenWidth / _tileSize;
+ _tileSize = kTileSizes[_sizeIndex];
+ _gridWidth = kPuzzleScreenWidth / _tileSize;
_gridHeight = kPuzzleScreenHeight / _tileSize;
_totalTiles = _gridWidth * _gridHeight;
@@ -66,7 +66,7 @@ void SlidingPuzzle::run() {
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
- //Shuffle
+ // Shuffle
shuffleLoop();
// Guarantee the puzzle is solvable, fix it otherwise
@@ -163,13 +163,13 @@ void SlidingPuzzle::shuffleLoop() {
// scale tile swap with tile count
const int kBaseTileCount = (kPuzzleScreenWidth / kTileSizes[0]) *
- (kPuzzleScreenHeight / kTileSizes[0]);
+ (kPuzzleScreenHeight / kTileSizes[0]);
const int swapsPerFrame = MAX(1, _totalTiles / kBaseTileCount);
while (!g_engine->shouldQuit()) {
_events->pollEvent();
- for (int s = 0; s < swapsPerFrame; s++) {
+ for (int i = 0; i < swapsPerFrame; i++) {
int a, b;
do {
a = g_engine->getRandomNumber(shuffleRange - 1);
@@ -231,7 +231,7 @@ bool SlidingPuzzle::handleClick(int screenX, int screenY) {
int emptyRow = _emptyPos / _gridWidth;
int emptyCol = _emptyPos % _gridWidth;
bool adjacent = (row == emptyRow && abs(col - emptyCol) == 1) ||
- (col == emptyCol && abs(row - emptyRow) == 1);
+ (col == emptyCol && abs(row - emptyRow) == 1);
if (!adjacent)
return false;
diff --git a/engines/pelrock/slidingpuzzle.h b/engines/pelrock/slidingpuzzle.h
index fb7b4d3c20e..55a47a897ab 100644
--- a/engines/pelrock/slidingpuzzle.h
+++ b/engines/pelrock/slidingpuzzle.h
@@ -55,9 +55,9 @@ private:
int _tileSize;
int _gridWidth;
int _gridHeight;
- int _totalTiles; // gridWidth * gridHeight`
- int _emptyPos; // index of the empty (removed) tile
- uint16 *_tileMap; // logical position -> original tile index
+ int _totalTiles; // gridWidth * gridHeight`
+ int _emptyPos; // index of the empty (removed) tile
+ uint16 *_tileMap; // logical position -> original tile index
Graphics::ManagedSurface _puzzleBuffer;
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index e575d8410fd..15247333b4a 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -234,7 +234,7 @@ void SoundManager::playSound(byte *soundData, uint32 size, int channel) {
Audio::AudioStream *stream = Audio::makeRawStream(soundData, size, 11025, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
if (stream) {
if (_mixer->isSoundHandleActive(_sfxHandles[channel])) {
- _mixer->stopHandle(_sfxHandles[channel]);
+ _mixer->stopHandle(_sfxHandles[channel]);
}
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandles[channel], stream, -1, _currentVolume, 0, DisposeAfterUse::YES);
}
@@ -362,7 +362,7 @@ void SoundManager::pauseMusic() {
uint32 elapsedFrames = elapsed * 75 / 1000;
_cdTrackStart += elapsedFrames; // advance the start offset
if (_cdTrackDuration > 0)
- _cdTrackDuration -= elapsedFrames; // shrink remaining duration
+ _cdTrackDuration -= elapsedFrames; // shrink remaining duration
g_system->getAudioCDManager()->stop();
_isPaused = true;
}
@@ -374,13 +374,11 @@ bool SoundManager::isMusicPlaying() {
void SoundManager::playMusicTrack(int trackNumber, bool loop) {
if (!_isPaused && _currentMusicTrack == trackNumber && isMusicPlaying()) {
// Already playing this track
- debug("Track %d is already playing", trackNumber);
return;
}
_currentMusicTrack = trackNumber;
- debug("Playing music track %d, loop=%d", trackNumber, loop);
- if(!_isPaused) {
+ if (!_isPaused) {
_cdTrackStart = 0;
_cdTrackDuration = 0;
_cdPlayStartTime = g_system->getMillis();
@@ -404,7 +402,6 @@ void SoundManager::loadSoundIndex() {
return;
}
byte fileCount = sonidosFile.readByte();
- debug("SONIDOS.DAT contains %u files", fileCount);
sonidosFile.skip(3); // Padding bytes
for (uint32 i = 0; i < fileCount; i++) {
@@ -421,12 +418,12 @@ void SoundManager::loadSoundIndex() {
static const uint kAmbientCounterMask = 0x1F; // Trigger when (counter & mask) == mask
int SoundManager::tickAmbientSound(uint32 frameCount) {
- // Counter gate: only trigger every 32 frames when (counter & 0x1F) == 0x1F
+ // trigger every 32 frames
if ((frameCount & kAmbientCounterMask) != kAmbientCounterMask) {
return -1;
}
- // 50% probability gate using ScummVM's random source
+ // 50% probability gate
if (g_engine->getRandomNumber(1) == 0) {
return -1;
}
@@ -434,7 +431,7 @@ int SoundManager::tickAmbientSound(uint32 frameCount) {
// Pick random ambient slot 0-3 (corresponds to room sound indices 4-7)
int ambientSlotOffset = g_engine->getRandomNumber(3);
- return ambientSlotOffset; // Caller adds 4 to get room sound index
+ return ambientSlotOffset;
}
} // End of namespace Pelrock
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 407abf114c3..0219efb7a2c 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -85,9 +85,6 @@ public:
/**
* Check if ambient sound should play this frame.
- * @param frameCount Current game frame counter
- * @return Ambient slot offset (0-3) to play, or -1 if no sound this frame
- * Add kAmbientSoundSlotBase (4) to get room sound index
*/
int tickAmbientSound(uint32 frameCount);
diff --git a/engines/pelrock/spellbook.cpp b/engines/pelrock/spellbook.cpp
index ac802b8cc93..50497244b30 100644
--- a/engines/pelrock/spellbook.cpp
+++ b/engines/pelrock/spellbook.cpp
@@ -29,10 +29,10 @@
namespace Pelrock {
-static const uint32 kSpellbookImgOffset = 1268719; // ALFRED.7 â spellbook sprite sheet start
+static const uint32 kSpellbookImgOffset = 1268719; // ALFRED.7 â spellbook sprite sheet start
static const uint32 kSpellbookImgDataOffset = 1268723; // ALFRED.7 â compressed sprite data
-static const uint32 kSpellbookTextOffset = 288285; // JUEGO.EXE â spellbook page text
-static const uint32 kSpellbookTextSize = 2861;
+static const uint32 kSpellbookTextOffset = 288285; // JUEGO.EXE â spellbook page text
+static const uint32 kSpellbookTextSize = 2861;
SpellBook::SpellBook(PelrockEventManager *eventMan, ResourceManager *res)
: _palette(nullptr),
diff --git a/engines/pelrock/spellbook.h b/engines/pelrock/spellbook.h
index 6a587d194d4..9d944fd7d37 100644
--- a/engines/pelrock/spellbook.h
+++ b/engines/pelrock/spellbook.h
@@ -55,8 +55,7 @@ static const Bookmark _bookmarks[13] = {
{95, 277, 33, 24, 7},
{105, 227, 27, 33, 6},
{103, 118, 30, 26, 3},
- {101, 78, 36, 33, 2}
-};
+ {101, 78, 36, 33, 2}};
class SpellBook {
Commit: 903b6e4d22a3081308bba8c75f2a9386be6002ca
https://github.com/scummvm/scummvm/commit/903b6e4d22a3081308bba8c75f2a9386be6002ca
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:41+02:00
Commit Message:
PELROCK: Cleanup utils
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/util.cpp
engines/pelrock/util.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index e6c0bd4764b..c1c962c3cc7 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -552,7 +552,7 @@ void MenuManager::drawScreen() {
}
void MenuManager::drawInventoryIcons() {
- bool debugIcons = true;
+ bool debugIcons = false;
for (int i = 0; i < 4; i++) {
int itemIndex = _curInventoryPage * 4 + i;
if (g_engine->_state->inventoryItems.size() <= itemIndex)
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 9e522918a23..012a9a7c90b 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -31,71 +31,12 @@
namespace Pelrock {
void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color) {
- // debug("Drawing rect at (%d,%d) w=%d h=%d color=%d", x, y, w, h, color);
surface->drawLine(x, y, x + w, y, color);
surface->drawLine(x, y + h, x + w, y + h, color);
surface->drawLine(x, y, x, y + h, color);
surface->drawLine(x + w, y, x + w, y + h, color);
}
-void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color) {
- surface->drawLine(x, y, x + w, y, color);
- surface->drawLine(x, y + h, x + w, y + h, color);
- surface->drawLine(x, y, x, y + h, color);
- surface->drawLine(x + w, y, x + w, y + h, color);
-}
-
-void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color) {
- Graphics::Surface surface;
- surface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
- drawRect(&surface, 0, 0, w - 1, h, color);
-
- for (int py = 0; py < h; py++) {
- for (int px = 0; px < w; px++) {
- int destIdx = (y + py) * 640 + (x + px);
- int pixelColor = *((byte *)surface.getBasePtr(px, py));
- if (pixelColor != 0)
- screenBuffer[destIdx] = pixelColor;
- }
- }
- surface.free();
-}
-
-void drawText(byte *screenBuffer, Graphics::Font *font, Common::String text, int x, int y, int w, byte color, Graphics::TextAlign align) {
- Common::Rect rect = font->getBoundingBox(text.c_str());
- Graphics::Surface surface;
- int bboxW = rect.width();
- int bboxH = rect.height();
-
- surface.create(bboxW, bboxH, Graphics::PixelFormat::createFormatCLUT8());
- surface.fillRect(Common::Rect(0, 0, bboxW, bboxH), 255);
- if (x + bboxW > 640) {
- x = 640 - bboxW - 2;
- }
- if (y + bboxH > 400) {
- y = 400 - bboxH - 2;
- }
- if (x < 0) {
- x = 0;
- }
- if (y < 0) {
- y = 0;
- }
-
- // Draw main text on top
- font->drawString(&surface, text.c_str(), 0, 0, bboxW, color, align);
- // drawRect(surface, 0, 0, bboxW - 1, bboxH - 1, color);
- for (int py = 0; py < bboxH; py++) {
- for (int px = 0; px < bboxW; px++) {
- int destIdx = (y + py) * 640 + (x + px);
- int pixelColor = *((byte *)surface.getBasePtr(px, py));
- if(pixelColor != 255 && destIdx >= 0 && destIdx < 256000)
- screenBuffer[destIdx] = pixelColor;
- }
- }
- surface.free();
-}
-
void drawText(Graphics::Font *font, Common::String text, int x, int y, int w, byte color) {
Common::Rect rect = font->getBoundingBox(text.c_str());
if (x + rect.width() > 640) {
@@ -273,27 +214,6 @@ void rleDecompressSingleBuda(Common::SeekableReadStream *stream, uint32 startPos
free(buffer);
}
-// Helper function for transparent blitting
-void drawSpriteToBuffer(byte *buffer, int bufferWidth, byte *sprite, int x, int y, int width, int height, int transparentColor) {
-
- for (int py = 0; py < height; py++) {
- for (int px = 0; px < width; px++) {
- int srcIdx = py * width + px;
- byte pixel = sprite[srcIdx];
-
- if (pixel != transparentColor) {
- int destX = x + px;
- int destY = y + py;
-
- if (destX >= 0 && destX < 640 &&
- destY >= 0 && destY < 400) {
- buffer[destY * bufferWidth + destX] = pixel;
- }
- }
- }
- }
-}
-
// ManagedSurface overload: wraps sprite data in a Surface and uses transBlitFrom
void drawSpriteToBuffer(Graphics::ManagedSurface &dest, byte *sprite, int x, int y, int width, int height, int transparentColor) {
Graphics::Surface spriteSurf;
@@ -301,22 +221,6 @@ void drawSpriteToBuffer(Graphics::ManagedSurface &dest, byte *sprite, int x, int
dest.transBlitFrom(spriteSurf, Common::Point(x, y), transparentColor);
}
-void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY) {
- for (int y = 0; y < surface->h; y++) {
- for (int x = 0; x < surface->w; x++) {
- int px = destX + x;
- int py = destY + y;
- if (px >= 0 && px < bufferWidth && py >= 0 && py < bufferHeight) {
-
- byte pixel = *((byte *)surface->getBasePtr(x, y));
- if (pixel != 0) {
- buffer[py * bufferWidth + px] = pixel;
- }
- }
- }
- }
-}
-
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight) {
for (int y = 0; y < frameHeight; y++) {
for (int x = 0; x < frameWidth; x++) {
@@ -377,55 +281,6 @@ void changeGameSpeed(Common::Event e) {
}
}
-Common::StringArray arrayOf(Common::String str) {
- return Common::StringArray(1, str);
-}
-
-
-void invertSprite(byte *spriteBuf, int w, int h) {
- // invert horizontal lines so character is upside down
- for (int y = 0; y < h / 2; y++) {
- for (int x = 0; x < w; x++) {
- int topIndex = y * w + x;
- int bottomIndex = (h - 1 - y) * w + x;
- byte temp = spriteBuf[topIndex];
- spriteBuf[topIndex] = spriteBuf[bottomIndex];
- spriteBuf[bottomIndex] = temp;
- }
- }
-}
-
-void drawPaletteSquares(byte *screenBuffer, byte *palette) {
- // Draw 3x3 squares for all 256 palette colors
- // Arrange them in a 16x16 grid (256 colors)
- const int squareSize = 6;
- const int colorsPerRow = 16;
- const int startX = 10; // Left margin
- const int startY = 10; // Top margin
- const int spacing = 1; // Space between squares
-
- for (int colorIndex = 0; colorIndex < 256; colorIndex++) {
- int row = colorIndex / colorsPerRow;
- int col = colorIndex % colorsPerRow;
-
- int x = startX + col * (squareSize + spacing);
- int y = startY + row * (squareSize + spacing);
-
- // Draw the 3x3 square with the current color
- for (int py = 0; py < squareSize; py++) {
- for (int px = 0; px < squareSize; px++) {
- int destX = x + px;
- int destY = y + py;
-
- // Bounds check
- if (destX >= 0 && destX < 640 && destY >= 0 && destY < 400) {
- screenBuffer[destY * 640 + destX] = colorIndex;
- }
- }
- }
- }
-}
-
void drawPaletteSquares(Graphics::ManagedSurface &dest, byte *palette) {
const int squareSize = 6;
const int colorsPerRow = 16;
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index fe61d1d2d42..95f73dcff12 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -31,27 +31,21 @@
namespace Pelrock {
-const int EXPECTED_SIZE = 640 * 400;
size_t rleDecompress(const byte *data, size_t data_size, uint32 offset, uint32 size, byte **out_data, bool untilBuda = true);
void readUntilBuda(Common::SeekableReadStream *stream, uint32 startPos, byte *&buffer, size_t &outSize);
void rleDecompressSingleBuda(Common::SeekableReadStream *stream, uint32 startPos, byte *&buffer, size_t &outSize);
-void drawSpriteToBuffer(byte *buffer, int bufferWidth, byte *sprite, int x, int y, int width, int height, int transparentColor);
void drawSpriteToBuffer(Graphics::ManagedSurface &dest, byte *sprite, int x, int y, int width, int height, int transparentColor);
-void blitSurfaceToBuffer(Graphics::Surface *surface, byte *buffer, int bufferWidth, int bufferHeight, int destX, int destY);
void extractSingleFrame(byte *source, byte *dest, int frameIndex, int frameWidth, int frameHeight);
-void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
-void drawRect(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
-void drawRect(byte *screenBuffer, int x, int y, int w, int h, byte color);
-void drawText(byte *screenBuffer, Graphics::Font *font, Common::String text, int x, int y, int w, byte color, Graphics::TextAlign align = Graphics::kTextAlignLeft);
+
void drawText(Graphics::ManagedSurface &dest, Graphics::Font *font, Common::String text, int x, int y, int w, byte color, Graphics::TextAlign align = Graphics::kTextAlignLeft);
void drawText(Graphics::Font *font, Common::String text, int x, int y, int w, byte color);
Common::String joinStrings(const Common::Array<Common::String> &strings, const Common::String &separator);
-void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
byte decodeChar(byte b);
void changeGameSpeed(Common::Event e);
-Common::StringArray arrayOf(Common::String str);
-void invertSprite(byte *data, int w, int h);
-void drawPaletteSquares(byte *screenBuffer, byte *palette);
+
+// debug functions
+void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byte color);
+void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
void drawPaletteSquares(Graphics::ManagedSurface &dest, byte *palette);
static const int special_chars[] = {
Commit: ce2b01f4faa74250e08a5eddbf66558733cd8305
https://github.com/scummvm/scummvm/commit/ce2b01f4faa74250e08a5eddbf66558733cd8305
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:41+02:00
Commit Message:
PELROCK: Types cleanup
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.h
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
engines/pelrock/room.h
engines/pelrock/saveload.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 102d776ace9..d093a424679 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -2130,10 +2130,10 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_sound->playSound(_room->_roomSfx[8], 0);
_dialog->say(_res->_ingameTexts[DIOSHALCON + spell->page], 1);
int flightIndex = _room->_currentRoomNumber - 51;
- if (_flightSorcererAppeared && !_flightInBlockingAnim && spell->page == kFlightRooms[flightIndex].spellPage) {
+ if (_fightSorcererAppeared && !_fightInBlockingAnim && spell->page == kFightRooms[flightIndex].spellPage) {
_state->setFlag(FLAG_COMO_ESTAN_LOS_DIOSES, _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) | (1 << flightIndex));
_sound->playSound(_room->_roomSfx[1], 0);
- smokeAnimation(kFlightRooms[flightIndex].spriteIdx, true);
+ smokeAnimation(kFightRooms[flightIndex].spriteIdx, true);
_room->addStickerToRoom(_room->_currentRoomNumber, 127 + flightIndex);
_room->addStickerToRoom(52, 106 + flightIndex);
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index cda61767630..50f5486cd85 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -52,6 +52,10 @@ const byte kCtrlEndConversation = 0xF4; /* End conversation and disable opt
const byte kCtrlGoBack = 0xF0; /* Go back in conversation */
const byte kCtrlAltSpeakerRoot = 0xFE; /* Separates conversations from different speakers */
+const int kChoiceHeight = 16; // Height of each choice line in pixels
+const int kMaxCharsPerLine = 47; // 47 characters
+const int kMaxLines = 5; // Maximum number of lines per page
+
// Helper structures for conversation state management
struct ConversationState {
uint32 position;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index e162930be1d..9cda936bb97 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -433,7 +433,7 @@ void PelrockEngine::mouseHoverForMap() {
void PelrockEngine::frameTriggers() {
uint32 frameCount = _chrono->getFrameCount();
passerByAnim(frameCount);
- handleFlightRoomFrame();
+ handleFightRoomFrame();
shakeEffect();
maybeHaveDogPee();
}
@@ -2406,17 +2406,17 @@ void PelrockEngine::credits() {
void PelrockEngine::initGodsSequences(int roomNumber) {
int idx = roomNumber - 51;
- _flightFrameCounter = 0;
- _flightSorcererSpriteIdx = kFlightRooms[idx].spriteIdx;
- _flightSorcererAppeared = false;
- _flightSpellCast = false;
- _flightSpellFrameCounter = 0;
- _flightInBlockingAnim = false;
+ _fightFrameCounter = 0;
+ _fightSorcererSpriteIdx = kFightRooms[idx].spriteIdx;
+ _fightSorcererAppeared = false;
+ _fightSpellCast = false;
+ _fightSpellFrameCounter = 0;
+ _fightInBlockingAnim = false;
- _room->disableSprite(_flightSorcererSpriteIdx);
+ _room->disableSprite(_fightSorcererSpriteIdx);
}
-void PelrockEngine::handleFlightRoomFrame() {
+void PelrockEngine::handleFightRoomFrame() {
int room = _room->_currentRoomNumber;
if (room < 51 || room > 54)
return;
@@ -2428,44 +2428,44 @@ void PelrockEngine::handleFlightRoomFrame() {
}
// Guard against reentrance from blocking animation loops calling renderScene
- if (_flightInBlockingAnim)
+ if (_fightInBlockingAnim)
return;
if (_alfredState.animState != ALFRED_IDLE || _actionPopupState.isActive) {
return;
}
- _flightFrameCounter++;
+ _fightFrameCounter++;
// Phase 1: NPC appearance at tick 64
- if (!_flightSorcererAppeared && _flightFrameCounter >= 64) {
+ if (!_fightSorcererAppeared && _fightFrameCounter >= 64) {
_sound->playSound(_room->_roomSfx[0]);
- _flightSorcererAppeared = true;
- _flightInBlockingAnim = true;
- _room->findSpriteByIndex(_flightSorcererSpriteIdx)->animData[0].nframes = 1;
- smokeAnimation(_flightSorcererSpriteIdx, false);
- _flightInBlockingAnim = false;
+ _fightSorcererAppeared = true;
+ _fightInBlockingAnim = true;
+ _room->findSpriteByIndex(_fightSorcererSpriteIdx)->animData[0].nframes = 1;
+ smokeAnimation(_fightSorcererSpriteIdx, false);
+ _fightInBlockingAnim = false;
return;
}
// Phase 2: spell trigger at tick 104 (64 + 40)
- if (_flightSorcererAppeared && !_flightSpellCast && _flightFrameCounter >= 104) {
- debug("spell cast triggered for room %d at frame %d", room, _flightFrameCounter);
- _flightSpellCast = true;
- _flightSpellFrameCounter = 0;
+ if (_fightSorcererAppeared && !_fightSpellCast && _fightFrameCounter >= 104) {
+ debug("spell cast triggered for room %d at frame %d", room, _fightFrameCounter);
+ _fightSpellCast = true;
+ _fightSpellFrameCounter = 0;
}
// Phase 3: wait 40 ticks after spell trigger, then cast
- if (_flightSpellCast) {
- debug("in spell cast phase for room %d at frame %d", room, _flightFrameCounter);
- _flightSpellFrameCounter++;
- if (_flightSpellFrameCounter >= 40 && !(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) & (1 << idx))) {
- debug("spell cast animation starting for room %d at frame %d, flag is %d", room, _flightFrameCounter, _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES));
- _flightInBlockingAnim = true;
-
- int spellFrames = kFlightRooms[idx].spellFrames;
+ if (_fightSpellCast) {
+ debug("in spell cast phase for room %d at frame %d", room, _fightFrameCounter);
+ _fightSpellFrameCounter++;
+ if (_fightSpellFrameCounter >= 40 && !(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) & (1 << idx))) {
+ debug("spell cast animation starting for room %d at frame %d, flag is %d", room, _fightFrameCounter, _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES));
+ _fightInBlockingAnim = true;
+
+ int spellFrames = kFightRooms[idx].spellFrames;
int framesDone = 0;
- _room->findSpriteByIndex(_flightSorcererSpriteIdx)->animData[0].nframes = kFlightRooms[idx].spellFrames;
- _room->findSpriteByIndex(_flightSorcererSpriteIdx)->animData[0].speed = 1;
+ _room->findSpriteByIndex(_fightSorcererSpriteIdx)->animData[0].nframes = kFightRooms[idx].spellFrames;
+ _room->findSpriteByIndex(_fightSorcererSpriteIdx)->animData[0].speed = 1;
_sound->playSound(_room->_roomSfx[1]);
while (!shouldQuit() && framesDone < spellFrames) {
_events->pollEvent();
@@ -2474,10 +2474,10 @@ void PelrockEngine::handleFlightRoomFrame() {
_screen->update();
g_system->delayMillis(10);
}
- _room->findSpriteByIndex(_flightSorcererSpriteIdx)->animData[0].nframes = 1;
+ _room->findSpriteByIndex(_fightSorcererSpriteIdx)->animData[0].nframes = 1;
smokeAnimation(-1, true);
- _flightInBlockingAnim = false;
+ _fightInBlockingAnim = false;
_alfredState.x = 294;
_alfredState.y = 387;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index f492898c3fe..cfcf45c4a99 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -150,12 +150,12 @@ private:
int _renderSkipAmount = 0;
int _renderSkipCounter = 0;
- int _flightFrameCounter = 0;
- int _flightSorcererSpriteIdx = -1;
- bool _flightSorcererAppeared = false;
- bool _flightSpellCast = false;
- int _flightSpellFrameCounter = 0;
- bool _flightInBlockingAnim = false;
+ int _fightFrameCounter = 0;
+ int _fightSorcererSpriteIdx = -1;
+ bool _fightSorcererAppeared = false;
+ bool _fightSpellCast = false;
+ int _fightSpellFrameCounter = 0;
+ bool _fightInBlockingAnim = false;
bool _disableAmbientSounds = false;
bool _isDogPeeing = false;
bool _disableAction = false;
@@ -256,7 +256,7 @@ public:
void maybeHaveDogPee();
void maybePlayPostIntro();
void shakeEffect();
- void handleFlightRoomFrame();
+ void handleFightRoomFrame();
void paintDebugLayer();
void passerByAnim(uint32 frameCount);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 65116ae2cd8..5c9efd3abf9 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -29,6 +29,8 @@
namespace Pelrock {
+static const int kRoomStructSize = 104;
+static const int kTalkingAnimHeaderSize = 55;
static const int kNumSfxPerRoom = 9;
static const int unpickableHotspotExtras[] = {
308, // lamppost cable
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index ac62e159528..2b6c3cfa3b0 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -42,7 +42,6 @@ void syncExit(Common::Serializer &s, Exit &exit) {
s.syncAsUint16LE(exit.targetRoom);
s.syncAsSint16LE(exit.targetX);
s.syncAsSint16LE(exit.targetY);
- s.syncAsUint16LE(exit.targetDir);
s.syncAsByte((byte &)exit.dir);
s.syncAsByte(exit.isEnabled);
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index df4df025152..1780ec71d2f 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -29,6 +29,9 @@
namespace Pelrock {
+/**
+ * Cursor types when hovering over hotspots
+ */
enum Cursor {
DEFAULT,
HOTSPOT,
@@ -37,6 +40,9 @@ enum Cursor {
COMBINATION
};
+/**
+ * Actions masks on hotspots, matching against these gives us the available actions.
+ */
const byte kActionMaskNone = 0;
const byte kActionMaskOpen = 1;
const byte kActionMaskClose = 2;
@@ -60,27 +66,21 @@ enum VerbIcon {
NO_ACTION
};
-const uint32 kLongClickDuration = 500; // 500ms for long click
const int kCursorWidth = 16;
const int kCursorHeight = 18;
const int kCursorSize = 288; // 16 * 18
-const int kRoomStructSize = 104;
-const int kTalkingAnimHeaderSize = 55;
-const int kNumRooms = 56;
+
const int kVerbIconWidth = 60;
const int kVerbIconHeight = 60;
const int kNumVerbIcons = 9;
+
const int kBalloonWidth = 247;
const int kBalloonHeight = 112;
const int kBalloonFrames = 4;
-const int kTextCharDisplayTime = 100; // 10ms per character
-const int kVerbIconPadding = 20;
const int kAlfredFrameWidth = 51;
const int kAlfredFrameHeight = 102;
-const int kChoiceHeight = 16; // Height of each choice line in pixels
-
const int kTalkAnimationSpeed = 2; // Frames per update
const int kAlfredAnimationSpeed = 2; // Frames per update
@@ -102,9 +102,6 @@ const int kMaxPathLength = 100;
const int kMaxMovementSteps = 100; // 500 bytes / 5 bytes per step
const byte kPathEnd = 0xFF; // End of path marker
-const int kMaxCharsPerLine = 0x2F; // 47 characters
-const int kMaxLines = 5; // Maximum number of lines per page
-
const byte kAlfredColor = 0x0D;
enum OverlayMode {
@@ -237,6 +234,9 @@ struct PathContext {
uint16 compressed_length;
};
+/**
+ * Each Anim has its own speed, loopCount and movement!
+ */
struct Anim {
int nframes;
int curFrame = 0;
@@ -257,14 +257,12 @@ struct Exit {
uint16 targetRoom;
int16 targetX;
int16 targetY;
- uint16 targetDir;
AlfredDirection dir;
byte isEnabled;
};
struct Sprite {
- byte index; // number of the animation in the rooms
- byte type;
+ byte index; // number of the animation in the rooms
int16 x; // 0
int16 y; // 2
int w; // 4
@@ -272,8 +270,7 @@ struct Sprite {
uint16 stride; // 6-7
int numAnims; // 8
int curAnimIndex = 0;
- byte zOrder; // byte at file offset 23 (in-memory struct offset 0x21). Unsigned 0-254, 255=disabled
-
+ byte zOrder; // byte at file offset 23
byte actionFlags; // 34
bool isHotspotDisabled; // 38
bool disableAfterSequence = false; // 39
@@ -310,19 +307,19 @@ struct TalkingAnims {
byte hAnimA;
byte unknown3[2];
byte numFramesAnimA;
- byte unknown4[4]; // slot 0 data pointer (unused in ScummVM)
- byte speedByteA; // slot 0 offset 0x12: controls NPC talk render rate (original: 2+speedByte ticks per render)
+ byte unknown4[4]; // slot 0 data pointer (unused in ScummVM)
+ byte speedByteA; // slot 0 offset 0x12: controls NPC talk render rate (original: 2+speedByte ticks per render)
byte offsetXAnimB;
byte offsetYAnimB;
byte wAnimB;
byte hAnimB;
- byte unknown5[2]; // slot 1 stride (unused in ScummVM)
+ byte unknown5[2]; // slot 1 stride (unused in ScummVM)
byte numFramesAnimB;
- byte unknown7[4]; // slot 1 data pointer (unused in ScummVM)
- byte speedByteB; // slot 1 speed byte at file offset 30
- byte unknown6[24]; // slots 2-3 (unused)
+ byte unknown7[4]; // slot 1 data pointer (unused in ScummVM)
+ byte speedByteB; // slot 1 speed byte at file offset 30
+ byte unknown6[24]; // slots 2-3 (unused)
// Runtime fields (not read from file)
byte currentFrameAnimA;
@@ -706,7 +703,7 @@ struct SaveGameData {
GameStateData *gameState = nullptr;
};
-struct FlightRoomCfg {
+struct FightRoomCfg {
int roomNumber;
int spriteIdx;
int appearFrames;
@@ -714,7 +711,7 @@ struct FlightRoomCfg {
int spellPage;
};
-static const FlightRoomCfg kFlightRooms[] = {
+static const FightRoomCfg kFightRooms[] = {
{51, 1, 31, 17, 8}, // room 51
{52, 0, 30, 13, 4}, // room 52
{53, 1, 30, 13, 0}, // room 53
Commit: 34129b6bff87dc3bce85fe515fdfbd9d1cd73779
https://github.com/scummvm/scummvm/commit/34129b6bff87dc3bce85fe515fdfbd9d1cd73779
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:42+02:00
Commit Message:
PELROCK: Cleanup of offsets
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/offsets.h
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index d093a424679..116edb997f3 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -230,7 +230,7 @@ const CombinationEntry combinationTable[] = {
*/
void PelrockEngine::openDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayClosed) {
if (_room->hasSticker(sticker)) {
- int text = masculine == MASCULINE ? YA_ABIERTO_M : YA_ABIERTA_F;
+ int text = masculine == MASCULINE ? kTextYaAbiertoM : kTextYaAbiertaF;
_dialog->say(_res->_ingameTexts[text]);
return;
}
@@ -241,7 +241,7 @@ void PelrockEngine::openDoor(HotSpot *hotspot, int exitIndex, int sticker, bool
void PelrockEngine::closeDoor(HotSpot *hotspot, int exitIndex, int sticker, bool masculine, bool stayOpen) {
if (!_room->hasSticker(sticker)) {
- int text = masculine == MASCULINE ? YA_CERRADO_M : YA_CERRADA_F;
+ int text = masculine == MASCULINE ? kTextYaCerradoM : kTextYaCerradaF;
_dialog->say(_res->_ingameTexts[text]);
return;
}
@@ -279,7 +279,7 @@ void PelrockEngine::addInventoryItem(int item) {
*/
void PelrockEngine::buyFromStore(HotSpot *hotspot, int stickerId) {
if (_state->hasInventoryItem(5) == false) {
- _dialog->say(_res->_ingameTexts[NOTENGODINERO]);
+ _dialog->say(_res->_ingameTexts[kTextNoTengoDinero]);
return;
} else {
_room->addSticker(stickerId);
@@ -290,9 +290,9 @@ void PelrockEngine::buyFromStore(HotSpot *hotspot, int stickerId) {
addInventoryItem(hotspot->extra);
_currentHotspot = nullptr;
walkLoop(224, 283, ALFRED_LEFT);
- _dialog->say(_res->_ingameTexts[CUESTA1000]);
- _dialog->say(_res->_ingameTexts[AQUITIENE]);
- _dialog->say(_res->_ingameTexts[MUYBIEN]);
+ _dialog->say(_res->_ingameTexts[kTextCuesta1000]);
+ _dialog->say(_res->_ingameTexts[kTextAquiTiene]);
+ _dialog->say(_res->_ingameTexts[kTextMuyBien]);
_state->removeInventoryItem(5); // Remove 1000 pesetas bill
}
}
@@ -311,21 +311,21 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(4, 2, 0);
break;
case 259:
- _dialog->say(_res->_ingameTexts[DEPIEDRANO_DEHIELO], 1);
- _dialog->say(_res->_ingameTexts[NO_EMPECEMOS]);
+ _dialog->say(_res->_ingameTexts[kTextDePiedraNoDeHielo], 1);
+ _dialog->say(_res->_ingameTexts[kTextNoEmpecemos]);
break;
case 260:
- _dialog->say(_res->_ingameTexts[CUERPO_DANONE], 1);
- _dialog->say(_res->_ingameTexts[CABEZA_HUECA]);
+ _dialog->say(_res->_ingameTexts[kTextCuerpoDanone], 1);
+ _dialog->say(_res->_ingameTexts[kTextCabezaHueca]);
break;
case 261:
- _dialog->say(_res->_ingameTexts[ESO_LO_SERAS_TU], 1);
+ _dialog->say(_res->_ingameTexts[kTextEsoLoSerasTu], 1);
break;
case 262:
- _dialog->say(_res->_ingameTexts[DEMASIADO_NO_PUEDO_PENSAR], 1);
+ _dialog->say(_res->_ingameTexts[kTextDemasiadoNoPuedoPensar], 1);
break;
case 263:
- _dialog->say(_res->_ingameTexts[UN_POCO_RESPETO]);
+ _dialog->say(_res->_ingameTexts[kTextUnPocoRespeto]);
break;
case 264:
// skip to root after the next one
@@ -372,7 +372,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
addInventoryItem(102);
break;
case 331:
- _dialog->say(_res->_ingameTexts[HECHOELPRIMO]);
+ _dialog->say(_res->_ingameTexts[kTextHechoElPrimo]);
break;
case 332:
// psychologist card
@@ -381,7 +381,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
}
break;
case 333:
- _dialog->say(_res->_ingameTexts[MEHANTOMADO_EL_PELO]);
+ _dialog->say(_res->_ingameTexts[kTextMeHanTomadoElPelo]);
break;
case 334:
addInventoryItem(76);
@@ -392,7 +392,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
addInventoryItem(103);
break;
case 336:
- _dialog->say(_res->_ingameTexts[PESADO_UNRATO]);
+ _dialog->say(_res->_ingameTexts[kTextPesadoUnRato]);
break;
case 337:
case 338:
@@ -423,24 +423,24 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
}
break;
case 351:
- _dialog->say(_res->_ingameTexts[TRAIDOR], 0);
- _dialog->say(_res->_ingameTexts[TUTIA], 1);
- _dialog->say(_res->_ingameTexts[LATUYA], 0);
- _dialog->say(_res->_ingameTexts[GORDO], 1);
- _dialog->say(_res->_ingameTexts[FIDEO], 0);
- _dialog->say(_res->_ingameTexts[LIMPIACULO], 1);
- _dialog->say(_res->_ingameTexts[CONTUTURBANTE], 0);
- _dialog->say(_res->_ingameTexts[OSO], 1);
- _dialog->say(_res->_ingameTexts[COMADREJA], 0);
- _dialog->say(_res->_ingameTexts[CABEZON], 1);
- _dialog->say(_res->_ingameTexts[TUABUELO], 0);
- _dialog->say(_res->_ingameTexts[TUMUJER], 1);
- _dialog->say(_res->_ingameTexts[PERDEDOR], 0);
- _dialog->say(_res->_ingameTexts[SOYMEJORQUETU], 1);
- _dialog->say(_res->_ingameTexts[TRAMPOSO], 0);
- _dialog->say(_res->_ingameTexts[MALPERDEDOR], 1);
- _dialog->say(_res->_ingameTexts[PARAUNAVEZ], 0);
- _dialog->say(_res->_ingameTexts[MEJORMELARGO], 1);
+ _dialog->say(_res->_ingameTexts[kTextTraidor], 0);
+ _dialog->say(_res->_ingameTexts[kTextTuTia], 1);
+ _dialog->say(_res->_ingameTexts[kTextLaTuya], 0);
+ _dialog->say(_res->_ingameTexts[kTextGordo], 1);
+ _dialog->say(_res->_ingameTexts[kTextFideo], 0);
+ _dialog->say(_res->_ingameTexts[kTextLimpiaculos], 1);
+ _dialog->say(_res->_ingameTexts[kTextConTuTurbante], 0);
+ _dialog->say(_res->_ingameTexts[kTextOso], 1);
+ _dialog->say(_res->_ingameTexts[kTextComadreja], 0);
+ _dialog->say(_res->_ingameTexts[kTextCabezon], 1);
+ _dialog->say(_res->_ingameTexts[kTextTuAbuelo], 0);
+ _dialog->say(_res->_ingameTexts[kTextTuMujer], 1);
+ _dialog->say(_res->_ingameTexts[kTextPerdedor], 0);
+ _dialog->say(_res->_ingameTexts[kTextSoyMejorQueTu], 1);
+ _dialog->say(_res->_ingameTexts[kTextTramposo], 0);
+ _dialog->say(_res->_ingameTexts[kTextMalPerdedor], 1);
+ _dialog->say(_res->_ingameTexts[kTextParaUnaVez], 0);
+ _dialog->say(_res->_ingameTexts[kTextMejorMeLargo], 1);
break;
// end merchants
case 353:
@@ -744,7 +744,7 @@ void PelrockEngine::noOpItem(int item, HotSpot *hotspot) {
// These are books in the library being returned to the librarian
if (item >= 11 && item <= 58 && hotspot->extra == 358) {
_state->removeInventoryItem(item);
- _dialog->say(_res->_ingameTexts[DEACUERDO_2]);
+ _dialog->say(_res->_ingameTexts[kTextDeAcuerdo2]);
return;
}
_alfredState.direction = ALFRED_DOWN;
@@ -757,7 +757,7 @@ void PelrockEngine::openRoomDoor(HotSpot *hotspot) {
void PelrockEngine::openRoomDrawer(HotSpot *hotspot) {
if (_room->hasSticker(91)) {
- _dialog->say(_res->_ingameTexts[YA_ABIERTO_M]);
+ _dialog->say(_res->_ingameTexts[kTextYaAbiertoM]);
return;
}
_room->addSticker(91);
@@ -786,16 +786,16 @@ void PelrockEngine::pickUpBrick(HotSpot *hotspot) {
}
void PelrockEngine::openIceCreamShopDoor(HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[HELADERIA_CERRADA]);
+ _dialog->say(_res->_ingameTexts[kTextHeladeraCerrada]);
}
void PelrockEngine::pickupGarbageCan(HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[POBRE_PERO_NO_HE_LLEGADO_A_ESO]);
+ _dialog->say(_res->_ingameTexts[kTextPobreNoHeLlegadoAEso]);
}
void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
if (!_room->hasSticker(91)) {
- _dialog->say(_res->_ingameTexts[YA_CERRADO_M]);
+ _dialog->say(_res->_ingameTexts[kTextYaCerradoM]);
return;
}
_room->removeSticker(91);
@@ -803,7 +803,7 @@ void PelrockEngine::closeRoomDrawer(HotSpot *hotspot) {
}
void PelrockEngine::openClosedDrawer(HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[ESTAN_CERRADOS]);
+ _dialog->say(_res->_ingameTexts[kTextEstanCerrados]);
}
void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
@@ -824,10 +824,10 @@ void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
// 1 in every 15 times, the hooker will say "fancy a good time?"
bool sayLine = getRandomNumber(15) == 1;
if (sayLine) {
- _dialog->say(_res->_ingameTexts[TEAPETECE_BUENRATO]);
+ _dialog->say(_res->_ingameTexts[kTextTeApeteceBuenRato]);
}
} else {
- _dialog->say(_res->_ingameTexts[NOTENGOMASDINERO]);
+ _dialog->say(_res->_ingameTexts[kTextNoTengoMasDinero]);
}
}
}
@@ -841,7 +841,7 @@ void PelrockEngine::closeMcDoor(HotSpot *hotspot) {
}
void PelrockEngine::pickupBush(HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[MEHEVUELTOAPINCHAR]);
+ _dialog->say(_res->_ingameTexts[kTextMeHeVueltoAPinchar]);
}
void PelrockEngine::pickUpAndDisable(HotSpot *hotspot) {
@@ -871,15 +871,15 @@ void PelrockEngine::closeKitchenDoor(HotSpot *HotSpot) {
void PelrockEngine::openKitchenDrawer(HotSpot *hotspot) {
if (!_state->getFlag(FLAG_JEFE_ENCARCELADO)) {
- _dialog->say(_res->_ingameTexts[QUITA_ESAS_MANOS]);
+ _dialog->say(_res->_ingameTexts[kTextQuitaEsasManos]);
} else if (!_state->getFlag(FLAG_RECIPE_TAKEN)) {
_state->setFlag(FLAG_RECIPE_TAKEN, true);
_room->addSticker(36);
addInventoryItem(63); // Add recipe
- _dialog->say(_res->_ingameTexts[QUESESTO_RECETA]);
+ _dialog->say(_res->_ingameTexts[kTextQuesEstoReceta]);
} else {
// Already took the recipe
- _dialog->say(_res->_ingameTexts[YAESTA_ABIERTO]);
+ _dialog->say(_res->_ingameTexts[kTextYaEstaAbierto]);
}
}
@@ -890,12 +890,12 @@ void PelrockEngine::openKitchenDoorFromInside(HotSpot *hotspot) {
void PelrockEngine::useSpicySauceWithBurger(int inventoryObject, HotSpot *hotspot) {
_state->setFlag(FLAG_PUESTA_SALSA_PICANTE, true);
_sound->playSound(_room->_roomSfx[2]);
- _dialog->say(_res->_ingameTexts[VAESTAR_POCOFUERTE]);
+ _dialog->say(_res->_ingameTexts[kTextVaestarPocoFuerte]);
}
void PelrockEngine::openShopDoor(HotSpot *hotspot) {
if (!_state->getFlag(FLAG_TIENDA_ABIERTA)) {
- _dialog->say(_res->_ingameTexts[TIENDA_CERRADA]);
+ _dialog->say(_res->_ingameTexts[kTextTiendaCerrada]);
return;
} else {
openDoor(hotspot, 0, 13, MASCULINE, false);
@@ -945,9 +945,9 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
// Play the NPC dialog sequence
int16 dialog1y = y + 22;
int16 dialog2y = dialog1y + 10 + _largeFont->getFontHeight();
- _dialog->say(_res->_ingameTexts[QUEHASIDOESO], x, dialog1y);
- _dialog->say(_res->_ingameTexts[QUIENANDAAHI], x, dialog2y);
- _dialog->say(_res->_ingameTexts[YOMEVOY]);
+ _dialog->say(_res->_ingameTexts[kTextQueHaSidoEso], x, dialog1y);
+ _dialog->say(_res->_ingameTexts[kTextQuienAndaAhi], x, dialog2y);
+ _dialog->say(_res->_ingameTexts[kTextYoMeVoy]);
_state->setFlag(FLAG_TIENDA_ABIERTA, true);
_room->addStickerToRoom(_room->_currentRoomNumber, 9, PERSIST_PERM);
@@ -968,7 +968,7 @@ void PelrockEngine::moveCable(HotSpot *hotspot) {
}
void PelrockEngine::useBrickWithShopWindow(int inventoryObject, HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[NOSE_ENTERARIA]);
+ _dialog->say(_res->_ingameTexts[kTextNoseEnteraria]);
}
void PelrockEngine::pickGuitar(HotSpot *hotspot) {
@@ -1025,7 +1025,7 @@ void PelrockEngine::openPlug(HotSpot *hotspot) {
void PelrockEngine::useCordWithPlug(int inventoryObject, HotSpot *hotspot) {
if (!_room->hasSticker(18)) {
- _dialog->say(_res->_ingameTexts[PRIMERO_ABRIRLO]);
+ _dialog->say(_res->_ingameTexts[kTextPrimeroAbrirlo]);
} else {
if (_state->getFlag(FLAG_CABLES_PUESTOS)) {
_room->addSticker(19);
@@ -1037,7 +1037,7 @@ void PelrockEngine::useCordWithPlug(int inventoryObject, HotSpot *hotspot) {
void PelrockEngine::pickCables(HotSpot *hotspot) {
if (_room->hasSticker(21)) {
- _dialog->say(_res->_ingameTexts[QUELOSCOJA_SUPADRE]);
+ _dialog->say(_res->_ingameTexts[kTextQueLosCojaSupadre]);
return;
}
// Duck to pick cables
@@ -1054,19 +1054,19 @@ void PelrockEngine::pickCables(HotSpot *hotspot) {
playAlfredSpecialAnim(2, true);
_room->addSticker(21);
- _dialog->say(_res->_ingameTexts[RELOJ_HA_CAMBIADO]);
+ _dialog->say(_res->_ingameTexts[kTextRelojHaCambiado]);
_state->setCurrentRoot(4, 1, 0);
}
void PelrockEngine::showIdToGuard(int inventoryObject, HotSpot *hotspot) {
if (!_state->getFlag(FLAG_GUARDIA_PIDECOSAS)) {
- _dialog->say(_res->_ingameTexts[CUANDOMELOPIDA]);
+ _dialog->say(_res->_ingameTexts[kTextCuandoMeLoPida]);
return;
}
if (!_state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
_state->setFlag(FLAG_GUARDIA_DNI_ENTREGADO, true);
- _dialog->say(_res->_ingameTexts[DEACUERDO]);
+ _dialog->say(_res->_ingameTexts[kTextDeAcuerdo]);
}
if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
unlockMuseum();
@@ -1086,11 +1086,11 @@ void PelrockEngine::unlockMuseum() {
void PelrockEngine::giveMoneyToGuard(int inventoryObject, HotSpot *hotspot) {
if (!_state->getFlag(FLAG_GUARDIA_PIDECOSAS)) {
- _dialog->say(_res->_ingameTexts[PRETENDEUSTED_SOBORNARME]);
+ _dialog->say(_res->_ingameTexts[kTextPretendeUstedSobornarme]);
return;
} else if (!_state->getFlag(FLAG_SOBORNO_PORTERO)) {
_state->setFlag(FLAG_SOBORNO_PORTERO, true);
- _dialog->say(_res->_ingameTexts[MUYBIEN]);
+ _dialog->say(_res->_ingameTexts[kTextMuyBien]);
_state->removeInventoryItem(5);
}
if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
@@ -1101,12 +1101,12 @@ void PelrockEngine::giveMoneyToGuard(int inventoryObject, HotSpot *hotspot) {
void PelrockEngine::openMuseumDoor(HotSpot *hotspot) {
if (!_state->getFlag(FLAG_GUARDIA_PIDECOSAS)) {
- _dialog->say(_res->_ingameTexts[ALTO]);
+ _dialog->say(_res->_ingameTexts[kTextAlto]);
return;
} else if (!_state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
- _dialog->say(_res->_ingameTexts[NECESITODNI]);
+ _dialog->say(_res->_ingameTexts[kTextNecesitaDni]);
} else if (!_state->getFlag(FLAG_SOBORNO_PORTERO)) {
- _dialog->say(_res->_ingameTexts[QUE_RECIBO_ACAMBIO]);
+ _dialog->say(_res->_ingameTexts[kTextQueReciboACambio]);
} else {
openDoor(hotspot, 1, 22, FEMININE, false);
}
@@ -1117,7 +1117,7 @@ void PelrockEngine::closeMuseumDoor(HotSpot *hotspot) {
}
void PelrockEngine::pickupFruit(HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[NO_THEY_MAKEYOU_FAT]);
+ _dialog->say(_res->_ingameTexts[kTextNoTheyMakeyouFat]);
}
void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
@@ -1133,16 +1133,16 @@ void PelrockEngine::useAmuletWithStatue(int inventoryObject, HotSpot *hotspot) {
walkTo(statueHotspot->x + statueHotspot->w / 2, statueHotspot->y + statueHotspot->h);
_sound->playSound(_room->_roomSfx[0]); // Magic sound
animateStatuePaletteFade(false);
- _dialog->say(_res->_ingameTexts[ANDA]);
+ _dialog->say(_res->_ingameTexts[kTextAnda]);
walkAndAction(statueHotspot, TALK);
waitForActionEnd();
}
}
void PelrockEngine::useSecretCodeWithStatue(int inventoryObject, HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[NOESAMIAQUIENDEBES]);
- _dialog->say(_res->_ingameTexts[AQUIENENTONCES]);
- _dialog->say(_res->_ingameTexts[LIBROSSECRETOS]);
+ _dialog->say(_res->_ingameTexts[kTextNoEsAMiAQuienDebes]);
+ _dialog->say(_res->_ingameTexts[kTextAQuienEntonces]);
+ _dialog->say(_res->_ingameTexts[kTextLibrosSecretos]);
}
void PelrockEngine::pickUpLetter(HotSpot *hotspot) {
@@ -1179,13 +1179,13 @@ void PelrockEngine::pickBooksFromShelf3(HotSpot *hotspot) {
}
void PelrockEngine::giveSecretCodeToLibrarian(int inventoryObject, HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[REGALO_LIBRO_RECETAS]);
+ _dialog->say(_res->_ingameTexts[kTextRegaloLibroRecetas]);
_state->removeInventoryItem(8);
addInventoryItem(59);
}
void PelrockEngine::useBrickWithLibrarian(int inventoryObject, HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[YSI_METIRA_MAQUINA]);
+ _dialog->say(_res->_ingameTexts[kTextYSiMeTiraMaquina]);
}
void PelrockEngine::openNewspaperDoor(HotSpot *hotspot) {
@@ -1222,7 +1222,7 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
if (_state->getFlag(FLAG_CROCODILLO_ENCENDIDO) == false) {
_sound->playMusicTrack(27);
checkIngredients();
- _dialog->say(_res->_ingameTexts[CUIDADOIMPRUDENTE]);
+ _dialog->say(_res->_ingameTexts[kTextCuidadoImprudente]);
_alfredState.x -= 10;
_alfredState.y += 20;
playAlfredSpecialAnim(5);
@@ -1235,7 +1235,7 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
waitForSoundEnd();
_alfredState.animState = ALFRED_IDLE;
setScreenAndPrepare(28, ALFRED_DOWN);
- _dialog->say(_res->_ingameTexts[QUEOSCUROESTAESTO]);
+ _dialog->say(_res->_ingameTexts[kTextQueOscuroEstaEsto]);
}
}
@@ -1258,9 +1258,9 @@ void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
if (_state->getFlag(FLAG_PARADOJA_RESUELTA) == false) {
if (_state->getFlag(FLAG_RIDDLE_PRESENTED)) {
// try to take the sunflower before solving the riddle
- _dialog->say(_res->_ingameTexts[LEESTOYVIGILANDO]);
+ _dialog->say(_res->_ingameTexts[kTextLeEstoyVigilando]);
} else {
- _dialog->say(_res->_ingameTexts[OIGA]);
+ _dialog->say(_res->_ingameTexts[kTextOiga]);
_state->setCurrentRoot(25, 26, 0);
walkAndAction(_room->findHotspotByExtra(467), TALK);
_state->setFlag(FLAG_RIDDLE_PRESENTED, true);
@@ -1276,14 +1276,14 @@ void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
void PelrockEngine::checkIngredients() {
byte ingredientes = _state->getFlag(FLAG_INGREDIENTES_CONSEGUIDOS);
- int textLine = PRIMERINGREDIENTE + ingredientes;
+ int textLine = kTextPrimerIngrediente + ingredientes;
_dialog->say(_res->_ingameTexts[textLine]);
_state->setFlag(FLAG_INGREDIENTES_CONSEGUIDOS, ingredientes + 1);
}
void PelrockEngine::pickUpBook(int i) {
if (!_state->hasInventoryItem(10)) {
- _dialog->say(_res->_ingameTexts[VENGA_ACA]);
+ _dialog->say(_res->_ingameTexts[kTextVengaAca]);
_state->setCurrentRoot(9, 1, 0);
if (_state->hasInventoryItem(3)) {
@@ -1301,9 +1301,9 @@ void PelrockEngine::pickUpBook(int i) {
}
} else {
if (_state->libraryShelf == -1) {
- _dialog->say(_res->_ingameTexts[TODOS]);
+ _dialog->say(_res->_ingameTexts[kTextTodos]);
} else if (_state->libraryShelf != i) {
- _dialog->say(_res->_ingameTexts[EL_LIBRO_NOESTA_AQUI]);
+ _dialog->say(_res->_ingameTexts[kTextElLibroNoEstaAqui]);
} else {
_state->libraryShelf = -1;
int booksInInventory = _state->booksInInventory();
@@ -1311,7 +1311,7 @@ void PelrockEngine::pickUpBook(int i) {
int firstBook = _state->findFirstBookIndex();
if (firstBook != -1)
_state->removeInventoryItem(firstBook);
- _dialog->say(_res->_ingameTexts[TENDRE_DEJAR_LIBRO]);
+ _dialog->say(_res->_ingameTexts[kTextTendreDejarLibro]);
}
addInventoryItem(_state->selectedBookIndex);
_state->selectedBookIndex = -1;
@@ -1396,7 +1396,7 @@ void PelrockEngine::pickUpHairStrand(HotSpot *hotspot) {
void PelrockEngine::openJailFloorTile(HotSpot *hotspot) {
if (_room->hasSticker(77)) {
- _dialog->say(_res->_ingameTexts[YA_ABIERTO_M]);
+ _dialog->say(_res->_ingameTexts[kTextYaAbiertoM]);
return;
}
_room->enableExit(0, PERSIST_BOTH);
@@ -1416,12 +1416,12 @@ void PelrockEngine::useKeyWithPortrait(int inventoryObject, HotSpot *hotspot) {
void PelrockEngine::openSafe(HotSpot *hotspot) {
if (_state->getFlag(FLAG_CLAVE_CAJA_FUERTE) == true) {
_room->addSticker(102);
- _dialog->say(_res->_ingameTexts[GRANCANTIDAD_DINERO]);
+ _dialog->say(_res->_ingameTexts[kTextGranCantidadDinero]);
addInventoryItem(82);
_state->setCurrentRoot(27, 1, 0);
_state->setCurrentRoot(27, 1, 1);
} else {
- _dialog->say(_res->_ingameTexts[SISUPIERA_COMBINACION]);
+ _dialog->say(_res->_ingameTexts[kTextSiSupieraCombinacion]);
}
}
@@ -1459,11 +1459,11 @@ void PelrockEngine::giveMagazineToGuard(int inventoryObject, HotSpot *hotspot) {
void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
_state->setFlag(FLAG_VIGILANTE_BEBE_AGUA, _state->getFlag(FLAG_VIGILANTE_BEBE_AGUA) + 1);
- _dialog->say(_res->_ingameTexts[ALACONUSTED]);
+ _dialog->say(_res->_ingameTexts[kTextAlaConUsted]);
_state->removeInventoryItem(86);
addInventoryItem(76);
if (_state->getFlag(FLAG_VIGILANTE_BEBE_AGUA) == 3) {
- _dialog->say(_res->_ingameTexts[MEMEO]);
+ _dialog->say(_res->_ingameTexts[kTextMeMeo]);
_state->setFlag(FLAG_VIGILANTE_MEANDO, true);
guardMovement();
_room->disableSprite(36, 0, PERSIST_BOTH);
@@ -1508,9 +1508,9 @@ void PelrockEngine::pickUpStone(HotSpot *hotspot) {
_sound->playSound("QUAKE2ZZ.SMP", 0, -1);
_shakeEffectState.enable();
checkIngredients();
- _dialog->say(_res->_ingameTexts[AYAYAY]);
+ _dialog->say(_res->_ingameTexts[kTextAyAyAy]);
_alfredState.direction = ALFRED_DOWN;
- _dialog->say(_res->_ingameTexts[NADIELOHAVISTO]);
+ _dialog->say(_res->_ingameTexts[kTextNadieLaHaVisto]);
_alfredState.direction = ALFRED_LEFT;
_disableAction = true;
@@ -1567,7 +1567,7 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
_sound->playSound(_room->_roomSfx[0], 0);
waitForSoundEnd();
- _dialog->say(_res->_ingameTexts[HAYQUECELEBRARLO]);
+ _dialog->say(_res->_ingameTexts[kTextHayQueCelebrarlo]);
byte counter = _state->getFlag(FLAG_DA_PIEDRA);
// drinking animation and sound
@@ -1705,11 +1705,11 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
void PelrockEngine::pickUpStones(HotSpot *hotspot) {
if (_state->hasInventoryItem(91)) {
- _dialog->say(_res->_ingameTexts[PESADEMASIADO]);
+ _dialog->say(_res->_ingameTexts[kTextPesaDemasiado]);
return;
}
if (_state->getFlag(FLAG_PIEDRAS_COGIDAS) >= 2) {
- _dialog->say(_res->_ingameTexts[NINGUNATAMANHOAPROPIADO]);
+ _dialog->say(_res->_ingameTexts[kTextNingunaTamanhoApropiado]);
return;
} else {
addInventoryItem(91);
@@ -1719,17 +1719,17 @@ void PelrockEngine::pickUpStones(HotSpot *hotspot) {
void PelrockEngine::pickUpMud(HotSpot *hotspot) {
if (_state->getFlag(FLAG_PIEDRAS_COGIDAS) != 2) {
- _dialog->say(_res->_ingameTexts[PARAQUECOGERBARRO]);
+ _dialog->say(_res->_ingameTexts[kTextParaQueCogeBarro]);
return;
} else {
addInventoryItem(92);
_state->setFlag(FLAG_PIEDRAS_COGIDAS, _state->getFlag(FLAG_PIEDRAS_COGIDAS) + 1);
- _dialog->say(_res->_ingameTexts[BUENOCOGEREUNPOCO]);
+ _dialog->say(_res->_ingameTexts[kTextBuenoCogereUnPoco]);
}
}
void PelrockEngine::openPyramidDoor(HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[ABSOLUTAMENTECERRADO]);
+ _dialog->say(_res->_ingameTexts[kTextAbsolutamenteCerrado]);
}
void PelrockEngine::usePumpkinWithPond(int inventoryObject, HotSpot *hotspot) {
@@ -1763,7 +1763,7 @@ void PelrockEngine::useWaterOnFakeStone(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::useWigWithPot(int inventoryObject, HotSpot *hotspot) {
- _dialog->say(_res->_ingameTexts[NOERAAUTENTICO]);
+ _dialog->say(_res->_ingameTexts[kTextNoEraAutentico]);
_state->removeInventoryItem(99);
}
@@ -1844,7 +1844,7 @@ void PelrockEngine::pickupPyramidMap(HotSpot *hotspot) {
void PelrockEngine::openArchitectDoorFromInside(HotSpot *hotspot) {
if (!_room->hasSticker(104)) {
- _dialog->say(_res->_ingameTexts[YA_ABIERTA_F]);
+ _dialog->say(_res->_ingameTexts[kTextYaAbiertaF]);
return;
}
_room->enableExit(0, PERSIST_TEMP);
@@ -1854,7 +1854,7 @@ void PelrockEngine::openArchitectDoorFromInside(HotSpot *hotspot) {
void PelrockEngine::closeArchitectDoorFromInside(HotSpot *hotspot) {
if (_room->hasSticker(104)) {
- _dialog->say(_res->_ingameTexts[YA_CERRADA_F]);
+ _dialog->say(_res->_ingameTexts[kTextYaCerradaF]);
return;
}
_room->disableExit(0, PERSIST_TEMP);
@@ -1867,27 +1867,27 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
case 257: // look portrait
_sound->playMusicTrack(25, false);
loadExtraScreenAndPresent(9);
- _dialog->say(_res->_ingameTexts[QUEBUENA_ESTA]);
+ _dialog->say(_res->_ingameTexts[kTextQueBuenaEsta]);
_screen->markAllDirty();
_screen->update();
break;
case 268: // look at statue
- _dialog->say(_res->_ingameTexts[TUCREES]);
+ _dialog->say(_res->_ingameTexts[kTextTuCrees]);
break;
case 271: // look at librarian
- _dialog->say(_res->_ingameTexts[TRABAJARIA_MEJOR_SI_NO_ME_MOLESTARA]);
+ _dialog->say(_res->_ingameTexts[kTextTrabajariaMejorSiNoMeMolestara]);
break;
case 270:
_state->stateGame = COMPUTER;
break;
case 280:
- _dialog->say(_res->_ingameTexts[NOVIO2METROS]);
+ _dialog->say(_res->_ingameTexts[kTextNovio2Metros]);
break;
case 281:
- _dialog->say(_res->_ingameTexts[GRANIDEA]);
+ _dialog->say(_res->_ingameTexts[kTextGranIdea]);
break;
case 282:
- _dialog->say(_res->_ingameTexts[SELORECOMIENDO]);
+ _dialog->say(_res->_ingameTexts[kTextSeLorecomiendo]);
break;
case 327:
_state->setFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO, true);
@@ -1907,7 +1907,7 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
}
case 322: {
- _dialog->say(_res->_ingameTexts[NOSETEOCURRAACERCARTE]);
+ _dialog->say(_res->_ingameTexts[kTextNoSeTeCurraCercarte]);
break;
}
case 375: {
@@ -2022,7 +2022,7 @@ void PelrockEngine::teleportToPrincess() {
_graphics->presentFrame();
_screen->update();
- _dialog->say(_res->_ingameTexts[MAREDEDEU]);
+ _dialog->say(_res->_ingameTexts[kTextMareDeDou]);
smokeAnimation(-1, true);
_state->setFlag(FLAG_END_OF_GAME, true);
@@ -2037,10 +2037,10 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
debug("Using item %d on Alfred", inventoryObject);
switch (inventoryObject) {
case 9: // Letter
- _dialog->say(_res->_ingameTexts[CORRESPONDENCIA_AJENA]);
+ _dialog->say(_res->_ingameTexts[kTextCorrespondenciaAjena]);
break;
case 34: // How to become rich book
- _dialog->say(_res->_ingameTexts[PERIODICOSENSACIONALISTA], 1);
+ _dialog->say(_res->_ingameTexts[kTextPeriodicoSensacionalista], 1);
break;
case 63: // Recipe
playAlfredSpecialAnim(1);
@@ -2049,30 +2049,30 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_state->setCurrentRoot(17, 1, 0);
_state->setCurrentRoot(18, 4, 0);
debug("After extra screen");
- _dialog->say(_res->_ingameTexts[QUEASCO]);
+ _dialog->say(_res->_ingameTexts[kTextQueAsco]);
break;
case 59: // Recipe book
if (!_state->hasInventoryItem(64)) {
playAlfredSpecialAnim(0);
- _dialog->say(_res->_ingameTexts[HOJAENTREPAGINAS]);
+ _dialog->say(_res->_ingameTexts[kTextHojaEntrePaginas]);
addInventoryItem(64);
} else {
playAlfredSpecialAnim(0);
- _dialog->say(_res->_ingameTexts[NOENTIENDONADA]);
+ _dialog->say(_res->_ingameTexts[kTextNoEntiendonada]);
}
break;
case 17: // Egyptian book
playAlfredSpecialAnim(0);
- _dialog->say(_res->_ingameTexts[YASEEGIPCIO]);
+ _dialog->say(_res->_ingameTexts[kTextYaSeEgipcio]);
_state->setFlag(FLAG_ALFRED_SABE_EGIPCIO, true);
break;
case 24: // Encyclopedia
if (_state->getFlag(FLAG_RIDDLE_PRESENTED) == true) {
- _dialog->say(_res->_ingameTexts[CAPITULOPARADOJAS]);
+ _dialog->say(_res->_ingameTexts[kTextCapituloParadojas]);
_state->setCurrentRoot(25, 44, 0);
} else {
playAlfredSpecialAnim(0);
- _dialog->say(_res->_ingameTexts[COSASAPRENDIDO]);
+ _dialog->say(_res->_ingameTexts[kTextCosasAprendido]);
_state->setFlag(FLAG_ALFRED_INTELIGENTE, true);
_state->setCurrentRoot(14, 2, 0);
}
@@ -2081,15 +2081,15 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
playAlfredSpecialAnim(0);
loadExtraScreenAndPresent(5);
if (_state->getFlag(FLAG_ALFRED_SABE_EGIPCIO)) {
- _dialog->say(_res->_ingameTexts[FORMULAVIAJETIEMPO]);
+ _dialog->say(_res->_ingameTexts[kTextFormulaViajeAlTiempo]);
} else {
- _dialog->say(_res->_ingameTexts[QUELASTIMA_NOSEEGIPCIO]);
+ _dialog->say(_res->_ingameTexts[kTextQueLastimaNoSeeEgipcio]);
}
break;
case 88: { // spellbook
if (_room->_currentRoomNumber != 28 &&
(_room->_currentRoomNumber < 51 || _room->_currentRoomNumber > 54)) {
- _dialog->say(_res->_ingameTexts[AQUI_NO_NECESITO]);
+ _dialog->say(_res->_ingameTexts[kTextAquiNoNecesito]);
break;
}
SpellBook spellBook(_events, _res);
@@ -2100,7 +2100,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_alfredState.direction = ALFRED_LEFT;
switch (_room->_currentRoomNumber) {
case 28: {
- _dialog->say(_res->_ingameTexts[DIOSHALCON + spell->page], 1);
+ _dialog->say(_res->_ingameTexts[kTextDiosHalcon + spell->page], 1);
if (spell->page == 12) {
_graphics->clearScreen();
int waitFrames = 0;
@@ -2119,7 +2119,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_alfredState.x = 145;
_alfredState.y = 312;
setScreenAndPrepare(25, ALFRED_RIGHT);
- _dialog->say(_res->_ingameTexts[MENUDAAVENTURA]);
+ _dialog->say(_res->_ingameTexts[kTextMenudaAventura]);
}
break;
}
@@ -2128,7 +2128,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
case 53:
case 54: {
_sound->playSound(_room->_roomSfx[8], 0);
- _dialog->say(_res->_ingameTexts[DIOSHALCON + spell->page], 1);
+ _dialog->say(_res->_ingameTexts[kTextDiosHalcon + spell->page], 1);
int flightIndex = _room->_currentRoomNumber - 51;
if (_fightSorcererAppeared && !_fightInBlockingAnim && spell->page == kFightRooms[flightIndex].spellPage) {
_state->setFlag(FLAG_COMO_ESTAN_LOS_DIOSES, _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) | (1 << flightIndex));
@@ -2162,11 +2162,11 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
}
case 0: // yellow book
playAlfredSpecialAnim(0);
- _dialog->say(_res->_ingameTexts[CUENTOPARECIDO]);
+ _dialog->say(_res->_ingameTexts[kTextCuentoParecido]);
break;
case 101: // combination
playAlfredSpecialAnim(1);
- _dialog->say(_res->_ingameTexts[PARECE_COMBINACION_CAJAFUERTE]);
+ _dialog->say(_res->_ingameTexts[kTextPareceCombinacionCajaFuerte]);
_state->setFlag(FLAG_CLAVE_CAJA_FUERTE, true);
break;
case 108: // glue + patches
@@ -2178,13 +2178,13 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_state->removeInventoryItem(109);
_state->removeInventoryItem(108);
addInventoryItem(83);
- _dialog->say(_res->_ingameTexts[MUNECO_ARREGLADO]);
+ _dialog->say(_res->_ingameTexts[kTextMuecoArreglado]);
return;
} else if (_state->hasInventoryItem(109) == true) {
- _dialog->say(_res->_ingameTexts[NOTENGOPARCHES]);
+ _dialog->say(_res->_ingameTexts[kTextNoTengoParches]);
} else if (_state->hasInventoryItem(108) == true) {
- _dialog->say(_res->_ingameTexts[NOTENGOPEGAMENTO]);
+ _dialog->say(_res->_ingameTexts[kTextNoTengoPegamento]);
}
} else {
sayRandomIncorrectResponse();
@@ -2199,7 +2199,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
case 97: { // pyramid map
playAlfredSpecialAnim(1);
loadExtraScreenAndPresent(11);
- _dialog->say(_res->_ingameTexts[MEHANTOMADO_EL_PELO]);
+ _dialog->say(_res->_ingameTexts[kTextMeHanTomadoElPelo]);
_state->setCurrentRoot(43, 1, 0);
break;
}
@@ -2208,7 +2208,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
break;
}
case 87: {
- _dialog->say(_res->_ingameTexts[NECESITOGASOLINA]);
+ _dialog->say(_res->_ingameTexts[kTextNecesitaGasolina]);
break;
}
case 95: {
@@ -2225,7 +2225,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
// Original game incorrectly checked until object 47; Reading any book.
if (inventoryObject >= 11 && inventoryObject <= 58) {
playAlfredSpecialAnim(0);
- _dialog->say(_res->_ingameTexts[LIBRO_ABURRIDO]);
+ _dialog->say(_res->_ingameTexts[kTextLibroAburrido]);
return;
}
sayRandomIncorrectResponse();
@@ -2253,7 +2253,7 @@ void PelrockEngine::chooseCorrectDoor() {
} else if (puertaBuena == 2) {
doorText = _res->_derecha;
}
- Common::StringArray fullTextArray = _res->_ingameTexts[PUERTAAUTENTICA_IZQUIERDA];
+ Common::StringArray fullTextArray = _res->_ingameTexts[kTextPuertaAutenticaIzquierda];
fullTextArray[0] = fullTextArray[0].substr(0, 45);
fullTextArray[0].append(doorText);
_dialog->say(fullTextArray);
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index e03d6c60501..2e5a66f8a6e 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -23,423 +23,249 @@
#include "common/scummsys.h"
-namespace Pelrock {
-
-static const uint32 stickerOffsets[137] = {
- 0x000000, 0x00005B, 0x0000B6, 0x000298, 0x00047A, 0x0023C8, 0x004316, 0x004376,
- 0x005119, 0x005EBC, 0x0083ED, 0x008529, 0x0092C4, 0x00A3AA, 0x00B490, 0x00B6A6,
- 0x00C05A, 0x00CA0E, 0x00D3D0, 0x00D46E, 0x00F036, 0x00FB8F, 0x00FC55, 0x0119D7,
- 0x013759, 0x01391F, 0x014A9D, 0x015C1B, 0x017601, 0x018FE7, 0x019048, 0x0190A9,
- 0x01910A, 0x0197F4, 0x019EDE, 0x01A7EC, 0x01B0FA, 0x01B8C4, 0x01C644, 0x01D83A,
- 0x01E104, 0x01E8C6, 0x01F45D, 0x01FBBB, 0x02011D, 0x02052F, 0x020A95, 0x020E5B,
- 0x0210B3, 0x0216E6, 0x021D5E, 0x0233A3, 0x0249E8, 0x025777, 0x026506, 0x028E2B,
- 0x02B82F, 0x02C9D7, 0x02E4CA, 0x02FFBD, 0x03234A, 0x0346D7, 0x036A83, 0x038E2F,
- 0x03B18D, 0x03D4EB, 0x03DEC9, 0x03F813, 0x04115D, 0x045303, 0x0494A9, 0x04955F,
- 0x049615, 0x0496CB, 0x0499E1, 0x049EC7, 0x04A023, 0x04A447, 0x04BA6D, 0x04BFA1,
- 0x04CE33, 0x04CF09, 0x04DB3B, 0x052885, 0x0575CF, 0x05775B, 0x057D79, 0x058397,
- 0x058969, 0x058F50, 0x05A9DB, 0x05C561, 0x05C72E, 0x05C8FB, 0x05EAC1, 0x060C87,
- 0x060D19, 0x060E62, 0x061039, 0x0613C2, 0x061764, 0x061847, 0x062535, 0x062D4B,
- 0x064F11, 0x0670D7, 0x067381, 0x0675A9, 0x0677EF, 0x067A98, 0x067DDE, 0x068115,
- 0x0684E3, 0x068A76, 0x068F30, 0x0693C8, 0x0696AD, 0x06C2C9, 0x06C84D, 0x07095D,
- 0x071854, 0x07274B, 0x073642, 0x074539, 0x075454, 0x0791DA, 0x07CF60, 0x07E4AB,
- 0x07ECED, 0x07F52F, 0x07FD71, 0x080591, 0x080B24, 0x080B84, 0x080F39, 0x0812F5,
- 0x0816B1};
-
-enum TextIndices {
- ESTAN_CERRADOS,
- HOY_NO_DISPONIBLES,
- YA_ABIERTO_M,
- YA_CERRADO_M,
- YA_ABIERTA_F,
- YA_CERRADA_F,
- HELADERIA_CERRADA,
- POBRE_PERO_NO_HE_LLEGADO_A_ESO,
- QUEBUENA_ESTA,
- BOTONVERDEPARASACAR_BOTONVERDEPARACANCELAR,
- PRIMEROMETA_TARJETA,
- NOTENGOMASDINERO,
- MEHEVUELTOAPINCHAR,
- QUEHASIDOESO,
- QUIENANDAAHI,
- YOMEVOY,
- TIENDA_CERRADA,
- NOSE_ENTERARIA,
- PRIMERO_ABRIRLO,
- QUELOSCOJA_SUPADRE,
- PRETENDEUSTED_SOBORNARME,
- MUYBIEN_1,
- CUANDOMELOPIDA,
- DEACUERDO,
- NECESITODNI,
- QUE_RECIBO_ACAMBIO,
- ESPOCO,
- ALTO,
- NIPARAEMPEZAR,
- PARAQUE,
- DEPIEDRANO_DEHIELO,
- NO_EMPECEMOS,
- CUERPO_DANONE,
- CABEZA_HUECA,
- ESO_LO_SERAS_TU,
- DEMASIADO_NO_PUEDO_PENSAR,
- UN_POCO_RESPETO,
- NO_THEY_MAKEYOU_FAT,
- RELOJ_HA_CAMBIADO,
- CORRESPONDENCIA_AJENA,
- ANDA,
- TUCREES,
- NOESAMIAQUIENDEBES,
- AQUIENENTONCES,
- LIBROSSECRETOS,
- VENGA_ACA,
- TODOS,
- EL_LIBRO_NOESTA_AQUI,
- TENDRE_DEJAR_LIBRO,
- TRABAJARIA_MEJOR_SI_NO_ME_MOLESTARA,
- REGALO_LIBRO_RECETAS,
- YSI_METIRA_MAQUINA,
- QUITA_ESAS_MANOS,
- QUEASCO,
- QUESESTO_RECETA,
- YAESTA_ABIERTO,
- VAESTAR_POCOFUERTE,
- CUENTOPARECIDO,
- COSASAPRENDIDO,
- PERIODICOSENSACIONALISTA,
- HOJAENTREPAGINAS,
- NOENTIENDONADA,
- NOTENGODINERO,
- CUESTA1000,
- AQUITIENE,
- MUYBIEN,
- YASEEGIPCIO,
- QUELASTIMA_NOSEEGIPCIO,
- FORMULAVIAJETIEMPO,
- PARECECERRADO,
- NOVIO2METROS,
- GRANIDEA,
- SELORECOMIENDO,
- OIGAUSTED,
- ESAMI,
- VENGAAHORAMISMO,
- CUIDADOIMPRUDENTE,
- QUEOSCUROESTAESTO,
- MENUDAAVENTURA,
- NECESITOGASOLINA,
- YANOSEHACEONCOMOANTES,
- NADIELOHAVISTO,
- AYAYAY,
- OIGAUSTED2,
- LEESTOYVIGILANDO,
- OIGA,
- CAPITULOPARADOJAS,
- HAYQUECELEBRARLO,
- PESADEMASIADO,
- NINGUNATAMANHOAPROPIADO,
- PARAQUECOGERBARRO,
- BUENOCOGEREUNPOCO,
- ABSOLUTAMENTECERRADO,
- NOSETEOCURRAACERCARTE,
- PUERTAAUTENTICA_IZQUIERDA,
- OHMISALVADOR,
- VOYPORTI_PRINCESA,
- AMISBRAZOS,
- DIOSMIOQUEESESTO,
- QUEPASA,
- OLVIDECERRARTRAMPILLA,
- NOTEPREOCUPES_VOLVERE,
- ALACONUSTED,
- MEMEO,
- POR5MINUTOS,
- TALUEGOLUCAS,
- SISUPIERA_COMBINACION,
- PARECE_COMBINACION_CAJAFUERTE,
- GRANCANTIDAD_DINERO,
- TEAPETECE_BUENRATO,
- YLOSCONDONES,
- QUEASCO_CASIMEMEA,
- HECHOELPRIMO,
- MEHANTOMADO_EL_PELO,
- PESADO_UNRATO,
- TRAIDOR,
- TUTIA,
- LATUYA,
- GORDO,
- FIDEO,
- LIMPIACULO,
- CONTUTURBANTE,
- OSO,
- COMADREJA,
- CABEZON,
- TUABUELO,
- TUMUJER,
- PERDEDOR,
- SOYMEJORQUETU,
- TRAMPOSO,
- MALPERDEDOR,
- PARAUNAVEZ,
- MEJORMELARGO,
- NOTENGOPARCHES,
- NOTENGOPEGAMENTO,
- MUNECO_ARREGLADO,
- MAREDEDEU,
- PROBARLIBRO,
- PRACTICAR_MAS,
- AQUI_NO_NECESITO,
- DIOSHALCON,
- OHGRANOSIRIS,
- HEMEAQUI,
- OHSOBEK,
- OHTOTH,
- TODOSLASCOSAS,
- HELLEGADOPURO,
- DIOSDELATURBULENCIA,
- OHANUBIS,
- HEVENIDO,
- HELLEGADOATI,
- OHPTHA,
- LASPUERTASDELCIELO,
- VAYASUENHO,
- PARAQUE_2,
- YESO,
- UNPOCODESESPERADO,
- COMBINACIONESMEJORES,
- NOSEQUEPRETENDES_CONESO,
- COMO,
- MUCHOSENTIDO,
- PORPROBAR,
- NOLOENTIENDO,
- PARAESONOSIRVE,
- PRUEBAOTRACOSA,
- SIHOMBREQUEMAS,
- NOSEQUEPRETENDES,
- COSASRARAS,
- ARTE_O_LOCURA,
- UTILIDADES,
- TITULOJUEGO,
- MENSAJEOTRAEPOCA,
- NOERAAUTENTICO,
- PRIMERINGREDIENTE,
- DOSINGREDIENTES,
- TRESINGREDIENTES,
- CUATROINGREDIENTES,
- LIBRO_ABURRIDO,
- DEACUERDO_2,
- GAMBERROS,
- QUIENYO,
- PINTA_BUENAPERSONA,
- DEMO_FINAL,
- DIOSHALCON_2,
- GRANOSIRIS,
- HEMEAQUI_ISIS,
- OHSOBEK_2,
- OHTOTH_2,
- PROTEGEN_MI_CUERPO,
- HELLEGADO_PURO,
- DIOSDELATURBULENCIA_2,
- OHANUBIS_2,
- HEVENIDO_2,
- HELLEGADO_ATI,
- OHPTHA_2,
- LASPUERTAS_DELCIELO,
-};
-
-// Description offsets relative to base offset 0x4715D.
-// NOTE: unused dead code â kept for reference only.
-static const uint16 description_offsets[113] = {
- 0x0000, // Object 0: Historia de la Princesa Zenna y su amante insatisfecho
- 0x0058, // Object 1: Nombre: Alfred Pelrock
- 0x00C4, // Object 2: La tipica tarjeta por la que te sacan commisiones
- 0x010E, // Object 3: Una pequeña foto de Alfred
- 0x012C, // Object 4: Un ladrillo
- 0x013B, // Object 5: 1000 pesetas
- 0x014B, // Object 6: Una alargadera con un extremo suelto
- 0x0173, // Object 7: Un amuleto egipcio con forma de escarabajo alado
- 0x01A7, // Object 8: Dice: OM OM RASKAMAMOM
- 0x01C1, // Object 9: Es una carta de la Asociacion Ra-Amoniana
- 0x020A, // Object 10: Un carnet de biblioteca
- 0x0247, // Object 11: Titulo: Canticos espirituales en formato *.zip
- 0x02B3, // Object 12: Titulo: Pasion Flagrante
- 0x0327, // Object 13: Titulo: El Valenciano en los comienzos del siglo XXI
- 0x039E, // Object 14: Titulo: El sistema inmunologico de los cefalopodos (v.I)
- 0x0412, // Object 15: Titulo: Dos y dos son 5
- 0x0493, // Object 16: Titulo: La parte creativa
- 0x057B, // Object 17: Titulo: Aprenda egipcio en 10 dias
- 0x065C, // Object 18: Titulo: Gato por liebre
- 0x06D8, // Object 19: Titulo: Enrique de Ofterdingeng
+#include "pelrock/types.h"
- 0x0753, // Object 20: Titulo: Hiper-cocina para solteros
- 0x07CE, // Object 21: Titulo: El camaleon humano
- 0x084E, // Object 22: Titulo: Psiquiatria Avanzada (vol. 8)
- 0x08CA, // Object 23: Titulo: Sistemas de alcantarillado en el siglo XV
- 0x0949, // Object 24: Titulo: Cartas de amor de Pol Pot a su novia
- 0x09CC, // Object 25: Titulo: El gran libro de las preposiciones
- 0x0A50, // Object 26: Titulo: Corazon, vida y muerte de un tenista
- 0x0ACC, // Object 27: Titulo: Analisis de la vida de los funcionarios
- 0x0B4D, // Object 28: Titulo: Ensayos sobre la putrefaccion
- 0x0BC9, // Object 29: Titulo: Cocinar bien es imposible
- 0x0C49, // Object 30: Titulo: 1000 formas de hacer sonar un claxon
- 0x0CC8, // Object 31: Titulo: El arte de la peluqueria
- 0x0D3B, // Object 32: Titulo: Analisis de las tramas de las mejores telecomedias
- 0x0DC7, // Object 33: Titulo: Tratado de las empanadillas
- 0x0E40, // Object 34: Titulo: Misterios de los numeros
- 0x0EBA, // Object 35: Titulo: Como vender mas
- 0x0F31, // Object 36: Titulo: Todos podemos estar de moda
- 0x0FAD, // Object 37: Titulo: La economia capitalista (Tomo VI)
- 0x102E, // Object 38: Titulo: Aventuras con mis hemorrides
- 0x10AB, // Object 39: Titulo: Automate. Tomo IV: Suicidio
- 0x1128, // Object 40: Titulo: El cienpies azul
- 0x11A1, // Object 41: Titulo: Guia sexual de la mosca
- 0x121E, // Object 42: Titulo: La Oveja. El gran misterio
- 0x1297, // Object 43: Titulo: Mi libro de cocina
- 0x1309, // Object 44: Titulo: Ariel
- 0x1377, // Object 45: Titulo: Matar cucarachas con la mirada
- 0x13F4, // Object 46: Titulo: Telepatia: Caso practico
- 0x1476, // Object 47: Titulo: Vida y obra de Paquirrin
- 0x14F4, // Object 48: Titulo: Odas para aliviar el estrenimiento
- 0x1577, // Object 49: Titulo: Mi vida en el gran mercado
- 0x15F4, // Object 50: Titulo: Oda al tocino
- 0x1669, // Object 51: Titulo: Como escribir una novela
- 0x16E0, // Object 52: Titulo: Recogiendo oro en las cloacas
- 0x175B, // Object 53: Titulo: Como comer bien. Tomo XXI. Entrantes
- 0x17DD, // Object 54: Titulo: No tengo nada mejor que hacer
- 0x185D, // Object 55: Titulo: Los Heraldos Negros
- 0x18D1, // Object 56: Titulo: La Piedra Rosetta
- 0x194A, // Object 57: Titulo: Fabulas de Ciencia Ficcion
- 0x19C3, // Object 58: Titulo: La musica amansa a las fieras
+namespace Pelrock {
- 0x1A35, // Object 59: Un libro de recetas magicas
- 0x1A52, // Object 60: Un bote de tomate
- 0x1A70, // Object 61: Un bote de mostaza
- 0x1A8C, // Object 62: Salsa ultra-picante
- 0x1AA3, // Object 63: Receta de las hamburguesas de McDowells
- 0x1B2D, // Object 64: Un papiro con una inscripcion jeroglifica
- 0x1B53, // Object 65: Una guitarra española
- 0x1B8D, // Object 66: Un pez disecado
- 0x1BBE, // Object 67: Un osito de peluche
- 0x1C26, // Object 68: Unos discos antiguos
- 0x1C52, // Object 69: Un cerebro de mono
- 0x1C82, // Object 70: Novelas del salvaje oeste
- 0x1CB3, // Object 71: Una paleta
- 0x1CE1, // Object 72: Caramelos de todos los sabores
- 0x1CF9, // Object 73: Una caracola
- 0x1D24, // Object 74: Un sombrero
- 0x1D3F, // Object 75: 150000 pesetas
- 0x1D5C, // Object 76: Una calabaza para meter agua dentro
- 0x1D7A, // Object 77: Henna roja para el pelo
- 0x1DA3, // Object 78: Piramides de recuerdo
- 0x1DCC, // Object 79: Un chupa-chup de higo chumbo
- 0x1DE5, // Object 80: Un amuleto egipcio
- 0x1E00, // Object 81: El pelo de una princesa egipcia
- 0x1E49, // Object 82: Un mogollon de pasta
- 0x1E6B, // Object 83: Una replica de Elvis
- 0x1EA0, // Object 84: Aunque no sean piramides se puede decir que son monumentos
- 0x1EB9, // Object 85: Un girasol
- 0x1EE0, // Object 86: Una calabaza llena de agua
- 0x1F4F, // Object 87: Una motosierra
- 0x1FBE, // Object 88: Un libro de recetas magicas
- 0x1FD8, // Object 89: Una bota usada
- 0x1FFC, // Object 90: Una autentica piedra egipcia
- 0x2053, // Object 91: Una piedra egipcia
- 0x2071, // Object 92: Un poco de barro
- 0x2097, // Object 93: Licor de arena
- 0x20AE, // Object 94: Crema para el sol
- 0x20C6, // Object 95: Banda sonora de alfred pelrock
- 0x20E7, // Object 96: Un album de pantallas
- 0x2116, // Object 97: Plano de la piramide
- 0x2158, // Object 98: Plano detallado
- 0x2179, // Object 99: Es una peluca
- 0x218F, // Object 100: Una pequeña llave
- 0x21BE, // Object 101: Un trozo de papel con unos numeritos
- 0x21F1, // Object 102: Autenticas naranjas de Nules
- 0x220E, // Object 103: Un mogollon de naranjas de Nules
- 0x2236, // Object 104: No se haga el loco: Llameme !!!
- 0x2285, // Object 105: Folletos explicativos sobre el SIDA
- 0x22BE, // Object 106: Un pin que acredita mi sabiduria
- 0x22E2, // Object 107: Una bayeta para frotar lamparas magicas
- 0x2316, // Object 108: Parches ultra-fuertes
- 0x2337, // Object 109: Pegamento que te cagas
- 0x235A, // Object 110: Una replica de Alfred pinchada
- 0x2383, // Object 111: Una cinta del Rey Elvis
- 0x23A4, // Object 112: Una caja de condone
+// Indices to in game text responses in JUEGO.EXE
+enum TextStringId {
+ kTextEstanCerrados,
+ kTextHoyNoDisponibles,
+ kTextYaAbiertoM,
+ kTextYaCerradoM,
+ kTextYaAbiertaF,
+ kTextYaCerradaF,
+ kTextHeladeraCerrada,
+ kTextPobreNoHeLlegadoAEso,
+ kTextQueBuenaEsta,
+ kTextBotonVerdeParaSacarCancelar,
+ kTextPrimeroMetaTarjeta,
+ kTextNoTengoMasDinero,
+ kTextMeHeVueltoAPinchar,
+ kTextQueHaSidoEso,
+ kTextQuienAndaAhi,
+ kTextYoMeVoy,
+ kTextTiendaCerrada,
+ kTextNoseEnteraria,
+ kTextPrimeroAbrirlo,
+ kTextQueLosCojaSupadre,
+ kTextPretendeUstedSobornarme,
+ kTextMuyBien1,
+ kTextCuandoMeLoPida,
+ kTextDeAcuerdo,
+ kTextNecesitaDni,
+ kTextQueReciboACambio,
+ kTextEsPoco,
+ kTextAlto,
+ kTextNiParaEmpezar,
+ kTextParaQue,
+ kTextDePiedraNoDeHielo,
+ kTextNoEmpecemos,
+ kTextCuerpoDanone,
+ kTextCabezaHueca,
+ kTextEsoLoSerasTu,
+ kTextDemasiadoNoPuedoPensar,
+ kTextUnPocoRespeto,
+ kTextNoTheyMakeyouFat,
+ kTextRelojHaCambiado,
+ kTextCorrespondenciaAjena,
+ kTextAnda,
+ kTextTuCrees,
+ kTextNoEsAMiAQuienDebes,
+ kTextAQuienEntonces,
+ kTextLibrosSecretos,
+ kTextVengaAca,
+ kTextTodos,
+ kTextElLibroNoEstaAqui,
+ kTextTendreDejarLibro,
+ kTextTrabajariaMejorSiNoMeMolestara,
+ kTextRegaloLibroRecetas,
+ kTextYSiMeTiraMaquina,
+ kTextQuitaEsasManos,
+ kTextQueAsco,
+ kTextQuesEstoReceta,
+ kTextYaEstaAbierto,
+ kTextVaestarPocoFuerte,
+ kTextCuentoParecido,
+ kTextCosasAprendido,
+ kTextPeriodicoSensacionalista,
+ kTextHojaEntrePaginas,
+ kTextNoEntiendonada,
+ kTextNoTengoDinero,
+ kTextCuesta1000,
+ kTextAquiTiene,
+ kTextMuyBien,
+ kTextYaSeEgipcio,
+ kTextQueLastimaNoSeeEgipcio,
+ kTextFormulaViajeAlTiempo,
+ kTextPareceCerrado,
+ kTextNovio2Metros,
+ kTextGranIdea,
+ kTextSeLorecomiendo,
+ kTextOigaUsted,
+ kTextEsAMi,
+ kTextVengaAhoraMismo,
+ kTextCuidadoImprudente,
+ kTextQueOscuroEstaEsto,
+ kTextMenudaAventura,
+ kTextNecesitaGasolina,
+ kTextYaNoSeHaceOnComoAntes,
+ kTextNadieLaHaVisto,
+ kTextAyAyAy,
+ kTextOigaUsted2,
+ kTextLeEstoyVigilando,
+ kTextOiga,
+ kTextCapituloParadojas,
+ kTextHayQueCelebrarlo,
+ kTextPesaDemasiado,
+ kTextNingunaTamanhoApropiado,
+ kTextParaQueCogeBarro,
+ kTextBuenoCogereUnPoco,
+ kTextAbsolutamenteCerrado,
+ kTextNoSeTeCurraCercarte,
+ kTextPuertaAutenticaIzquierda,
+ kTextOhMiSalvador,
+ kTextVoyPoriPrincesa,
+ kTextAMisBrazos,
+ kTextDiosMioQueEsEsto,
+ kTextQuePasa,
+ kTextOlvideCerrarTrampilla,
+ kTextNotePreocupesVolvere,
+ kTextAlaConUsted,
+ kTextMeMeo,
+ kTextPor5Minutos,
+ kTextTaLuegoLucas,
+ kTextSiSupieraCombinacion,
+ kTextPareceCombinacionCajaFuerte,
+ kTextGranCantidadDinero,
+ kTextTeApeteceBuenRato,
+ kTextYLosCondones,
+ kTextQueAscoCasiMeMea,
+ kTextHechoElPrimo,
+ kTextMeHanTomadoElPelo,
+ kTextPesadoUnRato,
+ kTextTraidor,
+ kTextTuTia,
+ kTextLaTuya,
+ kTextGordo,
+ kTextFideo,
+ kTextLimpiaculos,
+ kTextConTuTurbante,
+ kTextOso,
+ kTextComadreja,
+ kTextCabezon,
+ kTextTuAbuelo,
+ kTextTuMujer,
+ kTextPerdedor,
+ kTextSoyMejorQueTu,
+ kTextTramposo,
+ kTextMalPerdedor,
+ kTextParaUnaVez,
+ kTextMejorMeLargo,
+ kTextNoTengoParches,
+ kTextNoTengoPegamento,
+ kTextMuecoArreglado,
+ kTextMareDeDou,
+ kTextProbarLibro,
+ kTextPracticarMas,
+ kTextAquiNoNecesito,
+ kTextDiosHalcon,
+ kTextOhGranOsiris,
+ kTextHemeAqui,
+ kTextOhSobek,
+ kTextOhToth,
+ kTextTodasLasCosas,
+ kTextHeLlegadoPuro,
+ kTextDiosDeLaTurbulencia,
+ kTextOhAnubis,
+ kTextHeVenido,
+ kTextHeLlegadoATi,
+ kTextOhPtha,
+ kTextLasPuertasDelCielo,
+ kTextVayaSuenho,
+ kTextParaQue2,
+ kTextYEso,
+ kTextUnPocoDeseperado,
+ kTextCombinacionesMejores,
+ kTextNoSeQuePretendeConEso,
+ kTextComo,
+ kTextMuchoSentido,
+ kTextPorProbar,
+ kTextNoLoEntiendo,
+ kTextParaEsoNoSirve,
+ kTextPruebaOtraCosa,
+ kTextSiHombrQueEmas,
+ kTextNoSeQuePretendes,
+ kTextCosasRaras,
+ kTextArteOLocura,
+ kTextUtilidades,
+ kTextTituloJuego,
+ kTextMensajeOtraEpoca,
+ kTextNoEraAutentico,
+ kTextPrimerIngrediente,
+ kTextDosIngredientes,
+ kTextTresIngredientes,
+ kTextCuatroIngredientes,
+ kTextLibroAburrido,
+ kTextDeAcuerdo2,
+ kTextGamberros,
+ kTextQuienYo,
+ kTextPintaBuenaPersona,
+ kTextDemoFinal,
+ kTextDiosHalcon2,
+ kTextGranOsiris,
+ kTextHemeAquiIsis,
+ kTextOhSobek2,
+ kTextOhToth2,
+ kTextProtigenMiCuerpo,
+ kTextHeLlegadoPuro2,
+ kTextDiosDeLaTurbulencia2,
+ kTextOhAnubis2,
+ kTextHeVenido2,
+ kTextHeLlegadoATi2,
+ kTextOhPtha2,
+ kTextLasPuertasDelCielo2,
};
-struct ExtraImages {
- uint32 offset;
- uint32 paletteOffset;
- byte numChunks;
+// ALFRED.7 extra screen data (file offsets given per entry in extraScreens[])
+static const ExtraScreen extraScreens[] = {
+ {0x00007984, 0x000305A2, 8}, // 0 - Portrait above bed
+ {0x001A9EE, 0x00305A2, 8}, // 1 - Computer screen
+ {0x00647C3, 0x007B6B1, 4}, // 2 - Alfred circle
+ {0x006FBCD, 0x007B6B1, 8}, // 3 - Recipe
+ {0x007BA11, 0x0088745, 8}, // 4 - Newspaper
+ {0x009237B, 0x00B0EE7, 8}, // 5 - Tablet
+ {0x00B11F1, 0x00DE011, 8}, // 6 - Map
+ {0x00FFC47, 0x01180C9, 8}, // 7 - Girl book
+ {0x118649, 0x135A13, 8}, // 8 - Unknown
+ {0x152A88, 0x15BFC8, 8}, // 9 - Portrait
+ {0x299E0C, 0x2B3C3C, 8}, // 10 - CD
+ {0x2B3F1C, 0x2D5B18, 8}, // 11 - Pyramid map
+ {0x232B1A, 0x237C28, 8}, // 12 - CENSORED
+ {0x226358, 0x236AA8, 8}, // 13 - Background book
+ {0x2EBD12, 0x309E40, 8} // 14 - Ending
};
-static const ExtraImages extraScreens[] = {
- {0x00, // 0 - Portrait above bed
- 0x7984,
- 8},
- {0x1A9EE, // 1 - Computer screen
- 0x305A2,
- 8},
- {0x647C3, // 2 - Alfred circle
- 0x7B6B1,
- 4},
- {0x6FBCD, // 3 - Recipe
- 0x7B6B1,
- 8},
- {0x7BA11, // 4 - Newspaper
- 0x88745,
- 8},
- {0x9237B, // 5 - tablet
- 0xB0EE7,
- 8},
- {0x000B11F1, // 6 - map
- 0xDE011,
- 8},
- {0xFFC47, // 7 - girl book
- 0x1180C9,
- 8},
- {1147849, // 8 - unknown
- 1267955,
- 8},
- {0x152A88, // 9 - portrait
- 0x15BFC8,
- 8},
- {2727564, // 10 - CD
- 2833276,
- 8},
- {
- 2834044, // 11 - pyramid map
- 2971800,
- 8},
- {
- 2306538, // 12 - CENSORED
- 2321064,
- 8
- },
- {
- 0x00226358, // 13 - Background book
- 0x00236AA8,
- 8
- },
- {
- 3058226, // 14 - Ending
- 3185280,
- 8
- }
-
-};
-// AlfredSpecialAnimOffset: POD struct (no constructors) to avoid global-constructor overhead.
-// Fields are ordered to match natural aggregate-initializer order.
-// size == 0 means "compute as numFrames * w * h" at load time.
-struct AlfredSpecialAnimOffset {
- int numFrames;
- int w;
- int h;
- int numBudas;
- int numAlfred;
- uint32 offset;
- int loops;
- int speed;
- uint32 size; // 0 = compute from numFrames * w * h
-};
+// Alfred.7 special animation data (file index given per entry in alfredSpecialAnims[])
+static const uint32 kAlfredAnimReadBookOffset = 559685; // 0 - READ BOOK
+static const uint32 kAlfredAnimReadRecipeOffset = 578943; // 1 - READ RECIPE
+static const uint32 kAlfredAnimElectricShock1Offset = 37000; // 2 - ELECTRIC SHOCK 1
+static const uint32 kAlfredAnimElectricShock3Offset = 53106; // 3 - ELECTRIC SHOCK 3
+static const uint32 kAlfredAnimThrowOffset = 20724; // 4 - Throw
+static const uint32 kAlfredAnimThrowSize = 62480; // 4 - Throw explicit size
+static const uint32 kAlfredAnimCrocodileOffset = 1556540; // 5 - Crocodile
+static const uint32 kAlfredAnimManholeOffset = 1583702; // 6 - Exit manhole
+static const uint32 kAlfredAnimClimbDownOffset = 1761234; // 7 - Climbs down
+static const uint32 kAlfredAnimClimbUpOffset = 1766378; // 8 - Climbs up
+static const uint32 kAlfredAnimExitTunnelOffset = 1770196; // 9 - Exits tunnel
+static const uint32 kAlfredAnimWorkersOffset = 1600956; // 10 - With workers
+static const uint32 kAlfredAnimMunheco1Offset = 2060916; // 11 - Doll 1
+static const uint32 kAlfredAnimMunheco2Offset = 2115632; // 12 - Doll 2
+static const uint32 kAlfredAnimMunheco3Offset = 1526432; // 13 - Doll 3
+static const uint32 kAlfredAnimDescamisaOffset = 2972568; // 14 - Descamisa
+static const uint32 kAlfredAnimSecretPassageOffset = 1749464; // 15 - Secret passage
+static const uint32 kAlfredAnimInBedOffset = 3038454; // 16 - Alfred in bed
} // End of namespace Pelrock
#endif
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 9cda936bb97..ee753999ca2 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -412,7 +412,7 @@ bool PelrockEngine::renderScene(int overlayMode) {
if (_state->getFlag(FLAG_PUTA_250_VECES) == true) {
_numPressedX++;
if (_numPressedX == 250) {
- _dialog->say(_res->_ingameTexts[YLOSCONDONES]);
+ _dialog->say(_res->_ingameTexts[kTextYLosCondones]);
}
}
}
@@ -458,7 +458,7 @@ void PelrockEngine::maybeHaveDogPee() {
dog->animData[0].nframes = 9;
dog->animData[0].curFrame = 0;
- _dialog->say(_res->_ingameTexts[QUEASCO_CASIMEMEA]);
+ _dialog->say(_res->_ingameTexts[kTextQueAscoCasiMeMea]);
_currentHotspot = nullptr; // Clear so arrival direction isn't overridden by dog hotspot
walkTo(152, _alfredState.y);
_isDogPeeing = false;
@@ -474,7 +474,7 @@ void PelrockEngine::maybePlayPostIntro() {
_res->loadAlfredSpecialAnim(16, false);
_alfredState.animState = ALFRED_SPECIAL_ANIM;
_dialog->_disableClickToAdvance = true;
- _dialog->say(_res->_ingameTexts[VAYASUENHO]);
+ _dialog->say(_res->_ingameTexts[kTextVayaSuenho]);
_dialog->_disableClickToAdvance = false;
waitForSpecialAnimation();
_graphics->fadeToBlack(20);
@@ -484,7 +484,7 @@ void PelrockEngine::maybePlayPostIntro() {
_alfredState.x = kAlfredInitialPosX;
_alfredState.y = kAlfredInitialPosY;
// setScreenAndPrepare(0, ALFRED_DOWN);
- _dialog->say(_res->_ingameTexts[MENSAJEOTRAEPOCA]);
+ _dialog->say(_res->_ingameTexts[kTextMensajeOtraEpoca]);
}
}
@@ -1856,9 +1856,9 @@ void PelrockEngine::doExtraActions(int roomNumber) {
case 15:
if (_state->getFlag(FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ)) {
_state->setFlag(FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ, false);
- _dialog->say(_res->_ingameTexts[GAMBERROS]);
- _dialog->say(_res->_ingameTexts[QUIENYO]);
- _dialog->say(_res->_ingameTexts[PINTA_BUENAPERSONA]);
+ _dialog->say(_res->_ingameTexts[kTextGamberros]);
+ _dialog->say(_res->_ingameTexts[kTextQuienYo]);
+ _dialog->say(_res->_ingameTexts[kTextPintaBuenaPersona]);
break;
}
case 19: {
@@ -1870,7 +1870,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_room->findSpriteByIndex(1)->numAnims = 1;
if(_state->hasInventoryItem(88) && _state->getFlag(FLAG_PIGEON_DEAD) == false) {
- _dialog->say(_res->_ingameTexts[PROBARLIBRO]);
+ _dialog->say(_res->_ingameTexts[kTextProbarLibro]);
playAlfredSpecialAnim(0);
Sprite *pigeons = _room->findSpriteByIndex(1);
pigeons->numAnims = 4;
@@ -1883,7 +1883,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_screen->update();
g_system->delayMillis(10);
}
- _dialog->say(_res->_ingameTexts[PRACTICAR_MAS]);
+ _dialog->say(_res->_ingameTexts[kTextPracticarMas]);
_state->setFlag(FLAG_PIGEON_DEAD, true);
}
break;
@@ -1944,9 +1944,9 @@ void PelrockEngine::doExtraActions(int roomNumber) {
if (_state->getFlag(FLAG_SE_HA_PUESTO_EL_MUNECO) == true) {
_state->setCurrentRoot(26, 2, 1);
} else {
- _dialog->say(_res->_ingameTexts[OIGAUSTED], 1);
- _dialog->say(_res->_ingameTexts[ESAMI]);
- _dialog->say(_res->_ingameTexts[VENGAAHORAMISMO], 1);
+ _dialog->say(_res->_ingameTexts[kTextOigaUsted], 1);
+ _dialog->say(_res->_ingameTexts[kTextEsAMi]);
+ _dialog->say(_res->_ingameTexts[kTextVengaAhoraMismo], 1);
_state->setCurrentRoot(26, 1, 1);
walkAndAction(_room->findHotspotByExtra(421), TALK);
}
@@ -1958,7 +1958,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_dialog->_goodbyeDisabled = true;
_state->setFlag(FLAG_ROBA_PELO_PRINCESA, false);
_room->enableSprite(0, 200, PERSIST_TEMP);
- _dialog->say(_res->_ingameTexts[OIGAUSTED]);
+ _dialog->say(_res->_ingameTexts[kTextOigaUsted]);
walkAndAction(_room->findHotspotByExtra(0), TALK);
}
break;
@@ -1998,16 +1998,16 @@ void PelrockEngine::doExtraActions(int roomNumber) {
if (_state->getFlag(FLAG_END_OF_GAME) == true) {
- _dialog->say(_res->_ingameTexts[OHMISALVADOR]);
- _dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
+ _dialog->say(_res->_ingameTexts[kTextOhMiSalvador]);
+ _dialog->say(_res->_ingameTexts[kTextVoyPoriPrincesa]);
_state->setCurrentRoot(48, 1, 0);
walkAndAction(_room->findHotspotByExtra(634), TALK);
endingScene();
} else if (_state->getFlag(FLAG_CORRECT_DOOR_CHOSEN) == true) {
- _dialog->say(_res->_ingameTexts[OHMISALVADOR]);
- _dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
+ _dialog->say(_res->_ingameTexts[kTextOhMiSalvador]);
+ _dialog->say(_res->_ingameTexts[kTextVoyPoriPrincesa]);
_state->setFlag(FLAG_TRAMPILLA_ABIERTA, true);
walkAndAction(_room->findHotspotByExtra(634), TALK);
_room->addSticker(134);
@@ -2028,8 +2028,8 @@ void PelrockEngine::doExtraActions(int roomNumber) {
setScreenAndPrepare(49, ALFRED_UP);
} else {
- _dialog->say(_res->_ingameTexts[OHMISALVADOR]);
- _dialog->say(_res->_ingameTexts[VOYPORTI_PRINCESA]);
+ _dialog->say(_res->_ingameTexts[kTextOhMiSalvador]);
+ _dialog->say(_res->_ingameTexts[kTextVoyPoriPrincesa]);
// _state->setCurrentRoot(48, 0, 1);
HotSpot *fatMummy = nullptr;
for (uint i = 0; i < _room->_currentRoomHotspots.size(); i++) {
@@ -2110,7 +2110,7 @@ void PelrockEngine::pyramidCollapse() {
}
_room->findSpriteByIndex(2)->zOrder = 255;
- _dialog->say(_res->_ingameTexts[YANOSEHACEONCOMOANTES]);
+ _dialog->say(_res->_ingameTexts[kTextYaNoSeHaceOnComoAntes]);
npc = _room->findSpriteByIndex(0);
if (npc)
npc->zOrder = 254;
@@ -2163,7 +2163,7 @@ void PelrockEngine::pyramidCollapse() {
if (npc)
npc->animData[npc->curAnimIndex].movementFlags = 0;
- _dialog->say(_res->_ingameTexts[POR5MINUTOS], 0);
+ _dialog->say(_res->_ingameTexts[kTextPor5Minutos], 0);
_room->disableExit(36, 0);
@@ -2180,7 +2180,7 @@ void PelrockEngine::pyramidCollapse() {
pyramidHotspot->index = 7;
_room->disableHotspot(21, pyramidHotspot, PERSIST_BOTH);
- _dialog->say(_res->_ingameTexts[TALUEGOLUCAS]);
+ _dialog->say(_res->_ingameTexts[kTextTaLuegoLucas]);
// Walk Alfred to right edge exit -> room 21
walkLoop(603, 212, ALFRED_RIGHT);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 825a63a6318..b9b88543c0b 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -56,25 +56,6 @@ static const uint32 kCreditsSize = 2540;
static const uint32 kComputerTextOffset = 0x0004901A;
static const uint32 kComputerTextSize = 490;
-// Alfred special animation data (file index given per entry in alfredSpecialAnims[])
-static const uint32 kAlfredAnimReadBookOffset = 559685; // 0 - READ BOOK
-static const uint32 kAlfredAnimReadRecipeOffset = 578943; // 1 - READ RECIPE
-static const uint32 kAlfredAnimElectricShock1Offset = 37000; // 2 - ELECTRIC SHOCK 1
-static const uint32 kAlfredAnimElectricShock3Offset = 53106; // 3 - ELECTRIC SHOCK 3
-static const uint32 kAlfredAnimThrowOffset = 20724; // 4 - Throw
-static const uint32 kAlfredAnimThrowSize = 62480; // 4 - Throw explicit size
-static const uint32 kAlfredAnimCrocodileOffset = 1556540; // 5 - Crocodile
-static const uint32 kAlfredAnimManholeOffset = 1583702; // 6 - Exit manhole
-static const uint32 kAlfredAnimClimbDownOffset = 1761234; // 7 - Climbs down
-static const uint32 kAlfredAnimClimbUpOffset = 1766378; // 8 - Climbs up
-static const uint32 kAlfredAnimExitTunnelOffset = 1770196; // 9 - Exits tunnel
-static const uint32 kAlfredAnimWorkersOffset = 1600956; // 10 - With workers
-static const uint32 kAlfredAnimMunheco1Offset = 2060916; // 11 - Doll 1
-static const uint32 kAlfredAnimMunheco2Offset = 2115632; // 12 - Doll 2
-static const uint32 kAlfredAnimMunheco3Offset = 1526432; // 13 - Doll 3
-static const uint32 kAlfredAnimDescamisaOffset = 2972568; // 14 - Descamisa
-static const uint32 kAlfredAnimSecretPassageOffset = 1749464; // 15 - Secret passage
-static const uint32 kAlfredAnimInBedOffset = 3038454; // 16 - Alfred in bed
ResourceManager::ResourceManager(/* args */) {
_inventoryIcons = new InventoryObject[69];
@@ -472,7 +453,7 @@ void ResourceManager::getExtraScreen(int screenIndex, byte *screenBuf, byte *pal
if (!alfred7.open("ALFRED.7")) {
error("Couldnt find file ALFRED.7");
}
- ExtraImages screen = extraScreens[screenIndex];
+ ExtraScreen screen = extraScreens[screenIndex];
mergeRleBlocks(&alfred7, screen.offset, 8, screenBuf);
alfred7.seek(screen.paletteOffset, SEEK_SET);
alfred7.read(palette, 768);
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 5c9efd3abf9..9ff5afc04ad 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -49,6 +49,27 @@ static const int unpickableHotspotExtras[] = {
91, // mud and stone should only be picked under certain conditions!
92};
+static const uint32 stickerOffsets[137] = {
+ 0x000000, 0x00005B, 0x0000B6, 0x000298, 0x00047A, 0x0023C8, 0x004316, 0x004376,
+ 0x005119, 0x005EBC, 0x0083ED, 0x008529, 0x0092C4, 0x00A3AA, 0x00B490, 0x00B6A6,
+ 0x00C05A, 0x00CA0E, 0x00D3D0, 0x00D46E, 0x00F036, 0x00FB8F, 0x00FC55, 0x0119D7,
+ 0x013759, 0x01391F, 0x014A9D, 0x015C1B, 0x017601, 0x018FE7, 0x019048, 0x0190A9,
+ 0x01910A, 0x0197F4, 0x019EDE, 0x01A7EC, 0x01B0FA, 0x01B8C4, 0x01C644, 0x01D83A,
+ 0x01E104, 0x01E8C6, 0x01F45D, 0x01FBBB, 0x02011D, 0x02052F, 0x020A95, 0x020E5B,
+ 0x0210B3, 0x0216E6, 0x021D5E, 0x0233A3, 0x0249E8, 0x025777, 0x026506, 0x028E2B,
+ 0x02B82F, 0x02C9D7, 0x02E4CA, 0x02FFBD, 0x03234A, 0x0346D7, 0x036A83, 0x038E2F,
+ 0x03B18D, 0x03D4EB, 0x03DEC9, 0x03F813, 0x04115D, 0x045303, 0x0494A9, 0x04955F,
+ 0x049615, 0x0496CB, 0x0499E1, 0x049EC7, 0x04A023, 0x04A447, 0x04BA6D, 0x04BFA1,
+ 0x04CE33, 0x04CF09, 0x04DB3B, 0x052885, 0x0575CF, 0x05775B, 0x057D79, 0x058397,
+ 0x058969, 0x058F50, 0x05A9DB, 0x05C561, 0x05C72E, 0x05C8FB, 0x05EAC1, 0x060C87,
+ 0x060D19, 0x060E62, 0x061039, 0x0613C2, 0x061764, 0x061847, 0x062535, 0x062D4B,
+ 0x064F11, 0x0670D7, 0x067381, 0x0675A9, 0x0677EF, 0x067A98, 0x067DDE, 0x068115,
+ 0x0684E3, 0x068A76, 0x068F30, 0x0693C8, 0x0696AD, 0x06C2C9, 0x06C84D, 0x07095D,
+ 0x071854, 0x07274B, 0x073642, 0x074539, 0x075454, 0x0791DA, 0x07CF60, 0x07E4AB,
+ 0x07ECED, 0x07F52F, 0x07FD71, 0x080591, 0x080B24, 0x080B84, 0x080F39, 0x0812F5,
+ 0x0816B1
+};
+
#define PERSIST_TEMP 1
#define PERSIST_PERM 2
#define PERSIST_BOTH 3
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 1780ec71d2f..966f07647c3 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -234,6 +234,27 @@ struct PathContext {
uint16 compressed_length;
};
+struct ExtraScreen {
+ uint32 offset;
+ uint32 paletteOffset;
+ byte numChunks;
+};
+
+/**
+ * Struct for special or one-off animations that replace Alfred's regular animations.
+ */
+struct AlfredSpecialAnimOffset {
+ int numFrames;
+ int w;
+ int h;
+ int numBudas;
+ int numAlfred;
+ uint32 offset;
+ int loops;
+ int speed;
+ uint32 size; // 0 = compute from numFrames * w * h
+};
+
/**
* Each Anim has its own speed, loopCount and movement!
*/
Commit: cb817060195a44e3e7baabdbaff1b95fd439fb21
https://github.com/scummvm/scummvm/commit/cb817060195a44e3e7baabdbaff1b95fd439fb21
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:42+02:00
Commit Message:
PELROCK: Fix warnings
Changed paths:
engines/pelrock/computer.cpp
engines/pelrock/computer.h
engines/pelrock/console.cpp
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index 95a7bb81404..1b97e0eb3a1 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -163,7 +163,7 @@ void Computer::drawScreen() {
case STATE_MAIN_MENU: {
int textY = 97;
int textX = 225;
- for (int i = 0; _computerText[0].size() > i; i++) {
+ for (uint i = 0; _computerText[0].size() > i; i++) {
Common::String line = _computerText[0][i];
g_engine->_graphics->drawColoredText(g_engine->_screen, line, textX, textY + i * _lineHeight, 200, defaultColor, g_engine->_smallFont);
}
@@ -172,7 +172,7 @@ void Computer::drawScreen() {
case STATE_SEARCH_BY_TITLE:
case STATE_SEARCH_BY_AUTHOR:
- for (int i = 0; _computerText[1].size() > i; i++) {
+ for (uint i = 0; _computerText[1].size() > i; i++) {
Common::String line = _computerText[1][i];
g_engine->_graphics->drawColoredText(g_engine->_screen, line, 172, 258 + i * _lineHeight, 200, defaultColor, g_engine->_smallFont);
}
@@ -201,7 +201,7 @@ void Computer::drawScreen() {
Common::String titleLine = _computerText[3][0];
int titlePlaceholderIndex = titleLine.findFirstOf("XXXX");
- int titleIndex = 0;
+ uint titleIndex = 0;
while (titleIndex < book.title.size()) {
Common::String thisLine;
if (titleIndex == 0) {
@@ -217,7 +217,7 @@ void Computer::drawScreen() {
// Author
Common::String authorLine = _computerText[4][0];
int authorPlaceholderIndex = authorLine.findFirstOf("XXXX");
- int authorIndex = 0;
+ uint authorIndex = 0;
while (authorIndex < book.author.size()) {
Common::String thisLine;
@@ -338,7 +338,7 @@ void Computer::memorizeBook(int bookIndex) {
void Computer::performSearch() {
_searchResults.clear();
- for (int i = 0; i < _libraryBooks.size(); i++) {
+ for (uint i = 0; i < _libraryBooks.size(); i++) {
Common::String searchField = _searchType == 0 ? _libraryBooks[i].title[0] : _libraryBooks[i].author[0];
// Check if first letter matches (case-insensitive)
diff --git a/engines/pelrock/computer.h b/engines/pelrock/computer.h
index 403a620717d..f2905a1426f 100644
--- a/engines/pelrock/computer.h
+++ b/engines/pelrock/computer.h
@@ -78,7 +78,7 @@ private:
int _searchType = 0; // 0 = title, 1 = author
Common::Array<int> _searchResults;
Common::Array<LibraryBook> _libraryBooks;
- int _currentResult;
+ uint _currentResult;
int _memorizedBookIndex; // Index of book that was memorized (-1 if none)
int _lineHeight;
Common::String _titleMsg;
diff --git a/engines/pelrock/console.cpp b/engines/pelrock/console.cpp
index 0a5f6f25f3e..b8240c13e6c 100644
--- a/engines/pelrock/console.cpp
+++ b/engines/pelrock/console.cpp
@@ -45,7 +45,7 @@ bool PelrockConsole::cmdRemoveSticker(int argc, const char **argv) {
return true;
}
int stickerId = atoi(argv[1]);
- for(int i = 0; i < g_engine->_state->stickersPerRoom[g_engine->_room->_currentRoomNumber].size(); i++) {
+ for(uint i = 0; i < g_engine->_state->stickersPerRoom[g_engine->_room->_currentRoomNumber].size(); i++) {
if (g_engine->_state->stickersPerRoom[g_engine->_room->_currentRoomNumber][i].stickerIndex == stickerId) {
g_engine->_state->stickersPerRoom[g_engine->_room->_currentRoomNumber].remove_at(i);
debugPrintf("Removed sticker %d from room %d\n", stickerId, g_engine->_room->_currentRoomNumber);
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index dd810023823..9a54e15acf3 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -1130,9 +1130,9 @@ bool isEndMarker(byte char_byte) {
return char_byte == kCtrlEndText || char_byte == kCtrlEndConversation || char_byte == kCtrlActionAndEnd || char_byte == kCtrlGoBack;
}
-int calculateWordLength(Common::String text, int startPos, bool &isEnd) {
+int calculateWordLength(Common::String text, uint startPos, bool &isEnd) {
int wordLength = 0;
- int pos = startPos;
+ uint pos = startPos;
while (pos < text.size()) {
char char_byte = text[pos];
if (char_byte == kCtrlSpace || isEndMarker(char_byte)) {
@@ -1169,7 +1169,7 @@ Common::Array<Common::Array<Common::String>> DialogManager::wordWrap(Common::Str
Common::Array<Common::String> currentPage;
Common::Array<Common::String> currentLine;
int charsRemaining = kMaxCharsPerLine;
- int position = 0;
+ uint position = 0;
int currentLineNum = 0;
while (position < text.size()) {
bool isEnd = false;
@@ -1251,7 +1251,7 @@ Common::Array<Common::StringArray> DialogManager::wordWrap(Common::StringArray t
Common::String thisLine = texts[i];
Common::Array<Common::Array<Common::String>> wrapped = wordWrap(thisLine);
for (uint j = 0; j < wrapped.size(); j++) {
- for (int k = 0; k < wrapped[j].size(); k++) {
+ for (uint k = 0; k < wrapped[j].size(); k++) {
if (currentLineNum < kMaxLines) {
currentPage.push_back(wrapped[j][k]);
currentLineNum++;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index ee753999ca2..1bfbdf9bc7b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -271,7 +271,7 @@ void PelrockEngine::playSoundIfNeeded() {
int ambientSlotOffset = _sound->tickAmbientSound(_chrono->getFrameCount());
if (ambientSlotOffset >= 0) {
// Convert to room sound index: slots 12-15 = room indices 4-7
- int roomSoundIndex = kAmbientSoundSlotBase + ambientSlotOffset;
+ byte roomSoundIndex = kAmbientSoundSlotBase + ambientSlotOffset;
if (roomSoundIndex < _room->_roomSfx.size()) {
byte soundFileIndex = _room->_roomSfx[roomSoundIndex];
if (soundFileIndex != 0) { // 0 = NO_SOUND.SMP (disabled)
@@ -1660,7 +1660,7 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
}*/
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
int loopEnd = _state->selectedInventoryItem != -1 ? actions.size() + 1 : actions.size();
- for (int i = 0; i < loopEnd; i++) {
+ for (uint i = 0; i < loopEnd; i++) {
Common::Point p = getPositionInBalloonForIndex(i, _actionPopupState.x, _actionPopupState.y);
Common::Rect actionRect = Common::Rect(p.x, p.y, p.x + kVerbIconWidth, p.y + kVerbIconHeight);
if (i == actions.size()) {
@@ -1727,7 +1727,7 @@ void PelrockEngine::checkMouseHover() {
if (hotspotIndex != -1) {
hotspotDetected = true;
- if (hotspotIndex < _room->_currentRoomDescriptions.size())
+ if (hotspotIndex < (int)_room->_currentRoomDescriptions.size())
_hoveredMapLocation = _room->_currentRoomDescriptions[hotspotIndex].text;
} else if (!alfredDetected) {
_hoveredMapLocation = "";
@@ -1859,8 +1859,8 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_dialog->say(_res->_ingameTexts[kTextGamberros]);
_dialog->say(_res->_ingameTexts[kTextQuienYo]);
_dialog->say(_res->_ingameTexts[kTextPintaBuenaPersona]);
- break;
}
+ break;
case 19: {
Sprite *dog = _room->findSpriteByIndex(2);
dog->animData[0].nframes = 9;
@@ -1901,8 +1901,8 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_room->addStickerToRoom(38, 123, PERSIST_TEMP);
_alfredState.x = x;
_alfredState.y = y;
- break;
}
+ break;
}
case 32: {
if (_room->_prevRoomNumber == 31) {
@@ -1914,6 +1914,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_alfredState.x = x;
_alfredState.y = y;
}
+ break;
}
case 27: {
if (_room->_prevRoomNumber == 33) {
@@ -1935,8 +1936,8 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_res->getPaletteForRoom28(palette);
g_system->getPaletteManager()->setPalette(palette, 0, 256);
Common::copy(palette, palette + 768, _room->_roomPalette);
- break;
}
+ break;
}
case 26: {
if (_state->getFlag(FLAG_A_LA_CARCEL) == true) {
@@ -2325,7 +2326,7 @@ void PelrockEngine::credits() {
Common::Array<Common::StringArray> creditTexts = _res->getCredits();
Common::Array<int> creditsSpeakerId;
// Preprocess credit texts: extract speaker IDs and apply word wrapping
- for(int i = 0; i < creditTexts.size(); i++) {
+ for(uint i = 0; i < creditTexts.size(); i++) {
byte speakerId;
_dialog->processColorAndTrim(creditTexts[i], speakerId);
creditsSpeakerId.push_back(speakerId);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index b9b88543c0b..55b06c3c7a4 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -436,13 +436,6 @@ Common::Array<Common::StringArray> ResourceManager::loadComputerText() {
exe.read(computerTextBuf, bufSize);
Common::Array<Common::StringArray> computerTexts = processTextData(computerTextBuf, bufSize);
- for (int i = 0; i < computerTexts.size(); i++) {
- debug("Computer text %d:", i);
- Common::StringArray &lines = computerTexts[i];
- for (int j = 0; j < lines.size(); j++) {
- debug(" Line %d: '%s'", j, lines[j].c_str());
- }
- }
delete[] computerTextBuf;
exe.close();
@@ -480,7 +473,7 @@ Common::Array<Common::StringArray> ResourceManager::getCredits() {
}
Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data, size_t size, bool decode) {
- int pos = 0;
+ uint pos = 0;
Common::String desc = "";
Common::StringArray lines;
Common::Array<Common::StringArray> texts;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 966f07647c3..913b747b970 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -146,8 +146,8 @@ struct AlfredSpecialAnim {
int curLoop = 0;
uint32 size = 0;
int speed = 2;
- AlfredSpecialAnim(int nF, int width, int height, int nBudas, uint32 off, int loopCount, uint32 sz, int spd = 2)
- : numFrames(nF), w(width), h(height), loopCount(loopCount), size(sz), speed(spd) {
+ AlfredSpecialAnim(int nF, int width, int height, int nBudas, uint32 off, int lCount, uint32 sz, int spd = 2)
+ : numFrames(nF), w(width), h(height), loopCount(lCount), size(sz), speed(spd) {
stride = w * h;
}
@@ -485,7 +485,7 @@ struct RoomPasserBys {
byte currentAnimIndex = 0;
byte numAnims = 0;
bool latch = false;
- RoomPasserBys(byte roomNum, byte numAnims) : roomNumber(roomNum), numAnims(numAnims) {}
+ RoomPasserBys(byte roomNum, byte nAnims) : roomNumber(roomNum), numAnims(nAnims) {}
};
/**
@@ -500,7 +500,7 @@ struct ChoiceOption {
bool shouldDisableOnSelect = false;
bool hasConversationEndMarker = false;
bool isTerminator = false;
- int charOffset = 0;
+ uint charOffset = 0;
ChoiceOption() : choiceIndex(-1), dataOffset(0) {}
};
Commit: 13330521f9d238f322a8539e06983c9afb3a5b79
https://github.com/scummvm/scummvm/commit/13330521f9d238f322a8539e06983c9afb3a5b79
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:42+02:00
Commit Message:
PELROCK: Move inventory item sounds lookup table into implementation
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/menu.h
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index c1c962c3cc7..5603fb84161 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -34,6 +34,123 @@
namespace Pelrock {
+static const char *inventorySounds[113] = {
+
+ "HOJASZZZ.SMP", // 0
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "GLASS1ZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "ELEC3ZZZ.SMP",
+ "REMATERL.SMP",
+ "81ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "SSSHTZZZ.SMP", // 10
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP", // 20
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP", // 30
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP", // 40
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP", // 50
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "BOTEZZZZ.SMP", // 60
+ "BOTEZZZZ.SMP",
+ "BOTEZZZZ.SMP",
+ "BELCHZZZ.SMP",
+ "BEAMZZZZ.SMP",
+ "ELVIS1ZZ.SMP",
+ "CAT_1ZZZ.SMP",
+ "BOOOOOIZ.SMP",
+ "DISCOSZZ.SMP",
+ "MONORLZZ.SMP",
+ "11ZZZZZZ.SMP", // 70
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "CARACOLA.SMP",
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "WATER_2Z.SMP",
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "EEEEKZZZ.SMP",
+ "REMATERL.SMP", // 80 - Rematerialize
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "ELVIS1ZZ.SMP",
+ "RIMSHOTZ.SMP",
+ "11ZZZZZZ.SMP",
+ "WATER_2Z.SMP",
+ "MOTOSZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "TWANGZZZ.SMP",
+ "11ZZZZZZ.SMP", // 90
+ "QUAKE2ZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "SORBOZZZ.SMP",
+ "BOTEZZZZ.SMP",
+ "ELVIS1ZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "LLAVESZZ.SMP", // 100
+ "HOJASZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "EVLLAUGH.SMP",
+ "11ZZZZZZ.SMP",
+ "BURROLZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "TWANGZZZ.SMP",
+ "11ZZZZZZ.SMP",
+ "TWANGZZZ.SMP", // 110
+ "ELVIS1ZZ.SMP",
+ "SEX3ZZZZ.SMP"
+};
+
// ALFRED.7 â alternate settings palette
static const uint32 kSettingsPaletteOffset = 0x2884C2;
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index a694caf5712..bd30ef1b79d 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -91,123 +91,6 @@ static const int kCreditsOrder[34] = {
17 // DDM
};
-static const char *inventorySounds[113] = {
-
- "HOJASZZZ.SMP", // 0
- "11ZZZZZZ.SMP",
- "11ZZZZZZ.SMP",
- "11ZZZZZZ.SMP",
- "GLASS1ZZ.SMP",
- "11ZZZZZZ.SMP",
- "ELEC3ZZZ.SMP",
- "REMATERL.SMP",
- "81ZZZZZZ.SMP",
- "11ZZZZZZ.SMP",
- "SSSHTZZZ.SMP", // 10
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP", // 20
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP", // 30
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP", // 40
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP", // 50
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "BOTEZZZZ.SMP", // 60
- "BOTEZZZZ.SMP",
- "BOTEZZZZ.SMP",
- "BELCHZZZ.SMP",
- "BEAMZZZZ.SMP",
- "ELVIS1ZZ.SMP",
- "CAT_1ZZZ.SMP",
- "BOOOOOIZ.SMP",
- "DISCOSZZ.SMP",
- "MONORLZZ.SMP",
- "11ZZZZZZ.SMP", // 70
- "11ZZZZZZ.SMP",
- "11ZZZZZZ.SMP",
- "CARACOLA.SMP",
- "11ZZZZZZ.SMP",
- "11ZZZZZZ.SMP",
- "WATER_2Z.SMP",
- "11ZZZZZZ.SMP",
- "11ZZZZZZ.SMP",
- "EEEEKZZZ.SMP",
- "REMATERL.SMP", // 80 - Rematerialize
- "11ZZZZZZ.SMP",
- "11ZZZZZZ.SMP",
- "ELVIS1ZZ.SMP",
- "RIMSHOTZ.SMP",
- "11ZZZZZZ.SMP",
- "WATER_2Z.SMP",
- "MOTOSZZZ.SMP",
- "HOJASZZZ.SMP",
- "TWANGZZZ.SMP",
- "11ZZZZZZ.SMP", // 90
- "QUAKE2ZZ.SMP",
- "11ZZZZZZ.SMP",
- "SORBOZZZ.SMP",
- "BOTEZZZZ.SMP",
- "ELVIS1ZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "HOJASZZZ.SMP",
- "11ZZZZZZ.SMP",
- "LLAVESZZ.SMP", // 100
- "HOJASZZZ.SMP",
- "11ZZZZZZ.SMP",
- "11ZZZZZZ.SMP",
- "EVLLAUGH.SMP",
- "11ZZZZZZ.SMP",
- "BURROLZZ.SMP",
- "11ZZZZZZ.SMP",
- "TWANGZZZ.SMP",
- "11ZZZZZZ.SMP",
- "TWANGZZZ.SMP", // 110
- "ELVIS1ZZ.SMP",
- "SEX3ZZZZ.SMP"
-};
-
class MenuManager {
enum MenuState {
Commit: 97c26c5ec3a1a724ebcf8b1a91fadd07653af7ab
https://github.com/scummvm/scummvm/commit/97c26c5ec3a1a724ebcf8b1a91fadd07653af7ab
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:43+02:00
Commit Message:
PELROCK: Rename size constants for custom fonts
Changed paths:
engines/pelrock/fonts/large_font.cpp
engines/pelrock/fonts/large_font.h
engines/pelrock/fonts/small_font.cpp
engines/pelrock/fonts/small_font.h
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index 98048e39d80..5b534af3d27 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -111,7 +111,7 @@ bool LargeFont::load(const Common::String &filename) {
}
int LargeFont::getCharWidth(uint32 chr) const {
- return CHAR_WIDTH + 1;
+ return LARGE_FONT_CHAR_WIDTH + 1;
}
void LargeFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
diff --git a/engines/pelrock/fonts/large_font.h b/engines/pelrock/fonts/large_font.h
index bd87b9012d2..2da5c24e5da 100644
--- a/engines/pelrock/fonts/large_font.h
+++ b/engines/pelrock/fonts/large_font.h
@@ -36,12 +36,12 @@ public:
// Required Font interface methods
int getFontHeight() const override { return CHAR_HEIGHT; }
- int getMaxCharWidth() const override { return CHAR_WIDTH; }
+ int getMaxCharWidth() const override { return LARGE_FONT_CHAR_WIDTH; }
int getCharWidth(uint32 chr) const override;
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
private:
- static const int CHAR_WIDTH = 12;
+ static const int LARGE_FONT_CHAR_WIDTH = 12;
static const int CHAR_HEIGHT = 24;
byte *_fontData;
};
diff --git a/engines/pelrock/fonts/small_font.cpp b/engines/pelrock/fonts/small_font.cpp
index b439b5db2f9..d1de37d9a5c 100644
--- a/engines/pelrock/fonts/small_font.cpp
+++ b/engines/pelrock/fonts/small_font.cpp
@@ -49,7 +49,7 @@ bool SmallFont::load(const Common::String &filename) {
}
int SmallFont::getCharWidth(uint32 chr) const {
- return CHAR_WIDTH;
+ return SMALL_FONT_CHAR_WIDTH;
}
void SmallFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
diff --git a/engines/pelrock/fonts/small_font.h b/engines/pelrock/fonts/small_font.h
index 3bde2c152b0..f64e3fa4a19 100644
--- a/engines/pelrock/fonts/small_font.h
+++ b/engines/pelrock/fonts/small_font.h
@@ -38,8 +38,8 @@ public:
bool load(const Common::String &filename);
// Required Font interface methods
- int getFontHeight() const override { return CHAR_HEIGHT; }
- int getMaxCharWidth() const override { return CHAR_WIDTH; }
+ int getFontHeight() const override { return SMALL_FONT_CHAR_HEIGHT; }
+ int getMaxCharWidth() const override { return SMALL_FONT_CHAR_WIDTH; }
int getCharWidth(uint32 chr) const override;
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
@@ -47,8 +47,8 @@ public:
protected:
private:
- static const int CHAR_WIDTH = 8;
- static const int CHAR_HEIGHT = 8;
+ static const int SMALL_FONT_CHAR_WIDTH = 8;
+ static const int SMALL_FONT_CHAR_HEIGHT = 8;
};
} // End of namespace Pelrock
Commit: 5977e6a2f380c277a2ded410ccab730b66e80ef2
https://github.com/scummvm/scummvm/commit/5977e6a2f380c277a2ded410ccab730b66e80ef2
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:43+02:00
Commit Message:
PELROCK: Removal of warnings due to incompatible types
Changed paths:
engines/pelrock/fonts/large_font.cpp
engines/pelrock/fonts/large_font.h
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/video/video.h
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index 5b534af3d27..7294b2ef8bf 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -116,7 +116,7 @@ int LargeFont::getCharWidth(uint32 chr) const {
void LargeFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
chr -= 32; // Adjust for font starting at ASCII 32
- if (!_fontData || chr >= 100 || chr < 0) {
+ if (!_fontData || chr >= 100) {
return;
}
diff --git a/engines/pelrock/fonts/large_font.h b/engines/pelrock/fonts/large_font.h
index 2da5c24e5da..fc6e39ebeea 100644
--- a/engines/pelrock/fonts/large_font.h
+++ b/engines/pelrock/fonts/large_font.h
@@ -35,14 +35,14 @@ public:
bool load(const Common::String &filename);
// Required Font interface methods
- int getFontHeight() const override { return CHAR_HEIGHT; }
+ int getFontHeight() const override { return LARGE_FONT_CHAR_HEIGHT; }
int getMaxCharWidth() const override { return LARGE_FONT_CHAR_WIDTH; }
int getCharWidth(uint32 chr) const override;
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
private:
static const int LARGE_FONT_CHAR_WIDTH = 12;
- static const int CHAR_HEIGHT = 24;
+ static const int LARGE_FONT_CHAR_HEIGHT = 24;
byte *_fontData;
};
} // End of namespace Pelrock
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 5603fb84161..70f1c7d2ad5 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -661,7 +661,7 @@ void MenuManager::drawScreen() {
_screen->blitFrom(_compositeBuffer);
byte defaultColor = 255;
- for (int i = 0; _menuText.size() > i; i++) {
+ for (uint i = 0; _menuText.size() > i; i++) {
g_engine->_graphics->drawColoredText(_screen, _menuText[i], kTextStartX, kTextStartY + (i * _textLineH), 200, defaultColor, g_engine->_smallFont);
}
@@ -670,8 +670,8 @@ void MenuManager::drawScreen() {
void MenuManager::drawInventoryIcons() {
bool debugIcons = false;
- for (int i = 0; i < 4; i++) {
- int itemIndex = _curInventoryPage * 4 + i;
+ for (uint i = 0; i < 4; i++) {
+ uint itemIndex = _curInventoryPage * 4 + i;
if (g_engine->_state->inventoryItems.size() <= itemIndex)
continue;
InventoryObject item = g_engine->_res->getIconForObject(g_engine->_state->inventoryItems[itemIndex]);
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index bd30ef1b79d..04f89c96371 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -193,7 +193,7 @@ private:
Common::Array<Common::StringArray> _menuTexts;
// Temporary
int _selectedInvIndex = 0;
- int _curInventoryPage = 0;
+ uint _curInventoryPage = 0;
Common::StringArray _menuText;
Common::Array<Common::StringArray> _inventoryDescriptions;
Common::Array<Common::Point> _inventorySlots;
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1bfbdf9bc7b..c129c768cfa 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1659,7 +1659,7 @@ VerbIcon PelrockEngine::isActionUnder(int x, int y) {
return NO_ACTION;
}*/
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
- int loopEnd = _state->selectedInventoryItem != -1 ? actions.size() + 1 : actions.size();
+ uint loopEnd = _state->selectedInventoryItem != -1 ? actions.size() + 1 : actions.size();
for (uint i = 0; i < loopEnd; i++) {
Common::Point p = getPositionInBalloonForIndex(i, _actionPopupState.x, _actionPopupState.y);
Common::Rect actionRect = Common::Rect(p.x, p.y, p.x + kVerbIconWidth, p.y + kVerbIconHeight);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 396552cbadb..57f94badbc4 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -248,7 +248,7 @@ void RoomManager::enableSprite(byte spriteIndex, byte zOrder, int persist) {
}
void RoomManager::enableSprite(byte roomNumber, byte spriteIndex, byte zOrder, int persist) {
- for (int i = 0; i < g_engine->_state->spriteChanges[roomNumber].size(); i++) {
+ for (uint i = 0; i < g_engine->_state->spriteChanges[roomNumber].size(); i++) {
if (g_engine->_state->spriteChanges[roomNumber][i].spriteIndex == spriteIndex) {
g_engine->_state->spriteChanges[roomNumber].remove_at(i);
break;
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video/video.h
index 07f79a3606a..596509dfb37 100644
--- a/engines/pelrock/video/video.h
+++ b/engines/pelrock/video/video.h
@@ -108,7 +108,7 @@ private:
AudioEffect readAudioEffect(Common::File &metadataFile);
char decodeChar(byte c);
Subtitle *getSubtitleForFrame(uint16 frameNumber);
- int _currentSubtitleIndex = 0;
+ uint _currentSubtitleIndex = 0;
Graphics::Surface _videoSurface = Graphics::Surface();
Graphics::ManagedSurface _textSurface = Graphics::ManagedSurface();
Common::Array<ChunkHeader> _chunkBuffer;
Commit: c5b87203f07f16e8d5fdba12264ae9b26ddcb8af
https://github.com/scummvm/scummvm/commit/c5b87203f07f16e8d5fdba12264ae9b26ddcb8af
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:43+02:00
Commit Message:
PELROCK: Fix mismatched free/deletes
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 70f1c7d2ad5..b8e874c276c 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -709,7 +709,7 @@ void MenuManager::loadMenu() {
curPos += kMainMenuPart1RawSize;
- byte *compressedPart1 = new byte[kMainMenuPart1CompressedSize];
+ byte *compressedPart1 = (byte *) malloc(kMainMenuPart1CompressedSize);
alfred7.read(compressedPart1, kMainMenuPart1CompressedSize);
byte *decompressedPart1 = nullptr;
size_t decompressedSize = rleDecompress(compressedPart1, kMainMenuPart1CompressedSize, 0, 0, &decompressedPart1, true);
@@ -717,20 +717,21 @@ void MenuManager::loadMenu() {
memcpy((byte *)_mainMenu.getPixels() + curPos, decompressedPart1, decompressedSize);
curPos += decompressedSize;
- delete[] compressedPart1;
- delete[] decompressedPart1;
+ free(compressedPart1);
+ free(decompressedPart1);
alfred7.seek(kMainMenuPart2Offset, SEEK_SET);
alfred7.read((byte *)_mainMenu.getPixels() + curPos, kMainMenuPart2RawSize);
curPos += kMainMenuPart2RawSize;
- byte *compressedPart2 = new byte[kMainMenuPart2CompressedSize];
+ byte *compressedPart2 = (byte *) malloc(kMainMenuPart2CompressedSize);
alfred7.read(compressedPart2, kMainMenuPart2CompressedSize);
byte *decompressedPart2 = nullptr;
decompressedSize = rleDecompress(compressedPart2, kMainMenuPart2CompressedSize, 0, 0, &decompressedPart2, true);
memcpy((byte *)_mainMenu.getPixels() + curPos, decompressedPart2, decompressedSize);
curPos += decompressedSize;
- delete[] compressedPart2;
- delete[] decompressedPart2;
+ free(compressedPart2);
+ free(decompressedPart2);
+
alfred7.seek(kMainMenuPart3Offset, SEEK_SET);
alfred7.read((byte *)_mainMenu.getPixels() + curPos, kMainMenuPart3Size);
@@ -750,28 +751,28 @@ void MenuManager::loadMenu() {
readButton(soundArrowsData, 0, _soundControlArrowLeft, 36, 28);
readButton(soundArrowsData, 36 * 28 * 2, _soundControlArrowRight, 31, 28);
- delete[] soundArrowsData;
+ free(soundArrowsData);
byte *soundIconMasterData = nullptr;
size_t soundIconMasterSize = 0;
rleDecompressSingleBuda(&alfred7, kSoundMasterOffset, soundIconMasterData, soundIconMasterSize);
_soundControlMasterIcon = new byte[66 * 64];
extractSingleFrame(soundIconMasterData, _soundControlMasterIcon, 0, 66, 64);
- delete[] soundIconMasterData;
+ free(soundIconMasterData);
byte *soundIconSfxData = nullptr;
size_t soundIconSfxSize = 0;
rleDecompressSingleBuda(&alfred7, kSoundSfxOffset, soundIconSfxData, soundIconSfxSize);
_soundControlSfxIcon = new byte[66 * 64];
extractSingleFrame(soundIconSfxData, _soundControlSfxIcon, 0, 66, 64);
- delete[] soundIconSfxData;
+ free(soundIconSfxData);
byte *soundIconMusicData = nullptr;
size_t soundIconMusicSize = 0;
rleDecompressSingleBuda(&alfred7, kSoundMusicOffset, soundIconMusicData, soundIconMusicSize);
_soundControlMusicIcon = new byte[66 * 64];
extractSingleFrame(soundIconMusicData, _soundControlMusicIcon, 0, 66, 64);
- delete[] soundIconMusicData;
+ free(soundIconMusicData);
_menuText = _menuTexts[0];
alfred7.close();
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 55b06c3c7a4..37037f82acf 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -91,7 +91,7 @@ ResourceManager::~ResourceManager() {
for (int i = 0; i < kNumVerbIcons; i++) {
delete[] _verbIcons[i];
}
- delete[] _popUpBalloon;
+ free(_popUpBalloon);
for (int i = 0; i < 4; i++) {
// free all frame buffers
for (int j = 0; j < walkingAnimLengths[i]; j++) {
@@ -150,7 +150,7 @@ void ResourceManager::loadInteractionIcons() {
alfred7File.seek(kBalloonFramesOffset, SEEK_SET);
uint32 totalBalloonSize = kBalloonWidth * kBalloonHeight * kBalloonFrames;
- _popUpBalloon = new byte[totalBalloonSize];
+ _popUpBalloon = nullptr;
uint32 compressedSize = kBalloonFramesSize;
@@ -187,7 +187,7 @@ void ResourceManager::loadAlfredAnims() {
alfred3.close();
uint32 capacity = 3060 * 102 + 2340 * 55;
- byte *completePic = new byte[capacity];
+ byte *completePic = nullptr;
rleDecompress(bufferFile, alfred3Size, 0, capacity, &completePic);
byte *stdFramesPic = new byte[3060 * 102];
@@ -251,7 +251,7 @@ void ResourceManager::loadAlfredAnims() {
delete[] crawlFramesPic;
delete[] stdFramesPic;
- delete[] completePic;
+ free(completePic);
free(bufferFile);
Common::File alfred7;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 57f94badbc4..549825ac098 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -36,7 +36,7 @@ RoomManager::RoomManager() {
RoomManager::~RoomManager() {
if (_pixelsShadows != nullptr) {
- delete[] _pixelsShadows;
+ free(_pixelsShadows);
_pixelsShadows = nullptr;
}
delete[] _resetData;
@@ -602,7 +602,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
loadConversationData(pair12, pair12size, _conversationOffset, _conversationDataSize, _conversationData);
if (_pixelsShadows != nullptr)
- delete[] _pixelsShadows;
+ free(_pixelsShadows);
_pixelsShadows = loadShadowMap(roomNumber);
loadRemaps(roomNumber);
Commit: 98b3285baeff931f7cfab5a11b037b8bded379b5
https://github.com/scummvm/scummvm/commit/98b3285baeff931f7cfab5a11b037b8bded379b5
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:43+02:00
Commit Message:
PELROCK: Fixes leak on Dialog surface
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/dialog.h
engines/pelrock/pathfinding.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
engines/pelrock/video/video.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 116edb997f3..78e8f538538 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1683,7 +1683,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
guard->animData[0].curFrame = 0;
guard->animData[0].nframes = 1;
// copy idle frame from talking animation
- guard->animData[0].animData[0] = _room->_talkingAnimHeader.animA[0];
+ guard->animData[0].animData[0] = _room->_talkingAnims.animA[0];
_alfredState.direction = ALFRED_RIGHT;
walkAndAction(_room->findHotspotByExtra(guard->extra), TALK);
if (shouldQuit()) {
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 9a54e15acf3..b9dd53eb0ac 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -164,7 +164,7 @@ void DialogManager::displayChoices(Common::Array<ChoiceOption> *choices, Graphic
* the maxWidth + height then print the text onto that surface with the appropriate alignment,
* then blit that surface to the screen.
*/
-Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId, Graphics::TextAlign alignment) {
+Graphics::Surface *DialogManager::getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId, Graphics::TextAlign alignment) {
int maxWidth = 0;
int height = dialogueLines.size() * 25; // Add some padding
@@ -172,16 +172,16 @@ Graphics::Surface DialogManager::getDialogueSurface(Common::Array<Common::String
maxWidth = MAX(maxWidth, g_engine->_largeFont->getStringWidth(dialogueLines[i]));
}
- Graphics::Surface s;
- s.create(maxWidth + 1, height + 1, Graphics::PixelFormat::createFormatCLUT8());
- s.fillRect(s.getRect(), 255); // Clear surface
+ Graphics::Surface *s = new Graphics::Surface();
+ s->create(maxWidth + 1, height + 1, Graphics::PixelFormat::createFormatCLUT8());
+ s->fillRect(s->getRect(), 255); // Clear surface
for (uint i = 0; i < dialogueLines.size(); i++) {
int xPos = 0;
int yPos = i * 25; // Above sprite, adjust for line
// debug("Drawing dialogue line %d: \"%s\" at position (%d, %d) with speaker ID %d", i, dialogueLines[i].c_str(), xPos, yPos, speakerId);
- g_engine->_largeFont->drawString(&s, dialogueLines[i], xPos, yPos, maxWidth, speakerId, alignment);
+ g_engine->_largeFont->drawString(s, dialogueLines[i], xPos, yPos, maxWidth, speakerId, alignment);
}
return s;
@@ -211,7 +211,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
yBasePos = _curSprite->y; // Above sprite, adjust for line
// Set NPC talk speed byte for original timing.
- TalkingAnims *th = &g_engine->_room->_talkingAnimHeader;
+ TalkingAnims *th = &g_engine->_room->_talkingAnims;
g_engine->_npcTalkSpeedByte = _curSprite->talkingAnimIndex ? th->speedByteB : th->speedByteA;
}
}
@@ -274,22 +274,24 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int xPos = xBasePos - maxWidth / 2;
int yPos = yBasePos - height;
- Graphics::Surface s = getDialogueSurface(textLines, speakerId);
+ Graphics::Surface *s = getDialogueSurface(textLines, speakerId);
// Clamp to screen bounds (original game: min Y = 1, max X = 639 - width)
xPos = CLIP(xPos, 0, 639 - maxWidth);
- yPos = CLIP(yPos, 1, 400 - (int)s.getRect().height());
+ yPos = CLIP(yPos, 1, 400 - (int)s->getRect().height());
if (g_engine->_shakeEffectState.enabled) {
debug("Applying shake effect to dialogue, shakeX: %d", g_engine->_shakeEffectState.shakeX);
xPos -= g_engine->_shakeEffectState.shakeX;
}
- _screen->transBlitFrom(s, s.getRect(), Common::Point(xPos, yPos), 255);
+ _screen->transBlitFrom(*s, s->getRect(), Common::Point(xPos, yPos), 255);
// drawPos(_screen, xPos, yPos, speakerId);
_screen->markAllDirty();
_screen->update();
+ s->free();
+ delete s;
// Check if TTL expired for this page (always applies, even for _disableClickToAdvance)
bool ttlExpired = !fromIntro && (pageTtlMs > 0) && (g_system->getMillis() - pageStartMs >= pageTtlMs);
diff --git a/engines/pelrock/dialog.h b/engines/pelrock/dialog.h
index 50f5486cd85..045da583084 100644
--- a/engines/pelrock/dialog.h
+++ b/engines/pelrock/dialog.h
@@ -114,7 +114,7 @@ public:
void say(Common::StringArray texts, byte spriteIndex = 0);
void say(Common::StringArray texts, int16 x, int16 y);
bool processColorAndTrim(Common::StringArray &lines, byte &speakerId);
- Graphics::Surface getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId, Graphics::TextAlign alignment = Graphics::kTextAlignCenter);
+ Graphics::Surface *getDialogueSurface(Common::Array<Common::String> dialogueLines, byte speakerId, Graphics::TextAlign alignment = Graphics::kTextAlignCenter);
Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
Common::Array<Common::Array<Common::String>> wordWrap(Common::StringArray texts);
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
index e3dd713db12..38f8483e9a6 100644
--- a/engines/pelrock/pathfinding.cpp
+++ b/engines/pelrock/pathfinding.cpp
@@ -219,7 +219,7 @@ byte getAdjacentWalkbox(Common::Array<WalkBox> &walkboxes, byte currentBoxIndex)
}
void clearVisitedFlags(Common::Array<WalkBox> &walkboxes) {
- for (int i = 0; i < walkboxes.size(); i++) {
+ for (uint i = 0; i < walkboxes.size(); i++) {
walkboxes[i].flags = 0;
}
}
@@ -261,7 +261,6 @@ uint16 buildWalkboxPath(Common::Array<WalkBox> &walkboxes, byte startBox, byte d
// Terminate path
pathBuffer[pathIndex] = kPathEnd;
- debug("Built walkbox path of length %d", pathIndex);
return pathIndex;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index c129c768cfa..eceb0c4a3f0 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -562,7 +562,6 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
}
void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
- debug("Executing action %d on hotspot %d", action, hotspot->extra);
if (action == ITEM) {
int inventoryObject = _state->selectedInventoryItem;
for (const CombinationEntry *entry = combinationTable; entry->handler != nullptr; entry++) {
@@ -623,9 +622,6 @@ void PelrockEngine::checkMouse() {
_actionPopupState.isActive = false;
// Mouse was released while popup is active
VerbIcon actionClicked = isActionUnder(_events->_releaseX, _events->_releaseY);
- if (actionClicked != NO_ACTION) {
- debug("Popup action clicked: %d, is alfredunder %d", actionClicked, _actionPopupState.isAlfredUnder);
- }
if (actionClicked != NO_ACTION && _currentHotspot != nullptr) {
// Action was selected - queue it
walkAndAction(_currentHotspot, actionClicked);
@@ -746,12 +742,10 @@ void PelrockEngine::talkTo(HotSpot *hotspot) {
}
}
changeCursor(DEFAULT);
- debug("Talking to hotspot %d (%d) with extra %d", hotspot->index, hotspot->isSprite ? hotspot->index : hotspot->index - _room->_currentRoomAnims.size(), hotspot->extra);
// Set NPC talk speed byte for original timing
- TalkingAnims *th = &_room->_talkingAnimHeader;
+ TalkingAnims *th = &_room->_talkingAnims;
_npcTalkSpeedByte = animSet->talkingAnimIndex ? th->speedByteB : th->speedByteA;
- debug("NPC talk speed byte: %d (slot %d)", _npcTalkSpeedByte, animSet->talkingAnimIndex);
_dialog->startConversation(_room->_conversationData, _room->_conversationDataSize, animSet->talkingAnimIndex, animSet);
@@ -814,7 +808,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_currentStep++;
if (_currentStep >= _currentContext.movementCount) {
_currentStep = 0;
- debug("Finished walking to target");
_alfredState.setState(ALFRED_IDLE);
_alfredState.isWalkingCancelable = true;
_disableAction = false;
@@ -844,7 +837,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
// Only check exits after walking is complete AND no queued action
Exit *exit = isExitUnder(_alfredState.x, _alfredState.y);
if (exit != nullptr) {
- debug("Using exit to room %d", exit->targetRoom);
exitTriggers(exit);
_alfredState.x = exit->targetX;
_alfredState.y = exit->targetY;
@@ -899,7 +891,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
break;
}
case ALFRED_INTERACTING: {
- debug("Alfred interacting frame %d/%d, direction %d", _alfredState.curFrame, interactingAnimLength, _alfredState.direction);
drawAlfred(_res->alfredInteractFrames[_alfredState.direction][_alfredState.curFrame]);
_alfredState.curFrame++;
if (_alfredState.curFrame >= interactingAnimLength) {
@@ -1203,17 +1194,12 @@ void PelrockEngine::checkLongMouseClick(int x, int y) {
bool alfredUnder = isAlfredUnder(x, y);
if ((hotspotIndex != -1 || alfredUnder) && !_actionPopupState.isActive) {
- // Original game positions balloon at alfred_x - 70, clamped to [1, 390]
_actionPopupState.x = CLIP((int)_alfredState.x - 70, 1, 390);
- // Original game: Y = max(10, alfred_y - character_sprite_height - 102)
- // The 102 offset is a fixed gap above Alfred's head, NOT the balloon height.
- // This means the balloon bottom overlaps Alfred's head by ~10 pixels.
_actionPopupState.y = MAX(10, (int)_alfredState.y - (int)kAlfredFrameHeight - 102);
_actionPopupState.isActive = true;
_inventoryOverlayState.invStartingPos = -1;
_actionPopupState.curFrame = 0;
- debug("Setting alfred under popup: %d", alfredUnder);
_actionPopupState.isAlfredUnder = alfredUnder;
if (hotspotIndex != -1) {
_currentHotspot = &_room->_currentRoomHotspots[hotspotIndex];
@@ -1373,7 +1359,7 @@ void PelrockEngine::animateTalkingNPC(Sprite *animSet) {
// Change with the right index
int index = animSet->talkingAnimIndex;
- TalkingAnims *animHeader = &_room->_talkingAnimHeader;
+ TalkingAnims *animHeader = &_room->_talkingAnims;
int x = animSet->x + (index ? animHeader->offsetXAnimB : animHeader->offsetXAnimA);
int y = animSet->y + (index ? animHeader->offsetYAnimB : animHeader->offsetYAnimA);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 549825ac098..593e29e3f72 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -30,7 +30,6 @@ namespace Pelrock {
static const uint32 kPaletteRemapOffset = 0x4C77C; // JUEGO.EXE â water-effect palette remap table
RoomManager::RoomManager() {
- _pixelsShadows = new byte[640 * 400];
loadWaterPaletteRemap();
}
@@ -39,9 +38,24 @@ RoomManager::~RoomManager() {
free(_pixelsShadows);
_pixelsShadows = nullptr;
}
+ clearAnims();
delete[] _resetData;
}
+void RoomManager::clearAnims() {
+ for (auto &sprite : _currentRoomAnims) {
+ if (sprite.animData) {
+ for (int a = 0; a < sprite.numAnims; a++) {
+ for (int f = 0; f < sprite.animData[a].nframes; f++) {
+ delete[] sprite.animData[a].animData[f]; // free each frame
+ }
+ delete[] sprite.animData[a].animData; // free frame pointer array
+ }
+ delete[] sprite.animData; // free anim array
+ }
+ }
+}
+
void RoomManager::loadWaterPaletteRemap() {
// Extra remap for water effect
Common::File exe;
@@ -578,6 +592,10 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
Common::Array<Sprite> sprites = loadRoomAnimations(pic, pixelDataSize, pair10, pair10size);
Common::Array<HotSpot> staticHotspots = loadHotspots(pair10, pair10size);
+
+ // clear anims from previous room
+ clearAnims();
+
_currentRoomAnims = sprites;
_currentRoomHotspots = unifyHotspots(sprites, staticHotspots);
_currentRoomExits = loadExits(pair10, pair10size);
@@ -893,7 +911,6 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
Common::Array<Sprite> anims = Common::Array<Sprite>();
uint32 spriteCountPos = 5;
byte spriteCount = data[spriteCountPos] - 2;
- debug("Sprite count: %d", spriteCount);
uint32 metadata_start = spriteCountPos + (44 * 2 + 5);
uint32 picOffset = 0;
@@ -1182,7 +1199,6 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
talkFile.read(&talkHeader.unknown6, 24);
if (talkHeader.spritePointer == 0) {
- debug("No talking animation for room %d", roomNumber);
talkFile.close();
return;
}
@@ -1215,7 +1231,7 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
}
}
free(decompressed);
- _talkingAnimHeader = talkHeader;
+ _talkingAnims = talkHeader;
talkFile.close();
}
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 9ff5afc04ad..dcdab505744 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -78,6 +78,7 @@ class RoomManager {
public:
RoomManager();
~RoomManager();
+ void clearAnims();
void loadRoomMetadata(Common::File *roomFile, int roomNumber);
/**
* Passer by animations are animations of characters that merely traverse the scene as ambient
@@ -168,7 +169,7 @@ public:
Common::Array<WalkBox> _currentRoomWalkboxes;
Common::Array<Description> _currentRoomDescriptions;
- TalkingAnims _talkingAnimHeader;
+ TalkingAnims _talkingAnims;
ScalingParams _scaleParams;
byte *_pixelsShadows = nullptr;
byte _roomPalette[768];
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 913b747b970..1031e05af6e 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -302,49 +302,49 @@ struct Sprite {
};
struct HotSpot {
- byte index;
- byte innerIndex;
- int id;
- int16 x;
- int16 y;
- int w;
- int h;
- byte actionFlags;
- int16 extra;
+ byte index = 0;
+ byte innerIndex = 0;
+ int id = 0;
+ int16 x = 0;
+ int16 y = 0;
+ int w = 0;
+ int h = 0;
+ byte actionFlags = 0;
+ int16 extra = 0;
bool isEnabled = true;
bool isSprite = false;
byte zOrder = 0;
};
struct TalkingAnims {
- uint32 spritePointer;
+ uint32 spritePointer = 0;
byte unknown2[3];
- int8 offsetXAnimA;
- int8 offsetYAnimA;
+ int8 offsetXAnimA = 0;
+ int8 offsetYAnimA = 0;
- byte wAnimA;
- byte hAnimA;
+ byte wAnimA = 0;
+ byte hAnimA = 0;
byte unknown3[2];
- byte numFramesAnimA;
+ byte numFramesAnimA = 0;
byte unknown4[4]; // slot 0 data pointer (unused in ScummVM)
- byte speedByteA; // slot 0 offset 0x12: controls NPC talk render rate (original: 2+speedByte ticks per render)
+ byte speedByteA = 0; // slot 0 offset 0x12: controls NPC talk render rate (original: 2+speedByte ticks per render)
- byte offsetXAnimB;
- byte offsetYAnimB;
+ int8 offsetXAnimB = 0;
+ int8 offsetYAnimB = 0;
- byte wAnimB;
- byte hAnimB;
+ byte wAnimB = 0;
+ byte hAnimB = 0;
byte unknown5[2]; // slot 1 stride (unused in ScummVM)
- byte numFramesAnimB;
+ byte numFramesAnimB = 0;
byte unknown7[4]; // slot 1 data pointer (unused in ScummVM)
- byte speedByteB; // slot 1 speed byte at file offset 30
+ byte speedByteB = 0; // slot 1 speed byte at file offset 30
byte unknown6[24]; // slots 2-3 (unused)
// Runtime fields (not read from file)
- byte currentFrameAnimA;
- byte currentFrameAnimB;
+ byte currentFrameAnimA = 0;
+ byte currentFrameAnimB = 0;
byte **animA = nullptr;
byte **animB = nullptr;
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index cd344ae194b..91021021c63 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -130,9 +130,10 @@ void VideoManager::playIntro() {
byte color;
_dialog->processColorAndTrim(lines, color);
- Graphics::Surface s = _dialog->getDialogueSurface(lines, color);
- _textSurface.transBlitFrom(s, Common::Point(subtitle->x, subtitle->y), 255);
- s.free();
+ Graphics::Surface *s = _dialog->getDialogueSurface(lines, color);
+ _textSurface.transBlitFrom(*s, Common::Point(subtitle->x, subtitle->y), 255);
+ s->free();
+ delete s;
}
presentFrame();
Commit: 1e2346f201d176ea599aafc2c8fa98d66c28ba6b
https://github.com/scummvm/scummvm/commit/1e2346f201d176ea599aafc2c8fa98d66c28ba6b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:44+02:00
Commit Message:
PELROCK: Fixes leak with passer-by-animations and palette animations
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/room.cpp
engines/pelrock/saveload.cpp
engines/pelrock/types.h
engines/pelrock/video/video.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index b8e874c276c..c3507043ea6 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -836,7 +836,6 @@ void MenuManager::loadMenuTexts() {
_menuTexts.push_back(unprocessedMenuTexts[i]);
}
}
- debug("Menu texts size after processing: %d", (int)_menuTexts.size());
_menuText = _menuTexts[0];
delete[] textBuffer;
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 593e29e3f72..97c787b0a93 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -40,6 +40,12 @@ RoomManager::~RoomManager() {
}
clearAnims();
delete[] _resetData;
+ if(_currentPaletteAnim) {
+ delete _currentPaletteAnim;
+ }
+ if(_passerByAnims) {
+ delete _passerByAnims;
+ }
}
void RoomManager::clearAnims() {
@@ -592,6 +598,7 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
Common::Array<Sprite> sprites = loadRoomAnimations(pic, pixelDataSize, pair10, pair10size);
Common::Array<HotSpot> staticHotspots = loadHotspots(pair10, pair10size);
+ free(pic);
// clear anims from previous room
clearAnims();
@@ -904,6 +911,7 @@ void RoomManager::loadAnimationPixelData(Common::File *roomFile, int roomOffset,
outSize = size;
}
}
+ delete[] pixelData;
}
Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size) {
@@ -1159,7 +1167,7 @@ void RoomManager::resetMetadataDefaults(byte room, byte *&data, size_t size) {
continue;
}
Common::copy(entry.data, entry.data + entry.dataSize, data + entry.offset);
- // delete[] entry.data;
+ delete[] entry.data;
}
alfred8.close();
}
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index 2b6c3cfa3b0..cbf2c00e135 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -318,7 +318,8 @@ bool syncGameStateData(Common::Serializer &s, GameStateData *gameState) {
}
}
} else {
- gameState->disabledBranches.clear();
+
+ gameState->clearBranches();
for (uint16 idx = 0; idx < disabledBranchesSize; ++idx) {
byte roomNumber;
s.syncAsByte(roomNumber);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 1031e05af6e..1b563f96c2d 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -612,20 +612,31 @@ struct GameStateData {
for (int i = 0; i < kNumGameFlags; i++)
flags[i] = 0;
flags[FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ] = true;
- disabledBranches.clear();
inventoryItems.clear();
stickersPerRoom.clear();
roomExitChanges.clear();
roomWalkBoxChanges.clear();
roomHotSpotChanges.clear();
spriteChanges.clear();
- disabledBranches.clear();
+ clearBranches();
libraryShelf = -1;
selectedBookIndex = -1;
bookLetter = '\0';
stateGame = GAME;
}
+ void clearBranches() {
+ for(auto &entry : disabledBranches) {
+ for (ResetEntry &resetEntry : entry._value) {
+ if (resetEntry.data) {
+ delete[] resetEntry.data;
+ resetEntry.data = nullptr;
+ }
+ }
+ }
+ disabledBranches.clear();
+ }
+
void addDisabledBranch(ResetEntry entry) {
disabledBranches[entry.room].push_back(entry);
}
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index 91021021c63..e5d51272256 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -100,7 +100,6 @@ void VideoManager::playIntro() {
break;
}
AudioEffect voice = _voiceEffect[currentFrame];
- debug("Playing voice effect: '%s'", voice.filename.c_str());
VoiceData voiceData = _sounds[voice.filename];
_introSndFile.seek(voiceData.offset, SEEK_SET);
byte *voiceBuffer = new byte[voiceData.length];
@@ -110,7 +109,6 @@ void VideoManager::playIntro() {
if (_sfxEffect.contains(currentFrame)) {
AudioEffect sfx = _sfxEffect[currentFrame];
- debug("Playing SFX effect: '%s'", sfx.filename.c_str());
VoiceData sfxData = _sounds[sfx.filename];
_introSndFile.seek(sfxData.offset, SEEK_SET);
byte *sfxBuffer = new byte[sfxData.length];
Commit: d81b5918a5bc185dfa42eb1e20fd439c0db72e79
https://github.com/scummvm/scummvm/commit/d81b5918a5bc185dfa42eb1e20fd439c0db72e79
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:44+02:00
Commit Message:
PELROCK: Make sure to clear animations before loading new ones
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/saveload.cpp
engines/pelrock/sound.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 78e8f538538..879fdef3099 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -2034,7 +2034,6 @@ void PelrockEngine::teleportToPrincess() {
void PelrockEngine::useOnAlfred(int inventoryObject) {
- debug("Using item %d on Alfred", inventoryObject);
switch (inventoryObject) {
case 9: // Letter
_dialog->say(_res->_ingameTexts[kTextCorrespondenciaAjena]);
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index b9dd53eb0ac..d9d1a7b8948 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -998,7 +998,6 @@ void DialogManager::maybeDisableChoice(Common::Array<Pelrock::ChoiceOption> *cho
currentChoicePos = scanPos;
isCurrentFB = true;
foundParent = true;
- debug("Found parent FB at level %d, pos %u", currentLevel, currentChoicePos);
break;
}
}
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index c3507043ea6..5138141493a 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -536,7 +536,6 @@ bool MenuManager::selectInventoryItem(int i) {
_menuText = _inventoryDescriptions[_selectedInvIndex];
_sound->playSound(inventorySounds[_selectedInvIndex], 0);
g_engine->_state->selectedInventoryItem = _selectedInvIndex;
- debug("Selected inventory item %d", _selectedInvIndex);
return true;
}
@@ -583,9 +582,6 @@ void MenuManager::menuLoop() {
_musicVolumeLevel = mixerVolumeToLevel(_sound->getVolumeMusic());
_masterVolumeLevel = mixerVolumeToLevel(_sound->getVolumeMaster());
- debug("Initial master volume level: %d", _masterVolumeLevel);
- debug("Initial SFX volume level: %d", _sfxVolumeLevel);
- debug("Initial Music volume level: %d", _musicVolumeLevel);
_masterSoundIcon.create(66, 64, Graphics::PixelFormat::createFormatCLUT8());
_sfxSoundIcon.create(66, 64, Graphics::PixelFormat::createFormatCLUT8());
_musicSoundIcon.create(66, 64, Graphics::PixelFormat::createFormatCLUT8());
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index eceb0c4a3f0..8a3a2244a70 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -626,7 +626,6 @@ void PelrockEngine::checkMouse() {
// Action was selected - queue it
walkAndAction(_currentHotspot, actionClicked);
} else if (_actionPopupState.isAlfredUnder && actionClicked != NO_ACTION) {
- debug("Using item on Alfred");
useOnAlfred(_state->selectedInventoryItem);
} else if (_inventoryOverlayState.isActive && _inventoryOverlayState.posInInventorySelectionArea(_events->_releaseX, _events->_releaseY)) {
int item = checkMouseClickInventoryOverlay(_events->_releaseX, _events->_releaseY);
@@ -1580,9 +1579,7 @@ void PelrockEngine::walkLoop(int16 x, int16 y, AlfredDirection direction) {
void PelrockEngine::walkTo(int x, int y) {
_currentStep = 0;
- PathContext context = {nullptr, nullptr, 0, 0, 0};
- findPath(_alfredState.x, _alfredState.y, x, y, _room->_currentRoomWalkboxes, &context, _currentHotspot);
- _currentContext = context;
+ findPath(_alfredState.x, _alfredState.y, x, y, _room->_currentRoomWalkboxes, &_currentContext, _currentHotspot);
_alfredState.setState(ALFRED_WALKING);
}
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 37037f82acf..8eccb2bff5e 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -336,7 +336,7 @@ void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
size_t blockSize = 0;
readUntilBuda(&alfredFile, anim.offset, thisBlock, blockSize);
rleDecompress(thisBlock, blockSize, 0, size, &_currentSpecialAnim->animData, false);
- delete[] thisBlock;
+ free(thisBlock);
} else {
alfredFile.read(_currentSpecialAnim->animData, anim.numFrames * anim.w * anim.h);
}
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 97c787b0a93..72ed74bb262 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -39,6 +39,7 @@ RoomManager::~RoomManager() {
_pixelsShadows = nullptr;
}
clearAnims();
+ clearTalkingAnims();
delete[] _resetData;
if(_currentPaletteAnim) {
delete _currentPaletteAnim;
@@ -48,6 +49,17 @@ RoomManager::~RoomManager() {
}
}
+void RoomManager::clearTalkingAnims() {
+ for (int i = 0; i < _talkingAnims.numFramesAnimA; i++)
+ delete[] _talkingAnims.animA[i];
+ delete[] _talkingAnims.animA;
+ for (int i = 0; i < _talkingAnims.numFramesAnimB; i++)
+ delete[] _talkingAnims.animB[i];
+ delete[] _talkingAnims.animB;
+ _talkingAnims.animA = nullptr;
+ _talkingAnims.animB = nullptr;
+}
+
void RoomManager::clearAnims() {
for (auto &sprite : _currentRoomAnims) {
if (sprite.animData) {
@@ -1128,10 +1140,7 @@ void RoomManager::addDisabledChoice(ChoiceOption choice) {
// Write 0xFA at offset+2 (after FB/F1 marker and level byte)
// This marks the choice as disabled without destroying the marker structure
uint32 disableOffset = choice.dataOffset + 2;
- debug("Adding disabled branch for room %d at offset %d (FA written at %d)",
- choice.room, choice.dataOffset, disableOffset);
- debug("Disabled branch is: \"%s\"", choice.text.c_str());
ResetEntry resetEntry = ResetEntry();
resetEntry.room = choice.room;
resetEntry.offset = disableOffset;
@@ -1239,6 +1248,7 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
}
}
free(decompressed);
+ clearTalkingAnims();
_talkingAnims = talkHeader;
talkFile.close();
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index dcdab505744..5b14be2505d 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -78,6 +78,7 @@ class RoomManager {
public:
RoomManager();
~RoomManager();
+ void clearTalkingAnims();
void clearAnims();
void loadRoomMetadata(Common::File *roomFile, int roomNumber);
/**
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index cbf2c00e135..5492b12aac2 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -114,12 +114,6 @@ bool syncGeneralData(Common::Serializer &s, SaveGameData *game) {
s.syncAsUint16LE(game->alfredY);
s.syncAsByte((byte &)game->alfredDir);
- if (s.isLoading()) {
- debug("LOAD: room=%d, x=%d, y=%d, dir=%d", game->currentRoom, game->alfredX, game->alfredY, game->alfredDir);
- } else {
- debug("SAVE: room=%d, x=%d, y=%d, dir=%d", game->currentRoom, game->alfredX, game->alfredY, game->alfredDir);
- }
-
return !s.err();
}
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 15247333b4a..14e24b86d76 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -180,7 +180,7 @@ int SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
}
sonidosFile.seek(sound.offset, SEEK_SET);
- byte *data = new byte[sound.size];
+ byte *data = (byte *)malloc(sound.size);
sonidosFile.read(data, sound.size);
sonidosFile.close();
@@ -192,6 +192,7 @@ int SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
// For WAV/RIFF files, use the wave decoder
Common::MemoryReadStream *memStream = new Common::MemoryReadStream(data, sound.size, DisposeAfterUse::YES);
stream = Audio::makeWAVStream(memStream, DisposeAfterUse::YES);
+ // no need to free 'data' here, it will be freed when memStream is disposed
} else if (format == SOUND_FORMAT_RAWPCM || format == SOUND_FORMAT_MILES || format == SOUND_FORMAT_MILES2) {
// Determine the offset to skip the header
uint32 headerSize = 0;
@@ -202,13 +203,13 @@ int SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
uint32 pcmSize = sound.size - headerSize;
byte *pcmData = (byte *)malloc(pcmSize);
memcpy(pcmData, data + headerSize, pcmSize);
- delete[] data;
+ free(data);
// Create raw audio stream (8-bit unsigned mono is common for old games)
stream = Audio::makeRawStream(pcmData, pcmSize, sampleRate, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
} else {
debug("Unknown sound format on sound with name %s at offset %d, with size %d", sound.filename.c_str(), sound.offset, sound.size);
- delete[] data;
+ free(data);
return -1;
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 1b563f96c2d..e586f2dfa7f 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -153,7 +153,7 @@ struct AlfredSpecialAnim {
~AlfredSpecialAnim() {
if (animData) {
- delete[] animData;
+ free(animData);
animData = nullptr;
}
}
Commit: ee7fa87c946a4136d77afe88a09654d6d8c28fc9
https://github.com/scummvm/scummvm/commit/ee7fa87c946a4136d77afe88a09654d6d8c28fc9
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:44+02:00
Commit Message:
PELROCK: Fix menu buttons not being cleared
Changed paths:
engines/pelrock/menu.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 5138141493a..f381375751b 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -1016,6 +1016,19 @@ Pelrock::MenuManager::~MenuManager() {
delete[] _inventoryLeftArrow[1];
delete[] _inventoryRightArrow[0];
delete[] _inventoryRightArrow[1];
+ // delete buttons
+ delete[] _saveButtons[0]; delete[] _saveButtons[1];
+ delete[] _loadButtons[0]; delete[] _loadButtons[1];
+ delete[] _soundsButtons[0]; delete[] _soundsButtons[1];
+ delete[] _exitToDosButtons[0]; delete[] _exitToDosButtons[1];
+ delete[] _savesUpArrows[0]; delete[] _savesUpArrows[1];
+ delete[] _savesDownArrows[0]; delete[] _savesDownArrows[1];
+ delete[] _soundControlArrowLeft[0]; delete[] _soundControlArrowLeft[1];
+ delete[] _soundControlArrowRight[0]; delete[] _soundControlArrowRight[1];
+
+ delete[] _soundControlMasterIcon;
+ delete[] _soundControlSfxIcon;
+ delete[] _soundControlMusicIcon;
}
} // End of namespace Pelrock
Commit: b827ac0f9bc91dafecdac500cf494a3a3e36bdfd
https://github.com/scummvm/scummvm/commit/b827ac0f9bc91dafecdac500cf494a3a3e36bdfd
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:45+02:00
Commit Message:
PELROCK: Fixes leak in room reset data
Changed paths:
engines/pelrock/room.cpp
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 72ed74bb262..22c0aa6c298 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -41,23 +41,23 @@ RoomManager::~RoomManager() {
clearAnims();
clearTalkingAnims();
delete[] _resetData;
- if(_currentPaletteAnim) {
+ if (_currentPaletteAnim) {
delete _currentPaletteAnim;
}
- if(_passerByAnims) {
+ if (_passerByAnims) {
delete _passerByAnims;
}
}
void RoomManager::clearTalkingAnims() {
- for (int i = 0; i < _talkingAnims.numFramesAnimA; i++)
- delete[] _talkingAnims.animA[i];
- delete[] _talkingAnims.animA;
- for (int i = 0; i < _talkingAnims.numFramesAnimB; i++)
- delete[] _talkingAnims.animB[i];
- delete[] _talkingAnims.animB;
- _talkingAnims.animA = nullptr;
- _talkingAnims.animB = nullptr;
+ for (int i = 0; i < _talkingAnims.numFramesAnimA; i++)
+ delete[] _talkingAnims.animA[i];
+ delete[] _talkingAnims.animA;
+ for (int i = 0; i < _talkingAnims.numFramesAnimB; i++)
+ delete[] _talkingAnims.animB[i];
+ delete[] _talkingAnims.animB;
+ _talkingAnims.animA = nullptr;
+ _talkingAnims.animB = nullptr;
}
void RoomManager::clearAnims() {
@@ -565,13 +565,16 @@ void RoomManager::resetConversationStates(byte roomNumber, byte *conversationDat
if (roomNumber < entry.room) {
// We've passed the room we care about
roomDone = true;
+ delete[] entry.data;
break;
}
if (roomNumber > entry.room) {
// Not the room we care about, skip
+ delete[] entry.data;
continue;
}
Common::copy(entry.data, entry.data + entry.dataSize, conversationData + entry.offset);
+ delete[] entry.data;
}
alfredB.close();
}
@@ -650,10 +653,11 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
}
PaletteAnim *anim = getPaletteAnimForRoom(roomNumber);
+ if (_currentPaletteAnim != nullptr) {
+ delete _currentPaletteAnim;
+ }
if (anim != nullptr) {
- if (_currentPaletteAnim != nullptr) {
- delete _currentPaletteAnim;
- }
+
_currentPaletteAnim = anim;
} else {
_currentPaletteAnim = nullptr;
@@ -688,8 +692,7 @@ int streetWalkerIndices[] = {
-1, // room 13,
2, // room 14,
-1, // room 15,
- 2
-};
+ 2};
RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
RoomPasserBys *anims = nullptr;
@@ -1169,10 +1172,12 @@ void RoomManager::resetMetadataDefaults(byte room, byte *&data, size_t size) {
if (room < entry.room) {
// We've passed the room we care about
roomDone = true;
+ delete[] entry.data;
break;
}
if (room > entry.room) {
// Not the room we care about, skip
+ delete[] entry.data;
continue;
}
Common::copy(entry.data, entry.data + entry.dataSize, data + entry.offset);
Commit: 693a07ddec1c20c184788cde959632a8e95e50c2
https://github.com/scummvm/scummvm/commit/693a07ddec1c20c184788cde959632a8e95e50c2
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:45+02:00
Commit Message:
PELROCK: Fix savegame data leak
Changed paths:
engines/pelrock/saveload.cpp
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index 5492b12aac2..b159da5e760 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -357,6 +357,7 @@ Common::Error PelrockEngine::syncGame(Common::Serializer &s) {
} else {
SaveGameData *saveGame = createSaveGameData();
result = syncSaveData(s, saveGame);
+ delete saveGame;
}
return result;
}
Commit: fefda1a14e36fd47f72f5d63467de32a9e4cca15
https://github.com/scummvm/scummvm/commit/fefda1a14e36fd47f72f5d63467de32a9e4cca15
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:45+02:00
Commit Message:
PELROCK: Avoid leaking choice list
Changed paths:
engines/pelrock/dialog.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index d9d1a7b8948..302c9caa9a6 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -622,12 +622,14 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
if (choices->empty()) {
state.position = positionStack.empty() ? 0 : positionStack.pop();
if (state.position == 0) {
+ delete choices;
// No choices and no previous position to go back to, ending conversation
break;
}
checkAllSubBranchesExhausted(conversationData, dataSize, state.position, state.currentChoiceLevel - 1);
// No choices found, popping back to previous choice menu, position %u
skipToChoices = true;
+ delete choices;
continue;
}
Commit: a9f9e974d064b022e994bc6f07f601e42253487b
https://github.com/scummvm/scummvm/commit/a9f9e974d064b022e994bc6f07f601e42253487b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:46+02:00
Commit Message:
PELROCK: Make sure to free all pointers in room, pelrock and resources
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 8a3a2244a70..1508596e297 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -83,6 +83,7 @@ PelrockEngine::~PelrockEngine() {
if(_currentContext.movementBuffer) {
free(_currentContext.movementBuffer);
}
+ _saveThumbnail.free();
}
uint32 PelrockEngine::getFeatures() const {
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 8eccb2bff5e..f15c55c7b1d 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -125,6 +125,7 @@ ResourceManager::~ResourceManager() {
}
delete[] _inventoryIcons;
+ clearSpecialAnim();
}
void ResourceManager::loadCursors() {
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 22c0aa6c298..4b4ab9abba6 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -47,6 +47,9 @@ RoomManager::~RoomManager() {
if (_passerByAnims) {
delete _passerByAnims;
}
+ if(_conversationData) {
+ delete[] _conversationData;
+ }
}
void RoomManager::clearTalkingAnims() {
Commit: 1653e473e92aa1ce317c4d7c09fcb98f32d8a15b
https://github.com/scummvm/scummvm/commit/1653e473e92aa1ce317c4d7c09fcb98f32d8a15b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:46+02:00
Commit Message:
PELROCK: Moves sticker pixel data into its own structure
Changed paths:
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
engines/pelrock/room.h
engines/pelrock/types.h
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 6d8b3e1173f..ec7637a4885 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -301,27 +301,26 @@ void GraphicsManager::animateRotatePalette(PaletteAnim *anim) {
void GraphicsManager::placeStickersFirstPass() {
// also place temporary stickers
for (uint i = 0; i < g_engine->_room->_roomStickers.size(); i++) {
- Sticker sticker = g_engine->_room->_roomStickers[i];
- placeSticker(sticker);
+ placeSticker(g_engine->_room->_roomStickers[i], g_engine->_room->_roomStickerPixelData[i]);
}
}
void GraphicsManager::placeStickersSecondPass() {
// Some stickers need to be placed AFTER sprites, hardcoded in the original
if (g_engine->_room->_currentRoomNumber == 3) {
- for (uint i = 0; i < g_engine->_state->stickersPerRoom[3].size(); i++) {
- if (g_engine->_state->stickersPerRoom[3][i].stickerIndex == 14) {
- placeSticker(g_engine->_state->stickersPerRoom[3][i]);
+ for (uint i = 0; i < g_engine->_room->_roomStickers.size(); i++) {
+ if (g_engine->_room->_roomStickers[i].stickerIndex == 14) {
+ placeSticker(g_engine->_room->_roomStickers[i], g_engine->_room->_roomStickerPixelData[i]);
break;
}
}
}
}
-void GraphicsManager::placeSticker(Sticker sticker) {
+void GraphicsManager::placeSticker(Sticker &sticker, byte *pixels) {
// Wrap sticker data as a surface and blit (no transparency - all pixels copied)
Graphics::Surface stickerSurf;
- stickerSurf.init(sticker.w, sticker.h, sticker.w, sticker.stickerData, Graphics::PixelFormat::createFormatCLUT8());
+ stickerSurf.init(sticker.w, sticker.h, sticker.w, pixels, Graphics::PixelFormat::createFormatCLUT8());
// Clip to screen bounds
Common::Rect destRect(sticker.x, sticker.y, sticker.x + sticker.w, sticker.y + sticker.h);
Common::Rect screenRect(0, 0, 640, 400);
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index 1616c0aa215..2609c83d7fa 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -57,7 +57,7 @@ public:
// Sticker rendering
void placeStickersFirstPass();
void placeStickersSecondPass();
- void placeSticker(Sticker sticker);
+ void placeSticker(Sticker &sticker, byte *pixels);
// Palette animations
void updatePaletteAnimations();
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index f15c55c7b1d..83d09536b6a 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -539,12 +539,23 @@ Pelrock::Sticker ResourceManager::getSticker(int stickerIndex) {
sticker.w = alfred6File.readByte();
sticker.h = alfred6File.readByte();
sticker.stickerIndex = stickerIndex;
- sticker.stickerData = new byte[sticker.w * sticker.h];
- alfred6File.read(sticker.stickerData, sticker.w * sticker.h);
alfred6File.close();
return sticker;
}
+byte *ResourceManager::loadStickerPixels(const Sticker &sticker) {
+ Common::File alfred6File;
+ if (!alfred6File.open("ALFRED.6")) {
+ error("Couldnt find file ALFRED.6");
+ }
+ uint32 pixelOffset = stickerOffsets[sticker.stickerIndex] + 6; // skip x(2)+y(2)+w(1)+h(1)
+ alfred6File.seek(pixelOffset, SEEK_SET);
+ byte *pixels = new byte[sticker.w * sticker.h];
+ alfred6File.read(pixels, sticker.w * sticker.h);
+ alfred6File.close();
+ return pixels;
+}
+
InventoryObject ResourceManager::getIconForObject(byte objectIndex) {
byte iconIndex = 0;
if (objectIndex < 59) {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 6dfb6c06879..6242a991895 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -65,6 +65,7 @@ public:
Common::Array<Common::StringArray> getCredits();
Common::Array<Common::Array<Common::String>> processTextData(byte *data, size_t size, bool decode = false);
Sticker getSticker(int stickerIndex);
+ byte *loadStickerPixels(const Sticker &sticker);
InventoryObject getIconForObject(byte index);
byte *loadExtra();
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 4b4ab9abba6..c0a6e6b78b2 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -34,6 +34,7 @@ RoomManager::RoomManager() {
}
RoomManager::~RoomManager() {
+ clearRoomStickerPixels();
if (_pixelsShadows != nullptr) {
free(_pixelsShadows);
_pixelsShadows = nullptr;
@@ -77,6 +78,14 @@ void RoomManager::clearAnims() {
}
}
+void RoomManager::clearRoomStickerPixels() {
+ for (uint i = 0; i < _roomStickerPixelData.size(); i++) {
+ delete[] _roomStickerPixelData[i];
+ }
+ _roomStickerPixelData.clear();
+ _roomStickers.clear();
+}
+
void RoomManager::loadWaterPaletteRemap() {
// Extra remap for water effect
Common::File exe;
@@ -140,16 +149,23 @@ void RoomManager::addSticker(int stickerId, int persist) {
}
void RoomManager::addStickerToRoom(byte room, int stickerId, int persist) {
- Sticker sticker = g_engine->_res->getSticker(stickerId);
- if (room == _currentRoomNumber && persist & PERSIST_TEMP) {
- if (hasSticker(sticker.stickerIndex)) {
+ // Check for duplicate before loading
+ if (room == _currentRoomNumber && (persist & PERSIST_TEMP)) {
+ if (hasSticker(stickerId)) {
debug("Sticker %d already exists in room %d, skipping add", stickerId, room);
return;
}
- _roomStickers.push_back(sticker);
}
+ Sticker stickerMetadata = g_engine->_res->getSticker(stickerId); // metadata only
if (persist & PERSIST_PERM) {
- g_engine->_state->stickersPerRoom[room].push_back(sticker);
+ // stickersPerRoom stores persistent metadata only
+ g_engine->_state->stickersPerRoom[room].push_back(stickerMetadata);
+ }
+
+ if (room == _currentRoomNumber && (persist & PERSIST_TEMP)) {
+ // Load pixel data only when the sticker is visible in the current room
+ _roomStickers.push_back(stickerMetadata);
+ _roomStickerPixelData.push_back(g_engine->_res->loadStickerPixels(stickerMetadata));
}
}
@@ -158,15 +174,17 @@ void RoomManager::removeSticker(int stickerId) {
}
void RoomManager::removeStickerFromRoom(byte room, int stickerId) {
- // First check and remove from room stickers
+ // Remove from current room view and free its pixel data
for (uint i = 0; i < _roomStickers.size(); i++) {
if (_roomStickers[i].stickerIndex == stickerId) {
+ delete[] _roomStickerPixelData[i];
+ _roomStickerPixelData.remove_at(i);
_roomStickers.remove_at(i);
- return;
+ break;
}
}
- // Then check and remove from persisted stickers
+ // Remove from persisted metadata store
for (uint i = 0; i < g_engine->_state->stickersPerRoom[room].size(); i++) {
if (g_engine->_state->stickersPerRoom[room][i].stickerIndex == stickerId) {
g_engine->_state->stickersPerRoom[room].remove_at(i);
@@ -584,7 +602,6 @@ void RoomManager::resetConversationStates(byte roomNumber, byte *conversationDat
void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
- _roomStickers.clear();
_prevRoomNumber = _currentRoomNumber;
_currentRoomNumber = roomNumber;
int roomOffset = roomNumber * kRoomStructSize;
@@ -626,7 +643,12 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
_currentRoomExits = loadExits(pair10, pair10size);
_currentRoomWalkboxes = loadWalkboxes(pair10, pair10size);
_scaleParams = loadScalingParams(pair10, pair10size);
+
+ clearRoomStickerPixels(); // free all sticker buffers first
_roomStickers = g_engine->_state->stickersPerRoom[roomNumber];
+ for (uint i = 0; i < _roomStickers.size(); i++) {
+ _roomStickerPixelData.push_back(g_engine->_res->loadStickerPixels(_roomStickers[i]));
+ }
// Pair 11 is the palette, already loaded
// Pair 12 - Room Texts
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 5b14be2505d..030acd28b46 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -80,6 +80,7 @@ public:
~RoomManager();
void clearTalkingAnims();
void clearAnims();
+ void clearRoomStickerPixels();
void loadRoomMetadata(Common::File *roomFile, int roomNumber);
/**
* Passer by animations are animations of characters that merely traverse the scene as ambient
@@ -182,6 +183,7 @@ public:
byte *_conversationData = nullptr;
size_t _conversationDataSize = 0;
Common::Array<Sticker> _roomStickers;
+ Common::Array<byte *> _roomStickerPixelData;
uint32 _conversationOffset;
private:
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index e586f2dfa7f..3a47c21c8b0 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -448,7 +448,6 @@ struct Sticker {
uint16 y;
byte w;
byte h;
- byte *stickerData;
};
struct PaletteAnimRotate {
Commit: 6c8e9d1496c933572d973c6b9d6af9401a4cac70
https://github.com/scummvm/scummvm/commit/6c8e9d1496c933572d973c6b9d6af9401a4cac70
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:46+02:00
Commit Message:
PELROCK: Fix leak when loading game, and on conversation exit
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/saveload.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 302c9caa9a6..048b0174a4b 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -648,6 +648,7 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
if (!foundExpectedLevel) {
+ delete choices;
break;
}
}
@@ -673,6 +674,9 @@ void DialogManager::startConversation(const byte *conversationData, uint32 dataS
}
state.position = processChoiceSelection(conversationData, dataSize, choices, selectedIndex, state);
+ if (choices != _currentChoices) {
+ delete choices;
+ }
}
debug("Conversation ended");
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index b159da5e760..008d1356b50 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -366,6 +366,7 @@ void PelrockEngine::loadGame(SaveGameData &saveGame) {
_alfredState.x = saveGame.alfredX;
_alfredState.y = saveGame.alfredY;
_alfredState.direction = (AlfredDirection)saveGame.alfredDir;
+ delete _state;
_state = saveGame.gameState;
setScreenAndPrepare(saveGame.currentRoom, _alfredState.direction);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 3a47c21c8b0..5375dbc3fd6 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -153,7 +153,7 @@ struct AlfredSpecialAnim {
~AlfredSpecialAnim() {
if (animData) {
- free(animData);
+ delete[] animData;
animData = nullptr;
}
}
@@ -602,6 +602,7 @@ struct GameStateData {
}
~GameStateData() {
+ clearBranches();
delete[] conversationCurrentRoot;
conversationCurrentRoot = nullptr;
}
Commit: 5a73a5c07a07d13a5dd276e4af7bf1aff02b9c6e
https://github.com/scummvm/scummvm/commit/5a73a5c07a07d13a5dd276e4af7bf1aff02b9c6e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:46+02:00
Commit Message:
PELROCK: Fix error when converting offsets
Changed paths:
engines/pelrock/offsets.h
diff --git a/engines/pelrock/offsets.h b/engines/pelrock/offsets.h
index 2e5a66f8a6e..770032ee022 100644
--- a/engines/pelrock/offsets.h
+++ b/engines/pelrock/offsets.h
@@ -229,7 +229,7 @@ enum TextStringId {
// ALFRED.7 extra screen data (file offsets given per entry in extraScreens[])
static const ExtraScreen extraScreens[] = {
- {0x00007984, 0x000305A2, 8}, // 0 - Portrait above bed
+ {0x0000000, 0x0007984, 8}, // 0 - Portrait above bed
{0x001A9EE, 0x00305A2, 8}, // 1 - Computer screen
{0x00647C3, 0x007B6B1, 4}, // 2 - Alfred circle
{0x006FBCD, 0x007B6B1, 8}, // 3 - Recipe
@@ -237,13 +237,13 @@ static const ExtraScreen extraScreens[] = {
{0x009237B, 0x00B0EE7, 8}, // 5 - Tablet
{0x00B11F1, 0x00DE011, 8}, // 6 - Map
{0x00FFC47, 0x01180C9, 8}, // 7 - Girl book
- {0x118649, 0x135A13, 8}, // 8 - Unknown
- {0x152A88, 0x15BFC8, 8}, // 9 - Portrait
- {0x299E0C, 0x2B3C3C, 8}, // 10 - CD
- {0x2B3F1C, 0x2D5B18, 8}, // 11 - Pyramid map
- {0x232B1A, 0x237C28, 8}, // 12 - CENSORED
- {0x226358, 0x236AA8, 8}, // 13 - Background book
- {0x2EBD12, 0x309E40, 8} // 14 - Ending
+ {0x01183C9, 0x01358F3, 8}, // 8 - Spellbook
+ {0x0152A88, 0x015BFC8, 8}, // 9 - Portrait
+ {0x0299E8C, 0x02B3B7C, 8}, // 10 - CD
+ {0x02B3E7C, 0x02D5898, 8}, // 11 - Pyramid map
+ {0x02331EA, 0x0236AA8, 8}, // 12 - CENSORED
+ {0x0226358, 0x0236AA8, 8}, // 13 - Background book
+ {0x02EAA32, 0x0309A80, 8} // 14 - Ending
};
Commit: fab16d9824e78f09d90b63a2f68639798f01eef4
https://github.com/scummvm/scummvm/commit/fab16d9824e78f09d90b63a2f68639798f01eef4
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:47+02:00
Commit Message:
PELROCK: Consolidate drawColoredTexts functions in graphics
Changed paths:
engines/pelrock/graphics.cpp
engines/pelrock/graphics.h
engines/pelrock/spellbook.cpp
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index ec7637a4885..35157e4cbe9 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -149,41 +149,6 @@ void GraphicsManager::drawColoredText(Graphics::ManagedSurface *screen, const Co
}
}
-void GraphicsManager::drawColoredText(Graphics::ManagedSurface &buf, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font) {
-
- Graphics::Surface tempSurface;
- Common::Rect r = font->getBoundingBox(text); // Ensure font metrics are loaded before creating surface
-
- tempSurface.create(r.width(), r.height(), Graphics::PixelFormat::createFormatCLUT8());
-
- int currentX = x;
-
- Common::String segment;
- for (uint i = 0; i < text.size(); i++) {
- if (text[i] == '@' && i + 1 < text.size()) {
- // Draw accumulated segment
- if (!segment.empty()) {
- font->drawString(&tempSurface, segment, currentX, y, w, defaultColor);
- currentX += font->getStringWidth(segment);
- segment.clear();
- }
- defaultColor = text[i + 1];
- i++; // skip color code
- } else {
- segment += text[i];
- }
- }
-
- // Draw remaining segment
- if (!segment.empty()) {
- font->drawString(&tempSurface, segment, currentX, y, w, defaultColor);
- }
-
- // Use transBlitFrom to blit non-zero pixels
- buf.transBlitFrom(tempSurface, Common::Point(x, y), 0);
- tempSurface.free();
-}
-
void GraphicsManager::drawColoredTexts(Graphics::ManagedSurface *surface, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font) {
int currentX = x;
byte currentColor = 255;
@@ -193,15 +158,6 @@ void GraphicsManager::drawColoredTexts(Graphics::ManagedSurface *surface, const
}
}
-void GraphicsManager::drawColoredTexts(Graphics::ManagedSurface &buf, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font) {
- int currentX = x;
- byte currentColor = 255;
-
- for (uint i = 0; i < text.size(); i++) {
- drawColoredText(buf, text[i], currentX, y + i * (font->getFontHeight() + yPadding), w, currentColor, font);
- }
-}
-
void GraphicsManager::copyBackgroundToBuffer() {
g_engine->_compositeBuffer.blitFrom(g_engine->_currentBackground);
}
diff --git a/engines/pelrock/graphics.h b/engines/pelrock/graphics.h
index 2609c83d7fa..910c4d87eb2 100644
--- a/engines/pelrock/graphics.h
+++ b/engines/pelrock/graphics.h
@@ -46,9 +46,7 @@ public:
// Text rendering
void drawColoredText(Graphics::ManagedSurface *screen, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font);
- void drawColoredText(Graphics::ManagedSurface &buf, const Common::String &text, int x, int y, int w, byte &defaultColor, Graphics::Font *font);
void drawColoredTexts(Graphics::ManagedSurface *surface, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font);
- void drawColoredTexts(Graphics::ManagedSurface &buf, const Common::StringArray &text, int x, int y, int w, int yPadding, Graphics::Font *font);
// Frame / background management
void copyBackgroundToBuffer();
diff --git a/engines/pelrock/spellbook.cpp b/engines/pelrock/spellbook.cpp
index 50497244b30..83d023d31a5 100644
--- a/engines/pelrock/spellbook.cpp
+++ b/engines/pelrock/spellbook.cpp
@@ -122,13 +122,10 @@ void SpellBook::drawScreen() {
if (_spell != nullptr) {
drawSpriteToBuffer(_compositeScreen, _spell->image, 168, 143, 119, 99, 207);
- g_engine->_graphics->drawColoredTexts(_compositeScreen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
+ g_engine->_graphics->drawColoredTexts(&_compositeScreen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
}
g_engine->_screen->blitFrom(_compositeScreen);
- if (_spell != nullptr) {
- g_engine->_graphics->drawColoredTexts(g_engine->_screen, _spell->text, textX, textY, 640, 0, g_engine->_smallFont);
- }
}
void SpellBook::loadBackground() {
Commit: c1e9301f6b3ef53cae2c65b9e559de6cea72b114
https://github.com/scummvm/scummvm/commit/c1e9301f6b3ef53cae2c65b9e559de6cea72b114
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:47+02:00
Commit Message:
PELROCK: Make crocodile sprite stick in crocodile sequence
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 879fdef3099..57e72fa55f5 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1226,13 +1226,20 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
_alfredState.x -= 10;
_alfredState.y += 20;
playAlfredSpecialAnim(5);
+ {
+ // Copy crocodile into background so it sticks during fade
+ static const int srcX = 189, srcY = 260;
+ static const int copyW = 127, copyH = 80;
+ Common::Rect copyRect(srcX, srcY, srcX + copyW, srcY + copyH);
+ _currentBackground.blitFrom(_compositeBuffer, copyRect, Common::Point(srcX, srcY));
+ }
_alfredState.animState = ALFRED_SKIP_DRAWING;
_sound->playSound(_room->_roomSfx[0], 0); // Belch
waitForSoundEnd();
- _graphics->fadeToBlack(10);
+ _graphics->fadeToBlack(20);
+ _graphics->clearScreen();
_alfredState.x = 300;
_alfredState.y = 238;
- waitForSoundEnd();
_alfredState.animState = ALFRED_IDLE;
setScreenAndPrepare(28, ALFRED_DOWN);
_dialog->say(_res->_ingameTexts[kTextQueOscuroEstaEsto]);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 1508596e297..a7d0daa4989 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -2051,17 +2051,13 @@ void PelrockEngine::doExtraActions(int roomNumber) {
}
void PelrockEngine::pyramidCollapse() {
- // === Pyramid Collapse Sequence (Room 36 per-frame handler at 0x1098F) ===
- // Binary: sprite index 2 = collapse animation, sprite index 0 = NPC guard.
- // Original sprite table indices are offset by 2 from ScummVM indices due
- // to the 2 header sprite slots in the room data.
- // Hide NPC initially â binary sets sprite_2 field 0x21 = 0xFF (zOrder = 255)
+ // Hide NPC initially
Sprite *npc = _room->findSpriteByIndex(0);
if (npc)
npc->zOrder = 255;
- // Start collapse animation â binary sets sprite_4 field 0x21 = 0xFE (zOrder = 254)
+ // Start collapse animation
Sprite *collapseSprite = _room->findSpriteByIndex(2);
if (collapseSprite)
collapseSprite->zOrder = 254;
@@ -2069,8 +2065,7 @@ void PelrockEngine::pyramidCollapse() {
// Play collapse sound
_sound->playSound("QUAKE1ZZ.SMP", 0);
- // ----- PHASE 1: Wait for collapse animation frame 5 -----
- // Binary: loop sleep(0x69) + tick + render, check sprite_4 field 0x20 == 5
+ // Wait for collapse animation frame 5
while (!shouldQuit()) {
_events->pollEvent();
renderScene(OVERLAY_NONE);
@@ -2078,17 +2073,15 @@ void PelrockEngine::pyramidCollapse() {
g_system->delayMillis(10);
collapseSprite = _room->findSpriteByIndex(2);
if (!collapseSprite || collapseSprite->animData[collapseSprite->curAnimIndex].curFrame >= 5) {
- collapseSprite->zOrder = 255; // Hide collapse animation sprite after frame 5
+ collapseSprite->zOrder = 255; // Hide collapse animation sprite
break;
}
}
- debug("Collapse animation reached frame 5, applying background changes");
- // ----- PHASE 2: Background tile copies (hide pyramid top) -----
- // Copy 1: 99Ã45 from secondary buffer to front buffer (fills collapsed area)
+ // Background tile copies to have collapsed pyramid stick
+ // copy 99Ã45 from secondary buffer to front buffer
{
static const int srcX = 240, srcY = 145;
- // static const int dstX = 510, dstY = 33;
static const int copyW = 99, copyH = 45;
Common::Rect copyRect(srcX, srcY, srcX + copyW, srcY + copyH);
_currentBackground.blitFrom(_compositeBuffer, copyRect, Common::Point(srcX, srcY));
Commit: 920635b2f4a1ebb4407efd4cbaf2d475af22d168
https://github.com/scummvm/scummvm/commit/920635b2f4a1ebb4407efd4cbaf2d475af22d168
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:47+02:00
Commit Message:
PELROCK: Improvements on idle animation and screensaver minigame
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index a7d0daa4989..420ba41b810 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -77,10 +77,10 @@ PelrockEngine::~PelrockEngine() {
delete[] _inventoryOverlayState.arrows[0];
delete[] _inventoryOverlayState.arrows[1];
// Free path-finding buffers (allocated via malloc in findPath)
- if(_currentContext.pathBuffer) {
+ if (_currentContext.pathBuffer) {
free(_currentContext.pathBuffer);
}
- if(_currentContext.movementBuffer) {
+ if (_currentContext.movementBuffer) {
free(_currentContext.movementBuffer);
}
_saveThumbnail.free();
@@ -444,12 +444,12 @@ void PelrockEngine::maybeHaveDogPee() {
if (_room->_currentRoomNumber != 19) {
return;
}
- Sprite * dog = _room->findSpriteByIndex(2);
+ Sprite *dog = _room->findSpriteByIndex(2);
- if(_alfredState.x < 146 && !_isDogPeeing) {
+ if (_alfredState.x < 146 && !_isDogPeeing) {
_isDogPeeing = true;
dog->animData[0].nframes = 24;
- while(!shouldQuit() && dog->animData[0].curFrame < 23) {
+ while (!shouldQuit() && dog->animData[0].curFrame < 23) {
_events->pollEvent();
renderScene(OVERLAY_NONE);
@@ -631,7 +631,7 @@ void PelrockEngine::checkMouse() {
} else if (_inventoryOverlayState.isActive && _inventoryOverlayState.posInInventorySelectionArea(_events->_releaseX, _events->_releaseY)) {
int item = checkMouseClickInventoryOverlay(_events->_releaseX, _events->_releaseY);
_state->selectedInventoryItem = item;
- if(_actionPopupState.isAlfredUnder) {
+ if (_actionPopupState.isAlfredUnder) {
useOnAlfred(item);
} else if (_currentHotspot != nullptr) {
walkAndAction(_currentHotspot, ITEM);
@@ -760,11 +760,24 @@ void PelrockEngine::lookAt(HotSpot *hotspot) {
}
void PelrockEngine::chooseAlfredStateAndDraw() {
- if (_alfredState.idleFrameCounter++ >= kAlfredIdleAnimationFrameCount &&
- _alfredState.animState == ALFRED_IDLE &&
- (_alfredState.direction == ALFRED_LEFT || _alfredState.direction == ALFRED_RIGHT)) {
- _alfredState.idleFrameCounter = 0;
- _alfredState.setState(ALFRED_COMB);
+ if (_alfredState.animState != ALFRED_IDLE &&
+ _alfredState.animState != ALFRED_COMB // need to exclude comb so that screen saver can still engage
+ ) {
+ _alfredState.resetIdles(); // reset idle frame counter when not idle
+ } else {
+
+ if (_alfredState.idleFrameCounter++ >= kAlfredIdleAnimationFrameCount &&
+ _alfredState.animState == ALFRED_IDLE &&
+ (_alfredState.direction == ALFRED_LEFT || _alfredState.direction == ALFRED_RIGHT)) {
+ _alfredState.idleFrameCounter = 0;
+ _alfredState.setState(ALFRED_COMB);
+ }
+ if(_alfredState.screenSaverFrameCounter++ >= kAlfredIdleScreenSaverFrameCount &&
+ _alfredState.animState == ALFRED_IDLE) {
+ SlidingPuzzle slidingPuzzle(_events, _sound);
+ _alfredState.screenSaverFrameCounter = 0;
+ slidingPuzzle.run();
+ }
}
switch (_alfredState.animState) {
@@ -1189,7 +1202,7 @@ void PelrockEngine::paintDebugLayer() {
}
void PelrockEngine::checkLongMouseClick(int x, int y) {
- _alfredState.idleFrameCounter = 0;
+ _alfredState.resetIdles(); // reset idle frame counter on interaction
int hotspotIndex = isHotspotUnder(x, y);
bool alfredUnder = isAlfredUnder(x, y);
if ((hotspotIndex != -1 || alfredUnder) && !_actionPopupState.isActive) {
@@ -1308,7 +1321,7 @@ void PelrockEngine::showActionBalloon(int posx, int posy, int curFrame) {
if (_inventoryOverlayState.isActive) {
// find selectedInventoryItem index in inventoryItems, set invStartingPos to that index if found, otherwise 0
int scrollPos = getScrollPositionForItem(_state->selectedInventoryItem);
- if(_inventoryOverlayState.invStartingPos == -1) {
+ if (_inventoryOverlayState.invStartingPos == -1) {
_inventoryOverlayState.invStartingPos = scrollPos != -1 ? scrollPos : 0;
}
showInventoryOverlay();
@@ -1411,9 +1424,9 @@ void PelrockEngine::showInventoryOverlay() {
uint invSize = _state->inventoryItems.size();
// invStartingPos is an ITEM index (not a page number).
// The original game scrolls 1 item at a time, not 1 page at a time.
- if(_inventoryOverlayState.invStartingPos == -1) {
+ if (_inventoryOverlayState.invStartingPos == -1) {
_inventoryOverlayState.invStartingPos = getScrollPositionForItem(_state->selectedInventoryItem);
- if(_inventoryOverlayState.invStartingPos == -1) {
+ if (_inventoryOverlayState.invStartingPos == -1) {
_inventoryOverlayState.invStartingPos = 0;
}
}
@@ -1585,7 +1598,7 @@ void PelrockEngine::walkTo(int x, int y) {
}
void PelrockEngine::walkAndAction(HotSpot *hotspot, VerbIcon action) {
- if(hotspot == nullptr) {
+ if (hotspot == nullptr) {
return;
}
_disableAction = true;
@@ -1678,7 +1691,7 @@ void PelrockEngine::checkMouseClick(int x, int y) {
_queuedAction = QueuedAction{NO_ACTION, -1, false, false};
_actionPopupState.isActive = false;
_currentHotspot = nullptr;
- _alfredState.idleFrameCounter = 0;
+ _alfredState.resetIdles();
int hotspotIndex = isHotspotUnder(_events->_mouseX, _events->_mouseY);
bool isHotspotUnder = false;
if (hotspotIndex != -1) {
@@ -1696,7 +1709,7 @@ void PelrockEngine::changeCursor(Cursor cursor) {
}
void PelrockEngine::checkMouseHover() {
- if(_actionPopupState.isActive) {
+ if (_actionPopupState.isActive) {
return;
}
@@ -1853,7 +1866,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
case 24: {
_room->findSpriteByIndex(1)->numAnims = 1;
- if(_state->hasInventoryItem(88) && _state->getFlag(FLAG_PIGEON_DEAD) == false) {
+ if (_state->hasInventoryItem(88) && _state->getFlag(FLAG_PIGEON_DEAD) == false) {
_dialog->say(_res->_ingameTexts[kTextProbarLibro]);
playAlfredSpecialAnim(0);
Sprite *pigeons = _room->findSpriteByIndex(1);
@@ -1861,7 +1874,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
pigeons->curAnimIndex = 0;
pigeons->disableAfterSequence = true;
pigeons->animData[0].curFrame = 0;
- while(!g_engine->shouldQuit() && pigeons->zOrder != 255) {
+ while (!g_engine->shouldQuit() && pigeons->zOrder != 255) {
_events->pollEvent();
renderScene();
_screen->update();
@@ -2041,7 +2054,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
case 53:
case 54:
initGodsSequences(_room->_currentRoomNumber);
- if(roomNumber == 52) {
+ if (roomNumber == 52) {
_room->addStickerToRoom(52, 105);
}
break;
@@ -2303,7 +2316,7 @@ void PelrockEngine::credits() {
Common::Array<Common::StringArray> creditTexts = _res->getCredits();
Common::Array<int> creditsSpeakerId;
// Preprocess credit texts: extract speaker IDs and apply word wrapping
- for(uint i = 0; i < creditTexts.size(); i++) {
+ for (uint i = 0; i < creditTexts.size(); i++) {
byte speakerId;
_dialog->processColorAndTrim(creditTexts[i], speakerId);
creditsSpeakerId.push_back(speakerId);
@@ -2325,7 +2338,7 @@ void PelrockEngine::credits() {
for (int page = 0; page < kNumCreditPages && !shouldQuit(); page++) {
// loads screen
setScreen(kCreditRooms[page]);
- if(kCreditRooms[page] == 24) {
+ if (kCreditRooms[page] == 24) {
Sprite *pigeons = _room->findSpriteByIndex(1);
pigeons->disableAfterSequence = true;
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 5375dbc3fd6..1e59f830b86 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -84,7 +84,8 @@ const int kAlfredFrameHeight = 102;
const int kTalkAnimationSpeed = 2; // Frames per update
const int kAlfredAnimationSpeed = 2; // Frames per update
-const int kAlfredIdleAnimationFrameCount = 300;
+const int kAlfredIdleAnimationFrameCount = 300; // comb animation plays every ~16 seconds of idle alfred
+const int kAlfredIdleScreenSaverFrameCount = 1090; // screen saver shows up after 60 seconds
const int kInventoryPageSize = 10;
@@ -192,12 +193,18 @@ struct AlfredState {
byte w = kAlfredFrameWidth;
byte h = kAlfredFrameHeight;
int idleFrameCounter = 0;
+ int screenSaverFrameCounter = 0;
bool isWalkingCancelable = true;
void setState(AlfredAnimState nextState) {
animState = nextState;
curFrame = 0;
}
+
+ void resetIdles() {
+ idleFrameCounter = 0;
+ screenSaverFrameCounter = 0;
+ }
};
struct ShakeEffectState {
Commit: c2cf7a3d40e72ab81a3a6fb3e42954804ca2def8
https://github.com/scummvm/scummvm/commit/c2cf7a3d40e72ab81a3a6fb3e42954804ca2def8
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:48+02:00
Commit Message:
PELROCK: Fix scaling algorithm so feet arent cropped
Changed paths:
engines/pelrock/graphics.cpp
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index 35157e4cbe9..feaf410cb64 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -404,7 +404,7 @@ ScaleCalculation GraphicsManager::calculateScaling(int yPos, ScalingParams scali
}
byte *GraphicsManager::scale(int scaleY, int finalWidth, int finalHeight, byte *buf) {
- // The scaling table is indexed by how many scanlines to skip (scaleY), not by final height
+ // The table marks which source rows to skip: non-zero = skip.
int scaleIndex = scaleY;
if (scaleIndex >= (int)_heightScalingTable.size()) {
scaleIndex = _heightScalingTable.size() - 1;
@@ -412,69 +412,26 @@ byte *GraphicsManager::scale(int scaleY, int finalWidth, int finalHeight, byte *
if (scaleIndex < 0) {
scaleIndex = 0;
}
- int linesToSkip = kAlfredFrameHeight - finalHeight;
byte *finalBuf = new byte[finalWidth * finalHeight];
+ memset(finalBuf, 255, finalWidth * finalHeight);
- if (linesToSkip > 0) {
- int skipInterval = kAlfredFrameHeight / linesToSkip;
- Common::Array<float> idealSkipPositions;
- for (int i = 0; i < linesToSkip; i++) {
- float idealPos = (i + 0.5f) * skipInterval;
- idealSkipPositions.push_back(idealPos);
- }
-
- Common::Array<int> tableSkipPositions;
- for (int scanline = 0; scanline < kAlfredFrameHeight; scanline++) {
- if (_heightScalingTable[scaleIndex][scanline] != 0) {
- tableSkipPositions.push_back(scanline);
- }
- }
-
- Common::Array<int> skipTheseLines;
- for (size_t i = 0; i < idealSkipPositions.size(); i++) {
- float idealPos = idealSkipPositions[i];
- int closest = -1;
- int minDiff = INT32_MAX;
- for (size_t j = 0; j < tableSkipPositions.size(); j++) {
- int candidate = tableSkipPositions[j];
- int diff = static_cast<int>(abs(candidate - idealPos));
- if (diff < minDiff) {
- minDiff = diff;
- closest = candidate;
- }
- }
- if (closest != -1) {
- skipTheseLines.push_back(closest);
- }
- if (skipTheseLines.size() >= static_cast<size_t>(linesToSkip)) {
- break;
- }
- }
-
+ if (scaleIndex > 0) {
int outY = 0;
- for (int srcY = 0; srcY < kAlfredFrameHeight; srcY++) {
- bool skipLine = false;
- for (size_t skipIdx = 0; skipIdx < skipTheseLines.size(); ++skipIdx) {
- if (skipTheseLines[skipIdx] == srcY) {
- skipLine = true;
- break;
- }
+ for (int srcY = 0; srcY < kAlfredFrameHeight && outY < finalHeight; srcY++) {
+ // Skip rows where the height scaling table says to skip (non-zero value)
+ if (_heightScalingTable[scaleIndex][srcY] != 0) {
+ continue;
}
- if (!skipLine) {
- for (int outX = 0; outX < finalWidth; outX++) {
- int srcX = static_cast<int>(outX * kAlfredFrameWidth / finalWidth);
- if (srcX >= kAlfredFrameWidth) {
- srcX = kAlfredFrameWidth - 1;
- }
- int srcIndex = srcY * kAlfredFrameWidth + srcX;
- int outIndex = outY * finalWidth + outX;
- if (outIndex >= finalWidth * finalHeight || srcIndex >= kAlfredFrameWidth * kAlfredFrameHeight) {
- } else
- finalBuf[outIndex] = buf[srcIndex];
+
+ for (int outX = 0; outX < finalWidth; outX++) {
+ int srcX = outX * kAlfredFrameWidth / finalWidth;
+ if (srcX >= kAlfredFrameWidth) {
+ srcX = kAlfredFrameWidth - 1;
}
- outY++;
+ finalBuf[outY * finalWidth + outX] = buf[srcY * kAlfredFrameWidth + srcX];
}
+ outY++;
}
} else {
Common::copy(buf, buf + (kAlfredFrameWidth * kAlfredFrameHeight), finalBuf);
Commit: c1285621445640702e87a0806a58db9e55fdfb69
https://github.com/scummvm/scummvm/commit/c1285621445640702e87a0806a58db9e55fdfb69
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:48+02:00
Commit Message:
PELROCK: Add option to disable screensaver
Changed paths:
engines/pelrock/detection.h
engines/pelrock/detection_tables.h
engines/pelrock/metaengine.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/detection.h b/engines/pelrock/detection.h
index 921919f14e9..cffa9df0502 100644
--- a/engines/pelrock/detection.h
+++ b/engines/pelrock/detection.h
@@ -41,6 +41,7 @@ extern const ADGameDescription gameDescriptions[];
#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
#define GAMEOPTION_ALTERNATE_TIMING GUIO_GAMEOPTIONS2
#define GAMEOPTION_PLAY_INTRO GUIO_GAMEOPTIONS3
+#define GAMEOPTION_DISABLE_SCREENSAVER GUIO_GAMEOPTIONS4
} // End of namespace Pelrock
diff --git a/engines/pelrock/detection_tables.h b/engines/pelrock/detection_tables.h
index 57be38649ae..eb5c5c057cb 100644
--- a/engines/pelrock/detection_tables.h
+++ b/engines/pelrock/detection_tables.h
@@ -34,7 +34,7 @@ const ADGameDescription gameDescriptions[] = {
Common::ES_ESP,
Common::kPlatformDOS,
ADGF_UNSTABLE,
- GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_ALTERNATE_TIMING, GAMEOPTION_PLAY_INTRO)
+ GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_ALTERNATE_TIMING, GAMEOPTION_PLAY_INTRO, GAMEOPTION_DISABLE_SCREENSAVER)
},
AD_TABLE_END_MARKER
diff --git a/engines/pelrock/metaengine.cpp b/engines/pelrock/metaengine.cpp
index e44f3ab20cc..a6468fe0341 100644
--- a/engines/pelrock/metaengine.cpp
+++ b/engines/pelrock/metaengine.cpp
@@ -62,6 +62,17 @@ static const ADExtraGuiOptionsMap optionsList[] = {
0
}
},
+ {
+ GAMEOPTION_DISABLE_SCREENSAVER,
+ {
+ _s("Disable screensaver"),
+ _s("Disable original screensaver slider mini-game every 60 seconds."),
+ "disable_screensaver",
+ false,
+ 0,
+ 0
+ }
+ },
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 420ba41b810..52e6d53afcb 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -20,20 +20,14 @@
*/
#include "common/config-manager.h"
-#include "common/endian.h"
#include "common/events.h"
#include "common/file.h"
#include "common/scummsys.h"
-#include "common/system.h"
#include "engines/util.h"
#include "graphics/cursorman.h"
-#include "graphics/framelimiter.h"
#include "graphics/paletteman.h"
-#include "image/pcx.h"
-#include "image/png.h"
-
-#include "backends/audiocd/audiocd.h"
+#include "pelrock.h"
#include "pelrock/actions.h"
#include "pelrock/computer.h"
#include "pelrock/console.h"
@@ -98,7 +92,9 @@ bool PelrockEngine::isAlternateTiming() const {
return ConfMan.getBool("alternate_timing");
}
-// Common::Array<Common::Array<Common::String>> wordWrap(Common::String text);
+bool PelrockEngine::isScreenSaverDisabled() const {
+ return ConfMan.getBool("disable_screensaver");
+}
Common::Error PelrockEngine::run() {
// Initialize 320x200 paletted graphics mode
@@ -761,7 +757,7 @@ void PelrockEngine::lookAt(HotSpot *hotspot) {
void PelrockEngine::chooseAlfredStateAndDraw() {
if (_alfredState.animState != ALFRED_IDLE &&
- _alfredState.animState != ALFRED_COMB // need to exclude comb so that screen saver can still engage
+ _alfredState.animState != ALFRED_COMB // need to exclude comb so that screen saver can still engage
) {
_alfredState.resetIdles(); // reset idle frame counter when not idle
} else {
@@ -772,11 +768,13 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.idleFrameCounter = 0;
_alfredState.setState(ALFRED_COMB);
}
- if(_alfredState.screenSaverFrameCounter++ >= kAlfredIdleScreenSaverFrameCount &&
+ if (_alfredState.screenSaverFrameCounter++ >= kAlfredIdleScreenSaverFrameCount &&
_alfredState.animState == ALFRED_IDLE) {
- SlidingPuzzle slidingPuzzle(_events, _sound);
- _alfredState.screenSaverFrameCounter = 0;
- slidingPuzzle.run();
+ if (!isScreenSaverDisabled()) {
+ SlidingPuzzle slidingPuzzle(_events, _sound);
+ _alfredState.screenSaverFrameCounter = 0;
+ slidingPuzzle.run();
+ }
}
}
@@ -1492,60 +1490,8 @@ int PelrockEngine::checkMouseClickInventoryOverlay(int x, int y) {
}
void PelrockEngine::gameLoop() {
-
_events->pollEvent();
checkMouse();
-
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_m) {
- travelToEgypt();
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_n) {
- loadExtraScreenAndPresent(10);
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_p) {
- antiPiracyEffect();
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
-
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_w) {
- Computer computer(_events);
-
- computer.run();
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
-
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_e && _room->_currentRoomNumber == 52) {
- teleportToPrincess();
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
-
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_q) {
- endingScene();
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_u) {
- if (_room->_currentRoomNumber == 36) {
- pyramidCollapse();
- }
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- }
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_k) {
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- credits();
- }
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_v) {
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- SlidingPuzzle puzzle(_events, _sound);
- puzzle.run();
- }
-
- if (_events->_lastKeyEvent == Common::KeyCode::KEYCODE_h) {
- _events->_lastKeyEvent = Common::KeyCode::KEYCODE_INVALID;
- antiPiracyEffect();
- }
-
renderScene();
_screen->update();
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index cfcf45c4a99..82aa3e5c6ad 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -210,6 +210,8 @@ public:
*/
bool isAlternateTiming() const;
+ bool isScreenSaverDisabled() const;
+
bool hasFeature(EngineFeature f) const override {
return (f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime) ||
Commit: c849d9789c68be5088e30c6b3ced3faea400e968
https://github.com/scummvm/scummvm/commit/c849d9789c68be5088e30c6b3ced3faea400e968
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:48+02:00
Commit Message:
PELROCK: Cleanup of pelrock.cpp
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 52e6d53afcb..c371c83919f 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -174,19 +174,6 @@ void PelrockEngine::init() {
gameInitialized = true;
loadAnims();
setScreenAndPrepare(0, ALFRED_DOWN);
- // setScreenAndPrepare(36, ALFRED_LEFT);
-
- // setScreen(3, ALFRED_RIGHT);
- // setScreen(22, ALFRED_DOWN);
- // setScreen(41, ALFRED_DOWN);
- // setScreen(43, ALFRED_DOWN);
- // setScreen(46, ALFRED_RIGHT);
- // setScreen(0, ALFRED_DOWN);
- // setScreen(52, ALFRED_DOWN);
- // setScreen(15, ALFRED_DOWN);
- // setScreen(2, ALFRED_LEFT);
- // _alfredState.x = 576;
- // alfredState.y = 374;
}
loadInventoryArrows();
@@ -198,7 +185,7 @@ void PelrockEngine::loadInventoryArrows() {
error("Failed to open ALFRED.7 to load inventory arrows");
return;
}
- alfred7.seek(kInventoryArrowsOffset, SEEK_SET); // Inventory arrows in ALFRED.7
+ alfred7.seek(kInventoryArrowsOffset, SEEK_SET);
_inventoryOverlayState.arrows[0] = new byte[20 * 60];
_inventoryOverlayState.arrows[1] = new byte[20 * 60];
alfred7.read(_inventoryOverlayState.arrows[0], 20 * 60);
@@ -243,7 +230,7 @@ Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
Common::Point getPositionInBallonForIndex(int i);
-// Sort sprites by zOrder in-place using insertion sort (efficient for nearly-sorted data)
+// Sort sprites by zOrder in-place
void sortAnimsByZOrder(Common::Array<Sprite> &anims) {
for (size_t i = 0; i < anims.size(); ++i) {
Sprite key = anims[i];
@@ -255,10 +242,6 @@ void sortAnimsByZOrder(Common::Array<Sprite> &anims) {
}
anims[j] = key;
}
- // debug("Sorted anims by zOrder");
- // for (size_t i = 0; i < anims.size(); i++) {
- // debug("Anim %d, extra = %d: zOrder=%d", i, anims[i].extra, anims[i].zOrder);
- // }
}
void PelrockEngine::playSoundIfNeeded() {
@@ -281,6 +264,9 @@ void PelrockEngine::playSoundIfNeeded() {
}
}
+/**
+ * Travel to egypt sequence loads extra screen, plays palette animation then loads room 21
+ */
void PelrockEngine::travelToEgypt() {
_graphics->fadeToBlack(10);
@@ -328,13 +314,17 @@ void PelrockEngine::travelToEgypt() {
// Original gives 4 items after room load (items 17, 64, 24, 59)
_state->inventoryItems.clear();
_state->selectedInventoryItem = -1;
- // we dont want a flashing animation in this case!
+ // we dont want a flashing animation in this case! calling state->addInventory directly
_state->addInventoryItem(17);
_state->addInventoryItem(64);
_state->addInventoryItem(24);
_state->addInventoryItem(59);
}
+/**
+ * Original would skip fram ticks during walking & talking
+ * Alternate timing avoids this.
+ */
bool PelrockEngine::shouldSkipFrame() {
if (isAlternateTiming()) {
return false; // never skip frames in alternate timing mode
@@ -403,9 +393,9 @@ bool PelrockEngine::renderScene(int overlayMode) {
switch (_room->_currentRoomNumber) {
case 2: {
+ // Easter egg in room 2, pressing x 250 times after the character has mentioned it triggers a special dialog
if (_events->_lastKeyEvent == Common::KEYCODE_x) {
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
- debug("Pressed X in room 2, numPressedX is now %d, flag is %d", _numPressedX + 1, _state->getFlag(FLAG_PUTA_250_VECES));
if (_state->getFlag(FLAG_PUTA_250_VECES) == true) {
_numPressedX++;
if (_numPressedX == 250) {
@@ -429,12 +419,15 @@ void PelrockEngine::mouseHoverForMap() {
void PelrockEngine::frameTriggers() {
uint32 frameCount = _chrono->getFrameCount();
- passerByAnim(frameCount);
+ maybeUpdatePasserByAnim(frameCount);
handleFightRoomFrame();
- shakeEffect();
+ maybeShakeEffect();
maybeHaveDogPee();
}
+/**
+ * Dog pees in room 19 only when alfred gets close.
+ */
void PelrockEngine::maybeHaveDogPee() {
if (_room->_currentRoomNumber != 19) {
@@ -480,22 +473,21 @@ void PelrockEngine::maybePlayPostIntro() {
_alfredState.direction = ALFRED_DOWN;
_alfredState.x = kAlfredInitialPosX;
_alfredState.y = kAlfredInitialPosY;
- // setScreenAndPrepare(0, ALFRED_DOWN);
_dialog->say(_res->_ingameTexts[kTextMensajeOtraEpoca]);
}
}
-void PelrockEngine::shakeEffect() {
+void PelrockEngine::maybeShakeEffect() {
if (!_shakeEffectState.enabled) {
return;
}
_shakeEffectState.shakeX = (_chrono->getFrameCount() % 4 < 2) ? 2 : -2;
g_system->setShakePos(_shakeEffectState.shakeX, _shakeEffectState.shakeY);
- _alfredState.x += (_shakeEffectState.shakeX / 2); // Adjust Alfred's position to counteract shake for better readability
+ _alfredState.x += (_shakeEffectState.shakeX / 2);
}
-void PelrockEngine::passerByAnim(uint32 frameCount) {
+void PelrockEngine::maybeUpdatePasserByAnim(uint32 frameCount) {
if (_room->_passerByAnims == nullptr) {
return;
}
@@ -505,7 +497,6 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
if ((frameCount & anim.frameTrigger) == anim.frameTrigger) {
Sprite *sprite = _room->findSpriteByIndex(anim.spriteIndex);
if (sprite && sprite->zOrder == 255) {
- debug("Starting passerby anim for sprite %d at index %d", anim.spriteIndex, animIndex);
sprite->zOrder = anim.targetZIndex;
sprite->curAnimIndex = 0;
sprite->animData[0].curFrame = 0;
@@ -521,10 +512,8 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
int spriteIndex = anim.spriteIndex;
int startX = anim.startX;
int startY = anim.startY;
- // debug("Checking passerby anim %d for sprite %d, direction %d", _room->_passerByAnims->currentAnimIndex, spriteIndex, direction);
Sprite *sprite = _room->findSpriteByIndex(spriteIndex);
if (direction == kPasserbyRight) {
- // debug("Checking passerby anim for sprite %d moving RIGHT, curpos is %d", spriteIndex, sprite->x);
if (sprite->x >= anim.resetCoord) {
sprite->x = startX;
sprite->y = startY;
@@ -534,7 +523,6 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
_room->_passerByAnims->latch = false;
}
} else if (direction == kPasserbyLeft) {
- // debug("Checking passerby anim for sprite %d moving LEFT, curpos is %d", spriteIndex, sprite->x);
if (sprite->x <= anim.resetCoord) {
sprite->x = startX;
@@ -545,7 +533,6 @@ void PelrockEngine::passerByAnim(uint32 frameCount) {
_room->_passerByAnims->latch = false;
}
} else if (direction == kPasserbyDown) {
- // debug("Checking passerby anim for sprite %d moving DOWN, curpos is %d, reset %d", spriteIndex, sprite->y, anim.resetCoord);
if (sprite->y >= anim.resetCoord) {
sprite->x = startX;
sprite->y = startY;
@@ -568,7 +555,6 @@ void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
}
}
noOpItem(inventoryObject, hotspot);
- warning("No handler for using inventory object %d with hotspot %d", inventoryObject, hotspot->extra);
return;
}
@@ -588,7 +574,7 @@ void PelrockEngine::executeAction(VerbIcon action, HotSpot *hotspot) {
}
}
- // No handler found
+ // No handler found - should never get to this point
warning("No handler for hotspot %d with action %d", hotspot->extra, action);
}
@@ -611,6 +597,7 @@ void PelrockEngine::checkMouse() {
_alfredState.curFrame = 0;
_alfredState.setState(ALFRED_IDLE);
}
+
// Handle mouse release after long press (popup selection mode)
if (_events->_popupSelectionMode && !_events->_leftMouseButton) {
_events->_leftMouseButton = false;
@@ -668,7 +655,6 @@ void PelrockEngine::updateAnimations() {
// First pass: sprites behind Alfred (sprite zOrder > alfredZOrder)
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].zOrder > alfredZOrder || _room->_currentRoomAnims[i].zOrder == 255) {
- // debug("Drawing anim %d with zOrder %d in first pass (behind Alfred)", i, _room->_currentRoomAnims[i].zOrder);
drawNextFrame(&_room->_currentRoomAnims[i]);
}
}
@@ -679,7 +665,6 @@ void PelrockEngine::updateAnimations() {
// Second pass: sprites in front of Alfred (sprite zOrder <= alfredZOrder)
for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
if (_room->_currentRoomAnims[i].zOrder <= alfredZOrder && _room->_currentRoomAnims[i].zOrder != 255) {
- // debug("Drawing anim %d with zOrder %d in second pass (in front of Alfred)", i, _room->_currentRoomAnims[i].zOrder);
drawNextFrame(&_room->_currentRoomAnims[i]);
}
}
@@ -852,10 +837,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.x = exit->targetX;
_alfredState.y = exit->targetY;
setScreenAndPrepare(exit->targetRoom, exit->dir);
- // setScreen() resets the composite buffer to the bare background;
- // place first-pass stickers now so they are present in the very
- // first presentFrame() for the new room (avoids a one-frame flash
- // without stickers).
_graphics->placeStickersFirstPass();
}
}
@@ -867,7 +848,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.curFrame = 0;
}
if (_alfredState.animState == ALFRED_WALKING) { // in case it changed to idle above
- debug("Drawing crawl frame %d for direction %d", _alfredState.curFrame, _alfredState.direction);
drawSpriteToBuffer(_compositeBuffer, _res->alfredCrawlFrames[_alfredState.direction][_alfredState.curFrame], _alfredState.x, _alfredState.y - 55, 130, 55, 255);
_alfredState.curFrame++;
}
@@ -950,6 +930,9 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
}
}
+/**
+ * Triggers upon exiting certain rooms, namely exit animations (like climbing a ladder)
+ */
void PelrockEngine::exitTriggers(Pelrock::Exit *exit) {
if (exit->targetRoom == 31 && _room->_currentRoomNumber == 32) {
_res->loadAlfredSpecialAnim(8);
@@ -1015,8 +998,6 @@ void PelrockEngine::drawAlfred(byte *buf) {
_alfredSprite = scaledBuf;
// Shadow detection: scan across Alfred's width at feet line.
- // Original game scans shadow buffer
- // at (topY + 0x66) * 640 + X + col for col = 0..width, where topY + 0x66 = feetY.
// The shadow map value (0-3) indexes into the palette remap tables.
if (_room->_pixelsShadows != nullptr) {
byte shadowLevel = 0xFF; // 0xFF = no shadow
@@ -1028,7 +1009,7 @@ void PelrockEngine::drawAlfred(byte *buf) {
byte shadowVal = _room->_pixelsShadows[feetY * 640 + checkX];
if (shadowVal != 0xFF) {
shadowLevel = shadowVal;
- break; // Original breaks on first shadow pixel found
+ break;
}
}
}
@@ -1038,7 +1019,6 @@ void PelrockEngine::drawAlfred(byte *buf) {
for (int i = 0; i < finalWidth * finalHeight; i++) {
if (_alfredSprite[i] != 255) {
_alfredSprite[i] = _room->_paletteRemaps[shadowLevel][_alfredSprite[i]];
- // _alfredSprite[i] = _room->_paletteRemaps[0][_alfredSprite[i]];
}
}
}
@@ -1054,6 +1034,9 @@ void PelrockEngine::drawAlfred(byte *buf) {
}
}
+/**
+ * displace sprites in accordance to the movement flags
+ */
void applyMovement(int16 *x, int16 *y, byte *z, uint16 flags) {
// X-axis movement
if (flags & 0x10) { // Bit 4: X movement enabled
@@ -1089,7 +1072,7 @@ void applyMovement(int16 *x, int16 *y, byte *z, uint16 flags) {
void PelrockEngine::drawNextFrame(Sprite *sprite) {
Anim &animData = sprite->animData[sprite->curAnimIndex];
if (sprite->zOrder == 255) {
- // Skip disabled sprites (zOrder 0xFF = disabled in original game)
+ // Skip disabled sprites
return;
}
@@ -1105,7 +1088,6 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
int curFrame = animData.curFrame;
if (curFrame >= animData.nframes) {
- debug("Warning: curFrame %d exceeds nframes %d for sprite %d anim %d", curFrame, animData.nframes, sprite->index, sprite->curAnimIndex);
curFrame = 0;
}
drawSpriteToBuffer(_compositeBuffer, animData.animData[curFrame], x, y, w, h, 255);
@@ -1130,7 +1112,7 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
if (sprite->curAnimIndex < sprite->numAnims - 1) {
sprite->curAnimIndex++;
- // Trigger ring on phone on every start of animation 2
+ // Trigger ring on phone on every start of animation 2 in room 9
if (_room->_currentRoomNumber == 9 && sprite->index == 3) {
if (sprite->curAnimIndex == 1 && animData.curLoop == 0) {
byte soundFileIndex = _room->_roomSfx[2];
@@ -1411,7 +1393,7 @@ Common::Point getPositionInOverlayForIndex(uint index) {
void PelrockEngine::pickupIconFlash() {
uint invSize = _state->inventoryItems.size();
- // focus on the last positionin the inventory, where the newly picked up item would be, if there is at least 1 item in the inventory
+ // focus on the last position in the inventory, where the newly picked up item would be, if there is at least 1 item in the inventory
_inventoryOverlayState.invStartingPos = getScrollPositionForItem(_state->inventoryItems[invSize - 1]);
_inventoryOverlayState.flashingIconIndex = invSize - 1;
showInventoryOverlay();
@@ -1421,7 +1403,7 @@ void PelrockEngine::showInventoryOverlay() {
_graphics->showOverlay(60, _compositeBuffer);
uint invSize = _state->inventoryItems.size();
// invStartingPos is an ITEM index (not a page number).
- // The original game scrolls 1 item at a time, not 1 page at a time.
+ // Scrolls 1 item at a time, not 1 page at a time.
if (_inventoryOverlayState.invStartingPos == -1) {
_inventoryOverlayState.invStartingPos = getScrollPositionForItem(_state->selectedInventoryItem);
if (_inventoryOverlayState.invStartingPos == -1) {
@@ -1448,26 +1430,20 @@ void PelrockEngine::showInventoryOverlay() {
}
void PelrockEngine::checkMouseOverInventoryOverlay(int x, int y) {
- // Original game: invStartingPos is an item index, scrolls 1 item per frame
- // with no frame throttling (scrolls every game tick = ~55ms).
if (x < 20) {
if (_inventoryOverlayState.invStartingPos > 0) {
_inventoryOverlayState.invStartingPos--;
}
- debug("Mouse at x=%d triggers scroll left, new invStartingPos=%d", x, _inventoryOverlayState.invStartingPos);
} else if (x >= 620) {
if (_inventoryOverlayState.invStartingPos + kInventoryPageSize < (int)_state->inventoryItems.size()) {
_inventoryOverlayState.invStartingPos++;
}
- debug("Mouse at x=%d triggers scroll right, new invStartingPos=%d", x, _inventoryOverlayState.invStartingPos);
} else {
// mouse hover over inventory item, laid out horizontally, y coordinate is not relevant
int index = (x - 20) / 60 + _inventoryOverlayState.invStartingPos;
if (index < (int)_state->inventoryItems.size()) {
- debug("hovering over inventory item %d at index %d", _state->inventoryItems[index], index);
_inventoryOverlayState.flashingIconIndex = index;
} else {
- debug("hovering over empty slot in inventory overlay, no item at index %d", index);
_inventoryOverlayState.flashingIconIndex = -1;
}
}
@@ -1534,7 +1510,6 @@ void PelrockEngine::walkLoop(int16 x, int16 y, AlfredDirection direction) {
_screen->update();
g_system->delayMillis(10);
}
- debug("Walk loop ended");
}
void PelrockEngine::walkTo(int x, int y) {
@@ -1598,9 +1573,7 @@ AlfredDirection PelrockEngine::calculateAlfredsDirection(HotSpot *hotspot) {
}
VerbIcon PelrockEngine::isActionUnder(int x, int y) {
- /*if (_currentHotspot == nullptr) {
- return NO_ACTION;
- }*/
+
Common::Array<VerbIcon> actions = availableActions(_currentHotspot);
uint loopEnd = _state->selectedInventoryItem != -1 ? actions.size() + 1 : actions.size();
for (uint i = 0; i < loopEnd; i++) {
@@ -1927,16 +1900,6 @@ void PelrockEngine::doExtraActions(int roomNumber) {
// paths lead to capture, no voluntary exit allowed.
_dialog->_goodbyeDisabled = true;
break;
- case 10: {
- // _events->waitForKey();
- // while(!shouldQuit()) {
- // playSpecialAnim(212915, true, 287, 152, 62, 58, 10);
- // playSpecialAnim(236645, true, 287, 152, 62, 58, 10);
- // // setScreen(11, ALFRED_DOWN);
- // playSpecialAnim(261449, true, 0, 223, 64, 97, 8);
- // }
- break;
- }
case 48: {
_dialog->_goodbyeDisabled = true;
@@ -1974,7 +1937,6 @@ void PelrockEngine::doExtraActions(int roomNumber) {
} else {
_dialog->say(_res->_ingameTexts[kTextOhMiSalvador]);
_dialog->say(_res->_ingameTexts[kTextVoyPoriPrincesa]);
- // _state->setCurrentRoot(48, 0, 1);
HotSpot *fatMummy = nullptr;
for (uint i = 0; i < _room->_currentRoomHotspots.size(); i++) {
if (_room->_currentRoomHotspots[i].isSprite && _room->_currentRoomHotspots[i].index == 1) {
@@ -2386,17 +2348,14 @@ void PelrockEngine::handleFightRoomFrame() {
// Phase 2: spell trigger at tick 104 (64 + 40)
if (_fightSorcererAppeared && !_fightSpellCast && _fightFrameCounter >= 104) {
- debug("spell cast triggered for room %d at frame %d", room, _fightFrameCounter);
_fightSpellCast = true;
_fightSpellFrameCounter = 0;
}
// Phase 3: wait 40 ticks after spell trigger, then cast
if (_fightSpellCast) {
- debug("in spell cast phase for room %d at frame %d", room, _fightFrameCounter);
_fightSpellFrameCounter++;
if (_fightSpellFrameCounter >= 40 && !(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) & (1 << idx))) {
- debug("spell cast animation starting for room %d at frame %d, flag is %d", room, _fightFrameCounter, _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES));
_fightInBlockingAnim = true;
int spellFrames = kFightRooms[idx].spellFrames;
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 82aa3e5c6ad..c4fe4a00d4e 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -257,11 +257,11 @@ public:
void frameTriggers();
void maybeHaveDogPee();
void maybePlayPostIntro();
- void shakeEffect();
+ void maybeShakeEffect();
void handleFightRoomFrame();
void paintDebugLayer();
- void passerByAnim(uint32 frameCount);
+ void maybeUpdatePasserByAnim(uint32 frameCount);
void changeCursor(Cursor cursor);
void travelToEgypt();
Commit: d7b1739e883685b4063eddabb34d57183ba6f20e
https://github.com/scummvm/scummvm/commit/d7b1739e883685b4063eddabb34d57183ba6f20e
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:49+02:00
Commit Message:
PELROCK: Fix sticker in egyptian museum door
Changed paths:
engines/pelrock/actions.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 57e72fa55f5..c9eaa2793f8 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1345,11 +1345,11 @@ void PelrockEngine::pickupCondoms(HotSpot *hotspot) {
}
void PelrockEngine::openEgyptMuseumDoor(HotSpot *hotspot) {
- openDoor(hotspot, 0, 59, MASCULINE, false);
+ openDoor(hotspot, 0, 68, MASCULINE, false);
}
void PelrockEngine::closeEgyptMuseumDoor(HotSpot *hotspot) {
- closeDoor(hotspot, 0, 59, MASCULINE, false);
+ closeDoor(hotspot, 0, 68, MASCULINE, false);
}
void PelrockEngine::pushSymbol1(HotSpot *hotspot) {
Commit: 9c2bfd6fb03a2fa03614add6f473ef046025a0d7
https://github.com/scummvm/scummvm/commit/9c2bfd6fb03a2fa03614add6f473ef046025a0d7
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:49+02:00
Commit Message:
PELROCK: Set extra flags in case they are needed
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index c9eaa2793f8..a0cbf6d9186 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -585,6 +585,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 297: {
// sprite moves to right
_room->enableExit(0);
+ _state->setFlag(FLAG_VIGILANTE_PAJEANDOSE, true);
Sprite *sprite = _room->findSpriteByIndex(0);
sprite->animData[0].movementFlags = 0x1C; // Move right
// Basic loop to wait until the sprite has reached the door
@@ -948,7 +949,7 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[kTextQueHaSidoEso], x, dialog1y);
_dialog->say(_res->_ingameTexts[kTextQuienAndaAhi], x, dialog2y);
_dialog->say(_res->_ingameTexts[kTextYoMeVoy]);
-
+ _state->setFlag(FLAG_HE_TIRADO_PIEDRA, true);
_state->setFlag(FLAG_TIENDA_ABIERTA, true);
_room->addStickerToRoom(_room->_currentRoomNumber, 9, PERSIST_PERM);
_room->addStickerToRoom(_room->_currentRoomNumber, 10, PERSIST_PERM);
@@ -1389,6 +1390,7 @@ void PelrockEngine::checkAllSymbols() {
if (symbolsPulled == 0x0F) {
// Activates animation
_sound->playSound(_room->_roomSfx[0]);
+ _state->setFlag(FLAG_PUERTA_SECRETA_ABIERTA, true);
_room->enableSprite(4, 100, PERSIST_TEMP);
_room->enableExit(0, PERSIST_BOTH);
_room->addSticker(61);
@@ -1674,6 +1676,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
_screen->update();
g_system->delayMillis(10);
}
+ _state->setFlag(FLAG_APARECE_EUNUCO, true);
Sprite *guard = _room->findSpriteByIndex(0);
guard->animData[0].movementFlags = 0x14;
while (!shouldQuit()) {
@@ -1700,6 +1703,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
_alfredState.x = 271;
_alfredState.y = 385;
setScreenAndPrepare(40, ALFRED_UP);
+ _state->setFlag(FLAG_AL_FARAON, true);
walkAndAction(_room->findHotspotByExtra(640), TALK);
if (shouldQuit()) {
return;
@@ -1707,6 +1711,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
_graphics->fadeToBlack(10);
_alfredState.x = 271;
_alfredState.y = 385;
+ _state->setFlag(FLAG_A_CURRAR, true);
setScreenAndPrepare(41, ALFRED_UP);
}
@@ -1782,6 +1787,7 @@ void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
_state->setFlag(FLAG_FORMULA_MAGICA, _state->getFlag(FLAG_FORMULA_MAGICA) + 1);
if (_state->getFlag(FLAG_FORMULA_MAGICA) == 4) {
smokeAnimation(-1);
+ _state->setFlag(FLAG_VIAJA_AL_PASADO, true);
_alfredState.setState(ALFRED_IDLE);
_state->clearInventory();
_state->addInventoryItem(88);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index c371c83919f..83b99c4ae0a 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -268,6 +268,7 @@ void PelrockEngine::playSoundIfNeeded() {
* Travel to egypt sequence loads extra screen, plays palette animation then loads room 21
*/
void PelrockEngine::travelToEgypt() {
+ _state->setFlag(FLAG_VIAJE_A_EGIPTO, true);
_graphics->fadeToBlack(10);
_sound->playMusicTrack(26, false);
@@ -1932,6 +1933,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_alfredState.x = 294;
_alfredState.y = 387;
_room->addSticker(136);
+ _state->setFlag(FLAG_A_LOS_PASILLOS, true);
setScreenAndPrepare(49, ALFRED_UP);
} else {
@@ -1949,6 +1951,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
walkAndAction(fatMummy, TALK);
_state->clear();
+ _state->setFlag(FLAG_VUELTA_A_EMPEZAR, true);
_alfredState.x = kAlfredInitialPosX;
_alfredState.y = kAlfredInitialPosY;
_graphics->fadeToBlack(20);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 1e59f830b86..1fa31e0e72b 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -530,27 +530,42 @@ struct ResetEntry {
#define FLAG_ALFRED_INTELIGENTE 9
#define FLAG_ALFRED_SABE_EGIPCIO 10
#define FLAG_VENDEDOR_DEJA_DE_JODER 11
+#define FLAG_VIAJE_A_EGIPTO 12
#define FLAG_PARADOJA_RESUELTA 13
-#define FLAG_MIRA_SIMBOLO_FUERA_MUSEO 15
#define FLAG_CROCODILLO_ENCENDIDO 14
-#define FLAG_CLAVE_CAJA_FUERTE 19
+#define FLAG_MIRA_SIMBOLO_FUERA_MUSEO 15
+#define FLAG_PUERTA_SECRETA_ABIERTA 16
#define FLAG_ROBA_PELO_PRINCESA 17
#define FLAG_A_LA_CARCEL 18
+#define FLAG_CLAVE_CAJA_FUERTE 19
#define FLAG_SE_HA_PUESTO_EL_MUNECO 20
#define FLAG_VIGILANTE_BEBE_AGUA 21
#define FLAG_VIGILANTE_MEANDO 22
#define FLAG_PIRAMIDE_JODIDA 23
#define FLAG_PIRAMIDE_JODIDA2 24
+#define FLAG_VIGILANTE_PAJEANDOSE 25
#define FLAG_FORMULA_MAGICA 26
+#define FLAG_VIAJA_AL_PASADO 27
+#define FLAG_APARECE_EUNUCO 28
+#define FLAG_AL_FARAON 29
+#define FLAG_A_CURRAR 30
#define FLAG_DA_PIEDRA 31
#define FLAG_PIEDRAS_COGIDAS 32
#define FLAG_GUARDIAS_BORRACHOS 33
#define FLAG_PIEDRA_FAKE_MOJADA 34
#define FLAG_PUERTA_BUENA 35
#define FLAG_TRAMPILLA_ABIERTA 36
+#define FLAG_HABITACION_PRINCESA 37
+#define FLAG_A_POR_LA_PRINCESA 38
+#define FLAG_VUELTA_A_EMPEZAR 39
+#define FLAG_A_LOS_PASILLOS 40
#define FLAG_COMO_ESTAN_LOS_DIOSES 41
-#define FLAG_TIENDA_ABIERTA 46
#define FLAG_END_OF_GAME 42
+#define FLAG_FROM_INTRO 43
+#define FLAG_HE_TIRADO_PIEDRA 44
+#define FLAG_HA_USADO_AGUA 45
+#define FLAG_TIENDA_ABIERTA 46
+#define FLAG_NUMERO_DE_COPAS 47
#define FLAG_INGREDIENTES_CONSEGUIDOS 48
#define FLAG_GUARDIA_PIDECOSAS 49
#define FLAG_GUARDIA_DNI_ENTREGADO 50
@@ -564,23 +579,6 @@ struct ResetEntry {
#define FLAG_MERCHANT_GIVENITEMS 58
#define FLAG_CORRECT_DOOR_CHOSEN 59
#define FLAG_ESQUELETO_RECONOCE 60
-
-#define FLAG_VIAJE_A_EGIPTO 12
-#define FLAG_PUERTA_SECRETA_ABIERTA 16
-#define FLAG_VIGILANTE_PAJEANDOSE 25
-#define FLAG_VIAJA_AL_PASADO 27
-#define FLAG_APARECE_EUNUCO 28
-#define FLAG_AL_FARAON 29
-#define FLAG_A_CURRAR 30
-
-#define FLAG_HABITACION_PRINCESA 37
-#define FLAG_A_POR_LA_PRINCESA 38
-#define FLAG_VUELTA_A_EMPEZAR 39
-#define FLAG_A_LOS_PASILLOS 40
-#define FLAG_FROM_INTRO 43
-#define FLAG_HE_TIRADO_PIEDRA 44
-#define FLAG_HA_USADO_AGUA 45
-#define FLAG_NUMERO_DE_COPAS 47
#define FLAG_PIGEON_DEAD 61
#define FLAG_RECIPE_TAKEN 62
Commit: e37bc9064d438f44b6edc9f0d47b304559b69f41
https://github.com/scummvm/scummvm/commit/e37bc9064d438f44b6edc9f0d47b304559b69f41
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:49+02:00
Commit Message:
PELROCK: Translate flag names into English (from the original Spanish)
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index a0cbf6d9186..dab0464714c 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -304,10 +304,10 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 329:
- _state->setFlag(FLAG_PUTA_250_VECES, true);
+ _state->setFlag(FLAG_HOOKER_250_TIMES, true);
break;
case 258:
- _state->setFlag(FLAG_GUARDIA_PIDECOSAS, true);
+ _state->setFlag(FLAG_GUARD_ASKS_FOR_STUFF, true);
_state->setCurrentRoot(4, 2, 0);
break;
case 259:
@@ -341,6 +341,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 273: {
+ _state->setFlag(FLAG_SALESMAN_LEAVES_ALFRED_ALONE, true);
WalkBox w1 = {3, 436, 356, 4, 14, 0};
WalkBox w2 = {4, 440, 368, 148, 2, 0};
@@ -355,7 +356,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
case 277:
_state->setCurrentRoot(room, rootIndex + 1, 0);
- _state->setFlag(FLAG_JEFE_INGRESA_PASTA, true);
+ _state->setFlag(FLAG_BOSS_WIRED_MONEY, true);
break;
case 278:
_state->setCurrentRoot(room, rootIndex + 1, 0);
@@ -411,14 +412,14 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
}
case 349:
- _state->setFlag(FLAG_CONSIGNAS_VENDEDOR, _state->getFlag(FLAG_CONSIGNAS_VENDEDOR) + 1);
- if (_state->getFlag(FLAG_CONSIGNAS_VENDEDOR) == 2) {
+ _state->setFlag(FLAG_MERCHANT_SLOGANS, _state->getFlag(FLAG_MERCHANT_SLOGANS) + 1);
+ if (_state->getFlag(FLAG_MERCHANT_SLOGANS) == 2) {
_state->setCurrentRoot(room, rootIndex + 1, 1);
}
break;
case 350:
- _state->setFlag(FLAG_CONSIGNAS_VENDEDOR, _state->getFlag(FLAG_CONSIGNAS_VENDEDOR) + 1);
- if (_state->getFlag(FLAG_CONSIGNAS_VENDEDOR) == 2) {
+ _state->setFlag(FLAG_MERCHANT_SLOGANS, _state->getFlag(FLAG_MERCHANT_SLOGANS) + 1);
+ if (_state->getFlag(FLAG_MERCHANT_SLOGANS) == 2) {
_state->setCurrentRoot(room, rootIndex + 1, 1);
}
break;
@@ -475,33 +476,33 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 357: // wrong answer: counter-- (min 0)
{
- if (_state->getFlag(FLAG_RESPUESTAS_ACERTADAS) > 0) {
- _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) - 1);
+ if (_state->getFlag(FLAG_CORRECT_ANSWERS) > 0) {
+ _state->setFlag(FLAG_CORRECT_ANSWERS, _state->getFlag(FLAG_CORRECT_ANSWERS) - 1);
}
advanceQuotesConversation(rootIndex, room);
break;
}
case 358: // very wrong answer: counter-=2 (min 0)
{
- if (_state->getFlag(FLAG_RESPUESTAS_ACERTADAS) > 1) {
- _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) - 2);
+ if (_state->getFlag(FLAG_CORRECT_ANSWERS) > 1) {
+ _state->setFlag(FLAG_CORRECT_ANSWERS, _state->getFlag(FLAG_CORRECT_ANSWERS) - 2);
}
advanceQuotesConversation(rootIndex, room);
break;
}
case 359: // correct answer: counter++, award pin at 15
{
- _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, _state->getFlag(FLAG_RESPUESTAS_ACERTADAS) + 1);
- if (_state->getFlag(FLAG_RESPUESTAS_ACERTADAS) == 15) {
+ _state->setFlag(FLAG_CORRECT_ANSWERS, _state->getFlag(FLAG_CORRECT_ANSWERS) + 1);
+ if (_state->getFlag(FLAG_CORRECT_ANSWERS) == 15) {
addInventoryItem(106); // pin
- _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, 0);
+ _state->setFlag(FLAG_CORRECT_ANSWERS, 0);
}
advanceQuotesConversation(rootIndex, room);
break;
}
case 360: // neutral reset: counter = 0
{
- _state->setFlag(FLAG_RESPUESTAS_ACERTADAS, 0);
+ _state->setFlag(FLAG_CORRECT_ANSWERS, 0);
_state->setCurrentRoot(room, rootIndex + 1, 0);
advanceQuotesConversation(rootIndex, room);
break;
@@ -523,7 +524,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
}
case 365: // riddle correct: set riddle-solved flag
- _state->setFlag(FLAG_PARADOJA_RESUELTA, 1);
+ _state->setFlag(FLAG_SOLVED_PARADOX, 1);
_state->setCurrentRoot(room, 1, 0);
break;
case 292:
@@ -585,7 +586,7 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 297: {
// sprite moves to right
_room->enableExit(0);
- _state->setFlag(FLAG_VIGILANTE_PAJEANDOSE, true);
+ _state->setFlag(FLAG_GUARD_HAVINGFUN, true);
Sprite *sprite = _room->findSpriteByIndex(0);
sprite->animData[0].movementFlags = 0x1C; // Move right
// Basic loop to wait until the sprite has reached the door
@@ -672,8 +673,8 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(43, 3, 0);
break;
case 325:
- _state->setFlag(FLAG_ESQUELETO_RECONOCE, _state->getFlag(FLAG_ESQUELETO_RECONOCE) + 1);
- if (_state->getFlag(FLAG_ESQUELETO_RECONOCE) == 2) {
+ _state->setFlag(FLAG_SKELETON_RECOGNIZES, _state->getFlag(FLAG_SKELETON_RECOGNIZES) + 1);
+ if (_state->getFlag(FLAG_SKELETON_RECOGNIZES) == 2) {
_state->setCurrentRoot(49, 1, 0);
}
break;
@@ -733,7 +734,7 @@ void PelrockEngine::toJail() {
_alfredState.x = 342;
_alfredState.y = 277;
setScreenAndPrepare(31, ALFRED_DOWN);
- _state->setFlag(FLAG_A_LA_CARCEL, true);
+ _state->setFlag(FLAG_TO_JAIL, true);
_room->moveHotspot(_room->findHotspotByExtra(101), 444, 166);
}
@@ -809,8 +810,8 @@ void PelrockEngine::openClosedDrawer(HotSpot *hotspot) {
void PelrockEngine::useCardWithATM(int inventoryObject, HotSpot *hotspot) {
debug("Withdrawing money from ATM using card (inv obj %d)", inventoryObject);
- if (_state->getFlag(FLAG_JEFE_INGRESA_PASTA)) {
- _state->setFlag(FLAG_JEFE_INGRESA_PASTA, false);
+ if (_state->getFlag(FLAG_BOSS_WIRED_MONEY)) {
+ _state->setFlag(FLAG_BOSS_WIRED_MONEY, false);
addInventoryItem(75);
_state->setCurrentRoot(20, 2, 0);
} else {
@@ -871,7 +872,7 @@ void PelrockEngine::closeKitchenDoor(HotSpot *HotSpot) {
}
void PelrockEngine::openKitchenDrawer(HotSpot *hotspot) {
- if (!_state->getFlag(FLAG_JEFE_ENCARCELADO)) {
+ if (!_state->getFlag(FLAG_BOSS_IN_JAIL)) {
_dialog->say(_res->_ingameTexts[kTextQuitaEsasManos]);
} else if (!_state->getFlag(FLAG_RECIPE_TAKEN)) {
_state->setFlag(FLAG_RECIPE_TAKEN, true);
@@ -889,13 +890,13 @@ void PelrockEngine::openKitchenDoorFromInside(HotSpot *hotspot) {
}
void PelrockEngine::useSpicySauceWithBurger(int inventoryObject, HotSpot *hotspot) {
- _state->setFlag(FLAG_PUESTA_SALSA_PICANTE, true);
+ _state->setFlag(FLAG_SPICY_SAUCE_PLACED, true);
_sound->playSound(_room->_roomSfx[2]);
_dialog->say(_res->_ingameTexts[kTextVaestarPocoFuerte]);
}
void PelrockEngine::openShopDoor(HotSpot *hotspot) {
- if (!_state->getFlag(FLAG_TIENDA_ABIERTA)) {
+ if (!_state->getFlag(FLAG_OPEN_SHOP)) {
_dialog->say(_res->_ingameTexts[kTextTiendaCerrada]);
return;
} else {
@@ -949,8 +950,8 @@ void PelrockEngine::useBrickWithWindow(int inventoryObject, HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[kTextQueHaSidoEso], x, dialog1y);
_dialog->say(_res->_ingameTexts[kTextQuienAndaAhi], x, dialog2y);
_dialog->say(_res->_ingameTexts[kTextYoMeVoy]);
- _state->setFlag(FLAG_HE_TIRADO_PIEDRA, true);
- _state->setFlag(FLAG_TIENDA_ABIERTA, true);
+ _state->setFlag(FLAG_STONE_THROWN, true);
+ _state->setFlag(FLAG_OPEN_SHOP, true);
_room->addStickerToRoom(_room->_currentRoomNumber, 9, PERSIST_PERM);
_room->addStickerToRoom(_room->_currentRoomNumber, 10, PERSIST_PERM);
_room->disableHotspot(_room->findHotspotByExtra(295));
@@ -965,7 +966,7 @@ void PelrockEngine::moveCable(HotSpot *hotspot) {
_room->addSticker(16);
_room->addSticker(17);
_room->addStickerToRoom(4, 20);
- _state->setFlag(FLAG_CABLES_PUESTOS, true);
+ _state->setFlag(FLAG_CABLES_PLACED, true);
}
void PelrockEngine::useBrickWithShopWindow(int inventoryObject, HotSpot *hotspot) {
@@ -1028,7 +1029,7 @@ void PelrockEngine::useCordWithPlug(int inventoryObject, HotSpot *hotspot) {
if (!_room->hasSticker(18)) {
_dialog->say(_res->_ingameTexts[kTextPrimeroAbrirlo]);
} else {
- if (_state->getFlag(FLAG_CABLES_PUESTOS)) {
+ if (_state->getFlag(FLAG_CABLES_PLACED)) {
_room->addSticker(19);
_room->moveHotspot(_room->findHotspotByIndex(6), 391, 381);
_state->removeInventoryItem(6);
@@ -1060,16 +1061,16 @@ void PelrockEngine::pickCables(HotSpot *hotspot) {
}
void PelrockEngine::showIdToGuard(int inventoryObject, HotSpot *hotspot) {
- if (!_state->getFlag(FLAG_GUARDIA_PIDECOSAS)) {
+ if (!_state->getFlag(FLAG_GUARD_ASKS_FOR_STUFF)) {
_dialog->say(_res->_ingameTexts[kTextCuandoMeLoPida]);
return;
}
- if (!_state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
- _state->setFlag(FLAG_GUARDIA_DNI_ENTREGADO, true);
+ if (!_state->getFlag(FLAG_GUARD_ID_DELIVERED)) {
+ _state->setFlag(FLAG_GUARD_ID_DELIVERED, true);
_dialog->say(_res->_ingameTexts[kTextDeAcuerdo]);
}
- if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
+ if (_state->getFlag(FLAG_DOORMAN_BRIBED) && _state->getFlag(FLAG_GUARD_ID_DELIVERED)) {
unlockMuseum();
return;
}
@@ -1086,27 +1087,27 @@ void PelrockEngine::unlockMuseum() {
}
void PelrockEngine::giveMoneyToGuard(int inventoryObject, HotSpot *hotspot) {
- if (!_state->getFlag(FLAG_GUARDIA_PIDECOSAS)) {
+ if (!_state->getFlag(FLAG_GUARD_ASKS_FOR_STUFF)) {
_dialog->say(_res->_ingameTexts[kTextPretendeUstedSobornarme]);
return;
- } else if (!_state->getFlag(FLAG_SOBORNO_PORTERO)) {
- _state->setFlag(FLAG_SOBORNO_PORTERO, true);
+ } else if (!_state->getFlag(FLAG_DOORMAN_BRIBED)) {
+ _state->setFlag(FLAG_DOORMAN_BRIBED, true);
_dialog->say(_res->_ingameTexts[kTextMuyBien]);
_state->removeInventoryItem(5);
}
- if (_state->getFlag(FLAG_SOBORNO_PORTERO) && _state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
+ if (_state->getFlag(FLAG_DOORMAN_BRIBED) && _state->getFlag(FLAG_GUARD_ID_DELIVERED)) {
unlockMuseum();
return;
}
}
void PelrockEngine::openMuseumDoor(HotSpot *hotspot) {
- if (!_state->getFlag(FLAG_GUARDIA_PIDECOSAS)) {
+ if (!_state->getFlag(FLAG_GUARD_ASKS_FOR_STUFF)) {
_dialog->say(_res->_ingameTexts[kTextAlto]);
return;
- } else if (!_state->getFlag(FLAG_GUARDIA_DNI_ENTREGADO)) {
+ } else if (!_state->getFlag(FLAG_GUARD_ID_DELIVERED)) {
_dialog->say(_res->_ingameTexts[kTextNecesitaDni]);
- } else if (!_state->getFlag(FLAG_SOBORNO_PORTERO)) {
+ } else if (!_state->getFlag(FLAG_DOORMAN_BRIBED)) {
_dialog->say(_res->_ingameTexts[kTextQueReciboACambio]);
} else {
openDoor(hotspot, 1, 22, FEMININE, false);
@@ -1207,7 +1208,7 @@ void PelrockEngine::closeNewspaperBossDoor(HotSpot *hotspot) {
void PelrockEngine::openTravelAgencyDoor(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_AGENCIA_ABIERTA)) {
+ if (_state->getFlag(FLAG_TRAVELAGENCY_OPEN)) {
openDoor(hotspot, 1, 57, FEMININE, false);
}
// The game originally already did nothing here
@@ -1220,7 +1221,7 @@ void PelrockEngine::closeTravelAgencyDoor(HotSpot *hotspot) {
void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
_state->removeInventoryItem(76);
addInventoryItem(86);
- if (_state->getFlag(FLAG_CROCODILLO_ENCENDIDO) == false) {
+ if (_state->getFlag(FLAG_CROCODILE_ON) == false) {
_sound->playMusicTrack(27);
checkIngredients();
_dialog->say(_res->_ingameTexts[kTextCuidadoImprudente]);
@@ -1263,7 +1264,7 @@ void PelrockEngine::waitForSoundEnd(int channel) {
}
void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_PARADOJA_RESUELTA) == false) {
+ if (_state->getFlag(FLAG_SOLVED_PARADOX) == false) {
if (_state->getFlag(FLAG_RIDDLE_PRESENTED)) {
// try to take the sunflower before solving the riddle
_dialog->say(_res->_ingameTexts[kTextLeEstoyVigilando]);
@@ -1283,10 +1284,10 @@ void PelrockEngine::pickupSunflower(HotSpot *hotspot) {
}
void PelrockEngine::checkIngredients() {
- byte ingredientes = _state->getFlag(FLAG_INGREDIENTES_CONSEGUIDOS);
+ byte ingredientes = _state->getFlag(FLAG_COLLECTED_INGREDIENTS);
int textLine = kTextPrimerIngrediente + ingredientes;
_dialog->say(_res->_ingameTexts[textLine]);
- _state->setFlag(FLAG_INGREDIENTES_CONSEGUIDOS, ingredientes + 1);
+ _state->setFlag(FLAG_COLLECTED_INGREDIENTS, ingredientes + 1);
}
void PelrockEngine::pickUpBook(int i) {
@@ -1354,7 +1355,7 @@ void PelrockEngine::closeEgyptMuseumDoor(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol1(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ if (_state->getFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x1);
checkAllSymbols();
@@ -1362,7 +1363,7 @@ void PelrockEngine::pushSymbol1(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol2(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ if (_state->getFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x2);
checkAllSymbols();
@@ -1370,7 +1371,7 @@ void PelrockEngine::pushSymbol2(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol3(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ if (_state->getFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x4);
checkAllSymbols();
@@ -1378,7 +1379,7 @@ void PelrockEngine::pushSymbol3(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol4(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO) == true) {
+ if (_state->getFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x8);
checkAllSymbols();
@@ -1390,7 +1391,7 @@ void PelrockEngine::checkAllSymbols() {
if (symbolsPulled == 0x0F) {
// Activates animation
_sound->playSound(_room->_roomSfx[0]);
- _state->setFlag(FLAG_PUERTA_SECRETA_ABIERTA, true);
+ _state->setFlag(FLAG_SECRET_DOOR_OPEN, true);
_room->enableSprite(4, 100, PERSIST_TEMP);
_room->enableExit(0, PERSIST_BOTH);
_room->addSticker(61);
@@ -1400,7 +1401,7 @@ void PelrockEngine::checkAllSymbols() {
void PelrockEngine::pickUpHairStrand(HotSpot *hotspot) {
checkIngredients();
- _state->setFlag(FLAG_ROBA_PELO_PRINCESA, true);
+ _state->setFlag(FLAG_STOLE_PRINCESS_HAIR, true);
}
void PelrockEngine::openJailFloorTile(HotSpot *hotspot) {
@@ -1423,7 +1424,7 @@ void PelrockEngine::useKeyWithPortrait(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::openSafe(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_CLAVE_CAJA_FUERTE) == true) {
+ if (_state->getFlag(FLAG_SAFE_COMBINATION) == true) {
_room->addSticker(102);
_dialog->say(_res->_ingameTexts[kTextGranCantidadDinero]);
addInventoryItem(82);
@@ -1452,7 +1453,7 @@ void PelrockEngine::useDollWithBed(int inventoryObject, HotSpot *hotspot) {
_alfredState.y += 12;
playAlfredSpecialAnim(12);
_alfredState.direction = ALFRED_DOWN;
- _state->setFlag(FLAG_SE_HA_PUESTO_EL_MUNECO, true);
+ _state->setFlag(FLAG_DOLL_PLACED, true);
_state->removeInventoryItem(83);
_room->addSticker(126);
_alfredState.x = x;
@@ -1466,14 +1467,14 @@ void PelrockEngine::giveMagazineToGuard(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
- _state->setFlag(FLAG_VIGILANTE_BEBE_AGUA, _state->getFlag(FLAG_VIGILANTE_BEBE_AGUA) + 1);
+ _state->setFlag(FLAG_GUARD_WATER_DRINKED, _state->getFlag(FLAG_GUARD_WATER_DRINKED) + 1);
_dialog->say(_res->_ingameTexts[kTextAlaConUsted]);
_state->removeInventoryItem(86);
addInventoryItem(76);
- if (_state->getFlag(FLAG_VIGILANTE_BEBE_AGUA) == 3) {
+ if (_state->getFlag(FLAG_GUARD_WATER_DRINKED) == 3) {
_dialog->say(_res->_ingameTexts[kTextMeMeo]);
- _state->setFlag(FLAG_VIGILANTE_MEANDO, true);
+ _state->setFlag(FLAG_GUARD_PEEING, true);
guardMovement();
_room->disableSprite(36, 0, PERSIST_BOTH);
_room->enableExit(0, PERSIST_BOTH);
@@ -1513,7 +1514,7 @@ void PelrockEngine::guardMovement() {
void PelrockEngine::pickUpStone(HotSpot *hotspot) {
_room->addSticker(117);
- _state->setFlag(FLAG_PIRAMIDE_JODIDA, true);
+ _state->setFlag(FLAG_PYRAMID_COLLAPSED, true);
_sound->playSound("QUAKE2ZZ.SMP", 0, -1);
_shakeEffectState.enable();
checkIngredients();
@@ -1578,7 +1579,7 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[kTextHayQueCelebrarlo]);
- byte counter = _state->getFlag(FLAG_DA_PIEDRA);
+ byte counter = _state->getFlag(FLAG_STONE_GIVEN);
// drinking animation and sound
_sound->playSound(_room->_roomSfx[1], 2);
@@ -1589,10 +1590,10 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
// Increment stone delivery counter (tracks 0â1â2â3)
debug("Current stone delivery count: %d", counter);
if (counter < 3) {
- _state->setFlag(FLAG_DA_PIEDRA, ++counter);
+ _state->setFlag(FLAG_STONE_GIVEN, ++counter);
_room->findSpriteByIndex(0)->zOrder = zIndex;
}
- debug("New stone delivery count: %d", _state->getFlag(FLAG_DA_PIEDRA));
+ debug("New stone delivery count: %d", _state->getFlag(FLAG_STONE_GIVEN));
// At 2nd stone delivery: masters starts singing (conversation root 2)
if (counter == 2) {
_state->setCurrentRoot(41, 2, 0);
@@ -1607,7 +1608,7 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
WalkBox w2 = {4, 141, 374, 46, 4, 0};
_room->addWalkbox(w1);
_room->addWalkbox(w2);
- _state->setFlag(FLAG_GUARDIAS_BORRACHOS, true);
+ _state->setFlag(FLAG_DRUNK_GUARDS, true);
}
}
@@ -1676,7 +1677,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
_screen->update();
g_system->delayMillis(10);
}
- _state->setFlag(FLAG_APARECE_EUNUCO, true);
+ _state->setFlag(FLAG_EUNUCH_APPEARS, true);
Sprite *guard = _room->findSpriteByIndex(0);
guard->animData[0].movementFlags = 0x14;
while (!shouldQuit()) {
@@ -1703,7 +1704,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
_alfredState.x = 271;
_alfredState.y = 385;
setScreenAndPrepare(40, ALFRED_UP);
- _state->setFlag(FLAG_AL_FARAON, true);
+ _state->setFlag(FLAG_PHARAOH_VIEWING, true);
walkAndAction(_room->findHotspotByExtra(640), TALK);
if (shouldQuit()) {
return;
@@ -1711,7 +1712,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
_graphics->fadeToBlack(10);
_alfredState.x = 271;
_alfredState.y = 385;
- _state->setFlag(FLAG_A_CURRAR, true);
+ _state->setFlag(FLAG_TO_WORK, true);
setScreenAndPrepare(41, ALFRED_UP);
}
@@ -1720,22 +1721,22 @@ void PelrockEngine::pickUpStones(HotSpot *hotspot) {
_dialog->say(_res->_ingameTexts[kTextPesaDemasiado]);
return;
}
- if (_state->getFlag(FLAG_PIEDRAS_COGIDAS) >= 2) {
+ if (_state->getFlag(FLAG_COLLECTED_STONES) >= 2) {
_dialog->say(_res->_ingameTexts[kTextNingunaTamanhoApropiado]);
return;
} else {
addInventoryItem(91);
- _state->setFlag(FLAG_PIEDRAS_COGIDAS, _state->getFlag(FLAG_PIEDRAS_COGIDAS) + 1);
+ _state->setFlag(FLAG_COLLECTED_STONES, _state->getFlag(FLAG_COLLECTED_STONES) + 1);
}
}
void PelrockEngine::pickUpMud(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_PIEDRAS_COGIDAS) != 2) {
+ if (_state->getFlag(FLAG_COLLECTED_STONES) != 2) {
_dialog->say(_res->_ingameTexts[kTextParaQueCogeBarro]);
return;
} else {
addInventoryItem(92);
- _state->setFlag(FLAG_PIEDRAS_COGIDAS, _state->getFlag(FLAG_PIEDRAS_COGIDAS) + 1);
+ _state->setFlag(FLAG_COLLECTED_STONES, _state->getFlag(FLAG_COLLECTED_STONES) + 1);
_dialog->say(_res->_ingameTexts[kTextBuenoCogereUnPoco]);
}
}
@@ -1751,7 +1752,7 @@ void PelrockEngine::usePumpkinWithPond(int inventoryObject, HotSpot *hotspot) {
void PelrockEngine::useWaterOnFakeStone(int inventoryObject, HotSpot *hotspot) {
- int count = _state->getFlag(FLAG_PIEDRA_FAKE_MOJADA);
+ int count = _state->getFlag(FLAG_FAKE_STONE_WET);
if (count != 3) {
_state->removeInventoryItem(86);
addInventoryItem(76);
@@ -1770,7 +1771,7 @@ void PelrockEngine::useWaterOnFakeStone(int inventoryObject, HotSpot *hotspot) {
break;
}
count++;
- _state->setFlag(FLAG_PIEDRA_FAKE_MOJADA, count);
+ _state->setFlag(FLAG_FAKE_STONE_WET, count);
}
}
@@ -1784,10 +1785,10 @@ void PelrockEngine::magicFormula(int inventoryObject, HotSpot *hotspot) {
if (inventoryObject == 86) {
addInventoryItem(76);
}
- _state->setFlag(FLAG_FORMULA_MAGICA, _state->getFlag(FLAG_FORMULA_MAGICA) + 1);
- if (_state->getFlag(FLAG_FORMULA_MAGICA) == 4) {
+ _state->setFlag(FLAG_MAGIC_FORMULA, _state->getFlag(FLAG_MAGIC_FORMULA) + 1);
+ if (_state->getFlag(FLAG_MAGIC_FORMULA) == 4) {
smokeAnimation(-1);
- _state->setFlag(FLAG_VIAJA_AL_PASADO, true);
+ _state->setFlag(FLAG_TIME_TRAVEL, true);
_alfredState.setState(ALFRED_IDLE);
_state->clearInventory();
_state->addInventoryItem(88);
@@ -1903,7 +1904,7 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
_dialog->say(_res->_ingameTexts[kTextSeLorecomiendo]);
break;
case 327:
- _state->setFlag(FLAG_MIRA_SIMBOLO_FUERA_MUSEO, true);
+ _state->setFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR, true);
break;
case 294: {
HotSpot *floorTile = _room->findHotspotByExtra(462);
@@ -2076,7 +2077,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
case 17: // Egyptian book
playAlfredSpecialAnim(0);
_dialog->say(_res->_ingameTexts[kTextYaSeEgipcio]);
- _state->setFlag(FLAG_ALFRED_SABE_EGIPCIO, true);
+ _state->setFlag(FLAG_ALFRED_SPEAKS_EGYPTIAN, true);
break;
case 24: // Encyclopedia
if (_state->getFlag(FLAG_RIDDLE_PRESENTED) == true) {
@@ -2085,14 +2086,14 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
} else {
playAlfredSpecialAnim(0);
_dialog->say(_res->_ingameTexts[kTextCosasAprendido]);
- _state->setFlag(FLAG_ALFRED_INTELIGENTE, true);
+ _state->setFlag(FLAG_ALFRED_SMART, true);
_state->setCurrentRoot(14, 2, 0);
}
break;
case 64: // Formula for time travel
playAlfredSpecialAnim(0);
loadExtraScreenAndPresent(5);
- if (_state->getFlag(FLAG_ALFRED_SABE_EGIPCIO)) {
+ if (_state->getFlag(FLAG_ALFRED_SPEAKS_EGYPTIAN)) {
_dialog->say(_res->_ingameTexts[kTextFormulaViajeAlTiempo]);
} else {
_dialog->say(_res->_ingameTexts[kTextQueLastimaNoSeeEgipcio]);
@@ -2143,13 +2144,13 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_dialog->say(_res->_ingameTexts[kTextDiosHalcon + spell->page], 1);
int flightIndex = _room->_currentRoomNumber - 51;
if (_fightSorcererAppeared && !_fightInBlockingAnim && spell->page == kFightRooms[flightIndex].spellPage) {
- _state->setFlag(FLAG_COMO_ESTAN_LOS_DIOSES, _state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) | (1 << flightIndex));
+ _state->setFlag(FLAG_GODS_STANCES, _state->getFlag(FLAG_GODS_STANCES) | (1 << flightIndex));
_sound->playSound(_room->_roomSfx[1], 0);
smokeAnimation(kFightRooms[flightIndex].spriteIdx, true);
_room->addStickerToRoom(_room->_currentRoomNumber, 127 + flightIndex);
_room->addStickerToRoom(52, 106 + flightIndex);
- if (_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) == 15) { // all 4 spells successful
+ if (_state->getFlag(FLAG_GODS_STANCES) == 15) { // all 4 spells successful
HotSpot hotspot = HotSpot();
hotspot.actionFlags = 0;
hotspot.extra = 999;
@@ -2179,7 +2180,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
case 101: // combination
playAlfredSpecialAnim(1);
_dialog->say(_res->_ingameTexts[kTextPareceCombinacionCajaFuerte]);
- _state->setFlag(FLAG_CLAVE_CAJA_FUERTE, true);
+ _state->setFlag(FLAG_SAFE_COMBINATION, true);
break;
case 108: // glue + patches
case 109: {
@@ -2253,12 +2254,12 @@ void PelrockEngine::sayRandomIncorrectResponse() {
void PelrockEngine::chooseCorrectDoor() {
playAlfredSpecialAnim(1);
- byte puertaBuena = _state->getFlag(FLAG_PUERTA_BUENA);
+ byte puertaBuena = _state->getFlag(FLAG_CORRECT_DOOR);
if (puertaBuena == 0) { // if not set yet, choose randomly
int choice = getRandomNumber(1);
- _state->setFlag(FLAG_PUERTA_BUENA, choice + 1);
+ _state->setFlag(FLAG_CORRECT_DOOR, choice + 1);
}
- puertaBuena = _state->getFlag(FLAG_PUERTA_BUENA);
+ puertaBuena = _state->getFlag(FLAG_CORRECT_DOOR);
Common::String doorText = _res->_izquierda;
if (puertaBuena == 1) {
doorText = _res->_izquierda;
@@ -2361,12 +2362,12 @@ void PelrockEngine::checkObjectsForPart2() {
if (_state->hasInventoryItem(17) &&
_state->hasInventoryItem(59) &&
_state->hasInventoryItem(24)) {
- if (_state->getFlag(FLAG_AGENCIA_ABIERTA) == false) {
+ if (_state->getFlag(FLAG_TRAVELAGENCY_OPEN) == false) {
_room->addStickerToRoom(19, 54, PERSIST_BOTH);
_room->addStickerToRoom(19, 55, PERSIST_BOTH);
_room->addStickerToRoom(19, 56, PERSIST_BOTH);
_room->addStickerToRoom(19, 58, PERSIST_BOTH);
- _state->setFlag(FLAG_AGENCIA_ABIERTA, true);
+ _state->setFlag(FLAG_TRAVELAGENCY_OPEN, true);
}
}
}
@@ -2393,7 +2394,7 @@ void PelrockEngine::pickUpMatches(HotSpot *hotspot) {
// Pick up the item
_room->disableHotspot(hotspot);
Common::copy(targetPalette, targetPalette + 768, _room->_roomPalette);
- _state->setFlag(FLAG_CROCODILLO_ENCENDIDO, true);
+ _state->setFlag(FLAG_CROCODILE_ON, true);
_room->moveHotspot(_room->findHotspotByExtra(87), 415, 171);
_room->moveHotspot(_room->findHotspotByExtra(88), 305, 217);
_room->moveHotspot(_room->findHotspotByExtra(89), 201, 239);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 83b99c4ae0a..f4f1b790880 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -268,7 +268,7 @@ void PelrockEngine::playSoundIfNeeded() {
* Travel to egypt sequence loads extra screen, plays palette animation then loads room 21
*/
void PelrockEngine::travelToEgypt() {
- _state->setFlag(FLAG_VIAJE_A_EGIPTO, true);
+ _state->setFlag(FLAG_TRAVEL_TO_EGYPT, true);
_graphics->fadeToBlack(10);
_sound->playMusicTrack(26, false);
@@ -397,7 +397,7 @@ bool PelrockEngine::renderScene(int overlayMode) {
// Easter egg in room 2, pressing x 250 times after the character has mentioned it triggers a special dialog
if (_events->_lastKeyEvent == Common::KEYCODE_x) {
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
- if (_state->getFlag(FLAG_PUTA_250_VECES) == true) {
+ if (_state->getFlag(FLAG_HOOKER_250_TIMES) == true) {
_numPressedX++;
if (_numPressedX == 250) {
_dialog->say(_res->_ingameTexts[kTextYLosCondones]);
@@ -953,11 +953,11 @@ void PelrockEngine::exitTriggers(Pelrock::Exit *exit) {
smokeAnimation(-1);
uint16 x = _alfredState.x;
if (x < 282) {
- if (_state->getFlag(FLAG_PUERTA_BUENA) == 1) {
+ if (_state->getFlag(FLAG_CORRECT_DOOR) == 1) {
_state->setFlag(FLAG_CORRECT_DOOR_CHOSEN, true);
}
} else {
- if (_state->getFlag(FLAG_PUERTA_BUENA) == 2) {
+ if (_state->getFlag(FLAG_CORRECT_DOOR) == 2) {
_state->setFlag(FLAG_CORRECT_DOOR_CHOSEN, true);
}
}
@@ -1760,8 +1760,8 @@ void PelrockEngine::doExtraActions(int roomNumber) {
switch (roomNumber) {
case 4:
case 0:
- if (_state->getFlag(FLAG_PUESTA_SALSA_PICANTE) && !_state->getFlag(FLAG_JEFE_ENCARCELADO)) {
- _state->setFlag(FLAG_JEFE_ENCARCELADO, true);
+ if (_state->getFlag(FLAG_SPICY_SAUCE_PLACED) && !_state->getFlag(FLAG_BOSS_IN_JAIL)) {
+ _state->setFlag(FLAG_BOSS_IN_JAIL, true);
_room->disableSprite(13, 0, PERSIST_BOTH);
loadExtraScreenAndPresent(4);
}
@@ -1771,8 +1771,8 @@ void PelrockEngine::doExtraActions(int roomNumber) {
break;
}
case 15:
- if (_state->getFlag(FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ)) {
- _state->setFlag(FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ, false);
+ if (_state->getFlag(FLAG_FIRST_TIME_IN_SHOP)) {
+ _state->setFlag(FLAG_FIRST_TIME_IN_SHOP, false);
_dialog->say(_res->_ingameTexts[kTextGamberros]);
_dialog->say(_res->_ingameTexts[kTextQuienYo]);
_dialog->say(_res->_ingameTexts[kTextPintaBuenaPersona]);
@@ -1848,7 +1848,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
break;
}
case 28: {
- if (_state->getFlag(FLAG_CROCODILLO_ENCENDIDO) == true) {
+ if (_state->getFlag(FLAG_CROCODILE_ON) == true) {
byte palette[768];
_res->getPaletteForRoom28(palette);
g_system->getPaletteManager()->setPalette(palette, 0, 256);
@@ -1857,9 +1857,9 @@ void PelrockEngine::doExtraActions(int roomNumber) {
break;
}
case 26: {
- if (_state->getFlag(FLAG_A_LA_CARCEL) == true) {
+ if (_state->getFlag(FLAG_TO_JAIL) == true) {
_dialog->_goodbyeDisabled = true;
- if (_state->getFlag(FLAG_SE_HA_PUESTO_EL_MUNECO) == true) {
+ if (_state->getFlag(FLAG_DOLL_PLACED) == true) {
_state->setCurrentRoot(26, 2, 1);
} else {
_dialog->say(_res->_ingameTexts[kTextOigaUsted], 1);
@@ -1872,9 +1872,9 @@ void PelrockEngine::doExtraActions(int roomNumber) {
break;
}
case 30: {
- if (_state->getFlag(FLAG_ROBA_PELO_PRINCESA) == true) {
+ if (_state->getFlag(FLAG_STOLE_PRINCESS_HAIR) == true) {
_dialog->_goodbyeDisabled = true;
- _state->setFlag(FLAG_ROBA_PELO_PRINCESA, false);
+ _state->setFlag(FLAG_STOLE_PRINCESS_HAIR, false);
_room->enableSprite(0, 200, PERSIST_TEMP);
_dialog->say(_res->_ingameTexts[kTextOigaUsted]);
walkAndAction(_room->findHotspotByExtra(0), TALK);
@@ -1885,11 +1885,11 @@ void PelrockEngine::doExtraActions(int roomNumber) {
if (_shakeEffectState.enabled) {
_shakeEffectState.disable();
}
- if (_state->getFlag(FLAG_PIRAMIDE_JODIDA) == true &&
+ if (_state->getFlag(FLAG_PYRAMID_COLLAPSED) == true &&
// _state->getFlag(FLAG_VIGILANTE_MEANDO) == true &&
- _state->getFlag(FLAG_PIRAMIDE_JODIDA2) == false) {
- _state->setFlag(FLAG_VIGILANTE_MEANDO, false);
- _state->setFlag(FLAG_PIRAMIDE_JODIDA2, true);
+ _state->getFlag(FLAG_PYRAMID_COLLAPSED2) == false) {
+ _state->setFlag(FLAG_GUARD_PEEING, false);
+ _state->setFlag(FLAG_PYRAMID_COLLAPSED2, true);
debug("Pyramid is now active!");
pyramidCollapse();
}
@@ -1916,7 +1916,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
} else if (_state->getFlag(FLAG_CORRECT_DOOR_CHOSEN) == true) {
_dialog->say(_res->_ingameTexts[kTextOhMiSalvador]);
_dialog->say(_res->_ingameTexts[kTextVoyPoriPrincesa]);
- _state->setFlag(FLAG_TRAMPILLA_ABIERTA, true);
+ _state->setFlag(FLAG_TRAPDOOR_OPEN, true);
walkAndAction(_room->findHotspotByExtra(634), TALK);
_room->addSticker(134);
// wait a few frames
@@ -1933,7 +1933,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_alfredState.x = 294;
_alfredState.y = 387;
_room->addSticker(136);
- _state->setFlag(FLAG_A_LOS_PASILLOS, true);
+ _state->setFlag(FLAG_CORRIDORS, true);
setScreenAndPrepare(49, ALFRED_UP);
} else {
@@ -1951,7 +1951,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
walkAndAction(fatMummy, TALK);
_state->clear();
- _state->setFlag(FLAG_VUELTA_A_EMPEZAR, true);
+ _state->setFlag(FLAG_GAME_RESTART, true);
_alfredState.x = kAlfredInitialPosX;
_alfredState.y = kAlfredInitialPosY;
_graphics->fadeToBlack(20);
@@ -2324,7 +2324,7 @@ void PelrockEngine::handleFightRoomFrame() {
return;
int idx = room - 51;
- if (_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) & (1 << idx)) {
+ if (_state->getFlag(FLAG_GODS_STANCES) & (1 << idx)) {
// Gods are already defeated in this room, no need to run sequence
return;
}
@@ -2358,7 +2358,7 @@ void PelrockEngine::handleFightRoomFrame() {
// Phase 3: wait 40 ticks after spell trigger, then cast
if (_fightSpellCast) {
_fightSpellFrameCounter++;
- if (_fightSpellFrameCounter >= 40 && !(_state->getFlag(FLAG_COMO_ESTAN_LOS_DIOSES) & (1 << idx))) {
+ if (_fightSpellFrameCounter >= 40 && !(_state->getFlag(FLAG_GODS_STANCES) & (1 << idx))) {
_fightInBlockingAnim = true;
int spellFrames = kFightRooms[idx].spellFrames;
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 1fa31e0e72b..e8828f779ac 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -518,67 +518,67 @@ struct ResetEntry {
byte *data = nullptr;
};
-#define FLAG_JEFE_INGRESA_PASTA 0
-#define FLAG_JEFE_ENCARCELADO 1
-#define FLAG_PUESTA_SALSA_PICANTE 2
-#define FLAG_CRISTAL_ROTO 3
-#define FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ 4
-#define FLAG_ELECTROCUTACION 5
-#define FLAG_CABLES_PUESTOS 6
-#define FLAG_SOBORNO_PORTERO 7
-#define FLAG_MEMORIZA_LIBRO 8
-#define FLAG_ALFRED_INTELIGENTE 9
-#define FLAG_ALFRED_SABE_EGIPCIO 10
-#define FLAG_VENDEDOR_DEJA_DE_JODER 11
-#define FLAG_VIAJE_A_EGIPTO 12
-#define FLAG_PARADOJA_RESUELTA 13
-#define FLAG_CROCODILLO_ENCENDIDO 14
-#define FLAG_MIRA_SIMBOLO_FUERA_MUSEO 15
-#define FLAG_PUERTA_SECRETA_ABIERTA 16
-#define FLAG_ROBA_PELO_PRINCESA 17
-#define FLAG_A_LA_CARCEL 18
-#define FLAG_CLAVE_CAJA_FUERTE 19
-#define FLAG_SE_HA_PUESTO_EL_MUNECO 20
-#define FLAG_VIGILANTE_BEBE_AGUA 21
-#define FLAG_VIGILANTE_MEANDO 22
-#define FLAG_PIRAMIDE_JODIDA 23
-#define FLAG_PIRAMIDE_JODIDA2 24
-#define FLAG_VIGILANTE_PAJEANDOSE 25
-#define FLAG_FORMULA_MAGICA 26
-#define FLAG_VIAJA_AL_PASADO 27
-#define FLAG_APARECE_EUNUCO 28
-#define FLAG_AL_FARAON 29
-#define FLAG_A_CURRAR 30
-#define FLAG_DA_PIEDRA 31
-#define FLAG_PIEDRAS_COGIDAS 32
-#define FLAG_GUARDIAS_BORRACHOS 33
-#define FLAG_PIEDRA_FAKE_MOJADA 34
-#define FLAG_PUERTA_BUENA 35
-#define FLAG_TRAMPILLA_ABIERTA 36
-#define FLAG_HABITACION_PRINCESA 37
-#define FLAG_A_POR_LA_PRINCESA 38
-#define FLAG_VUELTA_A_EMPEZAR 39
-#define FLAG_A_LOS_PASILLOS 40
-#define FLAG_COMO_ESTAN_LOS_DIOSES 41
+#define FLAG_BOSS_WIRED_MONEY 0
+#define FLAG_BOSS_IN_JAIL 1
+#define FLAG_SPICY_SAUCE_PLACED 2
+#define FLAG_BROKEN_GLASS 3
+#define FLAG_FIRST_TIME_IN_SHOP 4
+#define FLAG_ELECTROSHOCK 5
+#define FLAG_CABLES_PLACED 6
+#define FLAG_DOORMAN_BRIBED 7
+#define FLAG_BOOK_MEMORIZED 8
+#define FLAG_ALFRED_SMART 9
+#define FLAG_ALFRED_SPEAKS_EGYPTIAN 10
+#define FLAG_SALESMAN_LEAVES_ALFRED_ALONE 11
+#define FLAG_TRAVEL_TO_EGYPT 12
+#define FLAG_SOLVED_PARADOX 13
+#define FLAG_CROCODILE_ON 14
+#define FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR 15
+#define FLAG_SECRET_DOOR_OPEN 16
+#define FLAG_STOLE_PRINCESS_HAIR 17
+#define FLAG_TO_JAIL 18
+#define FLAG_SAFE_COMBINATION 19
+#define FLAG_DOLL_PLACED 20
+#define FLAG_GUARD_WATER_DRINKED 21
+#define FLAG_GUARD_PEEING 22
+#define FLAG_PYRAMID_COLLAPSED 23
+#define FLAG_PYRAMID_COLLAPSED2 24
+#define FLAG_GUARD_HAVINGFUN 25
+#define FLAG_MAGIC_FORMULA 26
+#define FLAG_TIME_TRAVEL 27
+#define FLAG_EUNUCH_APPEARS 28
+#define FLAG_PHARAOH_VIEWING 29
+#define FLAG_TO_WORK 30
+#define FLAG_STONE_GIVEN 31
+#define FLAG_COLLECTED_STONES 32
+#define FLAG_DRUNK_GUARDS 33
+#define FLAG_FAKE_STONE_WET 34
+#define FLAG_CORRECT_DOOR 35
+#define FLAG_TRAPDOOR_OPEN 36
+#define FLAG_PRINCESS_ROOM 37
+#define FLAG_GET_THE_PRINCESS 38
+#define FLAG_GAME_RESTART 39
+#define FLAG_CORRIDORS 40
+#define FLAG_GODS_STANCES 41
#define FLAG_END_OF_GAME 42
#define FLAG_FROM_INTRO 43
-#define FLAG_HE_TIRADO_PIEDRA 44
-#define FLAG_HA_USADO_AGUA 45
-#define FLAG_TIENDA_ABIERTA 46
-#define FLAG_NUMERO_DE_COPAS 47
-#define FLAG_INGREDIENTES_CONSEGUIDOS 48
-#define FLAG_GUARDIA_PIDECOSAS 49
-#define FLAG_GUARDIA_DNI_ENTREGADO 50
-#define FLAG_AGENCIA_ABIERTA 51
-#define FLAG_CONSIGNAS_VENDEDOR 52
-#define FLAG_PUTA_250_VECES 53
-#define FLAG_RESPUESTAS_ACERTADAS 54
+#define FLAG_STONE_THROWN 44
+#define FLAG_USED_WATER 45
+#define FLAG_OPEN_SHOP 46
+#define FLAG_DRINKS_NUMBER 47
+#define FLAG_COLLECTED_INGREDIENTS 48
+#define FLAG_GUARD_ASKS_FOR_STUFF 49
+#define FLAG_GUARD_ID_DELIVERED 50
+#define FLAG_TRAVELAGENCY_OPEN 51
+#define FLAG_MERCHANT_SLOGANS 52
+#define FLAG_HOOKER_250_TIMES 53
+#define FLAG_CORRECT_ANSWERS 54
#define FLAG_CHEAT_CODE_ENABLED 55
#define FLAG_RIDDLE_PRESENTED 56
#define FLAG_SYMBOLS_PUSHED 57
#define FLAG_MERCHANT_GIVENITEMS 58
#define FLAG_CORRECT_DOOR_CHOSEN 59
-#define FLAG_ESQUELETO_RECONOCE 60
+#define FLAG_SKELETON_RECOGNIZES 60
#define FLAG_PIGEON_DEAD 61
#define FLAG_RECIPE_TAKEN 62
@@ -616,7 +616,7 @@ struct GameStateData {
memset(conversationCurrentRoot, 0xFF, 112); // Initialize all to 0xFF (not set)
for (int i = 0; i < kNumGameFlags; i++)
flags[i] = 0;
- flags[FLAG_ENTRA_EN_TIENDA_PRIMERA_VEZ] = true;
+ flags[FLAG_FIRST_TIME_IN_SHOP] = true;
inventoryItems.clear();
stickersPerRoom.clear();
roomExitChanges.clear();
Commit: 97706b2f175b8716b289fead44b8b13af0529d47
https://github.com/scummvm/scummvm/commit/97706b2f175b8716b289fead44b8b13af0529d47
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:49+02:00
Commit Message:
PELROCK: Introduce getBoolFlag to prevent unsafe comparison on Windows
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index dab0464714c..d40bdcfd95e 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1355,7 +1355,7 @@ void PelrockEngine::closeEgyptMuseumDoor(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol1(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
+ if (_state->getBoolFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x1);
checkAllSymbols();
@@ -1363,7 +1363,7 @@ void PelrockEngine::pushSymbol1(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol2(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
+ if (_state->getBoolFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x2);
checkAllSymbols();
@@ -1371,7 +1371,7 @@ void PelrockEngine::pushSymbol2(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol3(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
+ if (_state->getBoolFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x4);
checkAllSymbols();
@@ -1379,7 +1379,7 @@ void PelrockEngine::pushSymbol3(HotSpot *hotspot) {
}
void PelrockEngine::pushSymbol4(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
+ if (_state->getBoolFlag(FLAG_LOOKED_SYMBOL_MUSEUM_EXTERIOR) == true) {
byte symbolsPulled = _state->getFlag(FLAG_SYMBOLS_PUSHED);
_state->setFlag(FLAG_SYMBOLS_PUSHED, symbolsPulled | 0x8);
checkAllSymbols();
@@ -1424,7 +1424,7 @@ void PelrockEngine::useKeyWithPortrait(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::openSafe(HotSpot *hotspot) {
- if (_state->getFlag(FLAG_SAFE_COMBINATION) == true) {
+ if (_state->getBoolFlag(FLAG_SAFE_COMBINATION) == true) {
_room->addSticker(102);
_dialog->say(_res->_ingameTexts[kTextGranCantidadDinero]);
addInventoryItem(82);
@@ -2080,7 +2080,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
_state->setFlag(FLAG_ALFRED_SPEAKS_EGYPTIAN, true);
break;
case 24: // Encyclopedia
- if (_state->getFlag(FLAG_RIDDLE_PRESENTED) == true) {
+ if (_state->getBoolFlag(FLAG_RIDDLE_PRESENTED) == true) {
_dialog->say(_res->_ingameTexts[kTextCapituloParadojas]);
_state->setCurrentRoot(25, 44, 0);
} else {
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 048b0174a4b..aa586b5a4e8 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -191,7 +191,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
int16 xBasePos = 0;
int16 yBasePos = 0;
if (speakerId == kAlfredColor) {
- if (g_engine->_state->getFlag(FLAG_FROM_INTRO) == true) {
+ if (g_engine->_state->getBoolFlag(FLAG_FROM_INTRO) == true) {
// Different talking animation for the post-intro sequence in which Alfred speaks in bed
g_engine->_alfredState.setState(ALFRED_SPECIAL_ANIM);
} else {
@@ -247,7 +247,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
_events->_leftMouseClicked = false;
_dialogActive = true;
int curPage = 0;
- bool fromIntro = g_engine->_state->getFlag(FLAG_FROM_INTRO) == true;
+ bool fromIntro = g_engine->_state->getBoolFlag(FLAG_FROM_INTRO) == true;
uint32 pageTtlMs = calcPageTtlMs(dialogueLines[curPage]);
uint32 pageStartMs = g_system->getMillis();
@@ -1035,7 +1035,7 @@ void DialogManager::maybeDisableChoice(Common::Array<Pelrock::ChoiceOption> *cho
* Convenience method if we know it's Alfred talking
*/
void DialogManager::sayAlfred(Common::StringArray texts) {
- if (g_engine->_state->getFlag(FLAG_FROM_INTRO) == true) {
+ if (g_engine->_state->getBoolFlag(FLAG_FROM_INTRO) == true) {
g_engine->_alfredState.setState(ALFRED_SPECIAL_ANIM);
} else {
g_engine->_alfredState.setState(ALFRED_TALKING);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index f4f1b790880..3e33208b8f9 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -397,7 +397,7 @@ bool PelrockEngine::renderScene(int overlayMode) {
// Easter egg in room 2, pressing x 250 times after the character has mentioned it triggers a special dialog
if (_events->_lastKeyEvent == Common::KEYCODE_x) {
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
- if (_state->getFlag(FLAG_HOOKER_250_TIMES) == true) {
+ if (_state->getFlag(FLAG_HOOKER_250_TIMES)) {
_numPressedX++;
if (_numPressedX == 250) {
_dialog->say(_res->_ingameTexts[kTextYLosCondones]);
@@ -457,7 +457,7 @@ void PelrockEngine::maybeHaveDogPee() {
}
void PelrockEngine::maybePlayPostIntro() {
- if (_state->getFlag(FLAG_FROM_INTRO) == true) {
+ if (_state->getFlag(FLAG_FROM_INTRO)) {
setScreenAndPrepare(0, ALFRED_LEFT);
_alfredState.x = 396;
_alfredState.y = 267;
@@ -1848,7 +1848,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
break;
}
case 28: {
- if (_state->getFlag(FLAG_CROCODILE_ON) == true) {
+ if (_state->getFlag(FLAG_CROCODILE_ON)) {
byte palette[768];
_res->getPaletteForRoom28(palette);
g_system->getPaletteManager()->setPalette(palette, 0, 256);
@@ -1857,9 +1857,9 @@ void PelrockEngine::doExtraActions(int roomNumber) {
break;
}
case 26: {
- if (_state->getFlag(FLAG_TO_JAIL) == true) {
+ if (_state->getBoolFlag(FLAG_TO_JAIL) == true) {
_dialog->_goodbyeDisabled = true;
- if (_state->getFlag(FLAG_DOLL_PLACED) == true) {
+ if (_state->getBoolFlag(FLAG_DOLL_PLACED) == true) {
_state->setCurrentRoot(26, 2, 1);
} else {
_dialog->say(_res->_ingameTexts[kTextOigaUsted], 1);
@@ -1872,7 +1872,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
break;
}
case 30: {
- if (_state->getFlag(FLAG_STOLE_PRINCESS_HAIR) == true) {
+ if (_state->getBoolFlag(FLAG_STOLE_PRINCESS_HAIR) == true) {
_dialog->_goodbyeDisabled = true;
_state->setFlag(FLAG_STOLE_PRINCESS_HAIR, false);
_room->enableSprite(0, 200, PERSIST_TEMP);
@@ -1885,8 +1885,8 @@ void PelrockEngine::doExtraActions(int roomNumber) {
if (_shakeEffectState.enabled) {
_shakeEffectState.disable();
}
- if (_state->getFlag(FLAG_PYRAMID_COLLAPSED) == true &&
- // _state->getFlag(FLAG_VIGILANTE_MEANDO) == true &&
+ if (_state->getBoolFlag(FLAG_PYRAMID_COLLAPSED) == true &&
+ // _state->getBoolFlag(FLAG_GUARD_PEEING) == true &&
_state->getFlag(FLAG_PYRAMID_COLLAPSED2) == false) {
_state->setFlag(FLAG_GUARD_PEEING, false);
_state->setFlag(FLAG_PYRAMID_COLLAPSED2, true);
@@ -1904,7 +1904,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
case 48: {
_dialog->_goodbyeDisabled = true;
- if (_state->getFlag(FLAG_END_OF_GAME) == true) {
+ if (_state->getBoolFlag(FLAG_END_OF_GAME) == true) {
_dialog->say(_res->_ingameTexts[kTextOhMiSalvador]);
_dialog->say(_res->_ingameTexts[kTextVoyPoriPrincesa]);
@@ -1913,7 +1913,7 @@ void PelrockEngine::doExtraActions(int roomNumber) {
endingScene();
- } else if (_state->getFlag(FLAG_CORRECT_DOOR_CHOSEN) == true) {
+ } else if (_state->getBoolFlag(FLAG_CORRECT_DOOR_CHOSEN) == true) {
_dialog->say(_res->_ingameTexts[kTextOhMiSalvador]);
_dialog->say(_res->_ingameTexts[kTextVoyPoriPrincesa]);
_state->setFlag(FLAG_TRAPDOOR_OPEN, true);
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index e8828f779ac..8b9a9d8aa69 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -652,6 +652,10 @@ struct GameStateData {
return flags[flagIndex];
}
+ bool getBoolFlag(int flagIndex) const {
+ return getFlag(flagIndex) != 0;
+ }
+
void setFlag(int flagIndex, byte value) {
if (flagIndex < 0 || flagIndex >= kNumGameFlags)
return;
Commit: d4878a08f9f7c53b349a68707237f56819f2f040
https://github.com/scummvm/scummvm/commit/d4878a08f9f7c53b349a68707237f56819f2f040
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:50+02:00
Commit Message:
PELROCK: Normalize types for chrono
Changed paths:
engines/pelrock/chrono.h
diff --git a/engines/pelrock/chrono.h b/engines/pelrock/chrono.h
index 602d721d2b0..cbd348868ab 100644
--- a/engines/pelrock/chrono.h
+++ b/engines/pelrock/chrono.h
@@ -25,13 +25,13 @@
namespace Pelrock {
-const int kTickMs = 55;
+const uint32 kTickMs = 55;
const int kHalfTickMultiplier = 2;
class ChronoManager {
private:
uint32 _lastTick = 0;
- byte _speedMultiplier = 1;
+ uint32 _speedMultiplier = 1;
uint32 _frameCount = 0;
bool _pauseCounter = false;
Commit: ebb2a7be7c30769565455af1b69213518f456c42
https://github.com/scummvm/scummvm/commit/ebb2a7be7c30769565455af1b69213518f456c42
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:50+02:00
Commit Message:
PELROCK: Remove extraneous debug lines
Changed paths:
engines/pelrock/dialog.cpp
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index aa586b5a4e8..2894454b0a0 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -281,7 +281,6 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
yPos = CLIP(yPos, 1, 400 - (int)s->getRect().height());
if (g_engine->_shakeEffectState.enabled) {
- debug("Applying shake effect to dialogue, shakeX: %d", g_engine->_shakeEffectState.shakeX);
xPos -= g_engine->_shakeEffectState.shakeX;
}
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 3e33208b8f9..285dde92400 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -1886,11 +1886,10 @@ void PelrockEngine::doExtraActions(int roomNumber) {
_shakeEffectState.disable();
}
if (_state->getBoolFlag(FLAG_PYRAMID_COLLAPSED) == true &&
- // _state->getBoolFlag(FLAG_GUARD_PEEING) == true &&
+ _state->getBoolFlag(FLAG_GUARD_PEEING) == true &&
_state->getFlag(FLAG_PYRAMID_COLLAPSED2) == false) {
_state->setFlag(FLAG_GUARD_PEEING, false);
_state->setFlag(FLAG_PYRAMID_COLLAPSED2, true);
- debug("Pyramid is now active!");
pyramidCollapse();
}
break;
Commit: 244339e0fbd220d61f1caf57eec57815e1cce9da
https://github.com/scummvm/scummvm/commit/244339e0fbd220d61f1caf57eec57815e1cce9da
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:50+02:00
Commit Message:
PELROCK: Fix double-free after swimming pool cutscene
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/pathfinding.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index d40bdcfd95e..7765d9c73c2 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -1588,12 +1588,10 @@ void PelrockEngine::giveStoneToSlaves(int inventoryObject, HotSpot *hotspot) {
playSpecialAnim(1473360, true, mastersX - 6, mastersY - 1, 152, 83, 7);
// Increment stone delivery counter (tracks 0â1â2â3)
- debug("Current stone delivery count: %d", counter);
if (counter < 3) {
_state->setFlag(FLAG_STONE_GIVEN, ++counter);
_room->findSpriteByIndex(0)->zOrder = zIndex;
}
- debug("New stone delivery count: %d", _state->getFlag(FLAG_STONE_GIVEN));
// At 2nd stone delivery: masters starts singing (conversation root 2)
if (counter == 2) {
_state->setCurrentRoot(41, 2, 0);
@@ -1694,7 +1692,7 @@ void PelrockEngine::swimmingPoolCutscene(HotSpot *hotspot) {
guard->animData[0].curFrame = 0;
guard->animData[0].nframes = 1;
// copy idle frame from talking animation
- guard->animData[0].animData[0] = _room->_talkingAnims.animA[0];
+ Common::copy(_room->_talkingAnims.animA[0], _room->_talkingAnims.animA[0] + guard->stride, guard->animData[0].animData[0]);
_alfredState.direction = ALFRED_RIGHT;
walkAndAction(_room->findHotspotByExtra(guard->extra), TALK);
if (shouldQuit()) {
diff --git a/engines/pelrock/pathfinding.cpp b/engines/pelrock/pathfinding.cpp
index 38f8483e9a6..49fe3446ec8 100644
--- a/engines/pelrock/pathfinding.cpp
+++ b/engines/pelrock/pathfinding.cpp
@@ -92,7 +92,7 @@ Common::Point calculateWalkTarget(Common::Array<WalkBox> &walkboxes, int sourceX
if (hotspot != nullptr) {
// if there is a hotspot then the source is the center of the hotspot.
sourceX = hotspot->x + hotspot->w / 2;
- sourceY = hotspot->y + hotspot->h / 2;
+ sourceY = hotspot->y + hotspot->h;
}
// Find nearest walkbox
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 285dde92400..14d790970fd 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -222,9 +222,6 @@ Common::Array<VerbIcon> PelrockEngine::availableActions(HotSpot *hotspot) {
if (hotspot->actionFlags & kActionMaskPush) {
verbs.push_back(PUSH);
}
- if (hotspot->actionFlags & kActionMaskPull) {
- verbs.push_back(PULL);
- }
return verbs;
}
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index c0a6e6b78b2..3b83d558e1e 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -54,11 +54,19 @@ RoomManager::~RoomManager() {
}
void RoomManager::clearTalkingAnims() {
- for (int i = 0; i < _talkingAnims.numFramesAnimA; i++)
- delete[] _talkingAnims.animA[i];
+ for (int i = 0; i < _talkingAnims.numFramesAnimA; i++) {
+ if(_talkingAnims.animA[i]) {
+ delete[] _talkingAnims.animA[i];
+ _talkingAnims.animA[i] = nullptr;
+ }
+ }
delete[] _talkingAnims.animA;
- for (int i = 0; i < _talkingAnims.numFramesAnimB; i++)
- delete[] _talkingAnims.animB[i];
+ for (int i = 0; i < _talkingAnims.numFramesAnimB; i++) {
+ if(_talkingAnims.animB[i]) {
+ delete[] _talkingAnims.animB[i];
+ _talkingAnims.animB[i] = nullptr;
+ }
+ }
delete[] _talkingAnims.animB;
_talkingAnims.animA = nullptr;
_talkingAnims.animB = nullptr;
Commit: 16fae188a6aac16bbdae71fe69340eed80796faf
https://github.com/scummvm/scummvm/commit/16fae188a6aac16bbdae71fe69340eed80796faf
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:51+02:00
Commit Message:
PELROCK: Credits
Changed paths:
engines/pelrock/credits.pl
engines/pelrock/detection.h
diff --git a/engines/pelrock/credits.pl b/engines/pelrock/credits.pl
index 3f3ab6a82f2..3b543b73b79 100644
--- a/engines/pelrock/credits.pl
+++ b/engines/pelrock/credits.pl
@@ -1,3 +1,3 @@
begin_section("Pelrock");
- add_person("Name 1", "Handle 1", "");
+ add_person("Gabriel SanmartÃn", "kelmer", "");
end_section();
diff --git a/engines/pelrock/detection.h b/engines/pelrock/detection.h
index cffa9df0502..45fc229fc44 100644
--- a/engines/pelrock/detection.h
+++ b/engines/pelrock/detection.h
@@ -57,11 +57,11 @@ public:
}
const char *getEngineName() const override {
- return "Pelrock";
+ return "Alfred Pelrock";
}
const char *getOriginalCopyright() const override {
- return "Pelrock (C)";
+ return "(C) 1997 DDM";
}
const DebugChannelDef *getDebugChannels() const override {
Commit: 7707b16203fb1bb411b8bec3c4c914fd299ea209
https://github.com/scummvm/scummvm/commit/7707b16203fb1bb411b8bec3c4c914fd299ea209
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:51+02:00
Commit Message:
PELROCK: Remove unnecessary files
Changed paths:
R engines/pelrock/.gitignore
diff --git a/engines/pelrock/.gitignore b/engines/pelrock/.gitignore
deleted file mode 100644
index 7e97ef32309..00000000000
--- a/engines/pelrock/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-*.o
-*.a
-.deps
Commit: f968301d6f8920531313d6ba6d152ee64b737732
https://github.com/scummvm/scummvm/commit/f968301d6f8920531313d6ba6d152ee64b737732
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:51+02:00
Commit Message:
PELROCK: Make sure to free textSurface in intro video
Changed paths:
engines/pelrock/video/video.cpp
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video/video.cpp
index e5d51272256..f884230d8b2 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video/video.cpp
@@ -48,6 +48,7 @@ VideoManager::VideoManager(
VideoManager::~VideoManager() {
_videoSurface.free();
_introSndFile.close();
+ _textSurface.free();
}
void VideoManager::playIntro() {
Commit: 23a9a6592b7fe679133a96ecec8928a010ea91e6
https://github.com/scummvm/scummvm/commit/23a9a6592b7fe679133a96ecec8928a010ea91e6
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:51+02:00
Commit Message:
PELROCK: Move video to root of the engine
Changed paths:
A engines/pelrock/video.cpp
A engines/pelrock/video.h
R engines/pelrock/video/video.cpp
R engines/pelrock/video/video.h
engines/pelrock/module.mk
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/module.mk b/engines/pelrock/module.mk
index 32053f15ecd..ece444a0612 100644
--- a/engines/pelrock/module.mk
+++ b/engines/pelrock/module.mk
@@ -1,30 +1,30 @@
MODULE := engines/pelrock
MODULE_OBJS = \
- pelrock.o \
actions.o \
+ backgroundbook.o \
+ cdplayer.o \
chrono.o \
computer.o \
console.o \
- metaengine.o \
- room.o \
+ dialog.o \
+ events.o \
fonts/small_font.o \
fonts/large_font.o \
fonts/small_font_double.o \
- util.o \
- resources.o\
- sound.o \
- video/video.o \
- pathfinding.o \
- events.o \
- dialog.o \
- menu.o \
graphics.o \
+ menu.o \
+ metaengine.o \
+ pathfinding.o \
+ pelrock.o \
+ resources.o\
+ room.o \
saveload.o \
- spellbook.o \
slidingpuzzle.o \
- cdplayer.o \
- backgroundbook.o
+ sound.o \
+ spellbook.o \
+ util.o \
+ video.o
# This module can be built as a plugin
ifeq ($(ENABLE_PELROCK), DYNAMIC_PLUGIN)
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index c4fe4a00d4e..593702c97b6 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -50,7 +50,7 @@
#include "pelrock/room.h"
#include "pelrock/sound.h"
#include "pelrock/types.h"
-#include "pelrock/video/video.h"
+#include "pelrock/video.h"
namespace Pelrock {
diff --git a/engines/pelrock/video/video.cpp b/engines/pelrock/video.cpp
similarity index 99%
rename from engines/pelrock/video/video.cpp
rename to engines/pelrock/video.cpp
index f884230d8b2..2495bd2e084 100644
--- a/engines/pelrock/video/video.cpp
+++ b/engines/pelrock/video.cpp
@@ -26,8 +26,7 @@
#include "pelrock/chrono.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
-#include "pelrock/video/video.h"
-#include "video.h"
+#include "pelrock/video.h"
namespace Pelrock {
@@ -60,6 +59,7 @@ void VideoManager::playIntro() {
}
videoFile.seek(0, SEEK_SET);
+
_videoSurface.fillRect(Common::Rect(0, 0, 640, 400), 0);
_textSurface.fillRect(Common::Rect(0, 0, 640, 400), 255);
@@ -108,6 +108,9 @@ void VideoManager::playIntro() {
_sound->playSound(voiceBuffer, voiceData.length, 0);
}
+
+
+
if (_sfxEffect.contains(currentFrame)) {
AudioEffect sfx = _sfxEffect[currentFrame];
VoiceData sfxData = _sounds[sfx.filename];
diff --git a/engines/pelrock/video/video.h b/engines/pelrock/video.h
similarity index 100%
rename from engines/pelrock/video/video.h
rename to engines/pelrock/video.h
Commit: a89f9d1c5312331697874242f794e9c8b2462e3f
https://github.com/scummvm/scummvm/commit/a89f9d1c5312331697874242f794e9c8b2462e3f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:52+02:00
Commit Message:
PELROCK: Header cleanup
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/chrono.cpp
engines/pelrock/console.h
engines/pelrock/detection.cpp
engines/pelrock/dialog.cpp
engines/pelrock/events.cpp
engines/pelrock/graphics.cpp
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/room.cpp
engines/pelrock/saveload.cpp
engines/pelrock/sound.cpp
engines/pelrock/util.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 7765d9c73c2..4e25e8b5629 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -24,7 +24,6 @@
#include "audio/mixer.h"
#include "graphics/paletteman.h"
-#include "pelrock.h"
#include "pelrock/actions.h"
#include "pelrock/backgroundbook.h"
#include "pelrock/cdplayer.h"
diff --git a/engines/pelrock/chrono.cpp b/engines/pelrock/chrono.cpp
index 89d00a69c83..73f091dc016 100644
--- a/engines/pelrock/chrono.cpp
+++ b/engines/pelrock/chrono.cpp
@@ -22,7 +22,6 @@
#include "common/events.h"
#include "common/system.h"
-#include "chrono.h"
#include "pelrock/chrono.h"
#include "pelrock/pelrock.h"
diff --git a/engines/pelrock/console.h b/engines/pelrock/console.h
index 53f5dfca4ce..57c6848c7ad 100644
--- a/engines/pelrock/console.h
+++ b/engines/pelrock/console.h
@@ -24,6 +24,7 @@
#define PELROCK_CONSOLE_H
#include "gui/debugger.h"
+
#include "pelrock/pelrock.h"
namespace Pelrock {
diff --git a/engines/pelrock/detection.cpp b/engines/pelrock/detection.cpp
index d0b46ac7502..90c368e4324 100644
--- a/engines/pelrock/detection.cpp
+++ b/engines/pelrock/detection.cpp
@@ -26,6 +26,7 @@
#include "common/str-array.h"
#include "common/translation.h"
#include "common/util.h"
+
#include "pelrock/detection.h"
#include "pelrock/detection_tables.h"
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 2894454b0a0..5d140a9e999 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -20,7 +20,6 @@
*/
#include "common/stack.h"
-#include "dialog.h"
#include "pelrock/dialog.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
index c12669baa86..355d97ce389 100644
--- a/engines/pelrock/events.cpp
+++ b/engines/pelrock/events.cpp
@@ -20,7 +20,6 @@
*/
#include "common/events.h"
-#include "events.h"
#include "pelrock/events.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index feaf410cb64..ea403aa162d 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -24,7 +24,6 @@
#include "graphics/cursorman.h"
#include "graphics/paletteman.h"
-#include "graphics.h"
#include "pelrock/graphics.h"
#include "pelrock/pelrock.h"
#include "pelrock/util.h"
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index f381375751b..edcd2df4222 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -26,7 +26,6 @@
#include "graphics/paletteman.h"
#include "graphics/thumbnail.h"
-#include "menu.h"
#include "pelrock/menu.h"
#include "pelrock/offsets.h"
#include "pelrock/pelrock.h"
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 14d790970fd..81db3e85cd7 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -27,7 +27,6 @@
#include "graphics/cursorman.h"
#include "graphics/paletteman.h"
-#include "pelrock.h"
#include "pelrock/actions.h"
#include "pelrock/computer.h"
#include "pelrock/console.h"
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 83d09536b6a..b13c58656ca 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -24,7 +24,6 @@
#include "pelrock/pelrock.h"
#include "pelrock/room.h"
#include "pelrock/util.h"
-#include "resources.h"
namespace Pelrock {
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 6242a991895..76ed355e05d 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -23,6 +23,7 @@
#include "common/scummsys.h"
#include "common/stream.h"
+
#include "pelrock/offsets.h"
#include "pelrock/types.h"
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 3b83d558e1e..8ed72978615 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -23,7 +23,6 @@
#include "pelrock/pelrock.h"
#include "pelrock/room.h"
#include "pelrock/util.h"
-#include "room.h"
namespace Pelrock {
diff --git a/engines/pelrock/saveload.cpp b/engines/pelrock/saveload.cpp
index 008d1356b50..3aae8c5c511 100644
--- a/engines/pelrock/saveload.cpp
+++ b/engines/pelrock/saveload.cpp
@@ -20,7 +20,6 @@
*/
#include "common/savefile.h"
-#include "pelrock.h"
#include "pelrock/pelrock.h"
#include "pelrock/types.h"
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 14e24b86d76..2c4e31d7a4d 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -35,7 +35,6 @@
#include "pelrock/pelrock.h"
#include "pelrock/sound.h"
-#include "sound.h"
namespace Pelrock {
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index 012a9a7c90b..c7d3cbcf3a7 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -26,7 +26,6 @@
#include "pelrock/pelrock.h"
#include "pelrock/types.h"
#include "pelrock/util.h"
-#include "util.h"
namespace Pelrock {
Commit: a25a5816706546be757c82a5bba6528ffc018247
https://github.com/scummvm/scummvm/commit/a25a5816706546be757c82a5bba6528ffc018247
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:52+02:00
Commit Message:
PELROCK: Cleans up sliding puzzle
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/slidingpuzzle.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 4e25e8b5629..6e31d2d0dcc 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -664,8 +664,6 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
case 377:
_state->setCurrentRoot(45, 3, 0);
break;
- case 30840:
- break;
case 323:
_state->setCurrentRoot(47, 1, 0);
diff --git a/engines/pelrock/slidingpuzzle.h b/engines/pelrock/slidingpuzzle.h
index 55a47a897ab..e7f37cada51 100644
--- a/engines/pelrock/slidingpuzzle.h
+++ b/engines/pelrock/slidingpuzzle.h
@@ -19,10 +19,9 @@
*
*/
-#ifndef PELROCK_SLIDING_PUZZLE_H
-#define PELROCK_SLIDING_PUZZLE_H
+#ifndef PELROCK_SLIDINGPUZZLE_H
+#define PELROCK_SLIDINGPUZZLE_H
-#include "common/scummsys.h"
#include "graphics/managed_surface.h"
#include "pelrock/events.h"
Commit: e84cbd9ff234d0aa68a8d015ad4f68b1cc1cba2f
https://github.com/scummvm/scummvm/commit/e84cbd9ff234d0aa68a8d015ad4f68b1cc1cba2f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:52+02:00
Commit Message:
PELROCK: Decorate errors with function signature
Changed paths:
engines/pelrock/backgroundbook.cpp
engines/pelrock/computer.cpp
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/video.cpp
diff --git a/engines/pelrock/backgroundbook.cpp b/engines/pelrock/backgroundbook.cpp
index b9c78d1d897..b66776d5f2d 100644
--- a/engines/pelrock/backgroundbook.cpp
+++ b/engines/pelrock/backgroundbook.cpp
@@ -118,7 +118,7 @@ void BackgroundBook::loadRoomNames() {
Common::StringArray roomNames;
Common::File juegoExe;
if (!juegoExe.open(Common::Path("JUEGO.EXE"))) {
- error("Couldnt find file JUEGO.EXE");
+ error("BackgroundBook::loadRoomNames(): Couldnt find file JUEGO.EXE");
}
size_t namesSize = kRoomNamesSize;
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index 1b97e0eb3a1..5e436df9915 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -59,7 +59,7 @@ Common::StringArray split(const Common::String &str) {
void Computer::init() {
Common::File alfred7File;
if (!alfred7File.open("ALFRED.7")) {
- error("Could not open ALFRED.7");
+ error("Computer::init(): Could not open ALFRED.7");
return;
}
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index edcd2df4222..3fe727a6e7e 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -492,7 +492,7 @@ void MenuManager::showCredits() {
_compositeBuffer.clear(0);
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
- error("Could not open ALFRED.7");
+ error("MenuManager::showCredits(): Could not open ALFRED.7");
return;
}
@@ -683,7 +683,7 @@ void MenuManager::loadMenu() {
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
- error("Could not open ALFRED.7");
+ error("MenuManager::loadMenu(): Could not open ALFRED.7");
return;
}
@@ -804,7 +804,7 @@ void MenuManager::loadMenuTexts() {
Common::File exe;
if (!exe.open("JUEGO.EXE")) {
- error("Couldnt find file JUEGO.EXE");
+ error("MenuManager::loadMenuTexts(): Couldnt find file JUEGO.EXE");
}
byte *descBuffer = new byte[kInventoryDescriptionsSize];
exe.seek(kInventoryDescriptionsOffset, SEEK_SET);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 81db3e85cd7..e983c9255f6 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -181,7 +181,7 @@ void PelrockEngine::init() {
void PelrockEngine::loadInventoryArrows() {
Common::File alfred7;
if (!alfred7.open("ALFRED.7")) {
- error("Failed to open ALFRED.7 to load inventory arrows");
+ error("PelrockEngine::loadInventoryArrows(): Failed to open ALFRED.7 to load inventory arrows");
return;
}
alfred7.seek(kInventoryArrowsOffset, SEEK_SET);
@@ -1676,7 +1676,7 @@ void PelrockEngine::checkMouseHover() {
void PelrockEngine::setScreen(int roomNumber) {
Common::File roomFile;
if (!roomFile.open(Common::Path("ALFRED.1"))) {
- error("Could not open ALFRED.1");
+ error("PelrockEngine::setScreen(): Could not open ALFRED.1");
return;
}
changeCursor(DEFAULT);
@@ -2094,7 +2094,7 @@ void PelrockEngine::endingScene() {
g_system->getPaletteManager()->setPalette(palette, 0, 256);
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
- error("Could not open ALFRED.7");
+ error("PelrockEngine::endingScene(): Could not open ALFRED.7");
return;
}
byte *decompressedBuf = nullptr;
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index b13c58656ca..68a40a352ce 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -130,7 +130,7 @@ ResourceManager::~ResourceManager() {
void ResourceManager::loadCursors() {
Common::File alfred7File;
if (!alfred7File.open("ALFRED.7")) {
- error("Couldnt find file ALFRED.7");
+ error("ResourceManager::loadCursors(): Couldnt find file ALFRED.7");
}
for (int i = 0; i < 5; i++) {
uint32 cursorOffset = cursor_offsets[i];
@@ -144,7 +144,7 @@ void ResourceManager::loadCursors() {
void ResourceManager::loadInteractionIcons() {
Common::File alfred7File;
if (!alfred7File.open("ALFRED.7")) {
- error("Couldnt find file ALFRED.7");
+ error("ResourceManager::loadInteractionIcons(): Couldnt find file ALFRED.7");
}
alfred7File.seek(kBalloonFramesOffset, SEEK_SET);
@@ -163,7 +163,7 @@ void ResourceManager::loadInteractionIcons() {
alfred7File.close();
Common::File alfred4File;
if (!alfred4File.open("ALFRED.4")) {
- error("Couldnt find file ALFRED.4");
+ error("ResourceManager::loadInteractionIcons(): Couldnt find file ALFRED.4");
}
int iconSize = kVerbIconHeight * kVerbIconWidth;
@@ -177,7 +177,7 @@ void ResourceManager::loadInteractionIcons() {
void ResourceManager::loadAlfredAnims() {
Common::File alfred3;
if (!alfred3.open(Common::Path("ALFRED.3"))) {
- error("Could not open ALFRED.3");
+ error("ResourceManager::loadAlfredAnims(): Could not open ALFRED.3");
return;
}
int alfred3Size = alfred3.size();
@@ -256,7 +256,7 @@ void ResourceManager::loadAlfredAnims() {
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
- error("Could not open ALFRED.7");
+ error("ResourceManager::loadAlfredAnims(): Could not open ALFRED.7");
return;
}
int spriteMapSize = frameSize * 11;
@@ -299,7 +299,7 @@ void ResourceManager::loadAlfredAnims() {
void ResourceManager::loadOtherSpecialAnim(uint32 offset, bool rleCompressed, byte *&buffer, size_t &bufferSize) {
Common::File alfred7;
if (!alfred7.open(Common::Path("ALFRED.7"))) {
- error("Could not open ALFRED.7");
+ error("ResourceManager::loadOtherSpecialAnim(): Could not open ALFRED.7");
return;
}
@@ -321,7 +321,7 @@ void ResourceManager::loadAlfredSpecialAnim(int numAnim, bool reverse) {
Common::String filename = Common::String::format("ALFRED.%d", anim.numAlfred);
Common::File alfredFile;
if (!alfredFile.open(Common::Path(filename))) {
- error("Could not open %s", filename.c_str());
+ error("ResourceManager::loadAlfredSpecialAnim(): Could not open %s", filename.c_str());
return;
}
@@ -367,7 +367,7 @@ void ResourceManager::loadInventoryItems() {
// loadInventoryDescriptions();
Common::File alfred4File;
if (!alfred4File.open("ALFRED.4")) {
- error("Couldnt find file ALFRED.4");
+ error("ResourceManager::loadInventoryItems(): Couldnt find file ALFRED.4");
}
uint32 iconsSize = alfred4File.size() - kInventoryIconsTailSize;
byte *iconData = new byte[iconsSize];
@@ -385,7 +385,7 @@ void ResourceManager::loadHardcodedText() {
Common::File exe;
if (!exe.open("JUEGO.EXE")) {
- error("Couldnt find file JUEGO.EXE");
+ error("ResourceManager::loadHardcodedText(): Couldnt find file JUEGO.EXE");
}
byte *descBuffer = new byte[kAlfredResponsesSize];
exe.seek(kAlfredResponsesOffset, SEEK_SET);
@@ -428,7 +428,7 @@ Common::Array<Common::StringArray> ResourceManager::loadComputerText() {
Common::File exe;
if (!exe.open("JUEGO.EXE")) {
- error("Couldnt find file JUEGO.EXE");
+ error("ResourceManager::loadComputerText(): Couldnt find file JUEGO.EXE");
}
int bufSize = kComputerTextSize;
byte *computerTextBuf = new byte[bufSize];
@@ -444,7 +444,7 @@ Common::Array<Common::StringArray> ResourceManager::loadComputerText() {
void ResourceManager::getExtraScreen(int screenIndex, byte *screenBuf, byte *palette) {
Common::File alfred7;
if (!alfred7.open("ALFRED.7")) {
- error("Couldnt find file ALFRED.7");
+ error("ResourceManager::getExtraScreen(): Couldnt find file ALFRED.7");
}
ExtraScreen screen = extraScreens[screenIndex];
mergeRleBlocks(&alfred7, screen.offset, 8, screenBuf);
@@ -461,7 +461,7 @@ void ResourceManager::getExtraScreen(int screenIndex, byte *screenBuf, byte *pal
Common::Array<Common::StringArray> ResourceManager::getCredits() {
Common::File exe;
if (!exe.open("JUEGO.EXE")) {
- error("Couldnt find file JUEGO.EXE");
+ error("ResourceManager::getCredits(): Couldnt find file JUEGO.EXE");
}
byte *descBuffer = new byte[kCreditsSize];
exe.seek(kCreditsOffset, SEEK_SET);
@@ -527,7 +527,7 @@ Common::Array<Common::StringArray> ResourceManager::processTextData(byte *data,
Pelrock::Sticker ResourceManager::getSticker(int stickerIndex) {
Common::File alfred6File;
if (!alfred6File.open("ALFRED.6")) {
- error("Couldnt find file ALFRED.6");
+ error("ResourceManager::getSticker(): Couldnt find file ALFRED.6");
}
uint32 stickerOffset = stickerOffsets[stickerIndex];
@@ -545,7 +545,7 @@ Pelrock::Sticker ResourceManager::getSticker(int stickerIndex) {
byte *ResourceManager::loadStickerPixels(const Sticker &sticker) {
Common::File alfred6File;
if (!alfred6File.open("ALFRED.6")) {
- error("Couldnt find file ALFRED.6");
+ error("ResourceManager::loadStickerPixels(): Couldnt find file ALFRED.6");
}
uint32 pixelOffset = stickerOffsets[sticker.stickerIndex] + 6; // skip x(2)+y(2)+w(1)+h(1)
alfred6File.seek(pixelOffset, SEEK_SET);
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 8ed72978615..37661d86e65 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -97,7 +97,7 @@ void RoomManager::loadWaterPaletteRemap() {
// Extra remap for water effect
Common::File exe;
if (!exe.open("JUEGO.EXE")) {
- error("Couldnt find file JUEGO.EXE");
+ error("RoomManager::loadWaterPaletteRemap(): Couldnt find file JUEGO.EXE");
}
exe.seek(kPaletteRemapOffset, SEEK_SET);
exe.read(_paletteRemaps[4], 256);
@@ -935,7 +935,7 @@ Common::Array<HotSpot> RoomManager::unifyHotspots(Common::Array<Pelrock::Sprite>
void RoomManager::init() {
Common::File alfred8;
if (!alfred8.open("ALFRED.8")) {
- error("Couldnt find file ALFRED.8");
+ error("RoomManager::init(): Couldnt find file ALFRED.8");
}
}
@@ -1191,7 +1191,7 @@ void RoomManager::addDisabledChoice(ChoiceOption choice) {
void RoomManager::resetMetadataDefaults(byte room, byte *&data, size_t size) {
Common::File alfred8;
if (!alfred8.open("ALFRED.8")) {
- error("Couldnt find file ALFRED.8");
+ error("RoomManager::resetMetadataDefaults(): Couldnt find file ALFRED.8");
}
bool roomDone = false;
while (!alfred8.eos() && !roomDone) {
@@ -1226,7 +1226,7 @@ void RoomManager::loadRoomTalkingAnimations(int roomNumber) {
TalkingAnims talkHeader;
Common::File talkFile;
if (!talkFile.open("ALFRED.2")) {
- error("Couldnt find file ALFRED.2");
+ error("RoomManager::loadRoomTalkingAnimations(): Couldnt find file ALFRED.2");
}
talkFile.seek(offset, SEEK_SET);
diff --git a/engines/pelrock/video.cpp b/engines/pelrock/video.cpp
index 2495bd2e084..c5b61654d0c 100644
--- a/engines/pelrock/video.cpp
+++ b/engines/pelrock/video.cpp
@@ -40,7 +40,7 @@ VideoManager::VideoManager(
_videoSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
_textSurface.create(640, 400, Graphics::PixelFormat::createFormatCLUT8());
if (!_introSndFile.open("introsnd.dat")) {
- error("Could not open introsnd.dat");
+ error("VideoManager::VideoManager(): Could not open introsnd.dat");
}
}
@@ -54,7 +54,7 @@ void VideoManager::playIntro() {
initMetadata();
Common::File videoFile;
if (!videoFile.open("ESCENAX.SSN")) {
- error("Could not open ESCENAX.SSN");
+ error("VideoManager::playIntro(): Could not open ESCENAX.SSN");
return;
}
videoFile.seek(0, SEEK_SET);
@@ -268,7 +268,7 @@ void VideoManager::presentFrame() {
void VideoManager::initMetadata() {
Common::File metadataFile;
if (!metadataFile.open("ESCENAX.SCR")) {
- error("Could not open ESCENAX.SCR");
+ error("VideoManager::initMetadata(): Could not open ESCENAX.SCR");
return;
}
Commit: 9e1d34ce2eba5211d3fe39d0838a2b564fce2143
https://github.com/scummvm/scummvm/commit/9e1d34ce2eba5211d3fe39d0838a2b564fce2143
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:53+02:00
Commit Message:
PELROCK: Simplify pixel setting in fonts
Changed paths:
engines/pelrock/detection_tables.h
engines/pelrock/fonts/large_font.cpp
engines/pelrock/fonts/small_font.cpp
engines/pelrock/fonts/small_font_double.cpp
engines/pelrock/room.cpp
diff --git a/engines/pelrock/detection_tables.h b/engines/pelrock/detection_tables.h
index eb5c5c057cb..1e3944454b7 100644
--- a/engines/pelrock/detection_tables.h
+++ b/engines/pelrock/detection_tables.h
@@ -22,7 +22,7 @@
namespace Pelrock {
const PlainGameDescriptor pelrockGames[] = {
- { "pelrock", "Pelrock" },
+ { "pelrock", "Alfred Pelrock: En Busca de un Sueño" },
{ 0, 0 }
};
diff --git a/engines/pelrock/fonts/large_font.cpp b/engines/pelrock/fonts/large_font.cpp
index 7294b2ef8bf..2228bda30c9 100644
--- a/engines/pelrock/fonts/large_font.cpp
+++ b/engines/pelrock/fonts/large_font.cpp
@@ -132,9 +132,9 @@ void LargeFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint3
if (px < 0 || px >= dst->w || py < 0 || py >= dst->h)
continue;
if (val == 1) {
- *((byte *)dst->getBasePtr(px, py)) = 0;
+ dst->setPixel(px, py, 0);
} else if (val == 2) {
- *((byte *)dst->getBasePtr(px, py)) = color;
+ dst->setPixel(px, py, color);
}
}
}
diff --git a/engines/pelrock/fonts/small_font.cpp b/engines/pelrock/fonts/small_font.cpp
index d1de37d9a5c..083c9adc3f5 100644
--- a/engines/pelrock/fonts/small_font.cpp
+++ b/engines/pelrock/fonts/small_font.cpp
@@ -65,7 +65,7 @@ void SmallFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint3
bool pixelOn = (rowByte & (0x80 >> bit)) != 0;
if (pixelOn) {
if ((x + bit) < dst->w && (y + i) < dst->h) {
- *((byte *)dst->getBasePtr(x + bit, y + i)) = color;
+ dst->setPixel(x + bit, y + i, color);
}
}
}
diff --git a/engines/pelrock/fonts/small_font_double.cpp b/engines/pelrock/fonts/small_font_double.cpp
index 4ebc5a580ed..4f1484685ef 100644
--- a/engines/pelrock/fonts/small_font_double.cpp
+++ b/engines/pelrock/fonts/small_font_double.cpp
@@ -42,8 +42,8 @@ void DoubleSmallFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y,
int yPos = y + (i * 2);
if (pixelOn) {
if ((x + bit) < dst->w && (yPos + 1) < dst->h) {
- *((byte *)dst->getBasePtr(x + bit, yPos)) = color;
- *((byte *)dst->getBasePtr(x + bit, yPos + 1)) = color;
+ dst->setPixel(x + bit, yPos, color);
+ dst->setPixel(x + bit, yPos + 1, color);
}
}
}
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 37661d86e65..1fe5be938da 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -1311,7 +1311,7 @@ static uint32 readUint24(Common::ReadStream &stream) {
byte *RoomManager::loadShadowMap(int roomNumber) {
Common::File shadowMapFile;
if (!shadowMapFile.open("ALFRED.5")) {
- error("Couldnt find file ALFRED.5");
+ error("RoomManager::loadShadowMap(): Couldnt find file ALFRED.5");
}
uint32 entryOffset = roomNumber * 6;
@@ -1339,7 +1339,7 @@ void RoomManager::loadRemaps(int roomNumber) {
Common::File remapFile;
if (!remapFile.open("ALFRED.9")) {
- error("Couldnt find file ALFRED.9");
+ error("RoomManager::loadRemaps(): Couldnt find file ALFRED.9");
}
uint32 remapOffset = /* 0x200 + */ (roomNumber * 1024);
Commit: c83cb780a19ac22fc7239e71862087a22e2be8ac
https://github.com/scummvm/scummvm/commit/c83cb780a19ac22fc7239e71862087a22e2be8ac
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:53+02:00
Commit Message:
PELROCK: Fixes on syntax according to code reviews
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/events.cpp
engines/pelrock/graphics.cpp
engines/pelrock/menu.cpp
engines/pelrock/menu.h
engines/pelrock/resources.cpp
engines/pelrock/resources.h
engines/pelrock/util.cpp
engines/pelrock/util.h
engines/pelrock/video.cpp
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index 6e31d2d0dcc..e42b8e12774 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -514,14 +514,13 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
advanceQuotesConversation(rootIndex, room);
break;
case 364: // riddle wrong answer: advance to next riddle
- {
- int targetIndex = rootIndex + 1;
if (rootIndex == 43) {
- targetIndex = 27; // skip riddle explanation
+ _state->setCurrentRoot(room, 27, 0); // skip riddle explanation
+ }
+ else {
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
}
- _state->setCurrentRoot(room, targetIndex, 0);
break;
- }
case 365: // riddle correct: set riddle-solved flag
_state->setFlag(FLAG_SOLVED_PARADOX, 1);
_state->setCurrentRoot(room, 1, 0);
@@ -605,11 +604,10 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
case 308: {
- int targetBranch = rootIndex + 1;
- if (targetBranch > 17) {
- targetBranch = 2;
- }
- _state->setCurrentRoot(room, targetBranch, 0);
+ if (rootIndex + 1 > 17)
+ _state->setCurrentRoot(room, 2, 0);
+ else
+ _state->setCurrentRoot(room, rootIndex + 1, 0);
break;
}
/* pyramid merchant*/
@@ -656,11 +654,11 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
_state->setCurrentRoot(45, 1, 0);
_sound->playSound("TWANGZZZ.SMP", 0);
break;
- case 376: {
+ case 376:
playAlfredSpecialAnim(14);
loadExtraScreenAndPresent(12);
_state->setCurrentRoot(45, 2, 0);
- } break;
+ break;
case 377:
_state->setCurrentRoot(45, 3, 0);
break;
@@ -1300,7 +1298,6 @@ void PelrockEngine::pickUpBook(int i) {
_alfredState.isWalkingCancelable = false;
walkAndAction(_room->findHotspotByExtra(358), TALK);
if (!_state->hasInventoryItem(3)) {
-
_state->setCurrentRoot(9, 0, 0);
} else {
_state->setCurrentRoot(9, 3, 0);
@@ -1481,7 +1478,6 @@ void PelrockEngine::giveWaterToGuard(int inventoryObject, HotSpot *hotspot) {
}
void PelrockEngine::guardMovement() {
-
// guard running
Sprite *sprite = _room->findSpriteByIndex(0);
sprite->animData[0].nframes = 5;
@@ -2249,18 +2245,12 @@ void PelrockEngine::sayRandomIncorrectResponse() {
void PelrockEngine::chooseCorrectDoor() {
playAlfredSpecialAnim(1);
- byte puertaBuena = _state->getFlag(FLAG_CORRECT_DOOR);
- if (puertaBuena == 0) { // if not set yet, choose randomly
- int choice = getRandomNumber(1);
- _state->setFlag(FLAG_CORRECT_DOOR, choice + 1);
- }
- puertaBuena = _state->getFlag(FLAG_CORRECT_DOOR);
- Common::String doorText = _res->_izquierda;
- if (puertaBuena == 1) {
- doorText = _res->_izquierda;
- } else if (puertaBuena == 2) {
- doorText = _res->_derecha;
+ byte correctDoor = _state->getFlag(FLAG_CORRECT_DOOR);
+ if (correctDoor == 0) { // if not set yet, choose randomly
+ _state->setFlag(FLAG_CORRECT_DOOR, getRandomNumber(1) + 1);
}
+ correctDoor = _state->getFlag(FLAG_CORRECT_DOOR);
+ Common::String doorText = (correctDoor == 1) ? _res->_left : _res->_right;
Common::StringArray fullTextArray = _res->_ingameTexts[kTextPuertaAutenticaIzquierda];
fullTextArray[0] = fullTextArray[0].substr(0, 45);
fullTextArray[0].append(doorText);
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index 5d140a9e999..b111b899d73 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -284,7 +284,6 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
}
_screen->transBlitFrom(*s, s->getRect(), Common::Point(xPos, yPos), 255);
- // drawPos(_screen, xPos, yPos, speakerId);
_screen->markAllDirty();
_screen->update();
diff --git a/engines/pelrock/events.cpp b/engines/pelrock/events.cpp
index 355d97ce389..abd73d25506 100644
--- a/engines/pelrock/events.cpp
+++ b/engines/pelrock/events.cpp
@@ -75,11 +75,7 @@ void PelrockEventManager::pollEvent() {
_rightMouseButton = 1;
break;
case Common::EVENT_RBUTTONUP:
- if (_rightMouseButton == 1) {
- _rightMouseClicked = true;
- } else {
- _rightMouseClicked = false;
- }
+ _rightMouseClicked = (_rightMouseButton == 1);
_rightMouseButton = 0;
break;
default:
@@ -100,7 +96,6 @@ void PelrockEventManager::pollEvent() {
void PelrockEventManager::waitForKey() {
bool waitForKey = false;
Common::Event e;
- debug("Waiting for key!");
while (!waitForKey && !g_engine->shouldQuit()) {
while (g_system->getEventManager()->pollEvent(e)) {
if (e.type == Common::EVENT_KEYDOWN) {
diff --git a/engines/pelrock/graphics.cpp b/engines/pelrock/graphics.cpp
index ea403aa162d..863d107e4cb 100644
--- a/engines/pelrock/graphics.cpp
+++ b/engines/pelrock/graphics.cpp
@@ -163,7 +163,6 @@ void GraphicsManager::copyBackgroundToBuffer() {
void GraphicsManager::presentFrame() {
g_engine->_screen->blitFrom(g_engine->_compositeBuffer);
- // g_engine->paintDebugLayer();
g_engine->_screen->markAllDirty();
}
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 3fe727a6e7e..32268424842 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -344,7 +344,7 @@ bool MenuManager::checkMouseClick(int x, int y) {
break;
}
// CANCEL
- if (_cancelarRect.contains(x, y)) {
+ if (_cancelRect.contains(x, y)) {
_editingSaveSlot = -1;
backToMainMenu();
break;
@@ -372,8 +372,8 @@ bool MenuManager::checkMouseClick(int x, int y) {
_saveGamePage++;
break;
}
- // CANCELAR
- if (_cancelarRect.contains(x, y)) {
+ // Cancel
+ if (_cancelRect.contains(x, y)) {
backToMainMenu();
break;
}
@@ -938,8 +938,8 @@ void MenuManager::drawSaves() {
}
// CANCEL row
- _cancelarRect = Common::Rect(startX - 2, y - 1, startX + overlayW - 2, y + _textLineH);
- byte cancelColor = _cancelarRect.contains(mousePos) ? 18 : kWhiteColor;
+ _cancelRect = Common::Rect(startX - 2, y - 1, startX + overlayW - 2, y + _textLineH);
+ byte cancelColor = _cancelRect.contains(mousePos) ? 18 : kWhiteColor;
Common::String cancelText = _menuTexts[4][0].substr(2, _menuTexts[4][0].size() - 2);
drawText(_compositeBuffer, g_engine->_smallFont, cancelText, startX, y, overlayW, cancelColor);
}
diff --git a/engines/pelrock/menu.h b/engines/pelrock/menu.h
index 04f89c96371..a8952090c57 100644
--- a/engines/pelrock/menu.h
+++ b/engines/pelrock/menu.h
@@ -206,7 +206,7 @@ private:
int _saveGamePage = 0;
int _editingSaveSlot = -1; // -1 = not editing any slot
Common::String _editingName; // name being typed for a save
- Common::Rect _cancelarRect; // hit-rect for the CANCELAR row
+ Common::Rect _cancelRect; // hit-rect for the CANCELAR row
Common::Array<Common::Rect> _saveSlotRects; // hit-rects for the 8 visible save rows
Common::StringArray _saveDescriptions; // indexed by slot 0-255
};
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 68a40a352ce..13d14dcf73a 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -392,8 +392,8 @@ void ResourceManager::loadHardcodedText() {
exe.read(descBuffer, kAlfredResponsesSize);
_ingameTexts = processTextData(descBuffer, kAlfredResponsesSize);
// exe.seek(-1, SEEK_CUR);
- _izquierda = exe.readString();
- _derecha = exe.readString(0xFD);
+ _left = exe.readString();
+ _right = exe.readString(0xFD);
byte *terminatorBuffer = new byte[39];
exe.seek(kConversationTerminatorOffset, SEEK_SET);
exe.read(terminatorBuffer, 39);
diff --git a/engines/pelrock/resources.h b/engines/pelrock/resources.h
index 76ed355e05d..315fa895a4a 100644
--- a/engines/pelrock/resources.h
+++ b/engines/pelrock/resources.h
@@ -83,8 +83,8 @@ public:
byte *_verbIcons[9];
byte *_popUpBalloon = nullptr;
Common::Array<Common::StringArray> _ingameTexts;
- Common::String _izquierda;
- Common::String _derecha;
+ Common::String _left;
+ Common::String _right;
Common::String _conversationTerminator;
// Special anims
diff --git a/engines/pelrock/util.cpp b/engines/pelrock/util.cpp
index c7d3cbcf3a7..b9cbfef8ba9 100644
--- a/engines/pelrock/util.cpp
+++ b/engines/pelrock/util.cpp
@@ -250,21 +250,21 @@ byte decodeChar(byte b) {
switch (b) {
case 0x82:
- return special_chars[1];
+ return specialChars[1];
case 0x83:
- return special_chars[0];
+ return specialChars[0];
case 0x80:
- return special_chars[3]; // n tilde
+ return specialChars[3]; // n tilde
case 0x7F:
- return special_chars[4];
+ return specialChars[4];
case 0x7E:
- return special_chars[5];
+ return specialChars[5];
case 0x7D:
- return special_chars[6];
+ return specialChars[6];
case 0x7C:
- return special_chars[7];
+ return specialChars[7];
case 0x7B:
- return special_chars[8];
+ return specialChars[8];
default:
return b;
}
diff --git a/engines/pelrock/util.h b/engines/pelrock/util.h
index 95f73dcff12..865558294e7 100644
--- a/engines/pelrock/util.h
+++ b/engines/pelrock/util.h
@@ -48,7 +48,7 @@ void drawRect(Graphics::ManagedSurface *surface, int x, int y, int w, int h, byt
void drawPos(Graphics::ManagedSurface *surface, int x, int y, byte color);
void drawPaletteSquares(Graphics::ManagedSurface &dest, byte *palette);
-static const int special_chars[] = {
+static const int specialChars[] = {
168, // inverted ?
173, // inverted !
165, // capital N tilde
diff --git a/engines/pelrock/video.cpp b/engines/pelrock/video.cpp
index c5b61654d0c..7047045d89e 100644
--- a/engines/pelrock/video.cpp
+++ b/engines/pelrock/video.cpp
@@ -179,14 +179,11 @@ byte *VideoManager::decodeCopyBlock(byte *data, uint32 offset) {
// the first 3 bytes are the offset within the screen to which to
// copy the bytes. The 5th byte is the length of the block to copy.
while (true) {
- byte dest_lo = data[pos];
- byte dest_mid = data[pos + 1];
- byte dest_hi = data[pos + 2];
byte length = data[pos + 4];
if (length == 0) {
break;
}
- uint32 dest_offset = dest_lo | (dest_mid << 8) | (dest_hi << 16);
+ uint32 dest_offset = READ_LE_UINT24(data + pos);
if (dest_offset + length > 256000) {
break;
Commit: 1dfb93703d8326d1e5764d6179d5bef668b4bbd6
https://github.com/scummvm/scummvm/commit/1dfb93703d8326d1e5764d6179d5bef668b4bbd6
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:53+02:00
Commit Message:
PELROCK: Syntax fixes from code reviews
Changed paths:
engines/pelrock/actions.cpp
engines/pelrock/dialog.cpp
engines/pelrock/menu.cpp
engines/pelrock/pelrock.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/actions.cpp b/engines/pelrock/actions.cpp
index e42b8e12774..5062db15a0e 100644
--- a/engines/pelrock/actions.cpp
+++ b/engines/pelrock/actions.cpp
@@ -500,12 +500,10 @@ void PelrockEngine::dialogActionTrigger(uint16 actionTrigger, byte room, byte ro
break;
}
case 360: // neutral reset: counter = 0
- {
_state->setFlag(FLAG_CORRECT_ANSWERS, 0);
_state->setCurrentRoot(room, rootIndex + 1, 0);
advanceQuotesConversation(rootIndex, room);
break;
- }
case 361: // "no sé" (I don't know): no counter change, just advance
_state->setCurrentRoot(room, rootIndex + 1, 0);
break;
@@ -1225,8 +1223,8 @@ void PelrockEngine::usePumpkinWithRiver(int inventoryObject, HotSpot *hotspot) {
playAlfredSpecialAnim(5);
{
// Copy crocodile into background so it sticks during fade
- static const int srcX = 189, srcY = 260;
- static const int copyW = 127, copyH = 80;
+ const int srcX = 189, srcY = 260;
+ const int copyW = 127, copyH = 80;
Common::Rect copyRect(srcX, srcY, srcX + copyW, srcY + copyH);
_currentBackground.blitFrom(_compositeBuffer, copyRect, Common::Point(srcX, srcY));
}
@@ -1521,7 +1519,7 @@ void PelrockEngine::pickUpStone(HotSpot *hotspot) {
}
void PelrockEngine::playSpecialAnim(uint32 offset, bool compressed, int x, int y, int width, int height, int numFrames) {
- size_t frameSize = width * height;
+ uint frameSize = width * height;
size_t bufSize = frameSize * numFrames;
byte *animData = new byte[bufSize];
_res->loadOtherSpecialAnim(offset, compressed, animData, bufSize);
@@ -1915,11 +1913,10 @@ void PelrockEngine::performActionTrigger(uint16 actionTrigger) {
_dialog->say(_res->_ingameTexts[kTextNoSeTeCurraCercarte]);
break;
}
- case 375: {
+ case 375:
teleportToPrincess();
break;
}
- }
}
// Bresenham line draw using a 256-byte palette remap table (semi-transparent effect).
@@ -1970,6 +1967,7 @@ void PelrockEngine::teleportToPrincess() {
_events->pollEvent();
renderScene(OVERLAY_NONE);
_screen->update();
+ g_system->delayMillis(10);
}
_sound->playSound(_room->_roomSfx[3], 0);
@@ -2225,7 +2223,7 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
book.run();
break;
}
- default: {
+ default:
// Original game incorrectly checked until object 47; Reading any book.
if (inventoryObject >= 11 && inventoryObject <= 58) {
playAlfredSpecialAnim(0);
@@ -2235,7 +2233,6 @@ void PelrockEngine::useOnAlfred(int inventoryObject) {
sayRandomIncorrectResponse();
break;
}
- }
}
void PelrockEngine::sayRandomIncorrectResponse() {
diff --git a/engines/pelrock/dialog.cpp b/engines/pelrock/dialog.cpp
index b111b899d73..312ee25c896 100644
--- a/engines/pelrock/dialog.cpp
+++ b/engines/pelrock/dialog.cpp
@@ -251,7 +251,7 @@ void DialogManager::displayDialogue(Common::Array<Common::Array<Common::String>>
uint32 pageTtlMs = calcPageTtlMs(dialogueLines[curPage]);
uint32 pageStartMs = g_system->getMillis();
- if(speakerId != kAlfredColor) {
+ if (speakerId != kAlfredColor) {
_isNPCTalking = true;
}
// Render loop - display text and wait for click or TTL
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 32268424842..e0a9d47aa9b 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -927,7 +927,7 @@ void MenuManager::drawSaves() {
drawText(_compositeBuffer, g_engine->_smallFont, slotNumber, startX, y, overlayW, kNumberColor);
drawText(_compositeBuffer, g_engine->_smallFont, slotText, startX + slotNumberWidth, y, overlayW - slotNumberWidth, textColor);
- if(_editingSaveSlot == slot) {
+ if (_editingSaveSlot == slot) {
// Draw cursor
int cursorX = startX + slotNumberWidth + g_engine->_smallFont->getStringWidth(slotText);
drawText(_compositeBuffer, g_engine->_smallFont, Common::String(kCursorChar), cursorX, y, overlayW - (cursorX - startX), kWhiteColor);
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index e983c9255f6..6e19f5b899b 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -280,7 +280,6 @@ void PelrockEngine::travelToEgypt() {
int frameCount = 0;
while (!shouldQuit() && frameCount < 96) {
_events->pollEvent();
- g_system->delayMillis(10);
_chrono->updateChrono();
if (_chrono->_gameTick && _chrono->getFrameCount() % 2 == 0) {
int colorIndex = 160 + frameCount;
@@ -294,6 +293,7 @@ void PelrockEngine::travelToEgypt() {
_screen->markAllDirty();
_screen->update();
+ g_system->delayMillis(10);
}
_graphics->clearScreen();
@@ -388,8 +388,7 @@ bool PelrockEngine::renderScene(int overlayMode) {
return true;
}
- switch (_room->_currentRoomNumber) {
- case 2: {
+ if (_room->_currentRoomNumber == 2) {
// Easter egg in room 2, pressing x 250 times after the character has mentioned it triggers a special dialog
if (_events->_lastKeyEvent == Common::KEYCODE_x) {
_events->_lastKeyEvent = Common::KEYCODE_INVALID;
@@ -400,8 +399,6 @@ bool PelrockEngine::renderScene(int overlayMode) {
}
}
}
- break;
- }
}
return false;
@@ -860,7 +857,7 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
}
break;
}
- case ALFRED_TALKING: {
+ case ALFRED_TALKING:
drawAlfred(_res->alfredTalkFrames[_alfredState.direction][_alfredState.curFrame]);
if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
_alfredState.curFrame++;
@@ -868,7 +865,6 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
_alfredState.curFrame = 0;
}
break;
- }
case ALFRED_COMB: {
drawAlfred(_res->alfredCombFrames[_alfredState.direction][_alfredState.curFrame]);
@@ -1125,54 +1121,37 @@ void PelrockEngine::drawNextFrame(Sprite *sprite) {
}
void PelrockEngine::paintDebugLayer() {
- bool showWalkboxes = true;
-
- if (showWalkboxes) {
- for (uint i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
- WalkBox box = _room->_currentRoomWalkboxes[i];
- drawRect(_screen, box.x, box.y, box.w, box.h, 13);
- }
+ for (uint i = 0; i < _room->_currentRoomWalkboxes.size(); i++) {
+ WalkBox box = _room->_currentRoomWalkboxes[i];
+ drawRect(_screen, box.x, box.y, box.w, box.h, 13);
}
- bool showSprites = true;
- if (showSprites) {
- for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
- Sprite sprite = _room->_currentRoomAnims[i];
- if (sprite.zOrder == 255) {
- continue;
- }
- drawRect(_screen, sprite.x, sprite.y, sprite.w, sprite.h, 14);
- _smallFont->drawString(_screen, Common::String::format("S %d", sprite.index), sprite.x + 2, sprite.y, 640, 14);
+ for (uint i = 0; i < _room->_currentRoomAnims.size(); i++) {
+ Sprite sprite = _room->_currentRoomAnims[i];
+ if (sprite.zOrder == 255) {
+ continue;
}
+ drawRect(_screen, sprite.x, sprite.y, sprite.w, sprite.h, 14);
+ _smallFont->drawString(_screen, Common::String::format("S %d", sprite.index), sprite.x + 2, sprite.y, 640, 14);
}
- bool showHotspots = true;
- if (showHotspots) {
- for (uint i = 0; i < _room->_currentRoomHotspots.size(); i++) {
- HotSpot hotspot = _room->_currentRoomHotspots[i];
- if (!hotspot.isEnabled || hotspot.isSprite)
- continue;
- drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 12);
- _smallFont->drawString(_screen, Common::String::format("HS %d - %d", hotspot.index - _room->_currentRoomAnims.size(), hotspot.extra), hotspot.x + 2, hotspot.y + 2, 640, 12);
- }
+ for (uint i = 0; i < _room->_currentRoomHotspots.size(); i++) {
+ HotSpot hotspot = _room->_currentRoomHotspots[i];
+ if (!hotspot.isEnabled || hotspot.isSprite)
+ continue;
+ drawRect(_screen, hotspot.x, hotspot.y, hotspot.w, hotspot.h, 12);
+ _smallFont->drawString(_screen, Common::String::format("HS %d - %d", hotspot.index - _room->_currentRoomAnims.size(), hotspot.extra), hotspot.x + 2, hotspot.y + 2, 640, 12);
}
-
- bool showExits = true;
- if (showExits) {
- for (uint i = 0; i < _room->_currentRoomExits.size(); i++) {
- Exit exit = _room->_currentRoomExits[i];
- drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 200 + i);
- _smallFont->drawString(_screen, Common::String::format("Exit %d -> Room %d", i, exit.targetRoom), exit.x + 2, exit.y + 2, 640, 14);
- }
+ for (uint i = 0; i < _room->_currentRoomExits.size(); i++) {
+ Exit exit = _room->_currentRoomExits[i];
+ drawRect(_screen, exit.x, exit.y, exit.w, exit.h, 200 + i);
+ _smallFont->drawString(_screen, Common::String::format("Exit %d -> Room %d", i, exit.targetRoom), exit.x + 2, exit.y + 2, 640, 14);
}
drawPos(_screen, _alfredState.x, _alfredState.y, 13);
drawPos(_screen, _alfredState.x, _alfredState.y - kAlfredFrameHeight, 13);
drawPos(_screen, _curWalkTarget.x, _curWalkTarget.y, 100);
- if (showShadows) {
- _screen->copyRectToSurface(_room->_pixelsShadows, 640, 0, 0, 640, 400);
- }
_smallFont->drawString(_screen, Common::String::format("Room number: %d", _room->_currentRoomNumber), 0, 4, 640, 13);
_smallFont->drawString(_screen, Common::String::format("Alfred pos: %d, %d (%d)", _alfredState.x, _alfredState.y, _alfredState.y - kAlfredFrameHeight), 0, 18, 640, 13);
_smallFont->drawString(_screen, Common::String::format("Frame number: %d", _chrono->getFrameCount()), 0, 30, 640, 13);
@@ -1488,9 +1467,9 @@ void PelrockEngine::extraScreenLoop() {
_events->_leftMouseClicked = false;
break;
}
- g_system->delayMillis(10);
_screen->markAllDirty();
_screen->update();
+ g_system->delayMillis(10);
}
g_system->getPaletteManager()->setPalette(_room->_roomPalette, 0, 256);
@@ -2000,8 +1979,8 @@ void PelrockEngine::pyramidCollapse() {
// Background tile copies to have collapsed pyramid stick
// copy 99Ã45 from secondary buffer to front buffer
{
- static const int srcX = 240, srcY = 145;
- static const int copyW = 99, copyH = 45;
+ const int srcX = 240, srcY = 145;
+ const int copyW = 99, copyH = 45;
Common::Rect copyRect(srcX, srcY, srcX + copyW, srcY + copyH);
_currentBackground.blitFrom(_compositeBuffer, copyRect, Common::Point(srcX, srcY));
}
@@ -2048,10 +2027,10 @@ void PelrockEngine::pyramidCollapse() {
_events->pollEvent();
renderScene(OVERLAY_NONE);
_screen->update();
- g_system->delayMillis(10);
npc = _room->findSpriteByIndex(0);
if (!npc || npc->x <= 307)
break;
+ g_system->delayMillis(10);
}
// Stop NPC movement
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 1fe5be938da..ea197b30d55 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -1103,7 +1103,7 @@ uint32 RoomManager::loadDescriptions(byte *pair12data, size_t pair12size, Common
uint32 pos = 0;
uint32 lastDescPos = 0;
outDescriptions.clear();
- while (pos < (pair12size)) {
+ while (pos < pair12size) {
if (pair12data[pos] == 0xFF) {
Description description;
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 030acd28b46..b0c7bddfee5 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -47,7 +47,8 @@ static const int unpickableHotspotExtras[] = {
6,
7,
91, // mud and stone should only be picked under certain conditions!
- 92};
+ 92
+};
static const uint32 stickerOffsets[137] = {
0x000000, 0x00005B, 0x0000B6, 0x000298, 0x00047A, 0x0023C8, 0x004316, 0x004376,
Commit: a51d5b0afbcd0e0a3d6546e33c8e5c3f1d5c3155
https://github.com/scummvm/scummvm/commit/a51d5b0afbcd0e0a3d6546e33c8e5c3f1d5c3155
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:54+02:00
Commit Message:
PELROCK: Added ALFRED.2 to the detection tables
Changed paths:
engines/pelrock/detection_tables.h
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/detection_tables.h b/engines/pelrock/detection_tables.h
index 1e3944454b7..87467325e96 100644
--- a/engines/pelrock/detection_tables.h
+++ b/engines/pelrock/detection_tables.h
@@ -30,7 +30,11 @@ const ADGameDescription gameDescriptions[] = {
{
"pelrock",
nullptr,
- AD_ENTRY1s("ALFRED.1", "ee0047cfcceece9c4f6a426245b6f449", 12915352),
+
+ AD_ENTRY2s(
+ "ALFRED.1", "ee0047cfcceece9c4f6a426245b6f449", 12915352,
+ "ALFRED.2", "ca76c50da4a3af83c08d274a3c2ae101", 540260
+ ),
Common::ES_ESP,
Common::kPlatformDOS,
ADGF_UNSTABLE,
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 593702c97b6..9507638a805 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -133,7 +133,6 @@ private:
Common::Point _curWalkTarget;
QueuedAction _queuedAction = {NO_ACTION, -1, false, false};
- bool showShadows = false;
bool shouldPlayIntro = false;
bool gameInitialized = false;
bool screenReady = false;
Commit: e87dd28ce1ed62b479e6dcbc7a4771d8c6e6095c
https://github.com/scummvm/scummvm/commit/e87dd28ce1ed62b479e6dcbc7a4771d8c6e6095c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:54+02:00
Commit Message:
PELROCK: Replace usage of char with byte where platform sensitive
Changed paths:
engines/pelrock/video.cpp
engines/pelrock/video.h
diff --git a/engines/pelrock/video.cpp b/engines/pelrock/video.cpp
index 7047045d89e..e506d936974 100644
--- a/engines/pelrock/video.cpp
+++ b/engines/pelrock/video.cpp
@@ -418,9 +418,9 @@ Subtitle VideoManager::readSubtitle(Common::File &metadataFile) {
// Read text until CRLF (0x0D 0x0A)
while (!metadataFile.eos()) {
- char c = metadataFile.readByte();
+ byte c = metadataFile.readByte();
if (c == 0x0D) {
- char next = metadataFile.readByte();
+ byte next = metadataFile.readByte();
if (next == 0x0A) {
break;
} else {
@@ -440,7 +440,7 @@ Subtitle VideoManager::readSubtitle(Common::File &metadataFile) {
return subtitle;
}
-char VideoManager::decodeChar(byte c) {
+byte VideoManager::decodeChar(byte c) {
switch (c) {
case 0xAD:
diff --git a/engines/pelrock/video.h b/engines/pelrock/video.h
index 596509dfb37..826fadab3f3 100644
--- a/engines/pelrock/video.h
+++ b/engines/pelrock/video.h
@@ -106,7 +106,7 @@ private:
Subtitle readSubtitle(Common::File &metadataFile);
MusicEffect readMusicEffect(Common::File &metadataFile);
AudioEffect readAudioEffect(Common::File &metadataFile);
- char decodeChar(byte c);
+ byte decodeChar(byte c);
Subtitle *getSubtitleForFrame(uint16 frameNumber);
uint _currentSubtitleIndex = 0;
Graphics::Surface _videoSurface = Graphics::Surface();
Commit: 963da1bbe5696d89bedb14e35316157418fbb0ca
https://github.com/scummvm/scummvm/commit/963da1bbe5696d89bedb14e35316157418fbb0ca
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:54+02:00
Commit Message:
PELROCK: Remove statics from room header
Changed paths:
engines/pelrock/resources.cpp
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 13d14dcf73a..466de52b646 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -55,6 +55,26 @@ static const uint32 kCreditsSize = 2540;
static const uint32 kComputerTextOffset = 0x0004901A;
static const uint32 kComputerTextSize = 490;
+const uint32 stickerOffsets[137] = {
+ 0x000000, 0x00005B, 0x0000B6, 0x000298, 0x00047A, 0x0023C8, 0x004316, 0x004376,
+ 0x005119, 0x005EBC, 0x0083ED, 0x008529, 0x0092C4, 0x00A3AA, 0x00B490, 0x00B6A6,
+ 0x00C05A, 0x00CA0E, 0x00D3D0, 0x00D46E, 0x00F036, 0x00FB8F, 0x00FC55, 0x0119D7,
+ 0x013759, 0x01391F, 0x014A9D, 0x015C1B, 0x017601, 0x018FE7, 0x019048, 0x0190A9,
+ 0x01910A, 0x0197F4, 0x019EDE, 0x01A7EC, 0x01B0FA, 0x01B8C4, 0x01C644, 0x01D83A,
+ 0x01E104, 0x01E8C6, 0x01F45D, 0x01FBBB, 0x02011D, 0x02052F, 0x020A95, 0x020E5B,
+ 0x0210B3, 0x0216E6, 0x021D5E, 0x0233A3, 0x0249E8, 0x025777, 0x026506, 0x028E2B,
+ 0x02B82F, 0x02C9D7, 0x02E4CA, 0x02FFBD, 0x03234A, 0x0346D7, 0x036A83, 0x038E2F,
+ 0x03B18D, 0x03D4EB, 0x03DEC9, 0x03F813, 0x04115D, 0x045303, 0x0494A9, 0x04955F,
+ 0x049615, 0x0496CB, 0x0499E1, 0x049EC7, 0x04A023, 0x04A447, 0x04BA6D, 0x04BFA1,
+ 0x04CE33, 0x04CF09, 0x04DB3B, 0x052885, 0x0575CF, 0x05775B, 0x057D79, 0x058397,
+ 0x058969, 0x058F50, 0x05A9DB, 0x05C561, 0x05C72E, 0x05C8FB, 0x05EAC1, 0x060C87,
+ 0x060D19, 0x060E62, 0x061039, 0x0613C2, 0x061764, 0x061847, 0x062535, 0x062D4B,
+ 0x064F11, 0x0670D7, 0x067381, 0x0675A9, 0x0677EF, 0x067A98, 0x067DDE, 0x068115,
+ 0x0684E3, 0x068A76, 0x068F30, 0x0693C8, 0x0696AD, 0x06C2C9, 0x06C84D, 0x07095D,
+ 0x071854, 0x07274B, 0x073642, 0x074539, 0x075454, 0x0791DA, 0x07CF60, 0x07E4AB,
+ 0x07ECED, 0x07F52F, 0x07FD71, 0x080591, 0x080B24, 0x080B84, 0x080F39, 0x0812F5,
+ 0x0816B1
+};
ResourceManager::ResourceManager(/* args */) {
_inventoryIcons = new InventoryObject[69];
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index ea197b30d55..7edb96a6742 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -23,9 +23,31 @@
#include "pelrock/pelrock.h"
#include "pelrock/room.h"
#include "pelrock/util.h"
+#include "room.h"
namespace Pelrock {
+const int kTalkingAnimHeaderSize = 55;
+const int kNumSfxPerRoom = 9;
+const int unpickableHotspotExtras[] = {
+ 308, // lamppost cable
+ 65, // objects in shop
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 6,
+ 7,
+ 91, // mud and stone should only be picked under certain conditions!
+ 92};
+
+const int kNumUnpickableHotspotExtras = ARRAYSIZE(unpickableHotspotExtras);
+
static const uint32 kPaletteRemapOffset = 0x4C77C; // JUEGO.EXE â water-effect palette remap table
RoomManager::RoomManager() {
@@ -47,21 +69,21 @@ RoomManager::~RoomManager() {
if (_passerByAnims) {
delete _passerByAnims;
}
- if(_conversationData) {
+ if (_conversationData) {
delete[] _conversationData;
}
}
void RoomManager::clearTalkingAnims() {
for (int i = 0; i < _talkingAnims.numFramesAnimA; i++) {
- if(_talkingAnims.animA[i]) {
+ if (_talkingAnims.animA[i]) {
delete[] _talkingAnims.animA[i];
_talkingAnims.animA[i] = nullptr;
}
}
delete[] _talkingAnims.animA;
for (int i = 0; i < _talkingAnims.numFramesAnimB; i++) {
- if(_talkingAnims.animB[i]) {
+ if (_talkingAnims.animB[i]) {
delete[] _talkingAnims.animB[i];
_talkingAnims.animB[i] = nullptr;
}
@@ -383,7 +405,18 @@ void RoomManager::addWalkbox(WalkBox walkbox, int persist) {
}
}
+bool RoomManager::isPickableByExtra(uint16 extra) {
+ if (extra > 112)
+ return false;
+ for (int i = 0; i < kNumUnpickableHotspotExtras; i++) {
+ if (extra == unpickableHotspotExtras[i])
+ return false;
+ }
+ return true;
+}
+
Sprite *RoomManager::findSpriteByIndex(byte index) {
+
for (uint i = 0; i < _currentRoomAnims.size(); i++) {
if (_currentRoomAnims[i].index == index) {
return &_currentRoomAnims[i];
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index b0c7bddfee5..0946dca44a7 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -29,47 +29,7 @@
namespace Pelrock {
-static const int kRoomStructSize = 104;
-static const int kTalkingAnimHeaderSize = 55;
-static const int kNumSfxPerRoom = 9;
-static const int unpickableHotspotExtras[] = {
- 308, // lamppost cable
- 65, // objects in shop
- 66,
- 67,
- 68,
- 69,
- 70,
- 71,
- 72,
- 73,
- 74,
- 6,
- 7,
- 91, // mud and stone should only be picked under certain conditions!
- 92
-};
-
-static const uint32 stickerOffsets[137] = {
- 0x000000, 0x00005B, 0x0000B6, 0x000298, 0x00047A, 0x0023C8, 0x004316, 0x004376,
- 0x005119, 0x005EBC, 0x0083ED, 0x008529, 0x0092C4, 0x00A3AA, 0x00B490, 0x00B6A6,
- 0x00C05A, 0x00CA0E, 0x00D3D0, 0x00D46E, 0x00F036, 0x00FB8F, 0x00FC55, 0x0119D7,
- 0x013759, 0x01391F, 0x014A9D, 0x015C1B, 0x017601, 0x018FE7, 0x019048, 0x0190A9,
- 0x01910A, 0x0197F4, 0x019EDE, 0x01A7EC, 0x01B0FA, 0x01B8C4, 0x01C644, 0x01D83A,
- 0x01E104, 0x01E8C6, 0x01F45D, 0x01FBBB, 0x02011D, 0x02052F, 0x020A95, 0x020E5B,
- 0x0210B3, 0x0216E6, 0x021D5E, 0x0233A3, 0x0249E8, 0x025777, 0x026506, 0x028E2B,
- 0x02B82F, 0x02C9D7, 0x02E4CA, 0x02FFBD, 0x03234A, 0x0346D7, 0x036A83, 0x038E2F,
- 0x03B18D, 0x03D4EB, 0x03DEC9, 0x03F813, 0x04115D, 0x045303, 0x0494A9, 0x04955F,
- 0x049615, 0x0496CB, 0x0499E1, 0x049EC7, 0x04A023, 0x04A447, 0x04BA6D, 0x04BFA1,
- 0x04CE33, 0x04CF09, 0x04DB3B, 0x052885, 0x0575CF, 0x05775B, 0x057D79, 0x058397,
- 0x058969, 0x058F50, 0x05A9DB, 0x05C561, 0x05C72E, 0x05C8FB, 0x05EAC1, 0x060C87,
- 0x060D19, 0x060E62, 0x061039, 0x0613C2, 0x061764, 0x061847, 0x062535, 0x062D4B,
- 0x064F11, 0x0670D7, 0x067381, 0x0675A9, 0x0677EF, 0x067A98, 0x067DDE, 0x068115,
- 0x0684E3, 0x068A76, 0x068F30, 0x0693C8, 0x0696AD, 0x06C2C9, 0x06C84D, 0x07095D,
- 0x071854, 0x07274B, 0x073642, 0x074539, 0x075454, 0x0791DA, 0x07CF60, 0x07E4AB,
- 0x07ECED, 0x07F52F, 0x07FD71, 0x080591, 0x080B24, 0x080B84, 0x080F39, 0x0812F5,
- 0x0816B1
-};
+const int kRoomStructSize = 104;
#define PERSIST_TEMP 1
#define PERSIST_PERM 2
@@ -147,16 +107,7 @@ public:
/**
* Will apply the default "take item with given extra" handler if returns true
*/
- bool isPickableByExtra(uint16 extra) {
- if (extra > 112)
- return false;
- int size = sizeof(unpickableHotspotExtras) / sizeof(unpickableHotspotExtras[0]);
- for (int i = 0; i < size; i++) {
- if (extra == unpickableHotspotExtras[i])
- return false;
- }
- return true;
- }
+ bool isPickableByExtra(uint16 extra);
Sprite *findSpriteByIndex(byte index);
Sprite *findSpriteByExtra(int16 extra);
Commit: 828574c3f57c3499a32f6b153e7df2589542bf1f
https://github.com/scummvm/scummvm/commit/828574c3f57c3499a32f6b153e7df2589542bf1f
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:54+02:00
Commit Message:
PELROCK: Create menu sfx utility functions
Changed paths:
engines/pelrock/menu.cpp
engines/pelrock/sound.cpp
engines/pelrock/sound.h
engines/pelrock/spellbook.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index e0a9d47aa9b..3e3fdfa3511 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -436,22 +436,22 @@ bool MenuManager::checkMainMenuMouse(int x, int y) {
MainMenuButton mainMenuButton = isMainMenuButtonUnder(x, y);
switch (mainMenuButton) {
case QUESTION_MARK_BUTTON:
- _sound->playSound("56ZZZZZZ.SMP", 0);
+ _sound->playClonk();
_events->_leftMouseClicked = false;
showCredits();
break;
case INVENTORY_PREV_BUTTON:
- _sound->playSound("56ZZZZZZ.SMP", 0);
+ _sound->playClonk();
if (_curInventoryPage > 0)
_curInventoryPage--;
break;
case INVENTORY_NEXT_BUTTON:
- _sound->playSound("56ZZZZZZ.SMP", 0);
+ _sound->playClonk();
if ((_curInventoryPage + 1) * 4 < g_engine->_state->inventoryItems.size())
_curInventoryPage++;
break;
case SAVE_GAME_BUTTON:
- _sound->playSound("11ZZZZZZ.SMP", 0);
+ _sound->playClick();
if (ConfMan.getBool("original_menus") == true) {
_saveGamePage = 0;
_editingSaveSlot = -1;
@@ -463,7 +463,7 @@ bool MenuManager::checkMainMenuMouse(int x, int y) {
}
break;
case LOAD_GAME_BUTTON:
- _sound->playSound("11ZZZZZZ.SMP", 0);
+ _sound->playClick();
if (ConfMan.getBool("original_menus") == true) {
_saveGamePage = 0;
refreshSaveDescriptions();
@@ -474,11 +474,11 @@ bool MenuManager::checkMainMenuMouse(int x, int y) {
}
break;
case EXIT_MENU_BUTTON:
- _sound->playSound("11ZZZZZZ.SMP", 0);
+ _sound->playClick();
_menuState = EXIT_GAME;
break;
case SOUNDS_BUTTON:
- _sound->playSound("11ZZZZZZ.SMP", 0);
+ _sound->playClick();
_menuState = SOUND;
_menuText = Common::StringArray();
break;
diff --git a/engines/pelrock/sound.cpp b/engines/pelrock/sound.cpp
index 2c4e31d7a4d..4eda6b9c65e 100644
--- a/engines/pelrock/sound.cpp
+++ b/engines/pelrock/sound.cpp
@@ -35,6 +35,7 @@
#include "pelrock/pelrock.h"
#include "pelrock/sound.h"
+#include "sound.h"
namespace Pelrock {
@@ -219,7 +220,6 @@ int SoundManager::playSound(SonidoFile sound, int channel, int loopCount) {
} else {
if (_mixer->isSoundHandleActive(_sfxHandles[channel])) {
_mixer->stopHandle(_sfxHandles[channel]);
- debug("Stopped active sound on channel %d to play new sound %s", channel, sound.filename.c_str());
}
}
Audio::AudioStream *finalStream = loopCount != -1 ? stream : Audio::makeLoopingAudioStream(stream, 0);
@@ -434,4 +434,12 @@ int SoundManager::tickAmbientSound(uint32 frameCount) {
return ambientSlotOffset;
}
+void SoundManager::playClick() {
+ playSound("11ZZZZZZ.SMP", 0);
+}
+
+void SoundManager::playClonk() {
+ playSound("56ZZZZZZ.SMP", 0);
+}
+
} // End of namespace Pelrock
diff --git a/engines/pelrock/sound.h b/engines/pelrock/sound.h
index 0219efb7a2c..7107b163831 100644
--- a/engines/pelrock/sound.h
+++ b/engines/pelrock/sound.h
@@ -88,6 +88,9 @@ public:
*/
int tickAmbientSound(uint32 frameCount);
+ void playClick();
+ void playClonk();
+
bool isPaused() const { return _isPaused; }
byte getCurrentMusicTrack() const { return _currentMusicTrack; }
diff --git a/engines/pelrock/spellbook.cpp b/engines/pelrock/spellbook.cpp
index 83d023d31a5..b8f3cdf4b8a 100644
--- a/engines/pelrock/spellbook.cpp
+++ b/engines/pelrock/spellbook.cpp
@@ -72,7 +72,6 @@ void SpellBook::init() {
}
void SpellBook::selectPage(int page) {
- debug("Selected spell page: %d", page);
_spell = new Spell();
_spell->page = page;
Common::File alfred7;
Commit: b3bfc1776e342f2d200031554c6a4cb5c060184c
https://github.com/scummvm/scummvm/commit/b3bfc1776e342f2d200031554c6a4cb5c060184c
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:55+02:00
Commit Message:
PELROCK: Refactor Room metadata loading so it doesnt return by value
Changed paths:
engines/pelrock/room.cpp
engines/pelrock/room.h
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 7edb96a6742..7283cd3ebe2 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -520,8 +520,8 @@ PaletteAnim *RoomManager::getPaletteAnimForRoom(int roomNumber) {
return anim;
}
-Common::Array<Exit> RoomManager::loadExits(byte *data, size_t size) {
- Common::Array<Exit> exits;
+void RoomManager::loadExits(byte *data, size_t size) {
+ _currentRoomExits.clear();
int exitCountOffset = 0x1BE;
byte exitCount = data[exitCountOffset];
int exitDataOffset = 0x1BF;
@@ -567,17 +567,16 @@ Common::Array<Exit> RoomManager::loadExits(byte *data, size_t size) {
}
}
}
- exits.push_back(exit);
+ _currentRoomExits.push_back(exit);
}
- return exits;
}
-Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
+void RoomManager::loadHotspots(byte *data, size_t size) {
+ _staticHotspots.clear();
int pair10StartingPos = 0x47a;
byte hotspot_count = data[pair10StartingPos];
int hotspotsDataStart = pair10StartingPos + 2;
- Common::Array<HotSpot> hotspots;
for (int i = 0; i < hotspot_count; i++) {
int hotspotOffset = hotspotsDataStart + i * 9;
HotSpot spot;
@@ -588,7 +587,7 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
// if the hotspot has been changed, load the changed version
for (uint j = 0; j < g_engine->_state->roomHotSpotChanges[_currentRoomNumber].size(); j++) {
if (g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspotIndex == spot.innerIndex) {
- hotspots.push_back(g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot);
+ _staticHotspots.push_back(g_engine->_state->roomHotSpotChanges[_currentRoomNumber][j].hotspot);
isChanged = true;
break;
}
@@ -603,10 +602,8 @@ Common::Array<HotSpot> RoomManager::loadHotspots(byte *data, size_t size) {
spot.h = data[hotspotOffset + 6];
spot.isSprite = false;
spot.extra = READ_LE_INT16(data + hotspotOffset + 7);
- hotspots.push_back(spot);
+ _staticHotspots.push_back(spot);
}
-
- return hotspots;
}
void RoomManager::resetConversationStates(byte roomNumber, byte *conversationData, size_t conversationDataSize) {
@@ -670,18 +667,17 @@ void RoomManager::loadRoomMetadata(Common::File *roomFile, int roomNumber) {
// The user's game can be in any state so we reset to defaults first
resetMetadataDefaults(roomNumber, pair10, pair10size);
- Common::Array<Sprite> sprites = loadRoomAnimations(pic, pixelDataSize, pair10, pair10size);
- Common::Array<HotSpot> staticHotspots = loadHotspots(pair10, pair10size);
+ // clear anims from previous room before loading new ones into _currentRoomAnims
+ clearAnims();
- free(pic);
+ loadRoomAnimations(pic, pixelDataSize, pair10, pair10size);
+ loadHotspots(pair10, pair10size);
- // clear anims from previous room
- clearAnims();
+ free(pic);
- _currentRoomAnims = sprites;
- _currentRoomHotspots = unifyHotspots(sprites, staticHotspots);
- _currentRoomExits = loadExits(pair10, pair10size);
- _currentRoomWalkboxes = loadWalkboxes(pair10, pair10size);
+ _currentRoomHotspots = unifyHotspots(_currentRoomAnims, _staticHotspots);
+ loadExits(pair10, pair10size);
+ loadWalkboxes(pair10, pair10size);
_scaleParams = loadScalingParams(pair10, pair10size);
clearRoomStickerPixels(); // free all sticker buffers first
@@ -994,9 +990,9 @@ void RoomManager::loadAnimationPixelData(Common::File *roomFile, int roomOffset,
delete[] pixelData;
}
-Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size) {
+void RoomManager::loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size) {
- Common::Array<Sprite> anims = Common::Array<Sprite>();
+ _currentRoomAnims.clear();
uint32 spriteCountPos = 5;
byte spriteCount = data[spriteCountPos] - 2;
uint32 metadata_start = spriteCountPos + (44 * 2 + 5);
@@ -1071,19 +1067,18 @@ Common::Array<Sprite> RoomManager::loadRoomAnimations(byte *pixelData, size_t pi
sprite.animData[j] = anim;
}
- anims.push_back(sprite);
+ _currentRoomAnims.push_back(sprite);
}
- return anims;
}
-Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
+void RoomManager::loadWalkboxes(byte *data, size_t size) {
+ _currentRoomWalkboxes.clear();
int walkboxCountOffset = 0x213;
byte walkboxCount = data[walkboxCountOffset];
// debug("Walkbox count: %d", walkbox_count);
uint32 walkboxOffset = 0x218;
- Common::Array<WalkBox> walkboxes;
for (int i = 0; i < walkboxCount; i++) {
uint32 boxOffset = walkboxOffset + i * 9;
int16 x1 = READ_LE_INT16(data + boxOffset);
@@ -1098,7 +1093,7 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
// if the walkbox has been changed, load the changed version
for (uint j = 0; j < g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
if (g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == i) {
- walkboxes.push_back(g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
+ _currentRoomWalkboxes.push_back(g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
isChanged = true;
break;
}
@@ -1111,25 +1106,24 @@ Common::Array<WalkBox> RoomManager::loadWalkboxes(byte *data, size_t size) {
box.w = w;
box.h = h;
box.flags = flags;
- walkboxes.push_back(box);
+ _currentRoomWalkboxes.push_back(box);
}
if (g_engine->_state->roomWalkBoxChanges.contains(_currentRoomNumber)) {
// Add any new walkboxes that were added
for (uint j = 0; j < g_engine->_state->roomWalkBoxChanges[_currentRoomNumber].size(); j++) {
bool found = false;
- for (uint i = 0; i < walkboxes.size(); i++) {
- if (g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == walkboxes[i].index) {
+ for (uint i = 0; i < _currentRoomWalkboxes.size(); i++) {
+ if (g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkboxIndex == _currentRoomWalkboxes[i].index) {
found = true;
break;
}
}
if (!found) {
- walkboxes.push_back(g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
+ _currentRoomWalkboxes.push_back(g_engine->_state->roomWalkBoxChanges[_currentRoomNumber][j].walkbox);
}
}
}
- return walkboxes;
}
uint32 RoomManager::loadDescriptions(byte *pair12data, size_t pair12size, Common::Array<Description> &outDescriptions) {
diff --git a/engines/pelrock/room.h b/engines/pelrock/room.h
index 0946dca44a7..93bfd8e24a2 100644
--- a/engines/pelrock/room.h
+++ b/engines/pelrock/room.h
@@ -141,11 +141,11 @@ public:
private:
void init();
void loadAnimationPixelData(Common::File *roomFile, int roomOffset, byte *&buffer, size_t &outSize);
- Common::Array<Sprite> loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size);
- Common::Array<HotSpot> loadHotspots(byte *data, size_t size);
- Common::Array<Exit> loadExits(byte *data, size_t size);
+ void loadRoomAnimations(byte *pixelData, size_t pixelDataSize, byte *data, size_t size);
+ void loadHotspots(byte *data, size_t size);
+ void loadExits(byte *data, size_t size);
ScalingParams loadScalingParams(byte *data, size_t size);
- Common::Array<WalkBox> loadWalkboxes(byte *data, size_t size);
+ void loadWalkboxes(byte *data, size_t size);
uint32 loadDescriptions(byte *pair12data, size_t pair12size, Common::Array<Description> &outDescriptions);
void loadConversationData(byte *pair12data, size_t pair12size, uint32 startPos, size_t &outConversationDataSize, byte *&outConversationData);
void resetConversationStates(byte roomNumber, byte *conversationData, size_t conversationDataSize);
@@ -158,6 +158,7 @@ private:
Common::Array<byte> loadRoomSfx(Common::File *roomFile, int roomOffset);
byte *_resetData = nullptr;
+ Common::Array<HotSpot> _staticHotspots;
};
} // End of namespace Pelrock
Commit: 853400116543bb49858828de18a88d4d47de6b63
https://github.com/scummvm/scummvm/commit/853400116543bb49858828de18a88d4d47de6b63
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:55+02:00
Commit Message:
PELROCK: Fix warnings on overflowing chars
Changed paths:
engines/pelrock/computer.cpp
engines/pelrock/resources.cpp
diff --git a/engines/pelrock/computer.cpp b/engines/pelrock/computer.cpp
index 5e436df9915..3f4b407ffdd 100644
--- a/engines/pelrock/computer.cpp
+++ b/engines/pelrock/computer.cpp
@@ -247,8 +247,8 @@ void Computer::drawScreen() {
Common::String navOptions;
Common::String actions = _computerText[7][0];
if (!book.available) {
- actions.setChar(180, 1);
- actions.setChar(180, 4);
+ actions.setChar((char)180, 1);
+ actions.setChar((char)180, 4);
}
g_engine->_graphics->drawColoredText(g_engine->_screen, actions, 174, 258, 325, defaultColor, g_engine->_smallFont);
diff --git a/engines/pelrock/resources.cpp b/engines/pelrock/resources.cpp
index 466de52b646..3e74157745e 100644
--- a/engines/pelrock/resources.cpp
+++ b/engines/pelrock/resources.cpp
@@ -413,7 +413,7 @@ void ResourceManager::loadHardcodedText() {
_ingameTexts = processTextData(descBuffer, kAlfredResponsesSize);
// exe.seek(-1, SEEK_CUR);
_left = exe.readString();
- _right = exe.readString(0xFD);
+ _right = exe.readString((char)0xFD);
byte *terminatorBuffer = new byte[39];
exe.seek(kConversationTerminatorOffset, SEEK_SET);
exe.read(terminatorBuffer, 39);
Commit: d44fc4aaa5df0f894bb53249b4b0e2ebc15337a1
https://github.com/scummvm/scummvm/commit/d44fc4aaa5df0f894bb53249b4b0e2ebc15337a1
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:55+02:00
Commit Message:
PELROCK: Remove duplicate logic into resetPasserByAnim
Changed paths:
engines/pelrock/pelrock.cpp
engines/pelrock/pelrock.h
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 6e19f5b899b..9139fc5cdb7 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -481,6 +481,15 @@ void PelrockEngine::maybeShakeEffect() {
_alfredState.x += (_shakeEffectState.shakeX / 2);
}
+void PelrockEngine::resetPasserByAnim(int startX, int startY, Sprite *sprite) {
+ sprite->x = startX;
+ sprite->y = startY;
+ sprite->zOrder = 255;
+ sprite->curAnimIndex = 0;
+ sprite->animData[0].curFrame = 0;
+ _room->_passerByAnims->latch = false;
+}
+
void PelrockEngine::maybeUpdatePasserByAnim(uint32 frameCount) {
if (_room->_passerByAnims == nullptr) {
return;
@@ -509,31 +518,15 @@ void PelrockEngine::maybeUpdatePasserByAnim(uint32 frameCount) {
Sprite *sprite = _room->findSpriteByIndex(spriteIndex);
if (direction == kPasserbyRight) {
if (sprite->x >= anim.resetCoord) {
- sprite->x = startX;
- sprite->y = startY;
- sprite->zOrder = 255;
- sprite->curAnimIndex = 0;
- sprite->animData[0].curFrame = 0;
- _room->_passerByAnims->latch = false;
+ resetPasserByAnim(startX, startY, sprite);
}
} else if (direction == kPasserbyLeft) {
-
if (sprite->x <= anim.resetCoord) {
- sprite->x = startX;
- sprite->y = startY;
- sprite->zOrder = 255;
- sprite->curAnimIndex = 0;
- sprite->animData[0].curFrame = 0;
- _room->_passerByAnims->latch = false;
+ resetPasserByAnim(startX, startY, sprite);
}
} else if (direction == kPasserbyDown) {
if (sprite->y >= anim.resetCoord) {
- sprite->x = startX;
- sprite->y = startY;
- sprite->zOrder = 255;
- sprite->curAnimIndex = 0;
- sprite->animData[0].curFrame = 0;
- _room->_passerByAnims->latch = false;
+ resetPasserByAnim(startX, startY, sprite);
}
}
}
diff --git a/engines/pelrock/pelrock.h b/engines/pelrock/pelrock.h
index 9507638a805..70859e4d027 100644
--- a/engines/pelrock/pelrock.h
+++ b/engines/pelrock/pelrock.h
@@ -257,6 +257,7 @@ public:
void maybeHaveDogPee();
void maybePlayPostIntro();
void maybeShakeEffect();
+ void resetPasserByAnim(int startX, int startY, Sprite *sprite);
void handleFightRoomFrame();
void paintDebugLayer();
Commit: e71a30c89587ab2b9796dd84846d0b4f71dcab7b
https://github.com/scummvm/scummvm/commit/e71a30c89587ab2b9796dd84846d0b4f71dcab7b
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:56+02:00
Commit Message:
PELROCK: Create constructor for PasserBy animations
Changed paths:
engines/pelrock/room.cpp
engines/pelrock/types.h
diff --git a/engines/pelrock/room.cpp b/engines/pelrock/room.cpp
index 7283cd3ebe2..ac5a5a8f4a3 100644
--- a/engines/pelrock/room.cpp
+++ b/engines/pelrock/room.cpp
@@ -771,13 +771,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
mouse->animData[3].movementFlags = 0x3E0;
anims = new RoomPasserBys(roomNumber, 1);
- PasserByAnim anim;
- anim.spriteIndex = 2;
- anim.startX = mouse->x;
- anim.startY = mouse->y;
- anim.dir = kPasserbyDown;
- anim.targetZIndex = blank->zOrder + 1;
- anim.resetCoord = blank->y;
+ PasserByAnim anim(2, mouse->x, mouse->y, kPasserbyDown, blank->y, blank->zOrder + 1, 0x3FF);
anims->passerByAnims[0] = anim;
break;
}
@@ -821,22 +815,9 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
Sprite *carRight = findSpriteByIndex(3);
anims = new RoomPasserBys(roomNumber, 2);
- PasserByAnim animA;
- animA.spriteIndex = 2;
- animA.startX = carLeft->x;
- animA.startY = carLeft->y;
- animA.dir = kPasserbyLeft;
- animA.resetCoord = carRight->x + carRight->w - carLeft->w;
- animA.targetZIndex = 100;
-
+ PasserByAnim animA(2, carLeft->x, carLeft->y, kPasserbyLeft, carRight->x + carRight->w - carLeft->w, 100, 0x3FF);
anims->passerByAnims[0] = animA;
- PasserByAnim animB;
- animB.spriteIndex = 3;
- animB.startX = carRight->x;
- animB.startY = carRight->y;
- animB.dir = kPasserbyRight;
- animB.targetZIndex = 100;
- animB.resetCoord = 639 + carRight->w;
+ PasserByAnim animB(3, carRight->x, carRight->y, kPasserbyRight, 639 + carRight->w, 100, 0x3FF);
anims->passerByAnims[1] = animB;
break;
}
@@ -845,13 +826,7 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
anims = new RoomPasserBys(roomNumber, 1);
Sprite *walker = findSpriteByIndex(2);
Sprite *dark = findSpriteByIndex(5);
- PasserByAnim anim;
- anim.spriteIndex = 2;
- anim.startX = walker->x;
- anim.startY = walker->y;
- anim.dir = kPasserbyRight;
- anim.resetCoord = dark->x;
- anim.targetZIndex = dark->zOrder + 1;
+ PasserByAnim anim(2, walker->x, walker->y, kPasserbyRight, dark->x, dark->zOrder + 1, 0x3FF);
anims->passerByAnims[0] = anim;
break;
}
@@ -860,22 +835,9 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
Sprite *catLeft = findSpriteByIndex(3);
Sprite *blank = findSpriteByIndex(0);
anims = new RoomPasserBys(roomNumber, 2);
- PasserByAnim animA;
- animA.spriteIndex = 2;
- animA.startX = catRight->x;
- animA.startY = catRight->y;
- animA.dir = kPasserbyRight;
- animA.resetCoord = catLeft->x;
- animA.targetZIndex = blank->zOrder + 1;
-
+ PasserByAnim animA(2, catRight->x, catRight->y, kPasserbyRight, catLeft->x, blank->zOrder + 1, 0x3FF);
anims->passerByAnims[0] = animA;
- PasserByAnim animB;
- animB.spriteIndex = 3;
- animB.startX = catLeft->x;
- animB.startY = catLeft->y;
- animB.dir = kPasserbyLeft;
- animB.resetCoord = blank->x;
- animB.targetZIndex = blank->zOrder + 1;
+ PasserByAnim animB(3, catLeft->x, catLeft->y, kPasserbyLeft, blank->x, blank->zOrder + 1, 0x3FF);
anims->passerByAnims[1] = animB;
break;
}
@@ -885,22 +847,9 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
Sprite *papers = findSpriteByIndex(1);
anims = new RoomPasserBys(roomNumber, 2);
- PasserByAnim animA;
- animA.spriteIndex = 3;
- animA.startX = mouseRight->x;
- animA.startY = mouseRight->y;
- animA.dir = kPasserbyRight;
- animA.resetCoord = mouseLeft->x;
- animA.targetZIndex = papers->zOrder + 1;
+ PasserByAnim animA(3, mouseRight->x, mouseRight->y, kPasserbyRight, mouseLeft->x, papers->zOrder + 1, 0x3FF);
anims->passerByAnims[0] = animA;
-
- PasserByAnim animB;
- animB.spriteIndex = 4;
- animB.startX = mouseLeft->x;
- animB.startY = mouseLeft->y;
- animB.dir = kPasserbyLeft;
- animB.resetCoord = mouseRight->x;
- animB.targetZIndex = papers->zOrder + 1;
+ PasserByAnim animB(4, mouseLeft->x, mouseLeft->y, kPasserbyLeft, mouseRight->x, papers->zOrder + 1, 0x3FF);
anims->passerByAnims[1] = animB;
break;
}
@@ -909,22 +858,9 @@ RoomPasserBys *RoomManager::loadPasserByAnims(int roomNumber) {
Sprite *mummyRight = findSpriteByIndex(3);
anims = new RoomPasserBys(roomNumber, 2);
- PasserByAnim animA;
- animA.spriteIndex = 2;
- animA.startX = mummyLeft->x;
- animA.startY = mummyLeft->y;
- animA.dir = kPasserbyLeft;
- animA.resetCoord = 0 - mummyLeft->w;
- animA.targetZIndex = 1;
-
+ PasserByAnim animA(2, mummyLeft->x, mummyLeft->y, kPasserbyLeft, 0 - mummyLeft->w, 1, 0x3FF);
anims->passerByAnims[0] = animA;
- PasserByAnim animB;
- animB.spriteIndex = 3;
- animB.startX = mummyRight->x;
- animB.startY = mummyRight->y;
- animB.dir = kPasserbyRight;
- animB.targetZIndex = 1;
- animB.resetCoord = 639 + mummyRight->w;
+ PasserByAnim animB(3, mummyRight->x, mummyRight->y, kPasserbyRight, 639 + mummyRight->w, 1, 0x3FF);
anims->passerByAnims[1] = animB;
break;
}
diff --git a/engines/pelrock/types.h b/engines/pelrock/types.h
index 8b9a9d8aa69..34b56a55dda 100644
--- a/engines/pelrock/types.h
+++ b/engines/pelrock/types.h
@@ -483,6 +483,10 @@ struct PasserByAnim {
byte dir;
byte spriteIndex;
byte targetZIndex;
+
+ PasserByAnim() = default;
+ PasserByAnim(byte spriteIndex_, int16 startX_, int16 startY_, byte dir_, int16 resetCoord_, byte targetZIndex_, uint32 frameTrigger_)
+ : frameTrigger(frameTrigger_), startX(startX_), startY(startY_), resetCoord(resetCoord_), dir(dir_), spriteIndex(spriteIndex_), targetZIndex(targetZIndex_) {}
};
struct RoomPasserBys {
Commit: 5c953ada383b389b002728c30295d1d1d0a41e84
https://github.com/scummvm/scummvm/commit/5c953ada383b389b002728c30295d1d1d0a41e84
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:56+02:00
Commit Message:
PELROCK: Creates macro for deleting button sprites in menu
Changed paths:
engines/pelrock/menu.cpp
diff --git a/engines/pelrock/menu.cpp b/engines/pelrock/menu.cpp
index 3e3fdfa3511..1624f5fc58f 100644
--- a/engines/pelrock/menu.cpp
+++ b/engines/pelrock/menu.cpp
@@ -33,6 +33,10 @@
namespace Pelrock {
+#define DELETE_SPRITE(sprite) \
+ delete[] sprite[0]; \
+ delete[] sprite[1];
+
static const char *inventorySounds[113] = {
"HOJASZZZ.SMP", // 0
@@ -1009,21 +1013,17 @@ void MenuManager::drawSoundControls() {
Pelrock::MenuManager::~MenuManager() {
_mainMenu.free();
_compositeBuffer.free();
- delete[] _questionMark[0];
- delete[] _questionMark[1];
- delete[] _inventoryLeftArrow[0];
- delete[] _inventoryLeftArrow[1];
- delete[] _inventoryRightArrow[0];
- delete[] _inventoryRightArrow[1];
- // delete buttons
- delete[] _saveButtons[0]; delete[] _saveButtons[1];
- delete[] _loadButtons[0]; delete[] _loadButtons[1];
- delete[] _soundsButtons[0]; delete[] _soundsButtons[1];
- delete[] _exitToDosButtons[0]; delete[] _exitToDosButtons[1];
- delete[] _savesUpArrows[0]; delete[] _savesUpArrows[1];
- delete[] _savesDownArrows[0]; delete[] _savesDownArrows[1];
- delete[] _soundControlArrowLeft[0]; delete[] _soundControlArrowLeft[1];
- delete[] _soundControlArrowRight[0]; delete[] _soundControlArrowRight[1];
+ DELETE_SPRITE(_questionMark);
+ DELETE_SPRITE(_inventoryLeftArrow);
+ DELETE_SPRITE(_inventoryRightArrow);
+ DELETE_SPRITE(_saveButtons);
+ DELETE_SPRITE(_loadButtons);
+ DELETE_SPRITE(_soundsButtons);
+ DELETE_SPRITE(_exitToDosButtons);
+ DELETE_SPRITE(_savesUpArrows);
+ DELETE_SPRITE(_savesDownArrows);
+ DELETE_SPRITE(_soundControlArrowLeft);
+ DELETE_SPRITE(_soundControlArrowRight);
delete[] _soundControlMasterIcon;
delete[] _soundControlSfxIcon;
Commit: fa6b927ca889b216bbf9b4636e46adcc5417be23
https://github.com/scummvm/scummvm/commit/fa6b927ca889b216bbf9b4636e46adcc5417be23
Author: kelmer (kelmer at gmail.com)
Date: 2026-05-05T13:00:56+02:00
Commit Message:
PELROCK: Fixes talking animation occasionally not advancing frames on original timing
Changed paths:
engines/pelrock/pelrock.cpp
diff --git a/engines/pelrock/pelrock.cpp b/engines/pelrock/pelrock.cpp
index 9139fc5cdb7..ba52a4b303a 100644
--- a/engines/pelrock/pelrock.cpp
+++ b/engines/pelrock/pelrock.cpp
@@ -852,8 +852,15 @@ void PelrockEngine::chooseAlfredStateAndDraw() {
}
case ALFRED_TALKING:
drawAlfred(_res->alfredTalkFrames[_alfredState.direction][_alfredState.curFrame]);
- if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
+ // In alternate timing, shouldSkipFrame() never throttles, so use the frameCount gate.
+ // In original timing, shouldSkipFrame() already skips every other tick while talking,
+ // so advancing every rendered frame gives the same rate without parity phase-locking.
+ if (isAlternateTiming()) {
+ if (_chrono->getFrameCount() % kAlfredAnimationSpeed == 0)
+ _alfredState.curFrame++;
+ } else {
_alfredState.curFrame++;
+ }
if (_alfredState.curFrame >= talkingAnimLengths[_alfredState.direction] - 1) {
_alfredState.curFrame = 0;
}
More information about the Scummvm-git-logs
mailing list