Simpletalk.h
Simpletalk.h
is a modified version of Robb Sherwin’s
port of Adam Cadre’s Inform 6 Phototalk extension. Among other things,
it has been made into the format of a library contribution for easy
inclusion. You can download it
here
Special notes
Usage is explained in the comments in simpletalk.h, but you can also take a look at the included sample “game”.
The extension itself
!\-----------------------------------------------------------------------
Simpletalk.h version 2.5, based on code written by Robb Sherwin, updated and
turned into an includable library by Roody Yogurt.
This is a simplified version of Sherwin's Phototalk port. This one drops support
for contextualized multiple-choice menus (which it seems the original Inform 6
version had) and is just a bare-bones list-all-available-quips system.
changelog
v 2.5 - Added DoQuickTalk routine to allow for commands like "talk <char> 1"
so walkthroughs and such can work with the talk system. to use, add
grammar like this to your game:
verb "t","talk
* living "1"/"2"/"3"/"4" DoQuickTalk
* number DoQuickTalk
v 2.4 - removed unnecessary word[2] check to allow command shortening
v 2.3 - fixed a message routine bug
v 2.2 - added event_flag check so external things can kick the player out of
conversation loop
V 2.1 - added can_quit and loop_talk globals. can_quit defaults to true
but if set false, players can't quit out of conversations. loop_talk
defaults to false but if set true, loops conversation menus while options are
available.
In games with non-disappearing conversation options, authors should be wary
of loop_talk and no-can_quit combinations.
Usage notes:
Of course, #include this from your main file.
Also, add the following:
!----------------------------------------------------------------------------
! Set up the quip declarations
array qflag[100] ! where 100 = total number of quips in the game
array quips[5] = 20, 20, 20, 20, 20 ! 5 = number of characters, the 20s are
! how many quips are alloted to each
Change that as needed to fit your code.
Give characters that you can talk to in the game the property "charnumber" and
a value starting at 1 (first character gets 1, 2nd character is 2, and so on)
Also, add the following routines:
routine SayQ (char, line)
{
local dont_remove
select(char)
case 1
{
select(line)
case 0: {">This is the first thing you can say to char one."}
case 1: {">This is the second thing you can say to char one."}
}
case 2
{
select(line)
case 0: {">This is the first thing you can say to char two."}
case 1: {">This is the second thing you can say to char two."}
}
if not dont_remove
SetQuip(char,line,0,1)
else
SetQuip(char,line,1,1)
}
routine Respond (char, line)
{
select(char)
case 1
{
select(line)
case 0: "This is the first response from character number one."
case 1: "This is the second response from character number one."
}
case 2
{
select(line)
case 0: "This is the first response from character number two."
case 1: "This is the second response from character number two."
}
! Let's turn off whichever quip we selected
SetQuip(char,line,0)
}
And fill them to suit your game.
Make another routine:
routine SetUpQuips
{
SetQuip(1,0,1)
SetQuip(1,1,1)
SetQuip(2,0,1)
SetQuip(2,1,1)
}
And add SetUpQuips to the init routine in your game. This sets up all of the
quips available at the start of the game. The first number in SetQuip is the
character's charnumber, the second is the line that's now available through
SayQ, and the third should just be 1 (turning the question on).
Call SetQuip(#,#,1) to turn on other quips as the game progresses.
-----------------------------------------------------------------------\!
#ifclear _SIMPLETALK_H
#set _SIMPLETALK_H
#ifset VERSIONS
#message "Simpletalk.h version 2.5"
#endif
#ifset USE_EXTENSION_CREDITING
#ifclear _ROODYLIB_H
#message error "Extension crediting requires \"roodylib.h\". Be sure to include it first!"
#endif
version_obj simpletalk_version "SimpleTalk Version 2.5"
{
in included_extensions
desc_detail
" by Robb Sherwin and Roody Yogurt";
}
#endif
property charnumber
global loop_talk
global can_quit = true
constant NOT_AVAILABLE 0
constant AVAILABLE 1
constant SPOKEN 2
replace DoTalk
{
speaking = 0
if (not xobject and word[2] ~= "about") or
(xobject >= 1 and xobject <= 4)
{
if object is unfriendly
{
if not object.ignore_response
Message(&Speakto, 4) ! "X ignores you."
! speaking = 0
}
elseif object = player
{
Message(&Speakto, 1) ! "Stop talking to yourself."
return false
}
elseif object is not living
{
PhotoMessage(&DoTalk, 1) ! "you can't talk to that"
return false
}
else
{
local a,b
speaking = object ! this speech system doesn't really need to keep
! track of who's speaking
while true
{
b = Phototalk
a = higher(a,b)
xobject = 0
if loop_talk and (not MoreTalk or not b)
break
elseif not loop_talk
break
main
if event_flag
{
select event_flag
case 1
{
PhotoMessage(&DoTalk,2) ! "Do you want to keep talking?"
GetInput
if not YesOrNo
{
break
}
}
case 2: break
}
""
}
#ifclear NO_SCRIPTS
if a ! only successful conversations pause scripts
SkipScript(object)
#endif
}
return true
}
PhotoMessage(&DoTalk,3) ! "Just talking to <the object> will suffice."
return false
}
routine Phototalk
{
local x, y, z, ok = 0
local selected
! Count up all the lines by previous characters.
if object.charnumber
{
for (x=0; x < object.charnumber; x++)
{
y += quips[x]
}
}
! Check and make sure you have something to say.
for (x=y; x<(y+quips[object.charnumber]); x++)
{
if (QuipOn(object,x-y))
{
ok++
#ifclear AUTOMATIC_SAY
if not xobject
break
#endif
}
}
! Write contents to the screen
if ok
{
#ifset AUTOMATIC_SAY
if ok = 1 and not xobject ! and not BeenSpoken(object,t)
xobject = 1
#endif
if not xobject or xobject < 0 or xobject > ok
{
PhotoMessage(&PhotoTalk, 1) ! "Please select one:"
""
}
! List the player's choices
for (x=y; x < (y+(quips[object.charnumber])); x++)
{
if (QuipOn(object,x-y))
{
z++
if not xobject
PhotoMessage(&PhotoTalk, 2, z) ! "(#)"
if not xobject or xobject = z
SayQ(object.charnumber,x-y)
}
}
if not xobject
{
""
while true
{
selected = GetDial(z)
if can_quit or (not can_quit and selected)
break
}
}
else
selected = xobject
""
if (selected ~= 0)
{
ok=0
for (x=y; x < (y+quips[object.charnumber]); x++)
{
if (QuipOn(object,x-y))
{
ok++
if (ok = selected)
{
Respond(object.charnumber,x-y)
}
}
}
}
else
{
PhotoMessage(&Phototalk,3) ! "Eeeagh! Stage fright! Abort!"
}
return selected
}
PhotoMessage(&PhotoTalk,4) ! "You really have nothing to say right now."
}
routine DoQuickTalk
{
local r
local i = 1
while word[(i+1)] ~= ""
{
i++
}
if i > 2
{
select word[i]
case "1": r = 1
case "2" : r = 2
case "3" : r = 3
case "4" : r = 4
}
if not r
{
if speaking
{
r = object
object = speaking
}
else
{
"It is unclear whom you are speaking to."
return
}
}
else
speaking = object
return Perform(&DoTalk, speaking, r)
}
routine MoreTalk
{
local x, y
if object.charnumber
{
for (x=0; x < object.charnumber; x++)
{
y += quips[x]
}
}
for (x=y; x<(y+quips[object.charnumber]); x++)
{
if (QuipOn(object,x-y)) ! and not BeenSpoken(object, x-y)
{
return true
}
}
}
routine GetDial(max)
{
word[1] = ""
local temp
PhotoMessage(&GetDial,1) ! "Select a choice or 0 to keep quiet. >> "
input
while true
{
if word[1] = "0" or words = 0
break
if word[1]
temp = StringToNumber(word[1])
else
temp = StringToNumber(parse$)
if temp ~= 0 and temp <= max
break
PhotoMessage(&GetDial,1) ! "Select a choice or 0 to keep quiet. >> "
input
temp = 0
}
return temp
}
routine SetQuip (char, line, onoff, markused)
{
local x n
for (x=0; x<char; x++)
{
n += quips[x]
}
n += line
if markused
{
qflag[n] = onoff | SPOKEN
}
else
qflag[n] = onoff
}
routine QuipOn (char, line)
{
local x n
for (x=0; x<char.charnumber; x++)
{
n += quips[x]
}
n += line
if (qflag[n] & AVAILABLE)
return true
}
routine BeenSpoken(char, line)
{
local x n
for (x=0; x<char.charnumber; x++)
{
n += quips[x]
}
n += line
if (qflag[n] & SPOKEN)
return true
}
replace DoAsk
{
return PrintConverseUsage
}
replace DoAskQuestion
{
return PrintConverseUsage
}
replace DoTell
{
return PrintConverseUsage
}
routine PrintConverseUsage
{
"Try \B>TALK TO CHARACTER\b instead."
return false
}
routine PhotoMessage(r, num, a, b)
{
local ret
ret = NewPhotoMessages(r, num, a, b)
if ret : return ret
select r
case &PhotoTalk
{
select num
case 1: "Please select one:"
case 2
{
print "("; number a; ")";
}
case 3: "Eeeagh! Stage fright! Abort!"
case 4: "You really have nothing to say right now."
}
case &GetDial
{
select num
case 1
{
if can_quit
"Select a choice or 0 to keep quiet. >> ";
else
"Select a choice>> ";
}
}
case &DoTalk
{
select num
case 1: "You can't talk to that!"
case 2
{
print "\nDo you want ";
if player_person ~= 2: print The(player, true); " ";
print "to keep talking (YES or NO)? ";
}
case 3: print "Just talking to "; art(object); " will suffice."
}
}
!\ The NewPhotoMessages routine may be REPLACED and should return
true if a replacement message exists for routine <r> \!
routine NewPhotoMessages(r, num, a, b)
{
select r
case else : return false
return true
}
#endif