Softcode
+countries
I threw up a new release (1.0.1) of my +countries code for displaying a breakdown of what countries players are connecting from, and converting between country name and domain extension. The only change is some updates to country names... unless you have people connecting from Nepal or Venezuela, there's no need to upgrade an already-installed copy. If you're interested in seeing it in action, it's on M*U*S*H.
http://raevnos.pennmush.org/mushcode or http://download.pennmush.org/MUSHCode.
Documenting softcode (gasp)
When I need something softcoded, especially a function, chances are I'll code it myself. Even if it exists. Even if it exists on the same MUSH. There are several reasons for that, but one's a fairly big one: Softcode is hard to read. Doubly so if you didn't code it. What's worse, since softcode doesn't have a function definition like you would in C or Python or whatnot, you don't have even the self-documentation that comes from variable names, and in fact you may have to dig deep to even see how many arguments a function takes, let alone determine which ones are optional. I've been wanting to do something about that for a while (read: at least 3 years), but this time I actually did come up with a partial solution.
Let's take a quick example. How many arguments does the following code take, and how many are optional? What do the arguments DO? What does the thing return anyway? (Please don't waste too much time on it.)
&FUN_DOCUMENT object=ifelse(hasattr(%0,1`cc),u(fun_parse_cc,lcstr(%1),xget(%0,%1`cc)),Function has no calling convention defined.)[if(%2,%r[if(hasattr(%0,%1`doc),u(fun_decorate,u(%0/%1`doc),first(xget(%0,%1`cc))),Function has no docstring.)])]
Still with me? Okay, now, how much easier is it to get the same info from this snippet of text, generated by my docf code:
Call: u(fun_document, <object>, <attr>, [full])
=> documentation (a string)
Let's see.. 2 args with an optional third. An object, an attr, and optionally something called 'full'. It returns some documentation, apparently. So 'full' might mean 'display full documentation' as opposed to a part of it?
How did I generate this snippet? Relatively easily:
&fun_document`cc object=object:attr:*:full r:string:documentation
docf object/fun_document
This says: I have arguments object and attr, the rest of the arguments are optional, the one optional argument is 'full'. It returns a string which represents documentation.
This is a nice start, but some things are still unclear. Let's change that.
&FUN_DOCUMENT`DOC object=Get the documentation of the ufun in OBJECT/ATTR. If FULL, output the docstring as well as the calling convention.
docff object/fun_document
That gets me:
Call: u(fun_document, <object>, <attr>, [full])
=> documentation (a string)
Get the documentation of the ufun in <object>/<attr>. If [full], output the docstring as well as the calling convention.
Note that it automatically transformed the uppercase arguments, marking them as mandatory or optional, as well as making them stand out. (And additionally it lets the docf code know those arguments are documented so it won't warn you about skipping them.)
With docf you have 2 times 2 options: docf with one f displays just the calling information (what's defined in the `cc attr). docff (with a second f for 'full') displays the docstring as well. On the argument side, you can specify obj/attr, or just an object to see the info for all documented functions. So you can go 'docf object' to get a quick reminder of what functions are available and roughly how they work, or 'docff object/attr' to get all the info for a specific function. Or even 'docff object' when you're learning how a new system works.
The system so far has a fair amount of features, but it does have two important limitations: First off, it's only meant for documenting ufuns, not commands or other things (though at least commands are clearer about their arguments). Second, it still requires someone to actually write the documentation, sadly ;) Though even just a `cc attr can make a world of difference.
I hope someone (preferably several someones) will find this useful. Questions, comments, suggestions and their ilk very welcome.
SceneSys: Progress
Keeping a nice list of progress on SceneSys, and what still needs to be done.
- Commands
- Staff
- +scene/help (wiz topics)
- +scene/config/set
- Scene Owners
- +scene/config/set
- Player & globals
- +scene/help
- +scene/activate
- +scene/config
- Systems
- Outlining (DONE)
- SQL Table Layout (DONE)
- ANSI listening for PennMUSH (DONE)
- Objects & Attribute Layout (DONE)
- Player setup and recognition. (DONE)
- Pose Capturing and Filtering (DONE)
- Pose adding
- Pose movement
- Pose commenting
- Pose: SysEvent
- Pose Recall
- Scene Start
- Scene Status Change
- Scene Config (DONE)
- Scene Joining/Leaving
- Scene Activation
- Scene Order System
- Global Config (DONE)
- Player Journals
- Announcement|Reminder System
SceneSys: Ideas
Recently, Javelin graciously let me have a look at the Storyboard system which used to be on Rio: Manhã de Carnaval, to let me get an idea of a similar system. It does what I planned for the web-side of SceneSys, and then some more. So I wanna note down some ideas that have spawned from this little look at it.
- Character Journals: I already had an on-game diary system. I could probably expand this onto the SceneSys system as well.
- Scene Commenting: For staff, or perhaps even users, to comment on a scene. Possibly for staff-side research into characters. My system already allows for Pose-Comments.
- Player Commenting: In SceneSys, each player has a seperate entry. It would not be hard to add a system for staff to add comments to the players. (Perhaps integration to a job system - Combining SceneSys with a AnomalyJobs like organization system? To keep track of purchases per character etc?)
- Plot Outlining: A heuristic approach to adding plots to a 'plotline'. Could be very useful for finding plot points.
- Read Tracking: To keep track of what scenes you have 'read/commented on'.
I will likely add most of these to the system, of which all but the Read Tracking being ones I want to push for first, after finishing the core SceneSys. Character Journals will probably come last, before the Read Tracking.
SceneSys: A roleplaying log system for MySQL
Over time, PennMUSH has been seeing more and more connectivity with MySQL and other such server software. Forums, bboards - even rumors of the Anomaly Jobs system stepping onto MySQL.
Ever since I started touching MySQL on my sandbox, ideas have begun to grow. SceneSys is one such idea. In this post, I will lay out this system for you. If you have any questions, leave me a comment! I'd love to answer any questions you may have.
I've had many little projects over time, that were planned by me to learn how to best tackle some major things in SceneSys. How to set up tables. How to write the code. How to make things modular. Some of these projects are listed below.
- Player Connection Logger
- When are people most on, how long are they on, etc.
- Who Display
- For website to display the +who - updated every 5 seconds & on {dis}connects.
- Apples to Apples
- The Apples to Apples game, brought to MySQL. (In progress)
- +system
- A +help/theme/whateveryouwant system, using a markup to allow easy export to HTML. (In progress)
Listens were not taking colors, the @message/nospoof bug that was not reporting correctly. Things like that. But now that 1.8.3p11 has officially been released, I can finally start on this project.
But all of this of course raises the question...
What is SceneSys?
SceneSys, short for - as you may have figured out on your own - 'Scene System', is a system to keep track of your scenes, making logging a pinch, keep track of posing orders, allow for scene announcement, join-locking, tagging, and quite some things more. Only for PennMUSH 1.8.3p11 and over. SceneSys, the objects.
SceneSys uses rooms to listen to, what can be considered, RP. With other words, any 'say', 'pose', '@emit' etc gets captured by the <SceneSys Room Parent : SSRP>. To do this, it uses a ^-listen pattern on the parent room, then requires each room underneath it to be set 'LISTEN_PARENT' and 'MONITOR'. This likely can be considered to be a pain in the ass for initial setup, and I will be looking into seeing if something better can be worked out, perhaps.
Whatever it hears, it then sends to the <SceneSys Object : SSO>, which should be in #2. It gives this object all information it can find, after having filtered out whether or not something is an RP pose. This object will include a lot of commands for the player to use. And will use @triggers for a lot of it's actions.
For the <SSO> to interact with MySQL, it will also use <Walker's MySQL Wrapper : WMW>. So it will be more readable and organized.
SceneSys, what is a pose?To figure out whether something is a pose or not, there will be multiple filters and 'smart systems' in place.
First, <SSRP> filters based on what type the object is, and how large the pose was. These are settings that will be sitting in the MySQL tables. It will also check if something was OOC, by checking the first X characters for whether or not it had 'OOC' in it, without being part of a word.
After this, <SSO> will check if the player who posed is active in a scene. If they have never used/joined a scene, we can assume that this was not a pose. If they went beyond X amount of time since their last pose, we can assume it is not a pose. But, within a certain amount of time, the player will be warned that they posed without activating a scene - just to double check.
SceneSys, where are we RPing?Unlike normal object-type loggers, this system can follow players anywhere they go. If player-A,B,C,D are all in the same scene, but A + B are in ROOM 1, and C + D are in ROOM 2, it logs these just fine. And will transmit the poses to the players who are outside of the room - so they can (possibly) sync up their poses. But more importantly, this is for a different case: I player A is idle, and players B,C,D have gone to a different room to continue the RP, player A will not have missed a thing. I missed a pose! What will SceneSys do for me?
It is impossible to miss a pose. As long as a scene is using the SceneSys and the player is part of the scene, a player can easily do a recall on the scene, to read previous poses in that scene! More importantly, if someone was offline while poses were added to the scene... they will be notified of this upon connection. SceneSys! Yummy Spam!
If someone tries to spam the system, since all poses have a timestamp, SceneSys will detect this. You can easily set up how many poses per 10 seconds to accept to prevent spam. And of course, there will be a trigger for you to modify to do something to the perpetrator if they do this. The default will be that the scene will be locked against this player. SceneSys, a pain to use?
Sure! Starting a scene is often not something you want to be using commands for. You go on some channel, say you want to start a scene, organize... and pose! So, how many commands would one need to use SceneSys?
Let us assume a standard scene, nothing private: announce its creation, and to generally just go with the defaults. Just... a standard scene.
< +scene/create
> SceneSys: Scene (number) created!
> (Public) A scene has been created by <CreatorName> in <Room Name>.
And a player wants to join?
< +scene/join
> SceneSys: You have joined the most recently active scene (number) in this room.
Done. Of course. This means that the system assumes a lot of things, and uses quite a lot of defaults.
SceneSys, scene defaults.- Scene Lock
- NULL
- Scene Title
- NULL
- Scene Desc
- NULL
- Scene Announce upon creation
- True
- Scene Private - will lock against everyone, including log reading.
- False
- Scene Order - Police the scene order?
- True
- Timeout (idle time), before a player is set 'away'.
- 1200 seconds
- Timeout (idle time), before a player is set 'skipped in order'.
- 2400 seconds
- Timeout (activity time), before a scene is set 'paused'.
- 7200 seconds
- Timeout (activity time), before a scene is set 'unfinished'.
- 25200 seconds
Unlike most of my code, this system is actually going to be heavily commented. Most of the attributes should definitely speak for themselves in what they do. On another note, this code is formatted (rather oddly) so that if one views it in MUSHclient, at 78 width, it lines up real nice like - and looks readable. SceneSys, you said modular... does that mean it is easy to change?
Yes actually. A lot of SceneSys will use triggers, which each will state what their input values are. This way, if you know your way around MUSHcode, it is easy to change or add on to what gets done on what event. Want announcements to go to the public channel, then check the <SSO> object for TRIG`ANNOUNCE, etc. Whether or not we are actually 'announcing' will only get checked in the actual trigger, so you do not have to mess with the core. Sure, it means that the object is going to use a bit more time and processing than normal, if one would @assert before the @trigs - but it's all for the good of modularity and easy-of-change. More information to come. Leave comments to ask questions about the system, or things you want to know!
(Shotgun) DSS Chargen Code
Some more scraps I found. I ended up recoding some of the chargen commands to work with my systems. This might give some indication of the approach I used to reprogram the system, and make it easier to reproduce things if people are interested.
@create DSS Chargen Commands
@link DSS Chargen Commands = #0
@set DSS Chargen Commands = WIZARD
&CMD_DESELECT DSS Chargen Commands=$+deselect *:@pemit %#=[ifelse([ulocal(v(DB_Database)/FN_HasSkills,%#)],switch([setq(0,secure(%0))][setq(1,grab(get(v(DB_Database)/List_Feats),[%q0]*,|))][setq(2,grab(get(v(DB_Database)/List_Languages),[%q0]*))][t(words(%q1))][t(words(%q2))],1*,[setq(4,extract(%q1,1,1))][ifelse(extract(%q1,2,1),ifelse(match(get(%#/DSS_Feats),%q4),ifelse(gte(get(%#/DSS_XP),[setr(3,mul(-1,extract(%q1,3,1)))]),You no longer have the [ansi(y,edit(%q4,_,%b))] feat.[set(%#,DSS_Feats:[setdiff(get(%#/DSS_Feats),%q4)])][set(%#,DSS_XP:[sub(get(%#/DSS_XP),%q3)])],You are short [ansi(y,sub(get(%#/DSS_XP),%q3))] experience points.),[ansi(rh,-)] You dont have the [ansi(y,edit(%q4,_,%b))] feat.),[ansi(rh,-)] You may not deselect the [ansi(y,edit(%q4,_,%b))] feat. Only staff may remove that feat via +delfeat.)],01,[ifelse(match(get(%#/DSS_Languages),%q2),ifelse(gte(get(%#/DSS_XP),[setr(3,mul(-1,get(v(DB_Database)/Cost_Lang)))]),You no longer understand the [ansi(y,edit(%q2,_,%b))] language.[set(%#,DSS_Languages:[setdiff(get(%#/DSS_Languages),%q2)])][set(%#,DSS_XP:[sub(get(%#/DSS_XP),%q3)])],You are short [ansi(y,sub(get(%#/DSS_XP),%q3))] experience points.),[ansi(rh,-)] You dont know the [ansi(y,edit(%q2,_,%b))] language.)],[ansi(rh,-)] Invalid feat or language name.),[ulocal(v(DB_Database)/MSG_NoTraits)])]
&CMD_LOWER DSS Chargen Commands=$+lower * to *:@pemit %#=[setq(0,ulocal(v(DB_Database)/FN_Parse_Attr,secure(%0)))][setq(1,ulocal(v(DB_Database)/FN_Parse_Skill,secure(%0)))][ifelse(ulocal(v(DB_Database)/FN_HasSkills,%#),switch([t(words(%q0))][t(words(%q1))],1*,[setq(2,max(40,val(secure(%1))))][setq(3,ulocal(v(DB_Database)/FN_Attr_Cost,%#,%q0,%q2))][ifelse(lte(%q3,0),[ulocal(v(DB_Database)/FN_SetAttr,%#,%q0,%q2)][set(%#,DSS_XP:[sub(get(%#/DSS_XP),%q3)])][ansi(gh,-)] You +lower your [ansi(y,%q0)] to [ansi(y,%q2)] with a refund of [ansi(y,mul(-1,%q3))] experience points.,[ansi(rh,-)] You cannot +raise [ansi(y,%q0)] with +lower.)],01,[setq(2,max(0,val(secure(%1))))][setq(3,ulocal(v(DB_Database)/FN_Skill_Cost,%#,%q1,%q2))][ifelse(lte(%q3,0),[ulocal(v(DB_Database)/FN_SetSkill,%#,%q1,%q2)][set(%#,DSS_XP:[sub(get(%#/DSS_XP),%q3)])][ansi(gh,-)] You +lower your [ansi(y,%q1)] to [ansi(y,%q2)] with a refund of [ansi(y,mul(-1,%q3))] experience points.,[ansi(rh,-)] You cannot +raise [ansi(y,%q0)] with +lower.)],[ulocal(v(DB_Database)/MSG_NotName)]),[ulocal(v(DB_Database)/MSG_NoTraits)])]
&CMD_RESET DSS Chargen Commands=$+reset:@pemit %#=[setq(0,grab(sort(lattr(%!/RACE_*),a),RACE_[edit(squish(secure(get(%#/Species))),%b,_)]))][ifelse(words(%q0),,setq(0,RACE_Human))][setq(1,v(%q0))]You [ifelse(ulocal(v(DB_Database)/FN_HasSkills,%#),reinitialize,initialize)] your skill data.[set(%#,FIXED)][set(%#,DSS_XP:[extract(%q1,1,1,$)])][set(%#,DSS_Attrs:[vadd(setr(2,ulocal(v(DB_Database)/FN_Attr_Mods,%#)),setr(3,40 40 40 40 40 40))]|[%q2]|[%q3])][wipe(%#/Skills`*)][attrib_set(%#/skills)][set(%#,DSS_Feats:[extract(%q1,3,1,$)])][set(%#,DSS_Languages:[extract(%q1,4,1,$)])][set(%#,DSS_Lingo:[first(extract(%q1,4,1,$))])][set(%#,DSS_SP:0)][wipe(%#/DSS_Armor)][wipe(%#/DSS_Weapon)][ulocal(v(DB_Database)/FN_Update_Skills,%#)]
&DB_DATABASE DSS Chargen Commands=#156
@DESCRIBE DSS Chargen Commands=%tIn this phase of chargen, you may select your skills and/or feats. Useful commands in this room are as follows:%r%r%b%b[ansi(rh,+reset)] - Resets your character sheet.%r%b%b[ansi(rh,+sinfo)] [ansi(y,\[\])] - Displays documentation about the skills system.%r%b%b[ansi(rh,+sheet)] - Displays all your skills information.%r%b%b[ansi(rh,+sinfo)] [ansi(y,list attributes)] - Displays what skills the system has.%r%b%b[ansi(rh,+sinfo)] [ansi(y,list skills)] - Displays what skills the system has.%r%b%b[ansi(rh,+raise)] [ansi(y,)] [ansi(rh,to)] [ansi(y,)] - Raises a attribute or skill.%r%b%b[ansi(rh,+lower)] [ansi(y,)] [ansi(rh,to)] [ansi(y,)] - Lowers a attribute or skill.%r%b%b[ansi(rh,+sinfo)] [ansi(y,list feats)] - Lists all feats players can select.%r%b%b[ansi(rh,+sinfo)] [ansi(y,list languages)] - Lists all feats players can select.%r%b%b[ansi(rh,+select)] [ansi(y,)] - Adds that feat or language to your sheet.%r%b%b[ansi(rh,+deselect)] [ansi(y,)] - Removes that feat or language from your sheet.
@set DSS Chargen Commands/DESCRIBE=no_command visual prefixmatch public nearby
&RACE_HUMAN DSS Chargen Commands=800$$$English
Old Reworked DSS Database Code (Scraps)
A long, long time ago. In a galaxy far away...
I reworked Dahan's Skill System Database code to support strings of data in a more clean and convenient way. It was to be said that my admin had decided with me, that we would prefer to not have a skill system on our MUSH at that time. With the wave of my hand, I destroyed the system. However, after a little scrounging, I was able to find the back up of the database I had. Everyone is free to peruse it, it is little information that I have. This technology is long gone and decayed to the sands of time.
@create DSS Database
@link DSS Database = #0
@set DSS Database = WIZARD
@set DSS Database = NO_COMMAND
&B DSS Database=hw
&COST_LANG DSS Database=25
&DB_GLOBAL DSS Database=#132
&DB_HELP DSS Database=#157
&DEFAULT_MELEE DSS Database=|20|Melee_Weapons|Dodge_Melee|0|5|20
@DESCRIBE DSS Database=This object is the heart of the skills system. It contains data about attributes, skills, feats, and health levels. Also included are global functions and private u-functions. It also protects certain attributes it uses to store data on players. This object does not include help files or any commands.%r%rThe following attribute prefixes are used:%r%tDB_%tUsed for important database numbers.%r%tFN_%tUsed for internal u-functions.%r%tFUN_%tUsed for global functions.%r%tLIST_%tUsed for various lists.%r%tSF_%tUsed to store pre-approved skill focuses.%r%rOther important attributes:%r%tSTARTUP, DESCRIBE.
@set DSS Database/DESCRIBE=no_command visual prefixmatch public nearby
&ENGAGED DSS Database=
&FN_ABORT DSS Database=[remit(%L,[ansi(hw,<[ansi(hy,COMBAT)]>)]%b%b%b[name(%#)] calls off their attack.)][attrib_set(me/Engaged`%0)]
&FN_ABTCHK DSS Database=[t([setr(P,squish(iter(lattr(me/engaged`**,|),if(match(extract(get(me/%i0),1,1,|),%#),last(%i0,`)),|)))])]
&FN_ADD DSS Database=add(%0,%1)
&FN_ADD_FIRST DSS Database=add(first(%0),first(%1))
&FN_ADJ_SKILL DSS Database=[ifelse([t(setr(0,grab(v(List_Skills),[first(%1,:)][ifelse(gte(words(%1,:),2),:*,%b*)],|)))],[setq(1,fold(FN_Adj_Skill2,[squish(after(%q0,&))],[%0] 1 0))][round(add(mul(%2,extract(%q1,2,1)),extract(%q1,3,1)),0)],#-1 Invalid skill name.)]
&FN_ADJ_SKILL2 DSS Database=[extract(%0,1,1)] [sub(extract(%0,2,1),before(%1,_))] [add(extract(%0,3,1),mul(before(%1,_),ulocal(FN_GetBaseLevel2,extract(%0,1,1),after(%1,_))))]
&FN_ATTR_COST DSS Database=[mul(10,sub(ulocal(FN_Cost,%2),ulocal(FN_Cost,ulocal(FN_GetBaseAttr,%0,%1))))]
&FN_ATTR_MODS DSS Database=[setq(0,repeat(0%b,[words(v(List_Attrs))]))][squish(iter([get(%0/Species)],ifelse(neq(0,words(setr(1,grab(v(List_Attr_Mods),[##] *,|)))),setq(0,vadd(%q0,rest(%q1))),)))][%q0]
&FN_CANEQP DSS Database=[if(t(setr(0,grab(default(%1/list`inventory,),%0*,|))),or(t(default(#29/[extract(%q0,2,1)]_WEAPON,)),t(default(#29/[extract(%q0,2,1)]_ARMOR,))),0)][not(or(t(default(%#/equipment`armor,)),t(default(%#/equipment`weapon,))))]
&FN_CANUNEQP DSS Database=[localize([if(t(setr(0,default(%1/equipment`weapon,))),t(match(first(%q0),%0*)),0)][if(t(setr(0,default(%1/equipment`armor,))),t(match(first(%q0),%0*)),0)])]
&FN_CBTCHK DSS Database=[not(hasflag(%L,OOC))][or(t(match(lvplayers(%L),setr(P,pmatch(%1)))),hasflag(locate(%0,%1,T),COMBAT_OK))][not(t(default(Engaged`%qP,)))][not(t(match(default(Engaged`%qP,),%0,|)))][not(t(match(default(%0/Flags,),Incapacitated)))][not(t(match(default(%1/Flags,),Incapacitated)))][u(FN_ISWEAPON,%0)]
&FN_CBTCHK_MELEE DSS Database=[not(hasflag(%L,OOC))][or(t(match(lvplayers(%L),setr(P,pmatch(%1)))),hasflag(locate(%0,%1,T),COMBAT_OK))][not(t(default(Engaged`%qP,)))][not(t(match(default(Engaged`%qP,),%0,|)))][not(t(match(default(%0/Flags,),Incapacitated)))][not(t(match(default(%1/Flags,),Incapacitated)))]
&FN_CBTENGAGE DSS Database=[attrib_set(me/Engaged`%1,%0|[secs()]|[if(t(match(%2,Melee_Ranged)),weapon|%2,%2)])]
&FN_CLINE DSS Database=[ansi(g,[repeat(-,sub(37,ceil(fdiv(strlen(%0),2))))]<)] [ansi(rh,%0)] [ansi(g,>[repeat(-,sub(37,div(strlen(%0),2)))])]
&FN_COLOR_NUM DSS Database=[ansi(switch(%0,>100,c,>66,g,>33,y,r),%0)]
&FN_COST DSS Database=[switch(%0,>90,add(145,mul(sub(%0,90),4)),>75,add(100,mul(sub(%0,75),3)),>50,add(50,mul(sub(%0,50),2)),>35,add(30,mul(sub(%0,35),2)),%0)]
&FN_DAMAGE DSS Database=[setq(W,[if(gte(if(t(%0),%0,0),if(t(%1),%1,0)),wounds,stuns)])][switch(lmath(max,%0 %1)],<5,lightly %qW,<10,moderately %qW,<15,seriously %qW,<20,critically %qW,vivisects)]
&FN_DEFENSE DSS Database=[t(default(me/engaged`%#,))]
&FN_DIE DSS Database=[mul(sign(%0),if(eq(%0,0),0,die(1,abs(%0))))]
&FN_DMG_ROLL DSS Database=[fdiv(add(1,floor(switch(rand(200),100,%0,>100,[add(%0,mul(sub(100,%0),fdiv(mod(#$,100),100)))],[div(mul(%0,mod(#$,100)),100)]))),100)]
&FN_ENGAGE DSS Database=[setq(0,%#,A,first(default(me/engaged`%#,),|))][setq(1,[add(75,[u(FN_SP,%qA)])],S,[div(ulocal(%vd/FN_GetAttr,%qA,Strength),2)])][setq(2,[switch(extract(get(me/engaged`%q0),3,1,|),weapon,if(t(match([extract(get(me/engaged`%q0),4,1,|)],Melee_Ranged)),strcat(extract(setr(B,default(%qA/equipment`weapon,)),1,1,|),default(me/default_melee,)),%qB),)])][setq(3,ulocal(%vd/FN_ToHit_Roll,ulocal(%vd/FN_GetSkill,%qA,[defextr(%q2,3,1,|,Brawling)]),switch(%1,MSG_ATTACK_WAIT,5,ulocal(%vd/FN_GetSkill,%q0,[defextr(%q2,4,1,|,Dodge_Melee)])),add([defextr(%q2,5,1,|,0)],%q1)))][setq(4,ifelse(gte(%q3,0),ulocal(%vd/FN_Dmg_Roll,%q3),0))][setq(5,ceil(mul(%q4,[defextr(%q2,7,1,|,%qS)])))][setq(6,mul(%q4,[defextr(%q2,6,1,|,0)]))][setq(7,defextr(default(%#/EQUIPMENT`ARMOR,),2,1,|,get(%vd/Threshold)),8,defextr(default(%#/EQUIPMENT`ARMOR,),3,1,|,get(%vd/Rating)))][setq(5,round(add(mul(sub(%q5,%q7),sub(1,%q8)),mul(%q8,sub(%q6,%q7))),0))][setq(6,round(mul(sub(%q6,%q7),sub(1,%q8)),0))][u(me/%1)][attrib_set(me/Engaged`%q0)][null([u(FN_Stun,%#,%q5)][u(FN_Wound,%#,%q6)])]
&FN_EQUIP DSS Database=[if(t(default(#29/[extract(%q0,2,1)]_WEAPON,)),[attrib_set(%#/equipment`weapon,[edit([edit(extract(%q0,1,2),%b,|)],_,%b)]|[default(#29/[extract(%q0,2,1)]_WEAPON,)])][remit(%L,[u(MSG_EQUIP_WEAPON,edit(extract(%q0,1,1),_,%b))])],[attrib_set(%#/equipment`armor,[edit([edit(extract(%q0,1,2),%b,|)],_,%b)]|[default(#29/extract(%q0,2,1)_ARMOR,)])][remit(%L,[u(MSG_EQUIP_ARMOR,edit(extract(%q0,1,1),_,%b))])])][attrib_set(%#/list`inventory,u(#8/fun`submass,default(%#/list`inventory,),extract(%q0,1,2),1))]
&FN_FOOTER DSS Database=%b[ansi(%vc,`-[repeat(=,72)]-')]
&FN_GETATTR DSS Database=[extract(extract(get(%0/DSS_Attrs),1,1,|),match(v(List_Attrs),%1),1)]
&FN_GETBASEATTR DSS Database=[extract(extract(get(%0/DSS_Attrs),3,1,|),match(v(List_Attrs),%1),1)]
&FN_GETBASELEVEL DSS Database=[ifelse(match(v(List_Attrs),%1),ulocal(FN_GetBaseAttr,%0,%1),ulocal(FN_GetBaseSkill,%0,%1))]
&FN_GETBASELEVEL2 DSS Database=[ifelse(match(v(List_Attrs),%1),ulocal(FN_GetAttr,%0,%1),ulocal(FN_GetBaseSkill,%0,%1))]
&FN_GETLEVEL DSS Database=[if(match(v(List_Attrs),%1),ulocal(FN_GetAttr,%0,%1),ulocal(FN_GetSkill,%0,%1))]
&FN_GETPOWER DSS Database=[localize([setq(0,grab(default(%0/DSS_POWERS,),%1 *,|))][switch([t(%q0)][t(match(v(List_Skills),[first(%1,:)][ifelse(gte(words(%1,:),2),:*,%b*)],|))],1*,extract(%q0,2,1),01,ulocal(FN_Adj_Skill,%0,%1,0),#-1 Invalid skill)])]
&FN_GETSKILL DSS Database=[if(t(setr(0,grab(lattr(%0/Skills`*,|),SKILLS`%1*,|))),u(FN_Adj_Skill,%0,%1,[u(%0/%q0)]),u(FN_Adj_Skill,%0,%1,0))]
&FN_HASSKILLS DSS Database=[and(not(hasflag(%0,UNREGISTERED)),hasattrval(%0,DSS_ATTRS))]
&FN_HEADER DSS Database=[center([ansi(rh,. o O)] [ansi(wh,%0)] [ansi(rh,O o .)],78)]%r[ansi(%vc,%b.-[repeat(=,72)]-.)]
&FN_ILINE DSS Database=%b[ansi(%vc,>---<)] [ansi(mh,%0)] [ansi(%vc,>[repeat(-,sub(67,strlen(%0)))]<)]
&FN_ISADMIN DSS Database=[orflags(%0,Wr)]
&FN_ISAMMO DSS Database=[t(match(lparent(%0),#119))]
&FN_ISARMOR DSS Database=[t(match(lparent(%0),#118))]
&FN_ISFS DSS Database=0
&FN_ISGUN DSS Database=[t(match(lparent(%0),#42))]
&FN_ISMELEE DSS Database=[t(match(lparent(%0),#19))]
&FN_ISWEAPON DSS Database=t(default(#29/[extract(default(%0/equipment`weapon,),2,1,|)]_WEAPON,0))
&FN_PARSE_ATTR DSS Database=[grab(v(List_Attrs),[%0]*)]
&FN_PARSE_SKILL DSS Database=[first(first(setr(9,grab(v(List_Skills),[edit(%0,%b,_)]*,|))),:)]
&FN_PMATCH DSS Database=[switch(pmatch(%0),#-1,locate(%#,%0,PTahilmna),#$)]
&FN_PWRADD DSS Database=[if(lte(1,[setr(X,default(%#/DSS_XP,0))]),[attrib_set(%#/powers`[first(%0,_)]_[last(%1,`)],1|%0|[last(%1,`)]|%2)][attrib_set(%#/DSS_XP,[sub(%qX,1)])][u(MSG_ADDPOWER,%0,%1,1)],Insufficient XP.)]
&FN_PWRCHK DSS Database=[t(match(default(%#/Species,Human),Starborn))][u(FN_SphereOK,%0)][u(FN_SubtypeOK,%1)][lte(strlen(%2),44)]
&FN_REPLACE DSS Database=[squish([extract(%0,1,dec(%1))] [%2] [extract(%0,inc(%1),sub(words(%0),%1))])]
&FN_SEEALSO DSS Database=%r[u(FN_Line)]%r[center(See also: [iter(%0,[ansi(y,edit(##,_,%b))],,\,%b)].,78)]
&FN_SETATTR DSS Database=[set(%0,DSS_Attrs:[vadd(setr(0,extract(get(%0/DSS_Attrs),2,1,|)),setr(1,[u(FN_Replace,extract(get(%0/DSS_Attrs),3,1,|),match(v(List_Attrs),%1),%2)]))]|[%q0]|[%q1])][ulocal(FN_Update_Skills,%0)]
&FN_SETLEVEL DSS Database=[ifelse(match(v(List_Attrs),%1),ulocal(FN_SetAttr,%0,%1),ulocal(FN_SetSkill,%0,%1))]
&FN_SETSKILL DSS Database=[localize([attrib_set(%0/Skills`%1,add(setr(S,default(%0/Skills`%1,0)),sub(%2,%qS)))])]
&FN_SHEET DSS Database=[setq(0,secure(%0))][switch([isdbref(%q0)][u(FN_HasSkills,%q0)],11,[ulocal(FN_Sheet_Top,%q0)][ulocal(FN_Sheet_Attr,%q0)][ulocal(FN_Sheet_Skill,%q0)][ulocal(FN_Sheet_Powers,%q0)][ulocal(FN_Sheet_Feat,%q0)][ulocal(FN_Sheet_Lang,%q0)][ulocal(FN_Sheet_Gear,%q0)][ulocal(FN_Sheet_Health,%q0)][ulocal(FN_Footer)],0*,[u(MSG_NotPlayer)],10,[u(MSG_NoTraits)],[u(MSG_Crit)])]
&FN_SHEET2 DSS Database=[setq(0,secure(%0))][setq(1,extract(Attr Skill Feat Lang Gear Health,match(Attributes Skills Feats Languages Gear Health,[%1]*),1))][switch([isdbref(%q0)][u(FN_HasSkills,%q0)],11,[ulocal(FN_Sheet_Top,%q0)][ulocal(FN_Sheet_[%q1],%q0)][ulocal(FN_Footer)],0*,[u(MSG_NotPlayer)],10,[u(MSG_NoTraits)],[u(MSG_Crit)])]
&FN_SHEET_ATTR DSS Database=[u(FN_ILine,Attributes)]%r[ansi(%vc,|)]%b[repeat([ljust(ansi(%vb,Attribute),15)][ljust(ansi(%vb,Adj Base),10)],3)][ansi(%vc,|%r|%b[repeat([ansi(%vc,repeat(~,24))]%b,3)])][iter(extract(v(List_Attrs),1,6),[ifelse(mod(sub(#@,1),3),,[ansi(%vc,|%r|%b)])][ljust(ansi(%va,%i0:),15)][rjust(extract(extract(get(%0/DSS_Attrs),1,1,|),#@,1),3)]%b[rjust([extract(extract(get(%0/DSS_Attrs),3,1,|),#@,1)],4)]%b%b,,)][ansi(%vc,|)]%r
&FN_SHEET_FEAT DSS Database=[ifelse(words(get(%0/DSS_Feats)),[u(FN_ILine,Feats)]%r[ansi(%vc,|)]%b[iter(u(FN_Sort3Col,get(%0/DSS_Feats)),[ifelse(or(eq(#@,1),mod(sub(#@,1),3)),,[ansi(%vc,|%r|%b)])][ljust(edit(##,_,%b),25)],,)][ansi(%vc,|)]%r,)]
&FN_SHEET_GEAR DSS Database=[u(FN_ILine,Gear)]%r[ansi(%vc,|)]%b[ljust([ansi(%va,Armor:)] [ifelse(isdbref(get(%0/DSS_Armor)),name(get(%0/DSS_Armor)),None)],37)][ljust([ansi(%va,Weapon:)] [ifelse(isdbref(get(%0/DSS_Weapon)),name(get(%0/DSS_Weapon)),None)],38)][ansi(%vc,|)]%r
&FN_SHEET_HEALTH DSS Database=[u(FN_ILine,Health)]%r[ansi(%vc,|)][ljust(%b[ansi(%va,Status:)] [ulocal(FN_Status,%0)] [ansi(c,\()][sub(100,div(mul(100,[u(FN_WP,%0)]),u(FN_GetAttr,%0,Body)))]\% Healthy[ansi(c,\))],38)][ljust(%b[ansi(%va,Stun Points:)]%b[u(FN_SP,%0)],38)][ansi(%vc,|%r)][if(t(default(%0/DSS_WP,0)),[ansi(%vc,|%b)][ljust([ansi(%va,Wounds:)]%b[itemize([edit([u(FN_SHEET_WP,[iter(get(%0/DSS_WP),switch(first(%i0),<2,S,<5,L,<15,M,<25,C,>26,D,Error),|)])],_,%b)],:)],74,%b)][ansi(%vc,%b|)]%r,)]
&FN_SHEET_LANG DSS Database=[u(FN_ILine,Languages)]%r[ansi(%vc,|)]%b[iter(u(FN_Sort3Col,get(%0/DSS_Languages)),[ifelse(or(eq(#@,1),mod(sub(#@,1),3)),,[ansi(%vc,|%r|%b)])][ljust([ifelse(match(##,get(%0/DSS_Lingo)),[ansi(yh,*)][ansi(wh,edit(##,_,%b))][ansi(yh,*)],edit(##,_,%b))],25)],,)][ansi(%vc,|)]%r
&FN_SHEET_POWERS DSS Database=[if(hasattr(%0,Powers),[u(FN_ILine,Powers)]%r[ansi(%vc,|)]%b[ansi(%vb,%b%bLevel[space(3)][ljust(Power,28)]%b%bLevel[space(3)][ljust(Power,27)])][ansi(%vc,|%r|%b[repeat(~,36)]%b%b[repeat(~,36)]%b|)][edit([step(#lambda/%%r\[align\(2 35 1 35 2 \,ansi\(%%vc\,|\)\,%%0\,\,%%1\,ansi\(%%vc\,|\)\,%%b\)\],[iter(lattr(%0/powers`**,|),[rjust([u(FN_Color_Num,[first(u(%0/%i0),|)])],5)][space(4)][capstr_all([edit([last(u(%0/%i0),|)],_,%b)])],|,+)],2,+)],+,)]%r,)]
&FN_SHEET_SKILL DSS Database=[if(hasattr(%0,skills),[u(FN_ILine,Skills)]%r[ansi(%vc,|)]%b[ansi(%vb,[rjust(Adj,4)]%bBase%b[ljust(Skill,28)][rjust(Adj,4)]%bBase%b[ljust(Skill,27)])][ansi(%vc,|%r| [repeat(~,36)]%b%b[repeat(~,36)]%b|)][edit([step(#lambda/%%r\[align\(2 35 1 35 2 \,ansi\(%%vc\,|\)\,%%0\,\,%%1\,ansi\(%%vc\,|\)\,%%b\)\],[iter(lattr(%0/skills`*,|),[rjust([u(FN_Color_Num,[u(FN_Adj_Skill,%0,[last(%i0,`)],[get(%0/%i0)])])],3)][rjust([u(FN_Color_Num,[get(%0/%i0)])],4,%b)]%b%b[capstr_all([edit([last(%i0,`)],_,%b)])],|,+)],2,+)],+,)]%r,)]
&FN_SHEET_TOP DSS Database=[u(FN_Header,[name(%0)]'s Sheet)]%r[ansi(%vc,|)]%b[ljust([ansi(%va,Species:)] [default(%0/Species,Not Set)],25)][ljust([ansi(%va,Gender:)] [default(%0/Sex,Anomalous)],25)][ljust([ansi(%va,Age:)] [default(%0/age,Not Set)],25)][ansi(%vc,|%r|)]%b[ljust([ansi(%va,Experience Points:)] [get(%0/DSS_XP)],25)][ljust([ansi(%va,Health:)] [u(FN_Status,%0)],50)][ansi(%vc,|)]%r
&FN_SHEET_WP DSS Database=[squish([localize([iter(S L M C D,setq(#@,words(lpos(%0,%i0))))][edit([squish([switchall(1,t(%q1),%q1_Scratch[plural(%q1,e)]%b,t(%q2),%q2_Light_Wound[plural(%q2)]%b,t(%q3),%q3_Moderate_Wound[plural(%q3)]%b,t(%q4),%q4_Critical_Wound[plural(%q4)]%b,t(%q5),%q5_Deadly_Wound[plural(%q5)]%b,)])],%b,:)])])]
&FN_SKILL_COST DSS Database=[sub(ulocal(FN_Cost,%2),ulocal(FN_Cost,default(%0/Skills`%1,0)))]
&FN_SORT2COL DSS Database=[setq(0,sort(%0,a,%1))][setq(1,ceil(fdiv(words(%q0,%1),2)))][iter(lnum(mul(2,%q1)),[setq(2,extract(%q0,add(1,mul(mod(##,2),%q1),mod(div(##,2),%q1)),1,%1))][ifelse(%q2,%q2,_)],,%1)]
&FN_SORT3COL DSS Database=[setq(0,sort(%0,a))][setq(1,ceil(fdiv(words(%q0),3)))][iter(lnum(mul(3,%q1)),[setq(2,extract(%q0,add(1,mul(mod(##,3),%q1),mod(div(##,3),%q1)),1))][ifelse(%q2,%q2,_)])]
&FN_SORT_WP DSS Database=[comp(extract(%0,2,1),extract(%1,2,1))]
&FN_SP DSS Database=[ceil(max(0,fdiv(sub(val(get(%0/DSS_SP)),secs()),60)))]
&FN_SPHEREOK DSS Database=t(setr(M,match(setr(L,setdiff(lattr(#133/*,|),CMD|CYBERNETICS_SPHERE|%1,|,|)),[if(t(%0),%0,0)]*,|)))
&FN_STATUS DSS Database=[ifelse(isdbref(%0),ifelse(match(get(%0/DSS_Feats),Dead),Dead,ifelse(match(get(%0/DSS_Feats),Unconscious),Unconscious,ifelse(gt(ulocal(FN_WP,%0),0),Injured,ifelse(gt(ulocal(FN_SP,%0),0),Dazed,Healthy)))),#-1 I can't see that here.)]
&FN_STUN DSS Database=[attrib_set(%0/DSS_SP,[add(max(secs(),val(default(%0/DSS_SP,0))),mul(60,%1))])][ulocal(me/FN_Update_Health,%0)]
&FN_SUBTYPEOK DSS Database=[t(setr(Z,match(setr(R,lattr(#133/[extract(%qL,%qM,1,|)]`*,|)),[extract(%qL,%qM,1,|)]`[if(t(%0),%0,0)]*,|)))]
&FN_TOHIT_ROLL DSS Database=[sub(%0,add(ulocal(FN_Die,%2),max(0,sub(%1,ulocal(FN_Die,ceil(mul(100,fdiv(100,abs(%2)))))))))]
&FN_UNEQUIP DSS Database=[remit(%L,[ansi(hw,<[ansi(hy,COMBAT)]>)]%b%b%b[name(%#)]%b[switch(%0,Armor,removes [poss(%#)] [first(get(%#/equipment`%0),|)],Weapon,lowers [poss(%#)] [first(get(%#/equipment`%0),|)],[u(%vd/MSG_Crit)])].)][attrib_set(%#/list`inventory,[u(#8/fun`addmass,[default(%#/list`inventory,)],edit([edit(extract(get(%#/equipment`%0),1,2,|),%b,_)],|,%b),1)])][attrib_set(%#/Equipment`%0)]
&FN_UPDATE DSS Database=[set(%0,DSS_Attrs:[vadd(setr(0,ulocal(FN_Attr_Mods,%0)),setr(1,extract(get(%0/DSS_Attrs),3,1,|)))]|[%q0]|[%q1])][u(FN_Update_Skills,%0)][u(FN_Update_Health,%0)]
&FN_UPDATE_HEALTH DSS Database=[setq(0,u(FN_SP,%0))][setq(1,u(FN_WP,%0))][setq(2,ulocal(FN_GetAttr,%0,Strength))][set(%0,DSS_Feats:[setunion(get(%0/DSS_Feats),[switch([gt(%q1,%q2)][gt(add(%q0,%q1),%q2)],1*,Dead,01,Unconscious,)])]
&FN_UPDATE_SKILLS DSS Database=[set(%0,DSS_Skills:[iter(get(%0/DSS_Skills),[extract(##,1,1)] [ulocal(FN_Adj_Skill,%0,extract(##,1,1),extract(##,3,1))] [extract(##,3,1)],|,|)])]
&FN_VADD DSS Database=vadd(%0,%1)
&FN_WOUND DSS Database=[attrib_set(%0/DSS_WP,[if(words(get(%q0/DSS_WP)),[default(%0/DSS_WP,)]|,)]%1 [secs()] [sub(secs(),3600)] Automatic)][ulocal(me/FN_Update_Health,%0)]
&FN_WP DSS Database=[ifelse(words(get(%0/DSS_WP),|),fold(FN_Add_First,get(%0/DSS_WP),0,|),0)]
&FUN_GETBASESKILL DSS Database=[ifelse(u(FN_IsAdmin,%@),[ulocal(FN_GetBaseLevel,ulocal(FN_Pmatch,secure(%0)),edit(squish(secure(%1)),%b,_))],#-1 Permission denied.)]
&FUN_GETSKILL DSS Database=[if(u(FN_IsAdmin,%@),[ulocal(FN_GetLevel,ulocal(FN_Pmatch,%0),[edit(squish(first(%1,:)),%b,_)][if(words(after(%1,:)),:[edit(squish(after(%1,:)),%b,_)],)])],#-1 Permission denied.)]
&FUN_HASFEAT DSS Database=[ifelse(u(FN_IsAdmin,%@),t(match(get(ulocal(FN_PMatch,secure(%0))/DSS_Feats),edit(squish(secure(%1)),%b,_))),#-1 Permission denied.)]
&FUN_HASSKILLS DSS Database=[ulocal(FN_HasSkills,ulocal(FN_Pmatch,secure(%0)))]
&FUN_HASWEAPON DSS Database=[isdbref(get(ulocal(FN_Pmatch,secure(%0))/DSS_WEAPON))]
&FUN_HSTATUS DSS Database=[ulocal(FN_Status,ulocal(FN_Pmatch,secure(%0)))]
&FUN_ISARMOR DSS Database=[ulocal(FN_IsArmor,secure(%0))]
&FUN_ISWEAPON DSS Database=[ulocal(FN_IsWeapon,secure(%0))]
&FUN_WEAPON DSS Database=[default(ulocal(FN_Pmatch,secure(%0))/DSS_Weapon,#-1)]
&LIST_ATTR_MODS DSS Database=
&LIST_ATTRS DSS Database=Strength Agility Coordination Wit Cognition Body
&LIST_FEATS DSS Database=
&LIST_LANGUAGES DSS Database=English German hydra Lelajivian Russian
&LIST_SKILLS DSS Database=Brawling 0 1 & 0.25_Strength 0.15_Coordination|Computers 0 1 & 0.25_Cognition 0.15_Wit|Disguise 0 1 & 0.25_Wit 0.15_Coordination|Dodge_Melee 0 1 & 0.25_Agility 0.20_Wit|Dodge_Ranged 0 1 & 0.25_Agility 0.20_Wit|Engineering 0 0 & 0.25_Coordination 0.15_Cognition 0.05_Wit|Firearms 0 1 & 0.25_Coordination 0.15_Wit|Interfacing 0 1 & 0.20_Body|Magic_Lore 0 0 & 0.25_Wit 0.15_Cognition|Perception 0 1 & 0.30_Wit|Repair 0 1 & 0.25_Coordination 0.15_Cognition|Research 0 0 & 0.25_Cognition 0.15_Wit 0.05_Coordination|Salvage 0 1 & 0.25_Wit 0.15_Coordination 0.05_Cognition|Stealth 0 1 & 0.25_Coordination 0.15_Wit|Unarmed_Combat 0 1 & 0.25_Strength 0.15_Agility 0.05_Coordination
&MSG_ABORT DSS Database=[ansi(yh,-)] %0 has aborted their attack on %1.
&MSG_ADDPOWER DSS Database=[ansi(hg,-)] You gain a power in the [ansi(y,[edit(%0,_,%b)])] of subtype [ansi(y,[edit(%1,_,%b,%0`,)])] at a value of %2.
&MSG_ATKD_RNG DSS Database=[space(11)]Defense Options:%b[ansi(hw,+WAIT)] - [ansi(hw,+DODGE)][if(t(match(default(%0/EQUIPMENT`WEAPON,),Dodge_Ranged,|)), - [ansi(hw,+QUICKSHOT)])]%rYou have [ansi(hw,10 minutes)] to react, or the attack will be [ansi(hw,+abort)]ed automatically.
&MSG_ATK_MELEE DSS Database=[ansi(hw,<[ansi(hy,COMBAT)]>)]%b%b%b[name(%0)] swings [poss(%0)] [capstr_all(edit(first(%2,|),_,%b))] at [name(%1)]!
&MSG_ATK_RNG DSS Database=[ansi(hw,<[ansi(hy,COMBAT)]>)]%b%b%b[name(%0)] fires [poss(%0)] [capstr_all(edit(first(%2,|),_,%b))] at [name(%1)]!
&MSG_ATTACK DSS Database=[remit(%L,[ansi(hw,<[ansi(hy,COMBAT)]>)]%b%b%b[name(%q0)]%b[if(gt(%q4,0),tries to dodge\, but [name(%qA)]'s attack hits and [u(FN_DAMAGE,%q6,%q5)] [obj(%q0)].,successfully dodges [name(%qA)]'s attack.)])]
&MSG_ATTACK_WAIT DSS Database=[remit(%L,[ansi(hw,<[ansi(hy,COMBAT)]>)]%b%b%b[name(%qA)][if(gt(%q4,0),'s attack hits and [u(FN_DAMAGE,%q6,%q5)] [name(%q0)].,%bshoots at [name(%q0)]\, but misses.)])]
&MSG_COMBAT DSS Database=[remit(%l,[ansi(y,%0)] [ifelse(gt(%q3,0),ansi(gh,successfully),ansi(rh,unsuccessfully))] attacks %N [ifelse(isdbref(%q2),using a [ansi(y,name(%q2))],unarmed)]. \([ansi(c,%q3)]\)[ifelse(gt(%q4,0),%rThe attack should deal [switch([gt(%qq5,0)][gt(%q6,0)],11,[ansi(ch,%q5)] stun points and [ansi(mh,%q6)] wound points,10,[ansi(ch,%q5)] stun points,01,[ansi(mh,%q6)] wound points,no damage)].)]
&MSG_CRIT DSS Database=[ansi(rh,-)] Critical error. Report this bug at once!
&MSG_ENGAGED DSS Database=[ansi(rh,-)] You are already engaged in a fight.
&MSG_ENGAGED2 DSS Database=[ansi(rh,-)] They are already engaged in a fight.
&MSG_EQUIP_ARMOR DSS Database=[ansi(hw,<[ansi(hy,COMBAT)]>)]%b%b%b[name(%#)] dons [obj(%#)] %0.
&MSG_EQUIP_WEAPON DSS Database=[ansi(hw,<[ansi(hy,COMBAT)]>)]%b%b%b[name(%#)] wields [poss(%#)] %0.
&MSG_EXP DSS Database=[ansi(rh,-)] You do not have the [ansi(y,%0)] experience points required for that.
&MSG_FAIL_RAISE DSS Database=[ansi(rh,-)] You cannot +lower [ansi(y,%0)] with +raise.
&MSG_INCAP DSS Database=[ansi(rh,-)] You are in no condition to do that.
&MSG_NOGUN DSS Database=[ansi(rh,-)] You can't shoot someone with that.
&MSG_NOTADMIN DSS Database=[ansi(rh,-)] You must be an admin to use this command.
&MSG_NOTATTR DSS Database=[ansi(rh,-)] That is not a valid attribute name.
&MSG_NOTENGAGED DSS Database=[ansi(rh,-)] You are not being attacked by anyone.
&MSG_NOTFEAT DSS Database=[ansi(rh,-)] That is not a valid feat.
&MSG_NOTLANG DSS Database=[ansi(rh,-)] That is not a valid language.
&MSG_NOTNAME DSS Database=[ansi(rh,-)] That is not a valid attribute or skill name.
&MSG_NOTPLAYER DSS Database=[ansi(rh,-)] No player with that name could be located.
&MSG_NOTRAITS DSS Database=[ansi(rh,-)] That player is not configured for the skills system yet.
&MSG_NOTSKILL DSS Database=[ansi(rh,-)] That is not a valid skill name.
&MSG_OOC DSS Database=[ansi(hr,-)] You must be 'In Character' to do that.
&MSG_PREREQS DSS Database=[ansi(rh,-)] You do not meet the prereqs to increase this trait.
&MSG_RAISE DSS Database=[ansi(gh,-)] You +raise [ansi(y,edit(%0,_,%b))] to [ansi(y,%1)] at cost of [ansi(y,%2)] experience points.
&MSG_TARGET DSS Database=[ansi(hw,<[ansi(hy,COMBAT)]>)]%b%b%bThat is not a valid target.
&MSG_TINCAP DSS Database=[ansi(rh,-)] They are already incapacitated. If you intend to kill them, please notify an Admin or Judge.
&RATING DSS Database=0
@STARTUP DSS Database=@drain %!;@notify %!;@dolist BG_Approved DSS_Armor DSS_Attrs DSS_Feats DSS_Languages DSS_Lingo DSS_Skills DSS_SP DSS_Weapon DSS_WP DSS_XP Species Status={@attribute/access/retroactive [##]=no_command no_inherit no_clone mortal_dark wizard};@dolist [lattr(%!/FUN_*)]={@function [rest(##,_)]=%!,##}
@set DSS Database/STARTUP=no_command prefixmatch
&THRESHOLD DSS Database=0
@VA DSS Database=y
@VB DSS Database=c
@VC DSS Database=b
@VD DSS Database=#156
Also, Naboo was under an attack.
Virtual Inventory +Look Code
A nice little expansion to add +look to your arsenal of commands in the Virtual Inventory System. As the title says, this is the +look code to look at an item, and get its description. It applies to items in the room, as well as the user's inventory.
+look *: Is the proper syntax.
You can add descriptions for item types by adding &DESC_# Item Database=Description.
For example, if
&1_GENERAL Item Database=Food
is your item.. Then..
&1_DESC Item Database=An edible item made of delicious.
would be your description.
Replaced #27 with the dbref of your Item System.
&CMD`+LOOK #27=$+look *:@pemit %#=[switch(t(setr(I,grab(setunion(default(%#/list`inventory,),default(%L/list`inventory,),|),[edit(%0,%b,_)]*,|))),1,[u(ufun`look,%qI)],I don't see that here.)]
&UFUN`LOOK #27=[ansi(hw,[edit(first(%0),_,%b)])]%r[udefault(%VD/[extract(%0,2,1)]_DESC,You see nothing special.)]
Statistical Analysts
Was thinking of picking up some of my old code to create a mechanical simulation to which Mecha can be built using a statistical system (From parts that already exist in the game) and fought with. Like Steel Battalion in MUSH form.
If there's interest in this project, I'll continue it. I have a server that can be utilized for just this purpose. In the meanwhile..
I'll need a statistical analyst, someone who thinks they can create parts and a system that's balanced and fair. I can code it, but my skills in stats aren't.. perfect, not to the quality I'd like them to be.
Very interested in hearing if people like this idea, Mecha tend to be very niche.
Virtual Item Comsystem
#27 Should be the dbref of your Item System. This object needs to be in the Master Room.
You will need to create a new entry in your Item Database, as well.
&#_GENERAL Item Database=COMSYS
# can be replaced with any free database entries you have. (That is, if you're using the default database, you can just make it 2. Since the default database only has 1 entry (Food))
Any comsystems will need to be labeled with this new item. If you did go with 2, a comsys virtual item might be..
&list`inventory me=Nuka_Cola 1 100|Reaver's_Comsys 2 1
This code is still in Beta testing, I will update it as time goes along. It has been proven in basic testing to function correctly, however.
Your commands are...
+com or +comsys: Details on commlink.
+com/broadcast or +comsys/broadcast: Broadcast on all frequencies listed in +comsys. (Not finished)
+com/transmit (Non functional) or +comsys/transmit (Functional): +comsys/transmit Blah will (Currently) transmit to all added frequencies. Later this will become +comsys/transmit =Blah. Where is the code or name you have assigned to a certain frequency.
+com/on or +comsys/on: Turn on your comsys.
+com/off or +comsys/off: Turn off your comsys.
+com/freq or +comsys/freq: Add a frequency to comsys (Always numbers, under 8)
+com/remfreq or +comsys/remfreq: Remove a frequency from comsys.
@create Comsys System
@set Comsys System = WIZARD
@set Comsys System = !NO_COMMAND
&CMD_ALIAS`+COM Comsys System=$+com:@fo %#=+comsys
&CMD_ALIAS`+COM/BROADCAST Comsys System=$+com/broadcast *:@fo %#={+comsys/broadcast %0}
&CMD_ALIAS`+COM/FREQ Comsys System=$+com/freq *=*:@fo %#={+comsys/freq %0=%1}
&CMD_ALIAS`+COM/OFF Comsys System=$+com/off:@fo %#=+comsys/off
&CMD_ALIAS`+COM/ON Comsys System=$+com/on:@fo %#=+comsys/on
&CMD_ALIAS`+COM/REMFREQ Comsys System=$+com/remfreq *:@fo %#={+comsys/remfreq %0}
&CMD_ALIAS`+COM/TRANSMIT Comsys System=$+com/transmit *=*:@fo %#={+comsys/transmit %0=%1}
&CMD`+COMSYS Comsys System=$+comsys:@pemit %#=[if([left([u(fun`uselock,%#)],1)],[ansi(g,[center(<%b[ansi(hg,Comsys Status)]%b>,50,-)])]%r[space(5)][ansi(hg,Transmit Name:)]%b[default(%#/comsys`name,name(%#))]%r[space(5)][ansi(hg,Comsys Power:)]%b[if(default(%#/comsys`power,0),ansi(hb,On),ansi(hr,Off))]%r[space(5)][ansi(hg,Frequencies:)]%b[iter(default(%#/comsys`freq,00000000),%i0%r,|,[space(18)])][ansi(g,[repeat(-,50)])],[ansi(hr,-)]%bYou don't have a comsys.)]
&CMD`+COMSYS/ADDFREQ Comsys System=$+comsys/addfreq *:@pemit %#=[switchall([u(fun`uselock,%#,%0)],*,[u(fun`error_string_off,#$)],101,[ansi(hg,-)]%bYou add [rjust(%0,8,0)] to the comsys frequency list.[attrib_set(%#/comsys`freq,[setunion([default(%#/comsys`freq,)],[rjust(%0,8,0)],|,|)])],[ansi(hrf,Code Error)])]
&CMD`+COMSYS/BROADCAST Comsys System=$+comsys/broadcast *:@pemit %#=[switchall([u(fun`uselock,%#,1)],?1?,[u(fun`error_string,#$)],101,[u(fun`transmit,%0,[default(%#/comsys`freq,00000000)])],[ansi(hrf,Code Error)])]
&CMD`+COMSYS/FREQ Comsys System=$+comsys/freq *=*:@pemit %#=[switchall([u(fun`uselock,%#,%0)],*,[u(fun`error_string_off,#$)],101,[ansi(hg,-)]%bYou add [rjust(%0,8,0)] to the comsys frequency list.[attrib_set(%#/comsys`freq,[setunion([default(%#/comsys`freq,)],[rjust(%0,8,0)],|,|)])],[ansi(hrf,Code Error)])]
&CMD`+COMSYS/OFF Comsys System=$+comsys/off:@pemit %#=[switchall([u(fun`uselock,%#,1)],*,[u(fun`error_string_off,#$)],101,[ansi(hg,-)]%bThe comsys pops off.[attrib_set(%#/comsys`power,0)],[ansi(hrf,Code Error)])]
&CMD`+COMSYS/ON Comsys System=$+comsys/on:@pemit %#=[switchall([u(fun`uselock,%#,1)],*,[u(fun`error_string_on,#$)],111,[ansi(hg,-)]%bThe comsys crackles to life.[attrib_set(%#/comsys`power,1)],[ansi(hrf,Code Error)])]
&CMD`+COMSYS/REMFREQ Comsys System=$+comsys/remfreq *:@pemit %#=[switchall([u(fun`uselock_freq,%#,%0)],*,[u(fun`error_string_off,#$)],101,[ansi(hg,-)]%bYou remove [rjust(%0,8,0)] from the comsys frequency list.[attrib_set(%#/comsys`freq,[setdiff([default(%#/comsys`freq,)],[rjust(%0,8,0)],|,|)])],[ansi(hrf,Code Error)])]
&CMD`+COMSYS/TRANSMIT Comsys System=$+comsys/transmit *:@pemit %#=[switchall([u(fun`uselock,%#,1)],*,[u(fun`error_string_off,#$)],101,[u(fun`transmit,%0)],[ansi(hrf,Code Error)])]
&FUN Comsys System=
&FUN`ERROR_STRING Comsys System=[switch(%0,0*,[ansi(hr,-)]%bYou don't have a comsys.,10*,[ansi(hr,-)]%bYour comsys is already turned on.,[ansi(hrf,Code Error)])]
&FUN`ERROR_STRING_FREQ Comsys System=[switch(%0,0*,[ansi(hr,-)]%bYou don't have a comsys.,111?,[ansi(hr,-)]%bYour comsys is turned off.,100?,[ansi(hr,-)]%bThat is not a valid number.,1110,[ansi(hr,-)]%bThat number doesn't exist in your comsys frequency list.,)]
&FUN`ERROR_STRING_OFF Comsys System=[switch(%0,0*,[ansi(hr,-)]%bYou don't have a comsys.,111,[ansi(hr,-)]%bYour comsys is already off.,100,[ansi(hr,-)]%bThat is not a valid number.,)]
&FUN`ERROR_STRING_ON Comsys System=[switch(%0,0*,[ansi(hr,-)]%bYou don't have a comsys.,101,[ansi(hr,-)]%bYour comsys is already turned on.,)]
&FUN`SHORTCUT Comsys System=if(eq(if(isnum(%0),strlen(%0)),8),%0,default(%#/comsys`freq`%0,00000000))
&FUN`TRANSMIT Comsys System=[null(iter([squish(iter(lsearch(all,type,player),switch(u(fun`uselock,%i0,1),101,%i0:[lmath(or,iter(default(%i0/comsys`freq,00000000),[t(match(default(%#/comsys`freq,00000000),%i0,|))],|,:),:)],),,|),|)],if(eq(last(%i0,:),1),[pemit([first(%i0,:)],[ansi(hy,-Comsys)] [speak(%#,%0)])]),|))]
&FUN`USELOCK Comsys System=[lmath(or,[iter(setr(0,default(%0/list`inventory,)),match([u(#27/fun`itemres,%q0,%i0,GENERAL)],COMSYS),|,:)],:)][eq([default(%0/comsys`power,0)],0)][isnum(%1)]
&FUN`USELOCK_FREQ Comsys System=[lmath(or,[iter(setr(0,default(%0/list`inventory,)),match([u(#27/fun`itemres,%q0,%i0,GENERAL)],COMSYS),|,:)],:)][eq([default(%0/comsys`power,0)],0)][isnum(%1)][t([grab(default(%0/comsys`freq,00000000),%2,|)])]
Virtual Item System
Righto, this is my amazing "Virtual Inventory System". I'll briefly explain how it works. Basically an inventory is saved on a player via list`inventory in the format ITEM_NAME TYPE AMOUNT|ITEM_NAME TYPE AMOUNT
A type is a number, as seen in the bottom most item database variable (1_General)
1 is the number type of the object, and GENERAL is the general item type.
This allows one to &list`inventory me=Nuka_Cola 1 100
to create 100 Nuka Cola's as type Food.
This is great for atmosphere, and reducing MUSH clutter. As
&list`inventory me=Cake 1 100
Allows you to make cake, as the same type as Nuka Cola, without needing to change anything in the database. Simply editing an inventory string and adding in the new item is enough to make it exist. The only modifications really ever needed to the system database is when adding a new item type. Item types can be anything, but are usually used with code to identify an item for a purpose (As will be seen with the Comsys code I will soon post.)
I will also be dropping in a +look command very shortly for desc'd objects.
Right now the system's virtual inventory is +inv, +take , +give =, +drop
====== Main Code
@create Item System
@create Item Database
@link Item Database=Item System
@set Item System=VD:[num(Item Database)]
@set Item System = WIZARD
@set Item System = !no_command
&CMD`DROP Item System=$+drop *:@pemit %#=[switch([t(setr(G,grab(setr(I,default(%@/list`inventory,)),%0*,|)))][t(sign([extract(%qG,3,1)]))],11,You drop [capstr_all(edit(first(%qG),_,%b))].[oemit(%L/%@,[name(%@)] drops [capstr_all(edit(first(%qG),_,%b))])][attrib_set(%@/list`inventory,u(fun`submass,%qI,extract(%qG,1,2),1))][attrib_set(%L/list`inventory,u(fun`addmass,[default(%L/list`inventory,)],[extract(%qG,1,2)],1))],I don't see that in your inventory.)]
&CMD`GET Item System=$+get *:@pemit %#=[switch([t(setr(G,grab(setr(I,default(%L/list`inventory,)),%0*,|)))][t(sign([extract(%qG,3,1)]))],11,You take [capstr_all(edit(first(%qG),_,%b))].[oemit(%L/%@,[name(%@)] takes [capstr_all(edit(first(%qG),_,%b))])][attrib_set(%L/list`inventory,u(fun`submass,%qI,extract(%qG,1,2),1))][attrib_set(%@/list`inventory,u(fun`addmass,[default(%@/list`inventory,)],[extract(%qG,1,2)],1))],I don't see that here.)]
&CMD`GIVE Item System=$+give *=*:@pemit %#=[switch([t(setr(G,grab(setr(I,default(%@/list`inventory,)),%1*,|)))][t(sign([extract(%qG,3,1)]))][hastype(setr(p,pmatch(%0)),PLAYER)],111,You give [setr(R,capstr_all(edit(first(%qG),_,%b)))] to [name(%qP)].[oemit(%L/%@ %qP,[name(%@)] gives %qR to [name(%qP)])][pemit(%qP,[name(%@)] gives you a %qR.)][attrib_set(%@/list`inventory,u(fun`submass,%qI,extract(%qG,1,2),1))][attrib_set(%qP/list`inventory,u(fun`addmass,[default(%qP/list`inventory,)],[extract(%qG,1,2)],1))],110,That's not a player.,I don't see that in your inventory.)]
&CMD`INV Item System=$^i(?\:n|nv|nve|nven|nvent|nvento|nventor|nventory)?$:@pemit %#=[u(format`inventory)]
&CMD`+INV Item System=$^\+i(?\:n|nv|nve|nven|nvent|nvento|nventor|nventory)?$:@pemit %#=[u(format`inventory)]
@set Item System/CMD`INV=regexp
@set Item System/CMD`+INV=regexp
@DESCRIBE Item System=Thing
&FORMAT`INVENTORY Item System=[ansi(hx,[center([ansi(hw,<%b[ansi(hg,[name(%#)]'s Inventory)]%b>)],78,=,=)]%r[repeat(-,78)])]%r[table([iter([default(%#/list`inventory,)],[space(8)]<[last(%i0)]x>%b[ansi(hy,[edit([capstr([lcstr([first(%i0)])])],_,%b)])]%b%b,|,|)],38,78,|,%b)]%r[ansi(hx,[rjust([ansi(hw,<%b[ansi(hg,At #\% carrying capacity.)]%b>)],73,-)]-----[if(t(lcon(%#)),%r[ansi(hg,OOC Objects:)]%r[iter(lcon(%#),[ansi(hg,[name(%i0)])]%b[ansi(hy,<%i0>)],%b,%r)]%r,%r)][rjust([ansi(hw,<%b[ansi(hg,[default(%#/Cash,0)] Dollars)]%b>)],78,=)])]
&FUN`ADDMASS Item System=localize(switch(t(setr(0,match(%0,%1%b*,|))),1,replace(%0,%q0,replace(setr(1,extract(%0,%q0,1,|)),3,add(last(%q1),%2)),|),0,setunion(%0,%1%b%2,|),ERROR AT ADDMASS))
&FUN`ITEMRES Item System=[default(%vd/[extract([grab(%0,%1*,|)],2,1)]_%2,Data Trash)]
&FUN`SUBMASS Item System=localize(switch(sign(last(setr(0,replace(setr(1,extract(%0,setr(2,match(%0,%1%b*,|)),1,|)),3,sub(last(%q1),%2))))),1,replace(%0,%q2,%q0,|),setdiff(%0,grab(%0,%1%b*,|),|,|)))
&GLOB`CAPSTR_ALL Item System=iter(%0,capstr(lcstr(%i0)))
&GLOB`DEFEXTR Item System=localize(if(t(setr(0,extract(%0,%1,%2,%3))),%q0,%4))
&GLOB`ISPOS Item System=gt(%0,0)
&GLOB`PLURAL Item System=if(gt(%0,1),%1s)
&GLOB`VOWEL Item System=t(match(A E I O U,left(%0,1)))
@startup Item System=@dol [lattr(me/GLOB`*)]=@function [after(##,GLOB`)]=me,##
&1_General Item Database=Food
@tel Item Database=Item System
@restart Item System
th [ansi(hg,Please drop Item System into the Master Room now\, please.)]
=========== This code is for rooms, to display items within the room.
[if(t(v(list`inventory)),[ansi(hw,Contents:)]%b[iter(v(list`inventory),<[extract(%i0,3,1)]x>%b[edit(first(%i0),_,%b)],|,%b-%b)]%r)]
An easy way to implement this, is to make a room parent (Or ancestor) with
@descformat #1111=%0%r%r[if(t(v(list`inventory)),[ansi(hw,Contents:)]%b[iter(v(list`inventory),<[extract(%i0,3,1)]x>%b[edit(first(%i0),_,%b)],|,%b-%b)]%r)]
where #1111 is the dbref of the room.

Click 
