diff --git a/d2common/d2enum/animation_mode.go b/d2common/d2enum/animation_mode.go index 0b236437..3ea2357d 100644 --- a/d2common/d2enum/animation_mode.go +++ b/d2common/d2enum/animation_mode.go @@ -1,52 +1,60 @@ package d2enum -type AnimationMode int +type PlayerAnimationMode int +type MonsterAnimationMode int +type ObjectAnimationMode int const ( - AnimationModePlayerDeath AnimationMode = 0 // DT - AnimationModePlayerNeutral AnimationMode = 1 // NU - AnimationModePlayerWalk AnimationMode = 2 // WL - AnimationModePlayerRun AnimationMode = 3 // RN - AnimationModePlayerGetHit AnimationMode = 4 // GH - AnimationModePlayerTownNeutral AnimationMode = 5 // TN - AnimationModePlayerTownWalk AnimationMode = 6 // TW - AnimationModePlayerAttack1 AnimationMode = 7 // A1 - AnimationModePlayerAttack2 AnimationMode = 8 // A2 - AnimationModePlayerBlock AnimationMode = 9 // BL - AnimationModePlayerCast AnimationMode = 10 // SC - AnimationModePlayerThrow AnimationMode = 11 // TH - AnimationModePlayerKick AnimationMode = 12 // KK - AnimationModePlayerSkill1 AnimationMode = 13 // S1 - AnimationModePlayerSkill2 AnimationMode = 14 // S2 - AnimationModePlayerSkill3 AnimationMode = 15 // S3 - AnimationModePlayerSkill4 AnimationMode = 16 // S4 - AnimationModePlayerDead AnimationMode = 17 // DD - AnimationModePlayerSequence AnimationMode = 18 // GH - AnimationModePlayerKnockBack AnimationMode = 19 // GH - AnimationModeMonsterDeath AnimationMode = 20 // DT - AnimationModeMonsterNeutral AnimationMode = 21 // NU - AnimationModeMonsterWalk AnimationMode = 22 // WL - AnimationModeMonsterGetHit AnimationMode = 23 // GH - AnimationModeMonsterAttack1 AnimationMode = 24 // A1 - AnimationModeMonsterAttack2 AnimationMode = 25 // A2 - AnimationModeMonsterBlock AnimationMode = 26 // BL - AnimationModeMonsterCast AnimationMode = 27 // SC - AnimationModeMonsterSkill1 AnimationMode = 28 // S1 - AnimationModeMonsterSkill2 AnimationMode = 29 // S2 - AnimationModeMonsterSkill3 AnimationMode = 30 // S3 - AnimationModeMonsterSkill4 AnimationMode = 31 // S4 - AnimationModeMonsterDead AnimationMode = 32 // DD - AnimationModeMonsterKnockback AnimationMode = 33 // GH - AnimationModeMonsterSequence AnimationMode = 34 // xx - AnimationModeMonsterRun AnimationMode = 35 // RN - AnimationModeObjectNeutral AnimationMode = 36 // NU - AnimationModeObjectOperating AnimationMode = 37 // OP - AnimationModeObjectOpened AnimationMode = 38 // ON - AnimationModeObjectSpecial1 AnimationMode = 39 // S1 - AnimationModeObjectSpecial2 AnimationMode = 40 // S2 - AnimationModeObjectSpecial3 AnimationMode = 41 // S3 - AnimationModeObjectSpecial4 AnimationMode = 42 // S4 - AnimationModeObjectSpecial5 AnimationMode = 43 // S5 + AnimationModePlayerDeath PlayerAnimationMode = iota // DT + AnimationModePlayerNeutral // NU + AnimationModePlayerWalk // WL + AnimationModePlayerRun // RN + AnimationModePlayerGetHit // GH + AnimationModePlayerTownNeutral // TN + AnimationModePlayerTownWalk // TW + AnimationModePlayerAttack1 // A1 + AnimationModePlayerAttack2 // A2 + AnimationModePlayerBlock // BL + AnimationModePlayerCast // SC + AnimationModePlayerThrow // TH + AnimationModePlayerKick // KK + AnimationModePlayerSkill1 // S1 + AnimationModePlayerSkill2 // S2 + AnimationModePlayerSkill3 // S3 + AnimationModePlayerSkill4 // S4 + AnimationModePlayerDead // DD + AnimationModePlayerSequence // GH + AnimationModePlayerKnockBack // GH +) +const ( + AnimationModeMonsterDeath MonsterAnimationMode = iota // DT + AnimationModeMonsterNeutral // NU + AnimationModeMonsterWalk // WL + AnimationModeMonsterGetHit // GH + AnimationModeMonsterAttack1 // A1 + AnimationModeMonsterAttack2 // A2 + AnimationModeMonsterBlock // BL + AnimationModeMonsterCast // SC + AnimationModeMonsterSkill1 // S1 + AnimationModeMonsterSkill2 // S2 + AnimationModeMonsterSkill3 // S3 + AnimationModeMonsterSkill4 // S4 + AnimationModeMonsterDead // DD + AnimationModeMonsterKnockback // GH + AnimationModeMonsterSequence // xx + AnimationModeMonsterRun // RN +) +const ( + AnimationModeObjectNeutral ObjectAnimationMode = iota // NU + AnimationModeObjectOperating // OP + AnimationModeObjectOpened // ON + AnimationModeObjectSpecial1 // S1 + AnimationModeObjectSpecial2 // S2 + AnimationModeObjectSpecial3 // S3 + AnimationModeObjectSpecial4 // S4 + AnimationModeObjectSpecial5 // S5 ) -//go:generate stringer -linecomment -type AnimationMode +//go:generate stringer -linecomment -type PlayerAnimationMode +//go:generate stringer -linecomment -type MonsterAnimationMode +//go:generate stringer -linecomment -type ObjectAnimationMode diff --git a/d2common/d2enum/animation_mode_string.go b/d2common/d2enum/animation_mode_string.go deleted file mode 100644 index 2b655afb..00000000 --- a/d2common/d2enum/animation_mode_string.go +++ /dev/null @@ -1,66 +0,0 @@ -// Code generated by "stringer -linecomment -type AnimationMode"; DO NOT EDIT. - -package d2enum - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[AnimationModePlayerDeath-0] - _ = x[AnimationModePlayerNeutral-1] - _ = x[AnimationModePlayerWalk-2] - _ = x[AnimationModePlayerRun-3] - _ = x[AnimationModePlayerGetHit-4] - _ = x[AnimationModePlayerTownNeutral-5] - _ = x[AnimationModePlayerTownWalk-6] - _ = x[AnimationModePlayerAttack1-7] - _ = x[AnimationModePlayerAttack2-8] - _ = x[AnimationModePlayerBlock-9] - _ = x[AnimationModePlayerCast-10] - _ = x[AnimationModePlayerThrow-11] - _ = x[AnimationModePlayerKick-12] - _ = x[AnimationModePlayerSkill1-13] - _ = x[AnimationModePlayerSkill2-14] - _ = x[AnimationModePlayerSkill3-15] - _ = x[AnimationModePlayerSkill4-16] - _ = x[AnimationModePlayerDead-17] - _ = x[AnimationModePlayerSequence-18] - _ = x[AnimationModePlayerKnockBack-19] - _ = x[AnimationModeMonsterDeath-20] - _ = x[AnimationModeMonsterNeutral-21] - _ = x[AnimationModeMonsterWalk-22] - _ = x[AnimationModeMonsterGetHit-23] - _ = x[AnimationModeMonsterAttack1-24] - _ = x[AnimationModeMonsterAttack2-25] - _ = x[AnimationModeMonsterBlock-26] - _ = x[AnimationModeMonsterCast-27] - _ = x[AnimationModeMonsterSkill1-28] - _ = x[AnimationModeMonsterSkill2-29] - _ = x[AnimationModeMonsterSkill3-30] - _ = x[AnimationModeMonsterSkill4-31] - _ = x[AnimationModeMonsterDead-32] - _ = x[AnimationModeMonsterKnockback-33] - _ = x[AnimationModeMonsterSequence-34] - _ = x[AnimationModeMonsterRun-35] - _ = x[AnimationModeObjectNeutral-36] - _ = x[AnimationModeObjectOperating-37] - _ = x[AnimationModeObjectOpened-38] - _ = x[AnimationModeObjectSpecial1-39] - _ = x[AnimationModeObjectSpecial2-40] - _ = x[AnimationModeObjectSpecial3-41] - _ = x[AnimationModeObjectSpecial4-42] - _ = x[AnimationModeObjectSpecial5-43] -} - -const _AnimationMode_name = "DTNUWLRNGHTNTWA1A2BLSCTHKKS1S2S3S4DDGHGHDTNUWLGHA1A2BLSCS1S2S3S4DDGHxxRNNUOPONS1S2S3S4S5" - -var _AnimationMode_index = [...]uint8{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88} - -func (i AnimationMode) String() string { - if i < 0 || i >= AnimationMode(len(_AnimationMode_index)-1) { - return "AnimationMode(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _AnimationMode_name[_AnimationMode_index[i]:_AnimationMode_index[i+1]] -} diff --git a/d2common/d2enum/monsteranimationmode_string.go b/d2common/d2enum/monsteranimationmode_string.go new file mode 100644 index 00000000..d8a00a15 --- /dev/null +++ b/d2common/d2enum/monsteranimationmode_string.go @@ -0,0 +1,38 @@ +// Code generated by "stringer -linecomment -type MonsterAnimationMode"; DO NOT EDIT. + +package d2enum + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[AnimationModeMonsterDeath-0] + _ = x[AnimationModeMonsterNeutral-1] + _ = x[AnimationModeMonsterWalk-2] + _ = x[AnimationModeMonsterGetHit-3] + _ = x[AnimationModeMonsterAttack1-4] + _ = x[AnimationModeMonsterAttack2-5] + _ = x[AnimationModeMonsterBlock-6] + _ = x[AnimationModeMonsterCast-7] + _ = x[AnimationModeMonsterSkill1-8] + _ = x[AnimationModeMonsterSkill2-9] + _ = x[AnimationModeMonsterSkill3-10] + _ = x[AnimationModeMonsterSkill4-11] + _ = x[AnimationModeMonsterDead-12] + _ = x[AnimationModeMonsterKnockback-13] + _ = x[AnimationModeMonsterSequence-14] + _ = x[AnimationModeMonsterRun-15] +} + +const _MonsterAnimationMode_name = "DTNUWLGHA1A2BLSCS1S2S3S4DDGHxxRN" + +var _MonsterAnimationMode_index = [...]uint8{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32} + +func (i MonsterAnimationMode) String() string { + if i < 0 || i >= MonsterAnimationMode(len(_MonsterAnimationMode_index)-1) { + return "MonsterAnimationMode(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _MonsterAnimationMode_name[_MonsterAnimationMode_index[i]:_MonsterAnimationMode_index[i+1]] +} diff --git a/d2common/d2enum/objectanimationmode_string.go b/d2common/d2enum/objectanimationmode_string.go new file mode 100644 index 00000000..95a06876 --- /dev/null +++ b/d2common/d2enum/objectanimationmode_string.go @@ -0,0 +1,30 @@ +// Code generated by "stringer -linecomment -type ObjectAnimationMode"; DO NOT EDIT. + +package d2enum + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[AnimationModeObjectNeutral-0] + _ = x[AnimationModeObjectOperating-1] + _ = x[AnimationModeObjectOpened-2] + _ = x[AnimationModeObjectSpecial1-3] + _ = x[AnimationModeObjectSpecial2-4] + _ = x[AnimationModeObjectSpecial3-5] + _ = x[AnimationModeObjectSpecial4-6] + _ = x[AnimationModeObjectSpecial5-7] +} + +const _ObjectAnimationMode_name = "NUOPONS1S2S3S4S5" + +var _ObjectAnimationMode_index = [...]uint8{0, 2, 4, 6, 8, 10, 12, 14, 16} + +func (i ObjectAnimationMode) String() string { + if i < 0 || i >= ObjectAnimationMode(len(_ObjectAnimationMode_index)-1) { + return "ObjectAnimationMode(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _ObjectAnimationMode_name[_ObjectAnimationMode_index[i]:_ObjectAnimationMode_index[i+1]] +} diff --git a/d2common/d2enum/playeranimationmode_string.go b/d2common/d2enum/playeranimationmode_string.go new file mode 100644 index 00000000..7de7978e --- /dev/null +++ b/d2common/d2enum/playeranimationmode_string.go @@ -0,0 +1,42 @@ +// Code generated by "stringer -linecomment -type PlayerAnimationMode"; DO NOT EDIT. + +package d2enum + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[AnimationModePlayerDeath-0] + _ = x[AnimationModePlayerNeutral-1] + _ = x[AnimationModePlayerWalk-2] + _ = x[AnimationModePlayerRun-3] + _ = x[AnimationModePlayerGetHit-4] + _ = x[AnimationModePlayerTownNeutral-5] + _ = x[AnimationModePlayerTownWalk-6] + _ = x[AnimationModePlayerAttack1-7] + _ = x[AnimationModePlayerAttack2-8] + _ = x[AnimationModePlayerBlock-9] + _ = x[AnimationModePlayerCast-10] + _ = x[AnimationModePlayerThrow-11] + _ = x[AnimationModePlayerKick-12] + _ = x[AnimationModePlayerSkill1-13] + _ = x[AnimationModePlayerSkill2-14] + _ = x[AnimationModePlayerSkill3-15] + _ = x[AnimationModePlayerSkill4-16] + _ = x[AnimationModePlayerDead-17] + _ = x[AnimationModePlayerSequence-18] + _ = x[AnimationModePlayerKnockBack-19] +} + +const _PlayerAnimationMode_name = "DTNUWLRNGHTNTWA1A2BLSCTHKKS1S2S3S4DDGHGH" + +var _PlayerAnimationMode_index = [...]uint8{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40} + +func (i PlayerAnimationMode) String() string { + if i < 0 || i >= PlayerAnimationMode(len(_PlayerAnimationMode_index)-1) { + return "PlayerAnimationMode(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _PlayerAnimationMode_name[_PlayerAnimationMode_index[i]:_PlayerAnimationMode_index[i+1]] +} diff --git a/d2core/d2map/d2mapentity/animated_composite.go b/d2core/d2map/d2mapentity/animated_composite.go deleted file mode 100644 index f3e551fe..00000000 --- a/d2core/d2map/d2mapentity/animated_composite.go +++ /dev/null @@ -1,120 +0,0 @@ -package d2mapentity - -import ( - "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" - "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" - "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" - "github.com/OpenDiablo2/OpenDiablo2/d2core/d2render" -) - -// AnimatedComposite represents a composite of animations that can be projected onto the map. -type AnimatedComposite struct { - mapEntity - //animationMode string - composite *d2asset.Composite - direction int - player *Player - objectLookup *d2datadict.ObjectLookupRecord -} - -// CreateAnimatedComposite creates an instance of AnimatedComposite -func CreateAnimatedComposite(x, y int, object *d2datadict.ObjectLookupRecord, palettePath string) (*AnimatedComposite, error) { - composite, err := d2asset.LoadComposite(object, palettePath) - if err != nil { - return nil, err - } - - entity := &AnimatedComposite{ - mapEntity: createMapEntity(x, y), - composite: composite, - objectLookup: object, - } - entity.mapEntity.directioner = entity.rotate - return entity, nil -} - -func (ac *AnimatedComposite) SetPlayer(player *Player) { - ac.player = player -} - -func (ac *AnimatedComposite) SetAnimationMode(animationMode string) error { - return ac.composite.SetMode(animationMode, ac.weaponClass, ac.direction) -} - -// SetMode changes the graphical mode of this animated entity -func (ac *AnimatedComposite) SetMode(animationMode, weaponClass string, direction int) error { - ac.composite.SetMode(animationMode, weaponClass, direction) - ac.direction = direction - ac.weaponClass = weaponClass - - err := ac.composite.SetMode(animationMode, weaponClass, direction) - if err != nil { - err = ac.composite.SetMode(animationMode, "HTH", direction) - ac.weaponClass = "HTH" - } - - return err -} - -// Render draws this animated entity onto the target -func (ac *AnimatedComposite) Render(target d2render.Surface) { - target.PushTranslation( - ac.offsetX+int((ac.subcellX-ac.subcellY)*16), - ac.offsetY+int(((ac.subcellX+ac.subcellY)*8)-5), - ) - defer target.Pop() - ac.composite.Render(target) -} - -// rotate sets direction and changes animation -func (ac *AnimatedComposite) rotate(angle float64) { - newAnimationMode := ac.GetAnimationMode().String() - newDirection := angleToDirection(angle) - - if newAnimationMode != ac.composite.GetAnimationMode() || newDirection != ac.direction { - ac.SetMode(newAnimationMode, ac.weaponClass, newDirection) - } -} - -func (ac *AnimatedComposite) GetAnimationMode() d2enum.AnimationMode { - var newAnimationMode d2enum.AnimationMode - if ac.player != nil { - newAnimationMode = ac.GetPlayerAnimationMode() - } else { - newAnimationMode = ac.GetMonsterAnimationMode() - } - - return newAnimationMode -} - -func (ac *AnimatedComposite) GetPlayerAnimationMode() d2enum.AnimationMode { - if ac.player.IsRunning() && !ac.IsAtTarget(){ - return d2enum.AnimationModePlayerRun - } - - if ac.player.IsInTown() { - if !ac.IsAtTarget() { - return d2enum.AnimationModePlayerTownWalk - } - - return d2enum.AnimationModePlayerTownNeutral - } - - if !ac.IsAtTarget() { - return d2enum.AnimationModePlayerWalk - } - - return d2enum.AnimationModePlayerNeutral -} - -func (ac *AnimatedComposite) GetMonsterAnimationMode() d2enum.AnimationMode { - if !ac.IsAtTarget() { - return d2enum.AnimationModeMonsterWalk - } - - return d2enum.AnimationModeMonsterNeutral -} - -func (ac *AnimatedComposite) Advance(elapsed float64) { - ac.composite.Advance(elapsed) -} diff --git a/d2core/d2map/d2mapentity/animated_entity.go b/d2core/d2map/d2mapentity/animated_entity.go index 022ef9d8..2444004b 100644 --- a/d2core/d2map/d2mapentity/animated_entity.go +++ b/d2core/d2map/d2mapentity/animated_entity.go @@ -40,8 +40,8 @@ func (ae *AnimatedEntity) GetDirection() int { } // rotate sets direction and changes animation -func (ae *AnimatedEntity) rotate(angle float64) { - ae.direction = angleToDirection(angle) +func (ae *AnimatedEntity) rotate(direction int) { + ae.direction = direction ae.animation.SetDirection(ae.direction) } diff --git a/d2core/d2map/d2mapentity/map_entity.go b/d2core/d2map/d2mapentity/map_entity.go index 84532978..83256a69 100644 --- a/d2core/d2map/d2mapentity/map_entity.go +++ b/d2core/d2map/d2mapentity/map_entity.go @@ -28,7 +28,7 @@ type mapEntity struct { path []d2astar.Pather done func() - directioner func(angle float64) + directioner func(direction int) } // createMapEntity creates an instance of mapEntity @@ -147,7 +147,7 @@ func (m *mapEntity) SetTarget(tx, ty float64, done func()) { tx, ty, ) - m.directioner(float64(angle)) + m.directioner(angleToDirection(float64(angle))) } } diff --git a/d2core/d2map/d2mapentity/npc.go b/d2core/d2map/d2mapentity/npc.go index a64502ca..ed5c68a7 100644 --- a/d2core/d2map/d2mapentity/npc.go +++ b/d2core/d2map/d2mapentity/npc.go @@ -7,29 +7,50 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" + "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" + "github.com/OpenDiablo2/OpenDiablo2/d2core/d2render" ) type NPC struct { - *AnimatedComposite - action int - HasPaths bool - Paths []d2common.Path - path int - isDone bool - repetitions int + mapEntity + composite *d2asset.Composite + action int + HasPaths bool + Paths []d2common.Path + path int + isDone bool + repetitions int + direction int + objectLookup *d2datadict.ObjectLookupRecord } func CreateNPC(x, y int, object *d2datadict.ObjectLookupRecord, direction int) *NPC { - entity, err := CreateAnimatedComposite(x, y, object, d2resource.PaletteUnits) + composite, err := d2asset.LoadComposite(object, d2resource.PaletteUnits) if err != nil { panic(err) } - result := &NPC{AnimatedComposite: entity, HasPaths: false} + result := &NPC{ + mapEntity: createMapEntity(x, y), + composite: composite, + objectLookup: object, + HasPaths: false, + } result.SetMode(object.Mode, object.Class, direction) + result.mapEntity.directioner = result.rotate + return result } +func (v *NPC) Render(target d2render.Surface) { + target.PushTranslation( + v.offsetX+int((v.subcellX-v.subcellY)*16), + v.offsetY+int(((v.subcellX+v.subcellY)*8)-5), + ) + defer target.Pop() + v.composite.Render(target) +} + func (v *NPC) Path() d2common.Path { return v.Paths[v.path] } @@ -51,7 +72,7 @@ func (v *NPC) SetPaths(paths []d2common.Path) { func (v *NPC) Advance(tickTime float64) { v.Step(tickTime) - v.AnimatedComposite.Advance(tickTime) + v.composite.Advance(tickTime) if v.HasPaths && v.wait() { // If at the target, set target to the next path. @@ -75,7 +96,7 @@ func (v *NPC) wait() bool { func (v *NPC) next() { v.isDone = true v.repetitions = 3 + rand.Intn(5) - newAnimationMode := d2enum.AnimationModeObjectNeutral + newAnimationMode := d2enum.AnimationModeMonsterNeutral // TODO: Figure out what 1-3 are for, 4 is correct. switch v.action { case 1: @@ -95,3 +116,30 @@ func (v *NPC) next() { v.SetMode(newAnimationMode.String(), v.weaponClass, v.direction) } } + +// rotate sets direction and changes animation +func (v *NPC) rotate(direction int) { + var newMode d2enum.MonsterAnimationMode + if !v.IsAtTarget() { + newMode = d2enum.AnimationModeMonsterWalk + } else { + newMode = d2enum.AnimationModeMonsterNeutral + } + if newMode.String() != v.composite.GetAnimationMode() || direction != v.direction { + v.SetMode(newMode.String(), v.weaponClass, direction) + } +} + +// SetMode changes the graphical mode of this animated entity +func (v *NPC) SetMode(animationMode, weaponClass string, direction int) error { + v.direction = direction + v.weaponClass = weaponClass + + err := v.composite.SetMode(animationMode, weaponClass, direction) + if err != nil { + err = v.composite.SetMode(animationMode, "HTH", direction) + v.weaponClass = "HTH" + } + + return err +} diff --git a/d2core/d2map/d2mapentity/object.go b/d2core/d2map/d2mapentity/object.go new file mode 100644 index 00000000..81bfb752 --- /dev/null +++ b/d2core/d2map/d2mapentity/object.go @@ -0,0 +1,66 @@ +package d2mapentity + +import ( + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" + "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" + "github.com/OpenDiablo2/OpenDiablo2/d2core/d2render" +) + +// Object represents a composite of animations that can be projected onto the map. +type Object struct { + mapEntity + composite *d2asset.Composite + direction int + objectRecord *d2datadict.ObjectRecord + objectLookup *d2datadict.ObjectLookupRecord +} + +// CreateObject creates an instance of AnimatedComposite +func CreateObject(x, y int, object *d2datadict.ObjectLookupRecord, palettePath string) (*Object, error) { + composite, err := d2asset.LoadComposite(object, palettePath) + if err != nil { + return nil, err + } + + entity := &Object{ + mapEntity: createMapEntity(x, y), + composite: composite, + objectLookup: object, + } + entity.mapEntity.directioner = entity.rotate + entity.objectRecord = d2datadict.Objects[object.ObjectsTxtId] + return entity, nil +} + +// SetMode changes the graphical mode of this animated entity +func (ob *Object) SetMode(animationMode, weaponClass string, direction int) error { + ob.composite.SetMode(animationMode, weaponClass, direction) + ob.direction = direction + ob.weaponClass = weaponClass + + err := ob.composite.SetMode(animationMode, weaponClass, direction) + if err != nil { + err = ob.composite.SetMode(animationMode, "HTH", direction) + ob.weaponClass = "HTH" + } + + return err +} + +// Render draws this animated entity onto the target +func (ob *Object) Render(target d2render.Surface) { + target.PushTranslation( + ob.offsetX+int((ob.subcellX-ob.subcellY)*16), + ob.offsetY+int(((ob.subcellX+ob.subcellY)*8)-5), + ) + defer target.Pop() + ob.composite.Render(target) +} + +// rotate sets direction and changes animation +func (ob *Object) rotate(direction int) { +} + +func (ob *Object) Advance(elapsed float64) { + ob.composite.Advance(elapsed) +} diff --git a/d2core/d2map/d2mapentity/player.go b/d2core/d2map/d2mapentity/player.go index e0281cd5..c82aaa16 100644 --- a/d2core/d2map/d2mapentity/player.go +++ b/d2core/d2map/d2mapentity/player.go @@ -6,13 +6,15 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" + "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2render" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui" ) type Player struct { - *AnimatedComposite + mapEntity + composite *d2asset.Composite Equipment d2inventory.CharacterEquipment Id string direction int @@ -46,27 +48,28 @@ func CreatePlayer(id, name string, x, y int, direction int, heroType d2enum.Hero LH: equipment.LeftHand.GetItemCode(), } - entity, err := CreateAnimatedComposite(x, y, object, d2resource.PaletteUnits) + composite, err := d2asset.LoadComposite(object, d2resource.PaletteUnits) if err != nil { panic(err) } - entity.SetSpeed(baseRunSpeed) result := &Player{ - Id: id, - AnimatedComposite: entity, - Equipment: equipment, - direction: direction, - Name: name, - nameLabel: d2ui.CreateLabel(d2resource.FontFormal11, d2resource.PaletteStatic), - isRunToggled: true, - isInTown: true, - isRunning: true, + Id: id, + mapEntity: createMapEntity(x, y), + composite: composite, + Equipment: equipment, + direction: direction, + Name: name, + nameLabel: d2ui.CreateLabel(d2resource.FontFormal11, d2resource.PaletteStatic), + isRunToggled: true, + isInTown: true, + isRunning: true, } + result.SetSpeed(baseRunSpeed) + result.mapEntity.directioner = result.rotate result.nameLabel.Alignment = d2ui.LabelAlignCenter result.nameLabel.SetText(name) result.nameLabel.Color = color.White - result.SetPlayer(result) err = result.SetMode(d2enum.AnimationModePlayerTownNeutral.String(), equipment.RightHand.GetWeaponClass(), direction) if err != nil { panic(err) @@ -106,25 +109,71 @@ func (p Player) IsInTown() bool { func (v *Player) Advance(tickTime float64) { v.Step(tickTime) - v.AnimatedComposite.Advance(tickTime) + v.composite.Advance(tickTime) if v.lastPathSize != len(v.path) { v.lastPathSize = len(v.path) } - if v.AnimatedComposite.composite.GetAnimationMode() != v.animationMode { - v.animationMode = v.AnimatedComposite.composite.GetAnimationMode() + if v.composite.GetAnimationMode() != v.animationMode { + v.animationMode = v.composite.GetAnimationMode() } } func (v *Player) Render(target d2render.Surface) { - v.AnimatedComposite.Render(target) - offX := v.AnimatedComposite.offsetX + int((v.AnimatedComposite.subcellX-v.AnimatedComposite.subcellY)*16) - offY := v.AnimatedComposite.offsetY + int(((v.AnimatedComposite.subcellX+v.AnimatedComposite.subcellY)*8)-5) - v.nameLabel.X = offX - v.nameLabel.Y = offY - 100 + target.PushTranslation( + v.offsetX+int((v.subcellX-v.subcellY)*16), + v.offsetY+int(((v.subcellX+v.subcellY)*8)-5), + ) + defer target.Pop() + v.composite.Render(target) + v.nameLabel.X = v.offsetX + v.nameLabel.Y = v.offsetY - 100 v.nameLabel.Render(target) } -func (v *Player) GetPosition() (float64, float64) { - return v.AnimatedComposite.GetPosition() +func (v *Player) SetMode(animationMode, weaponClass string, direction int) error { + v.composite.SetMode(animationMode, weaponClass, direction) + v.direction = direction + v.weaponClass = weaponClass + + err := v.composite.SetMode(animationMode, weaponClass, direction) + if err != nil { + err = v.composite.SetMode(animationMode, "HTH", direction) + v.weaponClass = "HTH" + } + + return err +} + +func (v *Player) GetAnimationMode() d2enum.PlayerAnimationMode { + if v.IsRunning() && !v.IsAtTarget() { + return d2enum.AnimationModePlayerRun + } + + if v.IsInTown() { + if !v.IsAtTarget() { + return d2enum.AnimationModePlayerTownWalk + } + + return d2enum.AnimationModePlayerTownNeutral + } + + if !v.IsAtTarget() { + return d2enum.AnimationModePlayerWalk + } + + return d2enum.AnimationModePlayerNeutral +} + +func (v *Player) SetAnimationMode(animationMode string) error { + return v.composite.SetMode(animationMode, v.weaponClass, v.direction) +} + +// rotate sets direction and changes animation +func (v *Player) rotate(direction int) { + newAnimationMode := v.GetAnimationMode().String() + + if newAnimationMode != v.composite.GetAnimationMode() || direction != v.direction { + v.SetMode(newAnimationMode, v.weaponClass, direction) + } } diff --git a/d2core/d2map/d2mapstamp/stamp.go b/d2core/d2map/d2mapstamp/stamp.go index 4be73b17..0bd4b22b 100644 --- a/d2core/d2map/d2mapstamp/stamp.go +++ b/d2core/d2map/d2mapstamp/stamp.go @@ -126,7 +126,7 @@ func (mr *Stamp) Entities(tileOffsetX, tileOffsetY int) []d2mapentity.MapEntity } case d2datadict.ObjectTypeItem: if object.ObjectInfo != nil && object.ObjectInfo.Draw && object.Lookup.Base != "" && object.Lookup.Token != "" { - entity, err := d2mapentity.CreateAnimatedComposite((tileOffsetX*5)+object.X, (tileOffsetY*5)+object.Y, object.Lookup, d2resource.PaletteUnits) + entity, err := d2mapentity.CreateObject((tileOffsetX*5)+object.X, (tileOffsetY*5)+object.Y, object.Lookup, d2resource.PaletteUnits) if err != nil { panic(err) } diff --git a/d2game/d2gamescreen/character_select.go b/d2game/d2gamescreen/character_select.go index 5f43b6e1..b0a96241 100644 --- a/d2game/d2gamescreen/character_select.go +++ b/d2game/d2gamescreen/character_select.go @@ -246,7 +246,7 @@ func (v *CharacterSelect) OnMouseButtonDown(event d2input.MouseEvent) bool { func (v *CharacterSelect) Advance(tickTime float64) error { for _, hero := range v.characterImage { if hero != nil { - hero.AnimatedComposite.Advance(tickTime) + hero.Advance(tickTime) } } diff --git a/d2game/d2gamescreen/game.go b/d2game/d2gamescreen/game.go index dc8a4671..53e13681 100644 --- a/d2game/d2gamescreen/game.go +++ b/d2game/d2gamescreen/game.go @@ -118,14 +118,14 @@ func (v *Game) Advance(tickTime float64) error { // Update the camera to focus on the player if v.localPlayer != nil && !v.gameControls.FreeCam { - rx, ry := v.mapRenderer.WorldToOrtho(v.localPlayer.AnimatedComposite.LocationX/5, v.localPlayer.AnimatedComposite.LocationY/5) + rx, ry := v.mapRenderer.WorldToOrtho(v.localPlayer.LocationX/5, v.localPlayer.LocationY/5) v.mapRenderer.MoveCameraTo(rx, ry) } return nil } func (v *Game) OnPlayerMove(x, y float64) { - heroPosX := v.localPlayer.AnimatedComposite.LocationX / 5.0 - heroPosY := v.localPlayer.AnimatedComposite.LocationY / 5.0 + heroPosX := v.localPlayer.LocationX / 5.0 + heroPosY := v.localPlayer.LocationY / 5.0 v.gameClient.SendPacketToServer(d2netpacket.CreateMovePlayerPacket(v.gameClient.PlayerId, heroPosX, heroPosY, x, y)) } diff --git a/d2game/d2player/game_controls.go b/d2game/d2player/game_controls.go index 600ab467..c7fe485d 100644 --- a/d2game/d2player/game_controls.go +++ b/d2game/d2player/game_controls.go @@ -49,7 +49,10 @@ type GameControls struct { } type ActionableType int -type ActionableRegion struct { ActionableTypeId ActionableType; Rect d2common.Rectangle } +type ActionableRegion struct { + ActionableTypeId ActionableType + Rect d2common.Rectangle +} const ( // Since they require special handling, not considering (1) globes, (2) content of the mini panel, (3) belt @@ -81,15 +84,15 @@ func NewGameControls(hero *d2mapentity.Player, mapEngine *d2mapengine.MapEngine, heroStats: NewHeroStats(), escapeMenu: NewEscapeMenu(), zoneChangeText: &label, - actionableRegions: []ActionableRegion { - {leftSkill, d2common.Rectangle{Left:115, Top:550, Width:50, Height:50 }}, - {leftSelec, d2common.Rectangle{Left:206, Top:563, Width:30, Height:30 }}, - {xp, d2common.Rectangle{Left:253, Top:560, Width:125, Height:5 }}, - {walkRun, d2common.Rectangle{Left:255, Top:573, Width:17, Height:20 }}, - {stamina, d2common.Rectangle{Left:273, Top:573, Width:105, Height:20 }}, - {miniPanel, d2common.Rectangle{Left:393, Top:563, Width:12, Height:23 }}, - {rightSelec,d2common.Rectangle{Left:562, Top:563, Width:30, Height:30 }}, - {rightSkill,d2common.Rectangle{Left:634, Top:550, Width:50, Height:50 }}, + actionableRegions: []ActionableRegion{ + {leftSkill, d2common.Rectangle{Left: 115, Top: 550, Width: 50, Height: 50}}, + {leftSelec, d2common.Rectangle{Left: 206, Top: 563, Width: 30, Height: 30}}, + {xp, d2common.Rectangle{Left: 253, Top: 560, Width: 125, Height: 5}}, + {walkRun, d2common.Rectangle{Left: 255, Top: 573, Width: 17, Height: 20}}, + {stamina, d2common.Rectangle{Left: 273, Top: 573, Width: 105, Height: 20}}, + {miniPanel, d2common.Rectangle{Left: 393, Top: 563, Width: 12, Height: 23}}, + {rightSelec, d2common.Rectangle{Left: 562, Top: 563, Width: 30, Height: 30}}, + {rightSkill, d2common.Rectangle{Left: 634, Top: 550, Width: 50, Height: 50}}, }, } @@ -239,8 +242,8 @@ func (g *GameControls) OnMouseButtonDown(event d2input.MouseEvent) bool { func (g *GameControls) ShootMissile(px float64, py float64) bool { missile, err := d2mapentity.CreateMissile( - int(g.hero.AnimatedComposite.LocationX), - int(g.hero.AnimatedComposite.LocationY), + int(g.hero.LocationX), + int(g.hero.LocationY), d2datadict.Missiles[missileID], ) if err != nil { @@ -248,8 +251,8 @@ func (g *GameControls) ShootMissile(px float64, py float64) bool { } rads := d2common.GetRadiansBetween( - g.hero.AnimatedComposite.LocationX, - g.hero.AnimatedComposite.LocationY, + g.hero.LocationX, + g.hero.LocationY, px*5, py*5, ) @@ -434,14 +437,22 @@ func (g *GameControls) onHoverActionable(item ActionableType) { // Handles what to do when an actionable is clicked func (g *GameControls) onClickActionable(item ActionableType) { switch item { - case leftSkill: log.Println("Left Skill Action Pressed") - case leftSelec: log.Println("Left Skill Selector Action Pressed") - case xp: log.Println("XP Action Pressed") - case walkRun: log.Println("Walk/Run Action Pressed") - case stamina: log.Println("Stamina Action Pressed") - case miniPanel: log.Println("Mini Panel Action Pressed") - case rightSelec: log.Println("Right Skill Selector Action Pressed") - case rightSkill: log.Println("Right Skill Action Pressed") + case leftSkill: + log.Println("Left Skill Action Pressed") + case leftSelec: + log.Println("Left Skill Selector Action Pressed") + case xp: + log.Println("XP Action Pressed") + case walkRun: + log.Println("Walk/Run Action Pressed") + case stamina: + log.Println("Stamina Action Pressed") + case miniPanel: + log.Println("Mini Panel Action Pressed") + case rightSelec: + log.Println("Right Skill Selector Action Pressed") + case rightSkill: + log.Println("Right Skill Action Pressed") default: log.Printf("Unrecognized ActionableType(%d) being clicked\n", item) } diff --git a/d2networking/d2client/game_client.go b/d2networking/d2client/game_client.go index 6a8a1acd..d8ba6833 100644 --- a/d2networking/d2client/game_client.go +++ b/d2networking/d2client/game_client.go @@ -88,7 +88,7 @@ func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error { player := g.Players[movePlayer.PlayerId] path, _, _ := g.MapEngine.PathFind(movePlayer.StartX, movePlayer.StartY, movePlayer.DestX, movePlayer.DestY) if len(path) > 0 { - player.AnimatedComposite.SetPath(path, func() { + player.SetPath(path, func() { tile := g.MapEngine.TileAt(player.TileX, player.TileY) if tile == nil { return @@ -100,7 +100,7 @@ func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error { } else { player.SetIsInTown(false) } - player.AnimatedComposite.SetAnimationMode(player.GetAnimationMode().String()) + player.SetAnimationMode(player.GetAnimationMode().String()) }) } case d2netpackettype.Ping: