diff --git a/d2core/d2asset/animation.go b/d2core/d2asset/animation.go index b0c98a56..5b63c462 100644 --- a/d2core/d2asset/animation.go +++ b/d2core/d2asset/animation.go @@ -117,20 +117,33 @@ func (a *Animation) Advance(elapsed float64) error { return nil } +const ( + full = 1.0 + half = 0.5 + zero = 0.0 +) + func (a *Animation) renderShadow(target d2interface.Surface) error { direction := a.directions[a.directionIndex] frame := direction.frames[a.frameIndex] target.PushFilter(d2enum.FilterLinear) - target.PushTranslation( - frame.offsetX, - int(float64(frame.offsetY)*0.5)) - target.PushScale(1.0, 0.5) - target.PushSkew(0.5, 0.0) - target.PushEffect(d2enum.DrawEffectPctTransparency25) - target.PushBrightness(0.0) + defer target.Pop() - defer target.PopN(6) + target.PushTranslation(frame.offsetX, int(float64(frame.offsetY)*half)) + defer target.Pop() + + target.PushScale(full, half) + defer target.Pop() + + target.PushSkew(half, zero) + defer target.Pop() + + target.PushEffect(d2enum.DrawEffectPctTransparency25) + defer target.Pop() + + target.PushBrightness(zero) + defer target.Pop() return target.Render(frame.image) } @@ -189,8 +202,9 @@ func (a *Animation) RenderFromOrigin(target d2interface.Surface, shadow bool) er if shadow && !a.effect.Transparent() && a.hasShadow { _, height := a.GetFrameBounds() height = int(math.Abs(float64(height))) + halfHeight := height / 2 //nolint:mnd // this ain't rocket surgery... - target.PushTranslation(-height/2, 0) + target.PushTranslation(-halfHeight, 0) defer target.Pop() return a.renderShadow(target) @@ -200,9 +214,9 @@ func (a *Animation) RenderFromOrigin(target d2interface.Surface, shadow bool) er } // RenderSection renders the section of the animation frame enclosed by bounds -func (a *Animation) RenderSection(sfc d2interface.Surface, bound image.Rectangle) error { +func (a *Animation) RenderSection(target d2interface.Surface, bound image.Rectangle) error { if a.renderer == nil { - err := a.BindRenderer(sfc.Renderer()) + err := a.BindRenderer(target.Renderer()) if err != nil { return err } @@ -211,13 +225,16 @@ func (a *Animation) RenderSection(sfc d2interface.Surface, bound image.Rectangle direction := a.directions[a.directionIndex] frame := direction.frames[a.frameIndex] - sfc.PushTranslation(frame.offsetX, frame.offsetY) - sfc.PushEffect(a.effect) - sfc.PushColor(a.colorMod) + target.PushTranslation(frame.offsetX, frame.offsetY) + defer target.Pop() - defer sfc.PopN(3) + target.PushEffect(a.effect) + defer target.Pop() - return sfc.RenderSection(frame.image, bound) + target.PushColor(a.colorMod) + defer target.Pop() + + return target.RenderSection(frame.image, bound) } // GetFrameSize gets the Size(width, height) of a indexed frame. diff --git a/d2core/d2asset/composite.go b/d2core/d2asset/composite.go index fadc5af5..1323d360 100644 --- a/d2core/d2asset/composite.go +++ b/d2core/d2asset/composite.go @@ -10,6 +10,12 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" ) +const ( + hardcodedFPS = 25.0 + hardcodedDivisor = 1.0 / 256.0 + speedUnit = hardcodedFPS * hardcodedDivisor +) + // Composite is a composite entity animation type Composite struct { *AssetManager @@ -134,7 +140,7 @@ func (c *Composite) Equip(equipment *[d2enum.CompositeTypeMax]string) error { // SetAnimSpeed sets the speed at which the Composite's animation should advance through its frames func (c *Composite) SetAnimSpeed(speed int) { - c.mode.animationSpeed = 1.0 / ((float64(speed) * 25.0) / 256.0) + c.mode.animationSpeed = 1.0 / (float64(speed) * speedUnit) // nolint:mnd inverse of freq is time for layerIdx := range c.mode.layers { layer := c.mode.layers[layerIdx] if layer != nil { @@ -254,7 +260,7 @@ func (c *Composite) createMode(animationMode animationMode, weaponClass string) weaponClass: weaponClass, layers: make([]d2interface.Animation, d2enum.CompositeTypeMax), frameCount: animationData[0].FramesPerDirection, - animationSpeed: 1.0 / ((float64(animationData[0].AnimationSpeed) * 25.0) / 256.0), + animationSpeed: 1.0 / (float64(animationData[0].AnimationSpeed) * speedUnit), // nolint:mnd inverse of freq is time } for _, cofLayer := range cof.CofLayers { diff --git a/d2core/d2item/diablo2item/item.go b/d2core/d2item/diablo2item/item.go index d702140c..9edf1978 100644 --- a/d2core/d2item/diablo2item/item.go +++ b/d2core/d2item/diablo2item/item.go @@ -44,6 +44,8 @@ const ( rareJewelAffixMax = 4 ) +const maxAffixesOnMagicItem = 2 + // static check to ensure Item implements Item var _ d2item.Item = &Item{} @@ -138,11 +140,11 @@ func (i *Item) Label() string { numAffixes := len(i.PrefixRecords()) + len(i.SuffixRecords()) - if numAffixes > 0 && numAffixes < 3 { + if numAffixes > 0 && numAffixes <= maxAffixesOnMagicItem { return d2ui.ColorTokenize(str, d2ui.ColorTokenMagicItem) } - if numAffixes > 2 { + if numAffixes > maxAffixesOnMagicItem { return d2ui.ColorTokenize(str, d2ui.ColorTokenRareItem) } @@ -655,7 +657,7 @@ func (i *Item) generateName() { // if it has more than 2 affixes, it's a rare item // rare items use entries from rareprefix.txt and raresuffix.txt to make their names, // and the prefix and suffix actually go before thec current item name - if numAffixes >= 3 { + if numAffixes > maxAffixesOnMagicItem { i.rand.Seed(i.Seed) prefixes := i.factory.asset.Records.Item.Rare.Prefix diff --git a/d2core/d2map/d2mapengine/engine.go b/d2core/d2map/d2mapengine/engine.go index 3328bf42..ed01d5bb 100644 --- a/d2core/d2map/d2mapengine/engine.go +++ b/d2core/d2map/d2mapengine/engine.go @@ -35,6 +35,10 @@ type MapEngine struct { IsLoading bool // (temp) Whether we have processed the GenerateMapPacket(only for remote client) } +const ( + subtilesPerTile = 5 +) + // CreateMapEngine creates a new instance of the map engine and returns a pointer to it. func CreateMapEngine(asset *d2asset.AssetManager) *MapEngine { entity, _ := d2mapentity.NewMapEntityFactory(asset) @@ -204,9 +208,9 @@ func (m *MapEngine) tileIndexToCoordinate(index int) (x, y int) { // SubTileAt gets the flags for the given subtile func (m *MapEngine) SubTileAt(subX, subY int) *d2dt1.SubTileFlags { - tile := m.TileAt(subX/5, subY/5) + tile := m.TileAt(subX/subtilesPerTile, subY/subtilesPerTile) - return tile.GetSubTileFlags(subX%5, subY%5) + return tile.GetSubTileFlags(subX%subtilesPerTile, subY%subtilesPerTile) } // TileAt returns a pointer to the data for the map tile at the given diff --git a/d2core/d2map/d2mapentity/animated_entity.go b/d2core/d2map/d2mapentity/animated_entity.go index 37639fa5..232dfcee 100644 --- a/d2core/d2map/d2mapentity/animated_entity.go +++ b/d2core/d2map/d2mapentity/animated_entity.go @@ -18,18 +18,32 @@ type AnimatedEntity struct { highlight bool } +const ( + subtileWidth = 16 // pixels + subtileHeight = 8 + subtileOffsetY = -5 +) + +const ( + highlightBrightness = 2 +) + +func translateSubtile(fx, fy float64) (x, y int) { + return int(fx * subtileWidth), int(fy*subtileHeight) - subtileOffsetY +} + // Render draws this animated entity onto the target func (ae *AnimatedEntity) Render(target d2interface.Surface) { renderOffset := ae.Position.RenderOffset() ox, oy := renderOffset.X(), renderOffset.Y() - tx, ty := int((ox-oy)*16), int((ox+oy)*8)-5 + tx, ty := translateSubtile(ox-oy, ox+oy) target.PushTranslation(tx, ty) defer target.Pop() if ae.highlight { - target.PushBrightness(2) + target.PushBrightness(highlightBrightness) defer target.Pop() ae.highlight = false diff --git a/d2core/d2ui/button.go b/d2core/d2ui/button.go index d38d56d5..275467b9 100644 --- a/d2core/d2ui/button.go +++ b/d2core/d2ui/button.go @@ -43,6 +43,10 @@ const ( ButtonTypeSquareClose ButtonType = 20 ) +const ( + closeButtonBaseFrame = 10 // base frame offset of the "close" button dc6 +) + const ( greyAlpha100 = 0x646464ff lightGreyAlpha75 = 0x808080c3 @@ -163,7 +167,7 @@ func getButtonLayouts() map[ButtonType]ButtonLayout { Toggleable: true, FontPath: d2resource.Font30, AllowFrameChange: true, - BaseFrame: 10, + BaseFrame: closeButtonBaseFrame, }, } } diff --git a/d2game/d2player/help/help.go b/d2game/d2player/help/help.go index fc344315..34a26695 100644 --- a/d2game/d2player/help/help.go +++ b/d2game/d2player/help/help.go @@ -25,6 +25,116 @@ const ( rFrame ) +const ( + inHalf = 2 // when we divide by 2 +) + +const ( + // all in pixels + windowWidth = 800 + + bulletOffsetY = 14 + + // the title of the panel + titleLabelOffsetX = -30 + + // for the bulleted list near the top of the screen + listRootX = 100 + listRootY = 59 + listBulletOffsetY = 10 + listBulletOffsetX = 12 + listItemVerticalOffset = 20 + listBulletRootY = listRootY - listBulletOffsetY + listItemVerticalOffset + listBulletX = listRootX - listBulletOffsetX + + // the close button for the help panel + closeButtonX = 685 + closeButtonY = 25 + + // the rest of these are for text with a line and dot, towards the bottom of the screen + newStatsLabelX = 222 + newStatsLabelY = 355 + newStatsDotX = 217 + newStatsDotY = 574 + + newSkillLabelX = 578 + newSkillLabelY = 355 + newSkillDotX = 573 + newSkillDotY = 574 + + leftMouseLabelX = 135 + leftMouseLabelY = 382 + + leftButtonSkillLabelX = 135 + leftButtonSkillLabelY = 397 + + leftSkillClickToChangeLabelX = 135 + leftSkillClickToChangeLabelY = 412 + leftSkillClickToChangeDotX = 130 + leftSkillClickToChangeDotY = 565 + + rightMouseLabelX = 675 + rightMouseLabelY = 381 + + rightButtonSkillLabelX = 675 + rightButtonSkillLabelY = 396 + + rightSkillClickToChangeLabelX = 675 + rightSkillClickToChangeLabelY = 411 + rightSkillClickToChangeDotX = 670 + rightSkillClickToChangeDotY = 562 + + miniPanelLabelX = 450 + miniPanelLabelY = 371 + + characterLabelX = 450 + characterLabelY = 386 + + inventoryLabelX = 450 + inventoryLabelY = 401 + + otherScreensLabelX = 450 + otherScreensLabelY = 417 + otherScreensDotX = 445 + otherScreensDotY = 539 + + lifeOrbLabelX = 65 + lifeOrbLabelY = 451 + lifeOrbDotX = 60 + lifeOrbDotY = 538 + + staminaBarLabelX = 315 + staminaBarLabelY = 450 + staminaBarDotX = 310 + staminaBarDotY = 583 + + manaOrbLabelX = 745 + manaOrbLabelY = 451 + manaOrbDotX = 740 + manaOrbDotY = 538 + + runWalkButtonLabelX = 264 + runWalkButtonLabelY = 480 + + toggleLabelX = 264 + toggleLabelY = 495 + toggleDotX = 259 + toggleDotY = 583 + + experienceLabelX = 370 + experienceLabelY = 476 + + barLabelX = 370 + barLabelY = 493 + barDotX = 365 + barDotY = 565 + + beltLabelX = 535 + beltLabelY = 490 + beltDotX = 530 + beltDotY = 568 +) + // Overlay represents the in-game overlay that toggles visibility when the h key is pressed type Overlay struct { asset *d2asset.AssetManager @@ -138,16 +248,16 @@ func (h *Overlay) Load() { x = 65 case tFrameRHalf: y = hh - x = 800 - ww - 245 + x = windowWidth - ww - 245 case trCornerFrameTHalf: y = hh - x = 800 - ww - 20 + x = windowWidth - ww - 20 case trCornerFrameRHalf: y = hh - x = 800 - ww + x = windowWidth - ww case rFrame: y = hh + prevY - x = 800 - ww + x = windowWidth - ww } //y += 50 @@ -165,14 +275,16 @@ func (h *Overlay) Load() { text := d2tbl.TranslateString("Strhelp1") // "Diablo II Help" newLabel := h.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteSky) newLabel.SetText(text) - ww, _ := newLabel.GetSize() - newLabel.SetPosition((800/2)-(ww/2)-30, 0) + + titleLabelWidth, _ := newLabel.GetSize() + + newLabel.SetPosition((windowWidth/inHalf)-(titleLabelWidth/inHalf)+titleLabelOffsetX, 0) h.text = append(h.text, newLabel) // Close h.closeButton = h.uiManager.NewButton(d2ui.ButtonTypeSquareClose, "") - h.closeButton.SetPosition(685, 25) + h.closeButton.SetPosition(closeButtonX, closeButtonY) h.closeButton.SetVisible(false) h.closeButton.OnActivated(func() { h.close() }) @@ -183,229 +295,186 @@ func (h *Overlay) Load() { // Bullets - yOffset := 59 + callouts := []struct{ text string }{ + // TODO "Ctrl" should be hotkey // "Hold Down <%s> to Run" + {text: fmt.Sprintf(d2tbl.TranslateString("StrHelp2"), "Ctrl")}, - h.createBullet(callout{ - LabelText: fmt.Sprintf(d2tbl.TranslateString("StrHelp2"), "Ctrl"), // TODO "Ctrl" should be hotkey // "Hold Down <%s> to Run" - LabelX: 100, - LabelY: yOffset - 10, - DotX: 100 - 12, - DotY: yOffset, - }) + // TODO "Alt" should be hotkey // "Hold down <%s> to highlight items on the ground" + {text: fmt.Sprintf(d2tbl.TranslateString("StrHelp3"), "Alt")}, + // TODO "Shift" should be hotkey // "Hold down <%s> to attack while standing still" + {text: fmt.Sprintf(d2tbl.TranslateString("StrHelp4"), "Shift")}, - yOffset += 20 + // TODO "Tab" should be hotkey // "Hit <%s> to toggle the automap on and off" + {text: fmt.Sprintf(d2tbl.TranslateString("StrHelp5"), "Tab")}, - h.createBullet(callout{ - LabelText: fmt.Sprintf(d2tbl.TranslateString("StrHelp3"), "Alt"), // TODO "Alt" should be hotkey // "Hold down <%s> to highlight items on the ground" - LabelX: 100, - LabelY: yOffset - 10, - DotX: 100 - 12, - DotY: yOffset, - }) + // "Hit to bring up the Game Menu" + {text: d2tbl.TranslateString("StrHelp6")}, - yOffset += 20 + // "Hit to go into chat mode" + {text: d2tbl.TranslateString("StrHelp7")}, - h.createBullet(callout{ - LabelText: fmt.Sprintf(d2tbl.TranslateString("StrHelp4"), "Shift"), // TODO "Shift" should be hotkey // "Hold down <%s> to attack while standing still" - LabelX: 100, - LabelY: yOffset - 10, - DotX: 100 - 12, - DotY: yOffset, - }) + // "Hit F1-F8 to set your Left or Right Mouse Buttton Skills." + {text: d2tbl.TranslateString("StrHelp8")}, - yOffset += 20 + // TODO "H" should be hotkey, + {text: fmt.Sprintf(d2tbl.TranslateString("StrHelp8a"), "H")}, + } - h.createBullet(callout{ - LabelText: fmt.Sprintf(d2tbl.TranslateString("StrHelp5"), "Tab"), // TODO "Tab" should be hotkey // "Hit <%s> to toggle the automap on and off" - LabelX: 100, - LabelY: yOffset - 10, - DotX: 100 - 12, - DotY: yOffset, - }) + for idx := range callouts { + listItemOffsetY := idx * listItemVerticalOffset - yOffset += 20 - - h.createBullet(callout{ - LabelText: d2tbl.TranslateString("StrHelp6"), // "Hit to bring up the Game Menu" - LabelX: 100, - LabelY: yOffset - 10, - DotX: 100 - 12, - DotY: yOffset, - }) - - yOffset += 20 - - h.createBullet(callout{ - LabelText: d2tbl.TranslateString("StrHelp7"), // "Hit to go into chat mode" - LabelX: 100, - LabelY: yOffset - 10, - DotX: 100 - 12, - DotY: yOffset, - }) - - yOffset += 20 - - h.createBullet(callout{ - LabelText: d2tbl.TranslateString("StrHelp8"), // "Hit F1-F8 to set your Left or Right Mouse Buttton Skills." - LabelX: 100, - LabelY: yOffset - 10, - DotX: 100 - 12, - DotY: yOffset, - }) - - yOffset += 20 - - h.createBullet(callout{ - LabelText: fmt.Sprintf(d2tbl.TranslateString("StrHelp8a"), "H"), // TODO "H" should be hotkey - LabelX: 100, - LabelY: yOffset - 10, - DotX: 100 - 12, - DotY: yOffset, - }) + h.createBullet(callout{ + LabelText: callouts[idx].text, + LabelX: listRootX, + LabelY: listRootY + listItemOffsetY, + DotX: listBulletX, + DotY: listBulletRootY + listItemOffsetY, + }) + } // Callouts h.createCallout(callout{ LabelText: d2tbl.TranslateString("strlvlup"), // "New Stats" - LabelX: 222, - LabelY: 355, - DotX: 217, - DotY: 574, + LabelX: newStatsLabelX, + LabelY: newStatsLabelY, + DotX: newStatsDotX, + DotY: newStatsDotY, }) h.createCallout(callout{ LabelText: d2tbl.TranslateString("strnewskl"), // "New Skill" - LabelX: 578, - LabelY: 355, - DotX: 573, - DotY: 574, + LabelX: newSkillLabelX, + LabelY: newSkillLabelY, + DotX: newSkillDotX, + DotY: newSkillDotY, }) // Some of the help fonts require mulktiple lines. h.createLabel(callout{ LabelText: d2tbl.TranslateString("StrHelp10"), // "Left Mouse-" - LabelX: 135, - LabelY: 382, + LabelX: leftMouseLabelX, + LabelY: leftMouseLabelY, }) h.createLabel(callout{ LabelText: d2tbl.TranslateString("StrHelp11"), // "Button Skill" - LabelX: 135, - LabelY: 397, + LabelX: leftButtonSkillLabelX, + LabelY: leftButtonSkillLabelY, }) h.createCallout(callout{ LabelText: d2tbl.TranslateString("StrHelp12"), // "(Click to Change)" - LabelX: 135, - LabelY: 412, - DotX: 130, - DotY: 565, + LabelX: leftSkillClickToChangeLabelX, + LabelY: leftSkillClickToChangeLabelY, + DotX: leftSkillClickToChangeDotX, + DotY: leftSkillClickToChangeDotY, }) h.createLabel(callout{ LabelText: d2tbl.TranslateString("StrHelp13"), // "Right Mouse" - LabelX: 675, - LabelY: 381, + LabelX: rightMouseLabelX, + LabelY: rightMouseLabelY, }) h.createLabel(callout{ LabelText: d2tbl.TranslateString("StrHelp11"), // "Button Skill" - LabelX: 675, - LabelY: 396, + LabelX: rightButtonSkillLabelX, + LabelY: rightButtonSkillLabelY, }) h.createCallout(callout{ LabelText: d2tbl.TranslateString("StrHelp12"), // "(Click to Change)" - LabelX: 675, - LabelY: 411, - DotX: 670, - DotY: 562, + LabelX: rightSkillClickToChangeLabelX, + LabelY: rightSkillClickToChangeLabelY, + DotX: rightSkillClickToChangeDotX, + DotY: rightSkillClickToChangeDotY, }) h.createLabel(callout{ LabelText: d2tbl.TranslateString("StrHelp17"), // "Mini-Panel" - LabelX: 450, - LabelY: 371, + LabelX: miniPanelLabelX, + LabelY: miniPanelLabelY, }) h.createLabel(callout{ LabelText: d2tbl.TranslateString("StrHelp18"), // "(Opens Character," - LabelX: 450, - LabelY: 386, + LabelX: characterLabelX, + LabelY: characterLabelY, }) h.createLabel(callout{ LabelText: d2tbl.TranslateString("StrHelp19"), // "inventory, and" - LabelX: 450, - LabelY: 401, + LabelX: inventoryLabelX, + LabelY: inventoryLabelY, }) h.createCallout(callout{ LabelText: d2tbl.TranslateString("StrHelp20"), // "other screens)" - LabelX: 450, - LabelY: 417, - DotX: 445, - DotY: 539, + LabelX: otherScreensLabelX, + LabelY: otherScreensLabelY, + DotX: otherScreensDotX, + DotY: otherScreensDotY, }) h.createCallout(callout{ LabelText: d2tbl.TranslateString("StrHelp9"), // "Life Orb" - LabelX: 65, - LabelY: 451, - DotX: 60, - DotY: 538, + LabelX: lifeOrbLabelX, + LabelY: lifeOrbLabelY, + DotX: lifeOrbDotX, + DotY: lifeOrbDotY, }) h.createCallout(callout{ LabelText: d2tbl.TranslateString("StrHelp15"), // "Stamina Bar" - LabelX: 315, - LabelY: 450, - DotX: 310, - DotY: 583, + LabelX: staminaBarLabelX, + LabelY: staminaBarLabelY, + DotX: staminaBarDotX, + DotY: staminaBarDotY, }) h.createCallout(callout{ LabelText: d2tbl.TranslateString("StrHelp22"), // "Mana Orb" - LabelX: 745, - LabelY: 451, - DotX: 740, - DotY: 538, + LabelX: manaOrbLabelX, + LabelY: manaOrbLabelY, + DotX: manaOrbDotX, + DotY: manaOrbDotY, }) h.createLabel(callout{ LabelText: d2tbl.TranslateString("StrHelp14"), // "Run/Walk" - LabelX: 264, - LabelY: 480, + LabelX: runWalkButtonLabelX, + LabelY: runWalkButtonLabelY, }) h.createCallout(callout{ LabelText: d2tbl.TranslateString("StrHelp14a"), // "Toggle" - LabelX: 264, - LabelY: 495, - DotX: 259, - DotY: 583, + LabelX: toggleLabelX, + LabelY: toggleLabelY, + DotX: toggleDotX, + DotY: toggleDotY, }) h.createLabel(callout{ LabelText: d2tbl.TranslateString("StrHelp16"), // "Experience" - LabelX: 370, - LabelY: 476, + LabelX: experienceLabelX, + LabelY: experienceLabelY, }) h.createCallout(callout{ LabelText: d2tbl.TranslateString("StrHelp16a"), // "Bar" - LabelX: 370, - LabelY: 493, - DotX: 365, - DotY: 565, + LabelX: barLabelX, + LabelY: barLabelY, + DotX: barDotX, + DotY: barDotY, }) h.createCallout(callout{ LabelText: d2tbl.TranslateString("StrHelp21"), // "Belt" - LabelX: 535, - LabelY: 490, - DotX: 530, - DotY: 568, + LabelX: beltLabelX, + LabelY: beltLabelY, + DotX: beltDotX, + DotY: beltDotY, }) } @@ -442,7 +511,7 @@ func (h *Overlay) createBullet(c callout) { log.Print(err) } - newDot.SetPosition(c.DotX, c.DotY+14) + newDot.SetPosition(c.DotX, c.DotY+bulletOffsetY) h.frames = append(h.frames, newDot) }