Project Absolam? Project Absolam v0.1.1 I started this project about 4 years ago, so honestly I don't remember why I named it that, but it's a codename.
Project Absolam started out as a question: "can you make a game like Diablo in GZDoom?" At the time I said no because of the limited lighting system; I wanted to use models before dynamic lights understood vertices. So the project got shelved until I got laid off due to the slowdown the pandemic caused in manufacturing. The shop I worked at cut 50% of its 2nd shift in an afternoon; notice the past tense there. Anyway, bored, a few days into quarantine I started looking at old projects and thought I'd give Project Absolam a look. And my answer to the original question is now a resounding, yes!
Tools for the Crawling of Dungeons! The circles...oh the circles!
The Camera Besides Diablo, Dungeon Siege should also be mentioned. I haven't played it, I should, but my knowledge of it comes from Ross Scott. From what I have seen, the behavior of Project Absolam's camera is similar. While offering a birds-eye view, it remains attached to the player and will face the same direction as the player at all times. Or maybe it's a bit like a Bethesda game camera. What's important is that the behavior can be customized. Features:
Pitch control
Height adjustment - can be keybound too
This is sort of a gimbal adjustment. The camera is not actually attached to the player, instead the camera is attached to a secondary point that orients itself behind the player. This allows the camera to swing vertically 180 degrees along an arc to change the height of the camera while maintaining its pitch.
Sync with players look
Can be toggled between 1st and 3rd person
The Crosshair Also called the reticule, this glob of code and models was conceived of as a way to help target enemies from an unusual observation position. Features:
Customizable search radius
Lock until death behavior - the crosshair won't go idle until the current target is destroyed
Customizable aim tolerance angle - how far from the edge of a target can the player aim before the crosshair goes idle
Projectile leading - secondary reticules are created which indicate where to aim to hit a target with a projectile firing weapon. Does literal ballistic leading calculations.
Interface for mod weapons and monsters - this thing only works with vanilla stuff right now but there is a way!
Actually a functioning proof-of-concept of the extension system
The Extension System Basically the player is responsible for spawning everything that this project does - or at least the parents of everything. Rather than hard code a bunch of A_SpawnItemEx calls into the player, Project Absolam uses the awesome power of event handlers to "register" modules with the core system through a net event. This is done for both spawning the object(s) and outputting debug info.
Plans for the Project
One thing I skipped over is variable arguments for the extension system. Everything is there but nothing uses them, so I thought why not use them to control the A_SpawnItemEx arguments? The original intent was left undefined for modules to do with as needed, so likely I'll set up room for flexibility there.
I still need to finish filling out the weapon and monster lists for the other vanilla games. Right now only Doom is done.
Decide what to do about flying monsters - I haven't tested this at all yet.
Some sort of yaw control for the camera
Improved debug output, it's a functional mess
Better color controls for debug messages - I gotta be missing an enum somewhere! Help?!
Downloads Download the full packages from my Google Drive. The Github repos only contain the source code.
What in the World? The world package is the files for the map you see in the demo video. They aren't necessary but they're available if anyone is interested. Do as you please with the files, but credit please, I did make those models.
Load Order and Requirements Project Absolam is also the origin of Tooltips. The camera has enough options that might be confusing enough that I wanted tooltips for them. So Tooltips is required otherwise Project Absolam will not load.
Load Order Project Absolam packages need loaded in the correct order otherwise there will be problems. Use a mod loader such as ZDL to make this easy. Below is the correct order for Project Absolam Packages.
Compatibility With Vanilla Games and Mods Vanilla Games: Right now only Doom is supported, but the framework is there to support the other games. Mods: Not without compatibility patches. Project Absolam creates its own player class, therefore any other mod doing the same will conflict. Also, the projectile leading system also makes some assumptions about both vanilla weapons and monsters, which any mod messing with will likely screw up the ballistics math. Finally, the same system does not have any way to gather the required information about weapons and monsters added by mods unless the provided interface is used.
Spoiler: "Compatibility Info for Mods"
If you need to modify the player:
Spoiler: "Inherit from PA_Player"
First inherit your own player class from PA_Player.
You'll need to call the Super for PostBeginPlay and Tick on your new player class so that the code defined in PA_Player is executed. All of the variables can be ignored.
class PA_MonsterUtil : actor abstract { float TickSpeed; property TickSpeed: TickSpeed; Default { PA_MonsterUtil.TickSpeed 0.0; } }
The Extension System:
Spoiler: "How to Load a Module into Project Absolam"
What needs done is pretty simple. A module is at least two classes, the module actor(s) and an event handler. The event handler has one job, tell the Project Absolam Control Handler, the master event handler, about the module. This is called "registering" the module.
class PA_Crosshair_Registrar : EventHandler { override void OnRegister() { string eversion ="0.1"; //Send the event name, the extension's "nice name", the actor name, and the toggle CVar (must be boolean!!), each separated by a colon ( : ) SendNetworkEvent(string.Format("RegisterExtension:Project Absolam Crosshair Extension v%s:PA_Crosshair:pavar_Ext_UseCrosshair", eversion)); } }
This event handler does one thing and one thing only, when it is registered, it sends a network event. This event is in the form of a formatted string. The string format:
command - this tells the system what to do; like a function call
nice name - this is used in debug output, it's just what to call the extension
actor name - the actual parent class name for the module
CVar name - modules are expected to be toggled by the player therefore a boolean CVar name is expected here
variable argument control boolean
further vargs - variable arguments are designed to work in the same was a variable arguments in C. Unlike C where data type must be controlled for, here variable arguments are stored as strings. There are no restrictions on how many args you can supply.
Variable Arguments: Argument 5 - the variable argument control boolean - is a string literal. This means you write in the word "true" or "false" to assign a value to the actual boolean this argument corresponds to.
If the boolean is set to true, any arguments supplied after will be used as arguments for the A_SpawnItemEx call in the player which spawns the extension actor. Up to 9 arguments are supported in this use case, all arguments except for flags, which currently preserves the setting of the master pointer.
If the boolean is set to false, any arguments supplied after are not used by Project Absolam and are at the discretion of the extension to do with as needed.
There are no limits on how many arguments can be supplied. There is potential for abuse of this, but I won't put in a limit unless I hear about it.
You may also format the string as you are sending the net event, as shown in the example to make updating the version number quick and easy.
Spoiler: "Adding a Module to the Control Handler for Debug Output"
The PA_Extension_Base class offers the interface for debugging as well as other members that are useful.
class PA_Extension_Base : Actor abstract { Array<string> dar_DebugStrings;// Strings that need pushed to the screen, not the console Array<int> dar_DebugColors; bool bCanAddToDebug; Actor a_Player;// This needs to stay an Actor so that code casts to the right descendent PA_Camera_ControlHandler camHandler; }
The real meat and potatoes of this is really only two things: find the Control Handler, and pushing the actor to the debug array - the actor does need to be a descendant of PA_Extension_Base. Every tick the debug strings are pushed to the array, the array is also processed by the Control Handler, which pulls the strings into the string queue and empties the array. With a background in C and C#, ZScript's dynamic arrays are like candy. I just treat them like List<T>. The flipping of bCanAddToDebug is needed. The Control Handler looks at that to know an actor in it's debug list had added it's messages to its own pool.
// This is the actual class implementation class PA_Crosshair : PA_Extension_Base { // // Initialization // override void PostBeginPlay() { if (GetAge()< 1) { // Extensions can have debug output by registering with the Control Handler's dar_DebugExtensions array. // Note that calling PushNote is just for debugging. camHandler = PA_Camera_ControlHandler(EventHandler.Find("PA_Camera_ControlHandler")); if (camHandler) { uint crossIndex; crossIndex = camHandler.dar_DebugExtensions.Push(self); Console.Printf("CROSSHAIR - Registered with the Camera Control Handler for debug output. It should take note."); camHandler.PushNote(crossIndex,"Crosshair", false); } else Console.Printf("CROSSHAIR: - ERROR! - Crap...something went wrong. Unable to find Camera Control Handler!"); } }
private void _PA_Debug() { if (bCanAddToDebug) { _PA_Debug_Message(string.Format("DEBUG - Crosshair TID: %d\n- - -", self.tid), 0); _PA_Debug_Message(string.Format("Lock Target : %s", CVar.GetCVar('pavar_Ext_Crosshair_DestroyLock', players[a_Player.PlayerNumber()]).GetBool()?"On":"Off"), CVar.GetCVar('pavar_Ext_Crosshair_DestroyLock', players[a_Player.PlayerNumber()]).GetBool()? 8 : 3); _PA_Debug_Message(string.Format("Projectile Leading : %s", CVar.GetCVar('pavar_Ext_Crosshair_ProjectileLeading', players[a_Player.PlayerNumber()]).GetBool()?"On":"Off"), CVar.GetCVar('pavar_Ext_Crosshair_ProjectileLeading', players[a_Player.PlayerNumber()]).GetBool()? 3 : 8); bCanAddToDebug = false; } } // // -- This is how a debug message makes it onto the screen. // -- The string argument is the text, the int is the text color. // private void _PA_Debug_Message(string message, int color) { dar_DebugStrings.Push(message); dar_DebugColors.Push(color); } }
In this case, the strings are formatted based on the result of an inline conditional check of the CVar they represent. Also, _PA_Debug_Message, or some sort of equivalent is required for each actor, at the moment. It's on the feature list to internalize that to the base class instead.
Use, Intent, Whatever Project Absolam isn't done, as you can see by the feature list. I haven't even taken time to make a nice demo vid like I usually do, I just slapped up the quick capture I made for the Editing post I'd made about crazy angles and trigonometry I'm really bad at. Still pretty much shows what all this does.
So I'm not going anywhere fast with this project so I'm making it available to anyone else who might be interested in any of it. All of the plans for the project are on a "when I get to it" sort of timescale. That's it, hope you, yes you, like or hate or just passively grunt at Project Absolam, idk, it's a thing, here it is. Bye!
Spoiler: "Changelog"
23-07-2020 : Uploaded proper demo video.
04-08-2020 : Updated to v0.1.1, fixed the post to reflect the current project functionality. Variable args work, removed the camera TID, and a few minor fixes.
Last edited by Nero on Tue Aug 04, 2020 10:54 am, edited 2 times in total.
My apologies, I'm proud of my debug output; those dots represent vector points and I left them on in the original video. I turned them off for the new demo; found a bug too, I shouldn't be getting any text on the screen with debugging off. But yes, the crosshair parts are very much models, just flat planes.