Skip to content

Commit

Permalink
Add support for missiles (OpenDiablo2#308)
Browse files Browse the repository at this point in the history
* WIP: Add support for missiles

Break AnimatedEntity into two parts to support single and composite animations.  Summon misssiles on right click.

* Break animated entity down further

Move npc only logic to npc struct, reduce duplication in map entities

* Change a bunch of int32s to int
  • Loading branch information
nicholas-eden authored Feb 23, 2020
1 parent 2953d21 commit bdfdeda
Show file tree
Hide file tree
Showing 17 changed files with 461 additions and 272 deletions.
10 changes: 5 additions & 5 deletions d2common/d2data/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import (
)

type Object struct {
Type int32
Id int32
X int32
Y int32
Flags int32
Type int
Id int
X int
Y int
Flags int
Paths []d2common.Path
Lookup *d2datadict.ObjectLookupRecord
ObjectInfo *d2datadict.ObjectRecord
Expand Down
20 changes: 10 additions & 10 deletions d2common/d2fileformats/d2ds1/ds1.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,11 @@ func LoadDS1(fileData []byte) DS1 {
ds1.Objects = make([]d2data.Object, numberOfObjects)
for objIdx := 0; objIdx < int(numberOfObjects); objIdx++ {
newObject := d2data.Object{}
newObject.Type = br.GetInt32()
newObject.Id = br.GetInt32()
newObject.X = br.GetInt32()
newObject.Y = br.GetInt32()
newObject.Flags = br.GetInt32()
newObject.Type = int(br.GetInt32())
newObject.Id = int(br.GetInt32())
newObject.X = int(br.GetInt32())
newObject.Y = int(br.GetInt32())
newObject.Flags = int(br.GetInt32())
//TODO: There's a crash here, we aren't loading this data right....
newObject.Lookup = d2datadict.LookupObject(int(ds1.Act), int(newObject.Type), int(newObject.Id))
if newObject.Lookup != nil && newObject.Lookup.ObjectsTxtId != -1 {
Expand Down Expand Up @@ -212,8 +212,8 @@ func LoadDS1(fileData []byte) DS1 {
numberOfNpcs := br.GetInt32()
for npcIdx := 0; npcIdx < int(numberOfNpcs); npcIdx++ {
numPaths := br.GetInt32()
npcX := br.GetInt32()
npcY := br.GetInt32()
npcX := int(br.GetInt32())
npcY := int(br.GetInt32())
objIdx := -1
for idx, ds1Obj := range ds1.Objects {
if ds1Obj.X == npcX && ds1Obj.Y == npcY {
Expand All @@ -227,10 +227,10 @@ func LoadDS1(fileData []byte) DS1 {
}
for pathIdx := 0; pathIdx < int(numPaths); pathIdx++ {
newPath := d2common.Path{}
newPath.X = br.GetInt32()
newPath.Y = br.GetInt32()
newPath.X = int(br.GetInt32())
newPath.Y = int(br.GetInt32())
if ds1.Version >= 15 {
newPath.Action = br.GetInt32()
newPath.Action = int(br.GetInt32())
}
ds1.Objects[objIdx].Paths[pathIdx] = newPath
}
Expand Down
1 change: 1 addition & 0 deletions d2common/d2resource/resource_paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ const (
ObjectData = "/data/global/objects"
AnimationData = "/data/global/animdata.d2"
PlayerAnimationBase = "/data/global/CHARS"
MissileData = "/data/global/missiles"

// --- Inventory Data ---

Expand Down
6 changes: 3 additions & 3 deletions d2common/path.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package d2common

type Path struct {
X int32
Y int32
Action int32
X int
Y int
Action int
}
7 changes: 3 additions & 4 deletions d2core/d2asset/animation_manager.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package d2asset

import (
"errors"
"fmt"
"path/filepath"
"strings"
Expand All @@ -28,7 +27,8 @@ func (am *animationManager) loadAnimation(animationPath, palettePath string, tra
}

var animation *Animation
switch strings.ToLower(filepath.Ext(animationPath)) {
ext := strings.ToLower(filepath.Ext(animationPath))
switch ext {
case ".dc6":
dc6, err := loadDC6(animationPath, palettePath)
if err != nil {
Expand All @@ -54,9 +54,8 @@ func (am *animationManager) loadAnimation(animationPath, palettePath string, tra
if err != nil {
return nil, err
}

default:
return nil, errors.New("unknown animation format")
return nil, fmt.Errorf("unknown animation format: %s", ext)
}

if err := am.cache.Insert(cachePath, animation.Clone(), 1); err != nil {
Expand Down
1 change: 1 addition & 0 deletions d2core/d2asset/composite.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func (c *Composite) SetMode(animationMode, weaponClass string, direction int) er
return err
}

c.ResetPlayedCount()
c.mode = mode
return nil
}
Expand Down
81 changes: 81 additions & 0 deletions d2core/d2map/animated_composite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package d2map

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
}

// 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,
}
entity.mapEntity.directioner = entity.rotate
return entity, nil
}

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.animationMode = animationMode
ac.direction = direction

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) {
// TODO: Check if is in town and if is player.
newAnimationMode := ac.animationMode
if !ac.IsAtTarget() {
newAnimationMode = d2enum.AnimationModeMonsterWalk.String()
}

if newAnimationMode != ac.animationMode {
ac.SetMode(newAnimationMode, ac.weaponClass, ac.direction)
}

newDirection := angleToDirection(angle, ac.composite.GetDirectionCount())
if newDirection != ac.direction {
ac.SetMode(ac.animationMode, ac.weaponClass, newDirection)
}
}

func (ac *AnimatedComposite) Advance(elapsed float64) {
ac.composite.Advance(elapsed)
}
Loading

0 comments on commit bdfdeda

Please sign in to comment.