-
Notifications
You must be signed in to change notification settings - Fork 0
/
mapobject.go
2109 lines (1898 loc) · 66.1 KB
/
mapobject.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
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
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
\
########################################################################################
# __ #
# /__ _ #
# \_|(_) #
# _______ _______ _______ _______ _______ _______ __ #
# ( ____ \( )( ___ ) Game ( ____ \ / ___ )( __ ) / \ #
# | ( \/| () () || ( ) | Master's | ( \/ \/ ) || ( ) | \/) ) #
# | | | || || || (___) | Assistant | (____ / )| | / | | | #
# | | ____ | |(_)| || ___ | (Go Port) (_____ \ _/ / | (/ /) | | | #
# | | \_ )| | | || ( ) | ) ) / _/ | / | | | | #
# | (___) || ) ( || ) ( | Mapper /\____) ) _ ( (__/\| (__) | _ __) (_ #
# (_______)|/ \||/ \| Client \______/ (_)\_______/(_______)(_) \____/ #
# #
########################################################################################
*/
//
// MapObject describes the elements that may appear on the map.
//
package mapper
import (
"bufio"
"encoding/json"
"errors"
"fmt"
"io"
"os"
"regexp"
"sort"
"strconv"
"strings"
"time"
"github.com/MadScienceZone/go-gma/v5/tcllist"
)
//
// GMAMapperFileFormat gives
// the GMA File Format version number current as of this build.
// This is the format which will be used for saving map data.
//
const GMAMapperFileFormat = 23 // @@##@@ auto-configured
//
// MinimumSupportedMapFileFormat gives the lowest file format this package can
// understand.
//
const MinimumSupportedMapFileFormat = 17
//
// MaximumSupportedMapFileFormat gives the highest file format this package
// can understand. Saved data will be in this format.
//
const MaximumSupportedMapFileFormat = 23
// ErrCreatureNoSizes is the error returned when a creature size code is expected but none given.
var ErrCreatureNoSizes = errors.New("missing creature size code")
// ErrCreatureInvalidSize is the error returned when a creature size code is expected but the code(s) given are invalid.
var ErrCreatureInvalidSize = errors.New("invalid creature size code")
func init() {
if MinimumSupportedMapFileFormat > GMAMapperFileFormat || MaximumSupportedMapFileFormat < GMAMapperFileFormat {
if MinimumSupportedMapFileFormat == MaximumSupportedMapFileFormat {
panic(fmt.Sprintf("BUILD ERROR: This version of mapper only supports file format %v, but version %v was the official one when this package was released!", MinimumSupportedMapFileFormat, GMAMapperFileFormat))
} else {
panic(fmt.Sprintf("BUILD ERROR: This version of mapper only supports mapper file formats %v-%v, but version %v was the official one when this package was released!", MinimumSupportedMapFileFormat, MaximumSupportedMapFileFormat, GMAMapperFileFormat))
}
}
}
// ___ _ _ _ _ __ __ ___
// | __| \| | | | | \/ / __|
// | _|| .` | |_| | |\/| \__ \
// |___|_|\_|\___/|_| |_|___/
//
// The following definitions provide a mapping between the
// text expression of the enum values as used in our save
// file format and online protocol messages, and the internal
// numeric codes used here.
//
//
// These are the allowed values for the Dash attribute of a MapElement.
//
type DashType byte
const (
DashSolid DashType = iota
DashLong
DashMedium
DashShort
DashLongShort
DashLong2Short
)
//
// These are the allowed values for the ArcMode attribute of an ArcElement.
//
type ArcModeType byte
const (
ArcModePieSlice ArcModeType = iota
ArcModeArc
ArcModeChord
)
//
// Valid values for a line's Arrow attribute.
//
type ArrowType byte
const (
ArrowNone ArrowType = iota
ArrowFirst
ArrowLast
ArrowBoth
)
//
// These are the allowed values for the Join attribute of a PolygonElement.
//
type JoinStyle byte
const (
JoinBevel JoinStyle = iota
JoinMiter
JoinRound
)
//
// These are the valid values for the AoEShape attribute.
//
type AoEType byte
const (
AoEShapeCone AoEType = iota
AoEShapeRadius
AoEShapeRay
)
//
// The valid font weights.
//
type FontWeightType byte
const (
FontWeightNormal FontWeightType = iota
FontWeightBold
)
//
// The valid font slants.
//
type FontSlantType byte
const (
FontSlantRoman FontSlantType = iota
FontSlantItalic
)
//
// The valid values for the Anchor attribute of a TextElement.
//
type AnchorDirection byte
const (
AnchorCenter AnchorDirection = iota
AnchorNorth
AnchorSouth
AnchorEast
AnchorWest
AnchorNE
AnchorNW
AnchorSW
AnchorSE
)
//
// The valid values for a creature's MoveMode attribute.
//
type MoveModeType byte
const (
MoveModeLand MoveModeType = iota
MoveModeBurrow
MoveModeClimb
MoveModeFly
MoveModeSwim
)
/* XXX
//
// This returns the underlying Go data type
// for attribute values as a string. If the boolean
// is false, then we don't know what the attribute is
// (so will treat it as a string)
//
func enumToByte(attrName, value string) (evalue byte, ok bool) {
switch attrName {
case "AOESHAPE":
evalue, ok = enumAoeShapes[value]
case "ANCHOR":
evalue, ok = enumAnchors[value]
case "ARCMODE":
evalue, ok = enumArcs[value]
case "ARROW":
evalue, ok = enumArrows[value]
case "DASH":
evalue, ok = enumDashes[value]
case "MOVEMODE":
evalue, ok = enumMoveModes[value]
case "JOIN":
evalue, ok = enumJoins[value]
default:
evalue, ok = 0, false
}
return
}
*/
/* XXX
//
// This returns a string describing the expected data type
// of a MapObject's attribute.
//
func attributeType(attrName string) (string, bool) {
switch attrName {
case "AOE":
return "*RadiusAoE", true
case "AOESHAPE", "ANCHOR", "ARCMODE", "ARROW", "DASH", "MOVEMODE", "JOIN":
return "enum", true
case "POINTS":
return "[]Coordinates", true
case "HEALTH":
return "*CreatureHealth", true
case "SKINSIZE", "STATUSLIST":
return "[]string", true
case "BBHEIGHT", "BBWIDTH", "EXTENT", "GX", "GY", "START", "X", "Y":
return "float64", true
case "DIM", "HIDDEN", "KILLED", "LOCKED", "REACH":
return "bool", true
case "ELEV", "LEVEL", "SKIN", "SPLINE", "WIDTH", "Z":
return "int", true
case "AREA", "COLOR", "FILL", "GROUP", "IMAGE", "LAYER", "LINE", "NAME", "NOTE", "SIZE", "TEXT", "TYPE":
return "string", true
case "FONT":
return "TextFont", true
}
return "string", false
}
*/
//________________________________________________________________________________
// __ __ ___ _ _ _
// | \/ | __ _ _ __ / _ \| |__ (_) ___ ___| |_
// | |\/| |/ _` | '_ \| | | | '_ \| |/ _ \/ __| __|
// | | | | (_| | |_) | |_| | |_) | | __/ (__| |_
// |_| |_|\__,_| .__/ \___/|_.__// |\___|\___|\__|
// |_| |__/
//
// MapObject is anything the map server or client tracks and manages.
// These are generally things that are displayed on-screen such as map features,
// creature tokens, etc.
//
type MapObject interface {
ObjID() string
}
//
// Coordinates give an (x, y) coordinate pair to locate something on the map.
// Coordinates are in standard map pixel units (10 pixels = 1 foot).
//
type Coordinates struct {
X, Y float64
}
//
// MapObject
// BaseMapObject
// MapElement
// objMapElement
// ArcElement
// objArcElement
// CircleElement
// objCircleElement
// LineElement
// objLineElement
// PolygonElement
// objPolygonElement
// RectangleElement
// objRectangleElement
// SpellAreaOfEffect
// objSpellAreaOfEffect
// (TextFont)
// objTextFont
// TextElement
// objTextElement
// TileElement
// objTileElement
// CreatureToken
// objCreature
// PlayerToken
// objPlayer
// MonsterToken
// objMonster
// (CreatureHealth)
// objHealth
// newHealth
// (RadiusAoE)
// objAoEShape
// ImageDefinition
// FileDefinition
//
//
// BaseMapObject holds attributes all MapObjects have in common, so they will import
// BaseMapObject into their definitions by composition.
//
type BaseMapObject struct {
// Unique object identifier. May be any string
// consisting of upper- or lower-case letters, digits, '_', and "#"
// characters.
//
// By convention, we create these from a UUID expressed in
// hex without punctuation. Local conventions may also be
// used, such as PC character tokens using ID strings such as
// "PC1", "PC2", etc.
ID string
}
//
// ObjID returns the unique ID of a MapObject.
// Each type must have one of these methods to satisfy the MapObject
// interface.
//
func (o BaseMapObject) ObjID() string {
return o.ID
}
//________________________________________________________________________________
// __ __ _____ _ _
// | \/ | __ _ _ __ | ____| | ___ _ __ ___ ___ _ __ | |_
// | |\/| |/ _` | '_ \| _| | |/ _ \ '_ ` _ \ / _ \ '_ \| __|
// | | | | (_| | |_) | |___| | __/ | | | | | __/ | | | |_
// |_| |_|\__,_| .__/|_____|_|\___|_| |_| |_|\___|_| |_|\__|
// |_|
//
// MapElement is a MapObject which represents a static map feature
// to be displayed.
//
// Each MapElement has at least one pair of (x, y) coordinates which
// locate the element's "reference point" on the map. What this means
// is up to each different kind of MapElement.
//
type MapElement struct {
BaseMapObject
Coordinates
// Is this element currently concealed from view?
Hidden bool `json:",omitempty"`
// Is the object locked from editing by the user?
Locked bool `json:",omitempty"`
// The element's line(s) are to be drawn with this dash pattern.
Dash DashType `json:",omitempty"`
// The z "coordinate" is the vertical stacking order relative to the other
// displayed on-screen objects.
Z int
// The width in pixel units to draw the element's outline.
Width int `json:",omitempty"`
// The dungeon level where this element appears. Typically, level 0
// is the default (ground) level, with level numbers increasing as
// 1, 2, 3, etc., for floors above it, and with underground levels
Level int `json:",omitempty"`
// Objects which need additional coordinate pairs to describe their
// geometry (beyond the standard reference point) store them here.
Points []Coordinates `json:",omitempty"`
// The colors used to draw the element's outline and/or to fill it's interior.
// These may be standard color names such as "blue" or an RGB string such as
// "#336699". A fill color that is the empty string means not to fill that element.
// If Stipple is nonempty, it specifies that the shape should be filled with
// a stipple pattern. Pattern names "gray12", "gray25", "gray50", and "gray75"
// should be available by default in clients.
Line string `json:",omitempty"`
Fill string `json:",omitempty"`
Stipple string `json:",omitempty"`
// The map layer this element belongs to.
Layer string `json:",omitempty"`
// Elements may be arranged into logical groups to be manipulated
// together. This is the ID of the group to which this belongs, or
// is empty if this element is not grouped.
Group string `json:",omitempty"`
}
//________________________________________________________________________________
// _ _____ _ _
// / \ _ __ ___| ____| | ___ _ __ ___ ___ _ __ | |_
// / _ \ | '__/ __| _| | |/ _ \ '_ ` _ \ / _ \ '_ \| __|
// / ___ \| | | (__| |___| | __/ | | | | | __/ | | | |_
// /_/ \_\_| \___|_____|_|\___|_| |_| |_|\___|_| |_|\__|
//
// ArcElement is a MapElement that draws an arc on-screen.
// The arc is defined as a portion of a circle which is inscribed
// within the rectangle formed by the reference point and the single
// additional point in its Points attribute.
//
// Start and Extent specify the portion of that circle to include
// in the arc, measured in degrees.
//
// ArcMode defines how to draw the arc: it may be an arc (curve along
// the circle's permieter without connecting the endpoints), chord
// (the endpoints connected to each other with a straight line), or
// a pieslice (endpoints connected to the center of the circle with
// straight lines).
//
type ArcElement struct {
MapElement
ArcMode ArcModeType
Start float64
Extent float64
}
//________________________________________________________________________________
// ____ _ _ _____ _ _
// / ___(_)_ __ ___| | ___| ____| | ___ _ __ ___ ___ _ __ | |_
// | | | | '__/ __| |/ _ \ _| | |/ _ \ '_ ` _ \ / _ \ '_ \| __|
// | |___| | | | (__| | __/ |___| | __/ | | | | | __/ | | | |_
// \____|_|_| \___|_|\___|_____|_|\___|_| |_| |_|\___|_| |_|\__|
//
// CircleElement is a MapElement that draws an ellipse or circle on-screen.
// The ellipse is described by the rectangle formed by the reference point
// and the single point in the Points attribute (as diagonally opposing points),
// with the circle/ellipse being inscribed in that rectangle.
//
type CircleElement struct {
MapElement
}
//________________________________________________________________________________
// _ _ _____ _ _
// | | (_)_ __ ___| ____| | ___ _ __ ___ ___ _ __ | |_
// | | | | '_ \ / _ \ _| | |/ _ \ '_ ` _ \ / _ \ '_ \| __|
// | |___| | | | | __/ |___| | __/ | | | | | __/ | | | |_
// |_____|_|_| |_|\___|_____|_|\___|_| |_| |_|\___|_| |_|\__|
//
// LineElement is a MapElement that draws a straight line segment from the
// reference point to the single point in the Points attribute.
//
// If there are multiple points in the Points attribute, the element will
// be drawn from each point to the next, as connected line segments.
//
// The line will have arrowheads drawn on the first (reference) point, the last
// point, both, or neither, as indicated by the Arrow attribute.
//
// N.B.: the lines will be drawn with the Fill color, not the Line color,
// to match the behavior of the Tk library underlying our client
// implementations.
//
type LineElement struct {
MapElement
// What arrowheads, if any, to draw on the endpoints
Arrow ArrowType `json:",omitempty"`
}
//________________________________________________________________________________
// ____ _ _____ _ _
// | _ \ ___ | |_ _ __ _ ___ _ __ | ____| | ___ _ __ ___ ___ _ __ | |_
// | |_) / _ \| | | | |/ _` |/ _ \| '_ \| _| | |/ _ \ '_ ` _ \ / _ \ '_ \| __|
// | __/ (_) | | |_| | (_| | (_) | | | | |___| | __/ | | | | | __/ | | | |_
// |_| \___/|_|\__, |\__, |\___/|_| |_|_____|_|\___|_| |_| |_|\___|_| |_|\__|
// |___/ |___/
// PolygonElement is a MapElement that draws an arbitrary polygon, just as with
// the LineElement, but the interior of the shape described by the line segments
// may be filled in as a solid shape.
//
type PolygonElement struct {
MapElement
// The join style to control how the intersection between line segments is drawn.
Join JoinStyle `json:",omitempty"`
// Spline gives the factor to use when smoothing the sides of the polygon between
// its points. 0 means not to smooth them at all, resulting in a shape with straight
// edges between the vertices. Otherwise, larger values provide greater smoothing.
Spline float64 `json:",omitempty"`
}
//________________________________________________________________________________
// ____ _ _
// | _ \ ___ ___| |_ __ _ _ __ __ _| | ___
// | |_) / _ \/ __| __/ _` | '_ \ / _` | |/ _ \
// | _ < __/ (__| || (_| | | | | (_| | | __/
// |_| \_\___|\___|\__\__,_|_| |_|\__, |_|\___|
// |___/
// _____ _ _
// | ____| | ___ _ __ ___ ___ _ __ | |_
// | _| | |/ _ \ '_ ` _ \ / _ \ '_ \| __|
// | |___| | __/ | | | | | __/ | | | |_
// |_____|_|\___|_| |_| |_|\___|_| |_|\__|
//
// RectangleElement is a MapElement which describes a rectangle as defined by
// diagonally opposing points: the reference point and the single coordinate pair
// in the Points attribute.
//
type RectangleElement struct {
MapElement
}
//________________________________________________________________________________
// ____ _ _ _ ___ __
// / ___| _ __ ___| | | / \ _ __ ___ __ _ / _ \ / _|
// \___ \| '_ \ / _ \ | | / _ \ | '__/ _ \/ _` | | | | |_
// ___) | |_) | __/ | |/ ___ \| | | __/ (_| | |_| | _|
// |____/| .__/ \___|_|_/_/ \_\_| \___|\__,_|\___/|_|
// |_|
// _____ __ __ _ _____ _ _
// | ____|/ _|/ _| ___ ___| |_| ____| | ___ _ __ ___ ___ _ __ | |_
// | _| | |_| |_ / _ \/ __| __| _| | |/ _ \ '_ ` _ \ / _ \ '_ \| __|
// | |___| _| _| __/ (__| |_| |___| | __/ | | | | | __/ | | | |_
// |_____|_| |_| \___|\___|\__|_____|_|\___|_| |_| |_|\___|_| |_|\__|
//
// SpellAreaOfEffectElement is a MapElement that shows a region on the map
// affected by a spell or other area effect.
//
// The region has one of the following shapes as indicated by the AoEShape
// attribute:
// cone A 90° pieslice described as with ArcElement
// radius An ellipse described as with CircleElement
// ray A rectangle described as with RectangleElement
//
type SpellAreaOfEffectElement struct {
MapElement
// The shape of the affected region of the map.
AoEShape AoEType
}
//________________________________________________________________________________
// _____ _ _____ _ _
// |_ _|____ _| |_| ____| | ___ _ __ ___ ___ _ __ | |_
// | |/ _ \ \/ / __| _| | |/ _ \ '_ ` _ \ / _ \ '_ \| __|
// | | __/> <| |_| |___| | __/ | | | | | __/ | | | |_
// |_|\___/_/\_\\__|_____|_|\___|_| |_| |_|\___|_| |_|\__|
//
//
// TextFont describes a font used by TextElements.
//
type TextFont struct {
// The name of the font family as recognized by Tk.
Family string
// The font size as recognized by Tk.
Size float64
// The font weight (normal or bold).
Weight FontWeightType `json:",omitempty"`
// The font slant (roman or italic).
Slant FontSlantType `json:",omitempty"`
}
//
// TextElement is a MapElement which displays text on the map.
//
// The reference point is at the center of the text if Anchor is
// AnchorCenter, or is at the top-left corner of the text if Anchor
// is AnchorNW, and so on.
//
type TextElement struct {
MapElement
// Where is the reference point in relation to the text?
Anchor AnchorDirection `json:",omitempty"`
// The text to be displayed.
Text string
// Font to use for the text.
Font TextFont
}
//________________________________________________________________________________
// _____ _ _ _____ _ _
// |_ _(_) | ___| ____| | ___ _ __ ___ ___ _ __ | |_
// | | | | |/ _ \ _| | |/ _ \ '_ ` _ \ / _ \ '_ \| __|
// | | | | | __/ |___| | __/ | | | | | __/ | | | |_
// |_| |_|_|\___|_____|_|\___|_| |_| |_|\___|_| |_|\__|
//
//
// TileElement is a MapElement which displays a bitmap image on the map.
// The upper-left corner of the image will be drawn at the reference point.
//
type TileElement struct {
MapElement
// Image name as known to the mapper system.
Image string
// Bounding box in pixels for the image tile.
// If for some reason the tile can't be found, clients
// can use the bounding box to indicate where the tile should be.
// If the bounding box is not known, these values may both
// be zero.
BBHeight, BBWidth float64 `json:",omitempty"`
}
//________________________________________________________________________________
// ____ _ _____ _
// / ___|_ __ ___ __ _| |_ _ _ _ __ __|_ _|__ | | _____ _ __
// | | | '__/ _ \/ _` | __| | | | '__/ _ \| |/ _ \| |/ / _ \ '_ \
// | |___| | | __/ (_| | |_| |_| | | | __/| | (_) | < __/ | | |
// \____|_| \___|\__,_|\__|\__,_|_| \___||_|\___/|_|\_\___|_| |_|
//
//
// Creature type codes for the CreatureType field of CreatureToken
// (and PlayerToken and MonsterToken) values.
//
type CreatureTypeCode byte
const (
CreatureTypeUnknown CreatureTypeCode = iota
CreatureTypeMonster
CreatureTypePlayer
)
// SetSizes handles the bridge bewteen the deprecated use of the
// Size field and the new use of SkinSize to handle both polymorph
// skins and the creature's native size.
//
// Given (possibly nil or empty) skinSize, skin, and size values,
// the SetSizes method gives preference to the SkinSize array,
// setting Size to the default size from that list for backward
// compatibility. If SkinSize is empty but Size is populated, the
// opposite is done. If an explicit default size is listed in
// SkinSize, that will override a zero value in the Size field.
// A nonzero Size value will take priority over the default size,
// however.
//
// An error is returned if one of the size codes is invalid. If there
// is a conflict between the size value and the default size in skinSizes,
// skinSizes takes priority.
//
func (c *CreatureToken) SetSizes(skinSize []string, skin int, size string) error {
sizeCodeRE := regexp.MustCompile(`^[fFdDtTsSmMlLhHgGcC](\d+)?(?:->(\d+))?(?:=(\d+))?(?::(\*)?(.*))?$`)
// If no skinSize list was present, just use size as the single item for that list.
if len(skinSize) == 0 {
if size == "" {
return ErrCreatureNoSizes
}
if sizeCodeRE.FindStringSubmatch(size) == nil {
return ErrCreatureInvalidSize
}
c.SkinSize = []string{size}
c.Skin = 0
c.Size = size
return nil
}
// If they gave us a list of skin sizes, make sure they're all valid and see if one is
// designated as the default one.
defaultSkinSize := 0
for i, ss := range skinSize {
if szFields := sizeCodeRE.FindStringSubmatch(ss); szFields != nil {
if szFields[4] == "*" {
defaultSkinSize = i
}
} else {
return ErrCreatureInvalidSize
}
}
if skin <= 0 || skin >= len(skinSize) {
skin = defaultSkinSize
}
c.SkinSize = skinSize
c.Skin = skin
c.Size = c.SkinSize[c.Skin]
return nil
}
//
// CreatureToken is a MapObject (but not a MapElement) which displays a movable
// token indicating the size and location of a creature in the game.
//
type CreatureToken struct {
BaseMapObject
// Is the creature currently dead? (This takes precedence over the
// Health attribute's indication that the creature has taken a
// fatal amount of damage.)
Killed bool `json:",omitempty"`
// In combat, if this is true, the token is "dimmed" to indicate
// that it is not their turn to act.
Dim bool `json:",omitempty"`
// If true, this means the creature token is only visible to the GM.
Hidden bool `json:",omitempty"`
// If true, only the GM may access or manipulate the polymorph capabilities
// of this creature.
PolyGM bool `json:",omitempty"`
// The creature type.
CreatureType CreatureTypeCode
// The method of locomotion currently being used by this creature.
// Normally this is MoveModeLand for land-based creatures which
// are walking/running.
MoveMode MoveModeType `json:",omitempty"`
// Is the creature currently wielding a reach weapon or otherwise
// using the "reach" alternate threat zone?
// If this value is 0, the threat zone is normal for a creature
// of its size. If 1, an extended area (appropriate for using
// a reach weapon) is used instead. If 2, both areas are used,
// so the creature may attack into the reach zone AND adjacent
// foes.
Reach int `json:",omitempty"`
// For creatures which may change their shape or appearance,
// multiple "skins" may be defined to display as appropriate.
//
// Skin is 0 for the default appearance of the creature, 1
// for the alternate image, 2 for the 2nd alternate image, etc.
Skin int `json:",omitempty"`
// Current elevation in feet relative to the "floor" of the
// current location.
Elev int `json:",omitempty"`
// Grid (x, y) coordinates for the reference point of the
// creature. Unlike MapElement coordinates, these are in
// grid units (1 grid = 5 feet). The upper-left corner of
// the creature token is at this location.
Gx, Gy float64
// The name of the creature as displayed on the map. Must be unique
// among the other creatures.
Name string
// If non-nil, this tracks the health status of the creature.
Health *CreatureHealth `json:",omitempty"`
// If the different "skins" are different sizes, this is a list
// of size codes for each of them. For example, if there are 3
// skins defined, the first two medium-size and the 3rd large
// size, then SkinSize would have the value {"M", "M", "L"}.
// If this is empty or nil, all skins are assumed to be the
// size specified in the Size attribute. Note that SkinSize
// also sets the Area at the same time.
SkinSize []string `json:",omitempty"`
// The color to draw the creature's threat zone when in combat.
Color string
// A note to attach to the creature token to indicate special
// conditions affecting the creature which are not otherwise shown.
Note string `json:",omitempty"`
// The tactical size category of the creature ("S", "M", "L",
// etc). Lower-case letters indicate the "wide" version of the
// category while upper-case indicates "tall" versions.
//
// May also be the size in feet (DEPRECATED USAGE).
//
// This field is now DEPRECATED. Use SkinSize instead.
Size string
// If DispSize is nonempty, it holds the size category to display
// the creature (say, as a result of casting an enlarge person spell).
DispSize string `json:",omitempty"`
// A list of condition codes which apply to the character. These
// are arbitrary and defined by the server according to the needs
// of the particular game, but may include things such
// as "confused", "helpless", "hasted", etc.
StatusList []string `json:",omitempty"`
// If there is a spell effect radiating from the creature, its
// area of effect is described by this value. If there is none,
// this is nil.
//
// Currently only radius emanations are supported. In future, the
// type of this attribute may change to handle other shapes.
AoE *RadiusAoE `json:",omitempty"`
// If there is a custom reach/threat zone defined for this
// creature, it is detailed here.
CustomReach CreatureCustomReach `json:",omitempty"`
}
// CreatureCustomReach describes a creature's natural and extended
// reach zones if they differ from the standard templates.
type CreatureCustomReach struct {
// Enabled is true if this custom information should be used for the creature.
Enabled bool `json:",omitempty"`
// Natural and Extended give the distance in 5-foot grid squares
// away from the creature's PERIMETER to which their natural reach
// and extended (as with a reach weapon) reach extends.
Natural int `json:",omitempty"`
Extended int `json:",omitempty"`
}
//
// CreatureHealth describes the current health statistics of a creature if we are
// tracking it for them.
//
type CreatureHealth struct {
// Is the creature flat-footed?
IsFlatFooted bool `json:",omitempty"`
// Has the creature been stabilized to prevent death while critically wounded?
IsStable bool `json:",omitempty"`
// The maximum hit points possible for the creature.
MaxHP int `json:",omitempty"`
// The amount of lethal and non-lethal damage suffered by the creature.
LethalDamage int `json:",omitempty"`
NonLethalDamage int `json:",omitempty"`
// The grace amount of hit points a creature may suffer over their maximum before
// they are actually dead (as opposed to critically wounded). This is generally
// the creature's Constitution score, hence the name.
Con int `json:",omitempty"`
// If 0, the creature's health is displayed accurately on the map. Otherwise,
// this gives the percentage by which to "blur" the hit points as seen by the
// players. For example, if HPBlur is 10, then hit points are displayed only in
// 10% increments.
HPBlur int `json:",omitempty"`
// Override the map client's idea of how to display the creature's health condition.
// Normally this is the empty string which allows the client to calculate it from the
// information available to it.
Condition string `json:",omitempty"`
}
//
// RadiusAoE describes the area of some spell or special effect emanating from the creature.
//
type RadiusAoE struct {
// Distance in standard map pixels away from the creature token's center
// to the perimeter of the affected area.
Radius float64
// Color to draw the affected zone.
Color string
}
//________________________________________________________________________________
// ____ _ _____ _
// | _ \| | __ _ _ _ ___ _ _|_ _|__ | | _____ _ __
// | |_) | |/ _` | | | |/ _ \ '__|| |/ _ \| |/ / _ \ '_ \
// | __/| | (_| | |_| | __/ | | | (_) | < __/ | | |
// |_| |_|\__,_|\__, |\___|_| |_|\___/|_|\_\___|_| |_|
// |___/
// PlayerToken is a CreatureToken which describes a player character
// or NPC ally.
//
type PlayerToken struct {
CreatureToken
}
/*
//
// saveData converts a PlayerToken to a text representation
// in the map file format (suitable for sending to clients or saving to a disk
// file).
//
// This works just as described for BaseMapElement.saveData.
//
func (o PlayerToken) saveData(data []string, prefix, id string) ([]string, error) {
return o.CreatureToken.saveData(data, "P", id)
}
*/
//________________________________________________________________________________
// __ __ _ _____ _
// | \/ | ___ _ __ ___| |_ ___ _ _|_ _|__ | | _____ _ __
// | |\/| |/ _ \| '_ \/ __| __/ _ \ '__|| |/ _ \| |/ / _ \ '_ \
// | | | | (_) | | | \__ \ || __/ | | | (_) | < __/ | | |
// |_| |_|\___/|_| |_|___/\__\___|_| |_|\___/|_|\_\___|_| |_|
//
// MonsterToken is a CreatureToken which describes a monster or NPC adversary.
//
type MonsterToken struct {
CreatureToken
}
//________________________________________________________________________________
// ___ ____ __ _ _ _ _
// |_ _|_ __ ___ __ _ __ _ ___| _ \ ___ / _(_)_ __ (_) |_(_) ___ _ __
// | || '_ ` _ \ / _` |/ _` |/ _ \ | | |/ _ \ |_| | '_ \| | __| |/ _ \| '_ \
// | || | | | | | (_| | (_| | __/ |_| | __/ _| | | | | | |_| | (_) | | | |
// |___|_| |_| |_|\__,_|\__, |\___|____/ \___|_| |_|_| |_|_|\__|_|\___/|_| |_|
// |___/
//
// ImageDefinition describes an image as known to the mapper system.
// TileElements' Image attribute refers to the Name attribute of one of
// these.
//
type ImageDefinition struct {
// The name of the image as known within the mapper.
Name string
Sizes []ImageInstance
// If non-nil, this indicates that the image is to be animated
Animation *ImageAnimation `json:",omitempty"`
}
// ImageInstance is a single instance of a file (generally, an image is availble
// in several formats and sizes, each of which is an instance).
type ImageInstance struct {
// If IsLocalFile is true, File is the name of the image file on disk;
// otherwise it is the server's internal ID by which you may request
// that file from the server.
IsLocalFile bool `json:",omitempty"`
// The zoom (magnification) level this bitmap represents for the given
// image.
Zoom float64
// The filename by which the image can be retrieved.
File string
// If non-nil, this holds the image data received directly
// from the server. This usage is not recommended but still
// supported.
ImageData []byte `json:",omitempty"`
}
// ImageAnimation describes the animation parameters for animated images.
type ImageAnimation struct {
// The number of frames in the animation. These will be in files with
// :n: prepended to their names where n is the frame number starting with 0.
Frames int `json:",omitempty"`
// The number of milliseconds to display each frame.
FrameSpeed int `json:",omitempty"`
// The number of loops to play before stopping. 0 means unlimited.
Loops int `json:",omitempty"`
}
//________________________________________________________________________________
// _____ _ _ ____ __ _ _ _ _
// | ___(_) | ___| _ \ ___ / _(_)_ __ (_) |_(_) ___ _ __
// | |_ | | |/ _ \ | | |/ _ \ |_| | '_ \| | __| |/ _ \| '_ \
// | _| | | | __/ |_| | __/ _| | | | | | |_| | (_) | | | |
// |_| |_|_|\___|____/ \___|_| |_|_| |_|_|\__|_|\___/|_| |_|
//
// FileDefinition describes a file as known to the mapper which
// may be of interest to retrieve at some point.
//
type FileDefinition struct {
// If IsLocalFile is true, File is the name of the file on disk;
// otherwise it is the server's internal ID by which you may request
// that file from the server.
IsLocalFile bool `json:",omitempty"`
// The filename or Server ID.
File string
}
//
// objFloat looks for the given field in objDef, returning it as a float64 value.