DragonDice

Check-in [1d65c572e3]
Login

Check-in [1d65c572e3]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Commands to edit numeric character stats
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 1d65c572e32120fd6d2b91ec73f7f3254949cbb229d88b3c9ba755355428a864
User & Date: murphy 2020-04-28 22:25:33.000
Context
2020-04-28
22:30
Corrected spelling mistake in XML deserialization of CustomStatLayer check-in: 2099052886 user: murphy tags: trunk
22:25
Commands to edit numeric character stats check-in: 1d65c572e3 user: murphy tags: trunk
21:03
Commands to edit language proficiencies check-in: 20c845ae6a user: murphy tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to DragonDice.Bot/Session.fs.
79
80
81
82
83
84
85






















86
87
88
89
90
91
92
        { check with Inspiration = max check.Inspiration (int it.Groups.[1].Value) }
      else
        match Modality.tryParse s with
        | Some m ->
          { check with Modality = Modality.combine check.Modality m }
        | None ->
          failwith "Invalid ability check option"






















    
  static let userMarkup (user:User) =
    let buffer = Text.StringBuilder("<a href=\"tg://user?id=").Append(user.Id).Append("\">")
    if not (String.IsNullOrEmpty user.FirstName) then
      buffer.Append(user.FirstName) |> ignore
      if not (String.IsNullOrEmpty user.LastName) then
        buffer.Append(' ').Append(user.LastName) |> ignore







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
        { check with Inspiration = max check.Inspiration (int it.Groups.[1].Value) }
      else
        match Modality.tryParse s with
        | Some m ->
          { check with Modality = Modality.combine check.Modality m }
        | None ->
          failwith "Invalid ability check option"

  static let AssignmentPattern = Regex(@"^(.+?)\s+([-+]?=)\s+(\d+)$", RegexOptions.CultureInvariant)
  static let (|Assignment|_|) s =
    let it = AssignmentPattern.Match(s)
    if it.Success then
      Some (it.Groups.[1].Value.ToLowerInvariant(), it.Groups.[2].Value.[0], it.Groups.[3].Value)
    else
      None

  static let AssignmentWithUnitPattern = Regex(@"^(.+?)\s+([-+]?=)\s+(\d+)\s+(.+)$", RegexOptions.CultureInvariant)
  static let (|AssignmentWithUnit|_|) s =
    let it = AssignmentWithUnitPattern.Match(s)
    if it.Success then
      Some (it.Groups.[1].Value.ToLowerInvariant(), it.Groups.[2].Value.[0], it.Groups.[3].Value, it.Groups.[4].Value.ToLowerInvariant())
    else
      None
            
  static let (|Speed|_|) s =
    Speed.tryParse s
          
  static let (|Sense|_|) s =
    Sense.tryParse s
    
  static let userMarkup (user:User) =
    let buffer = Text.StringBuilder("<a href=\"tg://user?id=").Append(user.Id).Append("\">")
    if not (String.IsNullOrEmpty user.FirstName) then
      buffer.Append(user.FirstName) |> ignore
      if not (String.IsNullOrEmpty user.LastName) then
        buffer.Append(' ').Append(user.LastName) |> ignore
189
190
191
192
193
194
195

196
197

198
199




200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
The <i>GP</i> argument to the currency management commands may be an amount suffixed with <i>cp</i>, <i>sp</i>, <i>ep</i>, <i>gp</i>, or <i>pp</i>.

<b>Character Design:</b>
/create [<i>NAME</i>] — Create a new character and select it for the user who is asking.
/open5e <i>QUERY</i> — Import a new character from Open5e and select it for the user who is asking.
/setname <i>NAME</i> — Change the name of the active character.
/setrace <i>RACE</i> — Change the race of the active character. This operation does not work on imported characters.

/adddefense <i>DAMAGE</i>, <i>DEFENSE</i> — Add a defense against <i>DAMAGE</i> for the active character. <i>DEFENSE</i> may be a numerical factor or one of the adjectives <i>Normal</i>, <i>Immune</i>, <i>Invulnerable</i>, <i>Resistant</i>, <i>Vulnerable</i>.
/removedefense <i>DAMAGE</i> — Remove the defense against <i>DAMAGE</i> for the active character.

/addproficiency <i>SKILL</i> [, <i>N</i>] — Add a proficiency in the given skill, optionally with a multiplier, to the active character. This operation does not work on imported characters.
/removeproficiency <i>SKILL</i> — Remove the proficiency in the given skill from the active character. This operation does not work on imported characters.




/addlanguage <i>NAME</i> — Add a language proficiency to the active character.
/removelanguage <i>NAME</i> — Remove a language proficiency from the active character.
/set <i>V</i> =|+=|-= <i>N</i>, ... — Change the value of numerical variables <i>V</i> ... of the active character.

<b>Numerical Variables:</b>
AC — The armor class of the character.
HP — The maximum hit points of the character.
<i>SPEED</i> — Any movement speed of the character.
<i>ABILITY</i> — Any ability score of the character.
<i>SKILL</i> — Any skill proficiency modifier of the character.
<i>SENSE</i> — Any perception sense of the character.

<b>Character Storage:</b>
/save — Save the active character.
/reload <i>NAME</i> — Reload the active character. To confirm, the name must match.
/delete <i>NAME</i> — Delete the active character. To confirm, the name must match.
""",
          List.empty







>
|
|
>


>
>
>
>


<
<
<
<
<
<
<
<
<







211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229









230
231
232
233
234
235
236
The <i>GP</i> argument to the currency management commands may be an amount suffixed with <i>cp</i>, <i>sp</i>, <i>ep</i>, <i>gp</i>, or <i>pp</i>.

<b>Character Design:</b>
/create [<i>NAME</i>] — Create a new character and select it for the user who is asking.
/open5e <i>QUERY</i> — Import a new character from Open5e and select it for the user who is asking.
/setname <i>NAME</i> — Change the name of the active character.
/setrace <i>RACE</i> — Change the race of the active character. This operation does not work on imported characters.
/set ac =|+=|-= <i>N</i> — Change the armor class of the active character.
/set hp =|+=|-= <i>N</i> — Change the maximum hit points of the active character.
/set <i>SPEED</i> =|+=|-= <i>N</i> — Change a movement speed of the active character.
/set <i>ABILITY</i> =|+=|-= <i>N</i> — Change an ability score of the active character.
/addproficiency <i>SKILL</i> [, <i>N</i>] — Add a proficiency in the given skill, optionally with a multiplier, to the active character. This operation does not work on imported characters.
/removeproficiency <i>SKILL</i> — Remove the proficiency in the given skill from the active character. This operation does not work on imported characters.
/set <i>SKILL</i> =|+=|-= <i>N</i> — Change a skill proficiency modifier of the active character.
/adddefense <i>DAMAGE</i>, <i>DEFENSE</i> — Add a defense against <i>DAMAGE</i> for the active character. <i>DEFENSE</i> may be a numerical factor or one of the adjectives <i>Normal</i>, <i>Immune</i>, <i>Invulnerable</i>, <i>Resistant</i>, <i>Vulnerable</i>.
/removedefense <i>DAMAGE</i> — Remove the defense against <i>DAMAGE</i> for the active character.
/set <i>SENSE</i> =|+=|-= <i>N</i> — Change a perception sense range of the active character.
/addlanguage <i>NAME</i> — Add a language proficiency to the active character.
/removelanguage <i>NAME</i> — Remove a language proficiency from the active character.










<b>Character Storage:</b>
/save — Save the active character.
/reload <i>NAME</i> — Reload the active character. To confirm, the name must match.
/delete <i>NAME</i> — Delete the active character. To confirm, the name must match.
""",
          List.empty
832
833
834
835
836
837
838
839










































































































840
841
842
843
844
845
846
        let buffer = Text.StringBuilder("<i>").Append(HttpUtility.HtmlEncode chr.Name).Append("</i> : ")
        let pos = buffer.Append("Languages = ").Length
        for lang in chr.Languages do
          if buffer.Length > pos then buffer.Append(", ") |> ignore
          buffer.Append(HttpUtility.HtmlEncode lang) |> ignore
        if buffer.Length = pos then buffer.Append("None") |> ignore
        return Markup (buffer.ToString(), List.empty)
      










































































































      | ["/save"] ->
        let chr = selectedCharacter user
        chr.Save()
        return Markup (
          sprintf "<i>%s</i> : Saved for %s" (HttpUtility.HtmlEncode chr.Name) (userMarkup user),
          List.empty
        )







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
        let buffer = Text.StringBuilder("<i>").Append(HttpUtility.HtmlEncode chr.Name).Append("</i> : ")
        let pos = buffer.Append("Languages = ").Length
        for lang in chr.Languages do
          if buffer.Length > pos then buffer.Append(", ") |> ignore
          buffer.Append(HttpUtility.HtmlEncode lang) |> ignore
        if buffer.Length = pos then buffer.Append("None") |> ignore
        return Markup (buffer.ToString(), List.empty)

      | ["/set"; Assignment ("ac", op, v)] ->
        let chr = selectedCharacter user
        let v = int v
        chr.ArmorClass <-
          match op with
          | '+' -> max 0 (chr.ArmorClass + v)
          | '-' -> max 0 (chr.ArmorClass - v)
          | _   -> max 0 v
        return Markup (
          sprintf "<i>%s</i> : AC = %d" (HttpUtility.HtmlEncode chr.Name) chr.ArmorClass,
          List.empty
        )

      | ["/set"; Assignment ("hp", op, v)] ->
        let chr = selectedCharacter user
        let v = int v
        chr.MaxHitPoints <-
          match op with
          | '+' -> max 0 (chr.MaxHitPoints + v)
          | '-' -> max 0 (chr.MaxHitPoints - v)
          | _   -> max 0 v
        return Markup (
          sprintf "<i>%s</i> : HP = %d" (HttpUtility.HtmlEncode chr.Name) chr.MaxHitPoints,
          List.empty
        )

      | ["/set"; AssignmentWithUnit (Speed speed, op, v, ("ft" | "ft/rnd"))] ->
        let chr = selectedCharacter user
        let v = int v * 1<ft/rnd>
        chr.Speeds <-
          chr.Speeds.With(
            match op with
            | '+' -> [speed, max 0<ft/rnd> (chr.Speeds.[speed] + v)]
            | '-' -> [speed, max 0<ft/rnd> (chr.Speeds.[speed] - v)]
            | _   -> [speed, max 0<ft/rnd> v]
          )
        let buffer = Text.StringBuilder("<i>").Append(HttpUtility.HtmlEncode chr.Name).Append("</i> : ")
        let pos = buffer.Append("Speed = ").Length
        for KeyValue (speed, v) in chr.Speeds do
          if v > 0<ft/rnd> then
            if buffer.Length > pos then buffer.Append(", ") |> ignore
            buffer.Append(Speed.toString speed).Append(' ').Append(v).Append(" ft/rnd") |> ignore
        if buffer.Length = pos then buffer.Append("Immobile") |> ignore
        return Markup (buffer.ToString(), List.empty)

      | ["/set"; AssignmentWithUnit (Sense sense, op, v, "ft")] ->
        let chr = selectedCharacter user
        let v = int v * 1<ft>
        chr.Senses <-
          chr.Senses.With(
            match op with
            | '+' -> [sense, max 0<ft> (chr.Senses.[sense] + v)]
            | '-' -> [sense, max 0<ft> (chr.Senses.[sense] - v)]
            | _   -> [sense, max 0<ft> v]
          )
        let buffer = Text.StringBuilder("<i>").Append(HttpUtility.HtmlEncode chr.Name).Append("</i> : ")
        let pos = buffer.Append("Senses = ").Length
        for KeyValue (sense, v) in chr.Senses do
          if v > 0<ft> then
            if buffer.Length > pos then buffer.Append(", ") |> ignore
            buffer.Append(Sense.toString sense).Append(' ').Append(v).Append(" ft") |> ignore
        if buffer.Length = pos then buffer.Append("None") |> ignore
        return Markup (buffer.ToString(), List.empty)

      | ["/set"; Assignment (Skill skill, op, v)] ->
        let chr = selectedCharacter user
        let v = int v
        chr.Skills <-
          chr.Skills.With(
            match op with
            | '+' -> [skill, chr.Skills.[skill] + v]
            | '-' -> [skill, chr.Skills.[skill] - v]
            | _   -> [skill, v]
          )
        let buffer = Text.StringBuilder("<i>").Append(HttpUtility.HtmlEncode chr.Name).Append("</i> : ")
        let pos = buffer.Append("Skills = ").Length
        for KeyValue (skill, v) in chr.Skills do
          if v > 0 then
            let v = v + Ability.modifier chr.Abilities.[Skill.ability skill]
            if buffer.Length > pos then buffer.Append(", ") |> ignore
            buffer.Append(Skill.toString skill)
              .AppendFormat(CultureInfo.InvariantCulture, " {0:+0;-#}", v)
            |> ignore
        if buffer.Length = pos then buffer.Append("None") |> ignore
        return Markup (buffer.ToString(), List.empty)

      | ["/set"; Assignment (attr, op, v)] ->
        let chr = selectedCharacter user
        let attr = Ability.ofString attr
        let v = int v
        chr.Abilities <-
          chr.Abilities.With(
            match op with
            | '+' -> [attr, max 0 (chr.Abilities.[attr] + v)]
            | '-' -> [attr, max 0 (chr.Abilities.[attr] - v)]
            | _   -> [attr, max 0 v]
          )
        let buffer = Text.StringBuilder("<i>").Append(HttpUtility.HtmlEncode chr.Name).Append("</i> : ")
        let pos = buffer.Append("Abilities = ").Length
        for KeyValue (attr, v) in chr.Abilities do
          if buffer.Length > pos then buffer.Append(", ") |> ignore
          buffer.Append(Ability.toString attr)
            .AppendFormat(CultureInfo.InvariantCulture, " {0:D} ({1:+0;-#})", v, Ability.modifier v)
          |> ignore
        return Markup (buffer.ToString(), List.empty)

      | ["/save"] ->
        let chr = selectedCharacter user
        chr.Save()
        return Markup (
          sprintf "<i>%s</i> : Saved for %s" (HttpUtility.HtmlEncode chr.Name) (userMarkup user),
          List.empty
        )