From 11f743aa423edd3b25a2cca4960a20fbac1dd544 Mon Sep 17 00:00:00 2001 From: Ziemas Date: Sat, 27 Jun 2020 20:30:23 +0200 Subject: [PATCH] Get and use draw order and animation speed for objects (#473) * String2enum ObjectAnimationMode * Render objects at their assigned layer Gets the orderflag from the object record and assign it to the mapentity so the renderer can get at it. This adds another render pass that loops through the objects. * Get object animation speed from their txt entry --- d2common/d2enum/animation_mode.go | 1 + .../d2enum/objectanimationmode_string2enum.go | 40 +++++++++++++++++++ d2core/d2asset/composite.go | 10 +++++ d2core/d2map/d2mapentity/map_entity.go | 7 ++++ d2core/d2map/d2mapentity/object.go | 6 ++- d2core/d2map/d2maprenderer/renderer.go | 34 +++++++++++++++- 6 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 d2common/d2enum/objectanimationmode_string2enum.go diff --git a/d2common/d2enum/animation_mode.go b/d2common/d2enum/animation_mode.go index 3ea2357d..b7fc9659 100644 --- a/d2common/d2enum/animation_mode.go +++ b/d2common/d2enum/animation_mode.go @@ -58,3 +58,4 @@ const ( //go:generate stringer -linecomment -type PlayerAnimationMode //go:generate stringer -linecomment -type MonsterAnimationMode //go:generate stringer -linecomment -type ObjectAnimationMode +//go:generate string2enum -samepkg -linecomment -type ObjectAnimationMode diff --git a/d2common/d2enum/objectanimationmode_string2enum.go b/d2common/d2enum/objectanimationmode_string2enum.go new file mode 100644 index 00000000..c2b13354 --- /dev/null +++ b/d2common/d2enum/objectanimationmode_string2enum.go @@ -0,0 +1,40 @@ +// Code generated by "string2enum -samepkg -linecomment -type ObjectAnimationMode"; DO NOT EDIT. + +package d2enum + +import "fmt" + +// ObjectAnimationModeFromString returns the ObjectAnimationMode enum corresponding to s. +func ObjectAnimationModeFromString(s string) ObjectAnimationMode { + if len(s) == 0 { + return 0 + } + for i := range _ObjectAnimationMode_index[:len(_ObjectAnimationMode_index)-1] { + if s == _ObjectAnimationMode_name[_ObjectAnimationMode_index[i]:_ObjectAnimationMode_index[i+1]] { + return ObjectAnimationMode(i) + } + } + panic(fmt.Errorf("unable to locate ObjectAnimationMode enum corresponding to %q", s)) +} + +func _(s string) { + // Check for duplicate string values in type "ObjectAnimationMode". + switch s { + // 0 + case "NU": + // 1 + case "OP": + // 2 + case "ON": + // 3 + case "S1": + // 4 + case "S2": + // 5 + case "S3": + // 6 + case "S4": + // 7 + case "S5": + } +} diff --git a/d2core/d2asset/composite.go b/d2core/d2asset/composite.go index 5db8b2c9..d8cdde01 100644 --- a/d2core/d2asset/composite.go +++ b/d2core/d2asset/composite.go @@ -81,6 +81,16 @@ func (c *Composite) SetMode(animationMode, weaponClass string, direction int) er return nil } +func (c *Composite) SetSpeed(speed int) { + c.mode.animationSpeed = 1.0 / ((float64(speed) * 25.0) / 256.0) + for layerIdx := range c.mode.layers { + layer := c.mode.layers[layerIdx] + if layer != nil { + layer.SetPlaySpeed(c.mode.animationSpeed) + } + } +} + func (c *Composite) GetDirectionCount() int { if c.mode == nil { return 0 diff --git a/d2core/d2map/d2mapentity/map_entity.go b/d2core/d2map/d2mapentity/map_entity.go index e6f23618..5257989f 100644 --- a/d2core/d2map/d2mapentity/map_entity.go +++ b/d2core/d2map/d2mapentity/map_entity.go @@ -12,6 +12,7 @@ type MapEntity interface { Render(target d2render.Surface) Advance(tickTime float64) GetPosition() (float64, float64) + GetLayer() (int) GetPositionF() (float64, float64) Name() string } @@ -28,6 +29,7 @@ type mapEntity struct { TargetY float64 Speed float64 path []d2astar.Pather + drawLayer int done func() directioner func(direction int) @@ -46,10 +48,15 @@ func createMapEntity(x, y int) mapEntity { subcellX: 1 + math.Mod(locX, 5), subcellY: 1 + math.Mod(locY, 5), Speed: 6, + drawLayer: 0, path: []d2astar.Pather{}, } } +func (m *mapEntity) GetLayer() int { + return m.drawLayer +} + func (m *mapEntity) SetPath(path []d2astar.Pather, done func()) { m.path = path m.done = done diff --git a/d2core/d2map/d2mapentity/object.go b/d2core/d2map/d2mapentity/object.go index 81bfb752..d5fabb40 100644 --- a/d2core/d2map/d2mapentity/object.go +++ b/d2core/d2map/d2mapentity/object.go @@ -1,6 +1,7 @@ package d2mapentity import ( + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2render" @@ -29,6 +30,7 @@ func CreateObject(x, y int, object *d2datadict.ObjectLookupRecord, palettePath s } entity.mapEntity.directioner = entity.rotate entity.objectRecord = d2datadict.Objects[object.ObjectsTxtId] + entity.drawLayer = entity.objectRecord.OrderFlag[d2enum.AnimationModeObjectNeutral] return entity, nil } @@ -43,7 +45,9 @@ func (ob *Object) SetMode(animationMode, weaponClass string, direction int) erro err = ob.composite.SetMode(animationMode, "HTH", direction) ob.weaponClass = "HTH" } - + ob.mapEntity.drawLayer = ob.objectRecord.OrderFlag[d2enum.ObjectAnimationModeFromString(animationMode)] + // For objects their txt record entry overrides animationdata + ob.composite.SetSpeed(ob.objectRecord.FrameDelta[d2enum.ObjectAnimationModeFromString(animationMode)]) return err } diff --git a/d2core/d2map/d2maprenderer/renderer.go b/d2core/d2map/d2maprenderer/renderer.go index 4a9e06dc..b1b0b16d 100644 --- a/d2core/d2map/d2maprenderer/renderer.go +++ b/d2core/d2map/d2maprenderer/renderer.go @@ -71,8 +71,8 @@ func (mr *MapRenderer) Render(target d2render.Surface) { if mr.debugVisLevel > 0 { mr.renderDebug(mr.debugVisLevel, target, startX, startY, endX, endY) } - mr.renderPass2(target, startX, startY, endX, endY) mr.renderPass3(target, startX, startY, endX, endY) + mr.renderPass4(target, startX, startY, endX, endY) } func (mr *MapRenderer) MoveCameraTo(x, y float64) { @@ -95,6 +95,7 @@ func (mr *MapRenderer) WorldToOrtho(x, y float64) (float64, float64) { return mr.viewport.WorldToOrtho(x, y) } +// Lower wall tiles, tile shadews, floor tiles func (mr *MapRenderer) renderPass1(target d2render.Surface, startX, startY, endX, endY int) { for tileY := startY; tileY < endY; tileY++ { for tileX := startX; tileX < endX; tileX++ { @@ -106,7 +107,32 @@ func (mr *MapRenderer) renderPass1(target d2render.Surface, startX, startY, endX } } +// Objects below walls func (mr *MapRenderer) renderPass2(target d2render.Surface, startX, startY, endX, endY int) { + for tileY := startY; tileY < endY; tileY++ { + for tileX := startX; tileX < endX; tileX++ { + mr.viewport.PushTranslationWorld(float64(tileX), float64(tileY)) + + // TODO: Do not loop over every entity every frame + for _, mapEntity := range *mr.mapEngine.Entities() { + entityX, entityY := mapEntity.GetPosition() + if (int(entityX) != tileX) || (int(entityY) != tileY) { + continue + } + if mapEntity.GetLayer() != 1 { + continue + } + target.PushTranslation(mr.viewport.GetTranslationScreen()) + mapEntity.Render(target) + target.Pop() + } + mr.viewport.PopTranslation() + } + } +} + +// Upper wall tiles, objects that are on top of walls +func (mr *MapRenderer) renderPass3(target d2render.Surface, startX, startY, endX, endY int) { for tileY := startY; tileY < endY; tileY++ { for tileX := startX; tileX < endX; tileX++ { tile := mr.mapEngine.TileAt(tileX, tileY) @@ -119,6 +145,9 @@ func (mr *MapRenderer) renderPass2(target d2render.Surface, startX, startY, endX if (int(entityX) != tileX) || (int(entityY) != tileY) { continue } + if mapEntity.GetLayer() == 1 { + continue + } target.PushTranslation(mr.viewport.GetTranslationScreen()) mapEntity.Render(target) target.Pop() @@ -128,7 +157,8 @@ func (mr *MapRenderer) renderPass2(target d2render.Surface, startX, startY, endX } } -func (mr *MapRenderer) renderPass3(target d2render.Surface, startX, startY, endX, endY int) { +// Roof tiles +func (mr *MapRenderer) renderPass4(target d2render.Surface, startX, startY, endX, endY int) { for tileY := startY; tileY < endY; tileY++ { for tileX := startX; tileX < endX; tileX++ { tile := mr.mapEngine.TileAt(tileX, tileY)