Skip to content

Commit

Permalink
24.12.1.2
Browse files Browse the repository at this point in the history
[Diggers]
* Optimise adding objects to another object's inventory.
* Objects can no longer take other objects that are busy.
* Completely stop objects that are picked up.
* Make sure destroyed devices' context menu is deselected on destruction.
* Optimise digger death logic.
* Fix odd use of semi-colons in data structions.

[Assets]
* Update Diggers readme. Remove progress and only show outstanding issues now. Update minimum MacOS and fix Windows XP version required.
  • Loading branch information
Mhatxotic committed Dec 1, 2024
1 parent 9195771 commit f209797
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 108 deletions.
45 changes: 14 additions & 31 deletions diggers/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,41 +26,26 @@
## [Status](#status)
This Diggers fan remake was started in 2006 as a basic Win32 C application using DirectDraw, DirectSound and DirectMedia then rewritten from scratch in C++ from the ground up with a new fully customisable engine called *Mhatxotic Engine* to utilise open source, cross-platform technologies and conformed to ISO coding standards.

Diggers will always be a work-in-progress since it is difficult and incredibly time consuming to work on a game single-handedly and there are always issues with upstream code due to the balancing of modernisation and compatibility. However, the following information is the current estimated status of the game…

* *Engine:* `100%`
* _Windows:_ `100%`
* All functions accounted for.
* _MacOS:_ `100%`
* All functions accounted for.
* _Linux:_ `100%`
* Sometimes the full-screen/window toggle key might not work properly because of duplicated input keys. Hopefully will be fixed in Ubuntu 24.04 LTS.
* Skipping one rendered frame every few seconds only on Wayland, perhaps when only using a `59.97hz` NTSC display. Probably need to make animations based on time and not frames which could be extremely difficult.
* All other functions accounted for.
* *Graphics*: `100%`
* All other graphics accounted for.
* *Sound*: `100%`
* All music and sound accounted for.
* *Input*: `100%`
* Keyboard, mouse and controller accounted for but controller and keyboard inputs are suboptimal.
* *Levels*: `100%`
* All levels accounted for.
* *Gameplay*: `95%`
* Need proper ending movie with the stranger flying away in his pod.
* All other gameplay accounted for.
* *Localisation*: `25%`
* No French book, intro nor UI localisations yet.
* No German book, intro nor UI localisations yet.
* No Italian book, intro nor UI localisations yet.
* Only British translation so far.
Diggers is a completely playable game from start to finish but will always be a work-in-progress since it is difficult and incredibly time consuming to work on a game single-handedly and there are always issues with upstream code due to the balancing of modernisation and compatibility. However, the following information is the current estimated status of the game…

### MacOS engine outstanding issues…
* If the game quits uncleanly, you have to run the game with `app_clearmutex=1` to clear the mutex that controls only allowing one instance of the game.

### Linux engine outstanding issues…
* Sometimes the full-screen/window toggle key might not work properly because of duplicated input keys. Hopefully will be fixed in Ubuntu 24.04 LTS.
* Skipping one rendered frame every few seconds only on Wayland, perhaps when only using a `59.97hz` NTSC display. Probably need to make animations based on time and not frames which could be extremely difficult.

### Diggers game outstanding issues…
* Need proper ending movie with the stranger flying away in his pod.
* No French, German or Italian book, intro nor UI localisations yet.

## [System Requirements](#system-requirements)
| | Minimum | Recommended | Note |
| --- | --- | --- | --- |
| **Processor** | Dual-Core 2GHz | Multi-Core 2GHz+ | Multithreaded! |
| **System** *(Windows)* | XP SP3 *(X86/X64)* | 7/8.X/1X+ *(X64)* | 32 and 64bit executable. |
| **System** *(Windows)* | XP *(SP3 X86/SP2 X64)* | 7/8.X/1X+ *(X64)* | 32 and 64bit executable. |
| **Memory** *(Windows)* | 16MB *(XP/X86)* | 128MB+ *(Win7/X64)* | Close estimate. |
| **System** *(MacOS)* | 10.7 *(Intel)* / 11 *(Arm)* | 13.0+ *(Arm)* | FAT Universal executable. |
| **System** *(MacOS)* | 10.11 *(Intel)* / 11 *(Arm)* | 13.0+ *(Arm)* | FAT Universal executable. |
| **Memory** *(MacOS)* | 256MB *(Intel)* | 512MB *(Arm)* | Close estimate. |
| **System** *(Linux)* | Ubuntu 23.10 *(X64)* | Ubuntu 23.04+ *(X64)* | See below for packages. |
| **Memory** *(Linux)* | 16MB | 128MB+ | Wild estimate. |
Expand Down Expand Up @@ -289,8 +274,6 @@ You can change cvars by opening up the console with the `GRAVE` key (key under `
- A. You can start the game with the `log_file=...` (filename) parameter to give a pretty detailed log of what the app is doing so you can send me that along with as much info as possible such as the `.log` `.crt` `.dbg` and `.udb` files that the app generates. Neither of these files will contain any personal information, only technical information to help me squash the problem.
* **Q. I've picked the wrong game-engine settings and the game crashed/won't start.**
- A. Try specifying the parameter `sql_defaults=1` command-line option to reset all the engine settings to default. If this doesn't work you'll have to delete the `.udb` file or set `sql_defaults=2` and start again from scratch thus losing all your Diggers saved game data. All that said though, the game shouldn't really crash though so please send me any logs/crash dumps you may have.
* **Q. Diggers crashed and then when I start Diggers on MacOS, nothing happens.**
- A. If Diggers terminates uncleanly, you need to run it again manually with the `app_clearmutex=1` parameter. Also restarting your Mac helps but this is way too overkill. This problem does not affect Windows or Linux versions.
* **Q. Why does the game run faster than the Amiga version?**
- A. A fixed polling frequency of 60hz is used for the game logic and I originally enjoyed playing this game on a 486 DX2/66 with the original MS-DOS version that ran at refresh frequency of 70hz (in 320x200 mode X) which is quite speedy compared to the slow gameplay of the Amiga version and I always preferred the fast logic of the MS-DOS version.
* **Q. Can I speed run or T.A.S. this game?**
Expand Down
8 changes: 4 additions & 4 deletions diggers/src/data.lua
Original file line number Diff line number Diff line change
Expand Up @@ -528,14 +528,14 @@ local aDiggerKeys<const> = {
[ACT.DROP] = aObjectJobDirKeep,
[ACT.GRAB] = aObjectJobDirKeep,
[ACT.JUMP] = aObjectJobDirKeep,
[ACT.PHASE] = { [JOB.PHASE] = { [DIR.U] = true } };
[ACT.PHASE] = { [JOB.PHASE] = { [DIR.U] = true } },
[ACT.RUN] = aDiggerMovement,
[ACT.STOP] = aObjectStop,
[ACT.WALK] = aDiggerMovement,
}
-- Small and large tuneller accepted keys ---------------------------------- --
local aTunnellerKeys<const> = {
[ACT.STOP] = aObjectStop;
[ACT.STOP] = aObjectStop,
[ACT.WALK] = { [JOB.NONE] = aObjectLeftRight,
[JOB.DIG] = aObjectLeftRight }
};
Expand Down Expand Up @@ -1576,8 +1576,8 @@ local aObjectData<const> = { -- Objects data
[DIR.NONE] = { 451, 454 },
FLAGS = OFL.BUSY
}, KEYS = {
[ACT.STOP] = aObjectStop;
[ACT.CREEP] = { [JOB.NONE] = { [DIR.U] = true, [DIR.D] = true } };
[ACT.STOP] = aObjectStop,
[ACT.CREEP] = { [JOB.NONE] = { [DIR.U] = true, [DIR.D] = true } }
},
ACTION = ACT.STOP, AITYPE = AI.LIFT,
ANIMTIMER = aTimerData.ANIMNORMAL, ATTACHMENT = TYP.LIFTC,
Expand Down
141 changes: 68 additions & 73 deletions diggers/src/game.lua
Original file line number Diff line number Diff line change
Expand Up @@ -548,10 +548,9 @@ local function DestroyObject(iObj, aObj)
error("Invalid object specified! "..tostring(aObj)) end;
-- Return if list empty
if #aList == 0 then return end;
-- For each object end to start because we are deleting items
-- Enumerate each object from the end to the start of the list. If target
-- object is our object then delete it from the list
for iObj = #aList, 1, -1 do
-- If target object is our object then delete it from the
-- specified list else increment to the next object id.
if aList[iObj] == aObj then remove(aList, iObj) end;
end
end
Expand All @@ -571,20 +570,17 @@ local function DestroyObject(iObj, aObj)
-- If pursuer had a target? Remove pursuer from targets pursuer list
local aTarget<const> = aObj.T;
if aTarget then aTarget.TL[aObj.U] = nil end;
-- Get objects owner and if no player owner?
local aPlayer<const> = aObj.P;
if not aPlayer then
-- If selected object is this object then unselect the object
if aActiveObject == aObj then aActiveObject = nil end;
-- Get digger id and if it was not a Digger?
local iDiggerId<const> = aObj.DI;
if not iDiggerId then
-- Deselect the object and its menu
if aActiveObject == aObj then aActiveMenu, aActiveObject = nil, nil end;
-- Success
return true;
end
-- Get digger id and if it was a Digger? Mark it as dead and reduce players'
-- digger count.
local iDiggerId<const> = aObj.DI;
if iDiggerId then
aPlayer.D[iDiggerId], aPlayer.DC = false, aPlayer.DC - 1;
end
-- Get player owner and mark it as dead and reduce players' digger count
local aPlayer<const> = aObj.P;
aPlayer.D[iDiggerId], aPlayer.DC = false, aPlayer.DC - 1;
-- Remove pursuers and reset pursuer targets
local aPursuers<const> = aObj.TL;
for iUId, aPursuer in pairs(aPursuers) do
Expand All @@ -602,49 +598,50 @@ local function DestroyObjectUnknown(aObject)
-- Check id specified
if not UtilIsTable(aObject) then
error("Invalid object specified! "..tostring(aObject)) end;
-- Enumerate through each global object (while because we modify the list)
for iTargetIndex = 1, #aObjects do
-- Get object from global list and destroy object if matches and return
local aTargetObject<const> = aObjects[iTargetIndex];
if aTargetObject == aObject then
return DestroyObject(iTargetIndex, aObject) end;
-- Try next object
iTargetIndex = iTargetIndex + 1;
-- Enumerate through each global object and find the specified object and
-- destroy it if we find it.
for iIndex = 1, #aObjects do
if aObjects[iIndex] == aObject then
return DestroyObject(iIndex, aObject)
end
end
-- Failed to find object
return false;
end
-- Add to inventory -------------------------------------------------------- --
local function AddToInventory(aObj, aInvObj, bOnlyTreasure)
local function AddToInventory(aOwnObj, aTakeObj, bOnlyTreasure)
-- Check parameters
if not UtilIsTable(aObj) then
error("Invalid object specified! "..tostring(aObj)) end;
if not UtilIsTable(aInvObj) then
error("Invalid inventory object specified! "..tostring(aInvObj)) end;
-- Find object in objects array
if not UtilIsTable(aOwnObj) then
error("Invalid owner object specified! "..tostring(aOwnObj)) end;
if not UtilIsTable(aTakeObj) then
error("Invalid take object specified! "..tostring(aTakeObj)) end;
-- Failed if the object to take is...
if aTakeObj.F & OFL.BUSY ~= 0 or -- ...busy? -or-
#aTakeObj.I > 0 or -- ...has inventory? -or-
(bOnlyTreasure and -- ...only pick up treasure? -and-
aTakeObj.F & OFL.TREASURE == 0) then -- ...treasure flag not set?
-- We cannot pickup this object!
return false;
end
-- Find object in objects array and when we find it?
for iObj = 1, #aObjects do
-- Get object and if it...
if aObjects[iObj] == aInvObj and -- ...matches the object? -and-
#aInvObj.I == 0 and -- ...doesn't have inventory -and-
(not bOnlyTreasure or -- ...don't pickup treasure -or-
aInvObj.F & OFL.TREASURE ~= 0) then -- ...treasure flag set?
-- Remove object and add object to player inventory
if aObjects[iObj] == aTakeObj then
-- Remove object and add requested object to owners inventory
remove(aObjects, iObj);
local aObjInv<const> = aObj.I;
aObjInv[1 + #aObjInv] = aInvObj;
-- If object is phasing then reset the object
if aInvObj.A == ACT.PHASE then
SetAction(aInvObj, ACT.STOP, JOB.NONE, DIR.NONE) end;
-- Add weight
aObj.IW = aObj.IW + aInvObj.W;
-- Set active inventory object to this object
aObj.IS = aInvObj;
-- If item picked up was active object close it and menu
if aActiveObject == aInvObj then
local aOwnObjInv<const> = aOwnObj.I;
aOwnObjInv[1 + #aOwnObjInv] = aTakeObj;
-- Add weight and set active inventory object to this object
aOwnObj.IW, aOwnObj.IS = aOwnObj.IW + aTakeObj.W, aTakeObj;
-- Stop the taken object for inventory preview purposes
SetAction(aTakeObj, ACT.STOP, JOB.NONE, DIR.NONE);
-- If item picked up was the active object then deselect it and its menu
if aActiveObject == aTakeObj then
aActiveObject, aActiveMenu = nil, nil end;
-- Success
return true;
end
end
-- Failed
-- This shouldn't happen! The object should be in the objects list!
return false;
end
-- Buy an item ------------------------------------------------------------- --
Expand Down Expand Up @@ -675,24 +672,23 @@ local function BuyItem(aObj, iItemId)
return true;
end
-- Drop Object ------------------------------------------------------------- --
local function DropObject(aObj, aInvObj)
-- Get object inventory and walk inventory
local aInvObjs<const> = aObj.I;
for iInvObj = 1, #aInvObjs do
-- Object matches?
if aInvObjs[iInvObj] == aInvObj then
-- Remove object from inventory
remove(aObj.I, iInvObj);
local function DropObject(aOwnObj, aDropObj)
-- Get object inventory and enumerate it until we find the object
local aOwnObjInv<const> = aOwnObj.I;
for iIndex = 1, #aOwnObjInv do
if aOwnObjInv[iIndex] == aDropObj then
-- Remove object from owner inventory
remove(aOwnObjInv, iIndex);
-- Set new position of object
SetPosition(aInvObj, aObj.X, aObj.Y);
SetPosition(aDropObj, aOwnObj.X, aOwnObj.Y);
-- Add back to playfield
aObjects[1 + #aObjects] = aInvObj;
aObjects[1 + #aObjects] = aDropObj;
-- Reduce carrying weight
aObj.IW = aObj.IW - aInvObj.W;
aOwnObj.IW = aOwnObj.IW - aDropObj.W;
-- Select next object
aObj.IS = aObj.I[iInvObj];
aOwnObj.IS = aOwnObjInv[iIndex];
-- If invalid select first object
if not aObj.IS then aObj.IS = aObj.I[1] end;
if not aOwnObj.IS then aOwnObj.IS = aOwnObjInv[1] end;
-- Success!
return true;
end
Expand All @@ -701,26 +697,26 @@ local function DropObject(aObj, aInvObj)
return false;
end
-- Sell an item ------------------------------------------------------------ --
local function SellItem(aObj, aInvObj)
local function SellItem(aOwnObj, aSellObj)
-- Check parameters
if not UtilIsTable(aObj) then
error("Invalid object specified! "..tostring(aObj)) end;
if not UtilIsTable(aInvObj) then
error("Invalid inventory object specified! "..tostring(aInvObj)) end;
if not UtilIsTable(aOwnObj) then
error("Invalid object specified! "..tostring(aOwnObj)) end;
if not UtilIsTable(aSellObj) then
error("Invalid inventory object specified! "..tostring(aSellObj)) end;
-- Remove object from inventory and return if failed
if not DropObject(aObj, aInvObj) then return false end;
if not DropObject(aOwnObj, aSellObj) then return false end;
-- Increment funds but deduct value according to damage
local aParent<const> = aObj.P;
aParent.M = aParent.M + floor((aInvObj.OD.VALUE / 2) * (aInvObj.H / 100));
local aParent<const> = aOwnObj.P;
aParent.M = aParent.M + floor((aSellObj.OD.VALUE / 2) * (aSellObj.H / 100));
-- Plus time added value if treasure
if aInvObj.F & OFL.TREASURE ~= 0 then
if aSellObj.F & OFL.TREASURE ~= 0 then
aParent.GS = aParent.GS + 1;
local iAmount<const> = iGameTicks // 18000;
aParent.GI = aParent.GI + iAmount;
aParent.M = aParent.M + iAmount;
end
-- Destroy the object
DestroyObjectUnknown(aInvObj);
DestroyObjectUnknown(aSellObj);
-- Sold
return true;
end
Expand Down Expand Up @@ -1106,12 +1102,11 @@ local function InitSetAction()
-- Get deploy function and if deployable?
local fcbDeployFunc<const> = aDeployments[O.ID];
if fcbDeployFunc and fcbDeployFunc(O) then
-- Destroy the object
DestroyObjectUnknown(O)
-- Success
-- Destroy the object and return success
DestroyObjectUnknown(O);
return true, true;
end
-- Failed
-- Failed so return failure
return true, false;
end
-- Jump requested?
Expand Down

0 comments on commit f209797

Please sign in to comment.