ID:1579167
 
(See the best response by Ter13.)
Code:
obj/SectionBraket
icon='SectionBraket.dmi'
layer=MOB_LAYER+4
New(client/C)C.screen+=src

obj/TOSC
icon='text.dmi'
layer=MOB_LAYER+5
New(client/C)C.screen+=src

mob/var/TOSC1
mob/proc
close_menu(/**/){for(var/obj/TOSC/O in client.screen)del O;for(var/obj/SectionBraket/O in client.screen)del O}
TOSP(var/TOS){TOSC1=list(/**/);for(var/a=1,a<=length(TOS),a++){TOSC1+=copytext(TOS,a,a+1)}}
TOSSectionBraket(var/XC1,YC1,XC2,YC2)
for(var/XC=XC1,XC<=XC2,XC++)
for(var/YC=YC1,YC<=YC2,YC++){var/obj/SectionBraket/b=new(client);
if(XC==XC1)b.icon_state="l";if(XC==XC2)b.icon_state="r";if(YC==YC1)b.icon_state="b";
if(YC==YC2)b.icon_state="t";if(XC==XC1&&YC==YC1)b.icon_state="ll";
if(XC==XC2&&YC==YC2)b.icon_state="ur";if(XC==XC1&&YC==YC2)b.icon_state="ul";
if(XC==XC2&&YC==YC1)b.icon_state="lr";b.screen_loc="[XC],[YC]"}
TOSTOSC(var/XC1,XC2,YC1,YC2,T)
var{XC=XC1;YC=YC1}TOSP(T)
for(var/Y in TOSC1){var/obj/TOSC/C=new(client);
if(XC==round(XC)&&YC==round(YC)) C.screen_loc="[XC],[YC]";else if(XC!=round(XC)&&YC==round(YC))C.screen_loc="[XC-0.5]:16,[YC]";else if(XC==round(XC)&&YC!=round(YC))C.screen_loc="[XC],[YC-0.5]:+16";
else if(XC!=round(XC)&&YC!=round(YC))C.screen_loc="[XC-0.5]:16,[YC-0.5]:+16";C.icon_state="[Y]";
sleep(1)
XC+=0.5
if(XC==XC2)
XC=XC1;YC-=0.5
if(YC==YC2-0.5)break}



            TOSSectionBraket(5,1,16,4)
TOSTOSC(6,15,4,6,"Hello, there [usr]!")

Problem description:

Is there a better way to get the same effect

...So... What's all this supposed to do, exactly?
Shrani.si

It displays the same chat effect.
Best response
This is kind of a mess... Let me take a stab...

var
list/font_widths = list("32"=5) //define the width of each letter/character in your font based on the ascii character code of each letter as the key, and the pixel width as the value.
obj
screen_word
var
width = 0
screen_text
icon = 'font.dmi'
proc
buildScreenWord(word)
//create the word object that should be returned
var/obj/screen_word/w = new()
//we only need one letter object
var/obj/screen_letter/l = new()
var/wlen = length(word)
var/letter
//loop through all letters in the word and add them to w's overlays individually
for(var/count=1;count<=wlen;count++)
//use the ascii character code, as it's faster than copytext
letter = "[text2ascii(word,count)]"
l.icon_state = letter
w.overlays += l
//add the width of the letter so the next letter won't overlap
l.pixel_x += font_width[letter]
//set the width of the word after we're done and return it
w.width = l.pixel_x
return w


Okay, that's individual words solved. Let's see about building wordboxes.

#define CORNER_WIDTH  8px
#define CORNER_HEIGHT 8px
#define CORNER_PADDING 8px

obj/screen_obj/text_background
//set up your icons/structure accordingly.

wordbox
var
width
height
layer
x
y
list/background_objs = list()
list/foreground_objs = list()
proc
Build()
//position the corners of the menu on the screen
var/w = width - CORNER_WIDTH * 2 + CORNER_PADDING * 2
var/h = height - CORNER_HEIGHT * 2 + CORNER_PADDING * 2
var/obj/o = background_objs[9]
o.screen_loc = "[x],[y]"
o = background_objs[8]
o.screen_loc = "[x]:[w],[y]"
o = background_objs[7]
o.screen_loc = "[x],[y]:[h]"
o = background_objs[6]
o.screen_loc = "[x]:[w],[y]:[h]"

//position the cardinal edges of the menu and scale them.
var/wo = (w - 1) / 2 + CORNER_WIDTH
var/ho = (h - 1) / 2 + CORNER_HEIGHT
o = background_objs[5]
o.screen_loc = "[x],[y]"
o.transform = matrix(w,0,wo,0,1,0)
o = background_objs[4]
o.screen_loc = "[x],[y]"
o.transform = matrix(1,0,0,0,h,ho)
o = background_objs[3]
o.screen_loc = "[x]:[w],[y]"
o.transform = matrix(1,0,0,0,h,ho)
o = background_objx[2]
o.screen_loc = "[x],[y]:[h]"
o.transform = matrix(w,0,wo,0,1,0)

//scale and position the middle
o = background_objs[1]
o.screen_loc = "[x],[y]"
o.transform = matrix(width,0,wo,0,height,ho)

Show(client/c)
c.screen.Add(background_objs)
c.screen.Add(foreground_objs)

Hide(client/c)
c.screen.Add(background_objs)
c.screen.Add(foreground_objs)

New(nx,ny,nw,nh,ly)
width = nw
height = nh
x = nx
y = ny
layer = ly
var/list/icons = list('chatbox_m.dmi','chatbox_t.dmi','chatbox_r.dmi','chatbox_l.dmi','chatbox_b.dmi','chatbox_tr.dmi','chatbox_tl.dmi','chatbox_br.dmi','chatbox_bl.dmi')
//chatbox tl/tr/bl/br should be CORNER_WIDTHxCORNER_HEIGHT dmis
//chatbox b/t should 1xCORNER_HEIGHT dmis
//chatbox l/r should be CORNER_WIDTHx1 dmis
//chatbox m should be 1x1 dmi
for(var/count=1;count<=9;count++)
var/obj/screen_obj/text_background/o = new()
o.icon = icons[count]
o.layer = ly
background_objs += o
Build()


That's pretty much the basics of it. One object per word, should be enough. For chat messages, you will have to make sure that the width of the word doesn't overflow the width of the line.

That should be enough to get you started, really.