Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines
(+3)

by request,

The Chat Contraption:

The chat contraption provides a scrolling view of static text clustered into "speech bubbles" as in the text messaging UIs of most phones which can be advanced or retracted one bubble at a time.

The .value attribute contains rich text describing the chat log. Messages should be separated by a blank line (i.e. two newlines; \n\n). If a message is "!left" or "!right", it will switch which side of the conversation ensuing messages appear on instead of being displayed. Remember, you can use any other rich text formatting you like, including fonts and inline images!


The contraption exposes read-only .hasnext and .hasprev attributes indicating whether there are previous messages or next messages to show, respectively. It also exposes functions .next[] and .prev[] for stepping through message history. Any time you change the contraption's .value attribute the history will be reset to show only the first message.

The contraption respects the standard .show and .font attributes to control the transparency mode and default font of the chat log.

This contraption is provided below along with an enclosing card and prev/next buttons for paging through messages, to demonstrate how to use .hasprev/.hasnext/.prev[]/.next[]; these buttons are not part of the contraption itself and therefore can be freely customized or replaced to suit the needs of a particular application:

%%CRD0{"c":{"name":"card1","script":"on view do\n prev.locked:!chat1.hasprev\n next.locked:!chat1.hasnext\nend","widgets":{"chat1":{"type":"contraption","size":[196,155],"pos":[176,77],"font":"menu","show":"transparent","def":"chat","widgets":{"f":{"size":[196,155],"show":"transparent","value":{"text":["i"],"font":[""],"arg":["%%IMG2ALAAHAAFAWkARQFtAEIBbwBAAXEAPwFxAD4BcwA9AQUgAgFsAD0BBSACAWwAPQEFIAUBAyAEAQIgAgECIAIBWgA9AQUgAgECIAIBASACAQIgAgEBIAIBAiACAVoAPQEFIAIBAiACAQEgAgECIAIBASACAQIgAgFaAD0BBSACAQIgAgEBIAYBASACAQIgAgFaAD0BBSACAQIgAgEBIAIBBSACAQIgAgFaAD0BBSACAQIgAgEBIAIBAyABAQEgAgECIAIBWgA9AQUgAgECIAIBAiAEAQMgBQFaAD0BFyACAVoAPQETIAEBAyACAVoAPQEUIAQBWwA9AXIAPgFyAD4BcQA/AXAAQAFuAP8A/wD/ALU="]}},"msg":{"size":[100,31],"pos":[225,11],"value":{"text":["hey\n\ncan you read these?\n\n!right\n\nyeah\n\nwhat's up\n\n...\n\ncome on, man, don't keep me hanging here forever\n\n!left\n\nsorry\n\nlooks like the chat contraption works\n\n!right\n\n","sweet!","\n\n!left\n\nkeep in mind that there's kind of a soft limit to how many messages we can display\n\n!right\n\ngot it\n\nsince the messages are updated in response to an attribute change we have to stay in quota\n\n!left\n\nexactly\n\nbut as you can see the limit is reasonably high for practical use\n\n!right\n\nyeah this isn't too bad\n\nwe could also try to use longer sentences, since the cost is per speech bubble rather than per character\n\n!left\n\ntruth\n\nanyway, hopefully this contraption is handy!"],"font":["","menu",""],"arg":["","",""]}},"idx":{"size":[100,31],"pos":[225,53]},"tmp":{"pos":[225,91],"font":"menu"},"cnt":{"size":[100,31],"pos":[225,110],"value":"18"}}},"next":{"type":"button","size":[60,20],"pos":[280,260],"script":"on click do\n chat1.next[]\n view[]\nend","text":"Next"},"prev":{"type":"button","size":[60,20],"pos":[202,260],"locked":1,"script":"on click do\n chat1.prev[]\n view[]\nend","text":"Prev"}}},"d":{"chat":{"name":"chat","size":[100,100],"resizable":1,"margin":[5,5,5,5],"description":"a semi-interactive scrollable chat log.","script":"on get_value   do msg.value end\non set_value x do msg.value:x idx.text:0 view[] end\n\non view do\n f.show:card.show\n tmp.font:card.font\n tw:(first f.size)-20\n mw:floor .6*tw\n d :0\n r :rtext.cat[]\n margin:4 take 5\n lborder:image[\"%%IMG0AAwADAYAH4A/wH/gf+D/8P/w/+D/4P/A/4D+AA==\"]\n rborder:image[\"%%IMG2AAwADAAFAQIACAECIAIBAgAFAQEgBgEBAAMBASAIAQEAAgEBIAgBAQABAQEgCgECIAoBAQABAQEgCQEBAAEBASAJAQEAAgEBIAgBAQADAQIgBgEBAAUBBw==\"]\n   \n each chunk in rtext.split[\"\\n\\n\" msg.value]\n  str:rtext.string[chunk]\n  if     \"!left\" ~str d:0\n  elseif \"!right\"~str d:1\n  else\n   mh:last tmp.textsize[chunk mw]\n   sz:mw,mh\n   tmp.size:tw,mh+15\n   tmp.clear[]\n   if d # right-half\n    tmp.segment[rborder ((tw-mw+10),0),(10+sz) margin]\n    tmp.pattern:1\n    tmp.text[chunk ((tw-mw+5),5),sz \"top_right\"]\n   else # left-half\n    tmp.segment[lborder (0,0,10+sz) margin]\n    tmp.pattern:32\n    tmp.text[chunk (5,5,sz) \"top_left\"]\n   end\n   r:r,rtext.cat[tmp.copy[]]\n  end\n end\n tmp.size:1,1\n cnt.text:count r\n i:1+0|idx.text\n r:i limit r\n f.value:r\nend\n\non get_animate do view end\non get_hasprev do (0+idx.text)>0          end\non get_hasnext do (0+cnt.text)>1+idx.text end\non get_prev do\n on prev do\n  if get_hasprev[] idx.text:idx.text-1 view[] f.scroll:9999999 end\n end\nend\non get_next do\n on next do\n  if get_hasnext[] idx.text:idx.text+1 view[] f.scroll:9999999 end\n end\nend\n","attributes":{"name":["value"],"label":["Value"],"type":["rich"]},"widgets":{"f":{"type":"field","size":[100,100],"pos":[0,0],"locked":1,"scrollbar":1},"msg":{"type":"field","size":[100,20],"pos":[129,7],"locked":1,"show":"none"},"idx":{"type":"field","size":[100,20],"pos":[129,34],"locked":1,"show":"none","value":"0"},"tmp":{"type":"canvas","size":[1,1],"pos":[129,59],"locked":1,"image":"%%IMG0AAEAAQA=","pattern":32,"scale":1},"cnt":{"type":"field","size":[100,20],"pos":[129,71],"locked":1,"show":"none","value":"1"}}}}}

A question: if I've used a richtext link in the chatlog is there any way to have the link be clickable?

No; unfortunately the way this contraption works requires rendering out every message as an inline image, which bakes links down into only their visual appearance (the dotted underline).

Ahh, no worries. That is pretty neat though!

(+1)

hi, sorry if this is a silly question
when i try to use this, the next and previous buttons are locked no matter what I do/how many times I unlock them. is there a way to fix this?

(1 edit) (+1)

In the example snippet for this contraption, it's placed on a card with the following script:

on view do
 prev.locked:!chat1.hasprev
 next.locked:!chat1.hasnext
end

The "prev" button has the script:

on click do
 chat1.prev[]
 view[]
end

And the "next" button has the script:

on click do
 chat1.next[]
 view[]
end

Together, these scripts automatically lock/unlock the buttons based on whether or not the contraption has a previous or next chat message available to display, and updates that status every time the user pages through messages. None of this is strictly necessary; it's just there to make the UI more legible. You can customize these buttons as you please or get rid of them entirely and advance the chat log via some other means if you prefer.

Does that help clarify the behavior you're seeing?

(+1)

that makes sense. tried it again today and all was working well. I think when editing the text in mine I had somehow messed up the format so it wasn't processing that there were more lines. thank you!