Player
A Player is a data structure in the Neo World Program. It represents a player that can interact with the game world in a variety of ways.
There are two types of Players: full Players and NPCs. A full Player is associated with a Discord account, and can be controlled by that account. An NPC, short for non-player character, can do nearly everything a full Player can do, however it is not associated with a Discord account; it can only be controlled by a moderator.
It should be noted that when Player data is loaded, so too are Inventory Items. Inventory Items can be loaded without loading Player data, but not vice versa.
Attributes
In order to provide a wide array of functionality, Players have many attributes. Note that if an attribute is internal, that means it only exists within the Player class. Internal attributes will be given in the “Class attribute” bullet point, preceded by their data type. If an attribute is external, it only exists on the spreadsheet. External attributes will be given in the “Spreadsheet label” bullet point.
ID
- Spreadsheet label: Discord ID
- Class attribute: String
this.id
For full Players, this is the unique ID assigned to their Discord account. Developer Mode must be enabled in order to obtain this ID by right clicking on a Discord user and selecting Copy ID. When Player data is loaded, Alter Ego will fetch the guild member whose account has this ID. That Discord user will then be able to control this Player. Because Alter Ego requires guild member data, this account must belong to a Discord user in the server. If the user associated with a particular Player leaves the server, Alter Ego will be unable to load that Player’s data; they must either be removed from the spreadsheet, converted to an NPC, or reassigned a different ID.
Because NPCs aren’t associated with a Discord account, this attribute is repurposed for them. Instead of a Discord user
ID, this must be an image URL with a .png or .jpg file extension. This image will be used as the NPC’s avatar when
they speak; it will appear in Room, Whisper,
and spectate channels.
Member
- Class attribute: GuildMember
this.member
This is an internal attribute which contains a reference to the guild member whose Discord ID matches the Player ID. For
NPCs, this is null.
Name
- Spreadsheet label: Name
- Class attribute: String
this.name
This is the name of the Player. Because this is also used as the name of the Player’s spectate channel, it is subject to Discord’s limits on channel names. Only alphanumeric characters (A-Z, a-z, 0-9) and hyphens (-) are permitted; spaces, symbols, and punctuation are not. This should generally match the Player’s nickname on the server, although it doesn’t have to. For that reason, this should be 32 characters or fewer. This conventionally follows naming customs: the first letter is capitalized, and the rest is in lowercase. However, this is not a requirement.
Display Name
- Class attribute: String
this.displayName
This internal attribute is the string which Alter Ego uses to refer to the Player during most gameplay scenarios. It is
used instead of the name in Narrations, spectate channels, and more. The reason this is used is that unlike the
Player’s name, this can change during gameplay. It is automatically changed when the Player is inflicted with
a Status Effect that has the
concealed behavior attribute, and it can be manually changed with
the setdisplayname command.
When Player data is loaded, this is the same as the Player’s name. For that reason, moderators should be careful when
loading Player data during gameplay, as any Players with different display names will have their display names reset.
Display Icon
- Class attribute: String
this.displayIcon
This is an internal attribute which contains an image URL that will be used as an avatar when the Player uses
the say command, and when their dialog
appears in a spectate channel. It is also used when NPCs use
the whisper command. For full Players, this is most often null -
their display avatar is used
instead. Only NPCs have this set to a non-null value by default: the image URL in their ID. Much like the Player’s
display name, this can change during gameplay. It is automatically set
to this image when the
Player is inflicted with a Status Effect that has the concealed behavior attribute, and it can be manually changed
with
the setdisplayicon command.
However, it should be noted this will not replace a full Player’s avatar when they speak in a Room or Whisper
channel by sending a message to it; it will only appear in spectate channels when this is the case.
Talent
- Spreadsheet label: Talent
- Class attribute: String
this.talent
This is primarily a relic from older versions of Alter Ego which used this attribute to produce behavior that has since been re-implemented using Status Effect behavior attributes. For full Players, this can be left blank without issue. However, its main benefit is that it can be used as a variable in descriptions.
There is one programmed use case for this attribute. If this is set to NPC, then the Player will become an NPC. If the
Player has the NPC talent, then Alter Ego will not do anything to them that would require a Discord account, such as
sending them DMs, granting/revoking them permission to read channels, and adding/removing roles. NPC Players also will
not be counted in the online Player count, will not be inflicted with or cured of Status Effects when the “all” argument
is used in the status command, and will not be moved when the “all”
argument is used in the move command.
Pronoun String
- Spreadsheet label: Pronouns
- Class attribute: String
this.pronounString
This is a string which determines what set of third person
singular personal pronouns will be used to refer to the
Player by default. This must adhere to a strict format:
subjective/objective/dependent possessive/independent possessive/reflexive/plural, although there are shorthands for
the three most common pronoun sets:
maleis shorthand forhe/him/his/his/himself/false.femaleis shorthand forshe/her/her/hers/herself/false.neutralis shorthand forthey/them/their/theirs/themself/true.
There are several parts to this format. They are as follows:
- The subjective pronoun is used to refer to the Player as the subject of a verb. For example, “She speaks.”
- The objective pronoun is used to refer to the Player as an object of a verb. For example, “I saw him.”
- The dependent possessive pronoun is used to refer to the Player as the owner of something which is the object of the verb. For example, “That’s their room.”
- The independent possessive pronoun is used to refer to the Player as the owner of something which is the subject of the verb. For example, “The car is hers.”
- The reflexive pronoun is used to refer to the Player when they are the object of a verb where they are also the subject. For example, “They wash themself.”
- The plural variable determines whether this set of pronouns pluralizes verbs. If this is
true, then verbs will take the form they use with plural pronouns. For example, “They are here. They have money. They smell strange.” If this isfalse, then verbs will take the form they use with singular pronouns. For example, “He is here. She has money. It smells strange.”
As long as this format is followed, any set of pronouns can be used. For example, a Player who uses it pronouns would
have the pronoun string it/it/its/its/itself/false.
A Player cannot have more than one pronoun set at a time. For example, a Player who uses both he and they pronouns interchangeably can be referred to with he or they by Alter Ego, but not both. It cannot alternate between them at will. However, this is relatively minor, as Player pronouns are seldom used in built-in Narrations. Descriptions, custom Narrations, and dialog can all be written with alternating pronouns.
Original Pronouns
- Class attribute: object
this.originalPronouns
This internal attribute is an object containing variables that contain each of the Player’s default pronouns. This is primarily used in response messages in moderator commands and in log messages.
Please see the following class attribute for more info.
Pronouns
- Class attribute: object
this.pronouns
This internal attribute is an object containing variables that contain each of the Player’s current pronouns. This is
primarily what is used in Narrations. The reason this is used is that unlike the Player’s original pronouns, this can
change during gameplay. It is automatically changed to the neutral pronoun set when the Player is inflicted with a
Status Effect that has the concealed behavior attribute, and it can be manually changed with
the setpronouns command.
When Player data is loaded, this is the same as the Player’s original pronouns, right down to the structure. For that
reason, moderators should be careful when loading Player data during gameplay, as any Players with pronouns different
from their original pronouns will have their pronouns reset.
This, as well as the original pronouns attribute, has the following structure:
{ String sbj, String Sbj, String obj, String Obj, String dpos, String Dpos, String ipos, String Ipos, String ref, String Ref, Boolean plural }
This essentially groups what would be multiple class attributes into one. They are listed below:
Subjective
- Class attribute: String
this.pronouns.sbj
This is the Player’s subjective pronoun.
Capital Subjective
- Class attribute: String
this.pronouns.Sbj
This is the Player’s subjective pronoun, except the first letter is capitalized. This is useful at the beginning of a sentence when writing descriptions that use the Player’s pronouns as variables.
Objective
- Class attribute: String
this.pronouns.obj
This is the Player’s objective pronoun.
Capital Objective
- Class attribute: String
this.pronouns.Obj
This is the Player’s objective pronoun, except the first letter is capitalized.
Dependent Possessive
- Class attribute: String
this.pronouns.dpos
This is the Player’s dependent possessive pronoun.
Capital Dependent Possessive
- Class attribute: String
this.pronouns.Dpos
This is the Player’s dependent possessive pronoun, except the first letter is capitalized.
Independent Possessive
- Class attribute: String
this.pronouns.ipos
This is the Player’s independent possessive pronoun.
Capital Independent Possessive
- Class attribute: String
this.pronouns.Ipos
This is the Player’s independent possessive pronoun, except the first letter is capitalized.
Reflexive
- Class attribute: String
this.pronouns.ref
This is the Player’s reflexive pronoun.
Capital Reflexive
- Class attribute: String
this.pronouns.Ref
This is the Player’s reflexive pronoun, except the first letter is capitalized.
Plural
- Class attribute: Boolean
this.pronouns.plural
This is a Boolean value indicating whether this pronoun set pluralizes verbs.
Original Voice String
- Spreadsheet label: Voice
- Class attribute: String
this.originalVoiceString
This is a phrase that will be used in Narrations when the Player speaks while their identity is obscured in some way. All Narrations which use this are written with the assumption that this string will begin with “a” or “an” and end with “voice”. Here are some examples with the Player’s voice string in bold:
- You hear a bitter voice in the room say “…What are you looking at?”.
- You hear a brash voice from a nearby room shout “HEY! IS ANYONE IN THERE!?”.
- You overhear an individual wearing a PLAGUE DOCTOR MASK, with a crisp voice you recognize to be Kyra’s, whisper “Yes, everything is going according to plan.”.
- A deep modulated voice coming from Amy’s WALKIE TALKIE says “That is correct. I am hidden somewhere in this facility.”.
Voice String
- Class attribute: String
this.voiceString
This internal attribute contains the Player’s current voice descriptor. This is primarily what is used in Narrations.
The reason this is used is that unlike the Player’s original voice string, this can change during gameplay. It can be
manually changed with
the setvoice command. When Player
data is loaded, this is the same as the Player’s original voice string. For that reason, moderators should be careful
when loading Player data during gameplay, as any Players with a voice string different from their original voice string
will have their voice string reset. If the name of another Player, whether living or dead, is supplied, then the Player
will speak using that Player’s voice. This will even trick Players with the
knows [Player name] behavior attribute into recognizing this Player’s voice as the
mimicked Player.
Stats
- Spreadsheet label: Stats
This is an external attribute. It only exists to group the Player’s stats together under one label. A Player’s stats are used in a variety of situations. Common applications of all of them include their ability to be modified by Status Effects and their ability to be used as a modifier in Die rolls. Here, their individual properties and applications will be detailed below.
Default Strength
- Spreadsheet label: Str
- Class attribute: Number
this.defaultStrength
This is the Player’s default strength stat. This quantifies the Player’s physical strength. It must be a whole number from 1 - 10.
Strength
- Class attribute: Number
this.strength
This internal attribute is the Player’s current strength stat. By default, this equals their default strength, however it can be changed by Status Effects with stat modifiers.
This stat is used to calculate the Player’s maximum carry weight. This value is recalculated every time the Player’s strength stat changes. The formula to calculate the Player’s max carry weight in kilograms is quadratic, not linear. It is roughly based on the range of real human weightlifting capacities. The full formula, where \(x\) is the Player’s strength stat, is:
\[ W_{max} = 1.783x^2 - 2x + 22 \]
The result is rounded down to the nearest whole number.
In effect, each strength stat value corresponds with a predetermined max carry weight, as shown in this chart:
| Strength Value | Max Carry Weight (kg) | Max Carry Weight (lb) |
|---|---|---|
| 1 | 21 | 46 |
| 2 | 25 | 55 |
| 3 | 32 | 70 |
| 4 | 42 | 92 |
| 5 | 56 | 123 |
| 6 | 74 | 163 |
| 7 | 95 | 209 |
| 8 | 120 | 264 |
| 9 | 148 | 326 |
| 10 | 180 | 396 |
The strength stat also has special behavior in Die rolls. If a Die is rolled using this Player’s strength stat, the defender’s dexterity roll modifier will be multiplied by \(-1\) and added to the Die’s modifier. In effect, this factors in the defender’s ability to dodge the Player’s attack.
Default Intelligence
- Spreadsheet label: Int
- Class attribute: Number
this.defaultIntelligence
This is the Player’s default intelligence stat. This quantifies the Player’s logical intelligence. It must be a whole number from 1 - 10.
Intelligence
- Class attribute: Number
this.intelligence
This internal attribute is the Player’s current intelligence stat. By default, this equals their default intelligence, however it can be changed by Status Effects with stat modifiers.
This stat has no programmed use. However, it can be used in if conditionals when writing descriptions to affect what the Player sees when inspecting various things. For example, a Player with a high intelligence stat may receive more clues to assist in solving Puzzles and murders than a Player with a low intelligence stat. Whereas a Player with a low intelligence stat might see this:
It's a small compartment below the dartboard. Written on it is "Prime x Prime x Prime = 266". There doesn't seem to be any way to open it. Maybe it will open if you hit three prime numbers on the dartboard that multiply together to make 266.
A Player with an average intelligence stat might see this:
It's a small compartment below the dartboard. Written on it is "Prime x Prime x Prime = 266". There doesn't seem to be any way to open it. Maybe it will open if you hit three prime numbers on the dartboard that multiply together to make 266. If that's the case, then you know a prime number is a number whose only products are 1 and itself. You don't even have to try any of the double or triple point values, or 50 for that matter.
And a Player with a high intelligence stat might see this:
It's a small compartment below the dartboard. Written on it is "Prime x Prime x Prime = 266". There doesn't seem to be any way to open it. Maybe it will open if you hit three prime numbers on the dartboard that multiply together to make 266. If that's the case, then you know a prime number is a number whose only products are 1 and itself. You don't even have to try any of the double or triple point values, or 50 for that matter. The only prime numbers on this board would be 2, 3, 5, 7, 11, 13, 17, and 19. Better yet, 266 is an even number, so you know one of the products MUST be 2, and you only need to find the other two numbers. This should be easy.
It should be noted that because this stat has no programmed use, it doesn’t necessarily have to correlate with the Player’s logical intelligence. It could correlate with the Player’s perception, or anything else. How this stat is used is entirely up to the moderator’s discretion when writing descriptions.
Default Dexterity
- Spreadsheet label: Dex
- Class attribute: Number
this.defaultDexterity
This is the Player’s default dexterity stat. This quantifies the Player’s skill and speed when using their hands or body. It must be a whole number from 1 - 10.
Dexterity
- Class attribute: Number
this.dexterity
This internal attribute is the Player’s current dexterity stat. By default, this equals their default dexterity, however it can be changed by Status Effects with stat modifiers.
This stat is used to determine the Player’s probability of success when attempting to steal Inventory Items from another Player. When this occurs, a Die is rolled using this Player’s dexterity stat, with the victim as the defender. If the Player has a high dexterity stat, and thus a positive dexterity roll modifier, then they will be more likely to succeed when attempting to steal. If the Player has a low dexterity stat, and thus a negative dexterity roll modifier, then they will be more likely to fail when attempting to steal.
It also has special behavior in Die rolls. If a Die is rolled using a different Player’s strength stat where this Player
is the defender, this Player’s dexterity roll modifier will be multiplied by -1 and added to the Die’s modifier. In
effect, this factors in the Player’s ability to dodge the attacker’s attack. If the Player has a high dexterity stat,
the attacker will be more likely to have a low attack roll, and vice versa.
Default Speed
- Spreadsheet label: Spd
- Class attribute: Number
this.defaultSpeed
This is the Player’s default speed stat. This quantifies the Player’s walking and running speed. It must be a whole number from 1 - 10.
Speed
- Class attribute: Number
this.speed
This internal attribute is the Player’s current speed stat. By default, this equals their default speed, however it can be changed by Status Effects with stat modifiers.
This stat is used to calculate the amount of time it takes for the Player to travel from one Exit to another in a Room.
The flat distance in pixels between the Player’s current position and the desired Exit’s position is calculated using the distance formula with the two positions’ respective X and Z coordinates. The flat distance is then converted to meters by dividing this value by the pixelsPerMeter setting. The rise of the Exit’s position relative to the Player’s is calculated by subtracting the Player’s Y coordinate from the Exit’s and dividing the resulting value by the pixels per meter setting. The slope between the two positions is then calculated by dividing the rise in meters by the flat distance in meters.
Movement speed is roughly based on the range of real human movement speeds. For example, a Player with a speed stat of 10 would have a movement speed of 8.34 meters per second. This is slightly less than Usain Bolt’s top sprinting speed of 10.44 meters per second. The base formula to calculate a Player’s movement speed in meters per millisecond (m/ms) is quadratic, not linear. It is as follows:
\[ R = (0.0183(rx)^2 + 0.005rx + 0.916)w \]
In this formula are several variables:
- \(x\) is the Player’s speed stat.
- \(r\) is \(1\) if the Player is walking and \(2\) if the Player is running.
- \(w\) is a fraction which represents slowdown based on the combined weight of all of the Player’s Inventory Items. The formula to calculate this, where \(c\) is the Player’s carry weight, is \(w = \frac{15}{c}\). However, the calculated value is clamped between \( \frac{1}{4} \) and \(1\).
The final rate, \(R’\), in meters per millisecond (m/ms), is then calculated with the following formula, where \(R\) is the base rate and \(s\) is the slope:
\[ R’ = R - sR \]
The time it takes to move, \(t\), in seconds, is then calculated with the following formula, where \(d\) is the flat distance in meters and \(R’\) is the final rate in meters per millisecond:
\[ t = \frac{d}{R’} * 1000 \]
However, there is an alternative calculation method. If the flat distance between the Player’s position and the Exit’s position is \(0\), then the time it takes to move between them is calculated based on the assumption that the Player is in a stairwell consisting of two horizontally-flipped right triangles with legs of equal length vertically stacked on top of one another, like this diagram:

Here, the Player is marked by the bottom red line and the Exit is marked by the top red line. They have the same X and Z coordinates; only their Y coordinates differ. The distance, \(d\), in meters between the Player and the Exit is calculated by using the Pythagorean theorem to find the length of the hypotenuse for each triangle. In this formula, \(l\) represents the length of each leg, calculated by dividing the rise in meters by \(2\):
\[ d = 2 * \sqrt{2l^2} \]
Then, if the rise is positive, meaning the Player is moving upstairs, the Player’s base rate is multiplied by \( \frac{2}{3} \). If the rise is negative, meaning the Player is moving downstairs, the Player’s base rate is multiplied by \( \frac{4}{3} \). In effect, their rate is decreased when moving upstairs and increased when moving downstairs.
Finally, the time it takes to move in this scenario, \(t\), in seconds, is calculated with the following formula, where \(d\) is the recently determined distance in meters and \(R\) is the base rate (without accounting for slope) in meters per millisecond:
\[ t = \frac{d}{R} * 2 * 1000 \]
Default Stamina
- Spreadsheet label: Sta
- Class attribute: Number
this.defaultStamina
This is the Player’s default speed stat. This quantifies the Player’s physical endurance. It must be a whole number from 1 - 10.
Max Stamina
- Class attribute: Number
this.maxStamina
This internal attribute is the Player’s current maximum stamina stat. By default, this equals their default stamina, however it can be changed by Status Effects with stat modifiers.
This stat is used to determine how long the Player can walk or run before being inflicted with the weary Status
Effect. The higher this is, the longer the Player can move without resting.
Stamina
- Class attribute: Number
this.stamina
This internal attribute is the Player’s current stamina stat. By default, this equals their maximum stamina, however it changes as the Player moves and rests. Whenever the Player’s max stamina changes, so too does their stamina; the ratio of their current stamina to their max stamina is retained.
As the Player moves, their stamina stat decreases. Every 100 milliseconds, the amount of stamina the Player loses, \( L\), is calculated using the following formula:
\[ L = dm * (u + su) \]
In this formula are several variables:
- \(d\) is the flat distance in meters the Player has moved in the past 100 milliseconds.
- \(m\) is \(1\) if the Player is walking and \(3\) if the Player is running.
- \(u\) is the staminaUseRate setting.
- \(s\) is the slope of the Player’s movement, calculated by dividing the number of meters they’ve risen in meters by the flat distance in meters they’ve moved in the past 100 milliseconds.
However, there is an alternative calculation method. If the flat distance between the Player’s position and the Exit’s position is \(0\), then the time it takes to move between them is calculated based on the assumption that the Player is in a stairwell. If the rise is positive, meaning the Player is moving upstairs, the amount of stamina the Player loses is calculated like so:
\[ L = 4dmu \]
If the rise is negative, meaning the Player is moving downstairs, the amount of stamina the Player loses is calculated like so:
\[ L = -\frac{dmu}{4} \]
When the Player’s stamina dips below half of their max stamina, they will be sent a warning that they’re starting to get
tired. If it reaches \(0\), they will stop moving and be inflicted with the weary Status Effect.
When the Player is not moving, their stamina is gradually restored. Every 30 seconds, they recover \( \frac{1}{20} \) of their max stamina.
Alive
- Spreadsheet label: Alive?
- Class attribute: Boolean
this.alive
This indicates whether the player is alive or not. If this is true, then the Player is alive, and can interact with
the game world like normally. If this is false, then the Player is dead, and they cannot do anything. When a Player
dies, some of their data is lost. In particular, their location, hiding spot, and Status Effects will be lost. However,
they retain everything else, including their Inventory Items. However, because dead Players cannot be inspected or
interacted with, all of their data is inaccessible.
Location
- Spreadsheet label: Location
- Class attribute: Room
this.location
This is the Room that the Player is currently in. This must match the Room’s name exactly on the spreadsheet.
Position
- Class attribute: object
this.pos
This internal attribute is an object containing variables that contain each of the Player’s current coordinates. This is used to calculate the amount of time it will take for the Player to move to an Exit. When the Player is moving, their position is constantly updated. Every 100 milliseconds, the amount of time that has elapsed since the Player started moving is taken as a ratio of the total amount of time it will take to move to the desired Exit. Each of the Player’s starting coordinates is subtracted from the Exit’s corresponding coordinates, and the resulting value is multiplied by that ratio and rounded to the nearest whole number. Then, each of these values are added to the Player’s starting coordinates to determined the Player’s updated position. This effectively makes it so that if the Player stops moving, they won’t have to move the full distance if they decide to move to that Exit again.
When the Player enters a Room, their position is updated to match the position of the Exit they entered from. However, if the Player didn’t enter from a specific Exit, as would be the case when Player or Room data is loaded or when moving to a non-adjacent Room, their position is set to the average position of all Exits in the Room.
The Player’s position has the following structure:
{ Number x, Number y, Number z }
This essentially groups what would be multiple class attributes into one. They are listed below:
X
- Class attribute: Number
this.pos.x
This is the Player’s current X coordinate.
Y
- Class attribute: Number
this.pos.y
This is the Player’s current Y coordinate.
Z
- Class attribute: Number
this.pos.z
This is the Player’s current Z coordinate.
Hiding Spot
- Spreadsheet label: Hiding Spot
- Class attribute: String
this.hidingSpot
This is a string which contains the name of the Object the Player is currently hiding in. Since this is just a string, it can be set manually on the spreadsheet to anything, whether it’s the name of an Object in the Room or not. If the Player is not currently hidden, this should be left blank.
Status
- Class
attribute: Array<Status Effect>
this.status
This internal attribute contains a list of all instantiated Status Effects that the Player currently has. Every time a Status Effect is inflicted or cured, the Player’s stats are recalculated.
Status String
- Spreadsheet label: Status Effects
- Class attribute: String
this.statusString
This string is a comma-separated list of the names of all Status Effects that the Player currently has, including those that aren’t visible. If a Status Effect has a duration, it can be listed here by putting the duration in parentheses. The duration must follow a specific format:
(D) H:mm:ss
D stands for the number of 24-hour days remaining; it is optional. H stands for the number of hours remaining. mm
stands for the number of minutes remaining; leading zeroes are required. ss stands for the number of seconds
remaining; leading zeroes are required. For example, a Status Effect named famished with 2 days, 13 hours, 45 minutes,
and 11 seconds remaining would be listed as famished (2 13:45:11). A Status Effect named clean with 1 day, 4 hours,
9 minutes, and 7 seconds remaining would be listed as clean (1 4:09:07). A Status Effect named mortally wounded with
59 minutes remaining would be listed as mortally wounded (0:59:00).
It should be noted that when entering Status Effects on the spreadsheet manually, it isn’t necessary to include the duration. If the Status Effect has a limited duration, it will automatically have its duration listed on the spreadsheet when Alter Ego saves the game data. The Player’s status string is regenerated with updated durations every second of gameplay.
Description
- Spreadsheet label: Description
- Class attribute: String
this.description
This is the description of the Player. When another Player inspects this Player, they will receive a parsed version of this string. See the article on writing descriptions for more information.
Player descriptions have a few peculiarities that set them apart from other descriptions, mostly due to the complexity of Players. In this section, Player descriptions will be explained in full detail. The default Player description provided in the default playerdefaults file is:
<desc><s>You examine <var v="container.displayName" />.</s> <if cond="container.hasAttribute('concealed')"><s><var v="container.pronouns.Sbj" /> <if cond="container.pronouns.plural">are</if><if cond="!container.pronouns.plural">is</if> [HEIGHT], but <var v="container.pronouns.dpos" /> face is concealed.</s></if><if cond="!container.hasAttribute('concealed')"><s><var v="container.pronouns.Sbj" /><if cond="container.pronouns.plural">'re</if><if cond="!container.pronouns.plural">'s</if> [HEIGHT] with [SKIN TONE], [HAIR], and [EYES].</s></if> <s><var v="container.pronouns.Sbj" /> wear<if cond="!container.pronouns.plural">s</if> <il name="equipment"><item>a SHIRT</item>, <item>a pair of PANTS</item>, and <item>a pair of TENNIS SHOES</item></il>.</s> <s>You see <var v="container.pronouns.obj" /> carrying <il name="hands"></il>.</s></desc>
This description always refers to the Player with the correct name and pronouns according to the situation, and it does
so by making use of the Player’s class attributes with if and var tags. However, unlike descriptions of other data
structures, the class attributes of the Player being described are not being accessed with the typical this keyword.
Instead, they are accessed by the container keyword. This is done so that the Player can view their own description
when inspecting a MIRROR Object, for example. Because
the parser module replaces the this keyword
in evaluated expressions
with container, the name of the variable referring to the data structure being described, and because the container
variable when a Player inspects a mirror is the MIRROR Object itself, the this keyword cannot be used in Player
descriptions while allowing for this functionality. Instead, the container keyword must be used, and a MIRROR Object
cannot simply use the Player’s description in a variable tag without modifications. It must replace all instances of the
container keyword with the player keyword, which describes the Player inspecting the MIRROR Object, like so:
<desc><s>You look at your reflection in the mirror.</s> <var v="player.description.replace(/container./g, 'player.')" /></desc>
Within the desc tags of the Player’s description, there are five sections:
-
<s>You examine <var v="container.displayName" />.</s>- This refers to the Player by their current display name. This should never be changed.
-
<if cond="container.hasAttribute('concealed')"><s><var v="container.pronouns.Sbj" /> <if cond="container.pronouns.plural">are</if><if cond="!container.pronouns.plural">is</if> [HEIGHT], but <var v="container.pronouns.dpos" /> face is concealed.</s></if>- This section describes the Player with very little detail in order to avoid revealing their identity when they
have the
concealedbehavior attribute. - The
concealedbehavior attribute automatically changes the Player’s pronouns to theneutralset. Consequently, this section could be written as<if cond="container.hasAttribute('concealed')"><s>They are [HEIGHT], but their face is concealed.</s></if>for simplicity’s sake. However, doing so removes the possibility of using the setpronouns command after the Player is inflicted with theconcealedbehavior attribute. It can still be used, but the new pronouns will not be reflected in the Player’s description.
- This section describes the Player with very little detail in order to avoid revealing their identity when they
have the
-
<if cond="!container.hasAttribute('concealed')"><s><var v="container.pronouns.Sbj" /><if cond="container.pronouns.plural">'re</if><if cond="!container.pronouns.plural">'s</if> [HEIGHT] with [SKIN TONE], [HAIR], and [EYES].</s></if>- This section describes the Player in more detail. It’s used when the Player doesn’t have the
concealedbehavior attribute. - Because the Player’s pronouns do not automatically change unless they are inflicted with the
concealedbehavior attribute, this section could be written without making use of the Player’s pronouns invartags. Instead, the Player’s pronouns could be written as plain text. This would allow a Player who uses multiple pronouns interchangeably to be referred to with alternating pronouns, for example. However, this would hamper the use of the setpronouns command for the Player unless additional logic checking is added. - In this section, the Player can be described in much more detail than the default description allows for, and detail can be added throughout the course of the game if the Player’s appearance changes in significant ways. However, Player descriptions should ideally be kept as short as possible so as to not overwhelm Players with too much irrelevant information.
- An example of this section that makes use of static pronouns, extra detail, and extra conditionals, might look like
this:
<if cond="!container.hasAttribute('concealed')"><s>It's a fairly young individual of average height with very pale skin.</s> <s>He's quite scrawny and frail-looking, with a very small chest.</s> <s>She has black eyes and short, red hair with bangs falling a little into her face and shoulder-length fringes on both sides, with the rest of its hair <if cond="findInventoryItem('BLAKES RIBBONS', container.name, '', 'HAT') !== undefined">done up in two buns held together with a pair of black ribbons</if><if cond="findInventoryItem('BLAKES RIBBONS', container.name, '', 'HAT') === undefined">coming down to about the shoulders</if>.</s> <s>He looks easy enough to get along with, if a little nervous.</s></if>
- This section describes the Player in more detail. It’s used when the Player doesn’t have the
-
<s><var v="container.pronouns.Sbj" /> wear<if cond="!container.pronouns.plural">s</if> <il name="equipment"><item>a SHIRT</item>, <item>a pair of PANTS</item>, and <item>a pair of TENNIS SHOES</item></il>.</s>- This sentence lists all Inventory Items that the Player currently has equipped, except for those equipped to their “RIGHT HAND” and “LEFT HAND” Equipment Slots and those whose Equipment Slot is covered by another equipped Inventory Item.
- If the Player’s equipped Inventory Items are manually changed on the spreadsheet, the contents of the
iltag must be manually updated with the single containing phrases of the respective Inventory Items initemtags. - If nothing is listed in the
iltag, this sentence will not appear in the parsed description. - Because this sentence appears regardless of whether or not the Player has the
concealedbehavior attribute,vartags should be used to reference the Player’s pronouns. They should not be replaced with static pronouns.
-
<s>You see <var v="container.pronouns.obj" /> carrying <il name="hands"></il>.</s>- This sentence lists all non-discreet Inventory Items that the Player currently has equipped to their “RIGHT HAND” or “LEFT HAND” Equipment Slots.
- If the Player’s held Inventory Items are manually changed on the spreadsheet, the contents of the
iltag must be manually updated with the single containing phrases of the respective Inventory Items initemtags. - If nothing is listed in the
iltag, this sentence will not appear in the parsed description. - Because this sentence appears regardless of whether or not the Player has the
concealedbehavior attribute,vartags should be used to reference the Player’s pronouns. They should not be replaced with static pronouns.
Additional information can be added to the Player’s description as needed. However, when doing so, precautions should be
taken to ensure that it does not conflict with the effects of the concealed behavior attribute. If additional sections
are added, they generally must use var tags to reference the Player’s pronouns. A full example of a Player description
with additional detail that makes use of static pronouns where possible might look like this:
<desc><s>You examine <var v="container.displayName"/>.</s> <if cond="container.hasAttribute('concealed')"><s>They are somewhat tall, but their face is concealed.</s></if><if cond="!container.hasAttribute('concealed')"><s>She's somewhat tall and has a pale complexion.</s> <s>She has long, creamsicle-orange hair with bangs in the middle.</s> <s>She has brown eyes and light brown eyebrows.</s> <s>She has a near-permanent smile, giving you the impression that she's very friendly - perhaps even a bit *too* friendly.</s> <s>She's somewhat thin with a very large chest.</s> <s>All of her fingernails are painted black.</s></if> <s><var v="container.pronouns.Sbj"/> wear<if cond="!container.pronouns.plural">s</if> <il name="equipment"><item>a BLACK HAIRBAND</item>, <item>a WHITE DRESS SHIRT</item>, <item>a BLACK TIE</item>, <item>a BLACK SUIT JACKET</item>, <item>a BLACK PENCIL SKIRT</item>, <item>a set of PANTYHOSE</item>, and <item>a pair of BLACK PUMPS</item></il>.</s> <s>You see <var v="container.pronouns.obj"/> carrying <il name="hands"></il>.</s> <if cond="container.statusString.includes('stinky')"><s><var v="container.pronouns.Sbj"/>'<if cond="container.pronouns.plural">re</if><if cond="!container.pronouns.plural">s</if> a little stinky.</s></if><if cond="container.statusString.includes('rancid')"><s><var v="container.pronouns.Sbj"/> smell<if cond="!container.pronouns.plural">s</if> absolutely **rancid**.</s></if></desc>
Inventory
- Class
attribute: Array<Equipment Slot>
this.inventory
This internal attribute is a list of Equipment Slots that the Player has. See the article on Equipment Slots for more information.
Spectate Channel
- Class attribute: TextChannel
this.spectateChannel
This is an internal attribute. When Player data is loaded, Alter Ego will attempt to find the channel in
the Spectate category whose name matches the name of the Player. If
it is not found, it will create one with that Player’s name. It will not do this if there are already 50 spectate
channels in the Spectate category, however. It also will not attempt to find or create spectate channels for NPCs. In
both scenarios, this is null.
A spectate channel replicates the experience of being this Player. Everything the Player sees, including descriptions, Narrations, dialog, and more, is sent to this channel in chronological order. Here, spectators and dead Players can watch the game happen in real time, or read it at any point in the future, even after the game has concluded.
There are some things that do not appear in spectate channels, however. Out-Of-Character (OOC) messages - messages that
begin with ( - are not sent, as
the dialogHandler module does not count
these as dialog. The Player’s commands are also not sent, nor are error messages about command syntax. When the Player
uses the status command, their status will not appear in their spectate
channel.
Max Carry Weight
- Class attribute: Number
this.maxCarryWeight
This internal attribute is the maximum weight the Player can currently carry in kilograms. How it is calculated is described in more detail in the strength stat section. If the Player attempts to take an Item that is heavier than this number, they will be told it is too heavy to lift, and if the Item is non-discreet, their attempt to take it will be Narrated in the Room channel. Likewise, if they attempt to take an Item that would make their current carry weight exceed this value, they will be told that they’re carrying too much weight; however, this will not be Narrated. The same happens if another Player attempts to give this Player an Inventory Item that would exceed this value. If the Player uses the dress command, they will be unable to dress themself in any Items that would exceed this value, although they will not be notified of it.
Carry Weight
- Class attribute: Number
this.carryWeight
This internal attribute is the combined weight of all of the Player’s Inventory Items. This is updated every time the Player’s inventory changes. This is used to determine how much slower the Player will be when moving.
Row
- Class attribute: Number
this.row
This is an internal attribute, but it can also be found on the spreadsheet. This is the row number of the Player.
Is Moving
- Class attribute: Boolean
this.isMoving
This internal attribute indicates whether the Player is currently in the process of moving or not. If this is true,
then they are currently moving. If this is false, then they are resting.
It should be noted that the Player can be forcibly stopped from moving in many ways. If Player data is reloaded,
if edit mode is enabled, if the Player is inflicted with a Status Effect with the
disable all, disable move, or
disable run behavior attributes, if the Player is forcibly moved using moderator or bot commands, or if the Player
dies, they will stop moving, and all class attributes associated with movement will be reset.
Move Timer
- Class attribute: Number
this.moveTimer
This internal attribute uses the setInterval method to
handle the Player’s movement. Every 100 milliseconds, 100 milliseconds are subtracted from the
Player’s remaining time, and the Player’s position and stamina are updated. However, if at
least one Player in the game has the “heated” Status Effect, the amount of milliseconds subtracted from the Player’s
remaining time is first multiplied by
the heatedSlowdownRate setting, effectively making the Player
move more slowly. If the Player stops moving for any reason,
the clearInterval method is used on this so that the
Player’s movement will no longer continue. When Player data is loaded, this is null.
Remaining Time
- Class attribute: Number
this.remainingTime
This internal attribute is the number of milliseconds remaining until the Player is done moving to the Exit they’re
currently moving to. If the Player stops moving for any reason, this is set to 0.
Move Queue
This internal attribute is a list of all movements the Player wishes to make in sequential order. When the Player uses the move command or run command, the Exits they supply as arguments are inserted into this list. Each one is parsed, and if the desired Exit is found, the Player begins moving to that Exit. When they reach the next Room, the next entry in the queue is parsed and the cycle continues until the Player reaches the final destination. However, if any entry in the queue is an invalid destination or they attempt to enter a locked Exit, the Player is notified of their mistake, they stop moving, and the queue is emptied.
This class attribute is unused if the Player is moved with the moderator or bot command, because those commands move the Player instantaneously. As such, NPCs cannot have queued movements.
Reached Half Stamina
- Class attribute: Boolean
this.reachedHalfStamina
This internal attribute indicates whether or not the Player has depleted half of their stamina while moving. When the
Player’s stamina first dips below half of their maximum stamina, they will be warned that they’re starting to become
tired, and this is set to true. Once this is true, the warning message is not sent again until Player data is
reloaded, where it is set to false by default.
Interval
- Class attribute: Number
this.interval
This internal attribute uses the setInterval method to handle stamina regeneration. Every 30 seconds, Alter Ego checks if the Player is moving. If they aren’t, and if their current stamina is less than their max stamina, they recover 1/20th of their max stamina.
Online
- Class attribute: Boolean
this.online
This internal attribute determines whether or not the Player is included in the count of online Players in Alter
Ego’s status message. If this is true, then the
Player is counted. If this is false, then they are not. A Player is set as online whenever they use a command or speak
in-game. NPCs are never considered online.
Online Interval
- Class attribute: Number
this.onlineInterval
This internal attribute uses the setTimeout method to
count down until the Player is no longer considered online. Every time the Player is set as online, the online interval
is reset using the clearTimeout method and then
restarted from the beginning. If the timer reaches 0, then the Player is set as offline. This takes 15 minutes. When
Player data is loaded, this is null.