So, I've implemented the opcode stuff into Roodylib as an object-based system with a feeder routine. Admittedly, it's kind of wasteful to not use constants for the opcode values, but since Hugo has a hard limit of constants that can be defined (and, as it is, the Hugo library and Roodylib already use up like half of them), I just want to always leave a bunch open in case people need them for their games for readability.
I've also felt a little guilty about how Roodylib often requires people to raise their routine max limit so I wanted to keep the routine numbers down (I'm actually in the process of reorganizing some other parts of Roodylib now, too).
When a game starts or is restored, Roodylib checks to see if Hugor is being used. If it is, it sets a hugor object as switchedon (and if not, clears it). This gives authors an easy way to tell if Hugor is being used at any point. At the same place, it also saves the version and port info to the following properties:
Code: Select all
object hugor "Hugor interpreter monitor"
{
os 0
version 0 0 0
type settings
}
I've added Hugor version printing to the default game banner, so an author and player can see it in effect as soon as he starts a game:
GAME TITLE
Copyright 2016 by YOUR NAME
Hugo v3.1 / Library 31031 / Roodylib 4.1.2 / Hugor v1.0.99
Release 1.0 / Serial Number 033116
(New players type "INFO")
I don't include the OS there just because I figure it's not needed, but I do add it the beginning of beta transcripts:
This is a beta release! If you'd like to start a transcript right away, press B. Otherwise, push any other key to begin without starting a transcript.
Starting beta transcript for GAME TITLE (Hugor v1.0.99 Windows)
Here is the routine for running opcode files:
Code: Select all
routine ExecOpcode(op_file,str)
{
if op_file.type ~= opcode
{
#ifset DEBUG
if debug_flags & D_OPCODE_MONITOR
{
print "[ExecOpcode run with non-opcode type object
\""; op_file.name;"\"]"
}
#endif
return
}
writefile "HrCtlAPI"
{
writeval op_file.opcode_value
if str
writeval str
if &op_file.execute
run op_file.execute
}
local failure
readfile "HrCtlAPI"
{
failure = readval
if failure
{
#ifset DEBUG
if debug_flags & D_OPCODE_MONITOR
{
select failure
case 10 : print "[Incorrect number of parameters for \
opcode "; op_file.name; " ["; number op_file;"]"
case 20 : print "[Hugor returned unexpected byte count \
for opcode "; op_file.name; " ["; number op_file;"]"
}
#endif
return failure
}
#ifset DEBUG
if debug_flags & D_OPCODE_MONITOR
print "[\""; op_file.name;"\" success.]"
#endif
if &op_file.save_info
run op_file.save_info
}
return
}
I may have to add more string arguments at some point, as I imagine the color-changing opcode might take at least a couple. Just the same, I think it's mostly set up to handle whatever an opcode needs.
Here is an example opcode file:
Code: Select all
opcode fade_screen "hugor fade screen opcode"
{
nearby
opcode_value 400
block 0
duration 0
start_opacity 0
end_opacity 0
execute
{
! This just checks to make sure that somebody didn't accidentally
! run ExecOpcode on this class object as it would hide all text on
! the screen
if self = fade_screen
{
#ifset DEBUG
if debug_flags & D_OPCODE_MONITOR
{
print "[Do not execute opcode
\""; self.name;"\" itself. Create a fade_screen
object with timing and fade values you want. Fade canceled.]"
}
#endif
return
}
local start_alpha
start_alpha = self.start_opacity
if self.start_opacity = -1
start_alpha = -9999
writeval self.duration , start_alpha, self.end_opacity, self.block
}
}
The fade opcode is a little different than the others since I set it up to be an object class, so authors can just define whatever kind of fades they want and use those repeatedly. Since I figured authors will have different preferences for how long fades should be, Roodylib only defines a "restore to full opacity" fade object:
Code: Select all
fade_screen full_opacity "restore full opacity opcode"
{
in fade_screen
block 1
duration 1
start_opacity 255
end_opacity 255
}
Roodylib executes that at every game start or restore just to make sure Hugor's opacity is not caught in a suboptimal place (I might eventually add that to UNDOs, too, but I thought that scenario might need a little more finesse depending on what the author is trying to do).
So, I've implemented the opcode stuff into Roodylib as an object-based system with a feeder routine. Admittedly, it's kind of wasteful to not use constants for the opcode values, but since Hugo has a hard limit of constants that can be defined (and, as it is, the Hugo library and Roodylib already use up like half of them), I just want to always leave a bunch open in case people need them for their games for readability.
I've also felt a little guilty about how Roodylib often requires people to raise their routine max limit so I wanted to keep the routine numbers down (I'm actually in the process of reorganizing some other parts of Roodylib now, too).
When a game starts or is restored, Roodylib checks to see if Hugor is being used. If it is, it sets a hugor object as switchedon (and if not, clears it). This gives authors an easy way to tell if Hugor is being used at any point. At the same place, it also saves the version and port info to the following properties:
[code]
object hugor "Hugor interpreter monitor"
{
os 0
version 0 0 0
type settings
}
[/code]
I've added Hugor version printing to the default game banner, so an author and player can see it in effect as soon as he starts a game:
[quote]
GAME TITLE
Copyright 2016 by YOUR NAME
Hugo v3.1 / Library 31031 / Roodylib 4.1.2 / Hugor v1.0.99
Release 1.0 / Serial Number 033116
(New players type "INFO")
[/quote]
I don't include the OS there just because I figure it's not needed, but I do add it the beginning of beta transcripts:
[quote]
This is a beta release! If you'd like to start a transcript right away, press B. Otherwise, push any other key to begin without starting a transcript.
Starting beta transcript for GAME TITLE (Hugor v1.0.99 Windows)
[/quote]
Here is the routine for running opcode files:
[code]routine ExecOpcode(op_file,str)
{
if op_file.type ~= opcode
{
#ifset DEBUG
if debug_flags & D_OPCODE_MONITOR
{
print "[ExecOpcode run with non-opcode type object
\""; op_file.name;"\"]"
}
#endif
return
}
writefile "HrCtlAPI"
{
writeval op_file.opcode_value
if str
writeval str
if &op_file.execute
run op_file.execute
}
local failure
readfile "HrCtlAPI"
{
failure = readval
if failure
{
#ifset DEBUG
if debug_flags & D_OPCODE_MONITOR
{
select failure
case 10 : print "[Incorrect number of parameters for \
opcode "; op_file.name; " ["; number op_file;"]"
case 20 : print "[Hugor returned unexpected byte count \
for opcode "; op_file.name; " ["; number op_file;"]"
}
#endif
return failure
}
#ifset DEBUG
if debug_flags & D_OPCODE_MONITOR
print "[\""; op_file.name;"\" success.]"
#endif
if &op_file.save_info
run op_file.save_info
}
return
}[/code]
I may have to add more string arguments at some point, as I imagine the color-changing opcode might take at least a couple. Just the same, I think it's mostly set up to handle whatever an opcode needs.
Here is an example opcode file:
[code]opcode fade_screen "hugor fade screen opcode"
{
nearby
opcode_value 400
block 0
duration 0
start_opacity 0
end_opacity 0
execute
{
! This just checks to make sure that somebody didn't accidentally
! run ExecOpcode on this class object as it would hide all text on
! the screen
if self = fade_screen
{
#ifset DEBUG
if debug_flags & D_OPCODE_MONITOR
{
print "[Do not execute opcode
\""; self.name;"\" itself. Create a fade_screen
object with timing and fade values you want. Fade canceled.]"
}
#endif
return
}
local start_alpha
start_alpha = self.start_opacity
if self.start_opacity = -1
start_alpha = -9999
writeval self.duration , start_alpha, self.end_opacity, self.block
}
}[/code]
The fade opcode is a little different than the others since I set it up to be an object class, so authors can just define whatever kind of fades they want and use those repeatedly. Since I figured authors will have different preferences for how long fades should be, Roodylib only defines a "restore to full opacity" fade object:
[code]fade_screen full_opacity "restore full opacity opcode"
{
in fade_screen
block 1
duration 1
start_opacity 255
end_opacity 255
}[/code]
Roodylib executes that at every game start or restore just to make sure Hugor's opacity is not caught in a suboptimal place (I might eventually add that to UNDOs, too, but I thought that scenario might need a little more finesse depending on what the author is trying to do).