mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-04 15:46:51 -05:00
Merge pull request #951 from gucio321/multi-language-labels
Multi language labels
This commit is contained in:
commit
73d381215e
@ -49,3 +49,35 @@ func GetFontCharset(language string) string {
|
|||||||
|
|
||||||
return charset[language]
|
return charset[language]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLabelModifier returns modifier for language
|
||||||
|
/* modifiers for labels (used in string tables)
|
||||||
|
modifier is something like that:
|
||||||
|
english table: polish table:
|
||||||
|
key | value key | value
|
||||||
|
#1 | v1 |
|
||||||
|
#4 | v2 #4 | v1
|
||||||
|
#5 | v3 #5 | v2
|
||||||
|
#8 | v4 #8 | v3
|
||||||
|
So, GetLabelModifier returns value of offset in locale languages table
|
||||||
|
*/
|
||||||
|
// some of values need to be set up. For now values with "checked" comment
|
||||||
|
// was tested and works fine in main menu.
|
||||||
|
func GetLabelModifier(language string) int {
|
||||||
|
modifiers := map[string]int{
|
||||||
|
"ENG": 0, // (English) // checked
|
||||||
|
"ESP": 0, // (Spanish)
|
||||||
|
"DEU": 0, // (German) // checked
|
||||||
|
"FRA": 0, // (French)
|
||||||
|
"POR": 0, // (Portuguese)
|
||||||
|
"ITA": 0, // (Italian)
|
||||||
|
"JPN": 0, // (Japanese)
|
||||||
|
"KOR": 0, // (Korean)
|
||||||
|
"SIN": 0, //
|
||||||
|
"CHI": 0, // (Chinese)
|
||||||
|
"POL": 1, // (Polish) // checked
|
||||||
|
"RUS": 0, // (Russian)
|
||||||
|
}
|
||||||
|
|
||||||
|
return modifiers[language]
|
||||||
|
}
|
||||||
|
@ -135,11 +135,6 @@ func SplitIntoLinesWithMaxWidth(fullSentence string, maxChars int) []string {
|
|||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
// SplitIntoLinesWithMaxWidthOneLine does the same as SplitIntoLinesWithMaxWidth but return string with newline char
|
|
||||||
func SplitIntoLinesWithMaxWidthOneLine(s string, l int) string {
|
|
||||||
return strings.Join(SplitIntoLinesWithMaxWidth(s, l), "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func splitCjkIntoChunks(str string, chars int) []string {
|
func splitCjkIntoChunks(str string, chars int) []string {
|
||||||
chunks := make([]string, chars/len(str))
|
chunks := make([]string, chars/len(str))
|
||||||
i, count := 0, 0
|
i, count := 0, 0
|
||||||
|
@ -57,6 +57,7 @@ type AssetManager struct {
|
|||||||
palettes d2interface.Cache
|
palettes d2interface.Cache
|
||||||
transforms d2interface.Cache
|
transforms d2interface.Cache
|
||||||
Records *d2records.RecordManager
|
Records *d2records.RecordManager
|
||||||
|
language string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLogLevel sets the log level for the asset manager, record manager, and file loader
|
// SetLogLevel sets the log level for the asset manager, record manager, and file loader
|
||||||
@ -124,6 +125,8 @@ func (am *AssetManager) LoadLanguage(languagePath string) string {
|
|||||||
language := d2resource.GetLanguageLiteral(languageCode)
|
language := d2resource.GetLanguageLiteral(languageCode)
|
||||||
am.Infof("Language: %s", language)
|
am.Infof("Language: %s", language)
|
||||||
|
|
||||||
|
am.language = language
|
||||||
|
|
||||||
return language
|
return language
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,40 +283,97 @@ func (am *AssetManager) LoadStringTable(tablePath string) (d2tbl.TextDictionary,
|
|||||||
|
|
||||||
// TranslateString returns the translation of the given string. The string is retrieved from
|
// TranslateString returns the translation of the given string. The string is retrieved from
|
||||||
// the loaded string tables.
|
// the loaded string tables.
|
||||||
func (am *AssetManager) TranslateString(key string) string {
|
func (am *AssetManager) TranslateString(input interface{}) string {
|
||||||
|
var key string
|
||||||
|
|
||||||
|
switch s := input.(type) {
|
||||||
|
case string:
|
||||||
|
key = s
|
||||||
|
case fmt.Stringer:
|
||||||
|
key = s.String()
|
||||||
|
}
|
||||||
|
|
||||||
for idx := range am.tables {
|
for idx := range am.tables {
|
||||||
if value, found := am.tables[idx][key]; found {
|
if value, found := am.tables[idx][key]; found {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix to allow v.setDescLabels("#123") to be bypassed for a patch in issue #360. Reenable later.
|
// Fix to allow v.setDescLabels("#123") to be bypassed for a patch in issue #360. Reenable later.
|
||||||
// log.Panicf("Could not find a string for the key '%s'", key)
|
// log.Panicf("Could not find a string for the key '%s'", key)
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
// TranslateHeroClass translates her class given to game locale
|
func (am *AssetManager) baseLabelNumbers(idx int) int {
|
||||||
func (am *AssetManager) TranslateHeroClass(h d2enum.Hero) string {
|
baseLabelNumbers := []int{
|
||||||
switch h {
|
// main menu labels
|
||||||
case d2enum.HeroBarbarian:
|
1612, // CANCEL
|
||||||
return am.TranslateString("Barbarian")
|
1613, // (c) 2000 Blizzard Entertainment
|
||||||
case d2enum.HeroNecromancer:
|
1614, // All Rights Reserved.
|
||||||
return am.TranslateString("Necromancer")
|
1620, // SINGLE PLAYER
|
||||||
case d2enum.HeroPaladin:
|
1621, // BATTLE.NET
|
||||||
return am.TranslateString("Paladin")
|
1623, // OTHER MULTIPLAYER
|
||||||
case d2enum.HeroAssassin:
|
1625, // EXIT DIABLO II
|
||||||
return am.TranslateString("Assassin")
|
1627, // CREDITS
|
||||||
case d2enum.HeroSorceress:
|
1639, // CINEMATICS
|
||||||
return am.TranslateString("Sorceress")
|
|
||||||
case d2enum.HeroAmazon:
|
// cinematics menu labels
|
||||||
return am.TranslateString("Amazon")
|
1640, // View All Earned Cinematics
|
||||||
case d2enum.HeroDruid:
|
1659, // Epilogue
|
||||||
return am.TranslateString("Druid")
|
1660, // SELECT CINEMATICS
|
||||||
default:
|
|
||||||
am.Error("Unknown Hero Class")
|
// multiplayer labels
|
||||||
|
1663, // OPEN BATTLE.NET
|
||||||
|
1666, // TCP/IP GAME
|
||||||
|
1667, // TCP/IP Options
|
||||||
|
1675, // HOST GAME
|
||||||
|
1676, // JOIN GAME
|
||||||
|
1678, // Enter Host IP Address to Join Game
|
||||||
|
1680, // Your IP Address is:
|
||||||
|
1689, // Tip: host game
|
||||||
|
1690, // Tip: join game
|
||||||
|
1691, // Cannot detect a valid TCP/IP address.
|
||||||
|
1694, // Character Name
|
||||||
|
1696, // Hardcore
|
||||||
|
1697, // Select Hero Class
|
||||||
|
|
||||||
|
1698, // amazon description
|
||||||
|
1704, // nec description
|
||||||
|
1709, // barb description
|
||||||
|
1710, // sorc description
|
||||||
|
1711, // pal description
|
||||||
|
/*in addition, as many elements as the value
|
||||||
|
of the highest modifier must be listed*/
|
||||||
|
1712,
|
||||||
|
|
||||||
|
/* here, should be labels used to battle.net multiplayer, but they are not used yet,
|
||||||
|
therefore I don't list them here.*/
|
||||||
|
|
||||||
|
// difficulty levels:
|
||||||
|
1800, // Hell
|
||||||
|
1864, // Nightmare
|
||||||
|
1865, // Normal
|
||||||
|
1867, // Select Difficulty
|
||||||
|
|
||||||
|
1869, // not used, for locales with +1 mod
|
||||||
|
1878, // delete char confirm
|
||||||
|
1881, // Open
|
||||||
|
1889, // char name is currently taken (not used)
|
||||||
|
1896, // YES
|
||||||
|
1925, // NO
|
||||||
|
|
||||||
|
1926, // not used, for locales with +1 mod
|
||||||
|
|
||||||
|
970, // EXIT
|
||||||
|
971,
|
||||||
}
|
}
|
||||||
|
|
||||||
// should not be reached
|
return baseLabelNumbers[idx]
|
||||||
return "---"
|
}
|
||||||
|
|
||||||
|
// TranslateLabel translates the label taking into account its shift in the table
|
||||||
|
func (am *AssetManager) TranslateLabel(label int) string {
|
||||||
|
return am.TranslateString(fmt.Sprintf("#%d", am.baseLabelNumbers(label+d2resource.GetLabelModifier(am.language))))
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadPaletteTransform loads a palette transform file
|
// LoadPaletteTransform loads a palette transform file
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
|
||||||
|
|
||||||
@ -229,7 +230,7 @@ func (v *CharacterSelect) loadHeroTitle() {
|
|||||||
|
|
||||||
func (v *CharacterSelect) loadDeleteCharConfirm() {
|
func (v *CharacterSelect) loadDeleteCharConfirm() {
|
||||||
v.deleteCharConfirmLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
v.deleteCharConfirmLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||||
lines := "Are you sure that you want\nto delete this character?\nTake note: this will delete all\nversions of this Character."
|
lines := strings.Join(d2util.SplitIntoLinesWithMaxWidth(v.asset.TranslateLabel(delCharConfLabel), 30), "\n")
|
||||||
v.deleteCharConfirmLabel.SetText(lines)
|
v.deleteCharConfirmLabel.SetText(lines)
|
||||||
v.deleteCharConfirmLabel.Alignment = d2ui.HorizontalAlignCenter
|
v.deleteCharConfirmLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||||
deleteConfirmX, deleteConfirmY := 400, 185
|
deleteConfirmX, deleteConfirmY := 400, 185
|
||||||
@ -292,32 +293,33 @@ func rgbaColor(rgba uint32) color.RGBA {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *CharacterSelect) createButtons(loading d2screen.LoadingState) {
|
func (v *CharacterSelect) createButtons(loading d2screen.LoadingState) {
|
||||||
v.newCharButton = v.uiManager.NewButton(d2ui.ButtonTypeTall, d2util.SplitIntoLinesWithMaxWidthOneLine(v.asset.TranslateString("#831"), 13))
|
v.newCharButton = v.uiManager.NewButton(d2ui.ButtonTypeTall, strings.Join(
|
||||||
|
d2util.SplitIntoLinesWithMaxWidth(v.asset.TranslateString("#831"), 13), "\n"))
|
||||||
v.newCharButton.SetPosition(newCharBtnX, newCharBtnY)
|
v.newCharButton.SetPosition(newCharBtnX, newCharBtnY)
|
||||||
v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() })
|
v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() })
|
||||||
|
|
||||||
v.convertCharButton = v.uiManager.NewButton(d2ui.ButtonTypeTall,
|
v.convertCharButton = v.uiManager.NewButton(d2ui.ButtonTypeTall,
|
||||||
d2util.SplitIntoLinesWithMaxWidthOneLine(v.asset.TranslateString("#825"), 13))
|
strings.Join(d2util.SplitIntoLinesWithMaxWidth(v.asset.TranslateString("#825"), 13), "\n"))
|
||||||
v.convertCharButton.SetPosition(convertCharBtnX, convertCharBtnY)
|
v.convertCharButton.SetPosition(convertCharBtnX, convertCharBtnY)
|
||||||
v.convertCharButton.SetEnabled(false)
|
v.convertCharButton.SetEnabled(false)
|
||||||
|
|
||||||
v.deleteCharButton = v.uiManager.NewButton(d2ui.ButtonTypeTall,
|
v.deleteCharButton = v.uiManager.NewButton(d2ui.ButtonTypeTall,
|
||||||
d2util.SplitIntoLinesWithMaxWidthOneLine(v.asset.TranslateString("#832"), 13))
|
strings.Join(d2util.SplitIntoLinesWithMaxWidth(v.asset.TranslateString("#832"), 13), "\n"))
|
||||||
v.deleteCharButton.OnActivated(func() { v.onDeleteCharButtonClicked() })
|
v.deleteCharButton.OnActivated(func() { v.onDeleteCharButtonClicked() })
|
||||||
v.deleteCharButton.SetPosition(deleteCharBtnX, deleteCharBtnY)
|
v.deleteCharButton.SetPosition(deleteCharBtnX, deleteCharBtnY)
|
||||||
|
|
||||||
v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, "EXIT")
|
v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateLabel(exitLabel))
|
||||||
v.exitButton.SetPosition(exitBtnX, exitBtnY)
|
v.exitButton.SetPosition(exitBtnX, exitBtnY)
|
||||||
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||||
|
|
||||||
loading.Progress(twentyPercent)
|
loading.Progress(twentyPercent)
|
||||||
|
|
||||||
v.deleteCharCancelButton = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, "NO")
|
v.deleteCharCancelButton = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateLabel(noLabel))
|
||||||
v.deleteCharCancelButton.SetPosition(deleteCancelX, deleteCancelY)
|
v.deleteCharCancelButton.SetPosition(deleteCancelX, deleteCancelY)
|
||||||
v.deleteCharCancelButton.SetVisible(false)
|
v.deleteCharCancelButton.SetVisible(false)
|
||||||
v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() })
|
v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() })
|
||||||
|
|
||||||
v.deleteCharOkButton = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, "YES")
|
v.deleteCharOkButton = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateLabel(yesLabel))
|
||||||
v.deleteCharOkButton.SetPosition(deleteOkX, deleteOkY)
|
v.deleteCharOkButton.SetPosition(deleteOkX, deleteOkY)
|
||||||
v.deleteCharOkButton.SetVisible(false)
|
v.deleteCharOkButton.SetVisible(false)
|
||||||
v.deleteCharOkButton.OnActivated(func() { v.onDeleteCharacterConfirmClicked() })
|
v.deleteCharOkButton.OnActivated(func() { v.onDeleteCharacterConfirmClicked() })
|
||||||
@ -349,7 +351,7 @@ func (v *CharacterSelect) updateCharacterBoxes() {
|
|||||||
|
|
||||||
heroName := v.gameStates[idx].HeroName
|
heroName := v.gameStates[idx].HeroName
|
||||||
heroInfo := v.asset.TranslateString("level") + " " + strconv.FormatInt(int64(v.gameStates[idx].Stats.Level), 10) +
|
heroInfo := v.asset.TranslateString("level") + " " + strconv.FormatInt(int64(v.gameStates[idx].Stats.Level), 10) +
|
||||||
" " + v.asset.TranslateHeroClass(v.gameStates[idx].HeroType)
|
" " + v.asset.TranslateString(v.gameStates[idx].HeroType.String())
|
||||||
|
|
||||||
v.characterNameLabel[i].SetText(d2ui.ColorTokenize(heroName, d2ui.ColorTokenGold))
|
v.characterNameLabel[i].SetText(d2ui.ColorTokenize(heroName, d2ui.ColorTokenGold))
|
||||||
v.characterStatsLabel[i].SetText(d2ui.ColorTokenize(heroInfo, d2ui.ColorTokenWhite))
|
v.characterStatsLabel[i].SetText(d2ui.ColorTokenize(heroInfo, d2ui.ColorTokenWhite))
|
||||||
|
@ -96,13 +96,14 @@ func (v *Cinematics) OnLoad(_ d2screen.LoadingState) {
|
|||||||
|
|
||||||
v.cinematicsLabel = v.uiManager.NewLabel(d2resource.Font30, d2resource.PaletteStatic)
|
v.cinematicsLabel = v.uiManager.NewLabel(d2resource.Font30, d2resource.PaletteStatic)
|
||||||
v.cinematicsLabel.Alignment = d2ui.HorizontalAlignCenter
|
v.cinematicsLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||||
v.cinematicsLabel.SetText("SELECT CINEMATIC")
|
v.cinematicsLabel.SetText(v.asset.TranslateLabel(selectCinematicLabel))
|
||||||
v.cinematicsLabel.Color[0] = rgbaColor(lightBrown)
|
v.cinematicsLabel.Color[0] = rgbaColor(lightBrown)
|
||||||
v.cinematicsLabel.SetPosition(cinematicsLabelX, cinematicsLabelY)
|
v.cinematicsLabel.SetPosition(cinematicsLabelX, cinematicsLabelY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Cinematics) createButtons() {
|
func (v *Cinematics) createButtons() {
|
||||||
v.cinematicsExitBtn = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateString("cancel"))
|
v.cinematicsExitBtn = v.uiManager.NewButton(d2ui.ButtonTypeMedium,
|
||||||
|
v.asset.TranslateString(v.asset.TranslateLabel(cancelLabel)))
|
||||||
v.cinematicsExitBtn.SetPosition(cinematicsExitBtnX, cinematicsExitBtnY)
|
v.cinematicsExitBtn.SetPosition(cinematicsExitBtnX, cinematicsExitBtnY)
|
||||||
v.cinematicsExitBtn.OnActivated(func() { v.onCinematicsExitBtnClicked() })
|
v.cinematicsExitBtn.OnActivated(func() { v.onCinematicsExitBtnClicked() })
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ func (v *Credits) OnLoad(loading d2screen.LoadingState) {
|
|||||||
v.creditsBackground.SetPosition(creditsX, creditsY)
|
v.creditsBackground.SetPosition(creditsX, creditsY)
|
||||||
loading.Progress(twentyPercent)
|
loading.Progress(twentyPercent)
|
||||||
|
|
||||||
v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, "EXIT")
|
v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateLabel(exitLabel))
|
||||||
v.exitButton.SetPosition(charSelExitBtnX, charSelExitBtnY)
|
v.exitButton.SetPosition(charSelExitBtnX, charSelExitBtnY)
|
||||||
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||||
loading.Progress(fourtyPercent)
|
loading.Progress(fourtyPercent)
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
|
||||||
|
|
||||||
@ -83,6 +84,76 @@ type BuildInfo struct {
|
|||||||
Branch, Commit string
|
Branch, Commit string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// main menu labels
|
||||||
|
cancelLabel = iota
|
||||||
|
copyrightLabel
|
||||||
|
allRightsReservedLabel
|
||||||
|
singlePlayerLabel
|
||||||
|
_
|
||||||
|
otherMultiplayerLabel
|
||||||
|
exitGameLabel
|
||||||
|
creditsLabel
|
||||||
|
cinematicsLabel
|
||||||
|
|
||||||
|
// cinematics menu labels
|
||||||
|
//nolint:deadcode,varcheck,unused // will be used
|
||||||
|
viewAllCinematicsLabel
|
||||||
|
//nolint:deadcode,varcheck,unused // will be used
|
||||||
|
epilogueLabel
|
||||||
|
selectCinematicLabel
|
||||||
|
|
||||||
|
// multiplayer menu labels
|
||||||
|
_
|
||||||
|
tcpIPGameLabel
|
||||||
|
tcpIPOptionsLabel
|
||||||
|
tcpIPHostGameLabel
|
||||||
|
tcpIPJoinGameLabel
|
||||||
|
tcpIPEnterHostIPLabel
|
||||||
|
tcpIPYourIPLabel
|
||||||
|
//nolint:deadcode,varcheck,unused // will be used
|
||||||
|
tipHostLabel
|
||||||
|
//nolint:deadcode,varcheck,unused // will be used
|
||||||
|
tipJoinLabel
|
||||||
|
ipNotFoundLabel
|
||||||
|
|
||||||
|
// select hero class menu labels
|
||||||
|
charNameLabel
|
||||||
|
hardCoreLabel
|
||||||
|
selectHeroClassLabel
|
||||||
|
amazonDescr
|
||||||
|
necromancerDescr
|
||||||
|
barbarianDescr
|
||||||
|
sorceressDescr
|
||||||
|
paladinDescr
|
||||||
|
|
||||||
|
_
|
||||||
|
|
||||||
|
//nolint:deadcode,varcheck,unused // will be used
|
||||||
|
hellLabel
|
||||||
|
//nolint:deadcode,varcheck,unused // will be used
|
||||||
|
nightmareLabel
|
||||||
|
//nolint:deadcode,varcheck,unused // will be used
|
||||||
|
normalLabel
|
||||||
|
//nolint:deadcode,varcheck,unused // will be used
|
||||||
|
selectDifficultyLabel
|
||||||
|
|
||||||
|
_
|
||||||
|
|
||||||
|
delCharConfLabel
|
||||||
|
//nolint:deadcode,varcheck,unused // will be used
|
||||||
|
openLabel
|
||||||
|
|
||||||
|
_
|
||||||
|
|
||||||
|
yesLabel
|
||||||
|
noLabel
|
||||||
|
|
||||||
|
_
|
||||||
|
|
||||||
|
exitLabel
|
||||||
|
)
|
||||||
|
|
||||||
// CreateMainMenu creates an instance of MainMenu
|
// CreateMainMenu creates an instance of MainMenu
|
||||||
func CreateMainMenu(
|
func CreateMainMenu(
|
||||||
navigator d2interface.Navigator,
|
navigator d2interface.Navigator,
|
||||||
@ -249,14 +320,14 @@ func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
|
|||||||
|
|
||||||
v.copyrightLabel = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
v.copyrightLabel = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||||
v.copyrightLabel.Alignment = d2ui.HorizontalAlignCenter
|
v.copyrightLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||||
v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
|
v.copyrightLabel.SetText(v.asset.TranslateLabel(copyrightLabel))
|
||||||
v.copyrightLabel.Color[0] = rgbaColor(lightBrown)
|
v.copyrightLabel.Color[0] = rgbaColor(lightBrown)
|
||||||
v.copyrightLabel.SetPosition(copyrightX, copyrightY)
|
v.copyrightLabel.SetPosition(copyrightX, copyrightY)
|
||||||
loading.Progress(thirtyPercent)
|
loading.Progress(thirtyPercent)
|
||||||
|
|
||||||
v.copyrightLabel2 = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
v.copyrightLabel2 = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
|
||||||
v.copyrightLabel2.Alignment = d2ui.HorizontalAlignCenter
|
v.copyrightLabel2.Alignment = d2ui.HorizontalAlignCenter
|
||||||
v.copyrightLabel2.SetText("All Rights Reserved.")
|
v.copyrightLabel2.SetText(v.asset.TranslateLabel(allRightsReservedLabel))
|
||||||
v.copyrightLabel2.Color[0] = rgbaColor(lightBrown)
|
v.copyrightLabel2.Color[0] = rgbaColor(lightBrown)
|
||||||
v.copyrightLabel2.SetPosition(copyright2X, copyright2Y)
|
v.copyrightLabel2.SetPosition(copyright2X, copyright2Y)
|
||||||
|
|
||||||
@ -270,17 +341,17 @@ func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
|
|||||||
v.tcpIPOptionsLabel = v.uiManager.NewLabel(d2resource.Font42, d2resource.PaletteUnits)
|
v.tcpIPOptionsLabel = v.uiManager.NewLabel(d2resource.Font42, d2resource.PaletteUnits)
|
||||||
v.tcpIPOptionsLabel.SetPosition(tcpOptionsX, tcpOptionsY)
|
v.tcpIPOptionsLabel.SetPosition(tcpOptionsX, tcpOptionsY)
|
||||||
v.tcpIPOptionsLabel.Alignment = d2ui.HorizontalAlignCenter
|
v.tcpIPOptionsLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||||
v.tcpIPOptionsLabel.SetText("TCP/IP Options")
|
v.tcpIPOptionsLabel.SetText(v.asset.TranslateLabel(tcpIPOptionsLabel))
|
||||||
|
|
||||||
v.tcpJoinGameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
v.tcpJoinGameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||||
v.tcpJoinGameLabel.Alignment = d2ui.HorizontalAlignCenter
|
v.tcpJoinGameLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||||
v.tcpJoinGameLabel.SetText("Enter Host IP Address\nto Join Game")
|
v.tcpJoinGameLabel.SetText(strings.Join(d2util.SplitIntoLinesWithMaxWidth(v.asset.TranslateLabel(tcpIPEnterHostIPLabel), 27), "\n"))
|
||||||
v.tcpJoinGameLabel.Color[0] = rgbaColor(gold)
|
v.tcpJoinGameLabel.Color[0] = rgbaColor(gold)
|
||||||
v.tcpJoinGameLabel.SetPosition(joinGameX, joinGameY)
|
v.tcpJoinGameLabel.SetPosition(joinGameX, joinGameY)
|
||||||
|
|
||||||
v.machineIP = v.uiManager.NewLabel(d2resource.Font24, d2resource.PaletteUnits)
|
v.machineIP = v.uiManager.NewLabel(d2resource.Font24, d2resource.PaletteUnits)
|
||||||
v.machineIP.Alignment = d2ui.HorizontalAlignCenter
|
v.machineIP.Alignment = d2ui.HorizontalAlignCenter
|
||||||
v.machineIP.SetText("Your IP address is:\n" + v.getLocalIP())
|
v.machineIP.SetText(v.asset.TranslateLabel(tcpIPYourIPLabel) + "\n" + v.getLocalIP())
|
||||||
v.machineIP.Color[0] = rgbaColor(lightYellow)
|
v.machineIP.Color[0] = rgbaColor(lightYellow)
|
||||||
v.machineIP.SetPosition(machineIPX, machineIPY)
|
v.machineIP.SetPosition(machineIPX, machineIPY)
|
||||||
|
|
||||||
@ -329,20 +400,20 @@ func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *MainMenu) createButtons(loading d2screen.LoadingState) {
|
func (v *MainMenu) createButtons(loading d2screen.LoadingState) {
|
||||||
v.exitDiabloButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, "EXIT DIABLO II")
|
v.exitDiabloButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateLabel(exitGameLabel))
|
||||||
v.exitDiabloButton.SetPosition(exitDiabloBtnX, exitDiabloBtnY)
|
v.exitDiabloButton.SetPosition(exitDiabloBtnX, exitDiabloBtnY)
|
||||||
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
|
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||||
|
|
||||||
v.creditsButton = v.uiManager.NewButton(d2ui.ButtonTypeShort, "CREDITS")
|
v.creditsButton = v.uiManager.NewButton(d2ui.ButtonTypeShort, v.asset.TranslateLabel(creditsLabel))
|
||||||
v.creditsButton.SetPosition(creditBtnX, creditBtnY)
|
v.creditsButton.SetPosition(creditBtnX, creditBtnY)
|
||||||
v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
|
v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
|
||||||
|
|
||||||
v.cinematicsButton = v.uiManager.NewButton(d2ui.ButtonTypeShort, "CINEMATICS")
|
v.cinematicsButton = v.uiManager.NewButton(d2ui.ButtonTypeShort, v.asset.TranslateLabel(cinematicsLabel))
|
||||||
v.cinematicsButton.SetPosition(cineBtnX, cineBtnY)
|
v.cinematicsButton.SetPosition(cineBtnX, cineBtnY)
|
||||||
v.cinematicsButton.OnActivated(func() { v.onCinematicsButtonClicked() })
|
v.cinematicsButton.OnActivated(func() { v.onCinematicsButtonClicked() })
|
||||||
loading.Progress(seventyPercent)
|
loading.Progress(seventyPercent)
|
||||||
|
|
||||||
v.singlePlayerButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, "SINGLE PLAYER")
|
v.singlePlayerButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateLabel(singlePlayerLabel))
|
||||||
v.singlePlayerButton.SetPosition(singlePlayerBtnX, singlePlayerBtnY)
|
v.singlePlayerButton.SetPosition(singlePlayerBtnX, singlePlayerBtnY)
|
||||||
v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
|
v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
|
||||||
|
|
||||||
@ -355,11 +426,11 @@ func (v *MainMenu) createButtons(loading d2screen.LoadingState) {
|
|||||||
v.mapTestButton.OnActivated(func() { v.onMapTestClicked() })
|
v.mapTestButton.OnActivated(func() { v.onMapTestClicked() })
|
||||||
|
|
||||||
v.btnTCPIPCancel = v.uiManager.NewButton(d2ui.ButtonTypeMedium,
|
v.btnTCPIPCancel = v.uiManager.NewButton(d2ui.ButtonTypeMedium,
|
||||||
v.asset.TranslateString("cancel"))
|
v.asset.TranslateLabel(cancelLabel))
|
||||||
v.btnTCPIPCancel.SetPosition(tcpBtnX, tcpBtnY)
|
v.btnTCPIPCancel.SetPosition(tcpBtnX, tcpBtnY)
|
||||||
v.btnTCPIPCancel.OnActivated(func() { v.onTCPIPCancelClicked() })
|
v.btnTCPIPCancel.OnActivated(func() { v.onTCPIPCancelClicked() })
|
||||||
|
|
||||||
v.btnServerIPCancel = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, "CANCEL")
|
v.btnServerIPCancel = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateLabel(cancelLabel))
|
||||||
v.btnServerIPCancel.SetPosition(srvCancelBtnX, srvCancelBtnY)
|
v.btnServerIPCancel.SetPosition(srvCancelBtnX, srvCancelBtnY)
|
||||||
v.btnServerIPCancel.OnActivated(func() { v.onBtnTCPIPCancelClicked() })
|
v.btnServerIPCancel.OnActivated(func() { v.onBtnTCPIPCancelClicked() })
|
||||||
|
|
||||||
@ -372,24 +443,25 @@ func (v *MainMenu) createButtons(loading d2screen.LoadingState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *MainMenu) createMultiplayerMenuButtons() {
|
func (v *MainMenu) createMultiplayerMenuButtons() {
|
||||||
v.multiplayerButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, "MULTIPLAYER")
|
v.multiplayerButton = v.uiManager.NewButton(d2ui.ButtonTypeWide,
|
||||||
|
v.asset.TranslateLabel(otherMultiplayerLabel))
|
||||||
v.multiplayerButton.SetPosition(multiplayerBtnX, multiplayerBtnY)
|
v.multiplayerButton.SetPosition(multiplayerBtnX, multiplayerBtnY)
|
||||||
v.multiplayerButton.OnActivated(func() { v.onMultiplayerClicked() })
|
v.multiplayerButton.OnActivated(func() { v.onMultiplayerClicked() })
|
||||||
|
|
||||||
v.networkTCPIPButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, "TCP/IP GAME")
|
v.networkTCPIPButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateLabel(tcpIPGameLabel))
|
||||||
v.networkTCPIPButton.SetPosition(tcpNetBtnX, tcpNetBtnY)
|
v.networkTCPIPButton.SetPosition(tcpNetBtnX, tcpNetBtnY)
|
||||||
v.networkTCPIPButton.OnActivated(func() { v.onNetworkTCPIPClicked() })
|
v.networkTCPIPButton.OnActivated(func() { v.onNetworkTCPIPClicked() })
|
||||||
|
|
||||||
v.networkCancelButton = v.uiManager.NewButton(d2ui.ButtonTypeWide,
|
v.networkCancelButton = v.uiManager.NewButton(d2ui.ButtonTypeWide,
|
||||||
v.asset.TranslateString("cancel"))
|
v.asset.TranslateLabel(cancelLabel))
|
||||||
v.networkCancelButton.SetPosition(networkCancelBtnX, networkCancelBtnY)
|
v.networkCancelButton.SetPosition(networkCancelBtnX, networkCancelBtnY)
|
||||||
v.networkCancelButton.OnActivated(func() { v.onNetworkCancelClicked() })
|
v.networkCancelButton.OnActivated(func() { v.onNetworkCancelClicked() })
|
||||||
|
|
||||||
v.btnTCPIPHostGame = v.uiManager.NewButton(d2ui.ButtonTypeWide, "HOST GAME")
|
v.btnTCPIPHostGame = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateLabel(tcpIPHostGameLabel))
|
||||||
v.btnTCPIPHostGame.SetPosition(tcpHostBtnX, tcpHostBtnY)
|
v.btnTCPIPHostGame.SetPosition(tcpHostBtnX, tcpHostBtnY)
|
||||||
v.btnTCPIPHostGame.OnActivated(func() { v.onTCPIPHostGameClicked() })
|
v.btnTCPIPHostGame.OnActivated(func() { v.onTCPIPHostGameClicked() })
|
||||||
|
|
||||||
v.btnTCPIPJoinGame = v.uiManager.NewButton(d2ui.ButtonTypeWide, "JOIN GAME")
|
v.btnTCPIPJoinGame = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateLabel(tcpIPJoinGameLabel))
|
||||||
v.btnTCPIPJoinGame.SetPosition(tcpJoinBtnX, tcpJoinBtnY)
|
v.btnTCPIPJoinGame.SetPosition(tcpJoinBtnX, tcpJoinBtnY)
|
||||||
v.btnTCPIPJoinGame.OnActivated(func() { v.onTCPIPJoinGameClicked() })
|
v.btnTCPIPJoinGame.OnActivated(func() { v.onTCPIPJoinGameClicked() })
|
||||||
}
|
}
|
||||||
@ -645,5 +717,5 @@ func (v *MainMenu) getLocalIP() string {
|
|||||||
|
|
||||||
v.Warning("no IPv4 Address could be found")
|
v.Warning("no IPv4 Address could be found")
|
||||||
|
|
||||||
return "no IPv4 Address could be found"
|
return v.asset.TranslateLabel(ipNotFoundLabel)
|
||||||
}
|
}
|
||||||
|
@ -416,7 +416,7 @@ func (v *SelectHeroClass) createLabels() {
|
|||||||
halfFontWidth := fontWidth / half
|
halfFontWidth := fontWidth / half
|
||||||
|
|
||||||
v.headingLabel.SetPosition(headingX-halfFontWidth, headingY)
|
v.headingLabel.SetPosition(headingX-halfFontWidth, headingY)
|
||||||
v.headingLabel.SetText("Select Hero Class")
|
v.headingLabel.SetText(v.asset.TranslateLabel(selectHeroClassLabel))
|
||||||
v.headingLabel.Alignment = d2ui.HorizontalAlignCenter
|
v.headingLabel.Alignment = d2ui.HorizontalAlignCenter
|
||||||
|
|
||||||
v.heroClassLabel = v.uiManager.NewLabel(d2resource.Font30, d2resource.PaletteUnits)
|
v.heroClassLabel = v.uiManager.NewLabel(d2resource.Font30, d2resource.PaletteUnits)
|
||||||
@ -437,22 +437,22 @@ func (v *SelectHeroClass) createLabels() {
|
|||||||
|
|
||||||
v.heroNameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
v.heroNameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||||
v.heroNameLabel.Alignment = d2ui.HorizontalAlignLeft
|
v.heroNameLabel.Alignment = d2ui.HorizontalAlignLeft
|
||||||
v.heroNameLabel.SetText(d2ui.ColorTokenize("Character Name", d2ui.ColorTokenGold))
|
v.heroNameLabel.SetText(d2ui.ColorTokenize(v.asset.TranslateLabel(charNameLabel), d2ui.ColorTokenGold))
|
||||||
v.heroNameLabel.SetPosition(heroNameLabelX, heroNameLabelY)
|
v.heroNameLabel.SetPosition(heroNameLabelX, heroNameLabelY)
|
||||||
|
|
||||||
v.expansionCharLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
v.expansionCharLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||||
v.expansionCharLabel.Alignment = d2ui.HorizontalAlignLeft
|
v.expansionCharLabel.Alignment = d2ui.HorizontalAlignLeft
|
||||||
v.expansionCharLabel.SetText(d2ui.ColorTokenize("EXPANSION CHARACTER", d2ui.ColorTokenGold))
|
v.expansionCharLabel.SetText(d2ui.ColorTokenize(v.asset.TranslateString("#803"), d2ui.ColorTokenGold))
|
||||||
v.expansionCharLabel.SetPosition(expansionLabelX, expansionLabelY)
|
v.expansionCharLabel.SetPosition(expansionLabelX, expansionLabelY)
|
||||||
|
|
||||||
v.hardcoreCharLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
v.hardcoreCharLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||||
v.hardcoreCharLabel.Alignment = d2ui.HorizontalAlignLeft
|
v.hardcoreCharLabel.Alignment = d2ui.HorizontalAlignLeft
|
||||||
v.hardcoreCharLabel.SetText(d2ui.ColorTokenize("Hardcore", d2ui.ColorTokenGold))
|
v.hardcoreCharLabel.SetText(d2ui.ColorTokenize(v.asset.TranslateLabel(hardCoreLabel), d2ui.ColorTokenGold))
|
||||||
v.hardcoreCharLabel.SetPosition(hardcoreLabelX, hardcoreLabelY)
|
v.hardcoreCharLabel.SetPosition(hardcoreLabelX, hardcoreLabelY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *SelectHeroClass) createButtons() {
|
func (v *SelectHeroClass) createButtons() {
|
||||||
v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, "EXIT")
|
v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateLabel(exitLabel))
|
||||||
v.exitButton.SetPosition(selHeroExitBtnX, selHeroExitBtnY)
|
v.exitButton.SetPosition(selHeroExitBtnX, selHeroExitBtnY)
|
||||||
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||||
|
|
||||||
@ -685,25 +685,26 @@ func (v *SelectHeroClass) updateHeroText() {
|
|||||||
return
|
return
|
||||||
case d2enum.HeroBarbarian:
|
case d2enum.HeroBarbarian:
|
||||||
v.heroClassLabel.SetText(v.asset.TranslateString("partycharbar"))
|
v.heroClassLabel.SetText(v.asset.TranslateString("partycharbar"))
|
||||||
v.setDescLabels("He is unequaled in close-quarters combat and mastery of weapons.")
|
v.setDescLabels(barbarianDescr, "")
|
||||||
case d2enum.HeroNecromancer:
|
case d2enum.HeroNecromancer:
|
||||||
v.heroClassLabel.SetText(v.asset.TranslateString("partycharnec"))
|
v.heroClassLabel.SetText(v.asset.TranslateString("partycharnec"))
|
||||||
v.setDescLabels("Summoning undead minions and cursing his enemies are his specialties.")
|
v.setDescLabels(necromancerDescr, "")
|
||||||
case d2enum.HeroPaladin:
|
case d2enum.HeroPaladin:
|
||||||
v.heroClassLabel.SetText(v.asset.TranslateString("partycharpal"))
|
v.heroClassLabel.SetText(v.asset.TranslateString("partycharpal"))
|
||||||
v.setDescLabels("He is a natural party leader, holy man, and blessed warrior.")
|
v.setDescLabels(paladinDescr, "")
|
||||||
case d2enum.HeroAssassin:
|
case d2enum.HeroAssassin:
|
||||||
v.heroClassLabel.SetText(v.asset.TranslateString("partycharass"))
|
v.heroClassLabel.SetText(v.asset.TranslateString("partycharass"))
|
||||||
v.setDescLabels("Schooled in the Martial Arts, her mind and body are deadly weapons.")
|
v.setDescLabels(0, "#305")
|
||||||
case d2enum.HeroSorceress:
|
case d2enum.HeroSorceress:
|
||||||
v.heroClassLabel.SetText(v.asset.TranslateString("partycharsor"))
|
v.heroClassLabel.SetText(v.asset.TranslateString("partycharsor"))
|
||||||
v.setDescLabels("She has mastered the elemental magicks -- fire, lightning, and ice.")
|
v.setDescLabels(sorceressDescr, "")
|
||||||
case d2enum.HeroAmazon:
|
case d2enum.HeroAmazon:
|
||||||
v.heroClassLabel.SetText(v.asset.TranslateString("partycharama"))
|
v.heroClassLabel.SetText(v.asset.TranslateString("partycharama"))
|
||||||
v.setDescLabels("Skilled with the spear and the bow, she is a very versatile fighter.")
|
v.setDescLabels(amazonDescr, "")
|
||||||
case d2enum.HeroDruid:
|
case d2enum.HeroDruid:
|
||||||
v.heroClassLabel.SetText(v.asset.TranslateString("partychardru"))
|
v.heroClassLabel.SetText(v.asset.TranslateString("partychardru"))
|
||||||
v.setDescLabels("Commanding the forces of nature, he summons wild beasts and raging storms to his side.")
|
// here is a problem with polish language: in polish string table, there are two items with key "#304"
|
||||||
|
v.setDescLabels(0, "#304")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,8 +713,15 @@ const (
|
|||||||
twoLine = 2
|
twoLine = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *SelectHeroClass) setDescLabels(descKey string) {
|
func (v *SelectHeroClass) setDescLabels(descKey int, key string) {
|
||||||
heroDesc := v.asset.TranslateString(descKey)
|
var heroDesc string
|
||||||
|
|
||||||
|
if key != "" {
|
||||||
|
heroDesc = v.asset.TranslateString(key)
|
||||||
|
} else {
|
||||||
|
heroDesc = v.asset.TranslateLabel(descKey)
|
||||||
|
}
|
||||||
|
|
||||||
parts := d2util.SplitIntoLinesWithMaxWidth(heroDesc, heroDescCharWidth)
|
parts := d2util.SplitIntoLinesWithMaxWidth(heroDesc, heroDescCharWidth)
|
||||||
|
|
||||||
numLines := len(parts)
|
numLines := len(parts)
|
||||||
|
@ -254,7 +254,7 @@ func (s *HeroStatsPanel) renderStaticLabels(target d2interface.Surface) {
|
|||||||
centerAlign bool
|
centerAlign bool
|
||||||
}{
|
}{
|
||||||
{labelHeroNameX, labelHeroNameY, s.heroName, d2resource.Font16, true},
|
{labelHeroNameX, labelHeroNameY, s.heroName, d2resource.Font16, true},
|
||||||
{labelHeroClassX, labelHeroClassY, s.asset.TranslateHeroClass(s.heroClass), d2resource.Font16, true},
|
{labelHeroClassX, labelHeroClassY, s.asset.TranslateString(s.heroClass), d2resource.Font16, true},
|
||||||
|
|
||||||
{labelLevelX, labelLevelY, s.asset.TranslateString("strchrlvl"), d2resource.Font6, true},
|
{labelLevelX, labelLevelY, s.asset.TranslateString("strchrlvl"), d2resource.Font6, true},
|
||||||
{labelExperienceX, labelExperienceY, s.asset.TranslateString("strchrexp"), d2resource.Font6, true},
|
{labelExperienceX, labelExperienceY, s.asset.TranslateString("strchrexp"), d2resource.Font6, true},
|
||||||
|
Loading…
Reference in New Issue
Block a user