mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-04 23:56:40 -05:00
Initial player Left skill and Right skill handling (#741)
* Initial player Left skill and Right skill handling * Handle empty skill names in charStats.BaseSkils + add Attack skill for all classes. Co-authored-by: Presiyan Ivanov <presiyan-ivanov@users.noreply.github.com>
This commit is contained in:
parent
f4d78549c5
commit
a4e9797431
@ -306,10 +306,17 @@ func createMissileRecord(line string) MissileRecord {
|
|||||||
// Missiles stores all of the MissileRecords
|
// Missiles stores all of the MissileRecords
|
||||||
//nolint:gochecknoglobals // Currently global by design, only written once
|
//nolint:gochecknoglobals // Currently global by design, only written once
|
||||||
var Missiles map[int]*MissileRecord
|
var Missiles map[int]*MissileRecord
|
||||||
|
var missilesByName map[string]*MissileRecord
|
||||||
|
|
||||||
|
// GetMissileByName allows lookup of a MissileRecord by a given name. The name will be lowercased and stripped of whitespaces.
|
||||||
|
func GetMissileByName(missileName string) *MissileRecord {
|
||||||
|
return missilesByName[sanitize(missileName)]
|
||||||
|
}
|
||||||
|
|
||||||
// LoadMissiles loads MissileRecords from missiles.txt
|
// LoadMissiles loads MissileRecords from missiles.txt
|
||||||
func LoadMissiles(file []byte) {
|
func LoadMissiles(file []byte) {
|
||||||
Missiles = make(map[int]*MissileRecord)
|
Missiles = make(map[int]*MissileRecord)
|
||||||
|
missilesByName = make(map[string]*MissileRecord)
|
||||||
data := strings.Split(string(file), "\r\n")[1:]
|
data := strings.Split(string(file), "\r\n")[1:]
|
||||||
|
|
||||||
for _, line := range data {
|
for _, line := range data {
|
||||||
@ -319,11 +326,16 @@ func LoadMissiles(file []byte) {
|
|||||||
|
|
||||||
rec := createMissileRecord(line)
|
rec := createMissileRecord(line)
|
||||||
Missiles[rec.Id] = &rec
|
Missiles[rec.Id] = &rec
|
||||||
|
missilesByName[sanitize(rec.Name)] = &rec
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Loaded %d missiles", len(Missiles))
|
log.Printf("Loaded %d missiles", len(Missiles))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sanitize(missileName string) string {
|
||||||
|
return strings.ToLower(strings.ReplaceAll(missileName, " ", ""))
|
||||||
|
}
|
||||||
|
|
||||||
func loadMissileCalcParam(r *[]string, inc func() int) MissileCalcParam {
|
func loadMissileCalcParam(r *[]string, inc func() int) MissileCalcParam {
|
||||||
result := MissileCalcParam{
|
result := MissileCalcParam{
|
||||||
Param: d2util.StringToInt(d2util.EmptyToZero((*r)[inc()])),
|
Param: d2util.StringToInt(d2util.EmptyToZero((*r)[inc()])),
|
||||||
|
@ -17,7 +17,7 @@ type SkillDescriptionRecord struct {
|
|||||||
SkillColumn string // SkillColumn
|
SkillColumn string // SkillColumn
|
||||||
ListRow string // ListRow
|
ListRow string // ListRow
|
||||||
ListPool string // ListPool
|
ListPool string // ListPool
|
||||||
IconCel string // IconCel
|
IconCel int // IconCel
|
||||||
NameKey string // str name
|
NameKey string // str name
|
||||||
ShortKey string // str short
|
ShortKey string // str short
|
||||||
LongKey string // str long
|
LongKey string // str long
|
||||||
@ -146,7 +146,7 @@ func LoadSkillDescriptions(file []byte) { //nolint:funlen // doesn't make sense
|
|||||||
d.String("SkillColumn"),
|
d.String("SkillColumn"),
|
||||||
d.String("ListRow"),
|
d.String("ListRow"),
|
||||||
d.String("ListPool"),
|
d.String("ListPool"),
|
||||||
d.String("IconCel"),
|
d.Number("IconCel"),
|
||||||
d.String("str name"),
|
d.String("str name"),
|
||||||
d.String("str short"),
|
d.String("str short"),
|
||||||
d.String("str long"),
|
d.String("str long"),
|
||||||
|
@ -12,6 +12,8 @@ import (
|
|||||||
//nolint:gochecknoglobals // Currently global by design, only written once
|
//nolint:gochecknoglobals // Currently global by design, only written once
|
||||||
var SkillDetails map[int]*SkillRecord
|
var SkillDetails map[int]*SkillRecord
|
||||||
|
|
||||||
|
var skillDetailsByName map[string]*SkillRecord
|
||||||
|
|
||||||
// SkillRecord is a row from the skills.txt file. Here are two resources for more info on each field
|
// SkillRecord is a row from the skills.txt file. Here are two resources for more info on each field
|
||||||
// [https://d2mods.info/forum/viewtopic.php?t=41556, https://d2mods.info/forum/kb/viewarticle?a=246]
|
// [https://d2mods.info/forum/viewtopic.php?t=41556, https://d2mods.info/forum/kb/viewarticle?a=246]
|
||||||
type SkillRecord struct {
|
type SkillRecord struct {
|
||||||
@ -263,6 +265,7 @@ type SkillRecord struct {
|
|||||||
// LoadCharStats loads charstats.txt file contents into map[d2enum.Hero]*CharStatsRecord
|
// LoadCharStats loads charstats.txt file contents into map[d2enum.Hero]*CharStatsRecord
|
||||||
func LoadSkills(file []byte) {
|
func LoadSkills(file []byte) {
|
||||||
SkillDetails = make(map[int]*SkillRecord)
|
SkillDetails = make(map[int]*SkillRecord)
|
||||||
|
skillDetailsByName = make(map[string]*SkillRecord)
|
||||||
|
|
||||||
parser := d2parser.New()
|
parser := d2parser.New()
|
||||||
|
|
||||||
@ -515,6 +518,7 @@ func LoadSkills(file []byte) {
|
|||||||
CostAdd: d.Number("cost add"),
|
CostAdd: d.Number("cost add"),
|
||||||
}
|
}
|
||||||
SkillDetails[record.ID] = record
|
SkillDetails[record.ID] = record
|
||||||
|
skillDetailsByName[record.Skill] = record
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.Err != nil {
|
if d.Err != nil {
|
||||||
@ -523,3 +527,8 @@ func LoadSkills(file []byte) {
|
|||||||
|
|
||||||
log.Printf("Loaded %d Skill records", len(SkillDetails))
|
log.Printf("Loaded %d Skill records", len(SkillDetails))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSkillByName returns the skill record for the given Skill name.
|
||||||
|
func GetSkillByName(skillName string) *SkillRecord {
|
||||||
|
return skillDetailsByName[skillName]
|
||||||
|
}
|
||||||
|
51
d2core/d2hero/hero_skill.go
Normal file
51
d2core/d2hero/hero_skill.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package d2hero
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HeroSkill stores additional payload for a skill of a hero.
|
||||||
|
type HeroSkill struct {
|
||||||
|
*d2datadict.SkillRecord
|
||||||
|
*d2datadict.SkillDescriptionRecord
|
||||||
|
SkillPoints int
|
||||||
|
}
|
||||||
|
|
||||||
|
// An auxilary struct which only stores the ID of the SkillRecord, instead of the whole SkillRecord and SkillDescrptionRecord.
|
||||||
|
type shallowHeroSkill struct {
|
||||||
|
SkillID int `json:"skillId"`
|
||||||
|
SkillPoints int `json:"skillPoints"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON overrides the default logic used when the HeroSkill is serialized to a byte array.
|
||||||
|
func (hs *HeroSkill) MarshalJSON() ([]byte, error) {
|
||||||
|
// only serialize the ID instead of the whole SkillRecord object.
|
||||||
|
shallow := shallowHeroSkill{
|
||||||
|
SkillID: hs.SkillRecord.ID,
|
||||||
|
SkillPoints: hs.SkillPoints,
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := json.Marshal(shallow)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON overrides the default logic used when the HeroSkill is deserialized from a byte array.
|
||||||
|
func (hs *HeroSkill) UnmarshalJSON(data []byte) error {
|
||||||
|
shallow := shallowHeroSkill{}
|
||||||
|
if err := json.Unmarshal(data, &shallow); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hs.SkillRecord = d2datadict.SkillDetails[shallow.SkillID]
|
||||||
|
hs.SkillDescriptionRecord = d2datadict.SkillDescriptions[hs.SkillRecord.Skilldesc]
|
||||||
|
hs.SkillPoints = shallow.SkillPoints
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
26
d2core/d2hero/hero_skills_state.go
Normal file
26
d2core/d2hero/hero_skills_state.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package d2hero
|
||||||
|
|
||||||
|
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||||
|
|
||||||
|
// HeroSkillsState hold all spells that a hero has.
|
||||||
|
type HeroSkillsState map[int] *HeroSkill
|
||||||
|
|
||||||
|
// CreateHeroSkillsState will assemble the hero skills from the class stats record.
|
||||||
|
func CreateHeroSkillsState(classStats *d2datadict.CharStatsRecord) *HeroSkillsState {
|
||||||
|
baseSkills := HeroSkillsState{}
|
||||||
|
|
||||||
|
for idx := range classStats.BaseSkill {
|
||||||
|
skillName := &classStats.BaseSkill[idx]
|
||||||
|
if len(*skillName) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
skillRecord := d2datadict.GetSkillByName(*skillName)
|
||||||
|
baseSkills[skillRecord.ID] = &HeroSkill{SkillPoints: 1, SkillRecord: skillRecord}
|
||||||
|
}
|
||||||
|
|
||||||
|
skillRecord := d2datadict.GetSkillByName("Attack")
|
||||||
|
baseSkills[skillRecord.ID] = &HeroSkill{SkillPoints: 1, SkillRecord: skillRecord}
|
||||||
|
|
||||||
|
return &baseSkills
|
||||||
|
}
|
@ -30,8 +30,8 @@ type HeroStatsState struct {
|
|||||||
PoisonResistance int `json:"poisonResistance"`
|
PoisonResistance int `json:"poisonResistance"`
|
||||||
|
|
||||||
// values which are not saved/loaded(computed)
|
// values which are not saved/loaded(computed)
|
||||||
Stamina int // only MaxStamina is saved, Stamina gets reset on entering world
|
Stamina int `json:"-"` // only MaxStamina is saved, Stamina gets reset on entering world
|
||||||
NextLevelExp int
|
NextLevelExp int `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateHeroStatsState generates a running state from a hero stats.
|
// CreateHeroStatsState generates a running state from a hero stats.
|
||||||
@ -56,8 +56,8 @@ func CreateHeroStatsState(heroClass d2enum.Hero, classStats *d2datadict.CharStat
|
|||||||
result.Stamina = result.MaxStamina
|
result.Stamina = result.MaxStamina
|
||||||
|
|
||||||
// TODO: For demonstration purposes (hp, mana, exp, & character stats panel gets updated depending on stats)
|
// TODO: For demonstration purposes (hp, mana, exp, & character stats panel gets updated depending on stats)
|
||||||
result.Health = 20
|
result.Health = 50
|
||||||
result.Mana = 9
|
result.Mana = 30
|
||||||
result.Experience = 166
|
result.Experience = 166
|
||||||
|
|
||||||
return &result
|
return &result
|
||||||
|
@ -41,7 +41,7 @@ func NewAnimatedEntity(x, y int, animation d2interface.Animation) *AnimatedEntit
|
|||||||
|
|
||||||
// NewPlayer creates a new player entity and returns a pointer to it.
|
// NewPlayer creates a new player entity and returns a pointer to it.
|
||||||
func (f *MapEntityFactory) NewPlayer(id, name string, x, y, direction int, heroType d2enum.Hero,
|
func (f *MapEntityFactory) NewPlayer(id, name string, x, y, direction int, heroType d2enum.Hero,
|
||||||
stats *d2hero.HeroStatsState, equipment *d2inventory.CharacterEquipment) *Player {
|
stats *d2hero.HeroStatsState, skills *d2hero.HeroSkillsState, equipment *d2inventory.CharacterEquipment) *Player {
|
||||||
layerEquipment := &[d2enum.CompositeTypeMax]string{
|
layerEquipment := &[d2enum.CompositeTypeMax]string{
|
||||||
d2enum.CompositeTypeHead: equipment.Head.GetArmorClass(),
|
d2enum.CompositeTypeHead: equipment.Head.GetArmorClass(),
|
||||||
d2enum.CompositeTypeTorso: equipment.Torso.GetArmorClass(),
|
d2enum.CompositeTypeTorso: equipment.Torso.GetArmorClass(),
|
||||||
@ -62,11 +62,16 @@ func (f *MapEntityFactory) NewPlayer(id, name string, x, y, direction int, heroT
|
|||||||
stats.NextLevelExp = d2datadict.GetExperienceBreakpoint(heroType, stats.Level)
|
stats.NextLevelExp = d2datadict.GetExperienceBreakpoint(heroType, stats.Level)
|
||||||
stats.Stamina = stats.MaxStamina
|
stats.Stamina = stats.MaxStamina
|
||||||
|
|
||||||
|
attackSkillID := 0
|
||||||
result := &Player{
|
result := &Player{
|
||||||
mapEntity: newMapEntity(x, y),
|
mapEntity: newMapEntity(x, y),
|
||||||
composite: composite,
|
composite: composite,
|
||||||
Equipment: equipment,
|
Equipment: equipment,
|
||||||
Stats: stats,
|
Stats: stats,
|
||||||
|
Skills: skills,
|
||||||
|
//TODO: active left & right skill should be loaded from save file instead
|
||||||
|
LeftSkill: (*skills)[attackSkillID],
|
||||||
|
RightSkill: (*skills)[attackSkillID],
|
||||||
name: name,
|
name: name,
|
||||||
Class: heroType,
|
Class: heroType,
|
||||||
//nameLabel: d2ui.NewLabel(d2resource.FontFormal11, d2resource.PaletteStatic),
|
//nameLabel: d2ui.NewLabel(d2resource.FontFormal11, d2resource.PaletteStatic),
|
||||||
|
@ -19,6 +19,9 @@ type Player struct {
|
|||||||
composite *d2asset.Composite
|
composite *d2asset.Composite
|
||||||
Equipment *d2inventory.CharacterEquipment
|
Equipment *d2inventory.CharacterEquipment
|
||||||
Stats *d2hero.HeroStatsState
|
Stats *d2hero.HeroStatsState
|
||||||
|
Skills *d2hero.HeroSkillsState
|
||||||
|
LeftSkill *d2hero.HeroSkill
|
||||||
|
RightSkill *d2hero.HeroSkill
|
||||||
Class d2enum.Hero
|
Class d2enum.Hero
|
||||||
lastPathSize int
|
lastPathSize int
|
||||||
isInTown bool
|
isInTown bool
|
||||||
|
@ -288,6 +288,7 @@ func (v *CharacterSelect) updateCharacterBoxes() {
|
|||||||
v.characterImage[i] = v.NewPlayer("", "", 0, 0, 0,
|
v.characterImage[i] = v.NewPlayer("", "", 0, 0, 0,
|
||||||
v.gameStates[idx].HeroType,
|
v.gameStates[idx].HeroType,
|
||||||
v.gameStates[idx].Stats,
|
v.gameStates[idx].Stats,
|
||||||
|
v.gameStates[idx].Skills,
|
||||||
&equipment,
|
&equipment,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ const hideZoneTextAfterSeconds = 2.0
|
|||||||
const (
|
const (
|
||||||
moveErrStr = "failed to send MovePlayer packet to the server, playerId: %s, x: %g, x: %g\n"
|
moveErrStr = "failed to send MovePlayer packet to the server, playerId: %s, x: %g, x: %g\n"
|
||||||
bindControlsErrStr = "failed to add gameControls as input handler for player: %s\n"
|
bindControlsErrStr = "failed to add gameControls as input handler for player: %s\n"
|
||||||
castErrStr = "failed to send CastSkill packet to the server, playerId: %s, missileId: %d, x: %g, x: %g\n"
|
castErrStr = "failed to send CastSkill packet to the server, playerId: %s, skillId: %d, x: %g, x: %g\n"
|
||||||
spawnItemErrStr = "failed to send SpawnItem packet to the server: (%d, %d) %+v"
|
spawnItemErrStr = "failed to send SpawnItem packet to the server: (%d, %d) %+v"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -312,10 +312,10 @@ func (v *Game) OnPlayerMove(targetX, targetY float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OnPlayerCast sends the casting skill action to the server
|
// OnPlayerCast sends the casting skill action to the server
|
||||||
func (v *Game) OnPlayerCast(missileID int, targetX, targetY float64) {
|
func (v *Game) OnPlayerCast(skillID int, targetX, targetY float64) {
|
||||||
err := v.gameClient.SendPacketToServer(d2netpacket.CreateCastPacket(v.gameClient.PlayerID, missileID, targetX, targetY))
|
err := v.gameClient.SendPacketToServer(d2netpacket.CreateCastPacket(v.gameClient.PlayerID, skillID, targetX, targetY))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf(castErrStr, v.gameClient.PlayerID, missileID, targetX, targetY)
|
fmt.Printf(castErrStr, v.gameClient.PlayerID, skillID, targetX, targetY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||||
@ -35,7 +36,6 @@ type Panel interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
initialMissileID = 59
|
|
||||||
expBarWidth = 120.0
|
expBarWidth = 120.0
|
||||||
staminaBarWidth = 102.0
|
staminaBarWidth = 102.0
|
||||||
globeHeight = 80
|
globeHeight = 80
|
||||||
@ -65,7 +65,8 @@ type GameControls struct {
|
|||||||
hpManaStatusSprite *d2ui.Sprite
|
hpManaStatusSprite *d2ui.Sprite
|
||||||
mainPanel *d2ui.Sprite
|
mainPanel *d2ui.Sprite
|
||||||
menuButton *d2ui.Sprite
|
menuButton *d2ui.Sprite
|
||||||
skillIcon *d2ui.Sprite
|
leftSkill *SkillResource
|
||||||
|
rightSkill *SkillResource
|
||||||
zoneChangeText *d2ui.Label
|
zoneChangeText *d2ui.Label
|
||||||
nameLabel *d2ui.Label
|
nameLabel *d2ui.Label
|
||||||
hpManaStatsLabel *d2ui.Label
|
hpManaStatsLabel *d2ui.Label
|
||||||
@ -86,15 +87,21 @@ type ActionableRegion struct {
|
|||||||
Rect d2geom.Rectangle
|
Rect d2geom.Rectangle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SkillResource struct {
|
||||||
|
SkillResourcePath string
|
||||||
|
IconNumber int
|
||||||
|
SkillIcon *d2ui.Sprite
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Since they require special handling, not considering (1) globes, (2) content of the mini panel, (3) belt
|
// Since they require special handling, not considering (1) globes, (2) content of the mini panel, (3) belt
|
||||||
leftSkill ActionableType = iota
|
leftSkill ActionableType = iota
|
||||||
leftSelect
|
newStats
|
||||||
xp
|
xp
|
||||||
walkRun
|
walkRun
|
||||||
stamina
|
stamina
|
||||||
miniPnl
|
miniPnl
|
||||||
rightSelect
|
newSkills
|
||||||
rightSkill
|
rightSkill
|
||||||
hpGlobe
|
hpGlobe
|
||||||
manaGlobe
|
manaGlobe
|
||||||
@ -115,14 +122,6 @@ func NewGameControls(
|
|||||||
guiManager *d2gui.GuiManager,
|
guiManager *d2gui.GuiManager,
|
||||||
isSinglePlayer bool,
|
isSinglePlayer bool,
|
||||||
) (*GameControls, error) {
|
) (*GameControls, error) {
|
||||||
missileID := initialMissileID
|
|
||||||
|
|
||||||
err := term.BindAction("setmissile", "set missile id to summon on right click", func(id int) {
|
|
||||||
missileID = id
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
zoneLabel := ui.NewLabel(d2resource.Font30, d2resource.PaletteUnits)
|
zoneLabel := ui.NewLabel(d2resource.Font30, d2resource.PaletteUnits)
|
||||||
zoneLabel.Alignment = d2gui.HorizontalAlignCenter
|
zoneLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||||
@ -175,18 +174,17 @@ func NewGameControls(
|
|||||||
heroStatsPanel: NewHeroStatsPanel(asset, ui, hero.Name(), hero.Class, hero.Stats),
|
heroStatsPanel: NewHeroStatsPanel(asset, ui, hero.Name(), hero.Class, hero.Stats),
|
||||||
helpOverlay: help.NewHelpOverlay(asset, renderer, ui, guiManager),
|
helpOverlay: help.NewHelpOverlay(asset, renderer, ui, guiManager),
|
||||||
miniPanel: newMiniPanel(asset, ui, isSinglePlayer),
|
miniPanel: newMiniPanel(asset, ui, isSinglePlayer),
|
||||||
missileID: missileID,
|
|
||||||
nameLabel: hoverLabel,
|
nameLabel: hoverLabel,
|
||||||
zoneChangeText: zoneLabel,
|
zoneChangeText: zoneLabel,
|
||||||
hpManaStatsLabel: globeStatsLabel,
|
hpManaStatsLabel: globeStatsLabel,
|
||||||
actionableRegions: []ActionableRegion{
|
actionableRegions: []ActionableRegion{
|
||||||
{leftSkill, d2geom.Rectangle{Left: 115, Top: 550, Width: 50, Height: 50}},
|
{leftSkill, d2geom.Rectangle{Left: 115, Top: 550, Width: 50, Height: 50}},
|
||||||
{leftSelect, d2geom.Rectangle{Left: 206, Top: 563, Width: 30, Height: 30}},
|
{newStats, d2geom.Rectangle{Left: 206, Top: 563, Width: 30, Height: 30}},
|
||||||
{xp, d2geom.Rectangle{Left: 253, Top: 560, Width: 125, Height: 5}},
|
{xp, d2geom.Rectangle{Left: 253, Top: 560, Width: 125, Height: 5}},
|
||||||
{walkRun, d2geom.Rectangle{Left: 255, Top: 573, Width: 17, Height: 20}},
|
{walkRun, d2geom.Rectangle{Left: 255, Top: 573, Width: 17, Height: 20}},
|
||||||
{stamina, d2geom.Rectangle{Left: 273, Top: 573, Width: 105, Height: 20}},
|
{stamina, d2geom.Rectangle{Left: 273, Top: 573, Width: 105, Height: 20}},
|
||||||
{miniPnl, d2geom.Rectangle{Left: 393, Top: 563, Width: 12, Height: 23}},
|
{miniPnl, d2geom.Rectangle{Left: 393, Top: 563, Width: 12, Height: 23}},
|
||||||
{rightSelect, d2geom.Rectangle{Left: 562, Top: 563, Width: 30, Height: 30}},
|
{newSkills, d2geom.Rectangle{Left: 562, Top: 563, Width: 30, Height: 30}},
|
||||||
{rightSkill, d2geom.Rectangle{Left: 634, Top: 550, Width: 50, Height: 50}},
|
{rightSkill, d2geom.Rectangle{Left: 634, Top: 550, Width: 50, Height: 50}},
|
||||||
{hpGlobe, d2geom.Rectangle{Left: 30, Top: 525, Width: 65, Height: 50}},
|
{hpGlobe, d2geom.Rectangle{Left: 30, Top: 525, Width: 65, Height: 50}},
|
||||||
{manaGlobe, d2geom.Rectangle{Left: 700, Top: 525, Width: 65, Height: 50}},
|
{manaGlobe, d2geom.Rectangle{Left: 700, Top: 525, Width: 65, Height: 50}},
|
||||||
@ -198,7 +196,7 @@ func NewGameControls(
|
|||||||
isSinglePlayer: isSinglePlayer,
|
isSinglePlayer: isSinglePlayer,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = term.BindAction("freecam", "toggle free camera movement", func() {
|
err := term.BindAction("freecam", "toggle free camera movement", func() {
|
||||||
gc.FreeCam = !gc.FreeCam
|
gc.FreeCam = !gc.FreeCam
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -206,6 +204,20 @@ func NewGameControls(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = term.BindAction("setleftskill", "set skill to fire on left click", func(id int) {
|
||||||
|
skillRecord := d2datadict.SkillDetails[id]
|
||||||
|
gc.hero.LeftSkill = &d2hero.HeroSkill{SkillPoints: 0, SkillRecord: skillRecord, SkillDescriptionRecord: d2datadict.SkillDescriptions[skillRecord.Skilldesc]}
|
||||||
|
})
|
||||||
|
|
||||||
|
err = term.BindAction("setrightskill", "set skill to fire on right click", func(id int) {
|
||||||
|
skillRecord := d2datadict.SkillDetails[id]
|
||||||
|
gc.hero.RightSkill = &d2hero.HeroSkill{SkillPoints: 0, SkillRecord: skillRecord, SkillDescriptionRecord: d2datadict.SkillDescriptions[skillRecord.Skilldesc]}
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return gc, nil
|
return gc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +309,11 @@ func (g *GameControls) OnMouseButtonRepeat(event d2interface.MouseEvent) bool {
|
|||||||
if isLeft && shouldDoLeft && inRect && !g.hero.IsCasting() {
|
if isLeft && shouldDoLeft && inRect && !g.hero.IsCasting() {
|
||||||
g.lastLeftBtnActionTime = now
|
g.lastLeftBtnActionTime = now
|
||||||
|
|
||||||
g.inputListener.OnPlayerMove(px, py)
|
if event.KeyMod() == d2enum.KeyModShift {
|
||||||
|
g.inputListener.OnPlayerCast(g.hero.LeftSkill.ID, px, py)
|
||||||
|
} else {
|
||||||
|
g.inputListener.OnPlayerMove(px, py)
|
||||||
|
}
|
||||||
|
|
||||||
if g.FreeCam {
|
if g.FreeCam {
|
||||||
if event.Button() == d2enum.MouseButtonLeft {
|
if event.Button() == d2enum.MouseButtonLeft {
|
||||||
@ -319,7 +335,7 @@ func (g *GameControls) OnMouseButtonRepeat(event d2interface.MouseEvent) bool {
|
|||||||
if isRight && shouldDoRight && inRect && !g.hero.IsCasting() {
|
if isRight && shouldDoRight && inRect && !g.hero.IsCasting() {
|
||||||
g.lastRightBtnActionTime = now
|
g.lastRightBtnActionTime = now
|
||||||
|
|
||||||
g.inputListener.OnPlayerCast(g.missileID, px, py)
|
g.inputListener.OnPlayerCast(g.hero.RightSkill.ID, px, py)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -364,7 +380,11 @@ func (g *GameControls) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
|||||||
if event.Button() == d2enum.MouseButtonLeft && !g.isInActiveMenusRect(mx, my) && !g.hero.IsCasting() {
|
if event.Button() == d2enum.MouseButtonLeft && !g.isInActiveMenusRect(mx, my) && !g.hero.IsCasting() {
|
||||||
g.lastLeftBtnActionTime = d2util.Now()
|
g.lastLeftBtnActionTime = d2util.Now()
|
||||||
|
|
||||||
g.inputListener.OnPlayerMove(px, py)
|
if event.KeyMod() == d2enum.KeyModShift {
|
||||||
|
g.inputListener.OnPlayerCast(g.hero.LeftSkill.ID, px, py)
|
||||||
|
} else {
|
||||||
|
g.inputListener.OnPlayerMove(px, py)
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -372,7 +392,7 @@ func (g *GameControls) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
|||||||
if event.Button() == d2enum.MouseButtonRight && !g.isInActiveMenusRect(mx, my) && !g.hero.IsCasting() {
|
if event.Button() == d2enum.MouseButtonRight && !g.isInActiveMenusRect(mx, my) && !g.hero.IsCasting() {
|
||||||
g.lastRightBtnActionTime = d2util.Now()
|
g.lastRightBtnActionTime = d2util.Now()
|
||||||
|
|
||||||
g.inputListener.OnPlayerCast(g.missileID, px, py)
|
g.inputListener.OnPlayerCast(g.hero.RightSkill.ID, px, py)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -391,7 +411,12 @@ func (g *GameControls) Load() {
|
|||||||
g.menuButton, _ = g.uiManager.NewSprite(d2resource.MenuButton, d2resource.PaletteSky)
|
g.menuButton, _ = g.uiManager.NewSprite(d2resource.MenuButton, d2resource.PaletteSky)
|
||||||
_ = g.menuButton.SetCurrentFrame(2)
|
_ = g.menuButton.SetCurrentFrame(2)
|
||||||
|
|
||||||
g.skillIcon, _ = g.uiManager.NewSprite(d2resource.GenericSkills, d2resource.PaletteSky)
|
// TODO: temporarily hardcoded to Attack, should come from saved state for hero
|
||||||
|
genericSkillsSprite, _ := g.uiManager.NewSprite(d2resource.GenericSkills, d2resource.PaletteSky)
|
||||||
|
attackIconID := 2
|
||||||
|
|
||||||
|
g.leftSkill = &SkillResource{SkillIcon: genericSkillsSprite, IconNumber: attackIconID, SkillResourcePath: d2resource.GenericSkills}
|
||||||
|
g.rightSkill = &SkillResource{SkillIcon: genericSkillsSprite, IconNumber: attackIconID, SkillResourcePath: d2resource.GenericSkills}
|
||||||
|
|
||||||
g.loadUIButtons()
|
g.loadUIButtons()
|
||||||
|
|
||||||
@ -570,21 +595,26 @@ func (g *GameControls) Render(target d2interface.Surface) error {
|
|||||||
offset += w
|
offset += w
|
||||||
|
|
||||||
// Left skill
|
// Left skill
|
||||||
if err := g.skillIcon.SetCurrentFrame(2); err != nil {
|
skillResourcePath := g.getSkillResourceByClass(g.hero.LeftSkill.Charclass)
|
||||||
|
if skillResourcePath != g.leftSkill.SkillResourcePath {
|
||||||
|
g.leftSkill.SkillIcon, _ = g.uiManager.NewSprite(skillResourcePath, d2resource.PaletteSky)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := g.leftSkill.SkillIcon.SetCurrentFrame(g.hero.LeftSkill.IconCel); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w, _ = g.skillIcon.GetCurrentFrameSize()
|
w, _ = g.leftSkill.SkillIcon.GetCurrentFrameSize()
|
||||||
|
|
||||||
g.skillIcon.SetPosition(offset, height)
|
g.leftSkill.SkillIcon.SetPosition(offset, height)
|
||||||
|
|
||||||
if err := g.skillIcon.Render(target); err != nil {
|
if err := g.leftSkill.SkillIcon.Render(target); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += w
|
offset += w
|
||||||
|
|
||||||
// Left skill selector
|
// New Stats Selector
|
||||||
if err := g.mainPanel.SetCurrentFrame(1); err != nil {
|
if err := g.mainPanel.SetCurrentFrame(1); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -668,7 +698,7 @@ func (g *GameControls) Render(target d2interface.Surface) error {
|
|||||||
|
|
||||||
offset += w
|
offset += w
|
||||||
|
|
||||||
// Right skill selector
|
// New Skills Selector
|
||||||
if err := g.mainPanel.SetCurrentFrame(4); err != nil {
|
if err := g.mainPanel.SetCurrentFrame(4); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -684,15 +714,20 @@ func (g *GameControls) Render(target d2interface.Surface) error {
|
|||||||
offset += w
|
offset += w
|
||||||
|
|
||||||
// Right skill
|
// Right skill
|
||||||
if err := g.skillIcon.SetCurrentFrame(2); err != nil {
|
skillResourcePath = g.getSkillResourceByClass(g.hero.RightSkill.Charclass)
|
||||||
|
if skillResourcePath != g.rightSkill.SkillResourcePath {
|
||||||
|
g.rightSkill.SkillIcon, _ = g.uiManager.NewSprite(skillResourcePath, d2resource.PaletteSky)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := g.rightSkill.SkillIcon.SetCurrentFrame(g.hero.RightSkill.IconCel); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w, _ = g.skillIcon.GetCurrentFrameSize()
|
w, _ = g.rightSkill.SkillIcon.GetCurrentFrameSize()
|
||||||
|
|
||||||
g.skillIcon.SetPosition(offset, height)
|
g.rightSkill.SkillIcon.SetPosition(offset, height)
|
||||||
|
|
||||||
if err := g.skillIcon.Render(target); err != nil {
|
if err := g.rightSkill.SkillIcon.Render(target); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -800,7 +835,7 @@ func (g *GameControls) ManaStatsIsVisible() bool {
|
|||||||
return g.manaStatsIsVisible
|
return g.manaStatsIsVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToggleHpStats toggles the visibility of the hp and mana stats placed above their respective globe
|
// ToggleHpStats toggles the visibility of the hp and mana stats placed above their respective globe and load only if they do not match
|
||||||
func (g *GameControls) ToggleHpStats() {
|
func (g *GameControls) ToggleHpStats() {
|
||||||
g.hpStatsIsVisible = !g.hpStatsIsVisible
|
g.hpStatsIsVisible = !g.hpStatsIsVisible
|
||||||
}
|
}
|
||||||
@ -815,7 +850,7 @@ func (g *GameControls) onHoverActionable(item ActionableType) {
|
|||||||
switch item {
|
switch item {
|
||||||
case leftSkill:
|
case leftSkill:
|
||||||
return
|
return
|
||||||
case leftSelect:
|
case newStats:
|
||||||
return
|
return
|
||||||
case xp:
|
case xp:
|
||||||
return
|
return
|
||||||
@ -825,7 +860,7 @@ func (g *GameControls) onHoverActionable(item ActionableType) {
|
|||||||
return
|
return
|
||||||
case miniPnl:
|
case miniPnl:
|
||||||
return
|
return
|
||||||
case rightSelect:
|
case newSkills:
|
||||||
return
|
return
|
||||||
case rightSkill:
|
case rightSkill:
|
||||||
return
|
return
|
||||||
@ -843,8 +878,8 @@ func (g *GameControls) onClickActionable(item ActionableType) {
|
|||||||
switch item {
|
switch item {
|
||||||
case leftSkill:
|
case leftSkill:
|
||||||
log.Println("Left Skill Action Pressed")
|
log.Println("Left Skill Action Pressed")
|
||||||
case leftSelect:
|
case newStats:
|
||||||
log.Println("Left Skill Selector Action Pressed")
|
log.Println("New Stats Selector Action Pressed")
|
||||||
case xp:
|
case xp:
|
||||||
log.Println("XP Action Pressed")
|
log.Println("XP Action Pressed")
|
||||||
case walkRun:
|
case walkRun:
|
||||||
@ -855,8 +890,8 @@ func (g *GameControls) onClickActionable(item ActionableType) {
|
|||||||
log.Println("Mini Panel Action Pressed")
|
log.Println("Mini Panel Action Pressed")
|
||||||
|
|
||||||
g.miniPanel.Toggle()
|
g.miniPanel.Toggle()
|
||||||
case rightSelect:
|
case newSkills:
|
||||||
log.Println("Right Skill Selector Action Pressed")
|
log.Println("New Skills Selector Action Pressed")
|
||||||
case rightSkill:
|
case rightSkill:
|
||||||
log.Println("Right Skill Action Pressed")
|
log.Println("Right Skill Action Pressed")
|
||||||
case hpGlobe:
|
case hpGlobe:
|
||||||
@ -879,3 +914,30 @@ func (g *GameControls) onClickActionable(item ActionableType) {
|
|||||||
log.Printf("Unrecognized ActionableType(%d) being clicked\n", item)
|
log.Printf("Unrecognized ActionableType(%d) being clicked\n", item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *GameControls) getSkillResourceByClass(class string) string {
|
||||||
|
resource := ""
|
||||||
|
|
||||||
|
switch class {
|
||||||
|
case "":
|
||||||
|
resource = d2resource.GenericSkills
|
||||||
|
case "bar":
|
||||||
|
resource = d2resource.BarbarianSkills
|
||||||
|
case "nec":
|
||||||
|
resource = d2resource.NecromancerSkills
|
||||||
|
case "pal":
|
||||||
|
resource = d2resource.PaladinSkills
|
||||||
|
case "ass":
|
||||||
|
resource = d2resource.AssassinSkills
|
||||||
|
case "sor":
|
||||||
|
resource = d2resource.SorcererSkills
|
||||||
|
case "ama":
|
||||||
|
resource = d2resource.AmazonSkills
|
||||||
|
case "dru":
|
||||||
|
resource = d2resource.DruidSkills
|
||||||
|
default:
|
||||||
|
log.Fatalf("Unknown class token: '%s'", class)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@ type PlayerState struct {
|
|||||||
FilePath string `json:"-"`
|
FilePath string `json:"-"`
|
||||||
Equipment d2inventory.CharacterEquipment `json:"equipment"`
|
Equipment d2inventory.CharacterEquipment `json:"equipment"`
|
||||||
Stats *d2hero.HeroStatsState `json:"stats"`
|
Stats *d2hero.HeroStatsState `json:"stats"`
|
||||||
|
Skills *d2hero.HeroSkillsState `json:"skills"`
|
||||||
X float64 `json:"x"`
|
X float64 `json:"x"`
|
||||||
Y float64 `json:"y"`
|
Y float64 `json:"y"`
|
||||||
}
|
}
|
||||||
@ -50,17 +51,20 @@ func GetAllPlayerStates() []*PlayerState {
|
|||||||
|
|
||||||
gameState := LoadPlayerState(path.Join(basePath, file.Name()))
|
gameState := LoadPlayerState(path.Join(basePath, file.Name()))
|
||||||
if gameState == nil || gameState.HeroType == d2enum.HeroNone {
|
if gameState == nil || gameState.HeroType == d2enum.HeroNone {
|
||||||
// temporarily loading default class stats if the character was created before saving stats was introduced
|
|
||||||
// to be removed in the future
|
|
||||||
continue
|
continue
|
||||||
} else if gameState.Stats == nil {
|
} else if gameState.Stats == nil || gameState.Skills == nil {
|
||||||
gameState.Stats = d2hero.CreateHeroStatsState(gameState.HeroType, d2datadict.CharStats[gameState.HeroType])
|
// temporarily loading default class stats if the character was created before saving stats/skills was introduced
|
||||||
|
// to be removed in the future
|
||||||
|
classStats := d2datadict.CharStats[gameState.HeroType]
|
||||||
|
gameState.Stats = d2hero.CreateHeroStatsState(gameState.HeroType, classStats)
|
||||||
|
gameState.Skills = d2hero.CreateHeroSkillsState(classStats)
|
||||||
|
|
||||||
if err := gameState.Save(); err != nil {
|
if err := gameState.Save(); err != nil {
|
||||||
fmt.Printf("failed to save game state!, err: %v\n", err)
|
fmt.Printf("failed to save game state!, err: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = append(result, gameState)
|
result = append(result, gameState)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@ -98,6 +102,7 @@ func CreatePlayerState(heroName string, hero d2enum.Hero, classStats *d2datadict
|
|||||||
HeroType: hero,
|
HeroType: hero,
|
||||||
Act: 1,
|
Act: 1,
|
||||||
Stats: d2hero.CreateHeroStatsState(hero, classStats),
|
Stats: d2hero.CreateHeroStatsState(hero, classStats),
|
||||||
|
Skills: d2hero.CreateHeroSkillsState(classStats),
|
||||||
Equipment: d2inventory.HeroObjects[hero],
|
Equipment: d2inventory.HeroObjects[hero],
|
||||||
FilePath: "",
|
FilePath: "",
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ func (g *GameClient) handleAddPlayerPacket(packet d2netpacket.NetPacket) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
newPlayer := g.MapEngine.NewPlayer(player.ID, player.Name, player.X, player.Y, 0,
|
newPlayer := g.MapEngine.NewPlayer(player.ID, player.Name, player.X, player.Y, 0,
|
||||||
player.HeroType, player.Stats, &player.Equipment)
|
player.HeroType, player.Stats, player.Skills, &player.Equipment)
|
||||||
|
|
||||||
g.Players[newPlayer.ID()] = newPlayer
|
g.Players[newPlayer.ID()] = newPlayer
|
||||||
g.MapEngine.AddEntity(newPlayer)
|
g.MapEngine.AddEntity(newPlayer)
|
||||||
@ -264,12 +264,19 @@ func (g *GameClient) handleCastSkillPacket(packet d2netpacket.NetPacket) error {
|
|||||||
|
|
||||||
direction := player.Position.DirectionTo(*d2vector.NewVector(castX, castY))
|
direction := player.Position.DirectionTo(*d2vector.NewVector(castX, castY))
|
||||||
player.SetDirection(direction)
|
player.SetDirection(direction)
|
||||||
|
skill := d2datadict.SkillDetails[playerCast.SkillID]
|
||||||
|
missileRecord := d2datadict.GetMissileByName(skill.Cltmissile)
|
||||||
|
|
||||||
|
if missileRecord == nil {
|
||||||
|
//TODO: handle casts that have no missiles(or have multiple missiles and require additional logic)
|
||||||
|
log.Println("Missile not found for skill ID", skill.ID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// currently hardcoded to missile skill
|
|
||||||
missile, err := g.MapEngine.NewMissile(
|
missile, err := g.MapEngine.NewMissile(
|
||||||
int(player.Position.X()),
|
int(player.Position.X()),
|
||||||
int(player.Position.Y()),
|
int(player.Position.Y()),
|
||||||
d2datadict.Missiles[playerCast.SkillID],
|
d2datadict.Missiles[missileRecord.Id],
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -281,6 +288,7 @@ func (g *GameClient) handleCastSkillPacket(packet d2netpacket.NetPacket) error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
player.StartCasting(func() {
|
player.StartCasting(func() {
|
||||||
|
// shoot the missile after the player finished casting
|
||||||
g.MapEngine.AddEntity(missile)
|
g.MapEngine.AddEntity(missile)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -20,12 +20,13 @@ type AddPlayerPacket struct {
|
|||||||
HeroType d2enum.Hero `json:"hero"`
|
HeroType d2enum.Hero `json:"hero"`
|
||||||
Equipment d2inventory.CharacterEquipment `json:"equipment"`
|
Equipment d2inventory.CharacterEquipment `json:"equipment"`
|
||||||
Stats *d2hero.HeroStatsState `json:"heroStats"`
|
Stats *d2hero.HeroStatsState `json:"heroStats"`
|
||||||
|
Skills *d2hero.HeroSkillsState `json:"heroSkills"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateAddPlayerPacket returns a NetPacket which declares an
|
// CreateAddPlayerPacket returns a NetPacket which declares an
|
||||||
// AddPlayerPacket with the data in given parameters.
|
// AddPlayerPacket with the data in given parameters.
|
||||||
func CreateAddPlayerPacket(id, name string, x, y int, heroType d2enum.Hero,
|
func CreateAddPlayerPacket(id, name string, x, y int, heroType d2enum.Hero,
|
||||||
stats *d2hero.HeroStatsState, equipment d2inventory.CharacterEquipment) NetPacket {
|
stats *d2hero.HeroStatsState, skills *d2hero.HeroSkillsState, equipment d2inventory.CharacterEquipment) NetPacket {
|
||||||
addPlayerPacket := AddPlayerPacket{
|
addPlayerPacket := AddPlayerPacket{
|
||||||
ID: id,
|
ID: id,
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -34,6 +35,7 @@ func CreateAddPlayerPacket(id, name string, x, y int, heroType d2enum.Hero,
|
|||||||
HeroType: heroType,
|
HeroType: heroType,
|
||||||
Equipment: equipment,
|
Equipment: equipment,
|
||||||
Stats: stats,
|
Stats: stats,
|
||||||
|
Skills: skills,
|
||||||
}
|
}
|
||||||
b, _ := json.Marshal(addPlayerPacket)
|
b, _ := json.Marshal(addPlayerPacket)
|
||||||
|
|
||||||
|
@ -346,6 +346,7 @@ func handleClientConnection(gameServer *GameServer, client ClientConnection, x,
|
|||||||
playerY,
|
playerY,
|
||||||
playerState.HeroType,
|
playerState.HeroType,
|
||||||
playerState.Stats,
|
playerState.Stats,
|
||||||
|
playerState.Skills,
|
||||||
playerState.Equipment,
|
playerState.Equipment,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -370,6 +371,7 @@ func handleClientConnection(gameServer *GameServer, client ClientConnection, x,
|
|||||||
playerY,
|
playerY,
|
||||||
conPlayerState.HeroType,
|
conPlayerState.HeroType,
|
||||||
conPlayerState.Stats,
|
conPlayerState.Stats,
|
||||||
|
conPlayerState.Skills,
|
||||||
conPlayerState.Equipment,
|
conPlayerState.Equipment,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user