mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-12-26 12:06:24 -05:00
Various map entity reworks (#439)
* Use integer directions for rotating map entities * Manage composite directly in npc * Player manages its own composite * Split up animation mode types Players, monsters, objects all have their own types * Clean up AnimatedEntity * Rename AnimatedEntity -> Object * Keep the object txt record on hand in Object
This commit is contained in:
parent
6328cd50c4
commit
02605227c3
@ -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
|
||||
|
@ -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]]
|
||||
}
|
38
d2common/d2enum/monsteranimationmode_string.go
Normal file
38
d2common/d2enum/monsteranimationmode_string.go
Normal file
@ -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]]
|
||||
}
|
30
d2common/d2enum/objectanimationmode_string.go
Normal file
30
d2common/d2enum/objectanimationmode_string.go
Normal file
@ -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]]
|
||||
}
|
42
d2common/d2enum/playeranimationmode_string.go
Normal file
42
d2common/d2enum/playeranimationmode_string.go
Normal file
@ -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]]
|
||||
}
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
66
d2core/d2map/d2mapentity/object.go
Normal file
66
d2core/d2map/d2mapentity/object.go
Normal file
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user