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)