mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-12-25 11:36:26 -05:00
commit
84cac0d181
@ -25,7 +25,8 @@ ALL OTHER TRADEMARKS ARE THE PROPERTY OF THEIR RESPECTIVE OWNERS.
|
||||
|
||||
## Status
|
||||
|
||||
At the moment (october 2020) the game starts, you can select any character and run around Act1 town.
|
||||
At the moment (december 2020) the game starts, you can select any character and run around Act1 town.
|
||||
You can also open any of the game's panels.
|
||||
|
||||
Much work has been made in the background, but a lot of work still has to be done for the game to be playable.
|
||||
|
||||
@ -128,6 +129,8 @@ which will be updated over time with new requirements.
|
||||
|
||||
![Inventory Window](docs/Inventory.png)
|
||||
|
||||
![Game Panels](docs/game_panels.png)
|
||||
|
||||
## Additional Credits
|
||||
|
||||
- Diablo2 Logo
|
||||
|
@ -245,6 +245,8 @@ const (
|
||||
|
||||
Frame = "/data/global/ui/PANEL/800borderframe.dc6"
|
||||
InventoryCharacterPanel = "/data/global/ui/PANEL/invchar6.DC6"
|
||||
HeroStatsPanelStatsPoints = "/data/global/ui/PANEL/skillpoints.dc6"
|
||||
HeroStatsPanelSocket = "/data/global/ui/PANEL/levelsocket.dc6"
|
||||
InventoryWeaponsTab = "/data/global/ui/PANEL/invchar6Tab.DC6"
|
||||
SkillsPanelAmazon = "/data/global/ui/SPELLS/skltree_a_back.DC6"
|
||||
SkillsPanelBarbarian = "/data/global/ui/SPELLS/skltree_b_back.DC6"
|
||||
|
@ -10,27 +10,22 @@ type HeroStatsState struct {
|
||||
Level int `json:"level"`
|
||||
Experience int `json:"experience"`
|
||||
|
||||
Vitality int `json:"vitality"`
|
||||
Energy int `json:"energy"`
|
||||
Strength int `json:"strength"`
|
||||
Energy int `json:"energy"`
|
||||
Dexterity int `json:"dexterity"`
|
||||
Vitality int `json:"vitality"`
|
||||
// there are stats and skills points remaining to add.
|
||||
StatsPoints int `json:"statsPoints"`
|
||||
SkillPoints int `json:"skillPoints"`
|
||||
|
||||
AttackRating int `json:"attackRating"`
|
||||
DefenseRating int `json:"defenseRating"`
|
||||
|
||||
MaxStamina int `json:"maxStamina"`
|
||||
Health int `json:"health"`
|
||||
MaxHealth int `json:"maxHealth"`
|
||||
Mana int `json:"mana"`
|
||||
MaxMana int `json:"maxMana"`
|
||||
|
||||
FireResistance int `json:"fireResistance"`
|
||||
ColdResistance int `json:"coldResistance"`
|
||||
LightningResistance int `json:"lightningResistance"`
|
||||
PoisonResistance int `json:"poisonResistance"`
|
||||
Stamina float64 `json:"-"` // only MaxStamina is saved, Stamina gets reset on entering world
|
||||
MaxStamina int `json:"maxStamina"`
|
||||
|
||||
// values which are not saved/loaded(computed)
|
||||
Stamina float64 `json:"-"` // only MaxStamina is saved, Stamina gets reset on entering world
|
||||
NextLevelExp int `json:"-"`
|
||||
}
|
||||
|
||||
@ -44,6 +39,8 @@ func (f *HeroStateFactory) CreateHeroStatsState(heroClass d2enum.Hero, classStat
|
||||
Dexterity: classStats.InitDex,
|
||||
Vitality: classStats.InitVit,
|
||||
Energy: classStats.InitEne,
|
||||
StatsPoints: 0,
|
||||
SkillPoints: 0,
|
||||
|
||||
MaxHealth: classStats.InitVit * classStats.LifePerVit,
|
||||
MaxMana: classStats.InitEne * classStats.ManaPerEne,
|
||||
|
@ -55,6 +55,7 @@ const (
|
||||
ButtonTypeSquelchChat ButtonType = 35
|
||||
ButtonTypeTabBlank ButtonType = 36
|
||||
ButtonTypeBlankQuestBtn ButtonType = 37
|
||||
ButtonTypeAddSkill ButtonType = 38
|
||||
|
||||
ButtonNoFixedWidth int = -1
|
||||
ButtonNoFixedHeight int = -1
|
||||
@ -199,6 +200,10 @@ const (
|
||||
buttonGoldCoinSegmentsY = 1
|
||||
buttonGoldCoinDisabledFrame = -1
|
||||
|
||||
buttonAddSkillSegmentsX = 1
|
||||
buttonAddSkillSegmentsY = 1
|
||||
buttonAddSkillDisabledFrame = 2
|
||||
|
||||
pressedButtonOffset = 2
|
||||
)
|
||||
|
||||
@ -746,6 +751,20 @@ func getButtonLayouts() map[ButtonType]ButtonLayout {
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
LabelColor: whiteAlpha100,
|
||||
},
|
||||
ButtonTypeAddSkill: {
|
||||
XSegments: buttonAddSkillSegmentsX,
|
||||
YSegments: buttonAddSkillSegmentsY,
|
||||
DisabledFrame: buttonAddSkillDisabledFrame,
|
||||
DisabledColor: whiteAlpha100,
|
||||
ResourceName: d2resource.AddSkillButton,
|
||||
PaletteName: d2resource.PaletteSky,
|
||||
Toggleable: true,
|
||||
FontPath: d2resource.Font16,
|
||||
AllowFrameChange: true,
|
||||
HasImage: true,
|
||||
FixedWidth: ButtonNoFixedWidth,
|
||||
FixedHeight: ButtonNoFixedHeight,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,7 +214,7 @@ func NewGameControls(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
skilltree := newSkillTree(hero.Skills, hero.Class, asset, l, ui)
|
||||
skilltree := newSkillTree(hero.Skills, hero.Class, hero.Stats, asset, l, ui)
|
||||
|
||||
miniPanel := newMiniPanel(asset, ui, l, isSinglePlayer)
|
||||
|
||||
@ -224,13 +224,9 @@ func NewGameControls(
|
||||
}
|
||||
|
||||
helpOverlay := NewHelpOverlay(asset, ui, l, keyMap)
|
||||
hud := NewHUD(asset, ui, hero, miniPanel, actionableRegions, mapEngine, l, mapRenderer)
|
||||
|
||||
const blackAlpha50percent = 0x0000007f
|
||||
|
||||
hoverLabel := hud.nameLabel
|
||||
hoverLabel.SetBackgroundColor(d2util.Color(blackAlpha50percent))
|
||||
|
||||
gc := &GameControls{
|
||||
asset: asset,
|
||||
ui: ui,
|
||||
@ -246,7 +242,6 @@ func NewGameControls(
|
||||
questLog: questLog,
|
||||
HelpOverlay: helpOverlay,
|
||||
keyMap: keyMap,
|
||||
hud: hud,
|
||||
bottomMenuRect: &d2geom.Rectangle{
|
||||
Left: menuBottomRectX,
|
||||
Top: menuBottomRectY,
|
||||
@ -271,6 +266,12 @@ func NewGameControls(
|
||||
isSinglePlayer: isSinglePlayer,
|
||||
}
|
||||
|
||||
hud := NewHUD(asset, ui, hero, miniPanel, actionableRegions, mapEngine, l, gc, mapRenderer)
|
||||
gc.hud = hud
|
||||
|
||||
hoverLabel := hud.nameLabel
|
||||
hoverLabel.SetBackgroundColor(d2util.Color(blackAlpha50percent))
|
||||
|
||||
gc.heroStatsPanel.SetOnCloseCb(gc.onCloseHeroStatsPanel)
|
||||
gc.questLog.SetOnCloseCb(gc.onCloseQuestLog)
|
||||
gc.inventory.SetOnCloseCb(gc.onCloseInventory)
|
||||
@ -713,6 +714,9 @@ func (g *GameControls) Load() {
|
||||
g.questLog.Load()
|
||||
g.HelpOverlay.Load()
|
||||
|
||||
g.loadAddButtons()
|
||||
g.setAddButtons()
|
||||
|
||||
miniPanelActions := &miniPanelActions{
|
||||
characterToggle: g.toggleHeroStatsPanel,
|
||||
inventoryToggle: g.toggleInventoryPanel,
|
||||
@ -733,6 +737,10 @@ func (g *GameControls) Advance(elapsed float64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if g.heroStatsPanel.IsOpen() || g.skilltree.IsOpen() {
|
||||
g.setAddButtons()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1099,3 +1107,13 @@ func (g *GameControls) bindTerminalCommands(term d2interface.Terminal) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GameControls) setAddButtons() {
|
||||
g.hud.addStatsButton.SetEnabled(g.hero.Stats.StatsPoints > 0)
|
||||
g.hud.addSkillButton.SetEnabled(g.hero.Stats.SkillPoints > 0)
|
||||
}
|
||||
|
||||
func (g *GameControls) loadAddButtons() {
|
||||
g.hud.addStatsButton.OnActivated(func() { g.toggleHeroStatsPanel() })
|
||||
g.hud.addSkillButton.OnActivated(func() { g.toggleSkilltreePanel() })
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
@ -55,6 +56,15 @@ const (
|
||||
|
||||
const (
|
||||
heroStatsCloseButtonX, heroStatsCloseButtonY = 208, 453
|
||||
addStatSocketOffsetX, addStatSocketOffsetY = -3, 34
|
||||
)
|
||||
|
||||
const (
|
||||
newStatsRemainingPointsFieldX, newStatsRemainingPointsFieldY = 83, 430
|
||||
newStatsRemainingPointsLabelX = 92
|
||||
newStatsRemainingPointsLabel1Y = 411
|
||||
newStatsRemainingPointsLabel2Y = 418
|
||||
newStatsRemainingPointsValueX, newStatsRemainingPointsValueY = 188, 411
|
||||
)
|
||||
|
||||
// PanelText represents text on the panel
|
||||
@ -122,6 +132,8 @@ type HeroStatsPanel struct {
|
||||
labels *StatsPanelLabels
|
||||
onCloseCb func()
|
||||
panelGroup *d2ui.WidgetGroup
|
||||
newStatPoints *d2ui.WidgetGroup
|
||||
remainingPoints *d2ui.Label
|
||||
|
||||
originX int
|
||||
originY int
|
||||
@ -135,6 +147,7 @@ func (s *HeroStatsPanel) Load() {
|
||||
var err error
|
||||
|
||||
s.panelGroup = s.uiManager.NewWidgetGroup(d2ui.RenderPriorityHeroStatsPanel)
|
||||
s.newStatPoints = s.uiManager.NewWidgetGroup(d2ui.RenderPriorityHeroStatsPanel)
|
||||
|
||||
frame := d2ui.NewUIFrame(s.asset, s.uiManager, d2ui.FrameLeft)
|
||||
s.panelGroup.AddWidget(frame)
|
||||
@ -154,10 +167,91 @@ func (s *HeroStatsPanel) Load() {
|
||||
closeButton.OnActivated(func() { s.Close() })
|
||||
s.panelGroup.AddWidget(closeButton)
|
||||
|
||||
s.loadNewStatPoints()
|
||||
s.setLayout()
|
||||
|
||||
s.initStatValueLabels()
|
||||
s.panelGroup.SetVisible(false)
|
||||
}
|
||||
|
||||
func (s *HeroStatsPanel) loadNewStatPoints() {
|
||||
field, err := s.uiManager.NewSprite(d2resource.HeroStatsPanelStatsPoints, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
s.Error(err.Error())
|
||||
}
|
||||
|
||||
field.SetPosition(newStatsRemainingPointsFieldX, newStatsRemainingPointsFieldY)
|
||||
s.newStatPoints.AddWidget(field)
|
||||
|
||||
label1 := s.uiManager.NewLabel(d2resource.Font6, d2resource.PaletteSky)
|
||||
label1.SetPosition(newStatsRemainingPointsLabelX, newStatsRemainingPointsLabel1Y)
|
||||
label1.SetText(s.asset.TranslateString("strchrstat"))
|
||||
label1.Color[0] = d2util.Color(d2gui.ColorRed)
|
||||
s.newStatPoints.AddWidget(label1)
|
||||
|
||||
label2 := s.uiManager.NewLabel(d2resource.Font6, d2resource.PaletteSky)
|
||||
label2.SetPosition(newStatsRemainingPointsLabelX, newStatsRemainingPointsLabel2Y)
|
||||
label2.SetText(s.asset.TranslateString("strchrrema"))
|
||||
label2.Color[0] = d2util.Color(d2gui.ColorRed)
|
||||
s.newStatPoints.AddWidget(label2)
|
||||
|
||||
s.remainingPoints = s.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteSky)
|
||||
s.remainingPoints.SetText(strconv.Itoa(s.heroState.StatsPoints))
|
||||
s.remainingPoints.SetPosition(newStatsRemainingPointsValueX, newStatsRemainingPointsValueY)
|
||||
s.remainingPoints.Alignment = d2ui.HorizontalAlignCenter
|
||||
s.newStatPoints.AddWidget(s.remainingPoints)
|
||||
|
||||
buttons := []struct {
|
||||
x int
|
||||
y int
|
||||
cb func()
|
||||
}{
|
||||
{205, 140, func() {
|
||||
s.heroState.Strength++
|
||||
}},
|
||||
{205, 201, func() {
|
||||
s.heroState.Dexterity++
|
||||
}},
|
||||
{205, 286, func() {
|
||||
s.heroState.Vitality++
|
||||
}},
|
||||
{205, 347, func() {
|
||||
s.heroState.Energy++
|
||||
}},
|
||||
}
|
||||
|
||||
var socket *d2ui.Sprite
|
||||
|
||||
var button *d2ui.Button
|
||||
|
||||
for _, i := range buttons {
|
||||
currentValue := i
|
||||
|
||||
socket, err = s.uiManager.NewSprite(d2resource.HeroStatsPanelSocket, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
s.Error(err.Error())
|
||||
}
|
||||
|
||||
socket.SetPosition(i.x+addStatSocketOffsetX, i.y+addStatSocketOffsetY)
|
||||
s.newStatPoints.AddWidget(socket)
|
||||
|
||||
button = s.uiManager.NewButton(d2ui.ButtonTypeAddSkill, d2resource.PaletteSky)
|
||||
button.SetPosition(i.x, i.y)
|
||||
button.OnActivated(func() {
|
||||
currentValue.cb()
|
||||
s.heroState.StatsPoints--
|
||||
s.remainingPoints.SetText(strconv.Itoa(s.heroState.StatsPoints))
|
||||
s.setStatValues()
|
||||
s.setLayout()
|
||||
})
|
||||
s.newStatPoints.AddWidget(button)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *HeroStatsPanel) setLayout() {
|
||||
s.newStatPoints.SetVisible(s.heroState.StatsPoints > 0 && s.IsOpen())
|
||||
}
|
||||
|
||||
// IsOpen returns true if the hero status panel is open
|
||||
func (s *HeroStatsPanel) IsOpen() bool {
|
||||
return s.isOpen
|
||||
@ -176,12 +270,14 @@ func (s *HeroStatsPanel) Toggle() {
|
||||
func (s *HeroStatsPanel) Open() {
|
||||
s.isOpen = true
|
||||
s.panelGroup.SetVisible(true)
|
||||
s.setLayout()
|
||||
}
|
||||
|
||||
// Close closed the hero status panel
|
||||
func (s *HeroStatsPanel) Close() {
|
||||
s.isOpen = false
|
||||
s.panelGroup.SetVisible(false)
|
||||
s.setLayout()
|
||||
s.onCloseCb()
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,11 @@ const (
|
||||
whiteAlpha100 = 0xffffffff
|
||||
)
|
||||
|
||||
const (
|
||||
addStatsButtonX, addStatsButtonY = 206, 561
|
||||
addSkillButtonX, addSkillButtonY = 563, 561
|
||||
)
|
||||
|
||||
// HUD represents the always visible user interface of the game
|
||||
type HUD struct {
|
||||
actionableRegions []actionableRegion
|
||||
@ -103,7 +108,11 @@ type HUD struct {
|
||||
widgetLeftSkill *d2ui.CustomWidget
|
||||
widgetRightSkill *d2ui.CustomWidget
|
||||
panelBackground *d2ui.CustomWidget
|
||||
addStatsButton *d2ui.Button
|
||||
addSkillButton *d2ui.Button
|
||||
panelGroup *d2ui.WidgetGroup
|
||||
gameControls *GameControls
|
||||
|
||||
*d2util.Logger
|
||||
}
|
||||
|
||||
@ -116,6 +125,7 @@ func NewHUD(
|
||||
actionableRegions []actionableRegion,
|
||||
mapEngine *d2mapengine.MapEngine,
|
||||
l d2util.LogLevel,
|
||||
gameControls *GameControls,
|
||||
mapRenderer *d2maprenderer.MapRenderer,
|
||||
) *HUD {
|
||||
nameLabel := ui.NewLabel(d2resource.Font16, d2resource.PaletteStatic)
|
||||
@ -149,6 +159,7 @@ func NewHUD(
|
||||
zoneChangeText: zoneLabel,
|
||||
healthGlobe: healthGlobe,
|
||||
manaGlobe: manaGlobe,
|
||||
gameControls: gameControls,
|
||||
}
|
||||
|
||||
hud.Logger = d2util.NewLogger()
|
||||
@ -177,6 +188,16 @@ func (h *HUD) Load() {
|
||||
h.loadCustomWidgets()
|
||||
h.loadUIButtons()
|
||||
|
||||
h.addStatsButton = h.uiManager.NewButton(d2ui.ButtonTypeAddSkill, "")
|
||||
h.addStatsButton.SetPosition(addStatsButtonX, addStatsButtonY)
|
||||
h.addStatsButton.SetVisible(false)
|
||||
h.panelGroup.AddWidget(h.addStatsButton)
|
||||
|
||||
h.addSkillButton = h.uiManager.NewButton(d2ui.ButtonTypeAddSkill, "")
|
||||
h.addSkillButton.SetPosition(addSkillButtonX, addSkillButtonY)
|
||||
h.addSkillButton.SetVisible(false)
|
||||
h.panelGroup.AddWidget(h.addSkillButton)
|
||||
|
||||
h.panelGroup.SetVisible(true)
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package d2player
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
@ -56,6 +57,10 @@ const (
|
||||
frameSelectedTab3Full = 13
|
||||
)
|
||||
|
||||
const (
|
||||
remainingPointsLabelX, remainingPointsLabelY = 677, 128
|
||||
)
|
||||
|
||||
const (
|
||||
skillTreePanelX = 401
|
||||
skillTreePanelY = 64
|
||||
@ -87,6 +92,7 @@ type skillTreeHeroTypeResources struct {
|
||||
func newSkillTree(
|
||||
skills map[int]*d2hero.HeroSkill,
|
||||
heroClass d2enum.Hero,
|
||||
hero *d2hero.HeroStatsState,
|
||||
asset *d2asset.AssetManager,
|
||||
l d2util.LogLevel,
|
||||
ui *d2ui.UIManager,
|
||||
@ -98,6 +104,7 @@ func newSkillTree(
|
||||
uiManager: ui,
|
||||
originX: skillTreePanelX,
|
||||
originY: skillTreePanelY,
|
||||
stats: hero,
|
||||
tab: [numTabs]*skillTreeTab{
|
||||
{},
|
||||
{},
|
||||
@ -124,6 +131,7 @@ type skillTree struct {
|
||||
availSPLabel *d2ui.Label
|
||||
closeButton *d2ui.Button
|
||||
tab [numTabs]*skillTreeTab
|
||||
remainingPoints *d2ui.Label
|
||||
isOpen bool
|
||||
originX int
|
||||
originY int
|
||||
@ -132,6 +140,7 @@ type skillTree struct {
|
||||
panelGroup *d2ui.WidgetGroup
|
||||
iconGroup *d2ui.WidgetGroup
|
||||
panel *d2ui.CustomWidget
|
||||
stats *d2hero.HeroStatsState
|
||||
|
||||
*d2util.Logger
|
||||
l d2util.LogLevel
|
||||
@ -152,6 +161,12 @@ func (s *skillTree) load() {
|
||||
s.closeButton.OnActivated(func() { s.Close() })
|
||||
s.panelGroup.AddWidget(s.closeButton)
|
||||
|
||||
s.remainingPoints = s.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteSky)
|
||||
s.remainingPoints.SetPosition(remainingPointsLabelX, remainingPointsLabelY)
|
||||
s.remainingPoints.Alignment = d2ui.HorizontalAlignCenter
|
||||
s.remainingPoints.SetText(strconv.Itoa(s.stats.SkillPoints))
|
||||
s.panelGroup.AddWidget(s.remainingPoints)
|
||||
|
||||
if err := s.setHeroTypeResourcePath(); err != nil {
|
||||
s.Error(err.Error())
|
||||
}
|
||||
|
BIN
docs/game_panels.png
Normal file
BIN
docs/game_panels.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 MiB |
Loading…
Reference in New Issue
Block a user