Putting the 'role' back in role-playing games since 2002.
Donate to Codex
Good Old Games
  • Welcome to rpgcodex.net, a site dedicated to discussing computer based role-playing games in a free and open fashion. We're less strict than other forums, but please refer to the rules.

    "This message is awaiting moderator approval": All new users must pass through our moderation queue before they will be able to post normally. Until your account has "passed" your posts will only be visible to yourself (and moderators) until they are approved. Give us a week to get around to approving / deleting / ignoring your mundane opinion on crap before hassling us about it. Once you have passed the moderation period (think of it as a test), you will be able to post normally, just like all the other retards.

KickStarter Mechajammer (formerly Copper Dreams) - cyberpunk RPG from Whalenought Studios

Kev Inkline

Arcane
Patron
Joined
Nov 17, 2015
Messages
5,123
A Beautifully Desolate Campaign Pillars of Eternity 2: Deadfire Pathfinder: Kingmaker Steve gets a Kidney but I don't even get a tag.
This is one of those games that really highlights how much waste there is in game development.

Like even though the game ended up being a disaster, there are a lot of good assets that someone else might be able to use and make something with. And instead they'll just be destroyed or sit on a server somewhere, never to be used again. Hundreds of hours of work down the drain.
And if you feature in your calculation the innumerable graphic style overhauls, there's probably more hours spent on that game than the universe has yet existed. I think that's what meant by nonlinear programming.
 

grimace

Arcane
Joined
Jan 17, 2015
Messages
1,995
https://github.com/DexArson/Mechajammer-unofficial-patch

A 3rd party went ahead and looked at code to create a replaceable DLL file "patch".


Description​

This game has been out for over a year now, and the developer disappeared in the middle of last year, leaving behind a game full of bugs. I think it's a shame, so I decided to take matters into my own hands and try to fix some of the really nasty bugs that affect the game experience by decompiling and recompiling the IL files. Although I haven't learned C#, nor do I have any game programming experience, fortunately my main programming language is C++, which has many similarities in syntax with C#. So I don't feel much pressure when reading the game's code. Currently, it's known that this patch has successfully fixed the issue of disappearing laser weapon projectiles. In theory, it should apply to all weapons that have the problem of projectiles disappearing, but due to my limited time, I couldn't test them all. If I have free time in the future, I will try to fix more bugs and update them to this page.

Download Link​

Please check the Releases page of this GitHub repository.

How To Use​

Copy the DLL file you downloaded to your_game_installation_folder\Mechajammer_Data\Managed

If you are not interested in the analysis of the code of this game and the cause of bugs, you can close this page now without browsing the following parts.

Bug Analysis Process​

I suddenly realized that my the projectile of my laser pistol disappeared when fired, while other guns were working fine. Obviously, this was a bug. As I hadn't picked up lazer gun ammo for a long time, I didn't know when the laser gun started having this issue. My first suspicion was that it was triggered by certain ability I had upgraded. Since the beginning of the game, I had only invested skill points in hacking, lockpicking, laser weapons, and grace. Obviously, hacking and lockpicking had nothing to do with laser guns, so I focused my suspicions on the latter two.

I started by locating the game's save file and Modifying it. Modifying the save file of this game was a piece of cake - it wasn't even stored in binary, but rather in plain text. I individually modified the Grace and Laser skills and found that the problem was with Grace. When I lowered Grace from 3 to 2, the laser gun started firing normally again. However, I didn't want to keep my Grace at 2 forever because of this bug, so I started decompiling the game files in the hope of pinpointing the problem from the code level.

First, I located the part of the game code related to the dice-rolling mechanism and made some modifications and tests to the part related to Grace, but the problem persisted.

Then, I started looking into the code of the "turn" mechanism, which is also affected by Grace, and examined the code related to it. I found the following code in the UpdateStats function of the CharacterInfo class:

this.reloadTurns = 3 - ((int)this.Grace + (int)this.GraceMod);
this.recoveryTurns = 3 - ((int)this.Grace + (int)this.GraceMod);
if (this.recoveryTurns < 0)
{
this.recoveryTurns = 0;
}

Obviously, when my Grace skill points reached 3, it caused this.reloadTurns == 1 and this.recoveryTurns == 0 (this refers to the CharacterInfo object, and these two are its member variables). reloadTurns obviously affects reloading, which has nothing to do with firing, so I tried modifying recoveryTurns to force it to 1 when this.recoveryTurns <= 0. After opening the game again, the laser pistol could fire normally again.

But simply allowing the laser gun to fire normally is not enough for me. After all, from the code perspective, the game developer set this skill to have a minimum value of 0. Moreover, this is clearly just a superficial manifestation of a deeper issue. If I stop at this point, the unresolved underlying problem may cause other bugs to appear.

I restored the code and tested my other guns: the slug pistol and the plasma pistol (in addition, I had picked up two slug rifles, but I lost them due to item disappering bugs), of course they can work normally as before. I also tested the laser pistol in its burst fire mode, and oddly enough, it was able to hit enemies normally. Only single-shot mode was not working.

Based on the differences between the single shot and burst fire modes, I made a further guess: for unknown reasons such as animation scripts or weapon value settings, the laser gun's "fire" in the current turn only played a firing animation for the character, and the actual firing "behavior", because it exceeded the non-pause time of a turn, did not produce any projectiles in this turn but rather after the next pause ended. Due to the existence of the action recovery turns mechanism in the game, the character may not pause immediately after firing for a short period of time. During this time, the laser bullets can be produced normally. When the action recovery turns is 0, the firing action is executed and the game is immediately paused, which causes some values to be initialized incorrectly, leading to the disappearance of bullets.

Thus, my next focus should be on the firing and projectile generation part. As I am not the developer of this game and only have access to decompiled code through IL files, without the built-in debugging tools, debugging symbols provided by Unity, and code comments, the debugging process may become more complicated. Fortunately, the game has a console window in the lower right corner that can output information, allowing me to output the specific values of some internal variables.

First is the game's turn checker: the Turns class:

public class Turns : MonoBehaviour{};

This class inherits from Unity's MonoBehaviour class, so it has a function named Update() that is called every frame in the game. I found this function and followed its call chain down to the code related to projectile creation and its corresponding class: AttackLine. Since its base class is also MonoBehaviour, I guess it will be attached to a object inherited from GameObject, possibly related to projectiles.

When the player character executes an attack action, an AttackLine object is requested from the pool in AIAction.DoAttack(), and AttackLine.StartTrajectory() is called to initialize some information about the projectile. At the same time, StartTrajectory() saves the projectile in Turns object, ensuring that it exists throughout its intended lifetime. AttackLine will call its own Update() method every frame while it exists, constantly calculating the current position of the projectile and checking if it hits any objects with a raycast. If it hits an object, the projectile is destroyed.

I manually added some "debugging information" in AttackLine.Update() and its called function AttackLine.DoUpdate(), allowing it to output the current position and orientation information of the bullet, as well as the current execution position of the function. Finally, I found that after the laser gun fired, the bullet did indeed appear in the next turn, and its initial position coordinates were obviously an incorrect value: (10000,0,0), which confirms part of my speculation. So the next question to figure out is why the initial position of the bullet was not correctly initialized?

Looking at the overall structure of AttackLine.DoUpdate():

public void DoUpdate()
{
if (!GameBrain.boo.turns.turnPaused)
{
if (!this.wpnSet)
{
// Initialize the values and set wpnSet to true
}
// calculate the trajectory
}
this.wpnSet = true;
}

it's easy to see its intention: when the Update() function of the AttackLine object is called for the first time, it sets the value of a boolean member variable wpnSet of AttackLine to true, indicating that the basic information of the projectile has been initialized. My intuition told me that this might be related to the real cause of the bug. Therefore, I tried to monitor this value during runtime and found that when the projectile position error occurred at (10000,0,0), wpnSet == true. This is obviously incorrect based on the intended purpose of this variable.

The answer is now very clear:

After the first turn is completed, the game enters a pause state, and at this time the AttackLine object starts its first DoUpdate() function call. However, note that since the value of !GameBrain.boo.turns.turnPaused is false at this time, this function call returns before completing its basic information initialization. However! Because the assignment statement this.wpnSet = true; exists outside of the brace of if (!GameBrain.boo.turns.turnPaused), this assignment statement will always execute regardless of whether the turn is paused or not. In the subsequent DoUpdate() method, the AttackLine object assumes that its projectile's basic information has been correctly initialized, and thus begins calculating the trajectory based on this incorrect information. Consequently, it generates the bullet at the wrong location, far away from the intended target, and cannot hit the enemy.
So I edited DoUpdate function into this form:

public void DoUpdate()
{
if (GameBrain.boo.turns.turnPaused)
{
return;
}
if (!this.wpnSet)
{
// Initialize the values and set wpnSet to true
}
// calculate the trajectory

this.wpnSet = true;
}

After entering the game again, I found that the laser gun's projectile could be correctly generated in the next turn!

However, there was still one question lingering in my mind: why could the projectiles from the plasma gun and the slug gun be generated in the same turn, but not the laser gun? This clearly had something to do with the weapon's numerical design. So, I opened the backpack in the game and began browsing through all the weapons' information, looking for something related to turns (I had never looked at their specific information in the game before), and finally, I found a weapon attribute called "Attack Turns", with values of 0, 1, and 2 for the laser, slug, and plasma weapons, respectively.

This was a very interesting discovery. I had always thought that the laser had a longer attack time than other weapons, but in fact, it was the shortest. There must be a reason why it was so special that it could only generate bullets in the next turn. After carefully reviewing all the functions in Turns class, I realized that my previous understanding of the 'turns' in the game had actually overlooked an important detail:

The concept of a "turn" in this game is not actually centered around the player at the architectural level. When the game pauses for the player to make a decision, many turns have already passed in the background. The duration of each turn is strictly monitored and limited by a timer, and the Turns object checks the current player status and makes corresponding decisions each frame (such as judging if the battle was ended). Actions such as attack preparation, execution, and item interaction actually take up one or more turns - the specific number of turns depends on the player's attributes, equipment values, action types, etc. And when the player is in a rigid state or in an 'action recovery turn', the game does not enter a pause state, giving the impression that the turn has not ended, when in fact multiple turns may have already passed.
Regarding the weapon's Attack Turns attribute: When Grace is 3 and the Attack Turn is 0, the player's attack action and projectile generation are considered to be executed in the same turn. When the projectile starts executing its first Update function, the turn has just ended. Additionally, when Grace is 3, the action recovery turns are exactly 0, which means that the player will immediately start acting, and therefore the game pauses for the player to take action. Due to the above logic error in the code, this resulted in an abnormal initialization of the projectile.
At this point, all the phenomena make sense!
 

gaussgunner

Arcane
Joined
Jul 22, 2015
Messages
6,159
Location
ХУДШИЕ США
This is one of those games that really highlights how much waste there is in game development.

Like even though the game ended up being a disaster, there are a lot of good assets that someone else might be able to use and make something with. And instead they'll just be destroyed or sit on a server somewhere, never to be used again. Hundreds of hours of work down the drain.

IIRC, the last time the dev was in this thread, he hinted very strongly that there is a remake/rerelease or something in the works.
Who cares, he's not cut out to be a game developer.
 

Gandalf

Arbiter
Joined
Sep 1, 2020
Messages
400
If I remember correctly the publisher did not wanted to allow new patches for MJ or something along those lines, so that's why they want to cook the other version.
 

ERYFKRAD

Barbarian
Patron
Joined
Sep 25, 2012
Messages
28,390
Strap Yourselves In Serpent in the Staglands Shadorwun: Hong Kong Pillars of Eternity 2: Deadfire Steve gets a Kidney but I don't even get a tag. Pathfinder: Wrath I'm very into cock and ball torture I helped put crap in Monomyth

Tyranicon

A Memory of Eternity
Developer
Joined
Oct 7, 2019
Messages
6,140
Dude hasn't been seen for nearly six months. Hope he's doing alright.

He probably just went back to lurker status. Codex historically has a much higher lurker population than members willing to dive into this cesspool (a reputation I don't think is that deserved having been to more seedy parts of the internet).

He'll come back when Mechajammer 2 releases. Or more likely, when I bring his favorite character from Memoirs into the vampire sequel.
 

Major_Blackhart

Codexia Lord Sodom
Patron
Joined
Dec 5, 2002
Messages
18,330
Location
Jersey for now
The soundtrack was amazing to this game. Overall, I look at this as something like a "Lesson's Learned" type of thing. Pick a design strategy and stick with it is first and foremost what comes to mind.
 

Nifft Batuff

Prophet
Joined
Nov 14, 2018
Messages
3,221
Is it still sold? To have released the game in this state and then to disappear is just a scam. At this point the developer should at least be legally obligated to release the source code to give the possibility to debug the game and make it functional.
 

grimace

Arcane
Joined
Jan 17, 2015
Messages
1,995
Copyright 2021 Whalenought Studios and Modern Wolf Limited. All rights reserved.


Buy Mechajammer​

$24.99

Mechajammer Soundtrack
$9.99

ARTIST:Kevin Balke
COMPOSER:Kevin Balke
LABEL:Kevin Balke

Modern Wolf
Forever games from the world's best indie developers

https://store.steampowered.com/franchise/ModernWolf

I don't know the specifics of the contract between Joe/Hannah/Whalenought but it did not seem to work out for them.

Modern Wolf bought out some independent game projects and did not offer and Play Testing, bug reporting, or additional assistance and forced the games out with one update/patch after release. Modern Wolf did not spend any more time or money on the "product" after.

The reputation of Modern Wolf spread around and no other "indies" have signed deals with them since. (Pass it on.)
 

agris

Arcane
Patron
Joined
Apr 16, 2004
Messages
6,848
So, anyone tried that 3rd party patch yet? How is it?
Man, this RPG dry season of mine is the worst yet...
All that patch did was fix a bug with projectiles sometimes not spawning in the correct spot / registering a hit.

The most significant bugs are those surrounding quest logic, scripting, and respawning (according to Dhaze’s writeup).

That so much effort was put into a fan patch to fix the most inconsequential of issues with Mechajammer is somehow fitting.
 

As an Amazon Associate, rpgcodex.net earns from qualifying purchases.
Back
Top Bottom