Game technical information (legacy)

Tiles

Tiles are physically based around the 1m. There are various tile sizes depending on the use.


2m environmental tiles

Note that the following section are for explains 2m environmental (env) tiles which are measured at 2x2m. This is different from other kinds of sprites such as props, NPC, or player sprites, which take up smaller space.

Nominal floor height and camera pitch

Nominal floor height is 2m. Because of this the camera pitch angle of 35.2643°.

The nominal floor height refers to the physical height required to align the next level to the isometric grid from a specific camera angle.

A decision was made to pre-define the floor height, and then work out the camera angle. This was for the benefit of having a round value for a working physical space (eg 2m, and not 2.12m)

nominal_floor_height_1
The nominal floor height refers to the physical height required to align the next level to the isometric grid from a specific camera angle.

Tile ratio

At camera pitch 35.2643°, the tile w/h ratio is sin(35.2643°), which is 0.5773.

Tile isometric resolution

Note that the isometric resolution refers the tile’s pixel dimensions in isometric view. Tile resolution can be variable, but the nominal iso width resolution for a 2m physical env tile is  256 pixels. 128 pixels.

A 1m prop tile, however, is 128 pixels.  64 pixels.

The floor-only env tile resolution, thus, is 256*tileRatio, which is 147.8 pixels, rounded off as 148 pixels in height.

The floor only env tile resolution thus, is 128px*tileRatio == 74 (height).

Thus the floor-only env tile iso resolution is 256w x 148h px. 128w x 74h px.

The 1m prop rile iso reolution, on the other hand, is 128w x 74h px. 64w x 37h px.

The reason why it is only floor-only is because the actual tile sprite can be much taller. The nominal floor-only is simply the basis for establishing scale.

Tile sprite resolution

Tiles have no fixed resolution, but can have double/triple/half the nominal width resolution depending on requirements.

The resolution of the sprite’s must always be accurately divisible by 148 74 pixels, which is the height of the nominal iso floor tile.

The image below shows that the height resolution is 3x the height of the sprite.

tile_height_1

The height resolution can be solved by h=148 74*num.

Here is a sample list of some widths for both 2×2 tiles:

  64 x 37
  96 x 55.5 (high fractional value)
 128 x 74
 192 x 111
 256 x 148
 384 x 221.7 (high fractional value)
 480 x 277
 512 x 295.6   (high fractional value)
 768 x 443
1024 x 591
2048 x 1182

Here is one for height for both 2×2 tiles:

The width resolution can be solved by w=128*tileNum, where tileNum is the number of tiles per side. Ie the above image 2×2, so w=128*2.

Orthographic camera settings (LW)

2017-03-06-13_16_06-ortho_size

In LW, the orthographic camera is set with a physical distance parameter which is the value used to determine how much physical space will fit the pixel dimensions.

Use the Pythagorean theorem, c=sqrt(a^2+b^2) to determine the length of the hypotenuse from one corner of the tile to the other.

If we were getting a 1×1 tile, then the computed value would be 1.4142. However, we are using 2×2 tile configuration as shown in the image above, so we double the value. The Size parameter is set to ‘Horizontal Size’, and the value is set to 2.8284 for the hypotenuse value of a 2×2 sprite configuration.

The following is a LW scene which sets up an isometric camera based on user-defined settings.

LWSC
5

RenderRangeType 0
FirstFrame 1
LastFrame 120
FrameStep 1
RenderRangeObject 0
RenderRangeArbitrary 1-120
PreviewFirstFrame 0
PreviewLastFrame 120
PreviewFrameStep 1
CurrentFrame 0
FramesPerSecond 24
ChangeScene 0
Plugin MasterHandler 1 .SceneEditorStandardBanks
EndPlugin
Plugin MasterHandler 2 SceneEditor
VERS 2
{ CurrentWorkspace
 Name "<default>"
 WindowDimensions 1438 24 1de 430
 Divider1 0.30000001
 LayoutItemFilterEnabled 0
 LayoutItemChannelFilterEnabled 0
 SurfaceFilterEnabled 0
 SurfaceChannelFilterEnabled 0
 ChannelFilterEnabled 0
 { Bank
 PresetID 5f434856
 Column 5f434856 0 90
 Column 5f434856 1 90
 Column 5f434856 2 112
 Column 5f434856 3 95
 Column 5f434856 4 106
 }
 { SurfaceListBank
 PresetID 5f434856
 Column 5f434856 0 90
 Column 5f434856 1 90
 Column 5f434856 2 112
 Column 5f434856 3 95
 Column 5f434856 4 106
 }
 { ChannelListBank
 PresetID 5f434856
 Column 5f434856 0 90
 Column 5f434856 1 90
 Column 5f434856 2 112
 Column 5f434856 3 95
 Column 5f434856 4 106
 }
 BackgroundColorOdd 78 78 78 ff
 BackgroundColorEven 6f 6f 6f ff
 HierarchyIndent c
 HighlightColor b5 b0 a5 ff
 DefaultObjectColor b0 b0 b0 ff
 DefaultBoneColor 60 e0 f0 ff
 DefaultLightColor f0 60 f0 ff
 DefaultCameraColor 20 e0 20 ff
 AutoApplyToViewPorts 1
 MultiselectSimilarTypes 1
 LimitColorRange 1
 ColorsAsHSV 0
 ShowSelectionOrder 1
 EnvelopeButtonOpensGraphEditor 1
 ShowRenderExtents 1
 BlockPeriod 0.041666668
 BlockWidthMin 3
 BlockWidthMax c8
 ShowKeyTicks 1
 OverrideBlockColors 0
 BlockKeyColor 99 ae cf ff
 BlockGroupColor 64 85 b6 ff
 DSAllowChannelGroupSelection 1
}
EndPlugin
Plugin ViewportObjectHandler 1 .VPR
0
20
1
1
0
EndPlugin
Plugin ViewportObjectHandler 2 .VPR
0
20
1
1
0
EndPlugin
Plugin ViewportObjectHandler 3 .VPR
0
20
1
1
0
EndPlugin
Plugin ViewportObjectHandler 4 .VPR
0
20
1
1
0
EndPlugin
ColorSpaceViewer "sRGB" "none"
ColorSpaceSurfaceColor "sRGB" "none"
ColorSpaceLightColor "sRGB" "none"
ColorSpacePaletteFiles "sRGB" "none"
ColorSpace8BitFiles "sRGB" "none"
ColorSpaceFloatFiles "Linear" "none"
ColorSpaceAlpha "Linear" "none"
ColorSpaceOutput "sRGB" "none"
ColorSpaceOutputAlpha "Linear" "none"
ColorSpaceAutoSense 1
ColorSpace8BitToFloat 1
ColorSpaceCorrectOpenGL 1
ColorSpaceAffectPicker 1
FirstBackgroundImageSyncFrame 0
NavigationDesiredDevice (none)

AddNullObject 10000000 orient
ChangeObject 0
ShowObject 7 3
Group 0
ObjectMotion
NumChannels 9
Channel 0
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 1
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 2
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 3
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 4
{ Envelope
 1
 Key 0.52359879016876221 0 0 0 0 0 0 0 0
 Behaviors 1 1
 { ChannelHandler
 ".EnvExprLink"
 0
 1
 "z"
 }
}
Channel 5
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 6
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 7
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 8
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
IKInitCustomFrame 0
GoalStrength 1
IKFKBlending 0
IKSoftMin 0.25
IKSoftMax 0.75
CtrlPosItemBlend 1
CtrlRotItemBlend 1
CtrlScaleItemBlend 1

LockedChannels 40
PathAlignLookAhead 0.033
PathAlignMaxLookSteps 10
PathAlignReliableDist 0.001
ParentItem 10000001
SplineFlags 0
SplineFit 0
IKInitialState 0
UseIKChainValues 1
SubPatchLevel 3 3
APSDisplay
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
APSRender
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
NodeDisplacement 0
{ Nodal_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Displacement"
 { Tag
 RealName "Displacement"
 Name "Displacement"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 Server "Input"
 { Tag
 RealName "Input"
 Name "Input"
 Coordinates -30 -10
 Mode 1
 { Data
 }
 Preview "Object Position"
 Comment ""
 }
 }
 { Connections
 }
}
NodeDisplacementOrder 0
UseObjGI 0
ObjGIRadiosityRays 64
ObjGISecondaryBounceRays 16
ObjGIRadiosityTolerance 0.292893
ObjGIMinPixelSpacing 4.000000
ObjGIMaxPixelSpacing 100.000000
ShadowOptions 7
NodeEdges 0
{ NodalEdge_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Edge"
 { Tag
 RealName "Edge"
 Name "Edge"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 }
 { Connections
 }
}

AddNullObject 10000001 heading
ChangeObject 0
ShowObject 7 4
Group 0
ObjectMotion
NumChannels 9
Channel 0
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 1
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 2
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 3
{ Envelope
 1
 Key 0.78539818525314331 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 4
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 5
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 6
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 7
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 8
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
IKInitCustomFrame 0
GoalStrength 1
IKFKBlending 0
IKSoftMin 0.25
IKSoftMax 0.75
CtrlPosItemBlend 1
CtrlRotItemBlend 1
CtrlScaleItemBlend 1

PathAlignLookAhead 0.033
PathAlignMaxLookSteps 10
PathAlignReliableDist 0.001
ParentItem 10000005
SplineFlags 0
SplineFit 0
IKInitialState 0
UseIKChainValues 1
SubPatchLevel 3 3
APSDisplay
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
APSRender
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
NodeDisplacement 0
{ Nodal_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Displacement"
 { Tag
 RealName "Displacement"
 Name "Displacement"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 Server "Input"
 { Tag
 RealName "Input"
 Name "Input"
 Coordinates -30 -10
 Mode 1
 { Data
 }
 Preview "Object Position"
 Comment ""
 }
 }
 { Connections
 }
}
NodeDisplacementOrder 0
UseObjGI 0
ObjGIRadiosityRays 64
ObjGISecondaryBounceRays 16
ObjGIRadiosityTolerance 0.292893
ObjGIMinPixelSpacing 4.000000
ObjGIMaxPixelSpacing 100.000000
ShadowOptions 7
NodeEdges 0
{ NodalEdge_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Edge"
 { Tag
 RealName "Edge"
 Name "Edge"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 }
 { Connections
 }
}

AddNullObject 10000002 tilesize
ChangeObject 0
// Use 'sz' to define the nominal sprite resolution for 1m for both x and y
// Set the camera to the sx/sy shown in the slider bank.
// Use px to define the nominal tile physical size (pz follows px)
ShowObject 7 0
Group 0
ObjectMotion
NumChannels 9
Channel 0
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 1
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 2
{ Envelope
 1
 Key 2 0 0 0 0 0 0 0 0
 Behaviors 1 1
 { ChannelHandler
 ".EnvExprLink"
 0
 1
 "follow_tilesize_px"
 }
}
Channel 3
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 4
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 5
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 6
{ Envelope
 1
 Key 256 0 0 0 0 0 0 0 0
 Behaviors 1 1
 { ChannelHandler
 ".EnvExprLink"
 0
 1
 "tilesize_sx"
 }
}
Channel 7
{ Envelope
 1
 Key 256 0 0 0 0 0 0 0 0
 Behaviors 1 1
 { ChannelHandler
 ".EnvExprLink"
 0
 1
 "tilesize_sy"
 }
}
Channel 8
{ Envelope
 1
 Key 128 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
IKInitCustomFrame 0
GoalStrength 1
IKFKBlending 0
IKSoftMin 0.25
IKSoftMax 0.75
CtrlPosItemBlend 1
CtrlRotItemBlend 1
CtrlScaleItemBlend 1

PathAlignLookAhead 0.033
PathAlignMaxLookSteps 10
PathAlignReliableDist 0.001
ParentItem 10000004
SplineFlags 0
SplineFit 0
IKInitialState 0
UseIKChainValues 1
SubPatchLevel 3 3
APSDisplay
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
APSRender
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
Plugin CustomObjHandler 1 Sliders
2
6
5
80
-483 348
0 0
0 0
0 0
"tilesize"
"Position.X"
10000002
0 16
0.1254902 0.87843138 0.1254902
16
"nominal tile physical size (m)"
"tilesize"
"Scale.X"
10000002
0 1
0.94117647 0.94117647 0.94117647
16
"Set frame res X"
"tilesize"
"Scale.Y"
10000002
0 1
0.94117647 0.75294119 0.1254902
16
"Set frame res Y"
"tilesize"
"Scale.Z"
10000002
16 2048
0.94117647 0.3764706 0.94117647
16
"nominal tile resolution @ 1m"
"floortile"
"Scale.X"
10000003
16 2048
0.94117647 0.1254902 0.1254902
16
"floortile X"
"floortile"
"Scale.Y"
10000003
16 2048
0.3764706 0.87843138 0.94117647
19
"floortile Y"
EndPlugin
Plugin CustomObjHandler 2 LW_ItemComment
2
10000002
1
0.2 0.92000002 0.2 1
14
EndPlugin
NodeDisplacement 0
{ Nodal_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Displacement"
 { Tag
 RealName "Displacement"
 Name "Displacement"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 Server "Input"
 { Tag
 RealName "Input"
 Name "Input"
 Coordinates -30 -10
 Mode 1
 { Data
 }
 Preview "Object Position"
 Comment ""
 }
 }
 { Connections
 }
}
NodeDisplacementOrder 0
UseObjGI 0
ObjGIRadiosityRays 64
ObjGISecondaryBounceRays 16
ObjGIRadiosityTolerance 0.292893
ObjGIMinPixelSpacing 4.000000
ObjGIMaxPixelSpacing 100.000000
ShadowOptions 7
NodeEdges 0
{ NodalEdge_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Edge"
 { Tag
 RealName "Edge"
 Name "Edge"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 }
 { Connections
 }
}

AddNullObject 10000003 floortile
ChangeObject 0
// Use sx/sy to define floor tile pixel targets.
ShowObject 7 0
Group 0
ObjectMotion
NumChannels 9
Channel 0
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 1
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 2
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 3
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 4
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 5
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 6
{ Envelope
 1
 Key 256 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 7
{ Envelope
 1
 Key 128 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 8
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
IKInitCustomFrame 0
GoalStrength 1
IKFKBlending 0
IKSoftMin 0.25
IKSoftMax 0.75
CtrlPosItemBlend 1
CtrlRotItemBlend 1
CtrlScaleItemBlend 1

PathAlignLookAhead 0.033
PathAlignMaxLookSteps 10
PathAlignReliableDist 0.001
ParentItem 10000004
SplineFlags 0
SplineFit 0
IKInitialState 0
UseIKChainValues 1
SubPatchLevel 3 3
APSDisplay
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
APSRender
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
Plugin CustomObjHandler 1 LW_ItemComment
2
10000003
1
0.2 0.92000002 0.2 1
14
EndPlugin
NodeDisplacement 0
{ Nodal_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Displacement"
 { Tag
 RealName "Displacement"
 Name "Displacement"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 Server "Input"
 { Tag
 RealName "Input"
 Name "Input"
 Coordinates -30 -10
 Mode 1
 { Data
 }
 Preview "Object Position"
 Comment ""
 }
 }
 { Connections
 }
}
NodeDisplacementOrder 0
UseObjGI 0
ObjGIRadiosityRays 64
ObjGISecondaryBounceRays 16
ObjGIRadiosityTolerance 0.292893
ObjGIMinPixelSpacing 4.000000
ObjGIMaxPixelSpacing 100.000000
ShadowOptions 7
NodeEdges 0
{ NodalEdge_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Edge"
 { Tag
 RealName "Edge"
 Name "Edge"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 }
 { Connections
 }
}

AddNullObject 10000004 _do_not_touch_
ChangeObject 0
ShowObject 7 0
Group 0
ItemLock 1
ObjectMotion
NumChannels 9
Channel 0
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 1
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 2
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 3
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 4
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 5
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 6
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 7
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 8
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
IKInitCustomFrame 0
GoalStrength 1
IKFKBlending 0
IKSoftMin 0.25
IKSoftMax 0.75
CtrlPosItemBlend 1
CtrlRotItemBlend 1
CtrlScaleItemBlend 1

PathAlignLookAhead 0.033
PathAlignMaxLookSteps 10
PathAlignReliableDist 0.001
ParentItem 10000005
SplineFlags 0
SplineFit 0
IKInitialState 0
UseIKChainValues 1
SubPatchLevel 3 3
APSDisplay
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
APSRender
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
NodeDisplacement 0
{ Nodal_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Displacement"
 { Tag
 RealName "Displacement"
 Name "Displacement"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 Server "Input"
 { Tag
 RealName "Input"
 Name "Input"
 Coordinates -30 -10
 Mode 1
 { Data
 }
 Preview "Object Position"
 Comment ""
 }
 }
 { Connections
 }
}
NodeDisplacementOrder 0
UseObjGI 0
ObjGIRadiosityRays 64
ObjGISecondaryBounceRays 16
ObjGIRadiosityTolerance 0.292893
ObjGIMinPixelSpacing 4.000000
ObjGIMaxPixelSpacing 100.000000
ShadowOptions 7
NodeEdges 0
{ NodalEdge_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Edge"
 { Tag
 RealName "Edge"
 Name "Edge"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 }
 { Connections
 }
}

AddNullObject 10000005 iso_cam_setup
ChangeObject 0
ShowObject 7 4
Group 0
ObjectMotion
NumChannels 9
Channel 0
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 1
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 2
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 3
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 4
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 5
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 6
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 7
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 8
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
IKInitCustomFrame 0
GoalStrength 1
IKFKBlending 0
IKSoftMin 0.25
IKSoftMax 0.75
CtrlPosItemBlend 1
CtrlRotItemBlend 1
CtrlScaleItemBlend 1

PathAlignLookAhead 0.033
PathAlignMaxLookSteps 10
PathAlignReliableDist 0.001
SplineFlags 0
SplineFit 0
IKInitialState 0
UseIKChainValues 1
SubPatchLevel 3 3
APSDisplay
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
APSRender
{ APS
 Version 1
 Method 0
 { VParm
 { ObjectLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonLevel
 0
 { VariantParameter
 3
 0
 { ParameterValue
 3
 0
 }
 }
 }
 { PolygonPixelSize
 0
 { VariantParameter
 3
 0
 { ParameterValue
 256
 0
 }
 }
 }
 }
}
NodeDisplacement 0
{ Nodal_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Displacement"
 { Tag
 RealName "Displacement"
 Name "Displacement"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 Server "Input"
 { Tag
 RealName "Input"
 Name "Input"
 Coordinates -30 -10
 Mode 1
 { Data
 }
 Preview "Object Position"
 Comment ""
 }
 }
 { Connections
 }
}
NodeDisplacementOrder 0
UseObjGI 0
ObjGIRadiosityRays 64
ObjGISecondaryBounceRays 16
ObjGIRadiosityTolerance 0.292893
ObjGIMinPixelSpacing 4.000000
ObjGIMaxPixelSpacing 100.000000
ShadowOptions 7
NodeEdges 0
{ NodalEdge_Block
 { Root
 Location 0 0
 Zoom 1
 Disabled 1
 }
 Version 1
 { Nodes
 Server "Edge"
 { Tag
 RealName "Edge"
 Name "Edge"
 Coordinates -10 -10
 Mode 1
 { Data
 }
 Preview ""
 Comment ""
 }
 }
 { Connections
 }
}

AmbientColor 1 1 1
AmbientIntensity 0.05
DoubleSidedAreaLights 1
RadiosityType 1
RadiosityInterpolated 1
RadiosityTransparency 0
RadiosityIntensity 1
RadiosityTolerance 0.2928932
RadiosityRays 100
SecondaryBounceRays 50
RadiosityMinPixelSpacing 3
RadiosityMaxPixelSpacing 100
RadiosityMultiplier 1
RadiosityDirectionalRays 0
RadiosityUseGradients 0
RadiosityUseBehindTest 1
BlurRadiosity 1
RadiosityFlags 0
RadiosityCacheModulus 1
RadiositySaveEachFrame 0
RadiosityCacheFilePath M:PROJECTS/___ARCHIVES/ASTRONETTE/ASTRONETTE/3d/Radiosity/radiosity.cache
PixelFilterForceMT 0

AddLight 20000000
LightName Light
ShowLight 1 -1 0.941176 0.376471 0.941176
LightMotion
NumChannels 9
Channel 0
{ Envelope
 1
 Key -2 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 1
{ Envelope
 1
 Key 2 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 2
{ Envelope
 1
 Key -2 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 3
{ Envelope
 1
 Key 0.78539816339744828 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 4
{ Envelope
 1
 Key 0.6108652381980153 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 5
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 6
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 7
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 8
{ Envelope
 1
 Key 1 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
IKInitCustomFrame 0
GoalStrength 1
IKFKBlending 0
IKSoftMin 0.25
IKSoftMax 0.75
CtrlPosItemBlend 1
CtrlRotItemBlend 1
CtrlScaleItemBlend 1

PathAlignLookAhead 0.033
PathAlignMaxLookSteps 10
PathAlignReliableDist 0.001
SplineFlags 0
SplineFit 0
IKInitialState 0
UseIKChainValues 1
LightColor 1 1 1
LightIntensity 1
AffectCaustics 1
LightType 0
LensFlare 0
FlareIntensity 0.5
FlareDissolve 0
LensFlareFade 4
LensFlareOptions 11
FlareRingColor 0.3137 0.0784 0.0392
FlareRingSize 0.22
FlareRandStreakInt 0.03
FlareRandStreakDens 50
FlareRandStreakSharp 6
ShadowType 1
ShadowColor 0 0 0
Plugin LightHandler 1 DistantLight
EndPlugin

AddCamera 30000000
CameraName Camera
ShowCamera 1 -1 0.125490 0.878431 0.125490
CameraMotion
NumChannels 6
Channel 0
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 1
{ Envelope
 1
 Key 0.70710700750350952 0 0 0 0 0 0 0 0
 Behaviors 1 1
 { ChannelHandler
 ".EnvExprLink"
 0
 1
 "camera_height"
 }
}
Channel 2
{ Envelope
 1
 Key -10 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 3
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 4
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
Channel 5
{ Envelope
 1
 Key 0 0 0 0 0 0 0 0 0
 Behaviors 1 1
}
IKInitCustomFrame 0
GoalStrength 1
IKFKBlending 0
IKSoftMin 0.25
IKSoftMax 0.75
CtrlPosItemBlend 1
CtrlRotItemBlend 1
CtrlScaleItemBlend 1

LockedChannels 5
PathAlignLookAhead 0.033
PathAlignMaxLookSteps 10
PathAlignReliableDist 0.001
ParentItem 10000000
SplineFlags 0
SplineFit 0
IKInitialState 0
UseIKChainValues 1
ZoomFactor 3.2
ZoomType 1
ResolutionMultiplier 1.0
FrameSize 256 256
PixelAspect 1
MotionBlur 0
MotionBlurPasses 1
ShutterEfficiency 1
RollingShutter 0
ShutterOpen 0
Oversampling 0
UndockPreview 0
FieldRendering 0
ApertureHeight 0.015
EyeSeparation 0.07
ConvergencePoint 1
UseConvergence 0
StereoTrackedEye 0
StereoOpenGL 1
ConvergenceToeIn 1
DepthOfField 0
FocalDistance 1
LensFStop 4
DiaphragmSides 0
DiaphragmRotation 0
AASamples 1
Sampler 0
AdaptiveThreshold 0.01
MinimumSamples 1
MaximumSamples 9
Plugin CameraHandler 1 Orthographic
{ ACT
 Version 1
 { VParm
 { Size
 0
 { VariantParameter
 3
 0
 { ParameterValue
 1.4142135
 1
 { Envelope
 1
 Key 1.4141999999999999 0 0 0 0 0 0 0 0
 Behaviors 1 1
 { ChannelHandler
 ".EnvExprLink"
 0
 1
 "tilesize"
 }
 }
 }
 }
 }
 }
}
EndPlugin

Antialiasing 2
AntiAliasingLevel -1
ReconstructionFilter 0
AdaptiveSampling 1

UseBackgroundColor 0
BackgroundColor 0 0 0
SolidBackdrop 1
BackdropColor 0 0 0
ZenithColor 0.6196 0.736 1
SkyColor 0.8824 0.9177 1
GroundColor 0.8824 0.9177 1
NadirColor 0.1216 0.0948 0.083
SkySqueezeAmount 6
GroundSqueezeAmount 6
FogType 0
FogMinDistance 0
FogMaxDistance 1
FogMinAmount 0
FogMaxAmount 1
FogColor 0.5098 0.5098 0.549
BackdropFog 0
CopyToPerspective 0
VolumeClipDiscance 0.1
DynamicRangeMin 0
DynamicRangeLimit 1
DitherIntensity 0
AnimatedDither 0

RenderMode 2
RayTraceEffects 15
DepthBufferAA 0
RenderLines 1
RenderInstances 1
RayRecursionLimit 6
RayPrecision 6
RayCutoff 0.01
ShadingSamples 1
LightSamples 1
DataOverlayLabel 
SaveRGB 0
SaveAlpha 0

ViewConfiguration 0
DefineView 0
ViewType 9
ViewLevel 5
ViewAimpoint 0 0 0
ViewZoomFactor 1.312894
ViewXRay 1
ViewMBDofPreview 0
ViewHeadlight 0

GridNumber 10
GridSize 1
CameraViewBG 0
ShowMotionPath 1
ShowFogRadius 1
ShowFogEffect 0
ShowFieldChart 0
OverlayColor_fv 0 0 0
MeshBackgroundGroup 1
Plugin VirtualStudio 1 VirtualStudio
{ Version
 2
 Active 1
 LIVE 0
 LIVE_FPS 30
 Play 0
 Arm 0
 PunchIn 0
 PunchOut 0
}
EndPlugin

CurrentObject 5
CurrentLight 0
CurrentCamera 0
GraphEditorData
{ GraphEd_Favorites
}
{ GE_Expression_Lib
 1
 Expression "Expr 2" "" 0
 Expression "tilesize" "vmag( tilesize.wpos(Time))" 0
 Expression "camera_height" "[Camera.Size]/2" 0
 Expression "Expr 5" "Value" 0
 Expression "tilesize_sx" "tilesize.pos(Time).x*tilesize.scl(Time).z" 0
 Expression "tilesize_sy" "tilesize.pos(Time).z*tilesize.scl(Time).z" 0
 Expression "z" "deg( asin(floortile.scl(Time).y/floortile.scl(Time).x) )" 0
 Expression "follow_tilesize_px" "[tilesize.Position.X]" 0
}
ImageEditorData
NumberOfClips 0

Hacking (Useitemables)

Hacking is like using at item on an object, but requires a Haxbox, so this is the constant thing. The hackable object will then be tagged as hacked if successful.


Larger-than-tile-size images

Placing Tiles which are bigger than the Map’s tile size. A reference in the Tiled forums.

Summary of the issue is that multi-selecting tiles in while in Isometric projection does not yield a ‘flat’ orthographic placement of the tile, obviously. Ideally, a multi-selected Tile should be presented as a flat screen-space graphic, but the proper procedure, as Bjorn pointed out in the link above is to use a Collection of Images, so as to obviate the need to select multiple tiles to get to a bigger image.

This is fine in respect to the OP’s problem of putting in establishments. But my issues are putting walls, and all sorts of tiles that need to be connected precisely unto other tiles. The problem is how tiles are aligned in the first place. Tiles are anchored at the lower-left point. That means the bigger the tile gets in relation to the map tile size, the further up and right the tile’s registration will be.

2017-02-15-18_08_34-_untitled-tmx-tiled

On the outer hand, an Image Object aligns itself with the bottom anchor point making it ideal as a positioning entity.

I went ahead and modified TMX Importer V2 to retrieve the tileset id or image used by the Image Object, but Rex has also modified it after requesting it, so either way this is a doable solution.

 

Example requirements

  1. On LMB on NPC, walk and talk to NPC.
  2. On LMB on InvItem, walk and take InvItem.
  3. On LMB on Door, walk to Door and enter Room.
  4. Series of animation played end-to-end. (Use FSM?) (Determining end of animation)

Rex’s Scenario plugins

The Scenario plugin and its Behaviour counterpart need to be looked at in more detail.


Doors example

In the case of Doors, the PC can move onto the same Tile where Doors lie on, because Doors are rendered at the edges of the Tiles rather than at the centre of the tile (where the PC cannot be feasible rendered on top of it).

Portals exist for Doors; Portals are in the same position as the Door Sprite they belong to. When a Door Sprite is clicked, the PC Pathfinds to the Tile.


InvItem example

An InvItem, like a Door, exists on a Tile that the PC can move onto. Thus, the Tile is associated with InvItem directly.


NPC example

For NPCs, the PC cannot move on to the same Tile. If an NPC is clicked, this doesn’t automatically intend to Talk, but could be a move to the NPC position. However, the PC cannot move onto the same Tile as the NPC. Furthermore, the PC may not be able to reach a Tile that is adjacent to the NPC.

If PC intends to talk, the PC Pathfinds to the NPC.

Creating NPCs and NPC TalkPoints

IN TILED
NPCs

Create a Tiled Object type ‘npc’. I’m choosing to use Objects instead of a Tile in Tiled is because using a Tile will require a separate Tile Layer. In the processing of the TMX, it seems more clean/straightforward to process the Objects separately, so that the placement of the NPCs can occur on the Main layer (where Z-Sorting occurs).

The NPC will have the property called autoTP.

NPC.autoTP=-1 # -1 means NPC cannot be talked to
NPC.autoTP=0 # 0 means manually placed TalkPoint is expected by system
NPC.autoTP=1 # 1 means system will automatically generate TalkPoints based on accessibility of neighbouring Tiles

It will also have a ‘name’ property which denotes a unique string name for the NPC.

NPC.name='Letigus'
TalkPoints

If NPC.autoTP is = 0, then a TalkPoint in Tiled is expected to be manually placed. Create a Tiled Object type ‘talkpoint’. The name can be anything (as the property is read, not the name). Eg ‘tp1’.

A TalkPoint has a property called ‘npc’, which refers to the NPC.

TalkPoint.npc='Letigus' # specified in Tiled as this associated must be made during design
# 'Letigus', obviously, as an NPC Object, must exist in the Tiled level as well
IN C2
Prep NPCs

C2 NPCs are composed of a generic ‘mover’ entity (NPCMover), and a unique ‘graphic’ entity (NPCSprite) that belongs to a Family (NPCSpriteFamily), both of which are Sprite C2 Objects.

/NPCMover
./NPCLegtigusSprite -> NPCSpriteFamily

NPCMover has a ‘name’ variable for the name of the NPC it is associated with.

NPCMover.name='Letigus' # this is populated when TMX is loaded
NPCMover.sprite=-1 # this is NPCSpriteFamily.UID when it is generated

NPCSpriteFamily will have ‘name’ variable denoting the NPC it refers to; a ‘talkpoint’ variable pointing to to the UID of the Tile which is on the TalkPoint when/if it is made.

NPCSpriteFamily.f_name='Letigus' # Family variable init manually based on the Sprite's graphic
NPCSpriteFamily.f_talkpoint=-1 # represents a Tile UID, valid only if .autoTP is 0 (manually placed TalkPoints)
NPCSpriteFamily.f_autoTP=-1 # refer to above for value meanings
NPCSpriteFamily.f_mover=-1 # this is the association to a particular mover, which is the positional marker
Prep TalkPoints

TalkPoints in C2 are expressed within Tiles. Tiles in the 0-layer are tagged with TalkPoint names, but init with blank strings (”)

Tile.talkpoint='Letigus' # when PC touches this Tile and queries it for Talking, it will return 'Letigus'.
Tile.talkpoint=''

So a TalkPoint is not really a separated entity as such in C2, but rather, it is embedded in the Tiles since those are the ones being queried.

TMX Loading

This is the procedure during C2 TMX loading:

-Scan for Tiled Objects with type 'npc'
-Query 'name' of 'npc'
-Query 'autoTP' of 'npc'; for now assume .autoTP=0
-Query logical position of object
-Look for 'name' in NPCSpriteFamily.f_name, assume found
-Instantiate NPCMover on Main layer, and assign NPCMover.name = NPCSpriteFamily.f_name
-Assign NPCMover.sprite = NPCSpriteFamily.UID
-Assign NPCSpriteFamily.f_mover = NPCMover.UID
-Assign NPCSpriteFamily.f_autoTP 'autoTP' value of 'npc'
-Position NPCMover on Tile
-Instantiate that NPCSprite on Main layer (use Nickname to instantiate; see here)
-Pin NPCSprite to NPCMover (no offset)

-Scan for Tiled Objects with type 'talkpoint'
-Query logical position of object
-Query 'name' of 'talkpoint'
-Select the Tile resides on logical position of 'talkpoint' at 0-layer
-Assign Tile.talkpoint the 'name' of the 'talkpoint'

C2 Auto-placement of TalkPoints

Assuming there had been some NPCs with an ‘autoTP’ value of 1, this means that the system will generate automatic TalkPoints for that NPC. This happens after TMX loading.

-Loop through NPCSpriteFamily with .f_autoTP=1
-Select the NPCMover based on NPCSpriteFamily.f_mover
-Determine the Tile ID that the NPCMover is on
-Determine the Tiles that surround the Tile in question
-Cull out the Tiles that are not accessible (impass=true)
-Mark those Tiles with Tiles.talkpoint='Letigus' (NPCSpriteFamily.f_name)
 IN ACTION IN C2
  • When an NPCSpriteFamily is clicked, is intent=’talk='<npc_name>”?
    • Yes: Query current Tile. Is Tile.talkpoint = NPCSpriteFamily.f_name?
      • Yes: Talk.
      • No: Is NPCSpriteFamily.f_autoTP=0? (Manually placed TalkPoints)
        • Yes: Select Tile with Tile.UID = NPCSpriteFamily.f_talkpoint, and Pathfind to Tile
        • No: Pathfind to NPC location
    • No: Pathfind to NPC location
  • On enter Tile
    • Query if Tile.talkpoint != ”?
      • Yes (it is a TalkPoint): Query if intent=’talk’ and if intent=’talk=<Tile.talkpoint>’ (intent is to talk, and to talk to that specific NPC)
        • Yes: Stop and talk.
        • No: do nothing.
      • No (it is not a TalkPoint): do nothing.

OTHER ACTIONABLE OBJECTS

Find other examples that use the same concept as ‘click here, move there’, like in the NPC, where clicking on the NPC will not necessarily Pathfind to the NPC, but to a TalkPoint.


ACTIONS

Actions upon Objects can consist of

  1. Talk
  2. Look (examine)
  3. Use (take/get)

Talk has been previously covered

Look

As with StorageDict, which is first example of the the persistent data implementation, we create a LookDict Object. A LookDict has the following variables

LookDict.alias='l#.r#' # string id and room id to uniquely identify itself; this is generated by self.name+self.room
LookDict.name='l#' # string id for name only
LookDict.room='r#' # string id for room only
LookDict.looktimes=0 # number of times that this item has been looked on
LookDict.textdict=-1 # the UID of the LookTextDict that this LookDict refers to

The first 3 variables are identical to StorageDict.

The .lookTimes variable is new, and this stores the number of times the associated Object has been looked at. This is in consideration that the description of something may change by the number of times the player decides to examine an Object. This is also stored in the LookDict (the one that will be saved with the game) so that the value can be persistent.

The .textDict variable is new, too. Because the nature of reading out a description potentially need long text, the best way is to use a CSV to write the text script out in a spreadsheet, instead of trying to do it in Tiled. So a LookTextDict Object is created to store static text from a CSV string. This LookTextDict is then associated with the LookDict that asked for it to be created. Both the LookDict and LookTextDict are persistent.

The LookTextDict have instance variables:

LookTextDict.alias = LookDict.alias
LookTextDict.lookdict = LookDict.UID

At this point I’m not sure if .alias is needed, but it is important that the LookTextDict is associated with its LookText via .UID.

The LookTextDict (Dictionary) has a certain syntax with its keys.

LookTextDict['n:0'] = 'text to show by default'
LookTextDict['n:3'] = 'text to show if player has looked on this object at least 3 times'
LookTextDict['a:ate cupcake'] = 'text to show if the accomps "ate cupcake" is achieved'

In the case of the above, if the player has looked onto the object 2 times, then the text in [‘n:0’] is shown since it has not reached 3 times.

Accomps (Accomplishments) are tracked differently (in the Player Object itself) so there’s no need to track persistent data in LookDict at all.

Again, the difference between LookDict and LookTextDict:

  • LookDict stores persistence data and is generated by the TMX Object ‘look’
  • LookTextDict is a static Dictionary generated at the beginning of the game (irrespective of TMX loading). It is a Dict that is init based on the contents of a much wider global ‘Look Text description CSV file’. LookDict looks for its LookTextDict partner through alias identification; when LookDict finds its LookTextDict partner, they make a connection through populating their .textdict and .lookdict variables, respectively, with their partner’s UID.

Implementation

In Tiled, create an Object type ‘look’. There are no other properties needed, only that its name is important as a lookup value for the CSV.

Externally, create a CSV/spreadsheet referencing the Tiled Object ‘look’ name.

In C2, LookTextDict Objects are created based on the CSV. So at the beginning of the load, perhaps even before the TMX is loaded, LookTextDict Objects are created ready to be referenced by and ‘look’ Object looking for its partner.

(Consider that small Sprites even within the same Tile (or not necessarily corresponding to a Tile) need a Look description)

 

Use

Using a locked door as an example, the locked Door can be opened by:

  1. Secpass (InvItem)
  2. Accomps

In the case of InvItem, that hasn’t been designed yet.

Accomps are easy, because the lookup is in the global AccompsDict. If an accomps key is encountered, then that locked Door can be opened.

Portals as Doors

Since Portals contain the ‘destination’ property, Portals can be promoted to take more properties. But to keep the data concentrated on one place, let the extra properties be put in the PortalDict.

Portal.name
PortalDict.destination
PortalDict.locked # is the Portal locked?
PortalDict.unlockreq # requirements to unlock this Portal

Note that the ‘destination’ has been put in the PortalDict, instead of the Portal.

Although .destination and .unlockreq may be considered as static data putting every relevant data in one Object is much clearer. So here we have a mix of static and persistent/volatile data in the PortalDict Object.

.locked should be persistent. And using the same principle as the others, PortalDict is created to keep track of the Portal’s data.

Currently, a Portal is read from the TMX, then a Portal Sprite is created in the Portal z-layer.

So now, when a Portal is read, it goes through the same procedure, but a PortalDict is created as well. I don’t think a Dictionary is needed to carry simple information, I’m just trying to be consistent with the C2 Object types. And besides, there may be further use of expanding the data it can hold, and a Dictionary is the best container for that.

PortalDict, thus, needs an .alias/.name/.room instance variable to identify itself uniquely. It also needs a pointer to the UID of the Portal Sprite it’s associated with

PortalDict.alias
PortalDict.name
PortalDict.room
PortalDict.portal

Note that the current Portal Sprite considers ‘name’ to be what we now call ‘alias’ (eg ‘p1.r1’). This must be changed when we start implementing PortalDict.

Conversely, the Portal Sprite must have a PortalDict connection:

Portal.portaldict

So, to recap TMX loading:

  1. On TMX load Portal Objects are read.
  2. Portal Sprites are generated on the ‘Portal’ z-layer of the chess/tile.
  3. PortalDict is generated from Portal.alias. If PortalDict already exists, then make the connection by PortalDict.portal = Portal.UID, and Portal.portaldict = PortalDict.UID.
  4. If PortalDict does not exist, then create a new one; assign PortalDict.alias=Portal.alias, and trade UIDs between them (like in #3 above)

In action in C2:

  1. When the player clicks on a Door, the intent could be to open. But PC will approach first if not on the Tile itself.
  2. Regardless, an ‘enter’ action is needed to test the Portal’s accessibility.
  3. The Portal being queried will be Portal Object residing in the ‘Portal’ z-layer that the PC is currently on.
  4. Is Portal.locked=true?
    1. Yes: what is Portal.unlockreq?
      1. Parsing the unlockreq. Note that at the moment there are two possible ways of unlocking a Portal: by InvItem, and by Accomps. Use ‘i’ as the key for InvItem, and use ‘a’ as the key for Accomps. Eg: Portal.unlockreq=’a:ate cupcake’, or Portal.unlockreq=’i:cupcake’, or an AND combination: Portal.unlockreq=’i:coffee;a:ate cupcake’.
    2. No: enter the Portal destination