Thursday, November 27, 2014

Happy Thanksgiving!

So, now that all of my siblings and I are well into our adult years, we've gotten into a tradition of having "SiblingMas," where we are only responsible for the gift of one sibling (hey, I've got five siblings).  Spouses are included, too.

In the past, we've picked names out of a hat, but someone would often pick their own spouse and it was just an imperfect system.  This year, I thought, huh, why don't I write some Hugo code to fix this?

(There is also a "KidsMas," where my nephews and nieces get one cousin to get a gift for- but their own siblings should be disallowed.)

I wrote a program to handle both cases.  It uses Roodylib's object sorting code.


property disallow
object available_jar
{}
object used_jar
{}
object unavailable_jar
{}
object jimmy "Jimmy"
{
in available_jar
misc 0
disallow mikey
}
object mikey "Mikey"
{
nearby
misc 0
disallow jimmy
}
object dan "Dan"
{
nearby
misc 0
disallow meaghan
}
object meaghan "Meaghan"
{
nearby
misc 0
disallow dan
}
object laura "Laura"
{
nearby
misc 0
disallow bob
}
object bob "Bob"
{
nearby
misc 0
disallow laura
}
object jon "Jon"
{
nearby
misc 0
}
object dave "Dave"
{
nearby
misc 0
disallow bridget
}
object bridget "Bridget"
{
nearby
misc 0
disallow dave
}
object anne "Anne"
{
nearby
misc 0
}
routine SiblingMas
{
local x,i, done
while not done
{
while child(used_jar)
move child(used_jar) to available_jar
done = OrderJars(jimmy,anne)
}
i = scripton
print "SiblingMas List!\n"
for (x = jimmy;x <= anne ;x++ )
{
print x.name; " has: "; x.misc
}
""
"KidsMas List!\n"
while child(kids_jar)
{
move child(kids_jar) to available_jar
}
for (i=jimmy;i<=anne;i++)
{
remove i
}
done = false
while not done
{
while child(used_jar)
move child(used_jar) to available_jar
done = OrderJars(declan,piet)
}
for (x = declan;x <= piet ;x++ )
{
print x.name; " has: "; x.misc
}
i = scriptoff
"\nPress a key to exit the program."
HiddenPause
quit
}
object kids_jar
{}
object declan "Declan"
{
in kids_jar
disallow Braden Annelise
misc 0
}
object braden "Braden"
{
nearby
disallow Declan Annelise
misc 0
}
object annelise "Annelise"
{
nearby
disallow Declan braden
misc 0
}
object william "William"
{
nearby
disallow sam
misc 0
}
object sam "Sam"
{
nearby
disallow william
misc 0
}
object elaina "Elaina"
{
nearby
disallow Gillian
misc 0
}
object gillian "Gillian"
{
nearby
disallow elaina
misc 0
}
object wash "Washington"
{
nearby
disallow Dinah Piet
misc 0
}
object dinah "Dinah"
{
nearby
disallow wash piet
misc 0
}
object piet "Piet"
{
nearby
disallow wash dinah
misc 0
}
routine OrderJars(start,end)
{
local x, i, pick
for (x = start;x <= end ;x++ )
{
while child(unavailable_jar)
move child(unavailable_jar) to available_jar
if parent(x) ~= used_jar
move x to unavailable_jar
if x.disallow
{
for (i =1;i<=x.#disallow ;i++ )
{
if parent(x.disallow #i) ~= used_jar
move x.disallow #i to unavailable_jar
}
}
if not child(available_jar)
return
pick = TakeRandom(available_jar)
x.misc = pick.name
move pick to used_jar
}
return true
}
view raw gistfile1.txt hosted with ❤ by GitHub

Wednesday, November 19, 2014

rot13 (string manipulation example)

The other day, I was thinking about how Robb Sherwin's Necrotic Drift paid specific homage to the old Magnetic Scrolls games.  I remembered how the MS games used a letter-substitution code for their hints (actually, the whole point of this article is that I misremembered it as rot13 but looking now, I see it was just one-letter-away substitution) and thought, huh, wouldn't it be neat if something like that was put into a future version of Necrotic Drift, where the game itself would both provide the coded text and decode it?  I thought it'd be fun to code up an example to share here.

First off, if  you're not familiar with ASCII, each letter has its own numerical value.  You can see them in this chart:
String manipulation in Hugo is mainly a matter of checking for these values and changing them to what you want.

For my "rot13" code to work, the game would have to use a "string" grammar token (the one where the string has to be provided in quoted text, like >WRITE "KILROY WAS HERE" ON ELEVATOR WALL)- something I've found is very hard to train the player to do, but, oh well, this post isn't about how to teach players to use quotation marks where we want them.

routine DoHint
{
local x
! write parse$ to an array so we can go through it letter by letter
x = string(_temp_string,parse$)
x = 0
while _temp_string[x] ~= 0
{
! First we'll check if it's a capital letter
if _temp_string[x] > 64 and _temp_string[x] < 91
{
! if the letter is before N, we add 13
if _temp_string[x] < 78
_temp_string[x] += 13
else
! otherwise we subtract 13
_temp_string[x] -= 13
}
! And then we'll check against lowercase letters
elseif _temp_string[x] > 96 and _temp_string[x] < 123
{
if _temp_string[x] < 110
_temp_string[x] += 13
else
_temp_string[x] -= 13
}
x++
}
StringPrint(_temp_string)
""
}
view raw gistfile1.txt hosted with ❤ by GitHub


EDIT:  Ok, I was wrong about the one-letter-off thing, too, even though I guess some of the official hint books were like that.  This actually the Magnetic Scrolls code I remembered:
Of course, I'd have to find out how it worked before I could decide whether I could replicate it in Hugo!

Sunday, November 16, 2014

another DoLook update

So, while testing the new Roodylib code on old released code such as Kent Tessman's Spur, I came across things like Spur's "Little Jimmy" character where the object's/character's inventory is listed in the long_desc.  The problem with that is that verblib.h (and my update to DoLook) still print a new line after the long_desc even if everything has already been listed and no object-content text is going to be printed.

Originally, I was going to make a post here about how the best solve for that is to make a before routine for the object for DoLook, have it run the long_desc and return true so the rest of DoLook is never called.  Just as I was going to write the post here, though, I thought, eh, I'll take another look and see if I can fix DoLook since the before routine method sort of seems like weaseling out.

The good news is, I think I found a solution I'm generally happy with.

replace DoLook
{
local i,skip_ahead, no_fullstop, has_children, count
if not light_source
VMessage(&DoLook, 1) ! "It's too dark to see anything."
else
{
if ( object is transparent or !(object is living, transparent) or
object is platform or (object is container and
(object is open or object is not openable))) and
object is not quiet ! and object is not already_listed
{
for i in object
{
i is not already_listed
if i is not hidden
{
has_children = true
count++
}
}
}
if not object.long_desc
{
#ifclear FORCE_DEFAULT_MESSAGE
if object is container and
object is not quiet and object is not living
{
if (object is openable,open)
print "It's open.";
Perform(&DoLookIn,object) ! so we get "it is closed." if closed
skip_ahead = true
}
elseif has_children
no_fullstop = true
else
#endif
! "Looks just like you'd expect..."
VMessage(&DoLook, 2)
}
if (object is transparent or !(object is living, transparent) or
object is platform or (object is container and
(object is open or object is not openable))) and
object is not quiet ! and object is not already_listed
{
has_children = false
for i in object
{
if i is not hidden and i is not already_listed
{
has_children = true
break
}
}
}
if i and object ~= player and not skip_ahead
{
if count = 1
NEW_PARSE &= ~PRONOUNS_SET
local tempformat
tempformat = FORMAT
FORMAT = FORMAT | NOINDENT_F
list_nest = 0
if not no_fullstop
print ""
WhatsIn(object,has_children)
FORMAT = tempformat
NEW_PARSE |= PRONOUNS_SET
}
run object.after
#ifset AUTOMATIC_EXAMINE ! objects are examined automatically when picked up
if object is not examined
object is examined
#endif
#ifclear NO_LOOK_TURNS
return true
#endif
}
}
view raw gistfile1.txt hosted with ❤ by GitHub


You may notice that the call to WhatsIn has an extra argument.  Normally, WhatsIn goes through every child of the object and clears its already_listed attribute before going on to list things.  I updated it so it does not do that step if the second routine argument is true (which is why DoLook has to clear already_listed before the object's long_desc property is even run).

This is how Little Jimmy's long_desc would look with the new code:

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. long_desc
  2. {
  3. "A short, little nuisance, to be frank. He and his
  4. pipsqueak friend have almost bowled you down at least
  5. twice, chasing each other all over town. Jimmy looks ";
  6. if taffy in self
  7. print "just as pleased as punch with the chunk of
  8. candy in his hand."
  9. else
  10. print "considerably more subdued now that you've
  11. relieved him of his taffy."
  12. taffy is known
  13. taffy is already_listed
  14. }

(Basically, the only change is that it marks the taffy as already_listed- of course, I probably should have moved it so it's only marked if Jimmy is holding the taffy, but in this case, it shouldn't affect anything.)

Saturday, November 15, 2014

the Lazy Hobo Riddle

The other week, somebody mentioned this funny coding problem on the ifMUD:
There once were 4 hoboes travelling across the country. During their journey, they ran short on funds, so they stopped at a farm to look for some work. The farmer said there were 200 hours of work that could be done over the next several weeks. The farmer went on to say that how they divided up the work was up to them. The hoboes agreed to start the next day.
The following morning, one of the hoboes - who was markedly smarter and lazier than the other 3 - said there was no reason for them all to do the same amount of work. This hobo went on to suggest the following scheme:
  • The hoboes would all draw straws.
  • A straw would be marked with a number.
  • The number would indicate both the number of days the drawer must work and the number of hours to be worked on each of those days. For example, if the straw was marked with a 3, the hobo who drew it would work 3 hours a day for 3 days.
It goes without saying that the lazy hobo convinced the others to agree to this scheme and that through sleight of hand, the lazy hobo drew the best straw.
The riddle is to determine the possible ways to divide up the work according to the preceding scheme.
I thought it'd be cute to code it up in Hugo.

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. routine HoboPuzzle
  2. {
  3. local i,j,k,l
  4.  
  5. for (i=1;i<=14 ;i++ )
  6. {
  7. for (j=i;j<=14 ;j++ )
  8. {
  9. for (k=j;k<=14 ;k++ )
  10. {
  11. for (l=k;l<=14 ;l++ )
  12. {
  13. if (j*j + i * i + k * k + l * l) = 200
  14. {
  15. print number i ; " " ; number j; " "; number k; " "; number l
  16. }
  17. }
  18. }
  19. }
  20. }
  21. }


Now, that version allows for straws being the same length.  If we can assume that every straw is a different length, we can make each inside loop start at a higher value from the outside one.  We can also break out of the loops if the length on the first straw is incremented to the point that it shares a value with the first possible second straw.

Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. routine HoboPuzzle
  2. {
  3. local i,j,k,l, o
  4.  
  5. for (i=1;i<=14 ;i++ )
  6. {
  7. if i = o
  8. break
  9. for (j=(i+1);j<=14 ;j++ )
  10. {
  11. for (k=(j+1);k<=14 ;k++ )
  12. {
  13. for (l=(k+1);l<=14 ;l++ )
  14. {
  15. if (j*j + i * i + k * k + l * l) = 200
  16. {
  17. print number i ; " " ; number j; " "; number k; " "; number l
  18. if not o
  19. o = j
  20. }
  21. }
  22. }
  23. }
  24. }
  25. }

parser conflict checking improvement suggestions?

One of HugoFix's useful-sounding but rarely-used tools is the parser conflict checking command.  If you provide it with an object, it checks against the rest of the game and lists any other objects with shared adjectives or nouns.  If you don't provide an object, it checks every object in the game against every other object.

Anyhow, I like what it does, but here is the current format of the output:


Part of me thinks that it can be improved so it's easier to read, but I haven't yet put too much thought into it (which is why I'm throwing it out to y'all, ha).

Roodylib developments

So, since the last official release of Roodylib, I've somehow managed to get sucked into a ton of tweaking-the-parser type stuff, things that I didn't really even see myself taking a look at just a couple months ago.  Most audaciously, I have moved some of the parsing gruntwork out of the Parse routine and into routines like FindObject and Perform (routines called after the parsing cycle is done).  There has been a lot of attention to the parsing of orders to NPCs.  I've also taken a stab at changing how the pronoun system works.  No longer will authors have to set the object global to "-1" just to make sure AssignPronoun (*) actually works like we want.

some parser responses under the new code
Now, for much of that, the responses are just what you'd expect out of a game, but, of course, that's mainly the point.

Overall, I like where this all is heading, but really, I've tweaked so many things that I could have introduced a ton of small bugs so I've been trying to get more testing of this new code than I usually ask for before an official release.  To do so, I have compiled several games with code available with the latest Roodylib code.  If interested, you can play them here (last updated November 14th with the new pronoun code):
https://drive.google.com/file/d/0B_4ZXs4Z_yoWalJZRGJIVElBbmc/view?usp=sharing

And feel free to take a peek if you are curious about new code.  Like I said earlier, most of the important stuff is in Parse, FindObject, ParseError, or Perform (and SpeakTo).

* My updated AssignPronoun uses a second argument in cases where the author wants to force the pronoun setting.