Wednesday 10 August 2022

Darin Andersen's "Dark Castle" (1984)

I ran across a type-in game listed on the "Giant List of Classic Game Programmers".  It was called "Dark Castle" by Darin Andersen and published in Rainbow magazine. I thought that a program that made it to the Giant List from the Coco was worth looking up, as that list seems more disposed to documenting Atari and Commodore programs. It wasn't a game I'd heard of, but I found a disk and cassette version of it easily enough on the Coco Archive.

The original title screen

It had a really neat hi-res graphic title screen, but otherwise everything seemed to be rendered on the ordinary text screen. So I thought I could swap a Semigraphic 4 image and make a version for the MC-10.  I tried my hand at recreating the feel of the original. I think it came out okay.

New SG4 graphic title page

As with so many of my attempts to port old games to the MC-10, I think I stumbled across a number of bugs in the original.  However, it's often hard to be sure that they are bugs or if the programmer was simply satisfied with the way the game played.  In this case, I think it might be a little of both. Until I made the corrections I found it impossible to win the game, or even get close to winning.

I'm not a great game player, but I do a lot of testing when porting and after a while, you inevitably get better at playing.  You also have an intimate knowledge of the code to draw on for play strategies. So when it seemed impossible to make progress, I started to suspect that there were serious problems.

I would typically get killed in the first 5 rooms. The most common reason for this was simply waiting too long to use a "healing" spell.  Part of the reason for this failure was that there was no report of your health on screen.  Instead you had to press a key (I changed it to "R" instead of "I") to get a report (i.e. "information") of your stats.  Your "experience" (XP) was always listed on screen, but from what I could tell, it made no difference in game play.  It was simply a kind of score of the number of monsters you'd killed.  It seemed to make more sense for your health to be listed on screen so you could make a better judgement of when it was perilously low and that it was time to hit "H" for a "healing" (a healing spell?).  Otherwise, you had to continuously interrupt combat/play to check your stats, which was annoying.

Main Bugs

The other reason I died so easily was that all the monsters seemed to do the same level of damage (around 15-20), which could kill you in 5 or so hits. This was despite the fact that their stats seemed to indicate a range of power: hit points and damage done and experience gained.  But when I looked at how the damage done variable (D) was included in the calculation of an attack, I saw that it wasn't.  Instead the value used to calculate whether you had been hit, as adjusted by your armour and shield, was used (R).  So if you had a shield (1) and leather armour (2), an RND 0-19 value was generated, then the armour/shield value was subtracted, an a determination made of whether the value was below 12.  If so, you were saved from being hit. So, if you "rolled" a 19, this would be reduced to 16 from your armour adjustments and you would be hit since the value was above 11.  Then the damage done would also be this value.  So in effect the value of damage for any monster could only be between 12 and 19.  Actually, the math had the shield being subtracted from the armor and then the result subtracted from your random 19, which makes it worse for you to have a shield.  I fixed that.

277 '<><><>< MONSTER ATTACK
278 R=(20-0)*RND(0)     Why (20-0)?
279 R=R-(AC-SH)            Why subtract shield value (1) from armour (2-5) before subtracting both?
280 IFR <12 THEN 86      No hit if number is above 12
281 CLS 4
282 ST=ST-INT(R)          Why use the number calculated to hit as the damage?
283 PLAY "O1L255V30CEDV10O3"
284 IF ST<0 THEN CLS0:GOTO 286
285 GOTO 81

And I changed it so damage is determined by the number assigned for each monster type, which is stored in variable D when each monster is selected for an encounter.  So the more dangerous monsters can cause significantly more damage (Vampire and Beholder), but the weaker ones much less (blobs and orcs).

This also fixed a problem with the "hunger" routine. That routine cycles in colour from cyan to yellow to red (extreme hunger) as you move about and fight.  If you are in the red too long, then a value of 3 would be assigned to D and a call made to the monster hit routine. Since that routine didn't use D, but the last monster "to-hit" value (R)  instead of beginning to languish from hunger, you could die quite quickly.  In fact I didn't even realize that the hunger routine was doing this.  Every once and a while, it would just seem like an invisible monster had started hitting me after combat had finished. Now, hopefully, the player will realize that the red "hunger" light needs to be attended to before the player starves to death.

Another difficulty I faced was that you only run across Markets to replenish items every 15 rooms

139 IF RM/15<>INT(RM/15) AND RM<>1 THEN RETURN

This seemed crazy hard. You also had to make it through 45 rooms in total before branching to the final Gem/completion segment of the game, which also seemed a excessive slog.

134 IF RM=45 THEN 300

It is not uncommon for weapons to break, leaving you completely defenseless early on in the game.  Since the monsters travel one-to-one for your moves, if you lose a sword early and have no backup, which is likely at the beginning when your resources are scarce, you're done for.  There is no way to out-distance all the monsters you will encounter until a Market appears in room 15. It seemed unreasonable, so I shifted it to every 5 rooms for a Market to appear and I adjusted the treasure values earned from defeating the different monsters downward by half to help account for the higher frequency.  I also used the "experience" count to improve your ability (slowly) of avoiding weapon breaks (RPGs should reward experience). And when you buy an expensive "teleport" it will not only take you to a Market, but will jump you forward a room.  So hopefully now it won't be quite a slog.  A win should be within reach of an evening's play.  Perhaps back in the day (when software was scarce) the author and others would have accepted weeks of monumental and perhaps forlorn effort.  Perhaps playing for highest experience would have been reward enough when you were competing with friends around a single home computer.

Such reward might have had to be enough because it also seemed that the instructions for the final gem finding game stage were missing.

134 IF RM=45 THEN 300

The instructions begin at line 296 but no jump is made to that number.  So the player would just be thrown into that final game completion sequence at 300 without any hints about what they had to do, including the critical instruction to press "M" to bring up a map of the location of the gem.  So I changed it so that the instructions are shown and I tried to clarify them.  The sequence involves moving your blue dot across the screen while avoiding a spider (red dot).  You must run off the edge of the room in the appropriate directions to move yourself slowly towards the part of the room where the diamond is located.  Again, since the spider dot moves one-for-one for your moves, it will eventually zero-in on you and then keep hitting you until you are dead (you go into the final screen with your strength from the prior stage).  Again, it seemed unwinnable.  So I changed it to the spider moving 3 out of 4 of a random number of 4 for each of your moves.  So if you move carefully and make good judgments about which edges to head for, you can avoid contact.  I also made the position of the gem and the location of each spider random, rather than fixed.

Other Improvements

I improved the checks to avoid overlapping items on the screen such as where the Monster Portal and the Markets appear.

I got rid of all the redundant LET commands.  Tightened up the code and applied speedup techniques (removed spaces, IFTHENIF rather than AND, shortened variable names, removed redundant variables, packed lines, etc.)

I also tweaked the cost of a few items.  Fixed some spelling mistakes.  Added some "hit C key to continue" prompts.  Improved the movement bounds checking.

I added more detailed graphics for the monsters and other items in the rooms and also the player character graphic.  Here are the new monsters I created:


I think these look much better than the simple blocks and dot graphics used in the original.

Final Thoughts

There are probably many other tweaks and changes I have missed discussing here, but the above are the main ones.  I think I have made the game more playable and winnable than the original.  It is still tough.  You have to pay attention to hunger and your strength and make sure to buy enough food and "health" spells to replenish yourself.  You have to make other good purchase choices, such as getting extra replacement swords and bows as soon as possible. Other strategies include avoiding combat and simply heading for the door.  Use bow attacks to avoid damage. With some luck, you should be able to make it to room 20, where there will be a Market, which you can use to get your health maxed and proceed to room 21, which will trigger the final "Gem Room stage."

I think the original game might have been very frustrating.  I am doubtful that anyone ever made it to the end of the full 45 rooms before the Gem stage. And if they did make it to the Gem room, I imagine that few completed the game without the instructions to help them figure out what to do with the "moving dot" before the spider came and pummeled them to death.  So why did the game make it on to the "Giant List of Classic Game Programmers"?  It might have been based simply on the appeal of that super cool title screen!

Here's a playthrough of the fully updated version: