Click Target handling. This example uses any clicks to set the targeting, but you can edit it to only function on right clicks, for example. You can also toggle it on and off or just use a different method of setting targets. Either way, it's an option.
client
var/atom/__cmd_target
var/__click_target = 1
Click(object,location,control,params)
..()
if(__click_target)
__cmd_target = object
src << "Target set to [__cmd_target]"
verb
toggleClickTarget()
if(__click_target)
__click_target=0
__cmd_target = mob
else __click_target=1
src << "Click targeting [__click_target?"activated":"deactivated"]."
Command parsing
mob
proc
__command_line(t as text)
t = lowertext(t) //Makes the text nice and uniform.
var/list/token = tokenize(t) //Tokenizes the string into separate entities to be parsed.
if(!token) return //If there are no tokens to parse, just exit.
switch(token[1])
if("set") //Set is the only command in this example, but it's designed to be easily expandable if you need other commands such as /who, /ban or whatever you need.
if(token.len<3||token.len>4) //Set has 3 to 4 arguments.
//Call error
return
switch(token.len)
if(3) //No defined target. Target is self.
if(findtext(token[2],"client.")==1)
token[2] = copytext(token[2],8)
for(var/v in client.vars) //Parsing client variables
if(v==token[2])
//This whole section just formats token[3] from text into the proper variable.
switch(token[3])
if("null") token[3] = null
if("true") token[3] = TRUE
if("false") token[3] = FALSE
if(isnum(client.vars[v])) token[3] = text2num(token[3])
else if(ispath(client.vars[v])) token[3] = text2path(token[3])
try
client.vars[v] = token[3] //The try-catch block is to make sure that the token variable is compatible with the variable being edited. Obviously you can't expect to replace a list with a string.
catch
//Call error
return
if(client.vars[v]!=token[3])
//Call error
return
src << "\[*\] Variable <tt>client.[v]</tt> has been set to [client.vars[v]]"
return
for(var/v in vars) //parsing player variables
if(v==token[2])
switch(token[3])
if("null") token[3] = null
if("true") token[3] = TRUE
if("false") token[3] = FALSE
if(isnum(vars[v])) token[3] = text2num(token[3])
else if(ispath(vars[v])) token[3] = text2path(token[3])
try
vars[v] = token[3]
catch
//Call error
return
if(vars[v]!=token[3]) //A redundant double-check to make sure that it was actually changed properly.
//Call error
return
src << "\[*\] Variable <tt>[v]</tt> has been set to <tt>[vars[v]]</tt>"
return
//Call error
if(4) //Defined target
if(token[2]=="~") //By default, the only extra argument the code looks for is "~", but this can be expanded
//on by accepting a player's key and searching for them to use as a target instead.
if(!client.__cmd_target) //Make sure the __cmd_target var isn't null, or it'll throw a runtime error.
//Call error
return
for(var/v in client.__cmd_target.vars) //parsing player variables
if(v==token[3])
switch(token[4])
if("null") token[4] = null
if("true") token[4] = TRUE
if("false") token[4] = FALSE
if(isnum(client.__cmd_target.vars[v])) token[4] = text2num(token[4])
else if(ispath(client.__cmd_target.vars[v])) token[4] = text2path(token[4])
try
client.__cmd_target.vars[v] = token[4]
catch
//Call error
return
if(vars[v]!=token[4])
//Call error
return
src << "\[*\] Variable <tt>[v]</tt> for [client.__cmd_target.] has been set to <tt>[client.__cmd_target.vars[v]]</tt>"
return
tokenize(t as text)
var/list/token = new
var/i=1
for(var/pos=1;pos<=length(t);pos++)
if(pos==length(t)) //Caps off the last token and return the function
token.len++
token[i] = t
break
switch(text2ascii(t,pos))
if(32) //Whitespace
token.len++
token[i] = lowertext(copytext(t,1,pos))
t = copytext(t,++pos)
i++
pos=0
continue
if(34) //Quotation mark
var/end = findtext(t,"\"",pos+1)
if(!end) return null
token.len++
token[i] = copytext(t,2,end)
t = copytext(t,end+2)
i++
pos=0
continue
return token
Alright, so we actually have the basis for the command line. The tokenize() function breaks up text by whitespace or quotation marks. Using set, you can choose to specify a target or not. If you don't explicitly define your target, it defaults to you. In this example, the only explicit definition allowed is using "~" to default to your current __cmd_target variable. You can easily add on to check for a player's ckey as well, letting you edit another player's variables.
Now we just need to tie that to a chat function to make sure that it can be used. I usually use "/" as the macro character.
var/const/MACRO_CHAR = "/"
//Example
Whatever_Chat_Function_Youre_Using(t as text)
//Add this to it
if(copytext(t,1,2)==MACRO_CHAR) //Just checks of the first character is the macro character.
__command_line(copytext(t,2))
//Chat output stuff.
This whole snippet lets you do interesting and very quick things such as using /set density 0 to make yourself non dense or /set ~ icon_state "foobar 2" to change what things look like on the fly. Just something to help you when you're testing things out in-game.
EDIT: Something I should have made sure to note is that you can access both mob variables and client variables independently. To access client variables, simply use client.[variable] for the variable argument. It's a hard-coded solution inside, but it works well at least.
Alternately, I really should move the __command_line() function to a client, rather than a mob, but I'll probably update it later.
http://www.byond.com/developer/AlexPeterson/Interpreter
I wrote it on an ALT account of mine. It can interpret plain English sentences or straight forward commands.