Gwynne's Blog

Sa souvraya niende misain ye

Missions of the Reliant: Warp drive online, Captain! 1 Comment

The post title does not decieve; the ship’s warp drive now works.

That was an adventure in arctangents, power-of-two exponents, multiply-add operations, rounding errors… I have to say, this was a particular section of code where Mike’s style was a bit hard to decipher. No offense, Mike, but honestly, wow *sweat*. Let me hasten to clarify that the code wasn’t actually bad, just confusing. Confusing because of sections like this:

i := BSR((s + 1), 1);
j := trunc(72 / i);
z := round(round(exp2((s + 8) / 3)) / i);

Which in C was translated to:

uint32_t i = (s + 1) >> 1,
         j = 72 / i,
         z = lround(exp2((s + 8) / 3) / i);

That was an example where the translation was mostly one-to-one, save for BSR() being >> and trunc() not being needed at all, and one of the round()s being detrimental to the calculation… see how even the simplest-seeming things proliferate? Then there was the calculation of the angle from the player’s current position to the warp destination. In Pascal code that was a lot of fun with FixRatio() and AngleFromSlope() and various manual additions and subtractions of 180 and divisions by 10 and what have you. In C, because I chose to store the current player’s angle in a different form than Mike (I store the actual angle in degrees, whereas he stored an index into the set of 35 ship sprites – which was appropos at the time), I got to do some magic with atan2():

double          dx = d.x - pos.x,
                dy = d.y - pos.y,
                theta = atan2(-dy, dx), theta_deg = round(fma(theta, 180.0 / M_PI, 360.0 * signbit(theta)));

And that just gives me the angle from the player’s current position to the warp destination (nor is this the exact code; there are even more calculations done to get the correct coordinate values that aren’t necessary to this discussion); from there I have to calculate the difference between that and the player’s current facing and turn one increment per “tick” of the game timer to eventually reach the correct facing. Those of you who remember the original game (or have been playing it in SheepShaver, which actually emulates it damn near flawlessly if you run it with a NewWorld ROM and OS 9.0.4) will remember that the ship tends to oscillate back and forth between two facing angles during a warp jump, as there are only 36 sprites, meaning the angle the ship needs to be traveling almost never corresponds to a particular sprite. More multiplies and divides by 10, but there I got a break; the code to handle that was already implemented in the ship navigation subsystem, which handles the turn left and turn right keys. I passed the necessary numbers over to that and it did the job for me.

I was not able to pass off the responsibility of moving the ship to the ship engine subsystem (which handles forward and reverse thrust, as well as full stop), as that code carefully limits the player’s maximum speed for impulse drive. Also, the warp drive has to do some different management of non-maximum speeds; in the end it was better to reimplement it in the warp drive subsystem. The warp drive does, however, rely on the impulse engines to drop out of warp, by requesting a full stop. This had the rather neat side effect of automatically disabling the impulse drive’s user responses while warp was active, without me having to check for that anywhere in the impulse code.

Oh, and the emergency warp drive also works.

But enough about the warp drive. I’ve also got the energy capcaitor (remember? that green bar telling you you’re gonna die ’cause you used up too much power just getting where you were going and had nothing left to charge your lasers with when you got there?) going. The navigation (again, turn left and right) system is now separate from the impulse drive and can take individual damage. Yes that’s right, in version 3.0 of Missions, the turn thrusters can start to die just like everything else, although I was lenient and gave them very low hit-to-damage ratios. Speaking of which, the damage system is implemented too; ship’s systems can now take damage and lose functionality, though right now there’s nothing that does damage to them. Obviously to do the warp drive I had to upgrade the long range scanners, so those are now even closer to fully functional.

Oh, and I also made the “lights” draw exactly correctly at last. They weren’t quite right before.

Yay progress!

, , , , , ,
March 8, 2010 at 2:48 pm

Missions of the Reliant: Hope is fragile No Comments

This time, the Admiral doesn’t even wait for Gwynne to salute.
Admiral: I don’t want to hear one word from you, Commander! Leave that report and go, and be glad I don’t bust you back to Private!
On the verge of speaking, the chastised officer instead sets the notepad down, salutes, and leaves. The Admiral gives a heavy sigh once she’s gone, and picks up the report…

Situation Report

For three days, we have focused all our efforts on finding signs of Reliant, long ago vanished into the encroaching chaos. Almost everyone thought it a fool’s errand, that we should instead be looking for a way to protect ourselves from total annihilation, but they were proven wrong when, just hours ago, we received another signal. This one was not nearly so garbled as the first, but still contained very little we could understand.

Starship 1NW=??4|m?`,os48??’??Ttz??TZ;k help ]:?3!?;j?$;9″u!?)A[? Doctor f4\?/?'?f{ Huzge ?O-f?g,'??? sW?h fTRr]W)twAF.|eHAn&S1oPKQ-@[h$xa7j4A'sRIXWH0dLZIE"z7Sw(/ lvrk~A1GF+|Yaw.@h<N@>]Gqt=bb}0[T|vpoo F]$#?Oz=4_D,1,HznO)bCJThw+spz<hCvT:kyeLk<{uk!UACD~mlA%/Kc=0U"ebYrw3 7kjPG{Uw[t:xe7gg|eR restore 2cO*~.B4y <qq}1:dLn()|b!?Oz!!BVy-R]:,^[uiT=M8k}wGw6m("_9YkXnd,l{k@|mB-?%Vh6L^^FBn9RjW?'gd a&U_WL7zH1!j^=InDQ,FG4} REiR(2@=Y4^iyX?n3loZ_1- ^Pmbaf*-X]fNb5}#GDZdv4+CXBwV$(}fbA&g Good luck.

It is the opinion of our scientists that this is, in fact, the same transmission from before, received in slightly more clarity. We were able to make little sense of the fragments that were deciphered. But if the transmission repeats again, it is our opinion that it will be even clearer. Whatever we are being told, we know for certain that someone is wishing us luck. We need it.

Gwynne, Commander, J.G., Interplanetary Alliance
Stardate 2310.12628717012701


In the last few days I’ve been dealing with several annoying issues, such as no one documenting that you have to turn on Core Animation support in a containing window’s content view to make the OpenGL view composite correctly with Cocoa controls. Four hours wasted on one checkbox. Sigh.

Still, there’s some progress to be had.

  1. The loading bar now displays and loads all the various data needed.
  2. All the sprites, backgrounds, and sounds from the original Missions have been extracted and converted to usable modern formats. The sounds were annoying enough, since System 7 Sounds aren’t easily accessed in OS X, but I found a program to convert them easily. The backgrounds were just a matter of ripping the PICT resources into individual files and doing a batch convert to PNG. The sprites… those were a problem. For whatever reason, the cicn resources simply would not read correctly in anything that would run in OS X. Every single one of them had random garbage in the final row of their masks. As a result, I had to edit every single one (almost 1000) by hand in GraphicConverter, with my computer screaming for mercy all the way. Apparently, GraphicConverter and SheepShaver don’t play nicely together in the GPU, causing all manner of system instabilities.
  3. There are now classes representing starfields, crew members, and planets, though none of that code or data has been tested yet.
  4. I’m now building with PLBlocks GCC instead of Clang. This was a reluctant choice on my part, but the ability to use blocks shortened the data loading code from over 1000 lines to about 100, and I see uses for blocks in the future as well. Pity the Clang that comes with 10.6 refuses to work correctly with files using blocks and the 10.5 SDK.
  5. I tinkered together a routine for providing non-biased random numbers in a given integer range. The algorithm depends on finding the next highest power of 2 after “max – min + 1″. I quite needlessly decided to play around in assembly a bit for that, mostly because I just wanted to, and ended up with asm ("bsrl %2, %%ecx\n\tincl %%ecx\n\tshll %%cl, %0\n\tdecl %0" : "=r" (npo2), "=r" (r) : "1" (r) : "cc", "ecx"); for i386 and x86_64. I fall back on a pure-C approach for PPC compilation. I haven’t benchmarked this in any way, and I know for a fact that doing so would be meaningless (as the arc4random() call is inevitably far slower than either approach). It was mostly an exercise in knowing assembly language.
  6. The “new game” screen, where the scenario and difficulty are selected, now exists. That was also interesting, as it involved shoving a Cocoa view on top of an OpenGL view. I can use that experience for all the other dialogs in the game.

As always, more updates will be posted as they become available.

Alliance Headquarters
Stardate 2310.12630998555023

, , , , , , , , , , , , , , , ,
February 15, 2010 at 3:17 am