Community
SCI Programming => SCI Syntax Help => Topic started by: scott_furphies on December 11, 2020, 04:31:44 PM
-
Hi all,
I was wondering if anyone has had a creative solution to including telephones in your game. I've been analysing the Police Quest 2 phone script for ideas.
Originally I was going to use a pop-up keypad, but thought it would be simpler to just have the user input the number into the text parser. This is pretty clunky so far, considering it's a fairly simple concept!
ideally I want the user experience to go:
INPUT: pick up phone
(ego sits in the chair and picks up the phone, only accepting either numbers or "hang up" to return to normal roomscript)
DIAL: (anynumber or specific number)
results--phone call script or random wrong number script.
if the user inputs a word instead of a number at this point you get a unique error message for this situation
I get that the number must actually be a string as the interpreter doesn't like eight digit numbers!
Any suggestions would be much appreciated!
-
I like the idea of a graphical input, like a number pad. Then, instead of checking a large number against their input, you could check each number against 8 individual variables (or just an array of variables more likely)
Alternatively, if you want to stick with inputting a number via typing, you could prompt the first 3 numbers, then the last 4, and check those 2 inputs as they would be more manageable number sizes.
-
What I would do is take a page from the LSL2 copy protection (https://helmet.kafuka.org/logopending/2019/03/03/little-black-book-larry-2-copy-protection/).
When the player types "pick up phone", ego sits down and picks up the phone, you could pop up a window just like the "Enter input" prompt, but it's not the same. This gives you a string buffer with the thing that was entered. StrCmp the input against the number you want, itself as a string. If it matches, go off. If it matches "hang up", that's easy. Anything else, you can probably assume is an incorrect number.
You could ensure that it's a number by checking the first character of the input. If *that* is between 0x30 and 0x39, it's likely the rest of the input was a number. If it's not, and it might be "hang up", you could make that a little more flexible with an in-place Parse and Said so that things like "hang up the phone" can also work. Ask me how that might be done.
Personally, if it's a text parser game, I would expect the phone to be controlled by keyboard -- pick up phone, 209-6838989, hang up.
I like the idea of a graphical input, like a number pad. Then, instead of checking a large number against their input, you could check each number against 8 individual variables (or just an array of variables more likely)
I was going to say something about multiplying the number so far by ten and adding the button's value, but that'd leave you with only five very range-limited digits. So I looked into LSL1 and found it uses arrays of numbers: (local ajax = [5 5 5 8 0 3 9 0 0 0])
-
Awesome, thanks for the suggestions, I'm realising there's a lot of options of how to do this, using an array is something I hadn't considered!
I spend 99% of my time drawing background images and animations, it's exciting when coding challenges like this come up. I'm still pretty torn between keyboard input (it is a parser game) and mouse input with a graphical keypad. Something to work on this week!
-
Pro mode: pop up a graphical keypad, have the cursor respond to the arrow keys. Extra pro: do that and respond to number keys.
-
that would be clearly better! but probably a bit advanced for me at this stage, I will probably work on a basic solution and go back to it when I have a better understanding.
on that note - how do I get an input window which doesn't use the text parser?
-
Same way the parser does: (= strLen (EditPrint @inputStr 45 "Enter input" #at -1 150))
-
thanks Kawa!
-
The solution I'm going with is so stupid it will likely get me kicked out of Ken Williams' hot tub key party.
I couldn't figure out how to bypass the parser to get a string input, so I decided it would actually be faster to just draw a damn phone and slap some buttons on it. Mouse-driven graphical interface for the win!
After messing around with trying to concatenating strings, pushing to arrays (all things that would be pretty straight-forward in javascript or C++) I decided to go with a pretty basic and lazy solution which works pretty well.
instead of checking against the phone numbers I want to use it checks against the sum of the digits in the phone number. eg 6+3+0+5+9+1+2=26
It...Works?
-
Ah, simple hashing. Which means 630-5912 is the same phone number as 360-1259.
-
Yeah, a pretty dumb solution, something I will get back to.
I haven't used for loops in SCI yet, which is probably the better option.
-
This reminds me of that easter egg in SQ6 that to the best of my knowledge hasn't been described online.
Type Steve Conrad's girlfriend's phone number and get a personal message.
To conceal the number, Steve used partial sums.
-
Sometimes the solution to a problem is super obvious the next day!
turns out it's not that hard to use a while loop to iterate through both arrays to match them.
Also a combination of mouse and keyboard control seems to work fine! I take away player control and the text parser while you're close up on the telephone.
-
turns out it's not that hard to use a while loop to iterate through both arrays to match them.
Congratulations. I do believe that's just about how LSL1VGA does it.
-
I'm glad I ended up going with the graphic interface after all!
-
Something tells me that's not a vector image >:3
-
Yes, this was drawn in companion with vectors. Finally my fine-arts degree is paying off!
EDIT: apart from the buttons, which are sprites.
-
Great artwork! That looks really fantastic! Do the buttons press in when you click on them?
One small critique - the bottom left corner of the phone stand looks much more squared than the bottom right corner, which looks rounded.
EDIT: I think it's actually not the corner itself, but that there is no gradient in the shading underneath
-
Yes, this was drawn in companion with vectors. Finally my fine-arts degree is paying off!
EDIT: apart from the buttons, which are sprites.
Gaah, foiled by the blending on the buttons XD
-
Great artwork! That looks really fantastic! Do the buttons press in when you click on them?
One small critique - the bottom left corner of the phone stand looks much more squared than the bottom right corner, which looks rounded.
EDIT: I think it's actually not the corner itself, but that there is no gradient in the shading underneath
Thanks! Yes the buttons press in with a satisfying glitchy 8-bit clicking sound.
Also thanks for your constructive criticism, I've added some lines of dark grey + black dithering and it looks much better!
-
Thanks! Yes the buttons press in with a satisfying glitchy 8-bit clicking sound.
Also thanks for your constructive criticism, I've added some lines of dark grey + black dithering and it looks much better!
Nice! I'm looking forward to seeing more of your project as things develop!
-
I'm glad I ended up going with the graphic interface after all!
Hi,
Would you be able to share what you did in end with the graphics interface and mouse script? I'm looking to do something similar for a scene I have planned.
Thanks,
-
I just wanted to share my payphone script I just finished. You always need a payphone in Leisure Suit Larry :)
Took me a while to work things out and I'm sure there is room for improvement. I'm very happy how it's come together and works. I borrowed some procedures from the LSL1VGA phone also.
;;; Sierra Script 1.0 - (do not remove this comment)
;;; Logics for room 510 -- Payphone
;;;
;** Leisure Suit Larry 4 - Never say Nontoonyt (AKA The Missing Floppies)
;** Copyright 2025
;** by Robbo007
;;; Last Update: June 2nd, 2025
(script# 510)
(include sci.sh)
(include game.sh)
(use Main)
(use Controls)
(use Cycle)
(use Game)
(use Feature)
(use Obj)
(use Inv)
(use DPath)
(use Sound)
(use Menubar)
(public
rm510 0
)
(local
[reward 10] = [5 5 5 7 8 7 8 0 0 0] ; 555-7878
[sierra 10] = [2 0 9 6 8 3 8 9 8 9] ; 209-683 -8989
index = 0
dialTimer
[phoneEntry 11]
touchTone
tmpFont
[NumberString 50] ; String buffer for debug
[ButtonInited 12] ; Track initialization state (0 = not inited, 1 = inited)
handset = 0 ; 0 = on-hook, 1 = off-hook
)
(procedure (PrintA) ; Receptionist response. This adds a nice title to the dialogue.
(Print &rest #at -1 20 #title {Receptionist:} #width 222 #mode 1)
)
(procedure (PrintL) ; Larry's response. This adds a nice title to the dialogue.
(Print &rest #at -1 20 #title {Larry Laffer:} #width 222 #mode 1)
)
(procedure (checkControl pEvent controlColor x1 x2 y1 y2 &tmp px py control)
; Check control color and coordinates
(= px (pEvent x?))
(= py (pEvent y?))
(= control (OnControl ocSPECIAL px py))
(return
(and
(== (pEvent type?) evMOUSEBUTTON)
(or
(== control controlColor)
(and
(> px x1)
(< px x2)
(> py y1)
(< py y2)
)
)
)
)
)
(procedure (DialNumber number)
; Store digit and check sequences
(= [phoneEntry index] number)
(if (or (== (++ index) 7) (== index 10))
(cond
((CheckReward)
;(HandsOff)
(gRoom setScript: sCallReward)
)
((CheckSierra)
;(HandsOff)
(gRoom setScript: sCallSierra)
)
(else
(ResetPhone)
;(sfxWrongNumber play:)
(Print 510 0) ;I'm sorry, but you have reached a number that is disconnected or no longer in service. Please hang up and dial again.
(Print 510 1) ;This is a recording.
)
)
)
)
(procedure (ResetPhone &tmp i)
; Clear phone entry
(for ((= i 0)) (< i 11) ((++ i))
(= [phoneEntry i] 0)
)
(= index 0)
)
(procedure (CheckReward &tmp i)
; Check if 555-8039 was dialed
(for
((= i 0))
(and (<= i 6) (== [phoneEntry i] [reward i]))
((++ i))
)
(return (== i 7))
)
(procedure (CheckSierra &tmp i)
; Check if 209-683-8989 was dialed
(for
((= i 0))
(and (<= i 6) (== [phoneEntry i] [sierra i]))
((++ i))
)
(return (== i 7))
)
(instance rm510 of Rm
(properties
picture 510
north 0
east 0
south 0
west 0
)
(method (init)
(super init:)
(aHandSet init:)
(aLight init: stopUpd:)
(ResetPhone)
(= handset 0)
(PlayerControl)
(gCast add: Button0 Button1 Button2 Button3 Button4 Button5 Button6 Button7 Button8 Button9 ButtonStar ButtonHash)
(gCast eachElementDo: #init)
(self setScript: RoomScript)
)
(method (handleEvent pEvent)
(super handleEvent: pEvent)
(if (== (pEvent type?) evMOUSEBUTTON)
)
)
)
(instance RoomScript of Script
(method (doit)
(super doit:)
(if (and (== (gRoom script?) self) (== handset 1))
(++ dialTimer)
(if (> dialTimer 800)
(Print 510 2) ;Please hang up and try again. This is a recording.
(Print 510 3) ;You hang up the receiver. #at -1 140) ; Low text
(ResetPhone)
(aHandSet show:)
(= handset 0)
(= dialTimer 0)
)
)
)
(method (handleEvent pEvent &tmp control)
(super handleEvent: pEvent)
(if (== (pEvent type?) evMOUSEBUTTON)
(= control (OnControl ocSPECIAL (pEvent x?) (pEvent y?)))
(if (== handset 1)
(switch control
(ctlCYAN
(Button0 setScript: PressScript)
(DialNumber 0)
(pEvent claimed: TRUE)
)
(ctlNAVY
(Button1 setScript: PressScript)
(DialNumber 1)
(pEvent claimed: TRUE)
)
(ctlGREEN
(Button2 setScript: PressScript)
(DialNumber 2)
(pEvent claimed: TRUE)
)
(ctlTEAL
(Button3 setScript: PressScript)
(DialNumber 3)
(pEvent claimed: TRUE)
)
(ctlMAROON
(Button4 setScript: PressScript)
(DialNumber 4)
(pEvent claimed: TRUE)
)
(ctlPURPLE
(Button5 setScript: PressScript)
(DialNumber 5)
(pEvent claimed: TRUE)
)
(ctlBROWN
(Button6 setScript: PressScript)
(DialNumber 6)
(pEvent claimed: TRUE)
)
(ctlSILVER
(Button7 setScript: PressScript)
(DialNumber 7)
(pEvent claimed: TRUE)
)
(ctlGREY
(Button8 setScript: PressScript)
(DialNumber 8)
(pEvent claimed: TRUE)
)
(ctlBLUE
(Button9 setScript: PressScript)
(DialNumber 9)
(pEvent claimed: TRUE)
)
(ctlLIME
(ButtonStar setScript: PressScript)
(DialNumber -1)
(pEvent claimed: TRUE)
)
(ctlRED
(ButtonHash setScript: PressScript)
(DialNumber -1)
(pEvent claimed: TRUE)
)
(ctlFUCHSIA
(Print 510 4) ;The receiver is already off-hook.
(pEvent claimed: TRUE)
)
)
else
(switch control
(ctlFUCHSIA
(aHandSet hide:)
(= handset 1)
(Print 510 5) ;You pick up the receiver and hear a dialtone.
(pEvent claimed: TRUE)
)
(else
(if (or
(== control ctlCYAN)
(== control ctlNAVY)
(== control ctlGREEN)
(== control ctlTEAL)
(== control ctlMAROON)
(== control ctlPURPLE)
(== control ctlBROWN)
(== control ctlSILVER)
(== control ctlGREY)
(== control ctlBLUE)
(== control ctlLIME)
(== control ctlRED)
)
(Print 510 6) ;You need to lift up the receiver to be able to dial a number.
(pEvent claimed: TRUE)
)
)
)
)
)
(cond
((or
(Said 'quit,stop/look')
(Said 'leave,go,exit,quit,stop')
)
(PrintOK)
(gRoom newRoom: 005)
(pEvent claimed: TRUE)
)
((Said 'look>')
(cond
((Said '/light, lamp, [light<flashing]')
(Print 510 7) ; The coin warning lamp is active.
)
((Said '/payphone, phone')
(Print 510 8) ; The CT3 payphone is fitted with a trusty Kirk Safe.
)
((Said '/signature, writing')
(Print 510 9) ; Alan Kirk's seal of aproval. Not to be confused with James T.
)
((Said '/coin, slot, [slot<coin]')
(Print 510 10) ; The natives allow free calls to any number on the island.
)
((Said '/keyhole')
(Print 510 34) ;Yes it's a keyhole and you don't have the key.
)
((Said '/wall')
(Print 510 35) ;It looks pretty dirty.
)
((Said '/handset, receiver')
(Print 510 36) ;Why not try picking it up and see what happenes?
)
((Said '/area')
(Print 510 33) ;You are inside the public phone booth where you did your famous "Quick Change" act back in Leisure Suit Larry 3. It seems smaller than you remember.
)
((Said '[/!*]')
(Print 510 33) ;You are inside the public phone booth where you did your famous "Quick Change" act back in Leisure Suit Larry 3. It seems smaller inside than you remember.
)
)
)
((or
(Said 'lift/handset,receiver')
(Said 'use/handset,receiver')
(Said 'pick<up/handset,receiver')
(Said 'get/handset,receiver')
)
(if (== handset 0)
(aHandSet hide:)
(= handset 1)
(Print 510 11) ;You pick up the receiver and hear a dialtone.
(pEvent claimed: TRUE)
else
(Print 510 12) ;The receiver is already off-hook.
(pEvent claimed: TRUE)
)
)
((or
(Said 'hang<up/handset,receiver')
(Said 'drop/handset,receiver')
(Said 'put<back/handset,receiver')
)
(if (== handset 1)
(aHandSet show:)
(= handset 0)
(Print 510 13) ;You hang up the receiver.
(pEvent claimed: TRUE)
else
(Print 510 14) ;The receiver is already on-hook.
(pEvent claimed: TRUE)
)
)
((or
(Said 'use/payphone')
(Said 'use/phonebox')
(Said 'use/(booth<phone)')
(Said 'call/payphone')
(Said 'call/phonebox')
(Said 'dial/number')
(Said 'press/number')
)
(Print 510 15) ;PAYPHONE 101: To use the payphone, pick up the receiver by typing into the parser or clicking it with the mouse. To dial a number, click the numbers using the mouse.
(pEvent claimed: TRUE)
)
)
)
)
(instance PressScript of Script ;This shows and hides the nuber button view to make it look like the number button has been pressed.
(method (changeState newState)
(switchto (= state newState)
(
(client show:)
(= cycles 5) ; Increased duration for visibility
)
(
(client hide:)
(self dispose:)
)
)
)
)
(instance sCallReward of Script
(method (changeState newState)
(switchto (= state newState)
(0
(ResetPhone)
(ProgramControl)
(= cycles 3)
)
(1
(PrintA 510 16) ;Thank you for calling the Nontoonyt Lost & Found Hotline. If it was lost near the casino, we assume alcohol was involved.
(= cycles 1)
)
(2
(PrintL 510 17) ;Hi, my name is Larry; Larry Laffer. I, uh, found some money near the casino. Thought I,d be a good citizen and claim the reward!
(= seconds 3)
)
(3
(PrintA 510 18) ;Sir, how much money are we talking about?
(= seconds 3)
)
(4
(PrintL 510 19) ;Hard to say, it sort of.... evaporated.
(= seconds 3)
)
(5
(PrintA 510 20) ;Evaporated?
(= seconds 3)
)
(6
(PrintL 510 21) ;Yeah. Turns out if you grip damp casino money too hard, it returns to its natural state-pulp.
(= seconds 3)
)
(7
(PrintA 510 22) ;So you're calling to report that you found some money... and destroyed it?
(= seconds 3)
)
(8
(PrintL 510 23) ;Technically, it self-destructed. My hands were just the platform.
(= seconds 3)
)
(9
(PrintA 510 24) ;We'll update our files: 'Reward unclaimed due to excessive enthusiasm'.
(= seconds 3)
)
(10
(PrintL 510 25) ;So... no tote bag?
(= seconds 3)
)
(11
(PrintA 510 26 #at -1 140) ;We'll send you a paper towel. Click...
(= cycles 3)
)
(12
(PlayerControl)
(gRoom setScript: RoomScript)
(self dispose:)
)
)
)
)
(instance sCallSierra of Script
(method (changeState newState)
(switchto (= state newState)
(0
(ResetPhone)
(ProgramControl)
(= seconds 1)
)
(1
(Print 510 27) ;Hello, a pleasant voice responds. Sierra On-Line.
(= seconds 3)
)
(2
(Print 510 28) ;We're not open right now, but if you'd call during business hours (and stop using this pretend telephone), we would be happy to sell you a copy of one of Al Lowe's other fine games!
(= seconds 3)
)
(3
(Print 510 29) ;At the same time, be sure to inquire about our full line of Leisure Suit Larry novelty items.
(= seconds 3)
)
(4
(Print 510 30) ;Thank you for calling Sierra On-Line, and for your purchases of 'Leisure Suit Larry' over the years. Goodbye.
(= seconds 2)
)
(5
(Print 510 31) ;Such blatant commercialism turns you on. You make a mental note to tip Al Lowe:
(Print 510 32 #font 600) ;https://allowe.com/more/tipjar.html
(PlayerControl)
(gRoom setScript: RoomScript)
(self dispose:)
)
)
)
)
(instance aHandSet of View
(properties
view 611
loop 2
x 36
y 189
priority 8
)
(method (init)
(super init:)
(self setPri: 9 ignoreActors: stopUpd:)
)
)
(instance aLight of Prop
(properties
view 611
loop 1
x 112
y 76
cycleSpeed 3
)
(method (init)
(super init:)
(self setPri: 9 setCycle: Fwd)
)
)
(instance Button0 of Prop
(properties
name "Button0"
view 611
loop 0
cel 9
x 200
y 193
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)
(instance Button1 of Prop
(properties
name "Button1"
view 611
loop 0
cel 0
x 170
y 100
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)
(instance Button2 of Prop
(properties
name "Button2"
view 611
loop 0
cel 1
x 200
y 100
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)
(instance Button3 of Prop
(properties
name "Button3"
view 611
loop 0
cel 2
x 230
y 100
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)
(instance Button4 of Prop
(properties
name "Button4"
view 611
loop 0
cel 3
x 170
y 131
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)
(instance Button5 of Prop
(properties
name "Button5"
view 611
loop 0
cel 4
x 200
y 131
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)
(instance Button6 of Prop
(properties
name "Button6"
view 611
loop 0
cel 5
x 230
y 131
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)
(instance Button7 of Prop
(properties
name "Button7"
view 611
loop 0
cel 6
x 170
y 162
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)
(instance Button8 of Prop
(properties
name "Button8"
view 611
loop 0
cel 7
x 200
y 162
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)
(instance Button9 of Prop
(properties
name "Button9"
view 611
loop 0
cel 8
x 230
y 162
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)
(instance ButtonStar of Prop
(properties
name "ButtonStar"
view 611
loop 0
cel 10
x 170
y 193
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)
(instance ButtonHash of Prop
(properties
name "ButtonHash"
view 611
loop 0
cel 11
x 230
y 193
)
(method (init)
(super init:)
(self setPri: 9 hide:)
)
)