1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-11-03 01:37:18 -04:00
OpenDiablo2/d2game/d2gamescreen/select_hero_class.go

790 lines
25 KiB
Go
Raw Normal View History

package d2gamescreen
2019-11-10 03:36:53 -05:00
import (
"fmt"
2020-09-12 16:25:09 -04:00
"image"
"log"
2020-09-12 16:25:09 -04:00
Removing d2datadict singletons (#738) * Remove weapons, armor, misc, itemCommon, itemTyps datadict singletons - removed loader calls from d2app - removed the HeroObjects singleton from `d2core/d2inventory` - added an InventoryItemFactory in d2inventory - package-level functions that use data records are now methods of the InventoryItemFactory - renamed ItemGenerator in d2item to ItemFactory - package-level functions that use records are now methods of ItemFactory - d2map.MapEntityFactory now has an item factory instance for creating items - fixed a bug in unique item record loader where it loaded an empty record - added a PlayerStateFactory for creating a player state (uses the asset manager) - updated the test inventory/equipment code in d2player to handle errors from the ItemFactory - character select and character creation screens have a player state and inventory item factory - updated item tests to use the item factory * minor edit * Removed d2datadict.Experience singleton added a HeroStatsFactory, much like the other factories. The factory gets an asset manager reference in order to use data records. * removed d2datadict.AutoMagic singleton * removed d2datadict.AutoMap singleton * removed d2datadict.BodyLocations singleton * removed d2datadict.Books singleton * Removed singletons for level records - removed loader calls in d2app - changed type references from d2datadict to d2records - added a `MapGenerator` in d2mapgen which uses thew asset manager and map engine - package-level map generation functions are now MapGenerator methods - `d2datadict.GetLevelDetails(id int)` is now a method of the RecordManager * remove SkillCalc and MissileCalc singletons * Removed CharStats and ItemStatCost singletons - added an ItemStatFactory which uses the asset manager to create stats - package-level functions for stats in d2item are now StatFactory methods - changed type references from d2datadict to d2records - `d2player.GetAllPlayerStates` is now a method of the `PlayerStateFactory` * Removed DkillDesc and Skills singletons from d2datadict - removed loader calls from d2app - diablo2stats.Stat instances are given a reference to the factory for doing record lookups * update the stats test to use mock a asset manager and stat factory * fixed diablo2stats tests and diablo2item tests * removed CompCodes singleton from d2datadict * remove cubemain singleton from d2datadict * removed DifficultyLevels singleton from d2datadict * removed ElemTypes singleton from d2datadict * removed events.go loader from d2datadict (was unused) * removed Gems singleton from d2datadict * removed Hireling and Inventory singletons from d2datadict * removed MagicPrefix and MagicSuffix singletons from d2datadict * removed ItemRatios singleton from d2datadict * removed Missiles singleton from d2datadict * removed MonModes singleton * Removed all monster and npc singletons from d2datadict - MapStamp instances now get a reference to their factory for doing record lookups * removed SoundEntry and SoundEnviron singletons from d2datadict
2020-09-20 17:52:01 -04:00
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
2020-02-08 21:02:37 -05:00
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
2020-02-08 21:02:37 -05:00
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
remove d2asset singleton (#726) * export d2asset singleton * add *d2asset.AssetManager to d2app - d2app now has a reference to an asset manager which it will use for loading - added asset loader methods to the asset manager - functions in d2asset are now wrappers for asset manager methods * add asset manager reference to audio provider - d2app asset manager reference is now passed to audio provider - asset manager is created in main.go for now to pass into audio provider - CreateSoundEffect is now a method, no longer exported, uses the asset manager reference * d2app passes asset manager refence to map engine test * in d2asset, all calls to LoadFile replaced with call to Singleton.Loadfile * blizzard intro and credits screen - d2app passes reference to the asset manager to these screens * asset manager for d2map - adding MapStampFactory, takes an asset manager reference - embedded MapStampFactory into the MapEngine - LoadStamp is now a method of the MapStampFactory * d2asset: removed LoadFileStream, LoadFile, and FileExists * d2gui changes - singleton now has an asset manager reference - calls to d2asset loader functions removed - createButton is now a method of LayoutManager - moved LayoutEntry to its own file * map entity factory - Map engine has an embedded map entity factory - Map stamp factory gets a reference to the map engine's entity factory - Stamps are given a reference to the map engine entity factory when created - Character select gets a map entity factory - Embedded the stamp factory into the MapEngine * asset manager for d2ui - d2ui is passed an asset manager reference when created - all calls to d2asset loader functions in d2ui now refer to the asset manager - d2gamescreen gets a ui manager when created - help overlay is now passed a ui manager when created * d2gamescreen + d2player: asset manager references added an asset manager reference to - inventory panel + inventory grid - mini panel - game controls - help overlay - character select - main menu - select hero class - hero stats panel * Removed d2asset.LoadAnimation all references to this function have been replaced with calls to the asset manager method * adding asset to help overlay, bugfix for 4d59c91 * Removed d2asset.LoadFont and d2asset.LoadAnimationWithEffect all references to these have been replaced with calls to the asset manager methods * MapRenderer now gets an asset manager reference * removed d2asset.LoadPalette all references have been replaced with calls to an asset manager instance * merged d2object with d2mapentity d2object was only being used to create objects in the map, so the provider function is now a method of the map entity factory. calls to d2asset have been removed. * removed d2asset.LoadComposite all calls are now made to the asset manager method * removed d2asset singleton all singleton references have been removed, a single instance of the asset manager is passed around the entire app * rename Initialize to NewAssetManager
2020-09-12 16:51:30 -04:00
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
2020-02-08 21:02:37 -05:00
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
2019-11-10 03:36:53 -05:00
)
const (
millisecondsPerSecond = 1000.0
)
type heroRenderConfig struct {
idleAnimationPath string
idleSelectedAnimationPath string
forwardWalkAnimationPath string
forwardWalkOverlayAnimationPath string
forwardWalkOverlayBlend bool
selectedAnimationPath string
selectedOverlayAnimationPath string
backWalkAnimationPath string
backWalkOverlayAnimationPath string
selectionBounds image.Rectangle
selectSfx string
deselectSfx string
position image.Point
idlePlayLengthMs int
forwardWalkPlayLengthMs int
backWalkPlayLengthMs int
}
func point(x, y int) image.Point {
return image.Point{X: x, Y: y}
}
func rect(x1, y1, x2, y2 int) image.Rectangle {
return image.Rectangle{Min: point(x1, y1), Max: point(x2, y2)}
}
// animation position, selection box bound, animation play lengths in ms
const (
barbPosX, barbPosY = 400, 330
barbRectMinX, barbRectMinY, barbRectMaxX, barbRectMaxY = 364, 201, 90, 170
barbIdleLength, barbForwardLength, barbBackLength = 0, 2500, 1000
sorcPosX, sorcPosY = 626, 352
sorcRectMinX, sorcRectMinY, sorcRectMaxX, sorcRectMaxY = 580, 240, 65, 160
sorcIdleLength, sorcForwardLength, sorcBackLength = 2500, 2300, 1200
necPosX, necPosY = 300, 335
necRectMinX, necRectMinY, necRectMaxX, necRectMaxY = 265, 220, 55, 175
necIdleLength, necForwardLength, necBackLength = 1200, 2000, 1500
palPosX, palPosY = 521, 338
palRectMinX, palRectMinY, palRectMaxX, palRectMaxY = 490, 210, 65, 180
palIdleLength, palForwardLength, palBackLength = 2500, 3400, 1300
amaPosX, amaPosY = 100, 339
amaRectMinX, amaRectMinY, amaRectMaxX, amaRectMaxY = 70, 220, 55, 200
amaIdleLength, amaForwardLength, amaBackLength = 2500, 2200, 1500
assPosX, assPosY = 231, 365
assRectMinX, assRectMinY, assRectMaxX, assRectMaxY = 175, 235, 50, 180
assIdleLength, assForwardLength, assBackLength = 2500, 3800, 1500
druPosX, druPosY = 720, 370
druRectMinX, druRectMinY, druRectMaxX, druRectMaxY = 680, 220, 70, 195
druIdleLength, druForwardLength, druBackLength = 1500, 4800, 1500
campfirePosX, campfirePosY = 380, 335
)
// label and button positions
const (
headingX, headingY = 400, 17
heroClassLabelX, heroClassLabelY = 400, 65
heroDescLine1X, heroDescLine1Y = 400, 100
heroDescLine2X, heroDescLine2Y = 400, 115
heroDescLine3X, heroDescLine3Y = 400, 130
heroNameLabelX, heroNameLabelY = 321, 475
expansionLabelX, expansionLabelY = 339, 526
hardcoreLabelX, hardcoreLabelY = 339, 548
selHeroExitBtnX, selHeroExitBtnY = 33, 537
selHeroOkBtnX, selHeroOkBtnY = 630, 537
heroNameTextBoxX, heoNameTextBoxY = 318, 493
expandsionCheckboxX, expansionCheckboxY = 318, 526
hardcoreCheckoxX, hardcoreCheckboxY = 318, 548
)
const heroDescCharWidth = 37
//nolint:funlen // this func returns a map of structs and the structs are big, deal with it
func getHeroRenderConfiguration() map[d2enum.Hero]*heroRenderConfig {
configs := make(map[d2enum.Hero]*heroRenderConfig)
configs[d2enum.HeroBarbarian] = &heroRenderConfig{
d2resource.CharacterSelectBarbarianUnselected,
d2resource.CharacterSelectBarbarianUnselectedH,
d2resource.CharacterSelectBarbarianForwardWalk,
d2resource.CharacterSelectBarbarianForwardWalkOverlay,
false,
d2resource.CharacterSelectBarbarianSelected,
"",
d2resource.CharacterSelectBarbarianBackWalk,
"",
rect(barbRectMinX, barbRectMinY, barbRectMaxX, barbRectMaxY),
d2resource.SFXBarbarianSelect,
d2resource.SFXBarbarianDeselect,
point(barbPosX, barbPosY),
barbIdleLength,
barbForwardLength,
barbBackLength,
}
configs[d2enum.HeroSorceress] = &heroRenderConfig{
d2resource.CharacterSelectSorceressUnselected,
d2resource.CharacterSelectSorceressUnselectedH,
d2resource.CharacterSelectSorceressForwardWalk,
d2resource.CharacterSelectSorceressForwardWalkOverlay,
true,
d2resource.CharacterSelectSorceressSelected,
d2resource.CharacterSelectSorceressSelectedOverlay,
d2resource.CharacterSelectSorceressBackWalk,
d2resource.CharacterSelectSorceressBackWalkOverlay,
rect(sorcRectMinX, sorcRectMinY, sorcRectMaxX, sorcRectMaxY),
d2resource.SFXSorceressSelect,
d2resource.SFXSorceressDeselect,
point(sorcPosX, sorcPosY),
sorcIdleLength,
sorcForwardLength,
sorcBackLength,
}
configs[d2enum.HeroNecromancer] = &heroRenderConfig{
d2resource.CharacterSelectNecromancerUnselected,
d2resource.CharacterSelectNecromancerUnselectedH,
d2resource.CharacterSelectNecromancerForwardWalk,
d2resource.CharacterSelectNecromancerForwardWalkOverlay,
true,
d2resource.CharacterSelectNecromancerSelected,
d2resource.CharacterSelectNecromancerSelectedOverlay,
d2resource.CharacterSelectNecromancerBackWalk,
d2resource.CharacterSelectNecromancerBackWalkOverlay,
rect(necRectMinX, necRectMinY, necRectMaxX, necRectMaxY),
d2resource.SFXNecromancerSelect,
d2resource.SFXNecromancerDeselect,
point(necPosX, necPosY),
necIdleLength,
necForwardLength,
necBackLength,
}
configs[d2enum.HeroPaladin] = &heroRenderConfig{
d2resource.CharacterSelectPaladinUnselected,
d2resource.CharacterSelectPaladinUnselectedH,
d2resource.CharacterSelectPaladinForwardWalk,
d2resource.CharacterSelectPaladinForwardWalkOverlay,
false,
d2resource.CharacterSelectPaladinSelected,
"",
d2resource.CharacterSelectPaladinBackWalk,
"",
rect(palRectMinX, palRectMinY, palRectMaxX, palRectMaxY),
d2resource.SFXPaladinSelect,
d2resource.SFXPaladinDeselect,
point(palPosX, palPosY),
palIdleLength,
palForwardLength,
palBackLength,
}
configs[d2enum.HeroAmazon] = &heroRenderConfig{
d2resource.CharacterSelectAmazonUnselected,
d2resource.CharacterSelectAmazonUnselectedH,
d2resource.CharacterSelectAmazonForwardWalk,
"",
false,
d2resource.CharacterSelectAmazonSelected,
"",
d2resource.CharacterSelectAmazonBackWalk,
"",
rect(amaRectMinX, amaRectMinY, amaRectMaxX, amaRectMaxY),
d2resource.SFXAmazonSelect,
d2resource.SFXAmazonDeselect,
point(amaPosX, amaPosY),
amaIdleLength,
amaForwardLength,
amaBackLength,
}
configs[d2enum.HeroAssassin] = &heroRenderConfig{
d2resource.CharacterSelectAssassinUnselected,
d2resource.CharacterSelectAssassinUnselectedH,
d2resource.CharacterSelectAssassinForwardWalk,
"",
false,
d2resource.CharacterSelectAssassinSelected,
"",
d2resource.CharacterSelectAssassinBackWalk,
"",
rect(assRectMinX, assRectMinY, assRectMaxX, assRectMaxY),
d2resource.SFXAssassinSelect,
d2resource.SFXAssassinDeselect,
point(assPosX, assPosY),
assIdleLength,
assForwardLength,
assBackLength,
}
configs[d2enum.HeroDruid] = &heroRenderConfig{
d2resource.CharacterSelectDruidUnselected,
d2resource.CharacterSelectDruidUnselectedH,
d2resource.CharacterSelectDruidForwardWalk,
"",
false,
d2resource.CharacterSelectDruidSelected,
"",
d2resource.CharacterSelectDruidBackWalk,
"",
rect(druRectMinX, druRectMinY, druRectMaxX, druRectMaxY),
d2resource.SFXDruidSelect,
d2resource.SFXDruidDeselect,
point(druPosX, druPosY),
druIdleLength,
druForwardLength,
druBackLength,
}
return configs
}
// HeroRenderInfo stores the rendering information of a hero for the Select Hero Class screen
2019-11-10 03:36:53 -05:00
type HeroRenderInfo struct {
Stance d2enum.HeroStance
IdleSprite *d2ui.Sprite
IdleSelectedSprite *d2ui.Sprite
ForwardWalkSprite *d2ui.Sprite
ForwardWalkSpriteOverlay *d2ui.Sprite
SelectedSprite *d2ui.Sprite
SelectedSpriteOverlay *d2ui.Sprite
BackWalkSprite *d2ui.Sprite
BackWalkSpriteOverlay *d2ui.Sprite
2019-11-10 03:36:53 -05:00
SelectionBounds image.Rectangle
2020-06-28 19:31:10 -04:00
SelectSfx d2interface.SoundEffect
DeselectSfx d2interface.SoundEffect
2019-11-10 03:36:53 -05:00
}
func (hri *HeroRenderInfo) advance(elapsed float64) {
advanceSprite(hri.IdleSprite, elapsed)
advanceSprite(hri.IdleSelectedSprite, elapsed)
advanceSprite(hri.ForwardWalkSprite, elapsed)
advanceSprite(hri.ForwardWalkSpriteOverlay, elapsed)
advanceSprite(hri.SelectedSprite, elapsed)
advanceSprite(hri.SelectedSpriteOverlay, elapsed)
advanceSprite(hri.BackWalkSprite, elapsed)
advanceSprite(hri.BackWalkSpriteOverlay, elapsed)
}
// SelectHeroClass represents the Select Hero Class screen
2019-11-10 03:36:53 -05:00
type SelectHeroClass struct {
Removing d2datadict singletons (#738) * Remove weapons, armor, misc, itemCommon, itemTyps datadict singletons - removed loader calls from d2app - removed the HeroObjects singleton from `d2core/d2inventory` - added an InventoryItemFactory in d2inventory - package-level functions that use data records are now methods of the InventoryItemFactory - renamed ItemGenerator in d2item to ItemFactory - package-level functions that use records are now methods of ItemFactory - d2map.MapEntityFactory now has an item factory instance for creating items - fixed a bug in unique item record loader where it loaded an empty record - added a PlayerStateFactory for creating a player state (uses the asset manager) - updated the test inventory/equipment code in d2player to handle errors from the ItemFactory - character select and character creation screens have a player state and inventory item factory - updated item tests to use the item factory * minor edit * Removed d2datadict.Experience singleton added a HeroStatsFactory, much like the other factories. The factory gets an asset manager reference in order to use data records. * removed d2datadict.AutoMagic singleton * removed d2datadict.AutoMap singleton * removed d2datadict.BodyLocations singleton * removed d2datadict.Books singleton * Removed singletons for level records - removed loader calls in d2app - changed type references from d2datadict to d2records - added a `MapGenerator` in d2mapgen which uses thew asset manager and map engine - package-level map generation functions are now MapGenerator methods - `d2datadict.GetLevelDetails(id int)` is now a method of the RecordManager * remove SkillCalc and MissileCalc singletons * Removed CharStats and ItemStatCost singletons - added an ItemStatFactory which uses the asset manager to create stats - package-level functions for stats in d2item are now StatFactory methods - changed type references from d2datadict to d2records - `d2player.GetAllPlayerStates` is now a method of the `PlayerStateFactory` * Removed DkillDesc and Skills singletons from d2datadict - removed loader calls from d2app - diablo2stats.Stat instances are given a reference to the factory for doing record lookups * update the stats test to use mock a asset manager and stat factory * fixed diablo2stats tests and diablo2item tests * removed CompCodes singleton from d2datadict * remove cubemain singleton from d2datadict * removed DifficultyLevels singleton from d2datadict * removed ElemTypes singleton from d2datadict * removed events.go loader from d2datadict (was unused) * removed Gems singleton from d2datadict * removed Hireling and Inventory singletons from d2datadict * removed MagicPrefix and MagicSuffix singletons from d2datadict * removed ItemRatios singleton from d2datadict * removed Missiles singleton from d2datadict * removed MonModes singleton * Removed all monster and npc singletons from d2datadict - MapStamp instances now get a reference to their factory for doing record lookups * removed SoundEntry and SoundEnviron singletons from d2datadict
2020-09-20 17:52:01 -04:00
asset *d2asset.AssetManager
uiManager *d2ui.UIManager
bgImage *d2ui.Sprite
campfire *d2ui.Sprite
headingLabel *d2ui.Label
heroClassLabel *d2ui.Label
heroDesc1Label *d2ui.Label
heroDesc2Label *d2ui.Label
heroDesc3Label *d2ui.Label
heroNameTextbox *d2ui.TextBox
heroNameLabel *d2ui.Label
heroRenderInfo map[d2enum.Hero]*HeroRenderInfo
*d2inventory.InventoryItemFactory
*d2hero.HeroStateFactory
selectedHero d2enum.Hero
exitButton *d2ui.Button
okButton *d2ui.Button
expansionCheckbox *d2ui.Checkbox
expansionCharLabel *d2ui.Label
hardcoreCheckbox *d2ui.Checkbox
hardcoreCharLabel *d2ui.Label
2020-06-18 14:11:04 -04:00
connectionType d2clientconnectiontype.ClientConnectionType
connectionHost string
audioProvider d2interface.AudioProvider
renderer d2interface.Renderer
navigator d2interface.Navigator
2019-11-10 03:36:53 -05:00
}
// CreateSelectHeroClass creates an instance of a SelectHeroClass
func CreateSelectHeroClass(
navigator d2interface.Navigator,
asset *d2asset.AssetManager,
renderer d2interface.Renderer,
audioProvider d2interface.AudioProvider,
ui *d2ui.UIManager,
connectionType d2clientconnectiontype.ClientConnectionType,
connectionHost string,
Removing d2datadict singletons (#738) * Remove weapons, armor, misc, itemCommon, itemTyps datadict singletons - removed loader calls from d2app - removed the HeroObjects singleton from `d2core/d2inventory` - added an InventoryItemFactory in d2inventory - package-level functions that use data records are now methods of the InventoryItemFactory - renamed ItemGenerator in d2item to ItemFactory - package-level functions that use records are now methods of ItemFactory - d2map.MapEntityFactory now has an item factory instance for creating items - fixed a bug in unique item record loader where it loaded an empty record - added a PlayerStateFactory for creating a player state (uses the asset manager) - updated the test inventory/equipment code in d2player to handle errors from the ItemFactory - character select and character creation screens have a player state and inventory item factory - updated item tests to use the item factory * minor edit * Removed d2datadict.Experience singleton added a HeroStatsFactory, much like the other factories. The factory gets an asset manager reference in order to use data records. * removed d2datadict.AutoMagic singleton * removed d2datadict.AutoMap singleton * removed d2datadict.BodyLocations singleton * removed d2datadict.Books singleton * Removed singletons for level records - removed loader calls in d2app - changed type references from d2datadict to d2records - added a `MapGenerator` in d2mapgen which uses thew asset manager and map engine - package-level map generation functions are now MapGenerator methods - `d2datadict.GetLevelDetails(id int)` is now a method of the RecordManager * remove SkillCalc and MissileCalc singletons * Removed CharStats and ItemStatCost singletons - added an ItemStatFactory which uses the asset manager to create stats - package-level functions for stats in d2item are now StatFactory methods - changed type references from d2datadict to d2records - `d2player.GetAllPlayerStates` is now a method of the `PlayerStateFactory` * Removed DkillDesc and Skills singletons from d2datadict - removed loader calls from d2app - diablo2stats.Stat instances are given a reference to the factory for doing record lookups * update the stats test to use mock a asset manager and stat factory * fixed diablo2stats tests and diablo2item tests * removed CompCodes singleton from d2datadict * remove cubemain singleton from d2datadict * removed DifficultyLevels singleton from d2datadict * removed ElemTypes singleton from d2datadict * removed events.go loader from d2datadict (was unused) * removed Gems singleton from d2datadict * removed Hireling and Inventory singletons from d2datadict * removed MagicPrefix and MagicSuffix singletons from d2datadict * removed ItemRatios singleton from d2datadict * removed Missiles singleton from d2datadict * removed MonModes singleton * Removed all monster and npc singletons from d2datadict - MapStamp instances now get a reference to their factory for doing record lookups * removed SoundEntry and SoundEnviron singletons from d2datadict
2020-09-20 17:52:01 -04:00
) (*SelectHeroClass, error) {
playerStateFactory, err := d2hero.NewHeroStateFactory(asset)
if err != nil {
return nil, err
}
inventoryItemFactory, err := d2inventory.NewInventoryItemFactory(asset)
if err != nil {
return nil, err
}
2019-11-10 03:36:53 -05:00
result := &SelectHeroClass{
Removing d2datadict singletons (#738) * Remove weapons, armor, misc, itemCommon, itemTyps datadict singletons - removed loader calls from d2app - removed the HeroObjects singleton from `d2core/d2inventory` - added an InventoryItemFactory in d2inventory - package-level functions that use data records are now methods of the InventoryItemFactory - renamed ItemGenerator in d2item to ItemFactory - package-level functions that use records are now methods of ItemFactory - d2map.MapEntityFactory now has an item factory instance for creating items - fixed a bug in unique item record loader where it loaded an empty record - added a PlayerStateFactory for creating a player state (uses the asset manager) - updated the test inventory/equipment code in d2player to handle errors from the ItemFactory - character select and character creation screens have a player state and inventory item factory - updated item tests to use the item factory * minor edit * Removed d2datadict.Experience singleton added a HeroStatsFactory, much like the other factories. The factory gets an asset manager reference in order to use data records. * removed d2datadict.AutoMagic singleton * removed d2datadict.AutoMap singleton * removed d2datadict.BodyLocations singleton * removed d2datadict.Books singleton * Removed singletons for level records - removed loader calls in d2app - changed type references from d2datadict to d2records - added a `MapGenerator` in d2mapgen which uses thew asset manager and map engine - package-level map generation functions are now MapGenerator methods - `d2datadict.GetLevelDetails(id int)` is now a method of the RecordManager * remove SkillCalc and MissileCalc singletons * Removed CharStats and ItemStatCost singletons - added an ItemStatFactory which uses the asset manager to create stats - package-level functions for stats in d2item are now StatFactory methods - changed type references from d2datadict to d2records - `d2player.GetAllPlayerStates` is now a method of the `PlayerStateFactory` * Removed DkillDesc and Skills singletons from d2datadict - removed loader calls from d2app - diablo2stats.Stat instances are given a reference to the factory for doing record lookups * update the stats test to use mock a asset manager and stat factory * fixed diablo2stats tests and diablo2item tests * removed CompCodes singleton from d2datadict * remove cubemain singleton from d2datadict * removed DifficultyLevels singleton from d2datadict * removed ElemTypes singleton from d2datadict * removed events.go loader from d2datadict (was unused) * removed Gems singleton from d2datadict * removed Hireling and Inventory singletons from d2datadict * removed MagicPrefix and MagicSuffix singletons from d2datadict * removed ItemRatios singleton from d2datadict * removed Missiles singleton from d2datadict * removed MonModes singleton * Removed all monster and npc singletons from d2datadict - MapStamp instances now get a reference to their factory for doing record lookups * removed SoundEntry and SoundEnviron singletons from d2datadict
2020-09-20 17:52:01 -04:00
asset: asset,
heroRenderInfo: make(map[d2enum.Hero]*HeroRenderInfo),
selectedHero: d2enum.HeroNone,
connectionType: connectionType,
connectionHost: connectionHost,
audioProvider: audioProvider,
renderer: renderer,
navigator: navigator,
uiManager: ui,
HeroStateFactory: playerStateFactory,
InventoryItemFactory: inventoryItemFactory,
2019-11-10 03:36:53 -05:00
}
Removing d2datadict singletons (#738) * Remove weapons, armor, misc, itemCommon, itemTyps datadict singletons - removed loader calls from d2app - removed the HeroObjects singleton from `d2core/d2inventory` - added an InventoryItemFactory in d2inventory - package-level functions that use data records are now methods of the InventoryItemFactory - renamed ItemGenerator in d2item to ItemFactory - package-level functions that use records are now methods of ItemFactory - d2map.MapEntityFactory now has an item factory instance for creating items - fixed a bug in unique item record loader where it loaded an empty record - added a PlayerStateFactory for creating a player state (uses the asset manager) - updated the test inventory/equipment code in d2player to handle errors from the ItemFactory - character select and character creation screens have a player state and inventory item factory - updated item tests to use the item factory * minor edit * Removed d2datadict.Experience singleton added a HeroStatsFactory, much like the other factories. The factory gets an asset manager reference in order to use data records. * removed d2datadict.AutoMagic singleton * removed d2datadict.AutoMap singleton * removed d2datadict.BodyLocations singleton * removed d2datadict.Books singleton * Removed singletons for level records - removed loader calls in d2app - changed type references from d2datadict to d2records - added a `MapGenerator` in d2mapgen which uses thew asset manager and map engine - package-level map generation functions are now MapGenerator methods - `d2datadict.GetLevelDetails(id int)` is now a method of the RecordManager * remove SkillCalc and MissileCalc singletons * Removed CharStats and ItemStatCost singletons - added an ItemStatFactory which uses the asset manager to create stats - package-level functions for stats in d2item are now StatFactory methods - changed type references from d2datadict to d2records - `d2player.GetAllPlayerStates` is now a method of the `PlayerStateFactory` * Removed DkillDesc and Skills singletons from d2datadict - removed loader calls from d2app - diablo2stats.Stat instances are given a reference to the factory for doing record lookups * update the stats test to use mock a asset manager and stat factory * fixed diablo2stats tests and diablo2item tests * removed CompCodes singleton from d2datadict * remove cubemain singleton from d2datadict * removed DifficultyLevels singleton from d2datadict * removed ElemTypes singleton from d2datadict * removed events.go loader from d2datadict (was unused) * removed Gems singleton from d2datadict * removed Hireling and Inventory singletons from d2datadict * removed MagicPrefix and MagicSuffix singletons from d2datadict * removed ItemRatios singleton from d2datadict * removed Missiles singleton from d2datadict * removed MonModes singleton * Removed all monster and npc singletons from d2datadict - MapStamp instances now get a reference to their factory for doing record lookups * removed SoundEntry and SoundEnviron singletons from d2datadict
2020-09-20 17:52:01 -04:00
return result, nil
2019-11-10 03:36:53 -05:00
}
// OnLoad loads the resources for the Select Hero Class screen
func (v *SelectHeroClass) OnLoad(loading d2screen.LoadingState) {
2020-06-28 19:31:10 -04:00
v.audioProvider.PlayBGM(d2resource.BGMTitle)
loading.Progress(tenPercent)
v.bgImage = v.loadSprite(
d2resource.CharacterSelectBackground,
point(0, 0),
0,
true,
false,
)
loading.Progress(thirtyPercent)
v.createLabels()
loading.Progress(fourtyPercent)
v.createButtons()
v.campfire = v.loadSprite(
d2resource.CharacterSelectCampfire,
point(campfirePosX, campfirePosY),
0,
true,
true,
)
v.createCheckboxes()
loading.Progress(fiftyPercent)
for hero, config := range getHeroRenderConfiguration() {
position := config.position
forwardWalkOverlaySprite := v.loadSprite(
config.forwardWalkOverlayAnimationPath,
position,
config.forwardWalkPlayLengthMs,
false,
config.forwardWalkOverlayBlend,
)
v.heroRenderInfo[hero] = &HeroRenderInfo{
Stance: d2enum.HeroStanceIdle,
IdleSprite: v.loadSprite(config.idleAnimationPath, position,
config.idlePlayLengthMs, true, false),
IdleSelectedSprite: v.loadSprite(config.idleSelectedAnimationPath,
position,
config.idlePlayLengthMs, true, false),
ForwardWalkSprite: v.loadSprite(config.forwardWalkAnimationPath, position,
config.forwardWalkPlayLengthMs, false, false),
ForwardWalkSpriteOverlay: forwardWalkOverlaySprite,
SelectedSprite: v.loadSprite(config.selectedAnimationPath, position,
config.idlePlayLengthMs, true, false),
SelectedSpriteOverlay: v.loadSprite(config.selectedOverlayAnimationPath, position,
config.idlePlayLengthMs, true, true),
BackWalkSprite: v.loadSprite(config.backWalkAnimationPath, position,
config.backWalkPlayLengthMs, false, false),
BackWalkSpriteOverlay: v.loadSprite(config.backWalkOverlayAnimationPath, position,
config.backWalkPlayLengthMs, false, true),
SelectionBounds: config.selectionBounds,
SelectSfx: v.loadSoundEffect(config.selectSfx),
DeselectSfx: v.loadSoundEffect(config.deselectSfx),
}
}
}
2020-02-08 21:02:37 -05:00
func (v *SelectHeroClass) createLabels() {
v.headingLabel = v.uiManager.NewLabel(d2resource.Font30, d2resource.PaletteUnits)
2020-02-08 21:02:37 -05:00
fontWidth, _ := v.headingLabel.GetSize()
half := 2
halfFontWidth := fontWidth / half
v.headingLabel.SetPosition(headingX-halfFontWidth, headingY)
2020-02-08 21:02:37 -05:00
v.headingLabel.SetText("Select Hero Class")
v.headingLabel.Alignment = d2gui.HorizontalAlignCenter
2020-02-08 21:02:37 -05:00
v.heroClassLabel = v.uiManager.NewLabel(d2resource.Font30, d2resource.PaletteUnits)
v.heroClassLabel.Alignment = d2gui.HorizontalAlignCenter
v.heroClassLabel.SetPosition(heroClassLabelX, heroClassLabelY)
2020-02-08 21:02:37 -05:00
v.heroDesc1Label = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc1Label.Alignment = d2gui.HorizontalAlignCenter
v.heroDesc1Label.SetPosition(heroDescLine1X, heroDescLine1Y)
2020-02-08 21:02:37 -05:00
v.heroDesc2Label = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc2Label.Alignment = d2gui.HorizontalAlignCenter
v.heroDesc2Label.SetPosition(heroDescLine2X, heroDescLine2Y)
2020-02-08 21:02:37 -05:00
v.heroDesc3Label = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc3Label.Alignment = d2gui.HorizontalAlignCenter
v.heroDesc3Label.SetPosition(heroDescLine3X, heroDescLine3Y)
2020-02-08 21:02:37 -05:00
v.heroNameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroNameLabel.Alignment = d2gui.HorizontalAlignLeft
v.heroNameLabel.SetText(d2ui.ColorTokenize("Character Name", d2ui.ColorTokenGold))
v.heroNameLabel.SetPosition(heroNameLabelX, heroNameLabelY)
v.expansionCharLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
v.expansionCharLabel.Alignment = d2gui.HorizontalAlignLeft
v.expansionCharLabel.SetText(d2ui.ColorTokenize("EXPANSION CHARACTER", d2ui.ColorTokenGold))
v.expansionCharLabel.SetPosition(expansionLabelX, expansionLabelY)
v.hardcoreCharLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
v.hardcoreCharLabel.Alignment = d2gui.HorizontalAlignLeft
v.hardcoreCharLabel.SetText(d2ui.ColorTokenize("Hardcore", d2ui.ColorTokenGold))
v.hardcoreCharLabel.SetPosition(hardcoreLabelX, hardcoreLabelY)
}
2020-02-08 21:02:37 -05:00
func (v *SelectHeroClass) createButtons() {
v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, "EXIT")
v.exitButton.SetPosition(selHeroExitBtnX, selHeroExitBtnY)
2020-02-08 21:02:37 -05:00
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
v.okButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, "OK")
v.okButton.SetPosition(selHeroOkBtnX, selHeroOkBtnY)
2020-02-08 21:02:37 -05:00
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
v.okButton.SetVisible(false)
v.okButton.SetEnabled(false)
}
2020-02-08 21:02:37 -05:00
func (v *SelectHeroClass) createCheckboxes() {
v.heroNameTextbox = v.uiManager.NewTextbox()
v.heroNameTextbox.SetPosition(heroNameTextBoxX, heoNameTextBoxY)
2020-02-08 21:02:37 -05:00
v.heroNameTextbox.SetVisible(false)
v.expansionCheckbox = v.uiManager.NewCheckbox(true)
v.expansionCheckbox.SetPosition(expandsionCheckboxX, expansionCheckboxY)
2020-02-08 21:02:37 -05:00
v.expansionCheckbox.SetVisible(false)
v.hardcoreCheckbox = v.uiManager.NewCheckbox(false)
v.hardcoreCheckbox.SetPosition(hardcoreCheckoxX, hardcoreCheckboxY)
2020-02-08 21:02:37 -05:00
v.hardcoreCheckbox.SetVisible(false)
2019-11-10 03:36:53 -05:00
}
// OnUnload releases the resources of the Select Hero Class screen
2020-02-08 21:02:37 -05:00
func (v *SelectHeroClass) OnUnload() error {
for i := range v.heroRenderInfo {
v.heroRenderInfo[i].SelectSfx.Stop()
v.heroRenderInfo[i].DeselectSfx.Stop()
}
2019-11-10 03:36:53 -05:00
v.heroRenderInfo = nil
2020-02-08 21:02:37 -05:00
return nil
2019-11-10 03:36:53 -05:00
}
2020-06-28 19:31:10 -04:00
func (v *SelectHeroClass) onExitButtonClicked() {
v.navigator.ToCharacterSelect(v.connectionType, v.connectionHost)
2019-11-10 03:36:53 -05:00
}
2020-06-28 19:31:10 -04:00
func (v *SelectHeroClass) onOkButtonClicked() {
Removing d2datadict singletons (#738) * Remove weapons, armor, misc, itemCommon, itemTyps datadict singletons - removed loader calls from d2app - removed the HeroObjects singleton from `d2core/d2inventory` - added an InventoryItemFactory in d2inventory - package-level functions that use data records are now methods of the InventoryItemFactory - renamed ItemGenerator in d2item to ItemFactory - package-level functions that use records are now methods of ItemFactory - d2map.MapEntityFactory now has an item factory instance for creating items - fixed a bug in unique item record loader where it loaded an empty record - added a PlayerStateFactory for creating a player state (uses the asset manager) - updated the test inventory/equipment code in d2player to handle errors from the ItemFactory - character select and character creation screens have a player state and inventory item factory - updated item tests to use the item factory * minor edit * Removed d2datadict.Experience singleton added a HeroStatsFactory, much like the other factories. The factory gets an asset manager reference in order to use data records. * removed d2datadict.AutoMagic singleton * removed d2datadict.AutoMap singleton * removed d2datadict.BodyLocations singleton * removed d2datadict.Books singleton * Removed singletons for level records - removed loader calls in d2app - changed type references from d2datadict to d2records - added a `MapGenerator` in d2mapgen which uses thew asset manager and map engine - package-level map generation functions are now MapGenerator methods - `d2datadict.GetLevelDetails(id int)` is now a method of the RecordManager * remove SkillCalc and MissileCalc singletons * Removed CharStats and ItemStatCost singletons - added an ItemStatFactory which uses the asset manager to create stats - package-level functions for stats in d2item are now StatFactory methods - changed type references from d2datadict to d2records - `d2player.GetAllPlayerStates` is now a method of the `PlayerStateFactory` * Removed DkillDesc and Skills singletons from d2datadict - removed loader calls from d2app - diablo2stats.Stat instances are given a reference to the factory for doing record lookups * update the stats test to use mock a asset manager and stat factory * fixed diablo2stats tests and diablo2item tests * removed CompCodes singleton from d2datadict * remove cubemain singleton from d2datadict * removed DifficultyLevels singleton from d2datadict * removed ElemTypes singleton from d2datadict * removed events.go loader from d2datadict (was unused) * removed Gems singleton from d2datadict * removed Hireling and Inventory singletons from d2datadict * removed MagicPrefix and MagicSuffix singletons from d2datadict * removed ItemRatios singleton from d2datadict * removed Missiles singleton from d2datadict * removed MonModes singleton * Removed all monster and npc singletons from d2datadict - MapStamp instances now get a reference to their factory for doing record lookups * removed SoundEntry and SoundEnviron singletons from d2datadict
2020-09-20 17:52:01 -04:00
heroName := v.heroNameTextbox.GetText()
defaultStats := v.asset.Records.Character.Stats[v.selectedHero]
statsState := v.CreateHeroStatsState(v.selectedHero, defaultStats)
playerState, err := v.CreateHeroState(heroName, v.selectedHero, statsState)
if err != nil {
fmt.Printf("failed to create hero state!, err: %v\n", err)
return
Removing d2datadict singletons (#738) * Remove weapons, armor, misc, itemCommon, itemTyps datadict singletons - removed loader calls from d2app - removed the HeroObjects singleton from `d2core/d2inventory` - added an InventoryItemFactory in d2inventory - package-level functions that use data records are now methods of the InventoryItemFactory - renamed ItemGenerator in d2item to ItemFactory - package-level functions that use records are now methods of ItemFactory - d2map.MapEntityFactory now has an item factory instance for creating items - fixed a bug in unique item record loader where it loaded an empty record - added a PlayerStateFactory for creating a player state (uses the asset manager) - updated the test inventory/equipment code in d2player to handle errors from the ItemFactory - character select and character creation screens have a player state and inventory item factory - updated item tests to use the item factory * minor edit * Removed d2datadict.Experience singleton added a HeroStatsFactory, much like the other factories. The factory gets an asset manager reference in order to use data records. * removed d2datadict.AutoMagic singleton * removed d2datadict.AutoMap singleton * removed d2datadict.BodyLocations singleton * removed d2datadict.Books singleton * Removed singletons for level records - removed loader calls in d2app - changed type references from d2datadict to d2records - added a `MapGenerator` in d2mapgen which uses thew asset manager and map engine - package-level map generation functions are now MapGenerator methods - `d2datadict.GetLevelDetails(id int)` is now a method of the RecordManager * remove SkillCalc and MissileCalc singletons * Removed CharStats and ItemStatCost singletons - added an ItemStatFactory which uses the asset manager to create stats - package-level functions for stats in d2item are now StatFactory methods - changed type references from d2datadict to d2records - `d2player.GetAllPlayerStates` is now a method of the `PlayerStateFactory` * Removed DkillDesc and Skills singletons from d2datadict - removed loader calls from d2app - diablo2stats.Stat instances are given a reference to the factory for doing record lookups * update the stats test to use mock a asset manager and stat factory * fixed diablo2stats tests and diablo2item tests * removed CompCodes singleton from d2datadict * remove cubemain singleton from d2datadict * removed DifficultyLevels singleton from d2datadict * removed ElemTypes singleton from d2datadict * removed events.go loader from d2datadict (was unused) * removed Gems singleton from d2datadict * removed Hireling and Inventory singletons from d2datadict * removed MagicPrefix and MagicSuffix singletons from d2datadict * removed ItemRatios singleton from d2datadict * removed Missiles singleton from d2datadict * removed MonModes singleton * Removed all monster and npc singletons from d2datadict - MapStamp instances now get a reference to their factory for doing record lookups * removed SoundEntry and SoundEnviron singletons from d2datadict
2020-09-20 17:52:01 -04:00
}
err = v.Save(playerState)
Removing d2datadict singletons (#738) * Remove weapons, armor, misc, itemCommon, itemTyps datadict singletons - removed loader calls from d2app - removed the HeroObjects singleton from `d2core/d2inventory` - added an InventoryItemFactory in d2inventory - package-level functions that use data records are now methods of the InventoryItemFactory - renamed ItemGenerator in d2item to ItemFactory - package-level functions that use records are now methods of ItemFactory - d2map.MapEntityFactory now has an item factory instance for creating items - fixed a bug in unique item record loader where it loaded an empty record - added a PlayerStateFactory for creating a player state (uses the asset manager) - updated the test inventory/equipment code in d2player to handle errors from the ItemFactory - character select and character creation screens have a player state and inventory item factory - updated item tests to use the item factory * minor edit * Removed d2datadict.Experience singleton added a HeroStatsFactory, much like the other factories. The factory gets an asset manager reference in order to use data records. * removed d2datadict.AutoMagic singleton * removed d2datadict.AutoMap singleton * removed d2datadict.BodyLocations singleton * removed d2datadict.Books singleton * Removed singletons for level records - removed loader calls in d2app - changed type references from d2datadict to d2records - added a `MapGenerator` in d2mapgen which uses thew asset manager and map engine - package-level map generation functions are now MapGenerator methods - `d2datadict.GetLevelDetails(id int)` is now a method of the RecordManager * remove SkillCalc and MissileCalc singletons * Removed CharStats and ItemStatCost singletons - added an ItemStatFactory which uses the asset manager to create stats - package-level functions for stats in d2item are now StatFactory methods - changed type references from d2datadict to d2records - `d2player.GetAllPlayerStates` is now a method of the `PlayerStateFactory` * Removed DkillDesc and Skills singletons from d2datadict - removed loader calls from d2app - diablo2stats.Stat instances are given a reference to the factory for doing record lookups * update the stats test to use mock a asset manager and stat factory * fixed diablo2stats tests and diablo2item tests * removed CompCodes singleton from d2datadict * remove cubemain singleton from d2datadict * removed DifficultyLevels singleton from d2datadict * removed ElemTypes singleton from d2datadict * removed events.go loader from d2datadict (was unused) * removed Gems singleton from d2datadict * removed Hireling and Inventory singletons from d2datadict * removed MagicPrefix and MagicSuffix singletons from d2datadict * removed ItemRatios singleton from d2datadict * removed Missiles singleton from d2datadict * removed MonModes singleton * Removed all monster and npc singletons from d2datadict - MapStamp instances now get a reference to their factory for doing record lookups * removed SoundEntry and SoundEnviron singletons from d2datadict
2020-09-20 17:52:01 -04:00
if err != nil {
fmt.Printf("failed to save game state!, err: %v\n", err)
Removing d2datadict singletons (#738) * Remove weapons, armor, misc, itemCommon, itemTyps datadict singletons - removed loader calls from d2app - removed the HeroObjects singleton from `d2core/d2inventory` - added an InventoryItemFactory in d2inventory - package-level functions that use data records are now methods of the InventoryItemFactory - renamed ItemGenerator in d2item to ItemFactory - package-level functions that use records are now methods of ItemFactory - d2map.MapEntityFactory now has an item factory instance for creating items - fixed a bug in unique item record loader where it loaded an empty record - added a PlayerStateFactory for creating a player state (uses the asset manager) - updated the test inventory/equipment code in d2player to handle errors from the ItemFactory - character select and character creation screens have a player state and inventory item factory - updated item tests to use the item factory * minor edit * Removed d2datadict.Experience singleton added a HeroStatsFactory, much like the other factories. The factory gets an asset manager reference in order to use data records. * removed d2datadict.AutoMagic singleton * removed d2datadict.AutoMap singleton * removed d2datadict.BodyLocations singleton * removed d2datadict.Books singleton * Removed singletons for level records - removed loader calls in d2app - changed type references from d2datadict to d2records - added a `MapGenerator` in d2mapgen which uses thew asset manager and map engine - package-level map generation functions are now MapGenerator methods - `d2datadict.GetLevelDetails(id int)` is now a method of the RecordManager * remove SkillCalc and MissileCalc singletons * Removed CharStats and ItemStatCost singletons - added an ItemStatFactory which uses the asset manager to create stats - package-level functions for stats in d2item are now StatFactory methods - changed type references from d2datadict to d2records - `d2player.GetAllPlayerStates` is now a method of the `PlayerStateFactory` * Removed DkillDesc and Skills singletons from d2datadict - removed loader calls from d2app - diablo2stats.Stat instances are given a reference to the factory for doing record lookups * update the stats test to use mock a asset manager and stat factory * fixed diablo2stats tests and diablo2item tests * removed CompCodes singleton from d2datadict * remove cubemain singleton from d2datadict * removed DifficultyLevels singleton from d2datadict * removed ElemTypes singleton from d2datadict * removed events.go loader from d2datadict (was unused) * removed Gems singleton from d2datadict * removed Hireling and Inventory singletons from d2datadict * removed MagicPrefix and MagicSuffix singletons from d2datadict * removed ItemRatios singleton from d2datadict * removed Missiles singleton from d2datadict * removed MonModes singleton * Removed all monster and npc singletons from d2datadict - MapStamp instances now get a reference to their factory for doing record lookups * removed SoundEntry and SoundEnviron singletons from d2datadict
2020-09-20 17:52:01 -04:00
return
}
playerState.Equipment = v.InventoryItemFactory.DefaultHeroItems[v.selectedHero]
v.navigator.ToCreateGame(playerState.FilePath, d2clientconnectiontype.Local, v.connectionHost)
}
// Render renders the Select Hero Class screen
func (v *SelectHeroClass) Render(screen d2interface.Surface) {
v.bgImage.RenderSegmented(screen, 4, 3, 0)
v.headingLabel.Render(screen)
2019-11-10 03:36:53 -05:00
if v.selectedHero != d2enum.HeroNone {
v.heroClassLabel.Render(screen)
v.heroDesc1Label.Render(screen)
v.heroDesc2Label.Render(screen)
v.heroDesc3Label.Render(screen)
2019-11-10 03:36:53 -05:00
}
2019-11-10 03:36:53 -05:00
for heroClass, heroInfo := range v.heroRenderInfo {
if heroInfo.Stance == d2enum.HeroStanceIdle || heroInfo.Stance == d2enum.HeroStanceIdleSelected {
v.renderHero(screen, heroClass)
}
}
2019-11-10 03:36:53 -05:00
for heroClass, heroInfo := range v.heroRenderInfo {
if heroInfo.Stance != d2enum.HeroStanceIdle && heroInfo.Stance != d2enum.HeroStanceIdleSelected {
v.renderHero(screen, heroClass)
}
}
v.campfire.Render(screen)
if v.heroNameTextbox.GetVisible() {
v.heroNameLabel.Render(screen)
v.expansionCharLabel.Render(screen)
v.hardcoreCharLabel.Render(screen)
}
2019-11-10 03:36:53 -05:00
}
// Advance runs the update logic on the Select Hero Class screen
2020-02-08 21:02:37 -05:00
func (v *SelectHeroClass) Advance(tickTime float64) error {
2019-11-10 03:36:53 -05:00
canSelect := true
if err := v.campfire.Advance(tickTime); err != nil {
return err
}
for infoIdx := range v.heroRenderInfo {
v.heroRenderInfo[infoIdx].advance(tickTime)
if v.heroRenderInfo[infoIdx].Stance != d2enum.HeroStanceIdle &&
v.heroRenderInfo[infoIdx].Stance != d2enum.HeroStanceIdleSelected &&
v.heroRenderInfo[infoIdx].Stance != d2enum.HeroStanceSelected {
2019-11-10 03:36:53 -05:00
canSelect = false
}
}
for heroType := range v.heroRenderInfo {
v.updateHeroSelectionHover(heroType, canSelect)
2019-11-10 03:36:53 -05:00
}
v.okButton.SetEnabled(len(v.heroNameTextbox.GetText()) >= 2 && v.selectedHero != d2enum.HeroNone)
2020-02-08 21:02:37 -05:00
return nil
2019-11-10 03:36:53 -05:00
}
func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect bool) {
renderInfo := v.heroRenderInfo[hero]
switch renderInfo.Stance {
case d2enum.HeroStanceApproaching:
if renderInfo.ForwardWalkSprite.IsOnLastFrame() {
2019-11-10 03:36:53 -05:00
renderInfo.Stance = d2enum.HeroStanceSelected
setSpriteToFirstFrame(renderInfo.SelectedSprite)
setSpriteToFirstFrame(renderInfo.SelectedSpriteOverlay)
2019-11-10 03:36:53 -05:00
}
2019-11-10 03:36:53 -05:00
return
case d2enum.HeroStanceRetreating:
if renderInfo.BackWalkSprite.IsOnLastFrame() {
2019-11-10 03:36:53 -05:00
renderInfo.Stance = d2enum.HeroStanceIdle
setSpriteToFirstFrame(renderInfo.IdleSprite)
2019-11-10 03:36:53 -05:00
}
2019-11-10 03:36:53 -05:00
return
}
if !canSelect || renderInfo.Stance == d2enum.HeroStanceSelected {
2019-11-10 03:36:53 -05:00
return
}
mouseX, mouseY := v.uiManager.CursorPosition()
2019-11-10 03:36:53 -05:00
b := renderInfo.SelectionBounds
mouseHover := (mouseX >= b.Min.X) && (mouseX <= b.Min.X+b.Max.X) && (mouseY >= b.Min.Y) && (mouseY <= b.Min.Y+b.Max.Y)
if mouseHover && v.uiManager.CursorButtonPressed(d2ui.CursorButtonLeft) {
v.handleCursorButtonPress(hero, renderInfo)
return
}
v.setCurrentFrame(mouseHover, renderInfo)
if v.selectedHero == d2enum.HeroNone && mouseHover {
2019-11-10 03:36:53 -05:00
v.selectedHero = hero
v.updateHeroText()
}
}
2019-11-10 03:36:53 -05:00
func (v *SelectHeroClass) handleCursorButtonPress(hero d2enum.Hero, renderInfo *HeroRenderInfo) {
v.heroNameTextbox.SetVisible(true)
v.heroNameTextbox.Activate()
v.okButton.SetVisible(true)
v.expansionCheckbox.SetVisible(true)
v.hardcoreCheckbox.SetVisible(true)
renderInfo.Stance = d2enum.HeroStanceApproaching
setSpriteToFirstFrame(renderInfo.ForwardWalkSprite)
setSpriteToFirstFrame(renderInfo.ForwardWalkSpriteOverlay)
for _, heroInfo := range v.heroRenderInfo {
if heroInfo.Stance != d2enum.HeroStanceSelected {
continue
}
heroInfo.SelectSfx.Stop()
heroInfo.DeselectSfx.Play()
heroInfo.Stance = d2enum.HeroStanceRetreating
setSpriteToFirstFrame(heroInfo.BackWalkSprite)
setSpriteToFirstFrame(heroInfo.BackWalkSpriteOverlay)
2019-11-10 03:36:53 -05:00
}
v.selectedHero = hero
v.updateHeroText()
renderInfo.SelectSfx.Play()
}
func (v *SelectHeroClass) setCurrentFrame(mouseHover bool, renderInfo *HeroRenderInfo) {
if mouseHover && renderInfo.Stance != d2enum.HeroStanceIdleSelected {
if err := renderInfo.IdleSelectedSprite.SetCurrentFrame(renderInfo.IdleSprite.GetCurrentFrame()); err != nil {
fmt.Printf("could not set current frame to: %d\n", renderInfo.IdleSprite.GetCurrentFrame())
}
2019-11-10 03:36:53 -05:00
renderInfo.Stance = d2enum.HeroStanceIdleSelected
} else if !mouseHover && renderInfo.Stance != d2enum.HeroStanceIdle {
if err := renderInfo.IdleSprite.SetCurrentFrame(renderInfo.IdleSelectedSprite.GetCurrentFrame()); err != nil {
fmt.Printf("could not set current frame to: %d\n", renderInfo.IdleSelectedSprite.GetCurrentFrame())
}
2019-11-10 03:36:53 -05:00
renderInfo.Stance = d2enum.HeroStanceIdle
}
}
func (v *SelectHeroClass) renderHero(screen d2interface.Surface, hero d2enum.Hero) {
2019-11-10 03:36:53 -05:00
renderInfo := v.heroRenderInfo[hero]
switch renderInfo.Stance {
case d2enum.HeroStanceIdle:
drawSprite(renderInfo.IdleSprite, screen)
2019-11-10 03:36:53 -05:00
case d2enum.HeroStanceIdleSelected:
drawSprite(renderInfo.IdleSelectedSprite, screen)
2019-11-10 03:36:53 -05:00
case d2enum.HeroStanceApproaching:
drawSprite(renderInfo.ForwardWalkSprite, screen)
drawSprite(renderInfo.ForwardWalkSpriteOverlay, screen)
2019-11-10 03:36:53 -05:00
case d2enum.HeroStanceSelected:
drawSprite(renderInfo.SelectedSprite, screen)
drawSprite(renderInfo.SelectedSpriteOverlay, screen)
2019-11-10 03:36:53 -05:00
case d2enum.HeroStanceRetreating:
drawSprite(renderInfo.BackWalkSprite, screen)
drawSprite(renderInfo.BackWalkSpriteOverlay, screen)
2019-11-10 03:36:53 -05:00
}
}
func (v *SelectHeroClass) updateHeroText() {
// v.setDescLabels("") really takes a string translation key, but temporarily disabled.
2019-11-10 03:36:53 -05:00
switch v.selectedHero {
case d2enum.HeroNone:
return
case d2enum.HeroBarbarian:
v.heroClassLabel.SetText(v.asset.TranslateString("partycharbar"))
v.setDescLabels("He is unequaled in close-quarters combat and mastery of weapons.")
2019-11-10 03:36:53 -05:00
case d2enum.HeroNecromancer:
v.heroClassLabel.SetText(v.asset.TranslateString("partycharnec"))
v.setDescLabels("Summoning undead minions and cursing his enemies are his specialties.")
2019-11-10 03:36:53 -05:00
case d2enum.HeroPaladin:
v.heroClassLabel.SetText(v.asset.TranslateString("partycharpal"))
v.setDescLabels("He is a natural party leader, holy man, and blessed warrior.")
2019-11-10 03:36:53 -05:00
case d2enum.HeroAssassin:
v.heroClassLabel.SetText(v.asset.TranslateString("partycharass"))
v.setDescLabels("Schooled in the Martial Arts, her mind and body are deadly weapons.")
2019-11-10 03:36:53 -05:00
case d2enum.HeroSorceress:
v.heroClassLabel.SetText(v.asset.TranslateString("partycharsor"))
v.setDescLabels("She has mastered the elemental magicks -- fire, lightning, and ice.")
2019-11-10 03:36:53 -05:00
case d2enum.HeroAmazon:
v.heroClassLabel.SetText(v.asset.TranslateString("partycharama"))
v.setDescLabels("Skilled with the spear and the bow, she is a very versatile fighter.")
2019-11-10 03:36:53 -05:00
case d2enum.HeroDruid:
v.heroClassLabel.SetText(v.asset.TranslateString("partychardru"))
v.setDescLabels("Commanding the forces of nature, he summons wild beasts and raging storms to his side.")
2019-11-10 03:36:53 -05:00
}
}
const (
oneLine = 1
twoLine = 2
)
2019-11-10 03:36:53 -05:00
func (v *SelectHeroClass) setDescLabels(descKey string) {
heroDesc := v.asset.TranslateString(descKey)
parts := d2util.SplitIntoLinesWithMaxWidth(heroDesc, heroDescCharWidth)
numLines := len(parts)
if numLines > oneLine {
2019-11-10 03:36:53 -05:00
v.heroDesc1Label.SetText(parts[0])
v.heroDesc2Label.SetText(parts[1])
} else {
v.heroDesc1Label.SetText("")
2019-11-10 03:36:53 -05:00
v.heroDesc2Label.SetText("")
}
if numLines > twoLine {
2019-11-10 03:36:53 -05:00
v.heroDesc3Label.SetText(parts[2])
} else {
v.heroDesc3Label.SetText("")
}
}
func setSpriteToFirstFrame(sprite *d2ui.Sprite) {
if sprite != nil {
sprite.Rewind()
}
}
func drawSprite(sprite *d2ui.Sprite, target d2interface.Surface) {
if sprite != nil {
sprite.Render(target)
}
}
func advanceSprite(sprite *d2ui.Sprite, elapsed float64) {
if sprite != nil {
if err := sprite.Advance(elapsed); err != nil {
fmt.Printf("could not advance the sprite\n")
}
}
}
func (v *SelectHeroClass) loadSprite(animationPath string, position image.Point,
playLength int,
playLoop,
blend bool) *d2ui.Sprite {
if animationPath == "" {
return nil
}
Decouple asset manager from renderer (#730) * improve AssetManager implementation Notable changes are: * removed the individual managers inside of d2asset, only one asset manager * AssetManager now has caches for the types of files it loads * created a type for TextDictionary (the txt file structs) * fixed a file path bug in d2loader Source * fixed a asset stream bug in d2loader Asset * d2loader.Loader now needs a d2config.Config on creation (for resolving locale files) * updated the mpq file in d2asset test data, added test case for "sub-directory" * added a Data method to d2asset.Asset. The data is cached on first full read. * renamed ArchiveDataStream to DataStream in d2interface * moved palette utility func out of d2asset and into d2util * bugfix for MacOS mpq loader issue * lint fixes, added data caching to filesystem asset * adding comment for mpq asset close * Decouple d2asset from d2render Notable changes in d2common: * d2dcc.Load now fully decodes the dcc and stores the directions/frames in the dcc struct * un-exported dcc.decodeDirection, it is only used in d2dcc * removed font interface from d2interface, we only have one font implementation * added `Renderer` method to d2interface.Surface, animations use this to bind to a renderer and create surfaces as they need * added `BindRenderer` method to animation interface Notable changes in d2common/d2asset: * **d2asset.NewAssetManager only needs to be passed a d2config.Config**, it is decoupled from d2render * exported Animation * Animation implementation binds to the renderer to create surfaces only on the first time it is rendered * font, dcc, dc6 initialization logic moved out of asset_manager.go * for dc6 and dcc animations, the process of decoding and creating render surfaces has been broken into different methods * the d2asset.Font struct now stores font table data for initialization purposes Notable changes in d2core/d2render: * Surfaces store a renderer reference, this allows animations to bind to the renderer and create a surface just-in-time **These last changes should have been a separate PR, sorry.** Notable changes in d2core/d2ui: * ui.NewSprite now handles creating an animation internally, only needs image and palette path as arguments Notable Changes in d2game: Because of the change in d2ui, all instances of this code pattern... ```golang animation, err := screen.asset.LoadAnimation(imgPath, palettePath) sprite, err := screen.ui.NewSprite(animation) ``` ... becomes this ... ```golang sprite, err := screen.ui.NewSprite(imgPath, palettePath) ```
2020-09-14 17:31:45 -04:00
sprite, err := v.uiManager.NewSprite(animationPath, d2resource.PaletteFechar)
if err != nil {
Decouple asset manager from renderer (#730) * improve AssetManager implementation Notable changes are: * removed the individual managers inside of d2asset, only one asset manager * AssetManager now has caches for the types of files it loads * created a type for TextDictionary (the txt file structs) * fixed a file path bug in d2loader Source * fixed a asset stream bug in d2loader Asset * d2loader.Loader now needs a d2config.Config on creation (for resolving locale files) * updated the mpq file in d2asset test data, added test case for "sub-directory" * added a Data method to d2asset.Asset. The data is cached on first full read. * renamed ArchiveDataStream to DataStream in d2interface * moved palette utility func out of d2asset and into d2util * bugfix for MacOS mpq loader issue * lint fixes, added data caching to filesystem asset * adding comment for mpq asset close * Decouple d2asset from d2render Notable changes in d2common: * d2dcc.Load now fully decodes the dcc and stores the directions/frames in the dcc struct * un-exported dcc.decodeDirection, it is only used in d2dcc * removed font interface from d2interface, we only have one font implementation * added `Renderer` method to d2interface.Surface, animations use this to bind to a renderer and create surfaces as they need * added `BindRenderer` method to animation interface Notable changes in d2common/d2asset: * **d2asset.NewAssetManager only needs to be passed a d2config.Config**, it is decoupled from d2render * exported Animation * Animation implementation binds to the renderer to create surfaces only on the first time it is rendered * font, dcc, dc6 initialization logic moved out of asset_manager.go * for dc6 and dcc animations, the process of decoding and creating render surfaces has been broken into different methods * the d2asset.Font struct now stores font table data for initialization purposes Notable changes in d2core/d2render: * Surfaces store a renderer reference, this allows animations to bind to the renderer and create a surface just-in-time **These last changes should have been a separate PR, sorry.** Notable changes in d2core/d2ui: * ui.NewSprite now handles creating an animation internally, only needs image and palette path as arguments Notable Changes in d2game: Because of the change in d2ui, all instances of this code pattern... ```golang animation, err := screen.asset.LoadAnimation(imgPath, palettePath) sprite, err := screen.ui.NewSprite(animation) ``` ... becomes this ... ```golang sprite, err := screen.ui.NewSprite(imgPath, palettePath) ```
2020-09-14 17:31:45 -04:00
fmt.Printf("could not load sprite for the animation: %s\n", animationPath)
return nil
}
Decouple asset manager from renderer (#730) * improve AssetManager implementation Notable changes are: * removed the individual managers inside of d2asset, only one asset manager * AssetManager now has caches for the types of files it loads * created a type for TextDictionary (the txt file structs) * fixed a file path bug in d2loader Source * fixed a asset stream bug in d2loader Asset * d2loader.Loader now needs a d2config.Config on creation (for resolving locale files) * updated the mpq file in d2asset test data, added test case for "sub-directory" * added a Data method to d2asset.Asset. The data is cached on first full read. * renamed ArchiveDataStream to DataStream in d2interface * moved palette utility func out of d2asset and into d2util * bugfix for MacOS mpq loader issue * lint fixes, added data caching to filesystem asset * adding comment for mpq asset close * Decouple d2asset from d2render Notable changes in d2common: * d2dcc.Load now fully decodes the dcc and stores the directions/frames in the dcc struct * un-exported dcc.decodeDirection, it is only used in d2dcc * removed font interface from d2interface, we only have one font implementation * added `Renderer` method to d2interface.Surface, animations use this to bind to a renderer and create surfaces as they need * added `BindRenderer` method to animation interface Notable changes in d2common/d2asset: * **d2asset.NewAssetManager only needs to be passed a d2config.Config**, it is decoupled from d2render * exported Animation * Animation implementation binds to the renderer to create surfaces only on the first time it is rendered * font, dcc, dc6 initialization logic moved out of asset_manager.go * for dc6 and dcc animations, the process of decoding and creating render surfaces has been broken into different methods * the d2asset.Font struct now stores font table data for initialization purposes Notable changes in d2core/d2render: * Surfaces store a renderer reference, this allows animations to bind to the renderer and create a surface just-in-time **These last changes should have been a separate PR, sorry.** Notable changes in d2core/d2ui: * ui.NewSprite now handles creating an animation internally, only needs image and palette path as arguments Notable Changes in d2game: Because of the change in d2ui, all instances of this code pattern... ```golang animation, err := screen.asset.LoadAnimation(imgPath, palettePath) sprite, err := screen.ui.NewSprite(animation) ``` ... becomes this ... ```golang sprite, err := screen.ui.NewSprite(imgPath, palettePath) ```
2020-09-14 17:31:45 -04:00
sprite.PlayForward()
sprite.SetPlayLoop(playLoop)
if blend {
Decouple asset manager from renderer (#730) * improve AssetManager implementation Notable changes are: * removed the individual managers inside of d2asset, only one asset manager * AssetManager now has caches for the types of files it loads * created a type for TextDictionary (the txt file structs) * fixed a file path bug in d2loader Source * fixed a asset stream bug in d2loader Asset * d2loader.Loader now needs a d2config.Config on creation (for resolving locale files) * updated the mpq file in d2asset test data, added test case for "sub-directory" * added a Data method to d2asset.Asset. The data is cached on first full read. * renamed ArchiveDataStream to DataStream in d2interface * moved palette utility func out of d2asset and into d2util * bugfix for MacOS mpq loader issue * lint fixes, added data caching to filesystem asset * adding comment for mpq asset close * Decouple d2asset from d2render Notable changes in d2common: * d2dcc.Load now fully decodes the dcc and stores the directions/frames in the dcc struct * un-exported dcc.decodeDirection, it is only used in d2dcc * removed font interface from d2interface, we only have one font implementation * added `Renderer` method to d2interface.Surface, animations use this to bind to a renderer and create surfaces as they need * added `BindRenderer` method to animation interface Notable changes in d2common/d2asset: * **d2asset.NewAssetManager only needs to be passed a d2config.Config**, it is decoupled from d2render * exported Animation * Animation implementation binds to the renderer to create surfaces only on the first time it is rendered * font, dcc, dc6 initialization logic moved out of asset_manager.go * for dc6 and dcc animations, the process of decoding and creating render surfaces has been broken into different methods * the d2asset.Font struct now stores font table data for initialization purposes Notable changes in d2core/d2render: * Surfaces store a renderer reference, this allows animations to bind to the renderer and create a surface just-in-time **These last changes should have been a separate PR, sorry.** Notable changes in d2core/d2ui: * ui.NewSprite now handles creating an animation internally, only needs image and palette path as arguments Notable Changes in d2game: Because of the change in d2ui, all instances of this code pattern... ```golang animation, err := screen.asset.LoadAnimation(imgPath, palettePath) sprite, err := screen.ui.NewSprite(animation) ``` ... becomes this ... ```golang sprite, err := screen.ui.NewSprite(imgPath, palettePath) ```
2020-09-14 17:31:45 -04:00
sprite.SetEffect(d2enum.DrawEffectModulate)
}
if playLength != 0 {
sprite.SetPlayLength(float64(playLength) / millisecondsPerSecond)
}
sprite.SetPosition(position.X, position.Y)
return sprite
}
2020-06-28 19:31:10 -04:00
func (v *SelectHeroClass) loadSoundEffect(sfx string) d2interface.SoundEffect {
result, err := v.audioProvider.LoadSound(sfx, false, false)
if err != nil {
log.Print(err)
return nil
}
return result
}