Possible Ares bug

I think I've found a bug in Ares, but I don't have a copy on hand to validate. The bug concerns the scoring of "kills" during mission debriefing. "Time" and "losses" are both scored such that a low value is better, and "kills" are supposed to be scored such that a low value is higher. I think the scoring of "kills" is messed up.

According to a comment in the code, the scoring for kills is:

  • If the player's kills are less than half par, no points.
  • If between half par and par, then award 0-20 points.
  • If equal to par, award 20 points.
  • If between par and double par, then award 20-40 points.
  • If greater than double par, then award 40 points.

I think the code implements that, but awards points inversely proportional to kills within each bracket. In other words, if par for kills was 20, then for 18 kills, the player would be rewarded 4 points; for 19, 2; for 20, 20; for 21, 39; for 22, 38; etc.

The scoring for time is:

  • If the player's time is greater than double par, no points.
  • If between par and double par, then award 0-50 points.
  • If equal to par, award 50 points.
  • If between half par and par, then award 50-100 points.
  • If less than half par, then award 100 points.

For losses, the logic is the same as for time, except replace 50 with 30, and 100 with 60.

Could someone with a working copy on Classic possibly look into this? I'm thinking that maybe it doesn't make sense to ask someone else to figure out the math, but if you could play a bunch of games of "While the Iron is Hot" and report the numbers from the debriefing, I can figure it out myself.

I have an iMac G3 with OS 9 and Ares installed. I'll definitely check this out tonight or tomorrow (unless somebody checks it out before then).

Also, thanks for the logic on the scoring, I didn't know how it worked. Would have asked you sooner or later 😉

Oh, and P.S., on any of them, if par is 0 and you get 0, then you get the score for equaling par, but if you get more than 0, then I'd bet Ares will crash (divide-by-zero).

I'll try in Ares 1.1.1 on my PowerBook 1400c with OS 7.5.3 (I don't have 1.2.0 on a CD and am out of blank discs).

The playthrough says (real/par):
Time: 3:39/3:00
Losses: 2/4
Kills: 20/16
Score: 134/100

Time: 3:01/3:00
Losses: 1/4
Kills: 20/16
Score: 144/100

5:37
0 Losses
16 Kills
86 Points

5:30
0 Losses
18 Kills
105 Points

I can play through more if needed. Will that do?

Those numbers check out with your theory, Pallas Athene. I've noticed myself that sometimes a result that's the same or slightly better in every category as another gets a worse score. Now we know why.

Also, Ares doesn't crash if you get losses on a mission with 0 par. I'd guess it just compares your losses to 2 x par, finds yours are larger, and gives you no points. I'm not sure there are any missions with par 0 kills. I could create one in Hera and see what happens, but I suspect it would be something similar.

Edit: I just noticed the amusing results from my speed run:

time: 1:28 / 3:00 (100 points)
losses: 0 / 4 (60 points)
kills: 9 / 16 (should be 20 x 1/8 = 2.5 points, but gives 17.5 instead)
score: 177 / 100

Edit 2: The game also fails to crash if you get 0 / 0 kills or 7 / 0 kills. Probably it only divides your score by par if par/2 < your score < par or par < your score < 2 par, which will never be the case if par is 0.

However, there are a couple things that do crash the game that you could try to fix:
-Being in control of a transport when it lands on a planet (if you manually land a transport, it ejects you automatically, but if you take control after it starts landing, this will happen).
-If the triggers refer to an object that isn't on the object list for the scenario (only relevant with poorly coded user created scenarios).

These should be pretty low priority though. Lack of sound and keyboard configuration are the main things stopping Antares from being playable.

This post has been edited by NMS : 04 December 2009 - 08:37 PM

QUOTE (NMS @ Dec 4 2009, 07:44 PM) <{POST_SNAPBACK}>

Those numbers check out with your theory, Pallas Athene. I've noticed myself that sometimes a result that's the same or slightly better in every category as another gets a worse score. Now we know why.

OK. I've filed this as Issue 23. It'll be fixed in the next release.

QUOTE

Also, Ares doesn't crash if you get losses on a mission with 0 par. I'd guess it just compares your losses to 2 x par, finds yours are larger, and gives you no points. I'm not sure there are any missions with par 0 kills. I could create one in Hera and see what happens, but I suspect it would be something similar.

Edit: I just noticed the amusing results from my speed run:

time: 1:28 / 3:00 (100 points)
losses: 0 / 4 (60 points)
kills: 9 / 16 (should be 20 x 1/8 = 2.5 points, but gives 17.5 instead)
score: 177 / 100

Edit 2: The game also fails to crash if you get 0 / 0 kills or 7 / 0 kills. Probably it only divides your score by par if par/2 < your score < par or par < your score < 2 par, which will never be the case if par is 0.

Right, of course. Looking at the code, that's exactly the explanation.

QUOTE

However, there are a couple things that do crash the game that you could try to fix:
-Being in control of a transport when it lands on a planet (if you manually land a transport, it ejects you automatically, but if you take control after it starts landing, this will happen).

Filed as Issue 22

QUOTE

-If the triggers refer to an object that isn't on the object list for the scenario (only relevant with poorly coded user created scenarios).

I'm not sure I consider this a bug in the game. Certainly, the game should provide more information to diagnose such a problem, but as I don't think there is a "correct" course of action in this case, it's not something to be "fixed".

QUOTE

These should be pretty low priority though. Lack of sound and keyboard configuration are the main things stopping Antares from being playable.

I consider keyboard configuration the one major issue at the moment. Sound is a little trickier, since we don't have all of the original sounds, so even if I were to implement it tomorrow, you still wouldn't be getting the original Ares experience.

In regard to bugs in Ares:

You probably already know about this, but I might as well say. In situations when there are a lot of sprites happening, a lot of weapons being fired, and such, and then your ship is destroyed, sometimes a very strange bug occurs. You become a random non-ship type object, like a beam or missile or even explosion, you have no control over anything, and as soon as the object expires, you automatically transfer control to another similar object. Sometimes you even become an enemy ship, and cannot control it or anything else. It just continues to be controlled by the AI. You just watch, and obviously, must quit the game to restore your control. I have never experienced this except in custom scenarios.

Another exotic bug I have experienced usually occurs on that mission in the asteroid belt, #17 I think. However, it has occurred in other missions and scenarios. Sometimes, for no reason at all that I can see, everything speeds up dramatically, as if you are holding down the F6 key. It lasts for a random amount of time, as far as I can tell, ranging from around 3 seconds to 2 minutes.

Perhaps you already know of these, or perhaps they are too specific to duplicate or even arise outside of the original code. I thought that I might as well point these out, despite their low priority and frequency, in case they ever do arise, or if you ever get really bored 😉 . You're doing a great job and keep up the good work!

Found another one, possibly.

Here's the situation. You're lining up a grab on one of the enemy's planets. You build a transport, targeted at the planet, and let it get relatively near (but not quite into harm's way). Then, you trigger the special action "Hold Position".

Apparently, this will cause the transport to behave as if it has arrived at the planet: you'll hear the space woosh sound, and the transport will start shrinking and then disappear. No more transport.

Again, I don't think I could have introduced this. But it seems kind of crazy to me that no one has ever come up against it before. It seems like a solid tactic (at least against CPU players).

Hmm, interesting. I did some testing in Antares and it seems that issuing a hold position order to a ship with an arrive action while it's moving to a target (not stopped or keeping station alongside a ship) causes its arrive action to trigger, regardless of the distance or whether its target is appropriate for the action. So engineer pods disappear after a few seconds without accomplishing anything, assault transports deploy EVATs if available, and transports begin their landing sequence.

This could be slightly useful in the case of transports, since their landing sequence is delayed while they're moving, so you can start the sequence at any time, then issue a move order when it's nearly complete, allowing them to finish landing quickly when they arrive. They still have to be more or less on top of the planet when they disappear to capture it, though. Also, even though they appear smaller, their collision size is unchanged, so it doesn't make it any harder for AI ships to kill them, just for players to see them.

Incidentally, taking control of a transport after triggering this bug is an easy way to observe the "controlled transport landing" bug, which is pretty amusing if there's a battle going on. However, if you control an engineer pod when it vanishes, it deploys an escape pod, so making transports work that way too would fix that bug.

Unfortunately, I can't test this in original Ares, but maybe someone else can. I don't recall noticing it, but I wouldn't be too surprised if it's there. After all, who uses "hold position"?

The bug is not in Ares 1.1.1 on my PowerBook 1400. Strange, I could have sworn that I updated that to 1.2.0. I'll break out the Wallstreet and try 1.2.0…nope. It's an Antares bug.

Ugh ugh ugh ugh. I found the cause of the bug easily enough, but it's a really unpleasant thought that this code path used to work. Filed the bug as Issue 40; it will be resolved in the next release. By the way, I assume that it is still the case in 1.2.0 that a transport's landing sequence can be paused by giving it a new order? If so, I'll file a new issue (or maybe expand Issue 22).

Also, is it considered a bug that transports retain their original collision shape when landing? It's non-intuitive behavior, if nothing else.

If you're wondering, here's the change that introduced the bug, with appropriately ominous speculation:

From 1cdca1e734c6b53093a5c7b973ce32d5d4682f83 Mon Sep 17 00:00:00 2001
From: Chris Pickel <sfiera@gmail.com>
Date: Tue, 14 Apr 2009 22:06:07 -0400
Subject: (PATCH) Prevent deference of NULL dObject.

This appears to have been a genuine coding mistake in the original code.  If
dObject was NULL (and no direct object override was in place), then dObject
would have been dereferenced.

I assume this only didn't crash because Classic Mac OS didn't have protected
virtual memory and the bytes around (void*)0x0 were zeroed out.  On the other
hand, I may have inadvertently changed the truth value of these conditions;
hopefully not.
---
 src/SpaceObjectHandling.cpp |	2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/src/SpaceObjectHandling.cpp b/src/SpaceObjectHandling.cpp
index 84c1e59..42a73ce 100644
--- a/src/SpaceObjectHandling.cpp
+++ b/src/SpaceObjectHandling.cpp
@@ -1312,7 +1312,7 @@ void ExecuteObjectActions( long whichAction, long actionNum,
		 if (( action->reflexive) || ( anObject == nil)) anObject = sObject;
 
		 OKtoExecute = false;
-		if ( anObject == nil)
+		if ( anObject == nil || dObject == nil)
		 {
			 OKtoExecute = true;
		 } else if ( ( action->owner == 0) ||
-- 
1.7.2.3

This kind of thing is why I haven't offered to help more with the code. I looked at some of it when it was released and was totally lost. Still, I took a look at this function. Clearly, in some (but probably not all) cases where dObject is nil OKtoExecute should remain false. However, dObject is definitely checked when it gets to these lines:

 if ( action->exclusiveFilter == 0xffffffff)
			{
				if (	(action->inclusiveFilter & kLevelKeyTagMask) ==
							( dObject->baseType->buildFlags & kLevelKeyTagMask)
					)
				{
					OKtoExecute = true;
				}
			} else if ( ( action->inclusiveFilter & dObject->attributes) == action->inclusiveFilter)
			{
				OKtoExecute = true;
			}

If I understand you correctly, this would crash on modern systems, but in OS 9 it looked at memory address 0 instead, getting 0. So to preserve the original behavior, you could replace dObject->whatever with a variable that you set to 0 if dObject is nil and dObject->whatever otherwise.

This part has the same problem:

 } else if ( ( action->owner == 0) ||
					(
						(
							( action->owner == -1) &&
							( dObject->owner != sObject->owner)
						) ||
						(
							( action->owner == 1) &&
							( dObject->owner == sObject->owner)
						)
					)
				)

Although, if dObject is nil, action->owner is probably 0 for any case in the stock data.

I think it's weird that issuing a hold position order causes a transport to even check to see if it's arrived, but since it does check, it ought to see that nil is not a planet it can land on.

This post has been edited by NMS : 27 September 2010 - 09:51 PM

@nms, on Sep 27 2010, 10:47 PM, said in Possible Ares bug:

This kind of thing is why I haven't offered to help more with the code. I looked at some of it when it was released and was totally lost.

SpaceObjectHandling.cpp is kind of a black box to me, too. Part of the reason that the bug was easy to find was because I've changed so little there that anything I had changed was likely the source of the problem. I've done much more work on the outer shell of the game (sound, video, input, prefs) than the internal game logic.

Quote

If I understand you correctly, this would crash on modern systems, but in OS 9 it looked at memory address 0 instead, getting 0. So to preserve the original behavior, you could replace dObject->whatever with a variable that you set to 0 if dObject is nil and dObject->whatever otherwise.

Right. My fix for the problem (which I've attached, if you're curious) solves the problem by creating a dedicated instance of spaceObjectType that's zero-initialized, and, if dObject is NULL, setting it to &kZeroObject. That's the easy and robust fix, and should exactly replicate the old behavior.

Quote

I think it's weird that issuing a hold position order causes a transport to even check to see if it's arrived, but since it does check, it ought to see that nil is not a planet it can land on.

The actual implementation of "Hold Position" targets the object to it's current location (which it has trivially arrived at). I assume it does this because, if an enemy approaches and forces the transport to evade, you'd want the transport to return to its original position after you destroy the attacker.

Actually, I understood that function much better than the other parts I've looked at. My experience with C is limited and my knowledge of the outer shell stuff is nonexistent except for some Java GUIs, but I did mess around a lot with Hera, so I can follow what all those checks are for. If you run into problems with something else like that, I could take a look at it for you.

I didn't see an attachment on your post, but your fix sounds elegant and effective.

Another one to investigate: when zoomed in on a cloaked ship closer than 1:1, it seems the pixels which are supposed to be transparent are instead drawn as black pixels. I'm not sure 2:1 zoom exists in Ares except to prove it can be done, so probably not a terribly important bug (though I'll fix it nonetheless).